Index: branches/eam_branches/ipp-20230313/Nebulous/bin/whichnode
===================================================================
--- branches/eam_branches/ipp-20230313/Nebulous/bin/whichnode	(revision 42819)
+++ branches/eam_branches/ipp-20230313/Nebulous/bin/whichnode	(revision 42820)
@@ -1,3 +1,3 @@
-#!/bin/env perl
+#!/usr/bin/env perl
 
 # This script is a temporary "solution" to allow a client to determine whether
Index: branches/eam_branches/ipp-20230313/PS-IPP-Config/lib/PS/IPP/Config.pm
===================================================================
--- branches/eam_branches/ipp-20230313/PS-IPP-Config/lib/PS/IPP/Config.pm	(revision 42819)
+++ branches/eam_branches/ipp-20230313/PS-IPP-Config/lib/PS/IPP/Config.pm	(revision 42820)
@@ -1371,4 +1371,28 @@
 
 
+# Return array of the instances for this nebulous file
+sub find_instances
+{
+    my $self = shift;
+    my $file = shift;
+
+    my $scheme = file_scheme($file);
+    if (!$scheme or ($scheme ne 'neb')) {
+	# if not nebulous, the instance is the file
+	my @result;
+        push @result, $file;
+	return (\@result);
+    }
+
+    my $neb = $self->nebulous;
+    my $uris;
+    eval { $uris = $neb->find_instances($file); };
+    if ($@) { 
+	carp "failed to set user.copies for $file";
+        return 0;
+    }
+    return $uris;
+}
+
 # Return catdir for tessellation, from TESSELLATIONS within the site configuration
 sub tessellation_catdir
Index: branches/eam_branches/ipp-20230313/extsrc/gpcsw/gpcsrc/fits/burntool/persistio.c
===================================================================
--- branches/eam_branches/ipp-20230313/extsrc/gpcsw/gpcsrc/fits/burntool/persistio.c	(revision 42819)
+++ branches/eam_branches/ipp-20230313/extsrc/gpcsw/gpcsrc/fits/burntool/persistio.c	(revision 42820)
@@ -312,4 +312,5 @@
 		    cell[j].burn[k].fiterr != FIT_TOP_ERROR) continue;
 	       if(cell[j].burn[k].nfit <= 0) continue;
+	       /*kick out burns which are single pixels*/
 	     }
 	    } else {
@@ -317,4 +318,6 @@
 	       cell[j].burn[k].fiterr != FIT_TOP_ERROR) continue;
 	     if(cell[j].burn[k].nfit <= 0) continue;
+	     /*kick out burns which are single pixels*/
+
 	    }
 
Index: branches/eam_branches/ipp-20230313/extsrc/gpcsw/gpcsrc/fits/burntool/stardetect.c
===================================================================
--- branches/eam_branches/ipp-20230313/extsrc/gpcsw/gpcsrc/fits/burntool/stardetect.c	(revision 42819)
+++ branches/eam_branches/ipp-20230313/extsrc/gpcsw/gpcsrc/fits/burntool/stardetect.c	(revision 42820)
@@ -34,8 +34,14 @@
    starcut = STAR_THRESH/2 + cell->sky + cell->bias;
 
-   /*try a new value for thresh_lo which is 1 sigmas above the background, but with a safety limit of 1000 counts*/
+   /*try a new value for thresh_lo which is 10 sigmas above the background, but with a safety limit of 1000 counts*/
 	trailthresh = cell->sky + (10*cell->rms);
 	if(trailthresh <= 1000) trailthresh = 1000;
 	trailthresh = trailthresh + cell->bias;
+	thresh_lo = trailthresh;
+
+   /*try a new value for burnthresh which is twice the bias above the sky background, but with a safety limit of 30000 counts*/
+	burnthresh = cell->sky + (2*cell->bias);
+	if(burnthresh <= BURN_THRESH) burnthresh = BURN_THRESH;
+	thresh_hi = burnthresh;
 
 /* Look at all the pixels which pass the burn threshold */
@@ -81,4 +87,5 @@
 	        boxbuf[nbox].ey = k-1;
 	        grow_box(nx, ny, NX, data, thresh_lo, boxbuf+nbox);
+		
            /* Fill in max and center info */
 	        boxbuf[nbox].max = 0;
@@ -100,4 +107,22 @@
 			     boxbuf[nbox].ex, boxbuf[nbox].ey,
 			     boxbuf[nbox].max);
