Index: /tags/opihi-2-1/Ohana/src/opihi/Makefile
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/Makefile	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/Makefile	(revision 3338)
@@ -0,0 +1,47 @@
+
+### this is the top-level makefile for the opihi.v2 collection of programs
+
+default: all
+
+### the include file dependencies need to be cleaned up still
+
+mana:  lib.data lib.shell cmd.basic cmd.data cmd.astro
+dimm:  lib.data lib.shell cmd.basic cmd.data cmd.astro
+dvo2:  lib.data lib.shell cmd.basic cmd.data cmd.astro
+dvo:   lib.data lib.shell cmd.basic cmd.data cmd.astro
+sched: lib.data lib.shell cmd.basic cmd.data cmd.astro
+pclient: lib.data lib.shell cmd.basic
+pcontrol: lib.data lib.shell cmd.basic
+
+LIBS = cmd.basic cmd.data cmd.astro lib.data lib.shell
+
+PROGRAM = mana dvo
+
+EXTRAS = dvo2 sched dimm pclient pcontrol
+
+all:
+	for i in $(PROGRAM); do make $$i || exit; done
+
+extras:
+	for i in $(EXTRAS); do make $$i || exit; done
+
+install:
+	for i in $(PROGRAM); do make $$i.install || exit; done
+
+clean:
+	for i in $(PROGRAM) $(LIBS); do make $$i.clean || exit; done
+
+#############################################################
+
+$(PROGRAM) $(LIBS) $(EXTRAS):
+	if [ -d "$@" ]; then (cd $@ && make); fi
+
+%.install:
+	if [ -d "$*" ]; then make $*; fi
+	if [ -d "$*" ]; then (cd $* && make install); fi
+
+%.clean:
+	if [ -d "$*" ]; then (cd $* && make clean); fi
+
+.PHONY: $(PROGRAM) $(LIBS)
+
Index: /tags/opihi-2-1/Ohana/src/opihi/bin/.cvsignore
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/bin/.cvsignore	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/bin/.cvsignore	(revision 3338)
@@ -0,0 +1,1 @@
+*.linux *.lin64 *.sol *.sun *.sid *.hp *.irix
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/Makefile
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/Makefile	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/Makefile	(revision 3338)
@@ -0,0 +1,120 @@
+include ../../../Configure
+
+HOME    =       $(ROOT)/src/opihi.v2
+BIN     =       $(HOME)/bin
+LIB     =       $(HOME)/lib
+INC     =       $(HOME)/include
+SDIR    =       $(HOME)/cmd.astro
+#
+DESTBIN =       $(LBIN)
+DESTLIB =       $(LLIB)
+DESTINC =       $(LINC)
+DESTMAN =       $(LMAN)
+HELP    =       $(HOME)/help
+#  
+INCS    =       -I$(INC) -I$(LINC) -I$(XINC)
+LFLAGS  =       -L$(LLIB) -L$(LIB)
+LIBS    =       -lFITS -lsocket -lnsl -lreadline -ltermcap -lohana -lm
+CFLAGS  =       $(INCS)
+CCFLAGS =       $(LIBS) 
+
+# astro user commands ########################
+
+astrocmd = \
+$(SDIR)/init.$(ARCH).o             \
+$(SDIR)/biassub.$(ARCH).o	   \
+$(SDIR)/cgrid.$(ARCH).o		   \
+$(SDIR)/coords.$(ARCH).o	   \
+$(SDIR)/cplot.$(ARCH).o		   \
+$(SDIR)/csystem.$(ARCH).o	   \
+$(SDIR)/ctimes.$(ARCH).o	   \
+$(SDIR)/cval.$(ARCH).o		   \
+$(SDIR)/czplot.$(ARCH).o	   \
+$(SDIR)/drizzle.$(ARCH).o	   \
+$(SDIR)/flux.$(ARCH).o		   \
+$(SDIR)/gauss.$(ARCH).o		   \
+$(SDIR)/getvel.$(ARCH).o	   \
+$(SDIR)/medianmap.$(ARCH).o	   \
+$(SDIR)/mkgauss.$(ARCH).o	   \
+$(SDIR)/multifit.$(ARCH).o	   \
+$(SDIR)/objload.$(ARCH).o	   \
+$(SDIR)/outline2.$(ARCH).o	   \
+$(SDIR)/outline.$(ARCH).o	   \
+$(SDIR)/polar.$(ARCH).o		   \
+$(SDIR)/precess.$(ARCH).o	   \
+$(SDIR)/profile.$(ARCH).o	   \
+$(SDIR)/region.$(ARCH).o	   \
+$(SDIR)/rotcurve.$(ARCH).o	   \
+$(SDIR)/scale.$(ARCH).o		   \
+$(SDIR)/sexigesimal.$(ARCH).o	   \
+$(SDIR)/spec.$(ARCH).o		   \
+$(SDIR)/star.$(ARCH).o		   \
+$(SDIR)/transform.$(ARCH).o
+
+imfitstuff = \
+$(SDIR)/imsub.$(ARCH).o		   \
+$(SDIR)/imfit.$(ARCH).o		   \
+$(SDIR)/imfit-fgauss.$(ARCH).o	   \
+$(SDIR)/imfit-pgauss.$(ARCH).o	   \
+$(SDIR)/imfit-Pgauss.$(ARCH).o	   \
+$(SDIR)/imfit-qgauss.$(ARCH).o	   \
+$(SDIR)/imfit-Qgauss.$(ARCH).o	   \
+$(SDIR)/imfit-sgauss.$(ARCH).o	   \
+$(SDIR)/imfit-Sgauss.$(ARCH).o	   \
+$(SDIR)/imfit-qfgauss.$(ARCH).o	   \
+$(SDIR)/imfit-qrgauss.$(ARCH).o	   
+
+libastrocmd:    $(DESTLIB)/libastrocmd.a 
+
+$(LIB)/libastrocmd.$(ARCH).a:   	$(astrocmd) $(imfitstuff)
+
+# utilities #################################################
+$(BIN)/%.$(ARCH):
+	@if [ ! -d $(BIN) ]; then mkdir -p $(BIN); fi
+	$(CC) $^ -o $@ $(LFLAGS) $(LIBS)
+	@echo "compiled $*"
+	@echo ""
+
+$(DESTBIN)/%: $(BIN)/%.$(ARCH) 
+	@if [ ! -d $(DESTBIN) ]; then mkdir -p $(DESTBIN); fi
+	rm -f $(DESTBIN)/$*
+	cp $(BIN)/$*.$(ARCH) $(DESTBIN)/$*
+	@echo "installed $*"
+	@echo ""
+
+$(LIB)/%.$(ARCH).a:
+	@if [ ! -d $(LIB) ]; then mkdir -p $(LIB); fi
+	rm -f $@
+	ar rcv $@ $^ 
+	$(RANLIB) $@
+	@echo "compiled library $*"
+	@echo ""
+
+$(DESTLIB)/%.a: $(LIB)/%.$(ARCH).a
+	@if [ ! -d $(DESTLIB) ]; then mkdir -p $(DESTLIB); fi
+	@echo ""
+	rm -f $@
+	cp $^ $@
+
+lib%.clean:
+	rm -f $(LIB)/lib$*.$(ARCH).a
+	rm -f $($*)
+	@echo ""
+
+%.clean:
+	rm -f $(BIN)/$*.$(ARCH)
+	@echo ""
+
+%.$(ARCH).o : %.c
+	$(CC) $(CFLAGS) -c $*.c -o $@
+
+clean:
+	rm -f $(BIN)/*.$(ARCH)
+	rm -f $(LIB)/*.$(ARCH).a
+	rm -f `find . -name "*.o"`
+	rm -f `find . -name "*~"`
+	rm -f `find . -name "#*"`
+
+dist: clean
+	rm -f $(BIN)/*
+	rm -f $(LIB)/*
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/biassub.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/biassub.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/biassub.c	(revision 3338)
@@ -0,0 +1,125 @@
+# include "astro.h"
+
+int biassub (int argc, char **argv) {
+  
+  int i, j, k, N, dir, nlong, nwide, start;
+  int sx, sy, nx, ny, NX, NY, NoVector, Nval;
+  float *V, *DV, dV, *vect, *segment, val;
+  Vector *xvec, *yvec;
+  Buffer *buf;
+
+  NoVector = TRUE;
+  if ((N = get_argument (argc, argv, "-v"))) {
+    NoVector = FALSE;
+    remove_argument (N, &argc, argv);
+    if ((xvec = SelectVector (argv[N], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    remove_argument (N, &argc, argv);
+    if ((yvec = SelectVector (argv[N], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 7) {
+    fprintf (stderr, "USAGE: biassub <buffer> sx sy nx ny dir [-v N V]\n");
+    fprintf (stderr, "  optional storage of vector and sequence in N and V\n");
+    return (FALSE);
+  }
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  sx = atof (argv[2]);
+  sy = atof (argv[3]);
+  nx = atof (argv[4]);
+  ny = atof (argv[5]);
+  dir = atof (argv[6]);
+  if ((dir != 0) && (dir != 1)) {
+    fprintf (stderr, " dir must be either 0 (x) or 1 (y)\n");
+    return (FALSE);
+  }
+  if (dir) {
+    start = sy;
+    nwide = nx;
+    nlong = ny;
+  } else {
+    start = sx;
+    nwide = ny;
+    nlong = nx;
+  }    
+  fprintf (GetOutfile(), "start: %d %d  size: %d %d\n", sx, sy, nx, ny);
+
+    if ((sx < 0) || (sy < 0) || 
+      (sx+nx > buf[0].matrix.Naxis[0]) || 
+      (sy+ny > buf[0].matrix.Naxis[1])) {
+    fprintf (stderr, "region out of range\n");
+    return (FALSE);
+  }
+
+  ALLOCATE (vect, float, nlong);
+  ALLOCATE (segment, float, nwide);
+
+  NX = buf[0].matrix.Naxis[0];
+  NY = buf[0].matrix.Naxis[1];
+  if (dir) {
+    for (j = sy; j < sy + ny; j++) {
+      V = (float *)(buf[0].matrix.buffer) + j*NX + sx; 
+      for (i = 0; i < nx; i++, V++) {
+	segment[i] = *V;
+      }
+      fsort (segment, nwide);
+      val = Nval = 0;
+      for (k = 0.25*nwide; k <=0.75*nwide; k++) {
+	val += segment[k];
+	Nval ++;
+      }
+      vect[j-sy] = val / Nval;
+    }
+  } else {
+    for (i = 0; i < nx; i++) {
+      V = (float *)(buf[0].matrix.buffer) + sy*NX + sx + i; 
+      for (j = 0; j < ny; j++, V+=NX) {
+	segment[j] = *V;
+      }
+      fsort (segment, nwide);
+      val = Nval = 0;
+      for (k = 0.25*nwide; k <=0.75*nwide; k++) {
+	val += segment[k];
+	Nval ++;
+      }
+      vect[i] = val / Nval;
+    }
+  }
+
+  if (!NoVector) {
+    xvec[0].Nelements = yvec[0].Nelements = nlong;
+    REALLOCATE (xvec[0].elements, float, nlong);
+    REALLOCATE (yvec[0].elements, float, nlong);
+    for (i = 0; i < nlong; i++) {
+      xvec[0].elements[i] = i + start;
+      yvec[0].elements[i] = vect[i];
+    }
+  }
+
+  if (dir) {
+    /* here we run all the way across in X for the defined Y range */
+    for (j = sy; j < sy + ny; j++) {
+      V = (float *)(buf[0].matrix.buffer) + j*NX; 
+      dV = vect[j];
+      for (i = 0; i < NX; i++, V++) {
+	*V -= dV;
+      }
+    }
+  } else {
+    /* here we run all the way across in Y for the defined X range */
+    for (j = 0; j < NY; j++) {
+      V = (float *)(buf[0].matrix.buffer) + j*NX + sx; 
+      DV = vect;
+      for (i = 0; i < nx; i++, V++, DV++) {
+	*V -= *DV;
+      }
+    }
+  }
+
+  free (segment);
+  free (vect);
+
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/cgrid.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/cgrid.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/cgrid.c	(revision 3338)
@@ -0,0 +1,403 @@
+# include "astro.h"
+# define CHECKELEMENTS \
+  if (N == NELEMENTS) { \
+    NELEMENTS +=200; \
+    REALLOCATE (Xvec.elements, float, NELEMENTS); \
+    REALLOCATE (Yvec.elements, float, NELEMENTS); \
+  }
+
+int cgrid (int argc, char **argv) {
+  
+  double range, lrange, factor, mantis, power, fmantis;
+  double firstRA, firstDEC, minorRA, minorDEC;
+  double r, d, dR, dD, D;
+  double x, y;
+  Vector Xvec, Yvec;
+  int NorthPole, SouthPole, N, OnPic, LOnPic, status, NELEMENTS, First;
+  Graphdata graphmode;
+  int Ngraph;
+
+  Ngraph = 0;
+  if (!GetGraph (&graphmode, NULL, &Ngraph)) return (FALSE);
+
+  if (argc != 1) {
+    fprintf (stderr, "USAGE: cgrid\n");
+    return (FALSE);
+  }
+
+  /* are we plotting one of the poles? */
+  NorthPole = SouthPole = FALSE;
+  status = RD_to_XY (&x, &y, 0.0, 90.0, &graphmode.coords);
+  if ((x >= graphmode.xmin) && (x <= graphmode.xmax) && 
+      (y >= graphmode.ymin) && (y <= graphmode.ymax) && status)
+    NorthPole = TRUE;
+  status = RD_to_XY (&x, &y, 0.0, -90.0, &graphmode.coords);
+  if ((x >= graphmode.xmin) && (x <= graphmode.xmax) && 
+      (y >= graphmode.ymin) && (y <= graphmode.ymax) && status)
+    SouthPole = TRUE;
+
+  /* set spacings for RA */
+  minorRA = minorDEC = 0.1;
+  range = MIN (fabs(graphmode.xmax-graphmode.xmin), fabs(graphmode.ymax-graphmode.ymin));
+  if (NorthPole || SouthPole) range = 360;
+  lrange = log10(MAX(fabs(range), 1e-30));
+  factor = (int) (lrange);
+  if (lrange < 0) { factor -= 1; }
+  mantis = lrange - factor;
+  power = pow(10.0, factor);
+  fmantis = pow(10.0, mantis);
+  if ((fmantis >= 1.0) && (fmantis <=  2.0)) {
+    minorRA = 0.1 * power;
+  }
+  if ((fmantis > 2.0) && (fmantis <=  4.0)) {
+    minorRA = 0.2 * power;
+  }
+  if ((fmantis > 4.0) && (fmantis <=  6.0)) {
+    minorRA = 0.5 * power;
+  }
+  if ((fmantis > 6.0) && (fmantis <=  10.0)) {
+    minorRA = 0.5 * power;
+  }
+  dR = range / 100.0;
+  /* set spacings for DEC */
+  range = MIN (fabs(graphmode.xmax-graphmode.xmin), fabs(graphmode.ymax-graphmode.ymin));
+  lrange = log10(MAX(fabs(range), 1e-30));
+  factor = (int) (lrange);
+  if (lrange < 0) { factor -= 1; }
+  mantis = lrange - factor;
+  power = pow(10.0, factor);
+  fmantis = pow(10.0, mantis);
+  if ((fmantis >= 1.0) && (fmantis <=  2.0)) {
+    minorDEC = 0.1 * power;
+  }
+  if ((fmantis > 2.0) && (fmantis <=  4.0)) {
+    minorDEC = 0.2 * power;
+  }
+  if ((fmantis > 4.0) && (fmantis <=  6.0)) {
+    minorDEC = 0.5 * power;
+  }
+  if ((fmantis > 6.0) && (fmantis <=  10.0)) {
+    minorDEC = 0.5 * power;
+  }
+  dD = range / 100.0;
+
+  /* choose a starting point */
+  if ((int)(graphmode.coords.crval1/minorRA) == (graphmode.coords.crval1/minorRA)) {
+    firstRA = graphmode.coords.crval1;
+  } else {
+    firstRA = minorRA + minorRA*((int)(graphmode.coords.crval1/minorRA));
+  }
+  if ((int)(graphmode.coords.crval2/minorDEC) == (graphmode.coords.crval2/minorDEC)) {
+    firstDEC = graphmode.coords.crval2;
+  } else {
+    firstDEC = minorDEC + minorDEC*((int)(graphmode.coords.crval2/minorDEC));
+  }
+  if (SouthPole) firstDEC = -90;
+  if (NorthPole) firstDEC = 90;
+  
+  /* prepare vectors to hold data */
+  NELEMENTS = 200;
+  ALLOCATE (Xvec.elements, float, NELEMENTS);
+  ALLOCATE (Yvec.elements, float, NELEMENTS);
+  N = 0;
+  
+  /***  do consecutive RA lines, first increasing **/
+  OnPic = TRUE;
+  for (r = firstRA; (r <= firstRA + 180) && (OnPic); r += minorRA) {
+    /* first, DEC increasing */
+    LOnPic = TRUE;
+    OnPic = FALSE;
+    First = TRUE;
+    for (d = firstDEC; (d < 90 + dD) && (LOnPic || NorthPole || SouthPole); d += dD) {
+      D = MAX (-90, MIN(90, d));
+      status = fRD_to_XY (&Xvec.elements[N], &Yvec.elements[N], r, D, &graphmode.coords);
+      /*
+      if ((fabs(Xvec.elements[N] - Xvec.elements[N-1]) > 10) && (fabs(Yvec.elements[N] - Yvec.elements[N-1]) > 10))
+	First = TRUE;
+	*/
+      if ((Xvec.elements[N] >= graphmode.xmin) && (Xvec.elements[N] <= graphmode.xmax) && 
+	  (Yvec.elements[N] >= graphmode.ymin) && (Yvec.elements[N] <= graphmode.ymax) && status) {
+	N++;
+	CHECKELEMENTS;
+	OnPic = TRUE;
+	if (!First) {
+	  Xvec.elements[N] = Xvec.elements[N-1];
+	  Yvec.elements[N] = Yvec.elements[N-1];
+	  N++;
+	  CHECKELEMENTS;
+	} else {
+	  if (N > 1) {
+	    Xvec.elements[N-2] = Xvec.elements[N-1];
+	    Yvec.elements[N-2] = Yvec.elements[N-1];
+	    N--;
+	  }
+	  First = FALSE;
+	}
+      } else {
+	LOnPic = FALSE;
+	First = TRUE;
+      }
+    }
+    /* next, DEC decreasing */
+    First = TRUE;
+    LOnPic = TRUE;
+    for (d = firstDEC; (d > -90 - dD) && (LOnPic || NorthPole || SouthPole); d -= dD) {
+      D = MAX (-90, MIN(90, d));
+      status = fRD_to_XY (&Xvec.elements[N], &Yvec.elements[N], r, D, &graphmode.coords);
+      /*
+      if ((fabs(Xvec.elements[N] - Xvec.elements[N-1]) > 10) && (fabs(Yvec.elements[N] - Yvec.elements[N-1]) > 10))
+	First = TRUE;
+	*/
+      if ((Xvec.elements[N] >= graphmode.xmin) && (Xvec.elements[N] <= graphmode.xmax) && 
+	  (Yvec.elements[N] >= graphmode.ymin) && (Yvec.elements[N] <= graphmode.ymax) && status) {
+	N++;
+	CHECKELEMENTS;
+	OnPic = TRUE;
+	if (!First) {
+	  Xvec.elements[N] = Xvec.elements[N-1];
+	  Yvec.elements[N] = Yvec.elements[N-1];
+	  N++;
+	  CHECKELEMENTS;
+	} else {
+	  if (N > 1) {
+	    Xvec.elements[N-2] = Xvec.elements[N-1];
+	    Yvec.elements[N-2] = Yvec.elements[N-1];
+	    N--;
+	  }
+	  First = FALSE;
+	}
+      } else {
+	LOnPic = FALSE;
+	First = TRUE;
+      } 
+    }
+  }
+
+  /***  do consecutive RA lines, decreasing **/
+  OnPic = TRUE;
+  for (r = firstRA; (r >=  firstRA - 180) && (OnPic); r -= minorRA) {
+    /* first, DEC increasing */
+    First = TRUE;
+    LOnPic = TRUE;
+    OnPic = FALSE;
+    for (d = firstDEC; (d < 90 + dD) && (LOnPic || NorthPole || SouthPole); d += dD) {
+      D = MAX (-90, MIN(90, d));
+      status = fRD_to_XY (&Xvec.elements[N], &Yvec.elements[N], r, D, &graphmode.coords);
+      /*
+      if ((fabs(Xvec.elements[N] - Xvec.elements[N-1]) > 10) && (fabs(Yvec.elements[N] - Yvec.elements[N-1]) > 10))
+	First = TRUE;
+	*/
+      if ((Xvec.elements[N] >= graphmode.xmin) && (Xvec.elements[N] <= graphmode.xmax) && 
+	  (Yvec.elements[N] >= graphmode.ymin) && (Yvec.elements[N] <= graphmode.ymax) && status) {
+	N++;
+	CHECKELEMENTS;
+	OnPic = TRUE;
+	if (!First) {
+	  Xvec.elements[N] = Xvec.elements[N-1];
+	  Yvec.elements[N] = Yvec.elements[N-1];
+	  N++;
+	  CHECKELEMENTS;
+	} else {
+	  if (N > 1) {
+	    Xvec.elements[N-2] = Xvec.elements[N-1];
+	    Yvec.elements[N-2] = Yvec.elements[N-1];
+	    N--;
+	  }
+	  First = FALSE;
+	}
+      } else {
+	LOnPic = FALSE;
+	First = TRUE;
+      }
+    }
+    /* next, DEC decreasing */
+    First = TRUE;
+    LOnPic = TRUE;
+    for (d = firstDEC; (d > -90 - dD) && (LOnPic || NorthPole || SouthPole); d -= dD) {
+      D = MAX (-90, MIN(90, d));
+      status = fRD_to_XY (&Xvec.elements[N], &Yvec.elements[N], r, D, &graphmode.coords);
+      /*
+      if ((fabs(Xvec.elements[N] - Xvec.elements[N-1]) > 10) && (fabs(Yvec.elements[N] - Yvec.elements[N-1]) > 10))
+	First = TRUE;
+	*/
+      if ((Xvec.elements[N] >= graphmode.xmin) && (Xvec.elements[N] <= graphmode.xmax) && 
+	  (Yvec.elements[N] >= graphmode.ymin) && (Yvec.elements[N] <= graphmode.ymax) && status) {
+	N++;
+	CHECKELEMENTS;
+	OnPic = TRUE;
+	if (!First) {
+	  Xvec.elements[N] = Xvec.elements[N-1];
+	  Yvec.elements[N] = Yvec.elements[N-1];
+	  N++;
+	  CHECKELEMENTS;
+	} else {
+	  if (N > 1) {
+	    Xvec.elements[N-2] = Xvec.elements[N-1];
+	    Yvec.elements[N-2] = Yvec.elements[N-1];
+	    N--;
+	  }
+	  First = FALSE;
+	}
+      } else {
+	LOnPic = FALSE;
+	First = TRUE;
+      }
+    }
+  }
+
+  /***  do consecutive DEC lines, first increasing **/
+  OnPic = TRUE;
+  for (d = firstDEC; (d < 90 + dD) && (OnPic); d += minorDEC) {
+    D = MAX (-90, MIN(90, d));
+    /* first, RA increasing */
+    LOnPic = TRUE;
+    OnPic = FALSE;
+    First = TRUE;
+    for (r = firstRA; (r < firstRA + 180) && (LOnPic || NorthPole || SouthPole); r += dR) {
+      status = fRD_to_XY (&Xvec.elements[N], &Yvec.elements[N], r, D, &graphmode.coords);
+      /*
+      if ((fabs(Xvec.elements[N] - Xvec.elements[N-1]) > 10) && (fabs(Yvec.elements[N] - Yvec.elements[N-1]) > 10))
+	First = TRUE;
+	*/
+      if ((Xvec.elements[N] >= graphmode.xmin) && (Xvec.elements[N] <= graphmode.xmax) && 
+	  (Yvec.elements[N] >= graphmode.ymin) && (Yvec.elements[N] <= graphmode.ymax) && status) {
+	N++;
+	CHECKELEMENTS;
+	OnPic = TRUE;
+	if (!First) {
+	  Xvec.elements[N] = Xvec.elements[N-1];
+	  Yvec.elements[N] = Yvec.elements[N-1];
+	  N++;
+	  CHECKELEMENTS;
+	} else {
+	  if (N > 1) {
+	    Xvec.elements[N-2] = Xvec.elements[N-1];
+	    Yvec.elements[N-2] = Yvec.elements[N-1];
+	    N--;
+	  }
+	  First = FALSE;
+	}
+      } else {
+	LOnPic = FALSE;
+	First = TRUE;
+      }
+    }
+    /* next, RA decreasing */
+    First = TRUE;
+    LOnPic = TRUE;
+    for (r = firstRA; (r > firstRA - 180) && (LOnPic || NorthPole || SouthPole); r -= dR) {
+      status = fRD_to_XY (&Xvec.elements[N], &Yvec.elements[N], r, D, &graphmode.coords);
+      /*
+      if ((fabs(Xvec.elements[N] - Xvec.elements[N-1]) > 10) && (fabs(Yvec.elements[N] - Yvec.elements[N-1]) > 10))
+	First = TRUE;
+	*/
+      if ((Xvec.elements[N] >= graphmode.xmin) && (Xvec.elements[N] <= graphmode.xmax) && 
+	  (Yvec.elements[N] >= graphmode.ymin) && (Yvec.elements[N] <= graphmode.ymax) && status) {
+	N++;
+	CHECKELEMENTS;
+	OnPic = TRUE;
+	if (!First) {
+	  Xvec.elements[N] = Xvec.elements[N-1];
+	  Yvec.elements[N] = Yvec.elements[N-1];
+	  N++;
+	  CHECKELEMENTS;
+	} else {
+	  if (N > 1) {
+	    Xvec.elements[N-2] = Xvec.elements[N-1];
+	    Yvec.elements[N-2] = Yvec.elements[N-1];
+	    N--;
+	  }
+	  First = FALSE;
+	}
+      } else {
+	LOnPic = FALSE;
+	First = TRUE;
+      }
+    }
+  }
+
+  /***  do consecutive DEC lines, decreasing **/
+  OnPic = TRUE;
+  for (d = firstDEC; (d > -90 - dD) && (OnPic); d -= minorDEC) {
+    D = MAX (-90, MIN(90, d));
+    /* first, RA increasing */
+    LOnPic = TRUE;
+    OnPic = FALSE;
+    First = TRUE;
+    for (r = firstRA; (r < firstRA + 180) && (LOnPic || NorthPole || SouthPole); r += dR) {
+      status = fRD_to_XY (&Xvec.elements[N], &Yvec.elements[N], r, D, &graphmode.coords);
+      /*
+      if ((fabs(Xvec.elements[N] - Xvec.elements[N-1]) > 10) && (fabs(Yvec.elements[N] - Yvec.elements[N-1]) > 10))
+	First = TRUE;
+	*/
+      if ((Xvec.elements[N] >= graphmode.xmin) && (Xvec.elements[N] <= graphmode.xmax) && 
+	  (Yvec.elements[N] >= graphmode.ymin) && (Yvec.elements[N] <= graphmode.ymax) && status) {
+	N++;
+	CHECKELEMENTS;
+	OnPic = TRUE;
+	if (!First) {
+	  Xvec.elements[N] = Xvec.elements[N-1];
+	  Yvec.elements[N] = Yvec.elements[N-1];
+	  N++;
+	  CHECKELEMENTS;
+	} else {
+	  if (N > 1) {
+	    Xvec.elements[N-2] = Xvec.elements[N-1];
+	    Yvec.elements[N-2] = Yvec.elements[N-1];
+	    N--;
+	  }
+	  First = FALSE;
+	}
+      } else {
+	LOnPic = FALSE;
+	First = TRUE;
+      }
+    }
+    /* next, RA decreasing */
+    First = TRUE;
+    LOnPic = TRUE;
+    for (r = firstRA; (r > firstRA - 180) && (LOnPic || NorthPole || SouthPole); r -= dR) {
+      status = fRD_to_XY (&Xvec.elements[N], &Yvec.elements[N], r, D, &graphmode.coords);
+      /*
+      if ((fabs(Xvec.elements[N] - Xvec.elements[N-1]) > 10) && (fabs(Yvec.elements[N] - Yvec.elements[N-1]) > 10))
+	First = TRUE;
+	*/
+      if ((Xvec.elements[N] >= graphmode.xmin) && (Xvec.elements[N] <= graphmode.xmax) && 
+	  (Yvec.elements[N] >= graphmode.ymin) && (Yvec.elements[N] <= graphmode.ymax) && status) {
+	N++;
+	CHECKELEMENTS;
+	OnPic = TRUE;
+	if (!First) {
+	  Xvec.elements[N] = Xvec.elements[N-1];
+	  Yvec.elements[N] = Yvec.elements[N-1];
+	  N++;
+	  CHECKELEMENTS;
+	} else {
+	  if (N > 1) {
+	    Xvec.elements[N-2] = Xvec.elements[N-1];
+	    Yvec.elements[N-2] = Yvec.elements[N-1];
+	    N--;
+	  }
+	  First = FALSE;
+	}
+      } else {
+	LOnPic = FALSE;
+	First = TRUE;
+      }
+    }
+  }
+  
+  /* send the line segments as connect-points */
+  Xvec.Nelements = Yvec.Nelements = N;
+  graphmode.style = 2; /* points */
+  graphmode.ptype = 100; /* connect a pair */
+  graphmode.etype = 0;
+  PrepPlotting (N, &graphmode);
+  PlotVector (N, Xvec.elements);
+  PlotVector (N, Yvec.elements);
+
+  free (Xvec.elements);
+  free (Yvec.elements);
+  return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/coords.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/coords.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/coords.c	(revision 3338)
@@ -0,0 +1,55 @@
+# include "astro.h"
+
+int coords (int argc, char **argv) {
+
+  int mode, N;
+  double X, Y, R, D;
+  Coords coords;
+  Buffer *buf;
+
+  mode = 0;
+  if ((N = get_argument (argc, argv, "-p"))) {
+    remove_argument (N, &argc, argv);
+    X = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    Y = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    mode = 1;
+  }
+  if ((N = get_argument (argc, argv, "-c"))) {
+    if (mode == 1) {
+      fprintf (stderr, "only one of -p or -c can be used\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    R = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    D = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    mode = 2;
+  }
+  if ((mode == 0) || (argc != 2)) {
+    fprintf (stderr, "USAGE: coords [buffer] (-c R D) / (-p X Y)\n");
+    return (FALSE);
+  }    
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  GetCoords (&coords, &buf[0].header);
+  
+  if (mode == 1) {
+    XY_to_RD (&R, &D, X, Y, &coords);
+    fprintf (stderr, "%10.6f %10.6f\n", R, D);
+    set_variable ("RA", R);
+    set_variable ("DEC", D);
+  }
+    
+  if (mode == 2) {
+    RD_to_XY (&X, &Y, R, D, &coords);
+    fprintf (stderr, "%7.2f %7.2f\n", X, Y);
+    set_variable ("Xc", X);
+    set_variable ("Yc", Y);
+  }
+
+  return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/cplot.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/cplot.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/cplot.c	(revision 3338)
@@ -0,0 +1,60 @@
+# include "astro.h"
+
+int cplot (int argc, char **argv) {
+  
+  int i, Npts, Ngraph;
+  float *x, *y, *r, *d, Rmin, Rmax;
+  Vector Xvec, Yvec, *xvec, *yvec;
+  Graphdata graphmode;
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: cplot <ra> <dec>\n");
+    return (FALSE);
+  }
+  
+  Ngraph = 0;
+  if (!GetGraph (&graphmode, NULL, &Ngraph)) return (FALSE);
+
+  Rmin = graphmode.coords.crval1 - 182.0;
+  Rmax = graphmode.coords.crval1 + 182.0;
+
+  /* find vectors */
+  if ((xvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yvec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+
+  if (xvec[0].Nelements != yvec[0].Nelements) {
+    fprintf (stderr, "vectors are not the same length\n");
+    return (FALSE);
+  }
+
+  ALLOCATE (Xvec.elements, float, xvec[0].Nelements);
+  ALLOCATE (Yvec.elements, float, xvec[0].Nelements);
+    
+  Xvec.Nelements = xvec[0].Nelements;
+  Yvec.Nelements = xvec[0].Nelements;
+  
+  r = xvec[0].elements;
+  d = yvec[0].elements;
+  x = Xvec.elements;
+  y = Yvec.elements;
+  
+  for (i = 0; i < Xvec.Nelements; i++, r++, d++, x++, y++) {
+    while (*r < Rmin) *r += 360.0;
+    while (*r > Rmax) *r -= 360.0;
+    fRD_to_XY (x, y, *r, *d, &graphmode.coords);
+  }
+  
+  
+  Npts = Xvec.Nelements;
+  graphmode.etype = 0;
+  PrepPlotting (Npts, &graphmode);
+  PlotVector (Npts, Xvec.elements);
+  PlotVector (Npts, Yvec.elements);
+  
+  free (Xvec.elements);
+  free (Yvec.elements);
+    
+  return (TRUE);
+
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/csystem.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/csystem.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/csystem.c	(revision 3338)
@@ -0,0 +1,120 @@
+# include "astro.h"
+
+int csystem (int argc, char **argv) {
+
+  /* USAGE: csystem [C/G/E/H] [C/G/E/H] [epoch] */
+  int i;
+  double X, Y, Xo, xo, phi, T;
+  double sin_x, sin_y, cos_x, cos_y;
+  float *x, *y;
+  struct timeval now;
+  struct tm *local;
+  Vector *xvec, *yvec;
+   
+  if (argc != 5) {
+    fprintf (stderr, "USAGE: csystems [C/G/E/H] [C/G/E/H] X Y\n");
+    return (FALSE);
+  }
+
+  Xo = xo = phi = 0;
+  switch (argv[1][0]) {
+  case 'C':
+    switch (argv[2][0]) {
+    case 'C': 
+      fprintf (stderr, "same coordinate system\n");
+      return (TRUE);
+      break;
+    case 'G':
+      phi = -62.6*RAD_DEG;
+      Xo = 282.25;
+      xo = 33;
+      break;
+    case 'E':
+      gettimeofday (&now, (struct timezone *) NULL);
+      local = localtime (&now.tv_sec);
+      T = local[0].tm_year / 100.0;
+      phi = -1*(23.452294 - 0.013013*T - 0.000001639*T*T + 0.000000503*T*T*T);
+      phi *= RAD_DEG;
+      Xo = xo = 0.0;
+      break;
+    }
+    break;
+  case 'E':
+    switch (argv[2][0]) {
+    case 'C': 
+      gettimeofday (&now, (struct timezone *) NULL);
+      local = localtime (&now.tv_sec);
+      T = local[0].tm_year / 100.0;
+      phi = 23.452294 - 0.013013*T - 0.000001639*T*T + 0.000000503*T*T*T;
+      phi *= RAD_DEG;
+      Xo = xo = 0.0;
+      break;
+    case 'G':
+      fprintf (stderr, "error: conversions between galactic and ecliptic not implemented\n");
+      return (FALSE);
+      phi = -62.6*RAD_DEG;
+      Xo = 282.25;
+      xo = 33;
+      break;
+    case 'E':
+      phi = Xo = xo = 0.0;
+      break;
+    }
+    break;
+  case 'G':
+    switch (argv[2][0]) {
+    case 'C': 
+      phi = 62.6*RAD_DEG;
+      Xo = 33;
+      xo = 282.25;
+      break;
+    case 'G':
+      phi = Xo = xo = 0.0;
+      break;
+    case 'E':
+      fprintf (stderr, "error: conversions between galactic and ecliptic not implemented\n");
+      return (FALSE);
+      gettimeofday (&now, (struct timezone *) NULL);
+      local = localtime (&now.tv_sec);
+      T = local[0].tm_year / 100.0;
+      phi = -1*(23.452294 - 0.013013*T - 0.000001639*T*T + 0.000000503*T*T*T);
+      Xo = xo = 0.0;
+      break;
+    }
+  }
+ 
+  Xo *= RAD_DEG;
+
+  /* find vectors */
+  if ((xvec = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yvec = SelectVector (argv[4], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+
+  if (xvec[0].Nelements != yvec[0].Nelements) {
+    fprintf (stderr, "vectors %s and %s not the same length\n", argv[3], argv[4]);
+    return (FALSE);
+  }
+  
+  x = xvec[0].elements;
+  y = yvec[0].elements;
+
+  for (i = 0; i < xvec[0].Nelements; i++, x++, y++) {
+    X = *x*RAD_DEG;
+    Y = *y*RAD_DEG;
+
+    sin_y = cos(Y)*sin(X - Xo)*sin(phi) + sin(Y)*cos(phi);
+    cos_y = sqrt (1 - sin_y*sin_y);
+    sin_x = (cos(Y)*sin(X - Xo)*cos(phi) - sin(Y)*sin(phi)) /  cos_y;
+    cos_x = cos(Y)*cos(X - Xo) / cos_y;
+    
+    X = (DEG_RAD * atan2 (sin_x, cos_x) + xo + 360);
+    
+    while (X >= 360.0)
+      X -= 360;
+    Y = DEG_RAD * atan2 (sin_y, cos_y);
+    *x = X;
+    *y = Y;
+  }
+
+  return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/ctimes.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/ctimes.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/ctimes.c	(revision 3338)
@@ -0,0 +1,66 @@
+# include "astro.h"
+
+int ctimes (int argc, char **argv) {
+
+  int Reference, TimeFormat, N;
+  double value;
+  time_t time, TimeReference;
+  char *date, *Variable;
+
+  Variable = (char *) NULL;
+  if ((N = get_argument (argc, argv, "-var"))) {
+    remove_argument (N, &argc, argv);
+    Variable = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: ctimes [-ref (value) / -abs (date)] [-var name]\n");
+    return (FALSE);
+  }
+
+  GetTimeFormat (&TimeReference, &TimeFormat);
+
+  Reference = FALSE;
+  if (!strcmp (argv[1], "-ref")) Reference = TRUE;
+
+  if (Reference) {
+
+    value = atof (argv[2]);
+    time = TimeRef (value, TimeReference, TimeFormat);
+    date = sec_to_date (time);
+    
+    if (Variable != (char *) NULL) {
+      set_str_variable (Variable, date);
+      free (Variable);
+    } else {
+      fprintf (stderr, "time: %s\n", date);
+    }
+
+    free (date);
+    return (TRUE);
+
+  } else {
+
+    if (strcmp (argv[1], "-abs")) {
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+
+    if (!str_to_time (argv[2], &time)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    
+    value = TimeValue (time, TimeReference, TimeFormat);
+    
+    if (Variable != (char *) NULL) {
+      set_variable (Variable, value);
+      free (Variable);
+      return (TRUE);
+    }
+    fprintf (stderr, "time: %f\n", value);
+    return (TRUE);
+  }
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/cval.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/cval.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/cval.c	(revision 3338)
@@ -0,0 +1,51 @@
+# include "astro.h"
+
+int cval (int argc, char **argv) {
+  
+  int i, j, Nx;
+  int sx, sy, nx, ny, xo, yo, dx, dy;
+  float *V, cval, val, sn, sky;
+  Buffer *buf;
+
+  if (argc != 7) {
+    fprintf (stderr, "USAGE: cval <buffer> x y dx dy sky\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  xo = atof (argv[2]);
+  yo = atof (argv[3]);
+  dx = atof (argv[4]);
+  dy = atof (argv[5]);
+  sky = atof (argv[6]);
+
+  sx = xo - dx;
+  sy = yo - dy;
+  nx = 2*dx + 1;
+  ny = 2*dy + 1;
+  if ((sx < 0) || (sy < 0) || 
+      (sx+nx > buf[0].matrix.Naxis[0]) || 
+      (sy+ny > buf[0].matrix.Naxis[1])) {
+    fprintf (stderr, "region out of range\n");
+    return (FALSE);
+  }
+
+  V = (float *)buf[0].matrix.buffer;
+  Nx = buf[0].matrix.Naxis[0];
+  val = V[xo + yo*Nx];
+
+  sn = 0;
+  cval = 0;
+  for (j = sy; j < sy + ny; j++) {
+    for (i = sx; i < sx + nx; i++) {
+      cval += (val - V[i + j*Nx]) / sqrt(V[i + j*Nx]);
+      sn += SQ (V[i + j*Nx] - sky) / V[i + j*Nx];
+    }
+  }
+
+  fprintf (stderr, "cval: %f  sn: %f\n", cval, sqrt(sn));
+
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/czplot.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/czplot.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/czplot.c	(revision 3338)
@@ -0,0 +1,78 @@
+# include "astro.h"
+
+int czplot (int argc, char **argv) {
+  
+  int i, N, Npts, Ngraph;
+  double min, range, Rmin, Rmax;
+  float *in, *out, *r, *d, *x, *y;
+  Vector Xvec, Yvec, Zvec, *xvec, *yvec, *zvec;
+  Graphdata graphmode;
+
+  Ngraph = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Ngraph = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetGraph (&graphmode, NULL, &Ngraph)) return (FALSE);
+
+  if (argc != 6) {
+    fprintf (stderr, "USAGE: czplot <x> <y> <z> min max\n");
+    return (FALSE);
+  }
+
+  min = atof(argv[4]);
+  range = atof(argv[5]) - min;
+  Rmin = graphmode.coords.crval1 - 180.0;
+  Rmax = graphmode.coords.crval1 + 180.0;
+
+  /* find vectors */
+  if ((xvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yvec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((zvec = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+
+  if (xvec[0].Nelements != yvec[0].Nelements) {
+    fprintf (stderr, "vectors %s and %s not the same length\n", argv[1], argv[2]);
+    return (FALSE);
+  }
+  if (xvec[0].Nelements != zvec[0].Nelements) {
+    fprintf (stderr, "vectors %s and %s not the same length\n", argv[1], argv[3]);
+    return (FALSE);
+  }
+  Xvec.Nelements = xvec[0].Nelements;
+  Yvec.Nelements = xvec[0].Nelements;
+  Zvec.Nelements = zvec[0].Nelements;
+  ALLOCATE (Xvec.elements, float, Xvec.Nelements);
+  ALLOCATE (Yvec.elements, float, Yvec.Nelements);
+  ALLOCATE (Zvec.elements, float, Zvec.Nelements);
+  
+  r   = xvec[0].elements;
+  d   = yvec[0].elements;
+  in  = zvec[0].elements;
+  x   = Xvec.elements;
+  y   = Yvec.elements;
+  out = Zvec.elements;
+  for (i = 0; i < Zvec.Nelements; i++, in++, out++, r++, d++, x++, y++) {
+    *out = MIN (1.0, MAX (0.01, (*in - min) / range));
+    while (*r < Rmin) *r += 360.0;
+    while (*r > Rmax) *r -= 360.0;
+    fRD_to_XY (x, y, *r, *d, &graphmode.coords);
+  }
+
+  graphmode.style = 2;
+  graphmode.size = -1; /* point size determined by Zvec */
+  graphmode.etype = 0;
+  Npts = Xvec.Nelements;
+  PrepPlotting (Npts, &graphmode);
+
+  PlotVector (Npts, Xvec.elements);
+  PlotVector (Npts, Yvec.elements);
+  PlotVector (Npts, Zvec.elements);
+
+  free (Xvec.elements);
+  free (Yvec.elements);
+  free (Zvec.elements);
+
+  return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/drizzle.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/drizzle.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/drizzle.c	(revision 3338)
@@ -0,0 +1,228 @@
+# include "astro.h"
+
+static double XO, XX, XY;
+static double YO, YX, YY;
+int ZERO;
+
+int map_output_to_input (int Npix, double df);
+int map_input_to_output (int Npix, double df);
+void set_linear_terms (Coords *in, Coords *out, int i, int j, int Npix);
+void apply_terms (double *Xout, double *Yout, double Xin, double Yin);
+
+Coords coords_in, coords_out;
+Buffer *in, *out, *wt;
+
+int drizzle (int argc, char **argv) {
+
+  int Nlinear, Np, N;
+  double scale_in, scale_out, df;
+
+  ZERO = FALSE;
+  if ((N = get_argument (argc, argv, "-zero"))) {
+    ZERO = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 5) {
+    fprintf (stderr, "USAGE: transform <from> <to> <weight> (Nlinear)\n");
+    fprintf (stderr, "  output buffer must exist with target astrometry header\n");
+    fprintf (stderr, "  Nlinear is the pixel scale for linear astrometric transformation\n");
+    return (FALSE);
+  }
+
+  if ((in  = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((out = SelectBuffer (argv[2], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((wt  = SelectBuffer (argv[3], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  Nlinear = atoi (argv[4]);
+
+  GetCoords (&coords_in, &in[0].header);
+  GetCoords (&coords_out, &out[0].header);
+  
+  scale_in = sqrt(fabs(coords_in.cdelt1*coords_in.cdelt2*(coords_in.pc1_1*coords_in.pc2_2 - coords_in.pc1_2*coords_in.pc2_1)));
+  scale_out = sqrt(fabs(coords_out.cdelt1*coords_out.cdelt2*(coords_out.pc1_1*coords_out.pc2_2 - coords_out.pc1_2*coords_out.pc2_1)));
+  
+  fprintf (stderr, "%f - %f\n", scale_in, scale_out);
+
+  if (scale_in > scale_out) {
+    Np = MAX (1, 3*scale_out / scale_in);
+    df = 1.0 / Np;
+    map_output_to_input (Nlinear, df);
+  } else {
+    Np = MAX (1, 3*scale_in / scale_out);
+    df = 1.0 / Np;
+    map_input_to_output (Nlinear, df);
+  }
+  return (TRUE);
+}
+
+/* mode 1: input pixels >> output pixels: loop over output pixels */
+/* mode 2: input pixels << output pixels: loop over input pixels */
+/* mode 3: input pixels ~= output pixels: drizzle input to output */
+
+/* loop over the input pixels, map input output image */
+int map_output_to_input (int Npix, double df) {
+
+  int i, j, Ni, No, Nx, Ny, nx, ny;
+  float *Vin, *Vout, *Vwt;
+  double x, y, X, Y;
+
+  /* loop over output pixels */
+  /* set up pointers for buffers */
+  Vin  = (float *) in[0].matrix.buffer;
+  Vout = (float *) out[0].matrix.buffer;
+  Vwt  = (float *) wt[0].matrix.buffer;
+
+  nx = in[0].header.Naxis[0];
+  ny = in[0].header.Naxis[1];
+  Nx = out[0].header.Naxis[0];
+  Ny = out[0].header.Naxis[1];
+
+  if (ZERO) {
+    bzero (Vout, Nx*Ny*sizeof(float));
+    bzero (Vwt,  Nx*Ny*sizeof(float));
+  }
+
+  for (j = 0; j < Ny; j+=Npix) {
+    for (i = 0; i < Nx; i+=Npix) {
+      
+      /* define linear transformation in region */
+      set_linear_terms (&coords_out, &coords_in, i, j, Npix);
+
+      for (X = i; (X < i + Npix) && (X < Nx); X += df) {
+	for (Y = j; (Y < j + Npix) && (Y < Ny); Y += df) {
+	  
+	  No = (int)X + ((int)Y)*Nx;
+	  apply_terms (&x, &y, X, Y);
+	  if (x < 0) continue;
+	  if (x >= nx) continue;
+	  if (y < 0) continue;
+	  if (y >= ny) continue;
+	  Ni = (int)x + ((int)y)*nx;
+
+	  Vout[No] += Vin[Ni];
+	  Vwt[No] ++;
+	}
+      }
+    }
+  }
+  return (TRUE);
+}
+
+/* loop over the input pixels, map input output image */
+int map_input_to_output (int Npix, double df) {
+
+  int i, j, Ni, No, Nx, Ny, nx, ny;
+  float *Vin, *Vout, *Vwt;
+  double x, y, X, Y;
+
+  /* loop over output pixels */
+  /* set up pointers for buffers */
+  Vin  = (float *) in[0].matrix.buffer;
+  Vout = (float *) out[0].matrix.buffer;
+  Vwt  = (float *) wt[0].matrix.buffer;
+
+  Nx = in[0].header.Naxis[0];
+  Ny = in[0].header.Naxis[1];
+  nx = out[0].header.Naxis[0];
+  ny = out[0].header.Naxis[1];
+
+  if (ZERO) {
+    bzero (Vout, nx*ny*sizeof(float));
+    bzero (Vwt,  nx*ny*sizeof(float));
+  }
+
+  for (j = 0; j < Ny; j+=Npix) {
+    for (i = 0; i < Nx; i+=Npix) {
+      
+      /* define linear transformation in region */
+      set_linear_terms (&coords_in, &coords_out, i, j, Npix);
+
+      for (X = i; (X < i + Npix) && (X < Nx); X += df) {
+	for (Y = j; (Y < j + Npix) && (Y < Ny); Y += df) {
+	  
+	  Ni = (int)X + ((int)Y)*Nx;
+	  apply_terms (&x, &y, X, Y);
+	  if (x < 0) continue;
+	  if (x >= nx) continue;
+	  if (y < 0) continue;
+	  if (y >= ny) continue;
+	  No = (int)x + ((int)y)*nx;
+
+	  Vout[No] += Vin[Ni];
+	  Vwt[No] ++;
+	}
+      }
+    }
+  }
+  return (TRUE);
+}
+
+/* find the linear astrometric fix between images at this location */
+void set_linear_terms (Coords *in, Coords *out, int i, int j, int Npix) {
+
+  int n;
+  double x, y, x2, y2, xy, X, Y, Xx, Xy, Yx, Yy;
+  double Xin, Yin, Xout, Yout;
+  double Sx2, Sy2, Sxy, SXx, SXy, SYx, SYy;
+  double N, r, d;
+
+  N = x = y = x2 = y2 = xy = X = Y = Xx = Xy = Yx = Yy = 0;
+
+  /* define several test points, fit a line to the input,output pairs */
+  for (n = 0; n < 3; n++) {
+
+    switch (n) {
+    case 0:
+      Xin = i;
+      Yin = j;
+      break;
+    case 1:
+      Xin = i + Npix;
+      Yin = j;
+      break;
+    case 2:
+      Xin = i;
+      Yin = j + Npix;
+      break;
+    }
+
+    XY_to_RD (&r, &d, Xin, Yin, in);
+    RD_to_XY (&Xout, &Yout, r, d, out);
+
+    x  += Xin;
+    y  += Yin;
+    x2 += Xin*Xin;
+    y2 += Yin*Yin;
+    xy += Xin*Yin;
+    X  += Xout;
+    Y  += Yout;
+    Xx += Xout*Xin;
+    Xy += Xout*Yin;
+    Yx += Yout*Xin;
+    Yy += Yout*Yin;
+    N  += 1.0;
+  }
+
+  Sx2 = x2 - x*x/N;
+  Sy2 = y2 - y*y/N;
+  Sxy = xy - x*y/N;
+  SXx = Xx - X*x/N;
+  SXy = Xy - X*y/N;
+  SYx = Yx - Y*x/N;
+  SYy = Yy - Y*y/N;
+  
+  XX = (SXx*Sy2 - SXy*Sxy) / (Sx2*Sy2 - Sxy*Sxy);
+  XY = (SXy*Sx2 - SXx*Sxy) / (Sx2*Sy2 - Sxy*Sxy);
+  XO = X/N - XX*x/N - XY*y/N;
+
+  YX = (SYx*Sy2 - SYy*Sxy) / (Sx2*Sy2 - Sxy*Sxy);
+  YY = (SYy*Sx2 - SYx*Sxy) / (Sx2*Sy2 - Sxy*Sxy);
+  YO = Y/N - YX*x/N - YY*y/N;
+
+}
+
+
+void apply_terms (double *Xout, double *Yout, double Xin, double Yin) {
+  *Xout = XO + XX*Xin + XY*Yin;
+  *Yout = YO + YX*Xin + YY*Yin;
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/flux.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/flux.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/flux.c	(revision 3338)
@@ -0,0 +1,76 @@
+# include "astro.h"
+
+int flux (int argc, char **argv) {
+  
+  int i, j, k, xmin, ymin, xmax, ymax;
+  void *oldsignal;
+  double ax, ay, s, S, flux;
+  double bx[5], by[5], x[5], y[5], bb[5];
+  float *V;
+  FILE *f;
+  Buffer *buf;
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: flux <buffer> (region)\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  f = fopen (argv[2], "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "file %s not found\n", argv[2]);
+    return (FALSE);
+  }
+
+  xmin = buf[0].matrix.Naxis[0];
+  xmax = 0;
+  ymin = buf[0].matrix.Naxis[1];
+  ymax = 0;
+  for (i = 0; i < 4; i++) {
+    fscanf (f, "%lf %lf", &x[i], &y[i]);
+    xmin = MAX (0, MIN (xmin, x[i] - 1));
+    ymin = MAX (0, MIN (ymin, y[i] - 1));
+    xmax = MIN (MAX (xmax, x[i] + 1), buf[0].matrix.Naxis[0]);
+    ymax = MIN (MAX (ymax, y[i] + 1), buf[0].matrix.Naxis[1]);
+  }
+  fclose (f);
+
+  x[4] = x[0]; y[4] = y[0];
+  for (i = 0; i < 4; i++) {
+    bx[i] = x[i+1] - x[i];
+    by[i] = y[i+1] - y[i];
+  }
+  bx[4] = bx[0]; by[4] = by[0];
+  for (i = 0; i < 4; i++) {
+    bb[i] = hypot (bx[i], by[i]) * SIGN (bx[i]*by[i+1] - bx[i+1]*by[i]);
+  }
+  fprintf (stderr, "%f %f %f %f\n", bb[0], bb[1], bb[2], bb[3]);
+
+  /* this only works for convex contours --
+   we have to add up the angles for concave contours */
+  flux = 0;
+  oldsignal = signal (SIGINT, handle_interrupt);
+  interrupt = FALSE;
+  for (j = ymin; (j < ymax) && !interrupt; j++) {
+    V = (float *)(buf[0].matrix.buffer) + j*buf[0].matrix.Naxis[0] + xmin; 
+    for (i = xmin; (i < xmax) && !interrupt; i++, V++) {
+      S = 1.0;
+      for (k = 0; k < 4; k++) {
+	ax = i - x[k];
+	ay = j - y[k];
+	s = (ay*bx[k] - ax*by[k]) / bb[k] + 0.5;
+	/* s = b x a / |b|, with the correct sign (above) so inside is positive */
+	s = MAX (0.0, MIN (1.0, s));  /* s is between 0.0 and 1.0 */
+	S *= s;
+      }
+      flux += S * (*V);
+    }
+  }
+  signal (SIGINT, oldsignal);
+
+  fprintf (GetOutfile(), "flux: %f\n", flux);
+  set_variable ("FLUX", flux);
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/gauss.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/gauss.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/gauss.c	(revision 3338)
@@ -0,0 +1,69 @@
+# include "astro.h"
+
+int gauss (int argc, char **argv) {
+
+  char buffer[20], key;
+  int i, N, Npix, Nborder, Nspot;
+  double X, Y, Z, max;
+  int Ximage, Nimage;
+  Buffer *buf;
+
+  Nimage = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nimage = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetImage (&Ximage, &Nimage)) return (FALSE);
+
+  Nborder = 3;
+  if ((N = get_argument (argc, argv, "-border"))) {
+    remove_argument (N, &argc, argv);
+    Nborder  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  Nborder = MAX (Nborder, 1);
+  
+  max = 60000;
+  if ((N = get_argument (argc, argv, "-sat"))) {
+    remove_argument (N, &argc, argv);
+    max  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  
+  if ((argc != 2) && (argc != 3)) {
+    fprintf (stderr, "USAGE: gauss Npix [Nspots] [-border N] [-sat cnts]\n");
+    return (FALSE);
+  }
+  
+  if (Ximage < 1) {
+    fprintf (stderr, "no active TV\n");
+    return (FALSE);
+  }
+
+  Nspot = 0;
+  Npix = atof (argv[1]);
+  if (argc == 3) {
+    Nspot = atof (argv[2]);
+  }
+
+  if ((buf = SelectBuffer (GetImageName(), OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  fcntl (Ximage, F_SETFL, !O_NONBLOCK);  
+  write (Ximage, "CURS", 4); /* ask Ximage to look for the keystrokes */
+  
+  for (i = 0; (i < Nspot) || (Nspot == 0); i++) {
+    bzero (buffer, 20);
+    read (Ximage, buffer, 16);
+    buffer[16] = 0;
+    sscanf (buffer, "%c %lf %lf", &key, &X, &Y);
+    if ((key == 'q') || (key == 'Q')) {
+      break;
+    }
+    Z = get_aperture_stats (&buf[0].matrix, (int)(X+0.5), (int)(Y+0.5), Npix, Nborder, max);
+    
+  }
+  write (Ximage, "NCUR", 4); /* tell Ximage "end of keystrokes" */
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/getvel.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/getvel.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/getvel.c	(revision 3338)
@@ -0,0 +1,81 @@
+# include "astro.h"
+
+int getvel (int argc, char **argv) {
+  
+  int i, X, n, Ncurve;
+  int nx, ny;
+  double L, V, Vo, dV, Bo, dB;
+  double xo, yo;
+  double sl, cl, wo, Ro, Rs, wr, r, fr, d, x;
+  double R[100], T[100], W[100];
+  FILE *f;
+  Buffer *buf;
+
+  if (argc != 5) {
+    fprintf (stderr, "USAGE: rotcurve buf X Y curve.txt\n");
+    return (FALSE);
+  }
+
+  f = fopen (argv[4], "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "can't find rotation curve data file %s\n", argv[4]);
+    return (FALSE);
+  }
+  for (i = 0; fscanf (f, "%lf %lf", &R[i], &T[i]) != EOF; i++) {
+    W[i] = T[i] / R[i];
+  }  
+  fclose (f);
+  Ncurve = i;
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  nx = buf[0].matrix.Naxis[0];
+  ny = buf[0].matrix.Naxis[1];
+
+  /* we expect the input image to have units of velocity, lattitude, and longitude */
+  fits_scan (&buf[0].header, "CRVAL1", "%lf", 1, &Vo);
+  fits_scan (&buf[0].header, "CDELT1", "%lf", 1, &dV);
+  fits_scan (&buf[0].header, "CRPIX1", "%lf", 1, &xo);
+  fits_scan (&buf[0].header, "CRVAL2", "%lf", 1, &Bo);
+  fits_scan (&buf[0].header, "CDELT2", "%lf", 1, &dB);
+  fits_scan (&buf[0].header, "CRPIX2", "%lf", 1, &yo);
+  fits_scan (&buf[0].header, "CRVAL3", "%lf", 1, &L);
+  Vo *= 0.001;
+  dV *= 0.001;
+
+  while (L >= 360) {L -= 360.0;}
+  while (L < 0.0)  {L += 360.0;}
+  fprintf (stderr, "L: %f (%d)\n", L, X);
+
+  cl = cos (L*RAD_DEG);
+  sl = sin (L*RAD_DEG);
+  wo = 25.0;
+  Ro = 10.0;
+  Rs = Ro*sl;
+  x = atof (argv[2]);
+  /* this method depends on wr monotonically decreasing */
+
+  V = (x - xo) * dV + Vo;
+  wr = V/Rs + wo;
+  for (n = 0; (n < Ncurve) && (wr < W[n]); n++);
+  if ((n == 0) || (n == Ncurve)) {
+    fprintf (stderr, "velocity out of reasonable range\n");
+    fprintf (stderr, "%f %f %f %f\n", V, wr, W[0], W[Ncurve-1]);
+    return (TRUE);
+  }
+  r = (wr - W[n]) *  (R[n-1] - R[n]) / (W[n-1] - W[n]) + R[n];
+  fr = (Ro/r);
+  if (r < fabs(Rs)) { /* can't be on rotation curve */
+    fprintf (stderr, "velocity out of reasonable range\n");
+    fprintf (stderr, "%f %f %f %f %f %f %f\n", V, wr, W[0], W[Ncurve-1], r, fr, Rs);
+    return (TRUE);
+  }
+  if (r < Ro)
+    d = Ro*cl - sqrt(r*r - Rs*Rs);
+  else 
+    d = Ro*cl + sqrt(r*r - Rs*Rs);
+  
+  fprintf (stderr, "dist: %f, vel: %f\n", d, V);
+
+  return (TRUE);
+
+} 
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-Pgauss.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-Pgauss.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-Pgauss.c	(revision 3338)
@@ -0,0 +1,66 @@
+# include "imfit.h"
+
+float PgaussTD (float, float, float *, int, float *);
+void  PgaussCL ();
+
+void  Pgauss_setup (char *name) {
+
+  if (strcmp(name, "Pgauss")) return;
+
+  fitfunc = PgaussTD;
+  imfit_cleanup = PgaussCL;
+  Npar = 4;
+  Nfpar = 3;
+
+  /* allocate free and fixed parameters */
+  ALLOCATE (par, float, MAX (Npar, 1));
+  bzero (par, Npar*sizeof(float));
+  ALLOCATE (fpar, float, MAX (Nfpar, 1));
+  bzero (fpar, Nfpar*sizeof(float));
+
+  par[0] = get_variable_default ("Xg", 0);
+  par[1] = get_variable_default ("Yg", 0);
+  par[2] = get_variable_default ("Zpk", 10000);
+  par[3] = get_variable_default ("Sg", 0.0);
+  sky = &par[3];
+
+  fpar[0] = 2.35 / get_variable_default ("SXg", 2.0);
+  fpar[1] = 2.35 / get_variable_default ("SYg", 2.0);
+  fpar[2] = get_variable_default ("SXYg", 0);
+}
+
+void PgaussCL () {
+  set_variable ("Xg",   par[0]);
+  set_variable ("Yg",   par[1]);
+  set_variable ("Zpk",  par[2]);
+  set_variable ("Sg",   par[3]);
+}
+
+/* pseudo 2D gaussian -- x, y, (sx), (sy), (sxy), I, sky */
+float PgaussTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, px, py;
+  float z, r, q, f;
+
+  /* par -> fpar: (2,0), (3,1), (4,2) */
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  px = fpar[0]*X;
+  py = fpar[1]*Y;
+
+  z = 0.5*SQ(px) + 0.5*SQ(py) + fpar[2]*X*Y;
+  r = 1.0 / (1 + z + 0.5*z*z*(1 + z/3)); /* ~ exp (-Z) */
+  f = par[2]*r + par[3];
+  q = par[2]*r*r*(1 + z + 0.5*z*z);
+  /* note difference from gaussian: q = par[5]*r */
+
+  if (dpar != NULL) {
+    dpar[0] = q*(2*px*fpar[0] + fpar[2]*Y);
+    dpar[1] = q*(2*py*fpar[1] + fpar[2]*X);
+    dpar[2] = +r;
+    dpar[3] = +1;
+  }
+  return (f);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-Qgauss.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-Qgauss.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-Qgauss.c	(revision 3338)
@@ -0,0 +1,68 @@
+# include "imfit.h"
+
+float QgaussTD (float, float, float *, int, float *);
+void  QgaussCL ();
+
+void Qgauss_setup (char *name) {
+
+  if (strcmp(name, "Qgauss")) return;
+
+  fitfunc = QgaussTD;
+  imfit_cleanup = QgaussCL;
+  Npar = 4;
+  Nfpar = 5;
+
+  /* allocate free and fixed parameters */
+  ALLOCATE (par, float, MAX (Npar, 1));
+  bzero (par, Npar*sizeof(float));
+  ALLOCATE (fpar, float, MAX (Nfpar, 1));
+  bzero (fpar, Nfpar*sizeof(float));
+
+  par[0]  = get_variable_default ("Xg", 0);
+  par[1]  = get_variable_default ("Yg", 0);
+  par[2]  = get_variable_default ("Zpk", 10000);
+  par[3]  = get_variable_default ("Sg", 0.0);
+
+  fpar[0] = 2.35 / get_variable_default ("SXg", 15.0);
+  fpar[1] = 2.35 / get_variable_default ("SYg", 15.0);
+  fpar[2] = get_variable_default ("SXYg", 0.0);
+  fpar[3] = get_variable_default ("Sr", 1.0);
+  fpar[4] = get_variable_default ("Npow", 2.25);
+
+  sky = &par[3];
+}
+
+void QgaussCL () {
+  set_variable ("Xg",  par[0]);
+  set_variable ("Yg",  par[1]);
+  set_variable ("Zpk", par[2]);
+  set_variable ("Sg",  par[3]);
+}
+
+/* one component, two slopes: (1 + z^M + z^N)^(-1) -- x, y, sx, sy, sxy, I, sky, sr */
+float QgaussTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, px, py;
+  float z, r, q, f;
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  px = fpar[0]*X;
+  py = fpar[1]*Y;
+
+  z = 0.5*SQ(px) + 0.5*SQ(py) + fpar[2]*X*Y;
+
+  r = 1.0 / (1 + fpar[3]*z + pow(z,fpar[4]));
+  f = par[2]*r + par[3];
+  q = par[2]*SQ(r)*(fpar[3] + fpar[4]*pow(z,(fpar[4]-1)));
+
+  if (dpar != NULL) {
+    dpar[0] = q*(2*px*fpar[0] + fpar[2]*Y);
+    dpar[1] = q*(2*py*fpar[1] + fpar[2]*X);
+    dpar[2] = +r;
+    dpar[3] = +1;
+  }
+  return (f);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-Sgauss.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-Sgauss.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-Sgauss.c	(revision 3338)
@@ -0,0 +1,74 @@
+# include "imfit.h"
+
+float SgaussTD (float, float, float *, int, float *);
+void  SgaussCL ();
+
+void Sgauss_setup (char *name) {
+
+  if (strcmp(name, "Sgauss")) return;
+
+  fitfunc = SgaussTD;
+  imfit_cleanup = SgaussCL;
+  Npar = 4;
+  Nfpar = 7;
+
+  /* allocate free and fixed parameters */
+  ALLOCATE (par, float, MAX (Npar, 1));
+  bzero (par, Npar*sizeof(float));
+  ALLOCATE (fpar, float, MAX (Nfpar, 1));
+  bzero (fpar, Nfpar*sizeof(float));
+
+  par[0] = get_variable_default ("Xg", 0);
+  par[1] = get_variable_default ("Yg", 0);
+  par[2] = get_variable_default ("Zpk", 10000);
+  par[3] = get_variable_default ("Sg", 0.0);
+
+  fpar[0] = 2.35 / get_variable_default ("SXg", 15.0);
+  fpar[1] = 2.35 / get_variable_default ("SYg", 15.0);
+  fpar[2] = get_variable_default ("SXYg", 0.0);
+  fpar[3] = 2.35 / get_variable_default ("SXf", 15.0);
+  fpar[4] = 2.35 / get_variable_default ("SYf", 15.0);
+  fpar[5] = get_variable_default ("SXYf", 0.0);
+  fpar[6] = get_variable_default ("Npow", 2.25);
+
+  sky = &par[3];
+}
+
+void SgaussCL () {
+  set_variable ("Xg",   par[0]);
+  set_variable ("Yg",   par[1]);
+  set_variable ("Zpk",  par[2]);
+  set_variable ("Sg",   par[3]);
+}
+
+/* two components: (1 + z_1 + z_2^N)^(-1) -- x, y, sx1, sy1, sxy1, I, sky, sx2, sy2, sxy2 */
+float SgaussTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, px1, py1, px2, py2;
+  float z1, z2, r, q1, q2, f, f1, f2;
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  px1 = fpar[0]*X;
+  py1 = fpar[1]*Y;
+  px2 = fpar[3]*X;
+  py2 = fpar[4]*Y;
+
+  z1 = 0.5*SQ(px1) + 0.5*SQ(py1) + fpar[2]*X*Y;
+  z2 = 0.5*SQ(px2) + 0.5*SQ(py2) + fpar[5]*X*Y;
+
+  r = 1.0 / (1 + z1 + pow(z2,fpar[6]));
+  f = par[2]*r + par[3];
+
+  q1 = par[2]*SQ(r);
+  q2 = par[2]*SQ(r)*fpar[6]*pow(z2,(fpar[6]-1));
+
+  if (dpar != NULL) {
+    dpar[0] = q1*(2*px1*fpar[0] + fpar[2]*Y) + q2*(2*px2*fpar[3] + fpar[5]*Y);
+    dpar[1] = q1*(2*py1*fpar[1] + fpar[2]*X) + q2*(2*py2*fpar[4] + fpar[5]*X);
+    dpar[2] = +r;
+    dpar[3] = +1;
+  }
+  return (f);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-fgauss.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-fgauss.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-fgauss.c	(revision 3338)
@@ -0,0 +1,68 @@
+# include "imfit.h"
+
+float fgaussTD (float, float, float *, int, float *);
+void  fgaussCL ();
+
+void fgauss_setup (char *name) {
+
+  if (strcmp(name, "fgauss")) return;
+
+  fitfunc = fgaussTD;
+  imfit_cleanup = fgaussCL;
+  Npar = 7;
+  Nfpar = 0;
+
+  /* allocate free and fixed parameters */
+  ALLOCATE (par, float, MAX (Npar, 1));
+  bzero (par, Npar*sizeof(float));
+  ALLOCATE (fpar, float, MAX (Nfpar, 1));
+  bzero (fpar, Nfpar*sizeof(float));
+
+  par[0] = get_variable_default ("Xg", 0);
+  par[1] = get_variable_default ("Yg", 0);
+  par[2] = 2.35 / get_variable_default ("SXg", 2.0);
+  par[3] = 2.35 / get_variable_default ("SYg", 2.0);
+  par[4] = get_variable_default ("SXYg", 0);
+  par[5] = get_variable_default ("Zpk", 10000);
+  par[6] = get_variable_default ("Sg", 0.0);
+  sky = &par[6];
+}
+
+void fgaussCL () {
+  set_variable ("Xg",   par[0]);
+  set_variable ("Yg",   par[1]);
+  set_variable ("SXg",  2.35 / par[2]);
+  set_variable ("SYg",  2.35 / par[3]);
+  set_variable ("SXYg", par[4]);
+  set_variable ("Zpk",  par[5]);
+  set_variable ("Sg",   par[6]);
+}
+
+/* real 2D gaussian -- x, y, sx, sy, sxy, I, sky */
+float fgaussTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, px, py;
+  float z, r, q, f;
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  px = par[2]*X;
+  py = par[3]*Y;
+
+  z = 0.5*SQ(px) + 0.5*SQ(py) + par[4]*X*Y;
+  r = exp (-z);
+  q = par[5]*r;
+  f = q + par[6];
+
+  if (dpar != NULL) {
+    dpar[0] = q*(2*px*par[2] + par[4]*Y);
+    dpar[1] = q*(2*py*par[3] + par[4]*X);
+    dpar[2] = -2*q*px*X;
+    dpar[3] = -2*q*py*Y;
+    dpar[4] = -q*X*Y;
+    dpar[5] = +r;
+    dpar[6] = +1;
+  }
+  return (f);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-pgauss.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-pgauss.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-pgauss.c	(revision 3338)
@@ -0,0 +1,69 @@
+# include "imfit.h"
+
+float pgaussTD (float, float, float *, int, float *);
+void  pgaussCL ();
+
+void  pgauss_setup (char *name) {
+
+  if (strcmp(name, "pgauss")) return;
+
+  fitfunc = pgaussTD;
+  imfit_cleanup = pgaussCL;
+  Npar = 7;
+  Nfpar = 0;
+
+  /* allocate free and fixed parameters */
+  ALLOCATE (par, float, MAX (Npar, 1));
+  bzero (par, Npar*sizeof(float));
+  ALLOCATE (fpar, float, MAX (Nfpar, 1));
+  bzero (fpar, Nfpar*sizeof(float));
+
+  par[0] = get_variable_default ("Xg", 0.0);
+  par[1] = get_variable_default ("Yg", 0.0);
+  par[2] = 2.35 / get_variable_default ("SXg", 2.0);
+  par[3] = 2.35 / get_variable_default ("SYg", 2.0);
+  par[4] = get_variable_default ("SXYg", 0.0);
+  par[5] = get_variable_default ("Zpk", 10000);
+  par[6] = get_variable_default ("Sg", 0.0);
+  sky = &par[6];
+}
+
+void pgaussCL () {
+  set_variable ("Xg",   par[0]);
+  set_variable ("Yg",   par[1]);
+  set_variable ("SXg",  2.35 / par[2]);
+  set_variable ("SYg",  2.35 / par[3]);
+  set_variable ("SXYg", par[4]);
+  set_variable ("Zpk",  par[5]);
+  set_variable ("Sg",   par[6]);
+}
+
+/* pseudo 2D gaussian -- x, y, sx, sy, sxy, I, sky */
+float pgaussTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, px, py;
+  float z, r, q, f;
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  px = par[2]*X;
+  py = par[3]*Y;
+
+  z = 0.5*SQ(px) + 0.5*SQ(py) + par[4]*X*Y;
+  r = 1.0 / (1 + z + 0.5*z*z*(1 + z/3)); /* ~ exp (-Z) */
+  f = par[5]*r + par[6];
+  q = par[5]*r*r*(1 + z + 0.5*z*z);
+  /* note difference from gaussian: q = par[5]*r */
+
+  if (dpar != NULL) {
+    dpar[0] = q*(2*px*par[2] + par[4]*Y);
+    dpar[1] = q*(2*py*par[3] + par[4]*X);
+    dpar[2] = -2*q*px*X;
+    dpar[3] = -2*q*py*Y;
+    dpar[4] = -q*X*Y;
+    dpar[5] = +r;
+    dpar[6] = +1;
+  }
+  return (f);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-qfgauss.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-qfgauss.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-qfgauss.c	(revision 3338)
@@ -0,0 +1,74 @@
+# include "imfit.h"
+
+float qfgaussTD (float, float, float *, int, float *);
+void  qfgaussCL ();
+
+void qfgauss_setup (char *name) {
+
+  if (strcmp(name, "qfgauss")) return;
+
+  fitfunc = qfgaussTD;
+  imfit_cleanup = qfgaussCL;
+  Npar = 7;
+  Nfpar = 2;
+
+  /* allocate free and fixed parameters */
+  ALLOCATE (par, float, MAX (Npar, 1));
+  bzero (par, Npar*sizeof(float));
+  ALLOCATE (fpar, float, MAX (Nfpar, 1));
+  bzero (fpar, Nfpar*sizeof(float));
+
+  par[0]  = get_variable_default ("Xg", 0);
+  par[1]  = get_variable_default ("Yg", 0);
+  par[2]  = 2.35 / get_variable_default ("SXg", 2.0);
+  par[3]  = 2.35 / get_variable_default ("SYg", 2.0);
+  par[4]  = get_variable_default ("SXYg", 0);
+  par[5]  = get_variable_default ("Zpk", 10000);
+  par[6]  = get_variable_default ("Sg", 0.0);
+
+  fpar[0] = get_variable_default ("Npow", 2.25);
+  fpar[1]  = get_variable_default ("Sr", 1.0);
+
+  sky = &par[6];
+}
+
+void qfgaussCL () {
+  set_variable ("Xg",   par[0]);
+  set_variable ("Yg",   par[1]);
+  set_variable ("SXg",  2.35 / par[2]);
+  set_variable ("SYg",  2.35 / par[3]);
+  set_variable ("SXYg", par[4]);
+  set_variable ("Zpk",  par[5]);
+  set_variable ("Sg",   par[6]);
+}
+
+/* one component, two slopes: (1 + z^M + z^N)^(-1) -- x, y, sx, sy, sxy, I, sky */
+float qfgaussTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, px, py;
+  float z, r, q, f;
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  px = par[2]*X;
+  py = par[3]*Y;
+
+  z = 0.5*SQ(px) + 0.5*SQ(py) + par[4]*X*Y;
+
+  r = 1.0 / (1 + fpar[1]*z + pow(z,fpar[0]));
+  f = par[5]*r + par[6];
+  q = par[5]*SQ(r)*(fpar[1] + fpar[0]*pow(z,(fpar[0]-1)));
+
+  if (dpar != NULL) {
+    dpar[0] = q*(2*px*par[2] + par[4]*Y);
+    dpar[1] = q*(2*py*par[3] + par[4]*X);
+    dpar[2] = -2*q*px*X*2;
+    dpar[3] = -2*q*py*Y*2;
+    dpar[4] = -q*X*Y;
+    dpar[5] = +r;
+    dpar[6] = +1;
+  }
+  return (f);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-qgauss.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-qgauss.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-qgauss.c	(revision 3338)
@@ -0,0 +1,75 @@
+# include "imfit.h"
+
+float qgaussTD (float, float, float *, int, float *);
+void  qgaussCL ();
+
+void qgauss_setup (char *name) {
+
+  if (strcmp(name, "qgauss")) return;
+
+  fitfunc = qgaussTD;
+  imfit_cleanup = qgaussCL;
+  Npar = 8;
+  Nfpar = 1;
+
+  /* allocate free and fixed parameters */
+  ALLOCATE (par, float, MAX (Npar, 1));
+  bzero (par, Npar*sizeof(float));
+  ALLOCATE (fpar, float, MAX (Nfpar, 1));
+  bzero (fpar, Nfpar*sizeof(float));
+
+  par[0]  = get_variable_default ("Xg", 0);
+  par[1]  = get_variable_default ("Yg", 0);
+  par[2]  = 2.35 / get_variable_default ("SXg", 2.0);
+  par[3]  = 2.35 / get_variable_default ("SYg", 2.0);
+  par[4]  = get_variable_default ("SXYg", 0);
+  par[5]  = get_variable_default ("Zpk", 10000);
+  par[6]  = get_variable_default ("Sg", 0.0);
+  par[7]  = get_variable_default ("Sr", 1.0);
+  fpar[0] = get_variable_default ("Npow", 2.25);
+
+  sky = &par[6];
+}
+
+void qgaussCL () {
+  set_variable ("Xg",   par[0]);
+  set_variable ("Yg",   par[1]);
+  set_variable ("SXg",  2.35 / par[2]);
+  set_variable ("SYg",  2.35 / par[3]);
+  set_variable ("SXYg", par[4]);
+  set_variable ("Zpk",  par[5]);
+  set_variable ("Sg",   par[6]);
+  set_variable ("Sr", par[7]);
+}
+
+/* one component, two slopes: (1 + z^M + z^N)^(-1) -- x, y, sx, sy, sxy, I, sky, sr */
+float qgaussTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, px, py;
+  float z, r, q, f;
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  px = par[2]*X;
+  py = par[3]*Y;
+
+  z = 0.5*SQ(px) + 0.5*SQ(py) + par[4]*X*Y;
+
+  r = 1.0 / (1 + par[7]*z + pow(z,fpar[0]));
+  f = par[5]*r + par[6];
+  q = par[5]*SQ(r)*(par[7] + fpar[0]*pow(z,(fpar[0]-1)));
+
+  if (dpar != NULL) {
+    dpar[0] = q*(2*px*par[2] + par[4]*Y);
+    dpar[1] = q*(2*py*par[3] + par[4]*X);
+    dpar[2] = -2*q*px*X*2;
+    dpar[3] = -2*q*py*Y*2;
+    dpar[4] = -q*X*Y;
+    dpar[5] = +r;
+    dpar[6] = +1;
+    dpar[7] = -par[5]*SQ(r)*z;
+  }
+  return (f);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-qrgauss.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-qrgauss.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-qrgauss.c	(revision 3338)
@@ -0,0 +1,78 @@
+# include "imfit.h"
+
+float qrgaussTD (float, float, float *, int, float *);
+void  qrgaussCL ();
+
+void qrgauss_setup (char *name) {
+
+  if (strcmp(name, "qrgauss")) return;
+
+  fitfunc = qrgaussTD;
+  imfit_cleanup = qrgaussCL;
+  Npar = 8;
+  Nfpar = 1;
+
+  /* allocate free and fixed parameters */
+  ALLOCATE (par, float, MAX (Npar, 1));
+  bzero (par, Npar*sizeof(float));
+  ALLOCATE (fpar, float, MAX (Nfpar, 1));
+  bzero (fpar, Nfpar*sizeof(float));
+
+  par[0]  = get_variable_default ("Xg", 0);
+  par[1]  = get_variable_default ("Yg", 0);
+  par[2]  = 2.35 / get_variable_default ("SXg", 2.0);
+  par[3]  = 2.35 / get_variable_default ("SYg", 2.0);
+  par[4]  = get_variable_default ("SXYg", 0);
+  par[5]  = get_variable_default ("Zpk", 10000);
+  par[6]  = get_variable_default ("Sg", 0.0);
+  par[7]  = get_variable_default ("Npow", 2.25);
+
+  fpar[0] = get_variable_default ("Sr", 1.0);
+
+  sky = &par[6];
+}
+
+void qrgaussCL () {
+  set_variable ("Xg",   par[0]);
+  set_variable ("Yg",   par[1]);
+  set_variable ("SXg",  2.35 / par[2]);
+  set_variable ("SYg",  2.35 / par[3]);
+  set_variable ("SXYg", par[4]);
+  set_variable ("Zpk",  par[5]);
+  set_variable ("Sg",   par[6]);
+  set_variable ("Npow", par[7]);
+}
+
+/* one component, two slopes: (1 + z^M + z^N)^(-1) -- x, y, sx, sy, sxy, I, sky, sr */
+float qrgaussTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, px, py;
+  float z, r, q, f;
+
+  /* if (par[7] < 1.0) par[7] = 1.0; */
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  px = par[2]*X;
+  py = par[3]*Y;
+
+  z = 0.5*SQ(px) + 0.5*SQ(py) + par[4]*X*Y;
+
+  r = 1.0 / (1 + fpar[0]*z + pow(z,par[7]) + 0.05*z*z*z);
+  f = par[5]*r + par[6];
+  q = par[5]*SQ(r)*(fpar[0] + par[7]*pow(z,(par[7]-1)) + 0.15*z*z);
+
+  if (dpar != NULL) {
+    dpar[0] = q*(2*px*par[2] + par[4]*Y);
+    dpar[1] = q*(2*py*par[3] + par[4]*X);
+    dpar[2] = -2*q*px*X*2;
+    dpar[3] = -2*q*py*Y*2;
+    dpar[4] = -q*X*Y;
+    dpar[5] = +r;
+    dpar[6] = +1;
+    dpar[7] = -5*par[5]*SQ(r)*log(z)*pow(z,par[7]);
+  }
+  return (f);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-rgauss.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-rgauss.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-rgauss.c	(revision 3338)
@@ -0,0 +1,86 @@
+# include "imfit.h"
+
+float rgaussTD (float, float, float *, int, float *);
+void  rgaussCL ();
+
+void rgauss_setup (char *name) {
+
+  if (strcmp(name, "rgauss")) return;
+
+  fitfunc = rgaussTD;
+  cleanup = rgaussCL;
+  Npar = 10;
+  Nfpar = 1;
+
+  /* allocate free and fixed parameters */
+  ALLOCATE (par, float, MAX (Npar, 1));
+  bzero (par, Npar*sizeof(float));
+  ALLOCATE (fpar, float, MAX (Nfpar, 1));
+  bzero (fpar, Nfpar*sizeof(float));
+
+  par[0] = get_variable_default ("Xg", 0);
+  par[1] = get_variable_default ("Yg", 0);
+  par[2] = 2.35 * sqrt(2.0) / get_variable_default ("SXg", 2.0);
+  par[3] = 2.35 * sqrt(2.0) / get_variable_default ("SYg", 2.0);
+  par[4] = 0.0;
+  par[5] = get_variable_default ("Zpk", 10000);
+  par[6] = get_variable_default ("Sg", 0.0);
+  par[7] = 2.35 * sqrt(2.0) / get_variable_default ("SXf", 15.0);
+  par[8] = 2.35 * sqrt(2.0) / get_variable_default ("SYf", 15.0);
+  par[9] = get_variable_default ("SXYf", 0.0);
+
+  fpar[0] = get_variable_default ("Npow", 2.25);
+
+  sky = &par[6];
+}
+
+/* two components: (1 + z_1 + 0.5*z_1^2 + z_2^N)^(-1) -- x, y, sx1, sy1, sxy1, I, sky, sx2, sy2, sxy2 */
+float rgaussTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, px1, py1, px2, py2;
+  float z1, z2, r, q1, q2, f;
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  px1 = par[2]*X;
+  py1 = par[3]*Y;
+  px2 = par[7]*X;
+  py2 = par[8]*Y;
+
+  z1 = 0.5*SQ(px1) + 0.5*SQ(py1) + par[4]*X*Y;
+  z2 = 0.5*SQ(px2) + 0.5*SQ(py2) + par[9]*X*Y;
+
+  r = 1.0 / (1 + z1 + 0.5*SQ(z1)+ pow(z2,fpar[0]));
+  f = par[5]*r + par[6];
+
+  q1 = par[5]*SQ(r)*(1 + z1);
+  q2 = par[5]*SQ(r)*fpar[0]*pow(z2,(fpar[0]-1));
+
+  if (dpar != NULL) {
+    dpar[0] = q1*(2*px1*par[2] + par[4]*Y) + q2*(2*px2*par[7] + par[9]*Y);
+    dpar[1] = q1*(2*py1*par[3] + par[4]*X) + q2*(2*py2*par[8] + par[9]*X);
+    dpar[2] = -2*q1*px1*X;
+    dpar[3] = -2*q1*py1*Y;
+    dpar[4] = -q1*X*Y;
+    dpar[5] = +r;
+    dpar[6] = +1;
+    dpar[7] = -2*q2*px2*X;
+    dpar[8] = -2*q2*py2*Y;
+    dpar[9] = -q2*X*Y;
+  }
+  return (f);
+}
+
+int rgaussCL () {
+  set_variable ("Xg",   par[0]);
+  set_variable ("Yg",   par[1]);
+  set_variable ("SXg",  2.35 * sqrt(2.0) / par[2]);
+  set_variable ("SYg",  2.35 * sqrt(2.0) / par[3]);
+  set_variable ("SXYg", par[4]);
+  set_variable ("Zpk",  par[5]);
+  set_variable ("Sg",   par[6]);
+  set_variable ("SXf", 2.35 * sqrt(2.0) / par[7]);
+  set_variable ("SYf", 2.35 * sqrt(2.0) / par[8]);
+  set_variable ("SXYf", par[9]);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-serbulge.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-serbulge.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-serbulge.c	(revision 3338)
@@ -0,0 +1,102 @@
+# include "imfit.h"
+
+float serbulgeTD (float, float, float *, int, float *);
+void  serbulgeCL ();
+
+void serbulge_setup (char *name) {
+
+  if (strcmp(name, "serbulge")) return;
+
+  fitfunc = serbulgeTD;
+  cleanup = serbulgeCL;
+  Npar = 12;
+  Nfpar = 0;
+
+  /* allocate free and fixed parameters */
+  ALLOCATE (par, float, MAX (Npar, 1));
+  bzero (par, Npar*sizeof(float));
+  ALLOCATE (fpar, float, MAX (Nfpar, 1));
+  bzero (fpar, Nfpar*sizeof(float));
+
+  par[0] = get_variable_default ("Xg", 0);
+  par[1] = get_variable_default ("Yg", 0);
+  par[2] = 2.35 * sqrt(2.0) / get_variable_default ("SXg", 2.0);
+  par[3] = 2.35 * sqrt(2.0) / get_variable_default ("SYg", 2.0);
+  par[4] = 0.0;
+  par[5] = get_variable_default ("Zpk", 10000) / 2.0;
+
+  par[6] = get_variable_default ("Sg", 0.0);
+
+  par[7] = 2.35 * sqrt(2.0) / get_variable_default ("SXf", 15.0);
+  par[8] = 2.35 * sqrt(2.0) / get_variable_default ("SYf", 15.0);
+  par[9] = get_variable_default ("SXYf", 0.0);
+  par[10] = get_variable_default ("Zpk", 10000) / 2.0;
+
+  par[11] = get_variable_default ("Sr", 1.0);
+
+  sky = &par[6];
+}
+
+/*                                  0  1    2   3   4      5    6     7   8   9       10  11 */
+/* sersic galaxy model w/ bulge: -- x, y, (sx, sy, sxy)_1, I_1, sky, (sx, sy, sxy)_2, I_2, n */
+/* exp (-b (r/r_e)^(1/n)) + pgauss (r) */
+float serbulgeTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, px1, px2, py1, py2;
+  float z1, z2, r1, r2, t, q1, q2, f;
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  px1 = par[2]*X;
+  py1 = par[3]*Y;
+  px2 = par[7]*X;
+  py2 = par[8]*Y;
+
+  z1 = 0.5*SQ(px1) + 0.5*SQ(py1) + par[4]*X*Y;
+  z2 = 0.5*SQ(px2) + 0.5*SQ(py2) + par[9]*X*Y;
+
+  /* bulge component */
+  r1 = 1.0 / (1 + z1 + 0.5*z1*z1*(1 + z1/3)); /* ~ exp (-Z) */
+
+  /* disk component */
+  t = pow (z2, par[11]);
+  r2 = exp (-t);
+
+  f = par[5]*r1 + par[10]*r2 + par[6];
+
+  q1 = par[5]*r1*r1*(1 + z1 + 0.5*z1*z1);
+  q2 = par[10]*r2*par[11]*pow(z2, par[11]-1);
+
+  if (dpar != NULL) {
+    dpar[0] = q1*(2*px1*par[2] + par[4]*Y) + q2*(2*px2*par[7] + par[9]*Y);
+    dpar[1] = q1*(2*py1*par[3] + par[4]*X) + q2*(2*py2*par[8] + par[9]*X);
+    dpar[2] = -2*q1*px1*X;
+    dpar[3] = -2*q1*py1*Y;
+    dpar[4] = -q1*X*Y;
+    dpar[5] = +r1;
+    dpar[6] = +1;
+    dpar[7] = -2*q2*px2*X*50;
+    dpar[8] = -2*q2*py2*Y*50;
+    dpar[9] = -q2*X*Y*50;
+    dpar[10] = +r2*50;
+    dpar[11] = -q2*log(z2)*t*50;
+  }
+  return (f);
+}
+
+int serbulgeCL () {
+  set_variable ("Xg",   par[0]);
+  set_variable ("Yg",   par[1]);
+  set_variable ("SXg",  2.35 * sqrt(2.0) / par[2]);
+  set_variable ("SYg",  2.35 * sqrt(2.0) / par[3]);
+  set_variable ("SXYg", par[4]);
+  set_variable ("Zb",   par[5]);
+  set_variable ("Sg",   par[6]);
+
+  set_variable ("SXf",  2.35 * sqrt(2.0) / par[7]);
+  set_variable ("SYf",  2.35 * sqrt(2.0) / par[8]);
+  set_variable ("SXYf", par[9]);
+  set_variable ("Zd",   par[10]);
+  set_variable ("Sr",   par[11]);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-sersic.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-sersic.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-sersic.c	(revision 3338)
@@ -0,0 +1,74 @@
+# include "imfit.h"
+
+float sersicTD (float, float, float *, int, float *);
+void  sersicCL ();
+
+void sersic_setup (char *name) {
+
+  if (strcmp(name, "sersic")) return;
+
+  fitfunc = sersicTD;
+  cleanup = sersicCL;
+  Npar = 8;
+  Nfpar = 0;
+
+  /* allocate free and fixed parameters */
+  ALLOCATE (par, float, MAX (Npar, 1));
+  bzero (par, Npar*sizeof(float));
+  ALLOCATE (fpar, float, MAX (Nfpar, 1));
+  bzero (fpar, Nfpar*sizeof(float));
+
+  par[0] = get_variable_default ("Xg", 0);
+  par[1] = get_variable_default ("Yg", 0);
+  par[2] = 2.35 * sqrt(2.0) / get_variable_default ("SXg", 2.0);
+  par[3] = 2.35 * sqrt(2.0) / get_variable_default ("SYg", 2.0);
+  par[4] = 0.0;
+  par[5] = get_variable_default ("Zpk", 10000);
+  par[6] = get_variable_default ("Sg", 0.0);
+  par[7] = get_variable_default ("Sr", 1.0);
+
+  sky = &par[6];
+}
+
+/* sersic galaxy model -- x, y, sx, sy, sxy, I, sky, n */
+/* exp (-b (r/r_e)^(1/n)) */
+float sersicTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, px, py;
+  float z, r, t, q, f;
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  px = par[2]*X;
+  py = par[3]*Y;
+
+  z = 0.5*SQ(px) + 0.5*SQ(py) + par[4]*X*Y;
+  t = pow (z, par[7]);
+  r = exp (-t);
+  f = par[5]*r + par[6];
+  q = par[5]*r*par[7]*pow(z, par[7]-1);
+
+  if (dpar != NULL) {
+    dpar[0] = q*(2*px*par[2] + par[4]*Y);
+    dpar[1] = q*(2*py*par[3] + par[4]*X);
+    dpar[2] = -2*q*px*X;
+    dpar[3] = -2*q*py*Y;
+    dpar[4] = -q*X*Y;
+    dpar[5] = +r;
+    dpar[6] = +1;
+    dpar[7] = -q*log(z)*t;
+  }
+  return (f);
+}
+
+int sersicCL () {
+  set_variable ("Xg",   par[0]);
+  set_variable ("Yg",   par[1]);
+  set_variable ("SXg",  2.35 * sqrt(2.0) / par[2]);
+  set_variable ("SYg",  2.35 * sqrt(2.0) / par[3]);
+  set_variable ("SXYg", par[4]);
+  set_variable ("Zpk",  par[5]);
+  set_variable ("Sg",   par[6]);
+  set_variable ("Sr", par[7]);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-sgauss.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-sgauss.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-sgauss.c	(revision 3338)
@@ -0,0 +1,98 @@
+# include "imfit.h"
+# define FFACTOR 200
+# define FSCALE 1.2
+
+float sgaussTD (float, float, float *, int, float *);
+void  sgaussCL ();
+
+void sgauss_setup (char *name) {
+
+  if (strcmp(name, "sgauss")) return;
+
+  fitfunc = sgaussTD;
+  imfit_cleanup = sgaussCL;
+  Npar = 10;
+  Nfpar = 2;
+
+  /* allocate free and fixed parameters */
+  ALLOCATE (par, float, MAX (Npar, 1));
+  bzero (par, Npar*sizeof(float));
+  ALLOCATE (fpar, float, MAX (Nfpar, 1));
+  bzero (fpar, Nfpar*sizeof(float));
+
+  par[0] = get_variable_default ("Xg", 0);
+  par[1] = get_variable_default ("Yg", 0);
+  par[2] = 2.35 / get_variable_default ("SXg", 2.0);
+  par[3] = 2.35 / get_variable_default ("SYg", 2.0);
+  par[4] = get_variable_default ("SXYg", 0);
+  par[5] = get_variable_default ("Zpk", 10000);
+  par[6] = get_variable_default ("Sg", 0.0);
+  par[7] = 2.35 / get_variable_default ("SXf", 15.0);
+  par[8] = 2.35 / get_variable_default ("SYf", 15.0);
+  par[9] = get_variable_default ("SXYf", 0.0);
+
+  fpar[0] = get_variable_default ("Npow", 2.25);
+  fpar[1] = get_variable_default ("Npin", 1.00); // drop this?
+
+  sky = &par[6];
+}
+
+void sgaussCL () {
+  set_variable ("Xg",   par[0]);
+  set_variable ("Yg",   par[1]);
+  set_variable ("SXg",  2.35 / par[2]);
+  set_variable ("SYg",  2.35 / par[3]);
+  set_variable ("SXYg", par[4]);
+  set_variable ("Zpk",  par[5]);
+  set_variable ("Sg",   par[6]);
+  set_variable ("SXf", 2.35 / par[7]);
+  set_variable ("SYf", 2.35 / par[8]);
+  set_variable ("SXYf", par[9]);
+}
+
+/* two components: (1 + z_1 + z_2^N)^(-1) -- x, y, sx1, sy1, sxy1, I, sky, sx2, sy2, sxy2 */
+float sgaussTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, px1, py1, px2, py2;
+  float z1, z2, r, q1, q2, f, f1, f2;
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  px1 = par[2]*X;
+  py1 = par[3]*Y;
+  px2 = par[7]*X;
+  py2 = par[8]*Y;
+
+  z1 = 0.5*SQ(px1) + 0.5*SQ(py1) + par[4]*X*Y;
+  z2 = 0.5*SQ(px2) + 0.5*SQ(py2) + par[9]*X*Y;
+
+  r = 1.0 / (1 + z1 + pow(z2,fpar[0]));
+  f = par[5]*r + par[6];
+
+  q1 = par[5]*SQ(r);
+  q2 = par[5]*SQ(r)*fpar[0]*pow(z2,(fpar[0]-1));
+
+  if (dpar != NULL) {
+    dpar[0] = q1*(2*px1*par[2] + par[4]*Y) + q2*(2*px2*par[7] + par[9]*Y);
+    dpar[1] = q1*(2*py1*par[3] + par[4]*X) + q2*(2*py2*par[8] + par[9]*X);
+
+    /* these fudge factors impede the growth of par[2] beyond par[7] */
+    f1 = fabs(par[7]) / fabs(par[2]);
+    f2 = (f1 < FSCALE) ? 1 : FFACTOR*(f1 - FSCALE) + 1;
+    dpar[2] = -2*q1*px1*X*f2;
+
+    f1 = fabs(par[8]) / fabs(par[3]);
+    f2 = (f1 < FSCALE) ? 1 : FFACTOR*(f1 - FSCALE) + 1;
+    dpar[3] = -2*q1*py1*Y*f2;
+
+    dpar[4] = -q1*X*Y;
+    dpar[5] = +r;
+    dpar[6] = +1;
+    dpar[7] = -2*q2*px2*X;
+    dpar[8] = -2*q2*py2*Y;
+    dpar[9] = -q2*X*Y;
+  }
+  return (f);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-test.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-test.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-test.c	(revision 3338)
@@ -0,0 +1,314 @@
+  if (ShapeVariation) {
+    /* find dChi/dSx and dChi/dSy given by increasing shape terms by 5% */
+    float tp1, tp2, chix, chiy;
+    chix = chiy = 0;
+    if (fitfunc == sgaussTD) {
+      tp1 = par[2];
+      tp2 = par[7];
+      par[2] = par[2]*1.05;
+      par[7] = par[7]*1.05;
+      chix = mrq2dchi (x, y, z, dz, Npts, par, Npar, fitfunc) - chisq;
+      par[2] = tp1;
+      par[7] = tp2;
+
+      tp1 = par[3];
+      tp2 = par[8];
+      par[3] = par[3]*1.05;
+      par[8] = par[8]*1.05;
+      chiy = mrq2dchi (x, y, z, dz, Npts, par, Npar, fitfunc) - chisq;
+      par[3] = tp1;
+      par[8] = tp2;
+    }
+    if (fitfunc == pgaussTD) {
+      tp1 = par[2];
+      par[2] = par[2]*1.05;
+      chix = mrq2dchi (x, y, z, dz, Npts, par, Npar, fitfunc) - chisq;
+      par[2] = tp1;
+
+      tp1 = par[3];
+      par[3] = par[3]*1.05;
+      chiy = mrq2dchi (x, y, z, dz, Npts, par, Npar, fitfunc) - chisq;
+      par[3] = tp1;
+    }
+    if (fitfunc == SgaussTD) {
+      tp1 = par[0];
+      tp2 = par[3];
+      par[0] = par[0]*1.05;
+      par[3] = par[3]*1.05;
+      chix = mrq2dchi (x, y, z, dz, Npts, par, Npar, fitfunc) - chisq;
+      par[0] = tp1;
+      par[3] = tp2;
+
+      tp1 = par[1];
+      tp2 = par[4];
+      par[1] = par[1]*1.05;
+      par[4] = par[4]*1.05;
+      chiy = mrq2dchi (x, y, z, dz, Npts, par, Npar, fitfunc) - chisq;
+      par[1] = tp1;
+      par[4] = tp2;
+    }
+    if (fitfunc == PgaussTD) {
+      tp1 = par[0];
+      par[0] = par[0]*1.05;
+      chix = mrq2dchi (x, y, z, dz, Npts, par, Npar, fitfunc) - chisq;
+      par[0] = tp1;
+
+      tp1 = par[1];
+      par[1] = par[1]*1.05;
+      chiy = mrq2dchi (x, y, z, dz, Npts, par, Npar, fitfunc) - chisq;
+      par[1] = tp1;
+    }
+    set_variable ("dChiX", chix/chisq);
+    set_variable ("dChiY", chiy/chisq);
+  }
+
+# if (0)
+/* pars: x, y, sx, sy, sxy, I, sky */
+float fgalaxyTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, Z, E, F, q, R, f, p2, p3;
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  p2 = X / par[2];
+  p3 = Y / par[3];
+
+  Z = sqrt (0.5*p2*X + X*Y*par[4] + 0.5*p3*Y);                 /* R */
+  E = 1.0 / (1 + Z);   
+
+  q = par[5] * E;
+  R = q*E;
+  F = 0.5 / Z;
+  
+  f = q + par[6];
+
+  dpar[0] = F*R*(p2 + par[4]*Y);
+  dpar[1] = F*R*(p3 + par[4]*X);
+  dpar[2] = F*0.5*R*p2*p2;
+  dpar[3] = F*0.5*R*p3*p3;
+  dpar[4] = -R*X*Y*F;
+    
+  dpar[5] = E;
+  dpar[6] = 1;
+  return (f);
+}
+
+/* pars: x, y, sx, sy, sxy, I, sky */
+float fbarTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, Z, E, F, q, R, f, p2, p3;
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  p2 = X / par[2];
+  p3 = Y / par[3];
+
+  Z = 0.5*p2*X + X*Y*par[4] + 0.5*p3*Y;                 /* R */
+  E = 1.0 / (1 + Z*Z*Z);   
+
+  q = par[5] * E;
+  F = 3*Z*Z;
+  R = q*E*F;
+  
+  f = q + par[6];
+
+  dpar[0] = R*(p2 + par[4]*Y);
+  dpar[1] = R*(p3 + par[4]*X);
+  dpar[2] = 0.5*R*p2*p2;
+  dpar[3] = 0.5*R*p3*p3;
+  dpar[4] = -R*X*Y;
+    
+  dpar[5] = E;
+  dpar[6] = 1;
+  return (f);
+}
+
+/* convert from x,y to major,minor */
+void fix_ellipsegauss_pars (float *par, int Npar) {
+
+  float p2, p4, angle, t1, t2, tmp, area;
+
+  /* par[0], par[1] = Xo, Yo - stay the same */
+
+  p2 = 1/par[2];
+  p4 = 1/par[3];
+
+  angle = 0.5 * atan2 (-2*par[4], p4 - p2); 
+
+  tmp = sqrt (SQ(p2 - p4) + 4*SQ(par[4]));
+  t1 = (p2 + p4 + tmp) / 2;
+  t2 = t1 - tmp;
+
+  par[2] = 2.35482*sqrt(1/t2);
+  par[3] = 2.35482*sqrt(1/t1);
+  par[4] = DEG_RAD * angle;
+
+  area = 2*M_PI/sqrt(t1*t2);
+
+  par[5] *= area;
+
+}
+# endif
+
+/***  options for later
+
+  Subtract = FALSE;
+  if ((N = get_argument (argc, argv, "-sub"))) {
+    remove_argument (N, &argc, argv);
+    Subtract  = TRUE;
+  }
+
+  DFact = 1;
+  if ((N = get_argument (argc, argv, "-D"))) {
+    remove_argument (N, &argc, argv);
+    DFact  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  fitfunc = fgaussTD;
+  if ((N = get_argument (argc, argv, "-gal"))) {
+    remove_argument (N, &argc, argv);
+    fitfunc = fgalaxyTD; 
+  }
+  if ((N = get_argument (argc, argv, "-bar"))) {
+    remove_argument (N, &argc, argv);
+    fitfunc = fbarTD; 
+  }
+
+
+  f1 = 1;
+  if ((c = get_variable ("BETA1")) != (char *) NULL) f1 = atof (c);
+
+  f2 = 1;
+  if ((c = get_variable ("BETA2")) != (char *) NULL) f2 = atof (c);
+
+  if (Subtract) {
+    tmpsky = par[6];
+    par[6] = 0;
+    for (N = j = 0; j < ny; j++) {
+      V = (float *)(buf[0].matrix.buffer) + (j+sy)*buf[0].matrix.Naxis[0] + sx; 
+      for (i = 0; i < nx; i++, V++, N++) {
+	dx = i + sx;
+	dy = j + sy;
+	*V -= fitfunc (dx, dy, par, Npar, (float *) NULL);
+      }
+    }
+    par[6] = tmpsky;
+  }
+
+***/
+
+# if (0)
+
+/* these two tests were not very succcessful.  the first did not model the shape well because 
+   it could not match the change in roundness with radius.  the second did not work because the 
+   parameters were degenerate (amplitude and slope of second component) */
+
+/* test: fixed, non-integer higher-order term -- x, y, sx, sy, sxy, I, sky, f1, f2 */
+float qgaussTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, px, py;
+  float z, r, q, f, k;
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  px = par[2]*X;
+  py = par[3]*Y;
+
+  z = 0.5*SQ(px) + 0.5*SQ(py) + par[4]*X*Y;
+  k = pow(z,1.75*par[8]);
+  r = 1.0 / (1 + z + par[7]*k); /* ~ exp (-Z) */
+  q = par[5]*r*r*(1 + 1.75*par[7]*par[8]*pow(z,1.75*par[8]-1));
+  /* note difference from gaussian: q = par[5]*r */
+  f = par[5]*r + par[6];
+
+  dpar[0] = q*(2*px*par[2] + par[4]*Y);
+  dpar[1] = q*(2*py*par[3] + par[4]*X);
+  dpar[2] = -2*q*px*X;
+  dpar[3] = -2*q*py*Y;
+  dpar[4] = -q*X*Y;
+  dpar[5] = +r;
+  dpar[6] = +1;
+  dpar[7] = -10*par[5]*r*r*k;
+  dpar[8] = -10*par[5]*r*r*par[7]*k*1.75*log(z);
+
+  return (f);
+}
+
+/* test: two component model: inner pseudo gaussian with outer z^1.75 x, y, sx, sy, sxy, I, sky */
+float rgaussTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, px1, py1, px2, py2;
+  float z1, z2, r1, r2, q1, q2, f;
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  px1 = par[2]*X;
+  py1 = par[3]*Y;
+  px2 = par[8]*X;
+  py2 = par[9]*Y;
+
+  z1 = 0.5*SQ(px1) + 0.5*SQ(py1) + par[4]*X*Y;
+  z2 = 0.5*SQ(px2) + 0.5*SQ(py2) + par[10]*X*Y;
+
+  r1 = 1.0 / (1 + z1 + 0.5*SQ(z1)*(1 + z1/3)); /* ~ exp (-Z) */
+  r2 = 1.0 / (1 + pow(z2,1.75));
+
+  f = par[5]*r1 + par[6] + par[7]*r2;
+
+  q1 = par[5]*SQ(r1)*(1 + z1 + 0.5*SQ(z1));
+  q2 = par[7]*SQ(r2)*(1.75*pow(z2,0.75));
+
+  dpar[	0] = q1*(2*px1*par[2] + par[4]*Y) + q2*(2*px2*par[8] + par[10]*Y);
+  dpar[	1] = q1*(2*py1*par[3] + par[4]*X) + q2*(2*py2*par[9] + par[10]*X);
+  dpar[	2] = -2*q1*px1*X;
+  dpar[	3] = -2*q1*py1*Y;
+  dpar[	4] = -q1*X*Y;
+  dpar[	5] = +r1;
+  dpar[	6] = +1;
+  dpar[	7] = +r2*2;
+  dpar[	8] = -2*q2*px2*X*2;
+  dpar[	9] = -2*q2*py2*Y*2;
+  dpar[10] = -q2*X*Y;
+
+  return (f);
+}
+
+# endif
+
+  /* forcing values to have a rational range
+  ALLOCATE (parmin, float, Npar);
+  ALLOCATE (parmax, float, Npar);
+  bzero (parmin, Npar*sizeof(float));
+  bzero (parmax, Npar*sizeof(float));
+  parmin[0] = parmin[1] = 0;
+  parmax[0] = buf[0].matrix.Naxis[0];
+  parmax[1] = buf[0].matrix.Naxis[1];
+
+  parmin[2] = parmin[3] = 0.01;
+  parmax[2] = parmax[3] = 100.0;
+  parmin[4] = -1000;
+  parmax[4] = -1000;
+  
+  parmin[5] = 1;
+  parmax[5] = 1e5;
+
+  parmin[6] = 0.0;
+  parmax[6] = 1e5;
+
+  if (Npar == 9) {
+    parmin[7] = parmin[8] = 0.01;
+    parmax[7] = parmax[8] = 10.0;
+  }
+  if (Npar == 10) {
+    parmin[7] = parmin[8] = 0.01;
+    parmax[7] = parmax[8] = 10.0;
+    parmin[9] = -1000;
+    parmax[9] = -1000;
+  }
+  */
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-tgauss.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-tgauss.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-tgauss.c	(revision 3338)
@@ -0,0 +1,81 @@
+# include "imfit.h"
+
+float tgaussTD (float, float, float *, int, float *);
+void  tgaussCL ();
+
+void tgauss_setup (char *name) {
+
+  if (strcmp(name, "tgauss")) return;
+
+  fitfunc = tgaussTD;
+  cleanup = tgaussCL;
+  Npar = 10;
+  Nfpar = 2;
+
+  par[0] = get_variable_default ("Xg", 0);
+  par[1] = get_variable_default ("Yg", 0);
+  par[2] = 2.35 * sqrt(2.0) / get_variable_default ("SXg", 2.0);
+  par[3] = 2.35 * sqrt(2.0) / get_variable_default ("SYg", 2.0);
+  par[4] = 0.0;
+  par[5] = get_variable_default ("Zpk", 10000);
+  par[6] = get_variable_default ("Sg", 0.0);
+  par[7] = 2.35 * sqrt(2.0) / get_variable_default ("SXf", 15.0);
+  par[8] = 2.35 * sqrt(2.0) / get_variable_default ("SYf", 15.0);
+  par[9] = get_variable_default ("SXYf", 0.0);
+
+  fpar[0] = get_variable_default ("Npow", 2.25);
+  fpar[1] = get_variable_default ("Npin", 1.00); // drop this?
+
+  sky = &par[6];
+}
+
+/* two components: (1 + z_1^M + z_2^N)^(-1) -- x, y, sx1, sy1, sxy1, I, sky, sx2, sy2, sxy2 */
+float tgaussTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, px1, py1, px2, py2;
+  float z1, z2, r, q1, q2, f;
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  px1 = par[2]*X;
+  py1 = par[3]*Y;
+  px2 = par[7]*X;
+  py2 = par[8]*Y;
+
+  z1 = 0.5*SQ(px1) + 0.5*SQ(py1) + par[4]*X*Y;
+  z2 = 0.5*SQ(px2) + 0.5*SQ(py2) + par[9]*X*Y;
+
+  r = 1.0 / (1 + pow(z1,fpar[1]) + pow(z2,fpar[0]));
+  f = par[5]*r + par[6];
+
+  q1 = par[5]*SQ(r)*fpar[1]*pow(z1,(fpar[1]-1));
+  q2 = par[5]*SQ(r)*fpar[0]*pow(z2,(fpar[0]-1));
+
+  if (dpar != NULL) {
+    dpar[0] = q1*(2*px1*par[2] + par[4]*Y) + q2*(2*px2*par[7] + par[9]*Y);
+    dpar[1] = q1*(2*py1*par[3] + par[4]*X) + q2*(2*py2*par[8] + par[9]*X);
+    dpar[2] = -2*q1*px1*X*2;
+    dpar[3] = -2*q1*py1*Y*2;
+    dpar[4] = -q1*X*Y;
+    dpar[5] = +r;
+    dpar[6] = +1;
+    dpar[7] = -2*q2*px2*X;
+    dpar[8] = -2*q2*py2*Y;
+    dpar[9] = -q2*X*Y;
+  }
+  return (f);
+}
+
+int tgaussCL () {
+  set_variable ("Xg",   par[0]);
+  set_variable ("Yg",   par[1]);
+  set_variable ("SXg",  2.35 * sqrt(2.0) / par[2]);
+  set_variable ("SYg",  2.35 * sqrt(2.0) / par[3]);
+  set_variable ("SXYg", par[4]);
+  set_variable ("Zpk",  par[5]);
+  set_variable ("Sg",   par[6]);
+  set_variable ("SXf",  2.35 * sqrt(2.0) / par[7]);
+  set_variable ("SYf",  2.35 * sqrt(2.0) / par[8]);
+  set_variable ("SXYf", par[9]);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-vgauss.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-vgauss.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit-vgauss.c	(revision 3338)
@@ -0,0 +1,70 @@
+# include "imfit.h"
+
+float vgaussTD (float, float, float *, int, float *);
+void  vgaussCL ();
+
+void  vgauss_setup (char *name) {
+
+  if (strcmp(name, "vgauss")) return;
+
+  fitfunc = vgaussTD;
+  cleanup = vgaussCL;
+  Npar = 9;
+  Nfpar = 0;
+
+  par[0] = get_variable_default ("Xg", 0);
+  par[1] = get_variable_default ("Yg", 0);
+  par[2] = 2.35 * sqrt(2.0) / get_variable_default ("SXg", 2.0);
+  par[3] = 2.35 * sqrt(2.0) / get_variable_default ("SYg", 2.0);
+  par[4] = 0.0;
+  par[5] = get_variable_default ("Zpk", 10000);
+  par[6] = get_variable_default ("Sg", 0.0);
+  par[7] = 1;
+  par[8] = 1;
+  sky = &par[6];
+}
+
+/* pseudo 2D gaussian with floating 2nd and 3rd order terms -- x, y, sx, sy, sxy, I, sky, f1, f2 */
+float vgaussTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, px, py;
+  float z, r, q, f, k;
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  px = par[2]*X;
+  py = par[3]*Y;
+
+  z = 0.5*SQ(px) + 0.5*SQ(py) + par[4]*X*Y;
+  k = 0.5*z*z*(1 + par[8]*z/3);
+  r = 1.0 / (1 + z + par[7]*k); /* ~ exp (-Z) */
+  f = par[5]*r + par[6];
+  q = par[5]*r*r*(1 + par[7]*z*(1 + par[8]*z/2));
+  /* note difference from gaussian: q = par[5]*r */
+
+  if (dpar != NULL) {
+    dpar[0] = q*(2*px*par[2] + par[4]*Y);
+    dpar[1] = q*(2*py*par[3] + par[4]*X);
+    dpar[2] = -2*q*px*X;
+    dpar[3] = -2*q*py*Y;
+    dpar[4] = -q*X*Y;
+    dpar[5] = +r;
+    dpar[6] = +1;
+    dpar[7] = -100*par[5]*r*r*k;
+    dpar[8] = -100*par[5]*r*r*par[7]*(z*z*z)/6;
+  }
+  return (f);
+}
+
+int vgaussCL () {
+  set_variable ("Xg",   par[0]);
+  set_variable ("Yg",   par[1]);
+  set_variable ("SXg",  2.35 * sqrt(2.0) / par[2]);
+  set_variable ("SYg",  2.35 * sqrt(2.0) / par[3]);
+  set_variable ("SXYg", par[4]);
+  set_variable ("Zpk",  par[5]);
+  set_variable ("Sg",   par[6]);
+  set_variable ("SXf", par[7]);
+  set_variable ("SYf", par[8]);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imfit.c	(revision 3338)
@@ -0,0 +1,191 @@
+# include "imfit.h"
+
+int imfit (int argc, char **argv) {
+
+  int i, j, N, Npts, Save, VERBOSE, ShapeVariation;
+  int sx, sy, nx, ny, Nx, Ny;
+  float chisq, ochisq, dchisq, Gain, RDnoise, SatThreshold;
+  float *x, *y, *z, *dz, *V, *parmin, *parmax;
+  char line[64];
+  Buffer *buf;
+
+  Save = FALSE;
+  if ((N = get_argument (argc, argv, "-save"))) {
+    remove_argument (N, &argc, argv);
+    Save = TRUE;
+  }
+
+  ShapeVariation = FALSE;
+  if ((N = get_argument (argc, argv, "-shapes"))) {
+    remove_argument (N, &argc, argv);
+    ShapeVariation = TRUE;
+  }
+
+  SatThreshold = 0xffff;
+  if ((N = get_argument (argc, argv, "-sat"))) {
+    remove_argument (N, &argc, argv);
+    SatThreshold = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  /* Gain in e/DN */
+  Gain = 1.0;
+  if ((N = get_argument (argc, argv, "-gain"))) {
+    remove_argument (N, &argc, argv);
+    Gain = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  /* RD noise in DN */
+  RDnoise = 0.0;
+  if ((N = get_argument (argc, argv, "-rdnoise"))) {
+    remove_argument (N, &argc, argv);
+    RDnoise = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  VERBOSE = FALSE;
+  if ((N = get_argument (argc, argv, "-v"))) {
+    remove_argument (N, &argc, argv);
+    VERBOSE = TRUE;
+  }
+
+  /* set fitting function */
+  fgauss_setup ("fgauss");
+  if ((N = get_argument (argc, argv, "-func"))) {
+    fitfunc = NULL;
+    remove_argument (N, &argc, argv);
+    fgauss_setup (argv[N]);
+    pgauss_setup (argv[N]);
+    Pgauss_setup (argv[N]);
+    sgauss_setup (argv[N]);
+    Sgauss_setup (argv[N]);
+    qgauss_setup (argv[N]);
+    Qgauss_setup (argv[N]);
+    qfgauss_setup (argv[N]);
+    qrgauss_setup (argv[N]);
+    if (fitfunc == NULL) {
+      fprintf (stderr, "unknown function %s\n", argv[N]);
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 6) {
+    fprintf (stderr, "USAGE: imfit <buffer> sx sy nx ny\n");
+    return (FALSE);
+  }
+
+  /* non-optional arguments */
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  sx = atof (argv[2]);
+  sy = atof (argv[3]);
+  nx = atof (argv[4]);
+  ny = atof (argv[5]);
+  Nx = buf[0].matrix.Naxis[0];
+  Ny = buf[0].matrix.Naxis[1];
+
+  /* check if region is valid */
+  if (sx + 0.5*nx < 0) goto range;
+  if (sy + 0.5*ny < 0) goto range;
+  if (sx + 0.5*nx >= Nx) goto range;
+  if (sy + 0.5*ny >= Ny) goto range;
+
+  /* convert array z[x,y] to x[i], y[i], z[i] */
+  N = 0;
+  Npts = nx*ny;
+  ALLOCATE (x,  float, 2*Npts);
+  ALLOCATE (y,  float, 2*Npts);
+  ALLOCATE (z,  float, 2*Npts);
+  ALLOCATE (dz, float, 2*Npts);
+  for (j = 0; j < ny; j++) {
+    if (j + sy < 0) continue;
+    if (j + sy >= Ny) continue;
+    V = (float *)(buf[0].matrix.buffer) + (j+sy)*buf[0].matrix.Naxis[0] + sx; 
+    for (i = 0; i < nx; i++) {
+      if (i + sx < 0) continue;
+      if (i + sx >= Nx) continue;
+      if (*V > SatThreshold) goto next;
+      dz[N] = (SQ(RDnoise) + *V/Gain);
+      if (dz[N] <= 0) goto next;
+      dz[N] = 1.0 / dz[N];
+      x[N] = i + sx;
+      y[N] = j + sy;
+      z[N] = *V;
+      N++;
+    next:
+      V++;
+    }
+  }
+  Npts = N;
+
+  /* run fit routine */
+  ochisq = mrq2dinit (x, y, z, dz, Npts, par, Npar, fitfunc, VERBOSE);
+  dchisq = ochisq;
+  for (i = 0; (i < 25) && ((dchisq <= 0.0) || (dchisq > 0.01*(Npts - Npar))); i++) {
+    chisq = mrq2dmin (x, y, z, dz, Npts, par, Npar, fitfunc, VERBOSE);
+    dchisq = ochisq - chisq;
+    ochisq = chisq;
+  }  
+  set_int_variable ("Niter",  i);
+
+  /** create output image (keep in sky) **/
+  if (Save) {
+    Buffer *out;
+    float *Vi, *Vo, vr, vf;
+
+    if ((out = SelectBuffer ("out",   ANYBUFFER, TRUE)) == NULL) return (FALSE);
+    free (out[0].header.buffer);
+    free (out[0].matrix.buffer);
+    strcpy (out[0].file, "(empty)");
+    out[0].header.bitpix = -32;
+    out[0].header.bscale = 1.0;
+    out[0].header.bzero  = 0.0;
+    out[0].header.unsign = FALSE;
+    out[0].header.Naxes = 2;
+    out[0].header.Naxis[0] = 2*nx;
+    out[0].header.Naxis[1] = 2*ny;
+    CreateBuffer (out);
+
+    /* four panels: 1) raw image. 2) fit  3) raw - fit   4) ?? */
+    Vi = (float *)buf[0].matrix.buffer;
+    Vo = (float *)out[0].matrix.buffer;
+    for (j = 0; j < ny; j++) {
+      for (i = 0; i < nx; i++) {
+	vf = fitfunc ((float)(i+sx), (float)(j+sy), par, Npar, NULL);
+	vr = Vi[(i+sx)+(j+sy)*Nx];
+	Vo[(i   )+(j   )*2*nx] = vr;
+	Vo[(i+nx)+(j   )*2*nx] = vf;
+	Vo[(i   )+(j+ny)*2*nx] = vr - vf + *sky;
+	Vo[(i+nx)+(j+ny)*2*nx] = fabs(vr-vf) + *sky;
+      }
+    }
+  }
+
+  /* save parameters to opihi variables */
+  imfit_cleanup ();
+
+  set_variable ("ChiSq", chisq/(Npts - Npar));
+
+  if (VERBOSE) {
+    for (i = 0; i < Npar; i++) {
+      fprintf (stderr, "%g ", par[i]);
+    }
+    fprintf (stderr, "\n");
+  }
+
+  free (x);
+  free (y);
+  free (z);
+  free (dz);
+  free (par);
+  free (fpar);
+
+  mrq2dfree (Npar);
+  return (TRUE);
+
+range:
+  fprintf (stderr, "region out of range\n");
+  return (FALSE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imsub.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imsub.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/imsub.c	(revision 3338)
@@ -0,0 +1,79 @@
+# include "imfit.h"
+
+int imsub (int argc, char **argv) {
+
+  int i, j, N, VERBOSE;
+  int sx, sy, nx, ny, Nx, Ny;
+  float value;
+  float *V;
+  Buffer *buf;
+
+  VERBOSE = FALSE;
+  if ((N = get_argument (argc, argv, "-v"))) {
+    remove_argument (N, &argc, argv);
+    VERBOSE = TRUE;
+  }
+
+  /* set fitting function */
+  fgauss_setup ("fgauss");
+  if ((N = get_argument (argc, argv, "-func"))) {
+    fitfunc = NULL;
+    remove_argument (N, &argc, argv);
+    fgauss_setup (argv[N]);
+    pgauss_setup (argv[N]);
+    Pgauss_setup (argv[N]);
+    sgauss_setup (argv[N]);
+    Sgauss_setup (argv[N]);
+    qgauss_setup (argv[N]);
+    Qgauss_setup (argv[N]);
+    qfgauss_setup (argv[N]);
+    qrgauss_setup (argv[N]);
+    if (fitfunc == NULL) {
+      fprintf (stderr, "unknown function %s\n", argv[N]);
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 6) {
+    fprintf (stderr, "USAGE: imfit <buffer> sx sy nx ny\n");
+    return (FALSE);
+  }
+
+  /* non-optional arguments */
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  sx = atof (argv[2]);
+  sy = atof (argv[3]);
+  nx = atof (argv[4]);
+  ny = atof (argv[5]);
+  Nx = buf[0].matrix.Naxis[0];
+  Ny = buf[0].matrix.Naxis[1];
+
+  /* check if region is valid */
+  if (sx >= Nx) goto range;
+  if (sy >= Ny) goto range;
+  if (sx + nx < 0) goto range;
+  if (sy + ny < 0) goto range;
+
+  /* subtract model fit, but not local sky */
+  for (j = 0; j < ny; j++) {
+    if (j + sy < 0) continue;
+    if (j + sy >= Ny) continue;
+    V = (float *)(buf[0].matrix.buffer) + (j+sy)*buf[0].matrix.Naxis[0] + sx; 
+    for (i = 0; i < nx; i++, V++) {
+      if (i + sx < 0) continue;
+      if (i + sx >= Nx) continue;
+      value = fitfunc ((float)(i+sx), (float)(j+sy), par, Npar, NULL);
+      *V -= value;
+    }
+  }
+
+  free (par);
+  free (fpar);
+  return (TRUE);
+
+range:
+  fprintf (stderr, "region out of range\n");
+  return (FALSE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/init.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/init.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/init.c	(revision 3338)
@@ -0,0 +1,81 @@
+# include "astro.h"
+
+int biassub		    PROTO((int, char **));
+int cgrid		    PROTO((int, char **));
+int coords		    PROTO((int, char **));
+int cplot		    PROTO((int, char **));
+int csystem		    PROTO((int, char **));
+int ctimes		    PROTO((int, char **));
+int cval		    PROTO((int, char **));
+int czplot		    PROTO((int, char **));
+int drizzle		    PROTO((int, char **));
+int flux		    PROTO((int, char **));
+int gauss		    PROTO((int, char **));
+int gaussfit		    PROTO((int, char **));
+int getvel		    PROTO((int, char **));
+int imfit		    PROTO((int, char **));
+int imsub		    PROTO((int, char **));
+int medianmap		    PROTO((int, char **));
+int mkgauss		    PROTO((int, char **));
+int multifit		    PROTO((int, char **));
+int objload		    PROTO((int, char **));
+int outline		    PROTO((int, char **));
+int polar		    PROTO((int, char **));
+int precess		    PROTO((int, char **));
+int profile		    PROTO((int, char **));
+int region		    PROTO((int, char **));
+int rotcurve		    PROTO((int, char **));
+int scale		    PROTO((int, char **));
+int sexigesimal		    PROTO((int, char **));
+int spec		    PROTO((int, char **));
+int star		    PROTO((int, char **));
+int times		    PROTO((int, char **));
+int transform		    PROTO((int, char **));
+
+static Command cmds[] = {  
+  {"biassub", 	  biassub,      "subtract medianed overscan row or column"},
+  {"cgrid",       cgrid,        "plot sky coordinate grid"},
+  {"coords",  	  coords,       "load coordinates for buffer from file"},
+  {"cplot",       cplot,        "plot vectors in sky coordinates"},
+  {"csystem", 	  csystem,      "convert between coordinate systems"},
+  {"ctimes",  	  ctimes,       "convert between time formats"},
+  {"cval",        cval,         "cosmic ray flux?"},
+  {"czplot",  	  czplot,       "plot scaled vectors in sky coordinates"},
+  {"drizzle", 	  drizzle,      "transform image to image"},
+  {"flux",    	  flux,         "flux in a convex contour"},
+  {"gauss",   	  gauss,        "get statistics on a star, assuming gaussian profile"},
+  {"getvel",      getvel,       "rotcurve to velocities"},
+  {"imfit",   	  imfit,        "fit function"},
+  {"imsub",   	  imsub,        "subtract function"},
+  {"medianmap",   medianmap,    "small median image"},
+  {"mkgauss",     mkgauss,      "generate a 2-D gaussian centered in image"},
+  {"multifit",    multifit,     "fit multi-order spectrum"},
+  {"objload",     objload,      "plot obj data on Ximage "},
+  {"outline",     outline,      "fit outline region"},
+  {"polar",       polar,        "convert polar image to cartesian"},
+  {"precess",     precess,      "precess coordinates"},
+  {"profile",     profile,      "radial profile at X, Y"},
+  {"region",      region,       "define sky region for plot"},
+  {"rotcurve",    rotcurve,     "convert CO images to polar coords"},
+  {"scale",       scale,        "get / set real bzero / bscale values"},
+  {"sexigesimal", sexigesimal,  "convert to/from sexigesimal/decimal"},
+  {"spec",    	  spec,         "extract a spectrum"},
+  {"star",    	  star,         "star stats at rough coords"},
+  {"transform",   transform,    "geometric transformation of image"},
+}; 
+
+/* not currently implemented 
+  {"gaussfit",    gaussfit,     "fit a gaussian to pixels in a region"},
+  {"testfit",     testfit, ""},
+  {"times", , ""},
+*/
+
+void InitAstro () {
+  
+  int i;
+
+  for (i = 0; i < sizeof (cmds) / sizeof (Command); i++) {
+    AddCommand (&cmds[i]);
+  }
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/medianmap.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/medianmap.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/medianmap.c	(revision 3338)
@@ -0,0 +1,111 @@
+# include "astro.h"
+
+int medianmap (int argc, char **argv) {
+  
+  float *temp, *tp;
+  int i, j, k, I0, I1, J0, J1, I, J, n, N;
+  int nx, ny, Nx, Ny, NX, NY, Ignore;
+  float Mv, Nv, Mv2, value, min, max, IgnoreValue;
+  float *In, *Out, *ip;
+  float fx, fy;
+  Buffer *in, *out;
+
+  Ignore = FALSE;
+  if ((N = get_argument (argc, argv, "-ignore"))) {
+    Ignore = TRUE;
+    remove_argument (N, &argc, argv);
+    IgnoreValue = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  min = 0.45;
+  max = 0.55;
+  if ((N = get_argument (argc, argv, "-range"))) {
+    remove_argument (N, &argc, argv);
+    min  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    max  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 5) {
+    fprintf (stderr, "USAGE: medianmap (in) (out) Nx Ny [-range min max]\n");
+    fprintf (stderr, "       Nx, Ny specify dimensions of output image\n");
+    fprintf (stderr, "       min, max specify fractional range for sorted average\n");
+    return (FALSE);
+  }
+
+  if ((in  = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((out = SelectBuffer (argv[2], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+
+  Nx = atof (argv[3]);
+  Ny = atof (argv[4]);
+  NX = in[0].header.Naxis[0];
+  NY = in[0].header.Naxis[1];
+
+  /* duplicate the (in) buffer to the (out), with different size */
+  /* this should probably be a function in misc */
+  fits_free_matrix (&out[0].matrix);
+  fits_free_header (&out[0].header);
+  out[0].bitpix = in[0].bitpix;
+  out[0].unsign = in[0].unsign;
+  out[0].bscale = in[0].bscale;
+  out[0].bzero  = in[0].bzero;
+  fits_copy_header (&in[0].header, &out[0].header);
+  fits_modify (&out[0].header, "NAXIS1", "%d", 1, Nx);
+  fits_modify (&out[0].header, "NAXIS2", "%d", 1, Ny);
+  out[0].header.Naxis[0] = Nx;
+  out[0].header.Naxis[1] = Ny;
+  fits_create_matrix (&out[0].header, &out[0].matrix);
+
+  In = (float *) in[0].matrix.buffer;
+  Out = (float *) out[0].matrix.buffer;
+
+  fx = (float) Nx / NX;
+  fy = (float) Ny / NY;
+
+  nx = 1 + 1/fx;
+  ny = 1 + 1/fy;
+
+  ALLOCATE (temp, float, 2*nx*ny);
+
+  Nv = Mv = Mv2 = 0.0;
+
+  for (j = 0; j < Ny; j++) {
+    J0 = j / fy;
+    J1 = (j + 1) / fy;
+    for (i = 0; i < Nx; i++) {
+      
+      I0 = i / fx;
+      I1 = (i + 1) / fx;
+
+      n = 0;
+      tp = temp;
+      for (J = J0; J < J1; J++) {
+	ip = &In[J*NX + I0];
+	for (I = I0; I < I1; I++, tp++, ip++) {
+	  if (Ignore && (fabs (*ip - IgnoreValue) < 0.01)) continue;
+	  *tp = *ip;
+	  n++;
+	}
+      }
+
+      fsort (temp, n);
+
+      value = 0;
+      N = 0;
+      for (k = min*n; k < max*n; k++) {
+	value += temp[k];
+	N ++;
+      }
+      if (N == 0)
+	Out[j*Nx + i] = 0;
+      else 
+	Out[j*Nx + i] = value / N;
+    }
+  }
+
+  return (TRUE);
+
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/mkgauss.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/mkgauss.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/mkgauss.c	(revision 3338)
@@ -0,0 +1,71 @@
+# include "astro.h"
+
+int mkgauss (int argc, char **argv) {
+  
+  int i, j, Nx, Ny, N;
+  float *in;
+  double Sig_x, Sig_y, Theta;
+  double root1, root2, R, A1, A2, A3;
+  double Sx, Sy, Sxy;
+  double x, y, r, f, Xo, Yo;
+  Buffer *buf;
+
+  Xo = Yo = 0;
+  if ((N = get_argument (argc, argv, "-c"))) {
+    remove_argument (N, &argc, argv);
+    Xo = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    Yo = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if ((argc < 3) || (argc > 5)) {
+    fprintf (stderr, "USAGE: mkgauss (buffer) (sigma) [[sy/sx] angle]\n");
+    return (FALSE);
+  }
+
+  /* select input / output buffers */
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  Nx = buf[0].header.Naxis[0];
+  Ny = buf[0].header.Naxis[1];
+  
+  /* gaussian parameters */
+  Sig_x = atof (argv[2]);
+  Sig_y = Sig_x;
+  Theta = 0.0;
+  if (argc > 3) {
+    Sig_y = Sig_x*atof (argv[3]);
+    if (argc == 5) {
+      Theta = atof (argv[4]);
+    }
+  }
+
+  /* given Sig_x, Sig_y, Theta, find Sx, Sy, Sxy */
+  root1 = SQ(1.0 / Sig_y);
+  root2 = SQ(1.0 / Sig_x);
+
+  R = 0.5 * (root1 - root2);
+  A1 = 0.25*(root1 + root2) - 0.5*R*cos(2*RAD_DEG*Theta);
+  A2 = 0.25*(root1 + root2) + 0.5*R*cos(2*RAD_DEG*Theta);
+  A3 = -R*sin(2*RAD_DEG*Theta);
+
+  Sx = 0.5/A1;
+  Sy = 0.5/A2;
+  Sxy = A3;
+
+  /* f = exp (-r), r = (x^2 / 2Sx) + (y^2 / 2Sy) + Sxy*x*y */
+
+  in = (float *) buf[0].matrix.buffer;
+  for (j = 0; j < Ny; j++) {
+    for (i = 0; i < Nx; i++, in++) {
+
+      x = i - Xo;
+      y = j - Yo;
+      r = 0.5*x*x/Sx + 0.5*y*y/Sy + x*y*Sxy;
+      f = exp (-r);
+      *in += f;
+    }
+  }
+
+  return (TRUE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/multifit.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/multifit.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/multifit.c	(revision 3338)
@@ -0,0 +1,179 @@
+# include "astro.h"
+
+int multifit (int argc, char **argv) {
+  
+  char *p, name[64];
+  double **a, **b, v;
+  int i, j, I, J, n, valid;
+  Vector **Nc, **Nmb, **NMb, **Nwb, **Nmh, **Nml, **Nwo;
+  int *nterm;
+  int Ndim, Norder, Nx, Ny;
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: multifit (Norder)\n");
+    return (FALSE);
+  }
+
+  Ndim = 0;
+  Norder = atoi (argv[1]);
+  ALLOCATE (nterm, int, Norder);
+  for (i = 0; i < Norder; i++) {
+    sprintf (name, "nterm:%d", i);
+    p = get_variable (name);
+    nterm[i] = atoi (p); 
+    Ndim += nterm[i];
+    free (p);
+  }
+
+  ALLOCATE (a, double *, Ndim);
+  ALLOCATE (b, double *, Ndim);
+  for (i = 0; i < Ndim; i++) {
+    ALLOCATE (a[i], double, Ndim);
+    ALLOCATE (b[i], double, 1);
+    bzero (a[i], Ndim*sizeof(double));
+    bzero (b[i], sizeof(double));
+  }
+ 
+  ALLOCATE (Nc,  Vector *, Norder);
+  ALLOCATE (NMb, Vector *, Norder);
+  ALLOCATE (Nmb, Vector *, Norder);
+  ALLOCATE (Nwb, Vector *, Norder);
+  ALLOCATE (Nmh, Vector *, Norder - 1);
+  ALLOCATE (Nml, Vector *, Norder - 1);
+  ALLOCATE (Nwo, Vector *, Norder - 1);
+  
+  for (i = 0; i < Norder; i++) {
+    sprintf (name, "c%d", i);
+    if ((Nc[i]  = SelectVector (name, ANYVECTOR, TRUE)) == NULL) goto escape;
+    sprintf (name, "Mb%d", i);
+    if ((NMb[i] = SelectVector (name, OLDVECTOR, TRUE)) == NULL) goto escape;
+    sprintf (name, "mb%d", i);
+    if ((Nmb[i] = SelectVector (name, OLDVECTOR, TRUE)) == NULL) goto escape;
+    sprintf (name, "wb%d", i);
+    if ((Nwb[i] = SelectVector (name, OLDVECTOR, TRUE)) == NULL) goto escape;
+  }
+  for (i = 0; i < Norder - 1; i++) {
+    sprintf (name, "ml%d", i);
+    if ((Nml[i] = SelectVector (name, OLDVECTOR, TRUE)) == NULL) goto escape;
+    sprintf (name, "mh%d", i);
+    if ((Nmh[i] = SelectVector (name, OLDVECTOR, TRUE)) == NULL) goto escape;
+    sprintf (name, "wo%d", i);
+    if ((Nwo[i] = SelectVector (name, OLDVECTOR, TRUE)) == NULL) goto escape;
+  }
+
+  Ny = 0;
+  for (i = 0; i < Norder; i++) {
+    for (j = 0; j < nterm[i]; j++, Ny++) {
+      Nx = 0;
+      valid = FALSE;
+      for (I = 0; I < Norder; I++) {
+	if (I == i - 1) { 
+	  for (J = 0; J < nterm[I]; J++) {
+	    v = 0;
+	    for (n = 0; n < Nwo[i-1][0].Nelements; n++) {
+	      v += -pow (Nwo[i-1][0].elements[n], (double)(j+J));
+	    }
+	    a[Ny][Nx] = v;
+	    Nx ++;
+	  }
+	  valid = TRUE;
+	}
+	if (I == i + 1) { 
+	  for (J = 0; J < nterm[I]; J++) {
+	    v = 0;
+	    for (n = 0; n < Nwo[i][0].Nelements; n++) {
+	      v += -pow (Nwo[i][0].elements[n], (double)(j+J));
+	    }
+	    a[Ny][Nx] = v;
+	    Nx ++;
+	  }
+	  valid = TRUE;
+	}
+	if (I == i) { 
+	  for (J = 0; J < nterm[I]; J++) {
+	    v = 0;
+	    for (n = 0; n < Nwb[i][0].Nelements; n++) {
+	      v += pow (Nwb[i][0].elements[n], (double)(j+J));
+	    }
+	    if (i > 0) {
+	      for (n = 0; n < Nwo[i-1][0].Nelements; n++) {
+		v += pow (Nwo[i-1][0].elements[n], (double)(j+J));
+	      }
+	    }
+	    if (i < Norder - 1) {
+	      for (n = 0; n < Nwo[i][0].Nelements; n++) {
+		v += pow (Nwo[i][0].elements[n], (double)(j+J));
+	      }
+	    }
+	    a[Ny][Nx] = v;
+	    Nx ++;
+	  }
+	  valid = TRUE;
+	}
+	if (!valid) {
+	  Nx += nterm[I];
+	}
+      }
+    }
+  }
+
+  Ny = 0;
+  for (i = 0; i < Norder; i++) {
+    for (j = 0; j < nterm[i]; j++, Ny++) {
+      v = 0;
+      for (n = 0; n < Nwb[i][0].Nelements; n++) {
+	v += NMb[i][0].elements[n]*pow (Nwb[i][0].elements[n], (double)j);
+	v -= Nmb[i][0].elements[n]*pow (Nwb[i][0].elements[n], (double)j);
+      }
+      if (i > 0) {
+	for (n = 0; n < Nwo[i-1][0].Nelements; n++) {
+	  v += Nmh[i-1][0].elements[n] * pow (Nwo[i-1][0].elements[n], (double)j);
+	  v -= Nml[i-1][0].elements[n] * pow (Nwo[i-1][0].elements[n], (double)j);
+	}
+      }
+      if (i < Norder - 1) {
+	for (n = 0; n < Nwo[i][0].Nelements; n++) {
+	  v += Nml[i][0].elements[n] * pow (Nwo[i][0].elements[n], (double)j);
+	  v -= Nmh[i][0].elements[n] * pow (Nwo[i][0].elements[n], (double)j);
+	}
+      }
+      b[Ny][0] = v;
+    }
+  }
+  gaussj (a, Ndim, b, 1);
+
+  Ny = 0;
+  for (i = 0; i < Norder; i++) {
+    Nc[i][0].Nelements = nterm[i];
+    REALLOCATE (Nc[i][0].elements, float, nterm[i]);
+    for (j = 0; j < nterm[i]; j++, Ny++) {
+      Nc[i][0].elements[j] = b[Ny][0];
+    }
+  }
+
+  for (i = 0; i < Ndim; i++) {
+    free (a[i]);
+    free (b[i]);
+  }
+  free (a);
+  free (b);
+  free (nterm);
+  free (Nc);
+  free (NMb);
+  free (Nmb);
+  free (Nwb);
+  free (Nmh);
+  free (Nml);
+  free (Nwo);
+  
+  return (TRUE);
+  
+ escape: 
+  fprintf (stderr, "syntax error\n");
+  return (FALSE);
+  
+}
+
+
+
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/objload.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/objload.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/objload.c	(revision 3338)
@@ -0,0 +1,102 @@
+# include "dvo.h"
+# define CHAR_LINE 104
+# define NBLOCK 100
+
+int objload (int argc, char **argv) {
+  
+  int i, nstar, N, Nout, n, Type, type, NSTAR, Nline, status;
+  double *X, *Y;
+  FILE *f;
+  char *buffer, *line;
+  int Ximage, Nimage;
+  
+  Nimage = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nimage = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetImage (&Ximage, &Nimage)) return (FALSE);
+
+  Type = 0;
+  if ((N = get_argument (argc, argv, "-t"))) {
+    remove_argument (N, &argc, argv);
+    Type = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: load (overlay) <filename>\n");
+    return (FALSE);
+  }
+
+  if (!SelectOverlay (argv[1], &n)) return (FALSE);
+
+  f = fopen (argv[2], "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "ERROR: can't find object file %s\n", argv[2]);
+    return (FALSE);
+  }
+
+  /* read average values from first line */
+  ALLOCATE (line, char, 129);
+  scan_line (f, line);
+
+  nstar = 0;
+  NSTAR = 1000;
+  ALLOCATE (X, double, NSTAR);
+  ALLOCATE (Y, double, NSTAR);
+  ALLOCATE (buffer, char, CHAR_LINE*NBLOCK);
+
+  /* read in data from obj file */
+  while ((Nline = fread (buffer, CHAR_LINE, NBLOCK, f)) > 0) {
+    for (i = 0; i < Nline; i++) {
+      /* we are now using all entries on the *.obj line */
+      status = sscanf (&buffer[i*CHAR_LINE], "%d %lf %lf",  &type, &X[nstar], &Y[nstar]);
+      if (Type && (Type != type)) continue;
+      nstar ++;
+      if (nstar == NSTAR) {
+	NSTAR += 1000;
+	REALLOCATE (X, double, NSTAR);
+	REALLOCATE (Y, double, NSTAR);
+      }
+    }
+  }
+  fclose (f);
+  free (buffer);
+
+  write (Ximage, "LOAD", 4); /* force Ximage to look for the incoming image */
+  sprintf (line, "OVER %9d ", n);
+  write (Ximage, line, 16);
+  
+  ALLOCATE (buffer, char, 66000);
+  bzero (buffer, 65536);
+  for (Nout = i = 0; i < nstar; i++, Nout++) {
+    snprintf (&buffer[Nout*128], 129, "%15s %20.10f %20.10f %20.10f %20.10f ", "BOX", X[i], Y[i], 5.0, 5.0);
+    if (Nout == 512) {
+      sprintf (line, "NLINES  %7d ", Nout);
+      write (Ximage, line, 16);
+      write (Ximage, buffer, Nout*128);
+      bzero (buffer, 65536);
+      Nout = -1;
+    }
+  }
+
+  if (Nout) {
+    sprintf (line, "NLINES  %7d ", Nout);
+    write (Ximage, line, 16);
+    write (Ximage, buffer, Nout*128);
+  }
+  sprintf (line, "DONE ");
+  write (Ximage, line, 16);
+
+  free (X);
+  free (Y);
+
+  free (buffer);
+  free (line);
+
+  fprintf (stderr, "loaded %d objects\n", nstar);
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/outline.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/outline.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/outline.c	(revision 3338)
@@ -0,0 +1,303 @@
+# include "astro.h"
+
+float par[5];
+float dpar[5];
+float Dpar[5];
+float outline_chi (float, float *, int, int, float *);
+
+int outline (int argc, char **argv) {
+  
+  int i, j, k, Npar, BigChange, ABigChange;
+  float Io, *in, ochisq, dchi, chisq, chisq_p, chisq_m, dp, tmp_par;
+  float curve, frac;
+  Buffer *buf;
+
+  if (argc != 9) {
+    fprintf (stderr, "USAGE: outline x y dx dy dxy Io (buffer) Npar\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[7], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  par[0] = atof(argv[1]);
+  par[1] = atof(argv[2]);
+  par[2] = atof(argv[3]);
+  par[3] = atof(argv[4]);
+  par[4] = atof(argv[5]);
+  Io = atof(argv[6]);
+  Npar = atof (argv[8]);
+
+  dpar[0] = 10;
+  dpar[1] = 10;
+  dpar[2] = 10;
+  dpar[3] = 10;
+  dpar[4] = 10;
+
+  Dpar[0] = 10;
+  Dpar[1] = 10;
+  Dpar[2] = 10;
+  Dpar[3] = 10;
+  Dpar[4] = 10;
+
+  in = (float *) buf[0].matrix.buffer;
+
+  chisq = outline_chi (Io, in, buf[0].matrix.Naxis[0], buf[0].matrix.Naxis[1], &frac);
+  fprintf (stderr, "chisq (1): %f\n", chisq);
+  
+  for (j = 0; j < 15; j++) {
+
+    /*
+    if (!(j % 3)) {
+      chisq = outline_chi (Io, in, buf[0].matrix.Naxis[0], buf[0].matrix.Naxis[1], &frac);
+      for (k = 0; (k < 3) && (fabs (frac) > 0.3); k++) {
+	tmp1 = par[2];
+	tmp2 = par[3];
+	par[2] *= 1 + 0.1*frac;
+	par[3] *= 1 + 0.1*frac;
+	nchisq = outline_chi (Io, in, buf[0].matrix.Naxis[0], buf[0].matrix.Naxis[1], &frac);
+	if (nchisq > chisq) {
+	  par[2] = tmp1;
+	  par[3] = tmp2;
+	  k = 3;
+	} else {
+	  chisq = nchisq;
+	}
+	fprintf (stderr, "frac: %f  %f %f   %f\n", frac, par[2], par[3], chisq);
+      }
+    }
+    */
+    
+    ABigChange = FALSE;
+    ochisq = chisq;
+    for (i = 4; i >= 0; i--) {
+      /* find +chisq, -chisq for this par & adjust par as needed */
+
+      for (k = 0, BigChange = TRUE; (k < 3) && BigChange; k++) {
+	tmp_par = par[i];
+	par[i] = tmp_par + dpar[i];
+	chisq_p = outline_chi (Io, in, buf[0].matrix.Naxis[0], buf[0].matrix.Naxis[1], &frac);
+	par[i] = tmp_par - dpar[i];
+	chisq_m = outline_chi (Io, in, buf[0].matrix.Naxis[0], buf[0].matrix.Naxis[1], &frac);
+	
+	/* have we braketted a minimum? (curve < 0) */
+	curve = (chisq_p - chisq) * (chisq - chisq_m);
+	if (curve > 0) {
+	  dp = 2*dpar[i];
+	} else {
+	  dp = 0.5 * dpar[i] * (chisq_m - chisq_p) / (chisq_m + chisq_p - 2*chisq);
+	}      
+	if (chisq_m + chisq_p - 2*chisq == 0) dp = 0;
+	/* don't let extrapolation go too far */
+	if (fabs (dp) > 2*fabs(dpar[i])) { dp = SIGN(dp) * fabs (2*dpar[i]); }
+	
+	par[i] = tmp_par + dp;
+	chisq = outline_chi (Io, in, buf[0].matrix.Naxis[0], buf[0].matrix.Naxis[1], &frac);
+	
+	BigChange = FALSE;
+	if (chisq <= 1.001*ochisq) {
+	  /* got better */
+	  dchi = (ochisq - chisq) / ochisq; 
+	  if ((dchi > 0.03) || (curve > 0)) BigChange = TRUE;
+	} else {
+	  par[i] = tmp_par;
+	  chisq = ochisq;
+	  if (chisq_m < chisq) {
+	    chisq = chisq_m;
+	    par[i] = tmp_par - dpar[i];
+	  }	
+	  if (chisq_p < chisq) {
+	    chisq = chisq_p;
+	    par[i] = tmp_par + dpar[i];
+	  }	
+	}	
+	/*
+	fprintf (stderr, "try: %d  %f   ", i, chisq);
+	for (k = 0; k < 5; k++) {
+	  fprintf (stderr, "%f ", par[k]);
+	}
+	fprintf (stderr, "\n");
+	*/
+	ochisq = chisq;
+	ABigChange |= BigChange;
+      }
+      if (!BigChange) dpar[i] *= 0.8;
+    }
+
+    if (ABigChange) {
+      for (i = 0; i < 5; i++) {
+	dpar[i] = Dpar[i];
+      }
+    }
+
+    fprintf (stderr, "try: %d  %f   ", j, chisq);
+    for (i = 0; i < 5; i++) {
+      fprintf (stderr, "%f ", par[i]);
+    }
+    fprintf (stderr, "\n          ");
+    for (i = 0; i < 5; i++) {
+      fprintf (stderr, "%f ", dpar[i]);
+    }
+    fprintf (stderr, "\n");
+    dchi -= chisq;
+
+  }
+
+    /* code to draw dots on Ximage */
+    {
+      char *buffer, *line;
+      int Nline, Nimage, Ximage;
+      float xp, yp, x, y;
+      float dx, dy, theta, t, dt;
+      
+      Nimage = -1;
+      if (!GetImage (&Ximage, &Nimage)) return (FALSE);
+      
+      ALLOCATE (buffer, char, 65536);  /* space for 512 lines of 128 bytes */
+      bzero (buffer, 65536);
+      ALLOCATE (line, char, 1024);     /* space to read the file */
+      Nline = 0;
+      
+      write (Ximage, "LOAD", 4); /* force Ximage to look for the incoming image */
+      sprintf (line, "OVER %9d ", 0);
+      write (Ximage, line, 16);
+      
+      dx = par[2];
+      dy = par[3];
+      dt = 1 / MAX (dx, dy);
+      theta = par[4];
+      
+      for (t = 0; t < 6.3; t += dt) {
+	xp = dx * cos (t);
+	yp = dy * sin (t);
+	
+	x = xp * cos (theta * RAD_DEG) - yp * sin (theta * RAD_DEG) + par[0];
+	y = xp * sin (theta * RAD_DEG) + yp * cos (theta * RAD_DEG) + par[1];
+	
+	sprintf (&buffer[Nline*128], "%15s %20.10f %20.10f %20.10f %20.10f ", "BOX", x, y, 1.0, 1.0);
+	Nline ++;
+	
+	if (Nline >= 510) {
+	  sprintf (line, "NLINES  %7d ", Nline);
+	  write (Ximage, line, 16);
+	  write (Ximage, buffer, Nline*128);
+	  bzero (buffer, 65536);
+	  Nline = 0;
+	}
+      }
+      
+      sprintf (line, "NLINES  %7d ", Nline);
+      write (Ximage, line, 16);
+      write (Ximage, buffer, Nline*128);
+      sprintf (line, "DONE ");
+      write (Ximage, line, 16);
+      free (buffer);
+      free (line);
+      
+    }
+
+  return (TRUE);
+
+}
+
+/* par[0] = x
+   par[1] = y
+   par[2] = dx
+   par[3] = dy
+   par[4] = dxy
+   
+   ellipse is:  
+
+   ((X-x)/dx)^2 + ((Y-y)/dy)^2 + (X-x)(Y-y)dxy = 1
+  
+   (yp/dy)^2 + xp yp dxy + (xp/dx)^2 - 1 = 0
+
+   yp^2 + yp xp dxy dy^2 + xp^2 (dy/dx)^2 - dy^2 = 0
+
+*/
+
+float outline_chi (float Io, float *in, int Nx, int Ny, float *frac) {
+
+  int npts, xo, yo, x, y;
+  float xp, yp, dx, dy, theta;
+  float t, dt, dv, Dv;
+  float chisq, v, Frac;
+
+  /* 
+  if (!SelectVector (&Nvec, "diffs", ANYVECTOR)) return (FALSE);
+  if (!SelectVector (&Nvec2, "angle", ANYVECTOR)) return (FALSE);
+  if (!SelectVector (&Nvecx, "xdif", ANYVECTOR)) return (FALSE);
+  if (!SelectVector (&Nvecy, "ydif", ANYVECTOR)) return (FALSE);
+  */
+
+  dx = par[2];
+  dy = par[3];
+  theta = par[4];
+  dt = 1 / MAX (dx, dy);
+
+  Frac = 0;
+  chisq = 0;
+  npts = 0;
+  xo = -1; yo = -1;  /* an impossible coordinate */
+
+  /*
+  Npts = 1000;
+  REALLOCATE (vectors[Nvec].elements, float, Npts);
+  REALLOCATE (vectors[Nvec2].elements, float, Npts);
+  REALLOCATE (vectors[Nvecx].elements, float, Npts);
+  REALLOCATE (vectors[Nvecy].elements, float, Npts);
+  */
+
+  for (t = 0; t < 6.3; t += dt) {
+    xp = dx * cos (t);
+    yp = dy * sin (t);
+    
+    x = xp * cos (theta * RAD_DEG) - yp * sin (theta * RAD_DEG) + par[0];
+    y = xp * sin (theta * RAD_DEG) + yp * cos (theta * RAD_DEG) + par[1];
+    
+    if ((x == xo) && (y == yo)) continue;
+    xo = x; yo = y;
+
+    if ((x >= 0) && (x < Nx) && (y >= 0) && (y < Ny)) {
+      v = in[y*Nx + x];
+      if (v > 0) {
+	Dv = v - Io;
+	dv = v + 0.2 * fabs (Dv);
+	chisq += Dv * Dv / dv;
+	if (Dv > sqrt(dv)) Frac += 1.0;
+	if (Dv < sqrt(dv)) Frac -= 1.0;
+	/*
+	vectors[Nvec].elements[npts] = Dv;
+	vectors[Nvec2].elements[npts] = t*DEG_RAD;
+	vectors[Nvecx].elements[npts] = x;
+	vectors[Nvecy].elements[npts] = y;
+	*/
+	npts ++;
+	/* 
+	if (npts == Npts - 1) {
+	  Npts += 1000;
+	  REALLOCATE (vectors[Nvec].elements, float, Npts);
+	  REALLOCATE (vectors[Nvec2].elements, float, Npts);
+	  REALLOCATE (vectors[Nvecx].elements, float, Npts);
+	  REALLOCATE (vectors[Nvecy].elements, float, Npts);
+	}
+	*/
+      }
+    }
+  }
+  /* 
+  vectors[Nvec].Nelements = npts;
+  vectors[Nvec2].Nelements = npts;
+  vectors[Nvecx].Nelements = npts;
+  vectors[Nvecy].Nelements = npts;
+  */
+
+  chisq = chisq / npts;
+  *frac = Frac / npts;
+  if (npts == 0) {
+    chisq = 1e8;
+    *frac = -1.0;
+  }
+
+  return (chisq);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/outline2.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/outline2.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/outline2.c	(revision 3338)
@@ -0,0 +1,354 @@
+# include "astro.h"
+
+int Npts;
+float *xs, *ys, *zs;
+float par[5];
+float dpar[5];
+float Dpar[5];
+float outline_chi (float, float *);
+int plot_outline ();
+
+int outline (int argc, char **argv) {
+  
+  int i, j, k, Nx, Ny, NPTS, BigChange;
+  float dIo, Io, ochisq, dchi, chisq, chisq_p, chisq_m, dp;
+  float tmp_par, curve, value;
+  float *in;
+  Buffer *buf;
+
+  if (argc != 9) {
+    fprintf (stderr, "USAGE: outline x y dx dy dxy Io dIo (buffer)\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[8], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  par[0] = atof(argv[1]);
+  par[1] = atof(argv[2]);
+  par[2] = atof(argv[3]);
+  par[3] = atof(argv[4]);
+  par[4] = atof(argv[5]);
+  Io = atof(argv[6]);
+  dIo = atof(argv[7]);
+
+  dpar[0] = 10;
+  dpar[1] = 10;
+  dpar[2] = 10;
+  dpar[3] = 10;
+  dpar[4] = 10;
+
+  Dpar[0] = 10;
+  Dpar[1] = 10;
+  Dpar[2] = 10;
+  Dpar[3] = 10;
+  Dpar[4] = 10;
+
+  in = (float *) buf[0].matrix.buffer;
+
+  /* find all pixels within range Io-dIo : Io+dIo, in region about center guess */
+
+  Nx = buf[0].matrix.Naxis[0];  
+  Ny = buf[0].matrix.Naxis[1];
+  Npts = 0;
+  NPTS = 1000;
+  ALLOCATE (xs, float, NPTS);
+  ALLOCATE (ys, float, NPTS);
+  ALLOCATE (zs, float, NPTS);
+  for (j = par[1]-2*par[3]; j < par[1]+2*par[3]; j++) {
+    if (j < 0) continue;
+    if (j >= buf[0].matrix.Naxis[1]) continue;
+    for (i = par[0]-2*par[2]; i < par[0]+2*par[2]; i++) {
+      if (i < 0) continue;
+      if (i >= buf[0].matrix.Naxis[0]) continue;
+      value = in[i + Nx*j];
+      if (fabs (value - Io) < dIo) {
+	xs[Npts] = i;
+	ys[Npts] = j;
+	zs[Npts] = value;
+	Npts ++;
+	if (Npts == NPTS) {
+	  NPTS += 1000;
+	  REALLOCATE (xs, float, NPTS);
+	  REALLOCATE (ys, float, NPTS);
+	  REALLOCATE (zs, float, NPTS);
+	}
+      }
+    }
+  }
+
+  if (Npts == 0) {
+    fprintf (stderr, "no valid points in box, try again\n");
+    free (xs);
+    free (ys);
+    free (zs);
+    return (FALSE);
+  }
+
+  plot_outline ();
+  chisq = outline_chi (Io, in);
+  fprintf (stderr, "starting chisq: %f for %d pts\n", chisq, Npts);
+
+# if (1)
+  for (j = 0; j < 15; j++) {
+    
+    ochisq = chisq;
+    for (i = 0; i < 5; i++) {
+      /* find +chisq, -chisq for this par & adjust par as needed */
+
+      for (k = 0, BigChange = TRUE; (k < 3) && BigChange; k++) {
+	tmp_par = par[i];
+	par[i] = tmp_par + dpar[i];
+	chisq_p = outline_chi (Io, in);
+	par[i] = tmp_par - dpar[i];
+	chisq_m = outline_chi (Io, in);
+	
+	/* have we braketted a minimum? (curve < 0) */
+	curve = (chisq_p - chisq) * (chisq - chisq_m);
+	if (curve > 0) {
+	  dp = 2*dpar[i];
+	} else {
+	  dp = 0.5 * dpar[i] * (chisq_m - chisq_p) / (chisq_m + chisq_p - 2*chisq);
+	}      
+	if (chisq_m + chisq_p - 2*chisq == 0) dp = 0;
+	/* don't let extrapolation go too far */
+	if (fabs (dp) > 2*fabs(dpar[i])) { dp = SIGN(dp) * fabs (2*dpar[i]); }
+	
+	par[i] = tmp_par + dp;
+	chisq = outline_chi (Io, in);
+	
+	BigChange = FALSE;
+	if (chisq <= 1.001*ochisq) {
+	  /* got better */
+	  dchi = (ochisq - chisq) / ochisq; 
+	  if ((dchi > 0.03) || (curve > 0)) BigChange = TRUE;
+	} else {
+	  par[i] = tmp_par;
+	  chisq = ochisq;
+	  if (chisq_m < chisq) {
+	    chisq = chisq_m;
+	    par[i] = tmp_par - dpar[i];
+	  }	
+	  if (chisq_p < chisq) {
+	    chisq = chisq_p;
+	    par[i] = tmp_par + dpar[i];
+	  }	
+	}	
+	ochisq = chisq;
+      }
+      if (!BigChange) dpar[i] *= 0.8;
+    }
+
+    fprintf (stderr, "try: %d  %f   ", j, chisq);
+    for (i = 0; i < 5; i++) {
+      fprintf (stderr, "%f ", par[i]);
+    }
+    fprintf (stderr, "\n          ");
+    for (i = 0; i < 5; i++) {
+      fprintf (stderr, "%f ", dpar[i]);
+    }
+    fprintf (stderr, "\n");
+    dchi -= chisq;
+
+  }
+# endif
+
+  free (xs);
+  free (ys);
+  free (zs);
+  
+  plot_outline ();
+  return (TRUE);
+
+}
+
+/* par[0] = x
+   par[1] = y
+   par[2] = dx
+   par[3] = dy
+   par[4] = dxy
+   
+    xp = par[2] * cos (t);
+    yp = par[3] * sin (t);
+    
+    x = xp * cos (par[4] * RAD_DEG) - yp * sin (par[4] * RAD_DEG) + par[0];
+    y = xp * sin (par[4] * RAD_DEG) + yp * cos (par[4] * RAD_DEG) + par[1];
+
+*/
+
+# if (1)
+
+float outline_chi (float Io, float *in) {
+
+  int i;
+  float theta, phi;
+  float xp, yp, x, y;
+  float chisq, R2;
+
+  chisq = 0;
+
+  for (i = 0; i < Npts; i++) {
+    
+    phi = atan2 (ys[i] - par[1], xs[i] - par[0]) - RAD_DEG * par[4];
+    /* find a point:
+
+       xp, yp such that atan (r2 sin(phi), r1 cos(phi)) == theta 
+
+       tan (theta) = r2 sin(phi) / r1 cos (phi)
+
+       (r1/r2) tan(theta) = sin(phi) / cos (phi);
+       (r1/r2) tan(theta) = tan (phi)
+
+       phi = atan2 (r1 sin(theta), r2 cos(theta))
+    */
+
+    theta = atan2 (par[2]*sin(phi), par[3]*cos(phi));
+
+    /* this is the point on the ellipse at the same angle as ref point */
+    /* this is wrong, but close -- tends to make ellipses too fat */
+    xp = par[2] * cos (theta);
+    yp = par[3] * sin (theta);
+    
+    x = xp * cos (par[4] * RAD_DEG) - yp * sin (par[4] * RAD_DEG) + par[0];
+    y = xp * sin (par[4] * RAD_DEG) + yp * cos (par[4] * RAD_DEG) + par[1];
+
+    R2 = sqrt (SQ (x - xs[i]) + SQ (y - ys[i]));
+
+    /*
+    Dv = zs[i] - Io;
+    dv = fabs(zs[i]);
+    F2 = Dv * Dv / dv;
+    */
+
+    chisq += R2;
+
+  }
+
+  chisq = chisq / Npts;
+  return (chisq);
+
+}
+
+# else 
+
+float outline_chi (float Io, float *in) {
+
+  int i;
+  float theta, theta1, theta2;
+  float xp, yp, x, y;
+  float chisq, dv, Dv, R2, F2, R, dR;
+
+  int Nvec, Nvec2, Nvecx, Nvecy, Nv, nv;
+
+  chisq = 0;
+
+  nv = 0;
+  Nv = 1000;
+  if (!SelectVector (&Nvec, "dR", ANYVECTOR)) return (FALSE);
+  if (!SelectVector (&Nvec2, "dF", ANYVECTOR)) return (FALSE);
+  if (!SelectVector (&Nvecx, "x", ANYVECTOR)) return (FALSE);
+  if (!SelectVector (&Nvecy, "y", ANYVECTOR)) return (FALSE);
+  REALLOCATE (vectors[Nvec].elements, float, Nv);
+  REALLOCATE (vectors[Nvec2].elements, float, Nv);
+  REALLOCATE (vectors[Nvecx].elements, float, Nv);
+  REALLOCATE (vectors[Nvecy].elements, float, Nv);
+
+  for (i = 0; i < Npts; i++) {
+    
+    theta1 = atan2 (ys[i] - par[1], xs[i] - par[0]) - RAD_DEG * par[4];
+    theta = atan2 (par[2]*sin(theta1), par[3]*cos(theta1));
+
+    xp = par[2] * cos (theta);
+    yp = par[3] * sin (theta);
+    
+    x = xp * cos (par[4] * RAD_DEG) - yp * sin (par[4] * RAD_DEG) + par[0];
+    y = xp * sin (par[4] * RAD_DEG) + yp * cos (par[4] * RAD_DEG) + par[1];
+
+    R2 = SQ (x - xs[i]) + SQ (y - ys[i]);
+
+    /* 
+    Dv = fabs (zs[i] - Io) + 1;
+    dv = zs[i] + 0.2 * fabs (Dv);
+    F2 = Dv * Dv / dv;
+    */
+
+    vectors[Nvec].elements[nv] = x;
+    vectors[Nvec2].elements[nv] = y;
+    vectors[Nvecx].elements[nv] = xs[i];
+    vectors[Nvecy].elements[nv] = ys[i];
+    nv ++;
+    if (nv == Nv - 1) {
+      Nv += 1000;
+      REALLOCATE (vectors[Nvec].elements, float, Nv);
+      REALLOCATE (vectors[Nvec2].elements, float, Nv);
+      REALLOCATE (vectors[Nvecx].elements, float, Nv);
+      REALLOCATE (vectors[Nvecy].elements, float, Nv);
+    }
+
+    /* typical distance might be 1 - 10 pix,
+       typical z error might be 100 cts */
+    chisq += R2; 
+
+  }
+  vectors[Nvec].Nelements = nv;
+  vectors[Nvec2].Nelements = nv;
+  vectors[Nvecx].Nelements = nv;
+  vectors[Nvecy].Nelements = nv;
+
+  chisq = chisq / Npts;
+  return (chisq);
+
+}
+# endif
+
+int plot_outline () {
+  
+  char *buffer, *line;
+  int Nline, Nimage, Ximage;
+  float xp, yp, x, y;
+  float dx, dy, theta, t, dt;
+  
+  Nimage = -1;
+  if (!GetImage (&Ximage, &Nimage)) return (FALSE);
+  
+  ALLOCATE (buffer, char, 65536);  /* space for 512 lines of 128 bytes */
+  bzero (buffer, 65536);
+  ALLOCATE (line, char, 1024);     /* space to read the file */
+  Nline = 0;
+  
+  write (Ximage, "LOAD", 4); /* force Ximage to look for the incoming image */
+  sprintf (line, "OVER %9d ", 0);
+  write (Ximage, line, 16);
+  
+  dx = par[2];
+  dy = par[3];
+  dt = 1 / MAX (dx, dy);
+  theta = par[4];
+  
+  for (t = 0; t < 6.3; t += dt) {
+    xp = dx * cos (t);
+    yp = dy * sin (t);
+    
+    x = xp * cos (theta * RAD_DEG) - yp * sin (theta * RAD_DEG) + par[0];
+    y = xp * sin (theta * RAD_DEG) + yp * cos (theta * RAD_DEG) + par[1];
+    
+    sprintf (&buffer[Nline*128], "%15s %20.10f %20.10f %20.10f %20.10f ", "BOX", x, y, 1.0, 1.0);
+    Nline ++;
+    
+    if (Nline >= 510) {
+      sprintf (line, "NLINES  %7d ", Nline);
+      write (Ximage, line, 16);
+      write (Ximage, buffer, Nline*128);
+      bzero (buffer, 65536);
+      Nline = 0;
+    }
+  }
+  
+  sprintf (line, "NLINES  %7d ", Nline);
+  write (Ximage, line, 16);
+  write (Ximage, buffer, Nline*128);
+  sprintf (line, "DONE ");
+  write (Ximage, line, 16);
+  free (buffer);
+  free (line);
+  return (TRUE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/polar.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/polar.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/polar.c	(revision 3338)
@@ -0,0 +1,71 @@
+# include "astro.h"
+
+int polar (int argc, char **argv) {
+  
+  double Lo, dL, Do, dD, Mo, dM, No, dN;
+  double xo, yo, Xo, Yo;
+  double x, y, r, t;
+  float *Vin, *Vout, *Vmask;
+  int i, j, nx, ny, Nx, Ny;
+  int X, Y;
+  Buffer *in, *out, *mask;
+
+  if (argc != 4) {
+    fprintf (stderr, "USAGE: polar in out\n");
+    return (FALSE);
+  }
+
+  if ((in   = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((out  = SelectBuffer (argv[2], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((mask = SelectBuffer (argv[3], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  Nx = out[0].matrix.Naxis[0];
+  Ny = out[0].matrix.Naxis[1];
+  nx = mask[0].matrix.Naxis[0];
+  ny = mask[0].matrix.Naxis[1];
+  if ((Nx != nx) && (Ny != ny)) {
+    fprintf (stderr, "output and mask must have same dimensions\n");
+    return (FALSE);
+  }
+  nx = in[0].matrix.Naxis[0];
+  ny = in[0].matrix.Naxis[1];
+
+  /* we expect the output image to have units of longitude and distance */
+  fits_scan (&in[0].header, "CRVAL1", "%lf", 1, &Lo);
+  fits_scan (&in[0].header, "CDELT1", "%lf", 1, &dL);
+  fits_scan (&in[0].header, "CRPIX1", "%lf", 1, &xo);
+  fits_scan (&in[0].header, "CRVAL2", "%lf", 1, &Do);
+  fits_scan (&in[0].header, "CDELT2", "%lf", 1, &dD);
+  fits_scan (&in[0].header, "CRPIX2", "%lf", 1, &yo);
+
+  /* we expect the input image to have units of distance X and Y */
+  fits_scan (&out[0].header, "CRVAL1", "%lf", 1, &Mo);
+  fits_scan (&out[0].header, "CDELT1", "%lf", 1, &dM);
+  fits_scan (&out[0].header, "CRPIX1", "%lf", 1, &Xo);
+  fits_scan (&out[0].header, "CRVAL2", "%lf", 1, &No);
+  fits_scan (&out[0].header, "CDELT2", "%lf", 1, &dN);
+  fits_scan (&out[0].header, "CRPIX2", "%lf", 1, &Yo);
+
+  Vin  = (float *)in[0].matrix.buffer;
+  Vout = (float *)out[0].matrix.buffer;
+  Vmask = (float *)mask[0].matrix.buffer;
+  for (j = 0; j < Ny; j++) {
+    for (i = 0; i < Nx; i++, Vout++, Vmask++) {
+      x = (i - Xo) * dM + Mo;
+      y = (j - Yo) * dN + No;
+      r = hypot(x, y);
+      t = DEG_RAD*atan2 (y, x);
+      while (t < 360.0) {t += 360.0;}
+      while (t > 360.0) {t -= 360.0;}
+      X = (t - Lo) / dL + xo;
+      Y = (r - Do) / dD + yo;
+      if ((X >= 0) && (X < nx) && (Y >= 0) && (Y < ny)) {
+	*Vout += Vin[Y*nx + X];
+	*Vmask += 1;
+      }
+    }
+  }
+
+ return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/precess.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/precess.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/precess.c	(revision 3338)
@@ -0,0 +1,112 @@
+# include "astro.h"
+
+int precess (int argc, char **argv) {
+
+  int i, Julian, Besselian;
+  double T, in_epoch, out_epoch;
+  double A, D, RA, DEC, zeta, z, theta;
+  double SA, CA, SD, CD;
+  Vector *xvec, *yvec;
+
+  Besselian = Julian = 0;
+  Besselian = get_argument (argc, argv, "B");
+  Julian    = get_argument (argc, argv, "J");
+
+  in_epoch = out_epoch = 2000.0;
+  if (argc != 5) {
+    fprintf (stderr, "USAGE:  precess (from) (to) RA DEC \n");
+    fprintf (stderr, "   you may use B for B1950.0 or J for J2000.0\n");
+    return (FALSE);
+  }
+
+  if (!Julian && !Besselian) { /* assume Julian! */
+    in_epoch  = get_epoch (argv[1], 'J');
+    out_epoch = get_epoch (argv[2], 'J');
+  }
+
+  if ((Julian == 1) && !Besselian) {
+    in_epoch  = 2000.0;
+    out_epoch = get_epoch(argv[2], 'J');
+  }
+
+  if ((Julian == 2) && !Besselian) {
+    in_epoch  = get_epoch(argv[1], 'J');
+    out_epoch = 2000.0;
+  }
+
+  if ((Besselian == 1) && !Julian) {
+    in_epoch  = BtoJ(1950.0); 
+    out_epoch = get_epoch(argv[2], 'B'); 
+  }
+
+  if ((Besselian == 2) && !Julian) {
+    in_epoch  = get_epoch(argv[1], 'B'); 
+    out_epoch = BtoJ(1950.0); 
+  }
+  
+  if (Julian && Besselian) {
+    if (Julian > Besselian) {
+      in_epoch  = BtoJ(1950.0); 
+      out_epoch = 2000.0;
+    }
+    else {
+      in_epoch  = 2000.0;
+      out_epoch = BtoJ(1950.0); 
+    }
+  }
+
+  fprintf (stderr, "converting from J%f to J%f\n", in_epoch, out_epoch);
+
+  T = (out_epoch - in_epoch) / 100.0;
+  
+  zeta  = RAD_DEG*(0.6406161*T + 0.0000839*T*T + 0.0000050*T*T*T);
+  theta = RAD_DEG*(0.5567530*T - 0.0001185*T*T - 0.0000116*T*T*T);
+  z     =          0.6406161*T + 0.0003041*T*T + 0.0000051*T*T*T;
+
+  if (ISNUM(argv[3][0]) && ISNUM(argv[4][0])) {
+    A = atof (argv[3]);
+    D = atof (argv[4]);
+    SD =  cos(RAD_DEG*A + zeta)*sin(theta)*cos(RAD_DEG*D) + cos(theta)*sin(RAD_DEG*D);
+    CD = sqrt (1 - SD*SD);
+    SA =  sin(RAD_DEG*A + zeta)*cos(RAD_DEG*D)/CD;
+    CA = (cos(RAD_DEG*A + zeta)*cos(theta)*cos(RAD_DEG*D) - sin(theta)*sin(RAD_DEG*D))/CD;
+
+    DEC = DEG_RAD*asin(SD);
+    RA  = DEG_RAD*atan2(SA, CA) + z;
+
+    if (RA < 0)
+      RA += 360;
+    fprintf (GetOutfile(), "%f %f -> %f %f\n", A, D, RA, DEC);
+    return (TRUE);
+  }    
+
+  /* find vectors */
+  if ((xvec = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yvec = SelectVector (argv[4], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+
+  if (xvec[0].Nelements != yvec[0].Nelements) {
+    fprintf (stderr, "vectors %s and %s not the same length\n", argv[3], argv[4]);
+    return (FALSE);
+  }
+  
+  for (i = 0; i < xvec[0].Nelements; i++) {
+    A = xvec[0].elements[i];
+    D = yvec[0].elements[i];
+    SD =  cos(RAD_DEG*A + zeta)*sin(theta)*cos(RAD_DEG*D) + cos(theta)*sin(RAD_DEG*D);
+    CD = sqrt (1 - SD*SD);
+    SA =  sin(RAD_DEG*A + zeta)*cos(RAD_DEG*D)/CD;
+    CA = (cos(RAD_DEG*A + zeta)*cos(theta)*cos(RAD_DEG*D) - sin(theta)*sin(RAD_DEG*D))/CD;
+
+    DEC = DEG_RAD*asin(SD);
+    RA  = DEG_RAD*atan2(SA, CA) + z;
+
+    if (RA < 0)
+      RA += 360;
+    
+    xvec[0].elements[i] = RA;
+    yvec[0].elements[i] = DEC; 
+  }
+
+  return (TRUE);
+
+}  
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/profile.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/profile.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/profile.c	(revision 3338)
@@ -0,0 +1,52 @@
+# include "astro.h"
+
+int profile (int argc, char **argv) {
+  
+  int i, j, N, Nx, Npt;
+  float *V;
+  double sx, sy;
+  Vector *xvec, *yvec;
+  Buffer *buf;
+
+  if (argc != 7) {
+    fprintf (stderr, "USAGE: profile <buffer> <X vector> <Y vector> x y N\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  
+  sx = atof (argv[4]);
+  sy = atof (argv[5]);
+  N  = atof (argv[6]);
+
+  if (sx - N < 0) goto range_error;
+  if (sy - N < 0) goto range_error;
+  if (sx + N > buf[0].matrix.Naxis[0]) goto range_error;
+  if (sy + N > buf[0].matrix.Naxis[1]) goto range_error;
+
+  if ((xvec = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yvec = SelectVector (argv[3], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  xvec[0].Nelements = yvec[0].Nelements = (int)SQ(2*N+1);
+  REALLOCATE (xvec[0].elements, float, 5*(int)SQ(2*N+1));
+  REALLOCATE (yvec[0].elements, float, 5*(int)SQ(2*N+1));
+  bzero (yvec[0].elements, (int)SQ(2*N+1)*sizeof(float)+1);
+  V = (float *)(buf[0].matrix.buffer); 
+  Npt = 0;
+  Nx = buf[0].matrix.Naxis[0];
+  for (i = sx - N; i < sx + N; i++) {
+    for (j = sy - N; j < sy + N; j++, Npt++) {
+      yvec[0].elements[Npt] = V[i + j*Nx];
+      xvec[0].elements[Npt] = hypot (i - sx, j - sy);
+    }
+  }
+
+  fsortpair (xvec[0].elements, yvec[0].elements, xvec[0].Nelements);
+
+  return (TRUE);
+
+range_error:
+  fprintf (stderr, "region out of range\n");
+  return (FALSE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/region.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/region.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/region.c	(revision 3338)
@@ -0,0 +1,119 @@
+# include "astro.h"
+
+int region (int argc, char **argv) {
+  
+  char buffer[65], buffer2[35], string[256];
+  double Ra, Dec, Radius;
+  double dx, dy;
+  int status, N;
+  Graphdata graphmode;
+  int Ngraph, Xgraph;
+
+  Ngraph = 0;
+  if (!GetGraph (&graphmode, &Xgraph, &Ngraph)) return (FALSE);
+
+  if ((N = get_argument (argc, argv, "-ew"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.flipeast = TRUE;
+  }
+
+  if ((N = get_argument (argc, argv, "+ew"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.flipeast = FALSE;
+  }
+
+  if ((N = get_argument (argc, argv, "-ns"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.flipnorth = TRUE;
+  }
+
+  if ((N = get_argument (argc, argv, "+ns"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.flipnorth = FALSE;
+  }
+
+  if ((argc != 4) && (argc != 5)) {
+    fprintf (stderr, "USAGE: region Ra Dec Radius [projection] [orientation]\n");
+    fprintf (stderr, " current: %f %f (%f x %f) (%s)\n", 
+	     graphmode.coords.crval1, graphmode.coords.crval2, 
+	     fabs(graphmode.xmax - graphmode.xmin), 
+	     fabs(graphmode.ymax - graphmode.ymin), 
+	     &graphmode.coords.ctype[5]);
+    return (FALSE);
+  }
+  
+  if (!str_to_radec (&Ra, &Dec, argv[1], argv[2])) return (FALSE);
+  Radius = atof (argv[3]);
+  strcpy (graphmode.coords.ctype, "RA---TAN");
+  if (argc == 5) {
+    if (!strcasecmp (argv[4], "SIN")) 
+      strcpy (graphmode.coords.ctype, "RA---SIN");
+    if (!strcasecmp (argv[4], "ZEA"))
+      strcpy (graphmode.coords.ctype, "RA---ZEA");
+    if (!strcasecmp (argv[4], "AIT")) 
+      strcpy (graphmode.coords.ctype, "RA---AIT");
+    if (!strcasecmp (argv[4], "GLS")) 
+      strcpy (graphmode.coords.ctype, "RA---GLS");
+    if (!strcasecmp (argv[4], "PAR")) 
+      strcpy (graphmode.coords.ctype, "RA---PAR");
+  }
+
+  
+  /* ask kapa for coordinate limits, so get the right aspect ratio */
+  status = write (Xgraph, "LIMS", 4); 
+  read (Xgraph, buffer, 30); 
+  sscanf (buffer, "%*s %lf %lf", &dx, &dy); 
+  dx = fabs (dx);
+  dy = fabs (dy); 
+
+  /* define limits for Ra, Dec at center, grid in degrees */
+  if (dy < dx) {
+    graphmode.xmin = -(dx/dy)*Radius;
+    graphmode.ymin = -Radius;
+    graphmode.xmax = (dx/dy)*Radius;
+    graphmode.ymax = Radius;
+  } else {
+    graphmode.xmin = -Radius;
+    graphmode.ymin = -(dy/dx)*Radius;
+    graphmode.xmax = Radius;
+    graphmode.ymax = (dy/dx)*Radius;
+  } 
+
+  set_variable ("XMIN", graphmode.xmin);
+  set_variable ("XMAX", graphmode.xmax);
+  set_variable ("YMIN", graphmode.ymin);
+  set_variable ("YMAX", graphmode.ymax);
+
+  set_variable ("RMIN", Ra  + graphmode.xmin);
+  set_variable ("RMAX", Ra  + graphmode.xmax);
+  set_variable ("DMIN", Dec + graphmode.ymin);
+  set_variable ("DMAX", Dec + graphmode.ymax);
+
+  graphmode.coords.pc1_1 = (graphmode.flipeast) ? -1 : 1;
+  graphmode.coords.pc2_2 = (graphmode.flipnorth) ? -1 : 1;
+
+  graphmode.coords.pc1_2 = graphmode.coords.pc2_1 = 0.0;
+  graphmode.coords.crval1 = Ra;
+  graphmode.coords.crval2 = Dec;
+  graphmode.coords.crpix1 = 0.0;
+  graphmode.coords.crpix2 = 0.0;
+  graphmode.coords.cdelt1 = graphmode.coords.cdelt2 = 1.0;
+
+  write (Xgraph, "ERAS", 4);
+    
+  write (Xgraph, "SLIM", 4);
+  sprintf (buffer, "%f %f %f %f ", graphmode.xmin, graphmode.xmax, graphmode.ymin, graphmode.ymax);
+  sprintf (buffer2, "NBYTES: %6d ", strlen (buffer));
+  write (Xgraph, buffer2, 16);
+  write (Xgraph, buffer, strlen (buffer));
+
+  sprintf (string, "%8.4f %8.4f (%f)", Ra, Dec, Radius);
+  SendLabel (string, Xgraph, 2);
+
+  SetGraph (graphmode);
+
+  return (TRUE);
+
+}
+
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/rotcurve.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/rotcurve.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/rotcurve.c	(revision 3338)
@@ -0,0 +1,120 @@
+# include "astro.h"
+
+int rotcurve (int argc, char **argv) {
+  
+  int i, j, X, Y, n, Ncurve;
+  float *Vin, *Vout, *Vmask;
+  int nx, ny, Nx, Ny, N;
+  double L, dL, Lo, V, Vo, dV, Bo, dB, Do, dD;
+  double xo, yo, Xo, Yo;
+  double sl, cl, wo, Ro, Rs, wr, r, fr, d, min;
+  double R[100], T[100], W[100];
+  FILE *f;
+  Buffer *in, *out, *mask;
+
+  min = -1000;
+  if ((N = get_argument (argc, argv, "-min"))) {
+    remove_argument (N, &argc, argv);
+    min = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 5) {
+    fprintf (stderr, "USAGE: rotcurve in out mask curve.txt\n");
+    return (FALSE);
+  }
+
+  f = fopen (argv[4], "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "can't find rotation curve data file %s\n", argv[4]);
+    return (FALSE);
+  }
+  for (i = 0; fscanf (f, "%lf %lf", &R[i], &T[i]) != EOF; i++) {
+    W[i] = T[i] / R[i];
+  }  
+  fclose (f);
+  Ncurve = i;
+
+  if ((in   = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((out  = SelectBuffer (argv[2], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((mask = SelectBuffer (argv[3], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  Nx = out[0].matrix.Naxis[0];
+  Ny = out[0].matrix.Naxis[1];
+  nx = mask[0].matrix.Naxis[0];
+  ny = mask[0].matrix.Naxis[1];
+  if ((Nx != nx) && (Ny != ny)) {
+    fprintf (stderr, "output and mask must have same dimensions\n");
+    return (FALSE);
+  }
+  nx = in[0].matrix.Naxis[0];
+  ny = in[0].matrix.Naxis[1];
+
+  /* we expect the input image to have units of velocity, lattitude, and longitude */
+  fits_scan (&in[0].header, "CRVAL1", "%lf", 1, &Vo);
+  fits_scan (&in[0].header, "CDELT1", "%lf", 1, &dV);
+  fits_scan (&in[0].header, "CRPIX1", "%lf", 1, &xo);
+  fits_scan (&in[0].header, "CRVAL2", "%lf", 1, &Bo);
+  fits_scan (&in[0].header, "CDELT2", "%lf", 1, &dB);
+  fits_scan (&in[0].header, "CRPIX2", "%lf", 1, &yo);
+  fits_scan (&in[0].header, "CRVAL3", "%lf", 1, &L);
+  Vo *= 0.001;
+  dV *= 0.001;
+
+  /* we expect the output image to have units of longitude and distance */
+  fits_scan (&out[0].header, "CRVAL1", "%lf", 1, &Lo);
+  fits_scan (&out[0].header, "CDELT1", "%lf", 1, &dL);
+  fits_scan (&out[0].header, "CRPIX1", "%lf", 1, &Xo);
+  fits_scan (&out[0].header, "CRVAL2", "%lf", 1, &Do);
+  fits_scan (&out[0].header, "CDELT2", "%lf", 1, &dD);
+  fits_scan (&out[0].header, "CRPIX2", "%lf", 1, &Yo);
+
+  while (L >= 360) {L -= 360.0;}
+  while (L < 0.0)  {L += 360.0;}
+  X = (L - Lo) / dL + Xo;
+  if ((X >= Nx) || (X < 0)) {
+    fprintf (stderr, "X out of range\n");
+    return (FALSE);
+  }
+  fprintf (stderr, "L: %f (%d)\n", L, X);
+
+  cl = cos (L*RAD_DEG);
+  sl = sin (L*RAD_DEG);
+  wo = 25.0;
+  Ro = 10.0;
+  Rs = Ro*sl;
+  /* this method depends on wr monotonically decreasing */
+
+  Vin  = (float *)in[0].matrix.buffer;
+  Vout = (float *)out[0].matrix.buffer;
+  Vmask = (float *)mask[0].matrix.buffer;
+  for (j = 0; j < ny; j++) {
+    for (i = 0; i < nx; i++, Vin++) {
+      if (*Vin <= min) continue;
+      V = (i - xo) * dV + Vo;
+      wr = V/Rs + wo;
+      for (n = 0; (n < Ncurve) && (wr < W[n]); n++);
+      if ((n == 0) || (n == Ncurve)) {
+	continue;
+      }
+      r = (wr - W[n]) *  (R[n-1] - R[n]) / (W[n-1] - W[n]) + R[n];
+      fr = (Ro/r);
+      if (r < fabs(Rs)) { /* can't be on rotation curve */
+	continue;
+      }
+      if (r < Ro)
+	d = Ro*cl - sqrt(r*r - Rs*Rs);
+      else 
+	d = Ro*cl + sqrt(r*r - Rs*Rs);
+      Y = (d - Do) / dD + Yo;
+      if ((Y < Ny) && (Y >= 0)) {
+	Vout[Y*Nx + X] += *Vin;
+	Vmask[Y*Nx + X] += 1.0;
+      }
+    }
+  }
+
+
+  return (TRUE);
+
+} 
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/scale.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/scale.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/scale.c	(revision 3338)
@@ -0,0 +1,43 @@
+# include "astro.h"
+
+int scale (int argc, char **argv) {
+
+  Buffer *buf;
+
+  if (argc != 5) {
+    fprintf (stderr, "USAGE: scale (buffer) (key) [-r/-w] (value)\n");
+    return (FALSE);
+  }  
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  if (strcasecmp (argv[2], "bzero") && strcasecmp (argv[2], "bscale")) {
+    fprintf (stderr, "use bzero or bscale only\n");
+    return (FALSE);
+  }
+    
+  if (strcmp (argv[3], "-r") && strcmp (argv[3], "-w")) {
+    fprintf (stderr, "use -r or -w only\n");
+    return (FALSE);
+  }
+    
+  if (!strcmp (argv[3], "-r")) {
+    if (!strcasecmp (argv[2], "bzero")) {
+      set_variable (argv[4], (double) buf[0].bzero);
+    } else {
+      set_variable (argv[4], (double) buf[0].bscale);
+    }      
+  } else {
+    if (!strcasecmp (argv[2], "bzero")) {
+      buf[0].bzero = atof (argv[4]);
+    } else {
+      buf[0].bscale = atof (argv[4]);
+    }      
+  }
+
+  return (TRUE);
+}
+
+/* get or set external bzero / bscale values 
+   (these keywords are set to 0,1 internally, 
+   so we can't just manipulate them like other keywords */
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/sexigesimal.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/sexigesimal.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/sexigesimal.c	(revision 3338)
@@ -0,0 +1,49 @@
+# include "astro.h"
+
+int sexigesimal (int argc, char **argv) {
+  
+  int HMS, N;
+  double value;
+  char string[80];
+
+  HMS = TRUE;
+  if ((N = get_argument (argc, argv, "-hms"))) {
+    HMS = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-hh"))) {
+    HMS = FALSE;
+    remove_argument (N, &argc, argv);
+  }
+
+  if ((argc != 3) && (argc != 2)) {
+    fprintf (stderr, "USAGE: sexigesimal (from) [to]\n");
+    return (FALSE);
+  }
+
+  if (HMS) {
+    if (!dms_to_ddd (&value, argv[1])) {
+      fprintf (stderr, "syntax error in input\n");
+      return (FALSE);
+    }
+    if (argc == 3) {
+      set_variable (argv[2], value);
+    } else {
+      fprintf (GetOutfile(), "%10.6f\n", value);
+    }
+    return (TRUE);
+  } else {
+    value = atof (argv[1]);
+    hms_format (string, value);
+    if (argc == 3) {
+      set_str_variable (argv[2], string);
+    } else {
+      fprintf (GetOutfile(), "%s\n", string);
+    }
+    return (TRUE);
+  }      
+
+  return (TRUE);
+
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/spec.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/spec.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/spec.c	(revision 3338)
@@ -0,0 +1,112 @@
+# include "astro.h"
+
+int spec (int argc, char **argv) {
+
+  int i, j, Xo, X1, y1, y2, Nx, Ny;
+  int Nlong, Ngap, Nrow, N, Nring;
+  float *buffer, *V;
+  double sky, sky2, S, SX, F, R, Npts;
+  Vector *xvec, *yvec;
+  Buffer *buf;
+
+  Nlong = 31;
+  if ((N = get_argument (argc, argv, "-Nlong"))) {
+    remove_argument (N, &argc, argv);
+    Nlong  = 0.5*atof(argv[N]);
+    Nlong = 2*Nlong + 1;  /* force an odd number */
+    remove_argument (N, &argc, argv);
+  }
+  
+  Ngap = 15;
+  if ((N = get_argument (argc, argv, "-Ngap"))) {
+    remove_argument (N, &argc, argv);
+    Ngap  = 0.5*atof(argv[N]);
+    Ngap = 2*Ngap + 1;  /* force an odd number */
+    remove_argument (N, &argc, argv);
+  }
+  
+  Nrow = 1;
+  if ((N = get_argument (argc, argv, "-Nrow"))) {
+    remove_argument (N, &argc, argv);
+    Nrow  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  
+  if (argc != 7) {
+    fprintf (stderr, "USAGE: spec buffer x y1 y2 X Y [-Nlong N] [-Ngap N] [-Nrow N]\n");
+    return (FALSE);
+  }
+  
+  if ((Nrow < 1) || (Nlong < 2) || (Ngap < 1) || (Nlong - Ngap < 2)) {
+    fprintf (stderr, "bad values for options\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  Nx = buf[0].matrix.Naxis[0];
+  Ny = buf[0].matrix.Naxis[1];
+
+  Xo = atof (argv[2]);
+  y1 = atof (argv[3]);
+  y2 = atof (argv[4]);
+
+  if ((xvec = SelectVector (argv[5], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yvec = SelectVector (argv[6], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  N = y2 - y1;
+  REALLOCATE (xvec[0].elements, float, N);
+  REALLOCATE (yvec[0].elements, float, N);
+  xvec[0].Nelements = N;
+  yvec[0].Nelements = N;
+  
+  ALLOCATE (buffer, float, Nlong);
+
+  for (j = 0; j < y2 - y1; j++) {
+    V = (float *) (buf[0].matrix.buffer) + Nx*(y1 + j) + Xo - (int)(0.5*Nlong);
+    /* find sky on edge */
+    for (i = 0, Nring = 0; i < 0.5*(Nlong - Ngap); i++, V++, Nring++) {
+      buffer[i] = *V;
+    }
+    fsort (buffer, Nring);
+    for (Npts = sky = 0, i = 0.25*Nring; i < 0.75*Nring; i++, Npts += 1.0) {
+      sky += buffer[i];
+    }
+    sky = sky / Npts;
+    /* find center column for this row */
+    for (S = SX = i = 0, Nring = 0; i < Ngap; i++, V++, Nring++) {
+      S += (*V - sky);
+      SX += (*V - sky)*(i + Xo - 0.5*Ngap);
+    }
+    X1 = SX / S;
+    fprintf (stderr, "%4d %4d %5.1f ", j+y1, X1, sky);
+    /*    X1 = MAX (MIN (X1, Xo + 0.5+Ngap), Xo - 0.5+Ngap); */
+    V = (float *) (buf[0].matrix.buffer) + Nx*(y1 + j) + X1 - (int)(0.5*Nlong);
+    /* find sky on edges */
+    for (i = 0, Nring = 0; i < 0.5*(Nlong - Ngap); i++, V++, Nring++) {
+      buffer[Nring] = *V;
+    }
+    V = (float *) (buf[0].matrix.buffer) + Nx*(y1 + j) + X1 + (int)(0.5*Ngap);
+    for (i = 0; i < 0.5*(Nlong - Ngap); i++, V++, Nring++) {
+      buffer[Nring] = *V;
+    }
+    fsort (buffer, Nring);
+    for (Npts = sky = 0, i = 0.25*Nring; i < 0.75*Nring; i++, Npts += 1.0) {
+      sky += buffer[i];
+      sky2 += buffer[i]*buffer[i];
+    }
+    sky = sky / Npts;
+    sky2 = (sky2 / Npts - sky*sky);
+    /* find weighted flux */
+    V = (float *) (buf[0].matrix.buffer) + Nx*(y1 + j) + X1 - (int)(0.5*Ngap);
+    for (F = R = i = 0; i < Ngap; i++, V++) {
+      F += (*V - sky) / sky2;
+      R += 1.0 / sky2;
+    }
+    xvec[0].elements[j] = j + y1; 
+    yvec[0].elements[j] = F / R; 
+    fprintf (stderr, " %5.1f %7.1f  %6.2f\n", sky, sky2, (F/R));
+  }    
+
+  free (buffer);
+  return (TRUE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/star.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/star.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/star.c	(revision 3338)
@@ -0,0 +1,41 @@
+# include "astro.h"
+
+int star (int argc, char **argv) {
+
+  int x, y, N, dx, Nborder;
+  double Z, max;
+  Buffer *buf;
+
+  Nborder = 3;
+  if ((N = get_argument (argc, argv, "-border"))) {
+    remove_argument (N, &argc, argv);
+    Nborder  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  Nborder = MAX (Nborder, 1);
+  
+  max = 60000;
+  if ((N = get_argument (argc, argv, "-sat"))) {
+    remove_argument (N, &argc, argv);
+    max  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  
+  if ((argc != 4) && (argc != 5)) {
+    fprintf (stderr, "USAGE: star (buffer) x y [dx] [-border N] [-sat cnts]\n");
+    return (FALSE);
+  }
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  dx = 11;
+  x = atof (argv[2]);
+  y = atof (argv[3]);
+  if (argc == 5) {
+    dx = atof (argv[4]);
+  }
+
+  Z = get_aperture_stats (&buf[0].matrix, x, y, dx, Nborder, max);
+  
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/testfit.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/testfit.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/testfit.c	(revision 3338)
@@ -0,0 +1,161 @@
+# include "astro.h"
+
+/* local private functions */
+float fgaussOD (float, float *, int, float *);
+
+int imfit (int argc, char **argv) {
+
+  float par[4], *v1, *v2, *dy, chisq, **covar;
+  int i, Npts, Npar;
+  Vector *xvec, *yvec, *svec;
+
+  if (argc != 4) {
+    fprintf (stderr, "USAGE: imfit <x> <y> <dy>\n");
+    return (FALSE);
+  }
+  
+  if ((xvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yvec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((svec = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+
+  Npts = xvec[0].Nelements;
+  ALLOCATE (dy, float, Npts);
+  v1 = svec[0].elements;
+  v2 = dy;
+  
+  for (i = 0; i < Npts; i++, v1++, v2++) *v2 = 1.0 / (*v1 * *v1);
+  
+  par[0] = 7;
+  par[1] = 2;
+  par[2] = 6;
+  par[3] = 1;
+  Npar = 4;
+
+  mrqinit (xvec[0].elements, yvec[0].elements, dy, Npts, par, Npar, fgaussOD);
+
+  for (i = 0; i < 10; i++) {
+
+    chisq = mrqmin (xvec[0].elements, yvec[0].elements, dy, Npts, par, Npar, fgaussOD);
+    fprintf (stderr, "chisq: %f, %f %f %f %f\n", chisq, par[0], par[1], par[2], par[3]);
+
+  }  
+
+  covar = mrqcovar (Npar);
+
+  for (i = 0; i < Npar; i++) {
+    fprintf (stderr, "%d  %f  %f\n", i, par[i], covar[i][i]);
+  }
+
+  mrqfree (Npar);
+  return (TRUE);
+}
+
+
+/* pars: x, y, sx, sy, sxy, sky I, */
+float fgaussOD (float x, float *par, int Npar, float *dpar) {
+
+  float X, S, Z, R, f;
+
+  X = x - par[0];
+  S = 1.0 / (par[1]*par[1]);
+  Z = -0.5*X*X*S;
+  R = exp (Z);
+  f = par[2]*R + par[3];
+
+  dpar[0] = par[2]*R*X*S;
+  dpar[1] = dpar[0]*X/par[1];
+  dpar[2] = R;
+  dpar[3] = 1;
+  
+  return (f);
+
+}
+
+# if (0)
+
+/* pars: x, y, sx, sy, sxy, sky I, */
+float testF (float x, float *par, int Npar, float *dpar) {
+
+  float f;
+
+  f = par[0]*x + par[1];
+
+  dpar[0] = x;
+  dpar[1] = 1;
+  
+  return (f);
+
+}
+
+
+/* pars: x, y, sx, sy, sxy, sky I, */
+float fgaussTD (float x, float y, float *par, int Npar) {
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  t1 = X / par[2];
+  t2 = Y * Y / par[3];
+  t3 = Y * par[4] * 2.0;
+
+  r = 0.5 * ((t1 + t3)*X + t2);
+  f = par[5] + par[6] / (1.0 + r*(1.0 + 0.5*r*(1.0 + 0.33333333*r)));
+  
+  return (f);
+
+}
+
+float chisq (float *buf, float *sig, int Nx, int Ny, float (func)(), float *par, int Npar) {
+
+  float *ptr;
+
+  X = 0;
+  ptr = buf;
+  for (i = 0; i < Nx; i++) {
+    for (j = 0; j < Ny; j++, ptr++, sig++) {
+      f = *ptr - func ((float) i, (float) j, par, Npar);
+      X += (f * f) / *sig;
+    }
+  }    
+  return (X);
+}
+
+  int i, j, Nbuf, status;
+  char *string;
+  double Npix, N1, N2, max, min, range, median;
+  float *V;
+  int sx, sy, nx, ny, *hist, Nhist, bin;
+
+  if (argc != 6) {
+    fprintf (stderr, "USAGE: imfit <buffer> sx sy nx ny\n");
+    return (FALSE);
+  }
+
+  if (!SelectBuffer (&Nbuf, argv[1], OLDBUFFER)) return (FALSE);
+
+  sx = atof (argv[2]);
+  sy = atof (argv[3]);
+  nx = atof (argv[4]);
+  ny = atof (argv[5]);
+
+  Npix = N1 = N2 = 0;
+  if ((sx < 0) || (sy < 0) || 
+      (sx+nx > buffers[Nbuf].matrix.Naxis[0]) || 
+      (sy+ny > buffers[Nbuf].matrix.Naxis[1])) {
+    fprintf (stderr, "region out of range\n");
+    return (FALSE);
+  }
+
+  Npix = nx*ny;
+
+  ALLOCATE (tempbuf, float, Npix);
+
+  buf = tempbuf;
+  for (j = 0; j < ny; j++) {
+    V = (float *)(buffers[Nbuf].matrix.buffer) + (j+sy)*buffers[Nbuf].matrix.Naxis[0] + sx; 
+    for (i = 0; i < nx; i++, V++) {
+      *buf = *V;
+    }
+  }
+
+# endif
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/transform.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/transform.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.astro/transform.c	(revision 3338)
@@ -0,0 +1,68 @@
+# include "astro.h"
+
+int transform (int argc, char **argv) {
+
+  int i, j, Nx, Ny;
+  Coords coords_in, coords_out;
+  double scale_in, scale_out;
+  int X, Y;
+  double x, y, r, d, dx, dy;
+  double frac;
+  char *Sout, *S;
+  float *Vin, *Vout;
+  Buffer *in, *out;
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: transform <from> <to>\n");
+    return (FALSE);
+  }
+
+  if ((in  = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((out = SelectBuffer (argv[2], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  GetCoords (&coords_in, &in[0].header);
+  GetCoords (&coords_out, &out[0].header);
+  
+  scale_in = sqrt(fabs(coords_in.cdelt1*coords_in.cdelt2*(coords_in.pc1_1*coords_in.pc2_2 - coords_in.pc1_2*coords_in.pc2_1)));
+  scale_out = sqrt(fabs(coords_out.cdelt1*coords_out.cdelt2*(coords_out.pc1_1*coords_out.pc2_2 - coords_out.pc1_2*coords_out.pc2_1)));
+
+  Vin  = (float *) in[0].matrix.buffer;
+  Vout = (float *) out[0].matrix.buffer;
+  Nx = out[0].header.Naxis[0];
+  Ny = out[0].header.Naxis[1];
+  bzero (Vout, Nx*Ny*sizeof(float));
+  ALLOCATE (S, char, Nx*Ny);
+  Sout = S;
+  bzero (Sout, Nx*Ny*sizeof(char));
+  frac = 0.333;
+
+  /* if (scale_in < scale_out) { */
+
+  for (j = 0; j < in[0].header.Naxis[1]; j++) {
+    fprintf (stderr, ".");
+    for (i = 0; i < in[0].header.Naxis[0]; i++, Vin++) {
+      for (dx = 0.0 + 0.5*frac; dx < 1.0 - 0.5*frac; dx += frac) {
+	for (dy = 0.0 + 0.5*frac; dy < 1.0 - 0.5*frac; dy += frac) {
+	  XY_to_RD (&r, &d, i + dx, j + dy, &coords_in);
+	  RD_to_XY (&x, &y, r, d, &coords_out);
+	  X = x; Y = y;
+	  if ((X > -1) && (X < Nx) && (Y > -1) && (Y < Ny)) {
+	    Vout[X + Y*Nx] += *Vin;
+	    Sout[X + Y*Nx] ++;
+	  }
+	}
+      }
+    }
+  }
+
+  Sout = S;
+  Vout = (float *) out[0].matrix.buffer;
+  for (i = 0; i < Nx*Ny; i++, Vout++, Sout++) {
+    *Vout = *Vout / *Sout;
+  }
+
+  free (S);
+    
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/Makefile
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/Makefile	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/Makefile	(revision 3338)
@@ -0,0 +1,109 @@
+include ../../../Configure
+
+HOME    =       $(ROOT)/src/opihi.v2
+BIN     =       $(HOME)/bin
+LIB     =       $(HOME)/lib
+INC     =       $(HOME)/include
+SDIR    =       $(HOME)/cmd.basic
+#
+DESTBIN =       $(LBIN)
+DESTLIB =       $(LLIB)
+DESTINC =       $(LINC)
+DESTMAN =       $(LMAN)
+HELP    =       $(HOME)/help
+#  
+INCS    =       -I$(INC) -I$(LINC) -I$(XINC)
+LFLAGS  =       -L$(LLIB) -L$(LIB)
+LIBS    =       -lFITS -lsocket -lnsl -lreadline -ltermcap -lohana -lm
+CFLAGS  =       $(INCS)
+CCFLAGS =       $(LIBS) 
+
+# basic user commands ########################
+
+basiccmd = \
+$(SDIR)/init.$(ARCH).o       \
+$(SDIR)/break.$(ARCH).o	     \
+$(SDIR)/cd.$(ARCH).o	     \
+$(SDIR)/config.$(ARCH).o     \
+$(SDIR)/continue.$(ARCH).o   \
+$(SDIR)/date.$(ARCH).o	     \
+$(SDIR)/echo.$(ARCH).o	     \
+$(SDIR)/file.$(ARCH).o	     \
+$(SDIR)/getchr.$(ARCH).o     \
+$(SDIR)/help.$(ARCH).o	     \
+$(SDIR)/input.$(ARCH).o	     \
+$(SDIR)/list.$(ARCH).o	     \
+$(SDIR)/list_help.$(ARCH).o  \
+$(SDIR)/list_vars.$(ARCH).o  \
+$(SDIR)/local.$(ARCH).o	     \
+$(SDIR)/macro.$(ARCH).o	     \
+$(SDIR)/memory.$(ARCH).o     \
+$(SDIR)/output.$(ARCH).o     \
+$(SDIR)/quit.$(ARCH).o	     \
+$(SDIR)/run_for.$(ARCH).o    \
+$(SDIR)/run_if.$(ARCH).o     \
+$(SDIR)/run_while.$(ARCH).o  \
+$(SDIR)/scan.$(ARCH).o	     \
+$(SDIR)/shell.$(ARCH).o	     \
+$(SDIR)/sprintf.$(ARCH).o    \
+$(SDIR)/strlen.$(ARCH).o     \
+$(SDIR)/substr.$(ARCH).o     \
+$(SDIR)/usleep.$(ARCH).o     \
+$(SDIR)/sleep.$(ARCH).o	     \
+$(SDIR)/wait.$(ARCH).o	     \
+$(SDIR)/which.$(ARCH).o
+
+libbasiccmd:    $(DESTLIB)/libbasiccmd.a 
+
+$(LIB)/libbasiccmd.$(ARCH).a:   	$(basiccmd)
+
+# utilities #################################################
+$(BIN)/%.$(ARCH):
+	@if [ ! -d $(BIN) ]; then mkdir -p $(BIN); fi
+	$(CC) $^ -o $@ $(LFLAGS) $(LIBS)
+	@echo "compiled $*"
+	@echo ""
+
+$(DESTBIN)/%: $(BIN)/%.$(ARCH) 
+	@if [ ! -d $(DESTBIN) ]; then mkdir -p $(DESTBIN); fi
+	rm -f $(DESTBIN)/$*
+	cp $(BIN)/$*.$(ARCH) $(DESTBIN)/$*
+	@echo "installed $*"
+	@echo ""
+
+$(LIB)/%.$(ARCH).a:
+	@if [ ! -d $(LIB) ]; then mkdir -p $(LIB); fi
+	rm -f $@
+	ar rcv $@ $^ 
+	$(RANLIB) $@
+	@echo "compiled library $*"
+	@echo ""
+
+$(DESTLIB)/%.a: $(LIB)/%.$(ARCH).a
+	@if [ ! -d $(DESTLIB) ]; then mkdir -p $(DESTLIB); fi
+	@echo ""
+	rm -f $@
+	cp $^ $@
+
+lib%.clean:
+	rm -f $(LIB)/lib$*.$(ARCH).a
+	rm -f $($*)
+	@echo ""
+
+%.clean:
+	rm -f $(BIN)/$*.$(ARCH)
+	@echo ""
+
+%.$(ARCH).o : %.c
+	$(CC) $(CFLAGS) -c $*.c -o $@
+
+clean:
+	rm -f $(BIN)/*.$(ARCH)
+	rm -f $(LIB)/*.$(ARCH).a
+	rm -f `find . -name "*.o"`
+	rm -f `find . -name "*~"`
+	rm -f `find . -name "#*"`
+
+dist: clean
+	rm -f $(BIN)/*
+	rm -f $(LIB)/*
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/break.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/break.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/break.c	(revision 3338)
@@ -0,0 +1,27 @@
+# include "basic.h"
+
+int exec_break (int argc, char **argv) {
+
+  int N, value;
+
+  if ((N = get_argument (argc, argv, "-auto"))) {
+    remove_argument (N, &argc, argv);
+    value = -1;
+    if (!strcasecmp (argv[N], "on")) value = TRUE;
+    if (!strcasecmp (argv[N], "off")) value = FALSE;
+    if (value == -1) {
+      fprintf (stderr, "USAGE: break -auto [on / off]\n");
+      if (auto_break) 
+	fprintf (stderr, "auto break on\n");
+      else 
+	fprintf (stderr, "auto break off\n");
+      return (FALSE);
+    }
+    auto_break = value;
+    return (TRUE);
+  }
+
+  loop_break = TRUE;
+  return (FALSE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/cd.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/cd.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/cd.c	(revision 3338)
@@ -0,0 +1,46 @@
+# include "basic.h"
+
+int cd (int argc, char **argv) {
+
+  int status;
+  char *cwd;
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: cd <path>\n");
+    return (FALSE);
+  }
+
+  status = chdir (argv[1]);
+  if (!status) {
+    if ((cwd = getcwd (NULL, 64)) == NULL) {
+      fprintf (stderr, "error getting cwd\n");
+      return (FALSE);
+    }
+    fprintf(stderr, "cwd: %s\n", cwd);
+    free (cwd);
+    return (TRUE);
+  }
+
+  fprintf (stderr, "error changing to %s\n", argv[1]);
+  return (FALSE);
+
+}
+
+int pwd (int argc, char **argv) {
+
+  char *cwd;
+
+  if (argc != 1) {
+    fprintf (stderr, "USAGE: pwd\n");
+    return (FALSE);
+  }
+  
+  if ((cwd = getcwd(NULL, 64)) == NULL) {
+    fprintf (stderr, "error getting cwd\n");
+    return (FALSE);
+  }
+  fprintf(stderr, "cwd: %s\n", cwd);
+  free (cwd);
+  return (TRUE);
+  
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/config.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/config.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/config.c	(revision 3338)
@@ -0,0 +1,9 @@
+# include "basic.h"
+
+int config (int argc, char **argv) {
+
+  if (!ConfigInit (&argc, argv)) return (FALSE);
+
+  return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/continue.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/continue.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/continue.c	(revision 3338)
@@ -0,0 +1,7 @@
+# include "basic.h"
+
+int exec_continue (int argc, char **argv) {
+  loop_continue = TRUE;
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/date.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/date.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/date.c	(revision 3338)
@@ -0,0 +1,26 @@
+# include "basic.h"
+
+int date (int argc, char **argv) {
+  
+  int N;
+  struct timeval now;
+  char *tstring;
+
+  if ((argc != 1) && (argc != 2)) {
+    fprintf (stderr, "USAGE: date [variable]\n");
+    return (FALSE);
+  }
+
+  gettimeofday (&now, NULL);
+  tstring = ctime (&now.tv_sec);
+  N = strlen (tstring) - 1;
+  tstring[N] = 0;
+
+  if (argc == 1) {
+    fprintf (stderr, "%s\n", tstring);
+  } else {
+    set_str_variable (argv[1], tstring);
+  }
+
+  return (TRUE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/echo.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/echo.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/echo.c	(revision 3338)
@@ -0,0 +1,12 @@
+# include "basic.h"
+
+int echo (int argc, char **argv) {
+  
+  int i;
+
+  for (i = 1; i < argc; i++) {
+    fprintf (GetOutfile(), "%s ", argv[i]);
+  }
+  fprintf (GetOutfile(), "\n");
+  return (TRUE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/file.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/file.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/file.c	(revision 3338)
@@ -0,0 +1,32 @@
+# include "basic.h"
+
+int file (int argc, char **argv) {
+  
+  /* usage: file (filename) [var] */
+
+  int status, vstat;
+  struct stat fstats;
+
+  if (argc < 2) {
+    fprintf (stderr, "USAGE: file (filename) [var]\n");
+    return (FALSE);
+  }
+
+  status = stat (argv[1], &fstats);
+
+  vstat = !status;
+
+  if (argc == 3) {
+      
+    set_int_variable (argv[2], vstat);
+
+  } else {
+
+    fprintf (stderr, "file %s is ", argv[1]);
+    if (!vstat) fprintf (stderr, "not ");
+    fprintf (stderr, "found\n");
+    
+  }
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/getchr.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/getchr.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/getchr.c	(revision 3338)
@@ -0,0 +1,29 @@
+# include "basic.h"
+
+int getchr_func (int argc, char **argv) {
+
+  /* returns position of the first given character */ 
+  char *c;
+  int pos;
+
+  if ((argc != 3) && (argc != 4)) {
+    fprintf (stderr, "USAGE: strchr (string) (char) [var]\n");
+    return (FALSE);
+  }
+
+  c = strchr (argv[1], argv[2][0]);
+
+  if (c == (char *) NULL) {
+    pos = -1;
+  } else {
+    pos = c - argv[1];
+  }
+
+  if (argc == 4) {
+    set_int_variable (argv[3], pos);
+  } else {
+    fprintf (stderr, "%d\n", pos);
+  }
+  return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/help.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/help.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/help.c	(revision 3338)
@@ -0,0 +1,34 @@
+# include "basic.h"
+
+int help (int argc, char **argv) {
+
+  FILE *f;
+  char *helpdir, file[1024], buff[512];
+
+  helpdir = get_variable ("HELPDIR");
+  if (helpdir == (char *) NULL) {
+    fprintf (stderr, "variable HELPDIR not found\n");
+    return (FALSE);
+  }
+
+  if (argc == 1) {
+    sprintf (buff, "ls %s", helpdir);
+    system (buff);
+    return (TRUE);
+  }
+
+  sprintf (file, "%s/%s", helpdir, argv[1]);
+
+  f = fopen (file, "r");
+  if (f == NULL) {
+    fprintf (stderr, "No help for: %s\n", argv[1]);
+    return (FALSE);
+  }
+
+  while (scan_line (f, buff) != EOF)
+    fprintf (stdout, "%s\n", buff);
+
+  fclose (f);
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/init.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/init.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/init.c	(revision 3338)
@@ -0,0 +1,80 @@
+# include "basic.h"
+
+int config          PROTO((int, char **));
+int exec_sleep      PROTO((int, char **));
+int exec_usleep     PROTO((int, char **));
+int cd              PROTO((int, char **));
+int date            PROTO((int, char **));
+int echo            PROTO((int, char **));
+int exec_break      PROTO((int, char **));
+int exec_continue   PROTO((int, char **));
+int file            PROTO((int, char **));
+int getchr_func     PROTO((int, char **));
+int help       	    PROTO((int, char **));
+int input      	    PROTO((int, char **));
+int list       	    PROTO((int, char **));
+int list_help  	    PROTO((int, char **));
+int list_vars  	    PROTO((int, char **));
+int local           PROTO((int, char **)); /* data? */
+int macro      	    PROTO((int, char **));
+int memory          PROTO((int, char **));
+int output     	    PROTO((int, char **));
+int pwd        	    PROTO((int, char **));
+int quit       	    PROTO((int, char **));
+int run_for    	    PROTO((int, char **));
+int run_if     	    PROTO((int, char **));
+int run_while  	    PROTO((int, char **));
+int scan       	    PROTO((int, char **));
+int shell      	    PROTO((int, char **));
+int sprintf_opihi   PROTO((int, char **));
+int strlen_func     PROTO((int, char **));
+int substr_func     PROTO((int, char **));
+int wait       	    PROTO((int, char **));
+int which      	    PROTO((int, char **));
+
+/** mapping of the command names to command functions **/
+static Command cmds[] = {  
+  {"config",        config,             "(re)load config file?"},
+  {"sleep",         exec_sleep,         "sleep for N seconds"},
+  {"usleep",        exec_usleep,        "sleep for N microseconds"},
+  {"cd",      	    cd,                 "change directory"},
+  {"date",    	    date,               "get current date"},
+  {"echo",    	    echo,               "type this line *"},
+  {"break",   	    exec_break,         "escape from function *"},
+  {"continue",	    exec_continue,      "next loop iteration"},
+  {"file",          file,               "test file existence"},
+  {"getchr",        getchr_func,        "find character in string"},
+  {"help",    	    help,               "get help on a function *"},
+  {"input",   	    input,              "read command lines from a file *"},
+  {"list",    	    list,               "get variable list"},
+  {"?",       	    list_help,          "list commands *"},
+  {"??",      	    list_vars,          "list variables *"},
+  {"local",  	    local,              "define local variables"},
+  {"macro",   	    macro,              "deal with the macros *"}, 
+  {"memory",        memory,             "long listing of the allocated memory"},
+  {"output",  	    output,             "redirect output to file"},
+  {"pwd",     	    pwd,                "print current working directory"},
+  {"exit",    	    quit,               "exit program *"}, 
+  {"quit",    	    quit,               "exit program *"},
+  {"for",     	    run_for,            "for loop"}, 
+  {"if",      	    run_if,             "logical cases *"}, 
+  {"while",   	    run_while,          "while loop"}, 
+  {"scan",    	    scan,               "scan line from keyboard or file to variable *"},
+  {"!",       	    shell,              "system call"},
+  {"exec",    	    shell,              "system call"},
+  {"sprintf",       sprintf_opihi,      "formatted print to a variable"},
+  {"strlen",        strlen_func,        "string length"},
+  {"substr",        substr_func,        "substring"},
+  {"wait",    	    wait,               "wait until return is typed"},
+  {"which",   	    which,              "show command *"}
+};
+
+void InitBasic () {
+  
+  int i;
+
+  for (i = 0; i < sizeof (cmds) / sizeof (Command); i++) {
+    AddCommand (&cmds[i]);
+  }
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/input.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/input.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/input.c	(revision 3338)
@@ -0,0 +1,52 @@
+# include "basic.h"
+# define D_NLINES 100
+
+int input (int argc, char **argv) {
+  
+  int i, NLINES, status;
+  FILE *infile;
+  Macro inlist;
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: input <filename>\n");
+    return (FALSE);
+  }
+
+  infile = fopen (argv[1], "r");
+  if (infile == NULL) {
+    fprintf (stderr, "no file %s\n", argv[1]); 
+    return (FALSE);
+  }
+
+  /* read file into the current list */
+  NLINES = D_NLINES;
+  ALLOCATE (inlist.line, char *, NLINES);
+  ALLOCATE (inlist.line[0], char, 1024);
+  for (i = 0; (scan_line (infile, inlist.line[i]) != EOF);) {
+    stripwhite (inlist.line[i]);
+    if (inlist.line[i][0] == 0) continue;
+    if (inlist.line[i][0] == '#') continue;
+    if (inlist.line[i][0] == '!') continue;
+
+    REALLOCATE (inlist.line[i], char, strlen(inlist.line[i]) + 1);
+    if (i == NLINES - 1) {
+      NLINES += D_NLINES;
+      REALLOCATE (inlist.line, char *, NLINES)
+    }
+    i++;
+    ALLOCATE (inlist.line[i], char, 1024);
+  }
+  inlist.Nlines = i;
+  fclose (infile);
+
+  /* process this list */
+  status = exec_loop (&inlist);
+
+  /* cleanup list */
+  for (i = 0; i < inlist.Nlines; i++) {
+    free (inlist.line[i]);
+  }
+  free (inlist.line);
+  return (status);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/list.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/list.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/list.c	(revision 3338)
@@ -0,0 +1,136 @@
+# include "basic.h"
+# define D_NLINES 100
+static char prompt[] = ">> ";
+
+int list (int argc, char **argv) {
+
+  int ThisList, depth, i, done;
+  char *input, line[1024];
+  int N, Nbytes, NBYTES, Nread, status;
+  int RunCommand;
+  char *A, *B, *val, *Cmd;
+  FILE *f;
+
+  RunCommand = FALSE;
+  if ((N = get_argument (argc, argv, "-x"))) {
+    remove_argument (N, &argc, argv);
+    Cmd = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+    RunCommand = TRUE;
+  }
+
+  if ((argc > 2) && (!strcmp (argv[2], "-split"))) {
+    if (argc == 3) {
+      fprintf (stderr, "USAGE: list (root) -split (word) (word) ...\n");
+      return (FALSE);
+    }
+    
+    for (i = 0; i < argc - 3; i++) {
+      sprintf (line, "%s:%d", argv[1], i);
+      set_str_variable (line, argv[i+3]);
+    }
+    sprintf (line, "%s:n", argv[1]);
+    set_int_variable (line, i);
+
+    return (TRUE);
+  }
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: list (root) -- terminate with 'END'\n");
+    return (FALSE);
+  }
+
+  if (RunCommand) {
+    
+    /* val will hold the result */
+    NBYTES = 1024;
+    ALLOCATE (val, char, NBYTES);
+    
+    /* need to loop until command produces no more output, 
+       REALLOCATING as needed. */
+    f = popen (Cmd, "r");
+    done = FALSE;
+    Nbytes = 0;
+    while (!done) {
+      Nread = fread (&val[Nbytes], 1, 1023, f);
+      if (Nread < 0) { 
+	fprintf (stderr, "error reading from command\n");
+	done = TRUE;
+      }
+      if (Nread > 0) {
+	Nbytes += Nread;
+	NBYTES = 1024 + Nbytes;
+	REALLOCATE (val, char, NBYTES);
+      }
+      if (Nread == 0) {
+	done = TRUE;
+      }
+      
+    }
+    val[Nbytes] = 0;
+    status = pclose (f);
+    free (Cmd);
+    
+    if (status) {
+      fprintf (stderr, "warning: exit status of command %d\n", status);
+    }
+      
+    A = B = val;
+    for (i = 0; B != (char *) NULL;) {
+      while (isspace (*A) && (*A != 0)) A++;
+      B = strchr (A, '\n');
+      if (B != (char *) NULL) { *B = 0; }
+      if (*A != 0) {
+	sprintf (line, "%s:%d", argv[1], i);
+	set_str_variable (line, A);
+	A = B + 1;
+	i++;
+      }
+    }      
+    free (val);
+    
+    sprintf (line, "%s:n", argv[1]);
+    set_int_variable (line, i);
+    return (TRUE);
+  }
+
+  /* read in loop */
+  depth = 0;
+  ThisList = Nlists;
+  for (i = 0, done = FALSE; !done; ) {
+
+    /* get the next line (from correct place) */
+    if (ThisList == 0) 
+      input = readline (prompt);
+    else 
+      input = get_next_listentry (ThisList);
+
+    if (input == (char *) NULL) {
+      if (ThisList == 0)  {
+	fprintf (stderr, "end list with 'END'\n");
+	continue;
+      } else {
+	return (FALSE);
+      }	
+    }
+    stripwhite (input);
+
+    /* test for end of nested list -- if not nested, END refers to this macro */
+    if (!strncasecmp (input, "END", 3)) {
+      depth --;
+      if (depth < 0) { /* we hit the last "END", loop is done */
+	sprintf (line, "%s:n", argv[1]);
+	set_int_variable (line, i);
+	free (input);
+	return (TRUE);
+      }
+    }
+
+    if (*input) { 
+      sprintf (line, "%s:%d", argv[1], i);
+      set_str_variable (line, input);
+      i++;
+    }
+  }
+  return (TRUE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/list_help.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/list_help.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/list_help.c	(revision 3338)
@@ -0,0 +1,24 @@
+# include "basic.h"
+
+int list_help (int argc, char **argv) {
+
+  FILE *f;
+  int fd;
+  char filename[128], line[256];
+
+  sprintf (filename, "/tmp/status.XXXXXX");
+  if ((fd = mkstemp (filename)) == -1) {
+    fprintf (stderr, "error opening output\n");
+    return (FALSE);
+  }
+  f = fdopen (fd, "w");
+  if (f == (FILE *) NULL) f = stdout;
+  print_commands (f);
+  if (f != stdout) {
+    fclose (f);
+    sprintf (line, "more %s", filename);
+    system (line);
+  }
+  unlink (filename);
+  return (TRUE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/list_vars.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/list_vars.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/list_vars.c	(revision 3338)
@@ -0,0 +1,8 @@
+# include "basic.h"
+
+int list_vars (int argc, char **argv) {
+
+  ListVariables ();
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/local.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/local.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/local.c	(revision 3338)
@@ -0,0 +1,33 @@
+# include "basic.h"
+
+int local (int argc, char **argv) {
+
+  int i, N, STATIC;
+  char *p;
+
+  /* create a variable named MacroDepth.argv[1] */
+
+  STATIC = FALSE;
+  if ((N = get_argument (argc, argv, "-static"))) {
+    remove_argument (N, &argc, argv);
+    STATIC = TRUE;
+  }
+
+  if (argc < 2) {
+    fprintf (stderr, "USAGE: local (variable)\n");
+    return (FALSE);
+  }
+  
+  for (i = 1; i < argc; i++) {
+    if (STATIC) {
+      p = get_local_variable_ptr (argv[i]);
+      if (p == NULL) {
+	set_local_variable (argv[i], "NULL");
+      }
+    } else {
+      set_local_variable (argv[i], "NULL");
+    }      
+  }
+  return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/macro.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/macro.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/macro.c	(revision 3338)
@@ -0,0 +1,52 @@
+# include "basic.h"
+# include "macro.h"
+
+int macro (int argc, char **argv) {
+
+  int i, N, status;
+
+  if ((argc != 2) && (argc != 3) && (argc != 4)) {
+    fprintf (stderr, "USAGE: macro (cmd)\n");
+    fprintf (stderr, "  (cmd) can be one of:\n");
+    fprintf (stderr, "    (name)         -- create macro (name)\n");
+    fprintf (stderr, "    create (name)  -- create macro (name)\n");
+    fprintf (stderr, "    delete (name)  -- delete macro (name)\n");
+    fprintf (stderr, "    list   (name)  -- list macro (name)\n");
+    fprintf (stderr, "    edit   (name)  -- edit macro (name) <not working yet!> *\n");
+    fprintf (stderr, "    read   (name)  -- read macro(s) from file (name) <not working yet!> *\n");
+    fprintf (stderr, "    write  (name)  -- write macro (name) to a file <not working yet!> *\n");
+    return (FALSE);
+  }
+
+  N = sizeof (in_macro) / sizeof (Command);
+
+  /* find the macro sub-command which matches from the list. */
+  /* if sub-command is not found, assume this is creating a new macro */
+  for (i = 0; i < N; i++) {
+    if (!strcmp (in_macro[i].name, argv[1])) {
+      (*in_macro[i].func) (argc - 1, argv + 1);
+      return (status);
+    }
+  }
+
+  /* sub-command was not found, pass argv[1..N] to macro create,
+     make argv[0] say "create" to be consistent (probably not needed) */
+  REALLOCATE (argv[0], char, 8);
+  strcpy (argv[0], "create");
+  status = macro_create (argc, argv);
+  return (status);
+}
+
+
+/* macro is called with the command "macro".  
+   the command line word "macro" is meant to be followed the one of several 
+   possible options:
+   
+   macro create
+   macro delete
+   macro list
+   macro edit
+   macro read
+   macro write
+
+*/
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/memory.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/memory.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/memory.c	(revision 3338)
@@ -0,0 +1,23 @@
+# include "basic.h"
+
+int memory (int argc, char **argv) {
+  
+# ifdef MEMMAP
+  struct mallinfo minfo;
+
+  minfo = mallinfo ();
+
+  fprintf (stderr, " arena: %d\n", minfo.arena);      /* total space in arena */
+  fprintf (stderr, " ordblks: %d\n", minfo.ordblks);    /* number of ordinary blocks */
+  fprintf (stderr, " smblks: %d\n", minfo.smblks);     /* number of small blocks */
+  fprintf (stderr, " hblkhd: %d\n", minfo.hblkhd);     /* space in holding block headers */
+  fprintf (stderr, " hblks: %d\n", minfo.hblks);      /* number of holding blocks */
+  fprintf (stderr, " usmblks: %d\n", minfo.usmblks);    /* space in small blocks in use */
+  fprintf (stderr, " fsmblks: %d\n", minfo.fsmblks);    /* space in free small blocks */
+  fprintf (stderr, " uordblks: %d\n", minfo.uordblks);   /* space in ordinary blocks in use */
+  fprintf (stderr, " fordblks: %d\n", minfo.fordblks);   /* space in free ordinary blocks */
+  fprintf (stderr, " keepcost: %d\n", minfo.keepcost);   /* space penalty if keep option is used */
+# endif
+
+  return (TRUE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/output.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/output.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/output.c	(revision 3338)
@@ -0,0 +1,34 @@
+# include "basic.h"
+
+static FILE *outfile;
+
+int output (int argc, char **argv) {
+  
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: output <filename>\n");
+    return (FALSE);
+  }
+
+  fflush (outfile);
+  if (outfile != stdout) fclose (outfile);
+  
+  /* we only use stdout, but let stderr be a synonym */
+  outfile = stdout;
+  if (strcmp (argv[1], "stdout") && strcmp (argv[1], "stderr")) {
+    outfile = fopen (argv[1], "a");
+  }
+
+  if (outfile == NULL) {
+    fprintf (stderr, "cannot open file %s\n", argv[1]);
+    outfile = stdout;
+  }
+  return (TRUE);
+}
+
+FILE *GetOutfile () {
+  return (outfile);
+}
+
+void InitOutfile () {
+  outfile = stdout;
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/quit.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/quit.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/quit.c	(revision 3338)
@@ -0,0 +1,16 @@
+# include "basic.h"
+
+int quit (int argc, char **argv) {
+
+  int state;
+
+  cleanup ();
+
+  state = 0;
+  if (argc > 1) {
+    state = atof (argv[1]);
+  } 
+
+  exit (state);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/run_for.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/run_for.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/run_for.c	(revision 3338)
@@ -0,0 +1,109 @@
+# include "basic.h"
+# define D_NLINES 100
+static char prompt[] = ">> ";
+
+int run_for (int argc, char **argv) {
+
+  int ThisList, depth, i, done, status, NLINES, j;
+  double start, end, delta;
+  char *input;
+  double value, sign;
+  Macro loop;
+
+  if ((argc != 4) && (argc != 5)) {
+    fprintf (stderr, "USAGE: for (var) (start) (stop) [delta] -- terminate with 'END'\n");
+    return (FALSE);
+  }
+
+  start = atof (argv[2]);
+  end   = atof (argv[3]);
+  delta = 1.0;
+  if (argc == 5) delta = atof (argv[4]);
+  sign = SIGN(delta);
+
+  NLINES = D_NLINES;
+  ALLOCATE (loop.line, char *, NLINES);
+
+  /* read in loop */
+  depth = 0;
+  ThisList = Nlists;
+  for (i = 0, done = FALSE; !done; ) {
+
+    /* get the next line (from correct place) */
+    if (ThisList == 0) 
+      input = readline (prompt);
+    else 
+      input = get_next_listentry (ThisList);
+    stripwhite (input);
+
+    /* check for end-of-data syntax error */
+    if (input == (char *) NULL) {
+      if (ThisList == 0)  {
+	fprintf (stderr, "end loop with 'END'\n");
+	continue;
+      } else {
+	fprintf (stderr, "misbalanced loop\n");
+	for (j = 0; j < loop.Nlines; j++) {
+	  free (loop.line[j]);
+	}
+	free (loop.line);
+	return (FALSE);
+      }	
+    }
+
+    /* test for new macro (or other list, in the future?) */
+    if (is_list (input)) depth ++;
+
+    /* test for end of nested list -- if not nested, END refers to this macro */
+    if (!strncasecmp (input, "END", 3)) {
+      depth --;
+      if (depth < 0) break;
+    }
+
+    /* if line has data, add to loop list */
+    if (*input) { 
+      loop.line[i] = input;
+      i++;
+      if (i == NLINES - 1) {
+	NLINES += D_NLINES;
+	REALLOCATE (loop.line, char *, NLINES);
+      }
+    }
+  }
+
+  /* cleanup loop data */
+  free (input);
+  loop.Nlines = i;
+  REALLOCATE (loop.line, char *, MAX (loop.Nlines, 1));
+
+  status = TRUE;
+  interrupt = loop_break = FALSE;
+  for (value = start; (sign*value < sign*end) && !interrupt; value += delta) {
+    loop_continue = loop_break = FALSE;
+    if ((int)value == value) 
+      set_int_variable (argv[1], (int) value);
+    else 
+      set_variable (argv[1], value);
+    status = exec_loop (&loop);
+    value = get_double_variable (argv[1]);
+    if (loop_break) break;
+    if (loop_continue) continue;
+  }
+  loop_continue = loop_break = FALSE;
+  if (auto_break && !status) loop_break = TRUE;
+
+  /* cleanup list */
+  for (j = 0; j < loop.Nlines; j++) {
+    free (loop.line[j]);
+  }
+  free (loop.line);
+  if (loop_break) return (FALSE);
+  return (TRUE);
+}
+
+/*
+  If we are entering at the keyboard (Nlists == 0), use readline.
+  Otherwise, read from the current list, remove list lines.
+  execute when we hit the final "END" (the true END -- we count macro defines!!) 
+*/
+     
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/run_if.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/run_if.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/run_if.c	(revision 3338)
@@ -0,0 +1,110 @@
+# include "basic.h"
+# define prompt    "if: "
+
+int run_if (int argc, char **argv) {
+
+  int ThisList, depth, done, status, BreakOnTrue;
+  int logic;
+  char *input, *outline, *val;
+  int nloop, size;
+
+  BreakOnTrue = FALSE;
+
+  if ((argc != 2) && (argc != 3)) {
+    fprintf (stderr, "USAGE: if (conditional) [break], end with the word 'END'\n");
+    return (FALSE);
+  }
+  if ((argc == 3) && strcmp (argv[2], "break")) {
+    fprintf (stderr, "USAGE: if (conditional) [break], end with the word 'END'\n");
+    return (FALSE);
+  }
+  if ((argc == 3) && !strcmp (argv[2], "break")) {
+    BreakOnTrue = TRUE;
+  }
+
+  /* read in if-list */
+  nloop = 0;
+  depth = 0;
+  ThisList = Nlists;
+
+  /* determine value of conditional expression */
+  val = dvomath (1, &argv[1], &size, 0);
+  if (val == NULL) return (FALSE);
+  logic = atof (val); /* warning: round-off error is a danger */ 
+
+  if (BreakOnTrue) {
+    if (logic) {
+      loop_break = TRUE;
+      return (FALSE);
+    } else {
+      return (TRUE);
+    }
+  }    
+
+  done = FALSE;
+  while (!done) {
+
+    nloop ++;
+    /* get the next line (from correct place) */
+    if (ThisList == 0) {
+      input = readline (prompt);
+    } else {
+      input = get_next_listentry (ThisList);
+    }
+
+    if ((ThisList == 0) && (input == (char *) NULL)) {
+      fprintf (stderr, "end if-block with 'END'\n");
+      continue;
+    }
+    if ((ThisList >  0) && (input == (char *) NULL)) {
+      fprintf (stderr, "missing 'END' in if-block\n");
+      input = strcreate ("end");
+    }
+
+    stripwhite (input);
+
+    /* test for new macro, search for "end" statement */
+    if (!logic && is_list (input)) {
+      depth ++;
+      free (input);
+      continue;
+    }
+    
+    /* check for an "else", invert logic */
+    if ((depth == 0) && !strncasecmp (input, "ELSE", 4)) {
+      logic ^= TRUE;
+      free (input);
+      continue;
+    }
+
+    /* test for end of nested block -- if not nested, END refers to this if */
+    if (!strncasecmp (input, "END", 3)) {
+      depth --;
+      if (depth < 0) { 
+	/* we hit the last "END", if-block is done */
+	free (input);
+	return (TRUE);	
+      }
+      free (input);  /* a do-nothing line */
+      continue;
+    }
+
+    if (logic) {
+      if (*input) { 
+	if (ThisList == 0) add_history (input);
+	status = command (input, &outline);
+	if (outline != (char *) NULL) free (outline);
+	if (!status) return (FALSE);
+      }
+    } else {
+      free (input);
+    }
+  }
+  return (TRUE);
+}
+
+/*
+     If we are entering at the keyboard (Nlists == 0), use readline.
+     Otherwise, read from the current list, remove list lines.
+     End when we hit the final "END" (the true END -- we count macro defines!!) 
+     */
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/run_while.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/run_while.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/run_while.c	(revision 3338)
@@ -0,0 +1,97 @@
+# include "basic.h"
+# define D_NLINES 100
+static char prompt[] = ">> ";
+
+int run_while (int argc, char **argv) {
+
+  int ThisList, depth, i, done, status, NLINES, j;
+  char *input, *val;
+  int logic, size;
+  Macro loop;
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: while (condition)\n");
+    return (FALSE);
+  }
+
+  val = dvomath (1, &argv[1], &size, 0);
+  if (val == NULL) return (FALSE);
+  logic = atof (val); /* warning: round-off error is a danger */
+  
+  NLINES = D_NLINES;
+  ALLOCATE (loop.line, char *, NLINES);
+
+  /* read in loop */
+  depth = 0;
+  ThisList = Nlists;
+  for (i = 0, done = FALSE; !done; ) {
+
+    /* get the next line (from correct place) */
+    if (ThisList == 0) 
+      input = readline (prompt);
+    else 
+      input = get_next_listentry (ThisList);
+    stripwhite (input);
+
+    /* check for end-of-data syntax error */
+    if (input == (char *) NULL) {
+      if (ThisList == 0)  {
+	fprintf (stderr, "end 'while' loop with 'END'\n");
+	continue;
+      } else {
+	fprintf (stderr, "misbalanced 'while' loop\n");
+	for (j = 0; j < loop.Nlines; j++) {
+	  free (loop.line[j]);
+	}
+	free (loop.line);
+	return (FALSE);
+      }	
+    }
+
+    /* test for new macro (or other list, in the future?) */
+    if (is_list (input)) depth ++;
+
+    /* test for end of nested list -- if not nested, END refers to this macro */
+    if (!strncasecmp (input, "END", 3)) {
+      depth --;
+      if (depth < 0) break;
+    }
+
+    /* if line has data, add to loop list */
+    if (*input) { 
+      loop.line[i] = input;
+      i++;
+      if (i == NLINES - 1) {
+	NLINES += D_NLINES;
+	REALLOCATE (loop.line, char *, NLINES);
+      }
+    }
+  }
+
+  /* cleanup loop data */
+  free (input);
+  loop.Nlines = i;
+  REALLOCATE (loop.line, char *, MAX (loop.Nlines, 1));
+
+  /* execute for loop */
+  do { 
+    loop_continue = loop_break = FALSE;
+    status = exec_loop (&loop);
+    if (loop_break) break;
+    if (loop_continue) continue;
+
+    val = dvomath (1, &argv[1], &size, 0);
+    if (val == NULL) return (FALSE);
+    logic = atof (val); /* warning: round-off error is a danger */
+  } while (logic && !interrupt);
+  loop_continue = loop_break = FALSE;
+  if (auto_break && !status) loop_break = TRUE;
+
+  /* cleanup list */
+  for (j = 0; j < loop.Nlines; j++) {
+    free (loop.line[j]);
+  }
+  free (loop.line);
+  if (loop_break) return (FALSE);
+  return (TRUE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/scan.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/scan.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/scan.c	(revision 3338)
@@ -0,0 +1,42 @@
+# include "basic.h"
+
+int scan (int argc, char **argv) {
+
+  int i, N, status;
+  char *line;
+  FILE *f;
+
+  if ((argc != 3) && (argc != 4)) {
+    fprintf (stderr, "USAGE: scan <filename> <var> [N]\n");
+    return (FALSE);
+  }
+
+  f = stdin;
+  if (strcmp (argv[1], "stdin")) {
+    f = fopen (argv[1], "r");
+    if (f == (FILE *) NULL) {
+      fprintf (stderr, "file %s not found\n", argv[1]);
+      return (FALSE);
+    }
+  }
+  
+  ALLOCATE (line, char, 1024);
+  N = 1;
+  if (argc == 4) 
+    N = atof(argv[3]);
+
+  for (i = 0; (i < N) && ((status = scan_line (f, line)) != EOF); i++);
+  if (i < N) {
+    set_str_variable (argv[2], "EOF");
+  } else {
+    set_str_variable (argv[2], line);
+  }
+  free (line);
+
+  if (f != stdin) {
+    fclose (f);
+  }
+  return (TRUE);
+ 
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/shell.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/shell.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/shell.c	(revision 3338)
@@ -0,0 +1,25 @@
+# include "basic.h"
+
+int shell (int argc, char **argv) {
+  
+  int i, status;
+  char line[2048], tmp[1024];
+
+  bzero (tmp, 1024);
+  bzero (line, 2048);
+
+  for (i = 1; i < argc; i++) {
+    sprintf (tmp, "%s ", argv[i]);
+    strcat (line, tmp);
+  }
+
+  strcat (line, "\n");
+  status = system (line);
+
+  if (status) {
+    return (FALSE);
+  } else {
+    return (TRUE);
+  }
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/sleep.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/sleep.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/sleep.c	(revision 3338)
@@ -0,0 +1,15 @@
+# include "basic.h"
+
+int exec_sleep (int argc, char **argv) {
+
+  int i;
+
+  if (argc < 2) {
+    fprintf (stderr, "usage: sleep N\n");
+    return (FALSE);
+  }
+
+  i = atof (argv[1]);
+  sleep (i);
+  return (TRUE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/sprintf.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/sprintf.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/sprintf.c	(revision 3338)
@@ -0,0 +1,82 @@
+# include "basic.h"
+# define NCHAR 1024
+
+/* convert line, tmp, fmt to dynamic strings? */
+
+int sprintf_opihi (int argc, char **argv) {
+
+  int i;
+  char line[NCHAR], tmp[NCHAR], fmt[NCHAR];
+  char *p1, *p2, *q;
+
+  if (argc < 3) {
+    fprintf (stderr, "USAGE: sprintf var format value value ...\n");
+    return (FALSE);
+  }
+
+  q  = line;
+  bzero (line, NCHAR);
+
+  p1 = argv[2];
+  for (i = 3; i < argc; i++) {
+    bzero (tmp, NCHAR);
+    bzero (fmt, NCHAR);
+
+    /* find next format character */
+    p2 = strchr (p1, '%');
+    if (p2 == (char *) NULL) {
+      fprintf (stderr, "mismatch between format and values\n");
+      return (FALSE);
+    }
+    if (strlen(q) + p2 - p1 > NCHAR) {
+      fprintf (stderr, "line too long");
+      return (FALSE);
+    }
+    memcpy (q, p1, p2-p1);
+    q = line + strlen(line);
+    
+    /* identify type (%NNNs %NNNNd %NNNNf) */
+    for (p1 = p2 + 1; (*p1 == '.') || (*p1 == '-') || (*p1 == '+') || (*p1 == ' ') || isdigit(*p1); p1++);
+    memcpy (fmt, p2, p1 - p2 + 1);
+    switch (*p1) {
+      case 'e':
+      case 'f':
+	sprintf (tmp, fmt, atof(argv[i]));
+	break;
+      case 's':
+	sprintf (tmp, fmt, argv[i]);
+	break;
+      case 'd':
+      case 'c':
+      case 'x':
+	sprintf (tmp, fmt, atoi(argv[i]));
+	break;
+      default:
+	fprintf (stderr, "syntax error in format (only e,f,s,d,c,x allowed)\n");
+	return (FALSE);
+    }
+    if (strlen(q) + strlen(tmp) > NCHAR) {
+      fprintf (stderr, "line too long");
+      return (FALSE);
+    }
+    memcpy (q, tmp, strlen(tmp));
+    q = line + strlen(line);
+    p1++;
+  }
+  p2 = strchr (p1, '%');
+  if (p2 != (char *) NULL) {
+    fprintf (stderr, "mismatch between format and values\n");
+    return (FALSE);
+  }
+  
+  p2 = p1 + strlen (p1);
+  if (strlen(q) + p2 - p1 > NCHAR) {
+    fprintf (stderr, "line too long");
+    return (FALSE);
+  }
+  memcpy (q, p1, p2-p1);
+  set_str_variable (argv[1], line);
+
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/strchr.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/strchr.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/strchr.c	(revision 3338)
@@ -0,0 +1,29 @@
+# include "basic.h"
+
+int getchr_func (int argc, char **argv) {
+
+  /* returns position of the first given character */ 
+  char *c;
+  int pos;
+
+  if ((argc != 3) && (argc != 4)) {
+    fprintf (stderr, "USAGE: strchr (string) (char) [var]\n");
+    return (FALSE);
+  }
+
+  c = strchr (argv[1], argv[2][0]);
+
+  if (c == (char *) NULL) {
+    pos = -1;
+  } else {
+    pos = c - argv[1];
+  }
+
+  if (argc == 5) {
+    set_variable (argv[3], pos);
+  } else {
+    fprintf (stderr, "%d\n", pos);
+  }
+  return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/strlen.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/strlen.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/strlen.c	(revision 3338)
@@ -0,0 +1,22 @@
+# include "basic.h"
+
+int strlen_func (int argc, char **argv) {
+
+  /* returns length of the given string */ 
+  int len;
+
+  if ((argc != 2) && (argc != 3)) {
+    fprintf (stderr, "USAGE: strchr (string) [var]\n");
+    return (FALSE);
+  }
+
+  len = strlen (argv[1]);
+
+  if (argc == 3) {
+    set_int_variable (argv[2], len);
+  } else {
+    fprintf (stderr, "%d\n", len);
+  }
+  return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/substr.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/substr.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/substr.c	(revision 3338)
@@ -0,0 +1,37 @@
+# include "basic.h"
+
+int substr_func (int argc, char **argv) {
+
+  int N1, N2, len;
+  char *c, *string;
+
+  if ((argc != 4) && (argc != 5)) {
+    fprintf (stderr, "USAGE: substr (string) N1 N2 [var]\n");
+    return (FALSE);
+  }
+
+  N1 = atof (argv[2]);
+  N2 = atof (argv[3]);
+
+  len = strlen (argv[1]);
+  if ((N1 >= len) || (N1 + N2 > len)) {
+    c = (char *) NULL;
+  } else {
+    c = strncreate (&argv[1][N1], N2);
+  }
+
+  if (c == (char *) NULL) {
+    string = strcreate ("");
+  } else {
+    string = strcreate (c);
+  }
+
+  if (argc == 5) {
+    set_str_variable (argv[4], string);
+  } else {
+    fprintf (stderr, "%s\n", string);
+  }
+  free (string);
+  return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/usleep.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/usleep.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/usleep.c	(revision 3338)
@@ -0,0 +1,15 @@
+# include "basic.h"
+
+int exec_usleep (int argc, char **argv) {
+
+  int i;
+
+  if (argc < 2) {
+    fprintf (stderr, "usage: usleep N\n");
+    return (FALSE);
+  }
+
+  i = atof (argv[1]);
+  usleep (i);
+  return (TRUE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/wait.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/wait.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/wait.c	(revision 3338)
@@ -0,0 +1,14 @@
+# include "basic.h"
+
+int wait (int argc, char **argv) {
+
+  char buff[1024];
+  int i;
+
+  for (i = 1; i < argc; i++) {
+    fprintf (stderr, "%s ", argv[i]);
+  }
+  fprintf (stderr, "\n");
+  scan_line (stdin, buff);
+  return (TRUE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/which.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/which.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.basic/which.c	(revision 3338)
@@ -0,0 +1,18 @@
+# include "basic.h"
+
+int which (int argc, char **argv) {
+
+  Command *cmd;
+ 
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: which <filename>\n");
+    return (FALSE);
+  }
+
+  cmd = MatchCommand (argv[1], TRUE, TRUE);
+  if (cmd == NULL) return (FALSE);
+
+  fprintf (stderr, "%-25s -- %s\n", cmd[0].name, cmd[0].help);
+  return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/Makefile
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/Makefile	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/Makefile	(revision 3338)
@@ -0,0 +1,174 @@
+include ../../../Configure
+
+HOME    =       $(ROOT)/src/opihi.v2
+BIN     =       $(HOME)/bin
+LIB     =       $(HOME)/lib
+INC     =       $(HOME)/include
+SDIR    =       $(HOME)/cmd.data
+#
+DESTBIN =       $(LBIN)
+DESTLIB =       $(LLIB)
+DESTINC =       $(LINC)
+DESTMAN =       $(LMAN)
+HELP    =       $(HOME)/help
+#  
+INCS    =       -I$(INC) -I$(LINC) -I$(XINC)
+LFLAGS  =       -L$(LLIB) -L$(LIB)
+LIBS    =       -lFITS -lsocket -lnsl -lreadline -ltermcap -lohana -lm
+CFLAGS  =       $(INCS)
+CCFLAGS =       $(LIBS) 
+
+# data user commands ########################
+datacmd = \
+$(SDIR)/init.$(ARCH).o          \
+$(SDIR)/accum.$(ARCH).o		\
+$(SDIR)/applyfit2d.$(ARCH).o	\
+$(SDIR)/applyfit.$(ARCH).o	\
+$(SDIR)/box.$(ARCH).o		\
+$(SDIR)/center.$(ARCH).o	\
+$(SDIR)/clear.$(ARCH).o		\
+$(SDIR)/clip.$(ARCH).o		\
+$(SDIR)/concat.$(ARCH).o	\
+$(SDIR)/contour.$(ARCH).o	\
+$(SDIR)/create.$(ARCH).o	\
+$(SDIR)/cursor.$(ARCH).o	\
+$(SDIR)/cut.$(ARCH).o		\
+$(SDIR)/delete.$(ARCH).o	\
+$(SDIR)/device.$(ARCH).o	\
+$(SDIR)/dimendown.$(ARCH).o	\
+$(SDIR)/dimenup.$(ARCH).o	\
+$(SDIR)/erase.$(ARCH).o		\
+$(SDIR)/extract.$(ARCH).o	\
+$(SDIR)/fft1d.$(ARCH).o		\
+$(SDIR)/fft2d.$(ARCH).o		\
+$(SDIR)/fit2d.$(ARCH).o		\
+$(SDIR)/fit.$(ARCH).o		\
+$(SDIR)/gaussj.$(ARCH).o	\
+$(SDIR)/gaussdeviate.$(ARCH).o	\
+$(SDIR)/grid.$(ARCH).o		\
+$(SDIR)/gridify.$(ARCH).o       \
+$(SDIR)/ungridify.$(ARCH).o     \
+$(SDIR)/histogram.$(ARCH).o	\
+$(SDIR)/imcut.$(ARCH).o	 	\
+$(SDIR)/imhist.$(ARCH).o	\
+$(SDIR)/imsmooth.$(ARCH).o	\
+$(SDIR)/integrate.$(ARCH).o	\
+$(SDIR)/interpolate.$(ARCH).o	\
+$(SDIR)/jpeg.$(ARCH).o		\
+$(SDIR)/kern.$(ARCH).o		\
+$(SDIR)/keyword.$(ARCH).o	\
+$(SDIR)/labels.$(ARCH).o	\
+$(SDIR)/limits.$(ARCH).o	\
+$(SDIR)/line.$(ARCH).o		\
+$(SDIR)/list_buffers.$(ARCH).o	\
+$(SDIR)/list_header.$(ARCH).o	\
+$(SDIR)/list_vectors.$(ARCH).o	\
+$(SDIR)/load.$(ARCH).o		\
+$(SDIR)/mcreate.$(ARCH).o	\
+$(SDIR)/medacc.$(ARCH).o	\
+$(SDIR)/mget.$(ARCH).o		\
+$(SDIR)/minterpolate.$(ARCH).o	\
+$(SDIR)/mset.$(ARCH).o		\
+$(SDIR)/peak.$(ARCH).o		\
+$(SDIR)/plot.$(ARCH).o		\
+$(SDIR)/dot.$(ARCH).o		\
+$(SDIR)/point.$(ARCH).o		\
+$(SDIR)/ps.$(ARCH).o		\
+$(SDIR)/pop.$(ARCH).o		\
+$(SDIR)/push.$(ARCH).o		\
+$(SDIR)/queues.$(ARCH).o	\
+$(SDIR)/radial.$(ARCH).o	\
+$(SDIR)/rd.$(ARCH).o		\
+$(SDIR)/rdseg.$(ARCH).o		\
+$(SDIR)/read_vectors.$(ARCH).o	\
+$(SDIR)/rebin.$(ARCH).o		\
+$(SDIR)/resize.$(ARCH).o	\
+$(SDIR)/roll.$(ARCH).o		\
+$(SDIR)/rotate.$(ARCH).o	\
+$(SDIR)/save.$(ARCH).o		\
+$(SDIR)/section.$(ARCH).o	\
+$(SDIR)/select.$(ARCH).o	\
+$(SDIR)/set.$(ARCH).o		\
+$(SDIR)/shift.$(ARCH).o		\
+$(SDIR)/sort.$(ARCH).o		\
+$(SDIR)/spline_apply.$(ARCH).o	\
+$(SDIR)/spline_construct.$(ARCH).o \
+$(SDIR)/stats.$(ARCH).o		   \
+$(SDIR)/style.$(ARCH).o		   \
+$(SDIR)/subraster.$(ARCH).o	   \
+$(SDIR)/subset.$(ARCH).o	   \
+$(SDIR)/svd.$(ARCH).o		   \
+$(SDIR)/swapbytes.$(ARCH).o	   \
+$(SDIR)/textline.$(ARCH).o	   \
+$(SDIR)/tv.$(ARCH).o		   \
+$(SDIR)/tvcontour.$(ARCH).o	   \
+$(SDIR)/tvgrid.$(ARCH).o	   \
+$(SDIR)/uniq.$(ARCH).o		   \
+$(SDIR)/unsign.$(ARCH).o	   \
+$(SDIR)/vbin.$(ARCH).o		   \
+$(SDIR)/vclip.$(ARCH).o		   \
+$(SDIR)/vgauss.$(ARCH).o           \
+$(SDIR)/vgrid.$(ARCH).o		   \
+$(SDIR)/vload.$(ARCH).o		   \
+$(SDIR)/vstat.$(ARCH).o		   \
+$(SDIR)/vroll.$(ARCH).o		   \
+$(SDIR)/vpop.$(ARCH).o		   \
+$(SDIR)/wd.$(ARCH).o		   \
+$(SDIR)/write_vectors.$(ARCH).o	   \
+$(SDIR)/zap.$(ARCH).o		   \
+$(SDIR)/zplot.$(ARCH).o
+
+libdatacmd:    $(DESTLIB)/libdatacmd.a 
+
+$(LIB)/libdatacmd.$(ARCH).a:   	$(datacmd)
+
+# utilities #################################################
+$(BIN)/%.$(ARCH):
+	@if [ ! -d $(BIN) ]; then mkdir -p $(BIN); fi
+	$(CC) $^ -o $@ $(LFLAGS) $(LIBS)
+	@echo "compiled $*"
+	@echo ""
+
+$(DESTBIN)/%: $(BIN)/%.$(ARCH) 
+	@if [ ! -d $(DESTBIN) ]; then mkdir -p $(DESTBIN); fi
+	rm -f $(DESTBIN)/$*
+	cp $(BIN)/$*.$(ARCH) $(DESTBIN)/$*
+	@echo "installed $*"
+	@echo ""
+
+$(LIB)/%.$(ARCH).a:
+	@if [ ! -d $(LIB) ]; then mkdir -p $(LIB); fi
+	rm -f $@
+	ar rcv $@ $^ 
+	$(RANLIB) $@
+	@echo "compiled library $*"
+	@echo ""
+
+$(DESTLIB)/%.a: $(LIB)/%.$(ARCH).a
+	@if [ ! -d $(DESTLIB) ]; then mkdir -p $(DESTLIB); fi
+	@echo ""
+	rm -f $@
+	cp $^ $@
+
+lib%.clean:
+	rm -f $(LIB)/lib$*.$(ARCH).a
+	rm -f $($*)
+	@echo ""
+
+%.clean:
+	rm -f $(BIN)/$*.$(ARCH)
+	@echo ""
+
+%.$(ARCH).o : %.c
+	$(CC) $(CFLAGS) -c $*.c -o $@
+
+clean:
+	rm -f $(BIN)/*.$(ARCH)
+	rm -f $(LIB)/*.$(ARCH).a
+	rm -f `find . -name "*.o"`
+	rm -f `find . -name "*~"`
+	rm -f `find . -name "#*"`
+
+dist: clean
+	rm -f $(BIN)/*
+	rm -f $(LIB)/*
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/accum.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/accum.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/accum.c	(revision 3338)
@@ -0,0 +1,72 @@
+# include "data.h"
+
+int accum (int argc, char **argv) {
+  
+  int i, Nbins, bin, N, Normalize;
+  float start, end, delta;
+  float *V, *K, *O, *NV;
+  Vector *val, *key, *out;
+
+  Normalize = FALSE;
+  if ((N = get_argument (argc, argv, "-norm"))) {
+    remove_argument (N, &argc, argv);
+    Normalize = TRUE;
+  }
+
+  if ((argc != 6) && (argc != 7)) {
+    fprintf (stderr, "USAGE: accum <value> <vector> <key> start end [delta]\n");
+    return (FALSE);
+  }
+
+  if ((val = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((key = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if (val[0].Nelements != key[0].Nelements) {
+    fprintf (stderr, "key and value don't match\n");
+    return (FALSE);
+  }
+  if ((out = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  start = atof (argv[4]);
+  end   = atof (argv[5]);
+  if (argc == 7) 
+    delta = atof (argv[6]);
+  else 
+    delta = 1;
+  if ((start == end) || (delta == 0)) {
+    fprintf (stderr, "error in value: %f to %f, %f\n", start, end, delta);
+    return (FALSE);
+  }
+  delta = fabs (delta);
+  if (end - start < 0) {
+    delta = -1.0 * delta;
+  }
+  Nbins = (end - start) / delta;
+
+  out[0].Nelements = Nbins;
+  REALLOCATE (out[0].elements, float, out[0].Nelements);
+  bzero (out[0].elements, sizeof(float)*out[0].Nelements);
+  if (Normalize) {
+    ALLOCATE (NV, float, Nbins);
+    bzero (NV, sizeof(float)*Nbins);
+  }
+
+  V = val[0].elements;
+  K = key[0].elements;
+  O = out[0].elements;
+
+  for (i = 0; i < val[0].Nelements; i++, V++, K++) {
+    bin = MIN (MAX (0, (*K - start) / delta), Nbins - 1);
+    O[bin] += *V;
+    if (Normalize) NV[bin] ++;
+  }      
+
+  if (Normalize) {
+    for (i = 0; i < Nbins; i++) {
+      O[i] /= (float) NV[i];
+    }
+    free (NV);
+  }
+
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/applyfit.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/applyfit.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/applyfit.c	(revision 3338)
@@ -0,0 +1,58 @@
+# include "data.h"
+
+char *get_variable (char *);
+
+int applyfit (int argc, char **argv) {
+  
+  int i, j, order;
+  char *c, name[64];
+  double *C, X;
+  float *x, *y;
+  Vector *xvec, *yvec;
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: applyfit x y\n");
+    return (FALSE);
+  }
+
+  c = get_variable ("Cn");
+  if (c == (char *) NULL) {
+    fprintf (stderr, "no fit available\n");
+    return (FALSE);
+  }
+  order = atof (c);
+
+  if ((xvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+  if ((yvec = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);    
+
+  ALLOCATE (C, double, order+1);
+  for (i = 0; i < order + 1; i++) {
+    sprintf (name, "C%d", i);
+    c = get_variable (name);
+    if (c == (char *) NULL) {
+      fprintf (stderr, "missing fit term %d\n", i);
+      return (FALSE);
+    }
+    C[i] = atof (c);
+  }
+  yvec[0].Nelements = xvec[0].Nelements;
+  REALLOCATE (yvec[0].elements, float, yvec[0].Nelements);
+  bzero (yvec[0].elements, sizeof(float)*yvec[0].Nelements);
+  x = xvec[0].elements;
+  y = yvec[0].elements;
+
+  for (j = 0; j < xvec[0].Nelements; j++, x++, y++) {
+    X = 1;
+    for (i = 0; i < order + 1; i++) {
+      *y += C[i]*X;
+      X = X * (*x);
+    }
+  }
+
+  return (TRUE);
+
+}
+
+
+
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/applyfit2d.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/applyfit2d.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/applyfit2d.c	(revision 3338)
@@ -0,0 +1,68 @@
+# include "data.h"
+
+char *get_variable (char *);
+
+int applyfit2d (int argc, char **argv) {
+  
+  int i, j, n, order;
+  char *c, name[64];
+  double **C, X, Y;
+  float *x, *y, *z;
+  Vector *xvec, *yvec, *zvec;
+
+  if (argc != 4) {
+    fprintf (stderr, "USAGE: applyfit x y z\n");
+    return (FALSE);
+  }
+
+  c = get_variable ("Cnn");
+  if (c == (char *) NULL) {
+    fprintf (stderr, "no fit available\n");
+    return (FALSE);
+  }
+  order = atof (c);
+
+  if ((xvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+  if ((yvec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+  if ((zvec = SelectVector (argv[3], ANYVECTOR, TRUE)) == NULL) return (FALSE);    
+
+  ALLOCATE (C, double *, order+1);
+  for (i = 0; i < order + 1; i++) {
+    ALLOCATE (C[i], double, order+1);
+    for (j = 0; j < order + 1 - i; j++) {
+      sprintf (name, "CX%dY%d", i, j);
+      c = get_variable (name);
+      if (c == (char *) NULL) {
+	fprintf (stderr, "missing fit term %d,%d\n", i, j);
+	return (FALSE);
+      }
+      C[i][j] = atof (c);
+    }
+  }
+
+  zvec[0].Nelements = xvec[0].Nelements;
+  REALLOCATE (zvec[0].elements, float, zvec[0].Nelements);
+  bzero (zvec[0].elements, sizeof(float)*zvec[0].Nelements);
+  x = xvec[0].elements;
+  y = yvec[0].elements;
+  z = zvec[0].elements;
+
+  for (n = 0; n < xvec[0].Nelements; n++, x++, y++, z++) {
+    Y = X = 1;
+    for (j = 0; j < order + 1; j++) {
+      X = Y;
+      for (i = 0; i < order + 1 - j; i++) {
+	*z += C[i][j]*X;
+	X = X * (*x);
+      }
+      Y = Y * (*y);
+    }
+  }
+
+  return (TRUE);
+
+}
+
+
+
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/box.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/box.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/box.c	(revision 3338)
@@ -0,0 +1,105 @@
+# include "data.h"
+
+int box (int argc, char **argv) {
+  
+  int i, N, Ngraph, Xgraph;
+  char buffer[65], buffer2[65];
+  Graphdata graphmode;
+  char Ticks[16], Axis[16], Labels[16];
+  
+  strcpy (Ticks, "2222");
+  if ((N = get_argument (argc, argv, "-ticks"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (Ticks, argv[N]);
+    remove_argument (N, &argc, argv);
+    if (strlen (Ticks) != 4) { goto usage; }
+    for (i = 0; i < strlen (Ticks); i++) {
+      if ((Ticks[i] != '0') && (Ticks[i] != '1') && (Ticks[i] != '2')) { goto usage; }
+    }
+  }
+  
+  strcpy (Labels, "2222");
+  if ((N = get_argument (argc, argv, "-labels"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (Labels, argv[N]);
+    remove_argument (N, &argc, argv);
+    if (strlen (Labels) != 4) { goto usage; }
+    for (i = 0; i < strlen (Labels); i++) {
+      if ((Labels[i] != '0') && (Labels[i] != '1') && (Labels[i] != '2')) { goto usage; }
+    }
+  }
+
+  strcpy (Axis, "2222");
+  if ((N = get_argument (argc, argv, "-axis"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (Axis, argv[N]);
+    remove_argument (N, &argc, argv);
+    if (strlen (Axis) != 4) { goto usage; }
+    for (i = 0; i < strlen (Axis); i++) {
+      if ((Axis[i] != '0') && (Axis[i] != '1') && (Axis[i] != '2')) { goto usage; }
+    }
+  }
+
+  Ngraph = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Ngraph = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetGraph (&graphmode, &Xgraph, &Ngraph)) return (FALSE);
+
+  if (argc != 1) goto usage;
+
+  write (Xgraph, "DBOX", 4);
+
+  snprintf (buffer, 64, "%12.6g %12.6g %12.6g %12.6g", graphmode.xmin, graphmode.xmax, graphmode.ymin, graphmode.ymax);
+  snprintf (buffer2, 64, "NBYTES: %6d", strlen (buffer));
+  write (Xgraph, buffer2, 16);
+  write (Xgraph, buffer, strlen (buffer));
+  
+  snprintf (buffer, 64, "%s %s %s", Axis, Labels, Ticks);
+  snprintf (buffer2, 64, "NBYTES: %6d", strlen (buffer));
+  write (Xgraph, buffer2, 16);
+  write (Xgraph, buffer, strlen (buffer));
+  
+  return (TRUE);
+      
+ usage:
+  fprintf (stderr, "USAGE: box [-ticks NNNN] [-axis NNNN] [-labels NNNN]\n");
+  return (FALSE);
+
+}
+
+
+/* box has:
+   axis
+   labels
+   ticks
+
+   assign like this:   
+   -axis 0000
+   -labels 0000
+   -ticks 0000
+
+   default:
+   -axis 1111
+   -labels 1100
+   -ticks 1111
+   
+
+
+   messages to kapa:
+
+   DBOX
+   (xmin) (xmax) (ymin) (ymax)
+   AAAA LLLL TTTT
+
+   A = axis
+   L = label
+   T = ticks
+   
+   0 = off
+   1 = on
+   2 = default / maintain
+
+*/
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/center.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/center.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/center.c	(revision 3338)
@@ -0,0 +1,39 @@
+# include "data.h"
+
+int center (int argc, char **argv) {
+  
+  double x, y;
+  int zoom;
+  char buffer[512], buffer2[20];
+  int Ximage, Nimage, N;
+  
+  Nimage = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nimage = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetImage (&Ximage, &Nimage)) return (FALSE);
+
+  if ((argc != 3) && (argc != 4)) {
+    fprintf (stderr, "USAGE: center x y [zoom]\n");
+    return (FALSE);
+  }
+
+  x = atof (argv[1]);
+  y = atof (argv[2]);
+  zoom = 0;
+  if (argc == 4) {
+    zoom = atof (argv[3]);
+  }
+
+  write (Ximage, "CENT", 4); /* tell Ximage to look for the incoming image */
+
+  sprintf (buffer, "%8.3f %8.3f %8d ", x, y, zoom);
+  sprintf (buffer2, "NBYTES %8d ", strlen (buffer));
+  write (Ximage, buffer2, 16);
+  write (Ximage, buffer, strlen (buffer));
+  
+  return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/clear.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/clear.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/clear.c	(revision 3338)
@@ -0,0 +1,36 @@
+# include "data.h"
+
+int clear (int argc, char **argv) {
+  
+  int N, ClearSection;
+  int Ngraph, Xgraph;
+
+  Ngraph = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Ngraph = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetGraph (NULL, &Xgraph, &Ngraph)) return (FALSE);
+
+  ClearSection = FALSE;
+  if ((N = get_argument (argc, argv, "-s"))) {
+    remove_argument (N, &argc, argv);
+    ClearSection = TRUE;
+  }
+
+  if (argc != 1) {
+    fprintf (stderr, "USAGE: clear [-n Xgraph]\n");
+    return (FALSE);
+  }
+
+  if (ClearSection) {
+    write (Xgraph, "ERAS", 4);
+  } else {
+    write (Xgraph, "ERSS", 4);
+  }
+  
+  return (TRUE);
+  
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/clip.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/clip.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/clip.c	(revision 3338)
@@ -0,0 +1,71 @@
+# include "data.h"
+
+int clip (int argc, char **argv) {
+
+  int i, Npix, DO_NAN, DO_INF, N;
+  double min, Vmin, max, Vmax, nan_val, inf_val;
+  float *in;
+  Buffer *buf;
+
+  DO_NAN = FALSE;
+  if ((N = get_argument (argc, argv, "-nan"))) {
+    remove_argument (N, &argc, argv);
+    nan_val  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    DO_NAN = TRUE;
+  }
+
+  DO_INF = FALSE;
+  if ((N = get_argument (argc, argv, "-inf"))) {
+    remove_argument (N, &argc, argv);
+    inf_val  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    DO_INF = TRUE;
+  }
+
+  if ((argc != 6) && (!(DO_INF || DO_NAN))) {
+    fprintf (stderr, "USAGE: clip (buffer) [min Vmin max Vmax] [-inf val] [-nan val]\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  if (argc == 6) {
+    min = atof (argv[2]);
+    Vmin = atof (argv[3]);
+    max = atof (argv[4]);
+    Vmax = atof (argv[5]);
+  }
+
+  Npix = buf[0].matrix.Naxis[0]*buf[0].matrix.Naxis[1];
+  in = (float *) buf[0].matrix.buffer;
+
+  if (argc == 6) {
+    for (i = 0; i < Npix; i++, in++) {
+      if (*in < min) 
+	*in = Vmin;
+      if (*in > max)
+	*in = Vmax;
+    }
+  }
+  in = (float *) buf[0].matrix.buffer;
+  if (DO_NAN) {
+    for (i = 0; i < Npix; i++, in++) {
+      if (isnan (*in)) {
+	*in = nan_val;
+      }
+    }
+  }
+  in = (float *) buf[0].matrix.buffer;
+  if (DO_INF) {
+    for (i = 0; i < Npix; i++, in++) {
+      if (!finite (*in)) {
+	*in = inf_val;
+      }
+    }
+  }
+  return (TRUE);
+
+}
+
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/concat.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/concat.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/concat.c	(revision 3338)
@@ -0,0 +1,39 @@
+# include "data.h"
+
+int concat (int argc, char **argv) {
+
+  int  i, j, Nin;
+  char *end;
+  double value;
+  Vector *ivec, *ovec;
+
+  /** check basic syntax **/
+  if (argc != 3) {
+    fprintf (stderr, "SYNTAX: concat (vector/value) vector\n");
+    fprintf (stderr, "  concatanate (vector/value) to vector\n");
+    return (FALSE);
+  }
+
+  if ((ovec = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  /* if argv[1] is a number, use just that */
+  value = strtod (argv[1], &end);
+  if (end == argv[1] + strlen(argv[1])) {
+    Nin = ovec[0].Nelements;
+    ovec[0].Nelements++;
+    REALLOCATE (ovec[0].elements, float, ovec[0].Nelements);
+    ovec[0].elements[Nin] = atof (argv[1]);
+    return (TRUE);
+  } 
+  
+  if ((ivec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  
+  REALLOCATE (ovec[0].elements, float, ovec[0].Nelements + ivec[0].Nelements);
+  for (j = ovec[0].Nelements, i = 0; i < ivec[0].Nelements; i++, j++) {
+    ovec[0].elements[j] = ivec[0].elements[i];
+  }
+  ovec[0].Nelements += ivec[0].Nelements;
+  
+  return (TRUE);
+    
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/contour.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/contour.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/contour.c	(revision 3338)
@@ -0,0 +1,262 @@
+# include "data.h"
+# define LL { \
+ dx =  d00 / (*v01 - *v00); \
+ dy = -d00 / (*v10 - *v00); \
+ x = i - 0.5; \
+ y = j - dy - 0.5; }
+
+# define UL { \
+ tmp = d00 / (*v10 - *v00); \
+ dy = 1 - tmp; \
+ dx =  d10 / (*v11 - *v10); \
+ x = i - 0.5; \
+ y = j + tmp - 0.5; }
+      
+# define LR { \
+ tmp = d00 / (*v01 - *v00); \
+ dx = 1 - tmp; \
+ dy = d01 / (*v11 - *v01); \
+ x = i + tmp - 0.5; \
+ y = j - 0.5; }
+
+# define UR { \
+ tmp = d10 / (*v11 - *v10); \
+ dx = 1 - tmp; \
+ dy = -d11 / (*v01 - *v11); \
+ x = i + tmp - 0.5; \
+ y = j + 1 - 0.5; }
+      
+# define HZ { \
+ tmp = d00 / (*v10 - *v00); \
+ dy = d01 / (*v11 - *v01) - tmp; \
+ dx = 1; \
+ x = i - 0.5; \
+ y = j + tmp - 0.5; }
+
+# define VT { \
+ tmp = d00 / (*v01 - *v00); \
+ dx = d10 / (*v11 - *v10) - tmp; \
+ x = i + tmp - 0.5; \
+ dy = 1; \
+ y = j - 0.5; }
+
+Vector *xv, *yv;
+int N, NVEC;
+
+void DUMP (float x, float y, float dx, float dy) {
+  
+  xv[0].elements[N]   = x;
+  xv[0].elements[N+1] = x+dx;
+  
+  yv[0].elements[N]   = y;
+  yv[0].elements[N+1] = y+dy;
+  
+  N+=2;
+
+  if (N >= NVEC - 2) {
+    NVEC += 100;
+    REALLOCATE (xv[0].elements, float, NVEC);
+    REALLOCATE (yv[0].elements, float, NVEC);
+  }
+}
+
+int contour (int argc, char **argv) {
+
+  int i, j, Nx, Ny;
+  float level, d00, d01, d10, d11, tmp;
+  float x, y, dx, dy;
+  float *v00, *v01, *v10, *v11;
+  float *matrix;
+  Buffer *buf;
+  
+  if (argc != 5) {
+    fprintf (stderr, "USAGE: contour <buffer> X Y level\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((xv = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yv = SelectVector (argv[3], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  level = atof (argv[4]);
+  matrix = (float *)(buf[0].matrix.buffer);
+  Nx = buf[0].matrix.Naxis[0];
+  Ny = buf[0].matrix.Naxis[1];
+
+  v00 = matrix;
+  v01 = matrix + 1;
+  v10 = matrix + Nx;
+  v11 = matrix + Nx + 1;
+  d01 = (level - *v00);
+  d11 = (level - *v10);
+
+  N = 0;
+  NVEC = 100;
+  REALLOCATE (xv[0].elements, float, NVEC);
+  REALLOCATE (yv[0].elements, float, NVEC);
+
+  for (j = 1; j < Ny; j++) {
+    if (!(j%10)) fprintf (stderr, ".");
+    for (i = 1; i < Nx; i++, v00++, v01++, v10++, v11++) {
+
+      d00 = d01;
+      d10 = d11;
+      d01 = (level - *v01);
+      d11 = (level - *v11);
+
+      if (((d00 > 0) && (d01 > 0) && (d10 > 0) && (d11 > 0)) ||
+	  ((d00 < 0) && (d01 < 0) && (d10 < 0) && (d11 < 0)))
+	continue;
+
+      if ((d00 > 0) && (d10 <= 0)) { 
+	if ((d01 <= 0) && (d11 <= 0)) { /* \  */
+	  LL;
+	  DUMP (x,y,dx,dy);
+	  continue;
+	}
+	if ((d01 > 0) && (d11 <= 0)) { /* -  */
+	  HZ;
+	  DUMP (x,y,dx,dy);
+	  continue;
+	}
+	if ((d01 > 0) && (d11 > 0)) { /* /  */
+	  UL;
+	  DUMP (x,y,dx,dy);
+	  continue;
+	}
+	if ((d01 <= 0) && (d11 > 0)) { /* \\  */
+	  LL;
+	  DUMP (x,y,dx,dy);
+	  UR;
+	  DUMP (x,y,dx,dy);
+	  continue;
+	}
+      }
+
+      if ((d00 <= 0) && (d10 > 0)) {
+	if ((d01 > 0) && (d11 > 0)) { /* \  */
+	  LL;
+	  DUMP (x,y,dx,dy);
+	  continue;
+	}
+	if ((d01 <= 0) && (d11 > 0)) { /* -  */
+	  HZ;
+	  DUMP (x,y,dx,dy);
+	  continue;
+	}
+	if ((d01 <= 0) && (d11 <= 0)) { /* /  */
+	  UL;
+	  DUMP (x,y,dx,dy);
+	  continue;
+	}
+	if ((d01 > 0) && (d11 <= 0)) { /* //  */
+	  UL;
+	  DUMP (x,y,dx,dy);
+	  LR;
+	  DUMP (x,y,dx,dy);
+	  continue;
+	}
+      }
+      
+
+      if ((d00 <= 0) && (d10 <= 0)) { 
+	if ((d01 > 0) && (d11 <= 0)) {
+	  LR;
+	  DUMP (x,y,dx,dy);
+	  continue;
+	}
+	if ((d01 <= 0) && (d11 > 0)) {
+	  UR;
+	  DUMP (x,y,dx,dy);
+	  continue;
+	}
+	if ((d01 > 0) && (d11 > 0)) {
+	  VT;
+	  DUMP (x,y,dx,dy);
+	  continue;
+	}
+      }
+
+      if ((d00 > 0) && (d10 > 0)) { 
+	if ((d01 <= 0) && (d11 > 0)) {
+	  LR;
+	  DUMP (x,y,dx,dy);
+	  continue;
+	}
+	if ((d01 > 0) && (d11 <= 0)) {
+	  UR;
+	  DUMP (x,y,dx,dy);
+	  continue;
+	}
+	if ((d01 <= 0) && (d11 <= 0)) {
+	  VT;
+	  DUMP (x,y,dx,dy);
+	  continue;
+	}
+      }
+
+    }
+    /* skip left-hand edge */
+    v00++; v01++; v10++; v11++;
+    d01 = (level - *v00);
+    d11 = (level - *v10);
+  }
+
+  /****** bottom line *******/
+  v00 = matrix;  
+  v01 = matrix + 1;  
+  y = 0;
+  dx = 0;
+  dy = -0.5;
+  for (i = 1; i < Nx; i++, v00++, v01++) { /* do the edges */
+    if (((*v00 > level) && (*v01 <= level)) || ((*v00 <= level) && (*v01 > level))) {
+      x = i + (level - *v01)/(*v01 - *v00);
+      DUMP (x,y,dx,dy);
+    }
+  }
+
+  /********** top line *******/
+  v00 = matrix + Nx*(Ny - 1);  
+  v01 = v00 + 1;
+  y = Ny - 1;
+  dx = 0;
+  dy = 0.5;
+  for (i = 1; i < Nx; i++, v00++, v01++) { /* do the edges */
+    if (((*v00 > level) && (*v01 <= level)) || ((*v00 <= level) && (*v01 > level))) {
+      x = i + (level - *v01)/(*v01 - *v00);
+      DUMP (x,y,dx,dy);
+    }
+  }
+
+  /******** left line *********/
+  v00 = matrix; 
+  v01 = matrix + Nx;
+  x = 0;
+  dx = -0.5;
+  dy = 0;
+  for (j = 1; j < Ny; j++, v00+=Nx, v01+=Nx) { /* do the edges */
+    if (((*v00 > level) && (*v01 <= level)) || ((*v00 <= level) && (*v01 > level))) {
+      y = j + (level - *v01)/(*v01 - *v00);
+      DUMP (x,y,dx,dy);
+    }
+  }
+
+  /******** right line *********/
+  v00 = matrix + Nx - 1; 
+  v01 = v00 + Nx;
+  x = Nx - 1;
+  dx = 0.5;
+  dy = 0;
+  for (j = 1; j < Ny; j++, v00+=Nx, v01+=Nx) { /* do the edges */
+    if (((*v00 > level) && (*v01 <= level)) || ((*v00 <= level) && (*v01 > level))) {
+      y = j + (level - *v01)/(*v01 - *v00);
+      DUMP (x,y,dx,dy);
+    }
+  }
+  
+/* free anything? */
+
+  xv[0].Nelements = N;
+  yv[0].Nelements = N;
+  return (TRUE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/create.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/create.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/create.c	(revision 3338)
@@ -0,0 +1,79 @@
+# include "data.h"
+
+int imcreate (int argc, char **argv);
+
+int create (int argc, char **argv) {
+  
+  int i, N;
+  float start, end, delta;
+  Vector *vec;
+  
+  if ((N = get_argument (argc, argv, "-image"))) {
+    remove_argument (N, &argc, argv);
+    return (imcreate (argc, argv));
+  }
+  
+  if ((argc != 5) && (argc != 4)) {
+    fprintf (stderr, "USAGE: create vector start end [delta]\n");
+    return (FALSE);
+  }
+
+  if ((vec = SelectVector (argv[1], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  start = atof (argv[2]);
+  end   = atof (argv[3]);
+  delta = 1;
+  if (argc == 5) delta = atof (argv[4]);
+  if ((start == end) || (delta == 0)) {
+    fprintf (stderr, "error in value: %f to %f, %f\n", start, end, delta);
+    return (FALSE);
+  }
+  delta = fabs (delta);
+  if (end - start < 0) {
+    delta = -1.0 * delta;
+  }
+
+  vec[0].Nelements = (end - start) / delta;
+  REALLOCATE (vec[0].elements, float, vec[0].Nelements);
+
+  for (i = 0; i < vec[0].Nelements; i++) {
+    vec[0].elements[i] = start + i*delta;
+  }
+
+  return (TRUE);
+}
+
+
+int imcreate (int argc, char **argv) {
+  
+  Buffer *buf;
+
+  if (argc != 4) {
+    fprintf (stderr, "USAGE: create -image buffer Nx Ny\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+  fits_free_matrix (&buf[0].matrix);
+  fits_free_header (&buf[0].header);
+
+  buf[0].bitpix = 16;
+  buf[0].unsign = FALSE;
+  buf[0].bscale = 1.0;
+  buf[0].bzero  = 0x8000;
+
+  buf[0].header.bitpix = -32;
+  buf[0].header.unsign = FALSE;
+  buf[0].header.bscale = 1.0;
+  buf[0].header.bzero  = 0.0;
+
+  buf[0].header.Naxes = 2;
+  buf[0].header.Naxis[0] = atoi (argv[2]);
+  buf[0].header.Naxis[1] = atoi (argv[3]);
+
+  fits_create_header (&buf[0].header);
+  fits_create_matrix (&buf[0].header, &buf[0].matrix);
+
+  return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/cursor.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/cursor.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/cursor.c	(revision 3338)
@@ -0,0 +1,93 @@
+# include "data.h"
+
+int cursor (int argc, char **argv) {
+
+  char buffer[40], string[20], key;
+  int i, N, Nsource, Source, IsImage;
+  double X, Y, R, D, Z;
+  void *oldsignal;
+  Graphdata graphmode;
+  Buffer *buf;
+
+  Nsource = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nsource = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-g"))) {
+    remove_argument (N, &argc, argv);
+    SetImageDevice (FALSE);
+  }  
+  if ((N = get_argument (argc, argv, "-i"))) {
+    remove_argument (N, &argc, argv);
+    SetImageDevice (TRUE);
+  }  
+  IsImage = GetCurrentDevice ();
+  if (IsImage) {
+    if (!GetImage (&Source, &Nsource)) return (FALSE);
+  } else {
+    if (!GetGraph (&graphmode, &Source, &Nsource)) return (FALSE);
+  }
+
+  N = 0;
+  if (argc == 2) N = atof (argv[1]);
+
+  if ((argc != 1) && (argc != 2)) {
+    fprintf (stderr, "USAGE: cursor [Npts] [-n window] [-g | -i]\n");
+    return (FALSE);
+  }
+  
+  buf = NULL;
+  if (IsImage) buf = SelectBuffer (GetImageName(), OLDBUFFER, FALSE);
+  
+  sprintf (string, "CURS");
+  write (Source, string, 4); /* ask Source to look for the keystrokes */
+  
+  oldsignal = signal (SIGINT, handle_interrupt);
+  interrupt = FALSE;
+  Z = -1.0;
+  for (i = 0; ((i < N) || (N == 0)) && !interrupt; i++) {
+    bzero (buffer, 20);
+    read (Source, buffer, 32);
+    buffer[32] = 0;
+    sscanf (buffer, "%c %lf %lf", &key, &X, &Y);
+
+    sprintf (string, "X%1c", key);
+    set_variable (string, X);
+    sprintf (string, "Y%1c", key);
+    set_variable (string, Y);
+    sprintf (string, "%c", key);
+    set_str_variable ("KEY", string);
+    
+    if (IsImage && (buf != NULL)) 
+      Z = fits_get_matrix_value (&buf[0].matrix, (int)X, (int)Y);
+
+    if (!IsImage) {
+      XY_to_RD (&R, &D, X, Y, &graphmode.coords);
+      sprintf (string, "R%1c", key);
+      set_variable (string, R);
+      sprintf (string, "D%1c", key);
+      set_variable (string, D);
+    }
+
+    /* I still don't like this, but I have to decide which to print... */
+    if (IsImage) {
+      fprintf (GetOutfile(), "%c %f %f  %f\n", key, X, Y, Z);
+    } else {
+      fprintf (GetOutfile(), "%c %f %f\n", key, X, Y);
+    }
+
+    if ((key == 'q') || (key == 'Q')) {
+      signal (SIGINT, (void *) oldsignal);
+      write (Source, "NCUR", 4); /* ask Source to stop looking for the keystrokes */
+      return (TRUE);
+    }
+
+  }
+
+  signal (SIGINT, oldsignal);
+  write (Source, "NCUR", 4); /* ask Source to look for the keystrokes */
+  return (TRUE);
+      
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/cut.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/cut.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/cut.c	(revision 3338)
@@ -0,0 +1,120 @@
+# include "data.h"
+
+enum {SUM, MEAN, MEDIAN};
+
+int cut (int argc, char **argv) {
+  
+  int i, j, N, Nx, Ny, Mode;
+  float *Vin, *Vbuf, value;
+  int sx, sy, nx, ny;
+  Vector *xvec, *yvec;
+  Buffer *buf;
+
+  Mode = SUM;
+  if ((N = get_argument (argc, argv, "-median"))) {
+    remove_argument (N, &argc, argv);
+    Mode = MEDIAN;
+  }
+  if ((N = get_argument (argc, argv, "-mean"))) {
+    remove_argument (N, &argc, argv);
+    Mode = MEAN;
+  }
+
+  if (argc != 9) {
+    fprintf (stderr, "USAGE: cut <buffer> <X vector> <Y vector> <X|Y> sx sy nx ny\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+ 
+  sx = atof (argv[5]);
+  sy = atof (argv[6]);
+  nx = atof (argv[7]);
+  ny = atof (argv[8]);
+
+  Nx = buf[0].matrix.Naxis[0];
+  Ny = buf[0].matrix.Naxis[1];
+
+  if ((sx < 0) || (sy < 0) || (sx+nx > Nx) || (sy+ny > Ny)) {
+    fprintf (stderr, "region out of range\n");
+    return (FALSE);
+  }
+
+  if ((xvec = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yvec = SelectVector (argv[3], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  switch (argv[4][0]) {
+  case 'x':
+  case 'X':
+    /* create output vectors */
+    xvec[0].Nelements = yvec[0].Nelements = nx;
+    REALLOCATE (xvec[0].elements, float, MAX (nx, 1));
+    REALLOCATE (yvec[0].elements, float, MAX (nx, 1));
+    bzero (yvec[0].elements, nx*sizeof(float));
+    for (i = 0; i < nx; i++) {
+      xvec[0].elements[i] = i + sx; 
+    }
+    ALLOCATE (Vbuf, float, MAX (ny, 1));
+
+    for (i = 0; i < nx; i++) {
+      /* accumulate values */
+      Vin = (float *)(buf[0].matrix.buffer) + sy*Nx + sx + i; 
+      for (j = 0; j < ny; j++, Vin += Nx) {
+	Vbuf[j] = *Vin;
+      }
+      /* apply stat of choice */
+      if (Mode == MEDIAN) {
+	fsort (Vbuf, ny);
+	value = Vbuf[(int)(0.5*ny)];
+      } else {
+	value = 0;
+	for (j = 0; j < ny; j++) {
+	  value += Vbuf[j];
+	}
+	if (Mode == MEAN) { value /= ny; }
+      }
+      yvec[0].elements[i] = value;
+    }
+    break;
+    
+  case 'y':
+  case 'Y':
+    xvec[0].Nelements = yvec[0].Nelements = ny;
+    REALLOCATE (xvec[0].elements, float, ny);
+    REALLOCATE (yvec[0].elements, float, ny);
+    bzero (yvec[0].elements, ny*sizeof(float));
+    for (i = 0; i < ny; i++) {
+      xvec[0].elements[i] = i + sy; 
+    }
+    ALLOCATE (Vbuf, float, MAX (nx, 1));
+
+    for (i = 0; i < ny; i++) {
+      /* accumulate values */
+      Vin = (float *)(buf[0].matrix.buffer) + (sy + i)*Nx + sx; 
+      for (j = 0; j < nx; j++, Vin ++) {
+	Vbuf[j] = *Vin;
+      }
+      /* apply stat of choice */
+      if (Mode == MEDIAN) {
+	fsort (Vbuf, nx);
+	value = Vbuf[(int)(0.5*nx)];
+      } else {
+	value = 0;
+	for (j = 0; j < nx; j++) {
+	  value += Vbuf[j];
+	}
+	if (Mode == MEAN) { value /= nx; }
+      }
+      yvec[0].elements[i] = value;
+    }
+    break;
+
+  default:
+    fprintf (stderr, "<dir> can be X or Y\n");
+    return (FALSE);
+    break;
+  }
+
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/delete.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/delete.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/delete.c	(revision 3338)
@@ -0,0 +1,31 @@
+# include "data.h"
+
+int delete (int argc, char **argv) {
+  
+  int i, N, Quiet;
+
+  Quiet = FALSE;
+  if ((N = get_argument (argc, argv, "-q"))) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-quiet"))) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc < 2) {
+    fprintf (stderr, "USAGE: delete <obiect> [<object> ..]\n");
+    return (FALSE);
+  }
+
+  for (i = 1; i < argc; i++) {
+    if (DeleteNamedBuffer (argv[i])) continue;
+    if (DeleteNamedVector (argv[i])) continue;
+    if (DeleteNamedScalar (argv[i])) continue;
+    if (!Quiet) fprintf (stderr, "can't find object %s\n", argv[i]);
+  }
+
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/device.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/device.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/device.c	(revision 3338)
@@ -0,0 +1,33 @@
+# include "data.h"
+
+int device (int argc, char **argv) {
+
+  int N, Source, Nsource, IsImage;
+  /* set / get current graphics device */
+
+  Nsource = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nsource = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-g"))) {
+    remove_argument (N, &argc, argv);
+    SetImageDevice (FALSE);
+  }  
+  if ((N = get_argument (argc, argv, "-i"))) {
+    remove_argument (N, &argc, argv);
+    SetImageDevice (TRUE);
+  }  
+
+  IsImage = GetCurrentDevice ();
+  if (IsImage) {
+    if (!GetImage (&Source, &Nsource)) return (FALSE);
+    fprintf (stderr, "kii %d\n", Nsource); 
+  } else {
+    if (!GetGraph (NULL, &Source, &Nsource)) return (FALSE);
+    fprintf (stderr, "kapa %d\n", Nsource); 
+  }
+
+  return (TRUE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/dimendown.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/dimendown.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/dimendown.c	(revision 3338)
@@ -0,0 +1,34 @@
+# include "data.h"
+
+int dimendown (int argc, char **argv) {
+  
+  int i, Nx, Ny, Npix;
+  float *in, *out;
+  Vector *vec;
+  Buffer *buf;
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: dimendown <buffer> <vector>\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((vec = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  Nx = buf[0].matrix.Naxis[0];
+  Ny = buf[0].matrix.Naxis[1];
+  Npix = Nx * Ny;
+
+  vec[0].Nelements = Npix;
+  REALLOCATE (vec[0].elements, float, Npix);
+
+  in = (float *) buf[0].matrix.buffer;
+  out = vec[0].elements;
+
+  for (i = 0; i < Npix; i++, in++, out++) {
+    *out = *in;
+  }
+
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/dimenup.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/dimenup.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/dimenup.c	(revision 3338)
@@ -0,0 +1,51 @@
+# include "data.h"
+
+int dimenup (int argc, char **argv) {
+  
+  int i, Nx, Ny, Npix;
+  float *in, *out;
+  Vector *vec;
+  Buffer *buf;
+
+  if (argc != 5) {
+    fprintf (stderr, "USAGE: dimenup <vector> <buffer> Nx Ny\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((vec = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  Npix = vec[0].Nelements;
+  Nx = atof (argv[3]);
+  Ny = atof (argv[4]);
+  if (Npix != Nx * Ny) {
+    fprintf (stderr, "dimensions don't match\n");
+    return (FALSE);
+  }
+
+  buf[0].matrix.Naxis[0] = Nx;
+  buf[0].matrix.Naxis[1] = Ny;
+
+  /* I should encapsulate this in a create_default_buffer */
+  fits_free_matrix (&buf[0].matrix);
+  fits_free_header (&buf[0].header);
+  buf[0].header.bitpix = buf[0].bitpix = -32;
+  buf[0].header.unsign = buf[0].unsign = FALSE;
+  buf[0].header.bscale = buf[0].bscale = 1.0;
+  buf[0].header.bzero  = buf[0].bzero  = 0.0;
+  buf[0].header.Naxes = 2;
+  buf[0].header.Naxis[0] = Nx;
+  buf[0].header.Naxis[1] = Ny;
+  fits_create_header (&buf[0].header);
+  fits_create_matrix (&buf[0].header, &buf[0].matrix);
+
+  out = (float *) buf[0].matrix.buffer;
+  in = vec[0].elements;
+
+  for (i = 0; i < Npix; i++, in++, out++) {
+    *out = *in;
+  }
+
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/dot.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/dot.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/dot.c	(revision 3338)
@@ -0,0 +1,81 @@
+# include "data.h"
+
+int dot (int argc, char **argv) {
+  
+  int N, Npts, Ngraph;
+  Graphdata graphmode;
+  float x, y;
+
+  /* choose the appropriate graphing window */
+  Ngraph = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Ngraph = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetGraph (&graphmode, NULL, &Ngraph)) return (FALSE);
+
+  /* evaluate various plotting options */
+  if ((N = get_argument (argc, argv, "-lt"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.ltype = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-lw"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.lweight = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-pt"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.ptype = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "+eb"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.ebar = TRUE;
+  }
+  if ((N = get_argument (argc, argv, "-eb"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.ebar = FALSE;
+  }
+  if ((N = get_argument (argc, argv, "-sz"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.size = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-c"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.color = GetColor (argv[N]);
+    if (graphmode.color == -1) return (FALSE);
+    remove_argument (N, &argc, argv);
+  }
+  /* only -x 2 makes sense here
+  if ((N = get_argument (argc, argv, "-x"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.style = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  */
+  graphmode.style = 2;
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: plot <x> <y>\n");
+    return (FALSE);
+  }
+  x = atof(argv[1]);
+  y = atof(argv[2]);
+
+  /* set plotting options (these are sticky) */
+  SetGraph (graphmode);
+
+  /* set errorbar mode (these are NOT sticky) */
+  graphmode.etype = 0;
+
+  if (!PrepPlotting (1, &graphmode)) return (FALSE);
+  
+  PlotVector (1, &x);
+  PlotVector (1, &y);
+  
+  return (TRUE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/erase.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/erase.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/erase.c	(revision 3338)
@@ -0,0 +1,53 @@
+# include "data.h"
+
+int erase (int argc, char **argv) {
+  
+  int i, n, N;
+  char buffer[128];
+  int Ximage, Nimage;
+  
+  Nimage = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nimage = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetImage (&Ximage, &Nimage)) return (FALSE);
+
+  if (argc < 2) {
+    fprintf (stderr, "USAGE: erase (overlay) [overlay, overlay, ..] \n");
+    fprintf (stderr, " (overlay) may be: red (0), green (1), blue (2), yellow (3) or all\n");
+    return (FALSE);
+  }
+
+  for (i = 1; i < argc; i++) {
+    if (strcmp (argv[i], "0")   && strcmp (argv[i], "1")     && strcmp (argv[i], "2")   && strcmp (argv[i], "3") &&
+	strcmp (argv[i], "red") && strcmp (argv[i], "green") && strcmp (argv[i], "blue") && strcmp (argv[i], "yellow") &&
+	strcmp (argv[i], "all") && strcmp (argv[i], "tick") ) {
+      fprintf (stderr, "%s is not a valid overlay\n", argv[i]);
+      return (FALSE);
+    }
+    n = atof (argv[i]);
+    if (!(strcmp (argv[i], "all"))) {
+      for (n = 0; n < 4; n++) {
+	write (Ximage, "ERAS", 4); /* force Ximage to look for the incoming image */
+	sprintf (buffer, "OVERLAY %7d ", n);
+	write (Ximage, buffer, 16);
+      }
+      return (TRUE);
+    }
+    
+    if (!(strcmp (argv[i], "red"))) n = 0;
+    if (!(strcmp (argv[i], "green"))) n = 1;
+    if (!(strcmp (argv[i], "blue"))) n = 2;
+    if (!(strcmp (argv[i], "yellow"))) n = 3;
+    if (!(strcmp (argv[i], "tick"))) n = 4;
+    
+    write (Ximage, "ERAS", 4); /* force Ximage to look for the incoming image */
+    sprintf (buffer, "OVERLAY %7d ", n);
+    write (Ximage, buffer, 16);
+  }
+
+  return (TRUE);
+  
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/extract.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/extract.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/extract.c	(revision 3338)
@@ -0,0 +1,92 @@
+# include "data.h"
+
+int extract (int argc, char **argv) {
+  
+  int i, j;
+  float *Vin, *Vout;
+  int sx, sy, nx, ny, NX, NY;
+  int Sx, Sy, Nx, Ny;
+  Buffer *in, *out;
+
+  if (argc != 11) {
+    fprintf (stderr, "USAGE: extract <from> <to> sx sy nx ny Sx Sy Nx Ny\n");
+    return (FALSE);
+  }
+
+  if ((in = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  NX = in[0].matrix.Naxis[0];
+  NY = in[0].matrix.Naxis[1];
+
+  sx = atof (argv[3]);
+  sy = atof (argv[4]);
+  nx = atof (argv[5]);
+  ny = atof (argv[6]);
+
+  Sx = atof (argv[7]);
+  Sy = atof (argv[8]);
+  Nx = atof (argv[9]);
+  Ny = atof (argv[10]);
+
+  if ((Sy + ny > Ny) || (Sx + nx > Nx)) {
+    fprintf (stderr, "mismatch between source and dest regions\n");
+    fprintf (stderr, "%d + %d > %d or %d + %d > %d\n", Sy, ny, Ny, Sx, nx, Nx);
+    return (FALSE);
+  }
+
+  /* region is not on first image */
+  if ((sx + nx < 0) || (sy + ny < 0) || 
+      (sx > in[0].matrix.Naxis[0]) || 
+      (sy > in[0].matrix.Naxis[1])) {
+    fprintf (stderr, "region outside of source image\n");
+    return (FALSE);
+  }
+
+  if ((Sx + nx > Nx) || (Sy + ny > Ny)) {
+    fprintf (stderr, "source region larger than dest region\n");
+    return (FALSE);
+  }
+  if ((Sx < 0) || (Sy < 0)) {
+    fprintf (stderr, "dest region out of range\n");
+    return (FALSE);
+  }
+
+  if ((out = SelectBuffer (argv[2], OLDBUFFER, FALSE)) == NULL) {
+    if ((out = SelectBuffer (argv[2], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+    fits_free_matrix (&out[0].matrix);
+    fits_free_header (&out[0].header);
+
+    out[0].bitpix = in[0].bitpix;
+    out[0].unsign = in[0].unsign;
+    out[0].bscale = in[0].bscale;
+    out[0].bzero  = in[0].bzero;
+    fits_copy_header (&in[0].header, &out[0].header);
+    fits_modify (&out[0].header, "NAXIS1", "%d", 1, Nx);
+    fits_modify (&out[0].header, "NAXIS2", "%d", 1, Ny);
+    out[0].header.Naxis[0] = Nx;
+    out[0].header.Naxis[1] = Ny;
+    fits_create_matrix (&out[0].header, &out[0].matrix);
+  } else {
+    if ((out[0].header.Naxis[1] != Ny) || (out[0].header.Naxis[0] != Nx)) {
+      fprintf (stderr, "matrix sizes mis-matched\n");
+      fprintf (stderr, "%d x %d  vs  %d x %d\n", Nx, Ny, 
+	       out[0].header.Naxis[0], out[0].header.Naxis[1]);
+      return (FALSE);
+    }
+  }
+
+  for (j = 0; j < ny; j++) {
+    if (j + sy < 0) continue;
+    if (j + sy >= NY) continue;
+    Vin = (float *)(in[0].matrix.buffer) + (j + sy)*in[0].matrix.Naxis[0] + sx;  
+    Vout = (float *)(out[0].matrix.buffer) + (j + Sy)*out[0].matrix.Naxis[0] + Sx;   
+    for (i = 0; i < nx; i++, Vin++, Vout++) {
+      if (i + sx < 0) continue;
+      if (i + sx >= NX) continue;
+      *Vout = *Vin;
+    }
+  }
+
+  return (TRUE);
+
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/fft1d.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/fft1d.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/fft1d.c	(revision 3338)
@@ -0,0 +1,69 @@
+# include "data.h"
+
+int fft1d (int argc, char **argv) {
+  
+  int i, Npix, ZeroImaginary;
+  float *t1, *t2, *temp;
+  Vector *Ire, *Iim, *Ore, *Oim;
+
+  if ((argc != 6) || (strcmp (argv[3], "to"))) {
+    fprintf (stderr, "USAGE: fft1d (real) (imag) to (real) (imag)\n");
+    return (FALSE);
+  }
+
+  ZeroImaginary = TRUE;
+  if ((Ire = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if (strcmp (argv[2], "0")) {
+    ZeroImaginary = FALSE;
+    if ((Iim = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  }    
+  if ((Ore = SelectVector (argv[4], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((Oim = SelectVector (argv[5], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  Npix = Ire[0].Nelements;
+  if (!ZeroImaginary && (Npix != Iim[0].Nelements)) {
+    fprintf (stderr, "vector mismatch in size\n");
+    return (FALSE);
+  }
+
+  if (!IsBinary (Npix)) {
+    fprintf (stderr, "Npix is not a binary number!\n");
+    return (FALSE);
+  }
+  
+  ALLOCATE (temp, float, 2*Npix);
+  if (ZeroImaginary) {
+    t1 = Ire[0].elements;
+    for (i = 0; i < Npix; i++, t1++) {
+      temp[2*i  ] = *t1;
+      temp[2*i+1] = 0;
+    }
+  } else {
+    t1 = Ire[0].elements;
+    t2 = Iim[0].elements;
+    for (i = 0; i < Npix; i++, t1++, t2++) {
+      temp[2*i  ] = *t1;
+      temp[2*i+1] = *t2;
+    }
+  }    
+    
+  fft (temp, Npix, 1); 
+
+  Ore[0].Nelements = Npix;
+  Oim[0].Nelements = Npix;
+  REALLOCATE (Ore[0].elements, float, Npix);
+  REALLOCATE (Oim[0].elements, float, Npix);
+ 
+  t1 = Ore[0].elements;
+  t2 = Oim[0].elements;
+  for (i = 0; i < Npix; i++, t1++, t2++) {
+    *t1 = temp[2*i  ] / Npix;
+    *t2 = temp[2*i+1] / Npix;
+  }    
+  
+  free (temp);
+  
+  return (TRUE);
+}
+
+  
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/fft2d.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/fft2d.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/fft2d.c	(revision 3338)
@@ -0,0 +1,112 @@
+# include "data.h"
+
+int fft2d (int argc, char **argv) {
+  
+  int i, N, Nx, Ny, Naxis[2];
+  int Npix, ZeroImaginary, isign;
+  float *t1, *t2, *out, *temp;
+  Buffer *Ire, *Iim, *Ore, *Oim;;
+
+  isign = 1;
+  if ((N = get_argument (argc, argv, "-inverse"))) {
+    remove_argument (N, &argc, argv);
+    isign = -1;
+  }
+
+  if ((argc != 6) || (strcmp (argv[3], "to"))) {
+    fprintf (stderr, "USAGE: fft2d (real) (imag) to (real) (imag)\n");
+    return (FALSE);
+  }
+
+  /* select input / output buffers */
+  if ((Ire = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  ZeroImaginary = TRUE; /* Input(imaginary) may be 0, in which case we create a 0 filled image */
+  if (!strcmp (argv[2], "0")) { 
+  } else {
+    ZeroImaginary = FALSE;
+    if ((Iim = SelectBuffer (argv[2], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  }    
+  if ((Ore = SelectBuffer (argv[4], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((Oim = SelectBuffer (argv[5], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+
+  /* free up output space */
+  fits_free_matrix (&Ore[0].matrix);
+  fits_free_header (&Ore[0].header);
+  fits_free_matrix (&Oim[0].matrix);
+  fits_free_header (&Oim[0].header);
+
+  /* get image dimensions, check value */
+  Npix = Ire[0].header.Naxis[0]*Ire[0].header.Naxis[1];
+  Nx = Ire[0].header.Naxis[0];
+  Ny = Ire[0].header.Naxis[1];
+  Naxis[0] = Ny; Naxis[1] = Nx;
+  if (!IsBinary (Npix)) {
+    fprintf (stderr, "dimensions are not binary!\n");
+    return (FALSE);
+  }
+  
+  /* create working space */
+  t1 = (float *) Ire[0].matrix.buffer;
+  ALLOCATE (temp, float, 2*Npix);
+  out = temp;
+
+  /* copy input to working space */
+  if (ZeroImaginary) {
+    for (i = 0; i < Npix; i++, t1++) {
+      *out = *t1;
+      out++;
+      *out = 0;
+      out++;
+    }
+  } else {
+    t2 = (float *) Iim[0].matrix.buffer;
+    for (i = 0; i < Npix; i++, t1++, t2++) {
+      *out = *t1;
+      out++;
+      *out = *t2;
+      out++;
+    }
+  } 
+    
+  /* run the fft */
+  fftN (temp, Naxis, 2, isign);
+
+  /* fix up output headers (real) */
+  fits_copy_header (&Ire[0].header, &Ore[0].header);
+  fits_modify (&Ore[0].header, "NAXIS1", "%d", 1, Nx);
+  fits_modify (&Ore[0].header, "NAXIS2", "%d", 1, Ny);
+  Ore[0].header.Naxis[0] = Nx;
+  Ore[0].header.Naxis[1] = Ny;
+  Ore[0].bitpix = Ire[0].bitpix;
+  Ore[0].unsign = Ire[0].unsign;
+  Ore[0].bscale = Ire[0].bscale;
+  Ore[0].bzero  = Ire[0].bzero;
+  fits_create_matrix (&Ore[0].header, &Ore[0].matrix);
+
+  /* fix up output headers (imaginary) */
+  fits_copy_header (&Ire[0].header, &Oim[0].header);
+  fits_modify (&Oim[0].header, "NAXIS1", "%d", 1, Nx);
+  fits_modify (&Oim[0].header, "NAXIS2", "%d", 1, Ny);
+  Oim[0].header.Naxis[0] = Nx;
+  Oim[0].header.Naxis[1] = Ny;
+  Oim[0].bitpix = Ire[0].bitpix;
+  Oim[0].unsign = Ire[0].unsign;
+  Oim[0].bscale = Ire[0].bscale;
+  Oim[0].bzero  = Ire[0].bzero;
+  fits_create_matrix (&Oim[0].header, &Oim[0].matrix);
+
+  /* move data from working space to output buffers */
+  out = temp;
+  t1 = (float *) Ore[0].matrix.buffer;
+  t2 = (float *) Oim[0].matrix.buffer;
+  for (i = 0; i < Npix; i++, t1++, t2++) {
+    *t1 = *out / Npix;
+    out ++;
+    *t2 = *out / Npix;
+    out ++;
+  }    
+
+  free (temp);
+
+  return (TRUE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/fit.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/fit.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/fit.c	(revision 3338)
@@ -0,0 +1,132 @@
+# include "data.h"
+
+int fit (int argc, char **argv) {
+  
+  double **c, **b, *s, X, Y, dY;
+  int i, j, nterm, mterm, order;
+  int N, Weight, Quiet;
+  Vector *xvec, *yvec, *dyvec;
+  float *x, *y, *dy;
+  char name[64];
+
+  Quiet = FALSE;
+  if ((N = get_argument (argc, argv, "-q"))) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-quiet"))) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  Weight = FALSE;
+  if ((N = get_argument (argc, argv, "-dy"))) {
+    remove_argument (N, &argc, argv);
+    if ((dyvec = SelectVector (argv[N], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+    remove_argument (N, &argc, argv);
+    Weight = TRUE;
+  }
+
+  if (argc != 4) {
+    fprintf (stderr, "USAGE: fit x y order [-dy wt]\n");
+    return (FALSE);
+  }
+
+  if ((xvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+  if ((yvec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+
+  order = atof (argv[3]);
+  nterm = order + 1;
+  mterm = 2*order + 1;
+
+  if (xvec[0].Nelements != yvec[0].Nelements) {
+    fprintf (stderr, "vectors must have same length\n");
+    return (FALSE);
+  }
+  if (Weight && xvec[0].Nelements != dyvec[0].Nelements) {
+    fprintf (stderr, "vectors must have same length\n");
+    return (FALSE);
+  }
+  
+  x = xvec[0].elements;
+  y = yvec[0].elements;
+  if (Weight) dy = dyvec[0].elements;
+
+  ALLOCATE (s, double, 2*mterm);
+  bzero (s, 2*mterm*sizeof(double));
+  ALLOCATE (b, double *, nterm);
+  ALLOCATE (c, double *, nterm);
+  for (i = 0; i < nterm; i++) {
+    ALLOCATE (c[i], double, nterm);
+    bzero (c[i], nterm*sizeof(double));
+    ALLOCATE (b[i], double, 1);
+    bzero (b[i], sizeof(double));
+  }
+
+  for (i = 0; i < xvec[0].Nelements; i++, x++, y++) {
+    if (!(finite(*x) && finite(*y))) continue;
+    dY = 1.0;
+    if (Weight) { 
+      dY = 1.0 / SQ(*dy);
+      dy ++;
+    }
+    X = 1*dY;
+    Y = *y*dY;
+    for (j = 0; j < nterm; j++) {
+      s[j] += X;
+      b[j][0] += Y;
+      X = X * (*x);
+      Y = Y * (*x);
+    }
+    for (j = nterm; j < mterm; j++) {
+      s[j] += X;
+      X = X * (*x);
+    }
+  }
+
+  for (i = 0; i < nterm; i++) {
+    for (j = 0; j < nterm; j++) {
+      c[i][j] = s[i + j];
+    }
+  }
+  if (!gaussj (c, nterm, b, 1)) goto escape;
+
+  /* print & save basic fit parameters */
+  if (!Quiet) fprintf (stderr, "y = ");
+  for (i = 0; i < nterm; i++) {
+    sprintf (name, "C%d", i);
+    set_variable (name, b[i][0]);
+    if (!Quiet) fprintf (stderr, "%f x^%d ", b[i][0], i);
+  }
+  sprintf (name, "Cn");
+  set_variable (name, (double) order);
+  
+  /* print & save basic fit parameters */
+  if (!Quiet) fprintf (stderr, "\n");
+  if (!Quiet) fprintf (stderr, "    ");
+  for (i = 0; i < nterm; i++) {
+    sprintf (name, "dC%d", i);
+    set_variable (name, sqrt(c[i][i]));
+    if (!Quiet) fprintf (stderr, "%f     ", sqrt(c[i][i]));
+  }
+  if (!Quiet) fprintf (stderr, "\n");
+
+  for (i = 0; i < nterm; i++) {
+    free (b[i]);
+    free (c[i]);
+  }
+  free (b);
+  free (c);
+  free (s);
+  return (TRUE);
+
+escape:
+  for (i = 0; i < nterm; i++) {
+    free (b[i]);
+    free (c[i]);
+  }
+  free (b);
+  free (c);
+  free (s);
+  return (FALSE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/fit2d.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/fit2d.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/fit2d.c	(revision 3338)
@@ -0,0 +1,128 @@
+# include "data.h"
+
+int fit2d (int argc, char **argv) {
+  
+  double **c, **b, **s, X, Y;
+  int k, K, i, j, nx, ny, nterm, mterm, wterm, order;
+  int N, Weight;
+  float *x, *y, *z; 
+  char name[64];
+  Vector *xvec, *yvec, *zvec, *dyvec;
+
+  Weight = FALSE;
+  if ((N = get_argument (argc, argv, "-dy"))) {
+    remove_argument (N, &argc, argv);
+    if ((dyvec = SelectVector (argv[N], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+    remove_argument (N, &argc, argv);
+    Weight = TRUE;
+    fprintf (stderr, "warning: weighting currently ignored!\n");
+  }
+
+  if (argc != 5) {
+    fprintf (stderr, "USAGE: fit x y z order [-dy`z wt]\n");
+    return (FALSE);
+  }
+
+  if ((xvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+  if ((yvec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+  if ((zvec = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+
+  order = atof (argv[4]);
+  nterm = order + 1;
+  wterm = nterm*(nterm + 1)/2;
+  mterm = 2*order + 1;
+
+  if (xvec[0].Nelements != yvec[0].Nelements) {
+    fprintf (stderr, "vectors must have same length\n");
+    return (FALSE);
+  }
+  if (xvec[0].Nelements != zvec[0].Nelements) {
+    fprintf (stderr, "vectors must have same length\n");
+    return (FALSE);
+  }
+  if (Weight && xvec[0].Nelements != dyvec[0].Nelements) {
+    fprintf (stderr, "vectors must have same length\n");
+    return (FALSE);
+  }
+  
+  x = xvec[0].elements;
+  y = yvec[0].elements;
+  z = zvec[0].elements;
+  /* dy = dyvec[0].elements; */
+
+  /* allocate the summation matrices */
+  ALLOCATE (b, double *, wterm);
+  ALLOCATE (c, double *, wterm);
+  for (i = 0; i < wterm; i++) {
+    ALLOCATE (c[i], double, wterm);
+    bzero (c[i], wterm*sizeof(double));
+    ALLOCATE (b[i], double, 1);
+    bzero (b[i], sizeof(double));
+  }
+  ALLOCATE (s, double *, mterm);
+  for (i = 0; i < mterm; i++) {
+    ALLOCATE (s[i], double, mterm);
+    bzero (s[i], mterm*sizeof(double));
+  }
+
+  /* add up the x,y values */
+  for (i = 0; i < xvec[0].Nelements; i++, x++, y++) {
+    Y = X = 1;
+    for (ny = 0; ny < mterm; ny++) {
+      X = Y;
+      for (nx = 0; nx < mterm - ny; nx++) {
+	s[nx][ny] += X;
+	X = X * (*x);
+      }
+      Y = Y * (*y);
+    }
+  }
+
+  /* add up the z values */
+  x = xvec[0].elements;
+  y = yvec[0].elements;
+  z = zvec[0].elements;
+  for (i = 0; i < xvec[0].Nelements; i++, x++, y++, z++) {
+    Y = X = *z;
+    for (N = 0, ny = 0; ny < nterm; ny++) {
+      X = Y;
+      for (nx = 0; nx < nterm - ny; nx++, N++) {
+	b[N][0] += X;
+	X = X * (*x);
+      }
+      Y = Y * (*y);
+    }
+  }
+
+  /* re-sort mterm x mterm matrix to wterm matrix */
+  for (k = j = 0; j < nterm; j++) {
+    for (i = 0; i < nterm - j; i++, k++) {
+      for (K = ny = 0; ny < nterm; ny++) {
+	for (nx = 0; nx < nterm - ny; nx++, K++) {
+	  c[K][k] = s[nx+i][ny+j];
+	}
+      }
+    }
+  }
+
+  gaussj (c, wterm, b, 1);
+
+  fprintf (stderr, "z = ");
+  for (N = ny = 0; ny < nterm; ny++) {
+    for (nx = 0; nx < nterm - ny; nx++, N++) {
+      sprintf (name, "CX%dY%d", nx, ny);
+      set_variable (name, b[N][0]);
+      fprintf (stderr, "%f x^%d y^%d  ", b[N][0], nx, ny);
+    }
+  }
+  sprintf (name, "Cnn");
+  set_variable (name, (double) order);
+  
+  fprintf (stderr, "\n");
+  return (TRUE);
+
+}
+
+
+
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/gaussdeviate.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/gaussdeviate.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/gaussdeviate.c	(revision 3338)
@@ -0,0 +1,30 @@
+# include "data.h"
+
+int gaussdeviate (int argc, char **argv) {
+  
+  int i, Npts;
+  double mean, sigma;
+  Vector *vec;
+
+  if (argc != 5) goto usage;
+
+  if ((vec = SelectVector (argv[1], ANYVECTOR, TRUE)) == NULL) return (FALSE);    
+
+  Npts = atoi (argv[2]);
+  mean = atof (argv[3]);
+  sigma = atof (argv[4]);
+
+  vec[0].Nelements = Npts;
+  REALLOCATE (vec[0].elements, float, Npts);
+
+  gauss_init (2048);
+  for (i = 0; i < Npts; i++) {
+    vec[0].elements[i] = rnd_gauss (mean, sigma);
+  }
+  return (TRUE);
+
+ usage:
+  fprintf (stderr, "USAGE: gaussdeviate (vector) Npts mean sigma\n");
+  return (FALSE);
+    
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/gaussj.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/gaussj.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/gaussj.c	(revision 3338)
@@ -0,0 +1,58 @@
+# include "data.h"
+
+int gaussjordan (int argc, char **argv) {
+  
+  float *m, *v;
+  double **a, **b;
+  int i, j, N;
+  Vector *B;
+  Buffer *A;
+
+  if (argc != 3) goto usage;
+
+  if ((A = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);    
+  if ((B = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+
+  N = B[0].Nelements;
+  if (A[0].matrix.Naxis[0] != N) goto usage;
+  if (A[0].matrix.Naxis[1] != N) goto usage;
+  
+  ALLOCATE (a, double *, N);
+  ALLOCATE (b, double *, N);
+  for (i = 0; i < N; i++) {
+    ALLOCATE (a[i], double, N);
+    ALLOCATE (b[i], double, 1);
+  }
+
+  m = (float *) A[0].matrix.buffer;
+  v = B[0].elements;
+  for (i = 0; i < N; i++) {
+    for (j = 0; j < N; j++) {
+      a[i][j] = m[i+j*N];
+    }
+    b[i][0] = v[i]; 
+  }
+  gaussj (a, N, b, 1);
+
+  for (i = 0; i < N; i++) {
+    for (j = 0; j < N; j++) {
+       m[i+j*N] = a[i][j];
+    }
+    v[i] = b[i][0]; 
+  }
+
+  for (i = 0; i < N; i++) {
+    free (a[i]);
+    free (b[i]);
+  }
+  free (a);
+  free (b);
+  return (TRUE);
+
+ usage:
+  fprintf (stderr, "USAGE: gaussj A B\n");
+  fprintf (stderr, "  solves Ax = B, returns 1/A in A and x in B\n");
+  fprintf (stderr, "  A must be square, B same dimensions\n");
+  return (FALSE);
+    
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/grid.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/grid.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/grid.c	(revision 3338)
@@ -0,0 +1,212 @@
+# include "data.h"
+
+int grid (int argc, char **argv) {
+  
+  int j, N, MinorTick, MajorTick;
+  Vector Xvec, Yvec;
+  double range, lrange, factor, mantis, fmantis, power, major, minor, first, next;
+  Graphdata graphmode;
+  int Ngraph;
+
+  Ngraph = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Ngraph = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetGraph (&graphmode, NULL, &Ngraph)) return (FALSE);
+
+  MajorTick = TRUE;
+  MinorTick = FALSE;
+  if ((N = get_argument (argc, argv, "-all"))) {
+    remove_argument (N, &argc, argv);
+    MinorTick = TRUE;
+  }
+
+  if (argc > 1) {
+    fprintf (stderr, "USAGE: grid [-n graph]\n");
+    return (FALSE);
+  }
+
+  N = 0;
+  Xvec.Nelements = 200;
+  Yvec.Nelements = 200;
+  ALLOCATE (Xvec.elements, float, Xvec.Nelements);
+  ALLOCATE (Yvec.elements, float, Yvec.Nelements);
+
+  major = minor = 1;
+  range = graphmode.xmax - graphmode.xmin;
+  lrange = log10(MAX(fabs(range), 1e-30));
+  factor = (int) (lrange);
+  if (lrange < 0) { factor -= 1; }
+  mantis = lrange - factor;
+  power = pow(10.0, factor);
+  fmantis = pow(10.0, mantis);
+  if ((fmantis >= 1.0) && (fmantis <=  2.0)) {
+    major = 0.5 * power;
+    minor = 0.1 * power;
+  }
+  if ((fmantis > 2.0) && (fmantis <=  4.0)) {
+    major = 1.0 * power;
+    minor = 0.2 * power;
+  }
+  if ((fmantis > 4.0) && (fmantis <=  6.0)) {
+    major = 1.0 * power;
+    minor = 0.5 * power;
+  }
+  if ((fmantis > 6.0) && (fmantis <=  10.0)) {
+    major = 2.0 * power;
+    minor = 0.5 * power;
+  }
+  if (graphmode.xmin > 0)
+    first = minor + minor*((int)(graphmode.xmin/minor));
+  else 
+    first = -minor + minor*((int)(graphmode.xmin/minor));
+  if (minor*((int)(graphmode.xmin/minor)) == graphmode.xmin) {
+    first = graphmode.xmin;
+  }
+  
+  for (j = 0, next = first; next <= graphmode.xmax; j++) {
+    if ((fabs((int)(next/major) - (next/major)) < 0.5*(minor/major)) || (fabs ((int)((next + 0.5*minor)/major) - (next/major)) < 0.5*(minor/major))) {
+      if (MajorTick) {
+	/* major tick */
+	Xvec.elements[N] = next;
+	Yvec.elements[N] = graphmode.ymin;
+	N++;
+	if (N == Xvec.Nelements) {
+	  Xvec.Nelements += 200;
+	  Yvec.Nelements += 200;
+	  REALLOCATE (Xvec.elements, float, Xvec.Nelements);
+	  REALLOCATE (Yvec.elements, float, Yvec.Nelements);
+	}
+	Xvec.elements[N] = next;
+	Yvec.elements[N] = graphmode.ymax;
+	N++;
+	if (N == Xvec.Nelements) {
+	  Xvec.Nelements += 200;
+	  Yvec.Nelements += 200;
+	  REALLOCATE (Xvec.elements, float, Xvec.Nelements);
+	  REALLOCATE (Yvec.elements, float, Yvec.Nelements);
+	}
+      }
+    } else {
+      if (MinorTick) {
+	/* minor tick */
+	Xvec.elements[N] = next;
+	Yvec.elements[N] = graphmode.ymin;
+	N++;
+	if (N == Xvec.Nelements) {
+	  Xvec.Nelements += 200;
+	  Yvec.Nelements += 200;
+	  REALLOCATE (Xvec.elements, float, Xvec.Nelements);
+	  REALLOCATE (Yvec.elements, float, Yvec.Nelements);
+	}
+	Xvec.elements[N] = next;
+	Yvec.elements[N] = graphmode.ymax;
+	N++;
+	if (N == Xvec.Nelements) {
+	  Xvec.Nelements += 200;
+	  Yvec.Nelements += 200;
+	  REALLOCATE (Xvec.elements, float, Xvec.Nelements);
+	  REALLOCATE (Yvec.elements, float, Yvec.Nelements);
+	}
+      }
+    }
+    next += minor;
+  }
+
+  range = graphmode.ymax - graphmode.ymin;
+  lrange = log10(MAX(fabs(range), 1e-30));
+  factor = (int) (lrange);
+  if (lrange < 0) { factor -= 1; }
+  mantis = lrange - factor;
+  power = pow(10.0, factor);
+  fmantis = pow(10.0, mantis);
+  if ((fmantis >= 1.0) && (fmantis <=  2.0)) {
+    major = 0.5 * power;
+    minor = 0.1 * power;
+  }
+  if ((fmantis > 2.0) && (fmantis <=  4.0)) {
+    major = 1.0 * power;
+    minor = 0.2 * power;
+  }
+  if ((fmantis > 4.0) && (fmantis <=  6.0)) {
+    major = 1.0 * power;
+    minor = 0.5 * power;
+  }
+  if ((fmantis > 6.0) && (fmantis <=  10.0)) {
+    major = 2.0 * power;
+    minor = 0.5 * power;
+  }
+  if (graphmode.ymin > 0)
+    first = minor + minor*((int)(graphmode.ymin/minor));
+  else 
+    first = -minor + minor*((int)(graphmode.ymin/minor));
+  if (minor*((int)(graphmode.ymin/minor)) == graphmode.ymin) {
+    first = graphmode.ymin;
+  }
+  
+  for (j = 0, next = first; next <= graphmode.ymax; j++) {
+    if ((fabs((int)(next/major) - (next/major)) < 0.5*(minor/major)) || (fabs ((int)((next + 0.5*minor)/major) - (next/major)) < 0.5*(minor/major))) {
+      if (MajorTick) {
+	/* major tick */
+	Xvec.elements[N] = graphmode.xmin;
+	Yvec.elements[N] = next;
+	N++;
+	if (N == Xvec.Nelements) {
+	  Xvec.Nelements += 200;
+	  Yvec.Nelements += 200;
+	  REALLOCATE (Xvec.elements, float, Xvec.Nelements);
+	  REALLOCATE (Yvec.elements, float, Yvec.Nelements);
+	}
+	Xvec.elements[N] = graphmode.xmax;
+	Yvec.elements[N] = next;
+	N++;
+	if (N == Xvec.Nelements) {
+	  Xvec.Nelements += 200;
+	  Yvec.Nelements += 200;
+	  REALLOCATE (Xvec.elements, float, Xvec.Nelements);
+	  REALLOCATE (Yvec.elements, float, Yvec.Nelements);
+	}
+      }
+    } else {
+      if (MinorTick) {
+	/* minor tick */
+	Xvec.elements[N] = graphmode.xmin;
+	Yvec.elements[N] = next;
+	N++;
+	if (N == Xvec.Nelements) {
+	  Xvec.Nelements += 200;
+	  Yvec.Nelements += 200;
+	  REALLOCATE (Xvec.elements, float, Xvec.Nelements);
+	  REALLOCATE (Yvec.elements, float, Yvec.Nelements);
+	}
+	Xvec.elements[N] = graphmode.xmax;
+	Yvec.elements[N] = next;
+	N++;
+	if (N == Xvec.Nelements) {
+	  Xvec.Nelements += 200;
+	  Yvec.Nelements += 200;
+	  REALLOCATE (Xvec.elements, float, Xvec.Nelements);
+	  REALLOCATE (Yvec.elements, float, Yvec.Nelements);
+	}
+      }
+    }
+    next += minor;
+  }
+
+  Xvec.Nelements = Yvec.Nelements = N;
+  graphmode.style = 2; /* points */
+  graphmode.ptype = 100; /* connect a pair */
+  graphmode.etype = 0;
+  PrepPlotting (N, &graphmode);
+  PlotVector (N, Xvec.elements);
+  PlotVector (N, Yvec.elements);
+
+  free (Xvec.elements);
+  free (Yvec.elements);
+
+  return (TRUE);
+
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/gridify.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/gridify.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/gridify.c	(revision 3338)
@@ -0,0 +1,96 @@
+# include "data.h"
+
+int gridify (int argc, char **argv) {
+
+  int i, Nx, Ny, Xb, Yb, Normalize, N;
+  float Xmin, Xmax, dX, Ymin, Ymax, dY;
+  float *buf, *val, *x, *y, *z;
+  int *Nval;
+  Buffer *bf;
+  Vector *vx, *vy, *vz;
+
+  Normalize = TRUE;
+  if ((N = get_argument (argc, argv, "-raw"))) {
+    remove_argument (N, &argc, argv);
+    Normalize = FALSE;
+  }
+
+  if (argc != 11) {
+    fprintf (stderr, "USAGE: gridify x y z buffer Xmin Xmax dX Ymin Ymax dY\n");
+    return (FALSE);
+  }
+  
+  if ((vx = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((vy = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((vz = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((bf = SelectBuffer (argv[4], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+
+  if (vx[0].Nelements != vy[0].Nelements) return (FALSE);
+  if (vx[0].Nelements != vz[0].Nelements) return (FALSE);
+
+  Xmin = atof (argv[5]);
+  Xmax = atof (argv[6]);
+  dX   = atof (argv[7]);
+
+  Ymin = atof (argv[8]);
+  Ymax = atof (argv[9]);
+  dY   = atof (argv[10]);
+
+  Nx = (Xmax - Xmin) / dX + 1;
+  Ny = (Ymax - Ymin) / dY + 1;
+  
+  /* these steps are a standard 'createbuffer', define? */
+  bf[0].bitpix = -32;
+  bf[0].unsign = FALSE;
+  bf[0].bscale = 1.0;
+  bf[0].bzero  = 0.0;
+  strcpy (bf[0].file, "(empty)");
+
+  bf[0].header.bitpix = bf[0].bitpix;
+  bf[0].header.bscale = bf[0].bscale;
+  bf[0].header.bzero  = bf[0].bzero; 
+  bf[0].header.unsign = bf[0].unsign;
+  bf[0].header.Naxes = 2;
+  bf[0].header.Naxis[0] = Nx;
+  bf[0].header.Naxis[1] = Ny;
+  free (bf[0].header.buffer);  /* ALLOCATEd in SelectBuffer */
+  free (bf[0].matrix.buffer);  /* ALLOCATEd in SelectBuffer */
+  fits_create_header (&bf[0].header);
+  fits_create_matrix (&bf[0].header, &bf[0].matrix);
+
+  ALLOCATE (val, float, Nx*Ny);
+  bzero (val, Nx*Ny*sizeof(float));
+  ALLOCATE (Nval, int, Nx*Ny);
+  bzero (Nval, Nx*Ny*sizeof(int));
+
+  x = vx[0].elements;
+  y = vy[0].elements;
+  z = vz[0].elements;
+  for (i = 0; i < vx[0].Nelements; i++, x++, y++, z++) {
+    Xb = (*x - Xmin) / dX;
+    Yb = (*y - Ymin) / dY;
+    if (Xb >= Nx) continue;
+    if (Yb >= Ny) continue;
+    val[Xb + Yb*Nx] += *z;
+    Nval[Xb + Yb*Nx]++;
+  }
+
+  buf = (float *) bf[0].matrix.buffer;
+  for (i = 0; i < Nx*Ny; i++) {
+    if (Normalize) {
+      if (Nval[i] == 0) {
+	buf[i] = 0;
+	continue;
+      }
+      buf[i] = val[i] / Nval[i];
+    } else {
+      buf[i] = val[i];
+    }
+  }
+
+  free (val);
+  free (Nval);
+
+  return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/histogram.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/histogram.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/histogram.c	(revision 3338)
@@ -0,0 +1,45 @@
+# include "data.h"
+
+int histogram (int argc, char **argv) {
+  
+  int i, bin, Nbins;
+  float *V, start, end, delta;
+  Vector *xvec, *yvec;
+
+  if ((argc != 6) && (argc != 5)) {
+    fprintf (stderr, "USAGE: hist invec outvec start end [delta]\n");
+    return (FALSE);
+  }
+
+  delta = 1;
+  start = atof (argv[3]);
+  end   = atof (argv[4]);
+  if (argc == 6) delta = atof (argv[5]);
+ 
+  if ((start == end) || (delta == 0)) {
+    fprintf (stderr, "error in value: %f to %f, %f\n", start, end, delta);
+    return (FALSE);
+  }
+  delta = fabs (delta);
+  if (end - start < 0) {
+    delta = -1.0 * delta;
+  }
+  Nbins = (end - start) / delta;
+  /* number here should match number in create.c */
+
+  if ((xvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yvec = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  yvec[0].Nelements = Nbins;
+    
+  REALLOCATE (yvec[0].elements, float, yvec[0].Nelements);
+  bzero (yvec[0].elements, sizeof(float)*yvec[0].Nelements);
+
+  V = xvec[0].elements;
+  for (i = 0; i < xvec[0].Nelements; i++, V++) {
+    bin = MIN (MAX (0, (*V - start) / delta), Nbins - 1);
+    yvec[0].elements[bin] += 1.0;
+  }      
+
+  return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/imcut.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/imcut.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/imcut.c	(revision 3338)
@@ -0,0 +1,66 @@
+# include "data.h"
+
+int imcut (int argc, char **argv) {
+  
+  int i, Nx, Ny, xi, yi, L;
+  double xs, ys, xe, ye, dX, dY;
+  Vector *xvec, *yvec;
+  Buffer *buf;
+  float *V;
+
+  if (argc != 8) {
+    fprintf (stderr, "USAGE: cut <buffer> <X vector> <Y vector> xs ys xe ye\n");
+    return (FALSE);
+  }
+
+  if ((buf  = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) goto missed;
+  if ((xvec = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) goto usage;
+  if ((yvec = SelectVector (argv[3], ANYVECTOR, TRUE)) == NULL) goto usage;
+ 
+  xs = atof (argv[4]);
+  ys = atof (argv[5]);
+  xe = atof (argv[6]);
+  ye = atof (argv[7]);
+
+  Nx = buf[0].matrix.Naxis[0];
+  Ny = buf[0].matrix.Naxis[1];
+
+  if ((xs < 0) || (xs > Nx)) goto range;
+  if ((ys < 0) || (ys > Ny)) goto range;
+  if ((xe < 0) || (xe > Nx)) goto range;
+  if ((ye < 0) || (ye > Ny)) goto range;
+
+  dX = xe - xs;
+  dY = ye - ys;
+  L = hypot (dX, dY);
+  dX = dX / L;
+  dY = dY / L;
+
+  REALLOCATE (xvec[0].elements, float, MAX (L, 1));
+  REALLOCATE (yvec[0].elements, float, MAX (L, 1));
+  xvec[0].Nelements = L;
+  yvec[0].Nelements = L;
+
+  V = (float *)buf[0].matrix.buffer;
+  for (i = 0; i < L; i++) {
+    xi = xs + i*dX - 0.5;
+    yi = ys + i*dY - 0.5;
+    xvec[0].elements[i] = i;
+    yvec[0].elements[i] = V[xi + Nx*yi];
+  }
+
+  return (TRUE);
+
+ usage: 
+  fprintf (stderr, "USAGE: circstats <buffer> x y radius\n");
+  return (FALSE);
+
+ range:
+  fprintf (stderr, "ERROR: coordinates out of range\n");
+  return (FALSE);
+
+ missed:
+  fprintf (stderr, "ERROR: buffer not found\n");
+  return (FALSE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/imhist.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/imhist.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/imhist.c	(revision 3338)
@@ -0,0 +1,97 @@
+# include "data.h"
+
+int imhist (int argc, char **argv) {
+  
+  int i, j, N;
+  int sx, sy, nx, ny, bin;
+  float *V;
+  double max, min, dx;
+  Vector *vec1, *vec2;
+  Buffer *buf;
+
+  min = max = 0.0;
+  if ((N = get_argument (argc, argv, "-range"))) {
+    remove_argument (N, &argc, argv);
+    min = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    max = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  sx = sy = 0.0;
+  nx = ny = 0.0;
+  if ((N = get_argument (argc, argv, "-region"))) {
+    remove_argument (N, &argc, argv);
+    sx = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    sy = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    nx = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    ny = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 4) {
+    fprintf (stderr, "USAGE: histogram <buffer> <x> <y> [-region sx sy nx ny] [-range min max]\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  
+  /* if either range is set to zero, use the rest of the chip */
+  if (nx == 0)
+    nx = buf[0].matrix.Naxis[0] - sx;
+  if (ny == 0)
+    ny = buf[0].matrix.Naxis[1] - sy;
+
+  if ((sx < 0) || (sy < 0) || 
+      (sx+nx > buf[0].matrix.Naxis[0]) || 
+      (sy+ny > buf[0].matrix.Naxis[1])) {
+    fprintf (stderr, "region out of range\n");
+    return (FALSE);
+  }
+
+  if ((vec1 = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((vec2 = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  /* unfortunately, we must do this in two passes:
+     first pass finds the max and min and defines the bin size
+     second pass counts the pixes in each bin 
+     */
+
+  if ((max == 0) && (min == 0)) {
+    max = min = *((float *)(buf[0].matrix.buffer) + sy*buf[0].matrix.Naxis[0] + sx);
+    fprintf (stderr, "sx: %d, sy: %d, first: %f\n", sx, sy, max);
+    for (j = sy; j < sy + ny; j++) {
+      V = (float *)(buf[0].matrix.buffer) + j*buf[0].matrix.Naxis[0] + sx; 
+      for (i = 0; i < nx; i++, V++) {
+	max = MAX (max, *V);
+	min = MIN (min, *V);
+      }
+    }
+  }
+  dx = (max - min) / 1024.0;
+  fprintf (stderr, "max %f, min %f, dx %f\n", max, min, dx);
+  
+  vec1[0].Nelements = 1025;
+  vec2[0].Nelements = 1025;
+  REALLOCATE (vec1[0].elements, float, vec1[0].Nelements);
+  bzero (vec1[0].elements, vec1[0].Nelements*sizeof(float));
+  REALLOCATE (vec2[0].elements, float, vec2[0].Nelements);
+  bzero (vec2[0].elements, vec2[0].Nelements*sizeof(float));
+  
+  for (j = sy; j < sy + ny; j++) {
+    V = (float *)(buf[0].matrix.buffer) + j*buf[0].matrix.Naxis[0] + sx; 
+    for (i = 0; i < nx; i++, V++) {
+      bin = MAX (MIN (1024, (*V - min) / dx), 0);
+      vec2[0].elements[bin] += 1.0;
+    }
+  }
+  for (i = 0; i < 1025; i++, V++) {
+    vec1[0].elements[i] = i*dx + min;
+  }
+  
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/imsmooth.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/imsmooth.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/imsmooth.c	(revision 3338)
@@ -0,0 +1,75 @@
+# include "data.h"
+
+int imsmooth (int argc, char **argv) {
+  
+  int i, j, n, N, Nx, Ny, Ns, Ngauss;
+  float *vi, *vo, *gauss, *gaussnorm;
+  float g, s, sigma, Nsigma;
+  Buffer *in;
+  float *temp;
+
+  Nsigma = 3;
+  if ((N = get_argument (argc, argv, "-Nsigma"))) {
+    remove_argument (N, &argc, argv);
+    Nsigma = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: imsmooth (input) sigma\n");
+    return (FALSE);
+  }
+  
+  if ((in  = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  sigma = atof (argv[2]);
+
+  Nx = in[0].matrix.Naxis[0];
+  Ny = in[0].matrix.Naxis[1];
+  ALLOCATE (temp, float, Nx*Ny);
+
+  /* build a 1D gaussian */
+  Ns = (int) (Nsigma*sigma + 0.5);
+  Ngauss = 2*Ns + 1;
+  ALLOCATE (gaussnorm, float, Ngauss);
+  gauss = &gaussnorm[Ns];
+  for (i = -Ns; i < Ns + 1; i++) {
+    gauss[i] = exp ((i*i)/(-2*sigma*sigma));
+  }
+
+  /* smooth in X direction */
+  for (j = 0; j < Ny; j++) {
+    vi = (float *) in[0].matrix.buffer + j*Nx;
+    vo = &temp[j*Nx];
+    for (i = 0; i < Nx; i++) {
+      g = s = 0;
+      for (n = -Ns; n < Ns + 1; n++) {
+	if (i+n < 0) continue;
+	if (i+n >= Nx) continue;
+	s += gauss[n]*vi[i+n];
+	g += gauss[n];
+      }
+      vo[i] = s / g;
+    }
+  }
+
+  /* smooth in Y direction */
+  for (i = 0; i < Nx; i++) {
+    vi = &temp[i];
+    vo = (float *)in[0].matrix.buffer + i;
+    for (j = 0; j < Ny; j++) {
+      g = s = 0;
+      for (n = -Ns; n < Ns + 1; n++) {
+	if (j+n < 0) continue;
+	if (j+n >= Ny) continue;
+	s += gauss[n]*vi[(n+j)*Nx];
+	g += gauss[n];
+      }
+      vo[j*Nx] = s / g;
+    }
+  }
+
+  free (temp);
+  free (gaussnorm);
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/init.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/init.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/init.c	(revision 3338)
@@ -0,0 +1,211 @@
+# include "data.h"
+
+int accum            PROTO((int, char **));
+int applyfit         PROTO((int, char **));
+int applyfit2d       PROTO((int, char **));
+int box              PROTO((int, char **));
+int center           PROTO((int, char **));
+int circstats        PROTO((int, char **));
+int clear            PROTO((int, char **));
+int clip             PROTO((int, char **));
+int concat           PROTO((int, char **));
+int contour          PROTO((int, char **));
+int create           PROTO((int, char **));
+int cursor           PROTO((int, char **));
+int cut              PROTO((int, char **));
+int datafile         PROTO((int, char **));
+int delete           PROTO((int, char **));
+int device           PROTO((int, char **));
+int dimendown        PROTO((int, char **));
+int dimenup          PROTO((int, char **));
+int erase            PROTO((int, char **));
+int extract          PROTO((int, char **));
+int fft1d            PROTO((int, char **));
+int fft2d            PROTO((int, char **));
+int fit2d            PROTO((int, char **));
+int fit              PROTO((int, char **));
+int gaussjordan      PROTO((int, char **));
+int gaussdeviate     PROTO((int, char **));
+int grid             PROTO((int, char **));
+int gridify          PROTO((int, char **));
+int ungridify        PROTO((int, char **));
+int histogram        PROTO((int, char **));
+int imcut            PROTO((int, char **));
+int imhist           PROTO((int, char **));
+int imsmooth         PROTO((int, char **));
+int integrate        PROTO((int, char **));
+int interpolate      PROTO((int, char **));
+int jpeg             PROTO((int, char **));
+int kern             PROTO((int, char **));
+int keyword          PROTO((int, char **));
+int labels           PROTO((int, char **));
+int limits           PROTO((int, char **));
+int line             PROTO((int, char **));
+int list_buffers     PROTO((int, char **));
+int header           PROTO((int, char **));
+int list_vectors     PROTO((int, char **));
+int load             PROTO((int, char **));
+int mcreate          PROTO((int, char **));
+int medacc           PROTO((int, char **));
+int mget             PROTO((int, char **));
+int minterp          PROTO((int, char **));
+int mset             PROTO((int, char **));
+int peak             PROTO((int, char **));
+int plot             PROTO((int, char **));
+int dot              PROTO((int, char **));
+int point            PROTO((int, char **));
+int pop              PROTO((int, char **));
+int ps               PROTO((int, char **));
+int push             PROTO((int, char **));
+int queuelist        PROTO((int, char **));
+int queuesize        PROTO((int, char **));
+int rd               PROTO((int, char **));
+int rdseg            PROTO((int, char **));
+int read_vectors     PROTO((int, char **));
+int rebin            PROTO((int, char **));
+int resize           PROTO((int, char **));
+int roll             PROTO((int, char **));
+int rotate           PROTO((int, char **));
+int save             PROTO((int, char **));
+int section          PROTO((int, char **));
+int set              PROTO((int, char **));
+int shift            PROTO((int, char **));
+int sort_vectors     PROTO((int, char **));
+int spline_apply     PROTO((int, char **));
+int spline_construct PROTO((int, char **));
+int stats            PROTO((int, char **));
+int style            PROTO((int, char **));
+int subraster        PROTO((int, char **));
+int subset           PROTO((int, char **));
+int svd              PROTO((int, char **));
+int swapbytes        PROTO((int, char **));
+int textline         PROTO((int, char **));
+int tv               PROTO((int, char **));
+int tvcontour        PROTO((int, char **));
+int tvgrid           PROTO((int, char **));
+int uniq             PROTO((int, char **));
+int unsign           PROTO((int, char **));
+int vbin             PROTO((int, char **));
+int vclip            PROTO((int, char **));
+int vect_select      PROTO((int, char **));
+int vgrid            PROTO((int, char **));
+int vgauss           PROTO((int, char **));
+int vload            PROTO((int, char **));
+int vstat            PROTO((int, char **));
+int vroll            PROTO((int, char **));
+int vpop             PROTO((int, char **));
+int wd               PROTO((int, char **));
+int write_vectors    PROTO((int, char **));
+int zap              PROTO((int, char **));
+int zplot            PROTO((int, char **));
+
+static Command cmds[] = {  
+  {"accum",        accum,	     "accumulate vector values in another vector"},
+  {"applyfit",     applyfit,	     "apply fit to new vector"},
+  {"applyfit2d",   applyfit2d,	     "apply 2-d fit to new vector"},
+  {"box",     	   box,		     "draw a box on the plot"},
+  {"center",       center,	     "center image on coords"},
+  {"circstats",    circstats,	     "circular statistics"},
+  {"clear",   	   clear,	     "erase plot"},
+  {"clip",         clip,	     "clip values in a buffer to be within a range"},
+  {"concat",  	   concat,	     "reduce vector dimension"},
+  {"contour", 	   contour,	     "create contour from image"},
+  {"create",  	   create,	     "create a new vector"},
+  {"cursor",  	   cursor,	     "get coords from cursor"},
+  {"cut",	   cut,		     "extract a cut across an image"},
+  {"datafile",     datafile,	     "define file to read vectors"},
+  {"delete",  	   delete,	     "delete vectors or matrices"},
+  {"device",  	   device,	     "set / get current graphics device"},
+  {"dimendown",	   dimendown,	     "convert matrix to vector"},
+  {"dimenup",	   dimenup,	     "convert vector to matrix"},
+  {"erase",        erase,	     "erase objects on an overlay"},
+  {"extract",      extract,	     "extract a portion of a buffer into another buffer"},
+  {"fft1d",        fft1d,	     "fft on the pixel-stream in an image"},
+  {"fft2d",        fft2d,	     "fft on an image"},
+  {"fit",     	   fit,		     "fit polynomial to vector pair"},
+  {"fit2d",        fit2d,	     "fit 2-d polynomial to vector triplet"},
+  {"gaussj",  	   gaussjordan,	     "solve Ax = B (N-D)"},
+  {"gaussdev",	   gaussdeviate,     "generate a gaussian deviate vector"},
+  {"grid",    	   grid,	     "plot cartesian grid"},
+  {"gridify",      gridify,	     "convert vector triplet to buffer"},
+  {"ungridify",    ungridify,        "convert buffer region to vector triplet"},
+  {"header",       header,	     "print buffer header"},
+  {"histogram",    histogram,	     "generate histogram from vector"},
+  {"imcut",        imcut,	     "linear image cut between arbitrary coords"},
+  {"imhist",       imhist,	     "histogram of an image region"},
+  {"imsmooth",     imsmooth,	     "circular gaussian smoothing"},
+  {"integrate",    integrate,	     "integrate a vector"},
+  {"interpolate",  interpolate,	     "interpolate between vector pairs"},
+  {"jpeg",         jpeg,	     "write text line on graph"},
+  {"kern",         kern,	     "convolve with 3x3 kernel"},
+  {"keyword",      keyword,	     "extract a FITS keyword from buffer header"},
+  {"labels",  	   labels,	     "define labels for plot"},
+  {"limits",  	   limits,	     "define plot limits"},
+  {"line",         line,	     "plot line"},
+  {"buffers",      list_buffers,     "list the currently allocated buffers"},
+  {"vectors", 	   list_vectors,     "list vectors"},
+  {"load",         load,	     "load an SAOimage style overlay"},
+  {"mcreate", 	   mcreate,	     "create a matrix"},
+  {"medacc",       medacc,	     "accumulate vector values in another vector"},
+  {"mget",    	   mget,	     "extract a vector from a matrix"},
+  {"minterp",      minterp,	     "interpolate image pixels"},
+  {"mset",    	   mset,	     "insert a vector in a matrix"},
+  {"peak",	   peak,	     "find vector peak in range"},
+  {"plot",    	   plot,	     "plot a pair of vectors"},
+  {"dot",    	   dot,	             "plot a single point"},
+  {"point",	   point,	     "load overlay with single point"},
+  {"ps",      	   ps,		     "define labels for plot"},
+  {"pop",      	   pop,		     "pop value from queue to variable"},
+  {"push",     	   push,	     "push value onto queue"},
+  {"queuelist",	   queuelist,	     "list defined queues"},
+  {"queuesize",    queuesize,	     "show queue size"},
+  {"rd",           rd,		     "load fits image"},
+  {"rdseg",	   rdseg,	     "read a segment of an image from a file"},
+  {"read",         read_vectors,     "read vectors from datafile"},
+  {"rebin",	   rebin,	     "rebin data by factor of N"},
+  {"resize",  	   resize,	     "set graphics/image window size"},
+  {"roll",	   roll,	     "roll image to new start point"},
+  {"rotate",	   rotate,	     "rotate image"},
+  {"save",	   save,	     "save an SAOimage style overlay"},
+  {"section", 	   section,	     "define section of graph"},
+  {"set",     	   set,		     "vector math"},
+  {"shift",	   shift,	     "shift data in an image"},
+  {"sort",    	   sort_vectors,     "sort list of vectors"},
+  {"spline.apply", spline_apply,     "apply spline fit to generate an image"},
+  {"spline.const", spline_construct, "create spline 2nd deriv. terms"},
+  {"stats",   	   stats,	     "give statistics on a portion of a buffer"},
+  {"style",   	   style,	     "set the style for graph plots"},
+  {"subraster",    subraster,	     "subraster of fits image"},
+  {"subset",  	   subset,	     "expand vector dimension"},
+  {"svd",	   svd,		     "singular value decomposition of a matrix"},
+  {"swapbytes",	   swapbytes,        "byte swap thing"},
+  {"textline",     textline,	     "write text line on graph"},
+  {"tv",      	   tv,		     "display an image on the Kii window"},
+  {"tvcontour",	   tvcontour,	     "send contour to overlay"},
+  {"tvgrid",	   tvgrid,	     "wait until return is typed"},
+  {"uniq",    	   uniq,	     "create a uniq vector subset from a vector"},
+  {"unsign",	   unsign,	     "toggle the UNSIGN status"},
+  {"vbin",	   vbin,	     "bin values in a vector to be within a range"},
+  {"vclip",	   vclip,	     "clip values in a vector to be within a range"},
+  {"select",	   vect_select,	     "selective vector assignment"},
+  {"vgauss",       vgauss,	     ""},
+  {"vgrid",        vgrid,	     ""},
+  {"vload",        vload,	     "load vectors on Kii"},
+  {"vstat",        vstat,	     "get info from imreg database"},
+  {"vroll",        vroll,	     "roll vector elements"},
+  {"vpop",         vpop, 	     "remove first element"},
+  {"wd",      	   wd,		     "write an image to a file"},
+  {"write",   	   write_vectors,    "write vectors to datafile"},
+  {"zap",     	   zap,		     "delete pixels"},
+  {"zplot",   	   zplot,	     "plot x y with size scaled by z"},
+}; 
+
+void InitData () {
+  
+  int i;
+
+  for (i = 0; i < sizeof (cmds) / sizeof (Command); i++) {
+    AddCommand (&cmds[i]);
+  }
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/integrate.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/integrate.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/integrate.c	(revision 3338)
@@ -0,0 +1,44 @@
+# include "data.h"
+
+int integrate (int argc, char **argv) {
+  
+  int i, N, VERBOSE;
+  float *X, *Y;
+  double start, end, value, range;
+  Vector *vecx, *vecy;
+
+  VERBOSE = FALSE;
+  if ((N = get_argument (argc, argv, "-v"))) {
+    VERBOSE = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 5) {
+    fprintf (stderr, "USAGE: integrate <x> <y> start end\n");
+    return (FALSE);
+  }
+
+  if ((vecx = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((vecy = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+
+  start = atof (argv[3]);
+  end   = atof (argv[4]);
+
+  X = vecx[0].elements;
+  Y = vecy[0].elements;
+
+  value = 0;
+  range = 0;
+  for (i = 0; i < vecx[0].Nelements-1; i++, X++, Y++) {
+    if ((*X >= start) && (*X <= end)) {
+      value += *Y * (X[1] - X[0]);
+      range += (X[1] - X[0]);
+    }
+  }      
+
+  set_variable ("sum", value); 
+  set_variable ("range", range);
+  if (VERBOSE) fprintf (GetOutfile(), "sum: %f\n", value);
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/interpolate.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/interpolate.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/interpolate.c	(revision 3338)
@@ -0,0 +1,53 @@
+# include "data.h"
+
+int interpolate (int argc, char **argv) {
+
+  int  i, j;
+  double x0, x1, dx, dy, y0;
+  Vector *xout, *yout, *xin, *yin;
+
+  /** check basic syntax **/
+  if (argc != 5) {
+    fprintf (stderr, "USAGE: interpolate Xi Yi Xo Yo\n");
+    fprintf (stderr, "  Xi Yi - sorted reference vectors\n");
+    fprintf (stderr, "  Xo    - output positions\n");
+    fprintf (stderr, "  Yo    - output values\n");
+    return (FALSE);
+  }
+
+  if ((xin  = SelectVector (argv[1],  OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yin  = SelectVector (argv[2],  OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((xout = SelectVector (argv[3],  OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yout = SelectVector (argv[4],  ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  yout[0].Nelements = xout[0].Nelements;
+  REALLOCATE (yout[0].elements, float, yout[0].Nelements);
+
+  dx = xin[0].elements[1] - xin[0].elements[0];
+  dy = yin[0].elements[1] - yin[0].elements[0];
+  x0 = xin[0].elements[0];
+  y0 = yin[0].elements[0];
+  
+  /* in vectors are sorted, out vectors are not */
+  for (j = 0; j < xin[0].Nelements - 1; j++) {
+    dx = xin[0].elements[j+1] - xin[0].elements[j];
+    dy = yin[0].elements[j+1] - yin[0].elements[j];
+    x0 = xin[0].elements[j];
+    y0 = yin[0].elements[j];
+    x1 = xin[0].elements[j+1];
+    for (i = 0; i < xout[0].Nelements; i++) {
+      if ((xout[0].elements[i] >= x0) && (xout[0].elements[i] < x1)) {
+	yout[0].elements[i] = (dy/dx)*(xout[0].elements[i] - x0) + y0;
+      }
+      if ((j == 0) && (xout[0].elements[i] < x0)) {
+	yout[0].elements[i] = (dy/dx)*(xout[0].elements[i] - x0) + y0;
+      }
+      if ((j == xin[0].Nelements - 2) && (xout[0].elements[i] > x1)) {
+	yout[0].elements[i] = (dy/dx)*(xout[0].elements[i] - x0) + y0;
+      }
+    }    
+  }
+
+  return (TRUE);
+    
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/jpeg.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/jpeg.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/jpeg.c	(revision 3338)
@@ -0,0 +1,64 @@
+# include "data.h"
+
+int jpeg (int argc, char **argv) {
+
+  char filename[1024], buffer[20], type[16];
+  int N, Source, Nsource, IsImage;
+  
+  if ((N = get_argument (argc, argv, "--help"))) {
+    fprintf (stderr, "USAGE: jpeg [-name file] [-g | -i] [-n device] [-ppm]\n");
+    return (FALSE);
+  }
+
+  /* image type */
+  strcpy (type, "PNGF");
+  if ((N = get_argument (argc, argv, "-ppm"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (type, "PPMF");
+  }
+
+  /* file name */
+  filename[0] = 0;
+  if ((N = get_argument (argc, argv, "-name"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (filename, argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  /* display source */
+  Nsource = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nsource = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-g"))) {
+    remove_argument (N, &argc, argv);
+    SetImageDevice (FALSE);
+  }  
+  if ((N = get_argument (argc, argv, "-i"))) {
+    remove_argument (N, &argc, argv);
+    SetImageDevice (TRUE);
+  }  
+  IsImage = GetCurrentDevice ();
+  if (IsImage) {
+    if (!GetImage (&Source, &Nsource)) return (FALSE);
+    if (!filename[0]) strcpy (filename, "Ximage.jpg");
+    strcpy (type, "JPEG");
+  } else {
+    if (!GetGraph (NULL, &Source, &Nsource)) return (FALSE);
+    if (!filename[0]) strcpy (filename, "Xgraph.png");
+  }
+
+  strcpy (buffer, type);
+  write (Source, buffer, 4);
+  sprintf (buffer, "LEN: %11d", strlen(filename));
+  write (Source, buffer, 16);
+  write (Source, filename, strlen(filename));
+  read (Source, buffer, 4);
+
+  return (TRUE);
+}
+
+/* jpeg -g converts graph to png
+   jpeg converts image to jpeg */
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/kern.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/kern.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/kern.c	(revision 3338)
@@ -0,0 +1,106 @@
+# include "data.h"
+
+/** need to allow larger kernels (5x5, 7x7, etc) **/
+int kern (int argc, char **argv) {
+
+  int i, n, m;
+  int NX, NY, status;
+  FILE *f;
+  float *in_buff, *out_buff, *ib, *ob;
+  char line[256], *list;
+  double kernel[3][3], val;
+  Buffer *buf;
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: kern buffer (file)\n");
+    fprintf (stderr, "USAGE: kern buffer (list)\n");
+    fprintf (stderr, "USAGE: kern buffer -\n");
+    fprintf (stderr, "kernel file contains a 3x3 matrix for convolution\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  /* open file to read in kernel */
+  if (!strcmp (argv[2], "-")) {
+    for (i = 0; i < 3; i++) {
+      status = scan_line (stdin, line);
+      if (status == EOF) {
+	fprintf (stderr, "kernel should be a 3x3 matrix...\n");
+	return (FALSE);
+      }
+      dparse (&kernel[0][i], 1, line);
+      dparse (&kernel[1][i], 2, line);
+      dparse (&kernel[2][i], 3, line);
+    }
+    goto have_kernel;
+  }
+  /* test list */
+  sprintf (line, "%s:n", argv[2]);
+  if ((list = get_variable (line)) == (char *) NULL) {
+    /* file */
+    f = fopen (argv[2], "r");
+    if (f == NULL) {
+      fprintf (stderr, "file not found: %s\n", argv[2]);
+      return (FALSE);
+    }
+    for (i = 0; i < 3; i++) {
+      status = scan_line (f, line);
+      if (status == EOF) {
+	fprintf (stderr, "kernel should be a 3x3 matrix...\n");
+	fclose (f);
+      }
+      return (FALSE);
+      dparse (&kernel[0][i], 1, line);
+      dparse (&kernel[1][i], 2, line);
+      dparse (&kernel[2][i], 3, line);
+    }
+    fclose (f);
+    goto have_kernel;
+  }
+  if (atoi (list) != 9) {
+    fprintf (stderr, "kernel should be a 3x3 matrix...\n");
+    return (FALSE);
+  }
+  free (list);
+  for (i = 0; i < 9; i++) {
+    sprintf (line, "%s:%d", argv[2], i);
+    list = get_variable (line);
+    if (list == (char *) NULL) {
+      fprintf (stderr, "kernel should be a 3x3 matrix...\n");
+      return (FALSE);
+    }
+    kernel[(int)(i/3)][i%3] = atof (list);
+    free (list);
+  }
+  goto have_kernel;
+
+ have_kernel:
+  fprintf (stderr, "working...");
+  
+  /* create output buffer */
+  NX = buf[0].header.Naxis[0];
+  NY = buf[0].header.Naxis[1];
+  in_buff = (float *)buf[0].matrix.buffer;
+  ALLOCATE (buf[0].matrix.buffer, char, sizeof(float)*NX*NY);
+  out_buff = (float *)buf[0].matrix.buffer;
+  
+  /* do the convolution (on all but outer rows) */
+  
+  for (n = 0; n < 3; n++) {
+    for (m = 0; m < 3; m++) {
+      fprintf (stderr, "%d", n*3 + m + 1);
+      val = kernel[n][m];
+      ob = out_buff + NX + 1;
+      ib = in_buff + m*NX + n;
+      for (i = 0; i < (NX-2)*(NY-2); i++, ob++, ib++) {
+	*ob += *ib*val;
+      }
+    }
+  }
+  fprintf (stderr, "(done)\n");
+
+  free (in_buff);
+  return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/keyword.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/keyword.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/keyword.c	(revision 3338)
@@ -0,0 +1,158 @@
+# include "data.h"
+
+enum {NONE, STRING, FLOAT, INT, BOOLEAN, KEYCOMMENT, COMMENT};
+
+/** WARNING: no error checking on variable validity **/
+int keyword (int argc, char **argv) {
+
+  int ivalue, status, N, ascomment, asfloat, delete, soft, Wmode;
+  char line[80];
+  double value;
+  Buffer *buf;
+
+  asfloat = FALSE;
+  if ((N = get_argument (argc, argv, "-f"))) {
+    remove_argument (N, &argc, argv);
+    asfloat = TRUE;
+  }
+  
+  ascomment = FALSE;
+  if ((N = get_argument (argc, argv, "-c"))) {
+    remove_argument (N, &argc, argv);
+    ascomment = TRUE;
+  }
+  
+  delete = FALSE;
+  if ((N = get_argument (argc, argv, "-d"))) {
+    remove_argument (N, &argc, argv);
+    delete = TRUE;
+  }
+  
+  /* return TRUE for missing keyword if soft */
+  soft = FALSE;
+  if ((N = get_argument (argc, argv, "-soft"))) {
+    remove_argument (N, &argc, argv);
+    soft = TRUE;
+  }
+  
+  /* identify write modes */
+  Wmode = NONE;
+  if ((N = get_argument (argc, argv, "-w"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (line, argv[N]);
+    remove_argument (N, &argc, argv);
+    Wmode = STRING;
+  }
+  if ((N = get_argument (argc, argv, "-wf"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (line, argv[N]);
+    remove_argument (N, &argc, argv);
+    Wmode = FLOAT;
+  }
+  if ((N = get_argument (argc, argv, "-wd"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (line, argv[N]);
+    remove_argument (N, &argc, argv);
+    Wmode = INT;
+  }
+  if ((N = get_argument (argc, argv, "-wc"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (line, argv[N]);
+    remove_argument (N, &argc, argv);
+    Wmode = KEYCOMMENT;
+  }
+  if ((N = get_argument (argc, argv, "-ws"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (line, argv[N]);
+    remove_argument (N, &argc, argv);
+    Wmode = COMMENT;
+  }
+  if ((N = get_argument (argc, argv, "-wb"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (line, argv[N]);
+    remove_argument (N, &argc, argv);
+    Wmode = BOOLEAN;
+  }
+
+  if (!((argc == 3) || (!N && argc == 4))) {
+    fprintf (stderr, "USAGE: keyword <buffer> (KEYWORD) [variable] [-d] [-w(mode) value]\n");
+    fprintf (stderr, " -w modes: \n");
+    fprintf (stderr, "  -w  - string\n");
+    fprintf (stderr, "  -wf - float\n");
+    fprintf (stderr, "  -wd - int\n");
+    fprintf (stderr, "  -wb - boolean\n");
+    fprintf (stderr, "  -wc - comment\n");
+    fprintf (stderr, "  -ws - full string comment\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  if (Wmode != NONE) {
+    switch (Wmode) {
+    case STRING:
+      fits_modify (&buf[0].header, argv[2], "%s", 1, line);
+      return (TRUE);
+    case FLOAT:
+      value = atof(line);
+      fits_modify (&buf[0].header, argv[2], "%lf", 1, value);
+      return (TRUE);
+    case INT:
+      fits_modify (&buf[0].header, argv[2], "%d", 1, atoi(line));
+      return (TRUE);
+    case BOOLEAN:
+      if (strcasecmp (line, "T") && strcasecmp (line, "TRUE") && strcasecmp (line, "F") && strcasecmp (line, "FALSE")) {
+	fprintf (stderr, "syntax error in boolean value\n");
+	return (FALSE);
+      }
+      ivalue = !strcasecmp (line, "T");
+      fits_modify (&buf[0].header, argv[2], "%t", 1, ivalue);
+      return (TRUE);
+    case KEYCOMMENT:
+      fits_modify (&buf[0].header, argv[2], "%C", 1, line);
+      return (TRUE);
+    case COMMENT:
+      fits_modify (&buf[0].header, argv[2], "%S", 0, line);
+      return (TRUE);
+    }
+  }
+  
+  if (delete) {
+    fits_delete (&buf[0].header, argv[2], -1);
+    return (TRUE);
+  }
+  
+  /* grab the value in the given format, either a string or a digit */
+  if (asfloat) {
+    status = fits_scan (&buf[0].header, argv[2], "%lf", 1, &value);
+    if (!status) goto failure;
+    if (argc == 4) 
+      set_variable (argv[3], value);
+    else 
+      fprintf (GetOutfile(), "%s: %f\n", argv[2], value);
+    return (TRUE);
+  } 
+
+  if (ascomment) {
+    status = fits_scan (&buf[0].header, argv[2], "%C", 1, line);
+    if (!status) goto failure;
+    if (argc == 4) 
+      set_str_variable (argv[3], line);
+    else 
+      fprintf (GetOutfile(), "%s: %s\n", argv[2], line);
+    return (TRUE);
+  }    
+
+  /* not-specified */
+  status = fits_scan (&buf[0].header, argv[2], "%s", 1, line);
+  if (!status) goto failure;
+  if (argc == 4) 
+    set_str_variable (argv[3], line);
+  else 
+    fprintf (GetOutfile(), "%s: %s\n", argv[2], line);
+  return (TRUE);
+
+ failure: 
+  if (!soft) fprintf (stderr, "keyword %s not found\n", argv[2]);
+  return (soft);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/labels.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/labels.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/labels.c	(revision 3338)
@@ -0,0 +1,99 @@
+# include "data.h"
+
+int labels (int argc, char **argv) {
+  
+  char name[64], buffer[32];
+  int N, size, Xgraph;
+
+  if (!GetGraph (NULL, &Xgraph, NULL)) return (FALSE);
+
+  if (get_argument (argc, argv, "-h")) {
+    fprintf (stderr, "label options: \n");
+    fprintf (stderr, " -x : bottom-center\n");
+    fprintf (stderr, " +x : top-center\n");
+    fprintf (stderr, " -y : right-side\n");
+    fprintf (stderr, " +y : left-side\n\n");
+
+    fprintf (stderr, " -ul : upper-left corner\n");
+    fprintf (stderr, " -ll : lower-left corner\n");
+    fprintf (stderr, " -ur : upper-right corner\n");
+    fprintf (stderr, " -lr : lower-right corner\n\n");
+
+    fprintf (stderr, " -fn (font) (size) : set font and size\n");
+    fprintf (stderr, "   (font) : courier, helvetica, times, symbol\n\n");
+    fprintf (stderr, " label special characters:\n");
+    fprintf (stderr, " ^ : superscript\n");
+    fprintf (stderr, " _ : subscript\n");
+    fprintf (stderr, " | : default script \n");
+    fprintf (stderr, " &c, &h, &t, &s : set font\n\n");
+    return (FALSE);
+  }
+
+  if ((N = get_argument (argc, argv, "-fn"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (name, argv[N]);
+    remove_argument (N, &argc, argv);
+    size = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    write (Xgraph, "FONT", 4);
+    sprintf (buffer, "%s", name);
+    write (Xgraph, buffer, 16);
+    sprintf (buffer, "%d", size);
+    write (Xgraph, buffer, 16);
+  } 
+
+  if ((N = get_argument (argc, argv, "-x"))) {
+    remove_argument (N, &argc, argv);
+    SendLabel (argv[N], Xgraph, 0);
+    remove_argument (N, &argc, argv);
+  }
+
+  if ((N = get_argument (argc, argv, "-y"))) {
+    remove_argument (N, &argc, argv);
+    SendLabel (argv[N], Xgraph, 1);
+    remove_argument (N, &argc, argv);
+  }
+
+  if ((N = get_argument (argc, argv, "+x"))) {
+    remove_argument (N, &argc, argv);
+    SendLabel (argv[N], Xgraph, 2);
+    remove_argument (N, &argc, argv);
+  }
+
+  if ((N = get_argument (argc, argv, "+y"))) {
+    remove_argument (N, &argc, argv);
+    SendLabel (argv[N], Xgraph, 3);
+    remove_argument (N, &argc, argv);
+  }
+
+  if ((N = get_argument (argc, argv, "-ul"))) {
+    remove_argument (N, &argc, argv);
+    SendLabel (argv[N], Xgraph, 4);
+    remove_argument (N, &argc, argv);
+  }
+
+  if ((N = get_argument (argc, argv, "-ur"))) {
+    remove_argument (N, &argc, argv);
+    SendLabel (argv[N], Xgraph, 5);
+    remove_argument (N, &argc, argv);
+  }
+
+  if ((N = get_argument (argc, argv, "-ll"))) {
+    remove_argument (N, &argc, argv);
+    SendLabel (argv[N], Xgraph, 6);
+    remove_argument (N, &argc, argv);
+  }
+
+  if ((N = get_argument (argc, argv, "-lr"))) {
+    remove_argument (N, &argc, argv);
+    SendLabel (argv[N], Xgraph, 7);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 1) {
+    fprintf (stderr, "USAGE: labels [-x] [-y] [+x] [+y] [-ul] [-ur] [-ll] [-lr]\n");
+    return (FALSE);
+  }
+
+  return (TRUE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/limits.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/limits.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/limits.c	(revision 3338)
@@ -0,0 +1,76 @@
+# include "data.h"
+
+int limits (int argc, char **argv) {
+
+  int N, APPLY;
+  int Ngraph, Xgraph;
+  Graphdata graphmode;
+  Vector *xvec, *yvec;
+
+  xvec = yvec = NULL;
+
+  APPLY = FALSE;
+  if ((N = get_argument (argc, argv, "-a"))) {
+    remove_argument (N, &argc, argv);
+    APPLY = TRUE;
+  }
+
+  Ngraph = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Ngraph = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetGraph (&graphmode, &Xgraph, &Ngraph)) return (FALSE);
+
+  if (argc == 1) {
+    fprintf (stderr, "limits: %f %f %f %f [-a] [-n Xgraph]\n",
+	     graphmode.xmin, graphmode.xmax,
+	     graphmode.ymin, graphmode.ymax);
+    goto success;
+  }
+
+  if (argc == 3) { /* expect to see: limits x y */
+    if ((xvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+    if ((yvec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+    goto success;
+  }
+    
+  if (argc == 4) { /* expect to see: limits x num num or limits num num y */
+    if (ISNUM(argv[1][0]) && ISNUM(argv[2][0])) {
+      if ((yvec = SelectVector (argv[3], OLDVECTOR, FALSE)) == NULL) goto error;
+      graphmode.xmin = atof (argv[1]);
+      graphmode.xmax = atof (argv[2]);
+      goto success;
+    }
+    if (ISNUM(argv[2][0]) && ISNUM(argv[3][0])) {
+      if ((xvec = SelectVector (argv[1], OLDVECTOR, FALSE)) == NULL) goto error;
+      graphmode.ymin = atof (argv[2]);
+      graphmode.ymax = atof (argv[3]);
+      goto success;
+    }
+    goto error;
+  }
+  
+  if (argc == 5) {
+    graphmode.xmin = atof (argv[1]);
+    graphmode.xmax = atof (argv[2]);
+    graphmode.ymin = atof (argv[3]);
+    graphmode.ymax = atof (argv[4]);
+    goto success;
+  }
+
+  fprintf (stderr, "USAGE: limits [xrange] [yrange]\n");
+  fprintf (stderr, " [range] may be either [min max] or a vector\n");
+  return (FALSE);
+
+ error:
+  fprintf (stderr, "error in vectors\n");
+  return (FALSE);
+
+ success:
+  SetLimits (xvec, yvec, &graphmode);
+  ApplyLimits (Xgraph, &graphmode, APPLY);
+  return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/line.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/line.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/line.c	(revision 3338)
@@ -0,0 +1,125 @@
+# include "data.h"
+
+int line (int argc, char **argv) {
+  
+  int N, Npts, Ngraph;
+  Graphdata graphmode;
+  Vector *vecx, *vecy, *dxm, *dxp, *dym, *dyp;
+
+  /* choose the appropriate graphing window */
+  Ngraph = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Ngraph = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetGraph (&graphmode, NULL, &Ngraph)) return (FALSE);
+
+  /* evaluate various plotting options */
+  if ((N = get_argument (argc, argv, "-lt"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.ltype = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-lw"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.lweight = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-pt"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.ptype = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "+eb"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.ebar = TRUE;
+  }
+  if ((N = get_argument (argc, argv, "-eb"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.ebar = FALSE;
+  }
+  if ((N = get_argument (argc, argv, "-sz"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.size = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-c"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.color = GetColor (argv[N]);
+    if (graphmode.color == -1) return (FALSE);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-x"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.style = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  /* decide on error bars */
+  dxm = dxp = dym = dyp = NULL;
+  if ((N = get_argument (argc, argv, "-dx"))) {
+    remove_argument (N, &argc, argv);
+    if ((dxm = SelectVector (argv[N], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "+dx"))) {
+    remove_argument (N, &argc, argv);
+    if ((dxp = SelectVector (argv[N], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-dy"))) {
+    remove_argument (N, &argc, argv);
+    if ((dym = SelectVector (argv[N], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "+dy"))) {
+    remove_argument (N, &argc, argv);
+    if ((dyp = SelectVector (argv[N], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: plot <x> <y>\n");
+    return (FALSE);
+  }
+
+  /* set plotting options (these are sticky) */
+  SetGraph (graphmode);
+
+  /* set errorbar mode (these are NOT sticky) */
+  graphmode.etype = 0;
+  if ((dym != NULL) && (dyp == NULL)) dyp = dym;
+  if ((dyp != NULL) && (dym == NULL)) dym = dyp;
+  if ((dyp != NULL) || (dym != NULL)) graphmode.etype |= 0x01;
+  if ((dxm != NULL) && (dxp == NULL)) dxp = dxm;
+  if ((dxp != NULL) && (dxm == NULL)) dxm = dxp;
+  if ((dxp != NULL) || (dxm != NULL)) graphmode.etype |= 0x02;
+  
+  /* find vectors */
+  if ((vecx = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((vecy = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if (vecy[0].Nelements != vecy[0].Nelements) {
+    fprintf (stderr, "vectors %s and %s not the same length\n", argv[1], argv[2]);
+    return (FALSE);
+  }
+  
+  Npts = vecx[0].Nelements;
+  if (!PrepPlotting (Npts, &graphmode)) return (FALSE);
+  
+  PlotVector (Npts, vecx[0].elements);
+  PlotVector (Npts, vecy[0].elements);
+  if (graphmode.etype & 0x01) {
+    PlotVector (Npts, dym[0].elements);
+    PlotVector (Npts, dyp[0].elements);
+  }
+  if (graphmode.etype & 0x02) {
+    PlotVector (Npts, dxm[0].elements);
+    PlotVector (Npts, dxp[0].elements);
+  }
+  
+  return (TRUE);
+
+}
+
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/list_buffers.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/list_buffers.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/list_buffers.c	(revision 3338)
@@ -0,0 +1,10 @@
+# include "data.h"
+
+int list_buffers (int argc, char **argv) {
+
+  if (argc == 3) PrintBuffers (TRUE);
+  else PrintBuffers (FALSE);
+
+  return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/list_header.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/list_header.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/list_header.c	(revision 3338)
@@ -0,0 +1,79 @@
+# include "data.h"
+
+int header (int argc, char **argv) {
+  
+  int j, N, nlines, nbytes, Nbytes, LOADHEAD, status, bitpix, unsign;
+  char *p, filename[128];
+  FILE *f;
+  double bscale, bzero;
+  Buffer *buf;
+
+  LOADHEAD = FALSE;
+  if ((N = get_argument (argc, argv, "-w"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (filename, argv[N]);
+    remove_argument (N, &argc, argv);
+    LOADHEAD = TRUE;
+  }
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: header <buffer> [-w filename]\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  if (LOADHEAD) {
+    f = fopen (filename, "r");
+    if (f == (FILE *) NULL) {
+      fprintf (stderr, "file %s not found\n", filename);
+      return (FALSE);
+    }
+    fclose (f);
+    
+    bitpix = buf[0].header.bitpix;
+    bzero  = buf[0].header.bzero;
+    bscale = buf[0].header.bscale;
+    unsign = buf[0].header.unsign;
+    fits_free_header (&buf[0].header);
+    
+    strcpy (filename, buf[0].file);
+    strcpy (buf[0].file, "*");
+    strcat (buf[0].file, filename);
+    status = fits_read_header (argv[2], &buf[0].header);
+    buf[0].header.bitpix = bitpix;     
+    buf[0].header.bzero  = bzero;      
+    buf[0].header.bscale = bscale;     
+    buf[0].header.unsign = unsign;     
+    fits_modify (&buf[0].header, "BITPIX", "%d",  1, bitpix);
+    fits_modify (&buf[0].header, "BSCALE", "%lf", 1, bscale);
+    fits_modify (&buf[0].header, "BZERO",  "%lf", 1, bzero);
+    fits_modify (&buf[0].header, "UNSIGN", "%t",  1, unsign);
+    
+  } else {
+
+    f = popen ("more", "w");
+    
+    p = fits_header_field (&buf[0].header, "END", 1);
+    nlines = (p - buf[0].header.buffer) / 80;
+    nbytes = 81*nlines;
+
+    /* duplicate the header, add in the <return> chars, send to more */
+    ALLOCATE (p, char, nbytes);
+    for (j = 0; j < nlines; j++) {
+      memcpy (&p[81*j], &buf[0].header.buffer[80*j], 80);
+      p[81*j+80] = 10;
+    }
+    Nbytes = fwrite (p, sizeof(char), nbytes, f);
+    if (Nbytes != nbytes) {
+      fprintf (stderr, "warning: not all printed...\n");
+    }
+    free (p);
+
+    pclose (f);
+
+  }
+
+  return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/list_vectors.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/list_vectors.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/list_vectors.c	(revision 3338)
@@ -0,0 +1,8 @@
+# include "data.h"
+
+int list_vectors (int argc, char **argv) {
+
+  ListVectors ();
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/load.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/load.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/load.c	(revision 3338)
@@ -0,0 +1,147 @@
+# include "data.h"
+
+int load (int argc, char **argv) {
+  
+  int N, n, Nline, ISCEL;
+  int Ximage, Nimage;
+  char *c, type[10], string[128];
+  double x, y, dx, dy, x1, y1;
+  double dra, ddec, ra1, dec1, ra, dec;
+  FILE *f;
+  char *buffer, *line;
+  Coords coords;
+  Buffer *buf;
+  
+  Nimage = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nimage = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetImage (&Ximage, &Nimage)) return (FALSE);
+
+  ISCEL = FALSE;
+  if ((N = get_argument (argc, argv, "-c"))) {
+    remove_argument (N, &argc, argv);
+    ISCEL = TRUE;
+  }
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: load (overlay) <filename>\n [-c] [-n]");
+    fprintf (stderr, "  -c: read overlay in celestial coords\n");
+    return (FALSE);
+  }
+  
+  if (!SelectOverlay (argv[1], &n)) return (FALSE);
+
+  if (!strcmp (argv[2], "-")) {
+    f = stdin;
+  } else {
+    f = fopen (argv[2], "r");
+  }
+  if (f == NULL) {
+    fprintf (stderr, "can't find file %s\n", argv[2]);
+    return (FALSE);
+  }
+
+  if (ISCEL) {
+    if ((buf = SelectBuffer (GetImageName(), OLDBUFFER, TRUE)) == NULL) return (FALSE);
+    GetCoords (&coords, &buf[0].header);
+  }
+
+  ALLOCATE (buffer, char, 65536);  /* space for 512 lines of 128 bytes */
+  bzero (buffer, 65536);
+  ALLOCATE (line, char, 1024);     /* space to read the file */
+  Nline = 0;
+
+  write (Ximage, "LOAD", 4); /* force Ximage to look for the incoming image */
+  sprintf (line, "OVER %9d ", n);
+  write (Ximage, line, 16);
+  
+  for (n = 0; scan_line (f, line) != EOF;) {
+    c = strchr (line, '#');
+    if (c != (char *) NULL) 
+      *c = 0;  /* force end of line at comment! */
+    while ((c = strchr (line, '(')) != (char *) NULL) 
+      *c = ' ';
+    while ((c = strchr (line, ')')) != (char *) NULL) 
+      *c = ' ';
+    while ((c = strchr (line, ',')) != (char *) NULL) 
+      *c = ' ';
+    /* we could use some syntactial checks here */
+    /* have to get all three for this to be any valid object, if the line is commented out,
+     we should get none, so check that N == 3 before continuing: */
+    N = sscanf (line, "%s %lf %lf %lf %lf", type, &ra, &dec, &dra, &ddec);
+    switch (N) {
+    case 0:
+    case -1:
+      continue;
+    case 1:
+    case 2:
+    case 3:
+      if (strcmp (type, "TEXT")) {
+	fprintf (stderr, "syntactical error in line:\n   %s\n", line);
+	continue;
+      }
+      sscanf (line, "%s %lf %lf %127s", type, &ra, &dec, string);
+    case 4:
+      ddec = dra;
+    case 5:
+      if (ISCEL) {
+	if (!strcmp (type, "LINE")) {
+	  RD_to_XY (&x, &y, ra, dec, &coords);
+	  ra1 = ra + dra;
+	  dec1 = dec + ddec;
+	  RD_to_XY (&x1, &y1, ra1, dec1, &coords);
+	  dy = (y1 - y);
+	  dx = (x1 - x);
+	} else {
+	  RD_to_XY (&x, &y, ra, dec, &coords);
+	  ra1 = ra;
+	  dec1 = dec + ddec;
+	  RD_to_XY (&x1, &y1, ra1, dec1, &coords);
+	  dy = (fabs(x1 - x) + fabs(y1 - y));
+	  ra1 = ra + dra/cos(dec*RAD_DEG);;
+	  dec1 = dec;
+	  RD_to_XY (&x1, &y1, ra1, dec1, &coords);
+	  dx = (fabs(x1 - x) + fabs(y1 - y));
+	}
+      }
+      else {
+	x = ra;
+	y = dec;
+	dx = dra;
+	dy = ddec;
+      }
+    }
+    if (!strcmp (type, "TEXT")) {
+      snprintf (&buffer[Nline*128], 128, "%15s %20.10f %20.10f %s ", type, x, y, string);
+    } else {
+      snprintf (&buffer[Nline*128], 128, "%15s %20.10f %20.10f %20.10f %20.10f ", type, x, y, dx, dy);
+    }
+    n++;
+    Nline ++;
+    if (Nline == 512) {
+      sprintf (line, "NLINES  %7d ", Nline);
+      write (Ximage, line, 16);
+      write (Ximage, buffer, Nline*128);
+      bzero (buffer, 65536);
+      Nline = 0;
+    }
+  }
+
+  sprintf (line, "NLINES  %7d ", Nline);
+  write (Ximage, line, 16);
+  write (Ximage, buffer, Nline*128);
+  sprintf (line, "DONE ");
+  write (Ximage, line, 16);
+
+  free (buffer);
+  free (line);
+  fprintf (stderr, "loaded %d objects\n", n);
+  if (f != stdin) {
+    fclose (f);
+  }
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/mcreate.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/mcreate.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/mcreate.c	(revision 3338)
@@ -0,0 +1,36 @@
+# include "data.h"
+
+int mcreate (int argc, char **argv) {
+  
+  int Nx, Ny;
+  Buffer *buf;
+
+  if (argc != 4) {
+    fprintf (stderr, "USAGE: mcreate <buffer> Nx Ny\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  Nx = atof (argv[2]);
+  Ny = atof (argv[3]);
+
+  buf[0].matrix.Naxis[0] = Nx;
+  buf[0].matrix.Naxis[1] = Ny;
+
+  /* I should encapsulate this in a create_default_buffer */
+  fits_free_matrix (&buf[0].matrix);
+  fits_free_header (&buf[0].header);
+  buf[0].header.bitpix = buf[0].bitpix = -32;
+  buf[0].header.unsign = buf[0].unsign = FALSE;
+  buf[0].header.bscale = buf[0].bscale = 1.0;
+  buf[0].header.bzero  = buf[0].bzero  = 0.0;
+  buf[0].header.Naxes = 2;
+  buf[0].header.Naxis[0] = Nx;
+  buf[0].header.Naxis[1] = Ny;
+  fits_create_header (&buf[0].header);
+  fits_create_matrix (&buf[0].header, &buf[0].matrix);
+  return (TRUE);
+
+}
+
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/medacc.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/medacc.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/medacc.c	(revision 3338)
@@ -0,0 +1,83 @@
+# include "data.h"
+
+int medacc (int argc, char **argv) {
+  
+  int i, j, Nbins, Nvalues, N, N0, N1;
+  double start, end, delta, k0, k1, fn;
+  float *V, *K, *V1, *K1, *O, *tmpvec, *tmpkey;
+  Vector *val, *key, *out;
+
+  if ((argc != 6) && (argc != 7)) {
+    fprintf (stderr, "USAGE: medacc <value> <vector> <key> start end [delta]\n");
+    return (FALSE);
+  }
+
+  if ((val = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((key = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if (val[0].Nelements != key[0].Nelements) {
+    fprintf (stderr, "key and value don't match\n");
+    return (FALSE);
+  }
+  if ((out = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  start = atof (argv[4]);
+  end   = atof (argv[5]);
+  if (argc == 7) 
+    delta = atof (argv[6]);
+  else 
+    delta = 1;
+
+  delta = fabs (delta);
+  if (end - start < 0) {
+    delta = -1.0 * delta;
+  }
+  Nbins = 1 + (int)((end - start) / delta);
+
+  out[0].Nelements = Nbins;
+  REALLOCATE (out[0].elements, float, out[0].Nelements);
+  bzero (out[0].elements, sizeof(float)*out[0].Nelements);
+
+  /* copy vec and key to temp vectors */
+  ALLOCATE (tmpvec, float, val[0].Nelements);
+  ALLOCATE (tmpkey, float, val[0].Nelements);
+
+  V = val[0].elements;
+  K = key[0].elements;
+  V1 = tmpvec;
+  K1 = tmpkey;
+  Nvalues = val[0].Nelements;
+  for (i = 0; i < Nvalues; i++, V++, K++, V1++, K1++) {
+    *V1 = *V;
+    *K1 = *K;
+  }      
+
+  /* sort vec and key by key */
+  fsortpair (tmpkey, tmpvec, Nvalues);
+
+  O = out[0].elements;
+  /* find the start and end key for each range */
+  N0 = 0;
+  N1 = 0;
+  for (i = 0; i < Nbins; i++) {
+    k0 = i*delta + start;
+    k1 = (i+1)*delta + start;
+    for (j = N1; (j < Nvalues) && (tmpkey[j] < k0); j++);
+    N0 = j;
+    for (j = N0; (j < Nvalues) && (tmpkey[j] < k1); j++);
+    N1 = j;
+    N = N1 - N0;
+    fsort (&tmpvec[N0], N);
+    fn = O[i] = 0;
+    for (j = N0 + 0.25*N; j < N0 + 0.75*N; j++) {
+      O[i] += tmpvec[j];
+      fn += 1.0;
+    }
+    if (fn > 0) O[i] /= fn;
+  }      
+  
+  free (tmpvec);
+  free (tmpkey);
+
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/mget.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/mget.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/mget.c	(revision 3338)
@@ -0,0 +1,61 @@
+# include "data.h"
+
+int mget (int argc, char **argv) {
+  
+  int i, Nx, Ny, Npix, xdir, Nset;
+  float *in, *out;
+  Buffer *buf;
+  Vector *vec;
+
+  if (argc != 5) {
+    fprintf (stderr, "USAGE: mget <buffer> <vector> <-x/-y> <N>\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((vec = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  if (strcasecmp (argv[3], "-x") && strcasecmp (argv[3], "-y")) {
+    fprintf (stderr, "USAGE: mget <buffer> <vector> <-x/-y> <N>\n");
+    return (FALSE);
+  }
+  xdir = TRUE;
+  if (!strcasecmp (argv[3], "-y")) xdir = FALSE;
+
+  Nx = buf[0].matrix.Naxis[0];
+  Ny = buf[0].matrix.Naxis[1];
+  Nset = atof (argv[4]);
+  if (Nset < 0) {
+    fprintf (stderr, "selection out of range\n");
+    return (FALSE);
+  }
+
+  if (xdir) {
+    vec[0].Nelements = Npix = Nx;
+    REALLOCATE (vec[0].elements, float, Npix);
+    if (Nset >= Ny) {
+      fprintf (stderr, "row out of range\n");
+      return (FALSE);
+    }
+    in  = (float *) buf[0].matrix.buffer + Nx*Nset;
+    out = vec[0].elements;
+    for (i = 0; i < Npix; i++, in++, out++) {
+      *out = *in;
+    }
+    return (TRUE);
+  } else {
+    vec[0].Nelements = Npix = Ny;
+    REALLOCATE (vec[0].elements, float, Npix);
+    if (Nset >= Nx) {
+      fprintf (stderr, "column out of range\n");
+      return (FALSE);
+    }
+    in  = (float *) buf[0].matrix.buffer + Nset;
+    out = vec[0].elements;
+    for (i = 0; i < Npix; i++, in+=Nx, out++) {
+      *out = *in;
+    }
+    return (TRUE);
+  }    
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/minterpolate.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/minterpolate.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/minterpolate.c	(revision 3338)
@@ -0,0 +1,115 @@
+# include "data.h"
+
+int minterp (int argc, char **argv) {
+  
+  int i, j, status, nx, ny, Nx, Ny;
+  char temp[1024];
+  double scale, scale2, dX, dY;
+  float *V00, *V01, *V10, *V11, *Vout, dV1, dV2, dV3;
+  Buffer *in, *out;
+
+  if (argc != 4) {
+    fprintf (stderr, "USAGE: minterpolate <from> <to> scale \n");
+    return (FALSE);
+  }
+
+  if ((in  = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((out = SelectBuffer (argv[2], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+
+  fits_free_matrix (&out[0].matrix);
+  fits_free_header (&out[0].header);
+
+  scale  = atof (argv[3]);
+  scale2 = scale*scale;
+  Nx = in[0].header.Naxis[0];
+  Ny = in[0].header.Naxis[1];
+  nx = Nx * scale;
+  ny = Ny * scale;
+
+  /* create new matrix */
+  out[0].bitpix = in[0].bitpix;
+  out[0].unsign = in[0].unsign;
+  out[0].bscale = in[0].bscale;
+  out[0].bzero  = in[0].bzero;
+  fits_copy_header (&in[0].header, &out[0].header);
+
+  fits_modify (&out[0].header, "NAXIS1", "%d", 1, nx);
+  fits_modify (&out[0].header, "NAXIS2", "%d", 1, ny);
+  out[0].header.Naxis[0] = nx;
+  out[0].header.Naxis[1] = ny;
+  fits_create_matrix (&out[0].header, &out[0].matrix);
+
+  /* fix astrometric terms */
+  status =  fits_scan (&out[0].header, "CDELT1", "%lf", 1, &dX);
+  status &= fits_scan (&out[0].header, "CDELT2", "%lf", 1, &dY);
+  dX /= scale;
+  dY /= scale;
+  if (status) {
+    fits_modify (&out[0].header, "CDELT1", "%lf", 1, dX);
+    fits_modify (&out[0].header, "CDELT2", "%lf", 1, dY);
+  }
+  status =  fits_scan (&out[0].header, "CRPIX1", "%lf", 1, &dX);
+  status &= fits_scan (&out[0].header, "CRPIX2", "%lf", 1, &dY);
+  dX *= scale;
+  dY *= scale;
+  if (status) {
+    fits_modify (&out[0].header, "CRPIX1", "%lf", 1, dX);
+    fits_modify (&out[0].header, "CRPIX2", "%lf", 1, dY);
+  }
+
+  /* adjust filename */
+  temp[0] = 0;
+  if ((in[0].file[0] != '*') && (in[0].file[0] != '(')) {
+    strcpy (temp, "*");
+  }
+  strcat (temp, in[0].file);
+  strcpy (out[0].file, temp);
+
+  dX = dY = scale;
+
+  {
+
+    int dx, dy, Npix;
+    float I, J, x, y, xs, xe, ys, ye;
+
+    Npix = 0;
+    for (j = 0; j < Ny - 1; j++) {
+      for (i = 0; i < Nx - 1; i++) {
+	V00 = (float *)(in[0].matrix.buffer) + j*Nx + i;
+	V10 = V00 + 1;
+	V01 = V00 + Nx;
+	V11 = V01 + 1;
+	dV1 = (*V11 + *V00 - *V01 - *V10) / scale2;
+	dV2 = (*V01 - *V00) / scale;
+	dV3 = (*V10 - *V00) / scale;
+
+	x = (i + 0.5) * scale;
+	y = (j + 0.5) * scale;
+
+	xs = 0;
+	if (i == 0) { xs = -0.5*scale; }
+	xe = scale;
+	if (i == Nx - 2) { xe = 1.5*scale; }
+
+	ys = 0;
+	if (j == 0) { ys = -0.5*scale; }
+	ye = scale;
+	if (j == Ny - 2) { ye = 1.5*scale; }
+
+	for (J = ys; J < ye; J += 1.0) {
+	  dx = (x + xs);
+	  dy = (y + J);
+	  Vout = (float *)(out[0].matrix.buffer) + dy*nx + dx;
+	  for (I = xs; I < xe; I += 1.0, Vout++) {
+	    *Vout = dV1 * (I*J) + dV2 * J + dV3 * I + *V00;
+	    Npix ++;
+	  }
+	}
+      }
+    }
+  }
+
+  return (TRUE);
+
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/mset.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/mset.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/mset.c	(revision 3338)
@@ -0,0 +1,66 @@
+# include "data.h"
+
+int mset (int argc, char **argv) {
+  
+  int i, Nx, Ny, Npix, xdir, Nset;
+  float *in, *out;
+  Buffer *buf;
+  Vector *vec;
+
+  if (argc != 5) {
+    fprintf (stderr, "USAGE: mset <buffer> <vector> <-x/-y> <N>\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((vec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+
+  if (strcasecmp (argv[3], "-x") && strcasecmp (argv[3], "-y")) {
+    fprintf (stderr, "USAGE: mset <buffer> <vector> <-x/-y> <N>\n");
+    return (FALSE);
+  }
+  xdir = TRUE;
+  if (!strcasecmp (argv[3], "-y")) xdir = FALSE;
+
+  Npix = vec[0].Nelements;
+  Nx = buf[0].matrix.Naxis[0];
+  Ny = buf[0].matrix.Naxis[1];
+  Nset = atof (argv[4]);
+  if (Nset < 0) {
+    fprintf (stderr, "selection out of range\n");
+    return (FALSE);
+  }
+
+  if (xdir) {
+    if (Nx != Npix) {
+      fprintf (stderr, "dimensions don't match\n");
+      return (FALSE);
+    }
+    if (Nset >= Ny) {
+      fprintf (stderr, "row out of range\n");
+      return (FALSE);
+    }
+    out = (float *) buf[0].matrix.buffer + Nx*Nset;
+    in = vec[0].elements;
+    for (i = 0; i < Npix; i++, in++, out++) {
+      *out = *in;
+    }
+    return (TRUE);
+  } else {
+    if (Ny != Npix) {
+      fprintf (stderr, "dimensions don't match\n");
+      return (FALSE);
+    }
+    if (Nset >= Nx) {
+      fprintf (stderr, "column out of range\n");
+      return (FALSE);
+    }
+    out = (float *) buf[0].matrix.buffer + Nset;
+    in = vec[0].elements;
+    for (i = 0; i < Npix; i++, in++, out+=Nx) {
+      *out = *in;
+    }
+    return (TRUE);
+  }    
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/peak.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/peak.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/peak.c	(revision 3338)
@@ -0,0 +1,43 @@
+# include "data.h"
+
+int peak (int argc, char **argv) {
+  
+  int i, imax;
+  double start, end, xmax, ymax;
+  float *X, *Y;
+  Vector *vecx, *vecy;
+
+  if (argc != 5) {
+    fprintf (stderr, "USAGE: peak <x> <y> start end\n");
+    return (FALSE);
+  }
+
+  if ((vecx = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((vecy = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+
+  start = atof (argv[3]);
+  end   = atof (argv[4]);
+
+  X = vecx[0].elements;
+  Y = vecy[0].elements;
+
+  imax = -1;
+  for (i = 0; i < vecx[0].Nelements-1; i++, X++, Y++) {
+    if ((*X >= start) && (*X <= end)) {
+      if ((imax == -1) || (*Y > ymax)) {
+	xmax = *X;
+	ymax = *Y;
+	imax = i;
+      }
+    }
+  }      
+
+  set_variable ("peakval", ymax);
+  set_variable ("peakpos", xmax);
+  set_variable ("peaknum", imax);
+
+  fprintf (stderr, "peak %f @ %f (%d)\n", ymax, xmax, imax);
+
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/plot.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/plot.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/plot.c	(revision 3338)
@@ -0,0 +1,124 @@
+# include "data.h"
+
+int plot (int argc, char **argv) {
+  
+  int N, Npts, Ngraph;
+  Graphdata graphmode;
+  Vector *xvec, *yvec, *dxmvec, *dxpvec, *dymvec, *dypvec;
+
+  /* choose the appropriate graphing window */
+  Ngraph = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Ngraph = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetGraph (&graphmode, NULL, &Ngraph)) return (FALSE);
+
+  /* evaluate various plotting options */
+  if ((N = get_argument (argc, argv, "-lt"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.ltype = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-lw"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.lweight = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-pt"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.ptype = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "+eb"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.ebar = TRUE;
+  }
+  if ((N = get_argument (argc, argv, "-eb"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.ebar = FALSE;
+  }
+  if ((N = get_argument (argc, argv, "-sz"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.size = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-c"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.color = GetColor (argv[N]);
+    if (graphmode.color == -1) return (FALSE);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-x"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.style = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  /* decide on error bars */
+  dxmvec = dxpvec = dymvec = dypvec = NULL;
+  if ((N = get_argument (argc, argv, "-dx"))) {
+    remove_argument (N, &argc, argv);
+    if ((dxmvec = SelectVector (argv[N], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "+dx"))) {
+    remove_argument (N, &argc, argv);
+    if ((dxpvec = SelectVector (argv[N], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-dy"))) {
+    remove_argument (N, &argc, argv);
+    if ((dymvec = SelectVector (argv[N], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "+dy"))) {
+    remove_argument (N, &argc, argv);
+    if ((dypvec = SelectVector (argv[N], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: plot <x> <y>\n");
+    return (FALSE);
+  }
+
+  /* set plotting options (these are sticky) */
+  SetGraph (graphmode);
+
+  /* set errorbar mode (these are NOT sticky) */
+  graphmode.etype = 0;
+  if ((dymvec != NULL) && (dypvec == NULL)) dypvec = dymvec;
+  if ((dypvec != NULL) && (dymvec == NULL)) dymvec = dypvec;
+  if (dypvec != NULL) graphmode.etype |= 0x01;
+  if ((dxmvec != NULL) && (dxpvec == NULL)) dxpvec = dxmvec;
+  if ((dxpvec != NULL) && (dxmvec == NULL)) dxmvec = dxpvec;
+  if (dxpvec != NULL) graphmode.etype |= 0x02;
+  
+  /* find vectors */
+  if ((xvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yvec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if (xvec[0].Nelements != yvec[0].Nelements) {
+    fprintf (stderr, "vectors %s and %s not the same length\n", argv[1], argv[2]);
+    return (FALSE);
+  }
+  Npts = xvec[0].Nelements;
+  if (Npts == 0) return (TRUE);
+
+  if (!PrepPlotting (Npts, &graphmode)) return (FALSE);
+  
+  PlotVector (Npts, xvec[0].elements);
+  PlotVector (Npts, yvec[0].elements);
+  if (graphmode.etype & 0x01) {
+    PlotVector (Npts, dymvec[0].elements);
+    PlotVector (Npts, dypvec[0].elements);
+  }
+  if (graphmode.etype & 0x02) {
+    PlotVector (Npts, dxmvec[0].elements);
+    PlotVector (Npts, dxpvec[0].elements);
+  }
+  
+  return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/point.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/point.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/point.c	(revision 3338)
@@ -0,0 +1,87 @@
+# include "data.h"
+
+int point (int argc, char **argv) {
+  
+  int N, n, ISCEL, ISPIX;
+  int Ximage, Nimage;
+  double x, y, dx, dy, x1, y1;
+  double dra, ddec, ra1, dec1, ra, dec;
+  char *line;
+  Coords coords;
+  Buffer *buf;
+
+  Nimage = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nimage = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetImage (&Ximage, &Nimage)) return (FALSE);
+  
+  ISCEL = FALSE;
+  if ((N = get_argument (argc, argv, "-c"))) {
+    remove_argument (N, &argc, argv);
+    ISCEL = TRUE;
+  }
+  
+  ISPIX = FALSE;
+  if ((N = get_argument (argc, argv, "-p"))) {
+    remove_argument (N, &argc, argv);
+    ISPIX = TRUE;
+  }
+
+  if (argc != 7) {
+    fprintf (stderr, "USAGE: point (overlay) TYPE x y dx dy [-c]\n");
+    return (FALSE);
+  }
+  
+  if (!SelectOverlay (argv[1], &n)) 
+    return (FALSE);
+
+  if (ISCEL) {
+    if ((buf = SelectBuffer (GetImageName(), OLDBUFFER, TRUE)) == NULL) return (FALSE);
+    GetCoords (&coords, &buf[0].header);
+  }
+
+  ALLOCATE (line, char, 1024);     /* space to read the file */
+
+  ra = atof(argv[3]);
+  dec = atof(argv[4]);
+  dra = atof(argv[5]);
+  ddec = atof(argv[6]);
+  if (ISCEL) {
+    RD_to_XY (&x, &y, ra, dec, &coords);
+    if (!ISPIX) {
+      ra1 = ra + dra;
+      dec1 = dec + ddec;
+      RD_to_XY (&x1, &y1, ra1, dec1, &coords);
+      dx = x1 - x;
+      dy = y1 - y;
+    } else {
+      dx = atof(argv[5]);
+      dy = atof(argv[6]);
+    }
+  }
+  else {
+    x = ra;
+    y = dec;
+    dx = dra;
+    dy = ddec;
+  }
+
+  write (Ximage, "LOAD", 4); /* force Ximage to look for the incoming image */
+  sprintf (line, "OVERLAY %6d ", n);
+  write (Ximage, line, 16);
+  sprintf (line, "NLINES %7d ", 1);
+  write (Ximage, line, 16);
+  sprintf (line, "%15s %20.10f %20.10f %20.10f %20.10f ", argv[2], x, y, dx, dy);
+  write (Ximage, line, 128);
+  sprintf (line, "DONE ");
+  write (Ximage, line, 16);
+
+  free (line);
+
+  return (TRUE);
+
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/pop.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/pop.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/pop.c	(revision 3338)
@@ -0,0 +1,44 @@
+# include "data.h"
+
+int pop (int argc, char **argv) {
+  
+  int N;
+  char *var;
+  char *line;
+  Queue *queue;
+
+  var = (char *) NULL;
+  if ((N = get_argument (argc, argv, "-var"))) {
+    remove_argument (N, &argc, argv);
+    var = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: pop (queue) [-var variable]\n");
+    return (FALSE);
+  }
+
+  /* will create a queue if none exists */
+  queue = FindQueue (argv[1]);
+  if (queue == NULL) {
+    fprintf (stderr, "ERROR: queue %s not found\n", argv[1]);
+    return (FALSE);
+  }
+
+  line = PopQueue (queue);
+  if (line == NULL) {
+    fprintf (stderr, "ERROR: queue %s is empty\n", argv[1]);
+    return (FALSE);
+  }
+
+  if (var == (char *) NULL) {
+    fprintf (stderr, "%s\n", line);
+  } else {
+    set_str_variable (argv[2], line);
+  }
+
+  free (line);
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/ps.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/ps.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/ps.c	(revision 3338)
@@ -0,0 +1,68 @@
+# include "data.h"
+
+int ps (int argc, char **argv) {
+
+  char filename[1024], buffer[64];
+  int N, Source, Nsource, RawImage, NoScale, IsImage;
+  
+  if ((N = get_argument (argc, argv, "--help"))) {
+    fprintf (stderr, "USAGE: ps [-name file.ps] [-g | -i] [-n device] [-raw] [-scale]\n");
+    return (FALSE);
+  }
+
+  /* raw image? */
+  RawImage = FALSE;
+  if ((N = get_argument (argc, argv, "-raw"))) {
+    remove_argument (N, &argc, argv);
+    RawImage = TRUE;
+  }
+  /* scale image? */
+  NoScale = FALSE;
+  if ((N = get_argument (argc, argv, "-noscale"))) {
+    remove_argument (N, &argc, argv);
+    NoScale = TRUE;
+  }
+  /* what file? */
+  filename[0] = 0;
+  if ((N = get_argument (argc, argv, "-name"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (filename, argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  /* which tool */
+  Nsource = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nsource = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  /* which device */
+  if ((N = get_argument (argc, argv, "-g"))) {
+    remove_argument (N, &argc, argv);
+    SetImageDevice (FALSE);
+  }  
+  if ((N = get_argument (argc, argv, "-i"))) {
+    remove_argument (N, &argc, argv);
+    SetImageDevice (TRUE);
+  }  
+  IsImage = GetCurrentDevice ();
+  if (IsImage) {
+    if (!GetImage (&Source, &Nsource)) return (FALSE);
+    if (!filename[0]) strcpy (filename, "Ximage.ps");
+  } else {
+    if (!GetGraph (NULL, &Source, &Nsource)) return (FALSE);
+    if (!filename[0]) strcpy (filename, "Xgraph.ps");
+  }
+  
+  if (RawImage) write (Source, "PSRW", 4); /* tell Ximage to ps the image */
+  if (NoScale)  write (Source, "PSNS", 4); /* tell Ximage to ps the image */
+  if (!RawImage && !NoScale) write (Source, "PSIT", 4); /* tell Ximage to ps the image */
+
+  sprintf (buffer, "LEN: %11d", strlen(filename));
+  write (Source, buffer, 16);
+  write (Source, filename, strlen(filename));
+  read (Source, buffer, 4);
+
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/push.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/push.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/push.c	(revision 3338)
@@ -0,0 +1,17 @@
+# include "data.h"
+
+int push (int argc, char **argv) {
+  
+  Queue *queue;
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: push (queue) (value)\n");
+    return (FALSE);
+  }
+
+  /* will create a queue if none exists */
+  queue = CreateQueue (argv[1]);
+  PushQueue (queue, argv[2]);
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/queues.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/queues.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/queues.c	(revision 3338)
@@ -0,0 +1,48 @@
+# include "data.h"
+
+int queuelist (int argc, char **argv) {
+  
+  if (argc != 1) {
+    fprintf (stderr, "USAGE: queuelist\n");
+    return (FALSE);
+  }
+
+  ListQueues ();
+  return (TRUE);
+}
+
+
+int queuesize (int argc, char **argv) {
+  
+  int N;
+  char *var;
+  Queue *queue;
+
+  var = (char *) NULL;
+  if ((N = get_argument (argc, argv, "-var"))) {
+    remove_argument (N, &argc, argv);
+    var = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: queuesize (name) [-var variable]\n");
+    return (FALSE);
+  }
+
+  queue = FindQueue (argv[1]);
+  if (queue == NULL) {
+    fprintf (stderr, "ERROR: queue %s not found\n", argv[1]);
+    return (FALSE);
+  }
+
+  if (var == (char *) NULL) {
+    fprintf (stderr, "Nlines: %d\n", queue[0].Nlines);
+    return (TRUE);
+  }
+
+  set_int_variable (var, queue[0].Nlines);
+  free (var);
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/radial.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/radial.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/radial.c	(revision 3338)
@@ -0,0 +1,96 @@
+# include "data.h"
+
+int circstats (int argc, char **argv) {
+  
+  int i, j;
+  double Npix, S1, S2, max, min, Sum, Mean, Stdev, IgnoreValue; 
+  double xc, yc, radius, R2, r;
+  float *V;
+  int xs, ys, xe, ye;
+  int Ignore, Quiet, N, Nx, Ny;
+  Buffer *buf;
+
+  Ignore = FALSE;
+  if ((N = get_argument (argc, argv, "-ignore"))) {
+    Ignore = TRUE;
+    remove_argument (N, &argc, argv);
+    IgnoreValue = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  Quiet = FALSE;
+  if ((N = get_argument (argc, argv, "-q"))) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-quiet"))) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 5) goto usage;
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) goto missed;
+
+  xc = atof (argv[2]);
+  yc = atof (argv[3]);
+  radius = atof (argv[4]);
+  Nx = buf[0].matrix.Naxis[0];
+  Ny = buf[0].matrix.Naxis[1];
+
+  if (xc < 0) goto range;
+  if (yc < 0) goto range;
+  if (xc >= Nx) goto range;
+  if (yc >= Ny) goto range;
+
+  xs = MAX (0, xc - radius);
+  ys = MAX (0, yc - radius);
+  xe = MIN (Nx, xc + radius + 1);
+  ye = MAX (Ny, yc + radius + 1);
+  R2 = radius*radius;
+
+  S1 = S2 = Npix = 0;
+  min = max = *(float *)(buf[0].matrix.buffer) + (int)(yc)*buf[0].matrix.Naxis[0] + (int)(xc); 
+  for (j = ys; j < ye; j++) {
+    V = (float *)(buf[0].matrix.buffer) + j*buf[0].matrix.Naxis[0] + xs; 
+    for (i = xs; i < xe; i++, V++) {
+      r = SQ(i - xc) + SQ(j - yc);
+      if (r > R2) continue;
+      if (Ignore && (fabs (*V - IgnoreValue) < 1e-8)) continue;
+      S1 += *V;
+      S2 += (*V)*(*V);
+      Npix += 1.0;
+      max = MAX (max, *V);
+      min = MIN (min, *V);
+    }
+  }
+  Mean = S1 / Npix;
+  Sum  = Mean * M_PI * R2;
+  Stdev = sqrt (S2/Npix - Mean*Mean);
+
+  if (!Quiet) {
+    fprintf (GetOutfile(), "     mean     stdev       min       max    Npix     Total\n");
+    fprintf (GetOutfile(), "%9.4g %9.4g %9.4g %9.4g %7.0f %9.4g\n", Mean, Stdev, min, max, Npix, Sum);
+  }
+
+  set_variable ("MIN",    min);
+  set_variable ("MAX",    max);
+  set_variable ("MEAN",   Mean);
+  set_variable ("SUM",    Sum);
+  set_variable ("NPIX",   Npix);
+  set_variable ("SIGMA",  Stdev);
+
+  return (TRUE);
+
+ usage: 
+  fprintf (stderr, "USAGE: circstats <buffer> x y radius\n");
+  return (FALSE);
+
+ range:
+  fprintf (stderr, "ERROR: coordinates out of range\n");
+  return (FALSE);
+
+ missed:
+  fprintf (stderr, "ERROR: buffer not found\n");
+  return (FALSE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/rd.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/rd.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/rd.c	(revision 3338)
@@ -0,0 +1,240 @@
+# include "data.h"
+
+/* there is some confusion in this function with the several possible options */
+int rd (int argc, char **argv) {
+  
+  int i, N, status, plane, Nplane, extend, Nextend, Nskip, JustHead;
+  int ccdsel, done;
+  char region[512], *ccdid, *filename;
+  FILE *f;
+  Buffer *buf;
+
+  JustHead = FALSE;
+  if ((N = get_argument (argc, argv, "-head"))) {
+    remove_argument (N, &argc, argv);
+    JustHead = TRUE;
+  }
+
+  plane = 1;
+  if ((N = get_argument (argc, argv, "-plane"))) {
+    remove_argument (N, &argc, argv);
+    plane  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  extend = FALSE;
+  Nextend = -1;
+  if ((N = get_argument (argc, argv, "-x"))) {
+    remove_argument (N, &argc, argv);
+    Nextend  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    extend = TRUE;
+  }
+
+  ccdsel = FALSE;
+  ccdid = (char *) NULL;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    ccdid  = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+    ccdsel = TRUE;
+  }
+
+  if (extend && ccdsel) {
+    fprintf (stderr, "only specify one of -n and -x\n");
+    return (FALSE);
+  }
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: rd <buffer> <filename> [-head] [-plane N] [-n ccdid] [-x extnum]\n");
+    return (FALSE);
+  }
+
+  /* test if file exists */
+  f = fopen (argv[2], "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "file %s not found\n", argv[2]);
+    return (FALSE);
+  }
+  fclose (f);
+
+  /* find matrix, free old data */
+  if ((buf = SelectBuffer (argv[1], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+  fits_free_matrix (&buf[0].matrix);
+  fits_free_header (&buf[0].header);
+
+  /* save file name */
+  filename = filebasename (argv[2]);
+  strcpy (buf[0].file, filename);
+  free (filename);
+
+  if (extend) {
+    /* load in appropriate header */
+    Nskip = fits_read_Xheader (argv[2], &buf[0].header, Nextend);
+    if (!Nskip) {
+      fprintf (stderr, "entry in %s not found\n", argv[2]);
+      DeleteBuffer (buf);
+      return (FALSE);
+    }
+    /* fix up header */
+    {
+      static char simple[] = "SIMPLE  =                    T / Standard FITS";
+      int Ns, No;
+
+      Ns = strlen (simple);
+      No = 80 - Ns;
+      strncpy (buf[0].header.buffer, simple, Ns);
+      memset (&buf[0].header.buffer[Ns], ' ', No);
+    }
+    if (JustHead) {
+      /* should be in CreateMatrix / CreateBuffer function */
+      buf[0].header.Naxes = 0;
+      ALLOCATE (buf[0].matrix.buffer, char, 1);
+      buf[0].matrix.size = 0;
+      buf[0].bitpix = 16;
+      buf[0].bzero = 0;
+      buf[0].bscale = 1;
+      buf[0].matrix.bitpix = 16;
+      buf[0].matrix.bzero = 0;
+      buf[0].matrix.bscale = 1;
+      buf[0].header.bitpix = 16;
+      buf[0].header.bzero = 0;
+      buf[0].header.bscale = 1;
+      return (TRUE);
+    }
+    /* load matrix data */
+    f = fopen (argv[2], "r");
+    if (f == (FILE *) NULL) {
+      fprintf (stderr, "file %s not found\n", argv[2]);
+      DeleteBuffer (buf);
+      return (FALSE);
+    }
+    fseek (f, Nskip, SEEK_SET);
+    status = fits_load_matrix (f, &buf[0].matrix, &buf[0].header);
+    fclose (f);
+  } 
+
+  if (ccdsel) {
+    char *CCDKeyword, ID[64];
+
+    CCDKeyword = get_variable ("CCDKEYWORD");
+    if (CCDKeyword == (char *) NULL) {
+      fprintf (stderr, "CCDKEYWORD variable is not set; ");
+      fprintf (stderr, "using IMAGEID as default\n");
+      CCDKeyword = strcreate ("IMAGEID");
+    }
+    done = FALSE;
+    for (i = 0; !done; i++) {
+      Nskip = fits_read_Xheader (argv[2], &buf[0].header, i);
+      if (!Nskip) {
+	fprintf (stderr, "extension %s in %s not found\n", ccdid, argv[2]);
+	DeleteBuffer (buf);
+	free (CCDKeyword);
+	return (FALSE);
+      }
+      if (!fits_scan (&buf[0].header, CCDKeyword, "%s", 1, ID)) {
+	fprintf (stderr, "%s not in header\n", CCDKeyword);
+	DeleteBuffer (buf);
+	free (CCDKeyword);
+	return (FALSE);
+      }
+
+      /* compare as numbers if both are pure numbers, else as strings */
+      done = strnumcmp (ccdid, ID);
+
+      if (!done) fits_free_header (&buf[0].header);
+    }
+    free (CCDKeyword);
+
+    /* fix up header */
+    {
+      static char simple[] = "SIMPLE  =                    T / Standard FITS";
+      int Ns, No;
+
+      Ns = strlen (simple);
+      No = 80 - Ns;
+      strncpy (buf[0].header.buffer, simple, Ns);
+      memset (&buf[0].header.buffer[Ns], ' ', No);
+    }
+    if (JustHead) {
+      buf[0].header.Naxes = 0;
+      ALLOCATE (buf[0].matrix.buffer, char, 1);
+      buf[0].matrix.size = 0;
+      buf[0].bitpix = 16;
+      buf[0].bzero = 0;
+      buf[0].bscale = 1;
+      buf[0].matrix.bitpix = 16;
+      buf[0].matrix.bzero = 0;
+      buf[0].matrix.bscale = 1;
+      buf[0].header.bitpix = 16;
+      buf[0].header.bzero = 0;
+      buf[0].header.bscale = 1;
+      return (TRUE);
+    }
+    /* load matrix data */
+    f = fopen (argv[2], "r");
+    if (f == (FILE *) NULL) {
+      fprintf (stderr, "file %s not found\n", argv[2]);
+      DeleteBuffer (buf);
+      return (FALSE);
+    }
+    fseek (f, Nskip, SEEK_SET);
+    status = fits_load_matrix (f, &buf[0].matrix, &buf[0].header);
+    fclose (f);
+  }
+
+  if (!ccdsel && !extend) {
+    status = fits_read_header (argv[2], &buf[0].header);
+    if (JustHead) {
+      buf[0].header.Naxes = 0;
+      ALLOCATE (buf[0].matrix.buffer, char, 1);
+      buf[0].matrix.size = 0;
+      buf[0].bitpix = 16;
+      buf[0].bzero = 0;
+      buf[0].matrix.bscale = 1;
+      buf[0].matrix.bitpix = 16;
+      buf[0].matrix.bzero = 0;
+      buf[0].matrix.bscale = 1;
+      return (TRUE);
+    }
+    Nplane = buf[0].header.Naxis[2];
+    if (Nplane > 0) {
+      if (plane > Nplane) {
+	fprintf (stderr, "-plane is too large: %d total planes\n", Nplane);
+	DeleteBuffer (buf);
+	return (FALSE);
+      }
+      buf[0].header.Naxis[2] = 0;
+      buf[0].header.Naxes = 2;
+      fits_modify (&buf[0].header, "NAXIS", "%d", 1, 2);
+      fits_delete (&buf[0].header, "NAXIS3", 1);
+    }
+    sprintf (region, "-1 -1 -1 -1 %d %d", (plane - 1), plane);
+    status = fits_read_segment (argv[2], &buf[0].matrix, region);
+  }
+
+  if (!status) {
+    fprintf (stderr, "problem reading file, buffer not opened\n");
+    DeleteBuffer (buf);
+    return (FALSE);
+  }
+  if (buf[0].header.Naxes == 1) {
+    /* we need to return an array, so make Naxis[1] = 1 */
+    buf[0].header.Naxes = 2;
+    buf[0].header.Naxis[1] = 1;
+    buf[0].matrix.Naxis[1] = 1;
+  }    
+
+  buf[0].bitpix = buf[0].header.bitpix;    /* store the original values */
+  buf[0].bscale = buf[0].header.bscale;    /* store the original values */
+  buf[0].bzero  = buf[0].header.bzero;     /* store the original values */
+  buf[0].unsign = buf[0].header.unsign;
+  fprintf (GetOutfile(), "read %d bytes from %s into buffer %s\n", 
+	   buf[0].header.size + buf[0].matrix.size, argv[2], argv[1]);
+
+  /** now - convert the matrix values to floats for internal use **/
+  fits_convert_format (&buf[0].header, &buf[0].matrix, -32, 1.0, 0.0, FT_UNSIGN_MODE);
+  
+  return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/rdseg.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/rdseg.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/rdseg.c	(revision 3338)
@@ -0,0 +1,72 @@
+# include "data.h"
+
+/* there is some confusion in this function with the several possible options */
+int rdseg (int argc, char **argv) {
+  
+  int x, y, nx, ny, status;
+  char region[512], *filename;
+  FILE *f;
+  Buffer *buf;
+
+  if (argc != 7) {
+    fprintf (stderr, "USAGE: rdseg <buffer> <filename> x y nx ny\n");
+    return (FALSE);
+  }
+  x = atoi (argv[3]);
+  y = atoi (argv[4]);
+  nx = atoi (argv[5]);
+  ny = atoi (argv[6]);
+
+  /* test if file exists */
+  f = fopen (argv[2], "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "file %s not found\n", argv[2]);
+    return (FALSE);
+  }
+  fclose (f);
+
+  /* find matrix, free old data */
+  if ((buf = SelectBuffer (argv[1], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+  fits_free_matrix (&buf[0].matrix);
+  fits_free_header (&buf[0].header);
+
+  /* save file name */
+  filename = filebasename (argv[2]);
+  strcpy (buf[0].file, filename);
+  free (filename);
+
+  status = fits_read_header (argv[2], &buf[0].header);
+  sprintf (region, "%d %d %d %d 0 1", x, nx + x, y, ny + y);
+  status = fits_read_segment (argv[2], &buf[0].matrix, region);
+  fits_modify (&buf[0].header, "NAXIS1", "%d", 1, nx);
+  fits_modify (&buf[0].header, "NAXIS2", "%d", 1, ny);
+  buf[0].header.Naxis[0] = nx;
+  buf[0].header.Naxis[1] = ny;
+  buf[0].matrix.Naxis[0] = nx;
+  buf[0].matrix.Naxis[1] = ny;
+
+  if (!status) {
+    fprintf (stderr, "problem reading file, buffer not opened\n");
+    DeleteBuffer (buf);
+    return (FALSE);
+  }
+  if (buf[0].header.Naxes == 1) {
+    /* we need to return an array, so make Naxis[1] = 1 */
+    buf[0].header.Naxes = 2;
+    buf[0].header.Naxis[1] = 1;
+    buf[0].matrix.Naxis[1] = 1;
+  }    
+
+  buf[0].bitpix = buf[0].header.bitpix;    /* store the original values */
+  buf[0].bscale = buf[0].header.bscale;    /* store the original values */
+  buf[0].bzero  = buf[0].header.bzero;     /* store the original values */
+  buf[0].unsign = buf[0].header.unsign;
+  fprintf (GetOutfile(), "read %d bytes from %s into buffer %s\n", 
+	   buf[0].header.size + buf[0].matrix.size, argv[2], argv[1]);
+
+  /** now - convert the matrix values to floats for internal use **/
+  fits_convert_format (&buf[0].header, &buf[0].matrix, -32, 1.0, 0.0, FT_UNSIGN_MODE);
+  
+  return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/read_vectors.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/read_vectors.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/read_vectors.c	(revision 3338)
@@ -0,0 +1,274 @@
+ # include "data.h"
+
+FILE *f = (FILE *) NULL;
+char filename[256];
+
+int datafile (int argc, char **argv) {
+
+  if (argc < 2) {
+    fprintf (stderr, "USAGE: datafile (filename)\n");
+    return (FALSE);
+  }
+  
+  strcpy (filename, argv[1]);
+  if (f != (FILE *) NULL) { fclose (f); }
+  f = fopen (filename, "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "failed to open file %s\n", argv[1]);
+    return (FALSE);
+  }
+  return (TRUE);
+}
+
+int read_vectors (int argc, char **argv) {
+  
+  int i, j, Nskip, Nvec, *col, done, status;
+  int Nbytes, nbytes, Nstart, NELEM, N, nread;
+  char *colstr, *c0, *c1, *buffer, *extname;
+  double value;
+  Vector **vec;
+
+  /* auto-sense table type */
+  if ((N = get_argument (argc, argv, "-fits"))) {
+    remove_argument (N, &argc, argv);
+    extname = strcreate (argv[N]);
+    if (extname == (char *) NULL) return (FALSE);
+    remove_argument (N, &argc, argv);
+    status = read_table_vectors (argc, argv, extname);
+    free (extname);
+    return (status);
+  }
+
+  Nskip = 0;
+  if ((N = get_argument (argc, argv, "-skip"))) {
+    remove_argument (N, &argc, argv);
+    Nskip = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if ((argc < 3) || !(argc % 2)) {
+    fprintf (stderr, "USAGE: read name N name N ...\n");
+    return (FALSE);
+  }
+  /* read name N name N  */
+
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "no open file for read\n");
+    return (FALSE);
+  }
+  fseek (f, 0, SEEK_SET);
+
+  Nvec = (argc - 1) / 2;
+  ALLOCATE (vec, Vector *, Nvec);
+  ALLOCATE (col, int, Nvec);
+
+  for (i = 0; i < Nvec; i++) {
+    if ((vec[i] = SelectVector (argv[2*i + 1], ANYVECTOR, TRUE)) == NULL) {
+      fprintf (stderr, "USAGE: read name N name N ...\n");
+      free (vec);
+      free (col);
+      return (FALSE);    
+    }
+    colstr = argv[2*i+2];
+    for (j = 0; j < strlen (colstr); j++) {
+      if (!isdigit(colstr[j])) {
+	fprintf (stderr, "USAGE: read name N name N ...\n");
+	free (vec);
+	free (col);
+	return (FALSE);    
+      }
+    }
+    col[i] = atof (colstr);
+  }
+  
+  NELEM = 1000;
+  for (i = 0; i < Nvec; i++) {
+    REALLOCATE (vec[i][0].elements, float, NELEM);
+  }
+  
+  ALLOCATE (buffer, char, 0x10001);
+  bzero (buffer, 0x10001);
+  for (i = 0; i < Nskip; i++) {
+    scan_line (f, buffer);
+  }
+
+  Nstart = 0;
+  N = 0;
+  done = FALSE;
+  while (!done) {
+    Nbytes = 0x10000 - Nstart;
+    bzero (&buffer[Nstart], Nbytes);
+    nread = fread (&buffer[Nstart], 1, Nbytes, f);
+    if (ferror (f)) {
+      perror ("error reading data file");
+      break;
+    }
+    if (nread == 0) break;
+    nbytes = nread + Nstart;
+    
+    status = TRUE;
+    c0 = buffer; 
+    while (status) {
+      c1 = strchr (c0, '\n');
+      if (c1 == (char *) NULL) {
+	Nstart = strlen (c0);
+	memmove (buffer, c0, Nstart);
+	status = FALSE;
+      } else {
+	*c1 = 0;
+      }      
+      if ((*c0 != '#') && (*c0 != '!')) {
+	for (i = 0; (i < Nvec) && status; i++) {
+	  status = dparse (&value, col[i], c0);
+	  vec[i][0].elements[N] = value;
+	  if (!status) vec[i][0].elements[N] = 0.0/0.0;
+	}
+	if (status) N++;
+      }
+      c0 = c1 + 1;
+      if (N == NELEM) {
+	NELEM += 1000;
+	for (i = 0; i < Nvec; i++) {
+	  REALLOCATE (vec[i][0].elements, float, NELEM);
+	}
+      }
+	
+    }
+  }
+  for (i = 0; i < Nvec; i++) {
+    REALLOCATE (vec[i][0].elements, float, MAX (N,1));
+    vec[i][0].Nelements = N;
+  }
+  
+  free (vec);
+  free (col);
+  free (buffer);
+  return (TRUE);
+
+}
+
+int read_table_vectors (int argc, char **argv, char *extname) {
+
+  int i, j, k, Nbytes, Nread, Nextend, Ny, Binary;
+  char type[16];
+  FTable table;
+  Header header;
+  Vector **vec;
+
+  if (argc < 2) {
+    fprintf (stderr, "USAGE: read -fits extension name name ...\n");
+    fprintf (stderr, "  ('extension' may be a name or number)\n");
+    return (FALSE);
+  }
+
+  if (f == (FILE *) NULL) return (FALSE);
+  fseek (f, 0, SEEK_SET);
+  table.header = &header;
+
+  /* load appropriate extension (if extname is a number, use count) */
+  if (isdigit(extname[0])) {
+    Nextend = atoi (extname);
+
+    for (i = 0; i <= Nextend; i++) {
+      if (!fits_load_header (f, &header)) return (FALSE);
+      Nbytes = fits_matrix_size (&header);
+      /* skip the prior data buffers */
+      if (i < Nextend) { 
+	fseek (f, Nbytes, SEEK_CUR);
+	fits_free_header (&header);
+	continue;
+      }
+      /* on the desired header, load buffer */
+      ALLOCATE (table.buffer, char, Nbytes);
+      Nread = fread (table.buffer, sizeof (char), Nbytes, f);
+      if (Nread != Nbytes) {
+	fits_free_table  (&table);
+	fits_free_header (&header);
+	return (FALSE);
+      }
+      table.size = Nbytes;
+    }
+  } else {
+    if (!fits_fread_ftable (f, &table, extname)) return (FALSE);
+  }
+
+  /* identify table type (ascii / binary) */
+  Binary = FALSE;
+  fits_scan (&header, "XTENSION", "%s", 1, type);
+  if (!strcmp (type, "BINTABLE")) {
+    Binary = TRUE;
+  } 
+  Ny = header.Naxis[1];
+
+  /* find columns which match requested vectors */
+  for (i = 1; i < argc; i++) {
+    void   *data;
+    short  *Ps;
+    int    *Pi;
+    float  *Pf;
+    double *Pd;
+    int Nval;
+    char name[80];
+      
+    Nval = 0;
+    if (Binary) {
+      if (!fits_get_bintable_column_type (&header, argv[i], type, &Nval)) return (FALSE);
+      if (!strcmp (type, "char")) return (FALSE);
+      if (!fits_get_bintable_column (&header, &table, argv[i], &data)) return (FALSE);
+    } else {
+      if (!fits_get_table_column_type (&header, argv[i], type)) return (FALSE);
+      if (!strcmp (type, "char")) return (FALSE);
+      if (!fits_get_table_column (&header, &table, argv[i], &data)) return (FALSE);
+    }
+    if (Nval == 0) return (FALSE);
+
+    ALLOCATE (vec, Vector *, Nval);
+    for (j = 0; j < Nval; j++) {
+      if (Nval == 1) 
+	sprintf (name, "%s", argv[i]);
+      else
+	sprintf (name, "%s:%d", argv[i], j);
+      if ((vec[j] = SelectVector (name, ANYVECTOR, TRUE)) == NULL) return (FALSE);    
+      REALLOCATE (vec[j][0].elements, float, MAX (Ny,1));
+      vec[j][0].Nelements = Ny;
+    }
+
+    if (!strcmp (type, "double")) {
+      Pd = (double *) data;
+      for (j = 0; j < Ny; j++) {
+	for (k = 0; k < Nval; k++, Pd++) {
+	  vec[k][0].elements[j] = *Pd;
+	}
+      }
+    }
+    if (!strcmp (type, "float")) {
+      Pf = (float *) data;
+      for (j = 0; j < Ny; j++) {
+	for (k = 0; k < Nval; k++, Pf++) {
+	  vec[k][0].elements[j] = *Pf;
+	}
+      }
+    }
+    if (!strcmp (type, "int")) {
+      Pi = (int *) data;
+      for (j = 0; j < Ny; j++) {
+	for (k = 0; k < Nval; k++, Pi++) {
+	  vec[k][0].elements[j] = *Pi;
+	}
+      }
+    }
+    if (!strcmp (type, "short")) {
+      Ps = (short *) data;
+      for (j = 0; j < Ny; j++) {
+	for (k = 0; k < Nval; k++, Ps++) {
+	  vec[k][0].elements[j] = *Ps;
+	}
+      }
+    }
+    free (data);
+    free (vec);
+  }
+  fits_free_table (&table);
+  fits_free_header (&header);
+  return (TRUE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/rebin.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/rebin.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/rebin.c	(revision 3338)
@@ -0,0 +1,227 @@
+# include "data.h"
+
+int rebin (int argc, char **argv) {
+  
+  int i, j, status, n, nx, ny, Nx, Ny, x, y, N, *Npix, *Vn;
+  int Ignore, IgnoreValue, VERBOSE, Normalize, ExactScale;
+  char temp[1024];
+  float *Vout, *Vin, *Out, *In;
+  double scale, scale2, fx, fy, dX, dY;
+  Buffer *in, *out;
+
+  Normalize = FALSE;
+  if ((N = get_argument (argc, argv, "-norm"))) {
+    remove_argument (N, &argc, argv);
+    Normalize = TRUE;
+  }
+
+  VERBOSE = FALSE;
+  if ((N = get_argument (argc, argv, "-v"))) {
+    remove_argument (N, &argc, argv);
+    VERBOSE = TRUE;
+  }
+
+  Ignore = FALSE;
+  IgnoreValue = 0.0;
+  if ((N = get_argument (argc, argv, "-ignore"))) {
+    Ignore = TRUE;
+    remove_argument (N, &argc, argv);
+    IgnoreValue = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 4) {
+    fprintf (stderr, "USAGE: rebin <from> <to> scale \n");
+    fprintf (stderr, "  negative integer scale expands image\n");
+    return (FALSE);
+  }
+
+  if ((in  = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((out = SelectBuffer (argv[2], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+  fits_free_matrix (&out[0].matrix);
+  fits_free_header (&out[0].header);
+
+  scale  = atof (argv[3]);
+  if ((scale == (int) scale) || ((1.0/scale) == (int)(1.0/scale))) {
+    ExactScale = TRUE;
+    if (scale > 0) {
+      nx = in[0].header.Naxis[0] / scale;
+      ny = in[0].header.Naxis[1] / scale;
+    } else {
+      nx = in[0].header.Naxis[0] * fabs(scale);
+      ny = in[0].header.Naxis[1] * fabs(scale);
+    }    
+  } else {
+    ExactScale = FALSE;
+    if (scale > 0) {
+      nx = (int) (in[0].header.Naxis[0] / scale) + 1;
+      ny = (int) (in[0].header.Naxis[1] / scale) + 1;
+    } else {
+      nx = (int) (in[0].header.Naxis[0] * fabs(scale)) + 1;
+      ny = (int) (in[0].header.Naxis[1] * fabs(scale)) + 1;
+    }      
+  }
+  if (VERBOSE) fprintf (GetOutfile(), "rebin %s to %s (%d,%d to %d,%d)\n", argv[1], argv[2], in[0].header.Naxis[0], in[0].header.Naxis[1], nx, ny);
+
+  Nx = in[0].header.Naxis[0];
+  Ny = in[0].header.Naxis[1];
+  out[0].bitpix = in[0].bitpix;
+  out[0].unsign = in[0].unsign;
+  out[0].bscale = in[0].bscale;
+  out[0].bzero  = in[0].bzero;
+  fits_copy_header (&in[0].header, &out[0].header);
+  fits_modify (&out[0].header, "NAXIS1", "%d", 1, nx);
+  fits_modify (&out[0].header, "NAXIS2", "%d", 1, ny);
+
+  status =  fits_scan (&out[0].header, "CDELT1", "%lf", 1, &dX);
+  status &= fits_scan (&out[0].header, "CDELT2", "%lf", 1, &dY);
+  if (scale > 0) {
+    dX *= scale;
+    dY *= scale;
+  } else {
+    dX /= fabs(scale);
+    dY /= fabs(scale);
+  }    
+  if (status) {
+    fits_modify (&out[0].header, "CDELT1", "%lf", 1, dX);
+    fits_modify (&out[0].header, "CDELT2", "%lf", 1, dY);
+  }
+
+  status =  fits_scan (&out[0].header, "CRPIX1", "%lf", 1, &dX);
+  status &= fits_scan (&out[0].header, "CRPIX2", "%lf", 1, &dY);
+  if (scale > 0) {
+    dX /= scale;
+    dY /= scale;
+  } else {
+    dX *= fabs(scale);
+    dY *= fabs(scale);
+  }    
+  if (status) {
+    fits_modify (&out[0].header, "CRPIX1", "%lf", 1, dX);
+    fits_modify (&out[0].header, "CRPIX2", "%lf", 1, dY);
+  }
+
+  out[0].header.Naxis[0] = nx;
+  out[0].header.Naxis[1] = ny;
+  fits_create_matrix (&out[0].header, &out[0].matrix);
+  temp[0] = 0;
+  if ((in[0].file[0] != '*') && (in[0].file[0] != '(')) {
+    strcpy (temp, "*");
+  }
+  strcat (temp, in[0].file);
+  strcpy (out[0].file, temp);
+
+  if (Normalize) {
+    ALLOCATE (Npix, int, nx*ny);
+    bzero (Npix, nx*ny*sizeof(int));
+  }
+
+  if (ExactScale) {
+    n = scale;
+    if (n > 0) {
+      for (j = 0; j < ny; j++) {
+	for (y = 0; y < n; y++) {
+	  Vout = (float *)(out[0].matrix.buffer) + j*nx;
+	  Vin  = (float *)(in[0].matrix.buffer)  + (j*n + y)*in[0].header.Naxis[0];
+	  if (Normalize) { Vn = Npix + j*nx; }
+	  for (i = 0; i < nx; i++, Vout++) {
+	    for (x = 0; x < n; x++, Vin++) {
+	      if (Ignore && (*Vin == IgnoreValue)) continue;
+	      *Vout += *Vin;
+	      if (Normalize) {(*Vn) ++;}
+	    }
+	    if (Normalize) {Vn ++;}
+	  }
+	}
+      }
+    } else {
+      n = fabs (n);
+      for (j = 0; j < in[0].header.Naxis[1]; j++) {
+	for (y = 0; y < n; y++) {
+	  Vout = (float *)(out[0].matrix.buffer) + (j*n + y)*nx;
+	  Vin  = (float *)(in[0].matrix.buffer)  + j*in[0].header.Naxis[0];
+	  if (Normalize) { Vn = Npix + j*nx; }
+	  for (i = 0; i < in[0].header.Naxis[0]; i++, Vin++) {
+	    if (Ignore && (*Vin == IgnoreValue)) { 
+	      Vout += n; 
+	      if (Normalize) Vn += n; 
+	      continue; 
+	    }
+	    for (x = 0; x < n; x++, Vout++) {
+	      *Vout = *Vin;
+	      if (Normalize) {(*Vn) ++; Vn ++;}
+	    }
+	  }
+	}
+      }
+    }
+    if (Normalize) {
+      Vn = Npix;
+      Vout = (float *)out[0].matrix.buffer;
+      for (i = 0; i < nx*ny; i++, Vout++, Vn++) {
+	if (*Vn) { 
+	  *Vout /= *Vn; 
+	} else {
+	  *Vout = 0;
+	}
+      }
+    }
+  } else {
+    
+    /* normalization is broken.  repair please */
+    if (Normalize) { fprintf (stderr, "normalize not enabled for fractional scaling\n"); }
+
+    if (scale < 0) scale = 1.0 / fabs(scale);
+    In = (float *)in[0].matrix.buffer;
+    Out = (float *)out[0].matrix.buffer;
+    scale2 = scale*scale;
+    if (scale > 1) {
+      for (i = 0; i < Ny; i++) {
+	y = 0.5 + (i - 0.5) / scale;
+	fy = 0.5 + MIN (0.5, (y + 0.5) * scale - i);
+	for (j = 0; j < Nx; j++, In++) {
+	  x = 0.5 + (j - 0.5) / scale;
+	  fx = 0.5 + MIN (0.5, (x + 0.5) * scale - j);
+	  Vout = Out + y*nx + x;
+	  *Vout += fx*fy*(*In);
+	  if (fx < 1) {
+	    *(Vout+1)    += (1-fx)*fy*(*In);
+	  }
+	  if (fy < 1) {
+	    *(Vout+nx) += fx*(1-fy)*(*In);
+	  }
+	  if ((fx < 1) && (fy < 1)) {
+	    *(Vout+1+nx) += (1-fx)*(1-fy)*(*In);
+	  }
+	}
+      }
+    } else {
+      for (i = 0; i < ny; i++) {
+	y = 0.5 + (i - 0.5) * scale;
+	fy = 0.5 + MIN (0.5, (y + 0.5) / scale - i);
+	for (j = 0; j < nx; j++, Out++) {
+	  x = 0.5 + (j - 0.5) * scale;
+	  fx = 0.5 + MIN (0.5, (x + 0.5) / scale - j);
+	  Vin = In + y*Nx + x;
+	  *Out += *Vin*fx*fy;
+	  if (fx < 1) {
+	    *Out += *(Vin+1)*(1-fx)*fy;
+	  }
+	  if (fy < 1) {
+	    *Out += *(Vin+Nx)*fx*(1-fy);
+	  }
+	  if ((fx < 1) && (fy < 1)) {
+	    *Out += *(Vin+1+Nx)*(1-fx)*(1-fy);
+	  }
+	  *Out = *Out * scale2;
+	}
+      }
+    }
+  }
+
+  if (Normalize) free (Npix);
+
+  return (TRUE);
+
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/resize.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/resize.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/resize.c	(revision 3338)
@@ -0,0 +1,61 @@
+# include "data.h"
+
+int resize (int argc, char **argv) {
+
+  char buffer[128], buffer2[128], *end;
+  double NX, NY;
+  int N, Source, Nsource, IsImage;
+  
+  /* display source */
+  Nsource = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nsource = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-g"))) {
+    remove_argument (N, &argc, argv);
+    SetImageDevice (FALSE);
+  }  
+  if ((N = get_argument (argc, argv, "-i"))) {
+    remove_argument (N, &argc, argv);
+    SetImageDevice (TRUE);
+  }  
+  IsImage = GetCurrentDevice ();
+  if (IsImage) {
+    if (!GetImage (&Source, &Nsource)) return (FALSE);
+  } else {
+    if (!GetGraph (NULL, &Source, &Nsource)) return (FALSE);
+  }
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: resize NX NY [-n] [-g | -i]\n");
+    return (FALSE);
+  }
+
+  /* NX & NY are pixels for the screen & points for PS 
+     convert units to points (1in = 72pt, 1cm = 28pt) */
+
+  /* have kapa convert physical units to screen units 
+     for now, fixed at 96 pix / in == 38 pix / cm
+  */
+
+  NX = strtod (argv[1], &end);
+  if (!strcmp (end, "in")) { NX *= 96; }
+  if (!strcmp (end, "cm")) { NX *= 38; }
+
+  NY = strtod (argv[2], &end);
+  if (!strcmp (end, "in")) { NY *= 96; }
+  if (!strcmp (end, "cm")) { NY *= 38; }
+
+  write (Source, "RSIZ", 4); /* tell Source to resize the image */
+
+  sprintf (buffer, "%d %d", (int) NX, (int) NY);
+  sprintf (buffer2, "NBYTES: %6d ", strlen (buffer));
+  write (Source, buffer2, 16);
+  write (Source, buffer, strlen (buffer));
+
+  return (TRUE);
+
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/roll.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/roll.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/roll.c	(revision 3338)
@@ -0,0 +1,45 @@
+# include "data.h"
+
+int roll (int argc, char **argv) {
+  
+  int Nbytes, Nextra;
+  int dX, dx, dy, nx, ny;
+  Buffer *buf;
+
+  if (argc != 4) {
+    fprintf (stderr, "USAGE: roll <buffer> dx dy\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  dx = atof (argv[2]);
+  dy = atof (argv[3]);
+  if (dy != 0) {
+    fprintf (stderr, "only x rolls implemented for now\n");
+  }
+
+  /* if (dx < 0), we are moving the start position back by dx pixels,
+     if (dx > 0), we are moving the start position forward by dx pixels */
+  
+  nx = buf[0].matrix.Naxis[0];
+  ny = buf[0].matrix.Naxis[1];
+
+  dX = abs(dx);
+  Nbytes = nx * ny * sizeof (float);
+  Nextra = (nx * ny + dX) * sizeof (float);
+
+  REALLOCATE (buf[0].matrix.buffer, char, Nextra);
+
+  if (dx < 0) {
+    memmove (buf[0].matrix.buffer, &buf[0].matrix.buffer[dX*sizeof(float)], Nbytes);
+  } else {
+    memmove (&buf[0].matrix.buffer[dX*sizeof(float)], buf[0].matrix.buffer, Nbytes);
+  }
+
+  REALLOCATE (buf[0].matrix.buffer, char, Nbytes);
+
+  return (TRUE);
+
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/rotate.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/rotate.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/rotate.c	(revision 3338)
@@ -0,0 +1,298 @@
+# include "data.h"
+
+int rotate (int argc, char **argv) {
+  
+  int i, j, NX, NY, X, Y, Lx, Ly, N, newCenter;
+  float *in_buff, *out_buff, *c;
+  double angle, CosAngle, SinAngle, Xo, Yo, dX, dY, fx, fy, x, y, X1, Y1;
+  double pc11, pc12, pc21, pc22, PC11, PC12, PC21, PC22;
+  Buffer *buf;
+
+  Xo = 0;
+  Yo = 0;
+  if ((N = get_argument (argc, argv, "-center"))) {
+    newCenter = TRUE;
+    remove_argument (N, &argc, argv);
+    Xo  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    Yo  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  else 
+    newCenter  = FALSE;
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: rotate <buffer> <angle>\n");
+    return (FALSE);
+  }
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  if ((atof (argv[1]) < -180) || (atof (argv[1]) > 180)) {
+    fprintf (stderr, "valid rotate angle between -180 and +180 degrees\n");
+    return (FALSE);
+  }
+
+  /* save starting values */
+  NX = buf[0].header.Naxis[0];
+  NY = buf[0].header.Naxis[1];
+  in_buff = (float *) buf[0].matrix.buffer;  /* don't lose reference */
+
+  if (!strcasecmp (argv[2], "LEFT") || (atof (argv[2]) == -90)) {
+    buf[0].header.Naxis[0] = NY;
+    buf[0].header.Naxis[1] = NX;
+    fits_modify (&buf[0].header, "NAXIS1", "%d", 1, NY);
+    fits_modify (&buf[0].header, "NAXIS2", "%d", 1, NX);
+    fits_print  (&buf[0].header, "HISTORY", "%S", 1, "WARNING: rotated image!");
+    fits_create_matrix (&buf[0].header, &buf[0].matrix);
+    out_buff = (float *)buf[0].matrix.buffer;
+    for (i = NX - 1; i > -1; i--) {
+      for (j = 0; j < NY; j++, out_buff++) {
+	*out_buff = in_buff[i + j*NX];
+      }
+    }
+    /* fix reference pixel */
+    fits_scan (&buf[0].header, "CRPIX1", "%lf", 1, &Xo);
+    fits_scan (&buf[0].header, "CRPIX2", "%lf", 1, &Yo);
+    X1 = Yo;
+    Y1 = NX - Xo;
+    fits_modify (&buf[0].header, "CRPIX1", "%lf", 1, X1);
+    fits_modify (&buf[0].header, "CRPIX2", "%lf", 1, Y1);
+    
+    /* fix rotate matrix */
+    fits_scan (&buf[0].header, "PC001001", "%lf", 1, &pc11);
+    fits_scan (&buf[0].header, "PC001002", "%lf", 1, &pc12);
+    fits_scan (&buf[0].header, "PC002001", "%lf", 1, &pc21);
+    fits_scan (&buf[0].header, "PC002002", "%lf", 1, &pc22);
+    PC11 = pc21;
+    PC12 = pc22;
+    PC21 = -pc11;
+    PC22 = -pc12;
+    fits_modify (&buf[0].header, "PC001001", "%le", 1, PC11);
+    fits_modify (&buf[0].header, "PC001002", "%le", 1, PC12);
+    fits_modify (&buf[0].header, "PC002001", "%le", 1, PC21);
+    fits_modify (&buf[0].header, "PC002002", "%le", 1, PC22);
+
+    free (in_buff);
+    return (TRUE);
+  }
+
+  if (!strcasecmp (argv[2], "RIGHT") || (atof (argv[2]) == 90)) {
+    buf[0].header.Naxis[0] = NY;
+    buf[0].header.Naxis[1] = NX;
+    fits_modify (&buf[0].header, "NAXIS1", "%d", 1, NY);
+    fits_modify (&buf[0].header, "NAXIS2", "%d", 1, NX);
+    fits_print  (&buf[0].header, "HISTORY", "%S", 1, "WARNING: rotated image!");
+    fits_create_matrix (&buf[0].header, &buf[0].matrix);
+    out_buff = (float *)buf[0].matrix.buffer;
+    for (i = 0; i < NX; i++) {
+      for (j = NY - 1; j > -1; j--, out_buff++) {
+	*out_buff = in_buff[i + j*NX];
+      }
+    }
+    /* fix reference pixel */
+    fits_scan (&buf[0].header, "CRPIX1", "%lf", 1, &Xo);
+    fits_scan (&buf[0].header, "CRPIX2", "%lf", 1, &Yo);
+    X1 = NY - Yo;
+    Y1 = Xo;
+    fprintf (stderr, "%f %f -> %f %f\n", Xo, Yo, X1, Y1);
+    fits_modify (&buf[0].header, "CRPIX1", "%lf", 1, X1);
+    fits_modify (&buf[0].header, "CRPIX2", "%lf", 1, Y1);
+    
+    /* fix rotate matrix */
+    fits_scan (&buf[0].header, "PC001001", "%lf", 1, &pc11);
+    fits_scan (&buf[0].header, "PC001002", "%lf", 1, &pc12);
+    fits_scan (&buf[0].header, "PC002001", "%lf", 1, &pc21);
+    fits_scan (&buf[0].header, "PC002002", "%lf", 1, &pc22);
+    PC11 = -pc21;
+    PC12 = -pc22;
+    PC21 = pc11;
+    PC22 = pc12;
+    fprintf (stderr, "%f %f  ->  %f %f\n", pc11, pc12, PC11, PC12);
+    fprintf (stderr, "%f %f  ->  %f %f\n", pc21, pc22, PC21, PC22);
+    fits_modify (&buf[0].header, "PC001001", "%le", 1, PC11);
+    fits_modify (&buf[0].header, "PC001002", "%le", 1, PC12);
+    fits_modify (&buf[0].header, "PC002001", "%le", 1, PC21);
+    fits_modify (&buf[0].header, "PC002002", "%le", 1, PC22);
+
+    free (in_buff);
+    return (TRUE);
+  }
+
+  if (!strcasecmp (argv[2], "UPSIDE") || (atof (argv[2]) == -180) || (atof (argv[2]) == 180)) {
+    fits_print  (&buf[0].header, "HISTORY", "%S", 1, "WARNING: rotated image!");
+    fits_create_matrix (&buf[0].header, &buf[0].matrix);
+    out_buff = (float *)buf[0].matrix.buffer;
+    for (j = NY - 1; j > -1; j--) {
+      for (i = NX - 1; i > -1; i--, out_buff++) {
+	*out_buff = in_buff[i + j*NX];
+      }
+    }
+    /* fix reference pixel */
+    fits_scan (&buf[0].header, "CRPIX1", "%lf", 1, &Xo);
+    fits_scan (&buf[0].header, "CRPIX2", "%lf", 1, &Yo);
+    X1 = NX - Xo;
+    Y1 = NY - Yo;
+    fits_modify (&buf[0].header, "CRPIX1", "%lf", 1, X1);
+    fits_modify (&buf[0].header, "CRPIX2", "%lf", 1, Y1);
+    
+    /* fix rotate matrix */
+    fits_scan (&buf[0].header, "PC001001", "%lf", 1, &pc11);
+    fits_scan (&buf[0].header, "PC001002", "%lf", 1, &pc12);
+    fits_scan (&buf[0].header, "PC002001", "%lf", 1, &pc21);
+    fits_scan (&buf[0].header, "PC002002", "%lf", 1, &pc22);
+    PC11 = -pc11;
+    PC12 = -pc12;
+    PC21 = -pc21;
+    PC22 = -pc22;
+    fits_modify (&buf[0].header, "PC001001", "%le", 1, PC11);
+    fits_modify (&buf[0].header, "PC001002", "%le", 1, PC12);
+    fits_modify (&buf[0].header, "PC002001", "%le", 1, PC21);
+    fits_modify (&buf[0].header, "PC002002", "%le", 1, PC22);
+
+    free (in_buff);
+    return (TRUE);
+  }
+
+  if (!strcasecmp (argv[2], "FLIPY")) {
+    fits_print  (&buf[0].header, "HISTORY", "%S", 1, "WARNING: rotated image!");
+    fits_create_matrix (&buf[0].header, &buf[0].matrix);
+    out_buff = (float *)buf[0].matrix.buffer;
+    for (j = NY - 1; j > -1; j--) {
+      for (i = 0; i < NX; i++, out_buff++) {
+	*out_buff = in_buff[i + j*NX];
+      }
+    }
+    /* fix reference pixel */
+    fits_scan (&buf[0].header, "CRPIX1", "%lf", 1, &Xo);
+    fits_scan (&buf[0].header, "CRPIX2", "%lf", 1, &Yo);
+    X1 = Xo;
+    Y1 = NY - Yo;
+    fits_modify (&buf[0].header, "CRPIX1", "%lf", 1, X1);
+    fits_modify (&buf[0].header, "CRPIX2", "%lf", 1, Y1);
+    
+    /* fix rotate matrix */
+    fits_scan (&buf[0].header, "PC001001", "%lf", 1, &pc11);
+    fits_scan (&buf[0].header, "PC001002", "%lf", 1, &pc12);
+    fits_scan (&buf[0].header, "PC002001", "%lf", 1, &pc21);
+    fits_scan (&buf[0].header, "PC002002", "%lf", 1, &pc22);
+    PC11 = pc11;
+    PC12 = -pc12;
+    PC21 = pc21;
+    PC22 = -pc22;
+    fits_modify (&buf[0].header, "PC001001", "%le", 1, PC11);
+    fits_modify (&buf[0].header, "PC001002", "%le", 1, PC12);
+    fits_modify (&buf[0].header, "PC002001", "%le", 1, PC21);
+    fits_modify (&buf[0].header, "PC002002", "%le", 1, PC22);
+
+    free (in_buff);
+    return (TRUE);
+  }
+
+  if (!strcasecmp (argv[2], "FLIPX")) {
+    fits_print  (&buf[0].header, "HISTORY", "%S", 1, "WARNING: rotated image!");
+    fits_create_matrix (&buf[0].header, &buf[0].matrix);
+    out_buff = (float *)buf[0].matrix.buffer;
+    for (j = 0; j < NY; j++) {
+      for (i = NX - 1; i > -1; i--, out_buff++) {
+	*out_buff = in_buff[i + j*NX];
+      }
+    }
+    /* fix reference pixel */
+    fits_scan (&buf[0].header, "CRPIX1", "%lf", 1, &Xo);
+    fits_scan (&buf[0].header, "CRPIX2", "%lf", 1, &Yo);
+    X1 = NX - Xo;
+    Y1 = Yo;
+    fits_modify (&buf[0].header, "CRPIX1", "%lf", 1, X1);
+    fits_modify (&buf[0].header, "CRPIX2", "%lf", 1, Y1);
+    
+    /* fix rotate matrix */
+    fits_scan (&buf[0].header, "PC001001", "%lf", 1, &pc11);
+    fits_scan (&buf[0].header, "PC001002", "%lf", 1, &pc12);
+    fits_scan (&buf[0].header, "PC002001", "%lf", 1, &pc21);
+    fits_scan (&buf[0].header, "PC002002", "%lf", 1, &pc22);
+    PC11 = -pc11;
+    PC12 = pc12;
+    PC21 = -pc21;
+    PC22 = pc22;
+    fits_modify (&buf[0].header, "PC001001", "%le", 1, PC11);
+    fits_modify (&buf[0].header, "PC001002", "%le", 1, PC12);
+    fits_modify (&buf[0].header, "PC002001", "%le", 1, PC21);
+    fits_modify (&buf[0].header, "PC002002", "%le", 1, PC22);
+
+    free (in_buff);
+    return (TRUE);
+  }
+
+  angle = atof (argv[2]);
+  CosAngle = cos (angle*RAD_DEG);
+  SinAngle = sin (angle*RAD_DEG);
+  
+  fprintf (stderr, "rotating: %f %f %f\n", angle, CosAngle, SinAngle);
+
+  Lx = NX*fabs(CosAngle) + NY*fabs(SinAngle);
+  Ly = NX*fabs(SinAngle) + NY*fabs(CosAngle);
+  dX = MAX(0,NY*SinAngle);
+  dY = MAX(0,-NX*SinAngle);
+  /*
+  fprintf (stderr, "%f %f  -->  ", Xo, Yo);
+  X1 = Xo*CosAngle - Yo*SinAngle + dX;
+  Y1 =  Xo*SinAngle + Yo*CosAngle + dY;
+  fprintf (stderr, "%f %f\n", X1, Y1);
+  */
+
+  /* fix reference pixel */
+  fits_scan (&buf[0].header, "CRPIX1", "%lf", 1, &Xo);
+  fits_scan (&buf[0].header, "CRPIX2", "%lf", 1, &Yo);
+  /*
+  X1 = (Xo - dX)*CosAngle - (Yo - dY)*SinAngle;
+  Y1 = (dX - Xo)*SinAngle + (Yo - dY)*CosAngle;
+  */
+  X1 = Xo*CosAngle - Yo*SinAngle + dX;
+  Y1 =  Xo*SinAngle + Yo*CosAngle + dY;
+  fits_modify (&buf[0].header, "CRPIX1", "%lf", 1, X1);
+  fits_modify (&buf[0].header, "CRPIX2", "%lf", 1, Y1);
+
+  /* fix rotate matrix */
+  fits_scan (&buf[0].header, "PC001001", "%lf", 1, &pc11);
+  fits_scan (&buf[0].header, "PC001002", "%lf", 1, &pc12);
+  fits_scan (&buf[0].header, "PC002001", "%lf", 1, &pc21);
+  fits_scan (&buf[0].header, "PC002002", "%lf", 1, &pc22);
+  PC11 = pc11*CosAngle - pc21*SinAngle;
+  PC12 = pc12*CosAngle - pc22*SinAngle;
+  PC21 = pc21*CosAngle + pc11*SinAngle;
+  PC22 = pc22*CosAngle + pc12*SinAngle;
+  fits_modify (&buf[0].header, "PC001001", "%le", 1, PC11);
+  fits_modify (&buf[0].header, "PC001002", "%le", 1, PC12);
+  fits_modify (&buf[0].header, "PC002001", "%le", 1, PC21);
+  fits_modify (&buf[0].header, "PC002002", "%le", 1, PC22);
+
+  buf[0].header.Naxis[0] = Lx;
+  buf[0].header.Naxis[1] = Ly;
+  fits_modify (&buf[0].header, "NAXIS1", "%d", 1, Lx);
+  fits_modify (&buf[0].header, "NAXIS2", "%d", 1, Ly);
+  fits_create_matrix (&buf[0].header, &buf[0].matrix);
+  fits_print  (&buf[0].header, "HISTORY", "%S", 1, "WARNING: rotated image!");
+  out_buff = (float *)buf[0].matrix.buffer;
+  for (j = 0; j < Ly; j++) {
+    for (i = 0; i < Lx; i++, out_buff++) {
+
+      x = (i - dX)*CosAngle + (j - dY)*SinAngle;
+      y = (dX - i)*SinAngle + (j - dY)*CosAngle;
+      X = (int) x;
+      Y = (int) y;
+
+      if (X < 0) continue;
+      if (X >= NX - 1) continue;
+      if (Y < 0) continue;
+      if (Y >= NY - 1) continue;
+
+      c = &in_buff[X * NX*Y];
+      fx = x - X;
+      fy = y - Y;
+      *out_buff = (c[0]*(1-fx) + c[1]*fx)*(1-fy) + (c[NX+1]*fx + c[NX]*(1-fx))*fy;
+    }
+  }
+  free (in_buff);
+  return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/save.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/save.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/save.c	(revision 3338)
@@ -0,0 +1,44 @@
+# include "data.h"
+
+int save (int argc, char **argv) {
+  
+  int N, n, ISCEL;
+  char buffer[512], buffer2[512];
+  int Ximage, Nimage;
+  
+  Nimage = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nimage = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetImage (&Ximage, &Nimage)) return (FALSE);
+
+  ISCEL = FALSE;
+  if ((N = get_argument (argc, argv, "-c"))) {
+    remove_argument (N, &argc, argv);
+    ISCEL = TRUE;
+  }
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: save (overlay) <filename> [-c]\n");
+    fprintf (stderr, "  -c: write contour in celestial coords\n");
+    return (FALSE);
+  }
+
+  if (!SelectOverlay (argv[1], &n)) 
+    return (FALSE);
+
+  sprintf (buffer, "FILE: %d %s", n, argv[2]);
+  sprintf (buffer2, "NBYTES: %8d", strlen(buffer));
+  
+  if (ISCEL) 
+    write (Ximage, "CSVE", 4); /* force Ximage to look for the incoming image */
+  else 
+    write (Ximage, "SAVE", 4); /* force Ximage to look for the incoming image */
+  write (Ximage, buffer2, 16);
+  write (Ximage, buffer, strlen(buffer));
+  
+  return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/section.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/section.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/section.c	(revision 3338)
@@ -0,0 +1,67 @@
+# include "data.h"
+
+int section (int argc, char **argv) {
+  
+  int N, List;
+  char buffer[65], buffer2[65];
+  Graphdata graphmode;
+  int Ngraph, Xgraph;
+
+  List = FALSE;
+  if ((N = get_argument (argc, argv, "-list"))) {
+    remove_argument (N, &argc, argv);
+    List = TRUE;
+  }
+
+  Ngraph = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Ngraph = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetGraph (&graphmode, &Xgraph, &Ngraph)) return (FALSE);
+
+  if (argc == 1) {
+    /* list section */
+    write (Xgraph, "LSEC", 4);
+    sprintf (buffer, "* %s", argv[1]);
+    sprintf (buffer2, "NBYTES: %6d ", strlen (buffer));
+    write (Xgraph, buffer2, 16);
+    write (Xgraph, buffer, strlen (buffer));
+    fprintf (stderr, "USAGE: section name [x y dx dy]\n");
+    return (TRUE);
+  } 
+  
+  if (argc == 2) {
+    /* set section */
+    if (List) {
+      write (Xgraph, "LSEC", 4);
+    } else {
+      write (Xgraph, "SSEC", 4);
+    }
+    sprintf (buffer, "%s", argv[1]);
+    sprintf (buffer2, "NBYTES: %6d ", strlen (buffer));
+    write (Xgraph, buffer2, 16);
+    write (Xgraph, buffer, strlen (buffer));
+    return (TRUE);
+  } 
+  
+  if (argc == 6) {
+    /* define section */
+    write (Xgraph, "DSEC", 4);
+    snprintf (buffer, 65, "%s %6.3f %6.3f %6.3f %6.3f", argv[1], atof (argv[2]), atof (argv[3]), atof (argv[4]), atof (argv[5]));
+    snprintf (buffer2, 65, "NBYTES: %6d ", strlen (buffer));
+    write (Xgraph, buffer2, 16);
+    write (Xgraph, buffer, strlen (buffer));
+    return (TRUE);
+  }
+      
+  fprintf (stderr, "USAGE: section name [x y dx dy]\n");
+  return (FALSE);
+  
+}
+
+    /* should do some range checking on x y dx dy
+       should be between 0.0 and 1.0, precision of 0.001
+       is sufficient
+    */
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/select.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/select.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/select.c	(revision 3338)
@@ -0,0 +1,44 @@
+# include "data.h"
+
+int vect_select (int argc, char **argv) {
+  
+  int  i, size;
+  char *out;
+  Vector *in1, *in2, *tvec, *ovec;
+
+  out = NULL;
+  in1 = in2 = ovec = tvec = NULL;
+
+  /** check basic syntax **/
+  if ((argc != 8) || strcmp(argv[2], "=") || strcmp (argv[4], "if") || strcmp (argv[6], "else")) {
+    fprintf (stderr, "SYNTAX: select vec = vec if (logic expression) else vec\n");
+    return (FALSE);
+  }
+  if ((in1  = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((in2  = SelectVector (argv[7], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((ovec = SelectVector (argv[1], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  out = dvomath (argc - 5, &argv[5], &size, 1);
+  if (out == NULL) {
+    print_error ();
+    goto error;
+  }
+  if ((tvec = SelectVector (out, OLDVECTOR, TRUE)) == NULL) goto error;
+  /* check size of in1, in2, tvec: must match */
+
+  REALLOCATE (ovec[0].elements, float, MAX (tvec[0].Nelements, 1));
+  for (i = 0; i < tvec[0].Nelements; i++) {
+    ovec[0].elements[i] = tvec[0].elements[i] ? in1[0].elements[i] : in2[0].elements[i];
+  }
+  ovec[0].Nelements = tvec[0].Nelements;
+  REALLOCATE (ovec[0].elements, float, MAX (ovec[0].Nelements, 1));
+  
+  DeleteVector (tvec);
+  return (TRUE);
+
+ error:
+  DeleteVector (tvec);
+  DeleteVector (ovec);
+  DeleteNamedVector (out);
+  return (FALSE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/set.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/set.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/set.c	(revision 3338)
@@ -0,0 +1,42 @@
+# include "data.h"
+
+int set (int argc, char **argv) {
+  
+  int size;
+  char *out;
+
+  /** check basic form for line **/
+  if ((argc < 3) || strcmp(argv[2], "=")) {
+    fprintf (stderr, "%s = (matrix expression)\n", argv[0]);
+    return (FALSE);
+  }
+
+  out = dvomath (argc - 3, &argv[3], &size, -1);
+  if (out == NULL) {
+    print_error ();
+    return (FALSE);
+  }
+  
+  switch (size) {
+    case 0:
+      set_str_variable (argv[1], out);
+      break;
+
+    case 1:
+      if (!MoveNamedVector (argv[1], out)) {
+	DeleteNamedVector (out);
+	fprintf (stderr, "invalid output vector name\n");
+	return (FALSE);
+      }
+      break;
+  
+    case 2:
+      if (!MoveNamedBuffer (argv[1], out)) {
+	DeleteNamedBuffer (out);
+	fprintf (stderr, "invalid output matrix name\n");
+	return (FALSE);
+      }
+      break;
+  }
+  return (TRUE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/shift.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/shift.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/shift.c	(revision 3338)
@@ -0,0 +1,121 @@
+# include "data.h"
+
+int shift (int argc, char **argv) {
+ 
+  int i, j, N, ROLL;
+  int nx, ny, dx, dy, DXin, DXot, DYin, DYot;
+  float *Vin, *Vot;
+  double Dx, Dy, fdx, fdy;
+  Buffer *buf;
+
+  ROLL = FALSE;
+  if ((N = get_argument (argc, argv, "-roll"))) {
+    remove_argument (N, &argc, argv);
+    ROLL = TRUE;
+  }
+
+  if (argc != 4) {
+    fprintf (stderr, "USAGE: shift <buffer> dx dy\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  Dx = -atof (argv[2]);
+  Dy = -atof (argv[3]);
+
+  dx = Dx;
+  dy = Dy;
+  fdx = Dx - dx;
+  fdy = Dy - dy;
+  if (fdx < -0.001) {dx -= 1; fdx += 1;}
+  if (fdy < -0.001) {dy -= 1; fdy += 1;}
+
+  nx = buf[0].matrix.Naxis[0];
+  ny = buf[0].matrix.Naxis[1];
+
+  if ((dx > buf[0].matrix.Naxis[0]) || (dy > buf[0].matrix.Naxis[1])) {
+    fprintf (stderr, "shifting data out of image\n");
+    return (FALSE);
+  }
+  
+  if (dx < 0) {
+    DXin = 0;
+    DXot = -dx;
+  } else {
+    DXin = dx;
+    DXot = 0;
+  }
+  if (dy < 0) {
+    DYin = 0;
+    DYot = -dy;
+  } else {
+    DYin = dy;
+    DYot = 0;
+  }
+  
+  if ((dy > 0) || ((dy == 0) && (dx > 0))) {
+    for (j = 0; j < ny - fabs(dy); j++) {
+      Vin = (float *)(buf[0].matrix.buffer) + (j + DYin)*nx + DXin;  
+      Vot = (float *)(buf[0].matrix.buffer) + (j + DYot)*nx + DXot; 
+      for (i = 0; i < nx - fabs(dx); i++, Vin++, Vot++) {
+	*Vot = *Vin;
+      }
+      if (dx < 0) 
+	Vot = (float *)(buf[0].matrix.buffer) + (j + DYot)*nx; 
+      for (i = 0; i < fabs(dx); i++, Vot++) {
+	*Vot = 0.0;
+      }	
+    }
+    Vot = (float *)(buf[0].matrix.buffer) + nx*(ny - abs(dy));
+    for (j = 0; j < nx * fabs(dy); j++, Vot++) {
+      *Vot = 0.0;
+    }   
+  } else {
+    for (j = ny - fabs(dy) - 1; j >= 0; j--) {
+      Vin = (float *)(buf[0].matrix.buffer) + (j + DYin)*nx + DXin + nx - abs(dx) - 1; 
+      Vot = (float *)(buf[0].matrix.buffer) + (j + DYot)*nx + DXot + nx - abs(dx) - 1; 
+      for (i = 0; i < nx - fabs(dx); i++, Vin--, Vot--) {
+	*Vot = *Vin;
+      }
+      if (dx < 0) 
+	Vot = (float *)(buf[0].matrix.buffer) + (j + DYot)*nx; 
+      for (i = 0; i < fabs(dx); i++, Vot++) {
+	*Vot = 0.0;
+      }	
+    }
+    Vot = (float *)(buf[0].matrix.buffer);
+    for (j = 0; j < nx * fabs(dy); j++, Vot++) {
+      *Vot = 0.0;
+    }
+  } 
+
+  fprintf (stderr, "%f %f\n", fdx, fdy);
+  if ((fdx > 0) || (fdy > 0)) {
+    double f00, f01, f10, f11;
+    float value;
+
+    f00 = (1-fdx)*(1-fdy);
+    f01 =    fdx *(1-fdy);
+    f10 = (1-fdx)*   fdy;
+    f11 =    fdx *   fdy;
+
+    Vin = (float *)buf[0].matrix.buffer;
+    Vot = (float *)buf[0].matrix.buffer;
+    for (j = 0; j < ny - 1; j++) {
+      for (i = 0; i < nx - 1; i++, Vin++, Vot++) {
+	value  = Vin[   0] * f00;
+	value += Vin[   1] * f01;
+	value += Vin[ny  ] * f10;
+	value += Vin[ny+1] * f11;
+	*Vot = value;
+      }
+      Vin ++;
+      Vot ++;
+    }
+  }   
+
+  return (TRUE);
+
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/sort.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/sort.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/sort.c	(revision 3338)
@@ -0,0 +1,62 @@
+# include "data.h"
+
+int sort_vectors (int argc, char **argv) {
+  
+  int i, j, Nvec, Nval;
+  float *temp, *index, *T, *V, *I;
+  Vector **vec;
+
+  if (argc < 2) {
+    fprintf (stderr, "USAGE: sort (vector) [vectors ...] \n");
+    fprintf (stderr, "  first vector is sort key for others\n");
+    return (FALSE);
+  }
+
+  Nvec = (argc - 1);
+  ALLOCATE (vec, Vector *, Nvec);
+
+  /* find vectors and check sizes */
+  for (i = 0; i < Nvec; i++) {
+    if ((vec[i] = SelectVector (argv[i + 1], OLDVECTOR, FALSE)) == NULL) {
+      fprintf (stderr, "USAGE: sort vector vector ...\n");
+      free (vec);
+      return (FALSE);    
+    }
+    if (i == 0) {
+      Nval = vec[i][0].Nelements;
+    } else {
+      if (Nval != vec[i][0].Nelements) {
+	free (vec);
+	fprintf (stderr, "vectors must all be same length\n");
+	return (FALSE);
+      }
+    }
+  }
+  
+  /* create index (use float to use sortpair) */
+  ALLOCATE (index, float, Nval);
+  for (i = 0; i < Nval; i++) index[i] = i;
+
+  /* sort key & index */
+  fsortpair (vec[0][0].elements, index, Nval);
+
+  ALLOCATE (temp, float, Nval);
+  for (i = 1; i < Nvec; i++) {
+    T = temp;
+    V = vec[i][0].elements;
+    I = index;
+    for (j = 0; j < Nval; j++, T++, I++) {
+      *T = V[(int)(*I)];
+    }
+    /* swap .elements (== V) and temp */ 
+    vec[i][0].elements = temp;
+    temp = V;
+  }
+  free (temp);
+  free (vec);
+
+  return (TRUE);
+
+}
+
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/spline_apply.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/spline_apply.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/spline_apply.c	(revision 3338)
@@ -0,0 +1,100 @@
+# include "data.h"
+
+void spline (float *x, float *y, int N, float *y2);
+float splint (float *x, float *y, float *y2, int N, float X);
+
+int spline_apply (int argc, char **argv) {
+  
+  int i, j, I, J;
+  int nx, ny, Nx, Ny, xdir;
+  float rx, ry, x, y;
+  float *Tx1, *Tx2, *Txc, *Ty1, *Ty2, *Tyc, *V, *V1, *V2;
+  Buffer *out, *y1, *y2;
+
+  if (argc != 7) {
+    fprintf (stderr, "USAGE: spline_apply <Y> <Y2> <out> (x/y) Nx Ny\n");
+    return (FALSE);
+  }
+
+  if ((y1  = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((y2  = SelectBuffer (argv[2], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((out = SelectBuffer (argv[3], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+
+  xdir = FALSE;
+  if (!strcmp (argv[4], "x")) xdir = TRUE; 
+
+  nx = atoi (argv[5]);
+  ny = atoi (argv[6]);
+
+  Nx = y1[0].matrix.Naxis[0];
+  Ny = y1[0].matrix.Naxis[1];
+
+  rx = Nx / (float) nx;
+  ry = Ny / (float) ny;
+
+  /* create an output matrix buffer with desired nx, ny */
+  fits_free_matrix (&out[0].matrix);
+  fits_free_header (&out[0].header);
+
+  out[0].bitpix = y1[0].bitpix;
+  out[0].unsign = y1[0].unsign;
+  out[0].bscale = y1[0].bscale;
+  out[0].bzero  = y1[0].bzero;
+  fits_copy_header (&y1[0].header, &out[0].header);
+  fits_modify (&out[0].header, "NAXIS1", "%d", 1, nx);
+  fits_modify (&out[0].header, "NAXIS2", "%d", 1, ny);
+
+  out[0].header.Naxis[0] = nx;
+  out[0].header.Naxis[1] = ny;
+  fits_create_matrix (&out[0].header, &out[0].matrix);
+  if ((y1[0].file[0] != '*') && (y1[0].file[0] != '(')) {
+    sprintf (out[0].file, "*%s", y1[0].file);
+  } else {
+    sprintf (out[0].file, "%s", y1[0].file);
+  }
+
+  ALLOCATE (Ty2, float, Ny);
+  ALLOCATE (Ty1, float, Ny);
+  ALLOCATE (Tyc, float, Ny);
+  for (i = 0; i < Ny; i++) { Tyc[i] = i; }
+
+  ALLOCATE (Tx1, float, Nx);
+  ALLOCATE (Tx2, float, Nx);
+  ALLOCATE (Txc, float, Nx);
+  for (i = 0; i < Nx; i++) { Txc[i] = i; }
+
+  V = (float *)(out[0].matrix.buffer);
+
+  for (J = 0; J < ny; J++) {
+    y = J * ry;
+
+    /* construct spline for each element in this row */
+    for (i = 0; i < Nx; i++) {
+      V1 = (float *)(y1[0].matrix.buffer) + i;
+      V2 = (float *)(y2[0].matrix.buffer) + i;
+      for (j = 0; j < Ny; j++, V1+=Nx, V2+=Nx) {
+	Ty1[j] = *V1;
+	Ty2[j] = *V2;
+      }
+      Tx1[i] = splint (Tyc, Ty1, Ty2, Ny, y);
+    }
+    spline (Txc, Tx1, Nx, Tx2);
+
+    /* apply x-dir spline to new image */
+    for (I = 0; I < nx; I++, V++) {
+      x = I * rx;
+      *V = splint (Txc, Tx1, Tx2, Nx, x);
+    }
+  }
+
+  free (Ty1);
+  free (Ty2);
+  free (Tyc);
+  
+  free (Tx1);
+  free (Tx2);
+  free (Txc);
+  
+  return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/spline_construct.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/spline_construct.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/spline_construct.c	(revision 3338)
@@ -0,0 +1,71 @@
+# include "data.h"
+
+int spline_construct (int argc, char **argv) {
+  
+  int i, j, Nx, Ny, xdir;
+  float *Tx, *Ty, *Ty2, *V;
+  Buffer *in, *out;
+
+  if (argc != 4) {
+    fprintf (stderr, "USAGE: spline_construct <in> <out> (x/y)\n");
+    return (FALSE);
+  }
+
+  if ((in  = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((out = SelectBuffer (argv[2], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+
+  free (out[0].matrix.buffer);
+  free (out[0].header.buffer);
+  if ((in[0].file[0] != '*') && (in[0].file[0] != '(')) {
+    sprintf (out[0].file, "*%s", in[0].file);
+  } else {
+    sprintf (out[0].file, "%s", in[0].file);
+  }
+  out[0].bitpix = in[0].bitpix;
+  out[0].unsign = in[0].unsign;
+  out[0].bscale = in[0].bscale;
+  out[0].bzero  = in[0].bzero;
+  fits_copy_matrix_info (&in[0].matrix, &out[0].matrix);
+  fits_copy_header (&in[0].header, &out[0].header);
+  fits_create_matrix (&out[0].header, &out[0].matrix);
+
+  xdir = FALSE;
+  if (!strcmp (argv[3], "x")) xdir = TRUE; 
+  /* ideally, the resulting image should carry this info (in header?) */
+
+  Nx = in[0].matrix.Naxis[0];
+  Ny = in[0].matrix.Naxis[1];
+
+  ALLOCATE (Ty2, float, Ny);
+  ALLOCATE (Ty, float, Ny);
+  ALLOCATE (Tx, float, Ny);
+
+  /** for now only perform the operation for the ydir splines */
+
+  /* construct coordinate vector */
+  for (j = 0; j < Ny; j++) { Tx[j] = j; }
+  
+  for (i = 0; i < Nx; i++) {
+    
+    /* construct temp vector with values to spline */
+    V = (float *)(in[0].matrix.buffer) + i;
+    for (j = 0; j < Ny; j++, V+=Nx) {
+      Ty[j] = *V;
+    }
+  
+    spline (Tx, Ty, Ny, Ty2);
+  
+    /* copy derivatives to output buffer */
+    V = (float *)(out[0].matrix.buffer) + i;
+    for (j = 0; j < Ny; j++, V+=Nx) {
+      *V = Ty2[j];
+    }
+  }
+
+  free (Tx);
+  free (Ty);
+  free (Ty2);
+  
+  return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/stats.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/stats.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/stats.c	(revision 3338)
@@ -0,0 +1,111 @@
+# include "data.h"
+
+int stats (int argc, char **argv) {
+  
+  int i, j, Nmode, Imode;
+  double Npix, N1, N2, max, min, range, median, mode, IgnoreValue;
+  float *V;
+  int sx, sy, nx, ny, *hist, Nhist, bin;
+  int Ignore, Quiet, N;
+  Buffer *buf;
+
+  Ignore = FALSE;
+  if ((N = get_argument (argc, argv, "-ignore"))) {
+    Ignore = TRUE;
+    remove_argument (N, &argc, argv);
+    IgnoreValue = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  Quiet = FALSE;
+  if ((N = get_argument (argc, argv, "-q"))) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-quiet"))) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 6) {
+    fprintf (stderr, "USAGE: stats <buffer> sx sy nx ny\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  sx = strcmp (argv[2], "-") ? atof (argv[2]) : 0;
+  sy = strcmp (argv[3], "-") ? atof (argv[3]) : 0;
+  nx = strcmp (argv[4], "-") ? atof (argv[4]) : buf[0].matrix.Naxis[0];
+  ny = strcmp (argv[5], "-") ? atof (argv[5]) : buf[0].matrix.Naxis[1];
+
+  Npix = N1 = N2 = 0;
+  if ((sx < 0) || (sy < 0) || 
+      (sx+nx > buf[0].matrix.Naxis[0]) || 
+      (sy+ny > buf[0].matrix.Naxis[1])) {
+    fprintf (stderr, "region out of range\n");
+    return (FALSE);
+  }
+
+  max = min = *((float *)(buf[0].matrix.buffer) + sy*buf[0].matrix.Naxis[0] + sx);
+  for (j = sy; j < sy + ny; j++) {
+    V = (float *)(buf[0].matrix.buffer) + j*buf[0].matrix.Naxis[0] + sx; 
+    for (i = 0; i < nx; i++, V++) {
+      if (Ignore && (fabs (*V - IgnoreValue) < 1e-8)) continue;
+      N1 += *V;
+      N2 += (*V)*(*V);
+      Npix += 1.0;
+      max = MAX (max, *V);
+      min = MIN (min, *V);
+    }
+  }
+  N1 = N1 / Npix;
+
+  /* calculate mode, median */
+  median = mode = 0.5*(max + min);
+  if (range != 0) {
+    range = 0xffff / (max - min);
+    ALLOCATE (hist, int, 0x10000);
+    bzero (hist, 0x10000*sizeof(int));
+    for (j = sy; j < sy + ny; j++) {
+      V = (float *)(buf[0].matrix.buffer) + j*buf[0].matrix.Naxis[0] + sx; 
+      for (i = 0; i < nx; i++, V++) {
+	if (Ignore && (fabs (*V - IgnoreValue) < 1e-8)) continue;
+	bin = MIN (MAX (0, (*V - min) * range), 0xffff);
+	hist[bin] ++;
+      }
+    }
+    Nhist = 0;
+    for (i = 0; (i < 0xffff) && (Nhist < 0.5*Npix); i++) 
+      Nhist += hist[i];
+    median = i / range + min;
+    Nmode = hist[0];
+    Imode = 0;
+    for (i = 1; i < 0x10000; i++) {
+      if (hist[i] > Nmode) {
+	Nmode = hist[i];
+	Imode = i;
+      }
+    }
+    mode = Imode / range + min;
+    free (hist);
+  }  
+  
+  if (!Quiet) {
+    fprintf (GetOutfile(), "  mean    stdev    min     max   median   Npix   Total\n");
+    fprintf (GetOutfile(), "%7.4g %7.4g %7.4g %7.4g %7.4g %7.0f %7.4g\n", N1, sqrt (N2/Npix - N1*N1), 
+	     min, max, median, Npix, Npix*N1);
+  }
+
+  set_variable ("MIN",    min);
+  set_variable ("MAX",    max);
+  set_variable ("MEDIAN", median);
+  set_variable ("MEAN",   N1);
+  set_variable ("MODE",   mode);
+  set_variable ("TOTAL",  N1*Npix);
+  set_variable ("NPIX",   Npix);
+  set_variable ("SIGMA",  sqrt (N2/Npix - N1*N1));
+
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/style.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/style.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/style.c	(revision 3338)
@@ -0,0 +1,83 @@
+# include "data.h"
+# define NCOLORS 9
+static char colors[9][10] = {"black", "white", "red", "orange", "yellow", "green", "blue", "indigo", "violet"};
+
+int style (int argc, char **argv) {
+  
+  int N, Ngraph;
+  Graphdata graphmode;
+
+  Ngraph = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Ngraph = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetGraph (&graphmode, NULL, &Ngraph)) return (FALSE);
+
+  if (argc == 1) {
+    fprintf (stderr, "current style (%d): -x %d -c %s -pt %d -lt %d -lw %f -sz %f\n", Ngraph,
+	     graphmode.style, colors[graphmode.color], graphmode.ptype, 
+	     graphmode.ltype, graphmode.lweight,
+	     graphmode.size);
+    return (TRUE);
+  }
+
+  if ((N = get_argument (argc, argv, "-lt"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.ltype = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if ((N = get_argument (argc, argv, "-lw"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.lweight = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if ((N = get_argument (argc, argv, "-pt"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.ptype = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if ((N = get_argument (argc, argv, "+eb"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.ebar = TRUE;
+  }
+
+  if ((N = get_argument (argc, argv, "-eb"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.ebar = FALSE;
+  }
+
+  if ((N = get_argument (argc, argv, "-sz"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.size = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if ((N = get_argument (argc, argv, "-c"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.color = GetColor (argv[N]);
+    if (graphmode.color == -1) return (FALSE);
+    remove_argument (N, &argc, argv);
+  }
+
+  if ((N = get_argument (argc, argv, "-x"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.style = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  SetGraph (graphmode);
+
+  if (argc > 1) {
+    fprintf (stderr, "USAGE: style [-n Ngraph] [-x plot style] [-c color] [-pt point type] [-lt line type] [-lw line width] [-sz size]\n");
+    return (FALSE);
+  }
+
+  return (TRUE);
+
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/subraster.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/subraster.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/subraster.c	(revision 3338)
@@ -0,0 +1,86 @@
+# include "data.h"
+
+int subraster (int argc, char **argv) {
+  
+  int i, j;
+  float *Vin, *Vout;
+  int sx, sy, nx, ny;
+  int Sx, Sy, Nx, Ny;
+  int NX, NY;
+  Buffer *ibuf, *obuf;
+
+  if (argc != 11) {
+    fprintf (stderr, "USAGE: extract <from> <to> sx sy nx ny Sx Sy Nx Ny\n");
+    return (FALSE);
+  }
+
+  if ((ibuf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  NX = ibuf[0].matrix.Naxis[0];
+  NY = ibuf[0].matrix.Naxis[1];
+
+  sx = atof (argv[3]);
+  sy = atof (argv[4]);
+  nx = atof (argv[5]);
+  ny = atof (argv[6]);
+
+  Sx = atof (argv[7]);
+  Sy = atof (argv[8]);
+  Nx = atof (argv[9]);
+  Ny = atof (argv[10]);
+
+  if ((Sy + ny > Ny) || (Sx + nx > Nx)) {
+    fprintf (stderr, "mismatch between source and dest regions\n");
+    fprintf (stderr, "%d + %d > %d or %d + %d > %d\n", Sy, ny, Ny, Sx, nx, Nx);
+    return (FALSE);
+  }
+
+  /* region is not on first image */
+  if ((sx + nx < 0) || (sy + ny < 0) || 
+      (sx > ibuf[0].matrix.Naxis[0]) || 
+      (sy > ibuf[0].matrix.Naxis[1])) {
+    fprintf (stderr, "region outside of source image\n");
+    return (FALSE);
+  }
+
+  if ((Sx + nx > Nx) || (Sy + ny > Ny)) {
+    fprintf (stderr, "source region larger than dest region\n");
+    return (FALSE);
+  }
+  if ((Sx < 0) || (Sy < 0)) {
+    fprintf (stderr, "dest region out of range\n");
+    return (FALSE);
+  }
+
+  if ((obuf = SelectBuffer (argv[2], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+  fits_free_matrix (&obuf[0].matrix);
+  fits_free_header (&obuf[0].header);
+
+  obuf[0].bitpix = ibuf[0].bitpix;
+  obuf[0].unsign = ibuf[0].unsign;
+  obuf[0].bscale = ibuf[0].bscale;
+  obuf[0].bzero  = ibuf[0].bzero;
+  /* strcpy (obuf[0].name, ibuf[0].name); */
+  strcpy (obuf[0].file, ibuf[0].file);
+  fits_copy_header (&ibuf[0].header, &obuf[0].header);
+  fits_modify (&obuf[0].header, "NAXIS1", "%d", 1, Nx);
+  fits_modify (&obuf[0].header, "NAXIS2", "%d", 1, Ny);
+  obuf[0].header.Naxis[0] = Nx;
+  obuf[0].header.Naxis[1] = Ny;
+  fits_create_matrix (&obuf[0].header, &obuf[0].matrix);
+
+  for (j = 0; j < ny; j++) {
+    if (j + sy < 0) continue;
+    if (j + sy >= NY) continue;
+    Vin = (float *)(ibuf[0].matrix.buffer) + (j + sy)*ibuf[0].matrix.Naxis[0] + sx;  
+    Vout = (float *)(obuf[0].matrix.buffer) + (j + Sy)*obuf[0].matrix.Naxis[0] + Sx;   
+    for (i = 0; i < nx; i++, Vin++, Vout++) {
+      if (i + sx < 0) continue;
+      if (i + sx >= NX) continue;
+      *Vout = *Vin;
+    }
+  }
+
+  return (TRUE);
+
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/subset.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/subset.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/subset.c	(revision 3338)
@@ -0,0 +1,47 @@
+# include "data.h"
+
+int subset (int argc, char **argv) {
+  
+  char *out;
+  int  i, j, size;
+  Vector *ivec, *ovec, *tvec;
+
+  out = NULL;
+  ivec = ovec = tvec = NULL;
+
+  if ((argc < 6) || strcmp(argv[2], "=") || strcmp (argv[4], "if")) {
+    fprintf (stderr, "SYNTAX: subset vec = vec if (logic expression)\n");
+    return (FALSE);
+  }
+
+  if ((ovec = SelectVector (argv[1], ANYVECTOR, TRUE)) == NULL) goto error;
+  if ((ivec = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) goto error;
+
+  out = dvomath (argc - 5, &argv[5], &size, 1);
+  if (out == NULL) {
+    print_error ();
+    goto error;
+  }
+  if ((tvec = SelectVector (out, OLDVECTOR, TRUE)) == NULL) goto error;
+  /* check size of ivec, tvec: must match */
+
+  REALLOCATE (ovec[0].elements, float, MAX (tvec[0].Nelements, 1));
+  for (j = i = 0; i < tvec[0].Nelements; i++) {
+    if (tvec[0].elements[i]) {
+      ovec[0].elements[j] = ivec[0].elements[i];
+      j++;
+    }
+  }
+  ovec[0].Nelements = j;
+  REALLOCATE (ovec[0].elements, float, MAX (ovec[0].Nelements, 1));
+
+  DeleteVector (tvec);
+  return (TRUE);
+
+ error:
+  DeleteVector (tvec);
+  DeleteVector (ovec);
+  DeleteNamedVector (out);
+  return (FALSE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/svd.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/svd.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/svd.c	(revision 3338)
@@ -0,0 +1,71 @@
+# include "data.h"
+
+int svd (int argc, char **argv) {
+  
+  int i, Nx, Ny, status;
+  float *in, *out, *A, *U, *W, *V;
+  Vector *Vw;
+  Buffer *Ma, *Mu, *Mv;
+
+  if (argc != 6) goto usage;
+  if (strcmp (argv[2], "=")) goto usage;
+
+  if ((Ma = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((Mu = SelectBuffer (argv[3], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((Vw = SelectVector (argv[4], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((Mv = SelectBuffer (argv[5], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+
+  Nx = Ma[0].header.Naxis[0];
+  Ny = Ma[0].header.Naxis[1];
+
+  /* U is Nx, Ny */
+  fits_free_matrix (&Mu[0].matrix);
+  fits_free_header (&Mu[0].header);
+  Mu[0].bitpix = Ma[0].bitpix;
+  Mu[0].unsign = Ma[0].unsign;
+  Mu[0].bscale = Ma[0].bscale;
+  Mu[0].bzero  = Ma[0].bzero;
+  fits_copy_header (&Ma[0].header, &Mu[0].header);
+  fits_create_matrix (&Mu[0].header, &Mu[0].matrix);
+  
+  /* V is Nx, Nx */
+  fits_free_matrix (&Mv[0].matrix);
+  fits_free_header (&Mv[0].header);
+  Mv[0].bitpix = Ma[0].bitpix;
+  Mv[0].unsign = Ma[0].unsign;
+  Mv[0].bscale = Ma[0].bscale;
+  Mv[0].bzero  = Ma[0].bzero;
+  fits_copy_header (&Ma[0].header, &Mv[0].header);
+  fits_modify (&Mv[0].header, "NAXIS2", "%d", 1, Nx);
+  Mv[0].header.Naxis[1] = Nx;
+  fits_create_matrix (&Mv[0].header, &Mv[0].matrix);
+
+  /* w is Nx */
+  Vw[0].Nelements = Nx;
+  REALLOCATE (Vw[0].elements, float, Nx);
+
+  /* pointers to the various arrays */
+  A = (float *) Ma[0].matrix.buffer;
+  U = (float *) Mu[0].matrix.buffer;
+  W = (float *) Vw[0].elements;
+  V = (float *) Mv[0].matrix.buffer;
+
+  /* copy A to U (svdcmp replaces A with U) */
+  in  = A;
+  out = U;
+  for (i = 0; i < Nx*Ny; i++, in++, out++) *out = *in;
+  /* use a bcopy instead? */
+
+  status = svdcmp (U, W, V, Nx, Ny);
+  if (!status) {
+    fprintf (stderr, "error running svdcmp\n");
+    return (FALSE);
+  }
+  return (TRUE);
+
+ usage:
+  fprintf (stderr, "USAGE: svd A = U w Vt\n");
+  return (FALSE);
+  
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/swapbytes.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/swapbytes.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/swapbytes.c	(revision 3338)
@@ -0,0 +1,29 @@
+# include "data.h"
+
+int swapbytes (int argc, char **argv) {
+  
+  int i, nx, ny;
+  char *V, tmp;
+  Buffer *buf;
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: swapbytes <buffer>\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  nx = buf[0].matrix.Naxis[0];
+  ny = buf[0].matrix.Naxis[1];
+
+  fprintf (stderr, "npix: %d\n", nx*ny);
+
+  V = buf[0].matrix.buffer;
+  for (i = 0; i < nx*ny; i++, V+=4) {
+    tmp = V[0]; V[0] = V[3]; V[3] = tmp;
+    tmp = V[1]; V[1] = V[2]; V[2] = tmp;
+  }
+
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/teststats.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/teststats.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/teststats.c	(revision 3338)
@@ -0,0 +1,117 @@
+# include "data.h"
+
+int teststats (int argc, char **argv) {
+  
+  int i, N;
+  double max, min, sum, var, dvar, mean, stdev;
+  float *X, IgnoreValue;
+  int Ignore, Quiet;
+
+  int *Nval, bin, Nmode, Nmed;
+  double dx, mode, median;
+  Vector *vec;
+
+  Ignore = FALSE;
+  if (N = get_argument (argc, argv, "-ignore")) {
+    Ignore = TRUE;
+    remove_argument (N, &argc, argv);
+    IgnoreValue = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  Quiet = FALSE;
+  if (N = get_argument (argc, argv, "-q")) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  if (N = get_argument (argc, argv, "-quiet")) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: teststats (vector)\n");
+    return (FALSE);
+  }
+
+  if ((vec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+
+  Mean = Stdev = 0; 
+  /* first pass: measure the sample statistics */
+  for (j = 0; j < 3; j++) {
+    /* calculate mean, npix */
+    X = vec[0].elements;
+    max = min = *X;
+    sum = N = 0;
+    for (i = 0; i < vec[0].Nelements; i++, X++) {
+      if (!finite (*X)) continue;
+      if (Ignore && (*X == IgnoreValue)) continue;
+      if ((j > 0) && (fabs (*X - Mean) > 3*stdev)) continue;
+      sum += *X;
+      N++;
+    }      
+    mean = sum / N;
+    /* calculate stdev */
+    X = vec[0].elements;
+    var = 0;
+    for (i = 0; i < vec[0].Nelements; i++, X++) {
+      if (!finite (*X)) continue;
+      if (Ignore && (*X == IgnoreValue)) continue;
+      if ((j > 0) && (fabs (*X - mean) > 3*stdev)) continue;
+      dvar = (*X - mean);
+      var += dvar*dvar;
+    }      
+    stdev = sqrt (var / N);
+    Mean = mean;
+  }
+  mean = Mean;
+  set_variable ("MEAN_C",     mean);
+  set_variable ("SIGMA_C",    stdev);
+
+  /* construct histogram with resolution of 0.1*stdev and range -1000*dx : 1000*dx centered on mean */
+  dx = 0.1*stdev;
+  min = mean - 1000*dx;
+  max = mean + 1000*dx;
+  NVAL = 1 + (int)((max - min) / dx);
+  ALLOCATE (Nval, int, NVAL);
+  bzero (Nval, NVAL*sizeof(int));
+  X = vec[0].elements;
+  for (i = 0; i < vec[0].Nelements; i++, X++) {
+    if (!finite (*X)) continue;
+    if (Ignore && (*X == IgnoreValue)) continue;
+    bin = MAX (0, MIN (NVAL, (*X - min) / dx));
+    Nval[bin] ++;
+  }      
+
+  /* find mode */
+  Nmode = 0;
+  mode = Nval[Nmode];
+  for (i = 0; i < NVAL; i++) {
+    if (mode < Nval[i]) {
+      Nmode = i;
+      mode = Nval[Nmode];
+    }
+  }
+  mode = Nmode * dx + min;
+
+  
+
+  if (!Quiet) {
+    fprintf (stderr, "mean: %f, stdev: %f, min: %f, max: %f, median: %f, mode: %f, Npts: %d\n", 
+	     mean, stdev, min, max, median, mode, N);
+  }
+
+  set_variable ("MIN",      min);
+  set_variable ("MAX",      max);
+  set_variable ("MEDIAN",   median);
+  set_variable ("MODE",     mode);
+  set_variable ("TOTAL",    sum);
+  set_variable ("MEAN",     mean);
+  set_variable ("SIGMA",    stdev);
+
+  set_int_variable ("NPIX", N);
+
+  free (Nval);
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/textline.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/textline.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/textline.c	(revision 3338)
@@ -0,0 +1,78 @@
+# include "data.h"
+
+int textline (int argc, char **argv) {
+
+  int N, size, FracPositions;
+  char name[64], buffer[128];
+  double x, y, angle;
+  int Ngraph, Xgraph;
+  Graphdata graphmode;
+
+  Ngraph = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Ngraph = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetGraph (&graphmode, &Xgraph, &Ngraph)) return (FALSE);
+
+  if ((N = get_argument (argc, argv, "-fn"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (name, argv[N]);
+    remove_argument (N, &argc, argv);
+    size = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    write (Xgraph, "FONT", 4);
+    sprintf (buffer, "%s", name);
+    write (Xgraph, buffer, 16);
+    sprintf (buffer, "%d", size);
+    write (Xgraph, buffer, 16);
+  } 
+
+  /* FracPositions uses coordinates of 0-1 relative to axis range */
+  FracPositions = FALSE;
+  if ((N = get_argument (argc, argv, "-frac"))) {
+    remove_argument (N, &argc, argv);
+    FracPositions = TRUE;
+  } 
+
+  angle = 0.0;
+  if ((N = get_argument (argc, argv, "-rot"))) {
+    remove_argument (N, &argc, argv);
+    angle = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  } 
+
+  if (argc != 4) {
+    fprintf (stderr, "USAGE: text x y (line) [-fn (font) size] [-rot angle]\n");
+    return (FALSE);
+  }
+
+  if (strlen (argv[3]) > 127) {
+    fprintf (stderr, "labels currently limited to 127 chars\n");
+    return (FALSE);
+  }
+
+  x = atof (argv[1]);
+  y = atof (argv[2]);
+  
+  if (FracPositions) {
+    x =  x * (graphmode.xmax - graphmode.xmin) + graphmode.xmin;
+    y =  y * (graphmode.ymax - graphmode.ymin) + graphmode.ymin;
+  }    
+
+  write (Xgraph, "PTXT", 4);
+  sprintf (buffer, "%f", x);
+  write (Xgraph, buffer, 16);
+  sprintf (buffer, "%f", y);
+  write (Xgraph, buffer, 16);
+  sprintf (buffer, "%f", angle);
+  write (Xgraph, buffer, 16);
+
+  bzero (buffer, 128);
+  strcpy (buffer, argv[3]);
+  write (Xgraph, buffer, 128);
+
+  return (TRUE);
+}
+  
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/tv.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/tv.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/tv.c	(revision 3338)
@@ -0,0 +1,199 @@
+# include "data.h"
+
+int tv (int argc, char **argv) {
+  
+  int N, j, status, Npix, Ncolors, size, ISLOG, NNcol;
+  char buffer[1024], buffer2[100];
+  double a1, a2, max, min, zero, range;
+  float *in;
+  char *out, *outbuffer, *p, *tmpstring;
+  int Ximage, Nimage;
+  Coords coords;
+  Buffer *buf;
+
+  Nimage = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nimage = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetImage (&Ximage, &Nimage)) return (FALSE);
+
+  /* shell exits on pipe close, FIX */
+  if ((N = get_argument (argc, argv, "-kill"))) {
+    close (Ximage);
+    Ximage = 0;
+    return (TRUE);
+  }
+
+  min = max = 0.0;
+  ISLOG = FALSE;
+  if ((N = get_argument (argc, argv, "-log"))) {
+    remove_argument (N, &argc, argv);
+    ISLOG = TRUE;
+  }
+
+  if ((argc != 2) && (argc != 4)) {
+    fprintf (stderr, "USAGE: tv <buffer> [zero range] [-n Nimage] [-log] [-kill]\n");
+    return (FALSE);
+  }
+
+  GetImageScale (&zero, &range);
+  if (argc == 4) {
+    zero = atof (argv[2]);
+    range = atof (argv[3]);
+    if (range == 0.0) range = 0.001;
+    SetImageScale (zero, range);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  GetCoords (&coords, &buf[0].header);
+
+  Npix = buf[0].matrix.Naxis[0]*buf[0].matrix.Naxis[1];
+  size = Npix * sizeof (char);
+  in = (float *) (buf[0].matrix.buffer);
+  ALLOCATE (outbuffer, char, Npix);
+  out = outbuffer;
+
+  status = write (Ximage, "READ", 4); /* tell Ximage to look for the incoming image */
+
+  /* convert from (float) internal rep to 1 byte chars -- depends on how many colors Kii owns*/
+  read (Ximage, buffer, 16); 
+  sscanf (buffer, "%*s %d", &Ncolors); 
+
+  /* need to invert the logic if range < 0 */
+  /* define color table, */
+  NNcol = Ncolors - 1;
+  if (ISLOG) {
+    range = MAX (2, range);
+    a1 = Ncolors / log10 (range);
+    for (j = 0; j < Npix; j++, in++, out++) {
+      *out = (char) MIN (a1 * log10 (MAX (*in - zero, 1.0)), NNcol);
+    }
+  }
+  if (!ISLOG) {
+    a1 = Ncolors / range;
+    a2 = Ncolors * zero / range;
+    for (j = 0; j < Npix; j++, in++, out++) {
+      *out = (char) MIN (MAX (a1 * *in - a2, 0), NNcol);
+    }
+  }
+  
+  /* done with the conversion, now send Ximage the converted picture */
+  sprintf (buffer, "%8d %8d 8 1 %f %f ", buf[0].matrix.Naxis[0], buf[0].matrix.Naxis[1], 0.0, 1.0);
+  sprintf (buffer2, "NBYTES: %6d ", strlen (buffer));
+  write (Ximage, buffer2, 16);
+  write (Ximage, buffer, strlen (buffer));
+  
+  sprintf (buffer, "%f %f %f %f %d ", zero, range, min, max, size);
+  sprintf (buffer2, "NBYTES: %6d ", strlen (buffer));
+  write (Ximage, buffer2, 16);
+  write (Ximage, buffer, strlen (buffer));
+
+  sprintf (buffer, "%f %f %g %g %g ", coords.crval1, coords.crpix1, coords.cdelt1, coords.pc1_1, coords.pc1_2);
+  sprintf (buffer2, "NBYTES: %6d ", strlen (buffer));
+  write (Ximage, buffer2, 16);
+  write (Ximage, buffer, strlen (buffer));
+
+  sprintf (buffer, "%f %f %g %g %g ", coords.crval2, coords.crpix2, coords.cdelt2, coords.pc2_1, coords.pc2_2);
+  sprintf (buffer2, "NBYTES: %6d ", strlen (buffer));
+  write (Ximage, buffer2, 16);
+  write (Ximage, buffer, strlen (buffer));
+
+  p = strrchr (buf[0].file, '/');
+  if (p == (char *) NULL) p = buf[0].file;
+  else p++;
+  tmpstring = strcreate (p);
+  sprintf (buffer, "%s %s %s ", coords.ctype, tmpstring, buf[0].name);
+  free (tmpstring);
+  sprintf (buffer2, "NBYTES: %6d ", strlen (buffer));
+  write (Ximage, buffer2, 16);
+  write (Ximage, buffer, strlen (buffer));
+
+  write (Ximage, outbuffer, size);
+
+  free (outbuffer);
+
+  SetImageName (argv[1]);
+  set_str_variable ("TV", argv[1]);
+  return (TRUE);
+
+}
+
+
+/* 
+projections and coordinates:
+
+IRAS:
+CTYPE1  = 'LL      '                    /TANGENT PLANE (L)                     
+CRVAL1  =         0.100000D+02          /R.A. OF MAP CENTER  *** SEE COMMENT   
+CDELT1  =        -0.133333D-01          /SEPARATION IN L (DEG)                 
+CRPIX1  =                  128          /MAPCENTER IN L                        
+CROTA1  =         0.000000E+00          /NO ROTATION            
+                                                                               
+CTYPE2  = 'MM      '                    /TANGENT PLANE (M)                     
+CRVAL2  =         0.410000D+02          /DEC. OF MAP CENTER  *** SEE COMMENT   
+CDELT2  =         0.133333D-01          /SEPARATION IN M (DEG)                 
+CRPIX2  =                  128          /MAP CENTER IN M                       
+CROTA2  =         0.000000E+00          /NO ROTATION                           
+
+HIRAS:
+CTYPE1  = 'RA---TAN          ' / PRIMARY AXIS NAME                             
+CRVAL1  =   1.000000000000E+01 / PRIMARY REFERENCE VALUE                       
+CDELT1  =  -5.555555555556E-03 / PRIMARY PIXEL SEPARATION                      
+CRPIX1  =   2.560000000000E+02 / PRIMARY REFERENCE PIXEL                       
+CUNIT1  = 'DEGREE            ' / PRIMARY AXIS UNITS                            
+
+CDELT2  =   5.555555555556E-03 / PRIMARY PIXEL SEPARATION                      
+CRPIX2  =   2.560000000000E+02 / PRIMARY REFERENCE PIXEL                       
+CRVAL2  =   4.100000000000E+01 / PRIMARY REFERENCE VALUE                       
+CTYPE2  = 'DEC--TAN          ' / PRIMARY AXIS NAME                             
+CUNIT2  = 'DEGREE            ' / PRIMARY AXIS UNITS                            
+
+PROJTYPE= 'GNOMON    '                                                         
+COORDSYS= 'EQUATORIAL     '                                                    
+
+gene (small FOV linear):
+RA_O
+RA_X 
+RA_Y 
+DEC_O
+DEC_X
+DEC_Y
+
+
+*/
+
+# ifdef NEWTVMODE  
+  {
+    double *pixvalues, slope;
+
+    ALLOCATE (pixvalues, double, Ncolors + 1);
+    range = fabs (range);
+    for (i = 0; i < Ncolors + 1; i++) {
+      if (ISLOG) {
+	pixvalues[i] = i*range / NNcol + zero;
+      }
+      if (!ISLOG) {
+	pixvalues[i] = pow (10.0, i*log10(range - 1.0) / NNcol) + zero - 1.0;
+      }      
+    } 
+    for (j = 0; j < Npix; j++, in++, out++) {
+      if (*in < pixvalues[0]) {
+	i = 0;
+      } else {
+	if (*in > pixvalues[NNcol]) {
+	  i = NNcol;
+	} else {
+	  for (i = 0; (*in < pixvalues[i]) || (*in > pixvalues[i+1]); ) {
+	    slope = 1.0 / (pixvalues[i+1] - pixvalues[i]);
+	    i = MIN (MAX (0, i + (*in - pixvalues[i]) * slope), NNcol);
+	  }
+	}	
+      }
+      /* for (i = 0; (i < Ncolors - 1) && (pixvalues[i] < *in); i++); */
+      *out = i;
+    }
+    free (pixvalues);
+  }
+# endif
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/tvcontour.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/tvcontour.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/tvcontour.c	(revision 3338)
@@ -0,0 +1,297 @@
+# include "data.h"
+# define LL { \
+ dx =  d00 / (*v01 - *v00); \
+ dy = -d00 / (*v10 - *v00); \
+ x = i - 0.5; \
+ y = j - dy - 0.5; }
+
+# define UL { \
+ tmp = d00 / (*v10 - *v00); \
+ dy = 1 - tmp; \
+ dx =  d10 / (*v11 - *v10); \
+ x = i - 0.5; \
+ y = j + tmp - 0.5; }
+      
+# define LR { \
+ tmp = d00 / (*v01 - *v00); \
+ dx = 1 - tmp; \
+ dy = d01 / (*v11 - *v01); \
+ x = i + tmp - 0.5; \
+ y = j - 0.5; }
+
+# define UR { \
+ tmp = d10 / (*v11 - *v10); \
+ dx = 1 - tmp; \
+ dy = -d11 / (*v01 - *v11); \
+ x = i + tmp - 0.5; \
+ y = j + 1 - 0.5; }
+      
+# define HZ { \
+ tmp = d00 / (*v10 - *v00); \
+ dy = d01 / (*v11 - *v01) - tmp; \
+ dx = 1; \
+ x = i - 0.5; \
+ y = j + tmp - 0.5; }
+
+# define VT { \
+ tmp = d00 / (*v01 - *v00); \
+ dx = d10 / (*v11 - *v10) - tmp; \
+ x = i + tmp - 0.5; \
+ dy = 1; \
+ y = j - 0.5; }
+
+# define DUMP { \
+sprintf (&buffer[Nline*128], "%14s %20.10f %20.10f %20.10f %20.10f ", "LINE", Npix*x, Npix*y, Npix*dx, Npix*dy); \
+Nline ++; \
+if (Nline == 512) { \
+  sprintf (line, "NLINES  %7d ", Nline); \
+  write (Ximage, line, 16); \
+  write (Ximage, buffer, Nline*128); \
+  bzero (buffer, 65536); \
+  Nline = 0; \
+} \
+continue; }
+
+# define NUMP { \
+sprintf (&buffer[Nline*128], "%14s %20.10f %20.10f %20.10f %20.10f ", "LINE", Npix*x, Npix*y, Npix*dx, Npix*dy); \
+Nline ++; \
+if (Nline == 512) { \
+  sprintf (line, "NLINES  %7d ", Nline); \
+  write (Ximage, line, 16); \
+  write (Ximage, buffer, Nline*128); \
+  bzero (buffer, 65536); \
+  Nline = 0; \
+} }
+
+int tvcontour (int argc, char **argv) {
+
+  int i, j, ii, jj, n, Npix, Nx, Ny, Nline;
+  float level, d00, d01, d10, d11, tmp;
+  float x, y, dx, dy;
+  float *v00, *v01, *v10, *v11;
+  float *Vout, *Vin, *matrix;
+  char *buffer, line[17];
+  int Ximage, Nimage, N;
+  Buffer *buf;
+  
+  Nimage = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nimage = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetImage (&Ximage, &Nimage)) return (FALSE);
+
+  if ((argc != 4) && (argc != 5)) {
+    fprintf (stderr, "USAGE: contour <buffer> (overlay) level [Npix]\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if (!SelectOverlay (argv[2], &n)) return (FALSE);
+
+  level = atof (argv[3]);
+  if (argc == 5) 
+    Npix = (int) MAX (atof (argv[4]), 1); 
+  else 
+    Npix = 1;
+  level *= Npix*Npix;
+
+  /*** make rebinned image ***/
+  Nx = buf[0].header.Naxis[0]/Npix;
+  Ny = buf[0].header.Naxis[1]/Npix;
+  if (Npix != 1) {
+    fprintf (GetOutfile(), "rebin by a factor of %d (%d,%d)\n", Npix, Nx, Ny);
+    ALLOCATE (matrix, float, Nx*Ny);
+    bzero (matrix, Nx*Ny*sizeof(float));
+	
+    for (j = 0; j < Ny; j++) {
+      for (jj = 0; jj < Npix; jj++) {
+	Vout = matrix + j*Nx;
+	Vin  = (float *)(buf[0].matrix.buffer) + (j*Npix + jj)*buf[0].header.Naxis[0];
+	for (i = 0; i < Nx; i++, Vout++) {
+	  for (ii = 0; ii < Npix; ii++, Vin++) {
+	    *Vout += *Vin;
+	  }
+	}
+      }
+    }
+  }
+  else {
+    fprintf (stderr, "using scale of 1\n");
+    matrix = (float *)(buf[0].matrix.buffer);
+  }
+
+  write (Ximage, "LOAD", 4); /* force Ximage to look for the incoming image */
+  sprintf (line, "OVERLAY %7d ", n);
+  write (Ximage, line, 16);
+  ALLOCATE (buffer, char, 65536);  /* space for 512 lines of 128 bytes */
+  bzero (buffer, 65536);
+  Nline = 0;
+
+  v00 = matrix;
+  v01 = matrix + 1;
+  v10 = matrix + Nx;
+  v11 = matrix + Nx + 1;
+  d01 = (level - *v00);
+  d11 = (level - *v10);
+  for (j = 1; j < Ny; j++) {
+    if (!(j%10)) fprintf (stderr, ".");
+    for (i = 1; i < Nx; i++, v00++, v01++, v10++, v11++) {
+
+      d00 = d01;
+      d10 = d11;
+      d01 = (level - *v01);
+      d11 = (level - *v11);
+
+      if (((d00 > 0) && (d01 > 0) && (d10 > 0) && (d11 > 0)) ||
+	  ((d00 < 0) && (d01 < 0) && (d10 < 0) && (d11 < 0)))
+	continue;
+
+      if ((d00 > 0) && (d10 <= 0)) { 
+	if ((d01 <= 0) && (d11 <= 0)) { /* \  */
+	  LL;
+	  DUMP;
+	}
+	if ((d01 > 0) && (d11 <= 0)) { /* -  */
+	  HZ;
+	  DUMP;
+	}
+	if ((d01 > 0) && (d11 > 0)) { /* /  */
+	  UL;
+	  DUMP;
+	}
+	if ((d01 <= 0) && (d11 > 0)) { /* \\  */
+	  LL;
+	  NUMP;
+	  UR;
+	  DUMP;
+	}
+      }
+
+      if ((d00 <= 0) && (d10 > 0)) {
+	if ((d01 > 0) && (d11 > 0)) { /* \  */
+	  LL;
+	  DUMP;
+	}
+	if ((d01 <= 0) && (d11 > 0)) { /* -  */
+	  HZ;
+	  DUMP;
+	}
+	if ((d01 <= 0) && (d11 <= 0)) { /* /  */
+	  UL;
+	  DUMP;
+	}
+	if ((d01 > 0) && (d11 <= 0)) { /* //  */
+	  UL;
+	  NUMP;
+	  LR;
+	  DUMP;
+	}
+      }
+      
+
+      if ((d00 <= 0) && (d10 <= 0)) { 
+	if ((d01 > 0) && (d11 <= 0)) {
+	  LR;
+	  DUMP;
+	}
+	if ((d01 <= 0) && (d11 > 0)) {
+	  UR;
+	  DUMP;
+	}
+	if ((d01 > 0) && (d11 > 0)) {
+	  VT;
+	  DUMP;
+	}
+      }
+
+      if ((d00 > 0) && (d10 > 0)) { 
+	if ((d01 <= 0) && (d11 > 0)) {
+	  LR;
+	  DUMP;
+	}
+	if ((d01 > 0) && (d11 <= 0)) {
+	  UR;
+	  DUMP;
+	}
+	if ((d01 <= 0) && (d11 <= 0)) {
+	  VT;
+	  DUMP;
+	}
+      }
+
+    }
+    /* skip left-hand edge */
+    v00++; v01++; v10++; v11++;
+    d01 = (level - *v00);
+    d11 = (level - *v10);
+  }
+
+  /****** bottom line *******/
+  v00 = matrix;  
+  v01 = matrix + 1;  
+  y = 0;
+  dx = 0;
+  dy = -0.5;
+  for (i = 1; i < Nx; i++, v00++, v01++) { /* do the edges */
+    if (((*v00 > level) && (*v01 <= level)) || ((*v00 <= level) && (*v01 > level))) {
+      x = i + (level - *v01)/(*v01 - *v00);
+      NUMP;
+    }
+  }
+
+  /********** top line *******/
+  v00 = matrix + Nx*(Ny - 1);  
+  v01 = v00 + 1;
+  y = Ny - 1;
+  dx = 0;
+  dy = 0.5;
+  for (i = 1; i < Nx; i++, v00++, v01++) { /* do the edges */
+    if (((*v00 > level) && (*v01 <= level)) || ((*v00 <= level) && (*v01 > level))) {
+      x = i + (level - *v01)/(*v01 - *v00);
+      NUMP;
+    }
+  }
+
+  /******** left line *********/
+  v00 = matrix; 
+  v01 = matrix + Nx;
+  x = 0;
+  dx = -0.5;
+  dy = 0;
+  for (j = 1; j < Ny; j++, v00+=Nx, v01+=Nx) { /* do the edges */
+    if (((*v00 > level) && (*v01 <= level)) || ((*v00 <= level) && (*v01 > level))) {
+      y = j + (level - *v01)/(*v01 - *v00);
+      NUMP;
+    }
+  }
+
+  /******** right line *********/
+  v00 = matrix + Nx - 1; 
+  v01 = v00 + Nx;
+  x = Nx - 1;
+  dx = 0.5;
+  dy = 0;
+  for (j = 1; j < Ny; j++, v00+=Nx, v01+=Nx) { /* do the edges */
+    if (((*v00 > level) && (*v01 <= level)) || ((*v00 <= level) && (*v01 > level))) {
+      y = j + (level - *v01)/(*v01 - *v00);
+      NUMP;
+    }
+  }
+  
+  if (Nline > 0) {
+    sprintf (line, "NLINES  %7d ", Nline); 
+    write (Ximage, line, 16); 
+    write (Ximage, buffer, Nline*128); 
+  }
+
+  free (buffer);
+  sprintf (line, "DONE ");
+  write (Ximage, line, 16);
+  if (Npix != 1) {
+    free (matrix);
+  }
+  fprintf (stderr, "\n");
+  return (TRUE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/tvgrid.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/tvgrid.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/tvgrid.c	(revision 3338)
@@ -0,0 +1,215 @@
+# include "data.h"
+# define TEN(X) (pow(10.0, (double)(X)))
+
+int tvgrid (int argc, char **argv) {
+  
+  int ncolor, ndig1, ndig2, NX, NY, connect;
+  int tDEC, tRA;
+  double ra, dec, ra0, dec0, ra1, dec1;
+  double x0, y0, x1, y1;
+  double dDEC, fDEC, dRA, fRA;
+  char buffer[1024], format[16];
+  Coords coords;
+  int Ximage, Nimage, N;
+  Buffer *buf;
+
+  Nimage = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nimage = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetImage (&Ximage, &Nimage)) return (FALSE);
+  
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: load (overlay) (buffer)\n");
+    fprintf (stderr, " (overlay) may be: red, green, blue, yellow\n");
+    return (FALSE);
+  }
+  if (strcmp (argv[1], "0")   && strcmp (argv[1], "1")     && strcmp (argv[1], "2")   && strcmp (argv[1], "3") &&
+      strcmp (argv[1], "red") && strcmp (argv[1], "green") && strcmp (argv[1], "blue") && strcmp (argv[1], "yellow")) {
+    fprintf (stderr, "valid overlays may be: 0, red, 1, green, 2, blue, 3, yellow\n");
+    return (FALSE);
+  }
+
+  ncolor = atof (argv[1]);
+  if (!(strcmp (argv[1], "red"))) 
+    ncolor = 0;
+  if (!(strcmp (argv[1], "green"))) 
+    ncolor = 1;
+  if (!(strcmp (argv[1], "blue"))) 
+    ncolor = 2;
+  if (!(strcmp (argv[1], "yellow"))) 
+    ncolor = 3;
+
+  if ((buf = SelectBuffer (argv[2], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  GetCoords (&coords, &buf[0].header);
+
+  XY_to_RD (&ra0, &dec0, 0.0, 0.0, &coords);
+  XY_to_RD (&ra1, &dec1, (double)buf[0].header.Naxis[0], (double)buf[0].header.Naxis[1], &coords);
+  fprintf (stderr, "%f %f  %f %f\n", ra0, dec0, ra1, dec1);
+  
+  /* tell KII to expect overlay data */
+  write (Ximage, "LOAD", 4); 
+  sprintf (buffer, "OVERLAY: %7d", ncolor);
+  write (Ximage, buffer, 16);
+  
+  dDEC = fabs(dec1 - dec0);
+  tDEC = log10(dDEC) - log10(5.0);
+  fDEC = log10(dDEC) - tDEC;
+  if ((fDEC > log10(0.5)) && (fDEC < log10(1.0))) {
+    dDEC = TEN (tDEC + log10(0.1));
+  }
+  if ((fDEC > log10(1.0)) && (fDEC < log10(2.0))) {
+    dDEC = TEN (tDEC + log10(0.2));
+  }
+  if ((fDEC > log10(2.0)) && (fDEC < log10(5.0))) {
+    dDEC = TEN (tDEC + log10(0.5));
+  }
+  if ((fDEC > log10(5.0)) && (fDEC < log10(10.0))) {
+    dDEC = TEN (tDEC + log10(1.0));
+  }
+  if ((fDEC > log10(10.0)) && (fDEC < log10(20.0))) {
+    dDEC = TEN (tDEC + log10(2.0));
+  }
+  if ((fDEC > log10(20.0)) && (fDEC < log10(50.0))) {
+    dDEC = TEN (tDEC + log10(5.0));
+  }
+  ndig2 = ((log10(dDEC) < 0) ? fabs(log10(dDEC)) : 0);
+  ndig1 = 3 + log10(MAX(dec0, dec1)) + ndig2;
+  sprintf (format, "%%%d.%df", ndig1, ndig2);
+  fprintf (stderr, "format: %s..\n", format);
+
+  NX = buf[0].header.Naxis[0];
+  NY = buf[0].header.Naxis[1];
+
+    /* find starting position
+    RD_to_XY (&x0, &y0, MIN(ra0, ra1), dec + 0.1*dDEC, &coords);
+    sprintf (label, format, dec);
+    sprintf (buffer, "%15s %20.10f %20.10f %20.10f %20.10f ", "TEXT", x0, y0, (double)(strlen(label) + 1), 0.0);
+    write (Ximage, buffer, 128);
+    write (Ximage, label, strlen(label) + 1); */
+
+  dRA = MAX (fabs(ra1 - ra0) / 100.0, 0.1);
+  connect = FALSE;
+  for (dec = dDEC * ((int)(MIN(dec0,dec1)/dDEC) + 1); dec < MAX(dec0,dec1); dec += dDEC) {
+    for (ra = 0; ra < 361; ra += dRA) {
+      RD_to_XY (&x1, &y1, ra, dec, &coords);
+      if ((x1 >= 0) && (x1 < NX) && (y1 >= 0) && (y1 < NY)) {
+	if (connect) {
+	  sprintf (buffer, "%15s %20.10f %20.10f %20.10f %20.10f ", "LINE", x0, y0, (x1 - x0), (y1 - y0));
+	  write (Ximage, buffer, 128);
+	}
+	x0 = x1;
+	y0 = y1;
+	connect = TRUE;
+      }
+      else {
+	connect = FALSE;
+      }
+    }
+  }
+
+  dRA = fabs(ra1 - ra0);
+  tRA = log10(dRA) - log10(5.0);
+  fRA = log10(dRA) - tRA;
+  if ((fRA > log10(0.5)) && (fRA < log10(1.0))) {
+    dRA = TEN (tRA + log10(0.1));
+  }
+  if ((fRA > log10(1.0)) && (fRA < log10(2.0))) {
+    dRA = TEN (tRA + log10(0.2));
+  }
+  if ((fRA > log10(2.0)) && (fRA < log10(5.0))) {
+    dRA = TEN (tRA + log10(0.5));
+  }
+  if ((fRA > log10(5.0)) && (fRA < log10(10.0))) {
+    dRA = TEN (tRA + log10(1.0));
+  }
+  if ((fRA > log10(10.0)) && (fRA < log10(20.0))) {
+    dRA = TEN (tRA + log10(2.0));
+  }
+  if ((fRA > log10(20.0)) && (fRA < log10(50.0))) {
+    dRA = TEN (tRA + log10(5.0));
+  }
+  ndig2 = ((log10(dRA) < 0) ? fabs(log10(dRA)) : 0);
+  ndig1 = 3 + log10(MAX(ra0, ra1)) + ndig2;
+  sprintf (format, "%%%d.%df", ndig1, ndig2);
+  fprintf (stderr, "format: %s..\n", format);
+
+  dDEC = MAX (fabs(dec1 - dec0) / 100.0, 0.1);
+  connect = FALSE;
+  for (ra = dRA * ((int)(MIN(ra0,ra1)/dRA) + 1); ra < MAX(ra0,ra1); ra += dRA) {
+    for (dec = -90; dec < 90; dec += dDEC) {
+      RD_to_XY (&x1, &y1, ra, dec, &coords);
+      if ((x1 >= 0) && (x1 < NX) && (y1 >= 0) && (y1 < NY)) {
+	if (connect) {
+	  sprintf (buffer, "%15s %20.10f %20.10f %20.10f %20.10f ", "LINE", x0, y0, (x1 - x0), (y1 - y0));
+	  write (Ximage, buffer, 128);
+	}
+	x0 = x1;
+	y0 = y1;
+	connect = TRUE;
+      }
+      else {
+	connect = FALSE;
+      }
+    }
+  }
+
+  /*
+  dDEC = fabs(dec1 - dec0) / 100;
+  for (ra = dRA * ((int)(MIN(ra0, ra1)/dRA) + 1); ra < MAX(ra0, ra1); ra += dRA) {
+    RD_to_XY (&x0, &y0, ra + 0.1*dRA, MIN(dec0, dec1), &coords);
+    sprintf (label, format, ra);
+    sprintf (buffer, "%15s %20.10f %20.10f %20.10f %20.10f ", "TEXT", x0, y0, (double)(strlen(label) + 1), 0.0);
+    write (Ximage, buffer, 128);
+    write (Ximage, label, strlen(label) + 1);
+    RD_to_XY (&x0, &y0, ra, MIN(dec0, dec1), &coords);
+    for (dec = MIN(dec0, dec1) + dDEC; dec < MAX(dec0,dec1); dec += dDEC) {
+      RD_to_XY (&x1, &y1, ra, dec, &coords);
+      sprintf (buffer, "%15s %20.10f %20.10f %20.10f %20.10f ", "LINE", x0, y0, (x1 - x0), (y1 - y0));
+      write (Ximage, buffer, 128);
+      x0 = x1;
+      y0 = y1;
+    }
+  }
+  */
+
+  sprintf (buffer, "DONE");
+  write (Ximage, buffer, 128);
+  return (TRUE);
+}
+
+
+  
+
+/*
+  write (Ximage, "LOAD", 4); 
+  sprintf (buffer, "OVERLAY: %7d", n);
+  write (Ximage, buffer, 16);
+  
+  for (n = 0; scan_line (f, buffer) != EOF; n++) {
+    c = strchr (buffer, '#');
+    if (c != (char *) NULL) 
+      *c = 0;  
+    while ((c = strchr (buffer, '(')) != (char *) NULL) 
+      *c = ' ';
+    while ((c = strchr (buffer, ')')) != (char *) NULL) 
+      *c = ' ';
+    while ((c = strchr (buffer, ',')) != (char *) NULL) 
+      *c = ' ';
+    N = sscanf (buffer, "%s %lf %lf %lf %lf", type, &x, &y, &dx, &dy);
+    if (N > 3) {
+      if (N == 4)
+	dy = dx;
+      sprintf (buffer, "%15s %20.10f %20.10f %20.10f %20.10f ", type, x, y, dx, dy);
+      write (Ximage, buffer, 128);
+    }
+  }
+  fprintf (stderr, "loaded %d objects\n", n);
+  sprintf (buffer, "DONE");
+  write (Ximage, buffer, 128);
+  if (f != stdin) {
+    fclose (f);
+  }
+*/
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/ungridify.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/ungridify.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/ungridify.c	(revision 3338)
@@ -0,0 +1,56 @@
+# include "data.h"
+
+int ungridify (int argc, char **argv) {
+
+  int i, j, n;
+  int Nx, Ny, NX, NY;
+  int Xmin, Xmax, Ymin, Ymax;
+  float *v, *x, *y, *z;
+  Buffer *bf;
+  Vector *vx, *vy, *vz;
+
+  if (argc != 9) {
+    fprintf (stderr, "USAGE: ungridify buffer Xmin Xmax Ymin Ymax x y z\n");
+    return (FALSE);
+  }
+  
+  if ((bf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  Xmin = atof (argv[2]);
+  Xmax = atof (argv[3]);
+  Ymin = atof (argv[4]);
+  Ymax = atof (argv[5]);
+  Nx = Xmax - Xmin;
+  Ny = Ymax - Ymin;
+  
+  NX = bf[0].matrix.Naxis[0];
+  NY = bf[0].matrix.Naxis[1];
+
+  if ((vx = SelectVector (argv[6], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((vy = SelectVector (argv[7], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((vz = SelectVector (argv[8], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  REALLOCATE (vx[0].elements, float, Nx*Ny);
+  REALLOCATE (vy[0].elements, float, Nx*Ny);
+  REALLOCATE (vz[0].elements, float, Nx*Ny);
+
+  x = vx[0].elements;
+  y = vy[0].elements;
+  z = vz[0].elements;
+  n = 0;
+  v = (float *)bf[0].matrix.buffer;
+  for (j = Ymin; j < Ymax; j++) {
+    for (i = Xmin; i < Xmax; i++, x++, y++, z++, n++) {
+      vx[0].elements[n] = i;
+      vy[0].elements[n] = j;
+      if (i < 0) continue;
+      if (i >= NX) continue;
+      if (j < 0) continue;
+      if (j >= NY) continue;
+      vz[0].elements[n] = v[i+j*NX];
+    }
+  }
+  if (n != Nx*Ny) {
+    fprintf (stderr, "error in ungrid: %d vs %d (%d x %d)\n", n, Nx*Ny, Nx, Ny);
+  }
+  vx[0].Nelements = vy[0].Nelements = vz[0].Nelements = n;
+  return (TRUE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/uniq.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/uniq.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/uniq.c	(revision 3338)
@@ -0,0 +1,39 @@
+# include "data.h"
+
+int uniq (int argc, char **argv) {
+  
+  int Nnew, i, j, found;
+  float *v1, *v2;
+  Vector *ivec, *ovec;
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: uniq (in) (out)\n");
+    return (FALSE);
+  }
+
+  if ((ivec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((ovec = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  /* allocate the maximum possible needed */
+  ALLOCATE (ovec[0].elements, float, ivec[0].Nelements);
+
+  Nnew = 0;
+  v1 = ivec[0].elements;
+  for (i = 0; i < ivec[0].Nelements; i++, v1++) {
+    v2 = ovec[0].elements;
+    found = FALSE;
+    for (j = 0; !found && (j < Nnew); j++, v2++) {
+      if (*v1 == *v2) found = TRUE;
+    }
+    if (!found) {
+      ovec[0].elements[Nnew] = *v1;
+      Nnew ++;
+    }
+  }
+
+  ovec[0].Nelements = Nnew;
+  REALLOCATE (ovec[0].elements, float, ovec[0].Nelements);
+
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/unsign.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/unsign.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/unsign.c	(revision 3338)
@@ -0,0 +1,28 @@
+# include "data.h"
+
+int unsign (int argc, char **argv) {
+  
+  if (argc == 1) {
+    if (FT_UNSIGN_MODE) 
+      fprintf (stderr, "mode is now UNSIGNED int \n");
+    else
+      fprintf (stderr, "mode is now SIGNED int \n");
+    return (TRUE);
+  }
+
+  if (argc == 2) {
+    if (!strcmp (argv[1], "1")) {
+      FT_UNSIGN_MODE = TRUE;
+      set_int_variable ("UNSIGN", 1);
+      return (TRUE);
+    }
+    if (!strcmp (argv[1], "0")) {
+      FT_UNSIGN_MODE = FALSE;
+      set_int_variable ("UNSIGN", 0);
+      return (TRUE);
+    }
+  }
+
+  fprintf (stderr, "USAGE: unsign [0/1]\n");
+  return (FALSE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/vbin.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/vbin.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/vbin.c	(revision 3338)
@@ -0,0 +1,227 @@
+# include "data.h"
+
+int vbin (int argc, char **argv) {
+  
+  int i, j, status, ExactScale;
+  int n, nx, ny, Nx, Ny, x, y, N, Normalize, *Npix, *Vn;
+  int Ignore, IgnoreValue, VERBOSE;
+  float *Vout, *Vin, *Out, *In;
+  double scale, scale2, fx, fy, dX, dY;
+  char temp[1024];
+  Buffer *in, *out;
+
+  Normalize = FALSE;
+  if ((N = get_argument (argc, argv, "-norm"))) {
+    remove_argument (N, &argc, argv);
+    Normalize = TRUE;
+  }
+
+  VERBOSE = FALSE;
+  if ((N = get_argument (argc, argv, "-v"))) {
+    remove_argument (N, &argc, argv);
+    VERBOSE = TRUE;
+  }
+
+  Ignore = FALSE;
+  IgnoreValue = 0.0;
+  if ((N = get_argument (argc, argv, "-ignore"))) {
+    Ignore = TRUE;
+    remove_argument (N, &argc, argv);
+    IgnoreValue = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 4) {
+    fprintf (stderr, "USAGE: vbin <input> <output> scale \n");
+    fprintf (stderr, "  (use interpolate to expand)\n");
+    return (FALSE);
+  }
+
+  if ((in  = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((out = SelectBuffer (argv[2], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+  fits_free_matrix (&out[0].matrix);
+  fits_free_header (&out[0].header);
+
+  scale  = atof (argv[3]);
+  if ((scale == (int) scale) || ((1.0/scale) == (int)(1.0/scale))) {
+    ExactScale = TRUE;
+    if (scale > 0) {
+      nx = in[0].header.Naxis[0] / scale;
+      ny = in[0].header.Naxis[1] / scale;
+    } else {
+      nx = in[0].header.Naxis[0] * fabs(scale);
+      ny = in[0].header.Naxis[1] * fabs(scale);
+    }    
+  } else {
+    ExactScale = FALSE;
+    if (scale > 0) {
+      nx = (int) (in[0].header.Naxis[0] / scale) + 1;
+      ny = (int) (in[0].header.Naxis[1] / scale) + 1;
+    } else {
+      nx = (int) (in[0].header.Naxis[0] * fabs(scale)) + 1;
+      ny = (int) (in[0].header.Naxis[1] * fabs(scale)) + 1;
+    }      
+  }
+  if (VERBOSE) fprintf (GetOutfile(), "rebin %s to %s (%d,%d to %d,%d)\n", argv[1], argv[2], in[0].header.Naxis[0], in[0].header.Naxis[1], nx, ny);
+
+  Nx = in[0].header.Naxis[0];
+  Ny = in[0].header.Naxis[1];
+  out[0].bitpix = in[0].bitpix;
+  out[0].unsign = in[0].unsign;
+  out[0].bscale = in[0].bscale;
+  out[0].bzero  = in[0].bzero;
+  fits_copy_header (&in[0].header, &out[0].header);
+  fits_modify (&out[0].header, "NAXIS1", "%d", 1, nx);
+  fits_modify (&out[0].header, "NAXIS2", "%d", 1, ny);
+
+  status =  fits_scan (&out[0].header, "CDELT1", "%lf", 1, &dX);
+  status &= fits_scan (&out[0].header, "CDELT2", "%lf", 1, &dY);
+  if (scale > 0) {
+    dX *= scale;
+    dY *= scale;
+  } else {
+    dX /= fabs(scale);
+    dY /= fabs(scale);
+  }    
+  if (status) {
+    fits_modify (&out[0].header, "CDELT1", "%lf", 1, dX);
+    fits_modify (&out[0].header, "CDELT2", "%lf", 1, dY);
+  }
+
+  status =  fits_scan (&out[0].header, "CRPIX1", "%lf", 1, &dX);
+  status &= fits_scan (&out[0].header, "CRPIX2", "%lf", 1, &dY);
+  if (scale > 0) {
+    dX /= scale;
+    dY /= scale;
+  } else {
+    dX *= fabs(scale);
+    dY *= fabs(scale);
+  }    
+  if (status) {
+    fits_modify (&out[0].header, "CRPIX1", "%lf", 1, dX);
+    fits_modify (&out[0].header, "CRPIX2", "%lf", 1, dY);
+  }
+
+  out[0].header.Naxis[0] = nx;
+  out[0].header.Naxis[1] = ny;
+  fits_create_matrix (&out[0].header, &out[0].matrix);
+  temp[0] = 0;
+  if ((in[0].file[0] != '*') && (in[0].file[0] != '(')) {
+    strcpy (temp, "*");
+  }
+  strcat (temp, in[0].file);
+  strcpy (out[0].file, temp);
+
+  if (Normalize) {
+    ALLOCATE (Npix, int, nx*ny);
+    bzero (Npix, nx*ny*sizeof(int));
+  }
+
+  if (ExactScale) {
+    n = scale;
+    if (n > 0) {
+      for (j = 0; j < ny; j++) {
+	for (y = 0; y < n; y++) {
+	  Vout = (float *)(out[0].matrix.buffer) + j*nx;
+	  Vin  = (float *)(in[0].matrix.buffer)  + (j*n + y)*in[0].header.Naxis[0];
+	  if (Normalize) { Vn = Npix + j*nx; }
+	  for (i = 0; i < nx; i++, Vout++) {
+	    for (x = 0; x < n; x++, Vin++) {
+	      if (Ignore && (*Vin == IgnoreValue)) continue;
+	      *Vout += *Vin;
+	      if (Normalize) {(*Vn) ++;}
+	    }
+	    if (Normalize) {Vn ++;}
+	  }
+	}
+      }
+    } else {
+      n = fabs (n);
+      for (j = 0; j < in[0].header.Naxis[1]; j++) {
+	for (y = 0; y < n; y++) {
+	  Vout = (float *)(out[0].matrix.buffer) + (j*n + y)*nx;
+	  Vin  = (float *)(in[0].matrix.buffer)  + j*in[0].header.Naxis[0];
+	  if (Normalize) { Vn = Npix + j*nx; }
+	  for (i = 0; i < in[0].header.Naxis[0]; i++, Vin++) {
+	    if (Ignore && (*Vin == IgnoreValue)) { 
+	      Vout += n; 
+	      if (Normalize) Vn += n; 
+	      continue; 
+	    }
+	    for (x = 0; x < n; x++, Vout++) {
+	      *Vout = *Vin;
+	      if (Normalize) {(*Vn) ++; Vn ++;}
+	    }
+	  }
+	}
+      }
+    }
+    if (Normalize) {
+      Vn = Npix;
+      Vout = (float *)out[0].matrix.buffer;
+      for (i = 0; i < nx*ny; i++, Vout++, Vn++) {
+	if (*Vn) { 
+	  *Vout /= *Vn; 
+	} else {
+	  *Vout = 0;
+	}
+      }
+    }
+  } else {
+    
+    if (Normalize) { fprintf (stderr, "normalize not enabled for fractional scaling\n"); }
+
+    if (scale < 0) scale = 1.0 / fabs(scale);
+    In = (float *)in[0].matrix.buffer;
+    Out = (float *)out[0].matrix.buffer;
+    scale2 = scale*scale;
+    if (scale > 1) {
+      for (i = 0; i < Ny; i++) {
+	y = 0.5 + (i - 0.5) / scale;
+	fy = 0.5 + MIN (0.5, (y + 0.5) * scale - i);
+	for (j = 0; j < Nx; j++, In++) {
+	  x = 0.5 + (j - 0.5) / scale;
+	  fx = 0.5 + MIN (0.5, (x + 0.5) * scale - j);
+	  Vout = Out + y*nx + x;
+	  *Vout += fx*fy*(*In);
+	  if (fx < 1) {
+	    *(Vout+1)    += (1-fx)*fy*(*In);
+	  }
+	  if (fy < 1) {
+	    *(Vout+nx) += fx*(1-fy)*(*In);
+	  }
+	  if ((fx < 1) && (fy < 1)) {
+	    *(Vout+1+nx) += (1-fx)*(1-fy)*(*In);
+	  }
+	}
+      }
+    } else {
+      for (i = 0; i < ny; i++) {
+	y = 0.5 + (i - 0.5) * scale;
+	fy = 0.5 + MIN (0.5, (y + 0.5) / scale - i);
+	for (j = 0; j < nx; j++, Out++) {
+	  x = 0.5 + (j - 0.5) * scale;
+	  fx = 0.5 + MIN (0.5, (x + 0.5) / scale - j);
+	  Vin = In + y*Nx + x;
+	  *Out += *Vin*fx*fy;
+	  if (fx < 1) {
+	    *Out += *(Vin+1)*(1-fx)*fy;
+	  }
+	  if (fy < 1) {
+	    *Out += *(Vin+Nx)*fx*(1-fy);
+	  }
+	  if ((fx < 1) && (fy < 1)) {
+	    *Out += *(Vin+1+Nx)*(1-fx)*(1-fy);
+	  }
+	  *Out = *Out * scale2;
+	}
+      }
+    }
+  }
+
+  if (Normalize) free (Npix);
+
+  return (TRUE);
+
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/vclip.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/vclip.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/vclip.c	(revision 3338)
@@ -0,0 +1,71 @@
+# include "data.h"
+
+int vclip (int argc, char **argv) {
+
+  int i, Npix, DO_NAN, DO_INF, N;
+  double min, Vmin, max, Vmax, nan_val, inf_val;
+  float *in;
+  Vector *vec;
+
+  DO_NAN = FALSE;
+  if ((N = get_argument (argc, argv, "-nan"))) {
+    remove_argument (N, &argc, argv);
+    nan_val  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    DO_NAN = TRUE;
+  }
+
+  DO_INF = FALSE;
+  if ((N = get_argument (argc, argv, "-inf"))) {
+    remove_argument (N, &argc, argv);
+    inf_val  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    DO_INF = TRUE;
+  }
+
+  if ((argc != 6) && (!(DO_INF || DO_NAN))) {
+    fprintf (stderr, "USAGE: vclip (vector) [min Vmin max Vmax] [-inf val] [-nan val]\n");
+    return (FALSE);
+  }
+
+  if ((vec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+
+  if (argc == 6) {
+    min = atof (argv[2]);
+    Vmin = atof (argv[3]);
+    max = atof (argv[4]);
+    Vmax = atof (argv[5]);
+  }
+
+  Npix = vec[0].Nelements;
+  in =   vec[0].elements;
+
+  if (argc == 6) {
+    for (i = 0; i < Npix; i++, in++) {
+      if (*in < min) 
+	*in = Vmin;
+      if (*in > max)
+	*in = Vmax;
+    }
+  }
+  in = vec[0].elements;
+  if (DO_NAN) {
+    for (i = 0; i < Npix; i++, in++) {
+      if (isnan (*in)) {
+	*in = nan_val;
+      }
+    }
+  }
+  in = vec[0].elements;
+  if (DO_INF) {
+    for (i = 0; i < Npix; i++, in++) {
+      if (!finite (*in)) {
+	*in = inf_val;
+      }
+    }
+  }
+  return (TRUE);
+
+}
+
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/vcontour.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/vcontour.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/vcontour.c	(revision 3338)
@@ -0,0 +1,277 @@
+# include "data.h"
+# define LL { \
+ dx =  d00 / (*v01 - *v00); \
+ dy = -d00 / (*v10 - *v00); \
+ x = i - 0.5; \
+ y = j - dy - 0.5; }
+
+# define UL { \
+ tmp = d00 / (*v10 - *v00); \
+ dy = 1 - tmp; \
+ dx =  d10 / (*v11 - *v10); \
+ x = i - 0.5; \
+ y = j + tmp - 0.5; }
+      
+# define LR { \
+ tmp = d00 / (*v01 - *v00); \
+ dx = 1 - tmp; \
+ dy = d01 / (*v11 - *v01); \
+ x = i + tmp - 0.5; \
+ y = j - 0.5; }
+
+# define UR { \
+ tmp = d10 / (*v11 - *v10); \
+ dx = 1 - tmp; \
+ dy = -d11 / (*v01 - *v11); \
+ x = i + tmp - 0.5; \
+ y = j + 1 - 0.5; }
+      
+# define HZ { \
+ tmp = d00 / (*v10 - *v00); \
+ dy = d01 / (*v11 - *v01) - tmp; \
+ dx = 1; \
+ x = i - 0.5; \
+ y = j + tmp - 0.5; }
+
+# define VT { \
+ tmp = d00 / (*v01 - *v00); \
+ dx = d10 / (*v11 - *v10) - tmp; \
+ x = i + tmp - 0.5; \
+ dy = 1; \
+ y = j - 0.5; }
+
+# define DUMP { \
+sprintf (&buffer[Nline*128], "%14s %20.10f %20.10f %20.10f %20.10f \0", "LINE", Npix*x, Npix*y, Npix*dx, Npix*dy); \
+Nline ++; \
+if (Nline == 512) { \
+  sprintf (line, "NLINES  %7d \0", Nline); \
+  write (Ximage, line, 16); \
+  write (Ximage, buffer, Nline*128); \
+  bzero (buffer, 65536); \
+  Nline = 0; \
+} \
+continue; }
+
+# define NUMP { \
+sprintf (&buffer[Nline*128], "%14s %20.10f %20.10f %20.10f %20.10f \0", "LINE", Npix*x, Npix*y, Npix*dx, Npix*dy); \
+Nline ++; \
+if (Nline == 512) { \
+  sprintf (line, "NLINES  %7d \0", Nline); \
+  write (Ximage, line, 16); \
+  write (Ximage, buffer, Nline*128); \
+  bzero (buffer, 65536); \
+  Nline = 0; \
+} }
+
+int vcontour (int argc, char **argv) {
+
+  int i, j, ii, jj, n, Nbuf, Npix, Nx, Ny, Nline;
+  float level, d00, d01, d10, d11, tmp;
+  float x, y, dx, dy;
+  float *v00, *v01, *v10, *v11;
+  float *Vout, *Vin, *matrix;
+  char *buffer, line[17];
+  int Ximage, Nimage, N;
+  Vector *xvec, *yvec, *zvec;
+
+  fprintf (stderr, "vcontour not working yet\n");
+  return (FALSE);
+
+  if (argc != 7) {
+    fprintf (stderr, "USAGE: vcontour x y z Xc Yc (level)\n");
+    return (FALSE);
+  }
+  
+  if ((xvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yvec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((zvec = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((foo = SelectVector (argv[4], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((foo = SelectVector (argv[5], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  level = atof (argv[6]);
+
+  /* convert the x,y,z vectors to a matrix */
+  *V = xvec[0].elements;
+  max = min = *V;
+  for (i = 0; i < xvec[0].Nelements; i++, V++) {
+    if (!finite (*V)) continue;
+    max = MAX (*V, max);
+    min = MIN (*V, min);
+  }      
+  Xmax = max; Xmin = min;
+
+  *V = yvec[0].elements;
+  max = min = *V;
+  for (i = 0; i < yvec[0].Nelements; i++, V++) {
+    if (!finite (*V)) continue;
+    max = MAX (*V, max);
+    min = MIN (*V, min);
+  }      
+  Ymax = max; Ymin = min;
+
+  /* not really finished */
+
+  v01 = matrix + 1;
+  v10 = matrix + Nx;
+  v11 = matrix + Nx + 1;
+  d01 = (level - *v00);
+  d11 = (level - *v10);
+  for (j = 1; j < Ny; j++) {
+    if (!(j%10)) fprintf (stderr, ".");
+    for (i = 1; i < Nx; i++, v00++, v01++, v10++, v11++) {
+
+      d00 = d01;
+      d10 = d11;
+      d01 = (level - *v01);
+      d11 = (level - *v11);
+
+      if (((d00 > 0) && (d01 > 0) && (d10 > 0) && (d11 > 0)) ||
+	  ((d00 < 0) && (d01 < 0) && (d10 < 0) && (d11 < 0)))
+	continue;
+
+      if ((d00 > 0) && (d10 <= 0)) { 
+	if ((d01 <= 0) && (d11 <= 0)) { /* \  */
+	  LL;
+	  DUMP;
+	}
+	if ((d01 > 0) && (d11 <= 0)) { /* -  */
+	  HZ;
+	  DUMP;
+	}
+	if ((d01 > 0) && (d11 > 0)) { /* /  */
+	  UL;
+	  DUMP;
+	}
+	if ((d01 <= 0) && (d11 > 0)) { /* \\  */
+	  LL;
+	  NUMP;
+	  UR;
+	  DUMP;
+	}
+      }
+
+      if ((d00 <= 0) && (d10 > 0)) {
+	if ((d01 > 0) && (d11 > 0)) { /* \  */
+	  LL;
+	  DUMP;
+	}
+	if ((d01 <= 0) && (d11 > 0)) { /* -  */
+	  HZ;
+	  DUMP;
+	}
+	if ((d01 <= 0) && (d11 <= 0)) { /* /  */
+	  UL;
+	  DUMP;
+	}
+	if ((d01 > 0) && (d11 <= 0)) { /* //  */
+	  UL;
+	  NUMP;
+	  LR;
+	  DUMP;
+	}
+      }
+      
+
+      if ((d00 <= 0) && (d10 <= 0)) { 
+	if ((d01 > 0) && (d11 <= 0)) {
+	  LR;
+	  DUMP;
+	}
+	if ((d01 <= 0) && (d11 > 0)) {
+	  UR;
+	  DUMP;
+	}
+	if ((d01 > 0) && (d11 > 0)) {
+	  VT;
+	  DUMP;
+	}
+      }
+
+      if ((d00 > 0) && (d10 > 0)) { 
+	if ((d01 <= 0) && (d11 > 0)) {
+	  LR;
+	  DUMP;
+	}
+	if ((d01 > 0) && (d11 <= 0)) {
+	  UR;
+	  DUMP;
+	}
+	if ((d01 <= 0) && (d11 <= 0)) {
+	  VT;
+	  DUMP;
+	}
+      }
+
+    }
+    /* skip left-hand edge */
+    v00++; v01++; v10++; v11++;
+    d01 = (level - *v00);
+    d11 = (level - *v10);
+  }
+
+  /****** bottom line *******/
+  v00 = matrix;  
+  v01 = matrix + 1;  
+  y = 0;
+  dx = 0;
+  dy = -0.5;
+  for (i = 1; i < Nx; i++, v00++, v01++) { /* do the edges */
+    if (((*v00 > level) && (*v01 <= level)) || ((*v00 <= level) && (*v01 > level))) {
+      x = i + (level - *v01)/(*v01 - *v00);
+      NUMP;
+    }
+  }
+
+  /********** top line *******/
+  v00 = matrix + Nx*(Ny - 1);  
+  v01 = v00 + 1;
+  y = Ny - 1;
+  dx = 0;
+  dy = 0.5;
+  for (i = 1; i < Nx; i++, v00++, v01++) { /* do the edges */
+    if (((*v00 > level) && (*v01 <= level)) || ((*v00 <= level) && (*v01 > level))) {
+      x = i + (level - *v01)/(*v01 - *v00);
+      NUMP;
+    }
+  }
+
+  /******** left line *********/
+  v00 = matrix; 
+  v01 = matrix + Nx;
+  x = 0;
+  dx = -0.5;
+  dy = 0;
+  for (j = 1; j < Ny; j++, v00+=Nx, v01+=Nx) { /* do the edges */
+    if (((*v00 > level) && (*v01 <= level)) || ((*v00 <= level) && (*v01 > level))) {
+      y = j + (level - *v01)/(*v01 - *v00);
+      NUMP;
+    }
+  }
+
+  /******** right line *********/
+  v00 = matrix + Nx - 1; 
+  v01 = v00 + Nx;
+  x = Nx - 1;
+  dx = 0.5;
+  dy = 0;
+  for (j = 1; j < Ny; j++, v00+=Nx, v01+=Nx) { /* do the edges */
+    if (((*v00 > level) && (*v01 <= level)) || ((*v00 <= level) && (*v01 > level))) {
+      y = j + (level - *v01)/(*v01 - *v00);
+      NUMP;
+    }
+  }
+  
+  if (Nline > 0) {
+    sprintf (line, "NLINES  %7d \0", Nline); 
+    write (Ximage, line, 16); 
+    write (Ximage, buffer, Nline*128); 
+  }
+
+  free (buffer);
+  sprintf (line, "DONE \0");
+  write (Ximage, line, 16);
+  if (Npix != 1) {
+    free (matrix);
+  }
+  fprintf (stderr, "\n");
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/vgauss.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/vgauss.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/vgauss.c	(revision 3338)
@@ -0,0 +1,93 @@
+# include "data.h"
+
+/* local private functions */
+float fgaussOD (float, float *, int, float *);
+
+# define GET_VAR(V,A) \
+  c = get_variable (A); \
+  if (c == NULL) { \
+    fprintf (stderr, "missing fit parameter A\n"); \
+    return (FALSE); \
+  } \
+  V = atof (c);
+
+int vgauss (int argc, char **argv) {
+
+  int i, Npts, Npar;
+  float par[4], *v1, *v2, *dy, **covar;
+  float chisq, ochisq, dchisq;
+  Vector *xvec, *yvec, *svec, *ovec;
+  char *c, name[16];
+
+  if (argc != 5) {
+    fprintf (stderr, "USAGE: vgauss <x> <y> <dy> (out)\n");
+    return (FALSE);
+  }
+  
+  if ((xvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yvec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((svec = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((ovec = SelectVector (argv[4], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  Npts = xvec[0].Nelements;
+  ALLOCATE (dy, float, Npts);
+  REALLOCATE (ovec[0].elements, float, Npts);
+
+  GET_VAR (par[0], "C0");
+  GET_VAR (par[1], "C1");
+  GET_VAR (par[2], "C2");
+  GET_VAR (par[3], "C3");
+  par[1] = sqrt(0.5)*(1/par[1]);
+  Npar = 4;
+  /* careful of variable renomalization */
+
+  v1 = svec[0].elements;
+  v2 = dy;
+  for (i = 0; i < Npts; i++, v1++, v2++) *v2 = 1.0 / (*v1 * *v1);
+  
+  ochisq = mrqinit (xvec[0].elements, yvec[0].elements, dy, Npts, par, Npar, fgaussOD, TRUE);
+  dchisq = ochisq;
+
+  for (i = 0; (i < 20) && ((dchisq > (Npts - Npar)) || (dchisq <= 0.0)); i++) {
+    chisq = mrqmin (xvec[0].elements, yvec[0].elements, dy, Npts, par, Npar, fgaussOD, TRUE);
+    dchisq = ochisq - chisq;
+    ochisq = chisq;
+    fprintf (stderr, "dchisq: %f, Ndof: %d\n", dchisq, Npts - Npar);
+  }  
+
+  for (i = 0; i < Npts; i++) {
+    ovec[0].elements[i] = fgaussOD (xvec[0].elements[i], par, Npar, dy);
+  }
+  ovec[0].Nelements = Npts;
+  /* set output *before* variable renomalization */
+
+  covar = mrqcovar (Npar);
+  par[1] = sqrt(0.5)*(1/par[1]);
+  for (i = 0; i < Npar; i++) {
+    sprintf (name, "C%d", i);
+    set_variable (name, par[i]);
+    fprintf (stderr, "%d  %f  %f\n", i, par[i], covar[i][i]);
+  }
+
+  mrqfree (Npar);
+  return (TRUE);
+}
+
+/* pars: x_o, -0.5/sigma^2, I, back*/
+float fgaussOD (float x, float *par, int Npar, float *dpar) {
+
+  float z, r, f, q;
+
+  z = (x - par[0]);
+  r = exp (-1*SQ(par[1]*z));
+  f = par[2]*r + par[3];
+  q = 2*par[1]*par[2]*r*z;
+
+  dpar[0] = +q*par[1];
+  dpar[1] = -q*z;
+  dpar[2] = r;
+  dpar[3] = 1;
+  
+  return (f);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/vgrid.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/vgrid.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/vgrid.c	(revision 3338)
@@ -0,0 +1,86 @@
+# include "data.h"
+
+int vgrid (int argc, char **argv) {
+
+  int i, Nx, Ny, Xb, Yb;
+  float Xmin, Xmax, dX, Ymin, Ymax, dY;
+  float *buf, *val, *x, *y, *z;
+  int *Nval;
+  Buffer *bf;
+  Vector *vx, *vy, *vz;
+
+  if (argc != 11) {
+    fprintf (stderr, "USAGE: vgrid x y z buffer Xmin Xmax dX Ymin Ymax dY\n");
+    return (FALSE);
+  }
+  
+  if ((vx = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((vy = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((vz = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((bf = SelectBuffer (argv[4], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+
+  if (vx[0].Nelements != vy[0].Nelements) return (FALSE);
+  if (vx[0].Nelements != vz[0].Nelements) return (FALSE);
+
+  Xmin = atof (argv[5]);
+  Xmax = atof (argv[6]);
+  dX   = atof (argv[7]);
+
+  Ymin = atof (argv[8]);
+  Ymax = atof (argv[9]);
+  dY   = atof (argv[10]);
+
+  Nx = (Xmax - Xmin) / dX + 1;
+  Ny = (Ymax - Ymin) / dY + 1;
+  
+  /* these steps are a standard 'createbuffer', define? */
+  bf[0].bitpix = -32;
+  bf[0].unsign = FALSE;
+  bf[0].bscale = 1.0;
+  bf[0].bzero  = 0.0;
+  strcpy (bf[0].file, "(empty)");
+
+  bf[0].header.bitpix = bf[0].bitpix;
+  bf[0].header.bscale = bf[0].bscale;
+  bf[0].header.bzero  = bf[0].bzero; 
+  bf[0].header.unsign = bf[0].unsign;
+  bf[0].header.Naxes = 2;
+  bf[0].header.Naxis[0] = Nx;
+  bf[0].header.Naxis[1] = Ny;
+  free (bf[0].header.buffer);  /* ALLOCATEd in SelectBuffer */
+  free (bf[0].matrix.buffer);  /* ALLOCATEd in SelectBuffer */
+  fits_create_header (&bf[0].header);
+  fits_create_matrix (&bf[0].header, &bf[0].matrix);
+
+  ALLOCATE (val, float, Nx*Ny);
+  bzero (val, Nx*Ny*sizeof(float));
+  ALLOCATE (Nval, int, Nx*Ny);
+  bzero (Nval, Nx*Ny*sizeof(int));
+
+  x = vx[0].elements;
+  y = vy[0].elements;
+  z = vz[0].elements;
+  for (i = 0; i < vx[0].Nelements; i++, x++, y++, z++) {
+    Xb = (*x - Xmin) / dX;
+    Yb = (*y - Ymin) / dY;
+    if (Xb >= Nx) continue;
+    if (Yb >= Ny) continue;
+    val[Xb + Yb*Nx] = *z;
+    Nval[Xb + Yb*Nx]++;
+  }
+
+  buf = (float *) bf[0].matrix.buffer;
+  for (i = 0; i < Nx*Ny; i++) {
+    if (Nval[i] == 0) {
+      buf[i] = 0;
+      continue;
+    }
+    buf[i] = val[i] / Nval[i];
+  }
+
+  free (val);
+  free (Nval);
+
+  return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/vload.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/vload.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/vload.c	(revision 3338)
@@ -0,0 +1,69 @@
+# include "data.h"
+
+int vload (int argc, char **argv) {
+  
+  int i, N, n, Nline;
+  int Ximage, Nimage;
+  double dx, dy;
+  char *buffer, *line;
+  Vector *vecx, *vecy;
+  
+  Nimage = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nimage = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetImage (&Ximage, &Nimage)) return (FALSE);
+
+  if (argc != 4) {
+    fprintf (stderr, "USAGE: vload (overlay) (xvec) (yvec) [-n]\n");
+    return (FALSE);
+  }
+  
+  if (!SelectOverlay (argv[1], &n)) return (FALSE);
+
+  if ((vecx = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((vecy = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if (vecx[0].Nelements != vecy[0].Nelements) {
+    fprintf (stderr, "mismatched vector lengths\n");
+    return (FALSE);
+  }
+
+  ALLOCATE (buffer, char, 65536);  /* space for 512 lines of 128 bytes */
+  bzero (buffer, 65536);
+  ALLOCATE (line, char, 1024);     /* space to read the file */
+  Nline = 0;
+
+  write (Ximage, "LOAD", 4); /* force Ximage to look for the incoming image */
+  sprintf (line, "OVER %9d ", n);
+  write (Ximage, line, 16);
+  
+  dx = dy = 1.0;
+
+  for (i = 0; i < vecx[0].Nelements; i++) {
+    snprintf (&buffer[Nline*128], 128, "%15s %20.10f %20.10f %20.10f %20.10f ", "BOX", 
+	      vecx[0].elements[i]+0.5, vecy[0].elements[i]+0.5, dx, dy);
+    Nline ++;
+    if (Nline == 512) {
+      sprintf (line, "NLINES  %7d ", Nline);
+      write (Ximage, line, 16);
+      write (Ximage, buffer, Nline*128);
+      bzero (buffer, 65536);
+      Nline = 0;
+    }
+  }
+
+  sprintf (line, "NLINES  %7d ", Nline);
+  write (Ximage, line, 16);
+  write (Ximage, buffer, Nline*128);
+  sprintf (line, "DONE ");
+  write (Ximage, line, 16);
+
+  free (buffer);
+  free (line);
+  fprintf (stderr, "loaded %d objects\n", n);
+
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/vpop.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/vpop.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/vpop.c	(revision 3338)
@@ -0,0 +1,23 @@
+# include "data.h"
+
+int vpop (int argc, char **argv) {
+
+  int Npix;
+  Vector *vec;
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: vpop (vector)\n");
+    fprintf (stderr, "  remove first element of vector\n");
+    return (FALSE);
+  }
+
+  if ((vec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  Npix = vec[0].Nelements;
+  if (Npix < 1) return (TRUE);
+
+  if (Npix > 1) {
+    memmove (&vec[0].elements[0], &vec[0].elements[1], Npix*sizeof(float));
+  }
+  vec[0].Nelements = Npix - 1;
+  return (TRUE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/vroll.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/vroll.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/vroll.c	(revision 3338)
@@ -0,0 +1,23 @@
+# include "data.h"
+
+int vroll (int argc, char **argv) {
+
+  int Npix;
+  float first;
+  Vector *vec;
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: vroll (vector)\n");
+    fprintf (stderr, "  roll vector elements (first goes to end)\n");
+    return (FALSE);
+  }
+
+  if ((vec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  Npix = vec[0].Nelements;
+  if (Npix < 2) return (TRUE);
+
+  first = vec[0].elements[0];
+  memmove (&vec[0].elements[0], &vec[0].elements[1], Npix*sizeof(float));
+  vec[0].elements[Npix-1] = first;
+  return (TRUE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/vstat.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/vstat.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/vstat.c	(revision 3338)
@@ -0,0 +1,114 @@
+# include "data.h"
+
+int vstat (int argc, char **argv) {
+  
+  int i, N;
+  double max, min, sum, var, dvar, mean, stdev;
+  float *X, IgnoreValue;
+  int Ignore, Quiet;
+
+  int *Nval, bin, Nmode, Nmed;
+  double dx, mode, median;
+  Vector *vec;
+
+  Ignore = FALSE;
+  if ((N = get_argument (argc, argv, "-ignore"))) {
+    Ignore = TRUE;
+    remove_argument (N, &argc, argv);
+    IgnoreValue = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  Quiet = FALSE;
+  if ((N = get_argument (argc, argv, "-q"))) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-quiet"))) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: vstat (vector)\n");
+    return (FALSE);
+  }
+
+  if ((vec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+
+  /* we need two passes, one for max, min, mean, sum, one for median, stdev, etc */
+
+  /* calculate max, min, mean, sum, npix */
+  X = vec[0].elements;
+  max = -HUGE_VAL;
+  min = HUGE_VAL;
+  sum = N = 0;
+  for (i = 0; i < vec[0].Nelements; i++, X++) {
+    if (!finite (*X)) continue;
+    if (Ignore && (*X == IgnoreValue)) continue;
+    max = MAX (*X, max);
+    min = MIN (*X, min);
+    sum += *X;
+    N++;
+  }      
+  mean = sum / N;
+
+  /* calculate median and mode with resolution of (max - min) / 1000 */ 
+  dx = (max - min) / 1000;
+  if (dx == 0) {
+    median = mode = min;
+    stdev = 0.0;
+    goto skip;
+  }
+
+  ALLOCATE (Nval, int, 1002);
+  bzero (Nval, 1000*sizeof(int));
+  X = vec[0].elements;
+  var = 0;
+  for (i = 0; i < vec[0].Nelements; i++, X++) {
+    if (!finite (*X)) continue;
+    if (Ignore && (*X == IgnoreValue)) continue;
+    bin = MAX (0, MIN (1000, (*X - min) / dx));
+    Nval[bin] ++;
+    dvar = (*X - mean);
+    var += dvar*dvar;
+  }      
+  stdev = sqrt (var / N);
+
+  Nmode = 0;
+  mode = Nval[Nmode];
+  median = 0;
+  Nmed = -1;
+  for (i = 0; i < 1001; i++) {
+    if (Nmed == -1) {
+      median += Nval[i];
+      if (median >= N / 2.0) {
+	Nmed = i;
+	median = i * dx + min;
+      }
+    }
+    if (mode < Nval[i]) {
+      Nmode = i;
+      mode = Nval[Nmode];
+    }
+  }
+  mode = Nmode * dx + min;
+  free (Nval);
+
+skip:
+  if (!Quiet) {
+    fprintf (stderr, "mean: %g, stdev: %g, min: %g, max: %g, median: %g, mode: %g, Npts: %d\n", 
+	     mean, stdev, min, max, median, mode, N);
+  }
+
+  set_variable ("MIN",      min);
+  set_variable ("MAX",      max);
+  set_variable ("MEDIAN",   median);
+  set_variable ("MEAN",     mean);
+  set_variable ("MODE",     mode);
+  set_variable ("TOTAL",    sum);
+  set_int_variable ("NPIX", N);
+  set_variable ("SIGMA",    stdev);
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/wd.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/wd.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/wd.c	(revision 3338)
@@ -0,0 +1,179 @@
+# include "data.h"
+
+int wd (int argc, char **argv) {
+  
+  int N, Extend;
+  int newUnsign, newBitpix, newScale, newZero;
+  int outUnsign, outBitpix;
+  double outScale, outZero;
+  Header temp_header;
+  Matrix temp_matrix;
+  Buffer *buf;
+
+  Extend  = FALSE;
+  if ((N = get_argument (argc, argv, "-extend"))) {
+    remove_argument (N, &argc, argv);
+    Extend  = TRUE;
+  }
+
+  newZero  = FALSE;
+  if ((N = get_argument (argc, argv, "-bzero"))) {
+    remove_argument (N, &argc, argv);
+    outZero  = atof(argv[N]);
+    newZero  = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  newScale = FALSE;
+  if ((N = get_argument (argc, argv, "-bscale"))) {
+    remove_argument (N, &argc, argv);
+    outScale = atof(argv[N]);
+    newScale = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  newBitpix = FALSE;
+  if ((N = get_argument (argc, argv, "-bitpix"))) {
+    remove_argument (N, &argc, argv);
+    outBitpix = atof(argv[N]);
+    newBitpix = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  newUnsign = FALSE;
+  if ((N = get_argument (argc, argv, "-unsign"))) {
+    remove_argument (N, &argc, argv);
+    outUnsign = -1;
+    if (!strcasecmp (argv[N], "t") || !strcasecmp (argv[N], "true")) outUnsign = TRUE;
+    if (!strcasecmp (argv[N], "f") || !strcasecmp (argv[N], "false")) outUnsign = FALSE;
+    if (outUnsign == -1) {
+      fprintf (stderr, "-unsign options: t, f, true, false\n");
+      return (FALSE);
+    }
+    newUnsign = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: wd <buffer> <filename> [-bitpix N] [-bscale X] [-bzero X] [-newplane]\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  if (!newBitpix) outBitpix = buf[0].bitpix;
+  if (!newScale) outScale = buf[0].bscale;
+  if (!newZero) outZero = buf[0].bzero;
+  if (!newUnsign) outUnsign = buf[0].unsign;
+
+  /* Convert the buffer from (float) to correct format */
+  /* save the (float) version, write out a temporary buffer */
+  temp_matrix = buf[0].matrix;
+  ALLOCATE (temp_matrix.buffer, char, MAX(1, temp_matrix.size));
+  memcpy (temp_matrix.buffer, buf[0].matrix.buffer, temp_matrix.size);
+  temp_header = buf[0].header;
+  ALLOCATE (temp_header.buffer, char, MAX(1, temp_header.size));
+  memcpy (temp_header.buffer, buf[0].header.buffer, temp_header.size);
+
+  if (temp_header.Naxes) fits_convert_format (&temp_header, &temp_matrix, outBitpix, outScale, outZero, outUnsign);
+
+  if (Extend) {
+    Header Xhead;
+    FILE *f;
+    int status, Nextend;
+
+    /* assume failure means non-existent file */
+    if (!fits_read_header (argv[2], &Xhead)) {
+
+      Xhead.simple = TRUE;
+      Xhead.bitpix = 16;
+      Xhead.Naxes = 0;
+      
+      Xhead.extend = TRUE;
+      Xhead.bscale = 1.0;
+      Xhead.bzero  = 0.0;
+      Xhead.unsign = FALSE;
+      
+      fits_create_header (&Xhead);
+      fits_modify (&Xhead, "NEXTEND", "%d", 1, 0);
+      f = fopen (argv[2], "w");
+      fclose (f);
+    }
+
+    fits_modify (&Xhead, "EXTEND", "%t", 1, TRUE);
+
+    Nextend = 0;
+    fits_scan (&Xhead, "NEXTEND", "%d", 1, &Nextend);
+    Nextend ++;
+    fits_modify (&Xhead, "NEXTEND", "%d", 1, Nextend);
+
+    /* write the main header to the start of the file */
+    f = fopen (argv[2], "r+");
+    if (f == NULL) {
+      fprintf (stderr, "failed to write file\n");
+      status = FALSE;
+      goto done1;
+    }
+    
+    /* position to begining of file to write header */
+    fseek (f, 0, SEEK_SET);
+    status = fwrite (Xhead.buffer, 1, Xhead.size, f);
+    if (status != Xhead.size) {
+      fprintf (stderr, "ERROR: failed writing data to image header\n");
+      status = FALSE;
+      goto done1;
+    }
+    
+    /* fix up header */
+    {
+      static char simple[] = "XTENSION= 'IMAGE  '            / Image extension";
+      int Ns, No;
+      Ns = strlen (simple);
+      No = 80 - Ns;
+      strncpy (temp_header.buffer, simple, Ns);
+      memset (&temp_header.buffer[Ns], ' ', No);
+    }
+
+    /* position to end of file to write new extend */
+    fseek (f, 0, SEEK_END);
+    status = fwrite (temp_header.buffer, 1, temp_header.size, f);
+    fclose (f);
+    if (status != temp_header.size) {
+      fprintf (stderr, "failed to write file\n");
+      status = FALSE;
+      goto done1;
+    }
+    /* write the matrix buffer (automatically goes to end of file */
+    if (!fits_write_matrix (argv[2], &temp_matrix)) {
+      fprintf (stderr, "failed to write file\n");
+      status = FALSE;
+      goto done1;
+    }
+    status = TRUE;
+  done1:
+    fits_free_header (&Xhead);
+    fits_free_header (&temp_header);
+    fits_free_matrix (&temp_matrix);
+    return (status);
+  }
+  
+  /* the actual write-to-disk goes here */
+  if (!fits_write_header (argv[2], &temp_header)) {
+    fprintf (stderr, "failed to write header\n");
+    fits_free_header (&temp_header);
+    fits_free_matrix (&temp_matrix);
+    return (FALSE);
+  }
+  
+  if (!fits_write_matrix (argv[2], &temp_matrix)) {
+    fprintf (stderr, "failed to write matrix\n");
+    fits_free_header (&temp_header);
+    fits_free_matrix (&temp_matrix);
+    return (FALSE);
+  }
+
+  fits_free_header (&temp_header);
+  fits_free_matrix (&temp_matrix);
+  
+  return (TRUE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/write_vectors.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/write_vectors.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/write_vectors.c	(revision 3338)
@@ -0,0 +1,139 @@
+# include "data.h"
+
+int write_vectors (int argc, char **argv) {
+  
+  int i, j, Nvec, Ne, N;
+  FILE *f;
+  char **fmtlist, *fmttype;
+  char *p0, *p1, *p2, *format;
+  Vector **vec;
+
+  /* look for format option */
+  format = (char *) NULL;
+  if ((N = get_argument (argc, argv, "-f"))) {
+    remove_argument (N, &argc, argv);
+    format = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc < 3) {
+    fprintf (stderr, "USAGE: write [-f \"format\"] file vector vector ...\n");
+    return (FALSE);
+  }
+
+  /* open file for outuput */
+  f = fopen (argv[1], "w");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "can't open file for write\n");
+    return (FALSE);
+  }
+
+  /* find number of output vectors */
+  Nvec = (argc - 2);
+  if (Nvec < 1) {
+      fprintf (stderr, "USAGE: write (file) vector vector ...\n");
+      fclose (f);
+      return (FALSE);
+  }
+  ALLOCATE (vec, Vector *, Nvec);
+
+  /* select/check vectors from list */
+  for (i = 0; i < Nvec; i++) {
+    if ((vec[i] = SelectVector (argv[i + 2], OLDVECTOR, FALSE)) == NULL) {
+      fprintf (stderr, "USAGE: write (file) vector vector ...\n");
+      free (vec);
+      fclose (f);
+      return (FALSE);    
+    }
+  }
+  
+  /* select vector lengths */
+  Ne = vec[0][0].Nelements;
+  for (i = 0; i < Nvec; i++) {
+    if (vec[0][0].Nelements != Ne) {
+      fprintf (stderr, "error: vectors must all be the same size\n");
+      free (vec);
+      fclose (f);
+      return (FALSE);    
+    }
+  }
+
+  /* default output format */
+  if (format == (char *) NULL) {
+    for (i = 0; i < vec[0][0].Nelements; i++) {
+      for (j = 0; j < Nvec; j++) {
+	fprintf (f, "%.10g ", vec[j][0].elements[i]);
+      }
+      fprintf (f, "\n");
+    } 
+    fclose (f);
+    free (vec);
+    return (TRUE);
+  }
+
+  /* construct an array of format strings */
+  ALLOCATE (fmttype, char, Nvec);
+  ALLOCATE (fmtlist, char *, Nvec);
+  for (i = 0; i < Nvec; i++) {
+    ALLOCATE (fmtlist[i], char, 1024);
+    bzero (fmtlist[i], 1024);
+  }
+
+  p0 = format;
+  for (j = 0; j < Nvec; j++) {
+    /* find this format character */
+    p1 = strchr (p0, '%');
+    if (p1 == (char *) NULL) {
+      fprintf (stderr, "mismatch between format and values\n");
+      free (fmttype);
+      for (i = 0; i < Nvec; i++) free (fmtlist[i]);
+      free (fmtlist);
+      free (format);
+      fclose (f);
+      return (FALSE);
+    }
+    
+    /* identify type (%NNNNd %NNNNf) */
+    for (p2 = p1 + 1; (*p2 == '.') || (*p2 == '-') || (*p2 == '+') || (*p2 == ' ') || isdigit(*p2); p2++);
+    strncpy (fmtlist[j], p0, p2 - p0 + 1);
+    switch (*p2) {
+      case 'e':
+      case 'f':
+	fmttype[j] = 'f';
+	break;
+      case 'd':
+      case 'c':
+      case 'x':
+	fmttype[j] = 'd';
+	break;
+      default:
+	fprintf (stderr, "syntax error in format (only e,f,d,c,x allowed)\n");
+	return (FALSE);
+    }
+    p0 = p2 + 1;
+  }
+  strcat (fmtlist[Nvec-1], p0);
+  
+  for (i = 0; i < vec[0][0].Nelements; i++) {
+    for (j = 0; j < Nvec; j++) {
+      if (fmttype[j] == 'd') {
+	fprintf (f, fmtlist[j], (int)(vec[j][0].elements[i]));
+      } 
+      if (fmttype[j] == 'f') {
+	fprintf (f, fmtlist[j], (float)(vec[j][0].elements[i]));
+      } 
+    }
+    fprintf (f, "\n");
+  }
+  fclose (f);
+
+  free (fmttype);
+  for (i = 0; i < Nvec; i++) free (fmtlist[i]);
+  free (fmtlist);
+  free (format);
+  
+  return (TRUE);
+
+}
+
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/zap.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/zap.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/zap.c	(revision 3338)
@@ -0,0 +1,43 @@
+# include "data.h"
+
+int zap (int argc, char **argv) {
+
+  int i, j, N;
+  int sx, sy, nx, ny;
+  float *V, value;
+  Buffer *buf;
+
+  value = 0;
+  if ((N = get_argument (argc, argv, "-v"))) {
+    remove_argument (N, &argc, argv);
+    value  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 6) {
+    fprintf (stderr, "USAGE: zap <buffer> sx sy nx ny [-v value]\n");
+    return (FALSE);
+  }
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  sx = atof (argv[2]);
+  sy = atof (argv[3]);
+  nx = atof (argv[4]);
+  ny = atof (argv[5]);
+
+  if (sx < 0) goto error;
+  if (sy < 0) goto error;
+  if (sx + nx > buf[0].matrix.Naxis[0]) goto error;
+  if (sy + ny > buf[0].matrix.Naxis[1]) goto error;
+
+  for (j = sy; j < sy + ny; j++) {
+    V = (float *)(buf[0].matrix.buffer) + j*buf[0].matrix.Naxis[0] + sx; 
+    for (i = 0; i < nx; i++, V++) *V = value;
+  }
+  return (TRUE);
+
+ error:
+  fprintf (stderr, "region out of range\n");
+  return (FALSE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/cmd.data/zplot.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/cmd.data/zplot.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/cmd.data/zplot.c	(revision 3338)
@@ -0,0 +1,65 @@
+# include "data.h"
+
+int zplot (int argc, char **argv) {
+  
+  int i, N, Npts, Ngraph;
+  float *in, *out;
+  double min, range;
+  Graphdata graphmode;
+  Vector *xvec, *yvec, *zvec, Zvec;
+
+  Ngraph = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Ngraph = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetGraph (&graphmode, NULL, &Ngraph)) return (FALSE);
+
+  if (argc != 6) {
+    fprintf (stderr, "USAGE: zplot <x> <y> <z> min max\n");
+    return (FALSE);
+  }
+
+  min = atof(argv[4]);
+  range = atof(argv[5]) - min;
+
+  /* find vectors */
+  if ((xvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yvec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((zvec = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if (xvec[0].Nelements != yvec[0].Nelements) {
+    fprintf (stderr, "vectors %s and %s not the same length\n", argv[1], argv[2]);
+    return (FALSE);
+  }
+  if (xvec[0].Nelements != zvec[0].Nelements) {
+    fprintf (stderr, "vectors %s and %s not the same length\n", argv[1], argv[3]);
+    return (FALSE);
+  }
+  Zvec.Nelements = zvec[0].Nelements;
+  ALLOCATE (Zvec.elements, float, Zvec.Nelements);
+ 
+  in = zvec[0].elements;
+  out = Zvec.elements;
+  for (i = 0; i < Zvec.Nelements; i++, in++, out++) {
+    *out = MIN (1.0, MAX (0.01, (*in - min) / range));
+  }
+
+  /* point size determined by Zvec */
+  graphmode.style = 2; /* plot points */
+  graphmode.size = -1; /* point size determined by Zvec */
+  graphmode.etype = 0; /* no errorbars */
+  Npts = xvec[0].Nelements;
+  PrepPlotting (Npts, &graphmode);
+
+  PlotVector (Npts, xvec[0].elements);
+  PlotVector (Npts, yvec[0].elements);
+  PlotVector (Npts, Zvec.elements);
+
+  free (Zvec.elements);
+
+  return (TRUE);
+
+}
+
+
Index: /tags/opihi-2-1/Ohana/src/opihi/doc/Change.log
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/doc/Change.log	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/doc/Change.log	(revision 3338)
@@ -0,0 +1,34 @@
+
+opihi-2-1:
+  major reorg of imfit / added imfit functions
+  cleaned up get_argument calls so -Wall does not give errors
+  moved the 'elixir' command to dvo
+  tag added only to elixir implementations (mana + dvo)
+  dimm - need to coordinate with Olivier and Bernt
+  dvo2, pcontrol, pclient, sched - all under development
+
+2004.12.23
+
+  Moved typename/modename funcs to libohana.  this was motivated by
+  imregister, which would not compile cleanly using the old method.
+
+  Added library dependencies to the makefiles. previously, mana (etc)
+  would not re-build if the library was modified.
+
+  Fixed incorrect exit on non-tty.  this kept perl scripts with the
+  call "|mana" from running.
+
+  Fixed dvomath for strings.  since we moved to dvomath everywhere,
+  this broke complex string conditionals: (($a == hi) && ($b == lo)).
+  I added string types to the math functions, and tests to see if the
+  stack has strings which cannot be resolved as a vector or matrix.  
+
+2004.12.10:
+
+  fixed problem in lib.data/PlotVectors.c and lib.data/graphtools.c
+  that broke plotting for data with very large or small exponents (|x|
+  < 1e-12, |x| > 1e12).  also fixed cmd.data/vstats.c with same
+  problem.
+	
+opihi-2-0:
+  import to CVS 2004.12.03
Index: /tags/opihi-2-1/Ohana/src/opihi/doc/changes.txt
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/doc/changes.txt	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/doc/changes.txt	(revision 3338)
@@ -0,0 +1,54 @@
+Oct 19  2003 misc/startup.c              . minor changes, DONE
+Oct 19  2003 misc/conversions.c		 . minor changes, DONE
+Oct 19  2003 misc/match_image.c		 . copied to dvo
+Apr 19 17:41 misc/ConfigInit.c		 . minor changes, kept dvo version
+May  6 16:13 misc/ImageOps.c		 . minor changes, DONE
+May 12 09:00 misc/photometry.c           . major changes : DONE
+
+Oct 15  2003 user/badimages.c            . no change
+Oct 15  2003 user/imlist.c		 . no change
+Oct 15  2003 user/precess.c		 . dvo version ok
+Oct 15  2003 user/delete.c		 . dvo version ok
+
+May  6 15:25 user/extract.c		 . mostly deprecated (transfer USNO/HST/etc versions)
+May 10 21:13 user/mextract.c		 . used status version + vectors
+May 11 12:06 user/avextract.c		 . used status version + vectors
+Oct 27  2003 user/imextract.c		 . used status version + vectors
+
+May 12 09:06 user/dmags.c		 . used status version + vectors
+May 12 09:12 user/dmagmeas.c		 . used status version + vectors
+May 12 09:13 user/dmagaves.c		 . used status version + vectors
+May 11 16:18 user/ddmags.c		 . used status version + vectors
+
+May  2 11:14 user/calextract.c		 . used status version + vectors 
+May  3 20:08 user/calmextract.c		 . used status version + vectors
+Oct 19  2003 user/cmd.c			 . fixed (photcodes vs vectors)
+Oct 19  2003 user/ccd.c			 . used status version + vectors
+
+Apr 19 19:48 user/gimages.c		 . minor changes, fixed
+Nov 14  2003 user/gstar.c		 . minor changes, fixed
+May  3 20:49 user/gtypes.c		 . dvo version ok
+May  6 09:37 user/images.c		 . copied to dvo
+May  3 20:49 user/imdata.c		 . dvo version ok
+May  3 20:50 user/imphot.c		 . dvo version ok
+May  3 20:51 user/imrough.c		 . dvo version ok
+May  3 20:51 user/imsearch.c		 . dvo version ok
+Nov  5  2003 user/photcodes.c		 . copied to dvo
+Nov  1  2003 user/pmeasure.c		 . dvo version ok
+Mar  3 11:25 user/showtile.c		 . copied to dvo
+Nov  1  2003 user/subpix.c		 . copied to dvo
+Oct 30  2003 user/dmt.c			 . minor changes & photcodes
+Nov  1  2003 user/lcurve.c		 . minor changes & photcodes
+
+May 18 09:50 user/cgrid.c		 . copied to dvo
+
+Nov  1  2003 user/abszero.c		 . deprecated
+May  3 20:51 user/zeropts.c		 . deprecated
+Nov 13  2003 user/resid.c		 . deprecated
+Nov 13  2003 user/photresid.c		 . deprecated
+
+May  2 11:20 user/cals.c		 . deprecated?
+May  3 20:37 user/ddmagextract.c	 . deprecated?
+May  3 20:11 user/dmagextract.c		 . deprecated?
+Oct 19  2003 user/ccdextract.c		 . deprecated?
+Oct 19  2003 user/cmdextract.c		 . deprecated?
Index: /tags/opihi-2-1/Ohana/src/opihi/doc/command.txt
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/doc/command.txt	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/doc/command.txt	(revision 3338)
@@ -0,0 +1,24 @@
+
+readline: allocates a line and returns it; empty lines return NULL
+
+expand_vars: (recursively) expand expressions of the form $X
+	     frees the input line, allocates a new one.
+	     returns NULL on error (including NULL input)
+
+expand_vectors: expand expressions of the form $X
+	     frees the input line, allocates a new one.
+	     returns NULL on error (including NULL input)
+
+parse performs math expansion on the line, returning a new line (old one is freed)
+
+
+in newmath:
+
+isolate_elements converts argc,argv to cstack,Ncstack (argc,argv NOT freed)
+convert_to_RPN takes cstack,Nstack and converts to stack,Nstack; input cstack,Ncstack are freed
+check_stack puts pointers to data types on stack, no data allocated
+evaluate_stack 
+
+
+command parses a single input line (line) and expands
+
Index: /tags/opihi-2-1/Ohana/src/opihi/doc/dvo-2.txt
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/doc/dvo-2.txt	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/doc/dvo-2.txt	(revision 3338)
@@ -0,0 +1,28 @@
+
+Region APIs
+
+Region table is a FITS table
+
+- load region data from FITS table
+- save region data to FITS table
+
+/* find region which overlaps c at given depth (-1 : max depth) */
+SkyRegion *SkyFindPoint (SkyRegion *db, SkyCoord c, int depth);
+
+/* find regions at all levels which overlap c */
+SkyRegion **SkyFindLevels (SkyRegion *db, SkyCoord c, int *Nregion);
+
+/* find regions contained within rectangular region  c1 - c2 */
+SkyRegion **SkyFindArea (SkyRegion *db, SkyCoord c1, SkyCoord c2, *nlist);
+
+- I have created table generation functions which construct a
+  collection of table entries starting with the full sky and iterating
+  down N levels.  The function also fills out the names at the
+  appropriate levels.  This is currently ok up to level 6, but runs
+  out of memory at level 7.  This should not be the case, so I suspect
+  I'm not free'ing some memory.  
+
+- I need to create a function to take the GSC table list and construct
+  a set of SkyRegions that match the layout, starting with the full
+  sky and iterating down to and past the GSC tables.  
+
Index: /tags/opihi-2-1/Ohana/src/opihi/doc/dvo.html
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/doc/dvo.html	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/doc/dvo.html	(revision 3338)
@@ -0,0 +1,288 @@
+
+<h2> PA data requirements </h2>
+
+Counting the total size of the PA database for the PA survey, with
+roughly 20 pointings per location and 30 second exposures.  The depth
+for PA survey in P2 @ 20 \sigma is 21.3 (r).  Each detection uses 100
+bytes (<b>we need to flesh this out with more realistic numbers from
+our table of parameters</b>).  The access speed to a RAID disk is 100
+MB/sec.  The number density of stars in i' in the plane may be higher,
+but we reach saturation at ~1.4e6 detections per deg^2 (one object per
+100 pixels).  This is a factor of 5 higher than the raw numbers.
+
+<h3> stellar counts for PS-1 </h3>
+latitude                 90          30         0
+density (deg^{-2})      5e3         3e4       3e5
+N_det (FPA^{-1})        4e4         2e5       2e6
+Sum N_det (FPA^{-1})    8e5         4e6       4e7
+Sum Nbyte (FPA^{-1})  80 MB      400 MB      4 GB
+Nsec for 1 channel      0.8           4        40
+Nchannel for 2 sec        1           2        20
+
+The total number of bytes for the PA survey for P2 detections is ~12
+TB (30000 x 400MB).  The density of detections per FPA from P4 delta
+is roughly the same as P2 at 0 deg (2e5 vs 3e5 det deg^{-2}).  The
+total number of bytes needed to store the P4 Delta detections from all
+of PS-1 is 
+
+Fields in the plane will take longer to process
+
+<h2> addstar interactions for a distributed db </h2>
+
+addstar.client <---> addstar.daemon
+
+The sky is divided into hierarchical regions, each broken into smaller
+subregions.  Both the image and object tables are divided into
+subtables by region on the sky.  The density of image tables is
+smaller than the density of object tables.  A top-level table defines
+the distribution of the lower-level tables by defining the hierarchy
+of regions and subregions.  Each entry in this table contains:
+
+region ID  - an identifier for the subregion
+RAs, RAe   - RA range of region
+DECs, DECe - DEC range of region
+parent ID  - ID of the region which contains this region (NULL for allsky)
+Nchild     - number of children
+offset     - starting entry of first child
+images     - is this region used for images? (if FALSE, down one layer)
+objects    - is this region used for objects? (if FALSE, down one layer)
+
+use the machine name / file name as the indicator in the images and
+objects entries?
+
+The table defines the relationship between the subregions and provides
+a mechanism to find the subregions appropriate to a given sky
+location.  It also specified for a given depth if that depth is used
+for the image and/or the object table.  The image tables contain
+images whose reference coordinate is located in the given region.
+Other regions which the image overlaps contain entries in the image
+reference table which specify the primary image table in which they
+are stored.  
+
+The details of the sky region definitions do not matter for the
+structure of the region table.  The data structures can handle any
+arrangement of tables which meets the basic requirements that the
+boundaries be lines of constant RA & DEC and that each level defines
+all regions which cover the entire sky.  One implementation is as
+follows and is easy to generate:  
+
+Start with the complete sky as a single region (RAs = 0, RAe = 360;
+DECs = -90, DECe = 90).  To create a new region, always subdivide the
+region with the largest area (roughly (RAe - RAs)*(DECe -
+DECs)*cos((DECs + DECe)/2)).  To subdivide a region, define two
+possible subdivisions: RA = 0.5*(RAs + RAe) (which becomes RAs and RAe
+for the two new regions) or DEC = 0.5*(DECs + DECe).  Determine the
+length of these dividing lines (S1 = (DECe - DECs); S2 = (RAe - RAs) /
+cos (DEC)).  Choose the shorter of these two lines, and subdivide the
+region on that basis.  
+
+The number of subregions increases by a factor of 8 for
+each new level.  Approximate table size: Need at least 200,000
+lowest-level regions, leads to 2^18 regions (256k) in lowest-level.
+Total table size is roughly 300k rows.  Each row is roughly 32 bytes,
+for a table size of 10MB.
+
+There is one addstar.daemon per DVO server.  The addstar.daemons are
+responsible for serving the objects and images from the tables they
+contain.  
+
+addstar.client steps to load a new set of objects:
+- load region table (defined in config db)
+- find overlapping object regions
+- find overlapping image regions
+- identify primary image region
+- send image data to node for primary image region 
+- send image reference to nodes for secondary image regions
+- send detection data (with image ID) to corresponding object region nodes
+
+addstar.daemon responsibilities:
+- receive image data -> add to primary image table
+- receive detection data -> add to local region file
+- request objects in overlap regions from neighbor daemons
+- send detections to neighbor daemons if associated with object over
+  border
+- construct / update objects on basis of detections
+
+in DVO 1.0, addstar updates objects on every upload of the
+detections.  In fact, the construction of the objects need not be
+performed every time detections are added.  Do we need to construct
+objects for all single detections?  The current process is:
+
+- get list of new detections (from incoming image)
+- match each detection with each object
+- update object parameters
+
+another option:
+
+step 1:
+ - get list of new detections
+ - add to new.detection table
+
+step 2:
+ - match detections to object table
+ - update object parameters
+
+third option
+step 1:
+ - add new detections to new table
+
+step 2:
+ - compare detections to orphans 
+ - if found, promote to object
+ - if not, test against objects
+ - if found update object
+ - if not add to orphans
+
+<h2> DVO image organization </h2>
+
+DVO 1.0 uses a single image table to store all image data.  In this
+table, each image is a chip; that is, each entry represents a single
+astrometric system.  In principal, there is no reason this could not
+be an entire mosaic or (in the case of Pan-STARRS) an individual
+Cell. It is usually necessary to be able to define the relationship
+between the different detector / focal plane / etc coordinate
+systems.  If the data entity is a full mosaic, then it will be
+necessary to look up the chip (and cell) transformations.  If the data
+entity is the cell, the reverse conversions will be needed.  
+
+The image table should be distributed to multiple files to speed up
+the access.  One option is to do this by coordinate region.  In the
+plan for DVO 2.0, there will be a table of the region hierarchy for
+the object tables, and the image tables could be distibuted similarly,
+though with a different density.  In PS-1, for example, there will be
+around 250,000 images (FPAs).  If we store OTAs (chips) as the data
+entity in the image table, then we will have in the vicinity of 16M
+rows.  If each contains 256 bytes, the total data volume in the image
+table will be about 4 GB.  If we want to have typical access times to
+any image of 1 second, and we need to scan through the entire table to
+get to the image, then we will need to distribute the data across 40
+tables (note that they need not be distributed by machine).  If each
+table represents a region on the sky, this translates to 1000 - 500
+square degrees per table.  
+
+Some additional aspects are interesting.  First, the
+spatially-distributed tables correspond to specific regions on the
+sky, likely to be bounded by lines of constant RA and DEC, or
+something equivalent.  However, an image cannot be guaranteed to land
+in only one of these regions.  To mitigate this, each image (chip or
+FPA or whatever the data unit is) should have a single defined
+position with which the general location is identified and the choice
+of region is made.  In addition, there should be a table associated
+with each region which defines images in other tables (regions) which
+overlap the given region.  In general, these overlap tables will
+contain only a small fraction of the image entries (regions are much
+large than images) and they need only identify the image ID and the
+corresponding table.
+
+An additional accelerator table would include all images, their
+reference time and their reference coordinate, sorted by time, with an
+index for the name.
+
+The end result is three types of tables: images.db, overlaps.db,
+imagetimes.db.  images.db contains the bulk of the information (256
+byte / row).  overlaps.db contains only the image ID and the the RA
+and DEC of the reference position (not the actual table because that
+may change). imagetimes.db contains only image ID (8 byte? 16 byte?),
+time, RA, DEC, and and index.  This is a total of about 40 bytes per
+image, for a total of roughly 700 MB at the end of PS-1.
+
+<h3> Examples queries </h3>
+
+<h4> find a single, specific image by ID </h4>
+<ul>
+<li> open imagetimes.db
+<li> load block marker (ID,block; every 10000 blocks)
+<li> find appropriate block
+<li> load block
+<li> find appropriate image entry
+<li> determine appropriate image.db table (region)
+<li> open image.db 
+<li> load block marker (ra,block; every 10000 blocks)
+<li> find appropriate block
+<li> load block
+<li> find appropriate image entry
+</ul>
+
+<h4> find a single, specific image by ID </h4>
+<ul>
+<li> open imagetimes.db
+<li> load block marker (ID,block; every 10000 blocks)
+<li> find appropriate block
+<li> load block
+<li> find appropriate image entry
+<li> determine appropriate image.db table (region)
+<li> open image.db 
+<li> load block marker (ra,block; every 10000 blocks)
+<li> find appropriate block
+<li> load block
+<li> find appropriate image entry
+</ul>
+
+<h3> dvo / object catalog scaling to massive collections </h3>
+
+DVO divides the sky into tables which represent specific areas on the
+sky.  Currently, these are pre-defined to match the HST GSC regions,
+roughly 1 - 4 square degree patches with fixed RA and DEC boundaries.
+A future extension will provide a mechanism to increaese or decrease
+the table density on the fly.
+
+The likely data rate under Pan-STARRS PS-1 is in the vicinity of 5 x
+10<sup>5</sup> stars per square degree.  The density is likely to vary
+by a factor of 30 for the bulk of the sky.  The Pan-STARRS camera
+consists of 1.44 x 10<sup>8</sup> pixels.  The confusion limit will
+likely be reached when each object encompases 25 pixels, resulting in
+a saturation of 6 x 10<sup>6</sup> stars per square degree.  The
+Pan-STARRS camera covers a total of 7.45 square degrees, and the
+expected exposure rate is roughly 1 per minute on average.  This
+amounts to a total of 3000 square degrees covered per night of
+observation, or a total of 1.5 x 10<sup>9</sup>detections per night,
+or a total of 5 x 10<sup>11</sup> over the course of one year.  Given
+this total number of detections, and the total sky coverage of 30,000
+square degrees, the average number of detections per square degree
+will be in the vicinity of 1.7 x 10<sup>7</sup>
+
+There are two main limitations to the DVO object storage model.
+First, the large data volume translates to a finite time to read the
+data from the disk.  Second, the large number of objects limits the
+rate at which new detections may be associated with the existing
+objects.  The first of these has generally proven to be the more
+significant limitation in applications to date.  We can easily
+calculate the time needed to load the data relevant to a random image
+pointing, as well as the maximum time based on the range of data
+volumes.  A necessary assumption in this calculation is the number of
+bytes used per detection.  We generously assume 100 bytes per
+detection, 3 times the existing data structures used by DVO.  
+
+Based on the numbers above, the total data volume represented by a
+year of observations is 50 TB, assuming the detection component
+dominates the total.  The average camera footprint translates to
+roughly 13 GB worth of detections.  Since each footprint is performed
+once per minute, it will be necessary to perform the read and write in
+each 10 seconds.  This in turn corresponds to 1.3 GB per second for
+the read and write portions.  With typical local hard-drive access
+speeds for RAIDs of 100 MB/sec, the data will need to be distributed
+across more than the machines in order to achieve these average
+rates.  
+
+The existing DVO system expects only one object table to be open at a
+time.  In addition, access to the tables is not controlled through
+separate machines.  Rather, a single collection of tables is expected
+and all queries are performed independently.  In order to handle the
+above load with the DVO software, the following changes will be
+needed:
+
+<ul>
+<li> tables must be distributed across multiple machines.  This is
+mandatory regardless of the underlying database engine based on the
+data I/O analysis above.
+
+<li> the 'addstar' front end needs to send the data for each table to
+the database backends on each of the corresponding machines.  
+
+<li> the addstar update for a single image can be done in series as is
+currently done.
+
+<li> write locking should be done on the tables rather than on the
+database as a whole (currently using the image table). 
+</ul>
+
Index: /tags/opihi-2-1/Ohana/src/opihi/doc/libs.txt
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/doc/libs.txt	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/doc/libs.txt	(revision 3338)
@@ -0,0 +1,17 @@
+
+I have divided the (non-user) functions into classes. 
+
+- conversions can be placed in a single library
+
+- graph and image (tv) functions can be placed in a library
+
+- the opihi shell functions can go into a third library
+
+- the dvo-related functions can go into a fourth
+
+- i need to clean up the mana and dimm misc functions, and put them in libraries 
+
+- the user functions also need to go into some libraries.
+
+- how do I have the library add its functions to the command list?
+
Index: /tags/opihi-2-1/Ohana/src/opihi/doc/mana.updates.txt
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/doc/mana.updates.txt	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/doc/mana.updates.txt	(revision 3338)
@@ -0,0 +1,135 @@
+
+mana functions which existed in DVO from status:
+
+applyfit2d.c         : OK - vector changes only
+applyfit.c	     : OK - vector changes only
+box.c		     : OK - no diff
+center.c	     : OK - no diff
+clear.c		     : OK - no diff
+concat.c	     : OK - vector changes only
+contour.c	     : mana version writes to Ximage, dvo version writes to vectors.  mana/contour -> tvcontour.c
+create.c	     : OK - buffer changes only
+cursor.c	     : OK - buffer & minor changes only
+delete.c	     : OK - buffer & minor changes only
+device.c	     : OK - no diff
+extract.c	     : mana extract operates on buffers / status extract is db operation
+file.c		     : OK - no diff
+fit2d.c		     : OK - vector changes only
+fit.c		     : OK - added weights and parameter errors from mana version
+gaussj.c	     : OK - buffer changes only
+grid.c		     : mana version write to Ximage, dvo version writes to Xgraph. mana/grid -> tvgrid
+histogram.c	     : OK - vector changes only
+interpolate.c	     : OK - vector changes only
+jpeg.c		     : OK - no diff
+labels.c	     : OK - no diff
+limits.c	     : OK - vector & minor changes only
+list_buffers.c	     : OK - buffer changes only
+list_vectors.c	     : OK - vector & minor changes only
+mcreate.c	     : OK - buffer changes only
+mget.c		     : OK - buffer changes only
+mset.c		     : OK - buffer changes only
+ps.c		     : OK - no diff
+rd.c		     : OK - buffer changes only
+read_vectors.c	     : OK - included reading vectors from fits tables
+region.c	     : OK - no diff
+resize.c	     : OK - no diff
+section.c	     : OK - no diff
+set.c		     : OK - mana version out of date
+sprintf.c	     : OK - no diff
+stats.c		     : OK - included threshold comparison for IgnoreValue and min == max test
+style.c		     : OK - mana version out of date
+subset.c	     : OK - mana version out of date
+textline.c	     : OK - no diff
+tv.c		     : OK - buffer changes only
+uniq.c		     : OK - vector changes only
+vcontour.c	     : mana/vcontour equiv to dvo/contour
+vstat.c		     : OK - vector changes only
+wd.c		     : OK - buffer changes only
+write_vectors.c	     : OK - vector changes only
+zap.c		     : OK - buffer changes only
+zplot.c		     : OK - vector changes only
+
+mana functions not previously in DVO from status:
+
+accum.c			: fix vectors
+adc.c			: keep - specialized
+biassub.c		: fix buffers and vectors
+clip.c			: fix buffers and vectors
+cmpload.c		: keep
+coords.c		: fix buffers and vectors
+cut.c			: fix buffers and vectors
+cval.c			: ? superceeded by 'star'?
+demux.c			: keep - specialized
+dimendown.c		: fix buffers and vectors
+dimenup.c		: fix buffers and vectors
+drawline.c		: keep - unused
+drizzle.c		: fix buffers and vectors
+erase.c			: keep
+fft1d.c			: fix buffers and vectors
+fft2d.c			: fix buffers and vectors
+flux.c			: fix buffers and vectors
+gauss.c			: fix buffers and vectors
+gaussfit.c		: ? to correct?
+getchr.c		: keep
+getvel.c		: 
+imfit.c			: 
+imhist.c		: 
+integrate.c		: 
+kern.c			: 
+keyword.c		: 
+line.c			: 
+list_header.c		: 
+load.c			: 
+medacc.c		: 
+medianmap.c		: 
+memory.c		: 
+minterpolate.c		: 
+mkgauss.c		: 
+multifit.c		: 
+nextract.c		: 
+objload.c		: 
+outline2.c		: ??
+outline.c		: ??
+pause.c			: 
+peak.c			: 
+point.c			: 
+polar.c			: 
+profile.c		: 
+rdseg.c			: 
+rebin.c			: 
+roll.c			: 
+rotate.c		: 
+rotcurve.c		: 
+save.c			: 
+scale.c			: 
+select.c		: 
+sexigesimal.c		: 
+shape.c			: 
+shift.c			: 
+simsignal.c		: 
+sort_vectors.c		: 
+spec.c			: 
+spline_apply.c		: 
+spline_construct.c	: 
+star.c			: 
+strchr.c		: 
+strlen.c		: 
+substr.c		: 
+svd.c			: 
+swapbytes.c		: 
+testfit.c		: 
+transform.c		: 
+unsign.c		: 
+usleep.c		: 
+vbin.c			: 
+vclip.c			: 
+
+outdated or unneeded functions:
+
+dummy.c
+downdimen.c
+buftovec.c
+kernel.c
+updimen.c		: 
+stupidtest.c		: 
+plot2.c			: fixed GetColor in dvo/plot.c
Index: /tags/opihi-2-1/Ohana/src/opihi/doc/notes.dvo-data.html
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/doc/notes.dvo-data.html	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/doc/notes.dvo-data.html	(revision 3338)
@@ -0,0 +1,166 @@
+
+<h2> data structures in DVO </h2>
+
+DVO uses several data structures, defined in <tt>loneos.h</tt> to
+represent data in the database tables.  This document attempts to
+describe the actual usage, some of which may disagree with the comment
+entries in <tt>loneos.h</tt>.
+
+<b> Image </b>
+<table> 
+<tr><th> name               </th><th> type           </th><th> value                     </th><th> units              </th>
+<tr><td> coords             </td><td> Coords         </td><td> astrometry                </td><td>                    </td>
+<tr><td> tzero              </td><td> unsigned int   </td><td> readout time row 0        </td><td> unix time          </td>
+<tr><td> nstar              </td><td> unsigned int   </td><td> number of stars on image  </td><td>                    </td>
+<tr><td> secz               </td><td> short int      </td><td> airmass                   </td><td> 1000*airmass       </td>
+<tr><td> NX                 </td><td> short int      </td><td> image size                </td><td> pixels             </td>
+<tr><td> NY                 </td><td> short int      </td><td> image size                </td><td> pixels             </td>
+<tr><td> apmifit            </td><td> short int      </td><td> aperture correction       </td><td> 1000*mag           </td>
+<tr><td> dapmifit           </td><td> short int      </td><td> error                     </td><td> 1000*mag           </td>
+<tr><td> source             </td><td> short int      </td><td> photcode                  </td><td>                    </td>
+<tr><td> Mcal               </td><td> short int      </td><td> relphot correciton        </td><td> 1000*mag           </td>
+<tr><td> dMcal              </td><td> short int      </td><td> error                     </td><td> 1000*mag           </td>
+<tr><td> Xm                 </td><td> short int      </td><td> image chi-square          </td><td> 100*log(chisq)     </td>
+<tr><td> name[32]           </td><td> char           </td><td> image name                </td><td>                    </td>
+<tr><td> detection_limit    </td><td> unsigned char  </td><td>                           </td><td> 10*mag             </td>
+<tr><td> saturation_limit   </td><td> unsigned char  </td><td>                           </td><td> 10*mag             </td>
+<tr><td> cerror             </td><td> unsigned char  </td><td> astrometric error         </td><td> 50*arcsec          </td>
+<tr><td> fwhm_x             </td><td> unsigned char  </td><td> average FWHM X            </td><td> 25*arcsec          </td>
+<tr><td> fwhm_y             </td><td> unsigned char  </td><td> average FWHM Y            </td><td> 25*arcsec          </td>
+<tr><td> trate              </td><td> unsigned char  </td><td> drift rate                </td><td> 10000*sec/pix      </td>
+<tr><td> exptime            </td><td> float          </td><td> exposure time             </td><td> seconds            </td>
+<tr><td> code               </td><td> char           </td><td> data flags                </td><td>                    </td>
+<tr><td> ccdnum             </td><td> unsigned char  </td><td> mosaic CCD ID number      </td><td>                    </td>
+<tr><td> dummy[20]          </td><td> char           </td><td> extra                     </td><td>                    </td>
+<tr><td> order              </td><td> short int      </td><td> order of Mcal function    </td><td>                    </td>
+<tr><td> Mx                 </td><td> short int      </td><td> Mcal polynomial term      </td><td>                    </td>
+<tr><td> My                 </td><td> short int      </td><td> Mcal polynomial term      </td><td>                    </td>
+<tr><td> Mxx                </td><td> short int      </td><td> Mcal polynomial term      </td><td>                    </td>
+<tr><td> Mxy                </td><td> short int      </td><td> Mcal polynomial term      </td><td>                    </td>
+<tr><td> Myy                </td><td> short int      </td><td> Mcal polynomial term      </td><td>                    </td>
+<tr><td> Mxxx               </td><td> short int      </td><td> Mcal polynomial term      </td><td>                    </td>
+<tr><td> Mxxy               </td><td> short int      </td><td> Mcal polynomial term      </td><td>                    </td>
+<tr><td> Mxyy               </td><td> short int      </td><td> Mcal polynomial term      </td><td>                    </td>
+<tr><td> Myyy               </td><td> short int      </td><td> Mcal polynomial term      </td><td>                    </td>
+<tr><td> Mxxxx              </td><td> short int      </td><td> Mcal polynomial term      </td><td>                    </td>
+<tr><td> Mxxxy              </td><td> short int      </td><td> Mcal polynomial term      </td><td>                    </td>
+<tr><td> Mxxyy              </td><td> short int      </td><td> Mcal polynomial term      </td><td>                    </td>
+<tr><td> Mxyyy              </td><td> short int      </td><td> Mcal polynomial term      </td><td>                    </td>
+<tr><td> Myyyy              </td><td> short int      </td><td> Mcal polynomial term      </td><td>                    </td>
+</table>
+
+<em> apmifit, dapmifit are needed for dophot data, but not sextractor data.  are these correctly handled? </em>
+<em> skyprobe used Mxxxx for Ncal and Myyyy for sky - can this be reconciled? </em>
+
+<h3> codes in Image</h3>
+<ul>
+<li> ID_IMAGE_NOCAL = 0x04 - internal to relphot 
+<li> ID_IMAGE_POOR  = 0x02 - set by relphot
+<li> ID_IMAGE_SKIP  = 0x04 - use by relphot (!!!)
+</ul>
+
+<b> Average </b>
+<table> 
+<tr><th> name       </th><th> type           </th><th> value               </th><th> units                 </th></tr>
+<tr><td> R          </td><td> float          </td><td> RA                  </td><td> decimal degrees J2000 </td></tr>
+<tr><td> D          </td><td> float          </td><td> DEC                 </td><td> decimal degrees J2000 </td></tr>
+<tr><td> M          </td><td> short int      </td><td>                     </td><td> 1000*mag		    </td></tr>
+<tr><td> Nm         </td><td> unsigned short </td><td> N measure	    </td><td> 			    </td></tr>
+<tr><td> Nn         </td><td> unsigned short </td><td> N missing	    </td><td> 			    </td></tr>
+<tr><td> Xp         </td><td> short int      </td><td> position scatter    </td><td> 100*arcsec	    </td></tr>
+<tr><td> Xm         </td><td> short int      </td><td> mag chisq           </td><td> 100*log(chisq)	    </td></tr>
+<tr><td> code       </td><td> unsigned short </td><td> data flags	    </td><td> 			    </td></tr>
+<tr><td> offset     </td><td> signed int     </td><td> measure offset	    </td><td> 			    </td></tr>
+<tr><td> missing    </td><td> signed int     </td><td> missing offset	    </td><td> 			    </td></tr>
+<tr><td> dM         </td><td> short int      </td><td> error on M          </td><td> 1000*log(value)	    </td></tr>
+<tr><td> Xg         </td><td> short int      </td><td> best chisq value    </td><td> ??		    </td></tr>
+</table>		  
+
+<h3> codes in Average</h3>
+<li> set to 0 by addstar, etc
+<li> ID_STAR_NOCAL        = 0x0001 - set by relphot
+<li> ID_PROPER            = 0x0400 - set by addusno, used by markrock
+<li> ID_BAD_DATE          = 0x0800 - deprecate (not currently set)
+<li> ID_TRANSIENT         = 0x1000 - not currently set? 
+<li> ID_VARIABLE          = 0x2000 - not currently set? 
+<li> ID_ROCK              = 0xa000 - set by markrock
+<li> ID_GHOST             = 0xc001 - set by fixcat, markstar
+<li> ID_TRAIL             = 0xc002 - set by fixcat, markstar
+<li> ID_BLEED             = 0xc003 - set by fixcat, markstar, markrock
+<li> ID_COSMIC            = 0xc004 - set by markrock
+</ul>
+
+<b> Measure </b>
+<table> 
+<tr><th> name       </th><th> type           </th><th> value               </th><th> units             </th>
+<tr><td> dR         </td><td> short int      </td><td> RA offset           </td><td> 100*arcsec        </td>
+<tr><td> dD         </td><td> short int      </td><td> DEC offset          </td><td> 100*arcsec        </td>
+<tr><td> M          </td><td> short int      </td><td> catalog mag         </td><td> 1000*mag          </td>
+<tr><td> Mcal       </td><td> short int      </td><td> image cal mag       </td><td> 1000*mag          </td>
+<tr><td> Mgal       </td><td> short int      </td><td> 'galaxy' mag,       </td><td> 1000*mag          </td>
+<tr><td> airmass    </td><td> short int      </td><td> (airmass - 1),      </td><td> 1000*airmass      </td>
+<tr><td> FWx        </td><td> short int      </td><td> fwhm major axis     </td><td> 100*arcsec        </td>
+<tr><td> dM         </td><td> unsigned char  </td><td> mag error           </td><td> 1000*mag          </td>
+<tr><td> fwy        </td><td> unsigned char  </td><td> minor/major ratio   </td><td>                   </td>
+<tr><td> theta      </td><td> unsigned char  </td><td> angle wrt ccd X dir </td><td> degree*(256/360)  </td>
+<tr><td> dophot     </td><td> char           </td><td> dophot type         </td><td>                   </td>
+<tr><td> source     </td><td> unsigned short </td><td> photcode            </td><td>                   </td>
+<tr><td> t          </td><td> unsigned int   </td><td> time                </td><td> unix time         </td>
+<tr><td> averef     </td><td> unsigned int   </td><td> average entry       </td><td>                   </td>
+<tr><td> dt         </td><td> short int      </td><td> exposure time       </td><td> 2500*log(exptime) </td>
+<tr><td> flags      </td><td> unsigned short </td><td> data flags          </td><td>                   </td>
+</table>
+
+<h3> flags in Measure</h3>
+<ul>
+<li> ID_MEAS_POOR         = 0x0001 - set by relphot, unset?
+<li> ID_MEAS_NOCAL        = 0x0002 - set by relphot, unset?
+<li> BLEND_IMAGE          = 0x0100 - set by addstar, etc
+<li> BLEND_CATALOG        = 0x0200 - set by addstar, etc
+<li> BLEND_IMAGE_NEIGHBOR = 0x1000 - set by addstar, etc
+<li> PART_OF_TRAIL        = 0x2000 - set by markstar, fixcat, used by markrock
+<li> GHOST_DATA           = 0x4000 - set by markstar, fixcat, used by markrock
+</ul>
+
+<em> relphot flag meanings: </em>
+<b> ID_IMAGE_NOCAL </b> : completely ignore image (internal only)
+<b> ID_IMAGE_SKIP  </b> : externally marked, don't include in Mrel, calculate Mcal (?)
+<b> ID_IMAGE_POOR  </b> : internally marked, don't include in Mrel, calculate Mcal (?)
+
+<b> ID_STAR_NOCAL  </b> : poor star, don't include in Mcal, calculate Mrel
+STAR_BAD == (average.Xm > STAR_CHISQ) || (average.dM > STAR_SCATTER) || (NVALID < MEAS_TOOFEW)
+
+<b> ID_MEAS_NOCAL  </b> : skip this measurement (temporary, internal)
+<b> ID_MEAS_POOR   </b> : poor star, don't include in Mcal, calculate Mrel
+MEAS_POOR == (3 sigma outlier) || (out of detector area)
+<em> currently NOT sticky!! </em>
+
+--
+
+uniphot.h:
+# define MEAS_POOR     0x0001
+# define MEAS_NOCAL    0x0002
+# define ID_IMAGE_SKIP 0x0004
+
+relphot.h:
+# define ID_VARIABLE   0x2000
+# define ID_TRANSIENT  0x1000 /* is this mutually exclusive with USNO?  */
+# define ID_BAD_DATA   0x0800 /* stationary object with some bad data points */
+# define ID_PROPER     0x0400 /* star with large proper motion */
+
+# define MEAS_POOR     0x0001
+# define MEAS_NOCAL    0x0002
+# define ID_IMAGE_SKIP 0x0004
+
+<em> things to update, cleanup </em>
+<d> finish fix of photcode in imregister-3.0, etc </d>
+<d> move flag constants from relphot/uniphot/photdbc include -> loneos.h </d>
+<d> watch for use of Xp, Xg, code in photdbc & status.extract, status.gstar</d>
+<b> status.extract.NVALID : count !(measure.flag & MEAS_POOR) </b>
+<d> fix error with ID_IMAGE_NOCAL == ID_IMAGE_SKIP </d>
+<d> make sure ID_IMAGE_POOR is saved and ID_IMAGE_SKIP is kept, including with -mosaic </d>
+<d> should STAR_BAD be saved or not?  probably not: there is not one per photcode </d>
+<d> MEAS_POOR should be saved, MEAS_NOCAL should not </d>
+<b> recompile all dvo programs, test </b>
+
+<b> photdbc </b> <em> check on the use of flags, etc; consistent with relphot, uniphot? </em>
Index: /tags/opihi-2-1/Ohana/src/opihi/doc/notes.photcode.html
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/doc/notes.photcode.html	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/doc/notes.photcode.html	(revision 3338)
@@ -0,0 +1,221 @@
+
+<h2> A Primer on DVO Photcodes and Magnitude Representation </h2>
+
+<p>
+There are two types of DVO table which store magnitude data.  The
+Average table stores magnitudes which represent averages of multiple
+measurements.  The Measure table stores magnitudes which represent
+single measurements.  
+
+<p>
+Each type of entry is defined by a Photcode.  The individual Measure
+entries have their photcodes stored as part of the structure.  The
+Average entries have photcodes which are determined externally by
+their sequence.  For historical reasons, the Average photcode are
+divided into the Primary photcode (of which there may only be one) and
+Secondary (of which there may be several).  The average magnitude
+associated with the Primary photcode is stored with the Average
+structure while the Secondary photcodes are stored in a separate,
+associated table called Secfilt.  The layout of the Average and
+Secfilt tables, and the photcodes assigned to them, are defined when
+the database is created based on the layout of the photcode table.
+This table is defined with a single Primary and a number of Secondary
+photcodes.  When the database tables are created, primary photcode is
+automatically associated with the Average entry while the sequence of
+Secondary photcodes defines the sequence of the entries in the Secfilt
+table.  This is very fragile, but very fast for making the
+association.  Thus, changing the number or sequence of secondary
+photcodes would cause an existing database table to be
+mis-interpretted.  
+
+<p>
+The Measure entries are broken into two photcode types as well:
+internal and external measurements.  Internal measurements are those
+for which the data source is well understood; the instrumental
+magnitudes are available and the instrumental parameters which are
+required to determine a calibrated magnitude.  External measurements
+are provided by external sources: published catalogs, reference
+sources, etc.  For these measurements, there is no control over the
+instrumental parameters which determined the measurement, and in many
+cases the measurement represents an average of an ensemble.
+
+<p>
+The photcode table defines relationships between photcodes,
+representing different photometry systems.  Each photcode entry
+defines the target of the calibration (the equivalence), and it may
+potentially define the zero-point (Co), the airmass slope (Ko), the
+appropriate color terms (C1, C2), the reference color term (Color),
+and the polynomial coefficients of the color equation (starting with
+the 1st order term).  
+
+<p>
+I need to include operations to handle varying color terms between
+CCDs.  I have measured color terms between CCDs in the range +/- 0.1
+mag/mag.  This is an appropriate time to clean up some of the code
+that handles the photcodes, etc.  In particular, the photcode table
+should provide the relationship beween relate between filter systems.
+
+For all of the functions below, a REF photcode simply returns the
+stored magnitude without transformation.  
+
+PhotInst (measure)
+  returns the instrumental magnitude of the given Measure
+  Minst = measure[0].M - measure[0].dt - iZERO_POINT;
+
+PhotCat (measure)
+  returns the 'catalog' magnitude of the given Measure (best guess
+  given no other information like color):
+  Mcat = measure[0].M - iZERO_POINT + Klam*(measure[0].airmass - 1000) + photcodes[0].code[Np].C;
+
+PhotSys (measure, average, secfilt)
+  returns the 'system' magnitude of the given Measure (best guess
+  using existing color information, but without application of
+  relative photometry offsets):
+  Msys = Mcat + f(color)
+  color is derived from measure.photcode.c1,c2  (measure.source.c1,c2)
+
+PhotRel (measure, average, secfilt)
+  returns the 'relative' magnitude of the given Measure (best guess
+  using existing color information and current relative photometry
+  measurment for this image).  This is the same photometry system as
+  the Average (PRI/SEC) measurement equivalent to this measurement
+  photcode:
+  Mrel = Msys + measure[0].Mcal;
+  color is derived from measure.photcode.c1,c2  (measure.source.c1,c2)
+
+PhotCal (measure, average, secfilt, allmeasures, code)
+  returns the 'calibrated' magnitude of the given Measure (best guess
+  using existing color information and current relative photometry
+  measurment for this image transformed to the appropriate reference
+  photometry system):
+  Mcal = Mref + f(color)
+  color is derived from code.c1,c2
+  the provided code must be either the measure.photcode.equiv or an
+  alternate for that code.
+
+<p>
+consider two filters, B & V, and two CCDs 00 & 01.  also, reference
+data in B_L92, V_L92
+
+<pre>
+    N  photcode     type  Co      Ko       X    C1    C2    Ao     Color  Equivalent
+  100  CFH12K.B.00  dep   26.000 -0.15     -    B     V     0.1    -      B
+  101  CFH12K.B.01  dep   26.000 -0.15     -    B     V     0.0    -      B
+
+  200  CFH12K.V.00  dep   26.100 -0.15     -    B     V     0.0    -      V
+  201  CFH12K.V.01  dep   26.100 -0.15     -    B     V     0.1    -      V
+
+    1  B            pri    0.000  -        -    B_L92 V_L92 0.016  -      B_L92
+    2  V            sec    0.000  -        -    B_L92 V_L92 0.008  -      V_L92
+
+  1003 B_L92        ref    -      -        -    -     -     -      -      -
+  1004 V_L92        ref    -      -        -    -     -     -      -      -
+  
+  B = m + Co + Ko*(secz - 1) + Ao*(B - V)
+  B_L92 = B + Co + color*A0 + color^2*A1 + color^3*A2
+</pre>
+
+<b>changes I'd like to make related to photcodes</b>
+
+<li> use structure value 'photcode', not 'source' everywhere
+<li> better abstraction / conceptualization of PhotMode values (Inst, Rel, Abs, Sys)
+<li> N-order polynomial for color-fits
+
+<b> relevant programs </b>
+
+<table>
+<tr><td>* addrefs    </td><td> minor fixes, no conversions are used </td></tr> 
+<tr><td>* addspphot  </td><td> minor fixes, no conversions are used </td></tr> 
+<tr><td>* addstar    </td><td> minor fixes, no conversions are used </td></tr> 
+<tr><td>* delstar    </td><td> minor fixes, no conversions are used </td></tr> 
+<tr><td>* photcode   </td><td> probably ok, check is consistent with new (?) photcode structs </td></tr> 
+<tr><td>* photreg    </td><td> check consistency </td></tr> 
+<tr><td>* photsearch </td><td> check consistency, use photcode table to get Equivalent </td></tr> 
+<tr><td>* relphot    </td><td> signficant changes to handle new structures </td></tr>
+<tr><td>libohana     </td><td> update LoadPhotcodes funcs, check consistency, use photcode table to get Equivalent </td></tr> 
+<tr><td>photdbc      </td><td> signficant changes to handle new structures </td></tr>
+<tr><td>status       </td><td> signficant changes to handle new structures </td></tr>
+<tr><td>dvo          </td><td> repeat fixes in status </td></tr> 
+
+<tr><td>lightcurve </td><td> unused? </td></tr>
+</table>
+
+<b> basic photcode APIs </b>
+
+int LoadPhotcodes (char *filename);
+void SetZeroPoint (double ZP);
+
+PhotCode *GetPhotcodebyName (name);
+int       GetPhotcodeCodebyName (name);
+PhotCode *GetPhotEquivbyName (name);
+int       GetPhotEquivCodebyName (name);
+
+PhotCode *GetPhotcodebyCode (code);
+char     *GetPhotcodeNamebyCode (code);
+
+PhotCode *GetPhotEquivbyCode (code);
+int       GetPhotEquivCodebyCode (code);
+
+double PhotInst (Measure *measure);
+double PhotAbs (Measure *measure);
+double PhotCat (Measure *measure);
+double PhotSys (Measure *measure, Average *average, SecFilt *secfilt);
+double PhotRel (Measure *measure, Average *average, SecFilt *secfilt);
+double PhotAve (PhotCode *code, Average *average, SecFilt *secfilt);
+double PhotRef (PhotCode *code, Average *average, SecFilt *secfilt, Measure *measure);
+
+<b> examples </b>
+find measures which are of photcode equivalent to X
+if (GetPhotEquivCodebyCode (measure[0].source) == N1) { } 
+
+<b> code, entry, hashcode, hashNsec </b>
+entry = 1;
+photcode[entry].code = 100 
+photcode[entry].name = B
+hashcode[100] = 1;
+
+hashNsec is only valid for type PHOT_SEC:
+hashNsec[code] = Nsec entry in SecFilt table
+
+<b> note recursion relationships </b>
+hashcode[photcode[entry].code] = entry;
+photcode[hashcode[entry]].code = entry
+
+<b> outstanding questions / issues </b>
+
+<ul>
+<li> PhotSys needs to handle missing color values
+<li> define valid range for color?
+<li> double PhotFoo functions return what on NO_MAG?
+<li> PhotFoo functions need to check for valid input types:
+  <ul> 
+  <li> PhotInst - PHOT_DEP
+  <li> PhotAbs  - PHOT_DEP, PHOT_REF
+  <li> PhotCat  - PHOT_DEP, PHOT_REF
+  <li> PhotSys  - PHOT_DEP, PHOT_REF
+  <li> PhotRel  - PHOT_DEP, PHOT_REF
+  <li> PhotAve  - PHOT_PRI, PHOT_SEC
+  <li> PhotRef  - PHOT_PRI, PHOT_SEC
+  </ul>
+</ul>
+
+<b> phot definitions </b>
+PhotInst = Measure.M - dt - ZP 
+PhotCat  = Measure.M + K*(airmass-1) + C - ZP
+PhotSys  = Measure.M + K*(airmass-1) + C - ZP + X*color
+PhotRel  = Measure.M + K*(airmass-1) + C - ZP + X*color - Mcal  -> average.m
+PhotRef  = average.M + C + X*color 
+
+C: def ~ 26.0, pri ~ 0.0
+
+PhotAbs  = deprecate (measure.M + K*(airmass-1) + C - ZP
+
+<b> alt photcodes </b>
+
+photcodes of type ALT provide alternate calibration terms for a given
+photcode.  these codes are equivalent to primary/secondary codes, but
+no data is ever saved with this type.  There are only lookups between
+the photcode name and the photcode structure, never the photcode.code
+value, since that defines the photcode for which the given structure
+is an alternate relationship.
+
Index: /tags/opihi-2-1/Ohana/src/opihi/doc/notes.txt
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/doc/notes.txt	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/doc/notes.txt	(revision 3338)
@@ -0,0 +1,103 @@
+
+opihi improvements / fixes:
+
+* single math processing system : inline shell math used one set of
+  functions (shell/math.c), while the set = () used another set, and
+  logic used part of a third set.  This has been unified into a single
+  math handling function (newmath).  The new math expression handling
+  also returns temporary in-line vectors and matrix expressions.
+
+* global user variables (Buffers, Vectors) and other global variables
+  (outfile, tv parameters, graphic and image tool parameters) have
+  been encapsulated in fuctions to avoid the global data constructs.  
+
+* improved command exit status handling : in the past, a function
+  returning FALSE would halt all script executing, returning to the
+  top level of the command stack.  we now set the variable $STATUS
+  with the exit status and allow the the user to test the exit
+  status to choose an operation.  loops, macros, and input files can
+  use the 'break' and 'continue' functions to escape from the current
+  location.  calling break returns with an exit status of FALSE,
+  calling break returns immediately with an exit status of TRUE.
+
+* more extensive use of 'outfile' 
+
+* support for opihi scripts: there is now better interpretation of
+  command-line arguments to allow for embedded opihi scripts, ie
+  scripts with the dvo or mana interpretter named on the first line
+  with the prefix #! like a shell script.  The first command-line
+  argument is interpreted as a file to input while successive ones are
+  converted to variables $argv:0 - $argv:n  WARNING: in the past,
+  multiple input files could be specified on the command-line.  this
+  now must be specified with --load file arguments.
+
+* local variables: there is now support for local (vs global) opihi
+  variables.  any macro may have a variable declared as local with the
+  command 'local (var)', which may take a list of variables.  these
+  variables are stored internally in association with the macro name.
+  the command may include the option -static, in which case the
+  variable will retain its value on successive calls to the same
+  macro.
+
+- merge of all old opihi-type programs into a single code base 
+
+- group related functions into libraries
+
+- function names, etc, should come from a single function, now a
+  global include file.
+
+- update help files
+
+- update web pages
+
+--
+
+some notes: 
+
+- new vector interpretation is now somewhat slower, due to the multiple
+  assignments.
+
+- BinaryOp does not leak memory (tested)
+
+- 55 seconds for 1000 floating-pt operations on a 4Mpix (3 GHz) -> 0.2
+  seconds per FP OP on a 4k square image
+
+- loop / list functions:
+
+  opihi.c
+  run_loop.c
+  run_if.c
+  input.c
+  for_loop.c
+  macro_exec.c
+
+  I have added continue / break functionality to all loop operations:
+
+  * the variable $STATUS is set based on the exit status of each command
+  * each loop tests for break and continue
+  * in the case of break, the loop returns a status of FALSE
+  * in the case of continue, the loop returns a status of TRUE
+  * if break -auto is set to 'on', then any exit status of FALSE escapes to  
+    the top level.
+  * interrupts are carried up to the top level.
+
+- local variables
+
+  I have added local variables.  They have names of the form
+  MacroName.VarName, where MacroName is the macro in which they are
+  local.  They are declared local with the command 'local', which
+  takes a list of variables to declare local, and the optional -static
+  flag, which requires the shell to test for the existence of the
+  variable before creating it, and only create it if it does not
+  exist.  otherwise the existing value of the variable is maintained.
+
+- math
+
+  I have removed the last instances of math interpretation being
+  performed by math, not newmath, in expand_vectors (interpreting the
+  contents of the vector square brackets: x[5]), and in the two
+  locations where logic was used in the evaluation: run_in and
+  run_while.  there are still some error in the precedence of the
+  operators: logical operators >,<,==,!=, etc need to be lower
+  priority than other binary operators.
+
Index: /tags/opihi-2-1/Ohana/src/opihi/doc/sample.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/doc/sample.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/doc/sample.c	(revision 3338)
@@ -0,0 +1,18 @@
+# include <stdio.h>
+
+main (int argc, char **argv) {
+
+  int i;
+  char line[1024];
+
+  for (i = 0; i <= argc; i++) {
+    fprintf (stderr, "arg %2d: %s\n", i, argv[i]);
+  }
+  while (argv[i] != NULL) {
+    fprintf (stderr, "env %2d: %s\n", i, argv[i]);
+    i++;
+  } 
+  while (fscanf (stdin, "%s", line) != EOF) {
+    fprintf (stderr, "line: ...%s...\n", line);
+  }
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/doc/stds.txt
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/doc/stds.txt	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/doc/stds.txt	(revision 3338)
@@ -0,0 +1,40 @@
+
+notation:
+
+object : an astronomical source, may be observed multiple times
+measurement : a single observation of an object (one per object per exposure) 
+m_inst : instrumental magnitude measurement
+m_cat  : catalog magnitude measurement (m_inst + 25.0)
+m_sys  : nominal internal system magnitude measurement (m_inst + ZP(CCD,FILTER)
+m_rel  : transparency adjusted magnitude measurement (m_sys + offset)
+
+M_ave  : average (object) magnitude in internal system
+M_ref  : average (object) magnitude in reference system
+
+test for photometric consistency:
+
+for the output from dither.corr:
+
+M_ave - m_rel(ccd) vs x_ccd, y_ccd
+M_ave - m_rel vs x_mosaic, y_mosaic
+M_ave - m_rel vs airmass?
+
+
+
+  MEGACAM.g.00 Minst - MEGACAM.g.01 Mcal : time
+
+  MEGACAM.g.00 - g : time
+
+  MEGACAM.g.00,Mrel - MEGACAM.g.01,Mcal : MEGACAM.g.00 - MEGACAM.r.00
+
+- use relphot to flag stars in poor locations, etc
+
+- we can choose for entry if it is Minst, Mcat, Msys, Mvrel, Mcal, Mave, or Mref
+
+int GetMagnitudeType (char *name, PhotCode *code, int *MagMode);
+
+- should return photcode & value MEAS_MREL, AVE_MREF, or what ever
+- should provide an appropriate default for measures, etc
+- should check for consistency with photcode type:
+  PRI/SEC : AVE_MREF, AVE_MAVE
+  DEP     : MEAS_ETC
Index: /tags/opihi-2-1/Ohana/src/opihi/doc/todo.txt
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/doc/todo.txt	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/doc/todo.txt	(revision 3338)
@@ -0,0 +1,4 @@
+
+- convert and include all mana/dimm/status derived functions
+- local scalar variables
+- break / continue in: for, macro, 
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/ImageOps.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/ImageOps.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/ImageOps.c	(revision 3338)
@@ -0,0 +1,81 @@
+# include "dvo.h"
+
+void image_subset (Image *image, int Nimage, int **Subset, int *Nsubset,
+	      Graphdata *graph, int RegionSelect, 
+	      unsigned long int tzero, double trange, int TimeSelect) 
+{
+
+  int i, j, flipped, status, InPic;
+  int *subset;
+  int N, n, npts;
+  double r, d, x[4], y[4], Rmin, Rmax, Rmid;
+  double X[8], Y[8];
+
+  if (RegionSelect) {
+    Rmin = graph[0].coords.crval1 - 182.0;
+    Rmax = graph[0].coords.crval1 + 182.0;
+    Rmid = 0.5*(Rmin + Rmax);
+  }
+
+  if (trange < 0) {
+    tzero = tzero + trange;
+    trange = fabs (trange);
+  }
+  status = InPic = TRUE;
+  npts = 200;
+  ALLOCATE (subset, int, npts);
+  n = N = 0;
+  for (i = 0; i < Nimage; i++) {
+    if (TimeSelect && ((image[i].tzero < tzero) || (image[i].tzero+image[i].trate*image[i].NY > tzero + trange))) continue;
+    if (RegionSelect) {
+      /* project this image to screen display coords */
+      x[0] = 0;           y[0] = 0;
+      x[1] = image[i].NX; y[1] = 0;
+      x[2] = image[i].NX; y[2] = image[i].NY;
+      x[3] = 0;           y[3] = image[i].NY;
+      status = FALSE;
+      flipped = FALSE;
+      for (j = 0; j < 4; j++) {
+	XY_to_RD (&r, &d, x[j], y[j], &image[i].coords);
+	while ((j == 0) && (r < Rmin)) { flipped = TRUE; r += 360.0; }
+	while ((j == 0) && (r > Rmax)) { flipped = TRUE; r -= 360.0; }
+	if ((j > 0) && flipped) {
+	  while (r < Rmid) r+= 360.0;
+	  while (r > Rmid) r-= 360.0;
+	}
+	status |= RD_to_XY (&X[2*j], &Y[2*j], r, d, &graph[0].coords);
+	if (j > 0) {
+	  X[2*j - 1] = X[2*j];
+	  Y[2*j - 1] = Y[2*j];
+	}
+      }
+      X[7] = X[0];
+      Y[7] = Y[0];
+      InPic = FALSE;
+      for (j = 0; status && (j < 8); j+=2) {
+	if ((X[j] >= graph[0].xmin) && 
+	    (X[j] <= graph[0].xmax) && 
+	    (Y[j] >= graph[0].ymin) && 
+	    (Y[j] <= graph[0].ymax))
+	  InPic = TRUE;
+      }
+    }
+    if (InPic && status) {
+      subset[n] = i;
+      n++;
+      if (n > npts - 1) {
+	npts += 200;
+	REALLOCATE (subset, int, npts);
+      }
+    }
+  }
+
+  REALLOCATE (subset, int, MAX (n, 1));
+  *Subset = subset;
+  *Nsubset = n;
+  return;
+}
+
+/* this routine fills the subset index with the list of selected images.
+   images may be selected on the basis of the region or on a time range 
+*/
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/LoadImages.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/LoadImages.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/LoadImages.c	(revision 3338)
@@ -0,0 +1,51 @@
+# include "dvo.h"
+
+Image *LoadImages (int *Nimage) {
+
+  char filename[256];
+  int nimage, NIMAGE;
+  FILE *f;
+  Header header;
+  Image *image;
+  
+  VarConfig ("IMAGE_CATALOG", "%s", filename);
+
+  /* check if image datafile exists, get header */
+  if (!fits_read_header (filename, &header)) {
+    fprintf (stderr, "No available image catalog %s (1)\n", filename);
+    *Nimage = 0;
+    return ((Image *) NULL);
+  }
+
+  /* get ready to read data on images */ 
+  f = fopen (filename, "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "No available image catalog: %s (2)\n", filename);
+    free (header.buffer);
+    *Nimage = 0;
+    return ((Image *) NULL);
+  }
+
+  NIMAGE = 0;
+  fits_scan (&header, "NIMAGES", "%d", 1, &NIMAGE);
+  if (NIMAGE == 0) {
+    fprintf (stderr, "no images found\n");
+    *Nimage = NIMAGE;
+    fclose (f);
+    return ((Image *) NULL);
+  }
+
+  ALLOCATE (image, Image, NIMAGE);
+  fseek (f, header.size, SEEK_SET); 
+  nimage = Fread (image, sizeof(Image), NIMAGE, f, "image");
+  if (nimage != NIMAGE) {
+    fprintf (stderr, "failed to read in all images (%d of %d)\n", nimage, NIMAGE);
+  }
+
+  fclose (f);
+  *Nimage = nimage;
+  return (image);
+
+
+}
+  
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/Makefile
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/Makefile	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/Makefile	(revision 3338)
@@ -0,0 +1,177 @@
+include ../../../Configure
+
+default: all
+
+HOME    =       $(ROOT)/src/opihi.v2
+BIN     =       $(HOME)/bin
+LIB     =       $(HOME)/lib
+INC     =       $(HOME)/include
+HELP    =       $(HOME)/help
+SDIR    =       $(HOME)/dvo
+#
+DESTBIN =       $(LBIN)
+DESTLIB =       $(LLIB)
+DESTINC =       $(LINC)
+DESTMAN =       $(LMAN)
+#  
+INCS    =       -I$(INC) -I$(LINC) -I$(XINC)
+LFLAGS  =       -L$(LLIB) -L$(LIB)
+LIBS1   =       -lFITS -lsocket -lnsl -lreadline -ltermcap -lohana -lm
+LIBS2   =       -lbasiccmd -ldatacmd -lastrocmd -lshell -ldata 
+LIBS    =       $(LIBS2) $(LIBS1) 
+CFLAGS  =       $(INCS)
+CCFLAGS =       $(LIBS) 
+
+# dvo user commands and support functions ########################
+
+dvofuncs = \
+$(SDIR)/init.$(ARCH).o            	\
+$(SDIR)/ImageOps.$(ARCH).o		\
+$(SDIR)/LoadImages.$(ARCH).o		\
+$(SDIR)/aregion.$(ARCH).o               \
+$(SDIR)/compare.$(ARCH).o               \
+$(SDIR)/find_regions.$(ARCH).o	  	\
+$(SDIR)/get_regions.$(ARCH).o           \
+$(SDIR)/match_image.$(ARCH).o		\
+$(SDIR)/photometry.$(ARCH).o            \
+$(SDIR)/dvomisc.$(ARCH).o		\
+$(SDIR)/region_list.$(ARCH).o		\
+$(SDIR)/dvo.$(ARCH).o
+
+dvocmds = \
+$(SDIR)/avextract.$(ARCH).o	  	\
+$(SDIR)/badimages.$(ARCH).o	  	\
+$(SDIR)/calextract.$(ARCH).o      	\
+$(SDIR)/calmextract.$(ARCH).o     	\
+$(SDIR)/catalog.$(ARCH).o	  	\
+$(SDIR)/ccd.$(ARCH).o             	\
+$(SDIR)/cmatch.$(ARCH).o	  	\
+$(SDIR)/cmd.$(ARCH).o             	\
+$(SDIR)/cmpload.$(ARCH).o	  	\
+$(SDIR)/cmpread.$(ARCH).o	  	\
+$(SDIR)/ddmags.$(ARCH).o	  	\
+$(SDIR)/detrend.$(ARCH).o	  	\
+$(SDIR)/dmagaves.$(ARCH).o	  	\
+$(SDIR)/dmagmeas.$(ARCH).o	  	\
+$(SDIR)/dmags.$(ARCH).o		  	\
+$(SDIR)/dmt.$(ARCH).o		  	\
+$(SDIR)/elixir.$(ARCH).o                \
+$(SDIR)/gcat.$(ARCH).o		  	\
+$(SDIR)/gimages.$(ARCH).o	  	\
+$(SDIR)/gstar.$(ARCH).o		  	\
+$(SDIR)/images.$(ARCH).o	  	\
+$(SDIR)/imbox.$(ARCH).o		  	\
+$(SDIR)/imdata.$(ARCH).o	  	\
+$(SDIR)/imdense.$(ARCH).o	  	\
+$(SDIR)/imextract.$(ARCH).o	  	\
+$(SDIR)/imlist.$(ARCH).o	  	\
+$(SDIR)/imphot.$(ARCH).o	  	\
+$(SDIR)/imrough.$(ARCH).o	  	\
+$(SDIR)/imsearch.$(ARCH).o	  	\
+$(SDIR)/imstats.$(ARCH).o	  	\
+$(SDIR)/lcat.$(ARCH).o		  	\
+$(SDIR)/lcurve.$(ARCH).o	  	\
+$(SDIR)/mextract.$(ARCH).o	  	\
+$(SDIR)/pcat.$(ARCH).o		  	\
+$(SDIR)/photcodes.$(ARCH).o	  	\
+$(SDIR)/pmeasure.$(ARCH).o	  	\
+$(SDIR)/procks.$(ARCH).o	  	\
+$(SDIR)/showtile.$(ARCH).o	  	\
+$(SDIR)/simage.$(ARCH).o	  	\
+$(SDIR)/subpix.$(ARCH).o 		
+
+dvo = $(dvofuncs) $(dvocmds)
+
+libs = \
+$(DESTLIB)/libshell.a \
+$(DESTLIB)/libdata.a \
+$(DESTLIB)/libbasiccmd.a \
+$(DESTLIB)/libastrocmd.a \
+$(DESTLIB)/libdatacmd.a
+
+all: dvo
+
+dvo: $(BIN)/dvo.$(ARCH)
+	@echo done
+
+$(BIN)/dvo.$(ARCH) : $(dvo) $(libs)
+
+install: $(DESTBIN)/dvo
+
+# utilities #################################################
+$(BIN)/%.$(ARCH):
+	@if [ ! -d $(BIN) ]; then mkdir -p $(BIN); fi
+	$(CC) $^ -o $@ $(LFLAGS) $(LIBS)
+	@echo "compiled $*"
+	@echo ""
+
+$(DESTBIN)/%: $(BIN)/%.$(ARCH) 
+	@if [ ! -d $(DESTBIN) ]; then mkdir -p $(DESTBIN); fi
+	rm -f $(DESTBIN)/$*
+	cp $(BIN)/$*.$(ARCH) $(DESTBIN)/$*
+	@echo "installed $*"
+	@echo ""
+
+$(LIB)/%.$(ARCH).a:
+	@if [ ! -d $(LIB) ]; then mkdir -p $(LIB); fi
+	rm -f $@
+	ar rcv $@ $^ 
+	$(RANLIB) $@
+	@echo "compiled library $*"
+	@echo ""
+
+$(DESTLIB)/%.a: $(LIB)/%.$(ARCH).a
+	@if [ ! -d $(DESTLIB) ]; then mkdir -p $(DESTLIB); fi
+	@echo ""
+	rm -f $@
+	cp $^ $@
+
+clean:
+	rm -f $(BIN)/*.$(ARCH)
+	rm -f $(LIB)/*.$(ARCH).a
+	rm -f `find . -name "*.o"`
+	rm -f `find . -name "*~"`
+	rm -f `find . -name "#*"`
+
+dist: clean
+	rm -f $(BIN)/*
+	rm -f $(LIB)/*
+
+lib%.clean:
+	rm -f $(LIB)/lib$*.$(ARCH).a
+	rm -f $($*)
+	@echo ""
+
+%.clean:
+	rm -f $(BIN)/$*.$(ARCH)
+	@echo ""
+
+%.$(ARCH).o : %.c
+	$(CC) $(CFLAGS) -c $*.c -o $@
+
+
+
+## -*- makefile -*- 
+# deprecated functions: verify & delete
+#$(SDIR)/abszero.$(ARCH).o \
+#$(SDIR)/cals.$(ARCH).o \
+#$(SDIR)/dumpmags.$(ARCH).o \
+#$(SDIR)/extract.$(ARCH).o \
+#$(SDIR)/gtypes.$(ARCH).o \
+#$(SDIR)/photresid.$(ARCH).o \
+#$(SDIR)/resid.$(ARCH).o \
+#$(SDIR)/zeropts.$(ARCH).o
+#$(SDIR)/objload.$(ARCH).o \ - make sure we have vect to tv
+#$(SDIR)/ccdextract.$(ARCH).o \
+#$(SDIR)/cmdextract.$(ARCH).o \
+#$(SDIR)/dmagextract.$(ARCH).o \
+#$(SDIR)/ddmagextract.$(ARCH).o \
+
+# future functions, not fully implemented
+#$(SDIR)/detrend.$(ARCH).o \
+#$(SDIR)/getxtra.$(ARCH).o \
+#$(SDIR)/addxtra.$(ARCH).o \
+
+# functions that need to be updated
+#$(SDIR)/gregions.$(ARCH).o \
+
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/addxtra.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/addxtra.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/addxtra.c	(revision 3338)
@@ -0,0 +1,60 @@
+# include "dvo.h"
+
+typedef struct {
+  char type[64];
+  char name[64];
+  char source[256];
+  char mode[64];
+  char value[64];
+  char range[64];
+  double R, D;
+  int averef;
+} Xtras;
+
+int addxtra (int argc, char **argv) {
+  
+  Source = (char *) NULL;
+  if (N = get_argument (argc, argv, "-source")) {
+    remove_argument (N, &argc, argv);
+    Source = strcreate (atof[N]);
+    remove_argument (N, &argc, argv);
+  }
+  Name = (char *) NULL;
+  if (N = get_argument (argc, argv, "-name")) {
+    remove_argument (N, &argc, argv);
+    Name = strcreate (atof[N]);
+    remove_argument (N, &argc, argv);
+  }
+  Mode = (char *) NULL;
+  if (N = get_argument (argc, argv, "-mode")) {
+    remove_argument (N, &argc, argv);
+    Mode = strcreate (atof[N]);
+    remove_argument (N, &argc, argv);
+  }
+  Range = (char *) NULL;
+  if (N = get_argument (argc, argv, "-range")) {
+    remove_argument (N, &argc, argv);
+    Range = strcreate (atof[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 6) {
+    fprintf (stderr, "USAGE: addxtra R D radius (type) (value)\n");
+    return (FALSE);
+  }
+  
+  /*
+
+  validate the input values (type, defines the needed options)
+  find catalog (based on r,d)
+  load catalog (need to load measures?)
+  find the object
+  find the xtra entry (sorted by ra/dec? sorted by averef?)
+  add new entry
+  save catalog 
+  */
+}
+
+/* 
+  addxtra R D dR type value -name (name) -source (source) -mode (mode) -range (range) 
+*/
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/aregion.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/aregion.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/aregion.c	(revision 3338)
@@ -0,0 +1,81 @@
+# include "dvo.h"
+# include "hstgsc.h"
+
+/* find region file which contains ra, dec */
+void aregion (GSCRegion *region, FILE *f, double ra, double dec, char *path) {
+  
+  char buffer[28800], temp[50], file[50];
+  double RA0, RA1, DEC0, DEC1;
+  int i, NBigDec, NLINES, done;
+  
+  while (ra < 0) { ra += 360.0; }
+  while (ra >= 360.0) { ra -= 360.0; }
+
+  if (dec >= 86.25) {
+    sprintf (file, "%s/n8230/pole.cpt", path);
+    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;
+    hstgsc_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 (0);
+  }
+  temp[5] = 0;
+  sprintf (file, "%s/%s/%s.cpt", path, 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;
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/avextract.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/avextract.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/avextract.c	(revision 3338)
@@ -0,0 +1,151 @@
+# include "dvo.h"
+
+int avextract (int argc, char **argv) {
+  
+  Catalog catalog;
+  Graphdata graphsky;
+  RegionFile *regions;
+  PhotCode *code;
+  Vector *vec;
+
+  char filename[256], catdir[256], *p;
+  int i, j, m, N, NPTS, param;
+  int Ngraph, Nsec, Nregions, mode;
+
+  regions = NULL;
+  catalog.average = NULL; 
+  catalog.secfilt = NULL;
+  catalog.measure = NULL;
+
+  /* load photcode information */
+  if (!InitPhotcodes ()) goto escape;
+  Nsec = GetPhotcodeNsecfilt ();
+
+  /* load data about plot windows */
+  Ngraph = 0;
+  if (!GetGraphData (&graphsky, NULL, &Ngraph)) goto escape;
+ 
+  /* find CATDIR in config system */
+  VarConfig ("CATDIR", "%s", catdir);
+
+  /* grab value of photcode, if available */
+  code = NULL;
+  mode = MAG_AVE;
+  if (N = get_argument (argc, argv, "-photcode")) {
+    remove_argument (N, &argc, argv);
+    code = GetPhotcodebyName (argv[N]);
+    if (code == NULL) {
+      fprintf (stderr, "photcode not found in photcode table\n");
+      goto usage;
+    }
+    remove_argument (N, &argc, argv);
+  }
+
+  /* interpret command-line options */
+  if (!SetPhotSelections (&argc, argv)) goto usage;
+  if (argc != 3) { goto usage; }
+
+  /* identify selection */
+  param = GetAverageParam (argv[2]);
+  if (param == AVE_ZERO) {
+    if (!GetPhotcodeInfo (argv[2], &code, &mode)) {
+      GetAverageParam ("help");
+      fprintf (stderr, "value may also be a valid photcode\n");
+      fprintf (stderr, "photcodes or 'mag' may have optional magnitude mode: mag,[Mave, Mref]\n");
+      goto escape;
+    }
+    param = AVE_MAG;
+    for (p = argv[2]; *p != 0; p++) { 
+      if (*p == '.') *p = ':';
+    }
+  } 
+  if ((vec = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) goto escape;
+
+  /* need valid code for some params: */
+  switch (param) {
+    case AVE_MAG:
+    case AVE_dMAG:
+    case AVE_Xm:
+    case AVE_TYPE:
+    case AVE_NCODE:
+    case AVE_NPHOT: 
+      if (code == NULL) goto escape;
+      if (code[0].type == PHOT_DEP) goto escape;
+      if (code[0].type == PHOT_REF) goto escape;
+      break;
+    default:
+      break;
+  }
+
+  /* determine region-file names */
+  if (!strcmp (argv[1], "all")) {
+    float Radius;
+    Radius = MAX (fabs(graphsky.xmax), fabs(graphsky.ymax));
+    regions = find_regions (graphsky.coords.crval1, graphsky.coords.crval2, Radius, &Nregions);
+    if (!SetImageSelection (param, &graphsky, TRUE)) goto escape;
+  } else {
+    Nregions = 1;
+    ALLOCATE (regions, RegionFile, 1);
+    strcpy (regions[0].name, argv[1]);
+    if (!SetImageSelection (param, NULL, FALSE)) goto escape;
+  }
+
+  /* create storage vector */
+  N = 0;
+  NPTS = 1000;
+  REALLOCATE (vec[0].elements, float, NPTS);
+
+  for (i = 0; i < Nregions; i++) {
+    /* lock, load, unlock catalog */
+    sprintf (filename, "%s/%s", catdir, regions[i].name);
+    catalog.filename = filename;
+    switch (lock_catalog (&catalog, LCK_SOFT)) {
+    case 2:
+      unlock_catalog (&catalog);
+    case 0:
+      continue;
+    }
+    if (!load_catalog (&catalog, LOAD_AVES | LOAD_MEAS | LOAD_SECF, FALSE)) {
+      unlock_catalog (&catalog);
+      continue;
+    }
+    unlock_catalog (&catalog);
+
+    for (j = 0; j < catalog.Naverage; j++) {
+      m = catalog.average[j].offset;
+      vec[0].elements[N] = ExtractAverages (code, mode, &catalog.average[j], &catalog.secfilt[j*Nsec], &catalog.measure[m], param);
+      N++;
+      if (N == NPTS - 1) {
+	NPTS += 2000;
+	REALLOCATE (vec[0].elements, float, NPTS);
+      }
+    }
+    if (catalog.average != NULL) free (catalog.average);
+    if (catalog.secfilt != NULL) free (catalog.secfilt);
+    if (catalog.measure != NULL) free (catalog.measure);
+    catalog.average = (Average *) NULL; 
+    catalog.secfilt = (SecFilt *) NULL;
+    catalog.measure = (Measure *) NULL;
+  }
+  vec[0].Nelements = N;
+  REALLOCATE (vec[0].elements, float, MAX(1,N));
+
+  if (regions != NULL) free (regions);
+  FreeImageSelection ();
+  return (TRUE);
+
+usage:
+  fprintf (stderr, "USAGE: avextract (from) (value) [options]\n");
+  fprintf (stderr, "  from: cpt name or 'all'\n");
+  fprintf (stderr, "  value: average.parameter or photcode\n");
+  return (FALSE);
+
+escape:
+  fprintf (stderr, "error in avextract\n");
+  if (regions != NULL) free (regions);
+  FreeImageSelection ();
+  if (catalog.average != NULL) free (catalog.average);
+  if (catalog.secfilt != NULL) free (catalog.secfilt);
+  if (catalog.measure != NULL) free (catalog.measure);
+  return (FALSE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/badimages.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/badimages.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/badimages.c	(revision 3338)
@@ -0,0 +1,102 @@
+# include "dvo.h"
+
+static int badim_int = FALSE;
+void badim_escape () {
+  badim_int = TRUE;
+}
+
+int badimages (int argc, char **argv) {
+  
+  FILE *f;
+  int i, Nimage, nimage, entry, First, Cross;
+  float *ptr;
+  double nominal, big, small, value;
+  Header header;
+  Image *image;
+  char ImageCat[256];
+
+  VarConfig ("IMAGE_CATALOG", "%s", ImageCat);
+  
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: badimages entry value\n");
+    fprintf (stderr, "   OR: badimages -image N\n");
+    return (FALSE);
+  }
+  
+  First = FALSE;
+  if (!strcmp (argv[1], "-image")) {
+    First = TRUE;
+    entry = atof(argv[2]);
+  } else {
+    entry = atof(argv[1]);
+    nominal = atof(argv[2]);
+    Cross = FALSE;
+    if (!strcasecmp (argv[1], "x")) {
+      Cross = TRUE;
+    }
+  }
+  
+  /* check if image datafile exists, get header */
+  if (!fits_read_header (ImageCat, &header)) {
+    fprintf (stderr, "can't open image catalog %s\n", ImageCat);
+    return (FALSE);
+  }
+  
+  /* get ready to read data on images */ 
+  f = fopen (ImageCat, "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "can't open image catalog %s\n", ImageCat);
+    return (FALSE);
+  }
+  fseek (f, header.size, SEEK_SET); 
+  
+  /* read in image data */
+  Nimage = 0;
+  fits_scan (&header, "NIMAGES", "%d", 1, &Nimage);
+  ALLOCATE (image, Image, Nimage);
+  nimage = Fread (image, sizeof(Image), Nimage, f, "image");
+  fclose (f);
+  if (nimage != Nimage) {
+    fprintf (stderr, "error reading all data from image file (%d != %d)\n", nimage, Nimage);
+    free (image);
+    return (FALSE);
+  }
+  
+  if (First) {
+    ptr = &image[entry].coords.crpix1;
+    for (i = 0; i < 22; i++) {
+      fprintf (GetOutfile(), "%2d: %g\n", i, ptr[i]);
+    }
+    value = image[entry].coords.pc1_1*image[entry].coords.pc2_2 + image[entry].coords.pc1_2*image[entry].coords.pc2_1;
+    fprintf (GetOutfile(), " x: %g\n", value);
+    return (TRUE);
+  }
+  
+  big = nominal * 1.05;
+  small = nominal / 1.05;
+  if (big < small) {
+    double tmp;
+    tmp = big; big = small; small = tmp;
+  }
+  
+  badim_int = FALSE;
+  if (Cross) {
+    for (i = 0; (i < Nimage) && !badim_int; i++) {
+      value = image[i].coords.pc1_1*image[i].coords.pc2_2 + image[i].coords.pc1_2*image[i].coords.pc2_1;
+      if ((value > big) || (value < small)) {
+	fprintf (GetOutfile(), "%5d %s: %d %g\n", i, image[i].name, image[i].tzero, value);
+      }
+    }
+  } else {
+    for (i = 0; (i < Nimage) && !badim_int; i++) {
+      ptr = &image[i].coords.crpix1;
+      if ((ptr[entry] > big) || (ptr[entry] < small)) {
+	fprintf (GetOutfile(), "%5d %s: %d %g\n", i, image[i].name, image[i].tzero, ptr[entry]);
+      }
+    }
+  }
+  
+  return (TRUE);
+
+}
+  
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/calextract.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/calextract.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/calextract.c	(revision 3338)
@@ -0,0 +1,158 @@
+# include "dvo.h"
+
+enum {Nd, Nm, NC, NR, ND, Np, Nc, Nt, Nx, Nd1, Nd2, NVEC};
+
+int calextract (int argc, char **argv) {
+  
+  Catalog catalog;
+  Graphdata graphsky;
+  RegionFile *regions;
+  PhotCode *code[2];
+  Vector **vec;
+
+  int i, j, m, N, Nr, Nregions, mode[2];
+  int RegionList, Ngraph, Nsec, NSTAR;
+  char filename[256], catdir[256], RegionListFile[256];
+  double Radius, M1, M2, dM2, color;
+
+  /* these need to be freed in the end */
+  regions = NULL;
+  catalog.average = NULL; 
+  catalog.secfilt = NULL;
+  catalog.measure = NULL;
+
+  /* load photcode information */
+  if (!InitPhotcodes ()) return (FALSE);
+  Nsec = GetPhotcodeNsecfilt ();
+
+  /* load data about plot windows */
+  Ngraph = 0;
+  if (!GetGraphData (&graphsky, NULL, &Ngraph)) goto escape;
+
+  /* find CATDIR in config system */
+  VarConfig ("CATDIR", "%s", catdir);
+
+  /* specify catalog files */
+  RegionList = FALSE;
+  if (N = get_argument (argc, argv, "-list")) {
+    RegionList = TRUE;
+    remove_argument (N, &argc, argv);
+    strcpy (RegionListFile, argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  /* command line arguments */
+  if (!SetPhotSelections (&argc, argv)) goto usage;
+  if (argc != 4) goto usage;
+  if (strcmp (argv[2], "-")) goto usage;
+  if (!GetPhotcodeInfo (argv[1], &code[0], &mode[0])) goto usage;
+  if (!GetPhotcodeInfo (argv[3], &code[1], &mode[1])) goto usage;
+  /* code.type must be PHOT_REF */
+
+  /* one unique value per star */
+  N = 0;
+  NSTAR = 1;
+  ALLOCATE (vec, Vector *, NVEC);
+  if ((vec[Nd] 	= SelectVector ("cal:dmag",     ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nm] 	= SelectVector ("cal:mag",      ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[NC] 	= SelectVector ("cal:color",    ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[NR] 	= SelectVector ("cal:ra",       ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[ND] 	= SelectVector ("cal:dec",      ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Np] 	= SelectVector ("cal:nphot",    ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nc] 	= SelectVector ("cal:ncode",    ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nt] 	= SelectVector ("cal:ncrit",    ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nx] 	= SelectVector ("cal:chisq",    ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nd1] = SelectVector ("cal:dm1",      ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nd2] = SelectVector ("cal:dm2",      ANYVECTOR, TRUE)) == NULL) goto escape;
+
+  /* select region files */
+  if (RegionList) {
+    regions = region_list (RegionListFile, &Nregions);
+  } else {
+    Radius = MAX (fabs(graphsky.xmax), fabs(graphsky.ymax));
+    regions = find_regions (graphsky.coords.crval1, graphsky.coords.crval2, Radius, &Nregions);
+  }
+
+  for (Nr = 0; Nr < Nregions; Nr++) {
+    if (Nr && !(Nr % 500)) { fprintf (stderr, "."); }
+
+    /* lock, load, unlock catalog */
+    sprintf (filename, "%s/%s", catdir, regions[Nr].name);
+    catalog.filename = filename;
+    switch (lock_catalog (&catalog, LCK_SOFT)) {
+    case 2:
+      unlock_catalog (&catalog);
+    case 0:
+      continue;
+    }
+    if (!load_catalog (&catalog, LOAD_AVES | LOAD_MEAS | LOAD_SECF, FALSE)) {
+      unlock_catalog (&catalog);
+      continue;
+    }
+    unlock_catalog (&catalog);
+
+    /* extract values, assign to vectors */
+    for (i = 0; i < catalog.Naverage; i++) {
+      m = catalog.average[i].offset;
+
+      if (code[0][0].c1 && code[0][0].c2 && !PhotColor (&catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], code[0][0].c1, code[0][0].c2, &color)) continue;
+
+      /* find data for filter 2 (PHOT_REF) */
+      M2 = NO_MAG;
+      for (j = 0; j < catalog.average[i].Nm; j++) {
+	if (catalog.measure[m+j].source != code[1][0].code) continue;
+	M2 = PhotCat  (&catalog.measure[m+j]);
+	dM2 = 0.001*catalog.measure[m+j].dM;
+      }	
+      if (M2 == NO_MAG) continue;
+
+      /* find data for filter 1 */
+      M1 = ExtractAverages (code[0], mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], AVE_MAG);
+      if (M1 == NO_MAG) continue;
+
+      vec[Nd ][0].elements[N] = M1 - M2;
+      vec[Nm ][0].elements[N] = M2;
+      vec[NC ][0].elements[N] = color;
+      vec[NR ][0].elements[N] = catalog.average[i].R;
+      vec[ND ][0].elements[N] = catalog.average[i].D;
+      vec[Nd1][0].elements[N] = ExtractAverages (code[0], mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], AVE_dMAG);
+      vec[Nd2][0].elements[N] = dM2;
+      vec[Nx ][0].elements[N] = ExtractAverages (code[0], mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], AVE_Xm);
+      vec[Nc ][0].elements[N] = ExtractAverages (code[0], mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], AVE_NCODE);
+      vec[Np ][0].elements[N] = ExtractAverages (code[0], mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], AVE_NPHOT);
+      vec[Nt ][0].elements[N] = ExtractAverages (code[0], mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], AVE_NCRIT);
+      N ++;
+      if (N == NSTAR) {
+	NSTAR += 100;
+	for (i = 0; i < NVEC; i++) {
+	  REALLOCATE (vec[i][0].elements, float, NSTAR);
+	}
+      }
+    }
+    if (catalog.average != (Average *) NULL) free (catalog.average);
+    if (catalog.measure != (Measure *) NULL) free (catalog.measure);
+    if (catalog.secfilt != (SecFilt *) NULL) free (catalog.secfilt);
+    catalog.average = (Average *) NULL; 
+    catalog.secfilt = (SecFilt *) NULL;
+    catalog.measure = (Measure *) NULL;
+  }
+  if (regions != NULL) free (regions);  
+  for (i = 0; i < NVEC; i++) {
+    vec[i][0].Nelements = N;
+  }
+  return (TRUE);
+  
+usage:
+  fprintf (stderr, "USAGE: calextract F - F\n");
+  return (FALSE);
+
+ escape:
+  
+  if (regions != NULL) free (regions);  
+  for (i = 0; i < NVEC; i++) {
+    DeleteVector (vec[i]);
+  }
+  free (vec);
+
+  return (FALSE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/calmextract.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/calmextract.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/calmextract.c	(revision 3338)
@@ -0,0 +1,214 @@
+# include "dvo.h"
+
+enum {Nd, Nm1, Nm2, Nc, Ns, Nt, Nz, NR, ND, Nxc, Nyc, Nxm, Nym, NT, NP, Nd1, Nd2, NVEC};
+int ConcatMeasures (Vector *vec, PhotCode *code, int mode, Average *average, SecFilt *secfilt, Measure *measure, int param, int Nin);
+
+int calmextract (int argc, char **argv) {
+  
+  Catalog catalog;
+  Graphdata graphsky;
+  RegionFile *regions;
+  PhotCode *code[2];
+  Vector **vec;
+
+  int i, j, k, m, N, N1, Nr, mode[2];
+  int Ngraph, NSTAR, Nstar, Nsec, Nregions, RegionList;
+  char filename[256], catdir[256], RegionListFile[256];
+  double *M1, M2, dM2, color, Radius;
+
+  /* these need to be freed in the end */
+  regions = NULL;
+  catalog.average = NULL; 
+  catalog.secfilt = NULL;
+  catalog.measure = NULL;
+
+  /* load photcode information */
+  if (!InitPhotcodes ()) return (FALSE);
+  Nsec = GetPhotcodeNsecfilt ();
+
+  /* load data about plot windows */
+  Ngraph = 0;
+  if (!GetGraphData (&graphsky, NULL, &Ngraph)) goto escape;
+
+  /* find CATDIR in config system */
+  VarConfig ("CATDIR", "%s", catdir);
+
+  /* specify catalog files */
+  RegionList = FALSE;
+  if (N = get_argument (argc, argv, "-list")) {
+    RegionList = TRUE;
+    remove_argument (N, &argc, argv);
+    strcpy (RegionListFile, argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  /* command line arguments */
+  if (!SetPhotSelections (&argc, argv)) goto usage;
+  if (argc != 4) goto usage;
+  if (strcmp (argv[2], "-")) goto usage;
+  if (!GetPhotcodeInfo (argv[1], &code[0], &mode[0])) goto usage;
+  if (!GetPhotcodeInfo (argv[3], &code[1], &mode[1])) goto usage;
+  /* code.type must be PHOT_REF */
+
+  /* test PhotSelections: is photcode specified if needed? */
+  if (!TestPhotSelections (&code)) {
+    fprintf (stderr, "photcode selection rules violated\n");
+    fprintf (stderr, "average and ensemble restrictions require a corresponding photcode\n");
+    goto escape;
+  }
+
+
+  /* returned vectors are dmag, mag, color, time, airmass, ra, dec, x, y, exptime */
+  N = 0;
+  Nstar = 0;
+  NSTAR = 100;
+  ALLOCATE (vec, Vector *, NVEC);
+  if ((vec[Nd ] = SelectVector ("cal:dmag",     ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nm1] = SelectVector ("cal:mag1",     ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nm2] = SelectVector ("cal:mag2",     ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nc ] = SelectVector ("cal:color",    ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Ns ] = SelectVector ("cal:star",     ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nt ] = SelectVector ("cal:time",     ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nz ] = SelectVector ("cal:airmass",  ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[NR ] = SelectVector ("cal:ra",       ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[ND ] = SelectVector ("cal:dec",      ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nxc] = SelectVector ("cal:xccd",     ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nyc] = SelectVector ("cal:yccd",     ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nxm] = SelectVector ("cal:xmosaic",  ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nym] = SelectVector ("cal:ymosaic",  ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[NT ] = SelectVector ("cal:exptime",  ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[NP ] = SelectVector ("cal:photcode", ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nd1] = SelectVector ("cal:dm1",      ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nd2] = SelectVector ("cal:dm2",      ANYVECTOR, TRUE)) == NULL) goto escape;
+  for (k = 0; k < NVEC; k++) {
+    REALLOCATE (vec[k][0].elements, float, NSTAR);
+    vec[k][0].Nelements = 0;
+  }
+
+  /* select region files */
+  if (RegionList) {
+    regions = region_list (RegionListFile, &Nregions);
+    if (!SetImageSelection (MEAS_XMOSAIC, NULL, FALSE)) goto escape;
+  } else {
+    Radius = MAX (fabs(graphsky.xmax), fabs(graphsky.ymax));
+    regions = find_regions (graphsky.coords.crval1, graphsky.coords.crval2, Radius, &Nregions);
+    if (!SetImageSelection (MEAS_XMOSAIC, &graphsky, TRUE)) goto escape;
+  }
+
+  for (Nr = 0; Nr < Nregions; Nr++) {
+    if (Nr && !(Nr % 500)) { fprintf (stderr, "."); }
+
+    /* lock, load, unlock catalog */
+    sprintf (filename, "%s/%s", catdir, regions[Nr].name);
+    catalog.filename = filename;
+    switch (lock_catalog (&catalog, LCK_SOFT)) {
+    case 2:
+      unlock_catalog (&catalog);
+    case 0:
+      continue;
+    }
+    if (!load_catalog (&catalog, LOAD_AVES | LOAD_MEAS | LOAD_SECF, FALSE)) {
+      unlock_catalog (&catalog);
+      continue;
+    }
+    unlock_catalog (&catalog);
+
+    /* extract values, assign to vectors */
+    for (i = 0; i < catalog.Naverage; i++) {
+      m = catalog.average[i].offset;
+
+      /* PRI/SEC must have data for color term */
+      if (code[0][0].c1 && code[0][0].c2 && !PhotColor (&catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], code[0][0].c1, code[0][0].c2, &color)) continue;
+
+      /* find data for filter 2 (REF) */
+      M2 = NO_MAG;
+      for (j = 0; j < catalog.average[i].Nm; j++) {
+	if (catalog.measure[m+j].source != code[1][0].code) continue;
+	M2 = PhotCat  (&catalog.measure[m+j]); 
+	dM2 = 0.001*catalog.measure[m+j].dM;
+      }	
+      if (M2 == NO_MAG) continue;
+      
+      /* find data for filter 1 */
+      M1 = ExtractMeasures (code[0], mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], &N1, MEAS_MAG);
+      if (N1 == 0) goto skip;
+
+      /* extend storage vectors to take new data, if needed */
+      if (N + N1 >= NSTAR) {
+	NSTAR += N1 + 100;
+	for (k = 0; k < NVEC; k++) {
+	  REALLOCATE (vec[k][0].elements, float, NSTAR);
+	}
+      }
+
+      ConcatMeasures (vec[Nt ], code[0], mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], N1, MEAS_TIME); 
+      ConcatMeasures (vec[Nz ], code[0], mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], N1, MEAS_AIRMASS); 
+      ConcatMeasures (vec[NT ], code[0], mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], N1, MEAS_EXPTIME); 
+      ConcatMeasures (vec[NP ], code[0], mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], N1, MEAS_PHOTCODE); 
+      ConcatMeasures (vec[Nd1], code[0], mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], N1, MEAS_dMAG); 
+      ConcatMeasures (vec[Nxc], code[0], mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], N1, MEAS_XCCD); 
+      ConcatMeasures (vec[Nyc], code[0], mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], N1, MEAS_YCCD); 
+      ConcatMeasures (vec[Nxm], code[0], mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], N1, MEAS_XMOSAIC); 
+      ConcatMeasures (vec[Nym], code[0], mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], N1, MEAS_YMOSAIC); 
+
+      for (j = 0; j < N1; j++, N++) {
+	vec[Nd ][0].elements[N] = M1[j] - M2;
+	vec[Nm1][0].elements[N] = M1[j];
+	vec[Nm2][0].elements[N] = M2;
+	vec[Nd2][0].elements[N] = dM2;
+	vec[Nc ][0].elements[N] = color;
+	vec[Ns ][0].elements[N] = Nstar;
+	vec[NR ][0].elements[N] = catalog.average[i].R;
+	vec[ND ][0].elements[N] = catalog.average[i].D;
+      }
+      Nstar ++; 
+    skip:
+      if (M1 != NULL) free (M1);
+    }
+    if (catalog.average != (Average *) NULL) free (catalog.average);
+    if (catalog.measure != (Measure *) NULL) free (catalog.measure);
+    if (catalog.secfilt != (SecFilt *) NULL) free (catalog.secfilt);
+    catalog.average = (Average *) NULL; 
+    catalog.secfilt = (SecFilt *) NULL;
+    catalog.measure = (Measure *) NULL;
+  }
+  if (regions != NULL) free (regions);  
+  for (i = 0; i < NVEC; i++) {
+    vec[i][0].Nelements = N;
+  }
+  return (TRUE);
+  
+usage:
+  fprintf (stderr, "USAGE: dmags F - F : measure.param\n");
+  return (FALSE);
+
+ escape:
+  
+  if (regions != NULL) free (regions);  
+  for (i = 0; i < NVEC; i++) {
+    DeleteVector (vec[i]);
+  }
+  free (vec);
+  return (FALSE);
+}
+
+int ConcatMeasures (Vector *vec, PhotCode *code, int mode, Average *average, SecFilt *secfilt, Measure *measure, int Nin, int param) {
+
+  int i, Ns, N;
+  double *value;
+
+  value = ExtractMeasures (code, mode, average, secfilt, measure, &N, param); 
+  if (N != Nin) {
+    fprintf (stderr, "error!\n");
+    return (FALSE);
+  }
+
+  Ns = vec[0].Nelements;
+  for (i = 0; i < N; i++) {
+    vec[0].elements[Ns+i] = value[i];
+  }
+  vec[0].Nelements = Ns + N;
+
+  free (value);
+  return (TRUE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/catalog.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/catalog.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/catalog.c	(revision 3338)
@@ -0,0 +1,408 @@
+# include "dvo.h"
+# define NBYTES 160000
+# define BYTES_STAR 23
+# define BLOCK 1000
+# define DNSTARS 1000
+
+# define MAGSCALE 0
+# define NUMSCALE 1
+# define MISSCALE 2
+
+int catlog (int argc, char **argv) {
+  
+  FILE *f;
+  Catalog catalog;
+  Vector Xvec, Yvec, Zvec;
+  int i, N, Nm, Nn, NN, Nbytes, nbytes, Bytes_Star;
+  int Ar, Ad, Am, InRegion, GSC, ASCII, LONEOS, FIXED;
+  char filename[128];
+  double Mz, Mr, Nz, Nr;
+  int clip, mode, IDclip, IDchoice, LimExclude;
+  RegionFile *regions;
+  int j, Nregions;
+  double Radius, Rmin, Rmax;
+  Graphdata graphmode;
+  double epoch, current_epoch;
+  char gscdir[256], catdir[256];
+  int Ngraph;
+
+  Ngraph = 0;
+  if (!GetGraph (&graphmode, NULL, &Ngraph)) return (FALSE);
+
+  VarConfig ("CATDIR", "%s", catdir);
+  VarConfig ("GSCDIR", "%s", gscdir);
+
+  Mz = 17.0;
+  Mr = -5.0;
+  mode = MAGSCALE;
+  clip = FALSE;
+  Rmin = graphmode.coords.crval1 - 182.0;
+  Rmax = graphmode.coords.crval1 + 182.0;
+
+  regions = (RegionFile *) NULL;
+  f = (FILE *) NULL;
+  Nz = Nr = Am = Ar = Ad = 0;
+  /* either MagScale or NumScale, whichever is first is scale */
+  Nm = get_argument (argc, argv, "-m");
+  Nn = get_argument (argc, argv, "+n");
+  NN = get_argument (argc, argv, "-n");
+  if (NN && Nn) {
+    fprintf (stderr, "can't mix meas and miss scaling\n");
+    return (FALSE);
+  }
+ 
+  if (Nm)
+    mode = MAGSCALE;
+  if (Nn)
+    mode = NUMSCALE;
+  if (NN)
+    mode = MISSCALE;
+    
+  if (Nm && Nn) {
+    clip = TRUE;
+    if (Nm < Nn) 
+      mode = MAGSCALE;
+    else 
+      mode = NUMSCALE;
+  }
+  if (Nm && NN) {
+    clip = TRUE;
+    if (Nm < NN) 
+      mode = MAGSCALE;
+    else 
+      mode = MISSCALE;
+  }
+   
+  current_epoch = 2000.0;
+  epoch = 2000.0;
+  if (N = get_argument (argc, argv, "-e")) {
+    remove_argument (N, &argc, argv);
+    epoch  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  IDclip = FALSE;
+  if (N = get_argument (argc, argv, "-ID")) {
+    remove_argument (N, &argc, argv);
+    IDchoice  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    IDclip = TRUE;
+  }
+
+  LimExclude = FALSE;
+  if (N = get_argument (argc, argv, "-x")) {
+    remove_argument (N, &argc, argv);
+    LimExclude = TRUE;
+  }
+
+  if (Nm = get_argument (argc, argv, "-m")) {
+    remove_argument (Nm, &argc, argv);
+    Mr  = 1000*atof(argv[Nm]);
+    remove_argument (Nm, &argc, argv);
+    Mz = 1000*atof(argv[Nm]);
+    Mr = Mr - Mz;
+    remove_argument (Nm, &argc, argv);
+  }
+
+  if (Nn = get_argument (argc, argv, "+n")) {
+    remove_argument (Nn, &argc, argv);
+    Nz  = atof(argv[Nn]);
+    remove_argument (Nn, &argc, argv);
+    Nr = atof(argv[Nn]) - Nz;
+    remove_argument (Nn, &argc, argv);
+  }
+
+  if (Nn = get_argument (argc, argv, "-n")) {
+    remove_argument (Nn, &argc, argv);
+    Nz  = atof(argv[Nn]);
+    remove_argument (Nn, &argc, argv);
+    Nr = atof(argv[Nn]) - Nz;
+    remove_argument (Nn, &argc, argv);
+  }
+
+  InRegion = FALSE;
+  if (N = get_argument (argc, argv, "-all")) {
+    remove_argument (N, &argc, argv);
+    InRegion = TRUE;
+  }
+
+  ASCII = FALSE;
+  LONEOS = TRUE;
+  GSC = FALSE;
+  FIXED = FALSE;
+  if (N = get_argument (argc, argv, "-g")) {
+    remove_argument (N, &argc, argv);
+    GSC = TRUE;
+    ASCII = FALSE;
+    LONEOS = FALSE;
+  }
+
+  if (N = get_argument (argc, argv, "-a")) {
+    remove_argument (N, &argc, argv);
+    ASCII = TRUE;
+    GSC = FALSE;
+    LONEOS = FALSE;
+    Ar = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    Ad = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    Am = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    if (N = get_argument (argc, argv, "-f")) {
+      remove_argument (N, &argc, argv);
+      FIXED = TRUE;
+      ASCII = FALSE;
+      Bytes_Star = atof(argv[N]);
+      remove_argument (N, &argc, argv);
+    }
+  }
+
+  
+  if ((InRegion || (argc != 2)) && (!InRegion || (argc != 1))) {
+    fprintf (stderr, "USAGE: catalog (filename / -all) [-m M M] [-n N N] [-g] [-a RA DEC MAG] \n");
+    return (FALSE);
+  }
+  
+  if (InRegion) {
+    Radius = MAX (fabs(graphmode.xmax), fabs(graphmode.ymax));
+    regions = find_regions (graphmode.coords.crval1, graphmode.coords.crval2, Radius, &Nregions);
+  } else {
+    Nregions = 1;
+  }
+  
+  for (j = 0; j < Nregions; j++) {
+    catalog.average = 0;
+    
+    /* Load in data from an ASCII file list of ra, dec, mag */
+    if (ASCII) {
+      char *tbuffer;
+      int nstar, NSTARS;
+      double R, D, M;
+      
+      f = fopen (argv[1], "r");
+      if (f == (FILE *) NULL) {
+	fprintf (stderr, "ERROR: can't open catalog file: %s\n", argv[1]);
+	return (FALSE);
+      }
+      
+      nstar = 0;
+      NSTARS = DNSTARS;
+      ALLOCATE (tbuffer, char, 1024);
+      ALLOCATE (catalog.average, Average, NSTARS);
+      while (scan_line (f, tbuffer) != EOF) {
+	dparse (&R, Ar, tbuffer);
+	dparse (&D, Ad, tbuffer);
+	dparse (&M, Am, tbuffer);
+	catalog.average[nstar].R = R;
+	catalog.average[nstar].D = D;
+	catalog.average[nstar].M = M * 1000.0;
+	nstar++;
+	if (nstar == NSTARS - 1) {
+	  NSTARS += DNSTARS;
+	  REALLOCATE (catalog.average, Average, NSTARS);
+	}
+      }
+      fclose (f);
+      free (tbuffer);
+      REALLOCATE (catalog.average, Average, nstar);
+      catalog.Naverage = nstar;
+
+      if (epoch != current_epoch) {
+	cprecess (catalog.average, catalog.Naverage, epoch, current_epoch);
+      }
+
+    }
+    
+    /* Load in data from an ASCII file list of ra, dec, mag */
+    if (FIXED) {
+      char *tbuffer;
+      int nstar, NSTARS;
+      double R, D, M;
+      
+      f = fopen (argv[1], "r");
+      if (f == (FILE *) NULL) {
+	fprintf (stderr, "ERROR: can't open catalog file: %s\n", argv[1]);
+	return (FALSE);
+      }
+      
+      nstar = 0;
+      NSTARS = DNSTARS;
+      ALLOCATE (tbuffer, char, (BLOCK*Bytes_Star));
+      ALLOCATE (catalog.average, Average, NSTARS);
+      Nbytes = BLOCK*Bytes_Star;
+      while ((nbytes = fread (tbuffer, 1, Nbytes, f)) > 0) {
+	for (i = 0; i < nbytes / Bytes_Star; i++) {
+	  dparse (&R, Ar, &tbuffer[i*Bytes_Star]);
+	  dparse (&D, Ad, &tbuffer[i*Bytes_Star]);
+	  dparse (&M, Am, &tbuffer[i*Bytes_Star]);
+	  catalog.average[nstar].R = R;
+	  catalog.average[nstar].D = D;
+	  catalog.average[nstar].M = M * 1000.0;
+	  nstar++;
+	  if (nstar == NSTARS - 1) {
+	    NSTARS += DNSTARS;
+	    REALLOCATE (catalog.average, Average, NSTARS);
+	  }
+	}
+      }
+      fclose (f);
+      free (tbuffer);
+      REALLOCATE (catalog.average, Average, nstar);
+      catalog.Naverage = nstar;
+
+      if (epoch != current_epoch) {
+	cprecess (catalog.average, catalog.Naverage, epoch, current_epoch);
+      }
+
+    }
+    
+    /* load data from the GSC files */
+    if (GSC) {
+      char *tbuffer;
+      int nstar, NSTARS;
+      double R, D, M;
+      
+      if (InRegion) {
+	sprintf (filename, "%s/%s", gscdir, regions[j].name);
+      } else {
+	sprintf (filename, "%s/%s", gscdir, argv[1]);
+      }
+      
+      f = fopen (filename, "r");
+      if (f == (FILE *) NULL) {
+	fprintf (stderr, "no stars in %s, skipping\n", filename);
+	continue;
+	/* return (FALSE); */
+      }
+      
+      nstar = 0;
+      NSTARS = DNSTARS;
+      ALLOCATE (tbuffer, char, (BLOCK*BYTES_STAR));
+      ALLOCATE (catalog.average, Average, NSTARS);
+      Nbytes = BLOCK*BYTES_STAR;
+      while ((nbytes = fread (tbuffer, 1, Nbytes, f)) > 0) {
+	for (i = 0; i < nbytes / BYTES_STAR; i++) {
+	  dparse (&R, 1, &tbuffer[i*BYTES_STAR]);
+	  dparse (&D, 2, &tbuffer[i*BYTES_STAR]);
+	  dparse (&M, 3, &tbuffer[i*BYTES_STAR]);
+	  catalog.average[nstar].R = R;
+	  catalog.average[nstar].D = D;
+	  catalog.average[nstar].M = M * 1000.0;
+	  nstar++;
+	  if (nstar == NSTARS - 1) {
+	    NSTARS += DNSTARS;
+	    REALLOCATE (catalog.average, Average, NSTARS);
+	  }
+	}
+      }
+      fclose (f);
+      free (tbuffer);
+      REALLOCATE (catalog.average, Average, nstar);
+      catalog.Naverage = nstar;
+    }
+  
+    /* load data from the photometry database files */
+    if (LONEOS) {
+      
+      if (InRegion) {
+	sprintf (filename, "%s/%s", catdir, regions[j].name);
+      } else {
+	sprintf (filename, "%s/%s", catdir, argv[1]);
+      }
+      
+      /* lock, load, unlock catalog */
+      catalog.filename = filename;
+      switch (lock_catalog (&catalog, LCK_SOFT)) {
+      case 2:
+	unlock_catalog (&catalog);
+      case 0:
+	continue;
+      }
+      if (!load_catalog (&catalog, LOAD_AVES, TRUE)) {
+	unlock_catalog (&catalog);
+	continue;
+      }
+      unlock_catalog (&catalog);
+    }
+    
+    /* data has been loaded, get ready to plot it */
+    Xvec.Nelements = catalog.Naverage;
+    Yvec.Nelements = catalog.Naverage;
+    Zvec.Nelements = catalog.Naverage;
+    ALLOCATE (Xvec.elements, float, Xvec.Nelements);
+    ALLOCATE (Yvec.elements, float, Yvec.Nelements);
+    ALLOCATE (Zvec.elements, float, Zvec.Nelements);
+    /* project stars to screen display coords */
+    Xvec.Nelements = 0;
+    switch (mode) {
+    case (MAGSCALE):
+      for (N = i = 0; i < catalog.Naverage; i++) {
+	if (clip && ((catalog.average[i].Nm < Nz) || (catalog.average[i].Nm > Nr+Nz))) 
+	  continue;
+	if (IDclip && (catalog.average[i].code != IDchoice))
+	  continue;
+	Zvec.elements[N] = MIN (1.0, MAX (0.01, (catalog.average[i].M - Mz) / Mr));
+	if (LimExclude && (Zvec.elements[N] > 0.99)) continue;
+	if (Zvec.elements[N] < 0.011) continue;
+	while (catalog.average[i].R < Rmin) catalog.average[i].R += 360.0;
+	while (catalog.average[i].R > Rmax) catalog.average[i].R -= 360.0;
+	if (fRD_to_XY (&Xvec.elements[N], &Yvec.elements[N], catalog.average[i].R, catalog.average[i].D, &graphmode.coords)) N ++;
+      }
+      break;
+    case (NUMSCALE):
+      for (N = i = 0; i < catalog.Naverage; i++) {
+	if (clip && ((catalog.average[i].M > Mz) || (catalog.average[i].M < Mr+Mz))) 
+	  continue;
+	if (IDclip && (catalog.average[i].code != IDchoice))
+	  continue;
+	Zvec.elements[N] = MIN (1.0, MAX (0.01, (catalog.average[i].Nm - Nz) / Nr));
+	if (LimExclude && (Zvec.elements[N] == 1.0)) continue;
+	if (Zvec.elements[N] == 0.01) 
+	  continue;
+	while (catalog.average[i].R < Rmin) catalog.average[i].R += 360.0;
+	while (catalog.average[i].R > Rmax) catalog.average[i].R -= 360.0;
+	if (fRD_to_XY (&Xvec.elements[N], &Yvec.elements[N], catalog.average[i].R, catalog.average[i].D, &graphmode.coords)) N++;
+      }
+      break;
+    case (MISSCALE):
+      for (N = i = 0; i < catalog.Naverage; i++) {
+	if (clip && ((catalog.average[i].M > Mz) || (catalog.average[i].M < Mr+Mz))) 
+	  continue;
+	if (IDclip && (catalog.average[i].code != IDchoice))
+	  continue;
+	Zvec.elements[N] = MIN (1.0, MAX (0.01, (catalog.average[i].Nn - Nz) / Nr));
+	if (LimExclude && (Zvec.elements[N] == 1.0)) continue;
+	if (Zvec.elements[N] == 0.01) 
+	  continue;
+	while (catalog.average[i].R < Rmin) catalog.average[i].R += 360.0;
+	while (catalog.average[i].R > Rmax) catalog.average[i].R -= 360.0;
+	if (fRD_to_XY (&Xvec.elements[N], &Yvec.elements[N], catalog.average[i].R, catalog.average[i].D, &graphmode.coords)) N++;
+      }
+      break;
+    }
+
+    Zvec.Nelements = Yvec.Nelements = Xvec.Nelements = N;
+    REALLOCATE (Xvec.elements, float, MAX (Xvec.Nelements, 1));
+    REALLOCATE (Yvec.elements, float, MAX (Yvec.Nelements, 1));
+    REALLOCATE (Zvec.elements, float, MAX (Zvec.Nelements, 1));
+    
+    graphmode.style = 2; /* set style to points */
+    graphmode.size = -1; /* point size determined by Zvec */
+    graphmode.etype = 0; /* no errorbars */
+    PrepPlotting (N, &graphmode);
+    
+    PlotVector (N, Xvec.elements);
+    PlotVector (N, Yvec.elements);
+    PlotVector (N, Zvec.elements);
+    
+    free (Xvec.elements);
+    free (Yvec.elements);
+    free (Zvec.elements);
+
+    if (catalog.average != 0) free (catalog.average);
+
+  }
+  return (TRUE);
+
+}
+  
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/ccd.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/ccd.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/ccd.c	(revision 3338)
@@ -0,0 +1,125 @@
+# include "dvo.h"
+
+int ccd (int argc, char **argv) {
+  
+  Catalog catalog;
+  Graphdata graphsky;
+  RegionFile *regions;
+  PhotCode *code[4];
+  Vector *xvec, *yvec;
+
+  char filename[256], catdir[256];
+  double Radius;
+  double *M1, *M2;
+  int i, m, k, Npts, NPTS;
+  int N1, N2, i1, i2, mode[4];
+  int Ngraph, Nsec, Nregions, UseAverages;
+
+  /* defaults */
+  regions = NULL;
+  catalog.average = NULL; 
+  catalog.secfilt = NULL;
+  catalog.measure = NULL;
+
+  /* load photcode information */
+  if (!InitPhotcodes ()) goto escape;
+  Nsec = GetPhotcodeNsecfilt ();
+
+  /* load data about plot windows */
+  Ngraph = 0;
+  if (!GetGraphData (&graphsky, NULL, &Ngraph)) return (FALSE);
+ 
+  /* find CATDIR in config system */
+  VarConfig ("CATDIR", "%s", catdir);
+
+  /* interpret command-line options */
+  if (!SetPhotSelections (&argc, argv)) goto usage;
+  if (argc != 8) goto usage;
+  if (strcmp (argv[2], "-")) goto usage;
+  if (strcmp (argv[4], ":")) goto usage;
+  if (strcmp (argv[6], "-")) goto usage;
+
+  /* interpret command-line options */
+  if (!GetPhotcodeInfo (argv[1], &code[0], &mode[0])) return (FALSE);
+  if (!GetPhotcodeInfo (argv[3], &code[1], &mode[1])) return (FALSE);
+  if (!GetPhotcodeInfo (argv[5], &code[2], &mode[2])) return (FALSE);
+  if (!GetPhotcodeInfo (argv[7], &code[3], &mode[3])) return (FALSE);
+  if ((mode[2] == MAG_AVE) || (mode[2] == MAG_REF)) UseAverages = TRUE;
+
+  /* find catalog files which overlap this region */
+  Radius = MAX (fabs(graphsky.xmax), fabs(graphsky.ymax));
+  regions = find_regions (graphsky.coords.crval1, graphsky.coords.crval2, Radius, &Nregions);
+
+  /* init vectors to save data */
+  Npts = 0;
+  NPTS = 1;
+  if ((xvec = SelectVector ("xv", ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((yvec = SelectVector ("yv", ANYVECTOR, TRUE)) == NULL) goto escape;
+
+  /* loop over regions, extract data for each region */
+  for (k = 0; k < Nregions; k++) {
+    /* lock, load, unlock catalog */
+    sprintf (filename, "%s/%s", catdir, regions[k].name);
+    catalog.filename = filename;
+    switch (lock_catalog (&catalog, LCK_SOFT)) {
+      case 2:
+	unlock_catalog (&catalog);
+      case 0:
+	continue;
+    }
+    if (!load_catalog (&catalog, LOAD_AVES | LOAD_MEAS | LOAD_SECF, FALSE)) {
+      unlock_catalog (&catalog);
+      continue;
+    }
+    unlock_catalog (&catalog);
+
+    /* get correct mags, convert to X,Y */
+    for (i = 0; i < catalog.Naverage; i++) {
+      M1 = M2 = NULL;
+      m = catalog.average[i].offset;
+
+      M1 = ExtractDMag (&code[0], &mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], &N1);
+      if (N1 == 0) goto skip;
+
+      M2 = ExtractDMag (&code[2], &mode[2], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], &N2);
+      if (N2 == 0) goto skip;
+
+      for (i1 = 0; i1 < N1; i1++) {
+	for (i2 = 0; i2 < N2; i2++) {
+	  xvec[0].elements[Npts] = M1[i1];
+	  yvec[0].elements[Npts] = M2[i2];
+	  Npts++;
+	  if (Npts == NPTS) {
+	    NPTS += 2000;
+	    REALLOCATE (xvec[0].elements, float, NPTS);
+	    REALLOCATE (yvec[0].elements, float, NPTS);
+	  }
+	}
+      }
+    skip:
+      if (M1 != NULL) free (M1);
+      if (M2 != NULL) free (M2);
+    }
+    if (catalog.average != NULL) free (catalog.average);
+    if (catalog.secfilt != NULL) free (catalog.secfilt);
+    if (catalog.measure != NULL) free (catalog.measure);
+    catalog.average = (Average *) NULL; 
+    catalog.secfilt = (SecFilt *) NULL;
+    catalog.measure = (Measure *) NULL;
+  }
+  if (regions != NULL) free (regions);
+  xvec[0].Nelements = yvec[0].Nelements = Npts;
+  return (TRUE);
+
+usage:
+  fprintf (stderr, "USAGE: ccd F - F : measure.param\n");
+  return (FALSE);
+
+escape:
+  if (regions != NULL) free (regions);
+  if (catalog.average != NULL) free (catalog.average);
+  if (catalog.secfilt != NULL) free (catalog.secfilt);
+  if (catalog.measure != NULL) free (catalog.measure);
+  return (FALSE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/cmatch.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/cmatch.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/cmatch.c	(revision 3338)
@@ -0,0 +1,115 @@
+# include "dvo.h"
+# define BYTES_STAR 23
+# define BLOCK 1000
+# define DNSTARS 1000
+
+int cmatch (int argc, char **argv) {
+  
+  FILE *f;
+  Catalog catalog1, catalog2;
+  int i, Nbytes, nbytes, Nitems, nitems;
+  char *tbuffer, filename[128];
+  int nstar, NSTARS;
+  double R, D, M, radius;
+  char catdir[256], gscdir[256];
+  Vector *rvec, *dvec, *mvec, *drvec, *ddvec, *dmvec;
+
+  VarConfig ("CATDIR", "%s", catdir);
+  VarConfig ("GSCDIR", "%s", gscdir);
+      
+  if (argc != 9) {
+    fprintf (stderr, "USAGE: cmatch file radius (RA) (DEC) (Mag) (dRA) (dDEC) (dMag)\n");
+    return (FALSE);
+  }
+
+  radius = atof (argv[2]);
+
+  if ((rvec  = SelectVector (argv[3], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((dvec  = SelectVector (argv[4], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((mvec  = SelectVector (argv[5], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((drvec = SelectVector (argv[6], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((ddvec = SelectVector (argv[7], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((dmvec = SelectVector (argv[8], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  /* load data from the photometry database file */
+  sprintf (filename, "%s/%s", catdir, argv[1]);
+  if (!fits_read_header (filename, &catalog1.header)) {
+    fprintf (stderr, "no stars in %s\n", filename);
+    return (FALSE);
+  }
+  f = fopen (filename, "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "no stars in %s\n", filename);
+    return (FALSE);
+  }
+  fseek (f, catalog1.header.size, SEEK_SET); 
+  
+  /** find number of stars, measurements **/
+  catalog1.Naverage = 0;
+  fits_scan (&catalog1.header, "NSTARS", "%d", 1, &catalog1.Naverage);
+  if (catalog1.Naverage == 0) {
+    fprintf (stderr, "no stars in catalog %s\n", filename);
+    fclose (f);
+    return (TRUE);
+  }
+  ALLOCATE (catalog1.average, Average, catalog1.Naverage);
+  Nitems = catalog1.Naverage;
+  nitems = Fread (catalog1.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);
+    free (catalog1.average);
+    return (FALSE);
+  }
+  fclose (f);
+  fprintf (stderr, "read %d stars from phot catalog file %s\n", catalog1.Naverage, filename);
+
+  /* load data from the GSC file */
+  sprintf (filename, "%s/%s", gscdir, argv[1]);
+  f = fopen (filename, "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "no stars in %s\n", filename);
+    free (catalog1.average);
+    return (FALSE);
+    /* return (FALSE); */
+  }
+  
+  nstar = 0;
+  NSTARS = DNSTARS;
+  ALLOCATE (tbuffer, char, (BLOCK*BYTES_STAR));
+  ALLOCATE (catalog2.average, Average, NSTARS);
+  Nbytes = BLOCK*BYTES_STAR;
+  while ((nbytes = fread (tbuffer, 1, Nbytes, f)) > 0) {
+    for (i = 0; i < nbytes / BYTES_STAR; i++) {
+      dparse (&R, 1, &tbuffer[i*BYTES_STAR]);
+      dparse (&D, 2, &tbuffer[i*BYTES_STAR]);
+      dparse (&M, 3, &tbuffer[i*BYTES_STAR]);
+      catalog2.average[nstar].R = R;
+      catalog2.average[nstar].D = D;
+      catalog2.average[nstar].M = M * 1000.0;
+      nstar++;
+      if (nstar == NSTARS - 1) {
+	NSTARS += DNSTARS;
+	REALLOCATE (catalog2.average, Average, NSTARS);
+      }
+    }
+  }
+  free (tbuffer);
+  REALLOCATE (catalog2.average, Average, MAX (nstar, 1));
+  catalog2.Naverage = nstar;
+  fclose (f);
+
+  /* sort data in order of RA */
+  sortave (catalog1.average, catalog1.Naverage);
+  sortave (catalog2.average, catalog2.Naverage);
+
+  /* data has been loaded, use gcompare algorithm to match */
+  compare (&catalog1, &catalog2, rvec, dvec, mvec, drvec, ddvec, dmvec, radius);
+
+  free (catalog1.average);
+  free (catalog2.average);
+
+  return (TRUE);
+
+}
+  
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/cmd.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/cmd.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/cmd.c	(revision 3338)
@@ -0,0 +1,121 @@
+# include "dvo.h"
+
+int cmd (int argc, char **argv) { /* really need to think about upper limits & how to represent them */
+  
+  Catalog catalog;
+  Graphdata graphsky;
+  RegionFile *regions;
+  PhotCode *code[3];
+  Vector *xvec, *yvec;
+
+  char filename[256], catdir[256];
+  double Radius, *M1, *M3;
+  int i, j, m, i1, i3, N1, N3;
+  int Npts, NPTS, mode[3];
+  int Ngraph, Nsec, Nregions;
+
+  /* defaults */
+  regions = NULL;
+  catalog.average = NULL; 
+  catalog.secfilt = NULL;
+  catalog.measure = NULL;
+
+  /* load photcode information */
+  if (!InitPhotcodes ()) goto escape;
+  Nsec = GetPhotcodeNsecfilt ();
+
+  /* load data about plot windows */
+  Ngraph = 0;
+  if (!GetGraphData (&graphsky, NULL, &Ngraph)) return (FALSE);
+ 
+  /* find CATDIR in config system */
+  VarConfig ("CATDIR", "%s", catdir);
+
+  /* interpret command-line options */
+  if (!SetPhotSelections (&argc, argv)) goto usage;
+  if (argc != 6) { goto usage; }
+  if (strcmp (argv[2], "-")) goto usage;
+  if (strcmp (argv[4], ":")) goto usage;
+
+  /* interpret command-line options */
+  if (!GetPhotcodeInfo (argv[1], &code[0], &mode[0])) return (FALSE);
+  if (!GetPhotcodeInfo (argv[3], &code[1], &mode[1])) return (FALSE);
+  if (!GetPhotcodeInfo (argv[5], &code[2], &mode[2])) return (FALSE);
+
+  /* find catalog files which overlap this region */
+  Radius = MAX (fabs(graphsky.xmax), fabs(graphsky.ymax));
+  regions = find_regions (graphsky.coords.crval1, graphsky.coords.crval2, Radius, &Nregions);
+
+  /* init vectors to save data */
+  Npts = 0;
+  NPTS = 1;
+  if ((xvec = SelectVector ("xv", ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((yvec = SelectVector ("yv", ANYVECTOR, TRUE)) == NULL) goto escape;
+
+  /* loop over regions, extract data for each region */
+  for (j = 0; j < Nregions; j++) {
+    /* lock, load, unlock catalog */
+    sprintf (filename, "%s/%s", catdir, regions[j].name);
+    catalog.filename = filename;
+    switch (lock_catalog (&catalog, LCK_SOFT)) {
+    case 2:
+      unlock_catalog (&catalog);
+    case 0:
+      continue;
+    }
+    if (!load_catalog (&catalog, LOAD_AVES | LOAD_MEAS | LOAD_SECF, FALSE)) {
+      unlock_catalog (&catalog);
+      continue;
+    }
+    unlock_catalog (&catalog);
+    
+    /* get correct mags, convert to X,Y */
+    for (i = 0; i < catalog.Naverage; i++) {
+      M1 = M3 = NULL;
+      m = catalog.average[i].offset;
+
+      M1 = ExtractDMag (code, mode, &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], &N1);
+      if (N1 == 0) goto skip;
+
+      M3 = ExtractMagnitudes (code[2], mode[2], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], &N3);
+      if (N3 == 0) goto skip;
+
+      for (i1 = 0; i1 < N1; i1++) {
+	for (i3 = 0; i3 < N3; i3++) {
+	  xvec[0].elements[Npts] = M1[i1];
+	  yvec[0].elements[Npts] = M3[i3];
+	  Npts++;
+	  if (Npts == NPTS) {
+	    NPTS += 2000;
+	    REALLOCATE (xvec[0].elements, float, NPTS);
+	    REALLOCATE (yvec[0].elements, float, NPTS);
+	  }
+	}
+      }
+    skip:
+      if (M1 != NULL) free (M1);
+      if (M3 != NULL) free (M3);
+    }
+    if (catalog.average != NULL) free (catalog.average);
+    if (catalog.secfilt != NULL) free (catalog.secfilt);
+    if (catalog.measure != NULL) free (catalog.measure);
+    catalog.average = (Average *) NULL; 
+    catalog.secfilt = (SecFilt *) NULL;
+    catalog.measure = (Measure *) NULL;
+  }
+  if (regions != NULL) free (regions);
+  xvec[0].Nelements = yvec[0].Nelements = Npts;
+  return (TRUE);
+
+usage:
+  fprintf (stderr, "USAGE: cmd F - F : F\n");
+  return (FALSE);
+
+escape:
+  if (regions != NULL) free (regions);
+  if (catalog.average != NULL) free (catalog.average);
+  if (catalog.secfilt != NULL) free (catalog.secfilt);
+  if (catalog.measure != NULL) free (catalog.measure);
+  return (FALSE);
+}
+    
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/cmpload.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/cmpload.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/cmpload.c	(revision 3338)
@@ -0,0 +1,162 @@
+# include "dvo.h"
+# define D_NSTARS 1000
+# define BYTES_STAR 66
+# define BLOCK 1000
+
+int cmpload (int argc, char **argv) {
+  
+  int i, nstar, N, Nin, Nout, Nextra, n, Type, type;
+  int doneread, done, Nskip, Nbytes, nbytes, Ninstar;
+  char *c, *c2;
+  double *X, *Y, *M;
+  double dtmp;
+  FILE *f;
+  char *buffer, *buffer2, *line;
+  Header header;
+  int Ximage, Nimage;
+  
+  Nimage = -1;
+  if (N = get_argument (argc, argv, "-n")) {
+    remove_argument (N, &argc, argv);
+    Nimage = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetImage (&Ximage, &Nimage)) return (FALSE);
+
+  Type = 0;
+  if (N = get_argument (argc, argv, "-t")) {
+    remove_argument (N, &argc, argv);
+    Type = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: load (overlay) <filename>\n");
+    return (FALSE);
+  }
+
+  if (!SelectOverlay (argv[1], &n)) 
+    return (FALSE);
+
+  if (!fits_read_header (argv[2], &header)) {
+    fprintf (stderr, "ERROR: can't read header for %s\n", argv[2]);
+    return (FALSE);
+  }
+
+  /* find expected number of stars */
+  fits_scan (&header, "NSTARS", "%d", 1, &nstar);
+  if (nstar == 0) {
+    fprintf (stderr, "ERROR: can't get NSTARS from header\n");
+    fits_free_header (&header);
+    return (FALSE);
+  }
+
+  f = fopen (argv[2], "r");
+  if (f == NULL) {
+    fprintf (stderr, "ERROR: can't read data from %s\n", argv[2]);
+    fits_free_header (&header);
+    return (FALSE);
+  }
+  fseek (f, header.size, SEEK_SET); 
+
+  ALLOCATE (X, double, nstar);
+  ALLOCATE (Y, double, nstar);
+  ALLOCATE (M, double, nstar);
+
+  /* load in stars by blocks of 1000 */
+  Nin = 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);
+    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);
+      }
+      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);
+      } else {
+	c = c2;
+      }
+    }
+    Ninstar = nbytes / BYTES_STAR;
+    Nextra = nbytes % BYTES_STAR;
+    for (i = 0; i < Ninstar; i++, Nin++) {
+      dparse (&X[Nin],  1, &buffer[i*BYTES_STAR]);
+      dparse (&Y[Nin],  2, &buffer[i*BYTES_STAR]);
+      dparse (&M[Nin],  3, &buffer[i*BYTES_STAR]);
+      if (Type) {
+	dparse (&dtmp, 5, &buffer[i*BYTES_STAR]);
+	type = dtmp;
+	if (type != Type) {
+	  Nin --;
+	}
+      }
+    }
+  }
+  fclose (f);
+
+  ALLOCATE (line, char, 129);
+  write (Ximage, "LOAD", 4); /* force Ximage to look for the incoming image */
+  sprintf (line, "OVER %9d ", n);
+  write (Ximage, line, 16);
+  
+  ALLOCATE (buffer2, char, 66000);
+  bzero (buffer2, 65536);
+  for (Nout = i = 0; i < Nin; i++, Nout++) {
+    sprintf (&buffer2[Nout*128], "%15s %20.10f %20.10f %20.10f %20.10f ", "BOX", X[i], Y[i], 5.0, 5.0);
+    if (Nout == 512) {
+      sprintf (line, "NLINES  %7d ", Nout);
+      write (Ximage, line, 16);
+      write (Ximage, buffer2, Nout*128);
+      bzero (buffer2, 65536);
+      Nout = -1;
+    }
+  }
+
+  if (Nout) {
+    sprintf (line, "NLINES  %7d ", Nout);
+    write (Ximage, line, 16);
+    write (Ximage, buffer2, Nout*128);
+  }
+  sprintf (line, "DONE ");
+  write (Ximage, line, 16);
+
+  fits_free_header (&header);
+  free (X);
+  free (Y);
+  free (M);
+  free (buffer);
+  /*  */
+
+  free (buffer2);
+  free (line);
+
+  fprintf (stderr, "loaded %d objects\n", Nin);
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/cmpread.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/cmpread.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/cmpread.c	(revision 3338)
@@ -0,0 +1,148 @@
+# include "dvo.h"
+# define D_NSTARS 1000
+# define BYTES_STAR 66
+# define BLOCK 1000
+
+int cmpread (int argc, char **argv) {
+  
+  int i, nstar, Nin, Nextra;
+  int doneread, done, Nskip, Nbytes, nbytes, Ninstar, RAnDEC;
+  char *c, *c2, *name, *file;
+  float *R, *D, *V;
+  double tR, tD, tmp, X, Y;
+  FILE *f;
+  char *buffer;
+  int Nfield, Nra, Ndec;
+  Vector *rvec, *dvec, *vec;
+  Header header;
+  Coords coords;
+
+  if ((argc != 4) && (argc != 6)) {
+    fprintf (stderr, "USAGE: cmpread name Nfield <filename>\n");
+    fprintf (stderr, "USAGE: cmpread ra N dec N <filename>\n");
+    return (FALSE);
+  }
+
+  if (argc == 4) {
+    name = strcreate (argv[1]);
+    Nfield = atof (argv[2]);
+    file = strcreate (argv[3]);
+    RAnDEC = FALSE;
+  } else {
+    Nra  = atof (argv[2]);
+    Ndec = atof (argv[4]);
+    file = strcreate (argv[5]);
+    RAnDEC = TRUE;
+  }    
+
+  if (!fits_read_header (file, &header)) {
+    fprintf (stderr, "ERROR: can't read header for %s\n", file);
+    free (file);
+    if (!RAnDEC) free (name);
+    return (FALSE);
+  }
+
+  /* find expected number of stars */
+  fits_scan (&header, "NSTARS", "%d", 1, &nstar);
+  if (nstar == 0) {
+    fprintf (stderr, "ERROR: can't get NSTARS from header\n");
+    free (file);
+    if (!RAnDEC) free (name);
+    fits_free_header (&header);
+    return (FALSE);
+  }
+
+  f = fopen (file, "r");
+  if (f == NULL) {
+    fprintf (stderr, "ERROR: can't read data from %s\n", file);
+    free (file);
+    if (!RAnDEC) free (name);
+    fits_free_header (&header);
+    return (FALSE);
+  }
+  fseek (f, header.size, SEEK_SET); 
+
+  if (RAnDEC) {
+    if ((rvec = SelectVector ("ra",  ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    if ((dvec = SelectVector ("dec",  ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    REALLOCATE (rvec[0].elements, float, nstar);
+    REALLOCATE (dvec[0].elements, float, nstar);
+    R = rvec[0].elements;
+    D = dvec[0].elements;
+    rvec[0].Nelements = dvec[0].Nelements = nstar;
+    if (!GetCoords (&coords, &header)) {
+      fprintf (stderr, "can't get WCS info from header\n");
+      return (FALSE);
+    }
+  } else {
+    if ((vec = SelectVector (name, ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    REALLOCATE (vec[0].elements, float, nstar);
+    V = vec[0].elements;
+    vec[0].Nelements = nstar;
+  }
+
+  /* load in stars by blocks of 1000 */
+  Nin = 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);
+    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);
+      }
+      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);
+      } else {
+	c = c2;
+      }
+    }
+    Ninstar = nbytes / BYTES_STAR;
+    Nextra = nbytes % BYTES_STAR;
+    for (i = 0; i < Ninstar; i++, Nin++) {
+      if (RAnDEC) {
+	dparse (&X, Nra,  &buffer[i*BYTES_STAR]);
+	dparse (&Y, Ndec, &buffer[i*BYTES_STAR]);
+	XY_to_RD (&tR, &tD, X, Y, &coords);
+	R[Nin] = tR; D[Nin] = tD;
+      } else {
+	dparse (&tmp, Nfield, &buffer[i*BYTES_STAR]);
+	V[Nin] = tmp;
+      }
+    }
+  }
+  fclose (f);
+
+  fits_free_header (&header);
+  free (buffer);
+  free (file);
+  if (!RAnDEC) free (name);
+
+  fprintf (stderr, "loaded %d objects\n", Nin);
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/compare.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/compare.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/compare.c	(revision 3338)
@@ -0,0 +1,76 @@
+# include "dvo.h"
+# define D_NMATCH 500;
+
+void compare (Catalog *catlog1, Catalog *catlog2, 
+	 Vector *rvec,  Vector *dvec,  Vector *mvec, Vector *drvec, Vector *ddvec, Vector *dmvec, double radius) {
+
+  int i, j, first_j, Nmatch, NMATCH;
+  double dX, dY, dR;
+
+  Nmatch = 0;
+  NMATCH = D_NMATCH;
+  REALLOCATE (rvec[0].elements, float, NMATCH);
+  REALLOCATE (dvec[0].elements, float, NMATCH);
+  REALLOCATE (mvec[0].elements, float, NMATCH);
+  REALLOCATE (drvec[0].elements, float, NMATCH);
+  REALLOCATE (ddvec[0].elements, float, NMATCH);
+  REALLOCATE (dmvec[0].elements, float, NMATCH);
+
+  for (i = j = 0; (i < catlog1[0].Naverage) && (j < catlog2[0].Naverage);) {
+    
+    dX = catlog1[0].average[i].R - catlog2[0].average[j].R;
+
+    if (!(i % 100))
+      fprintf (stderr, ".");
+    
+    if (dX <= -radius)
+      i++;
+    if (dX >= radius)
+      j++;
+
+    if (fabs (dX) < radius) {
+      first_j = j;
+      for (j = first_j; (fabs (dX) < radius) && (j < catlog2[0].Naverage); j++) {
+	dX = catlog1[0].average[i].R - catlog2[0].average[j].R;
+	dY = catlog1[0].average[i].D - catlog2[0].average[j].D;
+	dR = hypot (dX, dY);
+	if (dR < radius) {
+	   rvec[0].elements[Nmatch] = catlog1[0].average[i].R;
+	   dvec[0].elements[Nmatch] = catlog1[0].average[i].D;
+	   mvec[0].elements[Nmatch] = catlog1[0].average[i].M;
+	  drvec[0].elements[Nmatch] = dX;
+	  ddvec[0].elements[Nmatch] = dY;
+	  dmvec[0].elements[Nmatch] = catlog1[0].average[i].M - catlog2[0].average[j].M;
+	  Nmatch ++;
+	  if (Nmatch == NMATCH - 1) {
+	    NMATCH += D_NMATCH;
+	    REALLOCATE ( rvec[0].elements, float, NMATCH);
+	    REALLOCATE ( dvec[0].elements, float, NMATCH);
+	    REALLOCATE ( mvec[0].elements, float, NMATCH);
+	    REALLOCATE (drvec[0].elements, float, NMATCH);
+	    REALLOCATE (ddvec[0].elements, float, NMATCH);
+	    REALLOCATE (dmvec[0].elements, float, NMATCH);
+	  }
+	}
+      }
+      j = first_j;
+      i++;
+    }
+  }
+
+  REALLOCATE ( rvec[0].elements, float, Nmatch);
+  REALLOCATE ( dvec[0].elements, float, Nmatch);
+  REALLOCATE ( mvec[0].elements, float, Nmatch);
+  REALLOCATE (drvec[0].elements, float, Nmatch);
+  REALLOCATE (ddvec[0].elements, float, Nmatch);
+  REALLOCATE (dmvec[0].elements, float, Nmatch);
+  
+   rvec[0].Nelements = Nmatch;
+   dvec[0].Nelements = Nmatch;
+   mvec[0].Nelements = Nmatch;
+  drvec[0].Nelements = Nmatch;
+  ddvec[0].Nelements = Nmatch;
+  dmvec[0].Nelements = Nmatch;
+
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/ddmags.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/ddmags.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/ddmags.c	(revision 3338)
@@ -0,0 +1,125 @@
+# include "dvo.h"
+
+int ddmags (int argc, char **argv) {
+  
+  Catalog catalog;
+  Graphdata graphsky;
+  RegionFile *regions;
+  PhotCode *code[4];
+  Vector *xvec, *yvec;
+
+  char filename[256], catdir[256];
+  double Radius;
+  double *M1, *M2;
+  int i, m, k, Npts, NPTS;
+  int N1, N2, i1, i2, mode[4];
+  int Ngraph, Nsec, Nregions, UseAverages;
+
+  /* defaults */
+  regions = NULL;
+  catalog.average = NULL; 
+  catalog.secfilt = NULL;
+  catalog.measure = NULL;
+
+  /* load photcode information */
+  if (!InitPhotcodes ()) goto escape;
+  Nsec = GetPhotcodeNsecfilt ();
+
+  /* load data about plot windows */
+  Ngraph = 0;
+  if (!GetGraphData (&graphsky, NULL, &Ngraph)) return (FALSE);
+ 
+  /* find CATDIR in config system */
+  VarConfig ("CATDIR", "%s", catdir);
+
+  /* interpret command-line options */
+  if (!SetPhotSelections (&argc, argv)) goto usage;
+  if (argc != 8) goto usage;
+  if (strcmp (argv[2], "-")) goto usage;
+  if (strcmp (argv[4], ":")) goto usage;
+  if (strcmp (argv[6], "-")) goto usage;
+
+  /* interpret command-line options */
+  if (!GetPhotcodeInfo (argv[1], &code[0], &mode[0])) return (FALSE);
+  if (!GetPhotcodeInfo (argv[3], &code[1], &mode[1])) return (FALSE);
+  if (!GetPhotcodeInfo (argv[5], &code[2], &mode[2])) return (FALSE);
+  if (!GetPhotcodeInfo (argv[7], &code[3], &mode[3])) return (FALSE);
+  if ((mode[2] == MAG_AVE) || (mode[2] == MAG_REF)) UseAverages = TRUE;
+
+  /* find catalog files which overlap this region */
+  Radius = MAX (fabs(graphsky.xmax), fabs(graphsky.ymax));
+  regions = find_regions (graphsky.coords.crval1, graphsky.coords.crval2, Radius, &Nregions);
+
+  /* init vectors to save data */
+  Npts = 0;
+  NPTS = 1;
+  if ((xvec = SelectVector ("xv", ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((yvec = SelectVector ("yv", ANYVECTOR, TRUE)) == NULL) goto escape;
+
+  /* loop over regions, extract data for each region */
+  for (k = 0; k < Nregions; k++) {
+    /* lock, load, unlock catalog */
+    sprintf (filename, "%s/%s", catdir, regions[k].name);
+    catalog.filename = filename;
+    switch (lock_catalog (&catalog, LCK_SOFT)) {
+      case 2:
+	unlock_catalog (&catalog);
+      case 0:
+	continue;
+    }
+    if (!load_catalog (&catalog, LOAD_AVES | LOAD_MEAS | LOAD_SECF, FALSE)) {
+      unlock_catalog (&catalog);
+      continue;
+    }
+    unlock_catalog (&catalog);
+
+    /* get correct mags, convert to X,Y */
+    for (i = 0; i < catalog.Naverage; i++) {
+      M1 = M2 = NULL;
+      m = catalog.average[i].offset;
+
+      M1 = ExtractDMag (&code[0], &mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], &N1);
+      if (N1 == 0) goto skip;
+
+      M2 = ExtractDMag (&code[2], &mode[2], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], &N2);
+      if (N2 == 0) goto skip;
+
+      for (i1 = 0; i1 < N1; i1++) {
+	for (i2 = 0; i2 < N2; i2++) {
+	  xvec[0].elements[Npts] = M1[i1];
+	  yvec[0].elements[Npts] = M2[i2];
+	  Npts++;
+	  if (Npts == NPTS) {
+	    NPTS += 2000;
+	    REALLOCATE (xvec[0].elements, float, NPTS);
+	    REALLOCATE (yvec[0].elements, float, NPTS);
+	  }
+	}
+      }
+    skip:
+      if (M1 != NULL) free (M1);
+      if (M2 != NULL) free (M2);
+    }
+    if (catalog.average != NULL) free (catalog.average);
+    if (catalog.secfilt != NULL) free (catalog.secfilt);
+    if (catalog.measure != NULL) free (catalog.measure);
+    catalog.average = (Average *) NULL; 
+    catalog.secfilt = (SecFilt *) NULL;
+    catalog.measure = (Measure *) NULL;
+  }
+  if (regions != NULL) free (regions);
+  xvec[0].Nelements = yvec[0].Nelements = Npts;
+  return (TRUE);
+
+usage:
+  fprintf (stderr, "USAGE: ddmags F - F : measure.param\n");
+  return (FALSE);
+
+escape:
+  if (regions != NULL) free (regions);
+  if (catalog.average != NULL) free (catalog.average);
+  if (catalog.secfilt != NULL) free (catalog.secfilt);
+  if (catalog.measure != NULL) free (catalog.measure);
+  return (FALSE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/detrend.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/detrend.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/detrend.c	(revision 3338)
@@ -0,0 +1,201 @@
+# include "dvo.h"
+
+/* qualities to be extracted */
+enum {ZERO, DTIME, SKY, BIAS, FWHM, AIRM, TIME, TEMP};
+
+detrend (int argc, char **argv) {
+ 
+  FILE *f;
+  int i, Nimage, status, N, TimeSelect;
+  char DataBase[256];
+  unsigned long int tzero, tend;
+  double trange;
+  int TypeSelect, CCDSelect, FilterSelect;
+  char *Filter;
+  int Type, mode, CCD;
+  int NVALUE;
+  float *value;
+  time_t TimeReference;
+  int TimeFormat;
+  Header header;
+  RegImage *pimage;
+  Vector *vec;
+
+  VarConfig ("REGISTRATION_DATABASE", "%s", DataBase);
+
+  TimeSelect = FALSE;
+  if (N = get_argument (argc, argv, "-time")) {
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &tzero)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (!str_to_dtime (argv[N], &trange)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (trange < 0) {
+      trange = fabs (trange);
+      tzero -= trange;
+    }
+    TimeSelect = TRUE;
+  }
+  if (N = get_argument (argc, argv, "-trange")) {
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &tzero)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &tend)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    trange = tend - tzero;
+    if (trange < 0) {
+      trange = fabs (trange);
+      tzero -= trange;
+    }
+    TimeSelect = TRUE;
+  }
+ 
+  TypeSelect = FALSE;
+  if (N = get_argument (argc, argv, "-type")) {
+    remove_argument (N, &argc, argv);
+    Type = get_image_type (argv[N]);
+    if (Type == T_UNDEF) {
+      fprintf (stderr, "ERROR: invalid image type %s\n", argv[N]);
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    TypeSelect = TRUE;
+  }
+
+  CCDSelect = FALSE;
+  if (N = get_argument (argc, argv, "-ccd")) {
+    remove_argument (N, &argc, argv);
+    CCD = atoi (argv[N]);
+    remove_argument (N, &argc, argv);
+    CCDSelect = TRUE;
+  }
+ 
+  FilterSelect = FALSE;
+  if (N = get_argument (argc, argv, "-filter")) {
+    remove_argument (N, &argc, argv);
+    Filter = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+    FilterSelect = TRUE;
+    if (!strcasecmp (Filter, "X")) {
+      FilterSelect = FALSE;
+    }
+  }
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: imrough (value)\n");
+    return (FALSE);
+  }
+  
+  /* identify selection */
+  mode = ZERO;
+  if (!strcasecmp (argv[1], "exptime")) mode = DTIME;
+  if (!strcasecmp (argv[1], "sky")) mode = SKY;
+  if (!strcasecmp (argv[1], "bias")) mode = BIAS;
+  if (!strcasecmp (argv[1], "fwhm")) mode = FWHM;
+  if (!strcasecmp (argv[1], "airmass")) mode = AIRM;
+  if (!strcasecmp (argv[1], "time")) mode = TIME;
+  if (!strcasecmp (argv[1], "temp")) mode = TEMP;
+  if (mode == ZERO) {
+    fprintf (stderr, "value may be one of the following:\n");
+    fprintf (stderr, " exptime, sky, bias, fwhm, airmass, time\n");
+    return (FALSE);
+  }
+
+  if ((vec = SelectVector (argv[1], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  /* load in database header */
+  if (!fits_read_header (DataBase, &header)) {
+    fprintf (stderr, "ERROR: trouble reading database header\n");
+    return (FALSE);
+  }
+
+  /* open database */
+  f = fopen (DataBase, "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "ERROR: can't open Registration Database\n");
+    return (FALSE);
+  }
+  fseek (f, header.size, SEEK_SET);
+
+  /* load existing data from database */
+  fits_scan (&header, "NIMAGES", "%d", 1, &Nimage);
+  ALLOCATE (pimage, RegImage, Nimage);
+  status = Fread (pimage, sizeof(RegImage), Nimage, f, "regimage");
+  fclose (f);
+
+  if (status != Nimage) {
+    fprintf (stderr, "ERROR: header and data in dB don't match (%d vs %d)\n", Nimage, status);
+    fits_free_header (&header);
+    free (pimage);
+    return (FALSE);
+  }
+
+  N = 0;
+  NVALUE = 1000;
+  REALLOCATE (vec[0].elements, float, NVALUE);
+  value = vec[0].elements;
+
+  GetTimeFormat (&TimeReference, &TimeFormat);
+  fprintf (stderr, "%d %d\n", TimeReference, TimeFormat);
+
+  /* get data */
+  for (i = 0; i < Nimage; i++) {
+    /* skip unmatched selections */
+    if (TimeSelect && ((pimage[i].obstime < tzero) || (pimage[i].obstime > tzero + trange))) continue;
+    if (TimeSelect && ((pimage[i].obstime < tzero) || (pimage[i].obstime > tzero + trange))) continue;
+    if (FilterSelect && (strcasecmp (pimage[i].filter, Filter))) continue;
+    if (CCDSelect && (pimage[i].ccd != CCD)) continue;
+    if (TypeSelect && (pimage[i].type != Type)) continue;
+
+    /* assign correct value */
+    switch (mode) {
+    case (DTIME):
+      value[N] = pimage[i].exptime;
+      break;
+    case (TIME):
+      value[N] = TimeValue (pimage[i].obstime, TimeReference, TimeFormat);
+      break;
+    case (SKY):
+      value[N] = pimage[i].sky;
+      break;
+    case (BIAS):
+      value[N] = pimage[i].bias;
+      break;
+    case (FWHM):
+      value[N] = pimage[i].fwhm;
+      break;
+    case (AIRM):
+      value[N] = pimage[i].airmass;
+      break;
+    case (TEMP):
+      value[N] = pimage[i].teltemp[0];
+      break;
+    }
+    N++;
+    if (N >= NVALUE - 1) {
+      NVALUE += 1000;
+      REALLOCATE (vec[0].elements, float, NVALUE);
+      value = vec[0].elements;
+    }
+  }
+
+  REALLOCATE (vec[0].elements, float, MAX (1,N));
+  vec[0].Nelements = N;
+
+  free (pimage);
+  fits_free_header (&header);
+  return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/dmagaves.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/dmagaves.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/dmagaves.c	(revision 3338)
@@ -0,0 +1,129 @@
+# include "dvo.h"
+
+int dmagaves (int argc, char **argv) {
+  
+  Catalog catalog;
+  Graphdata graphsky;
+  RegionFile *regions;
+  PhotCode *code[3];
+  Vector *xvec, *yvec;
+
+  char filename[256], catdir[256];
+  double Radius, *M1, M2;
+  int i, j, k, m, N1;
+  int Npts, NPTS, param, mode[3];
+  int Ngraph, Nsec, Nregions;
+
+  /* defaults */
+  regions = NULL;
+  catalog.average = NULL; 
+  catalog.secfilt = NULL;
+  catalog.measure = NULL;
+
+  /* load photcode information */
+  if (!InitPhotcodes ()) goto escape;
+  Nsec = GetPhotcodeNsecfilt ();
+
+  /* load data about plot windows */
+  Ngraph = 0;
+  if (!GetGraphData (&graphsky, NULL, &Ngraph)) return (FALSE);
+ 
+  /* find CATDIR in config system */
+  VarConfig ("CATDIR", "%s", catdir);
+
+  /* interpret command-line options */
+  if (!SetPhotSelections (&argc, argv)) goto usage;
+  if (argc != 6) { goto usage; }
+  if (strcmp (argv[2], "-")) goto usage;
+  if (strcmp (argv[4], ":")) goto usage;
+
+  /* interpret command-line options */
+  if (!GetPhotcodeInfo (argv[1], &code[0], &mode[0])) return (FALSE);
+  if (!GetPhotcodeInfo (argv[3], &code[1], &mode[1])) return (FALSE);
+  if ((param = GetAverageParam (argv[5])) == AVE_ZERO) return (FALSE);
+  code[2] = GetPhotcodeEquivbyCode (code[0][0].code);
+  mode[2] = mode[0];
+
+  /* test PhotSelections: is photcode specified if needed? */
+  for (i = 0; i < 3; i++) {
+    if (!TestPhotSelections (&code[i])) {
+      fprintf (stderr, "photcode selection rules violated\n");
+      fprintf (stderr, "average and ensemble restrictions require a corresponding photcode\n");
+      goto escape;
+    }
+  }
+
+  /* find catalog files which overlap this region */
+  Radius = MAX (fabs(graphsky.xmax), fabs(graphsky.ymax));
+  regions = find_regions (graphsky.coords.crval1, graphsky.coords.crval2, Radius, &Nregions);
+  if (!SetImageSelection (param, &graphsky, TRUE)) return (FALSE);
+  
+  /* init vectors to save data */
+  Npts = 0;
+  NPTS = 1;
+  if ((xvec = SelectVector ("xv", ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((yvec = SelectVector ("yv", ANYVECTOR, TRUE)) == NULL) goto escape;
+
+  for (j = 0; j < Nregions; j++) {
+    /* lock, load, unlock catalog */
+    sprintf (filename, "%s/%s", catdir, regions[j].name);
+    catalog.filename = filename;
+    switch (lock_catalog (&catalog, LCK_SOFT)) {
+    case 2:
+      unlock_catalog (&catalog);
+    case 0:
+      continue;
+    }
+    if (!load_catalog (&catalog, LOAD_AVES | LOAD_MEAS | LOAD_SECF, FALSE)) {
+      unlock_catalog (&catalog);
+      continue;
+    }
+    unlock_catalog (&catalog);
+
+    /* get correct mags, convert to X,Y */
+    for (i = 0; i < catalog.Naverage; i++) {
+      M1 = NULL;
+      m = catalog.average[i].offset;
+
+      M1 = ExtractDMag (code, mode, &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], &N1);
+      if (N1 == 0) goto skip;
+
+      M2 = ExtractAverages (code[2], mode[2], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], param);
+
+      for (k = 0; k < N1; k++) {
+	xvec[0].elements[Npts] = M1[k];
+	yvec[0].elements[Npts] = M2;
+	Npts++;
+	if (Npts == NPTS) {
+	  NPTS += 2000;
+	  REALLOCATE (xvec[0].elements, float, NPTS);
+	  REALLOCATE (yvec[0].elements, float, NPTS);
+	}
+      }
+    skip:
+      if (M1 != NULL) free (M1);
+    }
+    if (catalog.average != NULL) free (catalog.average);
+    if (catalog.secfilt != NULL) free (catalog.secfilt);
+    if (catalog.measure != NULL) free (catalog.measure);
+    catalog.average = (Average *) NULL; 
+    catalog.secfilt = (SecFilt *) NULL;
+    catalog.measure = (Measure *) NULL;
+  }
+  FreeImageSelection ();
+  if (regions != NULL) free (regions);
+  xvec[0].Nelements = yvec[0].Nelements = Npts;
+  return (TRUE);
+
+usage:
+  fprintf (stderr, "USAGE: dmagaves F - F : average.param\n");
+  return (FALSE);
+
+escape:
+  FreeImageSelection ();
+  if (regions != NULL) free (regions);
+  if (catalog.average != NULL) free (catalog.average);
+  if (catalog.secfilt != NULL) free (catalog.secfilt);
+  if (catalog.measure != NULL) free (catalog.measure);
+  return (FALSE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/dmagmeas.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/dmagmeas.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/dmagmeas.c	(revision 3338)
@@ -0,0 +1,132 @@
+# include "dvo.h"
+double *ExtractByDMag (PhotCode **code, int *mode, Average *average, SecFilt *secfilt, Measure *measure, int *nlist, int param);
+
+int dmagmeas (int argc, char **argv) {
+  
+  Catalog catalog;
+  Graphdata graphsky;
+  RegionFile *regions;
+  PhotCode *code[3];
+  Vector *xvec, *yvec;
+
+  char filename[256], catdir[256];
+  double Radius, *M1, *M3;
+  int i, j, k, m, N1, N3;
+  int Npts, NPTS, param, mode[3];
+  int Ngraph, Nsec, Nregions;
+
+  /* defaults */
+  regions = NULL;
+  catalog.average = NULL; 
+  catalog.secfilt = NULL;
+  catalog.measure = NULL;
+
+  /* load photcode information */
+  if (!InitPhotcodes ()) goto escape;
+  Nsec = GetPhotcodeNsecfilt ();
+
+  /* load data about plot windows */
+  Ngraph = 0;
+  if (!GetGraphData (&graphsky, NULL, &Ngraph)) return (FALSE);
+ 
+  /* find CATDIR in config system */
+  VarConfig ("CATDIR", "%s", catdir);
+
+  /* interpret command-line options */
+  if (!SetPhotSelections (&argc, argv)) goto usage;
+  if (argc != 6) { goto usage; }
+  if (strcmp (argv[2], "-")) goto usage;
+  if (strcmp (argv[4], ":")) goto usage;
+
+  /* interpret command-line options */
+  if (!GetPhotcodeInfo (argv[1], &code[0], &mode[0])) goto usage;
+  if (!GetPhotcodeInfo (argv[3], &code[1], &mode[1])) goto usage;
+  if ((param = GetMeasureParam (argv[5])) == MEAS_ZERO) goto usage;
+
+  /* test PhotSelections: is photcode specified if needed? */
+  for (i = 0; i < 2; i++) {
+    if (!TestPhotSelections (&code[i])) {
+      fprintf (stderr, "photcode selection rules violated\n");
+      fprintf (stderr, "average and ensemble restrictions require a corresponding photcode\n");
+      goto escape;
+    }
+  }
+
+  /* find catalog files which overlap this region */
+  Radius = MAX (fabs(graphsky.xmax), fabs(graphsky.ymax));
+  regions = find_regions (graphsky.coords.crval1, graphsky.coords.crval2, Radius, &Nregions);
+  if (!SetImageSelection (param, &graphsky, TRUE)) return (FALSE);
+
+  /* init vectors to save data */
+  Npts = 0;
+  NPTS = 1;
+  if ((xvec = SelectVector ("xv", ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((yvec = SelectVector ("yv", ANYVECTOR, TRUE)) == NULL) goto escape;
+
+  /* loop over regions, extract data for each region */
+  for (j = 0; j < Nregions; j++) {
+    /* lock, load, unlock catalog */
+    sprintf (filename, "%s/%s", catdir, regions[j].name);
+    catalog.filename = filename;
+    switch (lock_catalog (&catalog, LCK_SOFT)) {
+      case 2:
+	unlock_catalog (&catalog);
+      case 0:
+	continue;
+    }
+    if (!load_catalog (&catalog, LOAD_AVES | LOAD_MEAS | LOAD_SECF, FALSE)) {
+      unlock_catalog (&catalog);
+      continue;
+    }
+    unlock_catalog (&catalog);
+
+    /* get correct mags, convert to X,Y */
+    for (i = 0; i < catalog.Naverage; i++) {
+      M1 = M3 = NULL;
+      m = catalog.average[i].offset;
+
+      M1 = ExtractDMag (code, mode, &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], &N1);
+      if (N1 == 0) goto skip;
+
+      M3 = ExtractByDMag (code, mode, &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], &N3, param);
+      if (N3 != N1) { fprintf (stderr, "mismatch: programming error\n"); goto escape; }
+
+      for (k = 0; k < N1; k++) {
+	xvec[0].elements[Npts] = M1[k];
+	yvec[0].elements[Npts] = M3[k];
+	Npts++;
+	if (Npts == NPTS) {
+	  NPTS += 2000;
+	  REALLOCATE (xvec[0].elements, float, NPTS);
+	  REALLOCATE (yvec[0].elements, float, NPTS);
+	}
+      }
+    skip:
+      if (M1 != NULL) free (M1);
+      if (M3 != NULL) free (M3);
+    }
+    if (catalog.average != NULL) free (catalog.average);
+    if (catalog.secfilt != NULL) free (catalog.secfilt);
+    if (catalog.measure != NULL) free (catalog.measure);
+    catalog.average = (Average *) NULL; 
+    catalog.secfilt = (SecFilt *) NULL;
+    catalog.measure = (Measure *) NULL;
+  }
+  FreeImageSelection ();
+  if (regions != NULL) free (regions);
+  xvec[0].Nelements = yvec[0].Nelements = Npts;
+  return (TRUE);
+
+usage:
+  fprintf (stderr, "USAGE: dmagmeas F - F : measure.param\n");
+  return (FALSE);
+
+escape:
+  FreeImageSelection ();
+  if (regions != NULL) free (regions);
+  if (catalog.average != NULL) free (catalog.average);
+  if (catalog.secfilt != NULL) free (catalog.secfilt);
+  if (catalog.measure != NULL) free (catalog.measure);
+  return (FALSE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/dmags.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/dmags.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/dmags.c	(revision 3338)
@@ -0,0 +1,134 @@
+# include "dvo.h"
+
+int dmags (int argc, char **argv) {
+  
+  Catalog catalog;
+  Graphdata graphsky;
+  RegionFile *regions;
+  PhotCode *code[3];
+  Vector *xvec, *yvec;
+
+  char filename[256], catdir[256];
+  double Radius, *M1, *M3;
+  int i, j, m, i1, i3, N1, N3;
+  int Npts, NPTS, mode[3];
+  int Ngraph, Nsec, Nregions;
+
+  /* defaults */
+  regions = NULL;
+  catalog.average = NULL; 
+  catalog.secfilt = NULL;
+  catalog.measure = NULL;
+
+  /* load photcode information */
+  if (!InitPhotcodes ()) goto escape;
+  Nsec = GetPhotcodeNsecfilt ();
+
+  /* load data about plot windows */
+  Ngraph = 0;
+  if (!GetGraphData (&graphsky, NULL, &Ngraph)) return (FALSE);
+ 
+  /* find CATDIR in config system */
+  VarConfig ("CATDIR", "%s", catdir);
+
+  /* interpret command-line options */
+  if (!SetPhotSelections (&argc, argv)) goto usage;
+  if (argc != 6) { goto usage; }
+  if (strcmp (argv[2], "-")) goto usage;
+  if (strcmp (argv[4], ":")) goto usage;
+
+  /* interpret command-line options */
+  if (!GetPhotcodeInfo (argv[1], &code[0], &mode[0])) goto usage;
+  if (!GetPhotcodeInfo (argv[3], &code[1], &mode[1])) goto usage;
+  if (!GetPhotcodeInfo (argv[5], &code[2], &mode[2])) goto usage;
+
+  /* test PhotSelections: is photcode specified if needed? */
+  for (i = 0; i < 3; i++) {
+    if (!TestPhotSelections (&code[i])) {
+      fprintf (stderr, "photcode selection rules violated\n");
+      fprintf (stderr, "average and ensemble restrictions require a corresponding photcode\n");
+      goto escape;
+    }
+  }
+
+  /* find catalog files which overlap this region */
+  Radius = MAX (fabs(graphsky.xmax), fabs(graphsky.ymax));
+  regions = find_regions (graphsky.coords.crval1, graphsky.coords.crval2, Radius, &Nregions);
+
+  /* init vectors to save data */
+  Npts = 0;
+  NPTS = 1;
+  if ((xvec = SelectVector ("xv", ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((yvec = SelectVector ("yv", ANYVECTOR, TRUE)) == NULL) goto escape;
+
+  /* loop over regions, extract data for each region */
+  for (j = 0; j < Nregions; j++) {
+    /* lock, load, unlock catalog */
+    sprintf (filename, "%s/%s", catdir, regions[j].name);
+    catalog.filename = filename;
+    switch (lock_catalog (&catalog, LCK_SOFT)) {
+      case 2:
+	unlock_catalog (&catalog);
+      case 0:
+	continue;
+    }
+    if (!load_catalog (&catalog, LOAD_AVES | LOAD_MEAS | LOAD_SECF, FALSE)) {
+      unlock_catalog (&catalog);
+      continue;
+    }
+    unlock_catalog (&catalog);
+
+    /* get correct mags, convert to X,Y */
+    for (i = 0; i < catalog.Naverage; i++) {
+      M1 = M3 = NULL;
+      m = catalog.average[i].offset;
+
+      M1 = ExtractDMag (code, mode, &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], &N1);
+      if (N1 == 0) goto skip;
+
+      M3 = ExtractMagnitudes (code[2], mode[2], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], &N3);
+      if (N3 == 0) goto skip;
+
+      for (i1 = 0; i1 < N1; i1++) {
+	for (i3 = 0; i3 < N3; i3++) {
+	  xvec[0].elements[Npts] = M1[i1];
+	  yvec[0].elements[Npts] = M3[i3];
+	  Npts++;
+	  if (Npts == NPTS) {
+	    NPTS += 2000;
+	    REALLOCATE (xvec[0].elements, float, NPTS);
+	    REALLOCATE (yvec[0].elements, float, NPTS);
+	  }
+	}
+      }
+    skip:
+      if (M1 != NULL) free (M1);
+      if (M3 != NULL) free (M3);
+    }
+    if (catalog.average != NULL) free (catalog.average);
+    if (catalog.secfilt != NULL) free (catalog.secfilt);
+    if (catalog.measure != NULL) free (catalog.measure);
+    catalog.average = (Average *) NULL; 
+    catalog.secfilt = (SecFilt *) NULL;
+    catalog.measure = (Measure *) NULL;
+  }
+  if (regions != NULL) free (regions);
+  xvec[0].Nelements = yvec[0].Nelements = Npts;
+  return (TRUE);
+
+usage:
+  fprintf (stderr, "USAGE: dmags F - F : F\n");
+  fprintf (stderr, "  F : any photcodes with matched qualifiers:\n");
+  fprintf (stderr, "    pri: F:inst, F:cat, F:sys, F:rel, F:cal, F:ave, F:ref\n");
+  fprintf (stderr, "    sec: F:inst, F:cat, F:sys, F:rel, F:cal, F:ave, F:ref\n");
+  fprintf (stderr, "    dep: F:inst, F:cat, F:sys, F:rel, F:cal\n");
+  fprintf (stderr, "    ref: F:cat\n");
+  return (FALSE);
+
+escape:
+  if (regions != NULL) free (regions);
+  if (catalog.average != NULL) free (catalog.average);
+  if (catalog.secfilt != NULL) free (catalog.secfilt);
+  if (catalog.measure != NULL) free (catalog.measure);
+  return (FALSE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/dmt.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/dmt.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/dmt.c	(revision 3338)
@@ -0,0 +1,154 @@
+# include "dvo.h"
+
+/* extract vectors giving delta mags for multiple measurements */ 
+int dmt (int argc, char **argv) {
+  
+  int i, m, k, N, Nregions, Ngraph, SaveVectors;
+  int Ns, Nsec, NPTS;
+  char catdir[256], filename[256];
+  double Radius;
+  float dt1, dt2, dmt1, dmt2;
+  float M0, M1, M2, M3;
+  PhotCode *code;
+  Catalog catalog;
+  Graphdata graphmode, graphsky;
+  RegionFile *regions;
+  Vector Xvec, Yvec, Zvec, Rvec, Dvec;
+  Vector *vec1, *vec2, *vec3, *vec4, *vec5;
+
+  VarConfig ("CATDIR", "%s", catdir);
+  if (!InitPhotcodes ()) return (FALSE);
+
+  SaveVectors = FALSE;
+  if (N = get_argument (argc, argv, "-vect")) {
+    remove_argument (N, &argc, argv);
+    if ((vec1 = SelectVector ("dmtdmt", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    if ((vec2 = SelectVector ("dmtvar", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    if ((vec3 = SelectVector ("dmtmag", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    if ((vec4 = SelectVector ("dmtra",  ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    if ((vec5 = SelectVector ("dmtdec", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    SaveVectors = TRUE;
+  }
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: dmags filter\n");
+    return (FALSE);
+  }
+
+  Ngraph = 0;
+  if (!GetGraphData (&graphsky, NULL, &Ngraph)) return (FALSE);
+  if (!GetGraph (&graphmode, NULL, NULL)) return (FALSE);
+
+  if ((code = GetPhotcodebyName (argv[1])) == NULL) {
+    fprintf (stderr, "ERROR: photcode not found in photcode table\n");
+    return (FALSE);
+  }
+  if ((code[0].type != PHOT_SEC) && (code[0].type != PHOT_PRI)) {
+    fprintf (stderr, "first filter must be a PRIMARY or SECONDARY photometry type\n");
+    return (FALSE);
+  }
+  Nsec = GetPhotcodeNsecfilt();
+  Ns = GetPhotcodeNsec (code[0].code);
+
+  Radius = MAX (fabs(graphsky.xmax), fabs(graphsky.ymax));
+  regions = find_regions (graphsky.coords.crval1, graphsky.coords.crval2, Radius, &Nregions);
+  
+  N = 0;
+  NPTS = catalog.Nmeasure;
+  ALLOCATE (Xvec.elements, float, NPTS);
+  ALLOCATE (Yvec.elements, float, NPTS);
+  if (SaveVectors) {
+    ALLOCATE (Zvec.elements, float, NPTS);
+    ALLOCATE (Rvec.elements, float, NPTS);
+    ALLOCATE (Dvec.elements, float, NPTS);
+  }
+
+  for (k = 0; k < Nregions; k++) {
+
+    sprintf (filename, "%s/%s", catdir, regions[k].name);
+    /* lock, load, unlock catalog */
+    catalog.filename = filename;
+    switch (lock_catalog (&catalog, LCK_SOFT)) {
+    case 2:
+      unlock_catalog (&catalog);
+    case 0:
+      continue;
+    }
+    if (!load_catalog (&catalog, LOAD_AVES | LOAD_MEAS | LOAD_SECF, TRUE)) {
+      unlock_catalog (&catalog);
+      continue;
+    }
+    unlock_catalog (&catalog);
+
+    for (i = 0; i < catalog.Naverage; i++) {
+      if (catalog.average[i].Nm != 3) continue;
+      m = catalog.average[i].offset;
+      M0 = (Ns == -1) ? 0.001*catalog.average[i].M : 0.001*catalog.secfilt[i*Nsec+Ns].M;
+      M1 = PhotCat (&catalog.measure[m+0]);
+      M2 = PhotCat (&catalog.measure[m+1]);
+      M3 = PhotCat (&catalog.measure[m+2]);
+
+      dt1 = (catalog.measure[m+0].t < catalog.measure[m+1].t) ? catalog.measure[m+1].t - catalog.measure[m+0].t : -1 * ((float)(catalog.measure[m+1].t - catalog.measure[m+0].t));
+      dt2 = (catalog.measure[m+1].t < catalog.measure[m+2].t) ? catalog.measure[m+2].t - catalog.measure[m+1].t : -1 * ((float)(catalog.measure[m+2].t - catalog.measure[m+1].t));
+      dmt1 = (M2 - M1) / dt1;
+      dmt2 = (M3 - M2) / dt2;
+      Xvec.elements[N] = (dmt1 - dmt2) / (dmt1 + dmt2);
+      Yvec.elements[N] = (dmt1 + dmt2) / 2.0;
+      if (SaveVectors) {
+	Rvec.elements[N] = catalog.average[i].R;
+	Dvec.elements[N] = catalog.average[i].D;
+	Zvec.elements[N] = M0;
+      }
+      N++;
+      if (N == NPTS - 1) {
+	NPTS += 2000;
+	REALLOCATE (Xvec.elements, float, NPTS);
+	REALLOCATE (Yvec.elements, float, NPTS);
+	if (SaveVectors) {
+	  REALLOCATE (Zvec.elements, float, NPTS);
+	  REALLOCATE (Rvec.elements, float, NPTS);
+	  REALLOCATE (Dvec.elements, float, NPTS);
+	}
+      }
+    }
+  }
+  Yvec.Nelements = Xvec.Nelements = N;
+  REALLOCATE (Xvec.elements, float, MAX (1, N));
+  REALLOCATE (Yvec.elements, float, MAX (1, N));
+  if (SaveVectors) {
+    Rvec.Nelements = Dvec.Nelements = Zvec.Nelements = N;
+    REALLOCATE (Zvec.elements, float, MAX (1, N));
+    REALLOCATE (Rvec.elements, float, MAX (1, N));
+    REALLOCATE (Dvec.elements, float, MAX (1, N));
+  }
+
+  if (SaveVectors) {
+    free (vec1[0].elements);
+    vec1[0].elements = Yvec.elements;
+    vec1[0].Nelements = Yvec.Nelements;
+    free (vec2[0].elements);
+    vec2[0].elements = Xvec.elements;
+    vec2[0].Nelements = Xvec.Nelements;
+    free (vec3[0].elements);
+    vec3[0].elements = Zvec.elements;
+    vec3[0].Nelements = Zvec.Nelements;
+    free (vec4[0].elements);
+    vec4[0].elements = Rvec.elements;
+    vec4[0].Nelements = Rvec.Nelements;
+    free (vec5[0].elements);
+    vec5[0].elements = Dvec.elements;
+    vec5[0].Nelements = Dvec.Nelements;
+  } else {
+    graphmode.style = 2; /* set style to points */
+    PrepPlotting (N, &graphmode);
+    
+    PlotVector (N, Xvec.elements);
+    PlotVector (N, Yvec.elements);
+
+    free (Xvec.elements);
+    free (Yvec.elements);
+    free (Zvec.elements);
+  }
+  return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/dvo.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/dvo.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/dvo.c	(revision 3338)
@@ -0,0 +1,80 @@
+# include "opihi.h"
+
+# define opihi_name "DVO"
+# define opihi_prompt "dvo: "
+# define opihi_description "desktop virtual observatory\n"
+# define opihi_history ".dvo"
+# define opihi_rcfile ".dvorc"
+
+void InitBasic ();
+void InitData ();
+void InitAstro ();
+void InitDVO ();
+
+void welcome () {
+  fprintf (stderr, "\n");
+  fprintf (stderr, "Welcome to %s - %s\n\n", opihi_name, opihi_description);
+}
+
+/* program-dependent initialization */
+void initialize (int argc, char **argv) {
+  
+  FILE *f;
+
+  auto_break = TRUE;
+
+  Nlists = 0;
+  ALLOCATE (lists, List, 1); 
+
+  /* init functions required by libraries */
+  /* -libopihi */
+  InitCommands ();
+  InitMacros ();
+  InitBuffers ();
+  InitVectors ();
+  InitVariables ();
+
+  /* -libdisplay */
+  InitGraph ();
+  InitImage ();
+
+  /* load the commands used by this implementation */
+  InitBasic ();
+  InitData ();
+  InitAstro ();
+  InitDVO ();
+  InitOutfile ();
+
+  rl_readline_name = opihi_name;
+  rl_attempted_completion_function = command_completer;
+
+  set_str_variable ("HISTORY", opihi_history);
+  set_str_variable ("PROMPT", opihi_prompt);
+  set_str_variable ("RCFILE", opihi_rcfile);
+
+  /* here we open the history file for append.  it this fails, we
+     won't be able to write to it, warn the user.  otherwise, this
+     creates the file readline will write to, if it did not exist */  
+
+  /* check history file */
+  /* rewrite with fstat or stat */
+  f = fopen (opihi_history, "a");
+  if (f == NULL) /* no current history file here */
+    fprintf (stderr, "can't save history.\n");
+  else
+    fclose (f);
+  
+  stifle_history (200);
+  read_history (opihi_history);
+
+  signal (SIGINT, SIG_IGN);
+  return;
+}
+
+/* add program-dependent exit functions here */
+void cleanup () {
+  /* -libdisplay */
+  QuitImage ();
+  QuitGraph ();
+  return;
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/dvomisc.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/dvomisc.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/dvomisc.c	(revision 3338)
@@ -0,0 +1,141 @@
+# include "dvo.h"
+
+void cprecess (Average *average, int Naverage, double in_epoch, double out_epoch) {
+
+  int i;
+  double T;
+  double A, D, RA, DEC, zeta, z, theta;
+  double SA, CA, SD, CD;
+  
+  T = (out_epoch - in_epoch) / 100.0;
+  
+  zeta  = RAD_DEG*(0.6406161*T + 0.0000839*T*T + 0.0000050*T*T*T);
+  theta = RAD_DEG*(0.5567530*T - 0.0001185*T*T - 0.0000116*T*T*T);
+  z     =          0.6406161*T + 0.0003041*T*T + 0.0000051*T*T*T;
+  
+  for (i = 0; i < Naverage; i++) {
+    A = average[i].R;
+    D = average[i].D;
+    SD =  cos(RAD_DEG*A + zeta)*sin(theta)*cos(RAD_DEG*D) + cos(theta)*sin(RAD_DEG*D);
+    CD = sqrt (1 - SD*SD);
+    SA =  sin(RAD_DEG*A + zeta)*cos(RAD_DEG*D)/CD;
+    CA = (cos(RAD_DEG*A + zeta)*cos(theta)*cos(RAD_DEG*D) - sin(theta)*sin(RAD_DEG*D))/CD;
+    
+    DEC = DEG_RAD*asin(SD);
+    RA  = DEG_RAD*atan2(SA, CA) + z;
+    
+    if (RA < 0)
+      RA += 360;
+    
+    average[i].R = RA;
+    average[i].D = DEC; 
+  }
+
+}
+
+/* values are ave[i].R, ave[i].D, ave[i].M */
+void sortave (Average *ave, int N) {
+
+  int l,j,ir,i;
+  Average tmp;
+
+  if (N < 2) return;
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tmp = ave[l];
+    }
+    else {
+      tmp = ave[ir];
+      ave[ir] = ave[0];
+      if (--ir == 0) {
+	ave[0] = tmp;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && ave[j].R < ave[j+1].R) j++;
+      if (tmp.R < ave[j].R) {
+	ave[i] = ave[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    ave[i] = tmp;
+  }
+}
+
+/* values are ave[i].R, ave[i].D, ave[i].M */
+void sort_images (Image *image, int N) {
+
+  int l,j,ir,i;
+  Image tmp;
+
+  if (N < 2) return;
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tmp = image[l];
+    }
+    else {
+      tmp = image[ir];
+      image[ir] = image[0];
+      if (--ir == 0) {
+	image[0] = tmp;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && image[j].tzero < image[j+1].tzero) j++;
+      if (tmp.tzero < image[j].tzero) {
+	image[i] = image[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    image[i] = tmp;
+  }
+}
+
+/* sort subset by image[subset[i]].tzero */
+void sort_image_subset (Image *image, int *subset, int N) {
+
+  int l, j, ir, i, tmp;
+
+  if (N < 2) return;
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tmp = subset[l];
+    }
+    else {
+      tmp = subset[ir];
+      subset[ir] = subset[0];
+      if (--ir == 0) {
+	subset[0] = tmp;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && image[subset[j]].tzero < image[subset[j+1]].tzero) j++;
+      if (image[tmp].tzero < image[subset[j]].tzero) {
+	subset[i] = subset[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    subset[i] = tmp;
+  }
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/elixir.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/elixir.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/elixir.c	(revision 3338)
@@ -0,0 +1,162 @@
+# include "dvo.h"
+
+int elixir (int argc, char **argv) {
+  
+  char message[256], cmd[256], ElixirBase[256];
+  char fifo[256], fifodir[256], msgfile[256];
+  char *answer;
+  int N;
+
+  sprintf (cmd, "STATUS");
+  if (N = get_argument (argc, argv, "-time")) {
+    remove_argument (N, &argc, argv);
+    sprintf (cmd, "TIMES");
+  }
+  if (N = get_argument (argc, argv, "-live")) {
+    remove_argument (N, &argc, argv);
+    sprintf (cmd, "ALIVE");
+  }
+  if (N = get_argument (argc, argv, "-stop")) {
+    remove_argument (N, &argc, argv);
+    sprintf (cmd, "STOP");
+  }
+  if (N = get_argument (argc, argv, "-kill")) {
+    remove_argument (N, &argc, argv);
+    sprintf (cmd, "ABORT");
+  }
+ 
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: elixir (elixir) [-time] [-live]\n");
+    return (FALSE);
+  }
+
+  if (!VarConfig (argv[1], "%s", ElixirBase)) {
+    fprintf (stderr, "elixir %s not in config file\n", argv[1]);
+    return (FALSE);
+  }
+  sprintf (fifo, "%s.msg", ElixirBase);
+  if (!VarConfig ("FIFOS", "%s", fifodir)) {
+    fprintf (stderr, "FIFOS not in config, using local /tmp\n");
+    strcpy (fifodir, "/tmp");
+  }
+  sprintf (fifo, "%s.msg", ElixirBase);
+
+  sprintf (msgfile, "%s/EMsg.XXXXXX", fifodir);
+  mkstemp (msgfile);
+  sprintf (message, "%s %s", cmd, msgfile);
+  unlink (msgfile);
+
+  if (!WriteMsg (fifo, message)) {
+    fprintf (stderr, "can't access fifo %s\n", fifo);
+    return (FALSE);
+  }
+
+  if (ReadMsg (msgfile, &answer)) {
+    fprintf (stderr, "%s\n", answer);
+  } 
+  unlink (msgfile);
+  return (TRUE);
+  
+}
+
+int WriteMsg (char *fifo, char *message) {
+
+  int fd, state, mode;
+  FILE *f;
+
+  /* check lockfile */
+  fd = setlockfile2 (fifo, 2.0, LCK_XCLD, &state);
+  if (fd == -1) return (0);
+  f = fdopen (fd, "r+");
+  if (f == (FILE *) NULL) {
+    mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+    fchmod (fd, mode);
+    clearlockfile2 (fifo, fd, LCK_XCLD, &state);
+    return (0);
+  }
+
+  /* write message to end of file */
+  fseek (f, 0, SEEK_END);
+  fprintf (f, "%s\n", message);
+
+  mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+  fchmod (fd, mode);
+
+  clearlockfile2 (fifo, fd, LCK_XCLD, &state);
+  fclose (f);
+
+  return (1);
+
+}
+
+int ReadMsg (char *fifo, char **message) {
+
+  int i, nbytes, Nbytes, NBYTES;
+  char *buffer;
+  int fd, state, mode;
+  FILE *f;
+  struct stat filestat;
+
+  /* wait (2 sec) for file to exist, then try to read it */
+  for (i = 0; (stat (fifo, &filestat) == -1) && (i < 20); i++) {
+    usleep (100000);
+  }
+  if (i >= 20) {
+    fprintf (stderr, "no response\n");
+    return (0);
+  }
+
+  /* check lockfile */
+  fd = setlockfile2 (fifo, 2.0, LCK_XCLD, &state);
+  if (fd == -1) {
+    fprintf (stderr, "message locked (%d)\n", state);
+    return (0);
+  }
+  f = fdopen (fd, "r+");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "message blocked\n");
+    mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+    fchmod (fd, mode);
+    clearlockfile2 (fifo, fd, LCK_XCLD, &state);
+    return (0);
+  }
+
+  /* if file is empty, return 0 */
+  if (state == LCK_EMPTY) {
+    mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+    fchmod (fd, mode);
+    clearlockfile2 (fifo, fd, LCK_XCLD, &state);
+    fclose (f);
+    return (0);
+  }  
+
+  Nbytes = 0;
+  NBYTES = 0x1000;
+  ALLOCATE (buffer, char, NBYTES);
+  while (TRUE) {
+    nbytes = fread (&buffer[Nbytes], 1, 0x1000, f);
+    if (nbytes < 0) { 
+      fprintf (stderr, "error in ReadMsg -- got -1 bytes\n");
+      return (0);
+    }
+    if (nbytes == 0) break;
+    Nbytes += nbytes;
+    NBYTES += 0x1000;
+    REALLOCATE (buffer, char, NBYTES);
+  }
+  buffer[Nbytes] = 0;
+
+  mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+  fchmod (fd, mode);
+  clearlockfile2 (fifo, fd, LCK_XCLD, &state);
+  fclose (f);
+
+  if (Nbytes == 0) {
+    free (buffer);
+    return (0);
+  }
+
+  *message = buffer;
+  return (1);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/extract.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/extract.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/extract.c	(revision 3338)
@@ -0,0 +1,449 @@
+# include "dvo.h"
+
+enum {ZERO, RA, DEC, MAG, dMAG, Xm, Xp, NMEAS, NMISS, REF, TYPE, NPHOT, NCODE, FLAG};
+
+# define NBYTES 160000
+# define BYTES_STAR 23
+# define BLOCK 1000
+# define DNSTARS 1000
+
+int extract (int argc, char **argv) {
+  
+  FILE *f;
+  int i, Col, N, Nbytes, nbytes, NPTS;
+  int InRegion, GSC, ASCII, LONEOS, mode, loadmode;
+  int j, k, m, Nregions;
+  float M0, m0;
+  char filename[128];
+  float Radius;
+  char catdir[256], gscdir[256];
+  int PhotcodeSelect;
+  char PhotCodeFile[256], code[64];
+  double ZERO_POINT;
+  int Ns, N1, n1, Nsec;
+  int Ngraph;
+  int value;
+  Vector *vec;
+  PhotCodeData photcodes;
+  Graphdata graphmode;
+  Catalog catalog;
+  RegionFile *regions;
+
+  Ngraph = 0;
+  if (!GetGraphData (&graphmode, NULL, &Ngraph)) return (FALSE);
+  if (!InitPhotcodes ()) return (FALSE);
+
+  VarConfig ("CATDIR", "%s", catdir);
+  VarConfig ("GSCDIR", "%s", gscdir);
+
+  regions = (RegionFile *) NULL;
+  ASCII = FALSE;
+  LONEOS = TRUE;
+  GSC = FALSE;
+  if (N = get_argument (argc, argv, "-g")) {
+    remove_argument (N, &argc, argv);
+    GSC = TRUE;
+    ASCII = FALSE;
+    LONEOS = FALSE;
+  }
+
+  Col = 1;
+  if (N = get_argument (argc, argv, "-a")) {
+    remove_argument (N, &argc, argv);
+    ASCII = TRUE;
+    GSC = FALSE;
+    LONEOS = FALSE;
+    Col = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  /* check for region-based selection */
+  code = NULL;
+  PhotcodeSelect = FALSE;
+  if (N = get_argument (argc, argv, "-photcode")) {
+    PhotcodeSelect = True;
+    remove_argument (N, &argc, argv);
+    if ((code = GetPhotcodebyName (argv[N])) == NULL) {
+      fprintf (stderr, "ERROR: photcode %s not found in photcode table\n", argv[N]);
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: extract (filename) (value) [-g / -a Ncol] \n");
+    return (FALSE);
+  }
+  
+  InRegion = FALSE;
+  if (!strcmp (argv[1], "-all")) {
+    InRegion = TRUE;
+  }
+
+  /* identify selection */
+  if (LONEOS) {
+    mode = ZERO;
+    if (!strcasecmp (argv[2], "ra")) mode = RA;
+    if (!strcasecmp (argv[2], "dec")) mode = DEC;
+    if (!strcasecmp (argv[2], "mag")) mode = MAG;
+    if (!strcasecmp (argv[2], "Nmeas")) mode = NMEAS;
+    if (!strcasecmp (argv[2], "Nmiss")) mode = NMISS;
+    if (!strcasecmp (argv[2], "Xp")) mode = Xp;
+    if (!strcasecmp (argv[2], "Xm")) mode = Xm;
+    if (!strcasecmp (argv[2], "dM")) mode = dMAG;
+    if (!strcasecmp (argv[2], "flag")) mode = FLAG;
+    if (!strcasecmp (argv[2], "ref")) mode = REF;
+    if (!strcasecmp (argv[2], "type")) mode = TYPE;
+    if (!strcasecmp (argv[2], "Nphot")) mode = NPHOT;
+    if (!strcasecmp (argv[2], "Ncode")) mode = NCODE;
+    if (mode == ZERO) {
+      fprintf (stderr, "value may be one of the following:\n");
+      fprintf (stderr, " ra dec mag Nmeas Nmiss Xp Xm ID\n");
+      return (FALSE);
+    }
+  }
+
+  if ((mode == REF) && !PhotcodeSelect) {
+    fprintf (stderr, "must specify photcode for Reference\n");
+    return (FALSE);
+  }
+  if ((mode == TYPE) && !PhotcodeSelect) {
+    fprintf (stderr, "must specify photcode for Type\n");
+    return (FALSE);
+  }
+
+  /* check photcode data / selection validity */
+  Ns = -1;
+  Nsec = GetPhotcodeNsecfilt ();
+  if (PhotcodeSelect) {
+    Ns = GetPhotcodeNsec (code[0].code);
+    if ((mode != REF) && (code[0].type != PHOT_SEC) && (code[0].type != PHOT_PRI)) {
+      fprintf (stderr, "filter must be a PRIMARY or SECONDARY photometry type\n");
+      return (FALSE);
+    }
+    if ((mode == REF) && (code[0].type != PHOT_REF)) {
+      fprintf (stderr, "filter must be a REFERENCE photometry type\n");
+      return (FALSE);
+    }
+  }
+
+  if (GSC) {
+    mode = ZERO;
+    if (!strcasecmp (argv[2], "ra")) 
+      mode = RA;
+    if (!strcasecmp (argv[2], "dec")) 
+      mode = DEC;
+    if (!strcasecmp (argv[2], "mag")) 
+      mode = MAG;
+    if (mode == ZERO) {
+      fprintf (stderr, "for GSC, value may be one of the following:\n");
+      fprintf (stderr, " ra dec mag\n");
+      return (FALSE);
+    }
+  }
+
+  if ((vec = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  if (InRegion) {
+    Radius = MAX (fabs(graphmode.xmax), fabs(graphmode.ymax));
+    regions = find_regions (graphmode.coords.crval1, graphmode.coords.crval2, Radius, &Nregions);
+  } else {
+    Nregions = 1;
+  }
+  
+  /* create storage vector */
+  NPTS = 1000;
+  REALLOCATE (vec[0].elements, float, NPTS);
+  vec[0].Nelements = N = 0;
+
+  /* we loop over Nregions, but for ASCII Nregions = 1 */
+  for (j = 0; j < Nregions; j++) {
+    
+    /* Load in data from an ASCII file list of ra, dec, mag */
+    if (ASCII) {
+      char *tbuffer;
+      double tmp;
+      float *V;
+      
+      f = fopen (argv[1], "r");
+      if (f == (FILE *) NULL) {
+	fprintf (stderr, "ERROR: can't open data file: %s\n", argv[1]);
+	/* delete new vector! */
+	return (FALSE);
+      }
+      ALLOCATE (tbuffer, char, 1024);
+      
+      V = vec[0].elements;
+      while (scan_line (f, tbuffer) != EOF) {
+	dparse (&tmp, Col, tbuffer);
+	*V = tmp;
+	V++;
+	N++;
+	if (N == NPTS - 1) {
+	  NPTS += 1000;
+	  REALLOCATE (vec[0].elements, float, NPTS);
+	  V = &vec[0].elements[N];
+	}
+      }
+      free (tbuffer);
+      vec[0].Nelements = N;
+      REALLOCATE (vec[0].elements, float, MAX(1,N));
+      fclose (f);
+      return (TRUE);
+    }
+    
+    /* load data from the GSC files */
+    if (GSC) {
+      char *tbuffer;
+      double tmp;
+      float *V;
+      
+      if (InRegion) {
+	sprintf (filename, "%s/%s\0", gscdir, regions[j].name);
+      } else {
+	sprintf (filename, "%s/%s\0", gscdir, argv[1]);
+      }
+      
+      f = fopen (filename, "r");
+      if (f == (FILE *) NULL) {
+	fprintf (stderr, "no stars in %s, skipping\n", filename);
+	continue;
+      }
+      ALLOCATE (tbuffer, char, (BLOCK*BYTES_STAR));
+      
+      V = &vec[0].elements[N];
+      Nbytes = BLOCK*BYTES_STAR;
+      while ((nbytes = fread (tbuffer, 1, Nbytes, f)) > 0) {
+	for (i = 0; i < nbytes / BYTES_STAR; i++) {
+	  if (mode == RA) {
+	    dparse (&tmp, 1, &tbuffer[i*BYTES_STAR]);
+	    *V = tmp;
+	  }
+	  if (mode == DEC) {
+	    dparse (&tmp, 2, &tbuffer[i*BYTES_STAR]);
+	    *V = tmp;
+	  }
+	  if (mode == MAG) {
+	    dparse (&tmp, 3, &tbuffer[i*BYTES_STAR]);
+	    *V = tmp;
+	  }
+	  V++;
+	  N++;
+	  if (N == NPTS - 1) {
+	    NPTS += 1000;
+	    REALLOCATE (vec[0].elements, float, NPTS);
+	    V = &vec[0].elements[N];
+	  }
+	}
+      }
+      free (tbuffer);
+      fclose (f);
+    }
+  
+    /* load data from the photometry database files */
+    if (LONEOS) {
+      /* find and open correct file */
+      if (InRegion) {
+	sprintf (filename, "%s/%s\0", catdir, regions[j].name);
+      } else {
+	sprintf (filename, "%s/%s\0", catdir, argv[1]);
+      }
+      catalog.average = (Average *) NULL;
+      catalog.measure = (Measure *) NULL;
+      catalog.secfilt = (SecFilt *) NULL;
+      loadmode = LOAD_AVES | LOAD_SECF;
+      if ((mode == REF) || (mode == TYPE) || (mode == NPHOT) || (mode == NCODE)) 
+	loadmode = loadmode | LOAD_MEAS;
+
+      /* lock, load, unlock catalog */
+      catalog.filename = filename;
+      switch (lock_catalog (&catalog, LCK_SOFT)) {
+      case 2:
+	unlock_catalog (&catalog);
+      case 0:
+	continue;
+      }
+      if (!load_catalog (&catalog, loadmode, TRUE)) {
+	unlock_catalog (&catalog);
+	continue;
+      }
+      unlock_catalog (&catalog);
+
+      /* assign vector values */
+      switch (mode) {
+      case (RA):
+	for (i = 0; i < catalog.Naverage; i++) {
+	  vec[0].elements[N] = catalog.average[i].R;
+	  N++;
+	  if (N == NPTS - 1) {
+	    NPTS += 1000;
+	    REALLOCATE (vec[0].elements, float, NPTS);
+	  }
+	}
+	break;
+      case (DEC):
+	for (i = 0; i < catalog.Naverage; i++) {
+	  vec[0].elements[N] = catalog.average[i].D;
+	  N++;
+	  if (N == NPTS - 1) {
+	    NPTS += 1000;
+	    REALLOCATE (vec[0].elements, float, NPTS);
+	  }
+	}
+	break;
+      case (MAG):
+	for (i = 0; i < catalog.Naverage; i++) {
+	  M0 = (Ns == -1) ? catalog.average[i].M : catalog.secfilt[i*Nsec+Ns].M;
+	  vec[0].elements[N] = M0 / 1000.0;
+	  N++;
+	  if (N == NPTS - 1) {
+	    NPTS += 1000;
+	    REALLOCATE (vec[0].elements, float, NPTS);
+	  }
+	}
+	break;
+      case (NMEAS):
+	for (i = 0; i < catalog.Naverage; i++) {
+	  vec[0].elements[N] = catalog.average[i].Nm;
+	  N++;
+	  if (N == NPTS - 1) {
+	    NPTS += 1000;
+	    REALLOCATE (vec[0].elements, float, NPTS);
+	  }
+	}
+	break;
+      case (NMISS):
+	for (i = 0; i < catalog.Naverage; i++) {
+	  vec[0].elements[N] = catalog.average[i].Nn;
+	  N++;
+	  if (N == NPTS - 1) {
+	    NPTS += 1000;
+	    REALLOCATE (vec[0].elements, float, NPTS);
+	  }
+	}
+	break;
+      case (Xp):
+	for (i = 0; i < catalog.Naverage; i++) {
+	  /* Xp is scatter in 1/100 arcsec */
+	  vec[0].elements[N] = 0.01*catalog.average[i].Xp;
+	  N++;
+	  if (N == NPTS - 1) {
+	    NPTS += 1000;
+	    REALLOCATE (vec[0].elements, float, NPTS);
+	  }
+	}
+	break;
+      case (NCODE):
+	for (i = 0; i < catalog.Naverage; i++) {
+	  m = catalog.average[i].offset;
+	  Ncode = 0;
+	  for (k = 0; k < catalog.average[i].Nm; k++, m++) {
+	    if (code[0].code != GetPhotcodeEquivCodebyCode (catalog.measure[m].source)) continue;
+	    Ncode ++;
+	  }
+	  vec[0].elements[N] = Ncode;
+	  N++;
+	  if (N == NPTS - 1) {
+	    NPTS += 1000;
+	    REALLOCATE (vec[0].elements, float, NPTS);
+	  }
+	}
+	break;
+      case (NPHOT):
+	for (i = 0; i < catalog.Naverage; i++) {
+	  m = catalog.average[i].offset;
+	  Ncode = 0;
+	  for (k = 0; k < catalog.average[i].Nm; k++, m++) {
+	    if (code[0].code != GetPhotcodeEquivCodebyCode (catalog.measure[m].source)) continue;
+	    if (catalog.measure[m].source & (ID_MEAS_POOR | ID_MEAS_SKIP)) continue;
+	    Ncode ++;
+	  }
+	  vec[0].elements[N] = Ncode;
+	  N++;
+	  if (N == NPTS - 1) {
+	    NPTS += 1000;
+	    REALLOCATE (vec[0].elements, float, NPTS);
+	  }
+	}
+	break;
+      case (Xm):
+	for (i = 0; i < catalog.Naverage; i++) {
+	  M0 = (Ns == -1) ? catalog.average[i].Xm : catalog.secfilt[i*Nsec+Ns].Xm;
+	  vec[0].elements[N] = (M0 == NO_MAG) ? -1.0 : pow (10.0, 0.01*M0);
+	  N++;
+	  if (N == NPTS - 1) {
+	    NPTS += 1000;
+	    REALLOCATE (vec[0].elements, float, NPTS);
+	  }
+	}
+	break;
+      case (dMAG):
+	for (i = 0; i < catalog.Naverage; i++) {
+	  /* dM is 1000.0 * error */
+	  M0 = (Ns == -1) ? catalog.average[i].dM : catalog.secfilt[i*Nsec+Ns].dM;
+	  vec[0].elements[N] = (M0 == NO_MAG) ? -1.0 : 0.001*M0;
+	  N++;
+	  if (N == NPTS - 1) {
+	    NPTS += 1000;
+	    REALLOCATE (vec[0].elements, float, NPTS);
+	  }
+	}
+	break;
+      case (FLAG):
+	for (i = 0; i < catalog.Naverage; i++) {
+	  vec[0].elements[N] = catalog.average[i].code;
+	  N++;
+	  if (N == NPTS - 1) {
+	    NPTS += 1000;
+	    REALLOCATE (vec[0].elements, float, NPTS);
+	  }
+	}
+	break;
+      case (REF):
+	for (i = 0; i < catalog.Naverage; i++) {
+	  m = catalog.average[i].offset;
+	  vec[0].elements[N] = -32;
+	  for (k = 0; k < catalog.average[i].Nm; k++) {
+	    if (catalog.measure[m+k].source == N1) {
+	      vec[0].elements[N] = PhotCat (&catalog.measure[m+k]);
+	      k = catalog.average[i].Nm;
+	    }
+	  }
+	  N++;
+	  if (N == NPTS - 1) {
+	    NPTS += 1000;
+	    REALLOCATE (vec[0].elements, float, NPTS);
+	  }
+	}
+	break;
+      case (TYPE):
+	for (i = 0; i < catalog.Naverage; i++) {
+	  m = catalog.average[i].offset;
+	  vec[0].elements[N] = DetermineTypeCode (&catalog.average[i], &catalog.measure[m], &photcodes, N1);
+	  N++;
+	  if (N == NPTS - 1) {
+	    NPTS += 1000;
+	    REALLOCATE (vec[0].elements, float, NPTS);
+	  }
+	}
+	break;
+      }
+      if (catalog.average != 0) free (catalog.average);
+      if (catalog.measure != 0) free (catalog.measure);
+      if (catalog.secfilt != 0) free (catalog.secfilt);
+    }
+  }
+
+  vec[0].Nelements = N;
+  REALLOCATE (vec[0].elements, float, MAX(1,N));
+  return (TRUE);
+
+}
+  
+  /* USAGE: extract (what) (where) (from) [option] */
+  /* examples:
+     extract n0000/n0001 mag m 
+     extract -g n0000/n0020 ra r 
+     extract -all Xm xm
+     extract fred dec d -a 2 */
+  
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/find_regions.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/find_regions.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/find_regions.c	(revision 3338)
@@ -0,0 +1,155 @@
+# include "dvo.h"
+# include "hstgsc.h"
+
+/* returns a list of region files within the desired RA, DEC region */
+RegionFile *find_regions (double Ra, double Dec, double radius, int *Nregions) {
+  
+  char filename[256];
+  char buffer[28800], temp[50];
+  RegionFile *regions;
+  FILE *f;
+  double minRa, maxRa, minDec, maxDec, rad;
+
+  double RA0, RA1, DEC0, DEC1;
+  int i, j, NBigDec;
+  int NLINES, done, NREGIONS, nregion;
+  
+  VarConfig ("GSCFILE", "%s", filename);
+  f = fopen (filename, "r");
+  if (f == NULL) {
+    fprintf (stderr, "ERROR: can't find regions file %s\n", filename);
+    *Nregions = 0;
+    return ((RegionFile *) NULL);
+  }
+  
+  NREGIONS = 50;
+  ALLOCATE (regions, RegionFile, NREGIONS);
+  nregion = 0;
+
+  while (Ra < 0) Ra += 360.0;
+  while (Ra >= 360) Ra -= 360.0;
+
+  minDec = Dec - radius;
+  maxDec = Dec + radius;
+
+  if ((minDec <= -90) || (maxDec >= 90)) {
+    minRa = 0;
+    maxRa = 360;
+  } else {
+    rad = MAX (radius / (cos(minDec*RAD_DEG)), radius / (cos(maxDec*RAD_DEG)));
+    minRa = Ra - rad;
+    maxRa = Ra + rad;
+  }
+  
+  /* use the pole regions, if near pole */
+  if (maxDec > 86.25) {
+    sprintf (regions[nregion].name, "n8230/pole.cpt");
+    regions[nregion].RA0 = 0;
+    regions[nregion].RA1 = 360;
+    regions[nregion].DEC0 = 86.25;
+    regions[nregion].DEC1 = 90.0;
+    nregion ++;
+    if (nregion == NREGIONS) {
+      NREGIONS += 50;
+      REALLOCATE (regions, RegionFile, NREGIONS);
+    }
+  }
+
+  if (minDec > 86.25) {
+    return (regions);
+  }
+    
+  if ((minDec < 0) && (maxDec > 0)) {
+    /* Search Both Sides */
+    NBigDec = 0;
+  } else {
+    /* find large DEC region (directory) */
+    NBigDec = -1;
+    for (i = 0; i < 12; i++) {
+      if ((minDec >= BigDecBounds[i]) && (minDec < BigDecBounds[i+1])) {
+	NBigDec = i;
+	break;
+      }
+    }
+    if (NBigDec < 0) {
+      for (i = 13; i < 24; i++) {
+	if ((maxDec < BigDecBounds[i]) && (maxDec >= BigDecBounds[i+1])) {
+	  NBigDec = i;
+	  break;
+	}
+      }
+    }
+  }
+  if (NBigDec < 0) {
+    fprintf (stderr, "ERROR: Dec out of range: %f\n", minDec);
+    *Nregions = 0;
+    return ((RegionFile *) NULL);
+  }
+  
+  /* count lines before section */
+  NLINES = 0;
+  for (i = 0; i < NBigDec; i++) {
+    NLINES += NDecLines[i];
+  }
+  fseek (f, 5*2880 + 48*NLINES, SEEK_SET);
+  
+  /* should be in this section.  if not, there is a problem counting... */
+  /* careful with the 0,360.0 boundary **/
+  done = FALSE;
+  for (j = 0; !done && (NBigDec + j < 25); j++) {
+    fread (buffer, 48*NDecLines[NBigDec + j], 1, f);
+    for (i = 0; (i < NDecLines[NBigDec + j]); i++) {
+      strncpy (temp, &buffer[i*48], 48);
+      temp[49] = 0;
+      hstgsc_hms_to_deg (&RA0, &RA1, &DEC0, &DEC1, &temp[7]);
+      if (RA1 < RA0) RA1 += 360.0;
+      if ((DEC1 > 0) && (minDec < DEC1) && (maxDec > DEC0) && (minRa < RA1) && (maxRa > RA0)) {
+	temp[5] = 0;
+	sprintf (regions[nregion].name, "%s/%s.cpt", Dec2Sections[NBigDec + j], &temp[1]);
+	regions[nregion].RA0 = RA0;
+	regions[nregion].RA1 = RA1;
+	regions[nregion].DEC0 = DEC0;
+	regions[nregion].DEC1 = DEC1;
+	nregion ++;
+	if (nregion == NREGIONS) {
+	  NREGIONS += 50;
+	  REALLOCATE (regions, RegionFile, NREGIONS);
+	}
+      }
+      if ((DEC1 < 0) && (minDec < DEC0) && (maxDec > DEC1) && (minRa < RA1) && (maxRa > RA0)) {
+	temp[5] = 0;
+	sprintf (regions[nregion].name, "%s/%s.cpt", Dec2Sections[NBigDec + j], &temp[1]);
+	regions[nregion].RA0 = RA0;
+	regions[nregion].RA1 = RA1;
+	regions[nregion].DEC0 = DEC0;
+	regions[nregion].DEC1 = DEC1;
+	nregion ++;
+	if (nregion == NREGIONS) {
+	  NREGIONS += 50;
+	  REALLOCATE (regions, RegionFile, NREGIONS);
+	}
+      }
+      if (((DEC1 > 0) && (maxDec <= DEC1)) || ((DEC1 < 0) && (minDec >= DEC1))) {
+	done = TRUE;
+      }
+    }
+    if (done && (minDec < 0) && (maxDec > 0) && (BigDecBounds[NBigDec + j + 1] > 0)) {
+      /* skip remaining north sections, try south sections */
+      /* count lines before section */
+      NLINES = 0;
+      for (i = 0; i < 13; i++) { 
+	NLINES += NDecLines[i];
+      }
+      fseek (f, 5*2880 + 48*NLINES, SEEK_SET);
+      done = FALSE;
+      j = 12;
+    }
+  }
+
+  REALLOCATE (regions, RegionFile, MAX(1,nregion));
+  *Nregions = nregion;
+  
+  fclose (f);
+  return (regions);
+  
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/gcat.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/gcat.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/gcat.c	(revision 3338)
@@ -0,0 +1,42 @@
+# include "dvo.h"
+
+int gcat (int argc, char **argv) {
+  
+  int i, Nregions;
+  RegionFile *regions;
+  char filename[128];
+  struct stat filestat;
+  double Ra, Dec, Radius;
+  char catdir[256];
+
+  VarConfig ("CATDIR", "%s", catdir);
+
+  if ((argc != 3) && (argc != 4)) {
+    fprintf (stderr, "USAGE: gcat RA DEC [Radius]\n");
+    return (FALSE);
+  }
+
+  Ra = atof (argv[1]);
+  Dec = atof (argv[2]);
+  if (argc == 4) 
+    Radius = atof(argv[3]);
+  else 
+    Radius = 0.0001;
+
+  regions = find_regions (Ra, Dec, Radius, &Nregions);
+
+  for (i = 0; i < Nregions; i++) {
+    sprintf (filename, "%s/%s", catdir, regions[i].name);
+    if (stat (filename, &filestat) != -1) {
+      fprintf (stderr, "%3d %s *\n", i, regions[i].name);
+    } else {
+      fprintf (stderr, "%3d %s\n", i, regions[i].name);
+    } 
+    set_str_variable ("CATNAME", regions[i].name);
+  }
+
+  return (TRUE);
+  free (regions);
+
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/get_regions.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/get_regions.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/get_regions.c	(revision 3338)
@@ -0,0 +1,50 @@
+# include "dvo.h"
+
+/* return region files containing given image */
+GSCRegion *get_regions (Image *image, int *Nregions) {
+  
+  GSCRegion *region;
+  FILE *f;
+  double x, y;
+  double dec, ra;
+  int j, done, nregion, NREGION;
+  char filename[256], path[256];
+  
+  VarConfig ("CATDIR", "%s", path);
+  VarConfig ("GSCFILE", "%s", filename);
+  f = fopen (filename, "r");
+  if (f == NULL) {
+    fprintf (stderr, "ERROR: can't find GSC region file %s\n", filename);
+    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, path);
+      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);
+      }
+    }
+  }
+  *Nregions = nregion;
+  
+  fclose (f);
+  return (region);
+  
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/getxtra.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/getxtra.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/getxtra.c	(revision 3338)
@@ -0,0 +1,63 @@
+# include "dvo.h"
+
+int getxtra (int argc, char **argv) {
+  
+  SelectXtra = (char *) NULL;
+  if (N = get_argument (argc, argv, "-xtra")) {
+    SelectXtra = TRUE;
+    remove_argument (N, &argc, argv);
+    XtraType = strcreate (atof[N]);
+    remove_argument (N, &argc, argv);
+    XtraValue = strcreate (atof[N]);
+    remove_argument (N, &argc, argv);
+  }
+  SelectRegion = (char *) NULL;
+  if (N = get_argument (argc, argv, "-region")) {
+    SelectRegion = TRUE;
+    remove_argument (N, &argc, argv);
+    RA = atof (atof[N]);
+    remove_argument (N, &argc, argv);
+    Dec = atof (atof[N]);
+    remove_argument (N, &argc, argv);
+    Radius = atof (atof[N]);
+    remove_argument (N, &argc, argv);
+  }
+  Mode = (char *) NULL;
+  if (N = get_argument (argc, argv, "-mode")) {
+    remove_argument (N, &argc, argv);
+    Mode = strcreate (atof[N]);
+    remove_argument (N, &argc, argv);
+  }
+  Range = (char *) NULL;
+  if (N = get_argument (argc, argv, "-range")) {
+    remove_argument (N, &argc, argv);
+    Range = strcreate (atof[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 6) {
+    fprintf (stderr, "USAGE: addxtra R D radius (type) (value)\n");
+    return (FALSE);
+  }
+  
+  
+
+  /*
+
+  validate the input values (type, defines the needed options)
+  find catalog (based on r,d)
+  load catalog (need to load measures?)
+  find the object
+  find the xtra entry (sorted by ra/dec? sorted by averef?)
+  add new entry
+  save catalog 
+  */
+}
+
+/* 
+   get specified values for specified objects 
+
+   getxtra type -xtra name K01.01 
+   getxtra type -region R D radius 
+
+*/
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/gimages.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/gimages.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/gimages.c	(revision 3338)
@@ -0,0 +1,127 @@
+# include "dvo.h"
+
+int gimages (int argc, char **argv) {
+  
+  int i, j, N, Nimage, Nfound, *subset, Nsubset, status;
+  double ra, dec, Ra, Dec, X, Y, Mcal;
+  double trange, t;
+  int TimeSelect, PixelCoords, TimeFormat, PhotCodeSelect;
+  time_t tzero, TimeReference;
+  char name[64], *date;
+
+  PhotCode *code;
+  Image *image;
+
+  if (!InitPhotcodes ()) return (FALSE);
+
+  GetTimeFormat (&TimeReference, &TimeFormat);
+
+  TimeSelect = FALSE;
+  if (N = get_argument (argc, argv, "-time")) {
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &tzero)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (!str_to_dtime (argv[N], &trange)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    TimeSelect = TRUE;
+  }
+  if (N = get_argument (argc, argv, "-tref")) {
+    remove_argument (N, &argc, argv);
+    TimeSelect = TRUE;
+
+    t = atof (argv[N]);
+    tzero = TimeRef (t, TimeReference, TimeFormat);
+    remove_argument (N, &argc, argv);
+
+    if (!str_to_dtime (argv[N], &trange)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+  }
+
+  PhotCodeSelect = FALSE;
+  if (N = get_argument (argc, argv, "-photcode")) {
+    remove_argument (N, &argc, argv);
+    if ((code = GetPhotcodebyName (argv[N])) == NULL) {
+      fprintf (stderr, "ERROR: photcode not found in photcode table\n");
+      return (FALSE);
+    }
+    PhotCodeSelect = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  PixelCoords = FALSE;
+  if (N = get_argument (argc, argv, "-pix")) {
+    remove_argument (N, &argc, argv);
+    PixelCoords = TRUE;
+  }
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: gimages RA DEC [-time t dt] [-pix]\n");
+    return (FALSE);
+  }
+
+  if (!str_to_radec (&Ra, &Dec, argv[1], argv[2])) return (FALSE);
+
+  image = LoadImages (&Nimage);
+  if (Nimage == 0) {
+    return (FALSE);
+  }
+  image_subset (image, Nimage, &subset, &Nsubset, (Graphdata *) NULL, FALSE, tzero, trange, TimeSelect);
+
+  Nfound = 0;
+  for (j = 0; j < Nsubset; j++) {
+    i = subset[j];
+    status = RD_to_XY (&X, &Y, Ra, Dec, &image[i].coords);
+    if (!status || (X < 0) || (X > image[i].NX) || (Y < 0) || (Y > image[i].NY)) continue;
+    XY_to_RD (&ra, &dec, 0.5*image[i].NX, 0.5*image[i].NY, &image[i].coords);
+    Mcal = applyMcal (&image[i], 2048.0, 2048.0);
+    /* t = TimeValue (image[i].tzero, TimeReference, TimeFormat); */
+    date = sec_to_date (image[i].tzero);
+    if (PhotCodeSelect) {
+      if ((code[0].type == PHOT_REF) || (code[0].type == PHOT_DEP)) {
+	if (code[0].code != image[i].source) continue;
+      } 
+      if ((code[0].type == PHOT_PRI) || (code[0].type == PHOT_SEC)) {
+	if (code[0].code != GetPhotcodeEquivCodebyCode (image[i].source)) continue;
+      } 
+    }      
+    if (PixelCoords) {
+      fprintf (GetOutfile(), "%3d %s %6.1f %6.1f %20s %5d %2d %4.2f %6.3f %5.3f %5.3f %4x\n", 
+	       Nfound, image[i].name, X, Y, date, image[i].nstar, image[i].source, 0.001*image[i].secz, 0.001*Mcal, 0.001*image[i].dMcal, image[i].exptime, image[i].code);
+    } else {
+      fprintf (GetOutfile(), "%3d %s %8.4f %8.4f %20s %5d %2d %4.2f %6.3f %5.3f %5.3f %4x\n", 
+	       Nfound, image[i].name, ra, dec, date, image[i].nstar, image[i].source, 0.001*image[i].secz, 0.001*Mcal, 0.001*image[i].dMcal, image[i].exptime, image[i].code);
+    }
+    sprintf (name, "IMAGEx:%d", Nfound);
+    set_variable     (name, X);
+    sprintf (name, "IMAGEy:%d", Nfound);
+    set_variable     (name, Y);
+    sprintf (name, "IMAGEt:%d", Nfound);
+    set_str_variable (name, date);
+    sprintf (name, "IMAGEccd:%d", Nfound);
+    set_int_variable (name, image[i].ccdnum);
+    sprintf (name, "IMAGEname:%d", Nfound);
+    set_str_variable (name, image[i].name);
+    Nfound ++;
+    free (date);
+  }
+  set_int_variable ("IMAGEx:n", Nfound);
+  set_int_variable ("IMAGEy:n", Nfound);
+  set_int_variable ("IMAGEt:n", Nfound);
+  set_int_variable ("IMAGEccd:n", Nfound);
+  set_int_variable ("IMAGEname:n", Nfound);
+
+  free (image);
+  free (subset);
+
+  return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/gstar.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/gstar.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/gstar.c	(revision 3338)
@@ -0,0 +1,213 @@
+# include "dvo.h"
+
+void print_value (FILE *f, double value, short int ival);
+
+int gstar (int argc, char **argv) {
+  
+  char filename[128], catdir[256], *date;
+  double Ra, Dec, Radius, Radius2, r, dec0, dec1;
+  double t, Mcat, Mrel;
+  float *RA, *DEC;
+  int i, j, k, m, N, *N1, Nregions, Nsec, NPTS;
+  int Nstars, found, GetMeasures, Nlo, Nhi;
+  int SaveVectors;
+  Vector *vec1, *vec2, *vec3, *vec4;
+  RegionFile *regions;
+  Catalog catalog;
+  PhotCode *code;
+
+  VarConfig ("CATDIR", "%s", catdir);
+  if (!InitPhotcodes ()) return (FALSE);
+  Nsec = GetPhotcodeNsecfilt ();
+
+  SaveVectors = FALSE;
+  if (N = get_argument (argc, argv, "-save")) {
+    remove_argument (N, &argc, argv);
+    SaveVectors = TRUE;
+    if ((vec1 = SelectVector ("gs:m", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    if ((vec2 = SelectVector ("gs:t", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    if ((vec3 = SelectVector ("gs:z", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    if ((vec4 = SelectVector ("gs:f", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  }
+
+  GetMeasures = FALSE;
+  if (N = get_argument (argc, argv, "-m")) {
+    GetMeasures = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 4) {
+    fprintf (stderr, "USAGE: gstar RA DEC Radius [-m]\n");
+    return (FALSE);
+  }
+  
+  Ra = atof (argv[1]);
+  Dec = atof (argv[2]);
+  Radius = atof (argv[3]);
+
+  while (Ra < 0.0) Ra += 360.0;
+  while (Ra > 360.0) Ra -= 360.0;
+  
+  regions = find_regions (Ra, Dec, Radius, &Nregions);
+
+  if (Nregions > 1) {
+    fprintf (stderr, "warning, radius overlaps region boundary, not yet implemented\n");
+  }
+
+  /* set filename, read in header */
+  sprintf (filename, "%s/%s", catdir, regions[0].name);
+  /* lock, load, unlock catalog */
+  catalog.filename = filename;
+  switch (lock_catalog (&catalog, LCK_SOFT)) {
+  case 2:
+    unlock_catalog (&catalog);
+  case 0:
+    return (FALSE);
+  }
+  if (!load_catalog (&catalog, LOAD_AVES | LOAD_MEAS | LOAD_SECF, TRUE)) {
+    unlock_catalog (&catalog);
+    return (FALSE);
+  }
+  unlock_catalog (&catalog);
+
+  Nstars = catalog.Naverage;
+  ALLOCATE (RA, float, Nstars);
+  ALLOCATE (DEC, float, Nstars);
+  ALLOCATE (N1, int, Nstars);
+
+  /* find star(s) in RA, DEC list -- use a dumb algorithm for now, improve later */
+  /* stars are not guaranteed to be sorted in RA or in DEC, so first sort the list */
+  for (i = 0; i < Nstars; i++) {
+    RA[i] = catalog.average[i].R;
+    DEC[i] = catalog.average[i].D;
+    N1[i] = i;
+  }
+  /* sort list by DEC */
+  if (Nstars > 1) sort_lists (DEC, RA, N1, Nstars);
+  /* at this point, RA, DEC, and N1 are sorted by DEC.  
+     catalog.average[N1[i]].R = RA[i] */
+
+  /* bracket the RA range of interest */
+  dec0 = Dec - Radius;
+  dec1 = Dec + Radius;
+
+  Nlo = 0; Nhi = catalog.Naverage;
+  while (Nhi - Nlo > 10) {
+    N = 0.5*(Nlo + Nhi);
+    if (DEC[N] < dec0) {
+      Nlo = N;
+    } else {
+      Nhi = N + 1;
+    }
+  }
+  /* DEC[Nlo] is guaranteed to be just lower than dec0 */
+
+  Radius2 = Radius*Radius;
+  found = FALSE;
+
+  /* data has been loaded, get ready to plot it */
+  if (SaveVectors) {
+    N = 0;
+    NPTS = 1000;
+    ALLOCATE (vec1[0].elements, float, NPTS);
+    ALLOCATE (vec2[0].elements, float, NPTS);
+    ALLOCATE (vec3[0].elements, float, NPTS);
+    ALLOCATE (vec4[0].elements, float, NPTS);
+  }
+
+  for (i = Nlo; (i < catalog.Naverage) && !found; i++) {
+
+    if (dec0 > DEC[i]) continue;
+    if (dec1 < DEC[i]) found = TRUE;
+    
+    r = SQ(Dec - DEC[i]) + SQ(Ra - RA[i]);
+    if (r < Radius2) {
+      k = N1[i];
+      fprintf (GetOutfile(), "star: %d\n", k);
+      fprintf (GetOutfile(), "%9.5f %9.5f %3d of %3d  %4.1f %5d\n", catalog.average[k].R, catalog.average[k].D, 
+	       catalog.average[k].Nm, catalog.average[k].Nn + catalog.average[k].Nm,
+	       0.01*catalog.average[k].Xp, catalog.average[k].code);
+      
+      /* filter names -- primary code is 0 in this function */
+      for (j = 0; j < Nsec + 1; j++) {
+	code = GetPhotcodebyNsec (j);
+	fprintf (GetOutfile (), "%s ", code[0].name);
+      }
+      fprintf (GetOutfile (), "\n");
+
+      /* average mags */
+      print_value (GetOutfile(), 0.001*catalog.average[k].M, catalog.average[k].M);
+      for (j = 0; j < Nsec; j++) print_value (GetOutfile(), 0.001*catalog.secfilt[j + Nsec*k].M, catalog.secfilt[j + Nsec*k].M);
+      fprintf (GetOutfile(), "\n");
+
+      /* average mag errors */
+      print_value (GetOutfile(), 0.001*catalog.average[k].dM, catalog.average[k].dM);
+      for (j = 0; j < Nsec; j++) print_value (GetOutfile(), 0.001*catalog.secfilt[j + Nsec*k].dM, catalog.secfilt[j + Nsec*k].dM);
+      fprintf (GetOutfile(), "\n");
+
+      /* average mag chisq */
+      print_value (GetOutfile(), pow (10.0, 0.01*catalog.average[k].Xm), catalog.average[k].Xm);
+      for (j = 0; j < Nsec; j++) print_value (GetOutfile(), pow (10.0, 0.01*catalog.secfilt[j + Nsec*k].Xm), catalog.secfilt[j + Nsec*k].Xm);
+      fprintf (GetOutfile(), "\n");
+
+      if (GetMeasures || SaveVectors) {
+	m = catalog.average[k].offset;
+	for (j = 0; j < catalog.average[k].Nm; j++, m++) {
+
+	  Mcat = PhotCat (&catalog.measure[m]);
+	  Mrel = PhotRel (&catalog.measure[m], &catalog.average[k], &catalog.secfilt[k*Nsec]);
+
+	  if (GetMeasures) {
+	    date = sec_to_date (catalog.measure[m].t);
+	    fprintf (GetOutfile(), "%6.3f %6.3f %5.3f  %20s  %5.2f %5.2f %2d %3x %3d %-20s\n", 
+		     Mcat, Mrel, 0.001*catalog.measure[m].dM,
+		     date, 0.01*catalog.measure[m].dR, 0.01*catalog.measure[m].dD,
+		     catalog.measure[m].dophot, catalog.measure[m].flags,
+		     catalog.measure[m].source, GetPhotcodeNamebyCode (catalog.measure[m].source));
+	    free (date);
+	  }
+	  
+	  if (SaveVectors) {
+	    vec1[0].elements[N] = Mcat;
+	    vec2[0].elements[N] = t;
+	    vec3[0].elements[N] = 0.001*catalog.measure[m].airmass;
+	    vec4[0].elements[N] = catalog.measure[m].source;
+	    N ++;
+	    if (N == NPTS - 1) {
+	      NPTS += 2000;
+	      REALLOCATE (vec1[0].elements, float, NPTS);
+	      REALLOCATE (vec2[0].elements, float, NPTS);
+	      REALLOCATE (vec3[0].elements, float, NPTS);
+	      REALLOCATE (vec4[0].elements, float, NPTS);
+	    }
+	  }
+	}
+      }
+    }
+  }
+
+  if (SaveVectors) {
+    vec1[0].Nelements = N;
+    vec2[0].Nelements = N;
+    vec3[0].Nelements = N;
+    vec4[0].Nelements = N;
+  }
+
+  free (RA);
+  free (DEC);
+  free (N1);
+  if (catalog.average != 0) free (catalog.average);
+  if (catalog.measure != 0) free (catalog.measure);
+  if (catalog.secfilt != 0) free (catalog.secfilt);
+
+  return (TRUE);
+
+}
+
+
+void print_value (FILE *f, double value, short int ival) {
+  if (ival == NO_MAG) 
+    fprintf (f, "NaN    ");
+  else 
+    fprintf (f, "%6.3f ", value);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/images.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/images.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/images.c	(revision 3338)
@@ -0,0 +1,156 @@
+# include "dvo.h"
+
+int images (int argc, char **argv) {
+
+  int i, j, Nimage, status, InPic, leftside, *plist, TimeSelect, ByName;
+  time_t tzero, tend;
+  int N, NPTS, n, npts;
+  Vector Xvec, Yvec;
+  double r, d, x[4], y[4], Rmin, Rmax, Rmid, trange;
+  Image *image;
+  Graphdata graphmode;
+  char name[256];
+  int Ngraph;
+
+  Ngraph = 0;
+  if (!GetGraph (&graphmode, NULL, &Ngraph)) return (FALSE);
+
+  ByName = FALSE;
+  if (N = get_argument (argc, argv, "-name")) {
+    remove_argument (N, &argc, argv);
+    strcpy (name, argv[N]);
+    remove_argument (N, &argc, argv);
+    ByName = TRUE;
+  }
+
+  TimeSelect = FALSE;
+  if (N = get_argument (argc, argv, "-time")) {
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &tzero)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (!str_to_dtime (argv[N], &trange)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (trange < 0) {
+      trange = fabs (trange);
+      tzero -= trange;
+    }
+    TimeSelect = TRUE;
+  }
+  if (N = get_argument (argc, argv, "-trange")) {
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &tzero)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &tend)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    trange = tend - tzero;
+    if (trange < 0) {
+      trange = fabs (trange);
+      tzero -= trange;
+    }
+    TimeSelect = TRUE;
+  }
+ 
+  if (argc != 1) {
+    fprintf (stderr, "USAGE: image [-time start range]\n");
+    return (FALSE);
+  }
+  
+  image = LoadImages (&Nimage);
+  if (Nimage == 0) {
+    return (TRUE);
+  }
+
+  Rmin = graphmode.coords.crval1 - 180.0;
+  Rmax = graphmode.coords.crval1 + 180.0;
+  Rmid = 0.5*(Rmin + Rmax);
+  
+  npts = NPTS = 200;
+  ALLOCATE (Xvec.elements, float, NPTS);
+  ALLOCATE (Yvec.elements, float, NPTS);
+  ALLOCATE (plist, int, NPTS);
+  n = N = 0;
+  for (i = 0; i < Nimage; i++) {
+    if (ByName && strcmp (name, image[i].name)) continue;
+    if (TimeSelect && ((image[i].tzero < tzero) || (image[i].tzero+image[i].trate*image[i].NY > tzero + trange))) continue;
+    /* project this image to screen display coords */
+    x[0] = 0;           y[0] = 0;
+    x[1] = image[i].NX; y[1] = 0;
+    x[2] = image[i].NX; y[2] = image[i].NY;
+    x[3] = 0;           y[3] = image[i].NY;
+    status = FALSE;
+
+    leftside = FALSE;
+    for (j = 0; j < 4; j++) {
+      XY_to_RD (&r, &d, x[j], y[j], &image[i].coords);
+      while (r < Rmin) { r += 360.0; }
+      while (r > Rmax) { r -= 360.0; }
+      if (j == 0) {
+	leftside = (r < Rmid);
+      } 
+      if (j > 0) { 
+	if ( leftside && (r > Rmid + 90)) { r -= 360.0; }
+	if (!leftside && (r < Rmid - 90)) { r += 360.0; }
+      }
+      status |= fRD_to_XY (&Xvec.elements[N+2*j], &Yvec.elements[N+2*j], r, d, &graphmode.coords);
+      if (j > 0) {
+	Xvec.elements[N+2*j - 1] = Xvec.elements[N+2*j];
+	Yvec.elements[N+2*j - 1] = Yvec.elements[N+2*j];
+      }
+    }
+    Xvec.elements[N+7] = Xvec.elements[N];
+    Yvec.elements[N+7] = Yvec.elements[N];
+    InPic = FALSE;
+    for (j = 0; j < 8; j+=2) {
+      if ((Xvec.elements[N+j] >= graphmode.xmin) && 
+	  (Xvec.elements[N+j] <= graphmode.xmax) && 
+	  (Yvec.elements[N+j] >= graphmode.ymin) && 
+	  (Yvec.elements[N+j] <= graphmode.ymax))
+	InPic = TRUE;
+    }
+    if (InPic && status) {
+      plist[n] = i;
+      n++;
+      if (n > npts - 1) {
+	npts += 200;
+	REALLOCATE (plist, int, npts);
+      }
+      N+=8;
+      if (N > NPTS - 1) {  /* this is OK because NPTS is made always a multiple of 8 */
+	NPTS += 200;
+	REALLOCATE (Xvec.elements, float, NPTS);
+	REALLOCATE (Yvec.elements, float, NPTS);
+      }
+    }
+  }
+
+  fprintf (stderr, "plotting %d images\n", N/8);
+  Xvec.Nelements = Xvec.Nelements = N;
+  if (N > 0) {
+    graphmode.style = 2; /* points */
+    graphmode.ptype = 100; /* connect pairs of points */
+    graphmode.etype = 0;
+    PrepPlotting (N, &graphmode);
+    PlotVector (N, Xvec.elements);
+    PlotVector (N, Yvec.elements);
+  }
+
+  free (Xvec.elements);
+  free (Yvec.elements);
+  free (image);
+  return (TRUE);
+
+}
+
+
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/imbox.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/imbox.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/imbox.c	(revision 3338)
@@ -0,0 +1,95 @@
+# include "dvo.h"
+
+int imbox (int argc, char **argv) {
+  
+  int i, j, status, InPic, flipped, Nextend;
+  Vector Xvec, Yvec;
+  double r, d, x[4], y[4], Rmin, Rmax, Rmid;
+  Header header;
+  Coords coords;
+  Graphdata graphmode;
+  int Ngraph;
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: imbox (filename)\n");
+    return (FALSE);
+  }
+  Ngraph = 0;
+  if (!GetGraph (&graphmode, NULL, &Ngraph)) return (FALSE);
+
+  if (!fits_read_header (argv[1], &header)) {
+    fprintf (stderr, "file not found\n");
+    return (FALSE);
+  }
+  
+  Nextend = 0;
+  if (header.Naxes == 0) {
+    fits_scan (&header, "NEXTEND", "%d", 1, &Nextend);
+  }
+  
+  Rmin = graphmode.coords.crval1 - 182.0;
+  Rmax = graphmode.coords.crval1 + 182.0;
+  Rmid = 0.5*(Rmin + Rmax);
+  
+  /* project this image to screen display coords */
+  ALLOCATE (Xvec.elements, float, 8);
+  ALLOCATE (Yvec.elements, float, 8);
+
+  for (i = Nextend ? 0 : -1; i < Nextend; i++) {
+    if (Nextend) {
+      fits_read_Xheader (argv[1], &header, i);
+    }
+    if (!GetCoords (&coords, &header)) {
+      fprintf (stderr, "can't get WCS info from header\n");
+      return (TRUE);
+    }
+    x[0] = 0;               y[0] = 0;
+    x[1] = header.Naxis[0]; y[1] = 0;
+    x[2] = header.Naxis[0]; y[2] = header.Naxis[1];
+    x[3] = 0;               y[3] = header.Naxis[1];
+    status = FALSE;
+    flipped = FALSE;
+    for (j = 0; j < 4; j++) {
+      XY_to_RD (&r, &d, x[j], y[j], &coords);
+      while ((j == 0) && (r < Rmin)) { flipped = TRUE; r += 360.0; }
+      while ((j == 0) && (r > Rmax)) { flipped = TRUE; r -= 360.0; }
+      if ((j > 0) && flipped) {
+	while (r < Rmid) r+= 360.0;
+	while (r > Rmid) r-= 360.0;
+      }
+      status |= fRD_to_XY (&Xvec.elements[2*j], &Yvec.elements[2*j], r, d, &graphmode.coords);
+      if (j > 0) {
+	Xvec.elements[2*j - 1] = Xvec.elements[2*j];
+	Yvec.elements[2*j - 1] = Yvec.elements[2*j];
+      }
+    }
+    Xvec.elements[7] = Xvec.elements[0];
+    Yvec.elements[7] = Yvec.elements[0];
+    InPic = FALSE;
+    for (j = 0; j < 8; j+=2) {
+      if ((Xvec.elements[j] >= graphmode.xmin) && 
+	  (Xvec.elements[j] <= graphmode.xmax) && 
+	  (Yvec.elements[j] >= graphmode.ymin) && 
+	  (Yvec.elements[j] <= graphmode.ymax))
+	InPic = TRUE;
+    }
+
+    Xvec.Nelements = Xvec.Nelements = 8;
+    if (InPic) {
+      graphmode.style = 2; /* points */
+      graphmode.ptype = 100; /* connect pairs of points */
+      graphmode.etype = 0;
+      PrepPlotting (8, &graphmode);
+      PlotVector (8, Xvec.elements);
+      PlotVector (8, Yvec.elements);
+    }
+  }
+
+  fits_free_header (&header);
+  free (Xvec.elements);
+  free (Yvec.elements);
+  return (TRUE);
+
+}
+
+
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/imdata.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/imdata.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/imdata.c	(revision 3338)
@@ -0,0 +1,245 @@
+# include "dvo.h"
+void copy_region (GSCRegion *in, GSCRegion *out);
+
+int imdata (int argc, char **argv) {
+  
+  int i, j, k;
+  int Nimage, N, NPTS, skip, mode, TimeSelect;
+  int n, Nregion, Ntregion, TimeFormat;
+  int *subset, Nsubset;
+  char filename[256];
+  double trange;
+  unsigned long tzero, start, stop, TimeReference;
+  Image *image;
+  Catalog catalog;
+  GSCRegion *region, *tregion;
+  Vector *vec;
+
+  TimeSelect = FALSE;
+  if (N = get_argument (argc, argv, "-time")) {
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &tzero)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (!str_to_dtime (argv[N], &trange)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    TimeSelect = TRUE;
+    fprintf (stderr, "searching in range %ds - %ds (%f seconds)\n", (int)tzero, (int)(tzero + trange), trange);
+    if (trange > 0) {
+      start = tzero;
+      stop  = tzero + trange;
+    } else {
+      stop = tzero;
+      start  = tzero + trange;
+    }      
+  }
+
+  if (argc != 4) {
+    fprintf (stderr, "USAGE: imdata (value) [-time t dt]\n");
+    return (FALSE);
+  }
+
+  /* identify selection */
+  mode = 0;
+  if (!strcasecmp (argv[1], "ra")) 
+    mode = 1;
+  if (!strcasecmp (argv[1], "dec")) 
+    mode = 2;
+  if (!strcasecmp (argv[1], "mag")) 
+    mode = 3;
+  if (!strcasecmp (argv[1], "dmag")) 
+    mode = 4;
+  if (!strcasecmp (argv[1], "Mcal")) 
+    mode = 5;
+  if (!strcasecmp (argv[1], "Mrel")) 
+    mode = 6;
+  if (!strcasecmp (argv[1], "source")) 
+    mode = 7;
+  if (!strcasecmp (argv[1], "x")) 
+    mode = 8;
+  if (!strcasecmp (argv[1], "y")) 
+    mode = 9;
+  if (!strcasecmp (argv[1], "time")) 
+    mode = 10;
+  if (mode == 0) {
+    fprintf (stderr, "value may be one of the following:\n");
+    fprintf (stderr, " ra dR dec dD mag dmag Mrel Mcal source time\n");
+    return (FALSE);
+  }
+  if ((vec = SelectVector (argv[1], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  image = LoadImages (&Nimage);
+  if (Nimage == 0) {
+    return (FALSE);
+  }
+  image_subset (image, Nimage, &subset, &Nsubset, (Graphdata *) NULL, FALSE, tzero, trange, TimeSelect);
+  GetTimeFormat (&TimeReference, &TimeFormat);
+
+  /* for each image of interest, find the appropriate region files */
+  Nregion = 0;
+  ALLOCATE (region, GSCRegion, 1);
+  for (i = 0; i < Nsubset; i++) {
+    tregion = get_regions (&image[subset[i]], &Ntregion);
+    REALLOCATE (region, GSCRegion, MAX (1, Nregion + Ntregion));
+    for (j = 0; j < Ntregion; j++) {
+      skip = FALSE;
+      for (k = 0; (k < Nregion) && !skip; k++) {
+	if (!strcmp (region[k].filename, tregion[j].filename)) skip = TRUE;
+      }
+      if (!skip) {
+	copy_region (&tregion[j], &region[Nregion]);
+	Nregion ++;
+      }
+    }
+    free (tregion);
+  }	
+  free (subset);
+  for (i = 0; i < Nregion; i++) {
+    fprintf (stderr, "try %s\n", region[i].filename);
+  } 
+  
+  /* create output vector */
+  NPTS = 1000;
+  REALLOCATE (vec[0].elements, float, NPTS);
+  vec[0].Nelements = N = 0;
+
+  /* for each region file, extract the data of interest in the right time range */
+  for (j = 0; j < Nregion; j++) {
+
+    /* get file name and open */
+    strcpy (filename, region[j].filename);
+    catalog.filename = filename;
+    switch (lock_catalog (&catalog, LCK_SOFT)) {
+    case 2:
+      unlock_catalog (&catalog);
+    case 0:
+      continue;
+    }
+    if (!load_catalog (&catalog, LOAD_AVES, TRUE)) {
+      unlock_catalog (&catalog);
+      continue;
+    }
+    unlock_catalog (&catalog);
+
+    /* assign vector values */
+    switch (mode) {
+    case (1):  /* ra */
+      for (i = 0; i < catalog.Nmeasure; i++) {
+	if ((catalog.measure[i].t < start) || (catalog.measure[i].t > stop)) continue;
+	n = catalog.measure[i].averef;
+	vec[0].elements[N] = catalog.average[n].R - catalog.measure[i].dR / 360000.0;
+	N++;
+	if (N == NPTS - 1) {
+	  NPTS += 1000;
+	  REALLOCATE (vec[0].elements, float, NPTS);
+	}
+      }
+      break;
+    case (2):  /* dec */
+      for (i = 0; i < catalog.Nmeasure; i++) {
+	if ((catalog.measure[i].t < start) || (catalog.measure[i].t > stop)) continue;
+	n = catalog.measure[i].averef;
+	vec[0].elements[N] = catalog.average[n].D - catalog.measure[i].dD / 360000.0;
+	N++;
+	if (N == NPTS - 1) {
+	  NPTS += 1000;
+	  REALLOCATE (vec[0].elements, float, NPTS);
+	}
+      }
+      break;
+    case (3):  /* mag */
+      for (i = 0; i < catalog.Nmeasure; i++) {
+	if ((catalog.measure[i].t < start) || (catalog.measure[i].t > stop)) continue;
+	vec[0].elements[N] = catalog.measure[i].M / 1000.0;
+	N++;
+	if (N == NPTS - 1) {
+	  NPTS += 1000;
+	  REALLOCATE (vec[0].elements, float, NPTS);
+	}
+      }
+      break;
+    case (4):  /* dmag */
+      for (i = 0; i < catalog.Nmeasure; i++) {
+	if ((catalog.measure[i].t < start) || (catalog.measure[i].t > stop)) continue;
+	vec[0].elements[N] = catalog.measure[i].dM / 1000.0;
+	N++;
+	if (N == NPTS - 1) {
+	  NPTS += 1000;
+	  REALLOCATE (vec[0].elements, float, NPTS);
+	}
+      }
+      break;
+    case (5):  /* Mcal */
+      for (i = 0; i < catalog.Nmeasure; i++) {
+	if ((catalog.measure[i].t < start) || (catalog.measure[i].t > stop)) continue;
+	vec[0].elements[N] = catalog.measure[i].Mcal / 1000.0;
+	N++;
+	if (N == NPTS - 1) {
+	  NPTS += 1000;
+	  REALLOCATE (vec[0].elements, float, NPTS);
+	}
+      }
+      break;
+    case (6):  /* Mrel */
+      for (i = 0; i < catalog.Nmeasure; i++) {
+	if ((catalog.measure[i].t < start) || (catalog.measure[i].t > stop)) continue;
+	n = catalog.measure[i].averef;
+	vec[0].elements[N] = catalog.average[n].M / 1000.0;
+	N++;
+	if (N == NPTS - 1) {
+	  NPTS += 1000;
+	  REALLOCATE (vec[0].elements, float, NPTS);
+	}
+      }
+      break;
+    case (7):  /* source */
+      for (i = 0; i < catalog.Nmeasure; i++) {
+	if ((catalog.measure[i].t < start) || (catalog.measure[i].t > stop)) continue;
+	vec[0].elements[N] = catalog.measure[i].source;
+	N++;
+	if (N == NPTS - 1) {
+	  NPTS += 1000;
+	  REALLOCATE (vec[0].elements, float, NPTS);
+	}
+      }
+      break;
+    case (10):  /* time */
+      for (i = 0; i < catalog.Nmeasure; i++) {
+	if ((catalog.measure[i].t < start) || (catalog.measure[i].t > stop)) continue;
+	vec[0].elements[N] = TimeValue (catalog.measure[i].t, TimeReference, TimeFormat);
+	N++;
+	if (N == NPTS - 1) {
+	  NPTS += 1000;
+	  REALLOCATE (vec[0].elements, float, NPTS);
+	}
+      }
+      break;
+    }
+    if (catalog.average != 0) {
+      free (catalog.average);
+    }
+    if (catalog.measure != 0) {
+      free (catalog.measure);
+    }
+  }
+  
+  vec[0].Nelements = N;
+  REALLOCATE (vec[0].elements, float, MAX(1,N));
+  return (TRUE);
+}
+
+
+void copy_region (GSCRegion *in, GSCRegion *out) {
+    
+  out[0].RA[0]  = in[0].RA[0];
+  out[0].RA[1]  = in[0].RA[1];
+  out[0].DEC[0] = in[0].DEC[0];
+  out[0].DEC[1] = in[0].DEC[1];
+  strcpy (out[0].filename, in[0].filename);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/imdense.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/imdense.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/imdense.c	(revision 3338)
@@ -0,0 +1,77 @@
+# include "dvo.h"
+extern double drand48();
+
+int imdense (int argc, char **argv) {
+  
+  long A, B;
+  int i, N, Nimage, status, NPTS, Ngraph;
+  double r, d, x, y, Rmin, Rmax;
+  Vector Xvec, Yvec;
+  Image *image;
+  Graphdata graphmode;
+
+  /* need options to list only images in region and only images in a time range */
+  /* also, option to list and not plot or plot and not list images */
+  if (argc != 1) {
+    fprintf (stderr, "USAGE: image\n");
+    return (FALSE);
+  }
+  Ngraph = 0;
+  if (!GetGraph (&graphmode, NULL, &Ngraph)) return (FALSE);
+
+  image = LoadImages (&Nimage);
+  if (Nimage == 0) {
+    return (FALSE);
+  }
+
+  Rmin = graphmode.coords.crval1 - 182.0;
+  Rmax = graphmode.coords.crval1 + 182.0;
+  
+  A = time(NULL);
+  for (B = 0; A == time(NULL); B++);
+  srand48(B);
+
+  NPTS = 200;
+  ALLOCATE (Xvec.elements, float, NPTS);
+  ALLOCATE (Yvec.elements, float, NPTS);
+  N = 0;
+  for (i = 0; i < Nimage; i++) {
+    /* choose a position for point within image box */
+    x = (0.1 + 0.9*drand48()) * image[i].NX;
+    y = (0.1 + 0.9*drand48()) * image[i].NY;
+    /* project this image to screen display coords */
+    status = FALSE;
+    XY_to_RD (&r, &d, x, y, &image[i].coords);
+    while (r < Rmin) r += 360.0; 
+    while (r > Rmax) r -= 360.0; 
+    status |= fRD_to_XY (&Xvec.elements[N], &Yvec.elements[N], r, d, &graphmode.coords);
+    if ((Xvec.elements[N] >= graphmode.xmin) && 
+	(Xvec.elements[N] <= graphmode.xmax) && 
+	(Yvec.elements[N] >= graphmode.ymin) && 
+	(Yvec.elements[N] <= graphmode.ymax) && status) {
+      N++;
+      if (N > NPTS - 1) { 
+	NPTS += 200;
+	REALLOCATE (Xvec.elements, float, NPTS);
+	REALLOCATE (Yvec.elements, float, NPTS);
+      }
+    }
+  }
+
+  Xvec.Nelements = Xvec.Nelements = N;
+  if (N > 0) {
+    graphmode.style = 2; /* points */
+    graphmode.etype = 0;
+    PrepPlotting (N, &graphmode);
+    PlotVector (N, Xvec.elements);
+    PlotVector (N, Yvec.elements);
+  }
+
+  free (Xvec.elements);
+  free (Yvec.elements);
+  free (image);
+  return (TRUE);
+
+}
+
+
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/imextract.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/imextract.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/imextract.c	(revision 3338)
@@ -0,0 +1,185 @@
+# include "dvo.h"
+
+enum {ZERO, RA, DEC, Xm, AIRMASS, MCAL, dMCAL, PHOTCODE, TIME, FWHM, EXPTIME, NSTAR, SKY, NCAL, FLAG};
+
+int imextract (int argc, char **argv) {
+  
+  int i, j, Nimage, mode, N, Ngraph, PhotcodeSelect;
+  int TimeSelect, RegionSelect, *subset, Nsubset, TimeFormat, FlagSelect, FlagValue;
+  double x, y, ra, dec, t, trange;
+  time_t tzero, TimeReference;
+
+  PhotCode *code;
+  Graphdata graphsky;
+  Image *image;
+  Vector *vec;
+
+  Ngraph = 0;
+  if (!GetGraphData (&graphsky, NULL, &Ngraph)) return (FALSE);
+  if (!InitPhotcodes ()) return (FALSE);
+
+  /* check for time-based selection */
+  TimeSelect = FALSE;
+  if (N = get_argument (argc, argv, "-time")) {
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &tzero)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (!str_to_dtime (argv[N], &trange)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    TimeSelect = TRUE;
+  }
+
+  /* check for region-based selection */
+  RegionSelect = FALSE;
+  if (N = get_argument (argc, argv, "-region")) {
+    remove_argument (N, &argc, argv);
+    RegionSelect = TRUE;
+  }
+
+  /* check for region-based selection */
+  FlagSelect = FALSE;
+  if (N = get_argument (argc, argv, "-flag")) {
+    remove_argument (N, &argc, argv);
+    FlagValue = atoi (argv[N]);
+    remove_argument (N, &argc, argv);
+    FlagSelect = TRUE;
+  }
+
+  /* check for photcode-based selection */
+  code = NULL;
+  PhotcodeSelect = FALSE;
+  if (N = get_argument (argc, argv, "-photcode")) {
+    PhotcodeSelect = TRUE;
+    remove_argument (N, &argc, argv);
+    if ((code = GetPhotcodebyName (argv[N])) == NULL) {
+      fprintf (stderr, "ERROR: photcode %s not found in photcode table\n", argv[N]);
+      return (FALSE);
+    }
+    if ((code[0].type != PHOT_PRI) && (code[0].type != PHOT_SEC) && (code[0].type != PHOT_DEP)) {
+      fprintf (stderr, "photcode must be primary, secondary, or dependent code\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: imextract (value) [-region] [-time start range] [-photcode photcode]\n");
+    return (FALSE);
+  }
+  
+  /* identify selection */
+  mode = ZERO;
+  if (!strcasecmp (argv[1], "ra")) mode = RA;
+  if (!strcasecmp (argv[1], "dec")) mode = DEC;
+  if (!strcasecmp (argv[1], "Xm")) mode = Xm;
+  if (!strcasecmp (argv[1], "airmass")) mode = AIRMASS;
+  if (!strcasecmp (argv[1], "Mcal")) mode = MCAL;
+  if (!strcasecmp (argv[1], "dMcal")) mode = dMCAL;
+  if (!strcasecmp (argv[1], "photcode")) mode = PHOTCODE;
+  if (!strcasecmp (argv[1], "time")) mode = TIME;
+  if (!strcasecmp (argv[1], "FWHM")) mode = FWHM;
+  if (!strcasecmp (argv[1], "exptime")) mode = EXPTIME;
+  if (!strcasecmp (argv[1], "nstar")) mode = NSTAR;
+  if (!strcasecmp (argv[1], "ncal")) mode = NCAL;
+  if (!strcasecmp (argv[1], "sky")) mode = SKY;
+  if (!strcasecmp (argv[1], "flag")) mode = FLAG;
+  if (mode == ZERO) {
+    fprintf (stderr, "value may be one of the following:\n");
+    fprintf (stderr, " ra dec airmass Mcal dMcal Xm photcode time fwhm exptime nstar ncal sky flag\n");
+    return (FALSE);
+  }
+  if ((vec = SelectVector (argv[1], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  image = LoadImages (&Nimage);
+  if (Nimage == 0) {
+    return (FALSE);
+  }
+  image_subset (image, Nimage, &subset, &Nsubset, &graphsky, RegionSelect, tzero, trange, TimeSelect);
+
+  GetTimeFormat (&TimeReference, &TimeFormat);
+
+  /* create storage vector */
+  REALLOCATE (vec[0].elements, float, Nimage);
+  vec[0].Nelements = Nimage;
+  
+  N = 0;
+  /* assign vector values */
+  for (i = 0; i < Nsubset; i++) {
+    j = subset[i];
+    if (PhotcodeSelect) {
+      if (code[0].type == PHOT_DEP) {
+	if (code[0].code != image[j].source) continue;
+      } else {
+	if (code[0].code != GetPhotcodeEquivCodebyCode (image[j].source)) continue;
+      }
+    }
+    if (FlagSelect && (FlagValue != image[j].code)) continue;
+    switch (mode) {
+    case (RA):
+      x = 0.5*image[j].NX;
+      y = 0.5*image[j].NY;
+      XY_to_RD (&ra, &dec, x, y, &image[j].coords);
+      vec[0].elements[N] = ra;
+      break;
+    case (DEC):
+      x = 0.5*image[j].NX;
+      y = 0.5*image[j].NY;
+      XY_to_RD (&ra, &dec, x, y, &image[j].coords);
+      vec[0].elements[N] = dec;
+      break;
+    case (Xm):
+      vec[0].elements[N] = pow(10.0, 0.01*image[j].Xm);
+      break;
+    case (AIRMASS):
+      vec[0].elements[N] = 0.001*image[j].secz;
+      break;
+    case (MCAL):
+      vec[0].elements[N] = 0.001*image[j].Mcal;
+      break;
+    case (dMCAL):
+      vec[0].elements[N] = 0.001*image[j].dMcal;
+      break;
+    case (PHOTCODE):
+      vec[0].elements[N] = image[j].source;
+      break;
+    case (TIME):
+      t = image[j].tzero + 0.5*image[j].NY * image[j].trate / 10000;
+      vec[0].elements[N] = TimeValue (t, TimeReference, TimeFormat);
+      break;
+    case (FWHM):
+      vec[0].elements[N] = image[j].fwhm_x / 25.0;
+      break;
+    case (EXPTIME):
+      vec[0].elements[N] = image[j].exptime;
+      break;
+    case (NSTAR):
+      vec[0].elements[N] = image[j].nstar;
+      break;
+    case (NCAL):
+      vec[0].elements[N] = image[j].Mxxxx;
+      break;
+    case (SKY):
+      vec[0].elements[N] = image[j].Myyyy + 0x8000;
+      break;
+    case (FLAG):
+      vec[0].elements[N] = image[j].code;
+      break;
+    }
+    N++;
+  }
+  
+  vec[0].Nelements = N;
+  REALLOCATE (vec[0].elements, float, N);
+
+  free (subset);
+  free (image);
+  return (TRUE);
+  
+}
+  
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/imlist.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/imlist.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/imlist.c	(revision 3338)
@@ -0,0 +1,93 @@
+# include "dvo.h"
+
+int imlist (int argc, char **argv) {
+  
+  int i, j, N, Nimage, *subset, Nsubset, TimeSelect, RegionSelect, TimeFormat, NameSelect;
+  int PhotcodeSelect;
+  time_t tzero, TimeReference;
+  double r, d, trange, t;
+  char *name;
+  int Ngraph;
+  Image *image;
+  Graphdata graphmode;
+  PhotCode *PhotcodeValue;
+
+  Ngraph = 0;
+  if (!GetGraphData (&graphmode, NULL, &Ngraph)) return (FALSE);
+
+  TimeSelect = FALSE;
+  if (N = get_argument (argc, argv, "-time")) {
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &tzero)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (!str_to_dtime (argv[N], &trange)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    TimeSelect = TRUE;
+    fprintf (stderr, "plotting in range %ds - %ds (%f seconds)\n", (int)tzero, (int)(tzero + trange), trange);
+  }
+
+  RegionSelect = FALSE;
+  if (N = get_argument (argc, argv, "-region")) {
+    remove_argument (N, &argc, argv);
+    RegionSelect = TRUE;
+  }
+
+  PhotcodeSelect = FALSE;
+  if (N = get_argument (argc, argv, "-photcode")) {
+    PhotcodeSelect = TRUE;
+    remove_argument (N, &argc, argv);
+    PhotcodeValue = GetPhotcodebyName (argv[N]);
+    if (PhotcodeValue == NULL) {
+      fprintf (stderr, "photcode not found in photcode table\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+  }
+
+  NameSelect = FALSE;
+  if (N = get_argument (argc, argv, "-name")) {
+    remove_argument (N, &argc, argv);
+    name = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+    NameSelect = TRUE;
+  }
+
+  if (argc != 1) {
+    fprintf (stderr, "USAGE: image [-time start range] [-region] [-name string]\n");
+    return (FALSE);
+  }
+  
+  image = LoadImages (&Nimage);
+  if (Nimage == 0) {
+    return (FALSE);
+  }
+  image_subset (image, Nimage, &subset, &Nsubset, &graphmode, RegionSelect, tzero, trange, TimeSelect);
+
+  GetTimeFormat (&TimeReference, &TimeFormat);
+
+  for (j = 0; j < Nsubset; j++) {
+    i = subset[j];
+    if (NameSelect && (strstr (image[i].name, name) == (char *) NULL)) continue;
+    if (PhotcodeSelect) {
+      if (PhotcodeValue[0].type == PHOT_DEP) {
+	if (PhotcodeValue[0].code != image[i].source) continue;
+      } else {
+	if (PhotcodeValue[0].code != GetPhotcodeEquivCodebyCode (image[i].source)) continue;
+      }
+    }
+    t = TimeValue (image[i].tzero, TimeReference, TimeFormat);
+    XY_to_RD (&r, &d, 0.5*image[i].NX, 0.5*image[i].NY, &image[i].coords);
+    fprintf (GetOutfile(), "%3d %s %8.4f %8.4f %f %5d %2d %4.2f %5.3f %5.3f\n", 
+	     i, image[i].name, r, d, t, image[i].nstar, image[i].source, 0.001*image[i].secz, 0.001*image[i].Mcal, 0.001*image[i].dMcal);
+  }
+
+  free (subset);
+  free (image);
+  return (TRUE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/imphot.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/imphot.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/imphot.c	(revision 3338)
@@ -0,0 +1,102 @@
+# include "dvo.h"
+
+int imphot (int argc, char **argv) {
+  
+  unsigned long int tzero;
+  double trange;
+  int N, GreyScale;
+  int i, j, Nimage, Nsubset, *subset;
+  char bufname[64];
+  float *p;
+  double fx, fy, x, y, applyMcal();
+  Image *image;
+  Buffer *buf;
+
+  GreyScale = FALSE;
+  if (N = get_argument (argc, argv, "-g")) {
+    remove_argument (N, &argc, argv);
+    strcpy (bufname, argv[N]);
+    remove_argument (N, &argc, argv);
+    GreyScale = TRUE;
+  }
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: imphot tzero trange [-g buffer]\n");
+    return (FALSE);
+  }
+
+  if (GreyScale) {
+    if ((buf = SelectBuffer (bufname, ANYBUFFER, TRUE)) == NULL) return (FALSE);
+    buf[0].header.simple   = TRUE;
+    buf[0].header.unsign   = FALSE;
+    buf[0].header.extend   = FALSE;
+    buf[0].header.bitpix   = -32;
+    buf[0].header.Naxes    = 2;
+    buf[0].header.Naxis[0] = 100;
+    buf[0].header.Naxis[1] = 200;
+    buf[0].header.bzero    = 0;
+    buf[0].header.bscale   = 1;
+    CreateBuffer (&buf[0]);
+  }
+
+  /* load image(s) in time range given */
+  if (!str_to_time (argv[1], &tzero)) { 
+    fprintf (stderr, "syntax error\n");
+    return (FALSE);
+  }
+  if (!str_to_dtime (argv[2], &trange)) { 
+    fprintf (stderr, "syntax error\n");
+    return (FALSE);
+  }    
+  fprintf (stderr, "searching in range %ds - %ds (%f seconds)\n", (int)tzero, (int)(tzero + trange), trange);
+  
+  image = LoadImages (&Nimage);
+  if (Nimage == 0) {
+    return (FALSE);
+  }
+  image_subset (image, Nimage, &subset, &Nsubset, (Graphdata *) NULL, FALSE, tzero, trange, TRUE);
+
+  if ((Nsubset > 1) && GreyScale) {
+    fprintf (stderr, "more than one image selected, making GreyScale of first only\n");
+  }
+
+  if (GreyScale && Nsubset) {
+    fx = image[subset[0]].NX / 100;
+    fy = image[subset[0]].NY / 200;
+    p = (float *) buf[0].matrix.buffer;
+    for (y = 0; y < 200; y+=1.0) {
+      for (x = 0; x < 100; x+=1.0, p++) {
+	*p = applyMcal (&image[subset[0]], (fx*x), (fy*y));
+      }
+    }
+  }
+
+  for (j = 0; j < Nsubset; j++) {
+    i = subset[j];
+    switch (image[i].order) {
+    case 0:
+      fprintf (stderr, "%s: %d - %d\n", image[i].name, image[i].order, image[i].Mcal);
+      break;
+    case 1:
+      fprintf (stderr, "%s: %d - %d, %d %d\n", image[i].name, image[i].order, image[i].Mcal, image[i].Mx, image[i].My);
+      break;
+    case 2:
+      fprintf (stderr, "%s: %d - %d, %d %d, %d %d %d\n", image[i].name, image[i].order, image[i].Mcal, image[i].Mx, image[i].My, image[i].Mxx, image[i].Mxy, image[i].Myy);
+      break;
+    case 3:
+      fprintf (stderr, "%s: %d - %d, %d %d, %d %d %d, %d %d %d %d\n", image[i].name, image[i].order, image[i].Mcal, image[i].Mx, image[i].My, 
+	       image[i].Mxx, image[i].Mxy, image[i].Myy, image[i].Mxxx, image[i].Mxxy, image[i].Mxyy, image[i].Myyy);
+      break;
+    case 4:
+      fprintf (stderr, "%s: %d - %d, %d %d, %d %d %d, %d %d %d %d, %d %d %d %d %d\n", image[i].name, image[i].order, image[i].Mcal, image[i].Mx, image[i].My, 
+	       image[i].Mxx, image[i].Mxy, image[i].Myy, image[i].Mxxx, image[i].Mxxy, image[i].Mxyy, image[i].Myyy,
+	       image[i].Mxxxx, image[i].Mxxxy, image[i].Mxxyy, image[i].Mxyyy, image[i].Myyyy);
+      break;
+    }
+  }
+
+  free (image);
+  free (subset);
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/imrough.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/imrough.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/imrough.c	(revision 3338)
@@ -0,0 +1,307 @@
+# include "dvo.h"
+RegImage *load_imreg (char *DataBase, int *nimage);
+
+# define NVALUE 22
+enum {V_NONE, V_EXPTIME, V_CCDN, V_SKY, V_BIAS, V_FILTER, V_FWHM, V_AIRM, V_TIME, V_TEMP0, V_TEMP1, V_TEMP2, V_TEMP3, V_TELFOCUS, V_XPROBE, V_YPROBE, V_ZPROBE, V_RA, V_DEC, V_DETTEMP, V_ROTANGLE, V_REGTIME};
+static char valuename[NVALUE][32] = {"none", "exptime", "ccd", "sky", "bias", "filter", "fwhm", "airmass", "time", "temp0", "temp1", "temp2", "temp3", "telfocus", "xprobe", "yprobe", "zprobe", "ra", "dec", "dettemp", "rotangle", "regtime"};
+
+imrough (int argc, char **argv) {
+ 
+  int i, N, Nimage, TimeSelect;
+  int ModeSelect, TypeSelect, CCDSelect, FilterSelect, TimeFormat;
+  int type, value, mode, CCD, NVEC;
+  char DataBase[256], *Filter;
+  double trange;
+  float *Vec;
+  unsigned long tzero, tend, TimeReference;
+  RegImage *image;
+  Vector *vec;
+
+  VarConfig ("REGISTRATION_DATABASE", "%s", DataBase);
+
+  TimeSelect = FALSE;
+  if (N = get_argument (argc, argv, "-time")) {
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &tzero)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (!str_to_dtime (argv[N], &trange)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (trange < 0) {
+      trange = fabs (trange);
+      tzero -= trange;
+    }
+    TimeSelect = TRUE;
+  }
+  if (N = get_argument (argc, argv, "-trange")) {
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &tzero)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &tend)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    trange = tend - tzero;
+    if (trange < 0) {
+      trange = fabs (trange);
+      tzero -= trange;
+    }
+    TimeSelect = TRUE;
+  }
+ 
+  type = T_UNDEF;
+  TypeSelect = FALSE;
+  if (N = get_argument (argc, argv, "-type")) {
+    TypeSelect = TRUE;
+    remove_argument (N, &argc, argv);
+    type = get_image_type (argv[N]);
+    if (type == T_UNDEF) {
+      fprintf (stderr, "ERROR: invalid image type %s\n", argv[N]);
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+  }
+
+  mode = M_NONE;
+  ModeSelect = FALSE;
+  if (N = get_argument (argc, argv, "-mode")) {
+    ModeSelect = TRUE;
+    remove_argument (N, &argc, argv);
+    mode = get_image_mode (argv[N]);
+    if (mode == M_UNDEF) {
+      fprintf (stderr, "ERROR: invalid image mode %s\n", argv[N]);
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+  }
+
+  CCDSelect = FALSE;
+  if (N = get_argument (argc, argv, "-ccd")) {
+    remove_argument (N, &argc, argv);
+    CCD = atoi (argv[N]);
+    remove_argument (N, &argc, argv);
+    CCDSelect = TRUE;
+  }
+ 
+  FilterSelect = FALSE;
+  if (N = get_argument (argc, argv, "-filter")) {
+    remove_argument (N, &argc, argv);
+    Filter = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+    FilterSelect = TRUE;
+    if (!strcasecmp (Filter, "X")) {
+      FilterSelect = FALSE;
+    }
+  }
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: imrough (value)\n");
+    fprintf (stderr, "       value options:\n");
+    for (i = 1; i < NVALUE; i++) {
+      fprintf (stderr, "%s\n", valuename[i]);
+    }
+    return (FALSE);
+  }
+ 
+  /* identify selection */
+  value = V_NONE;
+  for (i = 0; (i < NVALUE) && (value == V_NONE); i++) {
+    if (!strncasecmp (argv[1], valuename[i], strlen(argv[1]))) value = i;
+  }
+  if (value == V_NONE) {
+    fprintf (stderr, "ERROR: invalid image value %s\n", argv[1]);
+    return (FALSE);
+  }
+
+  if ((vec = SelectVector (argv[1], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  image = load_imreg (DataBase, &Nimage);
+  if (image == (RegImage *) NULL) return (FALSE);
+
+  N = 0;
+  NVEC = 1000;
+  REALLOCATE (vec[0].elements, float, NVEC);
+  Vec = vec[0].elements;
+
+  GetTimeFormat (&TimeReference, &TimeFormat);
+
+  /* get data */
+  for (i = 0; i < Nimage; i++) {
+    /* skip unmatched selections */
+    if (TimeSelect && ((image[i].obstime < tzero) || (image[i].obstime > tzero + trange))) continue;
+    if (TimeSelect && ((image[i].obstime < tzero) || (image[i].obstime > tzero + trange))) continue;
+    if (FilterSelect && (strcasecmp (image[i].filter, Filter))) continue;
+    if (CCDSelect && (image[i].ccd != CCD)) continue;
+    if (TypeSelect && (image[i].type != type)) continue;
+    if (ModeSelect && (image[i].mode != mode)) continue;
+
+    /* assign correct value */
+    switch (value) {
+    case (V_EXPTIME):
+      Vec[N] = image[i].exptime;
+      break;
+    case (V_CCDN):
+      Vec[N] = image[i].ccd;
+      break;
+    case (V_SKY):
+      Vec[N] = image[i].sky;
+      break;
+    case (V_BIAS):
+      Vec[N] = image[i].bias;
+      break;
+    case (V_FILTER):
+      Vec[N] = image[i].filter[0];
+      break;
+    case (V_FWHM):
+      Vec[N] = image[i].fwhm;
+      break;
+    case (V_AIRM):
+      Vec[N] = image[i].airmass;
+      break;
+    case (V_TIME):
+      Vec[N] = TimeValue (image[i].obstime, TimeReference, TimeFormat);
+      break;
+    case (V_TEMP0):
+      Vec[N] = image[i].teltemp[0];
+      break;
+    case (V_TEMP1):
+      Vec[N] = image[i].teltemp[1];
+      break;
+    case (V_TEMP2):
+      Vec[N] = image[i].teltemp[2];
+      break;
+    case (V_TEMP3):
+      Vec[N] = image[i].teltemp[3];
+      break;
+    case (V_TELFOCUS):
+      Vec[N] = image[i].telfocus;
+      break;
+    case (V_XPROBE):
+      Vec[N] = image[i].xprobe;
+      break;
+    case (V_YPROBE):
+      Vec[N] = image[i].yprobe;
+      break;
+    case (V_ZPROBE):
+      Vec[N] = image[i].zprobe;
+      break;
+    case (V_RA):
+      Vec[N] = image[i].ra;
+      break;
+    case (V_DEC):
+      Vec[N] = image[i].dec;
+      break;
+    case (V_DETTEMP):
+      Vec[N] = image[i].dettemp;
+      break;
+    case (V_ROTANGLE):
+      Vec[N] = image[i].rotangle;
+      break;
+    case (V_REGTIME):
+      Vec[N] = TimeValue (image[i].regtime, TimeReference, TimeFormat);
+      break;
+    }
+    N++;
+    if (N >= NVEC - 1) {
+      NVEC += 1000;
+      REALLOCATE (vec[0].elements, float, NVEC);
+      Vec = vec[0].elements;
+    }
+  }
+
+  REALLOCATE (vec[0].elements, float, MAX (1,N));
+  vec[0].Nelements = N;
+
+  free (image);
+  return (TRUE);
+
+}
+
+RegImage *load_imreg (char *DataBase, int *nimage) {
+
+  int Nimage, status;
+  char line[80];
+  FILE *f;
+  Header header, theader;
+  Matrix matrix;
+  FTable table;
+  RegImage *image;
+
+  *nimage = 0;
+
+  /* open database */
+  f = fopen (DataBase, "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "ERROR: can't open Registration Database\n");
+    return ((RegImage *) NULL);
+  }
+
+  /* load in database header */
+  if (!fits_fread_header (f, &header)) {
+    fclose (f);
+    fits_free_header (&header);
+    fprintf (stderr, "ERROR: trouble reading database header\n");
+    return ((RegImage *) NULL);
+  }
+
+  /* check for database v1, v2 */
+  fits_scan (&header, "ORIGIN", "%s", 1, line);
+  if (!strcmp (line, "MDM Observatory")) {
+
+    fseek (f, header.size, SEEK_SET);
+    
+    /* load existing data from database */
+    fits_scan (&header, "NIMAGES", "%d", 1, &Nimage);
+    ALLOCATE (image, RegImage, Nimage);
+    status = Fread (image, sizeof(RegImage), Nimage, f, "regimage");
+    fclose (f);
+    
+    if (status != Nimage) {
+      fprintf (stderr, "ERROR: header and data in dB don't match (%d vs %d)\n", Nimage, status);
+      fits_free_header (&header);
+      free (image);
+      return ((RegImage *) NULL);
+    }
+
+    *nimage = Nimage;
+    return (image);
+  }
+
+  /* we probably have v3 */
+  if (!fits_fread_matrix (f, &matrix, &header)) {
+    fclose (f);
+    fits_free_header (&header);
+    fits_free_matrix (&matrix);
+    fprintf (stderr, "ERROR: trouble reading database matrix\n");
+    return ((RegImage *) NULL);
+  }
+
+  table.header = &theader;
+  if (!fits_fread_ftable  (f, &table, "IMAGE_DATABASE")) {
+    fclose (f);
+    fits_free_header (&header);
+    fits_free_matrix (&matrix);
+    fprintf (stderr, "ERROR: trouble reading database table\n");
+    return ((RegImage *) NULL);
+  }
+
+  /* convert to internal format */
+  image = (RegImage *) table.buffer;
+  fits_scan (table.header, "NAXIS2", "%d", 1, &Nimage);
+  ConvertStruct ((char *) image, sizeof (RegImage), Nimage, "regimage");
+
+  fits_free_header (&header);
+  fits_free_matrix (&matrix);
+
+  *nimage = Nimage;
+  return (image);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/imsearch.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/imsearch.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/imsearch.c	(revision 3338)
@@ -0,0 +1,149 @@
+# include "dvo.h"
+
+imsearch (int argc, char **argv) {
+ 
+  char DataBase[256], name[64];
+  FILE *f;
+  Header header;
+  RegImage *pimage;
+  int i, Nimage, status, N, TimeSelect, SaveNames;
+  int ModeSelect, TypeSelect, CCDSelect, FilterSelect;
+  char *Filter, *obstime;
+  int Type, Mode, CCD;
+  unsigned long int tzero;
+  double trange;
+   
+  VarConfig ("REGISTRATION_DATABASE", "%s", DataBase);
+
+  SaveNames = FALSE;
+  if (N = get_argument (argc, argv, "-save")) {
+    remove_argument (N, &argc, argv);
+    SaveNames = TRUE;
+  }
+ 
+  TimeSelect = FALSE;
+  if (N = get_argument (argc, argv, "-time")) {
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &tzero)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (!str_to_dtime (argv[N], &trange)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    TimeSelect = TRUE;
+  }
+ 
+  TypeSelect = FALSE;
+  if (N = get_argument (argc, argv, "-type")) {
+    remove_argument (N, &argc, argv);
+    Type = get_image_type (argv[N]);
+    if (Type == T_UNDEF) {
+      fprintf (stderr, "ERROR: invalid image type %s\n", argv[N]);
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    TypeSelect = TRUE;
+  }
+ 
+  ModeSelect = FALSE;
+  if (N = get_argument (argc, argv, "-mode")) {
+    remove_argument (N, &argc, argv);
+    Mode = get_image_mode (argv[N]);
+    if (Mode == M_UNDEF) {
+      fprintf (stderr, "ERROR: invalid image mode %s\n", argv[N]);
+      exit (1);
+    }
+    remove_argument (N, &argc, argv);
+    ModeSelect = TRUE;
+  }
+ 
+  CCDSelect = FALSE;
+  if (N = get_argument (argc, argv, "-ccd")) {
+    remove_argument (N, &argc, argv);
+    CCD = atoi (argv[N]);
+    remove_argument (N, &argc, argv);
+    CCDSelect = TRUE;
+  }
+ 
+  FilterSelect = FALSE;
+  if (N = get_argument (argc, argv, "-filter")) {
+    remove_argument (N, &argc, argv);
+    Filter = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+    FilterSelect = TRUE;
+    if (!strcasecmp (Filter, "X")) {
+      FilterSelect = FALSE;
+    }
+  }
+
+  if (argc != 1) {
+    fprintf (stderr, "USAGE: imsearch [-time start range] [-type type] [-mode mode] [-ccd N] [-filter name]\n");
+    exit (1);
+  }
+
+  /* load in database header */
+  if (!fits_read_header (DataBase, &header)) {
+    fprintf (stderr, "ERROR: trouble reading database header\n");
+    return (FALSE);
+  }
+
+  /* open database */
+  f = fopen (DataBase, "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "ERROR: can't open Registration Database\n");
+    return (FALSE);
+  }
+  fseek (f, header.size, SEEK_SET);
+
+  /* load existing data from database */
+  fits_scan (&header, "NIMAGES", "%d", 1, &Nimage);
+  ALLOCATE (pimage, RegImage, Nimage);
+  status = Fread (pimage, sizeof(RegImage), Nimage, f, "regimage");
+  fclose (f);
+
+  if (status != Nimage) {
+    fprintf (stderr, "ERROR: header and data in dB don't match (%d vs %d)\n", Nimage, status);
+    fits_free_header (&header);
+    free (pimage);
+    return (FALSE);
+  }
+
+  /* print out all data */
+  N = 0;
+  for (i = 0; i < Nimage; i++) {
+    if (TimeSelect && ((pimage[i].obstime < tzero) || (pimage[i].obstime > tzero + trange))) continue;
+    if (FilterSelect && (strcasecmp (pimage[i].filter, Filter))) continue;
+    if (ModeSelect && (pimage[i].mode != Mode)) continue;
+    if (CCDSelect && (pimage[i].ccd != CCD)) continue;
+    if (TypeSelect && (pimage[i].type != Type)) continue;
+
+    obstime = ctime ((time_t *)&pimage[i].obstime);
+    obstime[strlen(obstime)-1] = 0;
+
+    fprintf (stdout, "%5d %6s %6s %2d %2d   ", i, get_type_name(pimage[i].type), get_mode_name(pimage[i].mode), pimage[i].ccd, pimage[i].type);
+    fprintf (stdout, "%s %s  ", pimage[i].pathname, pimage[i].filename);
+    fprintf (stdout, "%s %s %f %s\n", pimage[i].filter, pimage[i].instrument, pimage[i].exptime, obstime);
+
+    if (SaveNames) {
+      sprintf (name, "IMAGEpath:%d", N);
+      set_str_variable (name, pimage[i].pathname);
+      sprintf (name, "IMAGEfile:%d", N);
+      set_str_variable (name, pimage[i].filename);
+      sprintf (name, "IMAGEmode:%d", N);
+      set_int_variable (name, pimage[i].mode);
+    }
+    N++;
+  }
+  if (SaveNames) {
+    set_int_variable ("IMAGEpath:n", N);
+    set_int_variable ("IMAGEfile:n", N);
+  }
+
+  free (pimage);
+  fits_free_header (&header);
+  return (TRUE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/imstats.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/imstats.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/imstats.c	(revision 3338)
@@ -0,0 +1,71 @@
+# include "dvo.h"
+
+int imstats (int argc, char **argv) {
+  
+  int i, Nimage, N;
+  int Mcal, AutoLimits, Ngraph;
+  double r, d;
+  Image *image;
+  Vector Xvec, Yvec;  
+  Graphdata graphmode;
+
+  Ngraph = -1;
+  if (N = get_argument (argc, argv, "-n")) {
+    remove_argument (N, &argc, argv);
+    Ngraph = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetGraph (&graphmode, NULL, &Ngraph)) return (FALSE);
+
+  Mcal = TRUE;
+  if (N = get_argument (argc, argv, "-dM")) {
+    remove_argument (N, &argc, argv);
+    Mcal = FALSE;
+  }
+
+  AutoLimits = FALSE;
+  if (N = get_argument (argc, argv, "-l")) {
+    remove_argument (N, &argc, argv);
+    AutoLimits = TRUE;
+  }
+
+  if (argc != 1) {
+    fprintf (stderr, "USAGE: imstats [-dM] [-l]\n");
+    return (FALSE);
+  }
+
+  image = LoadImages (&Nimage);
+  if (Nimage == 0) {
+    return (FALSE);
+  }
+
+  /* assign vector values */
+  Xvec.Nelements = Nimage;
+  Yvec.Nelements = Nimage;
+  ALLOCATE (Xvec.elements, float, Xvec.Nelements);
+  ALLOCATE (Yvec.elements, float, Yvec.Nelements);
+  fprintf (stdout, "seq  ra (J2000) dec    time (s)   Nstars\n");
+  for (i = 0; i < Nimage; i++) {
+    Xvec.elements[i] = 0.001*image[i].secz;
+    if (Mcal) 
+      Yvec.elements[i] = 0.001*image[i].Mcal;
+    else 
+      Yvec.elements[i] = 0.001*image[i].dMcal;
+    XY_to_RD (&r, &d, 0.5*image[i].NX, 0.5*image[i].NY, &image[i].coords);
+    fprintf (stderr, "%d %8.4f %8.4f %10d %6d  %5.3f %6.3f %6.3f\n", 
+	     i, r, d, image[i].tzero, image[i].nstar, Xvec.elements[i], 
+	     0.001*image[i].Mcal, 0.001*image[i].dMcal);
+  } 
+  if (AutoLimits) SetLimits (&Xvec, &Yvec, &graphmode);
+
+  graphmode.style = 2;
+  graphmode.etype = 0;
+  PrepPlotting (Nimage, &graphmode);
+  PlotVector (Nimage, Xvec.elements);
+  PlotVector (Nimage, Yvec.elements);
+  
+  free (Xvec.elements);
+  free (Yvec.elements);
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/init.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/init.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/init.c	(revision 3338)
@@ -0,0 +1,105 @@
+# include "dvo.h"
+
+int avextract	    PROTO((int, char **));
+int badimages	    PROTO((int, char **));
+int calextract	    PROTO((int, char **));
+int calmextract	    PROTO((int, char **));
+int catlog	    PROTO((int, char **));
+int ccd		    PROTO((int, char **));
+int cmatch	    PROTO((int, char **));
+int cmd		    PROTO((int, char **));
+int cmpload	    PROTO((int, char **));
+int cmpread	    PROTO((int, char **));
+int ddmags	    PROTO((int, char **));
+int detrend	    PROTO((int, char **));
+int dmagaves	    PROTO((int, char **));
+int dmagmeas	    PROTO((int, char **));
+int dmags	    PROTO((int, char **));
+int dmt		    PROTO((int, char **));
+int elixir          PROTO((int, char **));
+int gcat	    PROTO((int, char **));
+int getxtra	    PROTO((int, char **));
+int gimages	    PROTO((int, char **));
+int gstar	    PROTO((int, char **));
+int gtypes	    PROTO((int, char **));
+int images	    PROTO((int, char **));
+int imbox	    PROTO((int, char **));
+int imdata	    PROTO((int, char **));
+int imdense	    PROTO((int, char **));
+int imextract	    PROTO((int, char **));
+int imlist	    PROTO((int, char **));
+int imphot	    PROTO((int, char **));
+int imrough	    PROTO((int, char **));
+int imsearch	    PROTO((int, char **));
+int imstats	    PROTO((int, char **));
+int lcat	    PROTO((int, char **));
+int lcurve	    PROTO((int, char **));
+int mextract	    PROTO((int, char **));
+int pcat	    PROTO((int, char **));
+int photcodes	    PROTO((int, char **));
+int pmeasure	    PROTO((int, char **));
+int procks	    PROTO((int, char **));
+int showtile	    PROTO((int, char **));
+int simage	    PROTO((int, char **));
+int subpix	    PROTO((int, char **));
+
+/* temporarily exclude
+int addxtra	    PROTO((int, char **));
+  {"addxtra",     addxtra,      "add extra data to object"},
+  {"getxtra",     getxtra,      "get extra data from object"},
+*/
+
+static Command cmds[] = {  
+  {"avextract",   avextract,    "extract average data values"},
+  {"badimages",   badimages,    "look for images with anomalous astrometry"},
+  {"calextract",  calextract,   "extract photometry calibration"},
+  {"calmextract", calmextract,  "extract photometry calibration"},
+  {"catalog",     catlog,       "plot catalog stars"},
+  {"ccd",         ccd,          "plot color-color diagram"},
+  {"cmatch",      cmatch,       "match two catalogs"},
+  {"cmd",         cmd,          "plot cmd of stars in current region"},
+  {"cmpload",     cmpload,      "load cmp file into ?"},
+  {"cmpread",     cmpread,      "read data from cmp format files"},
+  {"ddmags",      ddmags,       "plot magnitude differences"},
+  {"detrend", 	  detrend,      "extract from detrend database?"},
+  {"dmagaves",    dmagaves,     "foo"},
+  {"dmagmeas",    dmagmeas,     "foo"},
+  {"dmags",       dmags,        "plot differential magnitudes between filters"},
+  {"dmt",         dmt,          "plot mag scatter"},
+  {"elixir",      elixir,       "talk to elixir"},
+  {"gcat",    	  gcat,         "get catalog at location"},
+  {"gimages", 	  gimages,      "get images at location"},
+  {"gstar",       gstar,        "get star statistics"},
+  {"images",  	  images,       "plot image boxes"},
+  {"imbox",   	  imbox,        "plot expected image box"},
+  {"imdata",  	  imdata,       "extract data for specific images"},
+  {"imdense", 	  imdense,      "image density plot"},
+  {"imextract",   imextract,    "extract vectors from catalogs"},
+  {"imlist",      imlist,       "list image info"},
+  {"imphot",      imphot,       "image photometry info"},
+  {"imrough",     imrough,      "get info from imruf database"},
+  {"imsearch",    imsearch,     "get info from imreg database"},
+  {"imstats", 	  imstats,      "plot image statistics"},
+  {"lcat",    	  lcat,         "list catalogs in region"},
+  {"lcurve",      lcurve,       "plot lightcurve for a star"},
+  {"mextract",    mextract,     "extract measure data values"},
+  {"pcat",    	  pcat,         "plot catalog boundaries"},
+  {"photcodes",   photcodes,    "list photometry codes"},
+  {"pmeasure",    pmeasure,     "plot individual measurements"},
+  {"procks",      procks,       "plot rocks"},
+  {"showtile",    showtile,     "plot tile pattern"},
+  {"simage",      simage,       "plot stars in an image"},
+  {"subpix",      subpix,       "get subpixel positions"},
+}; 
+
+/* move to astro */
+
+void InitDVO () {
+  
+  int i;
+
+  for (i = 0; i < sizeof (cmds) / sizeof (Command); i++) {
+    AddCommand (&cmds[i]);
+  }
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/lcat.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/lcat.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/lcat.c	(revision 3338)
@@ -0,0 +1,50 @@
+# include "dvo.h"
+
+int lcat (int argc, char **argv) {
+  
+  double Radius;
+  int i, N, Nregions, ShowAll;
+  RegionFile *regions;
+  char filename[128], exists;
+  struct stat filestat;
+  char catdir[256];
+  Graphdata graphmode;
+  int Ngraph;
+
+  Ngraph = 0;
+  if (!GetGraphData (&graphmode, NULL, &Ngraph)) return (FALSE);
+
+  VarConfig ("CATDIR", "%s", catdir);
+
+  ShowAll = FALSE;
+  if (N = get_argument (argc, argv, "-all")) {
+    remove_argument (N, &argc, argv);
+    ShowAll = TRUE;
+  }
+  if (argc != 1) {
+    fprintf (stderr, "USAGE: lcat [-all]\n");
+    return (FALSE);
+  }
+
+  Radius = MAX (fabs(graphmode.xmax), fabs(graphmode.ymax));
+  regions = find_regions (graphmode.coords.crval1, graphmode.coords.crval2, Radius, &Nregions);
+
+  for (i = 0; i < Nregions; i++) {
+    sprintf (filename, "%s/%s", catdir, regions[i].name);
+    exists = 'Y';
+    if (stat (filename, &filestat) == -1) exists = 'N';
+    if (ShowAll) {
+      fprintf (stderr, "%3d %s  %c\n", i, regions[i].name, exists);
+    } else {
+      if (exists == 'Y') {
+	fprintf (stderr, "%3d %s\n", i, regions[i].name);
+      }
+    }
+  }
+
+  return (TRUE);
+
+  free (regions);
+
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/lcurve.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/lcurve.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/lcurve.c	(revision 3338)
@@ -0,0 +1,199 @@
+# include "dvo.h"
+
+int lcurve (int argc, char **argv) {
+  
+  char filename[128], string[128], catdir[256], *p;
+  double Ra, Dec, Radius, Radius2, r;
+  float *RA, *DEC;
+  int Ngraph, Xgraph, TimeFormat;
+  int Nstars, found, AutoLimits, ErrorBars, GalMag, AbsPhot, SaveVectors;
+  int i, j, m, N, NPTS, *N1, Nregions;
+  time_t TimeReference;
+  struct tm *timeptr;
+  RegionFile *regions;
+  Vector *xvec, *yvec;
+  Vector Xvec, Yvec, dYvec;
+  Catalog catalog;
+  Graphdata graphmode;
+
+  VarConfig ("CATDIR", "%s", catdir);
+  if (!InitPhotcodes ()) return (FALSE);
+
+  Ngraph = -1;
+  if (N = get_argument (argc, argv, "-n")) {
+    remove_argument (N, &argc, argv);
+    Ngraph = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetGraph (&graphmode, &Xgraph, &Ngraph)) return (FALSE);
+
+  AutoLimits = FALSE;
+  if (N = get_argument (argc, argv, "-l")) {
+    remove_argument (N, &argc, argv);
+    AutoLimits = TRUE;
+  }
+
+  SaveVectors = FALSE;
+  if (N = get_argument (argc, argv, "-v")) {
+    remove_argument (N, &argc, argv);
+    SaveVectors = TRUE;
+    if ((xvec = SelectVector (argv[N], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    remove_argument (N, &argc, argv);
+    if ((yvec = SelectVector (argv[N], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    remove_argument (N, &argc, argv);
+  }
+
+  AbsPhot = FALSE;
+  if (N = get_argument (argc, argv, "-abs")) {
+    remove_argument (N, &argc, argv);
+    AbsPhot = TRUE;
+  }
+
+  GalMag = FALSE;
+  if (N = get_argument (argc, argv, "-gal")) {
+    fprintf (stderr, "galaxy magnitudes currently disabled\n");
+    return (FALSE);
+  }
+
+  ErrorBars = FALSE;
+  if (N = get_argument (argc, argv, "-d")) {
+    remove_argument (N, &argc, argv);
+    ErrorBars = TRUE;
+  }
+
+  if (argc < 4) {
+    fprintf (stderr, "USAGE: lcurve RA DEC Radius\n");
+    return (FALSE);
+  }
+  
+  Ra = atof (argv[1]);
+  Dec = atof (argv[2]);
+  Radius = atof (argv[3]);
+
+  regions = find_regions (Ra, Dec, Radius, &Nregions);
+
+  if (Nregions > 1) {
+    fprintf (stderr, "warning, radius overlaps region boundary, not yet implemented\n");
+  }
+
+  /* set filename, read in header */
+  sprintf (filename, "%s/%s", catdir, regions[0].name);
+  catalog.filename = filename;
+  switch (lock_catalog (&catalog, LCK_SOFT)) {
+  case 2:
+    unlock_catalog (&catalog);
+  case 0:
+    return (FALSE);
+  }
+  if (!load_catalog (&catalog, LOAD_AVES | LOAD_MEAS, TRUE)) {
+    unlock_catalog (&catalog);
+    return (FALSE);
+  }
+  unlock_catalog (&catalog);
+
+  Nstars = catalog.Naverage;
+  ALLOCATE (RA, float, Nstars);
+  ALLOCATE (DEC, float, Nstars);
+  ALLOCATE (N1, int, Nstars);
+
+  /* find star(s) in RA, DEC list -- use a dumb algorithm for now, improve later */
+  /* stars are not guaranteed to be sorted in RA or in DEC, so first sort the list */
+  for (i = 0; i < Nstars; i++) {
+    RA[i] = catalog.average[i].R;
+    DEC[i] = catalog.average[i].D;
+    N1[i] = i;
+  }
+  /* sort list by DEC */
+  if (Nstars > 1) sort_lists (DEC, RA, N1, Nstars);
+  /* at this point, RA, DEC, and N1 are sorted by DEC.  
+     catalog.average[N1[i]].R = RA[i] */
+
+  NPTS = 100;
+  ALLOCATE (Xvec.elements, float, NPTS);
+  ALLOCATE (Yvec.elements, float, NPTS);
+  if (ErrorBars) { ALLOCATE (dYvec.elements, float, NPTS); }
+  N = 0;
+
+  GetTimeFormat (&TimeReference, &TimeFormat);
+
+  Radius2 = Radius*Radius;
+  found = FALSE;
+  for (i = 0; (i < catalog.Naverage) && !found; i++) {
+
+    /* this can be improved by using a couple of jumps to get within range */
+    if (Dec > DEC[i] + Radius)
+      continue;
+    
+    r = SQ(Dec - DEC[i]) + SQ(Ra - RA[i]);
+    if (r < Radius2) {
+      /* found star, extract measurements */
+      m = catalog.average[N1[i]].offset;
+      for (j = 0; j < catalog.average[N1[i]].Nm; j++, m++) {
+	if (ErrorBars) dYvec.elements[N] = 0.001*catalog.measure[m].dM;
+	Xvec.elements[N] = TimeValue (catalog.measure[m].t, TimeReference, TimeFormat);
+	Yvec.elements[N] = PhotCat (&catalog.measure[m]);
+	/**** need to use PhotRel optionally here ****/
+	N++; 
+	if (N == NPTS) {
+	  NPTS += 100;
+	  REALLOCATE (Xvec.elements, float, NPTS);
+	  REALLOCATE (Yvec.elements, float, NPTS);
+	  if (ErrorBars) { REALLOCATE (dYvec.elements, float, NPTS); }
+	}
+      }      
+    }
+  }
+  Xvec.Nelements = Yvec.Nelements = N;
+  if (ErrorBars) dYvec.Nelements = N;
+  
+  if (ErrorBars)
+    sortthree (Xvec.elements, Yvec.elements, dYvec.elements, N);
+  else
+    fsortpair (Xvec.elements, Yvec.elements, N);
+
+  /* autoscale the plot */
+  if (AutoLimits) SetLimits (&Xvec, &Yvec, &graphmode);
+
+  if (ErrorBars) 
+    graphmode.etype = 1;  /* y errors only in lcurves */
+  else
+    graphmode.etype = 0;  
+
+  PrepPlotting (N, &graphmode);
+  PlotVector (N, Xvec.elements);
+  PlotVector (N, Yvec.elements);
+  if (ErrorBars) {
+    PlotVector (N, dYvec.elements);
+    PlotVector (N, dYvec.elements);
+  }
+
+  timeptr = gmtime ((time_t *)&TimeReference);
+
+  if ((p = get_variable ("TIMEFORMAT")) == (char *) NULL) p = strcreate ("days");
+  sprintf (string, "%s since %02d/%02d/%02d UT", p,
+	   timeptr[0].tm_year, timeptr[0].tm_mon+1, timeptr[0].tm_mday);
+  free (p);
+  SendLabel (string, Xgraph, 0);
+
+  free (RA);
+  free (DEC);
+  free (N1);
+
+  if (SaveVectors) {
+    free (xvec[0].elements);
+    free (yvec[0].elements);
+    xvec[0].elements = Xvec.elements;
+    yvec[0].elements = Yvec.elements;
+    xvec[0].Nelements = yvec[0].Nelements = Xvec.Nelements;
+  } else {
+    free (Xvec.elements);
+    free (Yvec.elements);
+  }
+
+  if (ErrorBars) free (dYvec.elements);
+  if (catalog.average != 0) free (catalog.average);
+  if (catalog.measure != 0) free (catalog.measure);
+ 
+  return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/match_image.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/match_image.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/match_image.c	(revision 3338)
@@ -0,0 +1,73 @@
+# include "dvo.h"
+
+int match_image (Image *image, int Nimage, unsigned int T, short int S) {
+
+  int N, Nlo, Nhi, N1, N2;
+
+  /* bracket first value of interest */
+  Nlo = 0; Nhi = Nimage;
+  while (Nhi - Nlo > 10) {
+    N = 0.5*(Nlo + Nhi);
+    if (image[N].tzero < T) {
+      Nlo = N;
+    } else {
+      Nhi = N + 1;
+    }
+  }
+  N1 = Nlo;
+
+  /* bracket last value of interest */
+  Nlo = 0; Nhi = Nimage;
+  while (Nhi - Nlo > 10) {
+    N = 0.5*(Nlo + Nhi);
+    if (image[N].tzero > T) {
+      Nhi = N;
+    } else {
+      Nlo = N - 1;
+    }
+  }
+  N2 = Nhi;
+
+  for (N = N1; N < N2; N++) {
+    if ((image[N].tzero == T) && (image[N].source == S)) {
+      return (N);
+    }
+  }
+  return (-1);
+}
+
+int match_image_subset (Image *image, int *subset, int Nsubset, unsigned int T, short int S) {
+
+  int N, Nlo, Nhi, N1, N2;
+
+  /* bracket first value of interest */
+  Nlo = 0; Nhi = Nsubset;
+  while (Nhi - Nlo > 10) {
+    N = 0.5*(Nlo + Nhi);
+    if (image[subset[N]].tzero < T) {
+      Nlo = N;
+    } else {
+      Nhi = N + 1;
+    }
+  }
+  N1 = Nlo;
+
+  /* bracket last value of interest */
+  Nlo = 0; Nhi = Nsubset;
+  while (Nhi - Nlo > 10) {
+    N = 0.5*(Nlo + Nhi);
+    if (image[subset[N]].tzero > T) {
+      Nhi = N;
+    } else {
+      Nlo = N - 1;
+    }
+  }
+  N2 = Nhi;
+
+  for (N = N1; N < N2; N++) {
+    if ((image[subset[N]].tzero == T) && (image[subset[N]].source == S)) {
+      return (subset[N]);
+    }
+  }
+  return (-1);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/mextract.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/mextract.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/mextract.c	(revision 3338)
@@ -0,0 +1,146 @@
+# include "dvo.h"
+
+int mextract (int argc, char **argv) {
+  
+  int i, j, k, m, N, N1, NPTS;
+  int param, mode, Nregions, Ngraph, Nsec;
+  char filename[128], catdir[256], *p;
+  double *M1;
+
+  PhotCode *code;
+  Catalog catalog;
+  RegionFile *regions;
+  Graphdata graphsky;
+  Vector *vec;
+
+  regions = NULL;
+  catalog.average = (Average *) NULL; 
+  catalog.secfilt = (SecFilt *) NULL;
+  catalog.measure = (Measure *) NULL;
+
+  /* load photcode information */
+  if (!InitPhotcodes ()) goto escape;
+  Nsec = GetPhotcodeNsecfilt ();
+
+  /* load data about plot windows */
+  Ngraph = 0;
+  if (!GetGraphData (&graphsky, NULL, &Ngraph)) goto escape;
+ 
+  /* find CATDIR in config system */
+  VarConfig ("CATDIR", "%s", catdir);
+
+  /* specify catalog files
+  RegionList = FALSE;
+  if (N = get_argument (argc, argv, "-list")) {
+    RegionList = TRUE;
+    remove_argument (N, &argc, argv);
+    strcpy (RegionListFile, argv[N]);
+    remove_argument (N, &argc, argv);
+  } */
+
+  /* interpret command-line options */
+  if (!SetPhotSelections (&argc, argv)) goto usage;
+  if (argc != 3) goto usage;
+
+  /* identify selection */
+  code = NULL;
+  mode = MAG_REL;
+  param = GetMeasureParam (argv[2]);
+  if (param == MEAS_ZERO) {
+    if (!GetPhotcodeInfo (argv[2], &code, &mode)) {
+      GetMeasureParam ("help");
+      fprintf (stderr, "value may also be a valid photcode\n");
+      fprintf (stderr, "photcodes or 'mag' may have optional magnitude type: mag,[Minst, Mcat, Msys, Mrel, Mcal]\n");
+      goto escape;
+    }
+    param = MEAS_MAG;
+    for (p = argv[2]; *p != 0; p++) { 
+      if (*p == '.') *p = ':';
+    }
+  } 
+  /* test PhotSelections: is photcode specified if needed? */
+  if (!TestPhotSelections (&code)) {
+    fprintf (stderr, "photcode selection rules violated\n");
+    fprintf (stderr, "average and ensemble restrictions require a corresponding photcode\n");
+    goto escape;
+  }
+
+  if ((vec = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) goto escape;
+
+  /* determine region-file names */
+  if (!strcmp (argv[1], "all")) {
+    float Radius;
+    Radius = MAX (fabs(graphsky.xmax), fabs(graphsky.ymax));
+    regions = find_regions (graphsky.coords.crval1, graphsky.coords.crval2, Radius, &Nregions);
+    /* I don't have a tool to select images by the overlapping region */
+    if (!SetImageSelection (param, &graphsky, TRUE)) goto escape;
+  } else {
+    Nregions = 1;
+    ALLOCATE (regions, RegionFile, 1);
+    strcpy (regions[0].name, argv[1]);
+    if (!SetImageSelection (param, NULL, FALSE)) goto escape;
+  }
+
+  /* create storage vector */
+  NPTS = 1000;
+  REALLOCATE (vec[0].elements, float, NPTS);
+  vec[0].Nelements = N = 0;
+
+  for (i = 0; i < Nregions; i++) {
+    /* lock, load, unlock catalog */
+    sprintf (filename, "%s/%s", catdir, regions[i].name);
+    catalog.filename = filename;
+    switch (lock_catalog (&catalog, LCK_SOFT)) {
+    case 2:
+      unlock_catalog (&catalog);
+    case 0:
+      continue;
+    }
+    if (!load_catalog (&catalog, LOAD_AVES | LOAD_MEAS | LOAD_SECF, FALSE)) {
+      unlock_catalog (&catalog);
+      continue;
+    }
+    unlock_catalog (&catalog);
+
+    for (j = 0; j < catalog.Naverage; j++) {
+      M1 = NULL;
+      m = catalog.average[j].offset;
+      M1 = ExtractMeasures (code, mode, &catalog.average[j], &catalog.secfilt[j*Nsec], &catalog.measure[m], &N1, param);
+      for (k = 0; k < N1; k++) {
+	vec[0].elements[N] = M1[k];
+	N++;
+	if (N == NPTS - 1) {
+	  NPTS += 2000;
+	  REALLOCATE (vec[0].elements, float, NPTS);
+	}
+      }
+      if (M1 != NULL) free (M1);
+    }
+    if (catalog.average != NULL) free (catalog.average);
+    if (catalog.secfilt != NULL) free (catalog.secfilt);
+    if (catalog.measure != NULL) free (catalog.measure);
+    catalog.average = (Average *) NULL; 
+    catalog.secfilt = (SecFilt *) NULL;
+    catalog.measure = (Measure *) NULL;
+  }
+  vec[0].Nelements = N;
+  REALLOCATE (vec[0].elements, float, MAX(1,N));
+
+  if (regions != NULL) free (regions);
+  FreeImageSelection ();
+  return (TRUE);
+
+usage:
+  fprintf (stderr, "USAGE: mextract (from) (value) [options]\n");
+  fprintf (stderr, "  from: cpt name or 'all'\n");
+  fprintf (stderr, "  value: measure.parameter or photcode\n");
+  return (FALSE);
+
+escape:
+  if (regions != NULL) free (regions);
+  FreeImageSelection ();
+  if (catalog.average != NULL) free (catalog.average);
+  if (catalog.secfilt != NULL) free (catalog.secfilt);
+  if (catalog.measure != NULL) free (catalog.measure);
+  return (FALSE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/pcat.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/pcat.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/pcat.c	(revision 3338)
@@ -0,0 +1,82 @@
+# include "dvo.h"
+
+int pcat (int argc, char **argv) {
+  
+  double Radius;
+  int i, j, N, Nregions, ShowAll, NPTS, Npts;
+  RegionFile *regions;
+  char filename[128];
+  struct stat filestat;
+  Vector Xvec, Yvec;
+  Graphdata graphmode;
+  double X[4], Y[4];
+  char catdir[256];
+  int Ngraph;
+
+  VarConfig ("CATDIR", "%s", catdir);
+
+  ShowAll = FALSE;
+  if (N = get_argument (argc, argv, "-all")) {
+    remove_argument (N, &argc, argv);
+    ShowAll = TRUE;
+  }
+  if (argc != 1) {
+    fprintf (stderr, "USAGE: pcat [-all]\n");
+    return (FALSE);
+  }
+  Ngraph = 0;
+  if (!GetGraph (&graphmode, NULL, &Ngraph)) return (FALSE);
+  
+  Radius = MAX (fabs(graphmode.xmax), fabs(graphmode.ymax));
+  regions = find_regions (graphmode.coords.crval1, graphmode.coords.crval2, Radius, &Nregions);
+
+  NPTS = 200;
+  ALLOCATE (Xvec.elements, float, NPTS);
+  ALLOCATE (Yvec.elements, float, NPTS);
+  Npts = 0;
+   
+  for (i = 0; i < Nregions; i++) {
+    sprintf (filename, "%s/%s", catdir, regions[i].name);
+    if (ShowAll || (stat (filename, &filestat) != -1)) {
+      fprintf (stderr, "%3d %s\n", i, regions[i].name);
+      RD_to_XY (&X[0], &Y[0], regions[i].RA0, regions[i].DEC0, &graphmode.coords);
+      RD_to_XY (&X[1], &Y[1], regions[i].RA0, regions[i].DEC1, &graphmode.coords);
+      RD_to_XY (&X[2], &Y[2], regions[i].RA1, regions[i].DEC1, &graphmode.coords);
+      RD_to_XY (&X[3], &Y[3], regions[i].RA1, regions[i].DEC0, &graphmode.coords);
+      for (j = 0; j < 4; j++) {
+	Xvec.elements[Npts + j*2] = X[j];
+	Yvec.elements[Npts + j*2] = Y[j];
+	if (j > 0) {
+	  Xvec.elements[Npts+2*j - 1] = Xvec.elements[Npts+2*j];
+	  Yvec.elements[Npts+2*j - 1] = Yvec.elements[Npts+2*j];
+	}
+      }
+      Xvec.elements[Npts+7] = Xvec.elements[Npts];
+      Yvec.elements[Npts+7] = Yvec.elements[Npts];
+      Npts += 8;
+      if (Npts > NPTS - 1) {  /* this is OK because NPTS is made always a multiple of 8 */
+	NPTS += 200;
+	REALLOCATE (Xvec.elements, float, NPTS);
+	REALLOCATE (Yvec.elements, float, NPTS);
+      }
+    }
+  }
+
+  fprintf (stderr, "plotting %d catalogs\n", Npts/8);
+  Xvec.Nelements = Xvec.Nelements = Npts;
+  if (Npts > 0) {
+    graphmode.style = 2; /* points */
+    graphmode.ptype = 100; /* connect pairs of points */
+    graphmode.etype = 0;
+    PrepPlotting (Npts, &graphmode);
+    PlotVector (Npts, Xvec.elements);
+    PlotVector (Npts, Yvec.elements);
+  }
+
+  free (Xvec.elements);
+  free (Yvec.elements);
+  free (regions);
+
+  return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/photcodes.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/photcodes.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/photcodes.c	(revision 3338)
@@ -0,0 +1,63 @@
+# include "dvo.h"
+
+/* list or return all photcodes equivalent to the given filter */
+int photcodes (int argc, char **argv) {
+  
+  int i, Np;
+  int *list, Nlist;
+  char name[64];
+  PhotCode *code;
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: photcodes (photcode)\n");
+    return (FALSE);
+  }
+
+  /* load photcodes, convert name to code */
+  if (!InitPhotcodes ()) return (FALSE);
+
+  if (!(Np = GetPhotcodeCodebyName (argv[1]))) {
+    fprintf (stderr, "ERROR: photcode not found in photcode table\n");
+    return (FALSE);
+  }
+
+  list = GetPhotcodeEquivList (Np, &Nlist);
+  
+  for (i = 0; i < Nlist; i++) {
+    code = GetPhotcodebyCode (list[i]);
+
+    sprintf (name, "photcode:name:%d", i);
+    set_str_variable (name, code[0].name);
+
+    sprintf (name, "photcode:C:%d", i);
+    set_variable (name, 0.001*code[0].C);
+
+    sprintf (name, "photcode:K:%d", i);
+    set_variable (name, code[0].K);
+
+    sprintf (name, "photcode:X:%d", i);
+    set_variable (name, code[0].X[0]);
+
+    sprintf (name, "photcode:dX:%d", i);
+    set_variable (name, 0.001*code[0].dX);
+
+    sprintf (name, "photcode:code:%d", i);
+    set_int_variable (name, code[0].code);
+
+    sprintf (name, "photcode:filter:%d", i);
+    set_str_variable (name, GetPhotcodeNamebyCode (code[0].equiv));
+
+    sprintf (name, "photcode:c1:%d", i);
+    set_str_variable (name, GetPhotcodeNamebyCode (code[0].c1));
+
+    sprintf (name, "photcode:c2:%d", i);
+    set_str_variable (name, GetPhotcodeNamebyCode (code[0].c2));
+
+    fprintf (stderr, "%5d %s %7.4f %7.4f %7.4f\n", 
+	     code[0].code, code[0].name, 0.001*code[0].C, code[0].K, code[0].X[0]);
+  }
+  set_int_variable ("photcode:n", Nlist);
+  free (list);
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/photometry.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/photometry.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/photometry.c	(revision 3338)
@@ -0,0 +1,1111 @@
+# include "dvo.h"
+
+/* match code to measure  */
+# define TESTCODE(C,M) \
+  switch (C[0].type) { \
+  case PHOT_DEP: \
+  case PHOT_REF: \
+    if (C[0].code != M.source) continue; \
+    break; \
+  case PHOT_PRI: \
+  case PHOT_SEC: \
+    if (C[0].code != GetPhotcodeEquivCodebyCode (M.source)) continue; \
+    break; \
+  default: \
+    break; \
+} 
+
+/* exclusions based on measure.params  */
+# define TESTMEASURE(M) \
+  if (TimeSelect && (M.t < tzero)) continue; \
+  if (TimeSelect && (M.t > tend)) continue; \
+  if (ErrSelect  && (M.dM > ErrValue)) continue; \
+  if (TypeSelect && (TypeValue != GetMeasureTypeCode (&M))) continue; \
+  if (iMagSelect && (PhotInst (&M) < iMagMin)) continue; \
+  if (FlagSelect && (M.flags != FlagValue)) continue;
+
+# define SETMAG(MOUT,MEAS,MODE) \
+  MOUT = NO_MAG; \
+  if (MODE == MAG_INST) MOUT = PhotInst (&MEAS);  \
+  if (MODE == MAG_CAT)  MOUT = PhotCat  (&MEAS); \
+  if (MODE == MAG_SYS)  MOUT = PhotSys  (&MEAS, average, secfilt); \
+  if (MODE == MAG_REL)  MOUT = PhotRel  (&MEAS, average, secfilt); \
+  if (MODE == MAG_CAL)  MOUT = PhotCal  (&MEAS, average, secfilt, measure, GetPhotcodeEquivbyCode (MEAS.source)); \
+  if (MagSelect && (MOUT > MagMax)) continue; \
+  if (MagSelect && (MOUT < MagMin)) continue;
+
+/* selection criteria */
+/* selections based on Measure quantities */
+static int TimeSelect;
+static time_t tzero, tend;
+static int MagSelect;
+static double MagMax, MagMin;
+static int TypeSelect, TypeValue;
+static int ErrSelect, ErrValue;
+static int iMagSelect;
+static double iMagMin;
+static int FlagSelect, FlagValue;
+
+/* applied to Average quantities */
+static int PhotcodeSelect;
+static PhotCode *PhotcodeValue;
+
+/* selections based on Average quantities */
+static int ChiSelect;
+static float ChiLimit;
+
+/* selections based on ensemble quantities */
+static int NphotSelect, NphotSign, NphotValue;
+static int NcodeSelect, NcodeSign, NcodeValue;
+static int FWHMSelect, FWHMsign;
+static double FWHMvalue, FWHMfrac;
+
+/* time concepts */
+static time_t TimeReference;
+static int TimeFormat;
+
+/* db image table */
+static Image *image = NULL;
+static int *subset = NULL;
+static int Nimage = 0;
+static int Nsubset = 0;
+static Coords mosaic;
+
+int GetPhotcodeInfo (char *string, PhotCode **Code, int *Mode) {
+
+  PhotCode *code;
+  int mode, status;
+  char *p, *tmpstring;
+
+  /* save local copy */
+  tmpstring = strcreate (string);
+
+  /* check for code:mode in photcode name */
+  mode = MAG_NONE;
+  p = strchr (tmpstring, ':');
+  if (p != NULL) {
+    mode = GetMagMode (p + 1);
+    if (mode == MAG_NONE) {
+      fprintf (stderr, "syntax error in magnitude mode\n");
+      free (tmpstring);
+      return (FALSE);
+    }
+    *p = 0;
+  }
+
+  /* how do we handle this elsewhere? */
+  if (!strcasecmp (tmpstring, "mag")) {
+    /* need to validate mode */
+    *Mode = mode;
+    *Code = NULL;
+    free (tmpstring);
+    return (TRUE);
+  }
+
+  code = GetPhotcodebyName (tmpstring);
+  if (code == NULL) {
+    fprintf (stderr, "photcode not found in photcode table\n");
+    free (tmpstring);
+    return (FALSE);
+  }
+
+  /* test allowable cases and/or set default values */
+  status = FALSE;
+  if (code[0].type == PHOT_DEP) {
+    if (mode == MAG_NONE) mode = MAG_REL;
+    if (mode == MAG_INST) status = TRUE;
+    if (mode == MAG_CAT)  status = TRUE;
+    if (mode == MAG_SYS)  status = TRUE;
+    if (mode == MAG_REL)  status = TRUE;
+    if (mode == MAG_CAL)  status = TRUE;
+  }  
+  if ((code[0].type == PHOT_PRI) || (code[0].type == PHOT_SEC)) {
+    if (mode == MAG_NONE) mode  = MAG_AVE;
+    if (mode == MAG_INST) status = TRUE;
+    if (mode == MAG_CAT)  status = TRUE;
+    if (mode == MAG_SYS)  status = TRUE;
+    if (mode == MAG_REL)  status = TRUE;
+    if (mode == MAG_CAL)  status = TRUE;
+    if (mode == MAG_AVE)  status = TRUE;
+    if (mode == MAG_REF)  status = TRUE;
+  }  
+  if (code[0].type == PHOT_ALT) {
+    if (mode == MAG_NONE) mode  = MAG_AVE;
+    if (mode == MAG_AVE)  status = TRUE;
+    if (mode == MAG_REF)  status = TRUE;
+  }
+
+  if (code[0].type == PHOT_REF) {
+    if (mode == MAG_NONE) mode  = MAG_CAT;
+    if (mode == MAG_CAT)  status = TRUE;
+  }
+
+  if (!status) {
+    fprintf (stderr, "mismatch in photcode and magmode\n");
+    free (tmpstring);
+    return (FALSE);
+  }
+  *Code = code;
+  *Mode = mode;
+  free (tmpstring);
+  return (TRUE);
+}
+ 
+int GetMagMode (char *string) {
+
+  int mode;
+
+  mode = MAG_NONE;
+  if (!strcasecmp (string, "inst"))   mode = MAG_INST;
+  if (!strcasecmp (string, "cat"))    mode = MAG_CAT;
+  if (!strcasecmp (string, "sys"))    mode = MAG_SYS;
+  if (!strcasecmp (string, "rel"))    mode = MAG_REL;
+  if (!strcasecmp (string, "cal"))    mode = MAG_CAL;
+  if (!strcasecmp (string, "ave"))    mode = MAG_AVE;
+  if (!strcasecmp (string, "ref"))    mode = MAG_REF;
+  return (mode);
+}
+
+int GetMeasureParam (char *parname) {
+
+  int param;
+
+  param = MEAS_ZERO;
+  if (!strcasecmp (parname, "ra"))   	 param = MEAS_RA;
+  if (!strcasecmp (parname, "dec"))  	 param = MEAS_DEC;
+  if (!strcasecmp (parname, "mag")) 	 param = MEAS_MAG;
+  if (!strcasecmp (parname, "dmag")) 	 param = MEAS_dMAG;
+  if (!strcasecmp (parname, "airmass"))  param = MEAS_AIRMASS;
+  if (!strcasecmp (parname, "exptime"))  param = MEAS_EXPTIME;
+  if (!strcasecmp (parname, "photcode")) param = MEAS_PHOTCODE;
+  if (!strcasecmp (parname, "time"))     param = MEAS_TIME;
+  if (!strcasecmp (parname, "dR")) 	 param = MEAS_dR;
+  if (!strcasecmp (parname, "dD")) 	 param = MEAS_dD;
+  if (!strcasecmp (parname, "fwhm"))   	 param = MEAS_FWHM;
+  if (!strcasecmp (parname, "dophot")) 	 param = MEAS_DOPHOT;
+  if (!strcasecmp (parname, "FLAGS"))    param = MEAS_FLAGS;
+  if (!strcasecmp (parname, "XCCD"))   	 param = MEAS_XCCD;
+  if (!strcasecmp (parname, "YCCD"))   	 param = MEAS_YCCD;
+  if (!strcasecmp (parname, "XMOSAIC"))  param = MEAS_XMOSAIC;
+  if (!strcasecmp (parname, "YMOSAIC"))  param = MEAS_YMOSAIC;
+  if (!strcasecmp (parname, "help")) {
+    fprintf (stderr, "value may be one of the following:\n");
+    fprintf (stderr, " ra dR dec dD mag dmag Mrel Mcal photcode time fwhm dophot xccd yccd xmosaic ymosaic flags\n");
+  }
+  return (param);
+}
+  
+int TestPhotSelections (PhotCode **code) {
+
+  int NeedPhotcode;
+
+  /* if i've supplied a photcode (code != NULL), i'm not allowed to restrict it */
+  if ((code[0] != NULL) && PhotcodeSelect) return (FALSE);
+
+  /* if I have an average or ensemble restriction, I must have a photcode */
+  if (ChiSelect || NphotSelect || NcodeSelect || FWHMSelect) {
+    if (code[0] != NULL) return (TRUE);
+    if (PhotcodeSelect) {
+      code[0] = PhotcodeValue;
+      return (TRUE);
+    }
+    return (FALSE);
+  }
+
+  /* if I have a photcode restriction, apply it to the code */
+  if (PhotcodeSelect) {
+    code[0] = PhotcodeValue;
+    return (TRUE);
+  }
+  return (TRUE);
+}
+
+int GetAverageParam (char *parname) {
+
+  int param;
+
+  param = AVE_ZERO;
+  if (!strcasecmp (parname, "ra"))    param = AVE_RA;
+  if (!strcasecmp (parname, "dec"))   param = AVE_DEC;
+  if (!strcasecmp (parname, "dmag"))  param = AVE_dMAG;
+  if (!strcasecmp (parname, "Nmeas")) param = AVE_NMEAS;
+  if (!strcasecmp (parname, "Nmiss")) param = AVE_NMISS;
+  if (!strcasecmp (parname, "Xp"))    param = AVE_Xp;
+  if (!strcasecmp (parname, "Xm"))    param = AVE_Xm;
+  if (!strcasecmp (parname, "flag"))  param = AVE_FLAG;
+  if (!strcasecmp (parname, "type"))  param = AVE_TYPE;
+  if (!strcasecmp (parname, "Nphot")) param = AVE_NPHOT;
+  if (!strcasecmp (parname, "Ncode")) param = AVE_NCODE;
+  if (!strcasecmp (parname, "help")) {
+    fprintf (stderr, "value may be one of the following:\n");
+    fprintf (stderr, " ra dec dmag Nmeas Nmiss Xm Xp Nphot Ncode flag type\n");
+  }
+  return (param);
+}
+
+/* load images based on parameters and region, etc */
+int SetImageSelection (int mode, Graphdata *graphsky, int RegionSelect) {
+
+  image = NULL;
+  subset = NULL;
+  
+  switch (mode) {
+  case MEAS_XCCD:
+  case MEAS_YCCD:
+    break;
+  case MEAS_XMOSAIC: 
+  case MEAS_YMOSAIC:
+    /* mosaic defines a frame with 0,0 at the mosaic center, and 1 arcsec / pixel */
+    mosaic.crpix1 = mosaic.crpix2 = 0.0;
+    mosaic.cdelt1 = mosaic.cdelt2 = 1.0 / 3600;
+    mosaic.pc1_1  = mosaic.pc2_2  = 1.0;
+    mosaic.pc1_2  = mosaic.pc2_1  = 0.0;
+    mosaic.Npolyterms = 0;
+    strcpy (mosaic.ctype, "RA---SIN");
+    break;
+  default:
+    return (TRUE);
+  }
+
+  image = LoadImages (&Nimage);
+  if (Nimage == 0) {
+    return (FALSE);
+  }
+  image_subset (image, Nimage, &subset, &Nsubset, graphsky, RegionSelect, tzero, (double) tend - tzero, TimeSelect);
+
+  sort_image_subset (image, subset, Nsubset);
+  return (TRUE);
+}
+
+/* free loaded images */
+void FreeImageSelection () {
+  if (image != NULL) free (image);
+  if (subset != NULL) free (subset);
+  return;
+}
+
+/* (re)load photcodes from photcode table */
+int InitPhotcodes () {
+
+  double ZERO_POINT;
+  char PhotCodeFile[256];
+
+  if (VarConfig ("ZERO_PT", "%lf", &ZERO_POINT) == (char *) NULL) return (FALSE);
+  SetZeroPoint (ZERO_POINT);
+
+  if (VarConfig ("PHOTCODE_FILE", "%s", PhotCodeFile) == (char *) NULL) return (FALSE);
+  if (!LoadPhotcodes (PhotCodeFile)) {
+    fprintf (stderr, "error loading photcodes\n");
+    return (FALSE);
+  }
+  return (TRUE);
+}
+
+/* remove standard photometry filtering options, set selections */
+/* not all functions respect all selections... */
+int SetPhotSelections (int *argc, char **argv) {
+
+  int N;
+  double trange;
+
+  if (N = get_argument (*argc, argv, "-phothelp")) {
+    fprintf (stderr, "optional photometry selection criteria:\n");
+    fprintf (stderr, " -magrange min max\n");
+    fprintf (stderr, " -imaglim min\n");
+    fprintf (stderr, " -flag value\n");
+    fprintf (stderr, " -chisq value\n");
+    fprintf (stderr, " -photcode code\n");
+    fprintf (stderr, " -time start range\n");
+    fprintf (stderr, " -errorlim value\n");
+    fprintf (stderr, " -type type\n");
+    fprintf (stderr, " -nmeas [+/-]N\n");
+    fprintf (stderr, " -fwhm [+/-]fraction\n");
+    return (FALSE);
+  }
+
+  /* select based on measured mag (MEASURE ONLY) */
+  MagSelect = FALSE;
+  if (N = get_argument (*argc, argv, "-magrange")) {
+    MagSelect = TRUE;
+    remove_argument (N, argc, argv);
+    MagMin = atof (argv[N]);
+    remove_argument (N, argc, argv);
+    MagMax = atof (argv[N]);
+    remove_argument (N, argc, argv);
+  }
+
+  /* select based on instrument mag (MEASURE ONLY) */
+  iMagSelect = FALSE;
+  if (N = get_argument (*argc, argv, "-imaglim")) {
+    iMagSelect = TRUE;
+    remove_argument (N, argc, argv);
+    iMagMin = atof (argv[N]);
+    remove_argument (N, argc, argv);
+  }
+
+  /* select on value of flag (MEASURE ONLY) */
+  FlagSelect = FALSE;
+  if (N = get_argument (*argc, argv, "-flag")) {
+    FlagSelect = TRUE;
+    remove_argument (N, argc, argv);
+    FlagValue = atof (argv[N]);
+    remove_argument (N, argc, argv);
+  }
+
+  /* select on value of flag (MEASURE ONLY) */
+  ChiSelect = FALSE;
+  if (N = get_argument (*argc, argv, "-chisq")) {
+    ChiSelect = TRUE;
+    remove_argument (N, argc, argv);
+    ChiLimit = atof (argv[N]);
+    remove_argument (N, argc, argv);
+  }
+
+  /* select on value of photcode */
+  PhotcodeSelect = FALSE;
+  if (N = get_argument (*argc, argv, "-photcode")) {
+    PhotcodeSelect = TRUE;
+    remove_argument (N, argc, argv);
+    PhotcodeValue = GetPhotcodebyName (argv[N]);
+    if (PhotcodeValue == NULL) {
+      fprintf (stderr, "photcode not found in photcode table\n");
+      PhotcodeSelect = FALSE;
+    }
+    remove_argument (N, argc, argv);
+  }
+
+  /* selection on basis of time range (MEASURE only) */
+  TimeSelect = FALSE;
+  if (N = get_argument (*argc, argv, "-time")) {
+    remove_argument (N, argc, argv);
+    if (!str_to_time (argv[N], &tzero)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, argc, argv);
+    if (!str_to_dtime (argv[N], &trange)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, argc, argv);
+    TimeSelect = TRUE;
+    if (trange < 0) {
+      trange = fabs (trange);
+      tend = tzero;
+      tzero -= trange;
+    } else {
+      tend = tzero + trange;
+    }
+  }
+
+  /* select by error (on measure or average) */
+  ErrSelect = FALSE;
+  if (N = get_argument (*argc, argv, "-errorlim")) {
+    remove_argument (N, argc, argv);
+    ErrValue = 1000*atof (argv[N]);
+    remove_argument (N, argc, argv);
+    ErrSelect = TRUE;
+  }
+
+  /* select on measurement type: 1,2,3 (AVERAGE ONLY) */
+  TypeSelect = FALSE;
+  if (N = get_argument (*argc, argv, "-type")) {
+    remove_argument (N, argc, argv);
+    TypeValue = atoi (argv[N]);
+    remove_argument (N, argc, argv);
+    TypeSelect = TRUE;
+  }
+
+  /* select by number of measurements (AVERAGE ONLY) */
+  NphotSelect = FALSE;
+  if (N = get_argument (*argc, argv, "-nphot")) {
+    remove_argument (N, argc, argv);
+    NphotValue = abs (atoi (argv[N]));
+    NphotSign = 0;
+    if (argv[N][0] == '-') NphotSign = -1;
+    if (argv[N][0] == '+') NphotSign = +1;
+    remove_argument (N, argc, argv);
+    NphotSelect = TRUE;
+  }
+
+  /* select by number of measurements (AVERAGE ONLY) */
+  NcodeSelect = FALSE;
+  if (N = get_argument (*argc, argv, "-ncode")) {
+    remove_argument (N, argc, argv);
+    NcodeValue = abs (atoi (argv[N]));
+    NcodeSign = 0;
+    if (argv[N][0] == '-') NcodeSign = -1;
+    if (argv[N][0] == '+') NcodeSign = +1;
+    remove_argument (N, argc, argv);
+    NcodeSelect = TRUE;
+  }
+
+  /* -fwhm value frac (AVERAGE ONLY) */
+  FWHMSelect = FALSE;
+  if (N = get_argument (*argc, argv, "-fwhm")) {
+    remove_argument (N, argc, argv);
+    FWHMvalue = abs (atof (argv[N]));
+    FWHMsign = 0;
+    if (argv[N][0] == '-') FWHMsign = -1;
+    if (argv[N][0] == '+') FWHMsign = +1;
+    remove_argument (N, argc, argv);
+    FWHMSelect = TRUE;
+    remove_argument (N, argc, argv);
+    FWHMfrac = atof (argv[N]);
+  }
+
+  GetTimeFormat (&TimeReference, &TimeFormat);
+  return (TRUE);
+}
+
+/* extract a list of measure parameters from the specified average entry based on the pre-set selections */
+double *ExtractMeasures (PhotCode *code, int mode, Average *average, SecFilt *secfilt, Measure *measure, int *nlist, int param) {
+
+  int i, k, m, Nlist, NLIST, np, found, Nm;
+  time_t t;
+  double ra, dec, x, y, value, M, fwhm;
+  double *list;
+  
+  *nlist = 0; 
+  Nlist = 0;
+  NLIST = MAX (1, average[0].Nm);
+  ALLOCATE (list, double, NLIST);
+
+  /* chisq, fwhm, Nphot, Ncode */
+  if (!TestAverage (code, average, secfilt, measure)) return (list);
+
+  /* look for measures */
+  for (i = 0; i < average[0].Nm; i++) {
+    if (code != NULL) {
+      TESTCODE (code, measure[i]);
+    }
+    /* exclusions based on measure.params  */
+    TESTMEASURE (measure[i]);
+
+    /* need to have the mag value to test MagSelect */ 
+    SETMAG (M, measure[i], mode);
+
+    /* assign value */
+    switch (param) {
+    case MEAS_MAG: /* magnitudes are already determined above */
+      value = M;
+      break;
+    case MEAS_RA: /* OK */
+      value = average[0].R - measure[i].dR / 360000.0;
+      break;
+    case MEAS_DEC: /* OK */
+      value = average[0].D - measure[i].dD / 360000.0;
+      break;
+    case MEAS_dMAG: /* OK */
+      value = 0.001*measure[i].dM;
+      break;
+    case MEAS_AIRMASS: /* OK */
+      value = 0.001*measure[i].airmass;
+      break;
+    case MEAS_EXPTIME: /* OK */
+      value = pow (10.0, measure[i].dt * 0.0004);
+      break;
+    case MEAS_PHOTCODE: /* OK */
+      value = measure[i].source;
+      break;
+    case MEAS_TIME: /* OK */
+      value = TimeValue (measure[i].t, TimeReference, TimeFormat);
+      break;
+    case MEAS_dR: /* OK */
+      value = 0.01*measure[i].dR;
+      break;
+    case MEAS_dD: /* OK */
+      value = 0.01*measure[i].dD;
+      break;
+    case MEAS_FWHM: /* OK */
+      value = 0.01*measure[i].FWx;
+      break;
+    case MEAS_DOPHOT: /* OK */
+      value = measure[i].dophot;
+      break;
+    case MEAS_FLAGS: /* ? */
+      value = measure[i].flags;
+      break;
+    case MEAS_XCCD: /* OK */
+      ra  = average[0].R - measure[i].dR / 360000.0;
+      dec = average[0].D - measure[i].dD / 360000.0;
+      m = match_image_subset (image, subset, Nsubset, measure[i].t, measure[i].source);
+      if (m == -1) {
+	value = 0.0;
+	break;
+      }
+      RD_to_XY (&x, &y, ra, dec, &image[m].coords);
+      value = x;
+      break;
+    case MEAS_YCCD: /* OK */
+      ra  = average[0].R - measure[i].dR / 360000.0;
+      dec = average[0].D - measure[i].dD / 360000.0;
+      m = match_image_subset (image, subset, Nsubset, measure[i].t, measure[i].source);
+      if (m == -1) {
+	value = 0.0;
+	break;
+      }
+      RD_to_XY (&x, &y, ra, dec, &image[m].coords);
+      value = y;
+      break;
+    case MEAS_XMOSAIC: /* OK */
+      ra  = average[0].R - measure[i].dR / 360000.0;
+      dec = average[0].D - measure[i].dD / 360000.0;
+      m = match_image_subset (image, subset, Nsubset, measure[i].t, measure[i].source);
+      if (m == -1) {
+	value = 0.0;
+	break;
+      }
+      mosaic.crval1 = image[m].coords.crval1;
+      mosaic.crval2 = image[m].coords.crval2;
+      RD_to_XY (&x, &y, ra, dec, &mosaic);
+      value = x;
+      break;
+    case MEAS_YMOSAIC: /* OK */
+      ra  = average[0].R - measure[i].dR / 360000.0;
+      dec = average[0].D - measure[i].dD / 360000.0;
+      m = match_image_subset (image, subset, Nsubset, measure[i].t, measure[i].source);
+      if (m == -1) {
+	value = 0.0;
+	break;
+      }
+      mosaic.crval1 = image[m].coords.crval1;
+      mosaic.crval2 = image[m].coords.crval2;
+      RD_to_XY (&x, &y, ra, dec, &mosaic);
+      value = y;
+      break;
+    }
+    list[Nlist] = value;
+    Nlist ++;
+  }
+  *nlist = Nlist;
+  return (list);
+}
+
+/* return average.param based on the selection */
+double ExtractAverages (PhotCode *code, int mode, Average *average, SecFilt *secfilt, Measure *measure, int param) {
+
+  int i, k, Nm, Type;
+  double fwhm, value, dM;
+
+  value = NO_MAG;
+
+  /* need valid code if param is: */
+  switch (param) {
+  case AVE_MAG:
+  case AVE_dMAG:
+  case AVE_Xm:
+  case AVE_TYPE:
+  case AVE_NCODE:
+  case AVE_NPHOT: 
+    if (code == NULL) return (NO_MAG);
+    break;
+  default:
+    break;
+  }
+
+  /* chisq, fwhm, Nphot, Ncode */
+  if (!TestAverage (code, average, secfilt, measure)) return (NO_MAG);
+
+  /* for ErrSelect, check average errors */
+  if (ErrSelect) {
+    dM = iPhotdM (code, average, secfilt);
+    if (dM > ErrValue) return (NO_MAG);
+  }
+  
+  /* for TypeSelect, check on TypeCode for this object */
+  if (TypeSelect) {
+    Type = DetermineTypeCode (average, measure, code[0].code);
+    if (Type != TypeValue) return (NO_MAG);
+  }
+
+  /* assign vector values */
+  switch (param) {
+  case AVE_RA:
+    value = average[0].R;
+    break;
+  case AVE_DEC:
+    value = average[0].D;
+    break;
+  case AVE_NMEAS:
+    value = average[0].Nm;
+    break;
+  case AVE_NMISS:
+    value = average[0].Nn;
+    break;
+  case AVE_Xp:
+    value = 0.01*average[0].Xp;
+    break;
+  case AVE_FLAG:
+    value = average[0].code;
+    break;
+  case AVE_MAG:
+    switch (mode) {
+    case MAG_AVE:
+      value = PhotAve  (code, average, secfilt);
+      break;
+    case MAG_REF:
+      value = PhotRef  (code, average, secfilt, measure);
+      break;
+    }
+    break;
+  case AVE_dMAG:
+    value = PhotdM (code, average, secfilt);
+    break;
+  case AVE_Xm:
+    value = PhotXm (code, average, secfilt);
+    break;
+  case AVE_TYPE:
+    value = DetermineTypeCode (average, measure, code[0].code);
+    break;
+  case AVE_NCODE:
+    value = 0;
+    for (i = 0; i < average[0].Nm; i++) {
+      if (code[0].code != GetPhotcodeEquivCodebyCode (measure[i].source)) continue;
+      value ++;
+    }
+    break;
+  case AVE_NPHOT:
+    value = 0;
+    for (i = 0; i < average[0].Nm; i++) {
+      if (code[0].code != GetPhotcodeEquivCodebyCode (measure[i].source)) continue;
+      if (measure[i].flags & (ID_MEAS_POOR | ID_MEAS_SKIP)) continue;
+      value ++;
+    }
+    break;
+  case AVE_NCRIT:
+    value = 0;
+    for (i = 0; i < average[0].Nm; i++) {
+      if (code[0].code != GetPhotcodeEquivCodebyCode (measure[i].source)) continue;
+      if (ErrSelect && (measure[i].dM > ErrValue)) continue;
+      if (FlagSelect && (measure[i].flags != FlagValue)) continue;
+      if (TypeSelect && (TypeValue != GetMeasureTypeCode (&measure[i]))) continue;
+      if (iMagSelect && (PhotInst (&measure[i]) < iMagMin)) continue;
+      value ++;
+    }
+    break;
+  }
+  return (value);
+}  
+
+/* determine the representative dophot type for this photcode */
+int DetermineTypeCode (Average *average, Measure *measure, int code) {
+
+  int k, N, Nt[3];
+  
+  Nt[0] = Nt[1] = Nt[2] = 0;
+  for (k = 0; k < average[0].Nm; k++) {
+    if (code != GetPhotcodeEquivCodebyCode (measure[k].source)) continue;
+    N = GetMeasureTypeCode (&measure[k]);
+    Nt[N] ++;
+  }
+  if (Nt[0]) return (0);
+  if (Nt[1]) return (1);
+  if (Nt[2]) return (2);
+  return (3);
+}
+
+int GetMeasureTypeCode (Measure *measure) {
+  switch (measure[0].dophot) {
+  case 0:
+  case 1:
+  case 2:
+    return (0);
+    break;
+  case 3:
+  case 4:
+  case 5:
+  case 7:
+  case 9:
+    return (1);
+    break;
+  case 10:
+  default:
+    return (2);
+  }
+  return (2);
+}  
+
+int Quality (Measure *measure, int IsDophot) {
+
+  return (TRUE);
+  
+  if (IsDophot) {
+    
+    if (measure[0].dophot == 4) return (FALSE);
+    return (TRUE);
+  
+  } else {
+    
+    if (0.01 * measure[0].FWx < 3.0) return (FALSE);
+    if (0.01 * measure[0].FWx > 10.0) return (FALSE);
+
+    return (TRUE);
+
+  }
+}
+
+int TestAverage (PhotCode *code, Average *average, SecFilt *secfilt, Measure *measure) {
+
+  int i, Nm;
+  double value, fwhm;
+
+  /* exclusions based on average.params  */
+  if (ChiSelect) {
+    /* some average.params need a valid photcode for reference */
+    if (code == NULL) return (FALSE);
+    value = PhotXm (code, average, secfilt);
+    if (value == -1) return (FALSE);
+    if (value > ChiLimit) return (FALSE);
+  }
+  
+  /* pass objects with more than FWHMfrac points with FWHM above / below FWHMvalue */ 
+  if (FWHMSelect) {
+    Nm = 0;
+    for (i = 0; i < average[0].Nm; i++) {
+      fwhm = measure[i].FWx / 100.0;
+      switch (FWHMsign) {
+      case 0:
+	if (fwhm == FWHMvalue) break;
+	continue;
+      case +1:
+	if (fwhm >= FWHMvalue) break;
+	continue;
+      case -1:
+	if (fwhm <= FWHMvalue) break;
+	continue;
+      }
+      Nm++;
+    }
+    if (average[0].Nm * FWHMfrac > Nm) return (FALSE);
+  }
+
+  /* for NcodeSelect, count Nmeas for appropriate photcode */
+  if (NcodeSelect) {
+    Nm = 0;
+    for (i = 0; i < average[0].Nm; i++) {
+      TESTCODE (code, measure[i]);
+      Nm++;
+    }
+    switch (NcodeSign) {
+    case 0:
+      if (Nm == NcodeValue) break;
+      return (FALSE);
+    case 1:
+      if (Nm >= NcodeValue) break;
+      return (FALSE);
+    case -1:
+      if (Nm <= NcodeValue) break;
+      return (FALSE);
+    default:
+      return (FALSE);
+    }
+  }
+
+  /* for NphotSelect, count Nmeas for appropriate photcode */
+  if (NphotSelect) {
+    Nm = 0;
+    for (i = 0; i < average[0].Nm; i++) {
+      TESTCODE (code, measure[i]);
+      if (measure[i].flags && ID_MEAS_SKIP) continue;
+      Nm++;
+    }
+    switch (NphotSign) {
+    case 0:
+      if (Nm == NphotValue) break;
+      return (FALSE);
+    case 1:
+      if (Nm >= NphotValue) break;
+      return (FALSE);
+    case -1:
+      if (Nm <= NphotValue) break;
+      return (FALSE);
+    default:
+      return (FALSE);
+    }
+  }
+  return (TRUE);
+}
+
+/* for this function, we don't need to call PhotRel, etc, but we
+   do need to multiply by 0.001:
+   average[].M is stored as 1000*mag where mag is PhotAbs
+   measure[].M for PHOT_REL is the same 
+*/ 
+
+/* send in:
+   Nphot - photcode number
+   Tphot - photcode type
+   Ns    - secfilt entry (-1 for PRI)
+   &catalog.average[i], 
+   &catalog.measure[catalog.average[i].offset], 
+   &catalog.secfilt[i*Nsec] 
+*/
+
+
+double *ExtractMagnitudes (PhotCode *code, int mode, Average *average, SecFilt *secfilt, Measure *measure, int *n) {
+  
+  double *M, mag;
+  int N;
+
+  if ((mode == MAG_AVE) || (mode == MAG_REF)) {
+    ALLOCATE (M, double, 1);
+    mag = ExtractAverages (code, mode, average, secfilt, measure, AVE_MAG);
+    if (mag == NO_MAG) {
+      N = 0;
+    } else {
+      N = 1;
+      M[0] = mag;
+    }
+  } else {
+    M = ExtractMeasures (code, mode, average, secfilt, measure, &N, MEAS_MAG);
+  }
+  
+  *n = N;
+  return (M);
+}
+
+double *ExtractDMag (PhotCode **code, int *mode, Average *average, SecFilt *secfilt, Measure *measure, int *nlist) {
+
+  int i, j, A1, A2, N1, N2, Nlist, NLIST;
+  double *M1, *M2, *list;
+
+  /* check for special case of measure-measure */
+  A1 = ((mode[0] == MAG_AVE) || (mode[0] == MAG_REF));
+  A2 = ((mode[1] == MAG_AVE) || (mode[1] == MAG_REF));
+  if (!A1 && !A2) {
+    list = ExtractMeasuresDMag (code, mode, average, secfilt, measure, nlist);
+    return (list);
+  }
+
+  *nlist = 0; 
+  Nlist = 0;
+  NLIST = MAX (1, average[0].Nm*average[0].Nm);
+  ALLOCATE (list, double, NLIST);
+  M1 = M2 = NULL;
+
+  /* one of the two is an average, must do independently */
+  M1 = ExtractMagnitudes (code[0], mode[0], average, secfilt, measure, &N1);
+  if (N1 == 0) goto skip;
+  
+  M2 = ExtractMagnitudes (code[1], mode[1], average, secfilt, measure, &N2);
+  if (N2 == 0) goto skip;
+
+  /* average mags can return NO_MAG : skip them? */
+  for (i = 0; i < N1; i++) {
+    for (j = 0; j < N2; j++) {
+      list[Nlist] = M1[i] - M2[j];
+      Nlist ++;
+    }
+  }
+  *nlist = Nlist;
+  return (list);
+
+ skip: 
+  if (M1 != NULL) free (M1);
+  if (M2 != NULL) free (M2);
+  M1 = M2 = NULL;
+  return (list);
+}
+  
+/* extract a list of delta-measure-mags from the specified average entry based on the pre-set selections */
+double *ExtractMeasuresDMag (PhotCode **code, int *mode, Average *average, SecFilt *secfilt, Measure *measure, int *nlist) {
+
+  int i, j, Nlist, NLIST;
+  double *list, M1, M2, value;
+  
+  *nlist = 0; 
+  Nlist = 0;
+  NLIST = MAX (1, average[0].Nm*average[0].Nm);
+  ALLOCATE (list, double, NLIST);
+
+  /* must have two code values */
+  if (code == NULL) return (list);
+  if (code[0] == NULL) return (list);
+  if (code[1] == NULL) return (list);
+
+  /* exclude based on chisq for both codes  */
+  if (ChiSelect) {
+    value = PhotXm (code[0], average, secfilt);
+    if (value == -1) return (list);
+    if (value > ChiLimit) return (list);
+    value = PhotXm (code[1], average, secfilt);
+    if (value == -1) return (list);
+    if (value > ChiLimit) return (list);
+  }
+
+  /* loop twice over all measures */
+  for (i = 0; i < average[0].Nm; i++) {
+    TESTCODE (code[0], measure[i]);
+    TESTMEASURE (measure[i]);
+    SETMAG(M1, measure[i], mode[0]);
+    for (j = 0; j < average[0].Nm; j++) {
+      if (i == j) continue;
+      TESTCODE (code[1], measure[j]);
+      TESTMEASURE (measure[j]);
+      SETMAG(M2, measure[j], mode[1]);
+      list[Nlist] = M1 - M2;
+      Nlist ++;
+    }
+  }
+  *nlist = Nlist;
+  return (list);
+}
+
+double *ExtractByDMag (PhotCode **code, int *mode, Average *average, SecFilt *secfilt, Measure *measure, int *nlist, int param) {
+
+  int A1, A2, N1;
+  double *list;
+
+  /* check for special case of measure-measure */
+  A1 = ((mode[0] == MAG_AVE) || (mode[0] == MAG_REF));
+  A2 = ((mode[1] == MAG_AVE) || (mode[1] == MAG_REF));
+  if (!A1 && !A2) {
+    list = ExtractMeasuresByDMag (code, mode, 1, average, secfilt, measure, nlist, param);
+    return (list);
+  }
+
+  if (A1) {
+    list = ExtractMeasures (code[1], mode[1], average, secfilt, measure, &N1, param);
+  } else {
+    list = ExtractMeasures (code[0], mode[0], average, secfilt, measure, &N1, param);
+  }
+  *nlist = N1;
+  return (list);
+}
+  
+/* extract a list of delta-measure-mags from the specified average entry based on the pre-set selections */
+double *ExtractMeasuresByDMag (PhotCode **code, int *mode, int use_first, Average *average, SecFilt *secfilt, Measure *measure, int *nlist, int param) {
+
+  int i, j, k, m, n, Nlist, NLIST;
+  time_t t;
+  int np, found;
+  double *list, M1, M2, value;
+  double ra, dec, x, y;
+  
+  *nlist = 0; 
+  Nlist = 0;
+  NLIST = MAX (1, average[0].Nm*average[0].Nm);
+  ALLOCATE (list, double, NLIST);
+
+  /* must have two code values */
+  if (code == NULL) return (list);
+  if (code[0] == NULL) return (list);
+  if (code[1] == NULL) return (list);
+
+  /* chisq, fwhm, Nphot, Ncode */
+  if (!TestAverage (code[0], average, secfilt, measure)) return (list);
+  if (!TestAverage (code[1], average, secfilt, measure)) return (list);
+
+  /* loop twice over all measures */
+  for (i = 0; i < average[0].Nm; i++) {
+    TESTCODE (code[0], measure[i]);
+    TESTMEASURE (measure[i]);
+    SETMAG(M1, measure[i], mode[0]);
+    for (j = 0; j < average[0].Nm; j++) {
+      if (i == j) continue;
+      TESTCODE (code[1], measure[j]);
+      TESTMEASURE (measure[j]);
+      SETMAG(M2, measure[j], mode[1]);
+      if (use_first) 
+	n = i;
+      else 
+	n = j;
+      /* assign value */
+      switch (param) {
+      case MEAS_MAG: /* magnitudes are already determined above */
+	value = use_first ? M1 : M2;
+	break;
+      case MEAS_RA: /* OK */
+	value = average[0].R - measure[n].dR / 360000.0;
+	break;
+      case MEAS_DEC: /* OK */
+	value = average[0].D - measure[n].dD / 360000.0;
+	break;
+      case MEAS_dMAG: /* OK */
+	value = 0.001*measure[n].dM;
+	break;
+      case MEAS_AIRMASS: /* OK */
+	value = 0.001*measure[n].airmass;
+	break;
+      case MEAS_EXPTIME: /* OK */
+	value = pow (10.0, measure[n].dt * 0.0004);
+	break;
+      case MEAS_PHOTCODE: /* OK */
+	value = measure[n].source;
+	break;
+      case MEAS_TIME: /* OK */
+	value = TimeValue (measure[n].t, TimeReference, TimeFormat);
+	break;
+      case MEAS_dR: /* OK */
+	value = 0.01*measure[n].dR;
+	break;
+      case MEAS_dD: /* OK */
+	value = 0.01*measure[n].dD;
+	break;
+      case MEAS_FWHM: /* OK */
+	value = 0.01*measure[n].FWx;
+	break;
+      case MEAS_DOPHOT: /* OK */
+	value = measure[n].dophot;
+	break;
+      case MEAS_FLAGS: /* ? */
+	value = measure[n].flags;
+	break;
+    case MEAS_XCCD: /* OK */
+      ra  = average[0].R - measure[n].dR / 360000.0;
+      dec = average[0].D - measure[n].dD / 360000.0;
+      m = match_image_subset (image, subset, Nsubset, measure[n].t, measure[n].source);
+      if (m == -1) {
+	value = 0.0;
+	break;
+      }
+      RD_to_XY (&x, &y, ra, dec, &image[m].coords);
+      value = x;
+      break;
+    case MEAS_YCCD: /* OK */
+      ra  = average[0].R - measure[n].dR / 360000.0;
+      dec = average[0].D - measure[n].dD / 360000.0;
+      m = match_image_subset (image, subset, Nsubset, measure[n].t, measure[n].source);
+      if (m == -1) {
+	value = 0.0;
+	break;
+      }
+      RD_to_XY (&x, &y, ra, dec, &image[m].coords);
+      value = y;
+      break;
+    case MEAS_XMOSAIC: /* OK */
+      ra  = average[0].R - measure[n].dR / 360000.0;
+      dec = average[0].D - measure[n].dD / 360000.0;
+      m = match_image_subset (image, subset, Nsubset, measure[n].t, measure[n].source);
+      if (m == -1) {
+	value = 0.0;
+	break;
+      }
+      mosaic.crval1 = image[m].coords.crval1;
+      mosaic.crval2 = image[m].coords.crval2;
+      RD_to_XY (&x, &y, ra, dec, &mosaic);
+      value = x;
+      break;
+    case MEAS_YMOSAIC: /* OK */
+      ra  = average[0].R - measure[n].dR / 360000.0;
+      dec = average[0].D - measure[n].dD / 360000.0;
+      m = match_image_subset (image, subset, Nsubset, measure[n].t, measure[n].source);
+      if (m == -1) {
+	value = 0.0;
+	break;
+      }
+      mosaic.crval1 = image[m].coords.crval1;
+      mosaic.crval2 = image[m].coords.crval2;
+      RD_to_XY (&x, &y, ra, dec, &mosaic);
+      value = y;
+      break;
+      }
+      list[Nlist] = value;
+      Nlist ++;
+    }
+  }
+  *nlist = Nlist;
+  return (list);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/pmeasure.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/pmeasure.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/pmeasure.c	(revision 3338)
@@ -0,0 +1,151 @@
+# include "dvo.h"
+
+int pmeasure (int argc, char **argv) {
+  
+  FILE *f;
+  int i, j, k, m, N;
+  int InRegion, Nregions, Ngraph;
+  char filename[128], catdir[256];
+  double Mz, Mr, mag;
+  double Radius, Rmin, Rmax;
+  unsigned IDclip, IDchoice, LimExclude;
+  unsigned FlagChoice, FlagClip, flags;
+
+  Catalog catalog;
+  RegionFile *regions;
+  Graphdata graphmode;
+  Vector Xvec, Yvec, Zvec;
+
+  Ngraph = -1;
+  if (!GetGraph (&graphmode, NULL, &Ngraph)) return (FALSE);
+  if (VarConfig ("CATDIR", "%s", catdir) == NULL) return (FALSE);
+  if (!InitPhotcodes ()) return (FALSE);
+
+  regions = (RegionFile *) NULL;
+  f = (FILE *) NULL;
+  Mz = 17.0;
+  Mr = -5.0;
+  Rmin = graphmode.coords.crval1 - 182.0;
+  Rmax = graphmode.coords.crval1 + 182.0;
+
+  IDclip = FALSE;
+  if (N = get_argument (argc, argv, "-ID")) {
+    remove_argument (N, &argc, argv);
+    IDchoice  = atoi(argv[N]);
+    remove_argument (N, &argc, argv);
+    IDclip = TRUE;
+  }
+  FlagClip = FALSE;
+  if (N = get_argument (argc, argv, "-flag")) {
+    remove_argument (N, &argc, argv);
+    FlagChoice  = atoi(argv[N]);
+    remove_argument (N, &argc, argv);
+    FlagClip = TRUE;
+  }
+
+  LimExclude = FALSE;
+  if (N = get_argument (argc, argv, "-x")) {
+    remove_argument (N, &argc, argv);
+    LimExclude = TRUE;
+  }
+
+  if (N = get_argument (argc, argv, "-m")) {
+    remove_argument (N, &argc, argv);
+    Mr  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    Mz = atof(argv[N]);
+    Mr = Mr - Mz;
+    remove_argument (N, &argc, argv);
+  }
+
+  InRegion = FALSE;
+  if (N = get_argument (argc, argv, "-all")) {
+    remove_argument (N, &argc, argv);
+    InRegion = TRUE;
+  }
+
+  if ((InRegion || (argc != 2)) && (!InRegion || (argc != 1))) {
+    fprintf (stderr, "USAGE: catalog (filename / -all) [-m M M] [-n N N] [-g] [-a RA DEC MAG] \n");
+    return (FALSE);
+  }
+  
+  if (InRegion) {
+    Radius = MAX (fabs(graphmode.xmax), fabs(graphmode.ymax));
+    regions = find_regions (graphmode.coords.crval1, graphmode.coords.crval2, Radius, &Nregions);
+  } else {
+    Nregions = 1;
+  }
+  
+  for (j = 0; j < Nregions; j++) {
+    catalog.average = 0;
+    
+    if (InRegion) {
+      sprintf (filename, "%s/%s", catdir, regions[j].name);
+    } else {
+      sprintf (filename, "%s/%s", catdir, argv[1]);
+    }
+    
+    /* lock, load, unlock catalog */
+    catalog.filename = filename;
+    switch (lock_catalog (&catalog, LCK_SOFT)) {
+    case 2:
+      unlock_catalog (&catalog);
+    case 0:
+      continue;
+    }
+    if (!load_catalog (&catalog, LOAD_AVES | LOAD_MEAS, TRUE)) {
+      unlock_catalog (&catalog);
+      continue;
+    }
+    unlock_catalog (&catalog);
+
+    /* data has been loaded, get ready to plot it */
+    Xvec.Nelements = catalog.Nmeasure;
+    Yvec.Nelements = catalog.Nmeasure;
+    Zvec.Nelements = catalog.Nmeasure;
+    ALLOCATE (Xvec.elements, float, Xvec.Nelements);
+    ALLOCATE (Yvec.elements, float, Yvec.Nelements);
+    ALLOCATE (Zvec.elements, float, Zvec.Nelements);
+
+    /* project stars to screen display coords */
+    Xvec.Nelements = 0;
+    for (N = i = 0; i < catalog.Naverage; i++) {
+      if (IDclip && (catalog.average[i].code != IDchoice)) continue;
+      while (catalog.average[i].R < Rmin) catalog.average[i].R += 360.0;
+      while (catalog.average[i].R > Rmax) catalog.average[i].R -= 360.0;
+      m = catalog.average[i].offset;
+      for (k = 0; k < catalog.average[i].Nm; k++) {
+	if (FlagClip) {
+	  flags = catalog.measure[m+k].flags;
+	  if (!(flags & FlagChoice)) continue;
+	}
+	mag = PhotCat (&catalog.measure[m+k]);
+	Zvec.elements[N] = MIN (1.0, MAX (0.01, (mag - Mz) / Mr));
+	if (LimExclude && (Zvec.elements[N] > 0.99)) continue;
+	if (Zvec.elements[N] < 0.011) continue;
+	fRD_to_XY (&Xvec.elements[N], &Yvec.elements[N], catalog.average[i].R - 2.777e-6*catalog.measure[m+k].dR, catalog.average[i].D - 2.777e-6*catalog.measure[m+k].dD, &graphmode.coords);
+	N ++;
+      }
+    }
+    Zvec.Nelements = Yvec.Nelements = Xvec.Nelements = N;
+
+    graphmode.style = 2; /* set style to points */
+    graphmode.size = -1; /* point size determined by Zvec */
+    graphmode.etype = 0; /* no errorbars */
+    PrepPlotting (N, &graphmode);
+    
+    PlotVector (N, Xvec.elements);
+    PlotVector (N, Yvec.elements);
+    PlotVector (N, Zvec.elements);
+
+    free (Xvec.elements);
+    free (Yvec.elements);
+    free (Zvec.elements);
+
+    if (catalog.average != 0) free (catalog.average);
+    if (catalog.measure != 0) free (catalog.measure);
+  }
+  return (TRUE);
+
+}
+  
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/procks.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/procks.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/procks.c	(revision 3338)
@@ -0,0 +1,159 @@
+# include "dvo.h"
+
+typedef struct {
+  double ra[3];
+  double dec[3];
+  double X[3];
+  double Y[3];
+  unsigned int t[3];
+  double mag[3];
+} Rocks;
+static Rocks *rocks = (Rocks *) NULL;
+static int   Nrocks;
+
+int procks (int argc, char **argv) {
+  
+  FILE *f;
+  Vector Xvec, Yvec;
+  int i, j, N, NROCKS;
+  int N0, N1, SpeedClip, Reload;
+  unsigned int t0, t1;
+  double Mz, Mr, S0, S1;
+  double Rmin, Rmax;
+  Graphdata graphmode;
+  char rockcat[256];
+  int Ngraph;
+
+  Ngraph = 0;
+  VarConfig ("ROCK_CATALOG", "%s", rockcat);
+  if (!GetGraph (&graphmode, NULL, &Ngraph)) return (FALSE);
+
+  f = (FILE *) NULL;
+  Mz = 17.0;
+  Mr = -5.0;
+  Rmin = graphmode.coords.crval1 - 182.0;
+  Rmax = graphmode.coords.crval1 + 182.0;
+
+  if (N = get_argument (argc, argv, "-m")) {
+    remove_argument (N, &argc, argv);
+    Mr  = 1000*atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    Mz = 1000*atof(argv[N]);
+    Mr = Mr - Mz;
+    remove_argument (N, &argc, argv);
+  }
+
+  SpeedClip = FALSE;
+  if (N = get_argument (argc, argv, "-speed")) {
+    SpeedClip = TRUE;
+    remove_argument (N, &argc, argv);
+    S0 = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    S1 = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  Reload = FALSE;
+  if (N = get_argument (argc, argv, "-reload")) {
+    Reload = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 1) {
+    fprintf (stderr, "USAGE: procks [-m M M] [-speed s s] \n");
+    return (FALSE);
+  }
+  
+  f = fopen (rockcat, "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "can't open rock catalog\n");
+    return (TRUE);
+  }
+
+  if ((rocks == (Rocks *) NULL) || Reload) {
+    if (rocks != (Rocks *) NULL) free (rocks);
+    NROCKS = 100;
+    ALLOCATE (rocks, Rocks, NROCKS);
+    for (i = 0; fscanf (f, "%lf %lf %d%lf%lf%lf %d%lf%lf%lf %d%lf%lf%lf", 
+			&rocks[i].X[0], &rocks[i].Y[0], 
+			&rocks[i].t[0], &rocks[i].ra[0], &rocks[i].dec[0], &rocks[i].mag[0], 
+			&rocks[i].t[1], &rocks[i].ra[1], &rocks[i].dec[1], &rocks[i].mag[1], 
+			&rocks[i].t[2], &rocks[i].ra[2], &rocks[i].dec[2], &rocks[i].mag[2]
+			) != EOF; i++) {
+      if (i == NROCKS - 1) {
+	NROCKS += 100;
+	REALLOCATE (rocks, Rocks, NROCKS);
+      }
+    }
+    Nrocks = i;
+  }
+      
+  if (Nrocks == 0) {
+    free (rocks);
+    fprintf (stderr, "no rocks in datafile\n");
+    return (TRUE);
+  }
+
+  /* data has been loaded, get ready to plot it */
+  Yvec.Nelements = Xvec.Nelements = 3*Nrocks;
+  ALLOCATE (Xvec.elements, float, Xvec.Nelements);
+  ALLOCATE (Yvec.elements, float, Yvec.Nelements);
+  
+  /* project stars to screen display coords */
+  for (N = i = 0; i < Nrocks; i++) {
+    if (SpeedClip && ((rocks[i].Y[0] < S0) || (rocks[i].Y[0] > S1))) continue;
+    for (j = 0; j < 3; j++) {
+      while (rocks[i].ra[j] < Rmin) rocks[i].ra[j] += 360.0;
+      while (rocks[i].ra[j] > Rmax) rocks[i].ra[j] -= 360.0;
+      fRD_to_XY (&Xvec.elements[N], &Yvec.elements[N], rocks[i].ra[j], rocks[i].dec[j], &graphmode.coords);
+      N ++;
+    }
+  }
+  Yvec.Nelements = Xvec.Nelements = N;
+  
+  graphmode.style = 2; /* set style to points */
+  graphmode.etype = 0; /* no errorbars */
+  PrepPlotting (N, &graphmode);
+  
+  PlotVector (N, Xvec.elements);
+  PlotVector (N, Yvec.elements);
+
+  /* now plot vectors between two extrema */
+  Yvec.Nelements = Xvec.Nelements = 2*Nrocks;
+  REALLOCATE (Xvec.elements, float, Xvec.Nelements);
+  REALLOCATE (Yvec.elements, float, Yvec.Nelements);
+  
+  /* project stars to screen display coords */
+  for (N = i = 0; i < Nrocks; i++) {
+    if (SpeedClip && ((rocks[i].Y[0] < S0) || (rocks[i].Y[0] > S1))) continue;
+    N0 = N1 = 0;
+    t0 = t1 = rocks[i].t[0];
+    for (j = 1; j < 3; j++) {
+      if (rocks[i].t[j] < t0) { N0 = j; t0 = rocks[i].t[j]; }
+      if (rocks[i].t[j] > t1) { N1 = j; t1 = rocks[i].t[j]; }
+    }
+    while (rocks[i].ra[N0] < Rmin) rocks[i].ra[N0] += 360.0;
+    while (rocks[i].ra[N0] > Rmax) rocks[i].ra[N0] -= 360.0;
+    while (rocks[i].ra[N1] < Rmin) rocks[i].ra[N1] += 360.0;
+    while (rocks[i].ra[N1] > Rmax) rocks[i].ra[N1] -= 360.0;
+    fRD_to_XY (&Xvec.elements[N], &Yvec.elements[N], rocks[i].ra[N0], rocks[i].dec[N0], &graphmode.coords);
+    N ++;
+    fRD_to_XY (&Xvec.elements[N], &Yvec.elements[N], rocks[i].ra[N1], rocks[i].dec[N1], &graphmode.coords);
+    N ++;
+  }
+  Yvec.Nelements = Xvec.Nelements = N;
+  
+  graphmode.style = 2; /* set style to points */
+  graphmode.ptype = 100; /* connect pairs */
+  graphmode.etype = 0; /* no errorbars */
+  PrepPlotting (N, &graphmode);
+  
+  PlotVector (N, Xvec.elements);
+  PlotVector (N, Yvec.elements);
+
+  free (Xvec.elements);
+  free (Yvec.elements);
+  return (TRUE);
+
+}
+  
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/region_list.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/region_list.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/region_list.c	(revision 3338)
@@ -0,0 +1,34 @@
+# include "dvo.h"
+
+/* returns a list of region files names from file */
+RegionFile *region_list (char *filename, int *Nregions) {
+  
+  int NREGIONS, nregion;
+  RegionFile *regions;
+  FILE *f;
+
+  f = fopen (filename, "r");
+  if (f == NULL) {
+    fprintf (stderr, "ERROR: can't find region list file %s\n", filename);
+    *Nregions = 0;
+    return ((RegionFile *) NULL);
+  }
+  
+  NREGIONS = 50;
+  ALLOCATE (regions, RegionFile, NREGIONS);
+  nregion = 0;
+
+  while (fscanf (f, "%s", regions[nregion].name) != EOF) {
+    nregion ++;
+    if (nregion == NREGIONS) {
+      NREGIONS += 50;
+      REALLOCATE (regions, RegionFile, NREGIONS);
+    }
+  }
+
+  *Nregions = nregion;
+
+  return (regions);
+
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/showtile.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/showtile.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/showtile.c	(revision 3338)
@@ -0,0 +1,99 @@
+# include "dvo.h"
+static float dr[] = {0.0, 1.0, 1.0, 0.0};
+static float dd[] = {0.0, 0.0, 1.0, 1.0};
+
+int showtile (int argc, char **argv) {
+
+  int Nd, N, NPTS, Ngraph, status, i, InPic;
+  Graphdata graphmode;
+  Coords coords;
+  Vector Xvec, Yvec;
+  float r, d, R, D;
+  float Ro[90], Do[90];
+
+  /* show tile pattern in viewed region */
+
+  Ngraph = 0;
+  if (!GetGraph (&graphmode, NULL, &Ngraph)) return (FALSE);
+
+  if (argc != 1) {
+    fprintf (stderr, "USAGE: showtile [option]\n");
+    return (FALSE);
+  }
+  
+  N = 0;
+  NPTS = 200;
+  ALLOCATE (Xvec.elements, float, NPTS);
+  ALLOCATE (Yvec.elements, float, NPTS);
+
+  /* starting position */
+
+  /* reference for coords is this image */
+  coords.crpix1 = coords.crpix2 = 0.0;
+  coords.crval1 = coords.crval2 = 0.0;
+  coords.cdelt1 = coords.cdelt2 = 1.0;
+  coords.pc1_1  = coords.pc2_2  = 1.0;
+  coords.pc1_2  = coords.pc2_1  = 0.0;
+  coords.Npolyterms = 0;
+  strcpy (coords.ctype, "RA---TAN");
+  
+  /* fill in top-left region */
+  for (r = 0; r < 3; r += 1.0) {
+    fprintf (stderr, "r: %f\n", r);
+    for (Nd = d = 0; d < 90; Nd ++, d += 1.0) {
+      if (r == 0) {
+	coords.crval1 = r;
+	coords.crval2 = d;
+      } else {
+	coords.crval1 = Ro[Nd];
+	coords.crval2 = Do[Nd];
+      }
+      for (i = 0; i < 4; i++) {
+	fXY_to_RD (&R, &D, dr[i], dd[i], &coords);
+	status |= fRD_to_XY (&Xvec.elements[N+2*i], &Yvec.elements[N+2*i], R, D, &graphmode.coords);
+	if (i > 0) {
+	  Xvec.elements[N+2*i - 1] = Xvec.elements[N+2*i];
+	  Yvec.elements[N+2*i - 1] = Yvec.elements[N+2*i];
+	}
+	if (i == 1) {
+	  Ro[Nd] = R;
+	  Do[Nd] = D;
+	}
+      }
+      Xvec.elements[N+7] = Xvec.elements[N];
+      Yvec.elements[N+7] = Yvec.elements[N];
+
+      /* check if any corner is in plotting region */
+      InPic = FALSE;
+      for (i = 0; i < 8; i+=2) {
+	if ((Xvec.elements[N+i] >= graphmode.xmin) && 
+	    (Xvec.elements[N+i] <= graphmode.xmax) && 
+	    (Yvec.elements[N+i] >= graphmode.ymin) && 
+	    (Yvec.elements[N+i] <= graphmode.ymax))
+	  InPic = TRUE;
+      }
+      if (!InPic) continue;
+      N+=8;
+      if (N > NPTS - 1) {  /* this is OK because NPTS is made always a multiple of 8 */
+	NPTS += 200;
+	REALLOCATE (Xvec.elements, float, NPTS);
+	REALLOCATE (Yvec.elements, float, NPTS);
+      }
+    }
+  }
+  
+  Xvec.Nelements = Xvec.Nelements = N;
+  if (N > 0) {
+    graphmode.style = 2; /* points */
+    graphmode.ptype = 100; /* connect pairs of points */
+    graphmode.etype = 0;
+    PrepPlotting (N, &graphmode);
+    PlotVector (N, Xvec.elements);
+    PlotVector (N, Yvec.elements);
+  }
+
+  free (Xvec.elements);
+  free (Yvec.elements);
+  return (TRUE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/simage.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/simage.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/simage.c	(revision 3338)
@@ -0,0 +1,173 @@
+# include "dvo.h"
+# define D_NSTARS 1000
+# define BYTES_STAR 31
+# define BLOCK 1000
+
+int simage (int argc, char **argv) {
+
+  char *buffer;
+  Vector Xvec, Yvec, Zvec;
+  double R, D, X, Y, M, zero, range;
+  FILE *f;
+  Header header;
+  Coords coords;
+  int i, j, Nstars, nstars, Nbytes, nbytes, Npts, N;
+  Graphdata graphmode;
+  int Ngraph;
+
+  Ngraph = 0;
+  if (!GetGraph (&graphmode, NULL, &Ngraph)) return (FALSE);
+
+  zero = 17.0;
+  range = -5.0;
+  if (N = get_argument (argc, argv, "-m")) {
+    remove_argument (N, &argc, argv);
+    range = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    zero  = atof(argv[N]);
+    range = range - zero;
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: image (filename)\n");
+    return (FALSE);
+  }
+
+  fprintf (stderr, "not working at the moment (cmp format)\n");
+  return (FALSE);
+  
+  /* read header */
+  if (!fits_read_header (argv[1], &header)) {
+    fprintf (stderr, "ERROR: can't find image file %s\n", argv[1]);
+    return (FALSE);
+  }
+  /* get astrometry information */
+  strcpy (coords.ctype, "NONE");
+  fits_scan (&header, "CTYPE1",   "%s",  1, coords.ctype);
+  if (strcmp (coords.ctype, "RA---PLY")) {
+    fprintf (stderr, "ERROR: wrong astrometric info in header\n");
+    return (FALSE);
+  }
+  fits_scan (&header, "CDELT1",   "%f", 1, &coords.cdelt1); 
+  fits_scan (&header, "CDELT2",   "%f", 1, &coords.cdelt2);
+  fits_scan (&header, "CRVAL1",   "%lf", 1, &coords.crval1);
+  fits_scan (&header, "CRVAL2",   "%lf", 1, &coords.crval2);  
+  fits_scan (&header, "CRPIX1",   "%f", 1, &coords.crpix1);
+  fits_scan (&header, "CRPIX2",   "%f", 1, &coords.crpix2);
+  fits_scan (&header, "PC001001", "%f", 1, &coords.pc1_1);
+  fits_scan (&header, "PC001002", "%f", 1, &coords.pc1_2);
+  fits_scan (&header, "PC002001", "%f", 1, &coords.pc2_1);
+  fits_scan (&header, "PC002002", "%f", 1, &coords.pc2_2);
+  /* RA Terms */
+  fits_scan (&header, "PCA1X2Y0", "%f", 1, &coords.polyterms[0][0]);
+  fits_scan (&header, "PCA1X1Y1", "%f", 1, &coords.polyterms[1][0]);
+  fits_scan (&header, "PCA1X0Y2", "%f", 1, &coords.polyterms[2][0]);
+  fits_scan (&header, "PCA1X3Y0", "%f", 1, &coords.polyterms[3][0]);
+  fits_scan (&header, "PCA1X2Y1", "%f", 1, &coords.polyterms[4][0]);
+  fits_scan (&header, "PCA1X1Y2", "%f", 1, &coords.polyterms[5][0]);
+  fits_scan (&header, "PCA1X0Y3", "%f", 1, &coords.polyterms[6][0]);
+  /* Dec Terms */			    
+  fits_scan (&header, "PCA2X2Y0", "%f", 1, &coords.polyterms[0][1]);
+  fits_scan (&header, "PCA2X1Y1", "%f", 1, &coords.polyterms[1][1]);
+  fits_scan (&header, "PCA2X0Y2", "%f", 1, &coords.polyterms[2][1]);
+  fits_scan (&header, "PCA2X3Y0", "%f", 1, &coords.polyterms[3][1]);
+  fits_scan (&header, "PCA2X2Y1", "%f", 1, &coords.polyterms[4][1]);
+  fits_scan (&header, "PCA2X1Y2", "%f", 1, &coords.polyterms[5][1]);
+  fits_scan (&header, "PCA2X0Y3", "%f", 1, &coords.polyterms[6][1]);
+  coords.Npolyterms = 2; /* how many do we use? */
+
+  /* find number of stars */
+  fits_scan (&header, "NSTARS", "%d", 1, &Nstars);
+  if (Nstars == 0) {
+    fprintf (stderr, "no stars in file\n");
+    return (FALSE);
+  }
+
+  /* open file data */
+  f = fopen (argv[1], "r");
+  if (f == NULL) {
+    fprintf (stderr, "can't find data in file %s\n", argv[1]);
+    return (FALSE);
+  }
+  fseek (f, header.size, SEEK_SET); 
+
+  /* set up storage buffers */
+  Xvec.Nelements = Nstars;
+  Yvec.Nelements = Nstars;
+  Zvec.Nelements = Nstars;
+  ALLOCATE (Xvec.elements, float, Xvec.Nelements);
+  ALLOCATE (Yvec.elements, float, Yvec.Nelements);
+  ALLOCATE (Zvec.elements, float, Zvec.Nelements);
+  ALLOCATE (buffer, char, (BLOCK*BYTES_STAR));
+
+  /* load in stars by blocks of 1000 */
+  nstars = 0;
+  Nbytes = Nstars*BYTES_STAR;
+  for (i = 0; i < (int)(Nbytes / (BLOCK*BYTES_STAR)); i++) {
+    nbytes = fread (buffer, 1, (BLOCK*BYTES_STAR), f);
+    if (nbytes != BLOCK*BYTES_STAR) {
+      fprintf (stderr, "failed to read in stars (1)\n");
+      free (Xvec.elements);
+      free (Yvec.elements);
+      free (Zvec.elements);
+      free (buffer);
+      return (FALSE);
+    }
+    for (j = 0; j < BLOCK; j++, nstars++) {
+      dparse (&X,  1, &buffer[j*BYTES_STAR]);
+      dparse (&Y,  2, &buffer[j*BYTES_STAR]);
+      dparse (&M,  3, &buffer[j*BYTES_STAR]);
+      XY_to_RD (&R, &D, X, Y, &coords);
+      fRD_to_XY (&Xvec.elements[nstars], &Yvec.elements[nstars], R, D, &graphmode.coords);
+      Zvec.elements[nstars] = MIN (1.0, MAX (0.01, (M - zero) / range));
+    }
+  }
+  /* left over fraction of a block */
+  nbytes = fread (buffer, 1, (Nbytes % (BLOCK*BYTES_STAR)), f);
+  if (nbytes != (Nbytes % (BLOCK*BYTES_STAR))) {
+    fprintf (stderr, "ERROR: failed to read in stars (2)\n");
+    free (Xvec.elements);
+    free (Yvec.elements);
+    free (Zvec.elements);
+    free (buffer);
+    return (FALSE);
+  }
+  for (j = 0; j < nbytes / BYTES_STAR; j++, nstars++) {
+    dparse (&X,  1, &buffer[j*BYTES_STAR]);
+    dparse (&Y,  2, &buffer[j*BYTES_STAR]);
+    dparse (&M,  3, &buffer[j*BYTES_STAR]);
+    XY_to_RD (&R, &D, X, Y, &coords);
+    fRD_to_XY (&Xvec.elements[nstars], &Yvec.elements[nstars], R, D, &graphmode.coords);
+    Zvec.elements[nstars] = MIN (1.0, MAX (0.01, (M - zero) / range));
+  }
+  
+  if (nstars != Nstars) {
+    fprintf (stderr, "ERROR: failed to read in all stars (%d of %d)\n", nstars, Nstars);
+    free (Xvec.elements);
+    free (Yvec.elements);
+    free (Zvec.elements);
+    free (buffer);
+    return (FALSE);
+  }
+
+  graphmode.style = 2;
+  graphmode.size = -1;
+  graphmode.etype = 0;
+  Npts = Xvec.Nelements;
+  PrepPlotting (Npts, &graphmode);
+
+  PlotVector (Npts, Xvec.elements);
+  PlotVector (Npts, Yvec.elements);
+  PlotVector (Npts, Zvec.elements);
+
+  free (Xvec.elements);
+  free (Yvec.elements);
+  free (Zvec.elements);
+  free (buffer);
+
+  return (TRUE);
+
+}
+
+
Index: /tags/opihi-2-1/Ohana/src/opihi/dvo/subpix.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/dvo/subpix.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/dvo/subpix.c	(revision 3338)
@@ -0,0 +1,189 @@
+# include "dvo.h"
+
+int bracket (double *list, double value, int Nlist, int mode);
+
+int subpix (int argc, char **argv) {
+  
+  int i, j, I, Nlo, Nhi, Nentry, Nstars, Nregions, Nimage, Nmeasure;
+  int *index, *entry;
+  int Nmin, Nsub, NSUB, status;
+  int TimeFormat;
+  time_t Timage, TimeReference;
+  double X, Y, Mabs, t;
+  double Ra, Dec, Radius, Radius2, r, Rmin;
+  double *RA, *DEC;
+  char catdir[256], filename[256];
+  
+  Measure *measure;
+  Image *image;
+  RegionFile *regions;
+  Catalog catalog;
+
+  if (!InitPhotcodes ()) return (FALSE);
+
+  VarConfig ("CATDIR", "%s", catdir);
+  GetTimeFormat (&TimeReference, &TimeFormat);
+
+  if (argc != 4) {
+    fprintf (stderr, "USAGE: subpix ra dec radius\n");
+    return (FALSE);
+  }
+  if (!str_to_radec (&Ra, &Dec, argv[1], argv[2])) return (FALSE);
+  if (Ra < 0) Ra += 360.0;
+  if (Ra > 360.0) Ra -= 360.0;
+  Radius = atof (argv[3]);
+
+  /* load star nearest position */
+  regions = find_regions (Ra, Dec, Radius, &Nregions);
+  if (Nregions > 1) {
+    fprintf (stderr, "warning, radius overlaps region boundary, not yet implemented\n");
+  }
+
+  /* lock, load, unlock catalog */
+  sprintf (filename, "%s/%s", catdir, regions[0].name);
+  catalog.filename = filename;
+  switch (lock_catalog (&catalog, LCK_SOFT)) {
+  case 2:
+    unlock_catalog (&catalog);
+  case 0:
+    return (FALSE);
+  }
+  if (!load_catalog (&catalog, LOAD_AVES | LOAD_MEAS, TRUE)) {
+    unlock_catalog (&catalog);
+    return (FALSE);
+  }
+  unlock_catalog (&catalog);
+
+  /* quick search of star list for Ra, Dec */
+  Nstars = catalog.Naverage;
+  ALLOCATE (RA, double, Nstars);
+  ALLOCATE (DEC, double, Nstars);
+  ALLOCATE (index, int, Nstars);
+  for (i = 0; i < Nstars; i++) {
+    RA[i] = catalog.average[i].R;
+    DEC[i] = catalog.average[i].D;
+    index[i] = i;
+  }
+  if (Nstars > 1) dsort_lists (DEC, RA, index, Nstars);
+
+  /* bracket the DEC range of interest */
+  Nlo = bracket (DEC, Dec - Radius, Nstars, FALSE);
+  Nhi = bracket (DEC, Dec + Radius, Nstars, TRUE);
+  ALLOCATE (entry, int, MAX (Nhi - Nlo, 1));
+  Nentry = 0;
+
+  /* find the list of stars */
+  Radius2 = Radius*Radius;
+  for (i = Nlo; i < Nhi; i++) {
+    r = SQ(Dec - DEC[i]) + SQ(Ra - RA[i]);
+    if (r < Radius2) {
+      entry[Nentry] = i;
+      Nentry ++;
+    }
+  }
+  if (!Nentry) {
+    fprintf (stderr, "no stars found\n");
+    free (RA);
+    free (DEC);
+    free (entry);
+    free (index);
+    if (catalog.average != 0) free (catalog.average);
+    if (catalog.measure != 0) free (catalog.measure);
+    free (regions);
+    return (TRUE);
+  }
+
+  /* find the closest star */
+  Nmin = 0;
+  Rmin = SQ(Dec - DEC[entry[0]]) + SQ(Ra - RA[entry[0]]);
+  for (i = 1; i < Nentry; i++) {
+    r = SQ(Dec - DEC[entry[i]]) + SQ(Ra - RA[entry[i]]);
+    if (r < Rmin) {
+      Rmin = r;
+      Nmin = i;
+    }
+  }
+  Nentry = index[entry[Nmin]];
+  Ra = RA[entry[Nmin]];
+  Dec = DEC[entry[Nmin]];
+  fprintf (stderr, "finding subpix values for star @ %f %f\n", Ra, Dec);
+
+  free (RA);
+  free (DEC);
+  free (entry);
+  free (index);
+
+  /* storage for the image references */
+  Nsub = 0;
+  NSUB = 100;
+  ALLOCATE (index, int, NSUB);
+
+  /* load all images, extract those touching Ra, Dec */
+  image = LoadImages (&Nimage);
+  for (i = 0; i < Nimage; i++) {
+    status = RD_to_XY (&X, &Y, Ra, Dec, &image[i].coords);
+    if (!status || (X < 0) || (X > image[i].NX) || (Y < 0) || (Y > image[i].NY)) continue;
+    index[Nsub] = i;
+    Nsub ++;
+    if (Nsub == NSUB - 1) {
+      NSUB += 100;
+      REALLOCATE (index, int, NSUB);
+    }
+  }
+
+  /* only print the entries for existing measurements of this star */ 
+  measure = &catalog.measure[catalog.average[Nentry].offset];
+  Nmeasure = catalog.average[Nentry].Nm;
+  for (i = 0; i < Nsub; i++) {
+    I = index[i];
+    Timage = image[I].tzero;
+    for (j = 0; j < Nmeasure; j++) {
+      if (measure[j].t == Timage) { 
+	Mabs = PhotCat (&measure[j]);
+	RD_to_XY (&X, &Y, Ra, Dec, &image[I].coords);
+	t = TimeValue (measure[j].t, TimeReference, TimeFormat);
+	fprintf (GetOutfile(), "%f %6.3f %7.2f %7.2f %5.3f\n", t, Mabs, X, Y, 0.001*image[I].secz);
+      } 
+    }
+  }
+
+  if (catalog.average != 0) free (catalog.average);
+  if (catalog.measure != 0) free (catalog.measure);
+  free (image);
+  free (index);
+  free (regions);
+
+  return (TRUE);
+}
+
+/* fast operation to find an entry just below (0) or above (1) value */
+int bracket (double *list, double value, int Nlist, int mode) {
+
+  int Nlo, Nhi, N;
+
+  if (mode == 0) {
+    Nlo = 0; Nhi = Nlist;
+    while (Nhi - Nlo > 10) {
+      N = 0.5*(Nlo + Nhi);
+      if (list[N] < value) {
+	Nlo = N;
+      } else {
+	Nhi = N + 1;
+      }
+    }
+    return (Nlo);
+  }
+  if (mode == 1) {
+    Nlo = 0; Nhi = Nlist;
+    while (Nhi - Nlo > 10) {
+      N = 0.5*(Nlo + Nhi);
+      if (list[N] > value) {
+	Nhi = N;
+      } else {
+	Nlo = N - 1;
+      }
+    }
+    return (Nhi);
+  }
+  return (0);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/help/!
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/!	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/!	(revision 3338)
@@ -0,0 +1,6 @@
+
+  exec (line)
+
+  perform a system call.  this can also be invoked with "!".  
+  don't use ! in a macro or input script as it is interpreted as a
+  comment character. 
Index: /tags/opihi-2-1/Ohana/src/opihi/help/Graphics
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/Graphics	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/Graphics	(revision 3338)
@@ -0,0 +1,20 @@
+
+  Kapa, the graphics window.
+
+  Kapa is the program which Status uses to display plots on an X
+terminal.  There are actually 5 graphics windows available to Status,
+though several functions write to specific windows by default.  All
+plots of sky coordinates are displayed on window 0, while 
+functions which plot other types of data use window 1.  Most functions
+have an option -n which allows the user to specify which Kapa window.
+If it is not specified, the last window used will receive the action.
+
+  Below are the available Resources.  
+
+  kii*Foreground:			white
+  kii*Background:			maroon
+  kii*geometry:				540x540+10+10
+
+  See Also: box, clear, limits, plot
+
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/Kii
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/Kii	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/Kii	(revision 3338)
@@ -0,0 +1,57 @@
+
+
+  Kii (= "picture" in Hawaiian) is the program which Mana uses to
+display images on an X terminal.  The window consists of a main region
+where the image is displayed, a small "zoom box" where a magnified
+view of the region around the cursor is shown, a colorbar showing the
+current color map across the top of the window, a status box where the
+coordinates and pixel values are displayed, and several buttons.
+Clicking with the mounse in the different regions produces different
+effects.
+
+  Image Window:  Clicking with the left mouse button (mouse-1)
+recenters the image at the specified location.  Clicking with the
+right button (mouse-3) also recenters, but increases the zoom factor
+by one.  Clicking with the middle button centers and decreases the
+zoom factor.  
+
+  Colorbar: Clicking and draging with the left button (mouse-1) alters
+the color mapping.  Moving left-to-right slides the center of the
+color scale with the mouse.  Moving up-and-down squeezes or expands
+the color scale.  The middle button resets the color mapping.
+Clicking and dragging side-to-side with the right button expands or
+squeezes the color mapping.  **Note: the dynamic colormap cannot be
+used with a 24 or 32 bit visual.  The standard Linux XFree86 server
+does not support 8 bit visuals in 24 or 32 bit/pixel mode.  In this
+case, the Kii window must resort to a static colormap with the
+colorbar disabled.  In Linux, it is possible to run startx with the
+following command-line options to force the 8 bit/pixel mode:
+# startx -- -bpp 8 
+This assumes that you have an 8bpp Display mode set in the XF86Config
+file.  If not, you can just duplicate the 24 or 32 bpp Display modes
+which will enable this option.
+
+  Buttons:
+    PS: this button creates a PostScript version of the image.
+    Grey: this button makes the colormap a greyscale.
+    Rainbow: this button makes the colormap a rainbow.
+    Puns: this button make the colormap a blue and yellow mapping.
+    Recenter: this button recenters the image and resets the zoom.
+
+  Kii also recognizes several X Resource values:
+
+  Below are the available Resources (with Gene's default values).  Unlike
+most standard X programs, the geometry resource specifies the size of
+the Image Window, not the borders of the entire window.  Valid values
+for the colormap are: greyscale, grayscale (photonegative), -greyscale,
+-grayscale (photopositive), Puns, GoBears (buff 'n blue colormap),
+Rainbow (a rainbow map).  
+
+  kii*Foreground:			white
+  kii*Background:			maroon
+  kii*Colormap:				greyscale
+  kii*geometry:				540x540+10+10
+  
+
+  See Also: tv, cursor
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/Math
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/Math	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/Math	(revision 3338)
@@ -0,0 +1,58 @@
+
+  Opihi shell math operations:
+
+  Mana will evaluate scalar (1D) arithmetic expresions in two
+situations.  To set a variable equal to a math operation, use the
+syntax is:
+
+  $foo = expression
+
+where "expression" is an arithmetic expression on numbers and
+variables, including a variety of functions (see below).  After
+performing the arithmetic and setting the variable to the resulting
+value, mana returns the prompts without performing any further
+command.  Mana will also evaluate any arithmetic expression enclosed
+in curly brackets before attempting to perform the given command.  For
+example, if the variables $MEAN and $SIGMA contain the mean and
+standard deviation of an image, it would be possible to display the
+image with a zero and range based on $MEAN and $SIGMA like this:
+
+  tv image {$MEAN - 1.5*$SIGMA} {5*$SIGMA}
+
+
+The two expressions in curly brackets are evaluated and the resulting
+numbers passed as arguments to the "tv" command.
+
+  See Also:  Variables, tv
+
+
+list of valid math operations:
+
+  binary operators:
+  * (times)
+  / (divided by)
+  + (plus)
+  - (minus)
+  ^ (to the power of: 2^3 = 8)
+
+  unary operators:
+  exp (e to the power of)
+  ten (10 to the power of)
+  ln  (natural logarithm)
+  log (log base 10)
+
+  angles in radians:
+  sin (sine)
+  cos (cosine)
+  tan (tangent)
+  asin (arcsin)
+  acos (arccos)
+  atan (arctan)
+
+  angles in degrees:
+  dsin (sine)
+  dcos (cosine)
+  dtan (tangent)
+  dasin (arcsin)
+  dacos (arccos)
+  datan (arctan)
Index: /tags/opihi-2-1/Ohana/src/opihi/help/Opihi
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/Opihi	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/Opihi	(revision 3338)
@@ -0,0 +1,5 @@
+
+
+    Opihi
+
+  
Index: /tags/opihi-2-1/Ohana/src/opihi/help/Photometry
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/Photometry	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/Photometry	(revision 3338)
@@ -0,0 +1,26 @@
+
+cals: Plot residuals for reference stars. 
+
+ This function takes the currently displayed region and looks for all
+ stars which have 'reference' photometry and plots the difference
+ between the reference magnitude (in the given filter) and the
+ observed magnitude (same filter) versus one of several options:  the
+ star color (based on the 'reference' photometry), the star magnitude,
+ the airmass, time, secqunce, etc.
+
+ These plots can use one of two options for the 'observed' magnitude.
+ Either, the magnitude for individual measurement, using the currently
+ set values for the CCD zeropoints (from the photometry database), or
+ using the relative photometry determined for the particular star.  
+
+
+dmags: plot difference between two measured magnitudes
+
+resid: 
+
+abszero
+
+zeropts
+
+cmd
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/Shell
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/Shell	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/Shell	(revision 3338)
@@ -0,0 +1,5 @@
+
+
+    Opihi
+
+  
Index: /tags/opihi-2-1/Ohana/src/opihi/help/Variables
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/Variables	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/Variables	(revision 3338)
@@ -0,0 +1,17 @@
+
+  Opihi shell variables (scalars):
+
+  The Opihi shell can have variables which are designated by a word
+following a dollar sign: $foo.  Certain Mana function create and set
+variables (ie, stats, cursor).  You can also set a variable to the
+result of an arithmetic expression or just a number like this:
+
+  $foo = 10.0
+  $bar = 5*$foo + 0.6
+
+Mana will replace the variables on a line before executing a command.
+See also "Math" for more description of arithmetic operations.
+
+  See Also:  Math
+
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/applyfit
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/applyfit	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/applyfit	(revision 3338)
@@ -0,0 +1,10 @@
+
+  applyfit x y
+
+  apply the results of a polynomial fit (stored in variables 
+  $C0, $C1, etc, with $Cn representing the order of the fit).
+  The second vector will contain the function value at the 
+  corresponding x coordinates of the first vector.
+
+  See also: fit
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/biassub
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/biassub	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/biassub	(revision 3338)
@@ -0,0 +1,9 @@
+
+  biassub buffer sx sy nx ny dir [-v N V]
+
+  Apply a bias correction.  The region defines a vector 
+  (median is taken perpendicular to the dir direction) which 
+  is subtracted from the image.
+
+
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/box
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/box	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/box	(revision 3338)
@@ -0,0 +1,11 @@
+
+  box [-n Nwindow]
+
+  draw a coordinate box on the current kapa window, or on the window
+specified by -n (0 - 4).
+
+  See also: Kapa
+
+
+
+  
Index: /tags/opihi-2-1/Ohana/src/opihi/help/break
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/break	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/break	(revision 3338)
@@ -0,0 +1,7 @@
+
+  break
+
+  halts macro, if, or for processes and returns to the basic prompt.
+
+  See also: macro, if, for
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/buffers
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/buffers	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/buffers	(revision 3338)
@@ -0,0 +1,9 @@
+
+  buffers
+
+  buffers gives information about the currently allocated buffers.  
+A * next to the filename means the data has been altered from the
+originally read in image.
+
+  See also: memory
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/catalog
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/catalog	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/catalog	(revision 3338)
@@ -0,0 +1,74 @@
+
+  catalog (filename/-all) [many options!]
+
+  plot the star positions from any of several possible catalogs.  By
+default, the photometry database (see Database) is used, but the HST
+Guide Star Catalog and a simple ASCII file may also be used.  The
+plotting is done on window 0, with the current point type.  The point
+size can be scaled by the magnitude of the star or by the number
+of observations (-n).  
+
+There are many options to this function.  Here they are all:
+
+-e epoch: given ASCII catalog has this epoch, plot in J2000
+
+-ID ID: plot only measurements with this ID number
+ ID may be one of:
+	0 - star
+	4 - variable
+	5 - transient
+      100 - ghost image
+      101 - trail (satellite)
+      102 - bright star garbage	
+      note that numbers < 50 are static objects, 
+	and numbers > 100 are bad data.
+
+-all:  plot all data for the current display region
+
+-g: use the HST GSC instead of the photometry database
+
+-a RA DEC MAG:  the given file is an ASCII file with 
+	RA, DEC, and MAG in columns given by the three numbers
+
+-v ra dec scale: save the values in vectors with the three names given
+	the ra and dec are always used, but the third is the size of 
+	the points plotted, based on whatever the scaling is.
+
+-m m1 m2: scale points by magnitude, with smallest points having
+	magnitude m2.
+
++n n1 n2: scale points by number of measurements, with smallest points
+	having number n1.
+
+-n n1 n2: scale points by number of missing values, with smallest points
+	having number n1.
+
+Note that if two of -m, -n, +n are given, the first determines the
+ scaling of the points.  the second provides an allowed range, so
+ points are only plotted if the second parameter has a value in the
+ given range.
+
+Examples: 
+
+  catalog -all -m 12 18  
+    plot all stars in current region with magnitude 12 having the
+    biggest points and magnitude 18 having the smallest.
+   
+  catalog -all -m 12 18 +n 2 4
+    plot all stars in current region with magnitude 12 having the
+    biggest points and magnitude 18 having the smallest, but only
+    if the stars have 2-4 measurements each
+   
+  catalog -all -m 12 18 +n 0 1 -ID 101
+    plot all stars in current region with magnitude 12 having the
+    biggest points and magnitude 18 having the smallest, but only
+    if the stars have 1 measurements each, and if the object is 
+    found to be a trail.
+   
+  catalog n2230/1819.cpt -n 2 8  
+    plot all stars in catalog n2230/1819.cpt with the biggest points
+    having 8 measurements and the smallest having only 2.
+
+  See Also: lcat, pcat, style, region
+
+   
Index: /tags/opihi-2-1/Ohana/src/opihi/help/cd
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/cd	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/cd	(revision 3338)
@@ -0,0 +1,9 @@
+
+   cd (path)
+
+   change current working directory. 
+
+   Note that Kii or Kapa will be launched in the original 
+   directory, which means PS files created by Kii or Kapa 
+   will land in that directory (perhaps an unexpected result).
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/center
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/center	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/center	(revision 3338)
@@ -0,0 +1,10 @@
+
+  center (xpix) (ypix) [magnification]
+
+  "center" centers the Kii window at the specified pixel coordinates.
+Specifying a magnification will change the image scale to the
+specified magnification.  If you do not specify a magnification
+(default), the image scale will remain the same.
+
+  See also: Kii, tv
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/cgrid
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/cgrid	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/cgrid	(revision 3338)
@@ -0,0 +1,6 @@
+
+  cgrid
+
+  draws a grid in RA and DEC on window 0 approriate for the current
+  region.
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/clear
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/clear	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/clear	(revision 3338)
@@ -0,0 +1,5 @@
+
+   clear
+
+   clear the Kapa window
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/clip
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/clip	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/clip	(revision 3338)
@@ -0,0 +1,8 @@
+
+  clip (buffer) [min Vmin max Vmax] [-inf val] [-nan val]
+
+  clip values in an image.  A min/max clip can be applied, 
+  in which case all values above max are set to Vmax and all
+  below min are set to Vmin.  -nan and -inf flags will set all 
+  instances of NaN or any non-finite values to the given value.
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/concat
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/concat	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/concat	(revision 3338)
@@ -0,0 +1,8 @@
+
+   concat v1 v2
+
+   concatenates the values of vector v2 to the end of vector
+   v1, increasing the length of v1.
+
+   See also: subset, set
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/contour
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/contour	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/contour	(revision 3338)
@@ -0,0 +1,13 @@
+
+  contour <buffer> (overlay) level [Npix]
+
+  "contour" makes a contour plot from the given <buffer> at the
+specified level.  If Npix is specified, the image is rebinned by a
+factor of Npix in each direction.  The contour is drawn as a series of
+lines on the specified overlay.  The new lines are added to any
+existing shapes.  (Use "erase" first to erase all objects if desired).
+
+Valid overlays may be: 0, red, 1, green, 2, blue, 3, yellow.
+
+  See also: load, save, erase
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/coords
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/coords	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/coords	(revision 3338)
@@ -0,0 +1,19 @@
+
+  coords <buffer> (filename)
+
+  "coords" loads astrometric parameters for the given buffer from the
+header of the named file.  The parameters are applied to the buffer,
+and will register in the Ki'i window if the buffer it tv'ed again.
+This is particularly convenient for intercomparing coordinate system
+or in the event the astrometry is stored in a different file (eg, a
+stripped off header).  Currently, the only format of coordinate
+information that is looked for are gene's linear transformation: RA_O,
+RA_X, RA_Y, DEC_O, DEC_X, DEC_Y such that the RA,DEC of an object is
+given by:
+
+RA  = RA_O  + x*RA_X  + y*RA_Y
+DEC = DEC_O + x*DEC_X + y*DEC_Y.
+
+
+  See also: rd, tv
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/create
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/create	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/create	(revision 3338)
@@ -0,0 +1,7 @@
+
+   create vector start end [delta]
+
+   create a vector of uniformly spaced values, starting at
+   start and going to end.  By default the spacing is 1, but
+   may be chosen with the delta option.
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/cursor
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/cursor	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/cursor	(revision 3338)
@@ -0,0 +1,13 @@
+
+  cursor
+
+  place cursor coordinates (and values ??) into Mana variables.  to do
+this, type cursor, then place the cursor on the desired spot in the
+Ki'i window and type a digit (0 - 9).  The coordinates of the cursor
+are then placed in the variables $Xn and $Yn (where n is the digit you
+typed).  To exit the cursor mode, type "q" (or "Q") in the Ki'i
+window.  
+
+  See Also: Kii, tv, center
+
+ 
Index: /tags/opihi-2-1/Ohana/src/opihi/help/cut
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/cut	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/cut	(revision 3338)
@@ -0,0 +1,9 @@
+
+   cut buffer <X vector> <Y vector> <X|Y> sx sy nx ny
+
+   take a cut from an image and place it in a pair of vectors.
+   the <X vector> gets the pixel coordinate in the given direction,
+   the <Y vector> gets the pixel values.  <X|Y> specifies the 
+   direction of the cut.  the region sx, sy, nx, ny specifies the
+   region for the cut, with summation in the cross-direction.
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/datafile
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/datafile	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/datafile	(revision 3338)
@@ -0,0 +1,6 @@
+
+   datafile (filename)
+
+   define a data file for subsequent vector reads.
+
+   See also: read
Index: /tags/opihi-2-1/Ohana/src/opihi/help/delete
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/delete	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/delete	(revision 3338)
@@ -0,0 +1,5 @@
+
+  delete <buffer>
+
+  delete the named buffer.  Warning: no second chances are given!
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/echo
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/echo	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/echo	(revision 3338)
@@ -0,0 +1,10 @@
+
+  echo [anything]
+
+  prints the rest of the line, after variables and math expressions
+are parsed.  
+
+
+  See Also:  Opihi, math
+
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/erase
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/erase	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/erase	(revision 3338)
@@ -0,0 +1,8 @@
+
+  erase (overlay)
+
+  "erase" erases all objects on the specified overlay.  
+  Valid overlays may be: all, red, green, blue, yellow.
+
+  See also: load, save, contour
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/exec
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/exec	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/exec	(revision 3338)
@@ -0,0 +1,6 @@
+
+   exec (or !) system function
+
+   perform a UNIX system call.  variables are parsed before 
+   the commands is passed to the UNIX shell.
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/extract
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/extract	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/extract	(revision 3338)
@@ -0,0 +1,12 @@
+
+  extract <from> <to> sx sy nx ny sx sy nx ny
+
+  extract takes a portion of an image (buffer <from>) and creates a
+new image (buffer <to>).  The source region is defined by the first
+set of (sx sy nx ny), the resulting image and the location of the
+extracted image are defined by the second (sx sy nx ny).  This allows
+a portion of an image to be overlayed at a particular location in a
+larger image.
+
+  See also: Kii, tv
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/fit
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/fit	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/fit	(revision 3338)
@@ -0,0 +1,9 @@
+
+   fit x y order [-dy wt]
+
+   perform a lease-square polynomial fit to the data defined 
+   by vectors x and y.  the coefficients are placed in the variables
+   $C0, $C1, ..., and the order is placed in $Cn.
+
+   See also: applyfit
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/flux
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/flux	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/flux	(revision 3338)
@@ -0,0 +1,7 @@
+
+   flux buffer (file)
+
+   calculate the flux enclosed by the contour given in the file.  The
+   file contains the coordinates of the polygon corners.
+
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/for
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/for	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/for	(revision 3338)
@@ -0,0 +1,19 @@
+
+   for var (start) (stop) [delta]
+
+    perform a loop, with $var as the loop variable. 
+    the value of $var runs from (start) to (stop) inclusive, 
+    and is incremented by [delta] (1 by default).
+
+    The loop commands are entered until the appropriate "end" is typed;
+    if there are nested loops, macro definitions, or logical blocks,
+    the correct "end" is used!
+
+    for may be used at the command line, in a macro, or in an input
+    file with no ill effects.
+
+    the variable $var may be accessed during the loop execution.  if
+    the variable $var is assigned a value beyond (stop) during the
+    loop, the loop execution will end.
+
+    See also: macro, if
Index: /tags/opihi-2-1/Ohana/src/opihi/help/gauss
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/gauss	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/gauss	(revision 3338)
@@ -0,0 +1,15 @@
+
+   gauss Npix [Nspots] [-border N] [-sat cnts]
+
+   calculate statistics on stars, assuming a Gaussian profile.  The
+   user types a key on a star in the Kii window, and the resulting
+   information is printed on the screen.  This is really aperture
+   photometry.  Npix defines the aperture width (square aperture), the
+   optional -border defines the number of pixels in an annulus used to
+   find the background, -sat defines the value of a saturated pixel.
+   If the Nspots option is given, exactly Nspots stars are chosen.
+   Otherwise, the user may type on stars until the 'q' is typed.  The
+   results of the last star are stored the a set of Mana variables.
+
+   See also: star, cursor
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/grid
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/grid	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/grid	(revision 3338)
@@ -0,0 +1,6 @@
+
+   grid (overlay) (buffer)
+
+   draw a coordinate grid for the given buffer in the 
+   given overlay in Kii.
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/header
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/header	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/header	(revision 3338)
@@ -0,0 +1,8 @@
+
+   header (buffer)
+
+   print the header information for the given buffer.  The header
+   information is Meta-information associated with an image.  It is
+   well-defined for the FITS images, but may not exist for some of the
+   other possible data types.  
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/help
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/help	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/help	(revision 3338)
@@ -0,0 +1,7 @@
+
+   help (function)
+
+   print the contents of the help file.  
+   typing "help" without an argument will list the available help
+   files.  
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/histogram
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/histogram	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/histogram	(revision 3338)
@@ -0,0 +1,8 @@
+
+   histogram <buffer> <x> <y> [-region sx sy nx ny] [-range min max]
+
+   calculate a histogram of the image pixel values in the given
+   buffer, optionally constrained to the given region, with optional
+   max and min values.  the results are placed in the vectors x and y,
+   which contain the pixel values and the number of occurences.
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/if
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/if	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/if	(revision 3338)
@@ -0,0 +1,22 @@
+
+   if (logic)
+     (commands)
+   end
+
+   or:
+
+   if (logic)
+     (commands)
+   else 
+     (commnds)
+   end
+
+   logical block.  The commands are performed subject to the logical
+   condition.  The syntax is simplified C:  
+   examples: (x = 6), (x < 6) , (x ! 6), ((x = 6) | (x > 10))
+
+   there are no delimiter characters.
+
+   See also: for, macro
+
+   
Index: /tags/opihi-2-1/Ohana/src/opihi/help/images
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/images	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/images	(revision 3338)
@@ -0,0 +1,9 @@
+
+  images 
+
+  plot the outlines of images in the photometry database and list
+  along with relevant information.  An example of relevant data is the
+  image time, which can be used in other functions to define a specific
+  image or a range of images relevant for the function.
+
+  See also: Database, lcat, pcat
Index: /tags/opihi-2-1/Ohana/src/opihi/help/imstats
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/imstats	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/imstats	(revision 3338)
@@ -0,0 +1,5 @@
+
+  imstats 
+
+  list interesting statistics for a set of images.
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/input
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/input	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/input	(revision 3338)
@@ -0,0 +1,15 @@
+
+   input (filename)
+
+   execute a series of commands given in the file.
+
+   Two special examples:  
+   ~/.manarc is loaded on startup, which give the user a place to
+   define personal macros, or interesting variables, etc.
+
+   If mana is called in the form "mana file", the file is loaded
+   (after .manarc) before the user is given the command-line prompt.
+   This can be used to invoke mana in a shell script, but care should
+   be taken in a shell-script that the file ends with the word "exit"
+   or "quit", or strange things may happen...
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/kern
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/kern	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/kern	(revision 3338)
@@ -0,0 +1,4 @@
+
+   kern buffer (kernel file or -)
+
+   apply a 3x3 kernel to the image.  
Index: /tags/opihi-2-1/Ohana/src/opihi/help/keyword
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/keyword	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/keyword	(revision 3338)
@@ -0,0 +1,11 @@
+
+  keyword <buffer> (KEYWORD) [variable] [-w value]
+
+  "keyword" extracts the specified keyword from the header of the
+   specified buffer.  If a third word is listed, the value of the
+   keyword is stored in a variable with the given name.  If the -w
+   option is given, the value is written to the header keyword.
+
+   The header Meta-data is well-defined for FITS, but not necessarily
+   for other data types.
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/labels
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/labels	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/labels	(revision 3338)
@@ -0,0 +1,23 @@
+
+   labels 
+
+   write a label on the Kapa window.  there are many options:
+
+   -fn font size -- define the font (may be times, helvetica, courier)
+
+   -x "a long line" -- label on the bottom x-axis
+
+   +x "a long line" -- label on the top x-axis
+
+   -y "a long line" -- label on the left y-axis
+
+   +y "a long line" -- label on the right y-axis
+
+   -ul "a long line" -- label on the upper left of plot
+
+   -ll "a long line" -- label on the lower left of plot
+
+   -ur "a long line" -- label on the upper right of plot
+
+   -lr "a long line" -- label on the lower right of plot
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/lcat
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/lcat	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/lcat	(revision 3338)
@@ -0,0 +1,10 @@
+
+  lcat [-all]
+
+  list photometry database files in the current region.  if the option
+  -all is given, all database in the region are listed, along with a
+  comment to show if there is data in the file or not.  if the option
+  is not given, only those files with data are listed.
+
+  See also: region, pcat
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/lcurve
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/lcurve	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/lcurve	(revision 3338)
@@ -0,0 +1,8 @@
+
+  lcurve RA DEC Radius [-l]
+
+  plot light curves for all stars within Radius of the given
+  coordinates.  The units for all three are decimal degrees.  
+  The option -l autoscales the limits of the plot.  
+
+  See also: limits
Index: /tags/opihi-2-1/Ohana/src/opihi/help/limits
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/limits	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/limits	(revision 3338)
@@ -0,0 +1,12 @@
+
+   limits min max min max
+   limits x y
+   limits x min max
+   limits min max y
+   
+   set Kapa plot limits.  The x and y axis limits may be explicitly
+   set (first example), or they may be assigned based on the range of
+   values in a pair of vectors (second examples), or one range may be
+   explicit and the other range assigned from a vector.
+
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/load
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/load	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/load	(revision 3338)
@@ -0,0 +1,20 @@
+
+   load (overlay) (filename)
+
+  "load" reads a file with objects in SAOimage style into the
+  specified overlay.  If the specified overlay is already used, the
+  new objects are added to the old.  If you do not want this, use
+  "erase" to erase all objects in the overlay first.  Valid overlays
+  may be: 0, red, 1, green, 2, blue, 3, yellow.
+
+Examples of SAOimage style objects:
+BOX   300  200  100 50  : draws a box centered at pixel 300,200 that
+			  is 100 pixels wide, and 50 pixels high
+
+CIRCLE 500 400 200 : draws a circle centered at pixel 500,400 with a
+                     radius of 200 pixels
+
+LINE 100 100 200 200 : draws a line from (100,100) with length (200,200)
+
+  See also: save, erase, contour
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/macro
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/macro	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/macro	(revision 3338)
@@ -0,0 +1,11 @@
+
+   macro (name)
+
+   create a macro.  the commands are entered until the word 'end' is
+   reached.  nested if, for, and macro definitions use the
+   appropriately matched occurances of the 'end'.
+
+   Within a macro, the command-line arguments are refered to as $1,
+   $2, etc.  The number of command-line arguments is given by $0.
+
+   
Index: /tags/opihi-2-1/Ohana/src/opihi/help/memory
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/memory	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/memory	(revision 3338)
@@ -0,0 +1,12 @@
+
+  memory [x]
+
+  list the currently used memory.  This gives a (possibly very) long
+  listing of the size of every allocated piece of memory.  Placing
+  anything after the word "memory" gives a summary also.  This is
+  useful to see just how close you are to filling your computer's
+  entire memory (Does not include memory allocated to Kii!)
+
+  See Also: buffers
+
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/mextract
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/mextract	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/mextract	(revision 3338)
@@ -0,0 +1,12 @@
+
+ mextract (filename) (value) [-g / -a Ncol]
+
+ extracts a vector from the photometry database.  The name also
+ specifies the type of data extracted (and is case insensitive).  Only
+ certain names may be used.
+
+ The possible values are:
+ ra, dec, mag, dmag, Mcal, Mrel, source, time, dR, dD
+
+
+ Note: this routine extracts the individual measurements.
Index: /tags/opihi-2-1/Ohana/src/opihi/help/output
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/output	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/output	(revision 3338)
@@ -0,0 +1,10 @@
+
+  output (filename or "stdout")
+
+  redirect the output to a file (concat to the end of the file).  This
+  can also be done with the UNIX ">".  However, this command is useful
+  to send information to a file for a part of a Mana session.  For
+  example, you can save results of a "stats" command.
+
+  See Also: input, stats
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/pause
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/pause	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/pause	(revision 3338)
@@ -0,0 +1,9 @@
+
+  pause (N)
+
+  pause N seconds.  This suspends Mana (not Ki'i) for N seconds.  Be
+careful:  Typing pause 100000 may be a bad idea!  (you can only get
+out of this with a cntl-C, which also kills Mana).
+
+  See Also: wait
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/pcat
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/pcat	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/pcat	(revision 3338)
@@ -0,0 +1,9 @@
+
+  pcat [-all]
+
+  plot outlines of photometry database files in the current region.
+  if the option -all is given, all database in the region are listed.
+  if the option is not given, only those files with data are listed.
+
+  See also: region, lcat
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/plot
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/plot	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/plot	(revision 3338)
@@ -0,0 +1,13 @@
+
+   plot <x> <y> [-dx dx] [-dy dy] [+dx dx] [+dy dy]
+
+   plot a pair of vectors.  the options allow for errorbars.  If only
+   one of -dy or +dy is given, the given vector is used for the
+   errorbar.  If both are given, -dy defines the lower errorbar, while
+   +dy defines the upper errorbar.  This allows for assymetric errors
+   in a trivial fashion.  The same applies to the -dx, +dx values.  
+
+   The vectors are plotted with the current plot style.  See style for
+   all of the options.
+
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/print
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/print	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/print	(revision 3338)
@@ -0,0 +1,4 @@
+
+  print X Y
+
+  write a pair of vectors to a disk file.  
Index: /tags/opihi-2-1/Ohana/src/opihi/help/profile
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/profile	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/profile	(revision 3338)
@@ -0,0 +1,6 @@
+
+   profile <buffer> <X vector> <Y vector> x y N
+
+   Find the radial profile of an image at the location x, y.  the
+   radius is placed in the X vector and the pixel value is placed in
+   the Y vector.   
Index: /tags/opihi-2-1/Ohana/src/opihi/help/ps
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/ps	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/ps	(revision 3338)
@@ -0,0 +1,8 @@
+
+   ps [-g]
+
+   create a PostScript file from the Kii window (or Kapa window if -g
+   is given).  Kii produces a file called Ximage.ps, while Kapa
+   produces a file called Xgraph.ps
+
+   Color postscript is an obvious, but unimplemented extension...
Index: /tags/opihi-2-1/Ohana/src/opihi/help/pwd
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/pwd	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/pwd	(revision 3338)
@@ -0,0 +1,5 @@
+
+   pwd
+
+   print current working directory
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/rd
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/rd	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/rd	(revision 3338)
@@ -0,0 +1,10 @@
+
+  rd (buffer) (filename)
+
+  "rd" reads a file into the specified buffer, creating the buffer if
+  none exists.  A buffer name may consist of any letters, numbers, and
+  some limited other characters.  However, the name may not start with
+  a digit.
+
+  See also: wd, tv
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/read
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/read	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/read	(revision 3338)
@@ -0,0 +1,10 @@
+
+   read vect col [vect col, ...]
+
+   read vector values from a file.  An arbitrary number of vectors can
+   be specified, and the (whitespace-separated) field number given for
+   each vector.  Data is read from the file defined by "datafile".
+
+   See also: datafile
+
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/rebin
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/rebin	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/rebin	(revision 3338)
@@ -0,0 +1,9 @@
+
+  rebin <from> <to> scale
+
+  "rebin" rebins the specified buffer by the given scale factor and
+  places the result in the <to> buffer.  Negative integer values imply
+  expansion, positive numbers imply compression.
+
+  See also: extract
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/region
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/region	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/region	(revision 3338)
@@ -0,0 +1,11 @@
+
+  region RA DEC Radius [projection]
+
+  define the current sky region and optionally the projection.  
+  RA, DEC and Radius are all values in decimal degrees.  The possible 
+  values for "projection" are:
+
+  TAN - a tangent plane projection (default, and typical for optical images)
+  SIN - a sine plane projection (more appropriate for polar regions)
+  AIT - aitoff projection (good for the full sky)
+  GLS - ?? (also good for the full sky)
Index: /tags/opihi-2-1/Ohana/src/opihi/help/resid
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/resid	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/resid	(revision 3338)
@@ -0,0 +1,12 @@
+
+  resid [-im time] [-X] [-l] (photometry file)
+
+  plot the photometry residuals for a photometry database file. 
+  For every star in the database, the average magnitude is plotted 
+  vs the difference between the average magnitude and each existing 
+  measurement for that star.  
+
+  -l		automatically set the plot limits.
+  -X		plot residual divided by photometric error
+  -im time	only plot the residuals for one of the images 
+		in the database, specified by the obseravation time.
Index: /tags/opihi-2-1/Ohana/src/opihi/help/resize
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/resize	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/resize	(revision 3338)
@@ -0,0 +1,6 @@
+
+   resize Nx Ny
+
+   change the size of the Kii window to have image dimensions Nx x
+   Ny.  
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/rotate
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/rotate	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/rotate	(revision 3338)
@@ -0,0 +1,10 @@
+
+   rotate (buffer) (angle) [-center x y]
+
+   rotate the buffer by the given angle.  The angle may also be one of
+   the following special words:
+
+   -flipx - flip in the x direction
+   -flipy - flip in the y direction
+
+   if the optional center is given the rotation is about this position.
Index: /tags/opihi-2-1/Ohana/src/opihi/help/save
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/save	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/save	(revision 3338)
@@ -0,0 +1,16 @@
+  save (overlay) (filename)
+
+  "save" stores the objects from the specified overlay into the named
+file.  Valid overlays may be: 0, red, 1, green, 2, blue, 3, yellow.
+
+Examples of SAOimage style objects:
+BOX   300  200  100 50  : draws a box centered at pixel 300,200 that
+			  is 100 pixels wide, and 50 pixels high
+
+CIRCLE 500 400 200 : draws a circle centered at pixel 500,400 with a
+                     radius of 200 pixels
+
+LINE 100 100 200 200 : draws a line from (100,100) with length (200,200)
+
+  See also: load, erase, contour
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/scan
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/scan	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/scan	(revision 3338)
@@ -0,0 +1,5 @@
+
+   scan (filename) (variable) [Nline]
+
+   place the Nth line in the file in the named variable
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/set
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/set	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/set	(revision 3338)
@@ -0,0 +1,41 @@
+
+  set (buffer) = expression..
+
+  perform math operations on images.  there are several allowed
+  operators.  the standard math functions are + - * /.  Exponentiation
+  is performed with ^ (set c = a ^ b).  There are several "logic"
+  operators which need some explanation.
+
+  set c = a < b  -- c is 1 if a < b, 0 otherwise
+  set c = a > b  -- c is 1 if a > b, 0 otherwise
+  set c = m1 & m1 - c is 1 if m1 AND m2 true (non-zero is true)
+  set c = m1 | m1 - c is 1 if m1 OR m2 true (non-zero is true)
+  set c = a << b -- c is the minimum of a and b
+  set c = a >> b -- c is maximum of a and b
+
+  complex operations may be performed:
+
+  set c = a*(a < b) + c*((a < c) | (c < d))
+
+  unary operators also exist:
+
+  exp(a) - e to the power of a
+  ten(a) - 10 to the power of a
+  ln(a) - log base e of a
+  log(a) - log base 10 of a
+  sqrt(a) - square root of a
+  sin(a) - sin of a
+  cos(a) - sin of a
+  tan(a) - sin of a
+  not(a) - logical inverse of a
+  abs(a) - absolute value of a
+  int(a) - integer value of a
+
+  Examples:
+  
+  set a = b + 10  (add 10 to every pixel in b and put the answer in a)
+  set a = a / b   (divide every pixel in a by the corresponding pixel
+                     b and put the answer in a)
+  set b = 10 / a  (divide 10 by every pixel in a and put the answer
+                     in b)
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/shift
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/shift	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/shift	(revision 3338)
@@ -0,0 +1,6 @@
+
+   shift buffer dx dy
+
+   shift image by dx,dy pixels (may be fractional values).
+
+   
Index: /tags/opihi-2-1/Ohana/src/opihi/help/simage
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/simage	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/simage	(revision 3338)
@@ -0,0 +1,7 @@
+
+  simage (filename)
+
+  plot the positions of stars in a CMP file.  This function is a
+  useful test for image comparisons, and astrometry must be determined
+  before the function is run.
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/stats
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/stats	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/stats	(revision 3338)
@@ -0,0 +1,10 @@
+
+  stats (buffer) (x) (y) (nx) (ny)
+
+  report the statistics on a portion of an image.  (x) and (y) specify
+the starting corner of the region, (nx) and (ny) specify the width and
+height of the region.  stats reports the mean, sigma, and number of
+pixels in the region.
+
+  See Also: ??
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/style
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/style	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/style	(revision 3338)
@@ -0,0 +1,36 @@
+
+   style -- many options
+
+   define or check the Kapa plotting style.  without any command-line arguments,
+   style prints the current style.  
+
+   option definitions:
+
+   -n	window number (0-4), can also be used to change active window.
+   -pt	point style: 
+		0 = filled box
+		1 = open box
+		2 = +
+		3 = X
+		4 = filled triangle
+		5 = blank
+		6 = open triangle 
+		7 = open circle
+		100 = connect pair of points
+   -x	plotting method:
+		0 = connect
+		1 = histogram
+		2 = points
+   -lt	line type:
+		0 = solid
+		1 = dashed
+		2 = dotted??
+   -lw	line weight (0-10)
+   -sz	point size
+   -c   color:
+	black, white, red, orange, 
+	yellow, green, blue, indigo, violet
+   -eb  errorbar with no top
+   +eb  errorbar with top
+
+   See also: plot, box
Index: /tags/opihi-2-1/Ohana/src/opihi/help/subset
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/subset	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/subset	(revision 3338)
@@ -0,0 +1,12 @@
+
+   subset vec = vec if (logic expression)
+
+   reduce the length of a vector based on logical expression.  The
+   logic expression is some function of vectors of equal length to the
+   main vector.
+
+   for example, we have vectors x and y of the same length:
+   
+   subset X = x if ((y > 100) | (x < 10))
+
+    
Index: /tags/opihi-2-1/Ohana/src/opihi/help/textline
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/textline	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/textline	(revision 3338)
@@ -0,0 +1,7 @@
+
+   textline x y (line) [-fn (font) size] [-rot angle]
+
+   write the string at the given coordinates and rotation,
+   in the given font.
+
+   (enclose long strings with spaces in quotes)
Index: /tags/opihi-2-1/Ohana/src/opihi/help/tv
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/tv	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/tv	(revision 3338)
@@ -0,0 +1,13 @@
+
+  tv [-log] (buffer) [zero range]
+
+  display an image in the Ki'i window (X display program).  zero and
+  range specify the data values corresponding to the color mapping.
+  If they are not specified, the old values are used (default is 0,
+  1024).
+
+  If -log is specified the color mapping scale will be logarithmic.  
+
+
+  See Also: Kii, rd, cursor
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/unsign
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/unsign	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/unsign	(revision 3338)
@@ -0,0 +1,20 @@
+  unsign
+
+  "unsign" toggles the status of the UNSIGN mode.  Warning: This is a
+non-FITS standard implementation.  The FITS standard does not allow
+for unsigned integer data values, but many sites write CCD images with
+16 bit UNSIGNED data.  Mana looks for a FITS keyword "UNSIGN" to
+determine if an image which is read in has signed or unsigned
+integers.  However, since this is a non-standard concept, many sites
+do not use the UNSIGN flag, yet still write unsigned data.  If the
+user knows the data in the file is unsigned (ie, the user must have
+apriori knowledge -- a FITS no-no!), then the user should set the
+UNSIGN mode to true.  In the event that the UNSIGN mode is set, if a
+FITS file is encountered which contains integers, but which does not
+contain the UNSIGN keyword, Mana will make the default assumption that
+the data is unsigned.  If the SIGNED mode is set, Mana will assume all
+integer FITS files contain signed integers.  
+
+((( should be able to say "unsign <buffer>" to convert the status of a
+buffer to UNSIGN or to toggle the buffer's status, but not yet
+implemented)))
Index: /tags/opihi-2-1/Ohana/src/opihi/help/vectors
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/vectors	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/vectors	(revision 3338)
@@ -0,0 +1,5 @@
+
+   vectors
+
+   list the currently defined vectors and lengths
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/wait
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/wait	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/wait	(revision 3338)
@@ -0,0 +1,5 @@
+
+  wait [anything]
+
+  wait echos the rest of the line and waits for <return> to be typed.
+Very useful for pausing the processing of an input file or a macro.
Index: /tags/opihi-2-1/Ohana/src/opihi/help/wd
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/wd	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/wd	(revision 3338)
@@ -0,0 +1,29 @@
+
+  wd (buffer) (filename) [BITPIX]
+
+  wd writes a buffer to the specified file in FITS format.  (You may
+need quotes around the filename if there are any /'s in the path).
+The FITS keyword BITPIX may be specified.  Valid values are 8, 16, 32
+(integer formats) and -32, -64 (floating point formats).  If BITPIX is
+unspecified, the original value of the image is used.  The image is
+converted blindly to the format and written out.  This may mean that
+values are rounded (integers), or wrapped by the range of the number
+of bits.  Also beware of the issue of signed vs unsigned images.
+
+  See Also: rd
+
+bitpix  bzero  bscale  file range     data range
+16      0      1       -32k : 32k     -32k : 32k
+16	32k    1       -32k : 32k        0 : 64k
+16	0      2       -32k : 32k     -64k : 64k
+16	0      0.001   -32k : 32k     -32. : 32.
+32	0      1       -2e9 : 2e9     -2e9 : 2e9
+8	0      1       -128 : 128     -128 : 128
+
+so for example, a file with a data range of -128k to +128k written
+with bitpix 16, bzero 0, bscale 1 will have all data outside -32k :
++32k wrapped back in that range.
+
+note: on write, bzero is subtracted from the data before the data is
+      divided by bscale.
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/which
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/which	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/which	(revision 3338)
@@ -0,0 +1,5 @@
+
+   which (command)
+
+   give a short summary info line on a command
+
Index: /tags/opihi-2-1/Ohana/src/opihi/help/zplot
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/help/zplot	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/help/zplot	(revision 3338)
@@ -0,0 +1,7 @@
+
+   zplot x y z min max
+
+   plot the vector pair x and y as a series of points with size scaled
+   by the values in the vector z, with the smallest point having
+   values <= min and the largest having values >= max.
+
Index: /tags/opihi-2-1/Ohana/src/opihi/include/astro.h
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/include/astro.h	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/include/astro.h	(revision 3338)
@@ -0,0 +1,13 @@
+# include "external.h"
+# include "shell.h"
+# include "dvomath.h"
+# include "convert.h"
+# include "display.h"
+# include "data.h"
+
+# ifndef ASTRO_H
+# define ASTRO_H
+
+/* why is nothing in here? */
+
+# endif
Index: /tags/opihi-2-1/Ohana/src/opihi/include/basic.h
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/include/basic.h	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/include/basic.h	(revision 3338)
@@ -0,0 +1,5 @@
+# include "external.h"
+# include "shell.h"
+# include "dvomath.h"
+
+void cleanup ();
Index: /tags/opihi-2-1/Ohana/src/opihi/include/convert.h
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/include/convert.h	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/include/convert.h	(revision 3338)
@@ -0,0 +1,34 @@
+# include "external.h"
+
+# ifndef CONVERT_H
+# define CONVERT_H
+
+/*** values for time formats */
+enum {TIME_NONE, TIME_JD, TIME_MJD, TIME_DATE, TIME_DAYS, TIME_HOURS, TIME_MINUTES, TIME_SECONDS};
+
+/*** conversion functions ***/
+time_t        TimeRef               PROTO((double time, time_t TimeReference, int TimeFormat));
+double        TimeValue             PROTO((time_t time, time_t TimeReference, int TimeFormat));
+int           chk_time              PROTO((char *line));
+time_t        date_to_sec           PROTO((char *date));
+int           dms_to_ddd            PROTO((double *Value, char *string));
+time_t        jd_to_sec             PROTO((double jd));
+time_t        mjd_to_sec            PROTO((double mjd));
+char         *sec_to_date           PROTO((time_t second));
+double        sec_to_jd             PROTO((time_t second));
+double        sec_to_mjd            PROTO((time_t second));
+int           str_to_dtime          PROTO((char *line, double *second));
+int           str_to_radec          PROTO((double *ra, double *dec, char *str1, char *str2));
+int           str_to_time           PROTO((char *line, time_t *second));
+int           hh_hms                PROTO((double hh, int *hr, int *mn, double *sc));
+int           dd_dms                PROTO((double dd, int *dg, int *mn, double *sc));
+int           hms_format            PROTO((char *line, double value));
+int           dms_format            PROTO((char *line, double value));
+int           hh_hm                 PROTO((double hh, int *hr, double *mn));
+
+char         *meade_deg_to_str      PROTO((double deg));
+char         *meade_ra_to_str       PROTO((double deg));
+char         *meade_dec_to_str      PROTO((double deg));
+int           hstgsc_hms_to_deg     PROTO((double *h0, double *h1, double *d0, double *d1, char *string));
+
+# endif
Index: /tags/opihi-2-1/Ohana/src/opihi/include/data.h
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/include/data.h	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/include/data.h	(revision 3338)
@@ -0,0 +1,108 @@
+# include "external.h"
+# include "shell.h"
+# include "dvomath.h"
+# include "convert.h"
+# include "display.h"
+
+# ifndef DATA_H
+# define DATA_H
+
+/* in misc/queues.c */
+void InitQueues ();
+void ListQueues ();
+Queue *FindQueue (char *name);
+Queue *CreateQueue (char *name);
+void PushQueue (Queue *queue, char *line);
+char *PopQueue (Queue *queue);
+
+/* in misc/sort.c */
+void sort (double *value, int N);
+void fsort (float *value, int N);
+void sortpair (double *value1, double *value2, int N);
+void fsortpair (float *X, float *Y, int N);
+void sortthree (float *X, float *Y, float *Z, int N);
+void sort_lists (float *X, float *Y, int *S, int N);
+void dsort_lists (double *X, double *Y, int *S, int N);
+
+/* in misc/fft.c */
+void fft (float *Data, int N, int isign);
+void fftold (float *Data, int N, int isign);
+void fftN (float *data, int *nn, int ndim, int isign);
+int IsBinary (int N);
+void fourn (float *data, int *nn, int ndim, int isign);
+
+/* in misc/gaussj.c */
+int gaussj (double **a, int n, double **b, int m);
+int fgaussj (float **a, int n, float **b, int m);
+
+/* in misc/svdcmp.c */
+int svdcmp (float *a, float *w, float *v, int Nx, int Ny);
+
+/* in misc/spline.c */
+void spline (float *x, float *y, int N, float *y2);
+float splint (float *x, float *y, float *y2, int N, float X);
+
+/* misc/mrqmin.c */
+float mrqcof (float *x, float *y, float *dy, int Npts, 
+	      float *par, int Npar, float **ta, float **tb, 
+	      float (funcs)(float, float *, int, float *));
+
+float mrqmin (float *x, float *y, float *dy, int Npts, 
+	      float *par, int Npar, 
+	      float (funcs)(float, float *, int, float *), int VERBOSE);
+
+float mrqinit (float *x, float *y, float *dy, int Npts, 
+	       float *par, int Npar, 
+	       float (funcs)(float, float *, int, float *), int VERBOSE);
+
+float **mrqcovar (int Npar);
+
+void mrqfree (int Npar);
+
+/* misc/mrq2dmin.c */
+float mrq2dcof (float *x, float *t, float *y, float *dy, int Npts, 
+		float *par, int Npar, float **ta, float **tb, 
+		float (funcs)(float, float, float *, int, float *));
+
+float mrq2dmin (float *x, float *t, float *y, float *dy, int Npts, 
+		float *par, int Npar, 
+		float (funcs)(float, float, float *, int, float *), int VERBOSE);
+
+float mrq2dinit (float *x, float *t, float *y, float *dy, int Npts, 
+		 float *par, int Npar, 
+		 float (funcs)(float, float, float *, int, float *), int VERBOSE);
+
+float mrq2dchi (float *x, float *t, float *y, float *dy, int Npts, 
+		float *par, int Npar, 
+		float (funcs)(float, float, float *, int, float *));
+
+int mrq2dlimits (float *pmin, float *pmax, int Npar);
+
+float **mrq2dcovar (int Npar);
+
+void mrq2dfree (int Npar);
+
+/* misc/powell.c */
+void powell (float *p, int Npar, float (func)() );
+
+/* misc/gaussian.c */
+double gaussian (double x, double mean, double sigma);
+void gauss_init (int Nbin);
+double rnd_gauss (double mean, double sigma);
+
+/* misc/starfuncs.c */
+double get_aperture_stats (Matrix *matrix, int X, int Y, int Npix, int Nborder, double max);
+int set_rough_radii (double Ra, double Ri, double Ro);
+int get_rough_star (float *data, int Nx, int Ny, int x, int y, float *xc, float *yc, float *sx, float *sy, float *sxy, float *zs, float *zp, float *sk);
+
+/* misc/precess.c */
+double BtoJ (double in_epoch);
+double get_epoch (char *in_epoch, char mode);
+
+/* misc/graphtools.c */
+void          SetLimits             PROTO((Vector *xvec, Vector *yvec, Graphdata *graphmode));
+void          ApplyLimits           PROTO((int Xgraph, Graphdata *graphmode, int apply));
+
+int read_table_vectors (int argc, char **argv, char *extname);
+# endif
+
Index: /tags/opihi-2-1/Ohana/src/opihi/include/dimm.h
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/include/dimm.h	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/include/dimm.h	(revision 3338)
@@ -0,0 +1,69 @@
+# include "external.h"
+# include "shell.h"
+# include "dvomath.h"
+# include "convert.h"
+# include "display.h"
+# include "sbig.h"
+
+/* telescope.c */
+double distSky (double r1, double r2, double d1, double d2);
+int getRD (double *r, double *d) ;
+int gotoRD (double r, double d);
+int offset (char *direction, double distance);
+int toffset (char *direction, char *rate, double duration);
+int getXY (double *x, double *y);
+int setRD (double r, double d);
+int setSite (char *sitename, double lon, double lat);
+int setTime (char *lst);
+int getSite (double *lon, double *lat, double *lst);
+int ParkScope();
+int SleepScope();
+int WakeScope();
+
+/* Serial.c */
+int SerialVerbose (int mode);
+int SerialInit (char *port);
+int SerialOpen (char *port);
+int SerialBaudRate (int fdesc, int rate);
+int SerialParity (int fdesc, int parity); 
+int SerialDataBits(int fdesc, int bits); 
+int SerialStopBit(int fdesc, int stpbit); 
+void SerialStop (int fdesc);
+int SerialCommand (char *in, char **out, int wait);
+
+/* camera.c */
+int InitCamera (int port);
+void DumpCameraInfo ();
+void CameraFullSize (int *x, int *y);
+int SetTemperature (double temp);
+double GetTemperature ();
+int DumpCameraStatus ();
+int Exposure (double exptime);
+static int readout_callback (float percent);
+int ReadOut (int x, int y, int dx, int dy, int binning, unsigned short *buffer);
+int OpenShutter ();
+int CloseShutter ();
+
+  /* this image structure stuff is considered for further development */ 
+# if (0)
+/** this Image is incompatible with the DVO Image struct */
+typedef struct {
+
+  /* image data area */
+  int Nx, Ny;
+  char *buffer;
+  int Nbytes;
+
+  /* image metadata */
+  double ccdtemp;
+  double airtemp;
+  double ra, dec, airmass;
+  double exptime;
+  int binning;
+} Image;
+
+/* analysis.c */
+int subtractImage (Image *a, Image *b);
+void statsImage (Image *image, Stats *stats);
+void findStars (Image *image, Stars **stars, int *Nstars, double threshold);
+# endif
Index: /tags/opihi-2-1/Ohana/src/opihi/include/display.h
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/include/display.h	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/include/display.h	(revision 3338)
@@ -0,0 +1,47 @@
+# include "external.h"
+
+# ifndef DISPLAY_H
+# define DISPLAY_H
+
+typedef struct {
+  double xmin, xmax, ymin, ymax;
+  int style, ptype, ltype, etype, ebar, color;
+  double lweight, size;
+  Coords coords;
+  int flipeast, flipnorth;
+} Graphdata;
+
+/*** plotting functions ***/
+int           GetCurrentDevice      PROTO((void));
+int           PrepPlotting          PROTO((int Npts, Graphdata *graphmode));
+int           PlotVector            PROTO((int, float *));
+int           GetGraphData          PROTO((Graphdata *data, int *sock, int *N));
+int           GetGraph              PROTO((Graphdata *data, int *socket, int *N));
+void          InitGraph             PROTO((void));
+int           open_graph            PROTO((int N));
+void          QuitGraph             PROTO((void));
+void          SetGraph              PROTO((Graphdata data));
+void          XGraphDead            PROTO((int input));
+int           GetColor              PROTO((char *name));
+
+/* image (tv) functions */
+int           GetImage              PROTO((int *socket, int *N));
+char         *GetImageName          PROTO((void));
+void          GetImageScale         PROTO((double *zero, double *range));
+void          InitImage             PROTO((void));
+int           open_image            PROTO((int N));
+void          QuitImage             PROTO((void));
+void          SetImageDevice        PROTO((int state));
+void          SetImageName          PROTO((char *name));
+void          SetImageScale         PROTO((double zero, double range));
+void          XImageDead            PROTO((int input));
+int           SelectOverlay         PROTO((char *name, int *number));
+
+/* calling program need to define a function 'get_variable' which
+ * returns the name of the executable for each of KAPA and KII
+ */
+char         *get_variable          PROTO((char *name));
+
+int SendLabel (char *string, int Xgraph, int mode);
+
+# endif
Index: /tags/opihi-2-1/Ohana/src/opihi/include/dvo.h
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/include/dvo.h	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/include/dvo.h	(revision 3338)
@@ -0,0 +1,63 @@
+# include "external.h"
+# include "shell.h"
+# include "dvomath.h"
+# include "convert.h"
+# include "display.h"
+# include "data.h"
+
+# ifndef DVO_H
+# define DVO_H
+
+/* magnitude types */
+enum {MAG_NONE, MAG_INST, MAG_CAT, MAG_SYS, MAG_REL, MAG_CAL, MAG_AVE, MAG_REF};
+
+/* measure params */
+enum {MEAS_ZERO, MEAS_RA, MEAS_DEC, MEAS_MAG, MEAS_dMAG, MEAS_MINST, MEAS_MCAT, 
+      MEAS_MSYS, MEAS_MREL, MEAS_MCAL, MEAS_PHOTCODE, MEAS_TIME, MEAS_dR, MEAS_dD, 
+      MEAS_FWHM, MEAS_DOPHOT, MEAS_XCCD, MEAS_YCCD, MEAS_XMOSAIC, MEAS_YMOSAIC, MEAS_FLAGS, MEAS_EXPTIME, MEAS_AIRMASS};
+
+/* average params */
+enum {AVE_ZERO, AVE_RA, AVE_DEC, AVE_MAG, AVE_REF, AVE_dMAG, AVE_Xm, AVE_Xp, AVE_NMEAS, 
+      AVE_NMISS, AVE_TYPE, AVE_NPHOT, AVE_NCODE, AVE_NCRIT, AVE_FLAG};
+
+typedef struct {
+  char name[64];
+  double RA0, RA1, DEC0, DEC1;
+} RegionFile;
+
+/* aregion, region_list, match_image, LoadImages */
+RegionFile   *find_regions	    PROTO((double Ra, double Dec, double radius, int *Nregions));
+GSCRegion    *get_regions	    PROTO((Image *image, int *Nregions));
+void	      aregion		    PROTO((GSCRegion *region, FILE *f, double ra, double dec, char *path));
+RegionFile   *region_list	    PROTO((char *filename, int *Nregions));
+int	      match_image	    PROTO((Image *image, int Nimage, unsigned int T, short int S));
+Image  	     *LoadImages	    PROTO((int *Nimage));
+void	      image_subset	    PROTO((Image *image, int Nimage, int **Subset, int *Nsubset, Graphdata *graph, int RegionSelect, unsigned long int tzero, double trange, int TimeSelect));
+void	      sort_images	    PROTO((Image *image, int N));
+void	      sortave		    PROTO((Average *ave, int N));
+void	      cprecess		    PROTO((Average *average, int Naverage, double in_epoch, double out_epoch));
+void	      compare		    PROTO((Catalog *catlog1, Catalog *catlog2, Vector *rvec,  Vector *dvec,  Vector *mvec, Vector *drvec, Vector *ddvec, Vector *dmvec, double radius));
+
+/*** photometry functions ***/
+int           SetPhotSelections     PROTO((int *argc, char **argv));
+int           SetImageSelection     PROTO((int mode, Graphdata *graphsky, int state));
+void          FreeImageSelection    PROTO(());
+
+int           InitPhotcodes         PROTO(());
+int           GetPhotcodeInfo       PROTO((char *string, PhotCode **Code, int *Mode));
+
+int           GetAverageParam       PROTO((char *parname));
+int           GetMeasureParam       PROTO((char *parname));
+int           GetMagMode            PROTO((char *string));
+int           SelectMags            PROTO((int Nphot, int Tphot, int Ns, Average *average, Measure *measure, SecFilt *secfilt, int UL));
+void          print_value           PROTO((FILE *f, double value, short int ival));
+int           GetMeasureTypeCode    PROTO((Measure *measure));
+int           DetermineTypeCode     PROTO((Average *average, Measure *measure, int Nphot));
+double        ExtractAverages       PROTO((PhotCode *code, int mode, Average *ave, SecFilt *sec, Measure *meas, int param));
+double       *ExtractMagnitudes     PROTO((PhotCode *code, int mode, Average *ave, SecFilt *sec, Measure *meas, int *n));
+double       *ExtractMeasures       PROTO((PhotCode *code, int mode, Average *ave, SecFilt *sec, Measure *meas, int *nlist, int param));
+double       *ExtractDMag           PROTO((PhotCode **code, int *mode, Average *average, SecFilt *secfilt, Measure *measure, int *nlist));
+double       *ExtractMeasuresDMag   PROTO((PhotCode **code, int *mode, Average *average, SecFilt *secfilt, Measure *measure, int *nlist));
+double       *ExtractMeasuresByDMag PROTO((PhotCode **code, int *mode, int use_first, Average *average, SecFilt *secfilt, Measure *measure, int *nlist, int param));
+
+# endif
Index: /tags/opihi-2-1/Ohana/src/opihi/include/dvo2.h
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/include/dvo2.h	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/include/dvo2.h	(revision 3338)
@@ -0,0 +1,35 @@
+# include "external.h"
+# include "shell.h"
+# include "dvomath.h"
+# include "convert.h"
+# include "display.h"
+# include "data.h"
+
+# ifndef DVO2_H
+# define DVO2_H
+
+typedef struct {
+  float r, d;
+} SkyCoord;
+
+typedef struct {
+  float Rmin, Rmax;
+  float Dmin, Dmax;
+  int   childS, childE, parent;
+  char  depth, child;
+  char  object, image;
+  char  name[24];
+} SkyRegion; /* 48 bytes */ 
+
+SkyRegion *SkyFindPoint (SkyRegion *db, SkyCoord c, int depth);
+SkyRegion **SkyFindLevels (SkyRegion *db, SkyCoord c, int *Nregion);
+SkyRegion **SkyFindArea (SkyRegion *db, SkyCoord c1, SkyCoord c2, int *nlist);
+SkyRegion *SkyFindAreaDB (SkyRegion *db, SkyRegion *ref, SkyCoord c1, SkyCoord c2, int *Nregion);
+SkyRegion *SkyBuildTable (SkyRegion *seed, int Nseed, int level, int depth);
+
+SkyRegion *SkyMakeRegions (int Nlevels, int *nlist);
+SkyRegion *SkyDivideRegions (SkyRegion *parents, int *N);
+SkyRegion *SkyDivideBiggest (SkyRegion *list, int *nlist);
+SkyRegion *SkyDivide (SkyRegion *in);
+
+# endif
Index: /tags/opihi-2-1/Ohana/src/opihi/include/dvomath.h
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/include/dvomath.h	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/include/dvomath.h	(revision 3338)
@@ -0,0 +1,123 @@
+/*** dvomath.h ***/
+
+# ifndef DVOMATH_H
+# define DVOMATH_H
+
+# define NCHARS 256
+
+enum {ANYVECTOR, NEWVECTOR, OLDVECTOR};
+enum {ANYBUFFER, NEWBUFFER, OLDBUFFER};
+
+/*** typedef structs used by math functions ***/
+typedef struct {
+  int   NLINES;
+  int   Nlines;
+  char **lines;
+  char  *name;
+} Queue;
+
+typedef struct {			/* representation of a variable (0-D) */
+  char     *name;
+  char     *value;
+} Variable;
+
+typedef struct {			/* representation of a vector (1-D) */
+  char name[1024];
+  float *elements;
+  int Nelements;
+} Vector;
+
+typedef struct {			/* representation of buffer (image) */
+  char name[1024];
+  char file[1024];
+  Header header;
+  Matrix matrix;
+  int  bitpix, unsign;
+  double bscale, bzero;
+} Buffer;
+
+typedef struct {			/* math stack structure */
+  char   *name;
+  char    type;
+  float  *ptr;
+  Buffer *buffer;
+  Vector *vector;
+  float   Float;
+} StackVar;
+
+/* math functions */
+char         *dvomath               PROTO((int argc, char **argv, int *size, int maxsize));
+char        **isolate_elements      PROTO((int argc, char **argv, int *nstack));
+StackVar     *convert_to_RPN        PROTO((int argc, char **argv, int *nstack));
+int           check_stack           PROTO((StackVar *stack, int Nstack, int validsize));
+int           evaluate_stack        PROTO((StackVar *stack, int *Nstack));
+void          init_stack            PROTO((StackVar *stack));
+void          copy_stack	    PROTO((StackVar *stack1, StackVar *stack2));
+void          move_stack	    PROTO((StackVar *stack1, StackVar *stack2));
+void          clean_stack	    PROTO((StackVar *stack, int Nstack));
+void          delete_stack	    PROTO((StackVar *stack, int Nstack));
+int           VV_binary             PROTO((StackVar *OUT, StackVar *V1, StackVar *V2, char *op));
+int           SV_binary             PROTO((StackVar *OUT, StackVar *V1, StackVar *V2, char *op));
+int           VS_binary             PROTO((StackVar *OUT, StackVar *V1, StackVar *V2, char *op));
+int           MV_binary             PROTO((StackVar *OUT, StackVar *V1, StackVar *V2, char *op));
+int           VM_binary             PROTO((StackVar *OUT, StackVar *V1, StackVar *V2, char *op));
+int           MM_binary             PROTO((StackVar *OUT, StackVar *V1, StackVar *V2, char *op));
+int           MS_binary             PROTO((StackVar *OUT, StackVar *V1, StackVar *V2, char *op));
+int           SM_binary             PROTO((StackVar *OUT, StackVar *V1, StackVar *V2, char *op));
+int           SS_binary             PROTO((StackVar *OUT, StackVar *V1, StackVar *V2, char *op));
+int           WW_binary             PROTO((StackVar *OUT, StackVar *V1, StackVar *V2, char *op));
+int           S_unary               PROTO((StackVar *OUT, StackVar *V1, char *op));
+int           V_unary               PROTO((StackVar *OUT, StackVar *V1, char *op));
+int           M_unary               PROTO((StackVar *OUT, StackVar *V1, char *op));
+
+/* variable handling */
+char         *get_variable          PROTO((char *name));
+char         *get_variable_ptr      PROTO((char *name));
+char         *get_local_variable_ptr PROTO((char *name));
+double        get_double_variable   PROTO((char *name));
+int           DeleteNamedScalar     PROTO((char *name));
+int           IsScalar              PROTO((char *name));
+int           set_variable          PROTO((char *name, double dvalue));
+int           set_int_variable      PROTO((char *name, int ivalue));
+int           set_str_variable      PROTO((char *name, char *value));
+int           set_local_variable    PROTO((char *name, char *value));
+void          InitVariables         PROTO((void));
+void          ListVariables         PROTO((void));
+float         get_variable_default  PROTO((char *name, float dvalue));
+
+/* vector handling */
+Vector       *InitVector            PROTO((void));
+void          InitVectors           PROTO((void));
+int           CopyVector            PROTO((Vector *out, Vector *in));
+int           MoveVector            PROTO((Vector *out, Vector *in));
+int           DeleteVector          PROTO((Vector *vec));
+int           CopyNamedVector       PROTO((char *out, char *in));
+int           MoveNamedVector       PROTO((char *out, char *in));
+int           DeleteNamedVector     PROTO((char *name));
+int           IsVector              PROTO((char *name));
+int           IsVectorPtr           PROTO((Vector *vec));
+int           ListVectors           PROTO((void));
+Vector       *SelectVector          PROTO((char *name, int mode, int verbose));
+
+/* buffer handling */
+Buffer       *InitBuffer            PROTO((void));
+void          InitBuffers           PROTO((void));
+int           CopyBuffer            PROTO((Buffer *out, Buffer *in));
+int           MoveBuffer            PROTO((Buffer *out, Buffer *in));
+int           DeleteBuffer          PROTO((Buffer *buf));
+int           CopyNamedBuffer       PROTO((char *out, char *in));
+int           MoveNamedBuffer       PROTO((char *out, char *in));
+int           DeleteNamedBuffer     PROTO((char *name));
+int           IsBuffer              PROTO((char *name));
+int           IsBufferPtr           PROTO((Buffer *buf));
+int           PrintBuffers          PROTO((int Long));
+int           CreateBuffer          PROTO((Buffer *buf));
+Buffer       *SelectBuffer          PROTO((char *name, int mode, int verbose));
+void          dump_buffers          PROTO((int n));  /* deprecated? */
+int           SelectOverlay         PROTO((char *name, int *number));
+
+/* why are these in here? */
+int           fits_copy_matrix_info (Matrix *matrix1, Matrix *matrix2);
+int           GetTimeFormat         PROTO((time_t *TimeReference, int *TimeFormat));
+
+# endif
Index: /tags/opihi-2-1/Ohana/src/opihi/include/external.h
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/include/external.h	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/include/external.h	(revision 3338)
@@ -0,0 +1,25 @@
+# include <signal.h>
+# include <unistd.h>
+# include <sys/uio.h>
+# include <fcntl.h>
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <sys/un.h>
+# include <sys/time.h>
+# include <time.h>
+# include <errno.h>
+
+# include <ohana.h>
+# include <fitsio.h>
+# include <loneos.h>
+
+/* provide missing external defines */
+# ifdef MISSING_SOCKET_INFO
+#   define F_SETFL         4   
+#   define O_NONBLOCK       0200000  
+#   define AF_UNIX         1          
+#   define SOCK_STREAM     1          
+#   define ENOENT          2 
+# endif
+
+# define strlen(A) ((int)strlen(A))
Index: /tags/opihi-2-1/Ohana/src/opihi/include/hstgsc.h
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/include/hstgsc.h	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/include/hstgsc.h	(revision 3338)
@@ -0,0 +1,24 @@
+
+static 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};
+static 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"};
+
+static 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"};
+
+static 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"};
+
+static 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};
+
+static 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};
Index: /tags/opihi-2-1/Ohana/src/opihi/include/imfit.h
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/include/imfit.h	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/include/imfit.h	(revision 3338)
@@ -0,0 +1,10 @@
+# include "astro.h"
+
+int Npar;
+int Nfpar;
+float *par;
+float *fpar;
+float *sky;
+
+float (*fitfunc)(float, float, float *, int, float *);
+void (*imfit_cleanup)();
Index: /tags/opihi-2-1/Ohana/src/opihi/include/inherent.h
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/include/inherent.h	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/include/inherent.h	(revision 3338)
@@ -0,0 +1,47 @@
+/******* List of the Inherent Commands *********/
+int cd         PROTO((int, char **));
+int echo       PROTO((int, char **));
+int exec_break PROTO((int, char **));
+int exec_continue PROTO((int, char **));
+int help       PROTO((int, char **));
+int input      PROTO((int, char **));
+int list_help  PROTO((int, char **));
+int list_vars  PROTO((int, char **));
+int macro      PROTO((int, char **));
+int output     PROTO((int, char **));
+int pwd        PROTO((int, char **));
+int quit       PROTO((int, char **));
+int run_while  PROTO((int, char **));
+int run_for    PROTO((int, char **));
+int run_if     PROTO((int, char **));
+int list       PROTO((int, char **));
+int scan       PROTO((int, char **));
+int shell      PROTO((int, char **));
+int wait       PROTO((int, char **));
+int which      PROTO((int, char **));
+
+/** mapping of the command names to command functions **/
+static Command inherent[] = {  
+  {"cd",      cd,                 "change directory"},
+  {"echo",    echo,               "type this line *"},
+  {"break",   exec_break,         "escape from function *"},
+  {"continue",exec_continue,      "next loop iteration"},
+  {"help",    help,               "get help on a function *"},
+  {"input",   input,              "read command lines from a file *"},
+  {"?",       list_help,          "list commands *"},
+  {"??",      list_vars,          "list variables *"},
+  {"list",    list,               "get variable list"},
+  {"macro",   macro,              "deal with the macros *"}, 
+  {"output",  output,             "redirect output to file"},
+  {"pwd",     pwd,                "print current working directory"},
+  {"exit",    quit,               "exit program *"}, 
+  {"quit",    quit,               "exit program *"},
+  {"while",   run_while,          "while loop"}, 
+  {"for",     run_for,            "for loop"}, 
+  {"if",      run_if,             "logical cases *"}, 
+  {"scan",    scan,               "scan line from keyboard or file to variable *"},
+  {"!",       shell,              "system call"},
+  {"exec",    shell,              "system call"},
+  {"wait",    wait,               "wait until return is typed"},
+  {"which",   which,              "show command *"}
+};
Index: /tags/opihi-2-1/Ohana/src/opihi/include/macro.h
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/include/macro.h	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/include/macro.h	(revision 3338)
@@ -0,0 +1,10 @@
+static Command in_macro[] = {
+  {"create", macro_create, "create a macro *"},
+  {"delete", macro_delete, "delete a macro *"},
+  {"list",   macro_list_f, "list a macro *"},
+  {"edit",   macro_edit,   "edit a macro <not working yet!> *"},
+  {"read",   macro_read,   "read a macro from a file <not working yet!> *"},
+  {"write",  macro_write,  "write a macro to a file <not working yet!> *"}
+};
+
+/*** need to encapsulate the macro command lookup ***/
Index: /tags/opihi-2-1/Ohana/src/opihi/include/mana.h
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/include/mana.h	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/include/mana.h	(revision 3338)
@@ -0,0 +1,7 @@
+# include "data.h"
+
+# ifndef MANA_H
+
+int *findrowpeaks (float *row, int Nrow, float threshold, int *npeaks);
+
+# endif
Index: /tags/opihi-2-1/Ohana/src/opihi/include/opihi.h
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/include/opihi.h	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/include/opihi.h	(revision 3338)
@@ -0,0 +1,5 @@
+# include "external.h"
+# include "shell.h"
+# include "dvomath.h"
+# include "convert.h"
+# include "display.h"
Index: /tags/opihi-2-1/Ohana/src/opihi/include/pclient.h
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/include/pclient.h	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/include/pclient.h	(revision 3338)
@@ -0,0 +1,77 @@
+# include "external.h"
+# include "shell.h"
+# include "dvomath.h"
+# include "convert.h"
+# include "display.h"
+# include <sys/types.h>
+# include <sys/wait.h>
+
+/** pclient global data **/
+
+/** child status values **/
+enum {
+  PCLIENT_NONE,
+  PCLIENT_BUSY,  
+  PCLIENT_EXIT,
+  PCLIENT_CRASH,
+};
+
+int ChildPID;				/** current child PID **/
+int ChildStatus;			/** current status of child **/
+int ChildExitStatus;			/** recent exit status of child **/
+
+/** child may be in the following states:
+    
+PCLIENT_NONE
+PCLIENT_BUSY
+PCLIENT_EXIT
+PCLIENT_CRASH
+
+allowed transitions:
+
+PCLIENT_NONE  ->    PCLIENT_BUSY  (start a job)
+
+PCLIENT_BUSY  ->    PCLIENT_EXIT  (job complete)
+PCLIENT_BUSY  ->    PCLIENT_CRASH (job crashed)
+
+PCLIENT_EXIT  ->    PCLIENT_NONE  (cleanup)
+PCLIENT_CRASH ->    PCLIENT_NONE  (cleanup)
+
+**/
+
+/** file descriptors for child I/O **/
+int child_stdin_fd[2];
+int child_stdout_fd[2];
+int child_stderr_fd[2];
+
+typedef struct {
+  char *buffer;
+  int   Nalloc;
+  int   Nreset;
+  int   Nblock;
+  int   Nbuffer;
+} IOBuffer;
+
+/** buffers for I/O storage **/
+IOBuffer child_stdout;
+IOBuffer child_stderr;
+
+/** IOBuffers allow the following operations **/
+
+/* create a new, empty IOBuffer with Nalloc free space */
+int  InitIOBuffer (IOBuffer *buffer, int Nalloc);
+
+/* read from the file descriptor into IOBuffer, expanding as needed */
+int  ReadtoIOBuffer (IOBuffer *buffer, int fd);
+
+/* empty the current IOBuffer, realloc to a minimal size */
+int  FlushIOBuffer (IOBuffer *buffer);
+
+/* free memory associated with IOBuffer */
+void FreeIOBuffer (IOBuffer *buffer);
+
+int InitChild ();
+int CheckChild ();
+void CheckChildStatus ();
+
+# define DTIME(A,B) ((A.tv_sec - B.tv_sec) + 1e-6*(A.tv_usec - B.tv_usec))
Index: /tags/opihi-2-1/Ohana/src/opihi/include/pcontrol.h
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/include/pcontrol.h	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/include/pcontrol.h	(revision 3338)
@@ -0,0 +1,165 @@
+# include "external.h"
+# include "shell.h"
+# include "dvomath.h"
+# include "convert.h"
+# include "display.h"
+# include <sys/types.h>
+# include <sys/wait.h>
+
+typedef struct timeval Ptime;
+typedef unsigned long long IDtype;
+
+/** job status values **/
+typedef enum {
+  PCONTROL_JOB_PENDING,
+  PCONTROL_JOB_BUSY,  
+  PCONTROL_JOB_EXIT,
+  PCONTROL_JOB_CRASH,
+  PCONTROL_JOB_HUNG,  
+  PCONTROL_JOB_DONE,  
+} JobStat;
+
+/** job status values **/
+typedef enum {
+  PCONTROL_JOB_ANYHOST,
+  PCONTROL_JOB_WANTHOST,
+  PCONTROL_JOB_NEEDHOST,
+} JobMode;
+
+/** host status values **/
+typedef enum {
+  PCONTROL_HOST_IDLE,
+  PCONTROL_HOST_BUSY,  
+  PCONTROL_HOST_DOWN,
+  PCONTROL_HOST_DONE,
+  PCONTROL_HOST_OFF,
+} HostStat;
+
+/* stack special positions */
+typedef enum {
+  STACK_TOP = 0,
+  STACK_BOTTOM = -1,
+} StackWhere;
+
+typedef enum {
+  PCLIENT_HUNG = -1,
+  PCLIENT_DOWN = 0,
+  PCLIENT_GOOD = 1,
+} PclientStat;
+
+typedef struct {
+  char *buffer;
+  int   Nalloc;
+  int   Nreset;
+  int   Nblock;
+  int   Nbuffer;
+} IOBuffer;
+
+typedef struct {
+  char *buffer;
+  int   Nalloc;
+  int   Nmaxread;
+  int   Nextra;
+  int   Nlast;
+  int   Nbuffer;
+} Fifo;
+
+/* data to define a job */
+typedef struct {
+  int          argc; 
+  char       **argv;
+  char        *hostname;
+  int          exit_status;
+  int          Reset;
+  JobMode      mode;
+  JobStat      state;
+  JobStat      stack;
+  IOBuffer     stdout;
+  IOBuffer     stderr;
+  Ptime        start;
+  Ptime        accum;
+  Ptime        timer;
+  struct Host *host;
+  int          pid;
+  IDtype       JobID;
+} Job;
+
+/* data to define a host machine */
+typedef struct {
+  char       *hostname;
+  int         stdin;
+  int         stdout;
+  int         stderr;
+  int         markoff;
+  int         pid;
+  HostStat    stack;
+  Ptime       start;
+  Ptime       accum;
+  Ptime       timer;
+  IDtype      HostID;
+  struct Job *job;
+} Host;
+
+typedef struct {
+  void **object;
+  int    Nobject;
+  int    NOBJECT;
+} Stack;
+
+/* these should be loaded from ConfigInit or from opihi variables */
+static char *CONNECT;  /* connection method (ssh, rsh, etc) */
+static char *PCLIENT;  /* shell on remote host (eg, pclient) */
+# define PCLIENT_PROMPT "pclient:"
+
+# define FREE(X) if (X != NULL) { free (X); }
+# define CLOSE(FD) { if (FD) close (FD); FD = 0; }
+
+/** IOBuffers allow the following operations (see pclient.h) **/
+int  InitIOBuffer (IOBuffer *buffer, int Nalloc);
+int  ReadtoIOBuffer (IOBuffer *buffer, int fd);
+int  FlushIOBuffer (IOBuffer *buffer);
+void FreeIOBuffer (IOBuffer *buffer);
+
+void *GetStack (Stack *stack, int where);
+int PutStack (Stack *stack, int where, void *object);
+Stack *InitStack ();
+Stack *GetHostStack (int StackID);
+int PutHost (Host *host, int StackID, int where);
+Host *GetHost (int StackID, int where);
+int FindHost (IDtype HostID, int StackID);
+int FindNamedHost (char *name, int StackID);
+void AddHost (char *hostname);
+void DownHost (Host *host);
+void OffHost (Host *host);
+void DelHost (Host *host);
+int CheckSystem ();
+int CheckBusyJobs ();
+int CheckDoneJobs ();
+int CheckDoneHosts ();
+int CheckLiveHosts ();
+int CheckDownHosts ();
+int CheckIdleHosts ();
+int CheckIdleHost (Host *host);
+void InitIDs ();
+IDtype NextJobID ();
+IDtype NextHostID ();
+void PrintID (FILE *f, IDtype ID);
+int CheckBusyJob (Job *job);
+int StartHost (Host *host);
+int CheckDoneHost (Host *host);
+int CheckDoneJob (Job *job);
+int GetJobOutput (Job *job, char *channel);
+int ResetJob (Job *job);
+int PclientCommand (Host *host, char *command, char *response, IOBuffer *buffer);
+int rconnect (char *command, char *hostname, char *shell, int *stdio);
+int CheckHost (Host *host);
+char *memstr (char *m1, char *m2, int n);
+Stack *GetJobStack (int StackID);
+int PutJob (Job *job, int StackID, int where);
+Job *GetJob (int StackID, int where);
+int FindJob (IDtype JobID, int StackID);
+IDtype AddJob (char *hostname, JobMode mode, int timeout, int argc, char **argv);
+void KillJob (Job *job);
+void DelJob (Job *job);
+Host *UnlinkJobAndHost (Job *job);
+void LinkJobAndHost (Job *job, Host *host);
Index: /tags/opihi-2-1/Ohana/src/opihi/include/scheduler.h
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/include/scheduler.h	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/include/scheduler.h	(revision 3338)
@@ -0,0 +1,66 @@
+
+enum {JOB_BUSY, JOB_EXIT, JOB_CRASH};
+
+/* a task is a description of the wrapping of a job */
+typedef struct {
+  Macro  *exec;				/* name is 'exec' */
+  Macro  *crash;			/* name is 'crash' */
+  Macro  *timeout;
+  Macro  *def;
+
+  int     NEXIT;
+  int     Nexit;
+  Macro **exit;				/* name is exit status */
+
+  int     argc;
+  char  **argv;
+  char   *host;
+
+  char   *name;
+
+  float   poll_period;
+  float   exec_period;
+  float   timeout_period;
+
+  struct timeval last;
+} Task;
+
+typedef struct {
+  int JobID;				/* internal ID for job */
+  int PID;				/* external ID for job */
+
+  Task task;
+
+  struct timeval last;
+  struct timeval start;
+  int state;
+  int exit_status;
+} Job;
+
+
+/* scheduler prototypes */
+void InitTasks ();
+void ListTasks ();
+Task *FindTask (char *name);
+Task *CreateTask (char *name);
+void SetCurrentTask (char *name);
+char *GetCurrentTask ();
+int DeleteTask (Task *task);
+Task *NextTask ();
+int TaskHash (char *input);
+int ShowTask (char *name);
+
+Job *NextJob ();
+void InitJobs ();
+int NextJobID ();
+void ListJobs ();
+Job *FindJob (int JobID);
+Job *CreateJob (Task *task);
+void SetCurrentJob (char *name);
+char *GetCurrentJob ();
+int SubmitJob (Job *job);
+int CheckJob (Job *job);
+int DeleteJob (Job *job);
+void FreeJob (Job *job);
+void SetTaskTimer (struct timeval *timer);
+double GetTaskTimer (struct timeval start);
Index: /tags/opihi-2-1/Ohana/src/opihi/include/shell.h
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/include/shell.h	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/include/shell.h	(revision 3338)
@@ -0,0 +1,106 @@
+/*** shell.h ***/
+
+# ifndef SHELL_H
+# define SHELL_H
+
+# define ISVAR(a) (isalnum (a) || (a == ':') || (a == '_'))
+# define ISWORD(a,q) ((q) ? (a != '"') : (isalnum(a) || (a == '/') || (a == '.') || (a == '_') || (a == '-')))
+# define ISNUM(c) (isdigit(c) || (c == '-') || (c == '.'))
+
+/*** typedef structs used by shell functions ***/
+typedef struct {			/* basic opihi command structure */
+  char     *name;
+  Function *func;    
+  char     *help;
+} Command;
+
+typedef struct {			/* a macro (collection of commands) */
+  char   *name;
+  char  **line;
+  int     Nlines;
+} Macro;
+
+typedef struct {			/* a list (macro/loop currently being executed) */
+  char **line;
+  int    n;
+  int    Nlines;
+} List;
+
+/*** globals used to track the shell language concepts  ***/
+List         *lists;			/* variable to store the list of all lists */
+int          Nlists;			/* number of currently available lists */
+
+int 	     interrupt;			/* true if C-C has been pressed */
+int 	     auto_break;		/* if true, zero exit status forces macros to escape */
+int 	     loop_break;		/* set to true when break is called */
+int 	     loop_continue;		/* set to true when continue is called */
+int          is_script;                 /* being run within a shell script */
+
+/*** basic opihi shell functions ***/
+void          initialize            	PROTO((int argc, char **argv));
+void          startup               	PROTO((int argc, char **argv));
+char        **multicommand          	PROTO((char *line, int *nlist));
+int           command               	PROTO((char *, char **));
+char         *expand_vars           	PROTO((char *line));
+char         *expand_vectors        	PROTO((char *line));
+char         *parse                 	PROTO((char *line));
+char        **parse_commands        	PROTO((char *, int *));
+void          welcome                   PROTO(());
+
+int           is_for_loop           	PROTO((char *line));
+int           is_if_block           	PROTO((char *line));
+int           is_list               	PROTO((char *line));
+int           is_loop               	PROTO((char *line));
+int           is_macro_create       	PROTO((char *line));
+
+void          InitCommands              PROTO(());
+void          AddCommand                PROTO((Command *new));
+int           DeleteCommand             PROTO((Command *command));
+Command      *MatchCommand              PROTO((char *name, int VERBOSE, int EXACT));
+void          sort_commands             PROTO((int *seq));
+
+void          SetCurrentMacroData	PROTO((char *name, int depth));
+Macro        *NewMacro			PROTO((char *name));
+int           DeleteMacro		PROTO((Macro *macro));
+Macro        *MatchMacro		PROTO((char *name, int VERBOSE, int EXACT));
+void          InitMacros                PROTO((void));
+char         *GetMacroName              PROTO((void));
+int           GetMacroDepth             PROTO((void));
+
+int           exec_loop                 PROTO((Macro *loop));
+char         *get_next_listentry    	PROTO((int ThisList));
+char         *remove_listentry      	PROTO((int current));
+int           ConfigInit            	PROTO((int *argc, char **argv));
+char         *VarConfig             	PROTO((char *keyword, char *mode, void *ptr));
+FILE         *GetOutfile            	PROTO((void));
+void          InitOutfile           	PROTO((void));
+
+int           push_error                PROTO((char *line));
+int           print_error               PROTO((void));
+void          handle_interrupt      	PROTO((int));
+char        **command_completer     	PROTO((const char *, int, int));
+char         *command_generator     	PROTO((const char *text, int state));
+char        **completion_matches    	PROTO((char *, rl_compentry_func_t *));
+void          print_commands            PROTO((FILE *f));
+void          InitCommands              PROTO((void));
+
+/* command line parsing */
+char         *thisword              	PROTO((char *));
+char         *nextword              	PROTO((char *));
+char         *lastword              	PROTO((char *, char *));
+char         *thisvar               	PROTO((char *));
+char         *aftervar              	PROTO((char *));
+char         *lastvar               	PROTO((char *, char *));
+char         *thiscomm              	PROTO((char *));
+char         *nextcomm              	PROTO((char *));
+
+/* macro functions (mapped to commands) */
+int 	      macro_create 		PROTO((int, char **)); 
+int 	      macro_delete 		PROTO((int, char **)); 
+int 	      macro_edit   		PROTO((int, char **));
+int 	      macro_exec   		PROTO((int, char **));
+int 	      macro_list_f 		PROTO((int, char **));  /* "macro_list" is a readline func */
+int 	      macro_read   		PROTO((int, char **));
+int 	      macro_write  		PROTO((int, char **));
+
+# endif
Index: /tags/opihi-2-1/Ohana/src/opihi/include/user.h
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/include/user.h	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/include/user.h	(revision 3338)
@@ -0,0 +1,260 @@
+int abszero         PROTO((int, char **));
+int applyfit        PROTO((int, char **));
+int applyfit2d      PROTO((int, char **));
+int badimages       PROTO((int, char **));
+int box             PROTO((int, char **));
+int calextract      PROTO((int, char **));
+int calmextract     PROTO((int, char **));
+int cals            PROTO((int, char **));
+int catlog          PROTO((int, char **));
+int ccd             PROTO((int, char **));
+int ccdextract      PROTO((int, char **));
+int center          PROTO((int, char **));
+int cgrid           PROTO((int, char **));
+int clear           PROTO((int, char **));
+int cmatch          PROTO((int, char **));
+int cmd             PROTO((int, char **));
+int cmdextract      PROTO((int, char **));
+int cmpread         PROTO((int, char **));
+int concat          PROTO((int, char **));
+int contour         PROTO((int, char **));
+int cplot           PROTO((int, char **));
+int create          PROTO((int, char **));
+int csystem         PROTO((int, char **));
+int ctimes          PROTO((int, char **));
+int cursor          PROTO((int, char **));
+int czplot          PROTO((int, char **));
+int datafile        PROTO((int, char **));
+int date            PROTO((int, char **));
+int ddmagextract    PROTO((int, char **));
+int ddmags          PROTO((int, char **));
+int delete          PROTO((int, char **));
+int device          PROTO((int, char **));
+int dmagaves        PROTO((int, char **));
+int dmagextract     PROTO((int, char **));
+int dmagmeas        PROTO((int, char **));
+int dmags           PROTO((int, char **));
+int dmt             PROTO((int, char **));
+int dumpmags        PROTO((int, char **));
+int elixir          PROTO((int, char **));
+int extract         PROTO((int, char **));
+int file            PROTO((int, char **));
+int fit             PROTO((int, char **));
+int fit2d           PROTO((int, char **));
+int gaussjordan     PROTO((int, char **));
+int gcat            PROTO((int, char **));
+int gimages         PROTO((int, char **));
+int grid            PROTO((int, char **));
+int gstar           PROTO((int, char **));
+int gtypes          PROTO((int, char **));
+int histogram       PROTO((int, char **));
+int images          PROTO((int, char **));
+int imbox           PROTO((int, char **));
+int imdata          PROTO((int, char **));
+int imdense         PROTO((int, char **)); 
+int imextract       PROTO((int, char **));
+int imlist          PROTO((int, char **));
+int imphot          PROTO((int, char **));
+int imrough         PROTO((int, char **));
+int imsearch        PROTO((int, char **));
+int imstats         PROTO((int, char **));
+int interpolate     PROTO((int, char **));
+int jpeg            PROTO((int, char **));
+int labels          PROTO((int, char **));
+int lcat            PROTO((int, char **));
+int lcurve          PROTO((int, char **));
+int limits          PROTO((int, char **));
+int list_buffers    PROTO((int, char **));
+int list_vectors    PROTO((int, char **));
+int mcreate         PROTO((int, char **));
+int mextract        PROTO((int, char **));
+int mget            PROTO((int, char **));
+int mset            PROTO((int, char **));
+int pcat            PROTO((int, char **));
+int photcodes       PROTO((int, char **));
+int photresid       PROTO((int, char **));
+int plot            PROTO((int, char **));
+int pmeasure        PROTO((int, char **));
+int precess         PROTO((int, char **));
+int print           PROTO((int, char **));
+int procks          PROTO((int, char **));
+int ps              PROTO((int, char **));
+int rd              PROTO((int, char **));
+int read_vectors    PROTO((int, char **));
+int region          PROTO((int, char **));
+int resid           PROTO((int, char **));
+int resize          PROTO((int, char **));
+int section         PROTO((int, char **));
+int set             PROTO((int, char **));
+int simage          PROTO((int, char **));
+int sort_vectors    PROTO((int, char **));
+int sprintf_opihi   PROTO((int, char **));
+int stats           PROTO((int, char **));
+int style           PROTO((int, char **));
+int subpix          PROTO((int, char **));
+int subraster       PROTO((int, char **));
+int subset          PROTO((int, char **));
+int textline        PROTO((int, char **));
+int tv              PROTO((int, char **));
+int uniq            PROTO((int, char **));
+int vectobuf        PROTO((int, char **));
+int vstat           PROTO((int, char **));
+int wd              PROTO((int, char **));
+int write_vectors   PROTO((int, char **));
+int zap             PROTO((int, char **));
+int zeropts         PROTO((int, char **));
+int zplot           PROTO((int, char **));
+
+static Command user[] = {  
+  {"abszero", 	   abszero,       "find filter zeropts"},
+  {"applyfit",     applyfit,      "apply fit to new vector"},
+  {"applyfit2d",   applyfit2d,    "apply 2-d fit to new vector"},
+  {"badimages",    badimages,     "look for images with anomalous astrometry"},
+  {"badimages",    badimages,     "look for images with anomalous astrometry"},
+  {"box",     	   box,           "draw a box on the plot"},
+  {"calextract",   calextract,    "extract dmags"},
+  {"calextract",   calextract,    "extract dmags"},
+  {"calmextract",  calmextract,   "extract dmags"},
+  {"cals",    	   cals,          "plot calibration data"},
+  {"catalog", 	   catlog,        "plot catalog stars"},
+  {"catalog", 	   catlog,        "plot catalog stars"},
+  {"ccd",     	   ccd,           "plot color-color diagram"},
+  {"ccd",     	   ccd,           "plot color-color diagram"},
+  {"ccdextract",   ccdextract,    "extract star coords from color-color diagram"},
+  {"center",       center,        "center image on coords"},
+  {"center",       center,        "center image on coords"},
+  {"cgrid",   	   cgrid,         "plot sky coordinate grid"},
+  {"cgrid",   	   cgrid,         "plot sky coordinate grid"},
+  {"clear",   	   clear,         "erase plot"},
+  {"cmatch",  	   cmatch,        "match two catalogs"},
+  {"cmatch",  	   cmatch,        "match two catalogs"},
+  {"cmd",     	   cmd,           "plot cmd of stars in current region"},
+  {"cmd",     	   cmd,           "plot cmd of stars in current region"},
+  {"cmdextract",   cmdextract,    "extract stars based on cmd regions"},
+  {"cmpread",      cmpread,       "read data from cmp format files"},
+  {"cmpread",      cmpread,       "read data from cmp format files"},
+  {"concat",  	   concat,        "reduce vector dimension"},
+  {"contour", 	   contour,       "create contour from image"},
+  {"cplot",   	   cplot,         "plot vectors in sky coordinates"},
+  {"cplot",   	   cplot,         "plot vectors in sky coordinates"},
+  {"create",  	   create,        "create a new vector"},
+  {"csystem", 	   csystem,       "convert between coordinate systems"},
+  {"csystem", 	   csystem,       "convert between coordinate systems"},
+  {"ctimes",  	   ctimes,        "convert between time formats"},
+  {"ctimes",  	   ctimes,        "convert between time formats"},
+  {"cursor",  	   cursor,        "get coords from cursor"},
+  {"czplot",  	   czplot,        "plot scaled vectors in sky coordinates"},
+  {"czplot",  	   czplot,        "plot scaled vectors in sky coordinates"},
+  {"datafile",     datafile,      "define file to read vectors"},
+  {"date",    	   date,          "get current date"},
+  {"ddmagextr",    ddmagextract,  "plot magnitude differences"},
+  {"ddmags",       ddmags,        "plot magnitude differences"},
+  {"ddmags",       ddmags,        "plot magnitude differences"},
+  {"delete",  	   delete,        "delete vectors or matrices"},
+  {"device",  	   device,        "set / get current graphics device"},
+  {"dmagaves",     dmagaves,      "plot differential magnitudes between filters"},
+  {"dmagextract",  dmagextract,   "extract stars based on differential magnitudes between filters"},
+  {"dmagmeas",     dmagmeas,      "plot differential magnitudes between filters"},
+  {"dmags",   	   dmags,         "plot differential magnitudes between filters"},
+  {"dmags",   	   dmags,         "plot differential magnitudes between filters"},
+  {"dmt",          dmt,           "plot mag scatter"},
+  {"dmt",          dmt,           "plot mag scatter"},
+  {"dumpmags",     dumpmags,      "custom dB dumping thingy"},
+  {"dumpmags",     dumpmags,      "custom dB dumping thingy"},
+  {"elixir",       elixir,        "get status info from elixir"},
+  {"elixir",       elixir,        "get status info from elixir"},
+  {"extract", 	   extract,       "extract vectors from catalogs"},
+  {"file",    	   file,          "test for a file"},
+  {"fit",     	   fit,           "fit polynomial to vector pair"},
+  {"fit2d",        fit2d,         "fit 2-d polynomial to vector triplet"},
+  {"gaussj",  	   gaussjordan,   "solve Ax = B (N-D)"},
+  {"gcat",         gcat,          "get catalog at location"},
+  {"gcat",         gcat,          "get catalog at location"},
+  {"gimages",      gimages,       "get images at location"},
+  {"gimages",      gimages,       "get images at location"},
+  {"grid",    	   grid,          "plot cartesian grid"},
+  {"gstar",   	   gstar,         "get star statistics"},
+  {"gstar",   	   gstar,         "get star statistics"},
+  {"gtypes",       gtypes,        "get type fractions"},
+  {"gtypes",       gtypes,        "get type fractions"},
+  {"histogram",    histogram,     "generate histogram from vector"},
+  {"images",  	   images,        "plot image boxes"},
+  {"images",  	   images,        "plot image boxes"},
+  {"imbox",   	   imbox,         "plot expected image box"},
+  {"imbox",   	   imbox,         "plot expected image box"},
+  {"imdata",  	   imdata,        "extract data for specific images"},
+  {"imdata",  	   imdata,        "extract data for specific images"},
+  {"imdense", 	   imdense,       "image density plot"},
+  {"imdense", 	   imdense,       "image density plot"},
+  {"imextract",    imextract,     "extract vectors from catalogs"},
+  {"imextract",    imextract,     "extract vectors from catalogs"},
+  {"imlist",  	   imlist,        "list image info"},
+  {"imlist",  	   imlist,        "list image info"},
+  {"imphot",  	   imphot,        "image photometry info"},
+  {"imphot",  	   imphot,        "image photometry info"},
+  {"imrough",      imrough,       "get info from imruf database"},
+  {"imrough",      imrough,       "get info from imruf database"},
+  {"imsearch",     imsearch,      "get info from imreg database"},
+  {"imsearch",     imsearch,      "get info from imreg database"},
+  {"imstats", 	   imstats,       "plot image statistics"},
+  {"imstats", 	   imstats,       "plot image statistics"},
+  {"interpolate",  interpolate,   "interpolate between vector pairs"},
+  {"jpeg",         jpeg,          "write text line on graph"},
+  {"labels",  	   labels,        "define labels for plot"},
+  {"lcat",    	   lcat,          "list catalogs in region"},
+  {"lcat",    	   lcat,          "list catalogs in region"},
+  {"lcurve",  	   lcurve,        "plot lightcurve for a star"},
+  {"lcurve",  	   lcurve,        "plot lightcurve for a star"},
+  {"limits",  	   limits,        "define plot limits"},
+  {"buffers",      list_buffers,  "list the currently allocated buffers"},
+  {"vectors", 	   list_vectors,  "list vectors"},
+  {"local",  	   local,         "define local variables"},
+  {"mcreate", 	   mcreate,       "create a matrix"},
+  {"mextract",	   mextract,      "extract vectors from catalogs"},
+  {"mextract",	   mextract,      "extract vectors from catalogs"},
+  {"mget",    	   mget,          "extract a vector from a matrix"},
+  {"mset",    	   mset,          "insert a vector in a matrix"},
+  {"pcat",    	   pcat,          "plot catalog boundaries"},
+  {"pcat",    	   pcat,          "plot catalog boundaries"},
+  {"photcodes",    photcodes,     "list photometry codes"},
+  {"photcodes",    photcodes,     "list photometry codes"},
+  {"photresid",    photresid,     "plot photometry residuals"},
+  {"plot",    	   plot,          "plot a pair of vectors"},
+  {"pmeasure",	   pmeasure,      "plot individual measurements"},
+  {"pmeasure",	   pmeasure,      "plot individual measurements"},
+  {"precess", 	   precess,       "precess coordinates"},
+  {"precess", 	   precess,       "precess coordinates"},
+  {"print",   	   print,         "write vectors to file"},
+  {"print",   	   print,         "write vectors to file"},
+  {"procks",  	   procks,        "plot rocks"},
+  {"procks",  	   procks,        "plot rocks"},
+  {"ps",      	   ps,            "define labels for plot"},
+  {"rd",           rd,            "load fits image"},
+  {"read",         read_vectors,  "read vectors from datafile"},
+  {"region",  	   region,        "define sky region for plot"},
+  {"region",  	   region,        "define sky region for plot"},
+  {"resid",   	   resid,         "plot residuals"},
+  {"resize",  	   resize,        "set graphics/image window size"},
+  {"section", 	   section,       "define section of graph"},
+  {"set",     	   set,           "vector math"},
+  {"simage",  	   simage,        "plot stars in an image"},
+  {"simage",  	   simage,        "plot stars in an image"},
+  {"sort",    	   sort_vectors,  "sort list of vectors"},
+  {"sprintf", 	   sprintf_opihi, "formated print to variable"},
+  {"stats",   	   stats,         "give statistics on a portion of a buffer"},
+  {"style",   	   style,         "set the style for graph plots"},
+  {"subpix",  	   subpix,        "get subpixel positions"},
+  {"subpix",  	   subpix,        "get subpixel positions"},
+  {"subraster",    subraster,     "subraster of fits image"},
+  {"subset",  	   subset,        "expand vector dimension"},
+  {"textline",     textline,      "write text line on graph"},
+  {"tv",      	   tv,            "display an image on the Kii window"},
+  {"uniq",    	   uniq,          "create a uniq vector subset from a vector"},
+  {"vectobuf",     vectobuf,      "convert vector triplet to buffer"},
+  {"vstat",        vstat,         "get info from imreg database"},
+  {"wd",      	   wd,            "write an image to a file"},
+  {"write",   	   write_vectors, "write vectors to datafile"},
+  {"zap",     	   zap,           "delete pixels"},
+  {"zeropts", 	   zeropts,       "show filter zeropts"},
+  {"zplot",   	   zplot,         "plot x y with size scaled by z"},
+}; 
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.data/Makefile
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.data/Makefile	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.data/Makefile	(revision 3338)
@@ -0,0 +1,93 @@
+include ../../../Configure
+
+HOME    =       $(ROOT)/src/opihi.v2
+BIN     =       $(HOME)/bin
+LIB     =       $(HOME)/lib
+INC     =       $(HOME)/include
+SDIR    =       $(HOME)/lib.data
+#
+DESTBIN =       $(LBIN)
+DESTLIB =       $(LLIB)
+DESTINC =       $(LINC)
+DESTMAN =       $(LMAN)
+HELP    =       $(HOME)/help
+#  
+INCS    =       -I$(INC) -I$(LINC) -I$(XINC)
+LFLAGS  =       -L$(LLIB) -L$(LIB)
+LIBS    =       -lFITS -lsocket -lnsl -lreadline -ltermcap -lohana -lm
+CFLAGS  =       $(INCS)
+CCFLAGS =       $(LIBS) 
+
+# general numerical functions (libdata) #####################
+libdata = \
+$(SDIR)/convert.$(ARCH).o               \
+$(SDIR)/sort.$(ARCH).o                  \
+$(SDIR)/fft.$(ARCH).o			\
+$(SDIR)/gaussj.$(ARCH).o		\
+$(SDIR)/svdcmp.$(ARCH).o		\
+$(SDIR)/spline.$(ARCH).o		\
+$(SDIR)/mrqmin.$(ARCH).o		\
+$(SDIR)/mrq2dmin.$(ARCH).o		\
+$(SDIR)/precess.$(ARCH).o		\
+$(SDIR)/starfuncs.$(ARCH).o		\
+$(SDIR)/powell.$(ARCH).o		\
+$(SDIR)/gaussian.$(ARCH).o		\
+$(SDIR)/graphtools.$(ARCH).o            \
+$(SDIR)/open_graph.$(ARCH).o            \
+$(SDIR)/open_image.$(ARCH).o            \
+$(SDIR)/PlotVectors.$(ARCH).o
+
+libdata:    $(DESTLIB)/libdata.a 
+
+$(LIB)/libdata.$(ARCH).a:   	$(libdata)
+
+# utilities #################################################
+$(BIN)/%.$(ARCH):
+	@if [ ! -d $(BIN) ]; then mkdir -p $(BIN); fi
+	$(CC) $^ -o $@ $(LFLAGS) $(LIBS)
+	@echo "compiled $*"
+	@echo ""
+
+$(DESTBIN)/%: $(BIN)/%.$(ARCH) 
+	@if [ ! -d $(DESTBIN) ]; then mkdir -p $(DESTBIN); fi
+	rm -f $(DESTBIN)/$*
+	cp $(BIN)/$*.$(ARCH) $(DESTBIN)/$*
+	@echo "installed $*"
+	@echo ""
+
+$(LIB)/%.$(ARCH).a:
+	@if [ ! -d $(LIB) ]; then mkdir -p $(LIB); fi
+	rm -f $@
+	ar rcv $@ $^ 
+	$(RANLIB) $@
+	@echo "compiled library $*"
+	@echo ""
+
+$(DESTLIB)/%.a: $(LIB)/%.$(ARCH).a
+	@if [ ! -d $(DESTLIB) ]; then mkdir -p $(DESTLIB); fi
+	@echo ""
+	rm -f $@
+	cp $^ $@
+
+lib%.clean:
+	rm -f $(LIB)/lib$*.$(ARCH).a
+	rm -f $($*)
+	@echo ""
+
+%.clean:
+	rm -f $(BIN)/$*.$(ARCH)
+	@echo ""
+
+%.$(ARCH).o : %.c
+	$(CC) $(CFLAGS) -c $*.c -o $@
+
+clean:
+	rm -f $(BIN)/*.$(ARCH)
+	rm -f $(LIB)/*.$(ARCH).a
+	rm -f `find . -name "*.o"`
+	rm -f `find . -name "*~"`
+	rm -f `find . -name "#*"`
+
+dist: clean
+	rm -f $(BIN)/*
+	rm -f $(LIB)/*
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.data/PlotVectors.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.data/PlotVectors.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.data/PlotVectors.c	(revision 3338)
@@ -0,0 +1,42 @@
+# include "display.h"
+
+static int Xgraph;
+
+int PrepPlotting (int Npts, Graphdata *graphmode) {
+
+  char buffer[128], buffer2[128];
+
+  if (!GetGraph (NULL, &Xgraph, NULL)) return (FALSE);
+  
+  /* tell kapa to look for the incoming image */
+  write (Xgraph, "PLOT", 4); 
+
+  /* send Xgraph the plot details */
+  sprintf (buffer, "%8d %8d %d %d %d %d %d %f %f ", 
+	   Npts, graphmode[0].style, 
+	   graphmode[0].ptype, graphmode[0].ltype, 
+	   graphmode[0].etype, graphmode[0].ebar, graphmode[0].color, 
+	   graphmode[0].lweight, graphmode[0].size);
+  sprintf (buffer2, "NBYTES: %6d ", strlen (buffer));
+  write (Xgraph, buffer2, 16);
+  write (Xgraph, buffer, strlen (buffer));
+  
+  sprintf (buffer, "%g %g %g %g ", 
+	   graphmode[0].xmin, graphmode[0].xmax, 
+	   graphmode[0].ymin, graphmode[0].ymax);
+  sprintf (buffer2, "NBYTES: %6d ", strlen (buffer));
+  write (Xgraph, buffer2, 16);
+  write (Xgraph, buffer, strlen (buffer));
+  return (TRUE);
+}
+
+int PlotVector (int Npts, float *values) {
+
+  int Nbytes;
+
+  Nbytes = Npts * sizeof (float);
+  write (Xgraph, values, Nbytes);
+  return (TRUE);
+}
+
+/* we don't use GetGraph in PlotVector because it flushes the connection */
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.data/convert.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.data/convert.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.data/convert.c	(revision 3338)
@@ -0,0 +1,556 @@
+# include "convert.h"
+  
+int hh_hms (double hh, int *hr, int *mn, double *sc) {
+
+  int flag;
+
+  flag = SIGN(hh);
+  hh *= flag;
+  hh = 24.0*(hh/24.0 - (int)(hh/24.0));
+  *sc = 60.0*(60.0*hh - (int)(60.0*hh));
+  *mn = 60.0*(hh - (int)hh);
+  *hr = (int) hh;
+  *hr *= flag;
+  return (TRUE);
+}
+ 
+int dd_dms (double dd, int *dg, int *mn, double *sc) {
+
+  int flag;
+
+  flag = SIGN(dd);
+  dd = fabs (dd);
+  *dg = (int) dd;
+  *mn = (int) 60*(dd - *dg);
+  *sc = 3600.0*(dd - *dg - *mn/60.0);
+  if (*sc > 59.99) {
+    *sc = 0;
+    *mn += 1.0;
+  }
+  *dg *= flag;
+  return (TRUE);
+}
+ 
+int hms_format (char *line, double value) {
+
+  int hr, mn;
+  double sc;
+
+  hh_hms (value, &hr, &mn, &sc);
+  hr = (int) value;
+  if (isnan (value))
+    sprintf (line, "xx:xx:xx.xx");
+  else {
+    if (value < 0) {
+      sprintf (line, "-%02d:%02d:%05.2f", abs(hr), mn, sc);
+    } else {
+      sprintf (line, "%02d:%02d:%05.2f", hr, mn, sc);
+    }
+  }      
+  return (TRUE);
+}
+
+int dms_format (char *line, double value) {
+
+  int dg, mn;
+  double sc;
+
+  dd_dms (value, &dg, &mn, &sc);
+  if (value < 0) {
+    sprintf (line, "-%02d:%02d:%05.2f", abs(dg), mn, sc);
+  } else {
+    sprintf (line, "%02d:%02d:%05.2f", dg, mn, sc);
+  }
+  return (TRUE);
+}
+
+/***** extract RA - RA, DEC - DEC from HST GSC entry *****/
+int hstgsc_hms_to_deg (double *h0, double *h1, double *d0, double *d1, char *string) {
+  
+  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);
+}
+
+/***** 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);
+}
+
+int hh_hm (double hh, int *hr, double *mn) {
+
+  int flag;
+
+  flag = SIGN(hh);
+  hh = fabs (hh);
+
+  *mn = 60.0*(hh - (int)hh);
+  *hr = (int) hh;
+  *hr *= flag;
+  return (TRUE);
+}
+
+char *meade_deg_to_str (double deg) {
+
+  int hr;
+  double mn;
+  char *line;
+
+  ALLOCATE (line, char, 16);
+
+  hh_hm (deg, &hr, &mn);
+
+  sprintf (line, "%03d:%04.1f", abs(hr), mn);
+  return (line);
+}
+
+char *meade_ra_to_str (double deg) {
+
+  int hr;
+  double mn;
+  char *line;
+
+  ALLOCATE (line, char, 16);
+
+  hh_hm (deg/15.0, &hr, &mn);
+
+  sprintf (line, "%02d:%04.1f", abs(hr), mn);
+  return (line);
+}
+
+char *meade_dec_to_str (double deg) {
+
+  int hr;
+  double mn;
+  char *line;
+
+  ALLOCATE (line, char, 16);
+
+  hh_hm (deg, &hr, &mn);
+
+  if (deg < 0) {
+    sprintf (line, "-%02d:%04.1f", abs(hr), mn);
+  } else {
+    sprintf (line, "+%02d:%04.1f", hr, mn);
+  }      
+  return (line);
+}
+
+/**********/
+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 == 'j') {
+      mode = TIME_JD;
+    }
+    if (*p2 == 'J') {
+      mode = TIME_MJD;
+    }
+    if (*p2 == 'd') {
+      mode = TIME_DAYS;
+    }
+    if (*p2 == 'h') {
+      mode = TIME_HOURS;
+    }
+    if (*p2 == 'm') {
+      mode = TIME_MINUTES;
+    }
+    if (*p2 == 's') {
+      mode = TIME_SECONDS;
+    }
+  } else { 
+    mode = TIME_DATE;
+  }
+  return (mode);
+}
+
+/**********/
+int str_to_time (char *line, time_t *second) {
+  
+  char *tmpline;
+  struct tm *gmt;
+  struct timeval now;
+  double jd;
+  time_t 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 TIME_JD:
+    jd = strtod (line, 0);
+    *second = jd_to_sec (jd);
+    return (TRUE);
+  case TIME_MJD:
+    jd = strtod (line, 0);
+    *second = mjd_to_sec (jd);
+    return (TRUE);
+  case TIME_DATE:
+    *second = date_to_sec (line);
+    return (TRUE);
+  case TIME_DAYS:
+    *second = strtod (line, 0) * 86400.0;
+    return (TRUE);
+  case TIME_HOURS:
+    *second = strtod (line, 0) * 3600.0;
+    return (TRUE);
+  case TIME_MINUTES:
+    *second = strtod (line, 0) * 60.0;
+    return (TRUE);
+  case TIME_SECONDS:
+    *second = strtod (line, 0);
+    return (TRUE);
+  }
+  return (FALSE);
+}
+
+
+/**********/
+int str_to_dtime (char *line, double *second) {
+  
+  switch (chk_time (line)) {
+  case 0:
+  case TIME_JD:
+  case TIME_MJD:
+  case TIME_DATE:
+    return (FALSE);
+  case TIME_DAYS:
+    *second = strtod (line, 0) * 86400.0;
+    return (TRUE);
+  case TIME_HOURS:
+    *second = strtod (line, 0) * 3600.0;
+    return (TRUE);
+  case TIME_MINUTES:
+    *second = strtod (line, 0) * 60.0;
+    return (TRUE);
+  case TIME_SECONDS:
+    *second = strtod (line, 0);
+    return (TRUE);
+  }
+  return (FALSE);
+}
+
+/**********/
+double sec_to_jd (time_t second) {
+
+  double jd;
+  
+  jd = second/86400.0 + 2440587.5;
+  return (jd);
+}
+
+/**********/
+time_t jd_to_sec (double jd) {
+
+  time_t second;
+
+  second = (jd - 2440587.5)*86400;
+  return (second);
+}
+
+/**********/
+double sec_to_mjd (time_t second) {
+
+  double mjd;
+  
+  mjd = second/86400.0 + 40587.0;
+  return (mjd);
+}
+
+/**********/
+time_t mjd_to_sec (double mjd) {
+
+  time_t second;
+
+  second = (mjd - 40587.0)*86400;
+  return (second);
+}
+
+/**********/
+char *sec_to_date (time_t 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 *****/
+time_t date_to_sec (char *date) {
+  
+  time_t 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);
+}
+
+/* convert UNIX time to a value referenced to the TimeReference in the given unit */
+double TimeValue (time_t time, time_t TimeReference, int TimeFormat) {
+
+  double value, dt;
+
+  dt = (time > TimeReference) ? (time - TimeReference) : -1 * (double)(TimeReference - time);
+  switch (TimeFormat) {
+  case TIME_JD:
+    value = time / 86400.0 + 2440587.5;
+    break;
+  case TIME_MJD:
+    value = time / 86400.0 + 40587.0;
+    break;
+  case TIME_DAYS:
+    value = dt / 86400.0;
+    break;
+  case TIME_HOURS:
+    value = dt / 3600.0;
+    break;
+  case TIME_MINUTES:
+    value = dt / 60.0;
+    break;
+  case TIME_SECONDS:
+  default:
+    value = dt;
+    break;
+  }
+  return (value);
+}
+  
+/* convert time value referenced to the TimeReference in the given unit to UNIX time */
+time_t TimeRef (double value, time_t TimeReference, int TimeFormat) {
+
+  int dt;
+  time_t time;
+
+  switch (TimeFormat) {
+  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_DAYS:
+    dt = value * 86400.0;
+    break;
+  case TIME_HOURS:
+    dt = value * 3600.0;
+    break;
+  case TIME_MINUTES:
+    dt = value * 60.0;
+    break;
+  case TIME_SECONDS:
+  default:
+    dt = value;
+    break;
+  }
+
+  time = TimeReference + dt;
+  return (time);
+}
+
+/* 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
+   */
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.data/fft.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.data/fft.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.data/fft.c	(revision 3338)
@@ -0,0 +1,270 @@
+# include "data.h"
+
+#define FSWAP(a,b) tempr=(a);(a)=(b);(b)=tempr
+
+void fft (float *Data, int N, int isign) {
+
+  int n,mmax,m,j,istep,i;
+  double wtemp,wr,wpr,wpi,wi,theta;
+  float tempr,tempi, *data;
+
+  data = Data;
+  n = N << 1;
+  j = 0;
+
+  for (i = 0; i < n; i+=2) {
+    if (j > i) {
+      FSWAP (data[j], data[i]);
+      FSWAP (data[j+1], data[i+1]);
+    }
+    m = n >> 1;
+    while (m >= 2 && j >= m) {
+      j -= m;
+      m >>= 1;
+    }
+    j += m;
+  }
+  mmax = 2;
+  while (n > mmax) {
+    istep = 2*mmax;
+    theta = 6.28318530717959 / (isign*mmax);
+    wtemp = sin(0.5*theta);
+    wpr = -2.0*wtemp*wtemp;
+    wpi = sin(theta);
+    wr = 1.0;
+    wi = 0.0;
+    for (m = 0; m < mmax; m+=2) {
+      for (i = m; i < n; i+=istep) {
+	j = i + mmax;
+	tempr = wr*data[j] - wi*data[j+1];
+	tempi = wr*data[j+1] + wi*data[j];
+	data[j] = data[i] - tempr;
+	data[j+1] = data[i+1] - tempi;
+	data[i] += tempr;
+	data[i+1] += tempi;
+      }
+      wr = (wtemp = wr)*wpr - wi*wpi+wr;
+      wi = wi*wpr + wtemp*wpi + wi;
+    }
+    mmax = istep;
+  }
+}
+
+void fftold (float *Data, int N, int isign) {
+
+  int n,mmax,m,j,istep,i;
+  double wtemp,wr,wpr,wpi,wi,theta;
+  float tempr,tempi, *data;
+
+  data = Data - 1;
+  n = N << 1;
+  j = 1;
+
+  for (i = 1; i < n; i+=2) {
+    if (j > i) {
+      FSWAP (data[j], data[i]);
+      FSWAP (data[j+1], data[i+1]);
+    }
+    m = n >> 1;
+    while (m >= 2 && j > m) {
+      j -= m;
+      m >>= 1;
+    }
+    j += m;
+  }
+  mmax = 2;
+  while (n > mmax) {
+    istep = 2*mmax;
+    theta = 6.28318530717959 / (isign*mmax);
+    wtemp = sin(0.5*theta);
+    wpr = -2.0*wtemp*wtemp;
+    wpi = sin(theta);
+    wr = 1.0;
+    wi = 0.0;
+    for (m = 1; m < mmax; m+=2) {
+      for (i = m; i <= n; i+=istep) {
+	j = i + mmax;
+	tempr = wr*data[j] - wi*data[j+1];
+	tempi = wr*data[j+1] + wi*data[j];
+	data[j] = data[i] - tempr;
+	data[j+1] = data[i+1] - tempi;
+	data[i] += tempr;
+	data[i+1] += tempi;
+      }
+      wr = (wtemp = wr)*wpr - wi*wpi+wr;
+      wi = wi*wpr + wtemp*wpi + wi;
+    }
+    mmax = istep;
+  }
+}
+
+/* convert indices to zero reference */
+void fftN (float *data, int *nn, int ndim, int isign) {
+
+  int i1,i2,i3,i2rev,i3rev,ip1,ip2,ip3,ifp1,ifp2;
+  int ibit,idim,k1,k2,n,nprev,nrem,ntot;
+  float tempi,tempr;
+  double theta,wi,wpi,wpr,wr,wtemp;
+
+  ntot = 1;
+  for (idim = 0; idim < ndim; idim++) ntot *= nn[idim];
+
+  nprev = 1;
+  for (idim = ndim - 1; idim >= 0; idim--) {
+    n  =  nn[idim];
+    nrem = ntot / (n*nprev);
+    ip1 = nprev << 1;
+    ip2 = ip1*n;
+    ip3 = ip2*nrem;
+    i2rev = 0;
+    for (i2 = 0; i2 < ip2; i2+=ip1) {
+      if (i2 < i2rev) {
+	for (i1 = i2; i1 <= i2+ip1-2; i1+=2) {
+	  for (i3 = i1; i3 < ip3; i3+=ip2) {	
+	    i3rev = i2rev+i3-i2;
+	    FSWAP(data[i3],data[i3rev]);
+	    FSWAP(data[i3+1],data[i3rev+1]);
+	  }
+	}
+      }
+      ibit = ip2 >> 1;
+      while (ibit >= ip1 && i2rev >= ibit) {
+	i2rev -= ibit;
+	ibit >>= 1;
+      }
+      i2rev += ibit;
+    }
+    ifp1 = ip1;
+    while (ifp1 < ip2) {
+      ifp2 = ifp1 << 1;
+      theta = isign*6.28318530717959/(ifp2/ip1);
+      wtemp = sin(0.5*theta);
+      wpr = -2.0*wtemp*wtemp;
+      wpi = sin(theta);
+      wr = 1.0;
+      wi = 0.0;
+      for (i3 = 0; i3 < ifp1; i3+=ip1) {
+	for (i1 = i3; i1 <= i3+ip1-2; i1+=2) {
+	  for (i2 = i1; i2 < ip3; i2+=ifp2) {
+	    k1 = i2;
+	    k2 = k1+ifp1;
+	    tempr = wr*data[k2]-wi*data[k2+1];
+	    tempi = wr*data[k2+1]+wi*data[k2];
+	    data[k2] = data[k1]-tempr;
+	    data[k2+1] = data[k1+1]-tempi;
+	    data[k1] += tempr;
+	    data[k1+1] += tempi;
+	  }
+	}
+	wr = (wtemp = wr)*wpr-wi*wpi+wr;
+	wi = wi*wpr+wtemp*wpi+wi;
+      }
+      ifp1 = ifp2;
+    }
+    nprev *= n;
+  }
+}
+
+#undef FSWAP
+
+/* based on the PRESS routine, this fft takes an array from data[0] to data[2N-1] */
+/* this function takes Data = h(t) and replaces it in situ with H(F) or vice versa.
+   There are assumed to be 2*N input values with 
+   Data[0,2,4,...] the real and Data[1,3,5,...] the imaginary ones.
+   the output is ordered the same.  
+
+   for h(t), values are in time sequence order.
+   for H(F), values are in order F = 0, 1/N, ... 1/2 - 1/N, +/- 1/2, -1/2 + 1/N, ... -1/N 
+
+   no normalization is performed, so a signal of amplitude A sin (w_k * t) will be 
+      give an H(F) value of 0.5 * A * N, and the DC term will have H(0) = A * N.
+
+*/ 
+
+int IsBinary (int N) {
+
+  int i, nbit;
+
+  /* check if number is a binary number */
+  nbit = 0;
+  for (i = 0; i < 8*sizeof(N); i++) {
+    nbit += (N & 0x01);
+    N = (N >> 1);
+  }
+  if (nbit == 1) { 
+    return (1); 
+  } else { 
+    return (0); 
+  }
+
+}  
+
+#define FSWAP(a,b) tempr=(a);(a)=(b);(b)=tempr
+
+void fourn (float *data, int *nn, int ndim, int isign) {
+
+  int i1,i2,i3,i2rev,i3rev,ip1,ip2,ip3,ifp1,ifp2;
+  int ibit,idim,k1,k2,n,nprev,nrem,ntot;
+  float tempi,tempr;
+  double theta,wi,wpi,wpr,wr,wtemp;
+
+  ntot = 1;
+  for (idim = 1; idim <= ndim; idim++)
+    ntot *= nn[idim];
+  nprev = 1;
+  for (idim = ndim; idim >= 1; idim--) {
+    n = nn[idim];
+    nrem = ntot/(n*nprev);
+    ip1 = nprev << 1;
+    ip2 = ip1*n;
+    ip3 = ip2*nrem;
+    i2rev = 1;
+    for (i2 = 1; i2 <= ip2; i2+=ip1) {
+      if (i2 < i2rev) {
+	for (i1 = i2; i1 <= i2+ip1-2; i1+=2) {
+	  for (i3 = i1; i3 <= ip3;i3+=ip2) {
+	    i3rev = i2rev+i3-i2;
+	    FSWAP(data[i3],data[i3rev]);
+	    FSWAP(data[i3+1],data[i3rev+1]);
+	  }
+	}
+      }
+      ibit = ip2 >> 1;
+      while (ibit >= ip1 && i2rev > ibit) {
+	i2rev -=  ibit;
+	ibit >>= 1;
+      }
+      i2rev += ibit;
+    }
+    ifp1 = ip1;
+    while (ifp1 < ip2) {
+      ifp2 = ifp1 << 1;
+      theta = isign*6.28318530717959/(ifp2/ip1);
+      wtemp = sin(0.5*theta);
+      wpr  =  -2.0*wtemp*wtemp;
+      wpi = sin(theta);
+      wr = 1.0;
+      wi = 0.0;
+      for (i3 = 1;i3<=ifp1;i3+=ip1) {
+	for (i1 = i3;i1<=i3+ip1-2;i1+=2) {
+	  for (i2 = i1;i2<=ip3;i2+=ifp2) {
+	    k1 = i2;
+	    k2 = k1+ifp1;
+	    tempr = wr*data[k2]-wi*data[k2+1];
+	    tempi = wr*data[k2+1]+wi*data[k2];
+	    data[k2] = data[k1]-tempr;
+	    data[k2+1] = data[k1+1]-tempi;
+	    data[k1] += tempr;
+	    data[k1+1] += tempi;
+	  }
+	}
+	wr = (wtemp = wr)*wpr-wi*wpi+wr;
+	wi = wi*wpr+wtemp*wpi+wi;
+      }
+      ifp1 = ifp2;
+    }
+    nprev *= n;
+  }
+}
+
+#undef FSWAP
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.data/gaussian.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.data/gaussian.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.data/gaussian.c	(revision 3338)
@@ -0,0 +1,66 @@
+# include "data.h"
+
+static int Ngaussint;
+static double *gaussint;
+
+extern double drand48();
+
+double gaussian (double x, double mean, double sigma) {
+
+  double f;
+
+  f = exp (-0.5 * SQ(x - mean) / SQ(sigma)) / sqrt(2 * M_PI * SQ(sigma));
+
+  return (f);
+
+}
+
+/* integrate a gaussian from -5 sigma to +5 sigma */
+void gauss_init (int Nbin) {
+ 
+  int i;
+  long A, B;
+  double val, x, dx, dx1, dx2, dx3, df;
+  double mean, sigma;
+ 
+  A = time(NULL);
+  for (B = 0; A == time(NULL); B++);
+  srand48(B);
+ 
+  Ngaussint = Nbin;
+  ALLOCATE (gaussint, double, Ngaussint + 1);
+
+  val = 0;
+  dx = 1.0 / Ngaussint;
+  dx1 = dx / 3.0;
+  dx2 = 2.0*dx/3.0;
+  dx3 = dx;
+  mean = 0.0;
+  sigma = 1.0;
+ 
+  for (i = 0, x = -7.0; (i < Ngaussint) && (x < 7.0); x += dx)  {
+    df = (3.0*gaussian(x    , mean, sigma) + 
+          9.0*gaussian(x+dx1, mean, sigma) +
+          9.0*gaussian(x+dx2, mean, sigma) + 
+          3.0*gaussian(x+dx3, mean, sigma)) * (dx1/8.0);
+    val += df;
+    if (val > (i / (double) Ngaussint)) {
+      gaussint[i] = x + dx / 2.0;
+      i++;
+    }
+  }
+}
+
+double rnd_gauss (double mean, double sigma) {
+ 
+  int i;
+  double y;
+ 
+  y = drand48();
+  i = Ngaussint*y;
+  y = gaussint[i]*sigma + mean;
+ 
+  return (y);
+ 
+}
+ 
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.data/gaussj.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.data/gaussj.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.data/gaussj.c	(revision 3338)
@@ -0,0 +1,176 @@
+# include "data.h"
+
+int gaussj (double **a, int n, double **b, int m) {
+
+  int *indxc,*indxr,*ipiv;
+  int i, icol, irow, j, k, l, ll;
+  double big,dum,pivinv;
+  
+  ALLOCATE (indxc, int, n);
+  ALLOCATE (indxr, int, n);
+  ALLOCATE (ipiv, int, n);
+  for (j = 0; j < n; j++) 
+    ipiv[j] = 0;
+
+  irow = icol = 0;
+  big = fabs(a[0][0]);
+
+  for (i = 0; i < n; i++) {
+    big = 0.0;
+    for (j = 0; j < n; j++) {
+      if (!finite(a[i][j])) {
+	fprintf (stderr, "GAUSSJ: NaN\n");
+	goto escape;
+      }
+      if (ipiv[j] != 1) {
+	for (k = 0; k < n; k++) {
+	  if (ipiv[k] == 0) {
+	    if (fabs (a[j][k]) >= big) {
+	      big  = fabs (a[j][k]);
+	      irow = j;
+	      icol = k;
+	    }
+	  } 
+	  else 
+	    if (ipiv[k] > 1) {
+	      fprintf (stderr, "GAUSSJ: Singular Matrix! (1)\n");
+	      goto escape;
+	    }
+	}
+      }
+    }
+    ipiv[icol]++;
+    if (irow != icol) {
+      for (l = 0; l < n; l++) 
+	SWAP (a[irow][l], a[icol][l]);
+      for (l = 0; l < m; l++) 
+	SWAP (b[irow][l], b[icol][l]);
+    }
+    indxr[i] = irow;
+    indxc[i] = icol;
+    if (a[icol][icol] == 0.0) {
+      fprintf (stderr, "GAUSSJ: Singular Matrix! (2)\n");
+      goto escape;
+    }
+    pivinv = 1.0 / a[icol][icol];
+    a[icol][icol] = 1.0;
+    for (l = 0; l < n; l++) 
+      a[icol][l] *= pivinv;
+    for (l = 0; l < m; l++) 
+      b[icol][l] *= pivinv;
+    for (ll = 0; ll < n; ll++) {
+      if (ll != icol) {
+	dum = a[ll][icol];
+	a[ll][icol] = 0.0;
+	for (l = 0; l < n; l++) 
+	  a[ll][l] -= a[icol][l]*dum;
+	for (l = 0; l < m; l++) 
+	  b[ll][l] -= b[icol][l]*dum;
+      }
+    }
+  }
+
+  for (l = n - 1; l >= 0; l--) {
+    if (indxr[l] != indxc[l])
+      for (k = 0; k < n; k++)
+	SWAP (a[k][indxr[l]], a[k][indxc[l]]);
+  }
+  free (ipiv);
+  free (indxr);
+  free (indxc);
+  return (TRUE);
+
+escape:
+  free (ipiv);
+  free (indxr);
+  free (indxc);
+  return (FALSE);
+}
+
+
+int fgaussj (float **a, int n, float **b, int m) {
+
+  int *indxc,*indxr,*ipiv;
+  int i, icol, irow, j, k, l, ll;
+  float big,dum,pivinv;
+  
+  ALLOCATE (indxc, int, n);
+  ALLOCATE (indxr, int, n);
+  ALLOCATE (ipiv, int, n);
+  for (j = 0; j < n; j++) 
+    ipiv[j] = 0;
+
+  irow = icol = 0;
+  big = fabs(a[0][0]);
+
+  for (i = 0; i < n; i++) {
+    big = 0.0;
+    for (j = 0; j < n; j++) {
+      if (!finite(a[i][j])) {
+	fprintf (stderr, "GAUSSJ: NaN\n");
+	goto fescape;
+      }
+      if (ipiv[j] != 1) {
+	for (k = 0; k < n; k++) {
+	  if (ipiv[k] == 0) {
+	    if (fabs (a[j][k]) >= big) {
+	      big  = fabs (a[j][k]);
+	      irow = j;
+	      icol = k;
+	    }
+	  } 
+	  else 
+	    if (ipiv[k] > 1) {
+	      fprintf (stderr, "GAUSSJ: Singular Matrix! (1)\n");
+	      goto fescape;
+	    }
+	}
+      }
+    }
+    ipiv[icol]++;
+    if (irow != icol) {
+      for (l = 0; l < n; l++) 
+	SWAP (a[irow][l], a[icol][l]);
+      for (l = 0; l < m; l++) 
+	SWAP (b[irow][l], b[icol][l]);
+    }
+    indxr[i] = irow;
+    indxc[i] = icol;
+    if (a[icol][icol] == 0.0) {
+      fprintf (stderr, "GAUSSJ: Singular Matrix! (2)\n");
+      goto fescape;
+    }
+    pivinv = 1.0 / a[icol][icol];
+    a[icol][icol] = 1.0;
+    for (l = 0; l < n; l++) 
+      a[icol][l] *= pivinv;
+    for (l = 0; l < m; l++) 
+      b[icol][l] *= pivinv;
+    for (ll = 0; ll < n; ll++) {
+      if (ll != icol) {
+	dum = a[ll][icol];
+	a[ll][icol] = 0.0;
+	for (l = 0; l < n; l++) 
+	  a[ll][l] -= a[icol][l]*dum;
+	for (l = 0; l < m; l++) 
+	  b[ll][l] -= b[icol][l]*dum;
+      }
+    }
+  }
+
+  for (l = n - 1; l >= 0; l--) {
+    if (indxr[l] != indxc[l])
+      for (k = 0; k < n; k++)
+	SWAP (a[k][indxr[l]], a[k][indxc[l]]);
+  }
+  free (ipiv);
+  free (indxr);
+  free (indxc);
+  return (1);
+
+fescape:
+  free (ipiv);
+  free (indxr);
+  free (indxc);
+  return (FALSE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.data/graphtools.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.data/graphtools.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.data/graphtools.c	(revision 3338)
@@ -0,0 +1,55 @@
+# include "data.h"
+
+void SetLimits (Vector *xvec, Vector *yvec, Graphdata *graphmode) {
+
+  double maxX, minX, maxY, minY, range;
+  int i;
+
+  if (xvec != NULL) {
+    maxX = minX = xvec[0].elements[0];
+    for (i = 1; i < xvec[0].Nelements; i++) {
+      if (!finite(xvec[0].elements[i])) continue;
+      maxX = MAX (maxX, xvec[0].elements[i]);
+      minX = MIN (minX, xvec[0].elements[i]);
+    }
+    range = maxX - minX;
+    if (range == 0) range = 0.001 * maxX;
+    if (range == 0) range = 0.001;
+    graphmode[0].xmin = minX - 0.05*range;
+    graphmode[0].xmax = maxX + 0.05*range;
+  }
+
+  if (yvec != NULL) {
+    maxY = minY = yvec[0].elements[0];
+    for (i = 1; i < yvec[0].Nelements; i++) {
+      if (!finite(yvec[0].elements[i])) continue;
+      maxY = MAX (maxY, yvec[0].elements[i]);
+      minY = MIN (minY, yvec[0].elements[i]);
+    }
+    range = maxY - minY;
+    if (range == 0) range = 0.0011 * maxY;
+    if (range == 0) range = 0.0011;
+    graphmode[0].ymin = minY - 0.05*range;
+    graphmode[0].ymax = maxY + 0.05*range;
+  }
+  SetGraph (graphmode[0]);
+
+  set_variable ("XMIN", graphmode[0].xmin);
+  set_variable ("XMAX", graphmode[0].xmax);
+  set_variable ("YMIN", graphmode[0].ymin);
+  set_variable ("YMAX", graphmode[0].ymax);
+}
+
+void ApplyLimits (int Xgraph, Graphdata *graphmode, int apply) { 
+
+  char buffer[128], buffer2[65];
+
+  if (!apply) return;
+
+  write (Xgraph, "SLIM", 4);
+  sprintf (buffer, "%g %g %g %g ", graphmode[0].xmin, graphmode[0].xmax, graphmode[0].ymin, graphmode[0].ymax);
+  sprintf (buffer2, "NBYTES: %6d ", strlen (buffer));
+  write (Xgraph, buffer2, 16);
+  write (Xgraph, buffer, strlen (buffer));
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.data/mrq2dmin.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.data/mrq2dmin.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.data/mrq2dmin.c	(revision 3338)
@@ -0,0 +1,210 @@
+# include "data.h"  /* only needed for the ALLOCATE def */
+
+/* need to pass in a function of the form:
+   funcs (x, t, a, Npar, dy/da) 
+   returns y (x,t) for Npar parameters a along with dy/da at (x,t)
+   dy carries 1/sig^2 
+*/
+
+# define VERY_VERBOSE 0
+
+static float **alpha, **talpha;
+static float **beta, **tbeta;
+static float *partry, *dyda;
+static float ochisq, lambda;
+
+static float *parmin = NULL;
+static float *parmax = NULL;
+
+float mrq2dcof (float *x, float *t, float *y, float *dy, int Npts, 
+	      float *par, int Npar, float **ta, float **tb, 
+	      float (funcs)(float, float, float *, int, float *)) {
+
+  int k, j, i;
+  float ydiff, wt, chisq;
+
+  for (j = 0; j < Npar; j++) {
+    for (k = 0; k <= j; k++) ta[j][k] = 0.0;
+    tb[j][0] = 0.0;
+  }
+
+  chisq = 0.0;
+  for (i = 0; i < Npts; i++) {
+
+    ydiff = funcs (x[i], t[i], par, Npar, dyda) - y[i];
+    chisq += SQ(ydiff) * dy[i];
+    
+    for (j = 0; j < Npar; j++) {
+      wt = dyda[j] * dy[i];
+      for (k = 0; k <= j; k++) ta[j][k] += wt * dyda[k];
+      tb[j][0] += wt * ydiff;
+    }
+  }
+
+  for (j = 1; j < Npar; j++)
+    for (k = 0; k < j; k++)
+      ta[k][j] = ta[j][k];
+      
+# if (VERY_VERBOSE)
+  for (j = 0; j < Npar; j++) {
+    for (k = 0; k < Npar; k++) {
+      fprintf (stderr, "%9.3e  ", ta[j][k]);
+    }
+    fprintf (stderr, "    :   %9.3e  ", tb[j][0]);
+    fprintf (stderr, "\n");
+  }
+# endif
+
+  return (chisq);
+
+}
+
+float mrq2dchi (float *x, float *t, float *y, float *dy, int Npts, 
+		float *par, int Npar, 
+		float (funcs)(float, float, float *, int, float *)) {
+
+  int k, j, i;
+  float ydiff, wt, chisq;
+
+  chisq = 0.0;
+  for (i = 0; i < Npts; i++) {
+    ydiff = funcs (x[i], t[i], par, Npar, dyda) - y[i];
+    chisq += SQ(ydiff) * dy[i];
+  }
+  return (chisq);
+}
+
+float mrq2dmin (float *x, float *t, float *y, float *dy, int Npts, 
+	      float *par, int Npar, 
+	      float (funcs)(float, float, float *, int, float *), int VERBOSE) {
+
+  int j, k;
+  float chisq;
+
+  /* set up test matrixes for this run */
+  for (j = 0; j < Npar; j++) {
+    for (k = 0; k < Npar; k++) talpha[j][k] = alpha[j][k];
+    talpha[j][j] = alpha[j][j] * (1.0 + lambda);
+    tbeta[j][0] = beta[j][0];
+  }
+
+  /* keep this test in here? */
+  if (!fgaussj (talpha, Npar, tbeta, 1)) {
+    lambda *= 10.0;
+    return (ochisq);
+  }
+
+  for (j = 0; j < Npar; j++) {
+    partry[j] = par[j] - tbeta[j][0];
+    /*
+    if (parmin != NULL) partry[j] = MAX (parmin[j], partry[j]);
+    if (parmax != NULL) partry[j] = MIN (parmax[j], partry[j]);
+    */
+  }
+
+  chisq = mrq2dcof (x, t, y, dy, Npts, partry, Npar, talpha, tbeta, funcs);
+  if (VERBOSE) { 
+    fprintf (stderr, "chisq: %f  ", chisq);
+    fprintf (stderr, "lambda: %f  ", lambda);
+    for (j = 0; j < Npar; j++) {
+      fprintf (stderr, "%f ", partry[j]);
+    }
+    fprintf (stderr, "\n");
+  }
+
+  /* if good, save temp values */
+  if (chisq < ochisq) {
+    lambda *= 0.1;
+    ochisq = chisq;
+    for (j = 0; j < Npar; j++) {
+      for (k = 0; k < Npar; k++) alpha[j][k] = talpha[j][k];
+      beta[j][0] = tbeta[j][0];
+      par[j] = partry[j];
+    }
+  } else {
+    lambda *= 10.0;
+    chisq = ochisq;
+  }
+
+  return (chisq);
+
+}
+
+int mrq2dlimits (float *pmin, float *pmax, int Npar) {
+
+  int i;
+
+  ALLOCATE (parmin, float, Npar);
+  ALLOCATE (parmax, float, Npar);
+  for (i = 0; i < Npar; i++) {
+    parmin[i] = pmin[i];
+    parmax[i] = pmax[i];
+  }
+  return (TRUE);
+}
+
+float mrq2dinit (float *x, float *t, float *y, float *dy, int Npts, 
+	      float *par, int Npar, 
+	      float (funcs)(float, float, float *, int, float *), int VERBOSE) {
+
+  int i;
+
+  ALLOCATE (dyda, float, Npar);
+  ALLOCATE (partry, float, Npar);
+  ALLOCATE (alpha, float *, Npar);
+  ALLOCATE (beta, float *, Npar);
+  ALLOCATE (talpha, float *, Npar);
+  ALLOCATE (tbeta, float *, Npar);
+  for (i = 0; i < Npar; i++) {
+    ALLOCATE (alpha[i], float, Npar);
+    ALLOCATE (beta[i], float, Npar);
+    ALLOCATE (talpha[i], float, Npar);
+    ALLOCATE (tbeta[i], float, Npar);
+  }
+
+  
+  lambda = 0.001;
+  
+  ochisq = mrq2dcof (x, t, y, dy, Npts, par, Npar, alpha, beta, funcs);
+  if (VERBOSE) {
+    fprintf (stderr, "chisq: %f  ", ochisq);
+    fprintf (stderr, "lambda: %f  ", lambda);
+    for (i = 0; i < Npar; i++) {
+      fprintf (stderr, "%f ", par[i]);
+    }
+    fprintf (stderr, "\n");
+  }
+
+  return (ochisq);
+
+}
+
+/* don't invoke this in the middle of a run, only near the end */ 
+float **mrq2dcovar (int Npar) {
+
+  fgaussj (alpha, Npar, beta, 1);
+  return (alpha);
+
+} 
+
+void mrq2dfree (int Npar) {
+
+  int i;
+
+  for (i = 0; i < Npar; i++) {
+    free (alpha[i]);
+    free (talpha[i]);
+    free (beta[i]);
+    free (tbeta[i]);
+  }
+  free (alpha);
+  free (talpha);
+  free (beta);
+  free (tbeta);
+  free (partry);
+  free (dyda);
+
+  if (parmin != NULL) free (parmin);
+  if (parmax != NULL) free (parmax);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.data/mrqmin.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.data/mrqmin.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.data/mrqmin.c	(revision 3338)
@@ -0,0 +1,148 @@
+# include "data.h"  /* only needed for the ALLOCATE def */
+
+/* need to pass in a function of the form:
+   funcs (x, a, Npar, dyda) 
+   returns f (x) for Npar parameters a, also df/da at x 
+   dy carries 1/sig^2 
+*/
+
+static float **alpha, **talpha;
+static float **beta, **tbeta;
+static float *partry, *dyda;
+static float ochisq, lambda;
+
+float mrqcof (float *x, float *y, float *dy, int Npts, 
+	      float *par, int Npar, float **ta, float **tb, 
+	      float (funcs)(float, float *, int, float *)) {
+
+  int k, j, i;
+  float ydiff, wt, chisq;
+
+  for (j = 0; j < Npar; j++) {
+    for (k = 0; k <= j; k++) ta[j][k] = 0.0;
+    tb[j][0] = 0.0;
+  }
+
+  chisq = 0.0;
+  for (i = 0; i < Npts; i++) {
+
+    ydiff = funcs (x[i], par, Npar, dyda) - y[i];
+    chisq += SQ(ydiff) * dy[i];
+
+    for (j = 0; j < Npar; j++) {
+      wt = dyda[j] * dy[i];
+      for (k = 0; k <= j; k++) ta[j][k] += wt * dyda[k];
+      tb[j][0] += wt * ydiff;
+    }
+  }
+
+  for (j = 1; j < Npar; j++)
+    for (k = 0; k < j; k++) 
+      ta[k][j] = ta[j][k];
+
+  return (chisq);
+
+}
+
+float mrqmin (float *x, float *y, float *dy, int Npts, 
+	      float *par, int Npar, 
+	      float (funcs)(float, float *, int, float *), int VERBOSE) {
+
+  int j, k;
+  float chisq;
+
+  /* set up test matrixes for this run */
+  for (j = 0; j < Npar; j++) {
+    for (k = 0; k < Npar; k++) talpha[j][k] = alpha[j][k];
+    talpha[j][j] = alpha[j][j] * (1.0 + lambda);
+    tbeta[j][0] = beta[j][0];
+  }
+
+  fgaussj (talpha, Npar, tbeta, 1);
+
+  for (j = 0; j < Npar; j++) partry[j] = par[j] - tbeta[j][0];
+
+  chisq = mrqcof (x, y, dy, Npts, partry, Npar, talpha, tbeta, funcs);
+  if (VERBOSE) { 
+    fprintf (stderr, "chisq: %f  ", chisq);
+    fprintf (stderr, "lambda: %f  ", lambda);
+    for (j = 0; j < Npar; j++) {
+      fprintf (stderr, "%f ", partry[j]);
+    }
+    fprintf (stderr, "\n");
+  }
+
+  /* if good, save temp values */
+  if (chisq < ochisq) {
+    lambda *= 0.1;
+    ochisq = chisq;
+    for (j = 0; j < Npar; j++) {
+      for (k = 0; k < Npar; k++) alpha[j][k] = talpha[j][k];
+      beta[j][0] = tbeta[j][0];
+      par[j] = partry[j];
+    }
+  } else {
+    lambda *= 10.0;
+    chisq = ochisq;
+  }
+
+  return (chisq);
+
+}
+
+float mrqinit (float *x, float *y, float *dy, int Npts, 
+	      float *par, int Npar, 
+	      float (funcs)(float, float *, int, float *), int VERBOSE) {
+
+  int i;
+
+  ALLOCATE (dyda, float, Npar);
+  ALLOCATE (partry, float, Npar);
+  ALLOCATE (alpha, float *, Npar);
+  ALLOCATE (beta, float *, Npar);
+  ALLOCATE (talpha, float *, Npar);
+  ALLOCATE (tbeta, float *, Npar);
+  for (i = 0; i < Npar; i++) {
+    ALLOCATE (alpha[i], float, Npar);
+    ALLOCATE (beta[i], float, Npar);
+    ALLOCATE (talpha[i], float, Npar);
+    ALLOCATE (tbeta[i], float, Npar);
+  }
+  
+  lambda = 0.01;
+  
+  ochisq = mrqcof (x, y, dy, Npts, par, Npar, alpha, beta, funcs);
+  if (VERBOSE) {
+    fprintf (stderr, "chisq: %f  ", ochisq);
+    fprintf (stderr, "lambda: %f  ", lambda);
+    for (i = 0; i < Npar; i++) {
+      fprintf (stderr, "%f ", par[i]);
+    }
+    fprintf (stderr, "\n");
+  }
+  return (ochisq);
+}
+
+/* don't invoke this in the middle of a run, only near the end */ 
+float **mrqcovar (int Npar) {
+  fgaussj (alpha, Npar, beta, 1);
+  return (alpha);
+} 
+
+void mrqfree (int Npar) {
+
+  int i;
+
+  for (i = 0; i < Npar; i++) {
+    free (alpha[i]);
+    free (talpha[i]);
+    free (beta[i]);
+    free (tbeta[i]);
+  }
+  free (alpha);
+  free (talpha);
+  free (beta);
+  free (tbeta);
+  free (partry);
+  free (dyda);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.data/open_graph.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.data/open_graph.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.data/open_graph.c	(revision 3338)
@@ -0,0 +1,254 @@
+# include "display.h"
+# define DEBUG 0
+
+/** this list must match the one in kapa/include/structures.h, and equiv */
+# define NGRAPHCOLORS 23
+static char GRAPHCOLORS[NGRAPHCOLORS][2][15] = {
+  {"black",    "0.00 0.00 0.00"},
+  {"white",    "1.00 1.00 1.00"},
+  {"red",      "1.00 0.00 0.00"}, 
+  {"pink",     "1.00 0.75 0.80"}, 
+  {"orange",   "1.00 0.65 0.00"}, 
+  {"yellow",   "1.00 1.00 0.00"}, 
+  {"wheat",    "0.96 0.87 0.70"}, 
+  {"gold",     "1.00 0.84 0.00"}, 
+  {"green",    "0.00 1.00 0.00"}, 
+  {"darkgreen","0.00 0.40 0.00"}, 
+  {"blue",     "0.00 0.00 1.00"}, 
+  {"skyblue",  "0.53 0.81 0.92"}, 
+  {"indigo",   "0.56 0.16 0.87"}, 
+  {"violet",   "1.00 0.00 0.00"},
+  {"grey10",   "0.10 0.10 0.10"},
+  {"grey20",   "0.20 0.20 0.20"},
+  {"grey30",   "0.30 0.30 0.30"},
+  {"grey40",   "0.40 0.40 0.40"},
+  {"grey50",   "0.50 0.50 0.50"},
+  {"grey60",   "0.60 0.60 0.60"},
+  {"grey70",   "0.70 0.70 0.70"},
+  {"grey80",   "0.80 0.80 0.80"},
+  {"grey90",   "0.90 0.90 0.90"}};
+
+  /* we have space for several kapa windows */
+# define NXGRAPH 5
+
+static int       IsImage = FALSE;
+static int       Active;
+static int       Xgraph[NXGRAPH];  
+static Graphdata graphdata[NXGRAPH];
+
+int GetCurrentDevice () {
+  return (IsImage);
+}
+
+void SetImageDevice (int state) {
+  IsImage = state;
+}
+
+void QuitGraph () {
+
+  int i;
+  
+  for (i = 0; i < NXGRAPH; i++) {
+    if (Xgraph[i] > 0) {
+      write (Xgraph[i], "QUIT", 4);
+    }
+  }
+}
+
+void InitGraph () {
+
+  int i;
+
+  Active = 0;
+  for (i = 0; i < NXGRAPH; i++) {
+    Xgraph[i] = -1;
+
+    graphdata[i].xmin = graphdata[i].ymin = 0.0;
+    graphdata[i].xmax = graphdata[i].ymax = 1.0;
+    graphdata[i].style = graphdata[i].ptype = 0;
+    graphdata[i].ltype = graphdata[i].color = 0;
+    graphdata[i].etype = graphdata[i].ebar = 0;
+    graphdata[i].lweight = graphdata[i].size = 1.0;
+    
+    graphdata[i].coords.pc1_1 = graphdata[i].coords.pc2_2 = 1.0;
+    graphdata[i].coords.pc1_2 = graphdata[i].coords.pc2_1 = 0.0;
+    strcpy (graphdata[i].coords.ctype, "RA---LIN");
+    graphdata[i].coords.crval1 = 0.0;
+    graphdata[i].coords.crval2 = 0.0;
+    graphdata[i].coords.crpix1 = 0.0;
+    graphdata[i].coords.crpix2 = 0.0;
+    graphdata[i].coords.cdelt1 = graphdata[i].coords.cdelt2 = 1.0;
+    graphdata[i].flipeast = TRUE;
+    graphdata[i].flipnorth = FALSE;
+  }
+}
+
+/* set SIGPIPE to this function to close cleanly */ 
+void XGraphDead (int input) {
+  signal (SIGPIPE, XGraphDead);
+  fprintf (stderr, "kapa is dead, must restart\n");
+  Xgraph[Active] = -1;
+}
+
+/** start socketed connection */
+int open_graph (int N) {
+
+  int InitSocket, status, addreslen, Ntry, fd;
+  char temp[128], socket_name[64], *kapa_exec;
+  struct sockaddr_un Address;
+  
+  kapa_exec = get_variable ("KAPA");
+  if (kapa_exec == (char *) NULL) {
+    fprintf (stderr, "variable KAPA not found\n");
+    return (FALSE);
+  }
+
+  sprintf (socket_name, "/tmp/Kapa.XXXXXX");
+  if ((fd = mkstemp (socket_name)) == -1) {
+    fprintf (stderr, "error starting kapa\n");
+    return (FALSE);
+  }
+  close (fd);
+  unlink (socket_name);
+
+  strcpy (Address.sun_path, socket_name); 
+  Address.sun_family = AF_UNIX; 
+  InitSocket = socket (AF_UNIX, SOCK_STREAM, 0); 
+  status = bind (InitSocket, (struct sockaddr *) &Address, sizeof (Address));
+  status = listen (InitSocket, 1);
+  
+  sprintf (temp, "%s %s &", kapa_exec, socket_name);
+  free (kapa_exec);
+
+# if DEBUG
+  fprintf (stderr, "start kapa, press return: %s\n", temp);
+  fscanf (stdin, "%d", &i);
+# else  
+  system (temp);
+# endif
+  
+  addreslen =  sizeof (Address);
+  fcntl (InitSocket, F_SETFL, O_NONBLOCK); 
+
+# define NTRY 200
+  Ntry = 0;
+  while (Ntry < NTRY) {
+    Xgraph[N] = accept (InitSocket, (struct sockaddr *)&Address, &addreslen);
+    if (Xgraph[N] == -1) {
+      if (errno == EAGAIN) {
+	usleep (10000);
+	Ntry ++;
+      } else { 
+	Ntry = NTRY;
+      }
+    } else {
+      Ntry = NTRY;
+    }
+  }
+  if (Xgraph[N] < 0) {
+    fprintf (stderr, "error starting kapa\n");
+    return (FALSE);
+  } else {
+    fcntl (Xgraph[N], F_SETFL, !O_NONBLOCK); 
+    return (TRUE);
+  }
+  
+}
+
+/* return pointers for current Xgraph, set if desired, test, open if needed */
+int GetGraph (Graphdata *data, int *socket, int *N) {
+
+  int i, n;
+  char buffer[70];
+
+  SetImageDevice (FALSE);
+  if (N == (int *) NULL) {
+    n = Active;
+  } else {
+    if (*N >= NXGRAPH) {
+      fprintf (stderr, "invalid Xgraph window %d\n", *N); 
+      return (FALSE);
+    }
+    if (*N < 0) {
+      *N = n = Active;
+    } else {
+      Active = n = *N;
+    }
+  }
+  
+  /* test Xgraph[0], flush junk from pipe */
+  signal (SIGPIPE, XGraphDead);
+  fcntl (Xgraph[n], F_SETFL,  O_NONBLOCK); 
+  for (i = 0; (read (Xgraph[n], buffer, 64) > 0) && (i < 20); i++);
+  fcntl (Xgraph[n], F_SETFL, !O_NONBLOCK); 
+  
+  if (Xgraph[n] < 1) {
+    if (!open_graph(n)) {
+      return (FALSE);
+    }
+  }
+
+  if (data != (Graphdata *) NULL) *data  = graphdata[n];
+  if (socket != (int *) NULL) *socket = Xgraph[n];
+
+  return (TRUE);
+
+}
+
+/* return pointers for given Xgraph, don't set or open */
+int GetGraphData (Graphdata *data, int *sock, int *N) {
+
+  int n;
+
+  if (N == (int *) NULL) {
+    n = Active;
+  } else {
+    if (*N >= NXGRAPH) {
+      fprintf (stderr, "invalid Xgraph window %d\n", *N); 
+      return (FALSE);
+    }
+    if (*N < 0) {
+      n = Active;
+    } else {
+      n = *N;
+    }
+  }
+  
+  if (data != (Graphdata *) NULL) *data  = graphdata[n];
+  if (sock != (int *) NULL) *sock = Xgraph[n];
+
+  return (TRUE);
+
+}
+
+/* assign given values to current Xgraph */
+void SetGraph (Graphdata data) {
+  graphdata[Active] = data;
+}
+
+int GetColor (char *name) {
+
+  int i;
+  
+  for (i = 0; i < NGRAPHCOLORS; i++) {
+    if (!strcmp (name, GRAPHCOLORS[i][0])) {
+      return (i);
+    }	
+  }
+  fprintf (stderr, "color may be one of:\n");
+  for (i = 0; i < NGRAPHCOLORS; i++) {
+    fprintf (stderr, "  %s\n", GRAPHCOLORS[i][0]);
+  }
+  return (-1);
+}	
+
+int SendLabel (char *string, int Xgraph, int mode) {
+
+  char buffer[64];
+
+  write (Xgraph, "LABL", 4);
+  sprintf (buffer, " %6d %6d  ", strlen (string), mode);
+  write (Xgraph, buffer, 16);
+  write (Xgraph, string, strlen (string));
+  return (TRUE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.data/open_image.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.data/open_image.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.data/open_image.c	(revision 3338)
@@ -0,0 +1,168 @@
+# include "display.h"
+# define DEBUG 0
+
+/* we have space for several kii windows */
+# define NXIMAGE 5
+
+static int       Active;
+static int       Ximage[NXIMAGE];  
+static char      Ximbuffer[NXIMAGE][512];
+static double    Xzero[NXIMAGE];
+static double    Xrange[NXIMAGE];
+
+/* define a structure to carry the relevant image data, eqiv to GraphData? */
+
+void QuitImage () {
+
+  int i;
+  
+  for (i = 0; i < NXIMAGE; i++) {
+    if (Ximage[i] > 0) {
+      write (Ximage[i], "QUIT", 4);
+    }
+  }
+}
+
+
+void InitImage () {
+
+  int i;
+
+  Active = 0;
+  for (i = 0; i < NXIMAGE; i++) {
+    Ximage[i] = -1;
+    Xzero[i] = 0;
+    Xrange[i] = 1024;
+    strcpy (Ximbuffer[i], "none");
+  }
+}
+
+/* set SIGPIPE to this function to close cleanly */ 
+void XImageDead (int input) {
+  signal (SIGPIPE, XImageDead);
+  fprintf (stderr, "kii is dead, must restart\n");
+  Ximage[Active] = -1;
+}
+
+/** start socketed connection */
+int open_image (int N) {
+
+  int InitSocket, status, addreslen;
+  struct sockaddr_un Address;
+  char temp[128], socket_name[64], *kii_exec;
+  int Ntry, fd;
+
+  kii_exec = get_variable ("KII");
+  if (kii_exec == (char *) NULL) {
+    fprintf (stderr, "variable KII not found\n");
+    return (FALSE);
+  }
+
+  sprintf (socket_name, "/tmp/Kii.XXXXXX");
+  if ((fd = mkstemp (socket_name)) == -1) {
+    fprintf (stderr, "error starting kapa\n");
+    return (FALSE);
+  }
+  close (fd);
+  unlink (socket_name);
+
+  strcpy (Address.sun_path, socket_name); 
+  Address.sun_family = AF_UNIX; 
+  InitSocket = socket (AF_UNIX, SOCK_STREAM, 0); 
+  status = bind (InitSocket, (struct sockaddr *) &Address, sizeof (Address));
+  status = listen (InitSocket, 1);
+  
+  sprintf (temp, "%s %s &", kii_exec, socket_name);
+  free (kii_exec);
+
+# if DEBUG
+  fprintf (stderr, "start kii, press return: %s\n", temp);
+  fscanf (stdin, "%d", &i);
+# else  
+  system (temp);
+# endif
+  
+  addreslen =  sizeof (Address);
+  fcntl (InitSocket, F_SETFL, O_NONBLOCK); 
+
+# define NTRY 2000
+  Ntry = 0;
+  while (Ntry < NTRY) {
+    Ximage[N] = accept (InitSocket, (struct sockaddr *)&Address, &addreslen);
+    if (Ximage[N] == -1) {
+      if (errno == EAGAIN) {
+	usleep (10000);
+	Ntry ++;
+      } else { 
+	Ntry = NTRY;
+      }
+    } else {
+      Ntry = NTRY;
+    }
+  }
+
+  if (Ximage[N] < 0) {
+    fprintf (stderr, "error starting kii\n");
+    return (FALSE);
+  } else {
+    fcntl (Ximage[N], F_SETFL, !O_NONBLOCK); 
+    return (TRUE);
+  }
+  
+}
+
+/* return pointers for current Ximage, set if desired, test, open if needed */
+int GetImage (int *socket, int *N) {
+
+  int i, n;
+  char buffer[70];
+
+  SetImageDevice (TRUE);
+  if (N == (int *) NULL) {
+    n = Active;
+  } else {
+    if (*N >= NXIMAGE) {
+      fprintf (stderr, "invalid Ximage window %d\n", *N); 
+      return (FALSE);
+    }
+    if (*N < 0) {
+      *N = n = Active;
+    } else {
+      Active = n = *N;
+    }
+  }
+  
+  /* test Ximage[0], flush junk from pipe */
+  signal (SIGPIPE, XImageDead);
+  fcntl (Ximage[n], F_SETFL,  O_NONBLOCK); 
+  for (i = 0; (read (Ximage[n], buffer, 64) > 0) && (i < 20); i++);
+  fcntl (Ximage[n], F_SETFL, !O_NONBLOCK); 
+  
+  if (Ximage[n] < 1) {
+    if (!open_image(n)) {
+      return (FALSE);
+    }
+  }
+
+  if (socket != (int *) NULL) *socket = Ximage[n];
+
+  return (TRUE);
+
+}
+
+void SetImageName (char *name) {
+  strcpy (Ximbuffer[Active], name);
+}
+
+char *GetImageName () {
+  return (Ximbuffer[Active]);
+}
+  
+void SetImageScale (double zero, double range) {
+  Xzero[Active] = zero;
+  Xrange[Active] = range;
+}
+void GetImageScale (double *zero, double *range) {
+  *zero = Xzero[Active];
+  *range = Xrange[Active];
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.data/powell.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.data/powell.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.data/powell.c	(revision 3338)
@@ -0,0 +1,126 @@
+# include "data.h"
+
+# define FTOL 0.001
+# define ITMAX 200
+
+void linmin (float *p, float *xi, int n, float *fret, float (*func)());
+
+/*** not well tested yet !! ***/
+
+void powell (float *p, int Npar, float (func)() ) {
+  
+  int i, ibig, j, Niter;
+  float t, fptt, fp, del;
+  float *pt, *ptt, *xit, **xi;
+  float ftemp;
+
+  ALLOCATE (pt, float, Npar);
+  ALLOCATE (ptt, float, Npar);
+
+  ALLOCATE (xi, float *, Npar);
+  for (i = 0; i < Npar; i++) {
+    ALLOCATE (xi[i], float, Npar);
+    bzero (xi[i], Npar * sizeof (float));
+    xi[i][i] = 1;
+  }
+  ALLOCATE (xit, float, Npar);
+  
+  ftemp = func (p);
+
+  for (j = 0; j < Npar; j++) pt[j] = p[j];
+
+  for (Niter = 0; Niter < ITMAX; Niter++) {
+    fp = ftemp;
+    ibig = 0;
+    del = 0.0;
+
+    for (i = 0; i < Npar; i++) {
+      for (j = 0; j < Npar; j++) xit[j] = xi[j][i];
+
+      fptt = ftemp;
+      linmin (p, xit, Npar, &ftemp, func);
+
+      if (fabs (fptt - ftemp) > del) {
+	del = fabs (fptt - ftemp);
+	ibig = i;
+      }
+    }
+
+    if (fabs (fp - ftemp) <= 0.5*FTOL*(fabs(fp) + fabs(ftemp))) {
+      free (xit);
+      free (ptt);
+      free (pt);
+      for (i = 0; i < Npar; i++) free (xi[i]);
+      free (xi);
+      return;
+    }
+
+    for (j = 0; j < Npar; j++) {
+      ptt[j] = 2.0*p[j] - pt[j];
+      xit[j] = p[j] - pt[j];
+      pt[j]  = p[j];
+    }
+
+    fptt = func (ptt);
+
+    if (fptt < fp) {
+      t = 2.0*(fp - 2.0*ftemp + fptt) * SQ(fp - ftemp - del) - del * SQ(fp - fptt);
+      if (t < 0.0) {
+	linmin (p, xit, Npar, &ftemp, func);
+	for (j = 0; j < Npar; j++) xi[j][ibig] = xit[j];
+      }
+    }
+  }
+
+  if (Niter == ITMAX) {
+    fprintf (stderr, "Too many iterations in routine POWELL\n");
+    return;
+  }
+
+}
+
+#undef ITMAX
+
+/* 
+   function has N parameters
+   p is the initial guess for the N parameters 
+   xi are the N unit vectors - x[i][j] = delta(i,j)
+   Npar = N parameters
+   
+   FTOL - ending tolerance
+*/
+   
+#define TOL 2.0e-4
+
+int ncom=0;	/* defining declarations */
+float *pcom=0,*xicom=0,(*nrfunc)();
+
+void linmin (float *p, float *xi, int n, float *fret, float (*func)()) {
+
+	int j;
+	float xx,xmin,fx,fb,fa,bx,ax;
+	float brent(),f1dim(),*vector();
+	void mnbrak(),free_vector();
+
+	ncom=n;
+	pcom=vector(1,n);
+	xicom=vector(1,n);
+	nrfunc=func;
+	for (j=1;j<=n;j++) {
+		pcom[j]=p[j];
+		xicom[j]=xi[j];
+	}
+	ax=0.0;
+	xx=1.0;
+	bx=2.0;
+	mnbrak(&ax,&xx,&bx,&fa,&fx,&fb,f1dim);
+	*fret=brent(ax,xx,bx,f1dim,TOL,&xmin);
+	for (j=1;j<=n;j++) {
+		xi[j] *= xmin;
+		p[j] += xi[j];
+	}
+	free_vector(xicom,1,n);
+	free_vector(pcom,1,n);
+}
+
+#undef TOL
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.data/precess.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.data/precess.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.data/precess.c	(revision 3338)
@@ -0,0 +1,49 @@
+# include "data.h"
+    
+double get_epoch (char *in_epoch, char mode) {
+
+  int done;
+  double epoch;
+
+  epoch = 2000.0;
+  done = FALSE;
+  if (in_epoch[0] == 'B') {
+    epoch = BtoJ(atof(&in_epoch[1]));
+    done = TRUE;
+  }
+
+  if (in_epoch[0] == 'J') {
+    epoch = atof(&in_epoch[1]);
+    done = TRUE;
+  }
+
+  if (!done && (mode == 'B')) {
+    epoch = BtoJ(atof(in_epoch));
+    done = TRUE;
+  }
+    
+  if (!done && (mode == 'J')) {
+    epoch = atof(in_epoch);
+    done = TRUE;
+  }
+
+  if (!done) {
+    fprintf (stderr, "error finding epoch %s\n", in_epoch);
+    exit (0);
+  }
+  
+  return (epoch);
+
+}
+
+  
+double BtoJ (double in_epoch) {
+
+  double JD, out_epoch;
+
+  JD = (in_epoch - 1900.0)*365.242198781 + 2415020.31352;
+  out_epoch = 2000.0 + (JD - 2451545.0)/365.25;
+
+  return (out_epoch);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.data/sort.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.data/sort.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.data/sort.c	(revision 3338)
@@ -0,0 +1,292 @@
+# include "data.h"
+
+void sort (double *value, int N) {
+
+  int l,j,ir,i;
+  double temp;
+  
+  if (N < 2) return;
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      temp = value[--l];
+    }
+    else {
+      temp = value[ir];
+      value[ir] = value[0];
+      if (--ir == 0) {
+	value[0] = temp;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && value[j] < value[j+1]) ++j;
+      if (temp < value[j]) {
+	value[i]=value[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    value[i] = temp;
+  }
+}
+
+void fsort (float *value, int N) {
+
+  int l,j,ir,i;
+  float temp;
+  
+  if (N < 2) return;
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      temp = value[--l];
+    }
+    else {
+      temp = value[ir];
+      value[ir] = value[0];
+      if (--ir == 0) {
+	value[0] = temp;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && value[j] < value[j+1]) ++j;
+      if (temp < value[j]) {
+	value[i]=value[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    value[i] = temp;
+  }
+}
+
+void sortpair (double *value1, double *value2, int N) {
+
+  int l,j,ir,i;
+  double temp1, temp2;
+  
+  if (N < 2) return;
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      temp1 = value1[l];
+      temp2 = value2[l];
+    }
+    else {
+      temp1 = value1[ir];
+      temp2 = value2[ir];
+      value1[ir] = value1[0];
+      value2[ir] = value2[0];
+      if (--ir == 0) {
+	value1[0] = temp1;
+	value2[0] = temp2;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && value1[j] < value1[j+1]) ++j;
+      if (temp1 < value1[j]) {
+	value1[i]=value1[j];
+	value2[i]=value2[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    value1[i] = temp1;
+    value2[i] = temp2;
+  }
+}
+
+void fsortpair (float *X, float *Y, int N) {
+
+  int l,j,ir,i;
+  float tX, tY;
+  
+  if (N < 2) return;
+  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;
+  }
+}
+
+void sortthree (float *X, float *Y, float *Z, int N) {
+
+  int l,j,ir,i;
+  float tX, tY, tZ;
+  
+  if (N < 2) return;
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tX = X[l];
+      tY = Y[l];
+      tZ = Z[l];
+    }
+    else {
+      tX = X[ir];
+      X[ir] = X[0];
+      tY = Y[ir];
+      Y[ir] = Y[0];
+      tZ = Z[ir];
+      Z[ir] = Z[0];
+      if (--ir == 0) {
+	X[0] = tX;
+	Y[0] = tY;
+	Z[0] = tZ;
+	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];
+	Z[i] = Z[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    X[i] = tX;
+    Y[i] = tY;
+    Z[i] = tZ;
+  }
+}
+
+void sort_lists (float *X, float *Y, int *S, int N) {
+
+  int l,j,ir,i;
+  double tX, tY, tS;
+  
+  if (N < 2) return;
+  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;
+  }
+}
+
+void dsort_lists (double *X, double *Y, int *S, int N) {
+
+  int l,j,ir,i;
+  double tX, tY, tS;
+  
+  if (N < 2) return;
+  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: /tags/opihi-2-1/Ohana/src/opihi/lib.data/spline.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.data/spline.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.data/spline.c	(revision 3338)
@@ -0,0 +1,58 @@
+# include "data.h"
+
+/* construct the natural spline for x, y in y2 */
+void spline (float *x, float *y, int N, float *y2) {
+
+  int i;
+  float dy, dx, *tmp;
+  
+  ALLOCATE (tmp, float, N);
+
+  y2[0] = tmp[0] = 0.0;
+  
+  for (i = 1; i < N-1; i++) {
+    dx = (x[i+0] - x[i-1]) / (x[i+1] - x[i-1]);
+    dy = dx * y2[i-1] + 2.0;
+    y2[i] = (dx - 1.0) / dy;
+    tmp[i] = (y[i+1] - y[i+0]) / (x[i+1] - x[i+0]) - (y[i+0] - y[i-1]) / (x[i+0] - x[i-1]);
+    tmp[i] = (6.0 * tmp[i] / (x[i+1] - x[i-1]) - dx*tmp[i-1]) / dy;
+  }
+  
+  y2[N-1] = 0;
+  for (i = N-2; i >= 1; i--)
+    y2[i] = y2[i]*y2[i+1] + tmp[i];
+
+  free (tmp);
+}
+
+/* evaluate spline for x, y, y2 at X */
+float splint (float *x, float *y, float *y2, int N, float X) {
+
+  int i, lo, hi;
+  float dx, a, b, value;
+  
+  /* find correct element in array (x must be sorted) */
+  lo = 0;
+  hi = N-1;
+  while (hi - lo > 1) {
+    i = (hi+lo) >> 1;
+    if (x[i] > X) 
+      hi = i;
+    else 
+      lo = i;
+  }
+
+  /* error condition: duplicate abssisca */
+  dx = x[hi] - x[lo];
+  if (dx == 0.0) {
+    return (HUGE_VAL);
+  }
+
+  /* evaluate spline */
+  a = (x[hi] - X) / dx;
+  b = (X - x[lo]) / dx;
+
+  value = a*y[lo] + b*y[hi] + ((a*a*a - a)*y2[lo] + (b*b*b - b)*y2[hi])*(dx*dx) / 6.0;
+  return (value);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.data/starfuncs.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.data/starfuncs.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.data/starfuncs.c	(revision 3338)
@@ -0,0 +1,248 @@
+# include "data.h"
+
+double get_aperture_stats (Matrix *matrix, int X, int Y, int Npix, int Nborder, double max) {
+
+  double *ring;
+  double x, y, x2, y2, I, sky, FWHMx, FWHMy, value, mag;
+  int i, j, n, Npix2, Nring, Nmax;
+  double Npts, gain, dsky2, dmag, peak, offset;
+  char *string;
+  
+  string = get_variable ("GAIN");
+  if (string == (char *) NULL) {
+    fprintf (stderr, "assuming a value of 1.0\n");
+    gain = 1.0;
+  } else {
+    gain = atof (string);
+  }
+  Nborder = MAX (1, Nborder);
+  Nborder = MIN (1000, Nborder);
+  
+  Npix2 = (int)(0.5*Npix);
+  Npix = 2 * Npix2 + 1;
+  Nring = 4*Nborder*(Nborder + Npix);
+  ALLOCATE (ring, double, Nring);
+  bzero (ring, sizeof(double)*Nring);
+
+  n = 0;  
+  for (j = 0; j < Nborder; j++) {
+    for (i = X - Npix2 - Nborder; i < X + Npix2 + Nborder + 1; i++, n+=2) {
+      ring[n]   = fits_get_matrix_value (matrix, i, (int)(Y - Npix2 - j));
+      ring[n+1] = fits_get_matrix_value (matrix, i, (int)(Y + Npix2 + j));
+    }
+    for (i = Y - Npix2; i < Y + Npix2 + 1; i++, n+=2) {
+      ring[n]   = fits_get_matrix_value (matrix, (int)(X - Npix2 - j), i);
+      ring[n+1] = fits_get_matrix_value (matrix, (int)(X + Npix2 + j), i);
+    }
+  }
+  sort (ring, Nring);
+  for (Npts = sky = dsky2 = 0, i = 0.25*Nring; i < 0.75*Nring; i++, Npts += 1.0) {
+    sky += ring[i];
+    dsky2 += ring[i]*ring[i];
+  }
+  sky = sky / Npts;
+  dsky2 = dsky2 / Npts - sky*sky;
+  free (ring);
+
+  peak = 0;
+  Npts = Nmax = 0;
+  x = y = x2 = y2 = I = 0;
+  for (i = X - Npix2; i < X + Npix2 + 1; i++) {
+    for (j = Y - Npix2; j < Y + Npix2 + 1; j++) {
+      value = fits_get_matrix_value (matrix, i, j);
+      offset = value - sky;
+      x  += i*offset;
+      y  += j*offset;
+      x2 += i*i*offset;
+      y2 += j*j*offset;
+      I  += offset;
+      Npts ++;
+      if (value > max) {
+	Nmax ++;
+      }
+      if (value > peak) peak = value;
+    }
+  }
+
+  x = x / I;
+  y = y / I;
+  FWHMx = 2.355*sqrt (fabs(x2 / I - x*x));
+  FWHMy = 2.355*sqrt (fabs(y2 / I - y*y));
+  mag = -2.5*log10(I);
+  dmag = sqrt (fabs(1.0 / (gain*I) + Npts*dsky2 / (I*I)));
+  x = x + 1;
+  y = y + 1;
+  
+  set_variable ("Xg", x);
+  set_variable ("Yg", y);
+  set_variable ("SXg", FWHMx);
+  set_variable ("SYg", FWHMy);
+  set_variable ("Sg", sky);
+  set_variable ("dSg", sqrt (fabs (dsky2)));
+  set_variable ("Zg", mag);
+  set_variable ("dZg", dmag);
+  set_variable ("Zcg", I);
+  set_variable ("Zpk", peak);
+  set_int_variable ("Nsat", Nmax);
+  
+  fprintf (GetOutfile(), "%f %f %f %f %f %f %f %f\n", x, y, FWHMx, FWHMy, sky, I, mag, dmag);
+
+  return (mag);
+
+}
+
+static double Raper  =  5;
+static double Rinner = 10;
+static double Router = 15;
+static double *sky = NULL;
+
+int set_rough_radii (double Ra, double Ri, double Ro) {
+
+  Raper = Ra;
+  Rinner = Ri;
+  Router = Ro;
+  if (sky == NULL) {
+    ALLOCATE (sky, double, SQ(2*Router + 1));
+  } else {
+    REALLOCATE (sky, double, SQ(2*Router + 1));
+  }
+  return (TRUE);
+}
+
+/* use a circular aperture */
+int get_rough_star (float *data, int Nx, int Ny, int x, int y,
+		    float *xc, float *yc, 
+		    float *sx, float *sy, float *sxy,
+		    float *zs, float *zp, float *sk) {
+
+  double Ra2, Ri2, Ro2, rad2;
+  int i, j, Npts, Nsky;
+  int Xs, Xe, Ys, Ye, off, Xc, Yc;
+  double peak, fsky, value;
+  double Sx, Sy, Sx2, Sy2, Sxy, Sum;
+  
+  /* define circular boundaries */
+  Ra2 = SQ(Raper);
+  Ri2 = SQ(Rinner);
+  Ro2 = SQ(Router);
+
+  /* measure the sky level */
+  /* boundaries for the outer sky region */
+  Xs = MAX (x - Router, 0);
+  Xe = MIN (x + Router + 1, Nx);
+  Ys = MAX (y - Router, 0);
+  Ye = MIN (y + Router + 1, Ny);
+
+/* this sample uses a circular aperture */
+# if (0)
+  Nsky = 0;  
+  for (j = Ys; j < Ye; j++) {
+    off = j*Nx;
+    for (i = Xs; i < Xe; i++) { 
+      rad2 = SQ(i - x) + SQ(j - y);
+      if (rad2 > Ro2) continue;
+      if (rad2 < Ri2) continue;
+      sky[Nsky] = data[i+off];
+      Nsky ++;
+    }
+  }
+  sort (sky, Nsky);
+  for (Npts = fsky = 0, i = 0.25*Nsky; i < 0.75*Nsky; i++, Npts += 1.0) {
+    fsky += sky[i];
+  }
+  fsky = fsky / Npts;
+# else
+
+/* this sample uses a square outer annulus, without loop if tests */
+  Nsky = 0;  
+  Xs = MAX (x - Router, 0);
+  Xe = MIN (x - Rinner + 1, Nx);
+  Ys = MAX (y - Rinner, 0);
+  Ye = MIN (y + Rinner + 1, Ny);
+  for (j = Ys; j < Ye; j++) {
+    off = j*Nx;
+    for (i = Xs; i < Xe; i++) { 
+      sky[Nsky] = data[i+off];
+      Nsky ++;
+    }
+  }
+  Xs = MAX (x + Rinner, 0);
+  Xe = MIN (x + Router + 1, Nx);
+  for (j = Ys; j < Ye; j++) {
+    off = j*Nx;
+    for (i = Xs; i < Xe; i++) { 
+      sky[Nsky] = data[i+off];
+      Nsky ++;
+    }
+  }
+  Xs = MAX (x - Rinner, 0);
+  Xe = MIN (x - Rinner + 1, Nx);
+  Ys = MAX (y - Router, 0);
+  Ye = MIN (y - Rinner + 1, Ny);
+  for (j = Ys; j < Ye; j++) {
+    off = j*Nx;
+    for (i = Xs; i < Xe; i++) { 
+      sky[Nsky] = data[i+off];
+      Nsky ++;
+    }
+  }
+  Ys = MAX (y + Rinner, 0);
+  Ye = MIN (y + Router + 1, Ny);
+  for (j = Ys; j < Ye; j++) {
+    off = j*Nx;
+    for (i = Xs; i < Xe; i++) { 
+      sky[Nsky] = data[i+off];
+      Nsky ++;
+    }
+  }
+  sort (sky, Nsky);
+  for (Npts = fsky = 0, i = 0.25*Nsky; i < 0.75*Nsky; i++, Npts += 1.0) {
+    fsky += sky[i];
+  }
+  fsky = fsky / Npts;
+# endif
+
+  /* boundaries for the star region */
+  Xs = MAX (x - Raper, 0);
+  Xe = MIN (x + Raper + 1, Nx);
+  Ys = MAX (y - Raper, 0);
+  Ye = MIN (y + Raper + 1, Ny);
+
+  /** note that this will fail on negative flux objects */
+  peak = Npts = 0;
+  Sx = Sy = Sx2 = Sy2 = Sxy = Sum = 0;
+  for (j = Ys; j < Ye; j++) {
+    off = j*Nx;
+    Yc = j - y;
+    for (i = Xs; i < Xe; i++) {
+      Xc = i - x;
+      rad2 = SQ(Xc) + SQ(Yc);
+      if (rad2 > Ro2) continue;
+      value = data[i+off] - fsky;
+      Sx  += Xc*value;
+      Sy  += Yc*value;
+      Sx2 += Xc*Xc*value;
+      Sy2 += Yc*Yc*value;
+      Sxy += Xc*Yc*value;
+      Sum += value;
+      Npts ++;
+      if (value > peak) peak = value;
+    }
+  }
+
+  *xc = Sx / Sum;
+  *yc = Sy / Sum;
+  *sx = sqrt (fabs (Sx2 / Sum - SQ(*xc)));
+  *sy = sqrt (fabs (Sy2 / Sum - SQ(*yc)));
+  *sxy = Sxy / Sum;
+  *xc += x;
+  *yc += y;
+  *zs = Sum;
+  *zp = peak;
+  *sk = fsky;
+  /* note sigma is rough: round-off errors can introduce errors */
+  /* using values relative to x,y should minimize this effect */
+
+  return (Npts);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.data/svdcmp.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.data/svdcmp.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.data/svdcmp.c	(revision 3338)
@@ -0,0 +1,210 @@
+# include "data.h"
+
+/*
+  static float at,bt,ct;
+  #define PYTHAG(a,b) ((at=fabs(a)) > (bt=fabs(b)) ? \
+  (ct=bt/at,at*sqrt(1.0+ct*ct)) : (bt ? (ct=at/bt,bt*sqrt(1.0+ct*ct)): 0.0))
+  pythag -> hypot (check on roundoff errors) 
+*/
+
+/* use simple max? */
+#define FSIGN(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a))
+
+/* n == Nx, m == Ny */
+int svdcmp (float *a, float *w, float *v, int Nx, int Ny) {
+
+  int flag, i, its, j, jj, k, l, nm, status;
+  float c, f, h, s, x, y, z;
+  float anorm=0.0, g = 0.0, scale = 0.0;
+  float *rv1;
+
+  if (Ny < Nx) return (0);
+
+  ALLOCATE (rv1, float, Nx);
+  for (i = 0; i < Nx; i++) {
+    l = i + 1;
+    rv1[i] = scale*g;
+    g = s = scale = 0.0;
+    if (i < Ny) {
+      for (k = i; k < Ny; k++) scale += fabs(a[k*Nx + i]);
+      if (scale) {
+	for (k = i; k < Ny; k++) {
+	  a[k*Nx + i] /= scale;
+	  s += a[k*Nx + i]*a[k*Nx + i];
+	}
+	f = a[i*Nx + i];
+	g  = -FSIGN(sqrt(s), f);
+	h = f*g - s;
+	a[i*Nx + i] = f-g;
+	if (i != Nx - 1) {
+	  for (j = l; j < Nx; j++) {
+	    for (s = 0.0, k = i; k < Ny; k++) s += a[k*Nx + i]*a[k*Nx + j];
+	    f = s/h;
+	    for (k = i; k < Ny; k++) a[k*Nx + j] += f*a[k*Nx + i];
+	  }
+	}
+	for (k = i; k < Ny; k++) a[k*Nx + i] *= scale;
+      }
+    }
+    w[i] = scale*g;
+    g = s = scale = 0.0;
+    if ((i < Ny) && (i != (Nx - 1))) {
+      for (k = l; k < Nx; k++) scale += fabs(a[i*Nx + k]);
+      if (scale) {
+	for (k = l; k < Nx; k++) {
+	  a[i*Nx + k] /= scale;
+	  s += a[i*Nx + k]*a[i*Nx + k];
+	}
+	f = a[i*Nx + l];
+	g = -FSIGN(sqrt(s), f);
+	h = f*g - s;
+	a[i*Nx + l] = f-g;
+	for (k = l; k < Nx; k++) rv1[k] = a[i*Nx + k]/h;
+	if (i != Ny - 1) {
+	  for (j = l; j < Ny; j++) {
+	    for (s = 0.0, k = l; k < Nx; k++) s += a[j*Nx + k]*a[i*Nx + k];
+	    for (k = l; k < Nx; k++) a[j*Nx + k] += s*rv1[k];
+	  }
+	}
+	for (k = l; k < Nx; k++) a[i*Nx + k] *= scale;
+      }
+    }
+    anorm = MAX(anorm, (fabs(w[i]) + fabs(rv1[i])));
+  }
+
+  for (i = Nx - 1; i >= 0; i--) {
+    if (i < Nx - 1) {
+      if (g) {
+	/* isn't l == n to start?? */
+	for (j = l; j < Nx; j++) v[j*Nx + i] = (a[i*Nx + j]/a[i*Nx + l])/g;
+	for (j = l; j < Nx; j++) {
+	  for (s = 0.0, k = l; k < Nx; k++) s += a[i*Nx + k]*v[k*Nx + j];
+	  for (k = l; k < Nx; k++) v[k*Nx + j] += s*v[k*Nx + i];
+	}
+      }
+      for (j = l; j < Nx; j++) v[i*Nx + j] = v[j*Nx + i] = 0.0;
+    }
+    v[i*Nx + i] = 1.0;
+    g = rv1[i];
+    l = i;
+  }
+  for (i = Nx - 1; i >= 0; i--) {
+    l = i + 1;
+    g = w[i];
+    if (i < Nx - 1)
+      for (j = l; j < Nx; j++) a[i*Nx + j] = 0.0;
+    if (g) {
+      g = 1.0/g;
+      if (i != Nx - 1) {
+	for (j = l; j < Nx; j++) {
+	  for (s = 0.0, k = l; k < Ny; k++) s += a[k*Nx + i]*a[k*Nx + j];
+	  f = (s/a[i*Nx + i])*g;
+	  for (k = i; k < Ny; k++) a[k*Nx + j] += f*a[k*Nx + i];
+	}
+      }
+      for (j = i; j < Ny; j++) a[j*Nx + i] *= g;
+    } else {
+      for (j = i; j < Ny; j++) a[j*Nx + i] = 0.0;
+    }
+    ++a[i*Nx + i];
+  }
+
+  status = 1;
+  for (k = Nx - 1; k >= 0; k--) {
+    for (its = 0; its < 30; its++) {
+      flag = 1;
+      for (l = k; l >= 0; l--) {
+	nm = l - 1;
+	if (fabs(rv1[l])+anorm == anorm) {
+	  flag = 0;
+	  break;
+	}
+	if (fabs(w[nm])+anorm == anorm) break;
+      }
+      if (flag) {
+	c = 0.0;
+	s = 1.0;
+	for (i = l; i < k; i++) {
+	  f = s*rv1[i];
+	  if (fabs(f)+anorm != anorm) {
+	    g = w[i];
+	    h = hypot (f, g);
+	    w[i] = h;
+	    h = 1.0/h;
+	    c = g*h;
+	    s = (-f*h);
+	    for (j = 0; j < Ny; j++) {
+	      y = a[j*Nx + nm];
+	      z = a[j*Nx + i];
+	      a[j*Nx + nm] = y*c + z*s;
+	      a[j*Nx + i] = z*c - y*s;
+	    }
+	  }
+	}
+      }
+      z = w[k];
+      if (l == k) {
+	if (z < 0.0) {
+	  w[k] = -z;
+	  for (j = 0; j < Nx; j++) v[j*Nx + k] = (-v[j*Nx + k]);
+	}
+	break;
+      }
+      if (its == 29) status = 0;
+      x = w[l];
+      nm = k-1;
+      y = w[nm];
+      g = rv1[nm];
+      h = rv1[k];
+      f = ((y-z)*(y+z) + (g-h)*(g+h))/(2.0*h*y);
+      g = hypot (f, 1.0);
+      f = ((x-z)*(x+z) + h*((y/(f+FSIGN(g, f)))-h))/x;
+      c = s = 1.0;
+      for (j = l; j < nm; j++) {
+	i = j+1;
+	g = rv1[i];
+	y = w[i];
+	h = s*g;
+	g = c*g;
+	z = hypot (f, h);
+	rv1[j] = z;
+	c = f/z;
+	s = h/z;
+	f = x*c+g*s;
+	g = g*c-x*s;
+	h = y*s;
+	y = y*c;
+	for (jj = 0; jj < Nx; jj++) {
+	  x = v[jj*Nx + j];
+	  z = v[jj*Nx + i];
+	  v[jj*Nx + j] = x*c+z*s;
+	  v[jj*Nx + i] = z*c-x*s;
+	}
+	z = hypot(f, h);
+	w[j] = z;
+	if (z) {
+	  z = 1.0/z;
+	  c = f*z;
+	  s = h*z;
+	}
+	f = (c*g) + (s*y);
+	x = (c*y) - (s*g);
+	for (jj = 0; jj < Ny; jj++) {
+	  y = a[jj*Nx + j];
+	  z = a[jj*Nx + i];
+	  a[jj*Nx + j] = y*c+z*s;
+	  a[jj*Nx + i] = z*c-y*s;
+	}
+      }
+      rv1[l] = 0.0;
+      rv1[k] = f;
+      w[k] = x;
+    }
+  }
+  free(rv1);
+  return (1);
+}
+
+#undef FSIGN
+#undef MAX
+#undef PYTHAG
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/BufferOps.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/BufferOps.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/BufferOps.c	(revision 3338)
@@ -0,0 +1,251 @@
+# include "opihi.h"
+
+static Buffer **buffers;
+static int     Nbuffers;
+
+void InitBuffers () {
+  Nbuffers = 0;
+  ALLOCATE (buffers, Buffer *, 1);
+}
+
+Buffer *InitBuffer () {
+  Buffer *buf;
+
+  ALLOCATE (buf, Buffer, 1);
+  bzero (buf[0].name, 1024);
+  bzero (buf[0].file, 1024);
+  ALLOCATE (buf[0].matrix.buffer, char, 1);
+  ALLOCATE (buf[0].header.buffer, char, 1);
+  return (buf);
+}
+
+int IsBuffer (char *name) {
+ 
+  int i;
+
+  if (name == NULL) return (FALSE);
+
+  for (i = 0; (i < Nbuffers) && (strcmp(buffers[i][0].name, name)); i++);
+  if (i == Nbuffers) return (FALSE);
+  return (TRUE);
+}
+
+int IsBufferPtr (Buffer *buf) {
+ 
+  int i;
+
+  if (buf == NULL) return (FALSE);
+
+  for (i = 0; (i < Nbuffers) && (buffers[i] != buf); i++);
+  if (i == Nbuffers) return (FALSE);
+  return (TRUE);
+}
+
+Buffer *SelectBuffer (char *name, int mode, int verbose) {
+
+  int i;
+
+  if (name == NULL) goto error;
+  if (ISNUM(name[0])) goto error;
+  if (IsVector(name)) goto error;
+
+  for (i = 0; (i < Nbuffers) && (strcmp(buffers[i][0].name, name)); i++);
+  /* is a new buffer */
+  if (i == Nbuffers) { 
+    if (mode == OLDBUFFER) goto error;
+    Nbuffers += 1;
+    REALLOCATE (buffers, Buffer *, Nbuffers);
+    buffers[i] = InitBuffer ();
+    strcpy (buffers[i][0].name, name);
+    return (buffers[i]);
+  } 
+  /* is an old buffer */
+  if (mode == NEWBUFFER) goto error;
+  return (buffers[i]);
+
+ error:
+  if (verbose) fprintf (stderr, "invalid matrix %s\n", name);
+  return (NULL);
+}
+
+int CreateBuffer (Buffer *buf) {
+
+  /* store the default output values */
+  buf[0].bitpix = buf[0].header.bitpix;
+  buf[0].unsign = buf[0].header.unsign;
+  buf[0].bzero  = buf[0].header.bzero;
+  buf[0].bscale = buf[0].header.bscale;
+  
+  /* assign the necessary internal values */
+  buf[0].header.bitpix   = -32;
+  buf[0].header.unsign   = FALSE;
+  buf[0].header.bzero    = 0;
+  buf[0].header.bscale   = 1;
+  
+  /* make some test of the validity of the values */
+
+  /* create the appropriate header and matrix */
+  fits_create_header (&buf[0].header);
+  fits_create_matrix (&buf[0].header, &buf[0].matrix);
+
+  return (TRUE);
+}
+  
+/* copy data from in to out - new memory space */
+int CopyNamedBuffer (char *out, char *in) {
+  Buffer *In, *Out;
+  if ((In  = SelectBuffer (in,  OLDBUFFER, FALSE)) == NULL) return (FALSE);
+  if ((Out = SelectBuffer (out, ANYBUFFER, FALSE)) == NULL) return (FALSE);
+  CopyBuffer (Out, In);
+  return (TRUE);
+}
+
+int CopyBuffer (Buffer *out, Buffer *in) {
+  free (out[0].matrix.buffer);
+  free (out[0].header.buffer);
+  out[0].bitpix = in[0].bitpix;
+  out[0].unsign = in[0].unsign;
+  out[0].bscale = in[0].bscale;
+  out[0].bzero  = in[0].bzero;
+  strcpy (out[0].file, in[0].file);
+  fits_copy_matrix (&in[0].matrix, &out[0].matrix);
+  fits_copy_header (&in[0].header, &out[0].header);
+  return (TRUE);
+}
+
+/* move data from in to out - use old memory space */
+int MoveNamedBuffer (char *out, char *in) {
+  Buffer *In, *Out;
+  if ((In  = SelectBuffer (in,  OLDBUFFER, FALSE)) == NULL) return (FALSE);
+  if ((Out = SelectBuffer (out, ANYBUFFER, FALSE)) == NULL) return (FALSE);
+  MoveBuffer (Out, In);
+  return (TRUE);
+}
+int MoveBuffer (Buffer *out, Buffer *in) {
+  int i, j;
+
+  free (out[0].matrix.buffer);
+  free (out[0].header.buffer);
+  out[0].bitpix = in[0].bitpix;
+  out[0].unsign = in[0].unsign;
+  out[0].bscale = in[0].bscale;
+  out[0].bzero  = in[0].bzero;
+  out[0].matrix = in[0].matrix;
+  out[0].header = in[0].header;
+  strcpy (out[0].file, in[0].file);
+
+  /* delete buffer entry from buffer list, if it exists */
+  for (i = 0; (i < Nbuffers) && (in != buffers[i]); i++);
+  if (i == Nbuffers) return (TRUE);
+
+  free (in);
+  for (j = i; j < Nbuffers - 1; j++) buffers[j] = buffers[j + 1];
+  Nbuffers -= 1;
+  REALLOCATE (buffers, Buffer *, MAX (Nbuffers, 1));
+  return (TRUE);
+}
+
+/* delete by ptr */
+int DeleteBuffer (Buffer *buf) {
+
+  int i, j;
+
+  if (buf == NULL) return (FALSE);
+  for (i = 0; (i < Nbuffers) && (buf != buffers[i]); i++);
+  if (i == Nbuffers) return (FALSE);
+
+  fits_free_header (&buffers[i][0].header);
+  fits_free_matrix (&buffers[i][0].matrix);
+
+  for (j = i; j < Nbuffers - 1; j++) buffers[j] = buffers[j + 1];
+
+  Nbuffers -= 1;
+  REALLOCATE (buffers, Buffer *, MAX (Nbuffers, 1));
+  return (TRUE);
+}
+  
+/* delete by name */
+int DeleteNamedBuffer (char *name) {
+
+  int i, j;
+
+  if (name == NULL) return (FALSE);
+  for (i = 0; (i < Nbuffers) && (strcmp(buffers[i][0].name, name)); i++);
+  if (i == Nbuffers) return (FALSE);
+
+  fits_free_header (&buffers[i][0].header);
+  fits_free_matrix (&buffers[i][0].matrix);
+
+  for (j = i; j < Nbuffers - 1; j++) buffers[j] = buffers[j + 1];
+
+  Nbuffers -= 1;
+  REALLOCATE (buffers, Buffer *, MAX (Nbuffers, 1));
+  return (TRUE);
+}
+
+int SelectOverlay (char *name, int *number) {
+
+  *number = -1;
+  if (!strcmp (name, "red") || !strcmp (name, "0"))
+    *number = 0;
+  if (!strcmp (name, "green") || !strcmp (name, "1"))
+    *number = 1;
+  if (!strcmp (name, "blue") || !strcmp (name, "2"))
+    *number = 2;
+  if (!strcmp (name, "yellow") || !strcmp (name, "3"))
+    *number = 3;
+
+  if (*number < 0) {
+    fprintf (stderr, "valid overlays may be: red (0), green (1), blue (2), yellow (3)\n");
+    return (FALSE);
+  }
+  else {
+    return (TRUE);
+  }
+}
+
+void dump_buffers (int n) {
+
+  int i;
+
+  fprintf (stderr, "try %d\n", n);
+  for (i = 0; i < Nbuffers; i++) {
+    fprintf (stderr, "%d  %lx\n", i, (long) buffers[i]);
+    fprintf (stderr, "%d  %lx  %s\n", i, (long) buffers[i][0].name, buffers[i][0].name);
+    fprintf (stderr, "%d  %lx  %s\n", i, (long) buffers[i][0].file, buffers[i][0].file);
+    fprintf (stderr, "%d  %lx  %lx\n", i, (long) &buffers[i][0].header, (long) buffers[i][0].header.buffer);
+    fprintf (stderr, "%d  %lx  %lx\n", i, (long) &buffers[i][0].matrix, (long) buffers[i][0].matrix.buffer);
+    fprintf (stderr, "%d  %d  %d  %f %f\n", i, buffers[i][0].bitpix, buffers[i][0].unsign, buffers[i][0].bscale, buffers[i][0].bzero);
+  }
+}
+
+int PrintBuffers (int Long) {
+
+  int i;
+
+  if (Nbuffers == 0) {
+    fprintf (stderr, "No allocated buffers\n");
+    return (TRUE);
+  }
+  
+  if (Long) {
+    fprintf (GetOutfile(), "    N       name                      file     X     Y    bytes BP  U   bzero     bscale  \n");
+    for (i = 0; i < Nbuffers; i++) {
+      fprintf (GetOutfile(), "%5d %10s %25s %5d %5d %10d %3d %1d %10.4e %10.4e\n",
+	       i, buffers[i][0].name, buffers[i][0].file, 
+	       buffers[i][0].header.Naxis[0], buffers[i][0].header.Naxis[1],
+	       buffers[i][0].header.size + buffers[i][0].matrix.size, buffers[i][0].bitpix, 
+	       buffers[i][0].unsign, buffers[i][0].bzero, buffers[i][0].bscale);
+    }
+    return (TRUE);
+  }
+
+  fprintf (GetOutfile(), "    N       name                      file     X     Y    bytes\n");
+  for (i = 0; i < Nbuffers; i++) {
+    fprintf (GetOutfile(), "%5d %10s %25s %5d %5d %10d\n",
+	     i, buffers[i][0].name, buffers[i][0].file, 
+	     buffers[i][0].header.Naxis[0], buffers[i][0].header.Naxis[1],
+	     buffers[i][0].header.size + buffers[i][0].matrix.size);
+  }
+  return (TRUE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/CommandOps.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/CommandOps.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/CommandOps.c	(revision 3338)
@@ -0,0 +1,174 @@
+# include "opihi.h"
+
+static Command  *commands;
+static int      Ncommands;
+static int      NCOMMANDS;
+
+void InitCommands () {
+  NCOMMANDS = 20;
+  Ncommands = 0;
+  ALLOCATE (commands, Command, NCOMMANDS);
+}
+
+void AddCommand (Command *new) {
+  
+  commands[Ncommands] = *new;
+  Ncommands ++;
+  if (Ncommands == NCOMMANDS) {
+    NCOMMANDS += 20;
+    REALLOCATE (commands, Command, NCOMMANDS);
+  }
+}
+
+int DeleteCommand (Command *command) {
+
+  int i, Nc;
+
+  Nc = -1;
+  for (i = 0; i < Ncommands; i++) {
+    if (command == &commands[i]) {
+      Nc = i;
+      break;
+    }
+  }
+  if (Nc == -1) {
+    fprintf (stderr, "programming error: command not found\n");
+    return (FALSE);
+  }
+
+  free (commands[Nc].name);
+  for (i = Nc + 1; i < Ncommands; i++)
+    commands[i - 1] = commands[i];
+  Ncommands --;
+  REALLOCATE (commands, Command, Ncommands);
+  return (TRUE);
+}
+
+/* return command which unambiguously matches name */
+Command *MatchCommand (char *name, int VERBOSE, int EXACT) {
+
+  int i, match[10], Nmatch;
+
+  /* try for an exact match first */
+  for (i = 0; i < Ncommands; i++) {
+    if (!strcmp (commands[i].name, name)) {
+      return (&commands[i]);
+    }
+  }
+  if (EXACT) {
+    if (VERBOSE) fprintf (stderr, "no exact match to %s\n", name);
+    return (NULL);
+  }
+
+  /* not found as complete command, try partial */
+  Nmatch = 0;
+  for (i = 0; (Nmatch < 10) && (i < Ncommands); i++) {
+    if (!strncmp (commands[i].name, name, strlen(name))) {  /* found a command */
+      match[Nmatch] = i;
+      Nmatch ++;
+    }
+  }
+  if (Nmatch == 1) return (&commands[match[0]]);
+
+  if (Nmatch > 1) {
+    if (VERBOSE) {
+      fprintf (stderr, "ambiguous command: %s ( ", name);
+      for (i = 0; i < Nmatch; i++) {
+	fprintf (stderr, "%s ", commands[match[i]].name);
+      }
+      fprintf (stderr, ")\n");
+    }
+    return (NULL);
+  }
+  if (VERBOSE) fprintf (stderr, "%s: Command not found.\n", name);
+  return (NULL);
+}  
+
+/* generate a command completion list for readline */
+char *command_generator (const char *text, int state) {
+
+  /* i must be remembered from call to call */
+  static int i, len;
+
+  /* On first call, state is set to 0: initial the state */
+  if (!state) {
+    i = -1;  
+    len = strlen (text);
+  }
+
+  /* Return the next partial match from the command list */
+  for (i++; i < Ncommands; i++) {
+    if (!len) 
+      return (strcreate(commands[i].name));
+    if (!strncmp (commands[i].name, text, len)) {
+      return (strcreate(commands[i].name));
+    }
+  }
+
+  /* If no names matched, then return NULL. */
+  return ((char *)NULL);
+}
+
+/* tell readline to use out command_generator rather than basic completion */
+char **command_completer (const char *text, int start, int end) {
+  
+  char **matches;
+
+  matches = (char **) NULL;
+  
+  if (start == 0)
+    matches = rl_completion_matches (text, command_generator);
+
+  return (matches);
+}
+
+void print_commands (FILE *f) {
+
+  int i, *seq;
+
+  ALLOCATE (seq, int, Ncommands);
+  sort_commands (seq);
+  for (i = 0; i < Ncommands; i++) {
+    fprintf (f, "%-25s -- %s\n", commands[seq[i]].name, commands[seq[i]].help);
+  }
+  free (seq);
+
+  return;
+}
+
+void sort_commands (int *seq) {
+
+  int l,j,ir,i, N;
+  int temp;
+  
+  N = Ncommands;
+  for (i = 0; i < N; i++) 
+    seq[i] = i;
+  
+  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 && (strcmp (commands[seq[j]].name, commands[seq[j+1]].name) < 0)) ++j;
+      if (strcmp (commands[temp].name, commands[seq[j]].name) < 0) {
+        seq[i]=seq[j];
+        j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    seq[i] = temp;
+  }
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/ConfigInit.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/ConfigInit.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/ConfigInit.c	(revision 3338)
@@ -0,0 +1,48 @@
+# include "opihi.h"
+
+static char *GlobalConfig;
+
+int ConfigInit (int *argc, char **argv) {
+
+  char *config, *file;
+
+  /*** load configuration info ***/
+  file = SelectConfigFile (argc, argv, "ptolemy");
+  config = LoadConfigFile (file);
+  if (config == (char *) NULL) {
+    if (file != (char *) NULL) free (file);
+    return (FALSE);
+  }
+
+  GlobalConfig = config;
+
+  free (file);
+  return (TRUE);
+}
+
+char *VarConfig (char *keyword, char *mode, void *ptr) {
+
+  char *answer;
+
+  answer = get_variable (keyword);
+  if (answer != (char *) NULL) {
+
+    if (!strcmp (mode, "%s")) {
+      strcpy ((char *) ptr, answer);
+    } else {
+      if (!strcmp (mode, "%d"))  *(int *) ptr       = atoi (answer);
+      if (!strcmp (mode, "%u"))  *(unsigned *) ptr  = atoi (answer);
+      if (!strcmp (mode, "%ld")) *(long *) ptr      = atoi (answer);
+      if (!strcmp (mode, "%hd")) *(short *) ptr     = atoi (answer);
+      if (!strcmp (mode, "%f"))  *(float *) ptr     = atof (answer);
+      if (!strcmp (mode, "%lf")) *(double *) ptr    = atof (answer);
+    }
+    free (answer);
+    return (ptr);
+  }
+
+  answer = ScanConfig (GlobalConfig, keyword, mode, 0, ptr);
+  return (answer);
+}
+
+  
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/ListOps.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/ListOps.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/ListOps.c	(revision 3338)
@@ -0,0 +1,141 @@
+# include "opihi.h"
+# include "macro.h"
+
+/* return a new string consisting of the next line in the current list */
+char *get_next_listentry (int ThisList) {
+
+  char *output;
+
+  lists[ThisList].n++;
+
+  if (lists[ThisList].n >= lists[Nlists].Nlines) 
+    return ((char *) NULL);
+
+  output = lists[Nlists].line[lists[ThisList].n];
+  
+  return (output);
+
+}
+
+char *remove_listentry (int current) {
+
+  int i;
+  char *output;
+
+  if ((current + 1) >= lists[Nlists].Nlines) 
+    return ((char *) NULL);
+
+  output = lists[Nlists].line[current + 1];
+  
+  for (i = current + 1; i < lists[Nlists].Nlines - 1; i++) {
+    lists[Nlists].line[i] = lists[Nlists].line[i + 1];
+  }
+
+  lists[Nlists].Nlines --;
+  return (output);
+
+}
+
+int is_for_loop (char *line) {
+
+  char *comm;
+
+  comm = thisword (line);
+  if (comm == (char *) NULL) return (FALSE);
+
+  if (strcmp (comm, "for")) {
+    free (comm);
+    return (FALSE);
+  }
+
+  return (TRUE);
+
+}
+
+int is_macro_create (char *line) {
+
+  int i, N;
+  char *comm;
+  char *this_macro;
+
+
+  comm = thisword (line);
+  if (comm == (char *) NULL)
+    return (FALSE);
+  if (strcmp (comm, "macro")) {
+    free (comm);
+    return (FALSE);
+  }
+  
+  this_macro = thisword (nextword (line));
+
+  if (this_macro == (char *)NULL) {
+    return (FALSE);
+  }
+
+  N = sizeof (in_macro) / sizeof (Command);
+
+  /* find the macro sub-command which matches from the list. */
+  /* if sub-command is not found, assume this is creating a new macro */
+  for (i = 0; i < N; i++) {
+    if (!strcmp (in_macro[i].name, this_macro)) {
+      free (this_macro);
+      return (FALSE);
+    }
+  }
+
+  free (this_macro);
+  return (TRUE);
+
+}
+
+int is_if_block (char *line) {
+
+  char *comm, *temp;
+
+  temp = thisword (nextword (nextword (line)));
+  comm = thisword (line);
+
+  if (comm == NULL) goto escape;
+
+  if (strcmp (comm, "if")) goto escape;
+
+  if ((temp != NULL) && !strcmp (temp, "break")) goto escape;
+
+  free (comm);
+  return (TRUE);
+
+escape: 
+  if (comm != NULL) free (comm);
+  if (temp != NULL) free (temp);
+  return (FALSE);
+}
+
+int is_loop (char *line) {
+
+  char *comm;
+
+  comm = thisword (line);
+  if (comm == (char *) NULL) return (FALSE);
+
+  if (strcmp (comm, "while")) {
+    free (comm);
+    return (FALSE);
+  }
+  free (comm);
+  return (TRUE);
+}
+
+
+int is_list (char *line) {
+  
+  int status;
+
+  status = is_if_block (line);
+  status |= is_macro_create (line);
+  status |= is_for_loop (line);
+  status |= is_loop (line);
+
+  return (status);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/MacroOps.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/MacroOps.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/MacroOps.c	(revision 3338)
@@ -0,0 +1,136 @@
+# include "opihi.h"
+
+static char dot[] = ".";
+
+static Macro *macros;
+static int   Nmacros;
+static int   NMACROS;
+
+static char *MacroName = dot;
+static int   MacroDepth = 0;
+
+void InitMacros () {
+  NMACROS = 20;
+  Nmacros = 0;
+  ALLOCATE (macros, Macro, NMACROS);
+  MacroName = dot;
+  MacroDepth = 0;
+}
+
+void SetCurrentMacroData (char *name, int depth) {
+  MacroName = name;
+  MacroDepth = depth;
+}
+
+char *GetMacroName () {
+  return (MacroName);
+}
+
+int GetMacroDepth () {
+  return (MacroDepth);
+}
+
+Macro *NewMacro (char *name) {
+  
+  macros[Nmacros].name = strcreate (name);;
+  macros[Nmacros].Nlines = 0;
+  ALLOCATE (macros[Nmacros].line, char *, 1);
+  Nmacros ++;
+  if (Nmacros == NMACROS) {
+    NMACROS += 20;
+    REALLOCATE (macros, Macro, NMACROS);
+  }
+  return (&macros[Nmacros-1]);
+}
+
+void ListMacro (Macro *macro) {
+
+  int i;
+
+  if ((macro == NULL) || (macro[0].Nlines == 0)) {
+    fprintf (stderr, "  macro not defined\n");
+    return;
+  }
+  for (i = 0; i < macro[0].Nlines; i++) {
+    fprintf (stderr, "%s\n", macro[0].line[i]);
+  }
+  return;
+}
+
+void FreeMacro (Macro *macro) {
+  
+  int i;
+
+  if (macro == NULL) return;
+
+  for (i = 0; i < macro[0].Nlines; i++) {
+    free (macro[0].line[i]);
+  }
+  free (macro[0].line);
+  free (macro[0].name);
+  return;
+}
+
+int DeleteMacro (Macro *macro) {
+
+  int i, Nm;
+
+  Nm = -1;
+  for (i = 0; i < Nmacros; i++) {
+    if (macro == &macros[i]) {
+      Nm = i;
+      break;
+    }
+  }
+  if (Nm == -1) {
+    fprintf (stderr, "programming error: macro not found\n");
+    return (FALSE);
+  }
+
+  FreeMacro (&macros[Nm]);
+  for (i = Nm + 1; i < Nmacros; i++)
+    macros[i - 1] = macros[i];
+  Nmacros --;
+  return (TRUE);
+}
+
+/* return macro which unambiguously matches name */
+Macro *MatchMacro (char *name, int VERBOSE, int EXACT) {
+
+  int i, match[10], Nmatch;
+
+  /* try for an exact match first */
+  for (i = 0; i < Nmacros; i++) {
+    if (!strcmp (macros[i].name, name)) {
+      return (&macros[i]);
+    }
+  }
+  if (EXACT) {
+    if (VERBOSE) fprintf (stderr, "no exact match to %s\n", name);
+    return (NULL);
+  }
+      
+  /* not found as complete macro, try partial */
+  Nmatch = 0;
+  for (i = 0; (Nmatch < 10) && (i < Nmacros); i++) {
+    if (!strncmp (macros[i].name, name, strlen(name))) {  /* found a macro */
+      match[Nmatch] = i;
+      Nmatch ++;
+    }
+  }
+  if (Nmatch == 1) return (&macros[match[0]]);
+
+  if (Nmatch > 1) {
+    if (VERBOSE) {
+      fprintf (stderr, "ambiguous macro: %s ( ", name);
+      for (i = 0; i < Nmatch; i++) {
+	fprintf (stderr, "%s ", macros[match[i]].name);
+      }
+      fprintf (stderr, ")\n");
+    }
+    return (NULL);
+  }
+  if (VERBOSE) fprintf (stderr, "%s: Macro not found.\n", name);
+  return (NULL);
+}  
+
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/Makefile
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/Makefile	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/Makefile	(revision 3338)
@@ -0,0 +1,118 @@
+include ../../../Configure
+
+HOME    =       $(ROOT)/src/opihi.v2
+BIN     =       $(HOME)/bin
+LIB     =       $(HOME)/lib
+INC     =       $(HOME)/include
+MDIR    =       $(HOME)/misc
+SDIR    =       $(HOME)/lib.shell
+#
+DESTBIN =       $(LBIN)
+DESTLIB =       $(LLIB)
+DESTINC =       $(LINC)
+DESTMAN =       $(LMAN)
+HELP    =       $(HOME)/help
+#  
+INCS    =       -I$(INC) -I$(LINC) -I$(XINC)
+LFLAGS  =       -L$(LLIB) -L$(LIB)
+LIBS    =       -lFITS -lsocket -lnsl -lreadline -ltermcap -lohana -lm
+CFLAGS  =       $(INCS)
+CCFLAGS =       $(LIBS) 
+
+# opihi shell functions (libopihi) ########################
+
+shell = \
+$(SDIR)/ConfigInit.$(ARCH).o		\
+$(SDIR)/ListOps.$(ARCH).o	   	\
+$(SDIR)/command.$(ARCH).o               \
+$(SDIR)/CommandOps.$(ARCH).o		\
+$(SDIR)/errors.$(ARCH).o		\
+$(SDIR)/expand_vars.$(ARCH).o           \
+$(SDIR)/expand_vectors.$(ARCH).o        \
+$(SDIR)/exec_loop.$(ARCH).o             \
+$(SDIR)/interrupt.$(ARCH).o	        \
+$(SDIR)/MacroOps.$(ARCH).o		\
+$(SDIR)/macro_create.$(ARCH).o          \
+$(SDIR)/macro_delete.$(ARCH).o          \
+$(SDIR)/macro_edit.$(ARCH).o            \
+$(SDIR)/macro_exec.$(ARCH).o            \
+$(SDIR)/macro_list.$(ARCH).o            \
+$(SDIR)/macro_read.$(ARCH).o            \
+$(SDIR)/macro_write.$(ARCH).o		\
+$(SDIR)/multicommand.$(ARCH).o          \
+$(SDIR)/parse.$(ARCH).o                 \
+$(SDIR)/parse_commands.$(ARCH).o	\
+$(SDIR)/startup.$(ARCH).o		\
+$(SDIR)/string.$(ARCH).o                \
+$(SDIR)/timeformat.$(ARCH).o            \
+$(SDIR)/BufferOps.$(ARCH).o             \
+$(SDIR)/VectorOps.$(ARCH).o             \
+$(SDIR)/check_stack.$(ARCH).o           \
+$(SDIR)/convert_to_RPN.$(ARCH).o	\
+$(SDIR)/evaluate_stack.$(ARCH).o  	\
+$(SDIR)/isolate_elements.$(ARCH).o 	\
+$(SDIR)/dvomath.$(ARCH).o               \
+$(SDIR)/stack_math.$(ARCH).o		\
+$(SDIR)/queues.$(ARCH).o		\
+$(SDIR)/variable.$(ARCH).o	   	\
+$(SDIR)/opihi.$(ARCH).o
+
+libshell:    $(DESTLIB)/libshell.a 
+
+$(LIB)/libshell.$(ARCH).a:   	$(shell)
+
+# dependancy rules for include files ########################
+baseinc = $(INC)/external.h $(INC)/shell.h $(INC)/dvomath.h $(INC)/convert.h $(INC)/display.h 
+
+$(shell)   	 : $(INC)/opihi.h $(baseinc)
+
+# utilities #################################################
+$(BIN)/%.$(ARCH):
+	@if [ ! -d $(BIN) ]; then mkdir -p $(BIN); fi
+	$(CC) $^ -o $@ $(LFLAGS) $(LIBS)
+	@echo "compiled $*"
+	@echo ""
+
+$(DESTBIN)/%: $(BIN)/%.$(ARCH) 
+	@if [ ! -d $(DESTBIN) ]; then mkdir -p $(DESTBIN); fi
+	rm -f $(DESTBIN)/$*
+	cp $(BIN)/$*.$(ARCH) $(DESTBIN)/$*
+	@echo "installed $*"
+	@echo ""
+
+$(LIB)/%.$(ARCH).a:
+	@if [ ! -d $(LIB) ]; then mkdir -p $(LIB); fi
+	rm -f $@
+	ar rcv $@ $^ 
+	$(RANLIB) $@
+	@echo "compiled library $*"
+	@echo ""
+
+$(DESTLIB)/%.a: $(LIB)/%.$(ARCH).a
+	@if [ ! -d $(DESTLIB) ]; then mkdir -p $(DESTLIB); fi
+	@echo ""
+	rm -f $@
+	cp $^ $@
+
+lib%.clean:
+	rm -f $(LIB)/lib$*.$(ARCH).a
+	rm -f $($*)
+	@echo ""
+
+%.clean:
+	rm -f $(BIN)/$*.$(ARCH)
+	@echo ""
+
+%.$(ARCH).o : %.c
+	$(CC) $(CFLAGS) -c $*.c -o $@
+
+clean:
+	rm -f $(BIN)/*.$(ARCH)
+	rm -f $(LIB)/*.$(ARCH).a
+	rm -f `find . -name "*.o"`
+	rm -f `find . -name "*~"`
+	rm -f `find . -name "#*"`
+
+dist: clean
+	rm -f $(BIN)/*
+	rm -f $(LIB)/*
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/VectorOps.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/VectorOps.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/VectorOps.c	(revision 3338)
@@ -0,0 +1,162 @@
+# include "opihi.h"
+
+static Vector **vectors;
+static int     Nvectors;
+  
+void InitVectors () {
+  Nvectors = 0;
+  ALLOCATE (vectors, Vector *, 1);
+}
+
+Vector *InitVector () {
+  Vector *vec;
+
+  ALLOCATE (vec, Vector, 1);
+  ALLOCATE (vec[0].elements, float, 1);
+  bzero (vec[0].name, 1024);
+  vec[0].Nelements = 0;
+  return (vec);
+}
+
+int IsVector (char *name) {
+ 
+  int i;
+
+  if (name == NULL) return (FALSE);
+
+  for (i = 0; (i < Nvectors) && (strcmp(vectors[i][0].name, name)); i++);
+  if (i == Nvectors) return (FALSE);
+  return (TRUE);
+}
+
+int IsVectorPtr (Vector *vec) {
+ 
+  int i;
+
+  if (vec == NULL) return (FALSE);
+
+  for (i = 0; (i < Nvectors) && (vectors[i] != vec); i++);
+  if (i == Nvectors) return (FALSE);
+  return (TRUE);
+}
+
+Vector *SelectVector (char *name, int mode, int verbose) {
+
+  int i;
+
+  if (name == NULL) goto error;
+  if (ISNUM(name[0])) goto error;
+  if (IsBuffer(name)) goto error;
+
+  for (i = 0; (i < Nvectors) && (strcmp(vectors[i][0].name, name)); i++);
+  /* is a new vector */
+  if (i == Nvectors) { 
+    if (mode == OLDVECTOR) goto error;
+    Nvectors += 1;
+    REALLOCATE (vectors, Vector *, Nvectors);
+    vectors[i] = InitVector ();
+    strcpy (vectors[i][0].name, name);
+    return (vectors[i]);
+  } 
+  /* is an old vector */
+  if (mode == NEWVECTOR) goto error;
+  return (vectors[i]);
+
+ error:
+  if (verbose) fprintf (stderr, "invalid vector %s\n", name);
+  return (NULL);
+}
+  
+/* delete by pointer */
+int DeleteVector (Vector *vec) {
+
+  int i, j;
+
+  if (vec == NULL) return (FALSE);
+
+  for (i = 0; (i < Nvectors) && (vec != vectors[i]); i++);
+  if (i == Nvectors) return (FALSE);
+
+  free (vectors[i][0].elements);
+  for (j = i; j < Nvectors - 1; j++) vectors[j] = vectors[j + 1];
+
+  Nvectors -= 1;
+  REALLOCATE (vectors, Vector *, MAX (Nvectors, 1));
+  return (TRUE);
+}
+  
+/* delete by name */
+int DeleteNamedVector (char *name) {
+
+  int i, j;
+
+  if (name == NULL) return (FALSE);
+  for (i = 0; (i < Nvectors) && (strcmp(vectors[i][0].name, name)); i++);
+  if (i == Nvectors) return (FALSE);
+
+  free (vectors[i][0].elements);
+  for (j = i; j < Nvectors - 1; j++) vectors[j] = vectors[j + 1];
+
+  Nvectors -= 1;
+  REALLOCATE (vectors, Vector *, MAX (Nvectors, 1));
+  return (TRUE);
+}
+
+/* copy data from in to out - new memory space */
+int CopyNamedVector (char *out, char *in) {
+  Vector *In, *Out;
+  if ((In  = SelectVector (in,  OLDVECTOR, FALSE)) == NULL) return (FALSE);
+  if ((Out = SelectVector (out, ANYVECTOR, FALSE)) == NULL) return (FALSE);
+  CopyVector (Out, In);
+  return (TRUE);
+}
+int CopyVector (Vector *out, Vector *in) {
+  free (out[0].elements);
+  out[0].Nelements = in[0].Nelements;
+  ALLOCATE (out[0].elements, float, out[0].Nelements);
+  memcpy (out[0].elements, in[0].elements, out[0].Nelements*sizeof(float));
+  return (TRUE);
+}
+
+/* move data from in to out - use old memory space */
+int MoveNamedVector (char *out, char *in) {
+  Vector *In, *Out;
+  if ((In  = SelectVector (in,  OLDVECTOR, FALSE)) == NULL) return (FALSE);
+  if ((Out = SelectVector (out, ANYVECTOR, FALSE)) == NULL) return (FALSE);
+  MoveVector (Out, In);
+  return (TRUE);
+}
+int MoveVector (Vector *out, Vector *in) {
+  int i, j;
+
+  free (out[0].elements);
+  out[0].Nelements = in[0].Nelements;
+  out[0].elements =  in[0].elements;
+
+  /* delete vector entry from vector list, if it exists */
+  for (i = 0; (i < Nvectors) && (in != vectors[i]); i++);
+  if (i == Nvectors) return (TRUE);
+
+  for (j = i; j < Nvectors - 1; j++) vectors[j] = vectors[j + 1];
+  Nvectors -= 1;
+  REALLOCATE (vectors, Vector *, MAX (Nvectors, 1));
+  return (TRUE);
+}
+
+int ListVectors () {
+
+  int i;
+
+  if (Nvectors == 0) {
+    fprintf (stderr, "No defined vectors\n");
+    return (FALSE);
+  }
+
+  fprintf (GetOutfile(), "    N       name      size\n");
+  for (i = 0; i < Nvectors; i++) {
+    fprintf (GetOutfile(), "%5d %10s %10d\n",
+	     i, vectors[i][0].name, vectors[i][0].Nelements);
+  }
+  return (TRUE);
+}
+  
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/check_stack.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/check_stack.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/check_stack.c	(revision 3338)
@@ -0,0 +1,90 @@
+# include "opihi.h"
+
+int check_stack (StackVar *stack, int Nstack, int validsize) {
+
+  int i, Nx, Ny, Nv, size;
+  char *c;
+
+  Nv = Nx = -1;
+
+  for (i = 0; i < Nstack; i++) {
+    if (stack[i].type == 'X') {
+
+      /** if this is a number, put it on the list of scalers and move on **/
+      stack[i].Float = strtod (stack[i].name, &c);
+      if (c == stack[i].name + strlen (stack[i].name)) {
+	stack[i].ptr   = &(stack[i].Float);
+	stack[i].type  = 'S';
+	continue;
+      } 
+
+      /** if this is a matrix, find the dimensions and check with existing values **/
+      if (IsBuffer (stack[i].name)) {
+	stack[i].buffer = SelectBuffer (stack[i].name, OLDBUFFER, TRUE);
+	stack[i].ptr    = (float *) stack[i].buffer[0].matrix.buffer;
+	stack[i].type   = 'M';
+	if (Nx == -1) {
+	  Nx = stack[i].buffer[0].matrix.Naxis[0];
+	  Ny = stack[i].buffer[0].matrix.Naxis[1];
+	} 
+	if ((Nx != stack[i].buffer[0].matrix.Naxis[0]) && (Ny != stack[i].buffer[0].matrix.Naxis[1])) {
+	  push_error ("dimensions don't match");
+	  return (-1);
+	}	
+	if (Nv != -1) {
+	  if ((Nv != Nx) && (Nv != Ny)) {
+	    push_error ("dimensions don't match");
+	    return (-1);
+	  }
+	}	
+	continue;
+      }
+
+      /** if this is a vector, find the dimensions and check with existing values **/
+      if (IsVector (stack[i].name)) {
+	stack[i].vector = SelectVector (stack[i].name, OLDVECTOR, FALSE);
+	stack[i].ptr    = (float *) stack[i].vector[0].elements;
+	stack[i].type   = 'V';
+
+	if (Nv == -1) Nv = stack[i].vector[0].Nelements;
+	if (Nv != stack[i].vector[0].Nelements) {
+	  push_error ("dimensions don't match");
+	  return (-1);
+	}
+	if (Nx != -1) {
+	  if ((Nx != Nv) && (Ny != Nv)) {
+	    push_error ("dimensions don't match");
+	    return (-1);
+	  }
+	}	
+	continue;
+      }
+
+      /* this is not a scalar, vector, or matrix.  must be string */
+      stack[i].type  = 'W';
+	
+      /* let's not consider this an error 
+      sprintf (line, "unknown object %s", stack[i].name);
+      push_error (line);
+      return (-1); 
+      */
+    }
+  }
+
+  /* return object dimensions */
+  size = 0;
+  if (Nv != -1) size = 1;
+  if (Nx != -1) size = 2;
+  if (validsize == -1)   return (size);
+  if (validsize != size) return (-1);
+  return (size);
+}
+
+/* check stack identifies the data elements as scalar, vector, matrix, or word.
+   operators have already been identified.  
+   check stack returns the total stack dimensionality (0,1,2)
+   on error, check stack returns -1
+   possible errors:
+     - mismatch with requested dimensionality
+     - mismatch in data dimensions
+*/
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/command.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/command.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/command.c	(revision 3338)
@@ -0,0 +1,74 @@
+# include "opihi.h"
+# define VERBOSE 0
+
+int command (char *line, char **outline) {
+
+  int i, status, argc, targc;
+  char **argv, **targv;
+  Command *cmd;
+
+  /* force a space between ! and first word: !ls becomes ! ls */
+  if (line[0] == '!') {
+    REALLOCATE (line, char, strlen(line) + 5);
+    memmove (&line[2], &line[1], strlen(&line[1]) + 1);
+    line[1] = ' ';
+  }
+
+  /* expand anything of the form $fred or $fred$sam, etc */ 
+  line = expand_vars (line);     /* line is freed here, new one allocated */
+  /* expand anything of the form fred[N] */ 
+  line = expand_vectors (line);  /* line is freed here, new one allocated */
+  /* solve math expresions, assign variable, if needed */
+  line = parse (line);        /* line is freed here, new one allocated */
+  /* any entry in line of the form {foo} returns value or tmp vector / buffer */
+  
+  targv = parse_commands (line, &targc);
+  if (targc == 0) {
+    /* empty command or assignment */
+    if (line != (char *) NULL) free (line);
+    *outline = (char *) NULL;
+    return (TRUE);
+  }
+
+  /* this needs some work to use multicommand correctly */
+  /* allocate extra space to have null terminated list */
+  ALLOCATE (argv, char *, targc + 1); 
+  argc = 0;
+  status = TRUE;
+  for (i = 0; status && (i < targc); i++) {
+    if (targv[i][0] != ';') {
+      argv[argc] = targv[i];
+      argc ++;
+    }
+    if ((targv[i][0] == ';') || (i == targc - 1)) {
+
+      if (argc == 0) continue;
+      argv[argc] = 0;
+
+      cmd = MatchCommand (argv[0], TRUE, FALSE);
+      if (cmd != NULL) {
+	REALLOCATE (argv[0], char, strlen(cmd[0].name) + 1);
+	strcpy (argv[0], cmd[0].name);
+	status &= (*cmd[0].func) (argc, argv);
+	if (auto_break && !status) break;
+      }
+      argc = 0;
+    }
+  }
+  for (i = 0; i < targc; i++) free (targv[i]);
+  free (argv);
+  free (targv);
+  *outline = line;
+  if (!status) {
+    char *msg;
+    msg = get_variable ("ERRORMSG");
+    if (msg != (char *) NULL) {
+      fprintf (stderr, "%s\n", msg);
+      free (msg);
+    }
+  }
+  set_int_variable ("STATUS", status);
+  if (VERBOSE) fprintf (stderr, "command: %s, status: %d\n", line, status);
+  return (status);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/convert_to_RPN.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/convert_to_RPN.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/convert_to_RPN.c	(revision 3338)
@@ -0,0 +1,206 @@
+# include "opihi.h"
+/* # define DUMPSTACK * for tests */
+
+StackVar *convert_to_RPN (int argc, char **argv, int *nstack) {
+  
+  int type, Nx, Ny;
+  int i, j, Nstack, Nop_stack, NSTACK;
+  StackVar *stack, *op_stack;
+
+  /* max total stack size is argc, though should be less, this is safe */
+  NSTACK = argc + 5;
+  ALLOCATE (stack, StackVar, NSTACK);
+  ALLOCATE (op_stack, StackVar, NSTACK);
+  for (i = 0; i < NSTACK; i++) {
+    init_stack (&stack[i]);
+    init_stack (&op_stack[i]);
+  }
+  
+  Nx = Ny = Nstack = Nop_stack = 0;
+  for (i = 0; i < argc; i++) {
+    
+    /* decide on priority of object */
+    type = 0;
+    /* unary operations */
+    if (!strcmp (argv[i], "abs"))   { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "int"))   { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "exp"))   { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "ten"))   { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "log"))   { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "ln"))    { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "sqrt"))  { type = 7; goto gotit; }
+
+    if (!strcmp (argv[i], "sinh"))   { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "cosh"))   { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "asinh"))  { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "acosh"))  { type = 7; goto gotit; }
+
+    if (!strcmp (argv[i], "sin"))   { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "cos"))   { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "tan"))   { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "dsin"))  { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "dcos"))  { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "dtan"))  { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "asin"))  { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "acos"))  { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "atan"))  { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "dasin")) { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "dacos")) { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "datan")) { type = 7; goto gotit; }
+
+    if (!strcmp (argv[i], "lgamma")) { type = 7; goto gotit; }
+
+    if (!strcmp (argv[i], "rnd"))   { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "xramp")) { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "yramp")) { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "ramp"))  { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "zero"))  { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "--"))    { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "not"))   { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "isinf")) { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "isnan")) { type = 7; goto gotit; }
+
+    /* binary operations */
+    if (!strcmp (argv[i], "^"))     { type = 6; goto gotit; }
+    if (!strcmp (argv[i], "@"))     { type = 5; goto gotit; }
+
+    if (!strcmp (argv[i], "<"))     { type = 5; goto gotit; }
+    if (!strcmp (argv[i], ">"))     { type = 5; goto gotit; }
+    if (!strcmp (argv[i], "&&"))    { type = 5; strcpy (argv[i], "A"); goto gotit; }
+    if (!strcmp (argv[i], "||"))    { type = 5; strcpy (argv[i], "O"); goto gotit; }
+    if (!strcmp (argv[i], "=="))    { type = 5; strcpy (argv[i], "E"); goto gotit; }
+    if (!strcmp (argv[i], "!="))    { type = 5; strcpy (argv[i], "N"); goto gotit; }
+    if (!strcmp (argv[i], "<="))    { type = 5; strcpy (argv[i], "L"); goto gotit; }
+    if (!strcmp (argv[i], ">="))    { type = 5; strcpy (argv[i], "G"); goto gotit; }
+    if (!strcmp (argv[i], ">>"))    { type = 5; strcpy (argv[i], "U"); goto gotit; }
+    if (!strcmp (argv[i], "<<"))    { type = 5; strcpy (argv[i], "D"); goto gotit; }
+
+    if (!strcmp (argv[i], "&"))     { type = 5; goto gotit; }
+    if (!strcmp (argv[i], "|"))     { type = 5; goto gotit; }
+
+    if (!strcmp (argv[i], "/"))     { type = 4; goto gotit; }
+    if (!strcmp (argv[i], "*"))     { type = 4; goto gotit; }
+
+    if (!strcmp (argv[i], "+"))     { type = 3; goto gotit; }
+    if (!strcmp (argv[i], "-"))     { type = 3; goto gotit; }
+	
+    if (!strcmp (argv[i], "("))     { type = 2; goto gotit; }
+    if (!strcmp (argv[i], ")"))     { type = 1; goto gotit; }
+
+  gotit:
+    /* choose how to deal with object */
+    switch (type) {
+    case 6:  /* unary OPs */
+      /* pop previous, higher operators from OP stack to stack */
+      for (j = Nop_stack - 1; (j >= 0) && (op_stack[j].type > type); j--) {
+	strcpy (stack[Nstack].name, op_stack[j].name);
+	stack[Nstack].type = op_stack[j].type;
+	Nstack ++;
+	Nop_stack --;
+      }
+      /* push operator on OP stack */
+      strcpy (op_stack[Nop_stack].name, argv[i]);
+      op_stack[Nop_stack].type = type;
+      Nop_stack ++;
+      break;
+    case 7: /* binary OPs */
+    case 5: /* binary OPs */
+    case 4: 
+    case 3: 
+      /* pop previous, higher or equal operators from OP stack to stack */
+      for (j = Nop_stack - 1; (j >= 0) && (op_stack[j].type >= type); j--) {
+	strcpy (stack[Nstack].name, op_stack[j].name);
+	stack[Nstack].type = op_stack[j].type;
+	Nstack ++;
+	Nop_stack --;
+      }
+      /* push operator on OP stack */
+      strcpy (op_stack[Nop_stack].name, argv[i]);
+      op_stack[Nop_stack].type = type;
+      Nop_stack ++;
+      break;
+    case 2:  
+      /* push operator on OP stack */
+      strcpy (op_stack[Nop_stack].name, argv[i]);
+      op_stack[Nop_stack].type = type;
+      Nop_stack ++;
+      break;
+    case 1: 
+      /* pop rest of operators from OP stack to stack, looking for '(' */
+      for (j = Nop_stack - 1; (j >= 0) && (op_stack[j].type != 2); j--) {
+	strcpy (stack[Nstack].name, op_stack[j].name);
+	stack[Nstack].type = op_stack[j].type;
+	Nstack ++;
+	Nop_stack --;
+      }
+      if ((j == -1) || (op_stack[j].type != 2)) {
+	push_error ("syntax error: mismatched parenthesis");
+	Nstack = 0;
+	goto cleanup;
+      }
+      Nop_stack --;
+      break;
+    case 0:
+      /* place the value (number or vector/matrix name) on stack */
+      /* value of 'X' is used as sentinel until we sort out values */
+      strcpy (stack[Nstack].name, argv[i]);
+      stack[Nstack].type = 'X';
+      Nstack ++;
+      break;
+    }
+  }
+
+  /* dump remaining operators on stack, checking for ')' */
+  for (j = Nop_stack - 1; j >= 0; j--) {
+    if (op_stack[j].type == 2) {
+      push_error ("syntax error: mismatched parenthesis");
+      Nstack = 0;
+      goto cleanup;
+    }
+    strcpy (stack[Nstack].name, op_stack[j].name);
+    stack[Nstack].type = op_stack[j].type;
+    Nstack ++;
+  }
+
+cleanup: 
+  /*** free up unused stack space ***/
+  clean_stack (op_stack, NSTACK);
+  free (op_stack);
+  clean_stack (&stack[Nstack], NSTACK - Nstack);
+  REALLOCATE (stack, StackVar, MAX (Nstack, 1));
+  *nstack = Nstack;
+
+  for (i = 0; i < argc; i++) {
+    free (argv[i]);
+  }
+  free (argv);
+
+#ifdef DUMPSTACK
+  for (i = 0; i < Nstack; i++) {
+    fprintf (stderr, "%s ", stack[i].name);
+  }
+  if (Nstack > 0) fprintf (stderr, "\n");
+  for (i = 0; i < Nstack; i++) {
+    fprintf (stderr, "%d ", stack[i].type);
+  }
+  if (Nstack > 0) fprintf (stderr, "\n");
+#endif
+
+  return (stack);
+
+}
+
+/* here are the rules for parsing a math AOL line to RPN:
+
+   1) if object is a number, push on stack
+   2) if object is a third order operand (exp, sin, cos), push on op stack
+   3) if object is an open paren, push on op stack,
+   4) if object is a second order operand, push on stack
+   5) if object is a first order operand, pop all second order operands from stack 
+   until paren, push on stack
+   6) if object is an end paren, pop all objects from stack until paren, 
+   pop next stack, if third order op
+   7) if end of line, pop all remaining objects, second order first, etc.
+   
+*/
+
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/dvomath.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/dvomath.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/dvomath.c	(revision 3338)
@@ -0,0 +1,88 @@
+# include "opihi.h"
+
+/* return value on success is temp vector/buffer name or scalar value return value on error is NULL, all
+   internals freed.  errors are sent to error stack.  may be printed by calling function */
+   
+char *dvomath (int argc, char **argv, int *size, int validsize) {
+  
+  int  i, Nstack, Ncstack;
+  char   **cstack, *outname;
+  StackVar *stack;
+  Buffer *buf;
+  Vector *vec;
+
+  ALLOCATE (outname, char, 256);
+
+  /* take char array with expression, convert to important elements */
+  cstack = isolate_elements (argc, argv, &Ncstack); 
+
+  /* generate RPN stack from cstack arguments */
+  stack = convert_to_RPN (Ncstack, cstack, &Nstack);
+  if (Nstack < 1) goto error;
+
+  /* distinguish scalar, vector, matrix, check dimensions */
+  *size = check_stack (stack, Nstack, validsize);
+  if (*size < 0) goto error;
+
+  switch (*size) {
+    case 0:
+      break;
+    case 1:  /* allocate temp vector */
+      vec = NULL;
+      for (i = 0; (i < 1000) && (vec == NULL); i++) {
+	sprintf (outname, "tmp%03d", i);
+	vec = SelectVector (outname, NEWVECTOR, FALSE);
+      }
+      if (vec == NULL) { 
+	push_error ("too many tmp vectors");
+	goto error;
+      }
+      break;
+    case 2:  /* allocate temp buffer */
+      buf = NULL;
+      for (i = 0; (i < 1000) && (buf == NULL); i++) {
+	sprintf (outname, "tmp%03d", i);
+	buf = SelectBuffer (outname, NEWBUFFER, FALSE);
+      }
+      if (buf == NULL) {
+	push_error ("too many tmp buffers");
+	goto error;
+      }
+      break;
+    default:
+      goto error;
+  }
+
+  /* evaluate operations, free stack on error */
+  if (!evaluate_stack (stack, &Nstack)) {
+    if (*size == 1) DeleteVector (vec);
+    if (*size == 2) DeleteBuffer (buf);
+    goto error;
+  }
+
+  switch (*size) {
+    case 0:
+      sprintf (outname, "%g", stack[0].Float);
+      break;
+
+    case 1:
+      MoveVector (vec, stack[0].vector);
+      free (stack[0].vector);
+      break;
+  
+    case 2:
+      MoveBuffer (buf, stack[0].buffer);
+      free (stack[0].buffer);
+      break;
+  }
+
+  clean_stack (stack, Nstack);
+  free (stack);
+  return (outname);
+
+error:  
+  clean_stack (stack, Nstack);
+  free (stack);
+  free (outname);
+  return (NULL);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/errors.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/errors.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/errors.c	(revision 3338)
@@ -0,0 +1,16 @@
+# include "opihi.h"
+
+static char errorline[1024];
+
+int push_error (char *line) {
+
+  bzero (errorline, 1024);
+  strncpy (errorline, line, 1023);
+  return (TRUE);
+}
+
+int print_error () {
+
+  fprintf (stderr, "%s\n", errorline);
+  return (TRUE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/evaluate_stack.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/evaluate_stack.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/evaluate_stack.c	(revision 3338)
@@ -0,0 +1,226 @@
+# include "opihi.h"
+# define VERBOSE 0
+
+int evaluate_stack (StackVar *stack, int *Nstack) {
+  
+  int i, j, Nvar, Nout, status;
+  char line[512];
+  StackVar tmp_stack;
+  Nout = Nvar = 0;
+
+  init_stack (&tmp_stack);
+
+  if (*Nstack == 1) {
+    if (stack[0].type == 'S') {
+      S_unary (&tmp_stack, &stack[0], "=");
+      move_stack (&stack[0], &tmp_stack);
+      return (TRUE);
+    }
+    if (stack[0].type == 'V') {
+      V_unary (&tmp_stack, &stack[0], "=");
+      move_stack (&stack[0], &tmp_stack);
+      return (TRUE);
+    }
+    if (stack[0].type == 'M') {
+      M_unary (&tmp_stack, &stack[0], "=");
+      move_stack (&stack[0], &tmp_stack);
+      return (TRUE);
+    }
+    push_error ("syntax error: not a math expression");
+    free (tmp_stack.name);
+    return (FALSE);
+  }      
+    
+  for (i = 0; i < *Nstack; i++) {
+
+    if (VERBOSE) {
+      fprintf (stderr, "%d: ", i);
+      for (j = 0; j < *Nstack; j++) {
+	fprintf (stderr, "%s ", stack[j].name);
+      }
+      if (*Nstack > 0) fprintf (stderr, "\n");
+      fprintf (stderr, "%d: ", i);
+      for (j = 0; j < *Nstack; j++) {
+	fprintf (stderr, "%d ", stack[j].type);
+      }
+      if (*Nstack > 0) fprintf (stderr, "\n");
+    }
+
+    /***** binary operators *****/
+    if ((stack[i].type == 3) || (stack[i].type == 4) || (stack[i].type == 5) || (stack[i].type == 6)) {
+
+      if (i < 2) {  /* need two variables to operate on */
+	sprintf (line, "syntax error: binary operator with one operand: %s\n", stack[i].name);
+	push_error (line);
+	free (tmp_stack.name); 
+	return (FALSE);
+      }
+
+      /* this could be macro generated... */
+      # define TWO_OP(A,B,FUNC) \
+      if (!strncasecmp (&stack[i - 2].type, A, 1) && !strncasecmp (&stack[i - 1].type, B, 1)) \
+	status = FUNC (&tmp_stack, &stack[i - 2], &stack[i - 1], stack[i].name); 
+
+      TWO_OP ("M","M",MM_binary);
+      TWO_OP ("M","V",MV_binary);
+      TWO_OP ("M","S",MS_binary);
+      TWO_OP ("V","M",VM_binary);
+      TWO_OP ("V","V",VV_binary);
+      TWO_OP ("V","S",VS_binary);
+      TWO_OP ("S","M",SM_binary);
+      TWO_OP ("S","V",SV_binary);
+      TWO_OP ("S","S",SS_binary);      
+      TWO_OP ("W","W",WW_binary);      
+      TWO_OP ("W","S",WW_binary);      
+      TWO_OP ("S","W",WW_binary);      
+      
+      /*
+      if (!strncasecmp (&stack[i - 2].type, "V", 1) && !strncasecmp (&stack[i - 1].type, "V", 1)) 
+	status = VV_binary (&tmp_stack, &stack[i - 2], &stack[i - 1], stack[i].name);
+      if (!strncasecmp (&stack[i - 2].type, "V", 1) && !strncasecmp (&stack[i - 1].type, "S", 1)) 
+	status = VS_binary (&tmp_stack, &stack[i - 2], &stack[i - 1], stack[i].name);
+      if (!strncasecmp (&stack[i - 2].type, "S", 1) && !strncasecmp (&stack[i - 1].type, "V", 1)) 
+	status = SV_binary (&tmp_stack, &stack[i - 2], &stack[i - 1], stack[i].name);
+      if (!strncasecmp (&stack[i - 2].type, "M", 1) && !strncasecmp (&stack[i - 1].type, "V", 1)) 
+	status = MV_binary (&tmp_stack, &stack[i - 2], &stack[i - 1], stack[i].name);
+      if (!strncasecmp (&stack[i - 2].type, "V", 1) && !strncasecmp (&stack[i - 1].type, "M", 1)) 
+	status = VM_binary (&tmp_stack, &stack[i - 2], &stack[i - 1], stack[i].name);
+      if (!strncasecmp (&stack[i - 2].type, "M", 1) && !strncasecmp (&stack[i - 1].type, "M", 1)) 
+	status = MM_binary (&tmp_stack, &stack[i - 2], &stack[i - 1], stack[i].name);
+      if (!strncasecmp (&stack[i - 2].type, "M", 1) && !strncasecmp (&stack[i - 1].type, "S", 1)) 
+	status = MS_binary (&tmp_stack, &stack[i - 2], &stack[i - 1], stack[i].name);
+      if (!strncasecmp (&stack[i - 2].type, "S", 1) && !strncasecmp (&stack[i - 1].type, "M", 1)) 
+	status = SM_binary (&tmp_stack, &stack[i - 2], &stack[i - 1], stack[i].name);
+      if (!strncasecmp (&stack[i - 2].type, "S", 1) && !strncasecmp (&stack[i - 1].type, "S", 1)) 
+	status = SS_binary (&tmp_stack, &stack[i - 2], &stack[i - 1], stack[i].name);
+      if (!strncasecmp (&stack[i - 2].type, "X", 1) && !strncasecmp (&stack[i - 1].type, "X", 1)) 
+	status = XX_binary (&tmp_stack, &stack[i - 2], &stack[i - 1], stack[i].name);
+      */
+
+      /* string op number is not valid 
+      if (!strncasecmp (&stack[i - 2].type, "W", 1) && strncasecmp (&stack[i - 1].type, "W", 1)) {
+	free (tmp_stack.name);
+	return (FALSE);
+      }
+      if (strncasecmp (&stack[i - 2].type, "W", 1) && !strncasecmp (&stack[i - 1].type, "W", 1)) {
+	free (tmp_stack.name);
+	return (FALSE);
+      } */
+
+      if (!status) {
+	free (tmp_stack.name);
+	return (FALSE);
+      }
+      move_stack (&stack[i-2], &tmp_stack);
+      delete_stack (&stack[i-1], 2);
+      for (j = i + 1; j < *Nstack; j++) {
+	copy_stack (&stack[j - 2], &stack[j]);
+      }
+      *Nstack -= 2;
+      i -= 2;
+      init_stack (&tmp_stack);
+      continue;
+    }
+
+    /***** unary operators **/
+    if (stack[i].type == 7) {
+
+      if (i < 1) {  /* need one variable to operate on */
+	push_error ("syntax error: unary operator with no operand");
+	free (tmp_stack.name);
+	return (FALSE);
+      }
+      
+      if (!strncasecmp (&stack[i - 1].type, "M", 1)) 
+	M_unary (&tmp_stack, &stack[i - 1], stack[i].name);
+      if (!strncasecmp (&stack[i - 1].type, "V", 1)) 
+	V_unary (&tmp_stack, &stack[i - 1], stack[i].name);
+      if (!strncasecmp (&stack[i - 1].type, "S", 1)) 
+	S_unary (&tmp_stack, &stack[i - 1], stack[i].name);
+
+      /* there are no valid unary string operators */
+      if (!strncasecmp (&stack[i - 1].type, "W", 1)) {
+	push_error ("syntax error: no valid string unary ops");
+	free (tmp_stack.name);
+	return (FALSE);
+      }
+
+      move_stack (&stack[i-1], &tmp_stack);
+      delete_stack (&stack[i], 1);
+      for (j = i + 1; j < *Nstack; j++) {
+	copy_stack (&stack[j - 1], &stack[j]);
+      }
+      init_stack (&tmp_stack);
+      *Nstack -= 1;
+      i -= 1;
+      continue;
+    } 
+  }
+  free (tmp_stack.name);
+
+  if (*Nstack > 1) {
+    push_error ("syntax error in evaluation");
+    return (FALSE);
+  }
+  return (TRUE);
+}
+
+/* copy data to new stack variable */
+void copy_stack (StackVar *stack1, StackVar *stack2) {
+  stack1[0].name   = stack2[0].name  ;
+  stack1[0].type   = stack2[0].type  ;
+  stack1[0].ptr    = stack2[0].ptr   ;
+  stack1[0].buffer = stack2[0].buffer;
+  stack1[0].vector = stack2[0].vector;
+  stack1[0].Float  = stack2[0].Float ;
+  if (!strncasecmp (&stack1[0].type, "S", 1)) {
+    stack1[0].ptr    = &stack1[0].Float;
+  }
+}
+
+/* replace data with new stack variable */
+void move_stack (StackVar *stack1, StackVar *stack2) {
+  if (stack1[0].name != (char *) NULL) 
+    free (stack1[0].name);
+  copy_stack (stack1, stack2);
+}
+
+/* delete name and data */
+void clean_stack (StackVar *stack, int Nstack) {
+
+  int i;
+
+  for (i = 0; i < Nstack; i++) {
+    if (IsBufferPtr (stack[i].buffer) && (stack[i].type == 'm')) {
+      if (VERBOSE) fprintf (stderr, "free %s (buff) (%lx)\n", stack[i].name, (long) stack[i].buffer);
+      free (stack[i].buffer[0].header.buffer);
+      free (stack[i].buffer[0].matrix.buffer);
+      free (stack[i].buffer);
+      stack[i].buffer = NULL;
+    }	
+    if (IsVectorPtr (stack[i].vector) && (stack[i].type == 'v')) {
+      if (VERBOSE) fprintf (stderr, "free %s (vect) (%lx)\n", stack[i].name, (long) stack[i].vector);
+      free (stack[i].vector[0].elements);
+      free (stack[i].vector);
+      stack[i].vector = NULL;
+    }	
+    if (VERBOSE) fprintf (stderr, "free %s (name) (%d) (%lx)\n", stack[i].name, i, (long) stack[i].name);
+    free (stack[i].name);
+    stack[i].name = NULL;
+  }
+
+}
+
+/* delete name only, not data */
+void delete_stack (StackVar *stack, int Nstack) {
+  int i;
+  for (i = 0; i < Nstack; i++) {
+    free (stack[i].name);
+  }
+}
+
+void init_stack (StackVar *stack) {
+  stack[0].buffer = NULL;
+  stack[0].vector = NULL;
+  stack[0].name = strncreate ("tmp", NCHARS);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/exec_loop.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/exec_loop.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/exec_loop.c	(revision 3338)
@@ -0,0 +1,49 @@
+# include "opihi.h"
+
+int exec_loop (Macro *loop) {
+
+  void *Signal;
+  int n, Nlines, j, status, ThisList;
+  char *outline;
+  
+  /* increase the shell level (Nlists) by one */
+  Nlists ++;
+  ThisList = Nlists;
+  REALLOCATE (lists, List, MAX (ThisList, 0) + 1);
+  
+  /* copy the macro to the current list */
+  lists[ThisList].Nlines = loop[0].Nlines;
+  ALLOCATE (lists[ThisList].line, char *, MAX (lists[ThisList].Nlines, 1));
+  for (j = 0; j < lists[ThisList].Nlines; j++) {
+    lists[ThisList].line[j] = strcreate (loop[0].line[j]);
+  }
+
+  /* set up interrupts */
+  Signal = signal (SIGINT, handle_interrupt);
+  interrupt = FALSE;
+
+  /* process the list */
+  loop_continue = loop_break = FALSE;
+  status = TRUE;
+  Nlines = lists[ThisList].Nlines;
+  for (n = 0; (n < Nlines) && !interrupt; n++) {
+    lists[ThisList].n = n; 
+    status = command (lists[ThisList].line[n], &outline);
+    n = lists[ThisList].n;
+    Nlines = lists[ThisList].Nlines;
+    if (outline != NULL) free (outline);
+    if (auto_break && !status) loop_break = TRUE;
+    if (loop_break || loop_continue) break;
+  }
+  signal (SIGINT, Signal);
+
+  /* free up the list and decrement the shell level */
+  free (lists[ThisList].line);
+  Nlists --;
+  REALLOCATE (lists, List, MAX (Nlists, 0) + 1);
+
+  if (loop_break) return (FALSE);
+  return (TRUE);
+}
+
+/** note that the list number runs from 1 - Nlists+1 **/
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/expand_vars.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/expand_vars.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/expand_vars.c	(revision 3338)
@@ -0,0 +1,103 @@
+# include "opihi.h"
+
+char *expand_vars (char *line) {
+
+  char *L, *N, *V0, *V1, *Val, *newline, *c, found;
+  int done, MacroDepth;
+
+  if (line == NULL) return (NULL);
+  MacroDepth = GetMacroDepth ();
+
+  found = FALSE;
+  ALLOCATE (newline, char, 1024);  /* WARNING: this limits the length of the input line */
+
+  /* look for form $a$b..$n and expand only the last ones */
+  for (L = line, N = newline; *L != 0; N++, L++) {  /* loop until end of line */
+    for (done = FALSE; !done;) {
+      if (*L == 0) done = TRUE;
+      if (*L == '$') {
+	V1 = aftervar(L);
+	if ((V1 != NULL) && (*V1 != '$')) done = TRUE;
+	if (V1 == NULL) done = TRUE;
+      }
+      if (!done) { 
+	*N = *L;
+	 L++; 
+	 N++;
+      }
+    }
+
+    if (*L == 0) break;
+
+    V1 = aftervar (L);           /* V1 points to the first non-whitespace after the variable */
+    V0 = thisvar (L);            /* V0 points to the name of the var */
+    /* note: V1 points to a fraction of L, it does not need to be freed */
+
+    /* no variable name */
+    if (V0 == NULL) {
+      *N = *L;
+      continue;
+    }
+
+    /* variable assignment (skip these variables) */
+    if ((L == line) && (V1 != NULL)) {
+      if ((*V1 == '=') || !strcmp (V1, "++") || !strcmp (V1, "--")) {
+	*N = *L;
+	continue;
+      }
+    }
+
+    found = TRUE;
+    for (c = V0; isdigit(*c); c++); /* test if this is a macro argument variable (ie, $1.2) */
+    if (*c == 0) {  /* all digit var == macro parameter */
+      if (!MacroDepth) {
+	fprintf (stderr, "not in a macro\n");
+	goto error;
+      } else { /* if we are executing a macro, attach the list depth to the front, pass on down the line */
+	ALLOCATE (c, char, 1024);
+	sprintf (c, "%d.%s", MacroDepth, V0);
+	free (V0);
+	V0 = c;
+      }
+    }
+
+    Val = get_variable_ptr (V0);
+    if (Val == NULL) {   /* var was not found! */
+      fprintf (stderr, "variable %s not found\n", V0);
+      goto error;
+    }
+    for (; *Val != 0; N++, Val++)  {
+      *N = *Val; /* place the value of the variable in the newline */
+    }
+
+    for (N--,L++; ISVAR(*L); L++);
+    L--;
+
+    if (V0 != NULL) free (V0);
+  }
+
+  *N = 0;
+  free (line);
+  REALLOCATE (newline, char, strlen (newline) + 1);
+  if (found) { /* try again for new variables */
+    newline = expand_vars (newline);
+  }
+  return (newline);
+
+error:
+  free (line);
+  free (V0);
+  free (newline);
+  return (NULL);
+}
+
+
+  /************************
+    we go through the line looking for the dollar signs ($) marking the 
+    variables.  We don't expand a variable if it is the first thing on the line 
+    AND it is followed by an equals sign.  
+    that is, don't expand if:
+    V0 = NULL ($ is last non-blank char on line -- no variable) or
+    V1[0] is = (assignment of variable value), AND L == line (ie, at beginning of line)
+    *************************/
+
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/expand_vectors.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/expand_vectors.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/expand_vectors.c	(revision 3338)
@@ -0,0 +1,97 @@
+# include "opihi.h"
+
+char *expand_vectors (char *line) {
+
+  char *newline, *tmpline, *val;
+  char *L, *N, *p, *q, *w;
+  int n, I, size;
+  double f1;
+  Vector *vec;
+
+  if (line == NULL) return (NULL);
+
+  ALLOCATE (newline, char, 1024);  /* WARNING: this limits the length of the input line */
+  ALLOCATE (tmpline, char, 1024);  /* WARNING: this limits the length of the input line */
+
+  /* look for form fred[stuff] */
+  /* skip first word (command) */
+  L = nextword (line);
+  if (L == NULL) {
+    free (newline);
+    return (line);
+  }
+
+  n = L - line;
+  strncpy (newline, line, n);
+  N = newline + n;
+  while (1) {
+    /* find vector subscript */
+    p = strchr (L, '[');
+    q = strchr (L, ']');
+    if ((p == NULL) && (q != NULL)) goto dumpline;
+    if ((p != NULL) && (q == NULL)) goto dumpline;
+    if ((p == NULL) && (q == NULL)) goto dumpline;
+    if (p > q) goto dumpline; /* odd state: unmatched pair: ][ */
+    n = (int) (q - p - 1);
+    if (n == 0) {
+      ALLOCATE (val, char, 64);
+      sprintf (val, "-1");
+      /* this choice of sentinel prevents us from using 
+	 x[-1], x[-2], and is not really needed */
+    } else {
+      strncpy (tmpline, p+1, n);
+      tmpline[n] = 0;
+      val = dvomath (1, &tmpline, &size, 0);
+      if (val == NULL) goto dumpline; /* not a valid vector subscript */
+    }
+    /* find vector name */
+    for (w = p - 1; (w >= line) && !whitespace(*w) && (isalnum(*w) || (*w == ':') || (*w == '_')); w--);
+    w ++;
+    n = (int)(p - w);
+    strncpy (tmpline, w, n);
+    tmpline[n] = 0;
+    if ((vec = SelectVector (tmpline, OLDVECTOR, TRUE)) == NULL) {
+      free (val);
+      goto dumpline;
+    }
+    /* find vector element */
+    I = atoi (val);
+    free (val);
+    if (I >= vec[0].Nelements) {
+      fprintf (stderr, "vector subscript out of range\n"); 
+      goto escape;
+    }
+    if (I < 0) {
+      f1 = vec[0].Nelements;
+    } else {
+      f1 = vec[0].elements[I];
+    }
+    if ((int)f1 == f1) 
+      sprintf (tmpline, "%.0f", f1);
+    else
+      sprintf (tmpline, "%.9g", f1);
+    /* interpolate vector element */
+    n = (int) (w - L);
+    strncpy (N, L, n);
+    N += n;
+    n = strlen (tmpline);
+    strncpy (N, tmpline, n);
+    N += n;
+    L = q + 1;
+  }
+
+dumpline:
+  n = strlen (L);
+  strncpy (N, L, n);
+  N[n] = 0;
+  free (line);
+  free (tmpline);
+  return (newline);
+  
+escape:
+  free (line);
+  free (newline);
+  free (tmpline);
+  return (NULL);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/interrupt.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/interrupt.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/interrupt.c	(revision 3338)
@@ -0,0 +1,51 @@
+# include "opihi.h"
+
+static int Nint = 0;
+
+/* return FALSE if we are called many times in a row 
+   without a valid answer or any answer */
+
+void handle_interrupt (int input) {
+  
+  char string[64];
+  int Nask;
+
+  signal (SIGINT, SIG_IGN);
+
+  Nask = 0;
+  Nint ++;
+  if (Nint > 10) { 
+    interrupt = TRUE;
+    return;
+  }
+  if (Nint > 100) { 
+    exit (3);
+  }
+  
+  while (1) {
+    fprintf (stderr, "operation halted, continue? (y/n) ");
+    fscanf (stdin, "%s", string);
+    
+    if ((string[0] == 'y') || (string[0] == 'Y')) {
+      interrupt = FALSE;
+      signal (SIGINT, handle_interrupt);
+      Nint = 0;
+      return;
+    }
+
+    if ((string[0] == 'n') || (string[0] == 'N')) {
+      interrupt = TRUE;
+      signal (SIGINT, handle_interrupt);
+      Nint = 0;
+      return;
+    }
+    Nask ++;
+    if (Nask > 10) {
+      interrupt = TRUE;
+      signal (SIGINT, handle_interrupt);
+      Nint = 0;
+      return;
+    }
+  }  
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/isolate_elements.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/isolate_elements.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/isolate_elements.c	(revision 3338)
@@ -0,0 +1,200 @@
+# include "opihi.h"
+
+/* local private functions */
+void InsertValue (char c);
+void EndOfString (void);
+int IsAnOp (char *c);
+int IsTwoOp (char *c);
+
+/* local private static variables */
+int Nchar, Nout, NOUT;
+char **out;
+
+char **isolate_elements (int Nin, char **in, int *nout) {
+  
+  int i, j, minus, negate, plus, posate, OpStat, SciNotation;
+
+  NOUT = Nin;
+  Nchar = Nout = 0;
+  ALLOCATE (out, char *, NOUT);
+  ALLOCATE (out[Nout], char, NCHARS);
+
+  for (i = 0; i < Nin; i++) {
+    for (j = 0; j < strlen(in[i]); j++) {
+      SciNotation = FALSE;
+      /* identify 'negate' or 'minus' ops */
+      negate = minus = FALSE;
+      if (in[i][j] == '-') { 
+	minus = TRUE;  
+	/* if - is first thing on line, must be a negator */
+	if ((Nout == 0) && (Nchar == 0)) {  
+	  minus = FALSE;
+	  negate = TRUE;
+	  goto skip1;
+	}
+	/* check previous entry on line */
+	if (Nchar) {
+	  OpStat = IsAnOp (out[Nout]);
+	  if (out[Nout][0] == ')') OpStat = FALSE;
+	} else {
+	  OpStat = IsAnOp (out[Nout-1]);
+	  if (out[Nout-1][0] == ')') OpStat = FALSE;
+	}
+	/* if - follows an operator, must be negator */
+	if (OpStat) {
+	  minus = FALSE;
+	  negate = TRUE;
+	  goto skip1;
+	}
+	/* if - follows 'e' is part of 1e-5 */
+	if (j == 0) goto skip1;
+	if ((in[i][j-1] == 'e') || (in[i][j-1] == 'E')) {
+	  SciNotation = TRUE;
+	  negate = minus = FALSE;
+	}
+      }
+    skip1:
+      /* idenfity 'posate' or 'plus' ops */
+      posate = plus = FALSE;
+      if (in[i][j] == '+') { 
+	plus = TRUE;  
+	/* if + is first thing on line, must be a posator */
+	if ((Nout == 0) && (Nchar == 0)) {  
+	  plus = FALSE;
+	  posate = TRUE;
+	  goto skip2;
+	}
+	/* check previous entry on line */
+	if (Nchar) {
+	  OpStat = IsAnOp (out[Nout]);
+	  if (out[Nout][0] == ')') OpStat = FALSE;
+	} else {
+	  OpStat = IsAnOp (out[Nout-1]);
+	  if (out[Nout-1][0] == ')') OpStat = FALSE;
+	}
+	/* if + follows an operator, must be posator */
+	if (OpStat) {
+	  plus = FALSE;
+	  posate = TRUE;
+	  goto skip2;
+	}
+	/* if + follows 'e' is part of 1e+5 */
+	if (j == 0) goto skip2;
+	if ((in[i][j-1] == 'e') || (in[i][j-1] == 'E')) {
+	  SciNotation = TRUE;
+	  posate = plus = FALSE;
+	}
+      }
+    skip2:
+      /* operators */
+      if (negate || minus || posate || plus || (IsAnOp (&in[i][j]) && !SciNotation)) {
+	if (posate) continue;
+	EndOfString ();
+	/* copy operator to out[Nout] */
+	InsertValue (in[i][j]);
+	if (negate) InsertValue ('-');
+
+	if (IsTwoOp (&in[i][j])) {
+	  InsertValue (in[i][j+1]);
+	  j++;
+	} 
+	EndOfString ();
+	continue;
+      }
+      /* quoted string */
+      if (in[i][j] == '"') {
+	InsertValue (in[i][j]);
+	j++;
+	while ((j < strlen(in[i])) && (in[i][j] != '"')) {
+	  InsertValue (in[i][j]);
+	  j++;
+	}
+	if (in[i][j] != '"') continue;
+	/* 
+	  fprintf (stderr, "mismatched quotes\n");
+	  return (FALSE);
+	}
+	*/
+	InsertValue (in[i][j]);
+	EndOfString ();
+	continue;
+      }
+      /* not an operator, not a quoted string */
+      if (!whitespace (in[i][j])) {
+	InsertValue (in[i][j]);
+      } else {
+	EndOfString ();
+      }
+    }
+    EndOfString ();
+  }
+
+  /* one extra entry is allocated, free here */
+  free (out[Nout]);
+  *nout = Nout;
+  return (out);
+
+}
+
+void InsertValue (char c) {
+  out[Nout][Nchar] = c;
+  Nchar ++;
+  out[Nout][Nchar] = 0;
+}
+
+void EndOfString () {
+  if (Nchar > 0) {
+    out[Nout][Nchar] = 0;
+    Nout ++;
+    Nchar = 0;
+    
+    if (Nout >= NOUT - 1) {
+      NOUT += 10; 
+      REALLOCATE (out, char *, NOUT); 
+    } 
+    ALLOCATE (out[Nout], char, NCHARS); 
+  }
+}
+
+int IsAnOp (char *c) {
+
+  if (!strncmp (c, "*",  1)) return (TRUE);
+  if (!strncmp (c, "/",  1)) return (TRUE);
+  if (!strncmp (c, "+",  1)) return (TRUE);
+  if (!strncmp (c, "-",  1)) return (TRUE);
+  if (!strncmp (c, "^",  1)) return (TRUE);
+  if (!strncmp (c, "@",  1)) return (TRUE);
+  if (!strncmp (c, "(",  1)) return (TRUE);
+  if (!strncmp (c, ")",  1)) return (TRUE);
+  if (!strncmp (c, "&",  1)) return (TRUE);
+  if (!strncmp (c, "|",  1)) return (TRUE);
+  if (!strncmp (c, ">",  1)) return (TRUE);
+  if (!strncmp (c, "<",  1)) return (TRUE);
+  if (!strncmp (c, "<",  1)) return (TRUE);
+  if (!strncmp (c, "<<", 2)) return (TRUE);
+  if (!strncmp (c, ">>", 2)) return (TRUE);
+  if (!strncmp (c, "&&", 2)) return (TRUE);
+  if (!strncmp (c, "||", 2)) return (TRUE);
+  if (!strncmp (c, "==", 2)) return (TRUE);
+  if (!strncmp (c, "!=", 2)) return (TRUE);
+  if (!strncmp (c, "<=", 2)) return (TRUE);
+  if (!strncmp (c, ">=", 2)) return (TRUE);
+
+  return (FALSE);
+
+}
+
+int IsTwoOp (char *c) {
+
+  if (!strncmp (c, "<<", 2)) return (TRUE);
+  if (!strncmp (c, ">>", 2)) return (TRUE);
+  if (!strncmp (c, "&&", 2)) return (TRUE);
+  if (!strncmp (c, "||", 2)) return (TRUE);
+  if (!strncmp (c, "==", 2)) return (TRUE);
+  if (!strncmp (c, "!=", 2)) return (TRUE);
+  if (!strncmp (c, "<=", 2)) return (TRUE);
+  if (!strncmp (c, ">=", 2)) return (TRUE);
+
+  return (FALSE);
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/macro_create.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/macro_create.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/macro_create.c	(revision 3338)
@@ -0,0 +1,115 @@
+# include "opihi.h"
+# define D_NLINES 100
+# define prompt "> "
+int macro_exec   PROTO((int, char **));
+
+static char helpline[] = "(macro)";
+
+int macro_create (int argc, char **argv) {
+
+  int ThisList, depth, i, done, NLINES, N;
+  char *input, *help;
+  Command *cmd;
+  Macro *macro;
+
+  help = helpline;
+  if ((N = get_argument (argc, argv, "-c"))) {
+    remove_argument (N, &argc, argv);
+    help = strcreate(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: macro <name> [-c \"comment line\"]\n");
+    fprintf (stderr, "  (enter commands, end with the word 'END')\n");
+    return (FALSE);
+  }
+
+  /**** Check for existence of this macro ****/
+  cmd = MatchCommand (argv[1], FALSE, TRUE);
+  macro = MatchMacro (argv[1], FALSE, TRUE);
+  
+  if ((macro == NULL) && (cmd != NULL)) {
+    fprintf (stderr, "cannot redefine inherent command %s\n", argv[1]);
+    return (FALSE);
+  }
+  if ((macro != NULL) && (cmd == NULL)) {
+    fprintf (stderr, "programming error: macro not in command list (%s)\n", argv[1]);
+    return (FALSE);
+  }
+
+  if (macro == NULL) { /**** New Macro ****/
+    ALLOCATE (cmd, Command, 1);
+    cmd[0].name = strcreate (argv[1]);
+    cmd[0].help = help;
+    cmd[0].func = macro_exec;
+    AddCommand (cmd);
+    free (cmd);
+
+    macro = NewMacro (argv[1]);
+  } else { /**** Old Macro ****/
+    /* replace existing command help with new value */
+    if (cmd[0].help != helpline) 
+      free (cmd[0].help);
+    cmd[0].help = help;
+  }
+
+  /* reallocate space for macro lines */
+  NLINES = D_NLINES;
+  for (i = 0; i < macro[0].Nlines; i++) free (macro[0].line[i]);
+  ALLOCATE (macro[0].line, char *, NLINES);
+
+  /* read in macro
+     If we are entering at the keyboard (Nlists == 0), use readline.
+     Otherwise, read from the current list
+     End when we hit the final "END" (the true END -- we count macro defines!!) */
+     
+  depth = 0;
+  ThisList = Nlists;
+  for (i = 0, done = FALSE; !done; ) {
+
+    /* get the next line (from correct place) */
+    if (ThisList == 0) 
+      input = readline (prompt);
+    else 
+      input = get_next_listentry (ThisList);
+
+    if ((ThisList == 0) && (input == (char *) NULL)) {
+      fprintf (stderr, "end macro with 'END'\n");
+      continue;
+    }
+
+    if ((ThisList > 0) && (input == (char *) NULL)) {
+      fprintf (stderr, "missing 'END' in macro definition\n");
+      input = strcreate ("end");
+    }
+
+    stripwhite (input);
+
+    /* test for new macro (or other list, in the future?) */
+    if (is_list (input)) depth ++;
+
+    /* test for end of nested list -- if not nested, END refers to this macro */
+    if (!strncasecmp (input, "END", 3)) {
+      depth --;
+      if (depth < 0) { /* we hit the last "END", macro is done */
+	free (input);
+	macro[0].Nlines = i;
+	if (macro[0].Nlines == 0) 
+	  i = 1;
+	REALLOCATE (macro[0].line, char *, i);
+	return (TRUE);
+      }
+    }
+
+    if (*input) { 
+      macro[0].line[i] = input;
+      i++;
+      if (i == NLINES - 1) {
+	NLINES += D_NLINES;
+	REALLOCATE (macro[0].line, char *, NLINES);
+      }
+    }
+  }
+  return (TRUE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/macro_delete.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/macro_delete.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/macro_delete.c	(revision 3338)
@@ -0,0 +1,28 @@
+# include "opihi.h"
+
+int macro_delete (int argc, char **argv) {
+
+  Command *cmd;
+  Macro *macro;
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: macro delete <macro>\n");
+    return (FALSE);
+  }
+
+  macro = MatchMacro (argv[1], FALSE, TRUE);
+  if (macro == NULL) {
+    fprintf (stderr, "Macro %s not found\n", argv[1]);
+    return (FALSE);
+  }
+  cmd = MatchCommand (argv[1], FALSE, TRUE);
+  if (cmd == NULL) {
+    fprintf (stderr, "programming error: macro exists but not command\n");
+    return (FALSE);
+  }
+
+  DeleteMacro (macro);
+  DeleteCommand (cmd);
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/macro_edit.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/macro_edit.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/macro_edit.c	(revision 3338)
@@ -0,0 +1,9 @@
+# include "opihi.h"
+
+int macro_edit (int argc, char **argv) {
+
+  fprintf (stderr, "this function is not implemented yet\n");
+  return (FALSE);
+
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/macro_exec.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/macro_exec.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/macro_exec.c	(revision 3338)
@@ -0,0 +1,45 @@
+# include "opihi.h"
+
+int macro_exec (int argc, char **argv) {
+
+  int i, status, MacroDepth;
+  char *PreviousName, **params, tmp[1024];
+  Macro *macro;
+  
+  macro = MatchMacro (argv[0], FALSE, TRUE);
+  if (macro == NULL) {
+    fprintf (stderr, "%s: Command not found.\n", argv[0]);
+    return (FALSE);
+  }
+
+  /* increase MacroDepth by one - governs macro args */
+  PreviousName = GetMacroName ();
+  MacroDepth = GetMacroDepth ();
+  MacroDepth ++;
+  SetCurrentMacroData (macro[0].name, MacroDepth);
+
+  ALLOCATE (params, char *, argc);
+  sprintf (tmp, "%d.%d", MacroDepth, 0);
+  params[0] = strcreate (tmp);
+  sprintf (tmp, "%d", argc);
+  set_str_variable (params[0], tmp);
+  for (i = 1; i < argc; i++) {
+    sprintf (tmp, "%d.%d", MacroDepth, i);
+    params[i] = strcreate (tmp);
+    set_str_variable (params[i], argv[i]);
+  }
+
+  /* process this list */
+  status = exec_loop (&macro[0]);
+
+  /* clear out the command line variables */
+  for (i = 0; i < argc; i++) {
+    DeleteNamedScalar (params[i]);
+    free (params[i]);
+  }
+  free (params);
+  
+  MacroDepth --;
+  SetCurrentMacroData (PreviousName, MacroDepth);
+  return (status);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/macro_list.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/macro_list.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/macro_list.c	(revision 3338)
@@ -0,0 +1,23 @@
+# include "opihi.h"
+
+int macro_list_f (int argc, char **argv) {
+
+  int i;
+  Macro *macro;
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: macro list <macro>\n");
+    return (FALSE);
+  }
+
+  macro = MatchMacro (argv[0], FALSE, TRUE);
+  if (macro == NULL) {
+    fprintf (stderr, "%s: Macro not found\n", argv[1]);
+    return (FALSE);
+  }
+
+  for (i = 0; i < macro[0].Nlines; i++) {
+    fprintf (stderr, "%s\n", macro[0].line[i]);
+  }
+  return (TRUE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/macro_read.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/macro_read.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/macro_read.c	(revision 3338)
@@ -0,0 +1,9 @@
+# include "opihi.h"
+
+int macro_read (int argc, char **argv) {
+
+  fprintf (stderr, "this function is not implemented yet\n");
+  return (FALSE);
+
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/macro_write.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/macro_write.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/macro_write.c	(revision 3338)
@@ -0,0 +1,9 @@
+# include "opihi.h"
+
+int macro_write (int argc, char **argv) {
+
+  fprintf (stderr, "this function is not implemented yet\n");
+  return (FALSE);
+
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/multicommand.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/multicommand.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/multicommand.c	(revision 3338)
@@ -0,0 +1,16 @@
+# include "opihi.h"
+
+char **multicommand (char *line, int *nlist) {
+
+  char **list;
+  int Nlist, NLIST;
+
+  Nlist = 0;
+  NLIST = 10;
+  ALLOCATE (list, char *, NLIST);
+
+  list[0] = strcreate (line);
+  *nlist = 1;
+  return (list);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/opihi.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/opihi.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/opihi.c	(revision 3338)
@@ -0,0 +1,55 @@
+# include "opihi.h"
+
+/******************/
+int main (int argc, char **argv) {
+
+  int i, Nbad, Nlist, status;
+  char **list, *line, *outline, *prompt, *history;
+  pid_t ppid;
+
+  initialize (argc, argv);
+  startup (argc, argv);
+  prompt = get_variable("PROMPT");
+  history = get_variable("HISTORY");
+  welcome ();
+
+  Nbad = 0;
+  while (1) {  /** must exit with command "exit" or "quit" */
+    if (Nbad == 10) exit (3);
+
+    line = readline (prompt);
+    if (line == NULL) { 
+      
+      ppid = getppid();
+      if (ppid == 1) {
+	fprintf (stderr, "caught parent shutdown\n");
+	exit (2);
+      }
+      if (!isatty (STDIN_FILENO)) exit (2);
+      fprintf (stdout, "Use \"quit\" to exit\n");
+      Nbad ++;
+      continue;
+    }
+    Nbad = 0;
+
+    stripwhite (line);
+    if (*line) {
+      list = multicommand (line, &Nlist);
+      for (i = 0; i < Nlist; i++) {
+	status = command (list[i], &outline);
+	if (outline != NULL) free (outline);
+      }
+      add_history (line);
+      append_history (1, history);
+      free (line);
+      free (list);
+    }
+    line = (char *) NULL;
+  }
+}
+
+  /* this needs some work to use multicommand correctly 
+     multicommand is currently a do-nothing function.  
+     if we want multicommand to interact with the list/macro style commands, 
+     we need a command to push all the elements of the line onto the command stack.
+   */
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/parse.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/parse.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/parse.c	(revision 3338)
@@ -0,0 +1,271 @@
+# include "opihi.h"
+
+void interpolate_slash (char *line);
+
+char *parse (char *line) {
+
+  double fval;
+  char *newline, *N, *L, *val, *B, *V, *V0, *V1, *end, *c1, *c2;
+  int Nval, Nbytes, status, size;
+  FILE *f;
+  Vector *vec;
+
+  val = V0 = NULL;
+
+  if (line == (char *) NULL) goto error;
+
+  /* case 1: $var = expression */
+  if (line[0] == '$') {  
+    /* find the target variable name and the rest of the line */
+    interpolate_slash (line);
+    V0 = thisvar (line);
+    if (V0 == NULL) goto error;
+    V1 = aftervar (line);
+    if (V1 == NULL) goto error;
+ 
+    /* increment operator */
+    if (!strcmp (V1, "++")) {
+      val = get_variable (V0);
+      if (val == NULL) {
+	fval = 1.0;
+      } else {
+	fval = atof (val) + 1.0;
+      }
+      set_variable (V0, fval);
+      goto escape;
+    }
+
+    /* decrement operator */
+    if (!strcmp (V1, "--")) {
+      val = get_variable (V0);
+      if (val == NULL) {
+	fval = -1.0;
+      } else {
+	fval = atof (val) - 1.0;
+      }
+      set_variable (V0, fval);
+      goto escape;
+    }
+
+    /* not an assignement, syntax error */
+    if (*V1 != '=') goto error;
+
+    /* find first non-whitespace character after = */
+    V1 ++;
+    while (isspace (*V1)) V1++;
+    if (*V1 == 0) goto error;
+
+    /* command replacement.  execute the line, place answer in val. */
+    if (*V1 == '`') {
+
+      /* look for end of line, must be ` */
+      B = V1 + strlen (V1) - 1;
+      if (*B != '`') goto error;
+
+      /* val will hold the result */
+      ALLOCATE (val, char, 1024);
+
+      /* B is the command to be executed */
+      B = strncreate (V1 + 1, strlen(V1) - 2);
+      f = popen (B, "r");
+      Nbytes = fread (val, 1, 1023, f);
+      val[Nbytes] = 0;
+      status = pclose (f);
+      free (B);
+
+      if (status) fprintf (stderr, "warning: exit status of command %d\n", status);
+
+      /* convert all but last return to ' '.  drop last return */
+      for (B = val; *B != 0; B++) {
+	if (*B == '\n') {
+	  if (B[1]) {
+	    *B = ' ';
+	  } else {
+	    *B = 0;
+	  }
+	}
+      }
+    } 
+
+    /* simple variable assignment */
+    if (*V1 != '`') {
+      /* dvomath returns a new string, or NULL, with the result of the expression */
+      val = dvomath (1, &V1, &size, 0);
+      if (val == NULL) { 
+	while (whitespace (*V1)) V1++;
+	val = strcreate (V1);
+      } 
+    }
+    /* both dvomath and command replacement create (char *) val */
+    set_str_variable (V0, val);
+    goto escape;  /* frees temp variables */
+  }
+
+  /* case 2: vect[N] = value */
+  V0 = thiscomm (line);
+  if (strchr(V0, '[') != (char *) NULL) { 
+    /* get vector name (left in V0) */
+    N = strchr (V0, '[');
+    if (N == V0) goto error;
+
+    /* get bracket contents (left in V) */
+    L = strchr (V0, ']');
+    if (L == (char *) NULL) goto error;
+    if (L != V0 + strlen (V0) - 1) goto error;
+
+    *N = 0;
+    V = strncreate (N+1, L - N - 1);
+
+    /* expand value in brackets */
+    val = dvomath (1, &V, &size, 0);
+    if (val == NULL) {
+      print_error ();
+      goto error;
+    }
+    Nval = atoi (val);
+    free (val); val = NULL;
+    free (V);
+
+    /* find vector */
+    if ((vec = SelectVector (V0, OLDVECTOR, TRUE)) == NULL) goto error;
+    free (V0); V0 = (char *) NULL;
+    if (Nval >= vec[0].Nelements) {
+      fprintf (stderr, "no element %d\n", Nval);
+      goto escape;
+    }
+
+    /* find value for assignment */
+    V1 = nextcomm (line);
+    if (V1 == (char *) NULL) goto error;
+    if (V1[0] != '=') goto error;
+    V1 ++;
+
+    /*** assign vector element to value ***/
+    val = dvomath (1, &V1, &size, 0); 
+    if (val == (char *) NULL) {
+      print_error ();
+      goto error;
+    }
+    vec[0].elements[Nval] = atof (val);
+    goto escape;
+  }
+  free (V0); V0 = (char *) NULL;
+
+  /* case 3: {expression} */
+  ALLOCATE (newline, char, 1024);
+  for (L = line, N = newline; *L != 0; L++, N++) { 
+
+    /* copy elements from L (line) to N (newline) until we hit a '{' */
+    for (; (*L != '{') && (*L != 0); L++, N++) *N = *L;
+    if (*L == 0) break;
+
+    if ((L != line) && (*(L-1) == 0x5c)) {
+      N--;
+      *N = *L;
+      continue;
+    }
+
+    /* check on the syntax of the line */
+    L++;
+    c1 = strchr (L, '}');
+    if (c1 == NULL) {
+      fprintf (stderr, "no close brackets!\n");
+      goto escape;
+    }
+    c2 = strchr (L, '{');
+    if ((c2 != NULL) && (c2 < c1)) {
+      fprintf (stderr, "can't nest brackets!\n");
+      goto escape;
+    }
+    end = c1;
+    *c1 = 0;
+
+    /* value in brackets must be a math expression of some sort.
+       isolated words are not valid here */
+    val = dvomath (1, &L, &size, -1);
+    if (val == NULL) {
+      print_error ();
+      goto escape;
+    } 
+    /* copy val to outline */
+    for (V = val; *V != 0; V++,N++) *N = *V;
+    L = end;
+    N--;
+    free (val); val = (char *) NULL;
+  }
+  
+  *N = 0;
+  free (line); line = (char *) NULL;
+
+  /* \ protects next character */
+  interpolate_slash (newline);
+  
+  REALLOCATE (newline, char, strlen (newline) + 1);
+  return (newline); 
+
+  error:
+  fprintf (stderr, "syntax error\n");
+
+  escape:
+  if (line != (char *) NULL) free (line);
+  if (val != (char *) NULL) free (val);
+  if (V0 != (char *) NULL) free (V0);
+  return (NULL);
+}
+
+/* replace all instances of \A with A in line */
+void interpolate_slash (char *line) {
+
+  char *in, *out;
+
+  for (in = out = line; *in != 0; in++, out++) {
+    if (*in == 0x5c) in++;
+    *out = *in;
+    if (*in == 0) return;
+  }
+  *out = *in;
+}
+
+  /* this routine looks for math and/or logic expressions that 
+     need to be evaluated and passes them on to "parenthesis",
+     which evaluates the expression */
+
+  /* There are two situations now which define an expression to 
+     be evaluated:
+     1) $var = expression   -- everything after the = must be a math expression or a string
+     2) {expression}        -- everything within the {} must be a math expression
+   */
+
+  /* case 1: $var = expression.  test that
+     a) there is a $ as the first character
+     b) the variable defined by that $ is not null
+     c) there is an = sign following the variable
+     d) there is something following the = sign
+     */
+  
+  /* case 2: vect[N] = expression. check syntax:
+     a) last char must be ]
+     b) word must contain [
+     c) between [ & ] must be an integer
+     d) vector must exist
+     e) there is an = sign following the first word
+     f) there is something following the = sign
+  */
+     
+
+  /* case 3: we hunt for '{', and then the first '}' and pass everything
+     inbetween.  no nested {{}}s are allowed! */
+  
+/* thisword ALLOCATES
+   thisvar  ALLOCATES
+   thiscomm ALLOCATES
+   
+   nextword !ALLOCATE
+   nextcomm !ALLOCATE
+   
+   lastword !ALLOCATE
+   lastvar !ALLOCATE
+   
+   aftervar !ALLOCATE
+*/   
+
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/parse_commands.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/parse_commands.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/parse_commands.c	(revision 3338)
@@ -0,0 +1,50 @@
+# include "opihi.h"
+# define D_NARG 10
+
+char **parse_commands (char *line, int *argc) {
+
+  int i, j, NARG;
+  char *c;
+  char **argv;
+
+  NARG = D_NARG;
+  ALLOCATE (argv, char *, NARG);
+
+  argv[0] = thisword (line);
+  if (argv[0] == (char *) NULL) {
+    free (argv);
+    *argc = 0;
+    return ((char **) NULL);
+  }
+
+  c = nextword (line);
+  for (i = 1; c != (char *) NULL; i++) {
+    argv[i] = thisword (c);
+    if (argv[i] == (char *) NULL) {
+      for (j = 0; j < i; j++) 
+	free (argv[i]);
+      free (argv);
+      *argc = 0;
+      return (argv);
+    }
+    c = nextword (c);
+    if (i == NARG - 1) {
+      NARG += D_NARG;
+      REALLOCATE (argv, char *, NARG);
+    }
+  }
+  REALLOCATE (argv, char *, i);
+  *argc = i;
+
+  return (argv);
+
+}
+
+  /* parse out the command line into (char **argv).  line looks like:
+     command word word word ... */
+
+  /* argv[0] and argv[1..argc-1] are handled differently because
+     the syntax of a valid command and a valid word are slighly 
+     different (not that this is obviously wanted...) */
+
+
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/queues.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/queues.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/queues.c	(revision 3338)
@@ -0,0 +1,93 @@
+# include "opihi.h"
+
+/* these functions are somewhat fragile: we cannot do multiple 
+   CreateQueue / FindQueue operations in a row or the pointers 
+   will get messed up
+   do we need a 'delete queue' function?
+*/
+
+Queue *queues;   /* queue to store the list of all queues */
+int   Nqueues;   /* number of currently available queues */
+
+void InitQueues () {
+  Nqueues = 0;
+  ALLOCATE (queues, Queue, 1); 
+}
+
+/* list known queues */
+void ListQueues () {
+
+  int i;
+
+  for (i = 0; i < Nqueues; i++) {
+    fprintf (stderr, "%-15s %3d\n", queues[i].name, queues[i].Nlines);
+  }
+  return;
+}
+
+/* return the given queue */
+Queue *FindQueue (char *name) {
+
+  int i;
+
+  for (i = 0; i < Nqueues; i++) {
+    if (!strcmp (queues[i].name, name)) {
+      return (&queues[i]);
+    }
+  }
+  return (NULL);
+}
+
+/* make a new named queue */
+Queue *CreateQueue (char *name) {
+
+  Queue *queue;
+
+  queue = FindQueue (name);
+  if (queue != NULL) return (queue);
+
+  Nqueues ++;
+  REALLOCATE (queues, Queue, Nqueues);
+  queue = &queues[Nqueues - 1];
+  queue[0].Nlines = 0;
+  queue[0].NLINES = 10;
+  queue[0].name = strcreate (name);
+  ALLOCATE (queue[0].lines, char *, queue[0].NLINES);
+  return (queue);
+}
+
+void PushQueue (Queue *queue, char *line) {
+
+  int N;
+
+  N = queue[0].Nlines;
+  queue[0].lines[N] = strcreate (line);
+  queue[0].Nlines ++;
+  if (queue[0].Nlines == queue[0].NLINES) {
+    queue[0].NLINES += 10;
+    REALLOCATE (queue[0].lines, char *, queue[0].NLINES);
+  }    
+  return;
+}
+
+char *PopQueue (Queue *queue) {
+
+  int i;
+  char *line;
+
+  if (queue[0].Nlines == 0) return (NULL);
+  line = queue[0].lines[0];
+
+  for (i = 1; i < queue[0].Nlines; i++) {
+    queue[0].lines[i-1] = queue[0].lines[i];
+  }
+  queue[0].Nlines --;
+
+  if (queue[0].Nlines < queue[0].NLINES - 20) {
+    queue[0].NLINES -= 20;
+    queue[0].NLINES = MAX (queue[0].NLINES, 10);
+    REALLOCATE (queue[0].lines, char *, queue[0].NLINES);
+  }    
+  return (line);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/stack_math.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/stack_math.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/stack_math.c	(revision 3338)
@@ -0,0 +1,1361 @@
+# include "opihi.h"
+
+/* the result of a matrix operation must go into a temp variable,
+   labeled by "m". if one of the input matrices is already a temp variable, we 
+   can continue using it this round 
+   */
+
+int VV_binary (StackVar *OUT, StackVar *V1, StackVar *V2, char *op) {
+
+  int i, Nx;
+  float *out, *M1, *M2;
+  char line[512];
+  
+  Nx = V1[0].vector[0].Nelements;
+  if (Nx != V2[0].vector[0].Nelements) {
+    return (FALSE);
+  }
+
+  if (V1[0].type == 'v') {  /** use V1 as temp buffer **/
+    OUT[0].vector = V1[0].vector;
+    V1[0].type = 'V'; /* prevent it from being freed below */
+  } else {
+    if (V2[0].type == 'v') { /** use V2 as temp buffer, but header of V1 **/
+      OUT[0].vector = V2[0].vector;
+      V2[0].type = 'V'; /* prevent it from being freed below */
+    } else {  /* no spare temp buffer */
+      OUT[0].vector = InitVector ();
+      CopyVector (OUT[0].vector, V1[0].vector);
+    }
+  }
+  OUT[0].type = 'v'; /*** <<--- says this is a temporary matrix ***/
+  strcpy (OUT[0].name, "tmp");
+  M1  = V1[0].ptr;
+  M2  = V2[0].ptr;
+  out = OUT[0].ptr = (float *)OUT[0].vector[0].elements;
+
+  switch (op[0]) { 
+  case '+': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++)
+      *out = *M1 + *M2;
+    break; 
+  case '-': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++)
+      *out = *M1 - *M2;
+    break; 
+  case '*': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++)
+      *out = *M1 * *M2;
+    break; 
+  case '/': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++)
+      *out = *M1 / *M2;
+    break; 
+  case 0x5e: 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++) 
+      *out = pow (*M1, *M2);
+    break; 
+  case '@': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++) 
+      *out = DEG_RAD*atan2 (*M1, *M2);
+    break; 
+  case 'D': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++) 
+      *out = MIN (*M1, *M2);
+    break; 
+  case 'U': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++) 
+      *out = MAX (*M1, *M2);
+    break; 
+  case '<': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++) 
+      *out = (*M1 < *M2) ? 1 : 0;
+    break; 
+  case '>': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++) 
+      *out = (*M1 > *M2) ? 1 : 0;
+    break; 
+  case '&': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++) 
+      *out = ((int)*M1 & (int)*M2);
+    break; 
+  case '|': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++) 
+      *out = ((int)*M1 | (int)*M2);
+    break; 
+  case 'E': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++) 
+      *out = (*M1 == *M2) ? 1 : 0;
+    break; 
+  case 'N': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++) 
+      *out = (*M1 != *M2) ? 1 : 0;
+    break; 
+  case 'L': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++) 
+      *out = (*M1 <= *M2) ? 1 : 0;
+    break; 
+  case 'G': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++) 
+      *out = (*M1 >= *M2) ? 1 : 0;
+    break; 
+  case 'A': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++) 
+      *out = (*M1 && *M2) ? 1 : 0;
+    break; 
+  case 'O': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++) 
+      *out = (*M1 || *M2) ? 1 : 0;
+    break; 
+  default:
+    sprintf (line, "error: op %c not defined!", op[0]);
+    push_error (line);
+    return (FALSE);
+  }
+
+  /** free up any temporary buffers: **/
+
+  if (V1[0].type == 'v') {
+    free (V1[0].vector[0].elements);
+    free (V1[0].vector);
+  }
+  if (V2[0].type == 'v') {
+    free (V2[0].vector[0].elements);
+    free (V2[0].vector);
+  }
+
+  /* at the end, V1 and V2 are deleted only if they were temporary */
+  return (TRUE);
+
+}
+
+int SV_binary (StackVar *OUT, StackVar *V1, StackVar *V2, char *op) {
+
+  int i, Nx;
+  float *out, *M1, *M2;
+  char line[512];
+  
+  Nx = V2[0].vector[0].Nelements;
+
+  if (V2[0].type == 'v') { /** use V2 as temp buffer, but header of V1 **/
+    OUT[0].vector = V2[0].vector;
+    V2[0].type = 'V'; /* prevent it from being freed below */
+  } else {  /* no spare temp buffer */
+    OUT[0].vector = InitVector ();
+    CopyVector (OUT[0].vector, V2[0].vector);
+  }
+  OUT[0].type = 'v';   /*** <<--- says this is a temporary matrix ***/
+  strcpy (OUT[0].name, "tmp");
+  M1  = V1[0].ptr;
+  M2  = V2[0].ptr;
+  out = OUT[0].ptr = (float *)OUT[0].vector[0].elements;
+
+  switch (op[0]) { 
+  case '+': 
+    for (i = 0; i < Nx; i++, out++, M2++)
+      *out = *M1 + *M2;
+    break; 
+  case '-': 
+    for (i = 0; i < Nx; i++, out++, M2++)
+      *out = *M1 - *M2;
+    break; 
+  case '*': 
+    for (i = 0; i < Nx; i++, out++, M2++)
+      *out = *M1 * *M2;
+    break; 
+  case '/': 
+    for (i = 0; i < Nx; i++, out++, M2++)
+      *out = *M1 / *M2;
+    break; 
+  case 0x5e: 
+    for (i = 0; i < Nx; i++, out++, M2++) 
+      *out = pow (*M1, *M2);
+    break; 
+  case '@': 
+    for (i = 0; i < Nx; i++, out++, M2++) 
+      *out = DEG_RAD*atan2 (*M1, *M2);
+    break; 
+  case 'D': 
+    for (i = 0; i < Nx; i++, out++, M2++) 
+      *out = MIN (*M1, *M2);
+    break; 
+  case 'U': 
+    for (i = 0; i < Nx; i++, out++, M2++) 
+      *out = MAX (*M1, *M2);
+    break; 
+  case '<': 
+    for (i = 0; i < Nx; i++, out++, M2++) 
+      *out = (*M1 < *M2) ? 1 : 0;
+    break; 
+  case '>': 
+    for (i = 0; i < Nx; i++, out++, M2++) 
+      *out = (*M1 > *M2) ? 1 : 0;
+    break; 
+  case '&': 
+    for (i = 0; i < Nx; i++, out++, M2++) 
+      *out = ((int)*M1 & (int)*M2);
+    break; 
+  case '|': 
+    for (i = 0; i < Nx; i++, out++, M2++) 
+      *out = ((int)*M1 | (int)*M2);
+    break; 
+  case 'E': 
+    for (i = 0; i < Nx; i++, out++, M2++) 
+      *out = (*M1 == *M2) ? 1 : 0;
+    break; 
+  case 'N': 
+    for (i = 0; i < Nx; i++, out++, M2++) 
+      *out = (*M1 != *M2) ? 1 : 0;
+    break; 
+  case 'L': 
+    for (i = 0; i < Nx; i++, out++, M2++) 
+      *out = (*M1 <= *M2) ? 1 : 0;
+    break; 
+  case 'G': 
+    for (i = 0; i < Nx; i++, out++, M2++) 
+      *out = (*M1 >= *M2) ? 1 : 0;
+    break; 
+  case 'A': 
+    for (i = 0; i < Nx; i++, out++, M2++) 
+      *out = (*M1 && *M2) ? 1 : 0;
+    break; 
+  case 'O': 
+    for (i = 0; i < Nx; i++, out++, M2++) 
+      *out = (*M1 || *M2) ? 1 : 0;
+    break; 
+  default:
+    sprintf (line, "error: op %c not defined!", op[0]);
+    push_error (line);
+    return (FALSE);
+  }
+
+  /** free up any temporary buffers: **/
+  if (V2[0].type == 'v') {
+    free (V2[0].vector[0].elements);
+    free (V2[0].vector);
+  }
+
+  /* at the end, V1 and V2 are deleted only if they were temporary */
+  return (TRUE);
+
+}
+
+int VS_binary (StackVar *OUT, StackVar *V1, StackVar *V2, char *op) {
+
+  int i, Nx;
+  float *out, *M1, *M2;
+  char line[512];
+  
+  Nx = V1[0].vector[0].Nelements;
+
+  if (V1[0].type == 'v') { /** use V1 as temp buffer **/
+    OUT[0].vector = V1[0].vector;
+    V1[0].type = 'V'; /* prevent it from being freed below */
+  } else {  /* no spare temp buffer */
+    OUT[0].vector = InitVector ();
+    CopyVector (OUT[0].vector, V1[0].vector);
+  }
+  OUT[0].type = 'v';   /*** <<--- says this is a temporary matrix ***/
+  strcpy (OUT[0].name, "tmp");
+  M1  = V1[0].ptr;
+  M2  = V2[0].ptr;
+  out = OUT[0].ptr = (float *)OUT[0].vector[0].elements;
+
+  switch (op[0]) { 
+  case '+': 
+    for (i = 0; i < Nx; i++, out++, M1++)
+      *out = *M1 + *M2;
+    break; 
+  case '-': 
+    for (i = 0; i < Nx; i++, out++, M1++)
+      *out = *M1 - *M2;
+    break; 
+  case '*': 
+    for (i = 0; i < Nx; i++, out++, M1++)
+      *out = *M1 * *M2;
+    break; 
+  case '/': 
+    for (i = 0; i < Nx; i++, out++, M1++)
+      *out = *M1 / *M2;
+    break; 
+  case 0x5e: 
+    for (i = 0; i < Nx; i++, out++, M1++) 
+      *out = pow (*M1, *M2);
+    break; 
+  case '@': 
+    for (i = 0; i < Nx; i++, out++, M1++) 
+      *out = DEG_RAD*atan2 (*M1, *M2);
+    break; 
+  case 'D': 
+    for (i = 0; i < Nx; i++, out++, M1++) 
+      *out = MIN (*M1, *M2);
+    break; 
+  case 'U': 
+    for (i = 0; i < Nx; i++, out++, M1++) 
+      *out = MAX (*M1, *M2);
+    break; 
+  case '<': 
+    for (i = 0; i < Nx; i++, out++, M1++) 
+      *out = (*M1 < *M2) ? 1 : 0;
+    break; 
+  case '>': 
+    for (i = 0; i < Nx; i++, out++, M1++) 
+      *out = (*M1 > *M2) ? 1 : 0;
+    break; 
+  case '&': 
+    for (i = 0; i < Nx; i++, out++, M1++) 
+      *out = ((int)*M1 & (int)*M2);
+    break; 
+  case '|': 
+    for (i = 0; i < Nx; i++, out++, M1++) 
+      *out = ((int)*M1 | (int)*M2);
+    break; 
+  case 'E': 
+    for (i = 0; i < Nx; i++, out++, M1++) 
+      *out = (*M1 == *M2) ? 1 : 0;
+    break; 
+  case 'N': 
+    for (i = 0; i < Nx; i++, out++, M1++) 
+      *out = (*M1 != *M2) ? 1 : 0;
+    break; 
+  case 'L': 
+    for (i = 0; i < Nx; i++, out++, M1++) 
+      *out = (*M1 <= *M2) ? 1 : 0;
+    break; 
+  case 'G': 
+    for (i = 0; i < Nx; i++, out++, M1++) 
+      *out = (*M1 >= *M2) ? 1 : 0;
+    break; 
+  case 'A': 
+    for (i = 0; i < Nx; i++, out++, M1++) 
+      *out = (*M1 && *M2) ? 1 : 0;
+    break; 
+  case 'O': 
+    for (i = 0; i < Nx; i++, out++, M1++) 
+      *out = (*M1 || *M2) ? 1 : 0;
+    break; 
+  default:
+    sprintf (line, "error: op %c not defined!", op[0]);
+    push_error (line);
+    return (FALSE);
+  }
+
+  /** free up any temporary buffers: **/
+
+  if (V1[0].type == 'v') {
+    free (V1[0].vector[0].elements);
+    free (V1[0].vector);
+  }
+  /* at the end, V1 and V2 are deleted only if they were temporary */
+  return (TRUE);
+
+}
+
+int MV_binary (StackVar *OUT, StackVar *V1, StackVar *V2, char *op) {
+
+  int i, j, Nx, Ny;
+  float *out, *M1, *M2;
+  char line[512];
+ 
+  Nx = V1[0].buffer[0].matrix.Naxis[0];
+  Ny = V1[0].buffer[0].matrix.Naxis[1];
+  if (Ny != V2[0].vector[0].Nelements) {
+    push_error ("dimension mismatch");
+    return (FALSE);
+  }
+
+  /* if possible, use V1 as temp buffer, otherwise create new one */
+  if (V1[0].type == 'm') {  
+    OUT[0].buffer = V1[0].buffer;
+    V1[0].type = 'M'; /* prevent it from being freed below */
+  } else {  
+    /* do buffer.matrix.buffer and buffer.header.buffer get correctly zeroed? */
+    OUT[0].buffer = InitBuffer ();
+    CopyBuffer (OUT[0].buffer, V1[0].buffer);
+  }
+  OUT[0].type = 'm'; /*** <<--- says this is a temporary matrix ***/
+  strcpy (OUT[0].name, "tmp");
+  M1  = V1[0].ptr;
+  M2  = V2[0].ptr;
+  out = OUT[0].ptr = (float *)OUT[0].buffer[0].matrix.buffer;
+
+  switch (op[0]) { 
+  case '+': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++)
+        *out = *M1 + *M2;
+    }
+    break; 
+  case '-': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++)
+        *out = *M1 - *M2;
+    }
+    break; 
+  case '*': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++)
+        *out = *M1 * *M2;
+    }
+    break; 
+  case '/': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++)
+        *out = *M1 / *M2;
+    }
+    break; 
+  case 0x5e: 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++) 
+        *out = pow (*M1, *M2);
+    }
+    break; 
+  case '@': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++) 
+        *out = DEG_RAD*atan2 (*M1, *M2);
+    }
+    break; 
+  case 'D': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++) 
+        *out = MIN (*M1, *M2);
+    }
+    break; 
+  case 'U': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++) 
+        *out = MAX (*M1, *M2);
+    }
+    break; 
+  case '<': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++) 
+        *out = (*M1 < *M2) ? 1 : 0;
+    }
+    break; 
+  case '>': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++) 
+        *out = (*M1 > *M2) ? 1 : 0;
+    }
+    break; 
+  case '&': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++) 
+        *out = ((int)*M1 & (int)*M2);
+    }
+    break; 
+  case '|': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++) 
+        *out = ((int)*M1 | (int)*M2);
+    }
+    break; 
+  case 'E': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++) 
+        *out = (*M1 == *M2) ? 1 : 0;
+    }
+    break; 
+  case 'N': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++) 
+        *out = (*M1 != *M2) ? 1 : 0;
+    }
+    break; 
+  case 'L': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++) 
+        *out = (*M1 <= *M2) ? 1 : 0;
+    }
+    break; 
+  case 'G': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++) 
+        *out = (*M1 >= *M2) ? 1 : 0;
+    }
+    break; 
+  case 'A': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++) 
+        *out = (*M1 && *M2) ? 1 : 0;
+    }
+    break; 
+  case 'O': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++) 
+        *out = (*M1 || *M2) ? 1 : 0;
+    }
+    break; 
+  default:
+    sprintf (line, "error: op %c not defined!", op[0]);
+    push_error (line);
+    return (FALSE);
+  }
+
+  /** free up any temporary buffers: **/
+
+  if (V1[0].type == 'm') {
+    free (V1[0].buffer[0].header.buffer);
+    free (V1[0].buffer[0].matrix.buffer);
+    free (V1[0].buffer);
+  }
+  if (V2[0].type == 'v') {
+    free (V2[0].vector[0].elements);
+    free (V2[0].vector);
+  }
+  /* at the end, V1 and V2 are deleted only if they were temporary */
+  return (TRUE);
+
+}
+
+
+int VM_binary (StackVar *OUT, StackVar *V1, StackVar *V2, char *op) {
+
+  int i, j, Nx, Ny;
+  float *out, *M1, *M2;
+  char line[512];
+  
+  Nx = V2[0].buffer[0].matrix.Naxis[0];
+  Ny = V2[0].buffer[0].matrix.Naxis[1];
+  if (Nx != V1[0].vector[0].Nelements) {
+    return (FALSE);
+  }
+
+  /* if possible, use V2 as temp buffer, otherwise create new one */
+  if (V2[0].type == 'm') {
+    OUT[0].buffer = V2[0].buffer;
+    V2[0].type = 'M'; /* prevent it from being freed below */
+  } else {  /* no spare temp buffer */
+    OUT[0].buffer = InitBuffer ();
+    CopyBuffer (OUT[0].buffer, V2[0].buffer);
+  }
+  OUT[0].type = 'm'; /*** <<--- says this is a temporary matrix ***/
+  strcpy (OUT[0].name, "tmp");
+  M1  = V1[0].ptr;
+  M2  = V2[0].ptr;
+  out = OUT[0].ptr = (float *)OUT[0].buffer[0].matrix.buffer;
+
+  switch (op[0]) { 
+  case '+': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++)
+        *out = *M1 + *M2;
+    }
+    break; 
+  case '-': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++)
+        *out = *M1 - *M2;
+    }
+    break; 
+  case '*': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++)
+        *out = *M1 * *M2;
+    }
+    break; 
+  case '/': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++)
+        *out = *M1 / *M2;
+    }
+    break; 
+  case 0x5e: 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++) 
+        *out = pow (*M1, *M2);
+    }
+    break; 
+  case '@': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++) 
+        *out = DEG_RAD*atan2 (*M1, *M2);
+    }
+    break; 
+  case 'D': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++) 
+        *out = MIN (*M1, *M2);
+    }
+    break; 
+  case 'U': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++) 
+        *out = MAX (*M1, *M2);
+    }
+    break; 
+  case '<': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++) 
+        *out = (*M1 < *M2) ? 1 : 0;
+    }
+    break; 
+  case '>': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++) 
+        *out = (*M1 > *M2) ? 1 : 0;
+    }
+    break; 
+  case '&': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++) 
+        *out = ((int)*M1 & (int)*M2);
+    }
+    break; 
+  case '|': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++) 
+        *out = ((int)*M1 | (int)*M2);
+    }
+    break; 
+  case 'E': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++) 
+        *out = (*M1 == *M2) ? 1 : 0;
+    }
+    break; 
+  case 'N': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++) 
+        *out = (*M1 != *M2) ? 1 : 0;
+    }
+    break; 
+  case 'L': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++) 
+        *out = (*M1 <= *M2) ? 1 : 0;
+    }
+    break; 
+  case 'G': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++) 
+        *out = (*M1 >= *M2) ? 1 : 0;
+    }
+    break; 
+  case 'A': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++) 
+        *out = (*M1 && *M2) ? 1 : 0;
+    }
+    break; 
+  case 'O': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++) 
+        *out = (*M1 || *M2) ? 1 : 0;
+    }
+    break; 
+  default:
+    sprintf (line, "error: op %c not defined!", op[0]);
+    push_error (line);
+    return (FALSE);
+  }
+
+  /** free up any temporary buffers: **/
+
+  if (V1[0].type == 'v') {
+    free (V1[0].vector[0].elements);
+    free (V1[0].vector);
+  }
+  if (V2[0].type == 'm') {
+    free (V2[0].buffer[0].header.buffer);
+    free (V2[0].buffer[0].matrix.buffer);
+    free (V2[0].buffer);
+  }
+  /* at the end, V1 and V2 are deleted only if they were temporary */
+  return (TRUE);
+
+}
+
+int MM_binary (StackVar *OUT, StackVar *V1, StackVar *V2, char *op) {
+
+  int i, Nx, Ny;
+  float *out, *M1, *M2;
+  char line[512];
+  
+  Nx = V1[0].buffer[0].matrix.Naxis[0];
+  Ny = V1[0].buffer[0].matrix.Naxis[1];
+
+  if (V1[0].type == 'm') {  /** use V1 as temp buffer **/
+    OUT[0].buffer = V1[0].buffer;
+    V1[0].type = 'M'; /* prevent it from being freed below */
+  } else {
+    if (V2[0].type == 'm') { /** use V2 as temp buffer, but header of V1 **/
+      OUT[0].buffer = V2[0].buffer;
+      V2[0].type = 'M'; /* prevent it from being freed below */
+    } else {  /* no spare temp buffer */
+      OUT[0].buffer = InitBuffer ();
+      CopyBuffer (OUT[0].buffer, V1[0].buffer);
+    }
+  }
+  OUT[0].type = 'm'; /*** <<--- says this is a temporary matrix ***/
+  strcpy (OUT[0].name, "tmp");
+  M1  = V1[0].ptr;
+  M2  = V2[0].ptr;
+  out = OUT[0].ptr = (float *)OUT[0].buffer[0].matrix.buffer;
+
+  switch (op[0]) { 
+  case '+': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++)
+      *out = *M1 + *M2;
+    break; 
+  case '-': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++)
+      *out = *M1 - *M2;
+    break; 
+  case '*': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++)
+      *out = *M1 * *M2;
+    break; 
+  case '/': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++)
+      *out = *M1 / *M2;
+    break; 
+  case 0x5e: 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++) 
+      *out = pow (*M1, *M2);
+    break; 
+  case '@': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++) 
+      *out = DEG_RAD*atan2 (*M1, *M2);
+    break; 
+  case 'D': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++) 
+      *out = MIN (*M1, *M2);
+    break; 
+  case 'U': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++) 
+      *out = MAX (*M1, *M2);
+    break; 
+  case '<': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++) 
+      *out = (*M1 < *M2) ? 1 : 0;
+    break; 
+  case '>': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++) 
+      *out = (*M1 > *M2) ? 1 : 0;
+    break; 
+  case '&': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++) 
+      *out = ((int)*M1 & (int)*M2);
+    break; 
+  case '|': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++) 
+      *out = ((int)*M1 | (int)*M2);
+    break; 
+  case 'E': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++) 
+      *out = (*M1 == *M2) ? 1 : 0;
+    break; 
+  case 'N': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++) 
+      *out = (*M1 != *M2) ? 1 : 0;
+    break; 
+  case 'L': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++) 
+      *out = (*M1 <= *M2) ? 1 : 0;
+    break; 
+  case 'G': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++) 
+      *out = (*M1 >= *M2) ? 1 : 0;
+    break; 
+  case 'A': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++) 
+      *out = (*M1 && *M2) ? 1 : 0;
+    break; 
+  case 'O': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++) 
+      *out = (*M1 || *M2) ? 1 : 0;
+    break; 
+  default:
+    sprintf (line, "error: op %c not defined!", op[0]);
+    push_error (line);
+    return (FALSE);
+  }
+
+  /** free up any temporary buffers: **/
+
+  if (V1[0].type == 'm') {
+    free (V1[0].buffer[0].header.buffer);
+    free (V1[0].buffer[0].matrix.buffer);
+    free (V1[0].buffer);
+  }
+  if (V2[0].type == 'm') {
+    free (V2[0].buffer[0].header.buffer);
+    free (V2[0].buffer[0].matrix.buffer);
+    free (V2[0].buffer);
+  }
+  /* at the end, V1 and V2 are deleted only if they were temporary */
+  return (TRUE);
+
+}
+
+
+int MS_binary (StackVar *OUT, StackVar *V1, StackVar *V2, char *op) {
+
+  int i, Nx, Ny;
+  float *out, *M1, *M2;
+  char line[512];
+  
+  Nx = V1[0].buffer[0].matrix.Naxis[0];
+  Ny = V1[0].buffer[0].matrix.Naxis[1];
+
+  /* if possible, use V1 as temp buffer, otherwise create new one */
+  if (V1[0].type == 'm') {
+    OUT[0].buffer = V1[0].buffer;
+    V1[0].type = 'M'; /* prevent it from being freed below */
+  } else {
+    OUT[0].buffer = InitBuffer ();
+    CopyBuffer (OUT[0].buffer, V1[0].buffer);
+  }
+  OUT[0].type = 'm';      /*** <<--- says this is a temporary matrix ***/
+  strcpy (OUT[0].name, "tmp");
+  M1  = V1[0].ptr;
+  M2  = V2[0].ptr;
+  out = OUT[0].ptr = (float *)OUT[0].buffer[0].matrix.buffer;
+
+  switch (op[0]) { 
+  case '+': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++)
+      *out = *M1 + *M2;
+    break; 
+  case '-': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++)
+      *out = *M1 - *M2;
+    break; 
+  case '*': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++)
+      *out = *M1 * *M2;
+    break; 
+  case '/': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++)
+      *out = *M1 / *M2;
+    break; 
+  case 0x5e: 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++) 
+      *out = pow (*M1, *M2);
+    break; 
+  case '@': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++) 
+      *out = DEG_RAD*atan2 (*M1, *M2);
+    break; 
+  case 'D': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++) 
+      *out = MIN (*M1, *M2);
+    break; 
+  case 'U': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++) 
+      *out = MAX (*M1, *M2);
+    break; 
+  case '<': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++) 
+      *out = (*M1 < *M2) ? 1 : 0;
+    break; 
+  case '>': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++) 
+      *out = (*M1 > *M2) ? 1 : 0;
+    break; 
+  case '&': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++) 
+      *out = ((int)*M1 & (int)*M2);
+    break; 
+  case '|': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++) 
+      *out = ((int)*M1 | (int)*M2);
+    break; 
+  case 'E': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++) 
+      *out = (*M1 == *M2) ? 1 : 0;
+    break; 
+  case 'N': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++) 
+      *out = (*M1 != *M2) ? 1 : 0;
+    break; 
+  case 'L': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++) 
+      *out = (*M1 <= *M2) ? 1 : 0;
+    break; 
+  case 'G': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++) 
+      *out = (*M1 >= *M2) ? 1 : 0;
+    break; 
+  case 'A': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++) 
+      *out = (*M1 && *M2) ? 1 : 0;
+    break; 
+  case 'O': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++) 
+      *out = (*M1 || *M2) ? 1 : 0;
+    break; 
+  default:
+    sprintf (line, "error: op %c not defined!", op[0]);
+    push_error (line);
+    return (FALSE);
+  }
+
+  if (V1[0].type == 'm') {
+    free (V1[0].buffer[0].header.buffer);
+    free (V1[0].buffer[0].matrix.buffer);
+    free (V1[0].buffer);
+  }
+  return (TRUE);
+
+}
+
+
+int SM_binary (StackVar *OUT, StackVar *V1, StackVar *V2, char *op) {
+
+  int i, Nx, Ny;
+  float *out, *M1, *M2;
+  char line[512];
+  
+  Nx = V2[0].buffer[0].matrix.Naxis[0];
+  Ny = V2[0].buffer[0].matrix.Naxis[1];
+
+  if (V2[0].type == 'm') {  /* V2[0] is NOT temporary, we can't use it for storage */
+    OUT[0].buffer = V2[0].buffer;
+    V2[0].type = 'M'; /* prevent it from being freed below */
+  } else {
+    OUT[0].buffer = InitBuffer ();
+    CopyBuffer (OUT[0].buffer, V2[0].buffer);
+  }
+  OUT[0].type = 'm'; /*** <<--- says this is a temporary matrix ***/
+  strcpy (OUT[0].name, "tmp");
+  M1  = V1[0].ptr;
+  M2  = V2[0].ptr;
+  out = OUT[0].ptr = (float *)OUT[0].buffer[0].matrix.buffer;
+
+  switch (op[0]) { 
+  case '+': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++)
+      *out = *M1 + *M2;
+    break; 
+  case '-': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++)
+      *out = *M1 - *M2;
+    break; 
+  case '*': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++)
+      *out = *M1 * *M2;
+    break; 
+  case '/': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++)
+      *out = *M1 / *M2;
+    break; 
+  case 0x5e: 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++)
+      *out = pow (*M1, *M2);
+    break; 
+  case '@': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++) 
+      *out = DEG_RAD*atan2 (*M1, *M2);
+    break; 
+  case 'D': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++) 
+      *out = MIN (*M1, *M2);
+    break; 
+  case 'U': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++) 
+      *out = MAX (*M1, *M2);
+    break; 
+  case '<': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++) 
+      *out = (*M1 < *M2) ? 1 : 0;
+    break; 
+  case '>': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++) 
+      *out = (*M1 > *M2) ? 1 : 0;
+    break; 
+  case '&': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++) 
+      *out = ((int)*M1 & (int)*M2);
+    break; 
+  case '|': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++) 
+      *out = ((int)*M1 | (int)*M2);
+    break; 
+  case 'E': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++) 
+      *out = (*M1 == *M2) ? 1 : 0;
+    break; 
+  case 'N': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++) 
+      *out = (*M1 != *M2) ? 1 : 0;
+    break; 
+  case 'L': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++) 
+      *out = (*M1 <= *M2) ? 1 : 0;
+    break; 
+  case 'G': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++) 
+      *out = (*M1 >= *M2) ? 1 : 0;
+    break; 
+  case 'A': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++) 
+      *out = (*M1 && *M2) ? 1 : 0;
+    break; 
+  case 'O': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++) 
+      *out = (*M1 || *M2) ? 1 : 0;
+    break; 
+  default:
+    sprintf (line, "error: op %c not defined!", op[0]);
+    push_error (line);
+    return (FALSE);
+  }
+
+  if (V2[0].type == 'm') {
+    free (V2[0].buffer[0].header.buffer);
+    free (V2[0].buffer[0].matrix.buffer);
+    free (V2[0].buffer);
+  }
+  return (TRUE);
+
+}
+
+
+int SS_binary (StackVar *OUT, StackVar *V1, StackVar *V2, char *op) {
+
+  float *M1, *M2, *out;
+  char line[512];
+
+  M1  = V1[0].ptr;
+  M2  = V2[0].ptr;
+  OUT[0].ptr = V1[0].ptr;
+  out = OUT[0].ptr;
+  strcpy (OUT[0].name, "tmp");
+
+  switch (op[0]) { 
+  case '+': 
+    *out = *M1 + *M2;
+    break;    
+  case '-': 
+    *out = *M1 - *M2;
+    break;    
+  case '*': 
+    *out = *M1 * *M2;
+    break;    
+  case '/': 
+    *out = *M1 / *M2;
+    break; 
+  case 0x5e: 
+    *out = pow (*M1, *M2);
+    break; 
+  case '@': 
+    *out = DEG_RAD*atan2 (*M1, *M2);
+    break; 
+  case 'D': 
+    *out = MIN (*M1, *M2);
+    break; 
+  case 'U': 
+    *out = MAX (*M1, *M2);
+    break; 
+  case '<': 
+    *out = (*M1 < *M2) ? 1 : 0;
+    break; 
+  case '>': 
+    *out = (*M1 > *M2) ? 1 : 0;
+    break; 
+  case '&': 
+    *out = ((int)*M1 & (int)*M2);
+    break; 
+  case '|': 
+    *out = ((int)*M1 | (int)*M2);
+    break; 
+  case 'E': 
+    *out = (*M1 == *M2) ? 1 : 0;
+    break; 
+  case 'N': 
+    *out = (*M1 != *M2) ? 1 : 0;
+    break; 
+  case 'L': 
+    *out = (*M1 <= *M2) ? 1 : 0;
+    break; 
+  case 'G': 
+    *out = (*M1 >= *M2) ? 1 : 0;
+    break; 
+  case 'A': 
+    *out = (*M1 && *M2) ? 1 : 0;
+    break; 
+  case 'O': 
+    *out = (*M1 || *M2) ? 1 : 0;
+    break; 
+  default:
+    sprintf (line, "error: op %c not defined!", op[0]);
+    push_error (line);
+    return (FALSE);
+  }
+  OUT[0].Float = *(OUT[0].ptr);
+  OUT[0].type = 'S';
+  return (TRUE);
+
+}
+
+int WW_binary (StackVar *OUT, StackVar *V1, StackVar *V2, char *op) {
+
+  int value;
+  char line[512];
+
+  /* evaluate stack will only call WW_binary with one numerical value,
+     and only in the case that the string did not parse to a number 
+     thus: string == number -> false */
+  if (!strncasecmp (&V1[0].type, "S", 1)) {
+    value = (op[0] == 'N');
+    goto escape;
+  }
+  if (!strncasecmp (&V2[0].type, "S", 1)) {
+    value = (op[0] == 'N');
+    goto escape;
+  }
+
+  switch (op[0]) { 
+  case 'E': 
+    value = strcmp (V1[0].name, V2[0].name) ? 0 : 1;
+    break; 
+  case 'N': 
+    value = strcmp (V1[0].name, V2[0].name) ? 1 : 0;
+    break; 
+  default:
+    sprintf (line, "error: op %c not defined for string operations!", op[0]);
+    push_error (line);
+    return (FALSE);
+  }
+
+escape:
+  strcpy (OUT[0].name, "tmp");
+  OUT[0].Float = value;
+  OUT[0].type = 'S';
+  OUT[0].ptr = &OUT[0].Float;
+  return (TRUE);
+
+}
+
+
+int S_unary (StackVar *OUT, StackVar *V1, char *op) {
+
+  float *out, *M1;
+  
+  out = OUT[0].ptr = V1[0].ptr;
+  M1  = V1[0].ptr;
+
+  if (!strcmp (op, "="))     {    }
+  if (!strcmp (op, "abs"))   {    *out = fabs(*M1);           }
+  if (!strcmp (op, "int"))   {    *out = (float)(int)(*M1);   }
+  if (!strcmp (op, "exp"))   {    *out = exp (*M1);           }
+  if (!strcmp (op, "ten"))   {    *out = pow (10.0,*M1);      }
+  if (!strcmp (op, "log"))   {    *out = log10 (*M1);         }
+  if (!strcmp (op, "ln"))    {    *out = log (*M1);           }
+  if (!strcmp (op, "sqrt"))  {    *out = sqrt (*M1);          }
+
+  if (!strcmp (op, "sinh"))  {    *out = sinh (*M1);          }
+  if (!strcmp (op, "cosh"))  {    *out = cosh (*M1);          }
+  if (!strcmp (op, "asinh")) {    *out = asinh (*M1);         }
+  if (!strcmp (op, "acosh")) {    *out = acosh (*M1);         }
+  if (!strcmp (op, "lgamma")) {   *out = lgamma (*M1);        }
+
+  if (!strcmp (op, "sin"))   {    *out = sin (*M1);           }
+  if (!strcmp (op, "cos"))   {    *out = cos (*M1);           }
+  if (!strcmp (op, "tan"))   {    *out = tan (*M1);           }
+  if (!strcmp (op, "dsin"))  {    *out = sin (*M1*RAD_DEG);   }
+  if (!strcmp (op, "dcos"))  {    *out = cos (*M1*RAD_DEG);   }
+  if (!strcmp (op, "dtan"))  {    *out = tan (*M1*RAD_DEG);   }
+  if (!strcmp (op, "asin"))  {    *out = asin (*M1);          }
+  if (!strcmp (op, "acos"))  {    *out = acos (*M1);          }
+  if (!strcmp (op, "atan"))  {    *out = atan (*M1);          }
+  if (!strcmp (op, "dasin")) {    *out = asin (*M1)*DEG_RAD;  }
+  if (!strcmp (op, "dacos")) {    *out = acos (*M1)*DEG_RAD;  }
+  if (!strcmp (op, "datan")) {    *out = atan (*M1)*DEG_RAD;  }
+  if (!strcmp (op, "rnd"))   {    *out = drand48();           }
+  if (!strcmp (op, "not"))   {    *out = !(*M1);              }
+  if (!strcmp (op, "--"))    {    *out = - (*M1);             }
+  if (!strcmp (op, "isinf")) {    *out = !finite(*M1);        }
+  if (!strcmp (op, "isnan")) {    *out = isnan(*M1);          } 
+
+  OUT[0].Float = *out;
+  OUT[0].type = 'S';
+  return (TRUE);
+
+}
+
+int V_unary (StackVar *OUT, StackVar *V1, char *op) {
+
+  int i, Nx;
+  float *out, *M1;
+  
+  Nx = V1[0].vector[0].Nelements;
+ 
+  if (V1[0].type == 'v') {  /** use V1 as temp buffer **/
+    OUT[0].vector = V1[0].vector;
+    V1[0].type = 'V'; /* prevent it from being freed below */
+  } else {  /* no spare temp buffer */
+    OUT[0].vector = InitVector ();
+    CopyVector (OUT[0].vector, V1[0].vector);
+  }
+  OUT[0].type = 'v'; /*** <<--- says this is a temporary matrix ***/
+  M1  = V1[0].ptr;
+  out = OUT[0].ptr = (float *)OUT[0].vector[0].elements;
+
+  if (!strcmp (op, "="))     { } /* already set equal */
+  if (!strcmp (op, "abs"))   { for (i = 0; i < Nx; i++, out++, M1++) { *out = fabs(*M1);         }}
+  if (!strcmp (op, "int"))   { for (i = 0; i < Nx; i++, out++, M1++) { *out = (float)(int)(*M1); }}
+  if (!strcmp (op, "exp"))   { for (i = 0; i < Nx; i++, out++, M1++) { *out = exp(*M1);          }}
+  if (!strcmp (op, "ten"))   { for (i = 0; i < Nx; i++, out++, M1++) { *out = pow(10.0,*M1);     }}
+  if (!strcmp (op, "log"))   { for (i = 0; i < Nx; i++, out++, M1++) { *out = log10(*M1);        }}
+  if (!strcmp (op, "ln"))    { for (i = 0; i < Nx; i++, out++, M1++) { *out = log(*M1);          }}
+  if (!strcmp (op, "sqrt"))  { for (i = 0; i < Nx; i++, out++, M1++) { *out = sqrt(*M1);         }}
+
+  if (!strcmp (op, "sinh"))   { for (i = 0; i < Nx; i++, out++, M1++) { *out = sinh(*M1);        }}
+  if (!strcmp (op, "cosh"))   { for (i = 0; i < Nx; i++, out++, M1++) { *out = cosh(*M1);        }}
+  if (!strcmp (op, "asinh"))  { for (i = 0; i < Nx; i++, out++, M1++) { *out = asinh(*M1);       }}
+  if (!strcmp (op, "acosh"))  { for (i = 0; i < Nx; i++, out++, M1++) { *out = acosh(*M1);       }}
+  if (!strcmp (op, "lgamma")) { for (i = 0; i < Nx; i++, out++, M1++) { *out = lgamma(*M1);      }}
+
+  if (!strcmp (op, "sin"))   { for (i = 0; i < Nx; i++, out++, M1++) { *out = sin(*M1);          }}
+  if (!strcmp (op, "cos"))   { for (i = 0; i < Nx; i++, out++, M1++) { *out = cos(*M1);          }}
+  if (!strcmp (op, "tan"))   { for (i = 0; i < Nx; i++, out++, M1++) { *out = tan(*M1);          }}
+  if (!strcmp (op, "dsin"))  { for (i = 0; i < Nx; i++, out++, M1++) { *out = sin(*M1*RAD_DEG);  }}
+  if (!strcmp (op, "dcos"))  { for (i = 0; i < Nx; i++, out++, M1++) { *out = cos(*M1*RAD_DEG);  }}
+  if (!strcmp (op, "dtan"))  { for (i = 0; i < Nx; i++, out++, M1++) { *out = tan(*M1*RAD_DEG);  }}
+  if (!strcmp (op, "asin"))  { for (i = 0; i < Nx; i++, out++, M1++) { *out = asin(*M1);         }}
+  if (!strcmp (op, "acos"))  { for (i = 0; i < Nx; i++, out++, M1++) { *out = acos(*M1);         }}
+  if (!strcmp (op, "atan"))  { for (i = 0; i < Nx; i++, out++, M1++) { *out = atan(*M1);         }}
+  if (!strcmp (op, "dasin")) { for (i = 0; i < Nx; i++, out++, M1++) { *out = asin(*M1)*DEG_RAD; }}
+  if (!strcmp (op, "dacos")) { for (i = 0; i < Nx; i++, out++, M1++) { *out = acos(*M1)*DEG_RAD; }}
+  if (!strcmp (op, "datan")) { for (i = 0; i < Nx; i++, out++, M1++) { *out = atan(*M1)*DEG_RAD; }}
+  if (!strcmp (op, "rnd"))   { for (i = 0; i < Nx; i++, out++, M1++) { *out = drand48();         }}
+  if (!strcmp (op, "ramp"))  { for (i = 0; i < Nx; i++, out++, M1++) { *out = i;                 }}
+  if (!strcmp (op, "zero"))  { for (i = 0; i < Nx; i++, out++, M1++) { *out = 0;                 }}
+  if (!strcmp (op, "not"))   { for (i = 0; i < Nx; i++, out++, M1++) { *out = !(*M1);            }}
+  if (!strcmp (op, "--"))    { for (i = 0; i < Nx; i++, out++, M1++) { *out = -(*M1);            }}
+  if (!strcmp (op, "isinf")) { for (i = 0; i < Nx; i++, out++, M1++) { *out = !finite(*M1);      }}
+  if (!strcmp (op, "isnan")) { for (i = 0; i < Nx; i++, out++, M1++) { *out = isnan(*M1);        }}
+
+  /* xramp and yramp only make sense in for matrices. for vectors, xramp = ramp, yramp = zero */
+  if (!strcmp (op, "xramp")) { for (i = 0; i < Nx; i++, out++, M1++) { *out = i;                 }}
+  if (!strcmp (op, "yramp")) { for (i = 0; i < Nx; i++, out++, M1++) { *out = 0;                 }}
+
+  if (V1[0].type == 'v') {
+    free (V1[0].vector[0].elements);
+    free (V1[0].vector);
+  }  
+  return (TRUE);
+
+}
+
+int M_unary (StackVar *OUT, StackVar *V1, char *op) {
+
+  int i, j, Nx, Ny;
+  float *out, *M1;
+  
+  Nx = V1[0].buffer[0].matrix.Naxis[0];
+  Ny = V1[0].buffer[0].matrix.Naxis[1];
+
+  if (V1[0].type == 'm') {
+    OUT[0].buffer = V1[0].buffer;
+    V1[0].type = 'M'; /* prevent it from being freed below */
+  } else {
+    OUT[0].buffer = InitBuffer ();
+    CopyBuffer (OUT[0].buffer, V1[0].buffer);
+  }
+  OUT[0].type = 'm';      /*** <<--- says this is a temporary matrix ***/
+  M1  = V1[0].ptr;
+  out = OUT[0].ptr = (float *)OUT[0].buffer[0].matrix.buffer;
+
+  if (!strcmp (op, "="))     { }
+  if (!strcmp (op, "abs"))   { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = fabs(*M1);         }}
+  if (!strcmp (op, "int"))   { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = (float)(int)(*M1); }}
+  if (!strcmp (op, "exp"))   { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = exp(*M1);          }}
+  if (!strcmp (op, "ten"))   { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = pow(10.0,*M1);     }}
+  if (!strcmp (op, "log"))   { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = log10(*M1);        }}
+  if (!strcmp (op, "ln"))    { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = log(*M1);          }}
+  if (!strcmp (op, "sqrt"))  { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = sqrt(*M1);         }}
+
+  if (!strcmp (op, "sinh"))  { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = sinh(*M1);         }}
+  if (!strcmp (op, "cosh"))  { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = cosh(*M1);         }}
+  if (!strcmp (op, "asinh")) { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = asinh(*M1);        }}
+  if (!strcmp (op, "acosh")) { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = acosh(*M1);        }}
+  if (!strcmp (op, "lgamma")) { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = lgamma(*M1);      }}
+
+  if (!strcmp (op, "sin"))   { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = sin(*M1);          }}
+  if (!strcmp (op, "cos"))   { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = cos(*M1);          }}
+  if (!strcmp (op, "tan"))   { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = tan(*M1);          }}
+  if (!strcmp (op, "dsin"))  { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = sin(*M1*RAD_DEG);  }}
+  if (!strcmp (op, "dcos"))  { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = cos(*M1*RAD_DEG);  }}
+  if (!strcmp (op, "dtan"))  { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = tan(*M1*RAD_DEG);  }}
+  if (!strcmp (op, "asin"))  { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = asin(*M1);         }}
+  if (!strcmp (op, "acos"))  { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = acos(*M1);         }}
+  if (!strcmp (op, "atan"))  { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = atan(*M1);         }}
+  if (!strcmp (op, "dasin")) { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = asin(*M1)*DEG_RAD; }}
+  if (!strcmp (op, "dacos")) { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = acos(*M1)*DEG_RAD; }}
+  if (!strcmp (op, "datan")) { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = atan(*M1)*DEG_RAD; }}
+  if (!strcmp (op, "not"))   { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = !(*M1);            }}
+  if (!strcmp (op, "--"))    { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = -(*M1);            }}
+  if (!strcmp (op, "rnd"))   { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = drand48();         }}
+  if (!strcmp (op, "ramp"))  { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = i;                 }}
+  if (!strcmp (op, "zero"))  { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = 0;                 }}
+  if (!strcmp (op, "isinf")) { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = !finite(*M1);      }}
+  if (!strcmp (op, "isnan")) { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = isnan(*M1);        }}
+
+  /* xrm and yrm only make sense in for matrices. see special meaning for vectors */
+  if (!strcmp (op, "xramp")) {
+    for (j = 0; j < Ny; j++) {
+      for (i = 0; i < Nx; i++, out++, M1++) {
+        *out = i;
+      }
+    }
+  }
+  if (!strcmp (op, "yramp")) {
+    for (j = 0; j < Ny; j++) {
+      for (i = 0; i < Nx; i++, out++, M1++) {
+        *out = j;
+      }
+    }
+  }
+  
+  if (V1[0].type == 'm') {
+    free (V1[0].buffer[0].header.buffer);
+    free (V1[0].buffer[0].matrix.buffer);
+    free (V1[0].buffer);
+  }
+  return (TRUE);
+
+}
+
+/*********************** fits copy header ***********************************/
+int fits_copy_matrix_info (Matrix *matrix1, Matrix *matrix2) {
+
+  int i;
+
+  /* copy all but the matrix */
+
+  matrix2[0].unsign = matrix1[0].unsign;
+  matrix2[0].bitpix = matrix1[0].bitpix;
+  matrix2[0].size   = matrix1[0].size;
+  matrix2[0].bzero  = matrix1[0].bzero;
+  matrix2[0].bscale = matrix1[0].bscale;
+  matrix2[0].Naxes  = matrix1[0].Naxes;
+  for (i = 0; i < FT_MAX_NAXES; i++) 
+    matrix2[0].Naxis[i] = matrix1[0].Naxis[i];
+
+
+  return (TRUE);
+}       
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/startup.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/startup.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/startup.c	(revision 3338)
@@ -0,0 +1,147 @@
+# include "opihi.h"
+
+/* program-independent initialization */
+void startup (int argc, char **argv) {
+
+  long A, B;
+    
+  signal (SIGINT, SIG_IGN);
+
+  /* init srand for rnd numbers elsewhere */
+  A = time(NULL);
+  for (B = 0; A == time(NULL); B++);
+  srand48(B);
+ 
+  if (0) {
+    /* fix the history list to remove the timestamp */
+    char *c;
+    int i;
+    HIST_ENTRY **entry;
+    
+    entry = history_list ();
+    if (entry != (HIST_ENTRY **) NULL) {
+      for (i = 0; entry[i]; i++) {
+	if ((strlen (entry[i][0].line) > 19) &&
+	    (entry[i][0].line[2] == '/') && 
+	    (entry[i][0].line[5] == '/') && 
+	    (entry[i][0].line[11] == ':') && 
+	    (entry[i][0].line[14] == ':') && 
+	    (entry[i][0].line[17] == ':')) {
+	  c = entry[i][0].line + 19;
+	  memmove (entry[i][0].line, c, strlen(c) + 1);
+	}
+      }
+    }
+  }
+  
+  /* keep these? 
+     set_int_variable ("UNSIGN", 0);
+     FT_UNSIGN_MODE = FALSE;
+  */
+
+  {
+    
+    int i, N, status, ONLY_INPUT, LOAD_RC;
+    char *line, *home, *outline, *varname;
+    char *rcfile, **list;
+    int Nlist, NLIST;
+    static char dot[] = ".";
+   
+    /* load in interesting environment variables */
+    ALLOCATE (line, char, 1024);
+    
+    home = getenv ("HOME");
+    if (home == NULL) home = dot;
+    set_str_variable ("HOME", home);
+    set_str_variable ("KII", "kii");
+    set_str_variable ("KAPA", "kapa");
+
+# if 0    
+    help = getenv ("MANA-HELP");
+    if (help == (char *) NULL) {
+      /* try in exec path */
+      ALLOCATE (help, char, 1024);
+      execdir = findexec (argc, argv);
+      if (execdir == (char *) NULL) {
+	fprintf (stderr, "error with executable name: can't resolve path\n");
+	execdir = strcreate (".");
+      }
+      execname = filebasename (argv[0]);
+      sprintf (help, "%s/%s.hlp", execdir, execname);
+    }
+    set_str_variable ("HELPDIR", help);
+# endif
+
+    if (!ConfigInit (&argc, argv)) {
+      fprintf (stderr, "can't find config file. some functions will be unavailable\n");
+    }
+
+    LOAD_RC = TRUE;
+    if ((N = get_argument (argc, argv, "--norc"))) {
+      remove_argument (N, &argc, argv);
+      LOAD_RC = FALSE;
+    }
+    
+    ONLY_INPUT = FALSE;
+    if ((N = get_argument (argc, argv, "--only"))) {
+      remove_argument (N, &argc, argv);
+      ONLY_INPUT = TRUE;
+    }
+
+    /* load cmdline files */
+    Nlist = 0;
+    NLIST = 10;
+    ALLOCATE (list, char *, NLIST);
+    while ((N = get_argument (argc, argv, "--load"))) {
+      remove_argument (N, &argc, argv);
+      list[Nlist] = strcreate (argv[N]);
+      remove_argument (N, &argc, argv);
+      Nlist++;
+      if (Nlist == NLIST) {
+	NLIST += 10;
+	REALLOCATE (list, char *, NLIST);
+      }
+    }
+
+    is_script = TRUE;
+    if (argc == 1) is_script = FALSE;
+    set_int_variable ("SCRIPT", is_script);
+
+    if (LOAD_RC && !is_script) {
+      rcfile = get_variable ("RCFILE");
+      sprintf (line, "input %s/%s", home, rcfile);
+      status = command (line, &outline);
+      if (outline != (char *) NULL) 
+	free (outline);
+      free (home);
+    }
+      
+    set_int_variable ("argv:n", 0);
+    if (is_script) {
+      /* first argument in input script, rest are argv */
+      list[Nlist] = strcreate (argv[1]);
+      Nlist ++;
+      /* generate list argv:0 - argv:n from arguments */
+      ALLOCATE (varname, char, 256);
+      for (i = 2; i < argc; i++) {
+	sprintf (varname, "argv:%d", i - 2);
+	set_str_variable (varname, argv[i]);
+      }
+      set_int_variable ("argv:n", i - 2);
+      free (varname);
+    }
+
+    /* execute command-line entries */
+    for (i = 0; i < Nlist; i++) {
+      ALLOCATE (line, char, 1024);
+      sprintf (line, "input %s", list[i]);
+      status = command (line, &outline);
+      if (outline != (char *) NULL) free (outline);
+    }
+    free (list);
+
+    /* if this is not an interactive session, exit here */
+    if (ONLY_INPUT) exit (2);
+    if (is_script) exit (2);
+  }
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/string.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/string.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/string.c	(revision 3338)
@@ -0,0 +1,240 @@
+# include "opihi.h"
+
+/**********************************************************************/
+/* returns a pointer to an isolated string containing the first word,
+   removing leading whitespace.  A "word" is a contiguous set of 
+   characters from the set: alphanumerics, and any of: / . _ -
+   Any other single, non-whitespace characters are considered to be 
+   complete words in themselves.  Any characters surrounded by quotes 
+   make a single word 
+*/
+
+char *thisword (char *string) {
+
+  int i, j, N;
+  char *word;
+
+  if (string == (char *) NULL) return ((char *) NULL);
+
+  for (i = 0; whitespace (string[i]); i++);
+  if (string[i] == 0) return ((char *)NULL);
+  if (string[i] == ';') {
+    word = strncreate (&string[i], 1);
+    return (word);
+  }
+
+  /* a string of characters contained within double quotes is 
+      a single entry.  check that there are pairs of quotes,
+      return only the string between the quotes */
+  if (string[i] == '"') { 
+    i++;
+    if (string[i] == 0) return ((char *) NULL);
+    for (j = i; (string[j] != 0) && (string[j] != '"'); j++);
+    if (string[j] == 0) {
+      fprintf (stderr, "misbalanced quotes\n");
+      return ((char *)NULL);
+    }
+    word = strncreate (&string[i], j - i);
+    return (word);
+  } 
+
+  /* a string of characters contained within parentheses is 
+      a single entry.  check that there are matched pairs of
+      parentheses, return string, including exterior parentheses */
+  if (string[i] == '(') { 
+    i++;
+    N = 1;
+    if (string[i] == 0) return ((char *) NULL);
+    for (j = i; (string[j] != 0) && (N > 0); j++) {
+      if (string[j] == '(') {
+	N++;
+      }
+      if (string[j] == ')') {
+	N--;
+      }
+    }
+    if ((string[j] == 0) && (N != 0)) {
+      fprintf (stderr, "misbalanced parenthesis\n");
+      return ((char *)NULL);
+    }
+    word = strncreate (&string[i-1], j - i + 1);
+    return (word);
+  } 
+
+
+  for (j = i; (string[j] != 0) && (string[j] != ';') && !whitespace(string[j]); j++);
+  word = strncreate (&string[i], j - i);
+  return (word);
+
+}
+
+/* returns a pointer to an isolated string containing the first command,
+   removing leading whitespace.  A command ends with the first non whitespace */
+char *thiscomm (char *string) {
+
+  int i, j;
+  char *word;
+
+  if (string == (char *) NULL) return ((char *) NULL);
+
+  for (i = 0; whitespace (string[i]); i++);
+  if (string[i] == 0) return ((char *)NULL);
+
+  for (j = i; ((string[j] != 0) && !whitespace (string[j])); j++);
+  if (i == j) return ((char *) NULL);
+
+  word = strncreate (&string[i], j - i);
+  return (word);
+
+}
+
+/* take a pointer to the beginning of a variable (ie $foo)
+and extract only the variable name (eg, foo) */
+
+char *thisvar (char *string) {
+
+  int i;
+  char *word;
+
+  if (string == (char *) NULL) return ((char *) NULL);
+  if (string[0] != '$') return ((char *) NULL);
+
+  for (i = 1; ISVAR(string[i]); i++);
+  if (i == 1) return ((char *) NULL);
+
+  word = strncreate (&string[1], i - 1);
+  return (word);
+
+}
+
+
+/**********************************************************************/
+/* returns a pointer to the next word, or (char *) NULL if there is not a next word */
+char *nextword (char *string) {
+
+  int i, j;
+
+  if (string == (char *) NULL) return ((char *) NULL);
+
+  for (i = 0; whitespace (string[i]); i++);
+  if (string[i] == 0) return ((char *)NULL);
+
+  if (string[i] == '"') { 
+    i++;
+    if (string[i] == 0) return ((char *) NULL);
+    for (; (string[i] != 0) && (string[i] != '"'); i++);
+    if (string[i] == 0) {
+      fprintf (stderr, "misbalanced quotes\n");
+      return ((char *)NULL);
+    }
+    i++;
+    for (; (string[i] != 0) && whitespace (string[i]); i++);
+    if (string[i] == 0) return ((char *) NULL);
+    return (&string[i]);
+  } 
+
+  if (string[i] == '(') { 
+    i++; 
+    j = 1;
+    if (string[i] == 0) return ((char *) NULL);
+    for (; (string[i] != 0) && (j > 0); i++) {
+      if (string[i] == '(') {
+	j++;
+      }
+      if (string[i] == ')') {
+	j--;
+      }
+    }
+    if ((string[i] == 0) && (j != 0)) {
+      fprintf (stderr, "misbalanced parenthesis\n");
+      return ((char *)NULL);
+    }
+    for (; (string[i] != 0) && whitespace (string[i]); i++);
+    if (string[i] == 0) return ((char *) NULL);
+    return (&string[i]);
+  } 
+
+  if (string[i] == ';') i++;
+  for (; (string[i] != 0) && (string[i] != ';') && !whitespace(string[i]); i++);
+  for (; (string[i] != 0) && whitespace (string[i]); i++);
+  if (string[i] == 0) return ((char *) NULL);
+
+  return (&string[i]);
+}
+
+/* returns a pointer to the next command, or (char *) NULL 
+   if there is not a next command.  A command is bounded by whitespace */
+char *nextcomm (char *string) {
+
+  int i;
+
+  if (string == (char *) NULL) return ((char *) NULL);
+  
+  for (i = 0; (string[i] != 0) && !whitespace (string[i]); i++);
+  if (string[i] == 0) return ((char *) NULL);
+  
+  for (; whitespace (string[i]); i++);
+  if (string[i] == 0) return ((char *) NULL);
+
+  return (&string[i]);
+}
+
+/* returns a pointer to the previous word,
+   or (char *) NULL if there is not a previous word
+*/
+char *lastword (char *string, char *c) {
+
+  if (string == (char *) NULL) return ((char *) NULL);
+  if (c == (char *) NULL) return ((char *) NULL);
+
+  for (; !whitespace(*c) && (c >= string); c--);
+  if (c < string) return ((char *)NULL);
+
+  for (; whitespace(*c) && (c >= string); c--);
+  if (c < string)
+    return ((char *)NULL);
+  for (; !whitespace(*c) && (c >= string); c--);
+  c++;
+  return (c);
+}
+
+
+
+/* take a pointer to the beginning of a variable (ie $fred) and return
+   a pointer to the next thing (non whitespace) which is not part of the
+   variable extract only the variable name */
+
+char *aftervar (char *string) {
+
+  int i, j;
+
+  if (string == (char *) NULL) return ((char *) NULL);
+  if (string[0] != '$') return ((char *) NULL);
+
+  for (i = 1; ISVAR(string[i]); i++);
+  if (i == 1) return ((char *) NULL);
+
+  for (j = i; whitespace (string[j]); j++);
+  if (string[j] == 0) return ((char *)NULL);
+
+  return (&string[j]);
+
+}
+
+
+/* returns a pointer to the previous var, 
+   or (char *) NULL if there is not a previous word
+*/
+char *lastvar (char *string, char *c) {
+
+  if (string == (char *) NULL) return ((char *) NULL);
+  if (c == (char *) NULL) return ((char *) NULL);
+
+  for (; (c >= string) && whitespace(*c); c--);
+  if (c < string) return ((char *)NULL);
+
+  for (; (c >= string) && ISVAR(*c) ; c--);
+  if ((c < string) || (*c != '$')) return ((char *)NULL);
+
+  return (c);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/timeformat.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/timeformat.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/timeformat.c	(revision 3338)
@@ -0,0 +1,30 @@
+# include "opihi.h"
+
+int GetTimeFormat (time_t *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, "JD")) *TimeFormat     = TIME_JD;
+    if (!strcasecmp (p, "MJD")) *TimeFormat    = TIME_MJD;
+    if (!strcasecmp (p, "date")) *TimeFormat   = TIME_DATE;
+    if (!strcasecmp (p, "days")) *TimeFormat   = TIME_DAYS;
+    if (!strcasecmp (p, "hours")) *TimeFormat  = TIME_HOURS;
+    if (!strcasecmp (p, "min")) *TimeFormat    = TIME_MINUTES;
+    if (!strcasecmp (p, "sec")) *TimeFormat    = TIME_SECONDS;
+    if (!*TimeFormat) fprintf (stderr, "unknown TIME_FORMAT\n");
+    free (p);
+    return (FALSE);
+  }
+  if (!*TimeFormat) *TimeFormat = TIME_SECONDS;
+  return (TRUE);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/lib.shell/variable.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib.shell/variable.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib.shell/variable.c	(revision 3338)
@@ -0,0 +1,255 @@
+# include "opihi.h"
+
+Variable *variables;   /* variable to store the list of all variables */
+int      Nvariables;   /* number of currently available variables */
+
+void InitVariables () {
+  Nvariables = 0;
+  ALLOCATE (variables, Variable, 1); 
+}
+
+int set_local_variable (char *name, char *value) {
+
+  int i;
+  char *local, *MacroName;
+
+  /* a local variable has the form (macroname).(varname) */
+  MacroName = GetMacroName ();
+
+  /* look for global variable (warning or error)
+  for (i = 0; i < Nvariables; i++) {
+    if (!strcmp (name, variables[i].name)) {
+      fprintf (stderr, "warning: local variable overrides global name\n");
+    }
+  } */
+
+  /* look for existing local variable */
+  ALLOCATE (local, char, strlen(name) + strlen(MacroName) + 2);
+  sprintf (local, "%s.%s", MacroName, name);
+  for (i = 0; i < Nvariables; i++) {
+    if (!strcmp (local, variables[i].name)) {
+      free (variables[i].value);
+      free (local);
+      variables[i].value = strcreate (value);
+      return (TRUE);
+    }
+  }
+  /* NEW variable */
+  Nvariables ++;
+  REALLOCATE (variables, Variable, Nvariables);
+  variables[Nvariables - 1].name = local;
+  variables[Nvariables - 1].value = strcreate (value);
+  return (TRUE);
+}
+
+int set_str_variable (char *name, char *value) {
+
+  int i;
+  char *local, *MacroName;
+
+  MacroName = GetMacroName ();
+
+  /* look for local variable first */
+  ALLOCATE (local, char, strlen(name) + strlen(MacroName) + 2);
+  sprintf (local, "%s.%s", MacroName, name);
+  for (i = 0; i < Nvariables; i++) {
+    if (!strcmp (local, variables[i].name)) {
+      free (variables[i].value);
+      free (local);
+      variables[i].value = strcreate (value);
+      return (TRUE);
+    }
+  }
+  free (local);
+
+  /* look for global variable */
+  for (i = 0; i < Nvariables; i++) {
+    if (!strcmp (name, variables[i].name)) {
+      free (variables[i].value);
+      variables[i].value = strcreate (value);
+      return (TRUE);
+    }
+  }
+  /* NEW variable */
+  Nvariables ++;
+  REALLOCATE (variables, Variable, Nvariables);
+  variables[Nvariables - 1].name = strcreate (name);
+  variables[Nvariables - 1].value = strcreate (value);
+  return (TRUE);
+}
+
+int set_variable (char *name, double dvalue) {
+
+  char value[1024];
+
+  sprintf (value, "%.9g", dvalue);
+  set_str_variable (name, value);
+  return (TRUE);
+}
+
+int set_int_variable (char *name, int ivalue) {
+
+  char value[1024];
+
+  sprintf (value, "%d", ivalue);
+  set_str_variable (name, value);
+  return (TRUE);
+}
+
+char *get_variable_ptr (char *name) {
+  
+  int i;
+  char *local, *MacroName;
+
+  MacroName = GetMacroName ();
+
+  /* look for local variable first */
+  ALLOCATE (local, char, strlen(name) + strlen(MacroName) + 2);
+  sprintf (local, "%s.%s", MacroName, name);
+  for (i = 0; i < Nvariables; i++) { /* find the variable mentioned */
+    if (!strcmp(local, variables[i].name)) {
+      free (local);
+      return (variables[i].value);
+    }
+  }
+  free (local);
+
+  /* look for global variable */
+  for (i = 0; i < Nvariables; i++) { /* find the variable mentioned */
+    if (!strcmp(name, variables[i].name)) {
+      return (variables[i].value);
+    }
+  }
+  return ((char *) NULL);
+}
+
+char *get_variable (char *name) {
+  
+  int i;
+  char *local, *MacroName;
+
+  MacroName = GetMacroName ();
+
+  /* look for local variable first */
+  ALLOCATE (local, char, strlen(name) + strlen(MacroName) + 2);
+  sprintf (local, "%s.%s", MacroName, name);
+  for (i = 0; i < Nvariables; i++) { /* find the variable mentioned */
+    if (!strcmp(local, variables[i].name)) {
+      free (local);
+      return (strcreate (variables[i].value));
+    }
+  }
+  free (local);
+
+  /* look for global variable */
+  for (i = 0; i < Nvariables; i++) { /* find the variable mentioned */
+    if (!strcmp(name, variables[i].name)) {
+      return (strcreate (variables[i].value));
+    }
+  }
+  return ((char *) NULL);
+}
+
+char *get_local_variable_ptr (char *name) {
+  
+  int i;
+  char *local, *MacroName;
+
+  MacroName = GetMacroName ();
+
+  /* look for local variable first */
+  ALLOCATE (local, char, strlen(name) + strlen(MacroName) + 2);
+  sprintf (local, "%s.%s", MacroName, name);
+  for (i = 0; i < Nvariables; i++) { /* find the variable mentioned */
+    if (!strcmp(local, variables[i].name)) {
+      free (local);
+      return (variables[i].value);
+    }
+  }
+  free (local);
+  return ((char *) NULL);
+}
+
+float get_variable_default (char *name, float dvalue) {
+
+  char *value;
+  float fvalue;
+
+  value = get_variable (name);
+  if (value == NULL) {
+    return (dvalue);
+  }
+  fvalue = atof (value);
+  return (fvalue);
+}
+
+double get_double_variable (char *name) {
+  
+  int i;
+  char *local, *MacroName;
+
+  MacroName = GetMacroName ();
+
+  /* look for local variable first */
+  ALLOCATE (local, char, strlen(name) + strlen(MacroName) + 2);
+  sprintf (local, "%s.%s", MacroName, name);
+  for (i = 0; i < Nvariables; i++) { /* find the variable mentioned */
+    if (!strcmp(local, variables[i].name)) {
+      free (local);
+      return (atof (variables[i].value));
+    }
+  }
+  free (local);
+
+  /* look for global variable */
+  for (i = 0; i < Nvariables; i++) { /* find the variable mentioned */
+    if (!strcmp(name, variables[i].name)) {
+      return (atof (variables[i].value));
+    }
+  }
+  return (0.0);
+}
+
+int DeleteNamedScalar (char *name) {
+
+  int i, j;
+
+  for (i = 0; i < Nvariables; i++) {
+    if (!strcmp (name, variables[i].name)) {
+      free (variables[i].name);
+      free (variables[i].value);
+      for (j = i; j < Nvariables - 1; j++) {
+	variables[j] = variables[j + 1];
+      }
+      Nvariables --;
+      REALLOCATE (variables, Variable, MAX (Nvariables, 1));
+      return (TRUE);
+    }
+  }
+  return (FALSE);
+}
+
+int IsScalar (char *name) { 
+
+  int i;
+
+  for (i = 0; i < Nvariables; i++) {
+    if (!strcmp (name, variables[i].name)) return (TRUE);
+  }
+  return (FALSE);
+}
+
+void ListVariables () {
+
+  int i;
+
+  if (Nvariables == 0) {
+    fprintf (stderr, "No defined variables\n");
+    return;
+  }
+
+  for (i = 0; i < Nvariables; i++) {
+    fprintf (stderr, "%s = %s\n", variables[i].name, variables[i].value);
+  }
+  return;
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/lib/.cvsignore
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/lib/.cvsignore	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/lib/.cvsignore	(revision 3338)
@@ -0,0 +1,1 @@
+*.linux *.lin64 *.sol *.sun *.sid *.hp *.irix
Index: /tags/opihi-2-1/Ohana/src/opihi/mana/Makefile
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/mana/Makefile	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/mana/Makefile	(revision 3338)
@@ -0,0 +1,139 @@
+include ../../../Configure
+
+default: all
+
+HOME    =       $(ROOT)/src/opihi.v2
+BIN     =       $(HOME)/bin
+LIB     =       $(HOME)/lib
+INC     =       $(HOME)/include
+HELP    =       $(HOME)/help
+SDIR    =       $(HOME)/mana
+#
+DESTBIN =       $(LBIN)
+DESTLIB =       $(LLIB)
+DESTINC =       $(LINC)
+DESTMAN =       $(LMAN)
+#  
+INCS    =       -I$(INC) -I$(LINC) -I$(XINC)
+LFLAGS  =       -L$(LLIB) -L$(LIB)
+LIBS1   =       -lFITS -lsocket -lnsl -lreadline -ltermcap -lohana -lm
+LIBS2   =       -lbasiccmd -ldatacmd -lastrocmd -lshell -ldata 
+LIBS    =       $(LIBS2) $(LIBS1) 
+CFLAGS  =       $(INCS)
+CCFLAGS =       $(LIBS) 
+
+# mana user commands and support functions ########################
+
+manafuncs = \
+$(SDIR)/init.$(ARCH).o \
+$(SDIR)/mana.$(ARCH).o \
+$(SDIR)/findrowpeaks.$(ARCH).o 
+
+manacmds = \
+$(SDIR)/rawstars.$(ARCH).o \
+$(SDIR)/fitcontour.$(ARCH).o \
+$(SDIR)/starcontour.$(ARCH).o \
+$(SDIR)/findpeaks.$(ARCH).o 
+
+mana = $(manacmds) $(manafuncs)
+
+libs = \
+$(DESTLIB)/libshell.a \
+$(DESTLIB)/libdata.a \
+$(DESTLIB)/libbasiccmd.a \
+$(DESTLIB)/libastrocmd.a \
+$(DESTLIB)/libdatacmd.a
+
+all: mana
+
+mana: $(BIN)/mana.$(ARCH)
+	@echo done
+
+$(BIN)/mana.$(ARCH) : $(mana) $(libs)
+
+install: $(DESTBIN)/mana
+
+# these need to have a better home
+# $(SDIR)/demux.$(ARCH).o		  	\
+# $(SDIR)/elixir.$(ARCH).o	  	\
+# $(SDIR)/adc.$(ARCH).o             	\
+# $(SDIR)/focus.$(ARCH).o		  	\
+# $(SDIR)/simsignal.$(ARCH).o	  	\
+
+# utilities #################################################
+$(BIN)/%.$(ARCH):
+	@if [ ! -d $(BIN) ]; then mkdir -p $(BIN); fi
+	$(CC) $^ -o $@ $(LFLAGS) $(LIBS)
+	@echo "compiled $*"
+	@echo ""
+
+$(DESTBIN)/%: $(BIN)/%.$(ARCH) 
+	@if [ ! -d $(DESTBIN) ]; then mkdir -p $(DESTBIN); fi
+	rm -f $(DESTBIN)/$*
+	cp $(BIN)/$*.$(ARCH) $(DESTBIN)/$*
+	@echo "installed $*"
+	@echo ""
+
+$(LIB)/%.$(ARCH).a:
+	@if [ ! -d $(LIB) ]; then mkdir -p $(LIB); fi
+	rm -f $@
+	ar rcv $@ $^ 
+	$(RANLIB) $@
+	@echo "compiled library $*"
+	@echo ""
+
+$(DESTLIB)/%.a: $(LIB)/%.$(ARCH).a
+	@if [ ! -d $(DESTLIB) ]; then mkdir -p $(DESTLIB); fi
+	@echo ""
+	rm -f $@
+	cp $^ $@
+
+clean:
+	rm -f $(BIN)/*.$(ARCH)
+	rm -f $(LIB)/*.$(ARCH).a
+	rm -f `find . -name "*.o"`
+	rm -f `find . -name "*~"`
+	rm -f `find . -name "#*"`
+
+dist: clean
+	rm -f $(BIN)/*
+	rm -f $(LIB)/*
+
+lib%.clean:
+	rm -f $(LIB)/lib$*.$(ARCH).a
+	rm -f $($*)
+	@echo ""
+
+%.clean:
+	rm -f $(BIN)/$*.$(ARCH)
+	@echo ""
+
+%.$(ARCH).o : %.c
+	$(CC) $(CFLAGS) -c $*.c -o $@
+
+
+
+## -*- makefile -*- 
+# deprecated functions: verify & delete
+#$(SDIR)/abszero.$(ARCH).o \
+#$(SDIR)/cals.$(ARCH).o \
+#$(SDIR)/dumpmags.$(ARCH).o \
+#$(SDIR)/extract.$(ARCH).o \
+#$(SDIR)/gtypes.$(ARCH).o \
+#$(SDIR)/photresid.$(ARCH).o \
+#$(SDIR)/resid.$(ARCH).o \
+#$(SDIR)/zeropts.$(ARCH).o
+#$(SDIR)/objload.$(ARCH).o \ - make sure we have vect to tv
+#$(SDIR)/ccdextract.$(ARCH).o \
+#$(SDIR)/cmdextract.$(ARCH).o \
+#$(SDIR)/dmagextract.$(ARCH).o \
+#$(SDIR)/ddmagextract.$(ARCH).o \
+
+# future functions, not fully implemented
+#$(SDIR)/detrend.$(ARCH).o \
+#$(SDIR)/getxtra.$(ARCH).o \
+#$(SDIR)/addxtra.$(ARCH).o \
+
+# functions that need to be updated
+#$(SDIR)/gregions.$(ARCH).o \
+
Index: /tags/opihi-2-1/Ohana/src/opihi/mana/adc.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/mana/adc.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/mana/adc.c	(revision 3338)
@@ -0,0 +1,117 @@
+# include "dimm.h"
+
+# define DIGITAL_OUT 0x40
+# define ANALOG_IN_INIT 0x00
+# define ANALOG_IN_HIGH 0xa1
+# define ANALOG_IN_LOW  0x91
+
+static char SerialConnected = FALSE;
+static unsigned char DigitalOutState = 0x00;
+static struct timeval reftime; 
+static char reftimeset = FALSE;
+
+# define DTIME(A,B) ((A.tv_sec - B.tv_sec) + 1e-6*(A.tv_usec - B.tv_usec))
+
+int adc (int argc, char **argv) {
+  
+  struct timeval now;
+  int i, N, mode, hi, lo, value;
+  unsigned char setbit, output[5], *input;
+  double dtime;
+
+  if (N = get_argument (argc, argv, "-reset")) {
+    remove_argument (N, &argc, argv);
+    gettimeofday (&reftime, (struct timeval *) NULL);
+    reftimeset = TRUE;
+    return (TRUE);
+  }
+
+  if (argc != 4) {
+    fprintf (stderr, "USAGE: adc ai N (variable)\n");
+    fprintf (stderr, "USAGE: adc di N (variable)\n");
+    fprintf (stderr, "USAGE: adc do N mode\n");
+    return (FALSE);
+  }
+
+  if (!SerialConnected) {
+    if (!SerialInit ('b')) {
+      fprintf (stderr, "error opening serial line\n");
+      return (FALSE);
+    }
+    SerialConnected = TRUE;
+  }
+
+  if (!reftimeset) {
+    gettimeofday (&reftime, (struct timeval *) NULL);
+    reftimeset = TRUE;
+  }      
+
+  gettimeofday (&now, (struct timeval *) NULL);
+  dtime = DTIME (now, reftime);
+  set_variable ("TIME", dtime);
+  
+  /* set the digital outputs */
+  if (!strcmp (argv[1], "do")) {
+    N = atof (argv[2]);
+    if ((N < 1) || (N > 6)) {
+      fprintf (stderr, "digital output is between 1 and 6\n");
+      return (FALSE);
+    }
+    if (!strcasecmp (argv[3], "on")) {
+      mode = TRUE;
+    } else {
+      mode = FALSE;
+    }
+    setbit = (0x01 << N-1);
+    if (mode) {
+      DigitalOutState |= setbit;
+    } else {
+      DigitalOutState &= ~setbit;
+    }      
+    output[0] = (DIGITAL_OUT | DigitalOutState);
+    output[1] = 0;
+    SerialCommand (output, &input, 50);
+    fprintf (stderr, "%x (%x, %x) -> %x (%d, %d)\n", 
+	     output[0], setbit, DigitalOutState, input[0], 
+	     strlen(input), strlen(output));
+    free (input);
+    return (TRUE);
+  }
+  /* read the analog inputs */
+  if (!strcmp (argv[1], "ai")) {
+    N = atof (argv[2]);
+    if ((N < 2) || (N > 16)) {
+      fprintf (stderr, "analog input is between 2 and 16\n");
+      fprintf (stderr, " (problem with 1 for the moment...)\n");
+      return (FALSE);
+    }
+    /* init A/D converter */
+    output[0] = (ANALOG_IN_INIT | (N-1));
+    output[1] = 0;
+    SerialCommand (output, &input, 50);
+    free (input);
+
+    usleep (10000);
+    /* get high byte */
+    output[0] = ANALOG_IN_HIGH;
+    output[1] = 0;
+    do {
+      SerialCommand (output, &input, 50);
+      hi = input[0];
+      free (input);
+    } while (hi & 0x80);
+
+    output[0] = ANALOG_IN_LOW;
+    output[1] = 0;
+    SerialCommand (output, &input, 50);
+    /* fprintf (stderr, "%x -> %x\n", output[0], input[0]); */
+    lo = input[0];
+    free (input);
+    value = ((hi & 0x0f) << 8) | lo;
+    if (hi & 0x10) { value = -value; }
+    set_variable (argv[3], 0.0001*value);
+    return (TRUE);
+  }
+
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/mana/demux.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/mana/demux.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/mana/demux.c	(revision 3338)
@@ -0,0 +1,72 @@
+# include "dimm.h"
+
+int demux (int argc, char **argv) {
+  
+  int i, j, k, N;
+  float *out, *in, *inptr, **outptr;
+  int nx, ny, Nx, Ny, NX, NY, Nmux, Nbuf;
+
+  if (argc != 4) {
+    fprintf (stderr, "USAGE: demux <buffer> nx ny\n");
+    return (FALSE);
+  }
+
+  if (!SelectBuffer (&Nbuf, argv[1], OLDBUFFER)) return (FALSE);
+
+  nx = atof (argv[2]);
+  ny = atof (argv[3]);
+  Nmux = nx*ny;
+
+  Nx = buffers[Nbuf].matrix.Naxis[0];
+  Ny = buffers[Nbuf].matrix.Naxis[1];
+
+  NX = Nx / nx;
+  NY = Ny / ny;
+
+  inptr = in = (float *) buffers[Nbuf].matrix.buffer;  /* don't lose reference */
+
+  ALLOCATE (out, float, Nx*Ny);
+  ALLOCATE (outptr, float *, Nmux);
+  
+  for (N = i = 0; i < nx; i++) {
+    for (j = 0; j < ny; j++, N++) {
+      outptr[N] = &out[i*NX + j*NX*NY*nx];
+    }
+  }
+
+  for (N = j = 0; j < NY; j++) {
+    for (i = 0; i < NX; i++) {
+      for (k = 0; k < Nmux; k++) {
+	*outptr[k] = *inptr;
+	outptr[k] ++;
+	inptr ++;
+      }
+    }
+    for (k = 0; k < Nmux; k++) outptr[k] += NX;
+  }
+
+  /*
+  for (X = Y = x = y = i = 0; i < NX*NY; i++) {
+    out[X + Y*NX + x*NX*(Y+1) + y*NX*NY*nx] = *in;
+    X++;
+    if (X == NX) {
+      X = 0;
+      Y++;
+    }
+    if (Y == NY) {
+      Y = 0;
+      x++;
+    }
+    if (x == nx) {
+      x = 0;
+      y++;
+    }
+  }
+  */
+
+  free (in);
+  buffers[Nbuf].matrix.buffer = (char *) out;
+
+  return (TRUE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/mana/findpeaks.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/mana/findpeaks.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/mana/findpeaks.c	(revision 3338)
@@ -0,0 +1,106 @@
+# include "mana.h"
+
+int findpeaks (int argc, char **argv) {
+  
+  int i, j, n, N, Nx, Ny;
+  int xo, yo;
+  int Npeak, NPEAK, Npeaks;
+  float *v;
+  int *peaks, *keep, *xp, *yp, *zp;
+  float threshold, vt, vo;
+  Vector *vecx, *vecy, *vecz;
+  Buffer *buf;
+
+  if (argc < 3) goto usage;
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  threshold = atof (argv[2]);
+
+  if ((vecx = SelectVector ("xp", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((vecy = SelectVector ("yp", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((vecz = SelectVector ("zp", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  Nx = buf[0].matrix.Naxis[0];
+  Ny = buf[0].matrix.Naxis[1];
+
+  Npeak = 0;
+  NPEAK = Nx;
+  ALLOCATE (xp, int, NPEAK);
+  ALLOCATE (yp, int, NPEAK);
+  ALLOCATE (zp, int, NPEAK);
+
+  /* find peaks for each row */
+  v = (float *) buf[0].matrix.buffer;
+  for (j = 0; j < Ny; j++) {
+    peaks = findrowpeaks (&v[j*Nx], Nx, threshold, &Npeaks);
+
+    if (Npeak + Npeaks >= NPEAK) {
+      NPEAK = Npeak + Npeaks + Nx;
+      REALLOCATE (xp, int, NPEAK);
+      REALLOCATE (yp, int, NPEAK);
+      REALLOCATE (zp, int, NPEAK);
+    }
+    for (i = 0; i < Npeaks; i++) {
+      xp[Npeak + i] = peaks[i];
+      yp[Npeak + i] = j;
+      zp[Npeak + i] = v[peaks[i] + j*Nx];
+    }
+    Npeak += Npeaks;
+    free (peaks);
+  }
+  
+  /* identify non-local peaks */
+  ALLOCATE (keep, int, MAX (Npeak, 1));
+  v = (float *) buf[0].matrix.buffer;
+  for (n = 0; n < Npeak; n++) {
+    xo = xp[n];
+    yo = yp[n];
+    vo = v[xo + yo*Nx];
+    keep[n] = TRUE;
+    for (i = xo - 1; i <= xo + 1; i++) {
+      if (i < 0) continue;
+      if (i >= Nx) continue;
+      for (j = yo - 1; j <= yo + 1; j++) {
+	if ((i == xo) && (j == yo)) continue;
+	if (j < 0) continue;
+	if (j >= Ny) continue;
+	vt = v[i + j*Nx];
+	if (vt > vo) {
+	  keep[n] = FALSE;
+	  goto next_peak;
+	}
+      }
+    }
+  next_peak:
+    continue;
+  }
+
+  REALLOCATE (vecx[0].elements, float, MAX (Npeak, 1));
+  REALLOCATE (vecy[0].elements, float, MAX (Npeak, 1));
+  REALLOCATE (vecz[0].elements, float, MAX (Npeak, 1));
+  /* eliminate non-local peaks */
+  for (N = n = 0; n < Npeak; n++) {
+    if (!keep[n]) continue;
+    vecx[0].elements[N] = xp[n];
+    vecy[0].elements[N] = yp[n];
+    vecz[0].elements[N] = zp[n];
+    N ++;
+  }
+  free (xp);
+  free (yp);
+  free (zp);
+  free (keep);
+
+  REALLOCATE (vecx[0].elements, float, MAX (N, 1));
+  REALLOCATE (vecy[0].elements, float, MAX (N, 1));
+  REALLOCATE (vecz[0].elements, float, MAX (N, 1));
+  vecx[0].Nelements = vecy[0].Nelements = vecz[0].Nelements = N;
+
+  return (TRUE);
+
+ usage:
+  fprintf (stderr, "findpeaks (buffer) (threshold)\n");
+  return (FALSE);
+}
+
+
Index: /tags/opihi-2-1/Ohana/src/opihi/mana/findrowpeaks.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/mana/findrowpeaks.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/mana/findrowpeaks.c	(revision 3338)
@@ -0,0 +1,45 @@
+# include "mana.h"
+
+int *findrowpeaks (float *row, int Nrow, float threshold, int *npeaks) {
+  
+  int i;
+  int Npeaks, NPEAKS;
+  int *peaks;
+
+  Npeaks = 0;
+  NPEAKS = 100;
+  ALLOCATE (peaks, int, NPEAKS);
+
+  if (Nrow < 3) {
+    *npeaks = Npeaks;
+    return (peaks);
+  }
+    
+  /* special case for first pixel in row */
+  if ((row[0] > row[1]) && (row[0] > threshold)) {
+    peaks[Npeaks] = 0;
+    Npeaks ++;
+  }    
+
+  for (i = 1; i < Nrow - 1; i++) {
+    if (row[i] < threshold) continue;
+    if (row[i] < row[i-1]) continue;
+    if (row[i] <= row[i+1]) continue;
+
+    peaks[Npeaks] = i;
+    Npeaks ++;
+    if (Npeaks >= NPEAKS) {
+      NPEAKS += 100;
+      REALLOCATE (peaks, int, NPEAKS);
+    }
+  }      
+
+  /* special case for last pixel in row */
+  if ((row[Nrow-1] >= row[Nrow-2]) && (row[Nrow-1] > threshold)) {
+    peaks[Npeaks] = Nrow-1;
+    Npeaks ++;
+  }    
+
+  *npeaks = Npeaks;
+  return (peaks);
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/mana/fitcontour.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/mana/fitcontour.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/mana/fitcontour.c	(revision 3338)
@@ -0,0 +1,139 @@
+# include "mana.h"
+# define NTERM 3
+
+int fitcontour (int argc, char **argv) {
+  
+  int i;
+  double **C, **B;
+  float cs1, sn1, cs, sn, x, y, r, xo, yo, t;
+  float dR, Rmin, Rmaj, Theta, Rx, Ry, Rxy, R1, R2, R3;
+  Vector *vecx, *vecy;
+
+  /* USAGE fitcontour x y Xo Yo */
+  if (argc < 5) goto usage;
+
+  if ((vecx = SelectVector (argv[1], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((vecy = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  xo = atof (argv[3]);
+  yo = atof (argv[4]);
+
+  ALLOCATE (B, double *, NTERM);
+  ALLOCATE (C, double *, NTERM);
+  for (i = 0; i < NTERM; i++) {
+    ALLOCATE (C[i], double, NTERM);
+    bzero (C[i], NTERM*sizeof(double));
+    ALLOCATE (B[i], double, 1);
+    bzero (B[i], sizeof(double));
+  }
+
+  /* we are fitting r = ro + rs*sin(2theta) + rc*cos(2theta) */
+  /* sin(2t) = 2cos(t)sin(t)
+     cos(2t) = cos^2(t) - sin^2(t)
+  */
+  for (i = 0; i < vecx[0].Nelements; i++) {
+    x = vecx[0].elements[i] - xo;
+    y = vecy[0].elements[i] - yo;
+    r = hypot (x, y);
+
+    /* calculate sin(2t), cos(2t) using 1/2 angle tri relationship above */
+    sn1 = y / r;
+    cs1 = x / r;
+    sn = 2*sn1*cs1;
+    cs = cs1*cs1 - sn1*sn1;
+
+    C[0][0] += 1.0;
+    C[1][0] += sn;
+    C[1][1] += SQ(sn);
+    C[2][0] += cs; 
+    C[2][1] += cs*sn; 
+    C[2][2] += SQ(cs);
+
+    B[0][0] += r;
+    B[1][0] += r*sn;
+    B[2][0] += r*cs; 
+  }
+  C[0][1] = C[1][0];
+  C[0][2] = C[2][0];
+  C[1][2] = C[2][1];
+    
+  gaussj (C, NTERM, B, 1);
+  
+  /** this is somewhat weak: if the object is too elongated, Rmin can be < 0 **/
+  dR = hypot (B[1][0], B[2][0]);
+  Rmaj = B[0][0] + dR;
+  Rmin = B[0][0] - dR;
+  Theta = DEG_RAD*atan2 (B[1][0], B[2][0]) / 2;
+
+  sn = B[1][0] / dR;
+  cs = B[2][0] / dR;
+
+  R1 = SQ(Rmaj) + SQ(Rmin);
+  R2 = SQ(Rmaj) - SQ(Rmin);
+  R3 = Rmaj*Rmin;
+
+  Rx = R3 / sqrt (R1 - R2*cs);
+  Ry = R3 / sqrt (R1 + R2*cs);
+  Rxy = -sn*R2 / SQ(R3);
+
+  set_variable ("Rx", Rx);
+  set_variable ("Ry", Ry);
+  set_variable ("Rxy", Rxy);
+
+  set_variable ("Rmin", Rmin);
+  set_variable ("Rmaj", Rmaj);
+  set_variable ("Theta", Theta);
+
+  for (i = 0; i < NTERM; i++) {
+    free (B[i]);
+    free (C[i]);
+  }
+  free (B);
+  free (C);
+
+  return (TRUE);
+
+ usage:
+  fprintf (stderr, "fitcontour x y (xo) (yo)\n");
+  return (FALSE);
+}
+
+
+/* this routine fits a single sine and cosine to the value of dr as a function of the angle around the central
+ * point, theta.  this is NOT an exact fit, an is increasingly in error for more eccentric ellipses.  however,
+ * it does a reasonable job of approximating the value of the major and minor axes, and it gets the angle of
+ * orientation right at well.  We then assume the values of major and minor axis and angle are correct to get
+ * the parameters for the elliptical gaussian fit:
+ 
+ z = (x^2) / (2 Rx^2) + (y^2) / (2 Ry^2) + Rxy x y
+
+ the functions above give the correct relationship between these:
+
+   R1 = SQ(Rmaj) + SQ(Rmin);
+   R2 = SQ(Rmaj) - SQ(Rmin);
+   R3 = Rmaj*Rmin;
+
+   Rx = R3 / sqrt (R1 - R2*cs);
+   Ry = R3 / sqrt (R1 + R2*cs);
+   Rxy = -sn*R2 / SQ(R3);
+
+ to derive these relationships, write the equation for an ellipse with major axis in the x-dir and minor in
+ the y-dir:
+
+ z = (x^2) / (2 Rmaj^2) + (y^2) / (2 Rmin^2)
+
+ apply the rotation matrix:
+
+ (x)' = (cos, -sin)(x,y)
+ (y)' = (sin, +cos)(x,y)  (modulo the sign on the sine)
+
+ then group the x^2 terms, the y^2 terms, and the xy terms to find the three coeffs.
+
+ NOTE: I spent a while having trouble deriving this from the polar form of an ellipse:
+
+ x = Rmaj*cos(theta)
+ y = Rmin*sin(theta)
+
+ it turns out that 'theta' above is NOT the angle (0,1)-(0,0)-(x,y). rather, it should be viewed as a
+ paraterization of the ellipse.  
+
+*/
Index: /tags/opihi-2-1/Ohana/src/opihi/mana/focus.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/mana/focus.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/mana/focus.c	(revision 3338)
@@ -0,0 +1,68 @@
+# include "dimm.h"
+
+int focus (int argc, char **argv) {
+  
+  if (argc < 2) goto usage;
+
+  if (!strcasecmp (argv[1], "init")) {
+    if (argc != 3) {
+      fprintf (stderr, "USAGE: focus init (port)\n");
+      return (FALSE);
+    }
+    if (!SerialInit (argv[2])) return (FALSE);
+    fprintf (stderr, "focus on port %s\n", argv[2]);
+    return (TRUE);
+  }
+
+  if (!strcasecmp (argv[1], "pos")) {
+
+    int status, servo, angle;
+    char *answer = (char *) NULL;
+    char line[64];
+
+    if (argc != 4) {
+      fprintf (stderr, "USAGE: focus pos Nservo (angle)\n");
+      return (FALSE);
+    }
+
+    servo = atoi (argv[2]);
+    angle = atoi (argv[3]);
+
+    sprintf (line, "%c%c%c\n", 0xff, servo, angle);
+    status = SerialCommand (line, &answer, 10);
+    fprintf (stderr, "status: %d\n", status);
+    if (answer != (char *) NULL) {
+      fprintf (stderr, "answer: ..%s..\n", answer);
+    }
+    return (TRUE);
+  }
+
+  if (!strcasecmp (argv[1], "raw")) {
+
+    int status, value;
+    char *answer = (char *) NULL;
+    char line[64];
+
+    if (argc != 3) {
+      fprintf (stderr, "USAGE: focus raw value\n");
+      return (FALSE);
+    }
+
+    value = atoi (argv[2]);
+
+    sprintf (line, "%c", value);
+    status = SerialCommand (line, &answer, 10);
+    fprintf (stderr, "status: %d\n", status);
+    if (answer != (char *) NULL) {
+      fprintf (stderr, "answer: ..%s..\n", answer);
+    }
+    return (TRUE);
+  }
+
+ usage:
+  fprintf (stderr, "focus init port\n");
+  fprintf (stderr, "focus pos (string)\n");
+  fprintf (stderr, "focus raw (value)\n");
+  return (FALSE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/mana/init.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/mana/init.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/mana/init.c	(revision 3338)
@@ -0,0 +1,23 @@
+# include "opihi.h"
+
+int findpeaks	    PROTO((int, char **));
+int fitcontour	    PROTO((int, char **));
+int starcontour	    PROTO((int, char **));
+int rawstars	    PROTO((int, char **));
+
+static Command cmds[] = {  
+  {"findpeaks",   findpeaks,    "find image peaks"},
+  {"fitcontour",  fitcontour,   "fit ellipse contour"},
+  {"starcontour", starcontour,  "object contour"},
+  {"rawstars",    rawstars,     "find raw star stats"},
+}; 
+
+void InitMana () {
+  
+  int i;
+
+  for (i = 0; i < sizeof (cmds) / sizeof (Command); i++) {
+    AddCommand (&cmds[i]);
+  }
+
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/mana/mana.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/mana/mana.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/mana/mana.c	(revision 3338)
@@ -0,0 +1,80 @@
+# include "opihi.h"
+
+# define opihi_name "MANA"
+# define opihi_prompt "mana: "
+# define opihi_description "an image manipulation tool\n"
+# define opihi_history ".mana"
+# define opihi_rcfile ".manarc"
+
+void InitBasic ();
+void InitData ();
+void InitAstro ();
+void InitMana ();
+
+void welcome () {
+  fprintf (stderr, "\n");
+  fprintf (stderr, "Welcome to %s - %s\n\n", opihi_name, opihi_description);
+}
+
+/* program-dependent initialization */
+void initialize (int argc, char **argv) {
+  
+  FILE *f;
+
+  auto_break = TRUE;
+
+  Nlists = 0;
+  ALLOCATE (lists, List, 1); 
+
+  /* init functions required by libraries */
+  /* -libopihi */
+  InitCommands ();
+  InitMacros ();
+  InitBuffers ();
+  InitVectors ();
+  InitVariables ();
+
+  /* -libdisplay */
+  InitGraph ();
+  InitImage ();
+
+  /* load the commands used by this implementation */
+  InitBasic ();
+  InitData ();
+  InitAstro ();
+  InitOutfile ();
+  InitMana ();
+
+  rl_readline_name = opihi_name;
+  rl_attempted_completion_function = command_completer;
+
+  set_str_variable ("HISTORY", opihi_history);
+  set_str_variable ("PROMPT", opihi_prompt);
+  set_str_variable ("RCFILE", opihi_rcfile);
+
+  /* here we open the history file for append.  it this fails, we
+     won't be able to write to it, warn the user.  otherwise, this
+     creates the file readline will write to, if it did not exist */  
+
+  /* check history file */
+  /* rewrite with fstat or stat */
+  f = fopen (opihi_history, "a");
+  if (f == NULL) /* no current history file here */
+    fprintf (stderr, "can't save history.\n");
+  else
+    fclose (f);
+  
+  stifle_history (200);
+  read_history (opihi_history);
+
+  signal (SIGINT, SIG_IGN);
+  return;
+}
+
+/* add program-dependent exit functions here */
+void cleanup () {
+  /* -libdisplay */
+  QuitImage ();
+  QuitGraph ();
+  return;
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/mana/opihi.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/mana/opihi.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/mana/opihi.c	(revision 3338)
@@ -0,0 +1,74 @@
+# include "opihi.h"
+
+# define opihi_name "Opihi"
+# define opihi_prompt "opihi: "
+# define opihi_description "Opihi - test shell\n"
+# define opihi_history ".opihi"
+# define opihi_rcfile ".opihirc"
+
+void InitBasic ();
+
+void welcome () {
+  fprintf (stderr, "\n");
+  fprintf (stderr, "Welcome to %s - %s\n\n", opihi_name, opihi_description);
+}
+
+/* program-dependent initialization */
+void initialize (int argc, char **argv) {
+  
+  FILE *f;
+
+  auto_break = TRUE;
+
+  Nlists = 0;
+  ALLOCATE (lists, List, 1); 
+
+  /* init functions required by libraries */
+  /* -libopihi */
+  InitCommands ();
+  InitMacros ();
+  InitBuffers ();
+  InitVectors ();
+  InitVariables ();
+
+  /* -libdisplay
+  InitGraph ();
+  InitImage (); */
+
+  /* load the commands used by this implementation */
+  InitBasic ();
+  InitOutfile ();
+
+  rl_readline_name = opihi_name;
+  rl_attempted_completion_function = command_completer;
+
+  set_str_variable ("HISTORY", opihi_history);
+  set_str_variable ("PROMPT", opihi_prompt);
+  set_str_variable ("RCFILE", opihi_rcfile);
+
+  /* here we open the history file for append.  it this fails, we
+     won't be able to write to it, warn the user.  otherwise, this
+     creates the file readline will write to, if it did not exist */  
+
+  /* check history file */
+  /* rewrite with fstat or stat */
+  f = fopen (opihi_history, "a");
+  if (f == NULL) /* no current history file here */
+    fprintf (stderr, "can't save history.\n");
+  else
+    fclose (f);
+  
+  stifle_history (200);
+  read_history (opihi_history);
+
+  signal (SIGINT, SIG_IGN);
+  return;
+}
+
+/* add program-dependent exit functions here */
+void cleanup () {
+  /* -libdisplay
+  QuitImage ();
+  QuitGraph (); */
+  return;
+}
Index: /tags/opihi-2-1/Ohana/src/opihi/mana/rawstars.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/mana/rawstars.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/mana/rawstars.c	(revision 3338)
@@ -0,0 +1,95 @@
+# include "mana.h"
+
+int rawstars (int argc, char **argv) {
+  
+  int i, x, y, N, Nx, Ny, Np;
+  float *v;
+  double Raper, Rinner, Router;
+  Vector *xp, *yp;
+  Vector *xc, *yc, *sx, *sy, *sxy, *zs, *zc, *sk;
+  Buffer *buff;
+
+  Raper = 5;
+  if ((N = get_argument (argc, argv, "-Raper"))) {
+    remove_argument (N, &argc, argv);
+    Raper = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  Rinner = 10;
+  if ((N = get_argument (argc, argv, "-Rinner"))) {
+    remove_argument (N, &argc, argv);
+    Rinner = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  Router = 15;
+  if ((N = get_argument (argc, argv, "-Router"))) {
+    remove_argument (N, &argc, argv);
+    Router = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc < 4) goto usage;
+
+  if ((buff = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((xp = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yp = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if (xp[0].Nelements != yp[0].Nelements) {
+    fprintf (stderr, "vectors are not the same length\n");
+    return (FALSE);
+  }
+
+  set_rough_radii (Raper, Rinner, Router);
+
+  /* output vectors */
+  if ((xc = SelectVector ("xc", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yc = SelectVector ("yc", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((zc = SelectVector ("zc", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((zs = SelectVector ("zs", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((sk = SelectVector ("sk", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((sx = SelectVector ("sx", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((sy = SelectVector ("sy", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((sxy = SelectVector ("sxy", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  Nx = buff[0].matrix.Naxis[0];
+  Ny = buff[0].matrix.Naxis[1];
+  Np = xp[0].Nelements;
+
+  REALLOCATE (xc[0].elements, float, Np);
+  REALLOCATE (yc[0].elements, float, Np);
+  REALLOCATE (sx[0].elements, float, Np);
+  REALLOCATE (sy[0].elements, float, Np);
+  REALLOCATE (sxy[0].elements, float, Np);
+  REALLOCATE (zs[0].elements, float, Np);
+  REALLOCATE (zc[0].elements, float, Np);
+  REALLOCATE (sk[0].elements, float, Np);
+  xc[0].Nelements = yc[0].Nelements = sx[0].Nelements = Np;
+  sy[0].Nelements = zs[0].Nelements = zc[0].Nelements = Np;
+  sxy[0].Nelements = sk[0].Nelements = Np;
+
+  v = (float *) buff[0].matrix.buffer;
+  for (i = 0; i < Np; i++) {
+    x = xp[0].elements[i];
+    y = yp[0].elements[i];
+    if (x < 0) continue;
+    if (x >= Nx) continue;
+    if (y < 0) continue;
+    if (y >= Ny) continue;
+
+    get_rough_star (v, Nx, Ny, x, y, 
+		    &xc[0].elements[i], 
+		    &yc[0].elements[i], 
+		    &sx[0].elements[i], 
+		    &sy[0].elements[i], 
+		    &sxy[0].elements[i], 
+		    &zs[0].elements[i], 
+		    &zc[0].elements[i],
+		    &sk[0].elements[i]);
+  }
+
+  return (TRUE);
+
+ usage:
+  fprintf (stderr, "rawstars (buffer) (xp) (yp)\n");
+  return (FALSE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/mana/simsignal.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/mana/simsignal.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/mana/simsignal.c	(revision 3338)
@@ -0,0 +1,50 @@
+# include "dimm.h"
+
+int simsignal (int argc, char **argv) {
+  
+  int Nvect, Nbin, Nbit, i, ivalue, jvalue, Nshift, mask, scale;
+  float *buf;
+  double cvalue, dvalue, sigma, SN, period;
+  double rnd_gauss ();
+
+  if (argc != 5) {
+    fprintf (stderr, "USAGE: simsignal (vector) Nbin Nbits period\n");
+    return (FALSE);
+  }
+
+  if (!SelectVector (&Nvect, argv[1], ANYVECTOR)) return (FALSE);
+  Nbin = atof (argv[2]);
+  Nbit = atof (argv[3]);
+  /* SN = atof (argv[4]); */
+  period = atof (argv[4]);
+
+  vectors[Nvect].Nelements = Nbin;
+  REALLOCATE (vectors[Nvect].elements, float, vectors[Nvect].Nelements);
+
+  scale = (0x1 << Nbit) - 1;
+
+  buf = vectors[Nvect].elements;
+  for (i = 0; i < Nbin; i++, buf++) {
+    ivalue = scale * 0.5 * (sin (i*2*M_PI/period) + 1) + 0.5;
+    /*
+    dvalue = rnd_gauss (cvalue, sigma);
+    cvalue = (dvalue + range) / (2.0*range);
+    dvalue = MAX (0, MIN (0.99999, cvalue));
+    ivalue = scale * dvalue;
+    *buf = (2.0 * range * ((double) ivalue + 0.5)) / scale - range; 
+    */
+    *buf = ivalue;
+  }
+
+  return (TRUE);
+}
+
+/* 
+
+8 bit = 2^8
+
+  gauss_init (2*scale);
+  sigma = 2.0 / SN;
+  range = 1 + 5*sigma;
+
+*/
Index: /tags/opihi-2-1/Ohana/src/opihi/mana/starcontour.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/mana/starcontour.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/mana/starcontour.c	(revision 3338)
@@ -0,0 +1,129 @@
+# include "mana.h"
+
+int starcontour (int argc, char **argv) {
+  
+  int x, y, xs, xp, yp;
+  int Nx, Ny, N, Npts, min, max;
+  float *v;
+  float zt, zo, xmin, xmax;
+  Vector *vecx, *vecy;
+  Buffer *buf;
+
+  if (argc < 5) goto usage;
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  xp = atof (argv[2]);
+  yp = atof (argv[3]);
+  zo = atof (argv[4]);
+
+  if ((vecx = SelectVector ("xo", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((vecy = SelectVector ("yo", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  N = 0;
+  Npts = 100;
+  REALLOCATE (vecx[0].elements, float, MAX (Npts, 1));
+  REALLOCATE (vecy[0].elements, float, MAX (Npts, 1));
+
+  Nx = buf[0].matrix.Naxis[0];
+  Ny = buf[0].matrix.Naxis[1];
+  v = (float *)buf[0].matrix.buffer;
+
+  /* find transition below (limit range?) */
+  xs = xp;
+  for (y = yp; (y >= 0) && (v[xs + y*Nx] > zo); y--) {
+    /* find transition below (limit range?) */
+    min = max = FALSE;
+    for (x = xs; (x >= 0) && !min; x--) {
+      min = FALSE;
+      zt = v[x + y*Nx];
+      if (zt < zo) {
+	min = TRUE;
+	xmin = x + (zo - zt)/(v[x + 1 + y*Nx] - zt);
+	vecx[0].elements[N] = xmin;
+	vecy[0].elements[N] = y;
+	N ++;
+	if (N >= Npts) {
+	  Npts += 100;
+	  REALLOCATE (vecx[0].elements, float, MAX (Npts, 1));
+	  REALLOCATE (vecy[0].elements, float, MAX (Npts, 1));
+	}
+      }
+      /* ignore edge cases? */
+    }
+    /* find transition above (limit range?) */
+    for (x = xs; (x < Nx) && !max; x++) {
+      max = FALSE;
+      zt = v[x + y*Nx];
+      if (zt < zo) {
+	max = TRUE;
+	xmax = x - (zo - zt)/(v[x - 1 + y*Nx] - zt);
+	vecx[0].elements[N] = xmax;
+	vecy[0].elements[N] = y;
+	N ++;
+	if (N >= Npts) {
+	  Npts += 100;
+	  REALLOCATE (vecx[0].elements, float, MAX (Npts, 1));
+	  REALLOCATE (vecy[0].elements, float, MAX (Npts, 1));
+	}
+      }
+      /* ignore edge cases? */
+    }
+    if (min && max) {
+      xs = 0.5*(xmin + xmax);
+    }
+  }
+
+  /* find transition above (limit range?) */
+  xs = xp;
+  for (y = yp; (y < Ny) && (v[xs + y*Nx] > zo); y++) {
+    /* find transition below (limit range?) */
+    min = max = FALSE;
+    for (x = xs; (x >= 0) && !min; x--) {
+      min = FALSE;
+      zt = v[x + y*Nx];
+      if (zt < zo) {
+	min = TRUE;
+	xmin = x + (zo - zt)/(v[x + 1 + y*Nx] - zt);
+	vecx[0].elements[N] = xmin;
+	vecy[0].elements[N] = y;
+	N ++;
+	if (N >= Npts) {
+	  Npts += 100;
+	  REALLOCATE (vecx[0].elements, float, MAX (Npts, 1));
+	  REALLOCATE (vecy[0].elements, float, MAX (Npts, 1));
+	}
+      }
+      /* ignore edge cases? */
+    }
+    /* find transition above (limit range?) */
+    for (x = xs; (x < Nx) && !max; x++) {
+      max = FALSE;
+      zt = v[x + y*Nx];
+      if (zt < zo) {
+	max = TRUE;
+	xmax = x - (zo - zt)/(v[x - 1 + y*Nx] - zt);
+	vecx[0].elements[N] = xmax;
+	vecy[0].elements[N] = y;
+	N ++;
+	if (N >= Npts) {
+	  Npts += 100;
+	  REALLOCATE (vecx[0].elements, float, MAX (Npts, 1));
+	  REALLOCATE (vecy[0].elements, float, MAX (Npts, 1));
+	}
+      }
+      /* ignore edge cases? */
+    }
+    if (min && max) {
+      xs = 0.5*(xmin + xmax);
+    }
+  }
+  vecx[0].Nelements = N;
+  vecy[0].Nelements = N;
+
+  return (TRUE);
+
+ usage:
+  fprintf (stderr, "starcontour (buffer) (xpeak) (ypeak) (level)\n");
+  return (FALSE);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/mana/tests.c
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/mana/tests.c	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/mana/tests.c	(revision 3338)
@@ -0,0 +1,108 @@
+# include "opihi.h"
+
+run_tests () {
+
+  /* test1 ();
+     test1b ();
+     test2 ();
+     test3 (); */
+  test4 (); 
+  test5 ();
+}
+
+test1 () {
+
+  int i, size;
+  char *test, *line;
+
+  fprintf (stderr, "starting test 1...  ");
+  ALLOCATE (test, char, 256);
+  sprintf (test, "100");
+  for (i = 0; i < 1000000; i++) {
+    line = dvomath (1, &test, &size, 0);
+    if (line != NULL) free (line);
+  }
+  fprintf (stderr, "done with test 1\n");
+  sleep (1);
+}
+
+test1b () {
+
+  int i, size;
+  char *test, *line;
+
+  fprintf (stderr, "starting test 1b...  ");
+  ALLOCATE (test, char, 256);
+  sprintf (test, "dsin(45)");
+  for (i = 0; i < 1000000; i++) {
+    line = dvomath (1, &test, &size, 0);
+    if (line != NULL) free (line);
+  }
+  fprintf (stderr, "done with test 1b\n");
+  sleep (1);
+}
+
+test2 () {
+
+  int i, size;
+  char *test, *line;
+
+  fprintf (stderr, "starting test 2...  ");
+  ALLOCATE (test, char, 256);
+  sprintf (test, "5 * 100");
+  for (i = 0; i < 1000000; i++) {
+    line = dvomath (1, &test, &size, 0);
+    if (line != NULL) free (line);
+  }
+  fprintf (stderr, "done with test 2\n");
+  sleep (1);
+}
+
+test3 () {
+
+  int i, size;
+  char *test, *line;
+
+  fprintf (stderr, "starting test 3...  ");
+  ALLOCATE (test, char, 256);
+  sprintf (test, "5 * dsin(45)");
+  for (i = 0; i < 1000000; i++) {
+    line = dvomath (1, &test, &size, 0);
+    if (line != NULL) free (line);
+  }
+  fprintf (stderr, "done with test 3\n");
+  sleep (1);
+}
+
+test4 () {
+
+  int i;
+  char *test, *line;
+
+  fprintf (stderr, "starting test 4...  ");
+  for (i = 0; i < 1000000; i++) {
+    ALLOCATE (test, char, 256);
+    sprintf (test, "$N = 100");
+    line = parse (test);
+    if (line != NULL) free (line);
+  }
+  fprintf (stderr, "done with test 4\n");
+  sleep (1);
+}
+
+test5 () {
+
+  int i;
+  char *test, *line;
+
+  fprintf (stderr, "starting test 5...  ");
+  for (i = 0; i < 1000000; i++) {
+    ALLOCATE (test, char, 256);
+    sprintf (test, "echo {100 * 800}");
+    line = parse (test);
+    if (line != NULL) free (line);
+  }
+  fprintf (stderr, "done with test 5\n");
+  sleep (1);
+}
+
Index: /tags/opihi-2-1/Ohana/src/opihi/scripts/sample.sh
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/scripts/sample.sh	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/scripts/sample.sh	(revision 3338)
@@ -0,0 +1,9 @@
+#!/usr/bin/env dvo
+
+echo "test"
+
+for i 0 $argv:n
+ echo $i $argv:$i
+end
+
+exit 0
Index: /tags/opihi-2-1/Ohana/src/opihi/scripts/sched.pro
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/scripts/sched.pro	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/scripts/sched.pro	(revision 3338)
@@ -0,0 +1,28 @@
+
+task foo
+  command ls foo baz
+  periods -poll 2.0
+  periods -exec 1.0
+  periods -timeout 5.0
+  host kiawe
+
+  task.exit 0
+    echo "successful job"
+  end
+
+  task.exit 1
+    echo "failed job"
+  end
+
+  task.exit crash
+    echo "crashed job"
+  end
+
+  task.exit timeout
+    echo "job timed out"
+  end
+
+  task.exec
+    echo "starting job foo"
+  end
+end
Index: /tags/opihi-2-1/Ohana/src/opihi/scripts/tag-elixir
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/scripts/tag-elixir	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/scripts/tag-elixir	(revision 3338)
@@ -0,0 +1,31 @@
+#!/bin/csh -f
+
+# this just organizes the tagging of the elixir components
+
+if ($#argv != 1) then
+  echo "USAGE: tag-elixir (TAG)"
+  exit 2
+endif
+
+cvs tag $1 Makefile
+cvs tag $1 bin/
+cvs tag $1 cmd.astro/
+cvs tag $1 cmd.basic/
+cvs tag $1 cmd.data/
+cvs tag $1 doc/
+cvs tag $1 dvo/
+cvs tag $1 help/
+cvs tag $1 include/
+cvs tag $1 lib/
+cvs tag $1 lib.data/
+cvs tag $1 lib.shell/
+cvs tag $1 mana/
+cvs tag $1 scripts/
+
+# don't place tag on these implementations
+# cvs tag $1 dimm/
+# cvs tag $1 dvo2/
+# cvs tag $1 old/
+# cvs tag $1 pclient/
+# cvs tag $1 pcontrol/
+# cvs tag $1 sched/
Index: /tags/opihi-2-1/Ohana/src/opihi/scripts/test.pro
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/scripts/test.pro	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/scripts/test.pro	(revision 3338)
@@ -0,0 +1,74 @@
+
+macro testloops
+ for i 0 100
+  if ($i < 20)
+   continue
+  end
+  if ($i > 40)
+   break
+  end
+  echo $i
+ end
+end  
+
+# test math parsing
+macro testvars
+ echo testing variable assignment
+ $a = 1
+ echo $a is 1
+ $b = 5*3 + $a
+ echo $b is 16
+
+ $a = `ls`
+ echo $a
+ exec ls
+
+ echo testing in-line math
+ $a = 1
+ echo {1 + 1} is 2
+ echo {2^3} is 8
+ echo {$a + 2} is 3
+
+ echo testing vector assignment
+ create x 0 10
+ set y = x^2
+ echo x[2] is 2
+ echo y[2] is 4
+ lim x y; clear; box; plot x y
+ label -x "x axis" -y "&s y axis"
+end
+
+macro testspeed
+ exec date
+ create x 0 100000
+ for i 0 5000
+  set y = 3*x + $i
+ end
+ exec date
+end
+
+macro testmemory.buffers
+ mcreate a 2048 2048
+ exec date
+ for i 0 500
+  set b = 3*a + 6
+ end
+ exec date
+end
+
+macro testmemory.macros
+ exec date
+ for i 0 1000
+   for j 0 1000
+    $N = $N + 1
+   end
+ end
+ exec date
+end
+
+macro sample
+ $N = 0
+ for j 0 1000000
+  $N = 100
+ end
+end
Index: /tags/opihi-2-1/Ohana/src/opihi/scripts/testloops.pro
===================================================================
--- /tags/opihi-2-1/Ohana/src/opihi/scripts/testloops.pro	(revision 3338)
+++ /tags/opihi-2-1/Ohana/src/opihi/scripts/testloops.pro	(revision 3338)
@@ -0,0 +1,90 @@
+
+macro testloop1
+ local i
+ for i 0 10
+  echo "1: $i"
+    end
+end
+
+macro testloop2
+ local i
+ for i 0 5
+   echo "2: $i"
+   testloop1
+end
+end
+
+macro testlocal1
+ local -static foo
+ echo "1 - foo: $foo"
+ $foo = local.1
+ echo "1 - foo: $foo"
+end
+
+macro testlocal2
+ local foo
+ $foo = local.2
+ echo "2 - foo: $foo"
+ testlocal1
+ echo "2 - foo: $foo"
+ testlocal1
+ echo "2 - foo: $foo"
+end
+
+macro test1
+ # echo step $1
+ if ($1 == 1)
+  echo "break here"
+  break
+ end
+ if ($1 == 2)
+  continue
+ end
+end
+
+# continue
+
+macro test2
+ echo "input test"
+ break
+ echo "error, can't get here"
+end
+
+macro testm
+ break -auto off
+ test1 0
+ # echo $STATUS
+ test1 1
+ # echo $STATUS
+ test1 2
+ # echo $STATUS
+ if ($1 == 10) 
+  test1 1
+  if ($STATUS == 0)
+   echo "breaking it"
+   break
+  end
+ end
+ echo done
+end
+
+echo "done loading"
+
+macro test3
+ for i 0 12
+  echo $i
+  testm $i
+  echo "status: $STATUS"
+ end
+end
+
+macro testL
+ for i 0 10
+  for j 0 10
+   for k 0 10
+    echo $i $j $k
+    mcreate a 1024 1024   
+   end
+  end
+ end
+end
