Index: branches/eam_branches/ipp-20101205/ppStack/src/Makefile.am
===================================================================
--- branches/eam_branches/ipp-20101205/ppStack/src/Makefile.am	(revision 30013)
+++ branches/eam_branches/ipp-20101205/ppStack/src/Makefile.am	(revision 30015)
@@ -49,4 +49,7 @@
 	ppStackFinish.c		\
 	ppStackTarget.c		\
+	ppStackUpdateHeader.c	\
+	ppStackJPEGs.c		\
+	ppStackStats.c		\
 	ppStackErrorCodes.c
 
Index: branches/eam_branches/ipp-20101205/ppStack/src/ppStack.c
===================================================================
--- branches/eam_branches/ipp-20101205/ppStack/src/ppStack.c	(revision 30013)
+++ branches/eam_branches/ipp-20101205/ppStack/src/ppStack.c	(revision 30015)
@@ -1,20 +1,8 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <pslib.h>
-#include <psmodules.h>
-#include <psphot.h>
-
 #include "ppStack.h"
-#include "ppStackLoop.h"
-
-#define TIMER_NAME "PPSTACK"            // Name of timer
 
 int main(int argc, char *argv[])
 {
     psLibInit(NULL);
-    psTimerStart(TIMER_NAME);
+    psTimerStart("PPSTACK");
     psTimerStart("PPSTACK_STEPS");
 
@@ -23,8 +11,9 @@
     psphotErrorRegister();
 
+    ppStackOptions *options = NULL;                               // Options for stacking
+
     pmConfig *config = pmConfigRead(&argc, argv, PPSTACK_RECIPE); // Configuration
-    ppStackOptions *options = NULL;                               // Options for stacking
     if (!config) {
-        goto die;
+	ppStackCleanup(config, options);
     }
 
@@ -33,100 +22,30 @@
     if (!pmModelClassInit()) {
         psError(PPSTACK_ERR_PROG, false, "Unable to initialise model classes.");
-        goto die;
+	ppStackCleanup(config, options);
     }
 
     if (!psphotInit()) {
         psError(PPSTACK_ERR_PROG, false, "Error initialising psphot.");
-        goto die;
+	ppStackCleanup(config, options);
     }
 
-    (void)psTraceSetLevel("ppStack", 5);
-
     if (!ppStackArgumentsSetup(argc, argv, config)) {
-        goto die;
+	ppStackCleanup(config, options);
     }
 
     if (!ppStackCamera(config)) {
-        goto die;
+	ppStackCleanup(config, options);
     }
 
     if (!ppStackArgumentsParse(config)) {
-        goto die;
+	ppStackCleanup(config, options);
     }
 
     options = ppStackOptionsAlloc();
     if (!ppStackLoop(config, options)) {
-        goto die;
+	ppStackCleanup(config, options);
     }
 
-
- die:
-    // Common code for the death.
-    {
-        psExit exitValue = ppStackExitCode(PS_EXIT_SUCCESS); // Exit code
-
-        // Ensure everything closes
-        if (config) {
-            ppStackFileActivation(config, PPSTACK_FILES_PREPARE, true);
-            ppStackFileActivation(config, PPSTACK_FILES_CONVOLVE, true);
-            ppStackFileActivation(config, PPSTACK_FILES_STACK, true);
-            ppStackFileActivation(config, PPSTACK_FILES_UNCONV, true);
-            ppStackFileActivation(config, PPSTACK_FILES_PHOT, true);
-            if (!ppStackFilesIterateUp(config)) {
-                psError(psErrorCodeLast(), false, "Unable to close files.");
-                exitValue = ppStackExitCode(exitValue);
-                pmFPAfileFreeSetStrict(false);
-            }
-        }
-
-        // Write out summary statistics
-        if (options && options->stats) {
-
-            psMetadataAddS32(options->stats, PS_LIST_TAIL, "QUALITY", PS_META_REPLACE,
-                             "Bad data quality flag", options->quality);
-            psMetadataAddF32(options->stats, PS_LIST_TAIL, "TIME_STACK", 0,
-                             "Total time", psTimerClear("PPSTACK_TOTAL"));
-
-            const char *statsMDC = psMetadataConfigFormat(options->stats);
-            if (!statsMDC || strlen(statsMDC) == 0) {
-                psError(PS_ERR_IO, false, "Unable to get statistics MDC file.");
-                return false;
-            }
-            if (fprintf(options->statsFile, "%s", statsMDC) != strlen(statsMDC)) {
-                psError(PS_ERR_IO, false, "Unable to write statistics MDC file.");
-                return false;
-            }
-            psFree(statsMDC);
-            if (fclose(options->statsFile) == EOF) {
-                psError(PS_ERR_IO, false, "Unable to close statistics MDC file.");
-                return false;
-            }
-            options->statsFile = NULL;
-            pmConfigRunFilenameAddWrite(config, "STATS",
-                                        psMetadataLookupStr(NULL, config->arguments, "STATS"));
-        }
-        psFree(options);
-
-        // Dump configuration
-        bool mdok;                                                                    // Status of MD lookup
-        psString dump = psMetadataLookupStr(&mdok, config->arguments, "DUMP_CONFIG"); // File for config
-        if (dump && !pmConfigDump(config, dump)) {
-            psError(psErrorCodeLast(), false, "Unable to dump configuration.");
-            exitValue = ppStackExitCode(exitValue);
-        }
-
-        psTrace("ppStack", 1, "Finished at %f sec\n", psTimerMark(TIMER_NAME));
-        psTimerStop();
-
-        psFree(config);
-        pmModelClassCleanup();
-        pmConfigDone();
-        psLibFinalize();
-        pmVisualClose();
-	pmVisualCleanup ();
-
-        exitValue = ppStackExitCode(exitValue);
-        exit(exitValue);
-    }
+    ppStackCleanup(config, options);
 }
 
Index: branches/eam_branches/ipp-20101205/ppStack/src/ppStack.h
===================================================================
--- branches/eam_branches/ipp-20101205/ppStack/src/ppStack.h	(revision 30013)
+++ branches/eam_branches/ipp-20101205/ppStack/src/ppStack.h	(revision 30015)
@@ -1,2 +1,12 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <pslib.h>
+#include <psmodules.h>
+#include <ppStats.h>
+#include <psphot.h>
+
 #ifndef PPSTACK_H
 #define PPSTACK_H
@@ -7,7 +17,4 @@
 #include <pslib.h>
 #include <psmodules.h>
-
-#include "ppStackOptions.h"
-#include "ppStackErrorCodes.h"
 
 // Mask values for inputs
@@ -25,4 +32,5 @@
 // List of files
 typedef enum {
+    PPSTACK_FILES_NONE,                 // NOP list
     PPSTACK_FILES_PREPARE,              // Files for preparation
     PPSTACK_FILES_TARGET,               // Files for target generation
@@ -33,4 +41,8 @@
 } ppStackFileList;
 
+#include "ppStackOptions.h"
+#include "ppStackThread.h"
+#include "ppStackLoop.h"
+#include "ppStackErrorCodes.h"
 
 // Setup command-line arguments
@@ -183,3 +195,5 @@
 psExit ppStackExitCode(psExit exitValue);
 
+bool ppStackCleanup(pmConfig *config, ppStackOptions *options) PS_ATTR_NORETURN;
+
 #endif
Index: branches/eam_branches/ipp-20101205/ppStack/src/ppStackArguments.c
===================================================================
--- branches/eam_branches/ipp-20101205/ppStack/src/ppStackArguments.c	(revision 30013)
+++ branches/eam_branches/ipp-20101205/ppStack/src/ppStackArguments.c	(revision 30015)
@@ -1,11 +1,2 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <string.h>
-#include <pslib.h>
-#include <psmodules.h>
-
 #include "ppStack.h"
 
@@ -198,16 +189,16 @@
 
     // stack-type : used to define the stack for PSPS