+		        fflush(stdout);
+	          }
+/* Mark the veto mask so as not to trigger on this one again */
+	          for(l=boxbuf[nbox].sy; l<=boxbuf[nbox].ey; l++) {
+		         for(k=boxbuf[nbox].sx; k<=boxbuf[nbox].ex; k++) {
+		          veto[k+l*NX] = boxbuf[nbox].max;
+		         }
+	          }
+	          xon = -1;
+	          continue;
+	        }
+
+/* A box that is composed of a single pixel should not be considered a burn */
+	        if((boxbuf[nbox].ex - boxbuf[nbox].sx) <= 2 && (boxbuf[nbox].ey - boxbuf[nbox].sy) <= 2) {
+	          if(VERBOSE & VERB_DETECT) {
+		        printf("Ditching box %d %d %d %d  for being too small\n",
+			     boxbuf[nbox].sx, boxbuf[nbox].sy,
+			     boxbuf[nbox].ex, boxbuf[nbox].ey);
 		        fflush(stdout);
 	          }
Index: branches/eam_branches/ipp-20230313/extsrc/gpcsw/gpcsrc/fits/burntool/trailfit.c
===================================================================
--- branches/eam_branches/ipp-20230313/extsrc/gpcsw/gpcsrc/fits/burntool/trailfit.c	(revision 42819)
+++ branches/eam_branches/ipp-20230313/extsrc/gpcsw/gpcsrc/fits/burntool/trailfit.c	(revision 42820)
@@ -290,5 +290,4 @@
 
    if(!strcmp(camera,"gpc2")) {
-
      /*Conpute the mean and standard deviation of the trail along x*/
      for(i=xs; i<=xe; i++) {
@@ -384,5 +383,5 @@
      }
      /* Update fit ranges */
-     if(box->nfit > 0) {
+     if(box->nfit > 1) {
         box->sxfit = box->xfit[0];
         box->exfit = box->xfit[box->nfit-1];
Index: branches/eam_branches/ipp-20230313/ippTasks/mergedvodb.pro
===================================================================
--- branches/eam_branches/ipp-20230313/ippTasks/mergedvodb.pro	(revision 42819)
+++ branches/eam_branches/ipp-20230313/ippTasks/mergedvodb.pro	(revision 42820)
@@ -7,5 +7,5 @@
 
 
-#There is a book for each task, because I don't use labels. 
+#There is a book for each task, because I dont use labels. 
 
 if (not($?havemergedvodbBooks))
@@ -44,5 +44,5 @@
 end
 
-## you get no choice - you add all of them in at the same time. you can always turn off the tasks you don't want to run.
+## you get no choice - you add all of them in at the same time. you can always turn off the tasks you dont want to run.
 macro add.mergedvodb
   if ($0 != 2)
Index: branches/eam_branches/ipp-20230313/ippTasks/summit.copy.pro
===================================================================
--- branches/eam_branches/ipp-20230313/ippTasks/summit.copy.pro	(revision 42819)
+++ branches/eam_branches/ipp-20230313/ippTasks/summit.copy.pro	(revision 42820)
@@ -49,4 +49,17 @@
 macro summitcopy.reset
     summitcopy.reset
+end
+
+# pzgetexp is loading exposure files to summitExp 
+macro pzgetexp.on
+  task pzgetexp
+    active true
+  end
+end
+
+macro pzgetexp.off
+  task pzgetexp
+    active false
+  end
 end
 
Index: branches/eam_branches/ipp-20230313/ippTools/src/pxtools.c
===================================================================
--- branches/eam_branches/ipp-20230313/ippTools/src/pxtools.c	(revision 42819)
+++ branches/eam_branches/ipp-20230313/ippTools/src/pxtools.c	(revision 42820)
@@ -36,4 +36,5 @@
     if (!strcmp(state, "wait")) return true;
     if (!strcmp(state, "keep")) return true;
+    if (!strcmp(state, "ignore")) return true;
     if (!strcmp(state, "goto_cleaned")) return true;
     if (!strcmp(state, "error_cleaned")) return true;
Index: branches/eam_branches/ipp-20230313/ippconfig/Makefile.am
===================================================================
--- branches/eam_branches/ipp-20230313/ippconfig/Makefile.am	(revision 42819)
+++ branches/eam_branches/ipp-20230313/ippconfig/Makefile.am	(revision 42820)
@@ -1,2 +1,4 @@
+TGT  = $(PSCONFDIR)/$(PSCONFIG)/etc/compress.mgc
+
 SUBDIRS = \
 	recipes \
@@ -36,5 +38,6 @@
 built_files = \
 	ipprc.config \
-	dvo.site
+	dvo.site \
+	$(TGT)
 
 installdir = $(datadir)/ippconfig
@@ -64,10 +67,4 @@
 
 
-TGTDIR  = $(PSCONFDIR)/$(PSCONFIG)/etc
-SRC	= 	compress
-TGT	= 	$(TGTDIR)/compress.mgc
-
-install: $(TGT)
-build:   $(MGC)
 
 if HAVE_LINUX
Index: branches/eam_branches/ipp-20230313/ippconfig/gpc1/ppImage.config
===================================================================
--- branches/eam_branches/ipp-20230313/ippconfig/gpc1/ppImage.config	(revision 42819)
+++ branches/eam_branches/ipp-20230313/ippconfig/gpc1/ppImage.config	(revision 42820)
@@ -1139,4 +1139,30 @@
 END
 
+# CZW 2018-02-14
+# The default PPIMAGE_N includes BACKGROUND=T, and that breaks detrend construction
+PPIMAGE_N          METADATA
+  BASE.FITS        BOOL    TRUE            # Save base detrended image?
+  BASE.MASK.FITS   BOOL    FALSE           # Save base detrended image?
+  BASE.VARIANCE.FITS BOOL    FALSE           # Save base detrended image?
+  CHIP.FITS        BOOL    FALSE           # Save chip-mosaic-ed image? 
+  CHIP.MASK.FITS   BOOL    FALSE           # Save chip-mosaic-ed image? 
+  CHIP.VARIANCE.FITS BOOL    FALSE           # Save chip-mosaic-ed image? 
+  OVERSCAN         BOOL    FALSE           # Overscan subtraction
+  NONLIN           BOOL    FALSE           # Non-linearity correction; not implemented
+  BIAS             BOOL    FALSE           # Bias subtraction
+  DARK             BOOL    FALSE           # Dark subtraction
+  SHUTTER          BOOL    FALSE           # Shutter correction
+  FLAT             BOOL    FALSE           # Flat-field normalisation
+  MASK             BOOL    FALSE           # Mask bad pixels
+  MASK.BUILD       BOOL    FALSE           # Build internal mask?
+  FRINGE           BOOL    FALSE           # Fringe subtraction
+  PHOTOM           BOOL    FALSE           # Source identification and photometry
+  ASTROM.CHIP      BOOL    FALSE           # Astrometry per chip?
+  ASTROM.MOSAIC    BOOL    FALSE           # Astrometry for mosaic?
+  BIN1.FITS        BOOL    TRUE            # Save 1st binned chip image?
+  BIN2.FITS        BOOL    TRUE            # Save 2nd binned chip image?
+  BACKGROUND       BOOL    FALSE           # Subtract background?
+END
+
 # JPEG images for different types of residual images
 # Save JPEG from BIN1 for bias
Index: branches/eam_branches/ipp-20230313/ippconfig/recipes/psphot.config
===================================================================
--- branches/eam_branches/ipp-20230313/ippconfig/recipes/psphot.config	(revision 42819)
+++ branches/eam_branches/ipp-20230313/ippconfig/recipes/psphot.config	(revision 42820)
@@ -107,4 +107,6 @@
 PSF_CLUMP_NY                        S32   1               # selecting PSF stars
 
+PSF_CLUMP_USE_CLIPPED_STATS         BOOL  TRUE            # define clump usig CLIPPED stats or ROBUST stats
+
 PSF_MIN_DS                          F32   0.01
 PSF_PARAM_WEIGHTS                   BOOL  FALSE
@@ -113,4 +115,6 @@
 LMM_FIT_GAIN_FACTOR_MODE            S32   0               # there are 3 options to determine the gain factor (0,1,2)
 LMM_FIT_USE_REWEIGHTING             BOOL  FALSE           # use IRLS-style reweighting (TRUE) or ordinary LMM
+
+PSF_FIT_STAR_COORDS                 BOOL  FALSE		  # if TRUE, fit position as well as shape for PSF stars
 
 PSF_FIT_ITER                        S32   50              # Maximum number of fitting iterations for PSF
Index: branches/eam_branches/ipp-20230313/ippconfig/simple/camera.config
===================================================================
--- branches/eam_branches/ipp-20230313/ippconfig/simple/camera.config	(revision 42819)
+++ branches/eam_branches/ipp-20230313/ippconfig/simple/camera.config	(revision 42820)
@@ -42,4 +42,5 @@
 RECIPES		METADATA
         PPIMAGE         STR     simple/ppImage.config   # Default: all (normal) options on
+        PPMERGE         STR     simple/ppMerge.config   # Default: all (normal) options on
 	PSPHOT		STR	simple/psphot.config	# psphot details
 END
Index: branches/eam_branches/ipp-20230313/ippconfig/simple/format.config
===================================================================
--- branches/eam_branches/ipp-20230313/ippconfig/simple/format.config	(revision 42819)
+++ branches/eam_branches/ipp-20230313/ippconfig/simple/format.config	(revision 42820)
@@ -20,11 +20,11 @@
 CELLS	METADATA
 	amplifier	METADATA
-		CELL.TRIMSEC.SOURCE	STR	VALUE
-		CELL.TRIMSEC		STR	[0:0,0:0]
+		# CELL.TRIMSEC.SOURCE	STR	VALUE
+		# CELL.TRIMSEC		STR	[0:0,0:0]
 		# alternatives for getting these from the headers
-		# CELL.TRIMSEC.SOURCE	STR	HEADER
-		# CELL.BIASSEC.SOURCE	STR	VALUE
-		# CELL.TRIMSEC		STR	DATASEC
-		# CELL.BIASSEC		STR	BIASSEC
+		CELL.TRIMSEC.SOURCE	STR	HEADER
+		CELL.BIASSEC.SOURCE	STR	HEADER
+		CELL.TRIMSEC		STR	DATASEC
+		CELL.BIASSEC		STR	BIASSEC
 	END
 END
Index: branches/eam_branches/ipp-20230313/ippconfig/simple/ppMerge.config
===================================================================
--- branches/eam_branches/ipp-20230313/ippconfig/simple/ppMerge.config	(revision 42820)
+++ branches/eam_branches/ipp-20230313/ippconfig/simple/ppMerge.config	(revision 42820)
@@ -0,0 +1,2 @@
+
+# ROWS                S32     16             # Number of rows to read at once
Index: branches/eam_branches/ipp-20230313/ippconfig/simquad/camera.config
===================================================================
--- branches/eam_branches/ipp-20230313/ippconfig/simquad/camera.config	(revision 42820)
+++ branches/eam_branches/ipp-20230313/ippconfig/simquad/camera.config	(revision 42820)
@@ -0,0 +1,75 @@
+# Camera configuration file for drop-dead boring camera, consisting of a single chip with single cell.
+
+# File formats that we know about
+FORMATS         METADATA
+	SIMPLE	   STR	simquad/format.config
+END
+
+# Description of camera --- all the chips and the cells that comprise them
+FPA     METADATA
+        Chip		STR	Cell00 Cell01 Cell10 Cell11
+END
+
+# move this elsewhere?  we need a lookup table to go from filter ID to abstract name
+FILTER.ID       METADATA
+	B	STR	B
+	V	STR	V
+	R	STR	R
+	I	STR	I
+	z	STR	z
+END
+
+# Table of strings to use for the class identifier (see ippdb) according to the file level.
+CLASSID		METADATA
+	FPA	STR	fpa
+	CHIP	STR	{CHIP.NAME}
+	CELL	STR	{CHIP.NAME}.{CELL.NAME}
+	fpa	STR	fpa
+	chip	STR	{CHIP.NAME}
+	cell	STR	{CHIP.NAME}.{CELL.NAME}
+END
+
+DVO.CAMERADIR	STR	megacam		# Camera directory for DVO
+
+# convert supplied FPA.OBSTYPE values to abstract exptype names
+OBSTYPE.TABLE METADATA
+  bias 	   STR BIAS
+  zero 	   STR BIAS
+  dark 	   STR DARK
+  flat 	   STR SKYFLAT
+  skyflat  STR SKYFLAT
+  domeflat STR DOMEFLAT
+  object   STR OBJECT
+  science  STR OBJECT
+END
+
+# Recipe options
+RECIPES		METADATA
+#        PPIMAGE         STR     simple/ppImage.config   # Default: all (normal) options on
+#	PSPHOT		STR	simple/psphot.config	# psphot details
+END
+
+PHOTCODE.RULE           STR     {DETECTOR}.{FILTER.ID}.{CHIP.NAME}	# Rule for generating photcode
+
+# reduction classes (recipes which are grouped together)
+REDUCTION	STR	recipes/reductionClasses.mdc
+
+FITSTYPES       STR     recipes/fitstypes.mdc
+
+FILERULES       STR     recipes/filerules-simple.mdc
+
+EXTNAME.RULES METADATA
+  CMF.HEAD STR hdr
+  CMF.DATA STR psf
+  CMF.XSRC STR xsrc
+  CMF.XRAD STR xrad
+  CMF.XFIT STR xfit
+  CMF.DETEFF STR deteff
+  CMF.XGAL STR xgal
+
+  PSF.HEAD  STR hdr
+  PSF.TABLE STR psf_model
+  PSF.RESID STR psf_resid
+END
+
+MASK.FORCE	BOOL	TRUE	# Force reliance on MASKS recipe if headers not present
Index: branches/eam_branches/ipp-20230313/ippconfig/simquad/format.config
===================================================================
--- branches/eam_branches/ipp-20230313/ippconfig/simquad/format.config	(revision 42820)
+++ branches/eam_branches/ipp-20230313/ippconfig/simquad/format.config	(revision 42820)
@@ -0,0 +1,112 @@
+# Simulated camera with 4 readout amplifiers on a single chip
+
+# How to identify this type
+RULE	METADATA
+	TELESCOP	STR	SimScope
+	INSTRUME	STR	SIMQUAD
+END
+
+# How to read this data
+FILE	METADATA
+	PHU		STR	FPA	# The FITS file represents an entire FPA
+        EXTENSIONS      STR     CELL       # The extensions represent cells
+	FPA.OBS		STR	FILENAME	# A PHU keyword for unique identifier within the hierarchy level
+	CONTENT	        STR     CHIPNAME	# How to determine content of FITS file
+	CONTENT.RULE	STR	{CHIP.NAME}	# How to derive the CONTENT when writing
+END
+
+# What's in the FITS file?
+CONTENTS	METADATA
+	# File identifier with corresponding file layout name
+	Chip		STR	SimChip:SimCell:
+	Chip		STR	SimChip:SimCell:
+	Chip		STR	SimChip:SimCell:
+	Chip		STR	SimChip:SimCell:
+???
+	Cell00	STR	Cell00:SimCell
+	Cell01	STR	Cell01:SimCell
+	Cell10	STR	Cell10:SimCell
+	Cell11	STR	Cell11:SimCell
+END
+
+# Specify the layout
+CHIPS	METADATA
+	SimChip		METADATA
+		# Extension name, cellName:cellType
+		Cell00	STR	Cell00:SimCell
+		Cell01	STR	Cell01:SimCell
+		Cell10	STR	Cell10:SimCell
+		Cell11	STR	Cell11:SimCell
+	END
+END
+
+# Specify the cell data
+CELLS	METADATA
+	SimCell		METADATA
+		CELL.TRIMSEC.SOURCE	STR	HEADER
+		CELL.TRIMSEC		STR	TRIMSEC
+		CELL.BIASSEC.SOURCE	STR	HEADER
+		CELL.BIASSEC		STR	BIASSEC
+	END
+END
+
+# How to translate PS concepts into FITS headers
+TRANSLATION	METADATA
+	FPA.TELESCOPE	STR	TELESCOP
+	FPA.INSTRUMENT	STR	INSTRUME
+	FPA.OBSTYPE	STR	OBSTYPE
+	FPA.AIRMASS	STR	AIRMASS
+	FPA.FILTER	STR	FILTER
+	FPA.POSANGLE	STR	POSANGLE
+	FPA.RA		STR	RA
+	FPA.DEC		STR	DEC
+	FPA.OBJECT	STR	OBJECT
+	FPA.TIME	STR	DATE-OBS UTC-OBS	# Date and time
+	FPA.EXPOSURE	STR	EXPTIME
+	CELL.EXPOSURE	STR	EXPTIME
+	CELL.DARKTIME	STR	DARKTIME
+#	CELL.TIME	STR	DATE-OBS TIME-OBS	# Date and time
+END
+
+# Default PS concepts that may be specified by value
+DEFAULTS	METADATA
+	CELL.XBIN	S32	1
+	CELL.YBIN	S32	1
+	FPA.TIMESYS	STR	UTC
+	FPA.RADECSYS	STR	ICRS
+	CELL.GAIN	F32	1.0
+	CELL.READNOISE	F32	2.0
+	CELL.BAD	F32	0
+	CELL.SATURATION	F32	65535
+#	CELL.BAD	F32	-65535
+	CELL.READDIR	S32	1
+	CELL.TIMESYS	STR	UTC
+	CELL.XPARITY	S32	1
+	CELL.YPARITY	S32	1
+	CHIP.XPARITY	S32	1
+	CHIP.YPARITY	S32	1
+	CELL.X0		S32	0
+	CELL.Y0		S32	0
+	CELL.X0.DEPEND	STR	CELL.NAME
+	CELL.X0		METADATA
+		Cell00	S32	0
+		Cell01	S32	0
+		Cell10	S32	1024
+		Cell11	S32	1024
+	END
+	CELL.Y0.DEPEND	STR	CELL.NAME
+	CELL.Y0		METADATA
+		Cell00	S32	0
+		Cell01	S32	1024
+		Cell10	S32	0
+		Cell11	S32	1024
+	END
+	CELL.XSIZE	S32	1024
+	CELL.YSIZE	S32	1024
+END
+
+FORMATS		METADATA
+	FPA.RA		STR	HOURS
+	FPA.DEC		STR	DEGREES
+	FPA.TIME	STR	SEPARATE,YEAR.FIRST
+END
Index: branches/eam_branches/ipp-20230313/ippconfig/system.config
===================================================================
--- branches/eam_branches/ipp-20230313/ippconfig/system.config	(revision 42819)
+++ branches/eam_branches/ipp-20230313/ippconfig/system.config	(revision 42820)
@@ -23,5 +23,6 @@
 	SUPRIMECAM		STR	suprime/camera.config           # Subaru Suprimecam
 	SIMMOSAIC		STR	simmosaic/camera.config		# Simulated mosaic, for testing
-	SIMTEST			STR	simtest/camera.config		# Simulation test camera
+ 	SIMTEST			STR	simtest/camera.config		# Simulation test camera
+#       SIMQUAD			STR	simquad/camera.config		# Simulation test camera
 	SIMPLE			STR	simple/camera.config		# If all else fails....
 END
Index: branches/eam_branches/ipp-20230313/ppImage/src/ppImageBurntoolApply.c
===================================================================
--- branches/eam_branches/ipp-20230313/ppImage/src/ppImageBurntoolApply.c	(revision 42819)
+++ branches/eam_branches/ipp-20230313/ppImage/src/ppImageBurntoolApply.c	(revision 42820)
@@ -226,5 +226,5 @@
         /* do separate masking strategy for old (14 and lower) and new burntool tables*/
         if (BURNTOOL_STATE_GOOD >= 15) {
-	 printf("DET: New burntool style %d\n",BURNTOOL_STATE_GOOD);
+	 /*printf("DET: New burntool style %d\n",BURNTOOL_STATE_GOOD);*/
           for (int i = box->sxfit; i<= box->exfit; i++) {
               if (box->up == 0) {
@@ -248,5 +248,5 @@
 
         } else {
-	 printf("DET: Old burntool style %d\n",BURNTOOL_STATE_GOOD);
+	/* printf("DET: Old burntool style %d\n",BURNTOOL_STATE_GOOD);*/
           for (int i = box->sxfit; i<= box->exfit; i++) {
               if (box->up == 0) {
Index: branches/eam_branches/ipp-20230313/ppMerge/src/ppMerge.c
===================================================================
--- branches/eam_branches/ipp-20230313/ppMerge/src/ppMerge.c	(revision 42819)
+++ branches/eam_branches/ipp-20230313/ppMerge/src/ppMerge.c	(revision 42820)
@@ -159,4 +159,6 @@
     psLibFinalize();
 
+    psLogMsg("ppMerge", PS_LOG_INFO, "Memory leaks: %d\\n", psMemCheckLeaks(0, NULL, stdout, false));
+
     exit(exitValue);
 }
Index: branches/eam_branches/ipp-20230313/ppMerge/src/ppMerge.h
===================================================================
--- branches/eam_branches/ipp-20230313/ppMerge/src/ppMerge.h	(revision 42819)
+++ branches/eam_branches/ipp-20230313/ppMerge/src/ppMerge.h	(revision 42820)
@@ -117,10 +117,11 @@
     );
 
+bool ppMergeFileFreeInput(pmConfig *config, const pmFPAview *view, int num);
+
 /**
  * Set the data level for files specified by name; return an array of the files
  */
 psArray *ppMergeFileDataLevel(const pmConfig *config, ///< Configuration
-                              const char *name, ///< Name of files
-                              pmFPALevel level ///< Level for file data level
+                              const char *name ///< Name of files
     );
 
Index: branches/eam_branches/ipp-20230313/ppMerge/src/ppMergeFiles.c
===================================================================
--- branches/eam_branches/ipp-20230313/ppMerge/src/ppMergeFiles.c	(revision 42819)
+++ branches/eam_branches/ipp-20230313/ppMerge/src/ppMergeFiles.c	(revision 42820)
@@ -105,5 +105,38 @@
 }
 
-psArray *ppMergeFileDataLevel(const pmConfig *config, const char *name, pmFPALevel level)
+bool ppMergeFileFreeInput(pmConfig *config, const pmFPAview *view, int num)
+{
+    {
+        pmFPAfile *input = pmFPAfileSelectSingle(config->files, "PPMERGE.INPUT", num);
+        if (!pmFPAfileFreeData(input, view)) {
+            psError(PS_ERR_UNKNOWN, false, "Unable to free data for image file %d", num);
+            return false;
+        }
+    }
+    bool mdok;          // Status of MD lookup
+    if (psMetadataLookupBool(&mdok, config->arguments, "INPUTS.MASKS")) {
+        pmFPAfile *mask = pmFPAfileSelectSingle(config->files, "PPMERGE.INPUT.MASK", num); // Mask file
+        if (!pmFPAfileFreeData(mask, view)) {
+            psError(PS_ERR_UNKNOWN, false, "Unable to free data for mask file %d", num);
+            return false;
+        }
+    }
+    if (psMetadataLookupBool(&mdok, config->arguments, "INPUTS.VARIANCES")) {
+        pmFPAfile *variance = pmFPAfileSelectSingle(config->files, "PPMERGE.INPUT.VARIANCE", num); // Variance file
+        if (!pmFPAfileFreeData(variance, view)) {
+            psError(PS_ERR_UNKNOWN, false, "Unable to free data for variance file %d", num);
+            return false;
+        }
+    }
+    return true;
+}
+
+// Select the specified input files and assign the dataLevel and freeLevel,
+// saving a pointer on output array.
+// This function takes the argument pmFPALevel and sets the dataLevel based on that value.
+// However, this is only used with the value PM_FPA_LEVEL_READOUT, and it must be set
+// to that level for the rest of ppMerge to work correctly.  Furthermore, the freeLevel
+// must be set to Cell.  Remove the (false) option.
+psArray *ppMergeFileDataLevel(const pmConfig *config, const char *name)
 {
     assert(config);
@@ -115,6 +148,6 @@
     for (int i = 0; i < numFiles; i++) {
         pmFPAfile *file = pmFPAfileSelectSingle(config->files, name, i); // Image file
-        file->dataLevel = level;
-        file->freeLevel = level;
+        file->dataLevel = PM_FPA_LEVEL_READOUT;
+        file->freeLevel = PM_FPA_LEVEL_CELL;
         files->data[i] = psMemIncrRefCounter(file);
     }
Index: branches/eam_branches/ipp-20230313/ppMerge/src/ppMergeLoop.c
===================================================================
--- branches/eam_branches/ipp-20230313/ppMerge/src/ppMergeLoop.c	(revision 42819)
+++ branches/eam_branches/ipp-20230313/ppMerge/src/ppMergeLoop.c	(revision 42820)
@@ -39,12 +39,7 @@
     bool haveVariances = psMetadataLookupBool(&mdok, arguments, "INPUTS.VARIANCES"); // Do we have variances?
 
-    psArray *inputs = ppMergeFileDataLevel(config, "PPMERGE.INPUT", PM_FPA_LEVEL_READOUT); // Input images
-    psArray *masks = NULL, *variances = NULL; // Input masks and variances
-    if (haveMasks) {
-        masks = ppMergeFileDataLevel(config, "PPMERGE.INPUT.MASK", PM_FPA_LEVEL_READOUT);
-    }
-    if (haveVariances) {
-        variances = ppMergeFileDataLevel(config, "PPMERGE.INPUT.VARIANCE", PM_FPA_LEVEL_READOUT);
-    }
+    psArray *inputs    = ppMergeFileDataLevel(config, "PPMERGE.INPUT"); // Input images
+    psArray *masks     = haveMasks ? ppMergeFileDataLevel(config, "PPMERGE.INPUT.MASK") : NULL; // Input masks 
+    psArray *variances = haveVariances ? ppMergeFileDataLevel(config, "PPMERGE.INPUT.VARIANCE") : NULL; // Input variances
 
     int nThreads = psMetadataLookupS32 (&mdok, arguments, "NTHREADS");
@@ -135,5 +130,4 @@
     psString darkNorm = psMetadataLookupStr(&mdok, arguments, "DARK.NORM"); ///< Dark normalisation
 
-
     if (!ppMergeFileActivate(config, PPMERGE_FILES_ALL, true)) {
         psError(PS_ERR_UNKNOWN, false, "Unable to activate files.");
@@ -152,5 +146,4 @@
     }
 
-
     // Average concepts across inputs
     {
@@ -180,5 +173,5 @@
         {
             psList *inChips = psListAlloc(NULL);
-            for (int i=0; i < numFiles; i++) {
+            for (int i = 0; i < numFiles; i++) {
                 pmChip *chip = pmFPAviewThisChip(view, ((pmFPAfile *)inputs->data[i])->fpa);
                 psListAdd(inChips, PS_LIST_TAIL, chip);
@@ -193,7 +186,4 @@
 
         pmCell *outCell;                ///< Cell of interest
-
-        // XXX TEST : force a single loop
-        // outCell = pmFPAviewNextCell(view, outFPA, 1); {
 
         while ((outCell = pmFPAviewNextCell(view, outFPA, 1))) {
@@ -291,4 +281,5 @@
                 psAssert (fileGroups->n > 0, "no valid file groups defined");
                 fileGroup = fileGroups->data[0];
+
                 if (!pmDarkCombinePrepare(outCell, fileGroup->readouts, darkOrdinates, darkNorm)) {
                     goto ERROR;
@@ -305,4 +296,6 @@
                 psAbort("Should never get here.");
             }
+	    fprintf (stderr, "after pmDarkCombinePrepare / pmReadoutCombinePrepare:\n");
+	    psMemStats(true, NULL, NULL);
 
             // Read input data by chunks
@@ -349,12 +342,16 @@
                       psArrayAdd(job->args, 1, outCell);
                       psArrayAdd(job->args, 1, fileGroup);
-                      psArrayAdd(job->args, 1, psScalarAlloc(iter, PS_TYPE_S32));
-                      psArrayAdd(job->args, 1, psScalarAlloc(rej, PS_TYPE_F32));
-                      psArrayAdd(job->args, 1, psScalarAlloc(maskVal, PS_TYPE_IMAGE_MASK));
+		      
+		      // need to free the allocated scalars:
+		      { psScalar *tmpVal = psScalarAlloc(iter,    PS_TYPE_S32);        psArrayAdd(job->args, 1, tmpVal); psFree (tmpVal); }
+		      { psScalar *tmpVal = psScalarAlloc(rej,     PS_TYPE_F32);        psArrayAdd(job->args, 1, tmpVal); psFree (tmpVal); }
+		      { psScalar *tmpVal = psScalarAlloc(maskVal, PS_TYPE_IMAGE_MASK); psArrayAdd(job->args, 1, tmpVal); psFree (tmpVal); }
 
                       // call: pmDarkCombine(outCell, fileGroup->readouts, iter, rej, maskVal);
                       if (!psThreadJobAddPending(job)) {
-			//                          goto ERROR;
-			// continue; // I don't care.
+			// CZW commented this out with a note that this was needed to allow ppMerge to work even if some inputs are invalid.
+			// EAM thinks pmDarkCombine will only return FALSE if there is a programming or setup error (see pmDark.c:pmDarkCombine)
+			// if so, we should raise an error here.
+			// goto ERROR;
                       }
                       break;
@@ -398,5 +395,4 @@
 
             psFree(fileGroups);
-	    //            psFree(zeros);
 
             // XXX eventually need to keep both the shutter and the pattern, as we do with dark
@@ -539,4 +535,12 @@
             }
 
+            // free the data used by the input files (we need to do the work ourselves)
+            for (int i = 0; i < numFiles; i++) {
+                if (!ppMergeFileFreeInput(config, view, i)) {
+                    psError(PS_ERR_UNKNOWN, false, "Unable to open file %d", i);
+                    goto ERROR;
+                }
+            }
+
             psFree(outRO);
             cellNum++;
@@ -545,4 +549,6 @@
                 goto ERROR;
             }
+
+	    // pmFPAfileIOList (config);
         }
 
@@ -562,4 +568,5 @@
     psFree(variances);
     psFree(stats);
+    psFree(zeros);
     return true;
 
@@ -571,4 +578,5 @@
     psFree(variances);
     psFree(stats);
+    psFree(zeros);
     return false;
 }
Index: branches/eam_branches/ipp-20230313/ppMerge/src/ppMergeMask.c
===================================================================
--- branches/eam_branches/ipp-20230313/ppMerge/src/ppMergeMask.c	(revision 42819)
+++ branches/eam_branches/ipp-20230313/ppMerge/src/ppMergeMask.c	(revision 42820)
@@ -427,12 +427,12 @@
     }
 
-    psArray *inputs = ppMergeFileDataLevel(config, "PPMERGE.INPUT", PM_FPA_LEVEL_READOUT); ///< Input images
+    psArray *inputs = ppMergeFileDataLevel(config, "PPMERGE.INPUT"); ///< Input images
     psFree(inputs);
     if (haveMasks) {
-        psArray *masks = ppMergeFileDataLevel(config, "PPMERGE.INPUT.MASK", PM_FPA_LEVEL_READOUT);
+        psArray *masks = ppMergeFileDataLevel(config, "PPMERGE.INPUT.MASK");
         psFree(masks);
     }
     if (haveVariances) {
-        psArray *variances = ppMergeFileDataLevel(config, "PPMERGE.INPUT.VARIANCE", PM_FPA_LEVEL_READOUT);
+        psArray *variances = ppMergeFileDataLevel(config, "PPMERGE.INPUT.VARIANCE");
         psFree(variances);
     }
Index: branches/eam_branches/ipp-20230313/ppMerge/src/ppMergeScaleZero.c
===================================================================
--- branches/eam_branches/ipp-20230313/ppMerge/src/ppMergeScaleZero.c	(revision 42819)
+++ branches/eam_branches/ipp-20230313/ppMerge/src/ppMergeScaleZero.c	(revision 42820)
@@ -232,4 +232,5 @@
     }
 
+    psFree(gains);
     psFree(background);
     psFree(shutters);
Index: branches/eam_branches/ipp-20230313/psLib/src/db/psDB.c
===================================================================
--- branches/eam_branches/ipp-20230313/psLib/src/db/psDB.c	(revision 42819)
+++ branches/eam_branches/ipp-20230313/psLib/src/db/psDB.c	(revision 42820)
@@ -1039,8 +1039,14 @@
     fieldCount = mysql_num_fields(result);
 
+<<<<<<< .working
     // annoyingly, in some versions of mysql the value my_ulonglong is actually unsigned long long and in others
     // it is actually unsigned long.  rather than try to set a print type which depends on the build, we just
     // cast here to the unsigned long since it is rare that we would need such a large rowCount
     psTrace("psLib.db", PS_LOG_INFO, "query returned %lu rows with %d fields", (unsigned long) rowCount, fieldCount);
+||||||| .merge-left.r42748
+    psTrace("psLib.db", PS_LOG_INFO, "query returned %lld rows with %d fields",             rowCount, fieldCount);
+=======
+    psTrace("psLib.db", PS_LOG_INFO, "query returned %lu rows with %d fields", (long unsigned int) rowCount, fieldCount);
+>>>>>>> .merge-right.r42814
 
     while ((row = mysql_fetch_row(result))) {
Index: branches/eam_branches/ipp-20230313/psLib/src/sys/psConfigure.c
===================================================================
--- branches/eam_branches/ipp-20230313/psLib/src/sys/psConfigure.c	(revision 42819)
+++ branches/eam_branches/ipp-20230313/psLib/src/sys/psConfigure.c	(revision 42820)
@@ -29,4 +29,5 @@
 #include <fftw3.h>
 #include <gsl/gsl_version.h>
+#include <gsl/gsl_errno.h>
 #ifdef HAVE_PSDB
 #include <mysql.h>
@@ -157,4 +158,6 @@
     // XXX: Still needs error codes to be set
 
+  gsl_set_error_handler_off();
+
     if (timeConfig && strlen(timeConfig) > 0) {
         if (!psTimeInit(timeConfig)) {
Index: branches/eam_branches/ipp-20230313/psModules/src/camera/pmFPA.c
===================================================================
--- branches/eam_branches/ipp-20230313/psModules/src/camera/pmFPA.c	(revision 42819)
+++ branches/eam_branches/ipp-20230313/psModules/src/camera/pmFPA.c	(revision 42820)
@@ -53,7 +53,7 @@
     }
     psTrace("psModules.camera", 9, "Freeing cell %zd\n", (size_t)cell);
+
     pmCellFreeReadouts(cell);
     psFree(cell->readouts);
-
     psFree(cell->concepts);
     psFree(cell->analysis);
@@ -166,4 +166,5 @@
     psFree(readout->variance);
     psFree(readout->covariance);
+    psFree(readout->analysis);
     psFree(readout->bias);
 
@@ -173,7 +174,7 @@
     readout->variance = NULL;
     readout->covariance = NULL;
+    readout->analysis = NULL;
     readout->mask = NULL;
-
-    readout->bias = psListAlloc(NULL);
+    readout->bias = NULL;
 
     readout->col0 = 0;
Index: branches/eam_branches/ipp-20230313/psModules/src/camera/pmFPAConstruct.c
===================================================================
--- branches/eam_branches/ipp-20230313/psModules/src/camera/pmFPAConstruct.c	(revision 42819)
+++ branches/eam_branches/ipp-20230313/psModules/src/camera/pmFPAConstruct.c	(revision 42820)
@@ -52,4 +52,14 @@
 
 // Parse a list of first:second:third pairs in a string
+// EAM : this function takes an input 'string' and attempts to parse out
+// groups of the form FIRST:SECOND:THIRD into the arrays (first, second, third).
+
+// The input string may have multiple entries of this form separated by spaces, commas, or
+// semi-colons.  The number of arrays which are supplied must match the string format or
+// an error will be raised.
+
+// e.g., the string could be CHIP:CELL:TYPE in which case all three arrays must exist
+// or, the string could be CHIP:CELL only, in which case the array 'third' must be NULL
+ 
 static int parseContent(psArray **first, // Array of the first values
                          psArray **second, // Array of the second values
@@ -83,4 +93,8 @@
     while ((value = psListGetAndIncrement(valuesIter))) {
         psArray *fst = psStringSplitArray(value, ":", true); // First, second, third
+	if (fst->n != numArrays) {
+	  psError(PS_ERR_BAD_PARAMETER_VALUE, false, "string %s does not match expected format (%ld colon-separated items supplied, %d expected)", value, fst->n, numArrays);
+	  return 0;
+	}
         switch (numArrays) {
           case 3:
@@ -1126,5 +1140,5 @@
     pmFPAview *view = pmFPAviewAlloc(0); // View, to be returned
     if (phuView) {
-        // Copy the view, for the case where we're given a view.
+        // Copy the view values, for the case where we're given a view.
         *view = *phuView;
     }
Index: branches/eam_branches/ipp-20230313/psModules/src/detrend/pmDark.c
===================================================================
--- branches/eam_branches/ipp-20230313/psModules/src/detrend/pmDark.c	(revision 42819)
+++ branches/eam_branches/ipp-20230313/psModules/src/detrend/pmDark.c	(revision 42820)
@@ -252,8 +252,8 @@
     }
 
+# if (PS_TRACE_ON)
     if (psTraceGetLevel("psModules.detrend") > 9) {
         for (int i = 0; i < inputs->n; i++) {
             psVector *val = values->data[i];
-            (void) val; // avoid unused variable message when tracing is compiled out
             for (int j = 0; j < ordinates->n; j++) {
                 psTrace("psModules.detrend", 9, "Image %d, ordinate %d: %f\n", i, j, val->data.F32[j]);
@@ -261,4 +261,5 @@
         }
     }
+# endif
 
     int numTerms = 1;                   // Number of terms in polynomial
@@ -292,7 +293,9 @@
         pmReadout *readout = output->readouts->data[i]; // Readout to update
         if (!readout) {
-            readout = output->readouts->data[i] = pmReadoutAlloc(output);
-        }
-
+  	    // pmReadoutAlloc places a reference to the readout on cell->readouts
+	    // and returns a second mem reference to the readout
+            readout = pmReadoutAlloc(output);
+	    psFree (readout); // free the extra mem reference returned by pmReadoutAlloc
+        }
         pmReadoutStackDefineOutput(readout, col0, row0, numCols, numRows, false, false, 0);
         psTrace("psModules.imcombine", 7, "Output minimum: %d,%d\n", col0, row0);
@@ -469,8 +472,4 @@
 	      for (int m = 0; m < poly->deviations->n; m++) {
 		logL->data.F64[k] += pow(poly->deviations->data.F32[m] / polySig->stdevFit,2);
-/* 		if ((xOut == 20) && (yOut == 256)) { */
-/* 		  psTrace("psModules.detrend",3,"pmDarkCombine DEV: %d %d: input %d models: Norders: %d logL: %g value: %g\n", */
-/* 			  xOut,yOut,m,k,logL->data.F64[k],poly->deviations->data.F32[m]); */
-/* 		} */
 	      }
 	      if (k > 0) {
@@ -487,15 +486,13 @@
 	      k_best = 1;
 	    }
-/* 	    k_best = 1; */
+
 	    // Select the polynomial that seems best.
 	    psPolynomialMD *poly = poly_set->data[k_best];
 	      
-	    //            for (int k = 0; k < poly->coeff->n; k++) {
 	    for (int k = 0; k < max_orders->n + 1; k++) { // There is one more coefficient than is stored here.
                 pmReadout *ro = output->readouts->data[k]; // Readout of interest
 		if (k < poly->coeff->n) {
 		  ro->image->data.F32[yOut][xOut] = poly->coeff->data.F64[k];
-		}
-		else {
+		} else {
 		  ro->image->data.F32[yOut][xOut] = 0.0;
 		}
Index: branches/eam_branches/ipp-20230313/psconfig/tagsets/ipp-ubuntu.dist
===================================================================
--- branches/eam_branches/ipp-20230313/psconfig/tagsets/ipp-ubuntu.dist	(revision 42819)
+++ branches/eam_branches/ipp-20230313/psconfig/tagsets/ipp-ubuntu.dist	(revision 42820)
@@ -69,5 +69,5 @@
   YYYYY  ippScripts             ipp-2-9          -0
   YYYYY  ippTasks               ipp-2-9          -0
-# YNYYY  ippToPsps              ipp-2-9          -0 : moved to $svn/psps
+  YNYYY  ippToPsps              ipp-2-9          -0 : moved to $svn/psps
           
   YNYYN  psconfig               ipp-2-9          -0
@@ -82,8 +82,8 @@
 
   YYYYY  extsrc/gpcsw           ipp-2-9          -0
-# YYYYY  magic                  ipp-2-9          -0
-# YYYYY  magic/censorObjects    ipp-2-9          -0
-# YYYYY  magic/remove           ipp-2-9          -0
-  YYYYY  console                ipp-2-9          -0
+  YNYYY  magic                  ipp-2-9          -0
+  YNYYY  magic/censorObjects    ipp-2-9          -0
+  YNYYY  magic/remove           ipp-2-9          -0
+  YNYYY  console                ipp-2-9          -0
 
 # there are externally required C libraries and perl modules (see INSTALL)
Index: branches/eam_branches/ipp-20230313/tools/eam/neb-apache-check.20241219/check.apache.connections.sh
===================================================================
--- branches/eam_branches/ipp-20230313/tools/eam/neb-apache-check.20241219/check.apache.connections.sh	(revision 42820)
+++ branches/eam_branches/ipp-20230313/tools/eam/neb-apache-check.20241219/check.apache.connections.sh	(revision 42820)
@@ -0,0 +1,62 @@
+#!/bin/csh
+
+set tmpfile = `mktemp`
+
+### old, hard-wired servers
+# set names = (ippx089 ippx090 ippx093 ippx097 ippx099 ippx101)
+# set Nvals = (      0       0       0       0       0       0)
+
+### load Nebulous servers from common source
+source ~ippps1/ippconfig/nebservers.csh
+
+# echo $nebservers
+# echo $#nebservers
+
+set names = (`echo $nebservers | sed "s|http://||g" | sed "s|/nebulous||g"`)
+set Nvals = (`echo $nebservers | sed "s|http://||g" | sed "s|/nebulous||g"`)
+
+# echo $names
+# echo $Nvals
+
+# exit 2
+
+while (1)
+  (mysql -h ippdb11 -u ipp -pipp nebulous -e "show processlist" > $tmpfile) >& /dev/null
+
+  set i = 1
+  while ($i <= $#names)
+    set Nvals[$i] = `grep $names[$i] $tmpfile | wc -l`
+    @ i++
+  end
+
+  set now = `date +"%Y/%m/%d %H:%M:%S"`
+  echo "$now $Nvals"
+
+  set myWarning = ""
+  set myRestart = ""
+
+  set i = 1
+  while ($i <= $#names)
+    if ($Nvals[$i] < 32) then
+      set myWarning = "$myWarning $names[$i]"
+    endif
+
+    if ($Nvals[$i] < 5) then
+      set myRestart = "$myRestart $names[$i]"
+      ssh $names[$i] "sudo -A systemctl restart apache2.service"
+    endif
+    @ i++
+  end
+
+  if ("$myWarning" != "") then
+    echo "too few apache servers on $myWarning : $now $Nvals"
+    echo "too few apache servers on $myWarning : $now $Nvals" | mail -s "WARNING: nebulous apache servers" magnier@hawaii.edu
+  endif
+
+  if ("$myRestart" != "") then
+    echo "critically few apache servers, restarting on $myRestart"
+    echo "critically few apache servers, restarting on $myRestart" | mail -s "WARNING: nebulous apache servers" magnier@hawaii.edu
+  endif
+
+  sleep 300
+end