-    if ((N = psArgumentGet (argc, argv, "-stack-type"))) {
-	if (argc <= N+1) {
-	  psErrorStackPrint(stderr, "Expected to see an argument for -stack-type");
-	  exit(PS_EXIT_CONFIG_ERROR);
+    if ((argNum = psArgumentGet (argc, argv, "-stack-type"))) {
+	if (argc <= argNum+1) {
+	    psErrorStackPrint(stderr, "Expected to see an argument for -stack-type");
+	    exit(PS_EXIT_CONFIG_ERROR);
 	}
-        psArgumentRemove (N, &argc, argv);
-	if (strcasecmp(argv[N], "NIGHTLY_STACK") && strcasecmp(argv[N], "DEEP_STACK") && strcasecmp(argv[N], "IQ_STACK")) {
-	  psErrorStackPrint(stderr, "Invalid option for -stack-type %s (must be one of NIGHTLY_STACK, DEEP_STACK, IQ_STACK)");
-	  exit(PS_EXIT_CONFIG_ERROR);
+        psArgumentRemove (argNum, &argc, argv);
+	if (strcasecmp(argv[argNum], "NIGHTLY_STACK") && strcasecmp(argv[argNum], "DEEP_STACK") && strcasecmp(argv[argNum], "IQ_STACK")) {
+	    psErrorStackPrint(stderr, "Invalid option for -stack-type %s (must be one of NIGHTLY_STACK, DEEP_STACK, IQ_STACK)", argv[argNum]);
+	    exit(PS_EXIT_CONFIG_ERROR);
 	}
-	psMetadataAddStr (arguments, PS_LIST_TAIL, "STACK_TYPE", PS_META_REPLACE, "Stack Type", argv[N]);
-        psArgumentRemove (N, &argc, argv);
+	psMetadataAddStr (arguments, PS_LIST_TAIL, "STACK_TYPE", PS_META_REPLACE, "Stack Type", argv[argNum]);
+        psArgumentRemove (argNum, &argc, argv);
     } else { 
 	psMetadataAddStr (arguments, PS_LIST_TAIL, "STACK_TYPE", PS_META_REPLACE, "Stack Type", "DEEP_STACK");
Index: branches/eam_branches/ipp-20101205/ppStack/src/ppStackCamera.c
===================================================================
--- branches/eam_branches/ipp-20101205/ppStack/src/ppStackCamera.c	(revision 30013)
+++ branches/eam_branches/ipp-20101205/ppStack/src/ppStackCamera.c	(revision 30015)
@@ -1,12 +1,2 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <string.h>
-#include <pslib.h>
-#include <psmodules.h>
-#include <psphot.h>
-
 #include "ppStack.h"
 
Index: branches/eam_branches/ipp-20101205/ppStack/src/ppStackCleanup.c
===================================================================
--- branches/eam_branches/ipp-20101205/ppStack/src/ppStackCleanup.c	(revision 30013)
+++ branches/eam_branches/ipp-20101205/ppStack/src/ppStackCleanup.c	(revision 30015)
@@ -1,17 +1,6 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#include "ppStack.h"
 
-#include <stdio.h>
-#include <pslib.h>
-#include <psmodules.h>
-#include <ppStats.h>
-
-#include "ppStack.h"
-#include "ppStackLoop.h"
-
-// XXX poor name : move jpeg & stats to a separate function?
 // ppStackCleanupFiles 
-bool ppStackCleanup(ppStackThreadData *stack, ppStackOptions *options, pmConfig *config)
+bool ppStackCleanupFiles(ppStackThreadData *stack, ppStackOptions *options, pmConfig *config, ppStackFileList stackFiles, ppStackFileList photFiles, bool closeJPEGs)
 {
     psAssert(stack, "Require stack");
@@ -19,67 +8,29 @@
     psAssert(config, "Require configuration");
 
-    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSTACK_RECIPE); // ppStack recipe
-    psAssert(recipe, "We've thrown an error on this before.");
-
-    // Generate binned JPEGs
-    {
-        int bin1 = psMetadataLookupS32(NULL, recipe, "BIN1"); // First binning level
-        int bin2 = psMetadataLookupS32(NULL, recipe, "BIN2"); // Second binning level
-
-        // Target cells
-        pmFPAview *view = pmFPAviewAlloc(0); // View to cells of interest
-        view->chip = view->cell = 0;
-        pmCell *cell1 = pmFPAfileThisCell(config->files, view, "PPSTACK.OUTPUT.JPEG1");
-        pmCell *cell2 = pmFPAfileThisCell(config->files, view, "PPSTACK.OUTPUT.JPEG2");
-        psImageMaskType maskValue = pmConfigMaskGet("BLANK", config); // Bits to mask
-        psFree(view);
-
-        pmReadout *ro1 = pmReadoutAlloc(cell1), *ro2 = pmReadoutAlloc(cell2); // Binned readouts
-        if (!pmReadoutRebin(ro1, options->outRO, maskValue, bin1, bin1) ||
-            !pmReadoutRebin(ro2, ro1, 0, bin2, bin2)) {
-            psError(PPSTACK_ERR_DATA, false, "Unable to bin output.");
-            psFree(ro1);
-            psFree(ro2);
-            return false;
-        }
-        psFree(ro1);
-        psFree(ro2);
-    }
-
-    // Statistics on output
-    if (options->stats) {
-        psTrace("ppStack", 1, "Gathering statistics on stacked image....\n");
-        psString maskBadStr = psMetadataLookupStr(NULL, recipe, "MASK.BAD"); // Name of bits for bad
-        psImageMaskType maskBad = pmConfigMaskGet(maskBadStr, config); // Bits to mask for bad pixels
-
-        pmFPAview *view = pmFPAviewAlloc(0); // View to readout
-        view->chip = view->cell = view->readout = 0;
-
-        ppStatsFPA(options->stats, options->outRO->parent->parent->parent, view, maskBad, config);
-
-        psFree(view);
-    }
-
     if (!ppStackFilesIterateUp(config)) {
         psError(psErrorCodeLast(), false, "Unable to close files.");
         return false;
     }
-    ppStackFileActivation(config, PPSTACK_FILES_STACK, false);
-    ppStackFileActivation(config, PPSTACK_FILES_PHOT, false);
+    ppStackFileActivation(config, stackFiles, false);
+    ppStackFileActivation(config, photFiles, false);
 
     // Ensure files are freed
-    {
-        options->outRO->data_exists = false;
-        options->outRO->parent->data_exists = false;
-        options->outRO->parent->parent->data_exists = false;
-        psFree(options->outRO);
-        options->outRO = NULL;
+    options->outRO->data_exists = false;
+    options->outRO->parent->data_exists = false;
+    options->outRO->parent->parent->data_exists = false;
+    psFree(options->outRO);
+    options->outRO = NULL;
 
-        options->expRO->data_exists = false;
-        options->expRO->parent->data_exists = false;
-        options->expRO->parent->parent->data_exists = false;
-        psFree(options->expRO);
-        options->expRO = NULL;
+    options->expRO->data_exists = false;
+    options->expRO->parent->data_exists = false;
+    options->expRO->parent->parent->data_exists = false;
+    psFree(options->expRO);
+    options->expRO = NULL;
 
+    for (int i = 0; i < options->num; i++) {
+        pmCellFreeData(options->cells->data[i]);
+    }
+
+    if (closeJPEGs) {
 	// XXX move these close / free operations to the jpeg creation function
         pmFPAview *view = pmFPAviewAlloc(0);// Pointer into FPA hierarchy
@@ -109,2 +60,70 @@
     return true;
 }
+
+bool ppStackCleanup (pmConfig *config, ppStackOptions *options) {
+
+    psExit exitValue = ppStackExitCode(PS_EXIT_SUCCESS); // Exit code
+
+    // Ensure everything closes
+    if (config) {
+	ppStackFileActivation(config, PPSTACK_FILES_PREPARE, true);
+	ppStackFileActivation(config, PPSTACK_FILES_CONVOLVE, true);
+	ppStackFileActivation(config, PPSTACK_FILES_STACK, true);
+	ppStackFileActivation(config, PPSTACK_FILES_UNCONV, true);
+	ppStackFileActivation(config, PPSTACK_FILES_PHOT, true);
+	if (!ppStackFilesIterateUp(config)) {
+	    psError(psErrorCodeLast(), false, "Unable to close files.");
+	    exitValue = ppStackExitCode(exitValue);
+	    pmFPAfileFreeSetStrict(false);
+	}
+    }
+
+    // Write out summary statistics
+    if (options && options->stats) {
+
+	psMetadataAddS32(options->stats, PS_LIST_TAIL, "QUALITY", PS_META_REPLACE, "Bad data quality flag", options->quality);
+	psMetadataAddF32(options->stats, PS_LIST_TAIL, "TIME_STACK", 0, "Total time", psTimerClear("PPSTACK_TOTAL"));
+
+	const char *statsMDC = psMetadataConfigFormat(options->stats);
+	if (!statsMDC || strlen(statsMDC) == 0) {
+	    psError(PS_ERR_IO, false, "Unable to get statistics MDC file.");
+	    exitValue = ppStackExitCode(exitValue);
+	    exit(exitValue);
+	}
+	if (fprintf(options->statsFile, "%s", statsMDC) != strlen(statsMDC)) {
+	    psError(PS_ERR_IO, false, "Unable to write statistics MDC file.");
+	    exitValue = ppStackExitCode(exitValue);
+	    exit(exitValue);
+	}
+	psFree(statsMDC);
+	if (fclose(options->statsFile) == EOF) {
+	    psError(PS_ERR_IO, false, "Unable to close statistics MDC file.");
+	    exitValue = ppStackExitCode(exitValue);
+	    exit(exitValue);
+	}
+	options->statsFile = NULL;
+	pmConfigRunFilenameAddWrite(config, "STATS", psMetadataLookupStr(NULL, config->arguments, "STATS"));
+    }
+    psFree(options);
+
+    // Dump configuration
+    bool mdok;                                                                    // Status of MD lookup
+    psString dump = psMetadataLookupStr(&mdok, config->arguments, "DUMP_CONFIG"); // File for config
+    if (dump && !pmConfigDump(config, dump)) {
+	psError(psErrorCodeLast(), false, "Unable to dump configuration.");
+	exitValue = ppStackExitCode(exitValue);
+    }
+
+    psTrace("ppStack", 1, "Finished at %f sec\n", psTimerMark("PPSTACK"));
+    psTimerStop();
+
+    psFree(config);
+    pmModelClassCleanup();
+    pmConfigDone();
+    psLibFinalize();
+    pmVisualClose();
+    pmVisualCleanup ();
+
+    exitValue = ppStackExitCode(exitValue);
+    exit(exitValue);
+}
Index: branches/eam_branches/ipp-20101205/ppStack/src/ppStackCombineFinal.c
===================================================================
--- branches/eam_branches/ipp-20101205/ppStack/src/ppStackCombineFinal.c	(revision 30013)
+++ branches/eam_branches/ipp-20101205/ppStack/src/ppStackCombineFinal.c	(revision 30015)
@@ -1,12 +1,3 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <pslib.h>
-#include <psmodules.h>
-
 #include "ppStack.h"
-#include "ppStackLoop.h"
 
 //#define TESTING                         // Enable test output
Index: branches/eam_branches/ipp-20101205/ppStack/src/ppStackCombineInitial.c
===================================================================
--- branches/eam_branches/ipp-20101205/ppStack/src/ppStackCombineInitial.c	(revision 30013)
+++ branches/eam_branches/ipp-20101205/ppStack/src/ppStackCombineInitial.c	(revision 30015)
@@ -1,12 +1,3 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <pslib.h>
-#include <psmodules.h>
-
 #include "ppStack.h"
-#include "ppStackLoop.h"
 
 //#define TESTING                         // Enable test output
Index: branches/eam_branches/ipp-20101205/ppStack/src/ppStackCombinePrepare.c
===================================================================
--- branches/eam_branches/ipp-20101205/ppStack/src/ppStackCombinePrepare.c	(revision 30013)
+++ branches/eam_branches/ipp-20101205/ppStack/src/ppStackCombinePrepare.c	(revision 30015)
@@ -1,12 +1,3 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <pslib.h>
-#include <psmodules.h>
-
 #include "ppStack.h"
-#include "ppStackLoop.h"
 
 bool ppStackCombinePrepare(const char *outName, const char *expName,
Index: branches/eam_branches/ipp-20101205/ppStack/src/ppStackConvolve.c
===================================================================
--- branches/eam_branches/ipp-20101205/ppStack/src/ppStackConvolve.c	(revision 30013)
+++ branches/eam_branches/ipp-20101205/ppStack/src/ppStackConvolve.c	(revision 30015)
@@ -1,15 +1,5 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <pslib.h>
-#include <psmodules.h>
-
 #include "ppStack.h"
-#include "ppStackLoop.h"
 
 //#define TESTING
-
 
 // Update the value of a concept
@@ -20,6 +10,4 @@
     item->data.F32 = VALUE; \
 }
-
-
 
 bool ppStackConvolve(ppStackOptions *options, pmConfig *config)
@@ -69,6 +57,5 @@
         ppStackFileActivationSingle(config, PPSTACK_FILES_CONVOLVE, true, i);
         if (options->convolve) {
-            // XXX PPSTACK.CONV.KERNEL not defined unless convolve
-            // pmFPAfileActivate(config->files, true, "PPSTACK.CONV.KERNEL");
+            // PPSTACK.CONV.KERNEL not defined unless convolve
             pmFPAfileActivateSingle(config->files, true, "PPSTACK.CONV.KERNEL", i); // Activated file
         }
Index: branches/eam_branches/ipp-20101205/ppStack/src/ppStackErrorCodes.c.in
===================================================================
--- branches/eam_branches/ipp-20101205/ppStack/src/ppStackErrorCodes.c.in	(revision 30013)
+++ branches/eam_branches/ipp-20101205/ppStack/src/ppStackErrorCodes.c.in	(revision 30015)
@@ -1,2 +1,4 @@
+#include "ppStack.h"
+
 /** @file ppStackErrorCodes.c.in
  *
@@ -10,7 +12,4 @@
  *  Copyright 2009 Institute for Astronomy, University of Hawaii
  */
-
-#include "pslib.h"
-#include "ppStackErrorCodes.h"
 
 /*
Index: branches/eam_branches/ipp-20101205/ppStack/src/ppStackFiles.c
===================================================================
--- branches/eam_branches/ipp-20101205/ppStack/src/ppStackFiles.c	(revision 30013)
+++ branches/eam_branches/ipp-20101205/ppStack/src/ppStackFiles.c	(revision 30015)
@@ -1,15 +1,8 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <unistd.h>
-#include <pslib.h>
-#include <psmodules.h>
-
 #include "ppStack.h"
 
-
 // Here follows lists of files for activation/deactivation at various stages.  Each must be NULL-terminated.
+
+/// NOP list
+static char *filesNOP[] = { NULL };
 
 /// Files required in preparation for convolution
@@ -41,4 +34,5 @@
 {
     switch (list) {
+      case PPSTACK_FILES_NONE:     return filesNOP;
       case PPSTACK_FILES_PREPARE:  return filesPrepare;
       case PPSTACK_FILES_TARGET:   return filesTarget;
Index: branches/eam_branches/ipp-20101205/ppStack/src/ppStackFinish.c
===================================================================
--- branches/eam_branches/ipp-20101205/ppStack/src/ppStackFinish.c	(revision 30013)
+++ branches/eam_branches/ipp-20101205/ppStack/src/ppStackFinish.c	(revision 30015)
@@ -1,14 +1,3 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <unistd.h>
-#include <pslib.h>
-#include <psmodules.h>
-#include <psphot.h>
-
 #include "ppStack.h"
-#include "ppStackLoop.h"
 
 // this function unlinks the temporary files (if desired)
@@ -57,54 +46,56 @@
 
     psErrorCode errorCode = psErrorCodeLast(); // Error code
-    if (errorCode != PS_ERR_NONE) {
-        psErrorStackPrint(stderr, "Unable to perform stack.");
-        pmFPAfileFreeSetStrict(false);
-        switch (errorCode) {
-          case PPSTACK_ERR_UNKNOWN:
-          case PS_ERR_UNKNOWN:
-            psLogMsg("ppStack", PS_LOG_WARN, "Unknown error code: %x", errorCode);
-            exitValue = PS_EXIT_UNKNOWN_ERROR;
-            break;
-          case PS_ERR_IO:
-          case PS_ERR_DB_CLIENT:
-          case PS_ERR_DB_SERVER:
-          case PS_ERR_BAD_FITS:
-          case PS_ERR_OS_CALL_FAILED:
-          case PM_ERR_SYS:
-          case PPSTACK_ERR_IO:
-            psLogMsg("ppStack", PS_LOG_WARN, "I/O error code: %x", errorCode);
-            exitValue = PS_EXIT_SYS_ERROR;
-            break;
-          case PS_ERR_BAD_PARAMETER_VALUE:
-          case PS_ERR_BAD_PARAMETER_TYPE:
-          case PS_ERR_BAD_PARAMETER_NULL:
-          case PS_ERR_BAD_PARAMETER_SIZE:
-          case PPSTACK_ERR_ARGUMENTS:
-          case PPSTACK_ERR_CONFIG:
-            psLogMsg("ppStack", PS_LOG_WARN, "Configuration error code: %x", errorCode);
-            exitValue = PS_EXIT_CONFIG_ERROR;
-            break;
-          case PPSTACK_ERR_PSF:
-          case PSPHOT_ERR_PSF:
-          case PM_ERR_STAMPS:
-          case PM_ERR_SMALL_AREA:
-          case PPSTACK_ERR_REJECTED:
-          case PPSTACK_ERR_DATA:
-            psLogMsg("ppStack", PS_LOG_WARN, "Data error code: %x", errorCode);
-            exitValue = PS_EXIT_DATA_ERROR;
-            break;
-          case PS_ERR_UNEXPECTED_NULL:
-          case PS_ERR_PROGRAMMING:
-          case PPSTACK_ERR_NOT_IMPLEMENTED:
-          case PPSTACK_ERR_PROG:
-            psLogMsg("ppStack", PS_LOG_WARN, "Programming error code: %x", errorCode);
-            exitValue = PS_EXIT_PROG_ERROR;
-            break;
-          default:
-            // It's a programming error if we're not dealing with the error correctly
-            psLogMsg("ppStack", PS_LOG_WARN, "Unrecognised error code: %x", errorCode);
-            exitValue = PS_EXIT_PROG_ERROR;
-            break;
-        }
+    if (errorCode == PS_ERR_NONE) {
+	return exitValue;
+    }
+
+    psErrorStackPrint(stderr, "Unable to perform stack.");
+    pmFPAfileFreeSetStrict(false);
+    switch (errorCode) {
+      case PPSTACK_ERR_UNKNOWN:
+      case PS_ERR_UNKNOWN:
+	psLogMsg("ppStack", PS_LOG_WARN, "Unknown error code: %x", errorCode);
+	exitValue = PS_EXIT_UNKNOWN_ERROR;
+	break;
+      case PS_ERR_IO:
+      case PS_ERR_DB_CLIENT:
+      case PS_ERR_DB_SERVER:
+      case PS_ERR_BAD_FITS:
+      case PS_ERR_OS_CALL_FAILED:
+      case PM_ERR_SYS:
+      case PPSTACK_ERR_IO:
+	psLogMsg("ppStack", PS_LOG_WARN, "I/O error code: %x", errorCode);
+	exitValue = PS_EXIT_SYS_ERROR;
+	break;
+      case PS_ERR_BAD_PARAMETER_VALUE:
+      case PS_ERR_BAD_PARAMETER_TYPE:
+      case PS_ERR_BAD_PARAMETER_NULL:
+      case PS_ERR_BAD_PARAMETER_SIZE:
+      case PPSTACK_ERR_ARGUMENTS:
+      case PPSTACK_ERR_CONFIG:
+	psLogMsg("ppStack", PS_LOG_WARN, "Configuration error code: %x", errorCode);
+	exitValue = PS_EXIT_CONFIG_ERROR;
+	break;
+      case PPSTACK_ERR_PSF:
+      case PSPHOT_ERR_PSF:
+      case PM_ERR_STAMPS:
+      case PM_ERR_SMALL_AREA:
+      case PPSTACK_ERR_REJECTED:
+      case PPSTACK_ERR_DATA:
+	psLogMsg("ppStack", PS_LOG_WARN, "Data error code: %x", errorCode);
+	exitValue = PS_EXIT_DATA_ERROR;
+	break;
+      case PS_ERR_UNEXPECTED_NULL:
+      case PS_ERR_PROGRAMMING:
+      case PPSTACK_ERR_NOT_IMPLEMENTED:
+      case PPSTACK_ERR_PROG:
+	psLogMsg("ppStack", PS_LOG_WARN, "Programming error code: %x", errorCode);
+	exitValue = PS_EXIT_PROG_ERROR;
+	break;
+      default:
+	// It's a programming error if we're not dealing with the error correctly
+	psLogMsg("ppStack", PS_LOG_WARN, "Unrecognised error code: %x", errorCode);
+	exitValue = PS_EXIT_PROG_ERROR;
+	break;
     }
     return exitValue;
Index: branches/eam_branches/ipp-20101205/ppStack/src/ppStackJPEGs.c
===================================================================
--- branches/eam_branches/ipp-20101205/ppStack/src/ppStackJPEGs.c	(revision 30015)
+++ branches/eam_branches/ipp-20101205/ppStack/src/ppStackJPEGs.c	(revision 30015)
@@ -0,0 +1,36 @@
+#include "ppStack.h"
+
+bool ppStackJPEGs(ppStackThreadData *stack, ppStackOptions *options, pmConfig *config)
+{
+    psAssert(stack, "Require stack");
+    psAssert(options, "Require options");
+    psAssert(config, "Require configuration");
+
+    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSTACK_RECIPE); // ppStack recipe
+    psAssert(recipe, "We've thrown an error on this before.");
+
+    // Generate binned JPEGs
+    int bin1 = psMetadataLookupS32(NULL, recipe, "BIN1"); // First binning level
+    int bin2 = psMetadataLookupS32(NULL, recipe, "BIN2"); // Second binning level
+
+    // Target cells
+    pmFPAview *view = pmFPAviewAlloc(0); // View to cells of interest
+    view->chip = view->cell = 0;
+    pmCell *cell1 = pmFPAfileThisCell(config->files, view, "PPSTACK.OUTPUT.JPEG1");
+    pmCell *cell2 = pmFPAfileThisCell(config->files, view, "PPSTACK.OUTPUT.JPEG2");
+    psImageMaskType maskValue = pmConfigMaskGet("BLANK", config); // Bits to mask
+    psFree(view);
+
+    pmReadout *ro1 = pmReadoutAlloc(cell1), *ro2 = pmReadoutAlloc(cell2); // Binned readouts
+    if (!pmReadoutRebin(ro1, options->outRO, maskValue, bin1, bin1) ||
+	!pmReadoutRebin(ro2, ro1, 0, bin2, bin2)) {
+	psError(PPSTACK_ERR_DATA, false, "Unable to bin output.");
+	psFree(ro1);
+	psFree(ro2);
+	return false;
+    }
+    psFree(ro1);
+    psFree(ro2);
+
+    return true;
+}
Index: branches/eam_branches/ipp-20101205/ppStack/src/ppStackLoop.c
===================================================================
--- branches/eam_branches/ipp-20101205/ppStack/src/ppStackLoop.c	(revision 30013)
+++ branches/eam_branches/ipp-20101205/ppStack/src/ppStackLoop.c	(revision 30015)
@@ -1,17 +1,219 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <pslib.h>
-#include <psmodules.h>
-
 #include "ppStack.h"
-#include "ppStackLoop.h"
+
+// static functions are defined below
+static int stackSummary(const ppStackOptions *options, const char *place);
+
+bool ppStackLoop(pmConfig *config, ppStackOptions *options)
+{
+    assert(config);
+
+    psTimerStart("PPSTACK_TOTAL");
+    psTimerStart("PPSTACK_STEPS");
+
+    // Setup
+    psTrace("ppStack", 1, "Setup....\n");
+    if (!ppStackSetup(options, config)) {
+        psError(psErrorCodeLast(), false, "Unable to setup.");
+        return false;
+    }
+    psLogMsg("ppStack", PS_LOG_INFO, "Stage 0: Setup: %f sec", psTimerClear("PPSTACK_STEPS"));
+    ppStackMemDump("setup");
+
+    // Preparation for stacking
+    psTrace("ppStack", 1, "Preparation for stacking: merging sources, determining target PSF....\n");
+
+    if (!ppStackPrepare(options, config)) {
+        psError(psErrorCodeLast(), false, "Unable to prepare for stacking.");
+        return false;
+    }
+    psLogMsg("ppStack", PS_LOG_INFO, "Stage 1: Load Sources and Generate Target PSF: %f sec", psTimerClear("PPSTACK_STEPS"));
+    ppStackMemDump("prepare");
+    if (options->quality) return true; // Can't do anything else
+
+    // Convolve inputs
+    psTrace("ppStack", 1, "Convolving inputs to target PSF....\n");
+    if (!ppStackConvolve(options, config)) {
+        psError(psErrorCodeLast(), false, "Unable to convolve images.");
+        return false;
+    }
+    psLogMsg("ppStack", PS_LOG_INFO, "Stage 2: Generate Convolutions and Save: %f sec", psTimerClear("PPSTACK_STEPS"));
+    ppStackMemDump("convolve");
+    if (options->quality) return true; // Can't do anything else
+
+    // Ensure sufficient inputs
+    {
+        int numGood = stackSummary(options, "initial combination");
+        psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSTACK_RECIPE); // ppStack recipe
+        bool safe = psMetadataLookupBool(NULL, recipe, "SAFE"); // Be safe when combining
+        if (safe && numGood <= 1) {
+            options->quality = PPSTACK_ERR_REJECTED;
+            psErrorStackPrint(stderr, "Insufficient inputs for combination with safety on");
+            psErrorClear();
+            psWarning("Insufficient inputs for combination with safety on");
+            return true;
+        }
+    }
+
+    // Start threading
+    ppStackThreadInit();
+    ppStackThreadData *stack = ppStackThreadDataSetup(options, config, true);
+    if (!stack) {
+        psError(psErrorCodeLast(), false, "Unable to initialise stack threads.");
+        return false;
+    }
+
+    // Prepare for combination
+    if (!ppStackCombinePrepare("PPSTACK.OUTPUT", "PPSTACK.OUTPUT.EXP", PPSTACK_FILES_STACK, stack, options, config)) {
+        psError(psErrorCodeLast(), false, "Unable to prepare for combination.");
+        psFree(stack);
+        return false;
+    }
+
+    // Initial combination
+    psTrace("ppStack", 1, "Initial stack of convolved images....\n");
+    if (!ppStackCombineInitial(stack, options, config)) {
+        psError(psErrorCodeLast(), false, "Unable to perform initial combination.");
+        psFree(stack);
+        return false;
+    }
+    ppStackMemDump("initial");
+    psLogMsg("ppStack", PS_LOG_INFO, "Stage 3: Make Initial Stack: %f sec", psTimerClear("PPSTACK_STEPS"));
+
+    // Done with stack inputs for now
+    // XXX is this where we are leaking??
+    for (int i = 0; i < options->num; i++) {
+        pmCellFreeData(options->cells->data[i]);
+    }
+    psFree(stack);
+
+    // Pixel rejection
+    psTrace("ppStack", 1, "Reject pixels....\n");
+    if (!ppStackReject(options, config)) {
+        psError(psErrorCodeLast(), false, "Unable to reject pixels.");
+        psFree(stack);
+        return false;
+    }
+    psLogMsg("ppStack", PS_LOG_INFO, "Stage 4: Pixel Rejection: %f sec", psTimerClear("PPSTACK_STEPS"));
+
+    // Check inputs
+    {
+        int numGood = stackSummary(options, "final combination");
+        if (numGood <= 0) {
+            options->quality = PPSTACK_ERR_REJECTED;
+            psErrorStackPrint(stderr, "Insufficient inputs survived rejection stage");
+            psErrorClear();
+            psWarning("Insufficient inputs survived rejection stage");
+            return true;
+        }
+    }
+
+    stack = ppStackThreadDataSetup(options, config, true);
+    if (!stack) {
+        psError(psErrorCodeLast(), false, "Unable to initialise stack threads.");
+        return false;
+    }
+
+    // Final combination
+    psTrace("ppStack", 2, "Final stack of convolved images....\n");
+    if (!ppStackCombineFinal(stack, options->convCovars, options, config, false, false, true)) {
+        psError(psErrorCodeLast(), false, "Unable to perform final combination.");
+        psFree(stack);
+        return false;
+    }
+    psLogMsg("ppStack", PS_LOG_INFO, "Stage 5: Final Stack: %f sec", psTimerClear("PPSTACK_STEPS"));
+    ppStackMemDump("final");
+
+    // Photometry
+    psTrace("ppStack", 1, "Photometering stacked image....\n");
+    if (!ppStackPhotometry(options, config)) {
+        psError(psErrorCodeLast(), false, "Unable to perform photometry.");
+        return false;
+    }
+    psLogMsg("ppStack", PS_LOG_INFO, "Stage 6: Photometry Analysis: %f sec", psTimerClear("PPSTACK_STEPS"));
+    ppStackMemDump("photometry");
+
+    // Update Header
+    if (!ppStackUpdateHeader(stack, options)) {
+        psError(psErrorCodeLast(), false, "Unable to update header.");
+        psFree(stack);
+        return false;
+    }
+    // Create JPEGS
+    if (!ppStackJPEGs(stack, options, config)) {
+        psError(psErrorCodeLast(), false, "Unable to make jpegs.");
+        psFree(stack);
+        return false;
+    }
+    // Assemble Stats
+    if (!ppStackStats(stack, options, config)) {
+        psError(psErrorCodeLast(), false, "Unable to assemble statistics.");
+        psFree(stack);
+        return false;
+    }
+
+   // Clean up
+    psTrace("ppStack", 2, "Cleaning up after combination....\n");
+    if (!ppStackCleanupFiles(stack, options, config, PPSTACK_FILES_STACK, PPSTACK_FILES_PHOT, true)) {
+        psError(psErrorCodeLast(), false, "Unable to clean up.");
+        psFree(stack);
+        return false;
+    }
+    psFree(stack);
+    psLogMsg("ppStack", PS_LOG_INFO, "Stage 7: Cleanup, WCS & JPEGS: %f sec", psTimerClear("PPSTACK_STEPS"));
+    ppStackMemDump("cleanup");
+
+    // Unconvolved stack --- it's cheap to calculate, compared to everything else!
+    // XXX unconvolved stack is currently using the convolved mask!  oops!
+    if (options->convolve) {
+        // Start threading
+        ppStackThreadData *stack = ppStackThreadDataSetup(options, config, false);
+        if (!stack) {
+            psError(psErrorCodeLast(), false, "Unable to initialise stack threads.");
+            return false;
+        }
+
+        // Prepare for combination
+        if (!ppStackCombinePrepare("PPSTACK.UNCONV", "PPSTACK.UNCONV.EXP", PPSTACK_FILES_UNCONV,
+                                   stack, options, config)) {
+            psError(psErrorCodeLast(), false, "Unable to prepare for combination.");
+            psFree(stack);
+            return false;
+        }
+
+	// generate the unconvolved stack
+        psTrace("ppStack", 2, "Stack of unconvolved images....\n");
+        if (!ppStackCombineFinal(stack, options->origCovars, options, config,
+                                 false, true, false)) {
+            psError(psErrorCodeLast(), false, "Unable to perform unconvolved combination.");
+            psFree(stack);
+            return false;
+        }
+        psLogMsg("ppStack", PS_LOG_INFO, "Stage 8: Unconvolved Stack: %f sec", psTimerClear("PPSTACK_STEPS"));
+        ppStackMemDump("unconv");
+
+	// Clean up unconvolved stack
+	psTrace("ppStack", 2, "Cleaning up after unconvolved stack....\n");
+	if (!ppStackCleanupFiles(stack, options, config, PPSTACK_FILES_UNCONV, PPSTACK_FILES_NONE, false)) {
+	    psError(psErrorCodeLast(), false, "Unable to clean up.");
+	    psFree(stack);
+	    return false;
+	}
+	psFree(stack);
+    }
+    psFree(options->cells); options->cells = NULL;
+
+    // Finish up
+    psTrace("ppStack", 1, "Finishing up....\n");
+    if (!ppStackFinish(options, config)) {
+        psError(psErrorCodeLast(), false, "Unable to finish up.");
+        return false;
+    }
+    ppStackMemDump("finish");
+
+    return true;
+}
 
 /// Print a summary of the inputs, and return the number of good inputs
-static int stackSummary(const ppStackOptions *options, // Stack options, with input mask
-                        const char *place              // Place in code
-    )
+static int stackSummary(const ppStackOptions *options, const char *place)
 {
     int numGood = 0;                // Number of good inputs
@@ -47,230 +249,2 @@
     return numGood;
 }
-
-
-
-bool ppStackLoop(pmConfig *config, ppStackOptions *options)
-{
-    assert(config);
-
-    psTimerStart("PPSTACK_TOTAL");
-    psTimerStart("PPSTACK_STEPS");
-
-    // Setup
-    psTrace("ppStack", 1, "Setup....\n");
-    if (!ppStackSetup(options, config)) {
-        psError(psErrorCodeLast(), false, "Unable to setup.");
-        return false;
-    }
-    psLogMsg("ppStack", PS_LOG_INFO, "Stage 0: Setup: %f sec", psTimerClear("PPSTACK_STEPS"));
-    ppStackMemDump("setup");
-
-
-    // Preparation for stacking
-    psTrace("ppStack", 1, "Preparation for stacking: merging sources, determining target PSF....\n");
-    if (!ppStackPrepare(options, config)) {
-        psError(psErrorCodeLast(), false, "Unable to prepare for stacking.");
-        return false;
-    }
-    psLogMsg("ppStack", PS_LOG_INFO, "Stage 1: Load Sources and Generate Target PSF: %f sec",
-             psTimerClear("PPSTACK_STEPS"));
-    ppStackMemDump("prepare");
-    if (options->quality) {
-        // Can't do anything else
-        return true;
-    }
-
-    // Convolve inputs
-    psTrace("ppStack", 1, "Convolving inputs to target PSF....\n");
-    if (!ppStackConvolve(options, config)) {
-        psError(psErrorCodeLast(), false, "Unable to convolve images.");
-        return false;
-    }
-    psLogMsg("ppStack", PS_LOG_INFO, "Stage 2: Generate Convolutions and Save: %f sec",
-             psTimerClear("PPSTACK_STEPS"));
-    ppStackMemDump("convolve");
-
-    if (options->quality) {
-        // Can't do anything else
-        return true;
-    }
-
-    // Ensure sufficient inputs
-    {
-        int numGood = stackSummary(options, "initial combination");
-        psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSTACK_RECIPE); // ppStack recipe
-        bool safe = psMetadataLookupBool(NULL, recipe, "SAFE"); // Be safe when combining
-        if (safe && numGood <= 1) {
-            options->quality = PPSTACK_ERR_REJECTED;
-            psErrorStackPrint(stderr, "Insufficient inputs for combination with safety on");
-            psErrorClear();
-            psWarning("Insufficient inputs for combination with safety on");
-            return true;
-        }
-    }
-
-    // Start threading
-    ppStackThreadInit();
-    ppStackThreadData *stack = ppStackThreadDataSetup(options, config, true);
-    if (!stack) {
-        psError(psErrorCodeLast(), false, "Unable to initialise stack threads.");
-        return false;
-    }
-
-    // Prepare for combination
-    if (!ppStackCombinePrepare("PPSTACK.OUTPUT", "PPSTACK.OUTPUT.EXP", PPSTACK_FILES_STACK,
-                               stack, options, config)) {
-        psError(psErrorCodeLast(), false, "Unable to prepare for combination.");
-        psFree(stack);
-        return false;
-    }
-
-    // Initial combination
-    psTrace("ppStack", 1, "Initial stack of convolved images....\n");
-    if (!ppStackCombineInitial(stack, options, config)) {
-        psError(psErrorCodeLast(), false, "Unable to perform initial combination.");
-        psFree(stack);
-        return false;
-    }
-    ppStackMemDump("initial");
-    psLogMsg("ppStack", PS_LOG_INFO, "Stage 3: Make Initial Stack: %f sec", psTimerClear("PPSTACK_STEPS"));
-
-    // Done with stack inputs for now
-    for (int i = 0; i < options->num; i++) {
-        pmCellFreeData(options->cells->data[i]);
-    }
-    psFree(stack);
-
-    // Pixel rejection
-    psTrace("ppStack", 1, "Reject pixels....\n");
-    if (!ppStackReject(options, config)) {
-        psError(psErrorCodeLast(), false, "Unable to reject pixels.");
-        psFree(stack);
-        return false;
-    }
-    psLogMsg("ppStack", PS_LOG_INFO, "Stage 4: Pixel Rejection: %f sec", psTimerClear("PPSTACK_STEPS"));
-
-    // Check inputs
-    {
-        int numGood = stackSummary(options, "final combination");
-        if (numGood <= 0) {
-            options->quality = PPSTACK_ERR_REJECTED;
-            psErrorStackPrint(stderr, "Insufficient inputs survived rejection stage");
-            psErrorClear();
-            psWarning("Insufficient inputs survived rejection stage");
-            return true;
-        }
-    }
-
-    stack = ppStackThreadDataSetup(options, config, true);
-    if (!stack) {
-        psError(psErrorCodeLast(), false, "Unable to initialise stack threads.");
-        return false;
-    }
-
-    // Final combination
-    psTrace("ppStack", 2, "Final stack of convolved images....\n");
-    if (!ppStackCombineFinal(stack, options->convCovars, options, config, false, false, true)) {
-        psError(psErrorCodeLast(), false, "Unable to perform final combination.");
-        psFree(stack);
-        return false;
-    }
-    psLogMsg("ppStack", PS_LOG_INFO, "Stage 5: Final Stack: %f sec", psTimerClear("PPSTACK_STEPS"));
-    ppStackMemDump("final");
-
-    // Photometry
-    psTrace("ppStack", 1, "Photometering stacked image....\n");
-    if (!ppStackPhotometry(options, config)) {
-        psError(psErrorCodeLast(), false, "Unable to perform photometry.");
-        return false;
-    }
-    psLogMsg("ppStack", PS_LOG_INFO, "Stage 6: Photometry Analysis: %f sec", psTimerClear("PPSTACK_STEPS"));
-    ppStackMemDump("photometry");
-
-    // Update Header
-    if (!ppStackUpdateHeader(options, config)) {
-        psError(psErrorCodeLast(), false, "Unable to update header.");
-        psFree(stack);
-        return false;
-    }
-
-    // Clean up
-    psTrace("ppStack", 2, "Cleaning up after combination....\n");
-    if (!ppStackCleanup(stack, options, config)) {
-        psError(psErrorCodeLast(), false, "Unable to clean up.");
-        psFree(stack);
-        return false;
-    }
-    for (int i = 0; i < options->num; i++) {
-        pmCellFreeData(options->cells->data[i]);
-    }
-    psFree(stack);
-    psLogMsg("ppStack", PS_LOG_INFO, "Stage 7: Cleanup, WCS & JPEGS: %f sec", psTimerClear("PPSTACK_STEPS"));
-    ppStackMemDump("cleanup");
-
-#if 1
-    // Unconvolved stack --- it's cheap to calculate, compared to everything else!
-    // XXX unconvolved stack is currently using the convolved mask!  oops!
-    if (options->convolve) {
-        // Start threading
-        ppStackThreadData *stack = ppStackThreadDataSetup(options, config, false);
-        if (!stack) {
-            psError(psErrorCodeLast(), false, "Unable to initialise stack threads.");
-            return false;
-        }
-
-        // Prepare for combination
-        if (!ppStackCombinePrepare("PPSTACK.UNCONV", "PPSTACK.UNCONV.EXP", PPSTACK_FILES_UNCONV,
-                                   stack, options, config)) {
-            psError(psErrorCodeLast(), false, "Unable to prepare for combination.");
-            psFree(stack);
-            return false;
-        }
-
-        psTrace("ppStack", 2, "Stack of unconvolved images....\n");
-        if (!ppStackCombineFinal(stack, options->origCovars, options, config,
-                                 false, true, false)) {
-            psError(psErrorCodeLast(), false, "Unable to perform unconvolved combination.");
-            psFree(stack);
-            return false;
-        }
-        psLogMsg("ppStack", PS_LOG_INFO, "Stage 8: Unconvolved Stack: %f sec", psTimerClear("PPSTACK_STEPS"));
-        ppStackMemDump("unconv");
-
-	// XXX this chunk is identical to the file close / free operations in ppStackCleanup.c
-	// check on which files are active and when...
-        if (!ppStackFilesIterateUp(config)) {
-            psError(psErrorCodeLast(), false, "Unable to close files.");
-            psFree(stack);
-            return false;
-        }
-        ppStackFileActivation(config, PPSTACK_FILES_UNCONV, false);
-        options->outRO->data_exists = false;
-        options->outRO->parent->data_exists = false;
-        options->outRO->parent->parent->data_exists = false;
-        psFree(options->outRO);
-        options->outRO = NULL;
-        options->expRO->data_exists = false;
-        options->expRO->parent->data_exists = false;
-        options->expRO->parent->parent->data_exists = false;
-        psFree(options->expRO);
-        options->expRO = NULL;
-
-        for (int i = 0; i < options->num; i++) {
-            pmCellFreeData(options->cells->data[i]);
-        }
-        psFree(stack);
-    }
-    psFree(options->cells); options->cells = NULL;
-#endif
-
-    // Finish up
-    psTrace("ppStack", 1, "Finishing up....\n");
-    if (!ppStackFinish(options, config)) {
-        psError(psErrorCodeLast(), false, "Unable to finish up.");
-        return false;
-    }
-    ppStackMemDump("finish");
-
-    return true;
-}
Index: branches/eam_branches/ipp-20101205/ppStack/src/ppStackLoop.h
===================================================================
--- branches/eam_branches/ipp-20101205/ppStack/src/ppStackLoop.h	(revision 30013)
+++ branches/eam_branches/ipp-20101205/ppStack/src/ppStackLoop.h	(revision 30015)
@@ -1,12 +1,4 @@
 #ifndef PPSTACK_LOOP_H
 #define PPSTACK_LOOP_H
-
-#include <pslib.h>
-#include <psmodules.h>
-
-#include "ppStackOptions.h"
-#include "ppStackThread.h"
-#include "ppStack.h"
-
 
 // Loop over the inputs, doing the combination
@@ -71,9 +63,12 @@
 
 // Cleanup following combination
-bool ppStackCleanup(
+bool ppStackCleanupFiles(
     ppStackThreadData *stack,           // Stack
     ppStackOptions *options,            // Options
-    pmConfig *config                    // Configuration
-    );
+    pmConfig *config,			// Configuration
+    ppStackFileList stackFiles,         // cleanup these stack files
+    ppStackFileList photFiles,          // cleanup these phot files (PHOT or NOP)
+    bool closeJPEGs    			// close the jpeg files?
+);
 
 // Photometry
@@ -89,3 +84,8 @@
     );
 
+
+bool ppStackUpdateHeader(ppStackThreadData *stack, ppStackOptions *options);
+bool ppStackJPEGs(ppStackThreadData *stack, ppStackOptions *options, pmConfig *config);
+bool ppStackStats(ppStackThreadData *stack, ppStackOptions *options, pmConfig *config);
+
 #endif
Index: branches/eam_branches/ipp-20101205/ppStack/src/ppStackMatch.c
===================================================================
--- branches/eam_branches/ipp-20101205/ppStack/src/ppStackMatch.c	(revision 30013)
+++ branches/eam_branches/ipp-20101205/ppStack/src/ppStackMatch.c	(revision 30015)
@@ -1,11 +1,2 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <pslib.h>
-#include <psmodules.h>
-#include <psphot.h>
-
 #include "ppStack.h"
 
Index: branches/eam_branches/ipp-20101205/ppStack/src/ppStackOptions.c
===================================================================
--- branches/eam_branches/ipp-20101205/ppStack/src/ppStackOptions.c	(revision 30013)
+++ branches/eam_branches/ipp-20101205/ppStack/src/ppStackOptions.c	(revision 30015)
@@ -1,8 +1,3 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <pslib.h>
-#include "ppStackLoop.h"
+#include "ppStack.h"
 
 static void stackOptionsFree(ppStackOptions *options)
Index: branches/eam_branches/ipp-20101205/ppStack/src/ppStackOptions.h
===================================================================
--- branches/eam_branches/ipp-20101205/ppStack/src/ppStackOptions.h	(revision 30013)
+++ branches/eam_branches/ipp-20101205/ppStack/src/ppStackOptions.h	(revision 30015)
@@ -1,7 +1,4 @@
 #ifndef PPSTACK_OPTIONS_H
 #define PPSTACK_OPTIONS_H
-
-#include <pslib.h>
-#include <psmodules.h>
 
 /// Options for stacking process
Index: branches/eam_branches/ipp-20101205/ppStack/src/ppStackPSF.c
===================================================================
--- branches/eam_branches/ipp-20101205/ppStack/src/ppStackPSF.c	(revision 30013)
+++ branches/eam_branches/ipp-20101205/ppStack/src/ppStackPSF.c	(revision 30015)
@@ -1,10 +1,2 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <pslib.h>
-#include <psmodules.h>
-
 #include "ppStack.h"
 
Index: branches/eam_branches/ipp-20101205/ppStack/src/ppStackPhotometry.c
===================================================================
--- branches/eam_branches/ipp-20101205/ppStack/src/ppStackPhotometry.c	(revision 30013)
+++ branches/eam_branches/ipp-20101205/ppStack/src/ppStackPhotometry.c	(revision 30015)
@@ -1,13 +1,3 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <pslib.h>
-#include <psmodules.h>
-#include <psphot.h>
-
 #include "ppStack.h"
-#include "ppStackLoop.h"
 
 bool ppStackPhotometry(ppStackOptions *options, pmConfig *config)
Index: branches/eam_branches/ipp-20101205/ppStack/src/ppStackPrepare.c
===================================================================
--- branches/eam_branches/ipp-20101205/ppStack/src/ppStackPrepare.c	(revision 30013)
+++ branches/eam_branches/ipp-20101205/ppStack/src/ppStackPrepare.c	(revision 30015)
@@ -1,12 +1,3 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <pslib.h>
-#include <psmodules.h>
-
 #include "ppStack.h"
-#include "ppStackLoop.h"
 
 #define PHOT_SOURCE_MASK (PM_SOURCE_MODE_FAIL | PM_SOURCE_MODE_SATSTAR | PM_SOURCE_MODE_BLEND | \
Index: branches/eam_branches/ipp-20101205/ppStack/src/ppStackReadout.c
===================================================================
--- branches/eam_branches/ipp-20101205/ppStack/src/ppStackReadout.c	(revision 30013)
+++ branches/eam_branches/ipp-20101205/ppStack/src/ppStackReadout.c	(revision 30015)
@@ -1,12 +1,2 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <pslib.h>
-#include <psmodules.h>
-#include <psphot.h>
-
-#include "ppStackThread.h"
 #include "ppStack.h"
 
Index: branches/eam_branches/ipp-20101205/ppStack/src/ppStackReject.c
===================================================================
--- branches/eam_branches/ipp-20101205/ppStack/src/ppStackReject.c	(revision 30013)
+++ branches/eam_branches/ipp-20101205/ppStack/src/ppStackReject.c	(revision 30015)
@@ -1,12 +1,3 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <pslib.h>
-#include <psmodules.h>
-
 #include "ppStack.h"
-#include "ppStackLoop.h"
 
 // #define TESTING
Index: branches/eam_branches/ipp-20101205/ppStack/src/ppStackSetup.c
===================================================================
--- branches/eam_branches/ipp-20101205/ppStack/src/ppStackSetup.c	(revision 30013)
+++ branches/eam_branches/ipp-20101205/ppStack/src/ppStackSetup.c	(revision 30015)
@@ -1,16 +1,5 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <libgen.h>
-#include <pslib.h>
-#include <psmodules.h>
-
 #include "ppStack.h"
-#include "ppStackLoop.h"
 
 #define BUFFER 16                       // Buffer for name array
-
 
 bool ppStackSetup(ppStackOptions *options, pmConfig *config)
Index: branches/eam_branches/ipp-20101205/ppStack/src/ppStackSources.c
===================================================================
--- branches/eam_branches/ipp-20101205/ppStack/src/ppStackSources.c	(revision 30013)
+++ branches/eam_branches/ipp-20101205/ppStack/src/ppStackSources.c	(revision 30015)
@@ -1,8 +1,2 @@
-#include <stdio.h>
-#include <math.h>
-#include <string.h>
-#include <pslib.h>
-#include <psmodules.h>
-
 #include "ppStack.h"
 
Index: branches/eam_branches/ipp-20101205/ppStack/src/ppStackStats.c
===================================================================
--- branches/eam_branches/ipp-20101205/ppStack/src/ppStackStats.c	(revision 30015)
+++ branches/eam_branches/ipp-20101205/ppStack/src/ppStackStats.c	(revision 30015)
@@ -0,0 +1,27 @@
+#include "ppStack.h"
+
+bool ppStackStats(ppStackThreadData *stack, ppStackOptions *options, pmConfig *config)
+{
+    psAssert(stack, "Require stack");
+    psAssert(options, "Require options");
+    psAssert(config, "Require configuration");
+
+    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSTACK_RECIPE); // ppStack recipe
+    psAssert(recipe, "We've thrown an error on this before.");
+
+    // Statistics on output
+    if (options->stats) {
+        psTrace("ppStack", 1, "Gathering statistics on stacked image....\n");
+        psString maskBadStr = psMetadataLookupStr(NULL, recipe, "MASK.BAD"); // Name of bits for bad
+        psImageMaskType maskBad = pmConfigMaskGet(maskBadStr, config); // Bits to mask for bad pixels
+
+        pmFPAview *view = pmFPAviewAlloc(0); // View to readout
+        view->chip = view->cell = view->readout = 0;
+
+        ppStatsFPA(options->stats, options->outRO->parent->parent->parent, view, maskBad, config);
+
+        psFree(view);
+    }
+
+    return true;
+}
Index: branches/eam_branches/ipp-20101205/ppStack/src/ppStackTarget.c
===================================================================
--- branches/eam_branches/ipp-20101205/ppStack/src/ppStackTarget.c	(revision 30013)
+++ branches/eam_branches/ipp-20101205/ppStack/src/ppStackTarget.c	(revision 30015)
@@ -1,6 +1,2 @@
-#include <stdio.h>
-#include <pslib.h>
-#include <psmodules.h>
-
 #include "ppStack.h"
 
Index: branches/eam_branches/ipp-20101205/ppStack/src/ppStackThread.c
===================================================================
--- branches/eam_branches/ipp-20101205/ppStack/src/ppStackThread.c	(revision 30013)
+++ branches/eam_branches/ipp-20101205/ppStack/src/ppStackThread.c	(revision 30015)
@@ -1,18 +1,5 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <unistd.h>
-#include <pslib.h>
-#include <psmodules.h>
-
 #include "ppStack.h"
-#include "ppStackOptions.h"
-#include "ppStackThread.h"
-
 
 #define THREAD_WAIT 10000               // Microseconds to wait if thread is not available
-
 
 static void stackThreadFree(ppStackThread *thread)
Index: branches/eam_branches/ipp-20101205/ppStack/src/ppStackThread.h
===================================================================
--- branches/eam_branches/ipp-20101205/ppStack/src/ppStackThread.h	(revision 30013)
+++ branches/eam_branches/ipp-20101205/ppStack/src/ppStackThread.h	(revision 30015)
@@ -1,9 +1,4 @@
 #ifndef PPSTACK_THREAD_H
 #define PPSTACK_THREAD_H
-
-#include <pslib.h>
-#include <psmodules.h>
-
-#include "ppStackOptions.h"
 
 // Thread for stacking chunks
Index: branches/eam_branches/ipp-20101205/ppStack/src/ppStackUpdateHeader.c
===================================================================
--- branches/eam_branches/ipp-20101205/ppStack/src/ppStackUpdateHeader.c	(revision 30013)
+++ branches/eam_branches/ipp-20101205/ppStack/src/ppStackUpdateHeader.c	(revision 30015)
@@ -1,16 +1,9 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <pslib.h>
-#include <psmodules.h>
-
 #include "ppStack.h"
-#include "ppStackLoop.h"
 
 #define WCS_TOLERANCE 0.001             // Tolerance for WCS
 
-bool ppStackUpdateHeader (ppStackOptions *optins, 
+bool ppStackUpdateHeader(ppStackThreadData *stack, ppStackOptions *options) {
+
+    pmReadout *outRO = options->outRO;                                      // Output readout
 
     // Propagate WCS
@@ -61,2 +54,5 @@
     }
     ppStackVersionHeader(hdu->header);
+    
+    return true;
+}
Index: branches/eam_branches/ipp-20101205/ppStack/src/ppStackVersion.c
===================================================================
--- branches/eam_branches/ipp-20101205/ppStack/src/ppStackVersion.c	(revision 30013)
+++ branches/eam_branches/ipp-20101205/ppStack/src/ppStackVersion.c	(revision 30015)
@@ -1,12 +1,2 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <pslib.h>
-#include <psmodules.h>
-#include <ppStats.h>
-#include <psphot.h>
-
 #include "ppStack.h"
 #include "ppStackVersionDefinitions.h"
