Index: /branches/eam_branches/ipp-20130307/ippScripts/scripts/camera_exp.pl
===================================================================
--- /branches/eam_branches/ipp-20130307/ippScripts/scripts/camera_exp.pl	(revision 35411)
+++ /branches/eam_branches/ipp-20130307/ippScripts/scripts/camera_exp.pl	(revision 35412)
@@ -363,5 +363,7 @@
     }
     # Construct FPA continuity corrected background images
-    {
+    if ($camera =~ /ISP/) {
+	print "Skipping FPA continuity corrected background images for ISP\n";
+    } else {
 	my $command;
 	$command = "$ppImage";
Index: /branches/eam_branches/ipp-20130307/ippScripts/scripts/relgroup_exp_list.pl
===================================================================
--- /branches/eam_branches/ipp-20130307/ippScripts/scripts/relgroup_exp_list.pl	(revision 35411)
+++ /branches/eam_branches/ipp-20130307/ippScripts/scripts/relgroup_exp_list.pl	(revision 35412)
@@ -16,10 +16,11 @@
 
 
-my ($group_id, $group_type, $lap_id, $release_name, $rebuild, $dbname, $no_update, $verbose);
+my ($group_id, $group_type, $lap_id, $group_name, $release_name, $rebuild, $dbname, $no_update, $verbose);
 
 GetOptions(
     'group_id=s'    =>      \$group_id,
+    'group_type=s'  =>      \$group_type,
     'lap_id=s'      =>      \$lap_id,
-    'group_type=s'  =>      \$group_type,
+    'group_name=s'  =>      \$group_name,
     'release_name=s' =>     \$release_name,
     'rebuild'       =>      \$rebuild,      # rebuild directory if it exists
@@ -36,4 +37,9 @@
            -exitval => 3) 
         unless $lap_id;
+    $group_name = "lap_$lap_id";
+} else {
+    pod2usage( -msg => "--group_name is required with --group_type $group_type",
+           -exitval => 3) 
+        unless $group_name;
 }
 
@@ -48,52 +54,26 @@
 
 # XXX: get this from site.config
-my $outputBase = "/data/ippc17.0/www/ipp-misc/ps1-data/single-frame/$release_name";
-
-my $outdir;
-if ($group_type eq 'lap') {
-    $outdir = "$outputBase/lap_$lap_id";
-    if (-e $outdir) {
-        if ($rebuild) {
-            my $rc = system "rm -rf $outdir";
-            if ($rc) {
-                my $status = $rc >> 8;
-                my_die("failed to remove existing directory $outdir: $rc $status", $group_id, $PS_EXIT_UNKNOWN_ERROR);
-            }
-        } else {
-            my_die("directory $outdir already exists and --rebuild not supplied", $group_id, $PS_EXIT_UNKNOWN_ERROR);
-        }
-    }
-} else {
-    my_die("Not ready to do group_type $group_type\n", $group_id, $PS_EXIT_UNKNOWN_ERROR);
+my $exposureListRoot = "/data/ippc17.0/www/ipp-misc/ps1-data/single-frame";
+
+my $outputBase = "$exposureListRoot/$release_name";
+
+if (!-e $outputBase) {
+    mkdir $outputBase or &my_die("Failed to create $outputBase", $group_id, $PS_EXIT_SYS_ERROR);
+}
+
+my $outdir = "$outputBase/$group_name";
+if (-e $outdir) {
+    if ($rebuild) {
+        my $rc = system "rm -rf $outdir";
+        if ($rc) {
+            my $status = $rc >> 8;
+            my_die("failed to remove existing directory $outdir: $rc $status", $group_id, $PS_EXIT_UNKNOWN_ERROR);
+        }
+    } else {
+        my_die("directory $outdir already exists and --rebuild not supplied", $group_id, $PS_EXIT_UNKNOWN_ERROR);
+    }
 }
 
 mkdir $outdir or my_die ("failed to create $outdir", $group_id, $PS_EXIT_UNKNOWN_ERROR);
-
-if (0) {
-    # XXX: old code from prototype for nightly lists
-        my $outroot;
-        my $oh;
-        my ($year, $month, $day);
-        if ($outroot) {
-        die "usage: $0 <year> <month> <day>\n" unless $year and $month and $day;
-            my $monthdir = sprintf "$outroot/%4d/%02d", $year, $month;
-            if (! -e $monthdir) {
-                die "can't find directory for $year-$month\n";
-            }
-            my $daydir = sprintf "$monthdir/%02d", $day;
-            if (! -e $daydir) {
-                mkdir $daydir or die "failed to create $daydir\n";
-            }
-            my $outfile = sprintf "$daydir/index.html", $day;
-            open $oh, ">$outfile" or die "failed to open $outfile";
-        } else {
-            $oh = *STDOUT;
-        }
-
-        my $ticks = timegm(0, 0, 0, $day, $month - 1, $year - 1900);
-
-        my $mjd = 40587 + ($ticks / 86400.);
-        my $date = sprintf "%04d-%02d-%02d", $year, $month, $day;
-}
 
 my $oh;
@@ -105,5 +85,10 @@
 open $oh2, ">$outfile2" or my_die("failed to open $outfile2", $group_id, $PS_EXIT_UNKNOWN_ERROR);
 
-my $title = "PS1 Exposure List for $release_name LAP run $lap_id";
+my $title = "PS1 Exposure List for";
+if ($group_type eq 'lap') {
+    $title .= " $release_name LAP run $lap_id";
+} else {
+    $title .= " $group_name";
+}
 
 my $head = "
@@ -125,5 +110,5 @@
 
 
-# find all exposures on given day that have a chip run
+# find all exposures in this relGroup
 my $query = "
 SELECT 
@@ -149,5 +134,5 @@
 $stmt->execute() or my_die("failed to execute query: $stmt->errstr\n", $group_id, $PS_EXIT_UNKNOWN_ERROR);
 
-printf STDERR "%4d exposures in group for LAP run $lap_id\n", $stmt->rows;
+printf STDERR "%4d exposures in group for $group_name\n", $stmt->rows;
 
 # $stmt->dump_results(1000);
Index: /branches/eam_branches/ipp-20130307/ippTools/share/Makefile.am
===================================================================
--- /branches/eam_branches/ipp-20130307/ippTools/share/Makefile.am	(revision 35411)
+++ /branches/eam_branches/ipp-20130307/ippTools/share/Makefile.am	(revision 35412)
@@ -473,4 +473,5 @@
 	releasetool_definerelstack.sql \
 	releasetool_definerelstack_with_skycal.sql \
+	releasetool_listrelstack.sql \
 	releasetool_definerelgroup_select_lap.sql \
 	releasetool_definerelgroup_select_data_group.sql \
Index: /branches/eam_branches/ipp-20130307/ippTools/share/pstamptool_completedreq.sql
===================================================================
--- /branches/eam_branches/ipp-20130307/ippTools/share/pstamptool_completedreq.sql	(revision 35411)
+++ /branches/eam_branches/ipp-20130307/ippTools/share/pstamptool_completedreq.sql	(revision 35412)
@@ -8,4 +8,5 @@
     	SELECT count(*) FROM pstampJob 
 	WHERE pstampJob.req_id = pstampRequest.req_id
-		AND pstampJob.state != 'stop'
+		AND pstampJob.state != 'stop' 
+                AND pstampJob.state != 'cancel'
 	) = 0
Index: /branches/eam_branches/ipp-20130307/ippTools/share/pstamptool_getdependent.sql
===================================================================
--- /branches/eam_branches/ipp-20130307/ippTools/share/pstamptool_getdependent.sql	(revision 35411)
+++ /branches/eam_branches/ipp-20130307/ippTools/share/pstamptool_getdependent.sql	(revision 35412)
@@ -1,3 +1,3 @@
 SELECT DISTINCT pstampDependent.*
 FROM pstampDependent
-WHERE pstampDependent.state = 'new'
+WHERE (pstampDependent.state = 'new' OR pstampDependent.state = 'hold')
Index: /branches/eam_branches/ipp-20130307/ippTools/share/releasetool_listrelexp.sql
===================================================================
--- /branches/eam_branches/ipp-20130307/ippTools/share/releasetool_listrelexp.sql	(revision 35411)
+++ /branches/eam_branches/ipp-20130307/ippTools/share/releasetool_listrelexp.sql	(revision 35412)
@@ -25,4 +25,5 @@
     warpRun.warp_id,
     warpRun.state as warp_state,
+    warpRun.tess_id,
     rawExp.filter,
     rawExp.dateobs,
Index: /branches/eam_branches/ipp-20130307/ippTools/share/releasetool_listrelstack.sql
===================================================================
--- /branches/eam_branches/ipp-20130307/ippTools/share/releasetool_listrelstack.sql	(revision 35412)
+++ /branches/eam_branches/ipp-20130307/ippTools/share/releasetool_listrelstack.sql	(revision 35412)
@@ -0,0 +1,18 @@
+SELECT
+    release_name,
+    surveyName,
+    relStack.*,
+    stackSumSkyfile.path_base AS stack_path_base,
+    stackSumSkyfile.quality,
+    stackRun.state AS stack_state,
+    stackRun.data_group AS stack_data_group,
+    skycalResult.path_base AS skycal_path_base,
+    skycalRun.data_group AS skycal_data_group,
+    'GPC1' AS camera
+FROM relStack
+JOIN ippRelease USING(rel_id) 
+JOIN survey USING(surveyID)
+JOIN stackRun USING(stack_id, filter, tess_id, skycell_id)
+JOIN stackSumSkyfile USING(stack_id)
+LEFT JOIN skycalRun USING(skycal_id)
+LEFT JOIN skycalResult USING(skycal_id)
Index: /branches/eam_branches/ipp-20130307/ippTools/share/releasetool_pendingrelgroup.sql
===================================================================
--- /branches/eam_branches/ipp-20130307/ippTools/share/releasetool_pendingrelgroup.sql	(revision 35411)
+++ /branches/eam_branches/ipp-20130307/ippTools/share/releasetool_pendingrelgroup.sql	(revision 35412)
@@ -5,2 +5,3 @@
     JOIN ippRelease USING(rel_id)
 WHERE relGroup.state = 'new'
+    AND relGroup.fault = 0
Index: /branches/eam_branches/ipp-20130307/ippTools/src/pstamptool.c
===================================================================
--- /branches/eam_branches/ipp-20130307/ippTools/src/pstamptool.c	(revision 35411)
+++ /branches/eam_branches/ipp-20130307/ippTools/src/pstamptool.c	(revision 35412)
@@ -49,7 +49,4 @@
 static bool revertjobMode(pxConfig *config);
 
-# if (1)
-// these are unused functions -- since they are 'static', this raises an warning
-// XXX: They actually are used
 static bool addprojectMode(pxConfig *config);
 static bool projectMode(pxConfig *config);
@@ -63,5 +60,4 @@
 static bool listfileMode(pxConfig *config);
 static bool deletefileMode(pxConfig *config);
-# endif
 
 # define MODECASE(caseName, func) \
@@ -103,5 +99,4 @@
         MODECASE(PSTAMPTOOL_MODE_STOPDEPENDENTJOB, stopdependentjobMode);
         MODECASE(PSTAMPTOOL_MODE_REVERTJOB, revertjobMode);
-# if (1)
         MODECASE(PSTAMPTOOL_MODE_ADDPROJECT, addprojectMode);
         MODECASE(PSTAMPTOOL_MODE_MODPROJECT, modprojectMode);
@@ -115,5 +110,5 @@
         MODECASE(PSTAMPTOOL_MODE_LISTFILE, listfileMode);
         MODECASE(PSTAMPTOOL_MODE_DELETEFILE, deletefileMode);
-# endif
+
         default:
             psAbort("invalid option (this should not happen)");
@@ -624,4 +619,7 @@
     if (outdir) {
         psStringAppend(&query, ", outdir = '%s'", outdir);
+    }
+    if (username) {
+        psStringAppend(&query, ", username = '%s'", username);
     }
     if (clearfault) {
@@ -1236,4 +1234,5 @@
     PXOPT_LOOKUP_BOOL(need_magic, config->args, "-need_magic", false);
     PXOPT_LOOKUP_BOOL(no_create,  config->args, "-no_create", false);
+    PXOPT_LOOKUP_BOOL(hold,       config->args, "-hold", false);
 
     psMetadata *where = psMetadataAlloc();
@@ -1243,5 +1242,5 @@
     PXOPT_COPY_STR(config->args, where, "-component", "component", "==");
 
-    // start a transaction eraly so it will contain any row level locks
+    // start a transaction early so it will contain any row level locks
     if (!psDBTransaction(config->dbh)) {
         psError(PS_ERR_UNKNOWN, false, "database error");
@@ -1267,4 +1266,7 @@
         psError(PS_ERR_UNKNOWN, false, "database error");
         psFree(query);
+        if (!psDBRollback(config->dbh)) {
+            psError(PS_ERR_UNKNOWN, false, "database error");
+        }
         return false;
     }
@@ -1274,4 +1276,7 @@
     if (!output) {
         psError(PS_ERR_UNKNOWN, false, "database error");
+        if (!psDBRollback(config->dbh)) {
+            psError(PS_ERR_UNKNOWN, false, "database error");
+        }
         return false;
     }
@@ -1282,4 +1287,7 @@
             psError(PS_ERR_UNKNOWN, false, "database error");
             psFree(output);
+            if (!psDBRollback(config->dbh)) {
+                psError(PS_ERR_UNKNOWN, false, "database error");
+            }
             return false;
         }
@@ -1287,10 +1295,51 @@
         if (fault > 0) {
             fprintf(stderr, "existing dependent has fault %d\n", fault);
+            if (!psDBRollback(config->dbh)) {
+                psError(PS_ERR_UNKNOWN, false, "database error");
+            }
+            // return the fault to the client. This is used by the postage stamp parser
             exit (fault);
         }
+        bool commit = false;
+        // Check the state of the exisiting dependent. By query it is either
+        // new or hold
+        psString state = psMetadataLookupStr(NULL, dep, "state");
+        if (!hold && !strcmp(state, "hold")) {
+            // There is a dependent for this component but it's state is hold.
+            // This client needs one that will run.
+            // Update the state
+            psString updateQuery = NULL;
+            psStringAppend(&updateQuery, "UPDATE pstampDependent SET state = 'new' "
+                "\nWHERE stage = '%s' AND imagedb = '%s' AND stage_id = %"PRId64 " AND component = '%s'", 
+                    stage, imagedb, stage_id, component);
+
+            if (!p_psDBRunQuery(config->dbh, updateQuery)) {
+                psError(PS_ERR_UNKNOWN, false, "database error");
+                psFree(updateQuery);
+                if (!psDBRollback(config->dbh)) {
+                    psError(PS_ERR_UNKNOWN, false, "database error");
+                }
+                return false;
+            }
+            // set flag to commit this change
+            commit = true;
+            psFree(updateQuery);
+        }
+        // print the dep_id for the user
         printf("%" PRId64 "\n", dep_id);
         psFree(output);
-        if (!psDBRollback(config->dbh)) {
+        // now either commit the change or rollback the transaction which releases the lock
+        if (commit) {
+            if (!psDBCommit(config->dbh)) {
+                // rollback
+                if (!psDBRollback(config->dbh)) {
+                    psError(PS_ERR_UNKNOWN, false, "database error");
+                }
             psError(PS_ERR_UNKNOWN, false, "database error");
+            return false;
+            }
+        } else if (!psDBRollback(config->dbh)) {
+            psError(PS_ERR_UNKNOWN, false, "database error");
+            return false;
         }
         return true;
@@ -1310,5 +1359,5 @@
         config->dbh,
         0,              // dep_id
-        "new",          // state
+        hold ? "hold" : "new",          // state
         stage,
         stage_id,
Index: /branches/eam_branches/ipp-20130307/ippTools/src/pstamptoolConfig.c
===================================================================
--- /branches/eam_branches/ipp-20130307/ippTools/src/pstamptoolConfig.c	(revision 35411)
+++ /branches/eam_branches/ipp-20130307/ippTools/src/pstamptoolConfig.c	(revision 35412)
@@ -223,4 +223,5 @@
     psMetadataAddBool(getdependentArgs,PS_LIST_TAIL, "-need_magic", 0, "define need_magic", false);
     psMetadataAddStr(getdependentArgs, PS_LIST_TAIL, "-outdir", 0,    "define output directory for dependent (required)", NULL);
+    psMetadataAddBool(getdependentArgs,PS_LIST_TAIL, "-hold", 0, "if creating new dependent set it's state to hold", false);
     psMetadataAddBool(getdependentArgs,PS_LIST_TAIL, "-no_create", 0, "if no matching dependent do not create one", false);
 
Index: /branches/eam_branches/ipp-20130307/ippTools/src/releasetool.c
===================================================================
--- /branches/eam_branches/ipp-20130307/ippTools/src/releasetool.c	(revision 35411)
+++ /branches/eam_branches/ipp-20130307/ippTools/src/releasetool.c	(revision 35412)
@@ -832,4 +832,5 @@
     PXOPT_LOOKUP_BOOL(pretend, config->args, "-pretend", false);
     PXOPT_LOOKUP_BOOL(simple, config->args,  "-simple", false);
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
 
     // find the parameters of all the exposures that we want to add to the release
@@ -852,4 +853,10 @@
 
     psFree(where);
+
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
 
     if (!p_psDBRunQuery(config->dbh, query)) {
@@ -968,23 +975,24 @@
     psMetadata *where = psMetadataAlloc();
 
+    PXOPT_COPY_S64(config->args, where, "-relstack_id", "relStack.relstack_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-stack_id",    "relStack.stack_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-skycal_id",   "relStack.skycal_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-relstack_id", "relStack.relstack_id", "==");
     PXOPT_COPY_STR(config->args, where, "-release_name", "ippRelease.release_name", "LIKE");
     pxAddLabelSearchArgs(config, where, "-release_state","ippRelease.state", "==");
-    PXOPT_COPY_STR(config->args, where, "-state",       "relExp.state", "==");
-    PXOPT_COPY_STR(config->args, where, "-filter",      "rawExp.filter", "LIKE");
-    PXOPT_COPY_TIME(config->args, where, "-dateobs_begin","rawExp.dateobs", ">=");
-    PXOPT_COPY_TIME(config->args, where, "-dateobs_end", "rawExp.dateobs", "<=");
-    PXOPT_COPY_F32(config->args, where, "-fwhm_min",    "skycalResult.fwhm_major", ">=");
+    PXOPT_COPY_STR(config->args, where, "-state",       "relStack.state", "==");
+    PXOPT_COPY_STR(config->args, where, "-filter",      "relStack.filter", "LIKE");
+    PXOPT_COPY_F32(config->args, where, "-mjd_min",    "stackSumSkyfile.mjd_obs", ">=");
+    PXOPT_COPY_F32(config->args, where, "-mjd_max",    "stackSumSkyfile.mjd_obs", "<=");
+    PXOPT_COPY_F32(config->args, where, "-fwhm_min",    "skycalResult.fwhm_minor", ">=");
     PXOPT_COPY_F32(config->args, where, "-fwhm_max",    "skycalresult.fwhm_major", "<=");
-    PXOPT_COPY_STR(config->args, where, "-exp_name",    "rawExp.exp_ame", "==");
-    PXOPT_COPY_S64(config->args, where, "-exp_id",      "relExp.exp_id", "==");
-    PXOPT_COPY_S64(config->args, where, "-chip_id",     "relExp.chip_id", "==");
-    PXOPT_COPY_S64(config->args, where, "-cam_id",      "relExp.cam_id", "==");
-    PXOPT_COPY_S64(config->args, where, "-warp_id",     "warpRun.warp_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-chip_data_group", "chipRun.data_group", "LIKE");
-    PXOPT_COPY_STR(config->args, where, "-cam_data_group",  "camRun.data_group", "LIKE");
-    PXOPT_COPY_STR(config->args, where, "-warp_data_group", "warpRun.data_group", "LIKE");
+    PXOPT_COPY_STR(config->args, where, "-tess_id",     "relStack.tess_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-skycell_id",  "relStack.skycell_id", "LIKE");
+    PXOPT_COPY_STR(config->args, where, "-stack_data_group",  "stackRun.data_group", "LIKE");
+    PXOPT_COPY_STR(config->args, where, "-skycal_data_group", "skycalRun.data_group", "LIKE");
 
     PXOPT_COPY_STR(config->args, where, "-surveyName",  "survey.surveyName", "LIKE");
     PXOPT_COPY_S32(config->args, where, "-rel_id",      "relExp.rel_id", "==");
+    pxskycellAddWhere(config, where);
 
     PXOPT_LOOKUP_BOOL(priority_order, config->args, "-priority_order", false);
@@ -993,13 +1001,7 @@
     PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
 
-    psString query = pxDataGet("releasetool_listrelexp.sql");
+    psString query = pxDataGet("releasetool_listrelstack.sql");
     if (!query) {
         psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    psString where2 = NULL;
-    if (!pxspaceAddWhere(config, &where2, "rawExp")) {
-        psError(psErrorCodeLast(), false, "pxspaceAddWhere failed");
         return false;
     }
@@ -1009,6 +1011,4 @@
         psStringAppend(&query, "\nWHERE %s", whereClause);
         psFree(whereClause);
-    } else if (where2) {
-        psStringAppend(&query, "\nWHERE ");
     } else {
         psError(PXTOOLS_ERR_CONFIG, false, "search parameters are required\n");
@@ -1017,11 +1017,6 @@
     }
 
-    if (where2) {
-        psStringAppend(&query, "\n%s", where2);
-        psFree(where2);
-    }
-
     if (priority_order) {
-        psStringAppend(&query, "\nAND priority > 0 order by exp_id, priority");
+        psStringAppend(&query, "\nAND priority > 0 order by stack_id, priority");
     }
 
@@ -1051,5 +1046,5 @@
     }
 
-    if (!ippdbPrintMetadatas(stdout, output, "relExp", !simple)) {
+    if (!ippdbPrintMetadatas(stdout, output, "relStack", !simple)) {
         psError(PS_ERR_UNKNOWN, false, "failed to print array");
         psFree(output);
@@ -1331,5 +1326,10 @@
     PS_ASSERT_PTR_NON_NULL(config, false);
 
-    PXOPT_LOOKUP_S32(group_id, config->args,      "-group_id", true, false);
+    PXOPT_LOOKUP_S32(group_id, config->args,      "-group_id", false, false);
+    PXOPT_LOOKUP_STR(group_name, config->args,    "-group_name",  false, false);
+    if (!group_id && !group_name) {
+        psError(PXTOOLS_ERR_CONFIG, true, "either group_id or group_name is required\n");
+        return false;
+    }
 
     PXOPT_LOOKUP_STR(state,    config->args,    "-set_state",  false, false);
@@ -1352,4 +1352,5 @@
 
     PXOPT_COPY_S64(config->args, where, "-group_id", "relGroup.group_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-group_name", "relGroup.group_name", "==");
     // XXX TODO if label is enabled (for changing label or state for a block) we should
     // disallow setting some parameters such as exp_list_path
Index: /branches/eam_branches/ipp-20130307/ippTools/src/releasetoolConfig.c
===================================================================
--- /branches/eam_branches/ipp-20130307/ippTools/src/releasetoolConfig.c	(revision 35411)
+++ /branches/eam_branches/ipp-20130307/ippTools/src/releasetoolConfig.c	(revision 35412)
@@ -195,9 +195,43 @@
     psMetadataAddF32(definerelstackArgs,  PS_LIST_TAIL, "-set_zpt_stdev", 0,  "define zero point stdev", NAN);
     psMetadataAddF32(definerelstackArgs,  PS_LIST_TAIL, "-set_fwhm_major", 0, "define fwhm_major", NAN);
-    psMetadataAddStr(definerelstackArgs,  PS_LIST_TAIL, "-set_path_base", 0,  "define state (required)", NULL);
+    psMetadataAddStr(definerelstackArgs,  PS_LIST_TAIL, "-set_path_base", 0,  "define state", NULL);
     psMetadataAddS16(definerelstackArgs,  PS_LIST_TAIL, "-set_fault", 0,      "define fault", 0);
 
-    psMetadataAddBool(definerelstackArgs, PS_LIST_TAIL, "-pretend",  0, "do not actually modify the database", false);
+    psMetadataAddBool(definerelstackArgs, PS_LIST_TAIL, "-pretend", 0, "do not actually modify the database", false);
     psMetadataAddBool(definerelstackArgs, PS_LIST_TAIL, "-simple",  0, "use the simple output format", false);
+    psMetadataAddU64(definerelstackArgs, PS_LIST_TAIL,  "-limit",   0, "limit result set to N items", 0);
+
+    // -listrelstack
+    psMetadata *listrelstackArgs = psMetadataAlloc();
+    psMetadataAddS64(listrelstackArgs, PS_LIST_TAIL,  "-relstack_id", 0,   "select by released exposure ID", 0);
+    psMetadataAddS64(listrelstackArgs, PS_LIST_TAIL,  "-stack_id", 0,   "select by stack ID", 0);
+    psMetadataAddS64(listrelstackArgs, PS_LIST_TAIL,  "-skycal_id", 0,   "select by skycal ID", 0);
+    psMetadataAddStr(listrelstackArgs,  PS_LIST_TAIL, "-release_name", 0, "select by release name (LIKE comparision)", NULL);
+    psMetadataAddStr(listrelstackArgs,  PS_LIST_TAIL, "-release_state", PS_META_DUPLICATE_OK, "select by release state", NULL);
+    psMetadataAddStr(listrelstackArgs,  PS_LIST_TAIL, "-state", 0,        "select by released stack state", NULL);
+
+    psMetadataAddStr(listrelstackArgs,  PS_LIST_TAIL, "-filter", 0,       "select by filter name (LIKE comparison)", NULL);
+    // psMetadataAddTime(listrelstackArgs, PS_LIST_TAIL, "-dateobs_begin", 0,"search for exposures by time (>=)", NULL);
+    // psMetadataAddTime(listrelstackArgs, PS_LIST_TAIL, "-dateobs_end", 0,  "search for exposures by time (<=)", NULL);
+
+    pxskycellAddArguments(listrelstackArgs);
+
+    psMetadataAddF32(listrelstackArgs,  PS_LIST_TAIL, "-fwhm_min", 0, "search by measured seeing (>=)", NAN);
+    psMetadataAddF32(listrelstackArgs,  PS_LIST_TAIL, "-fwhm_max", 0, "search by seeing (<=)", NAN);
+
+    psMetadataAddStr(listrelstackArgs,  PS_LIST_TAIL, "-tess_id", 0, "select by tess_id", NULL);
+    psMetadataAddStr(listrelstackArgs,  PS_LIST_TAIL, "-skycell_id", 0, "select by skycell_id (LIKE comparision)", NULL);
+
+    psMetadataAddStr(listrelstackArgs,  PS_LIST_TAIL, "-stack_data_group", 0, "select by stackRun.data_group (LIKE comparison)", NULL);
+    psMetadataAddStr(listrelstackArgs,  PS_LIST_TAIL, "-skycal_data_group", 0, "select by skycalRun.data_group (LIKE comparison)", NULL);
+
+    psMetadataAddStr(listrelstackArgs,  PS_LIST_TAIL, "-surveyName", 0, "select by survey name (LIKE comparision)", NULL);
+    psMetadataAddS64(listrelstackArgs,  PS_LIST_TAIL, "-rel_id", 0, "select by release ID", 0);
+
+    psMetadataAddBool(listrelstackArgs, PS_LIST_TAIL, "-priority_order",   0, "order by release priority", false);
+
+    psMetadataAddU64(listrelstackArgs,  PS_LIST_TAIL, "-limit",       0, "limit result set to N items", 0);
+    psMetadataAddBool(listrelstackArgs, PS_LIST_TAIL, "-simple",      0, "use the simple output format", false);
+
 
     // -definerelgroup
@@ -240,5 +274,6 @@
     psMetadata *updaterelgroupArgs = psMetadataAlloc();
 
-    psMetadataAddS32(updaterelgroupArgs,  PS_LIST_TAIL, "-group_id", 0,   "select by group ID (required)", 0);
+    psMetadataAddS32(updaterelgroupArgs,  PS_LIST_TAIL, "-group_id", 0,   "select by group ID",  0);
+    psMetadataAddStr(updaterelgroupArgs,  PS_LIST_TAIL, "-group_name", 0, "select by group name", 0);
 
         // parameters of the relGroup
@@ -272,4 +307,5 @@
 
     PXOPT_ADD_MODE("-definerelstack",     "define a released stack",    RELEASETOOL_MODE_DEFINERELSTACK,  definerelstackArgs);
+    PXOPT_ADD_MODE("-listrelstack",       "list released stacks",      RELEASETOOL_MODE_LISTRELSTACK,    listrelstackArgs);
 
     PXOPT_ADD_MODE("-definerelgroup",     "define a group of exposures", RELEASETOOL_MODE_DEFINERELGROUP,  definerelgroupArgs);
Index: /branches/eam_branches/ipp-20130307/psLib/src/math/Makefile.am
===================================================================
--- /branches/eam_branches/ipp-20130307/psLib/src/math/Makefile.am	(revision 35411)
+++ /branches/eam_branches/ipp-20130307/psLib/src/math/Makefile.am	(revision 35412)
@@ -16,4 +16,5 @@
 	psMinimizePowell.c \
 	psMinimizePolyFit.c \
+	psMixtureModels.c \
 	psPolynomial.c \
 	psPolynomialMetadata.c \
@@ -45,4 +46,5 @@
 	psMinimizePowell.h \
 	psMinimizePolyFit.h \
+	psMixtureModels.h \
 	psPolynomial.h \
 	psPolynomialMetadata.h \
Index: /branches/eam_branches/ipp-20130307/psLib/src/math/psMixtureModels.c
===================================================================
--- /branches/eam_branches/ipp-20130307/psLib/src/math/psMixtureModels.c	(revision 35412)
+++ /branches/eam_branches/ipp-20130307/psLib/src/math/psMixtureModels.c	(revision 35412)
@@ -0,0 +1,657 @@
+/** @file psMixtureModels.c
+ *
+ *  @brief Mixture Modeling/Clustering tools
+ *
+ *  Functions are provided to:
+ *      Determine N-dimensional K-means separation to data
+ *      Determine N-dimensional Gaussian mixture models to data
+ *      Provide 1-D simplifications of these methods
+ *  @author Chris Waters, IfA
+ *
+ *  version Based on CZW/brml/mixture_models.c v1.3
+ *  format/structure based on psMatrix.c
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+/******************************************************************************/
+/*  INCLUDE FILES                                                             */
+/******************************************************************************/
+#include <string.h>
+#include <gsl/gsl_matrix.h>
+#include <gsl/gsl_linalg.h>
+#include <gsl/gsl_blas.h>
+#include <gsl/gsl_permutation.h>
+#include <gsl/gsl_eigen.h>
+#include <gsl/gsl_cdf.h>
+
+#include "psAbort.h"
+#include "psMemory.h"
+#include "psError.h"
+#include "psImage.h"
+#include "psVector.h"
+#include "psMatrix.h"
+#include "psAssert.h"
+#include "psRandom.h"
+#include "psStats.h"
+#include "psTrace.h"
+
+#include "psMixtureModels.h"
+
+
+// #define TESTING
+/////////////////////////////////////////////////////////////////////////////////
+// Internal functions                                                          //
+/////////////////////////////////////////////////////////////////////////////////
+
+
+// Calculate Squared Euclidean Norm: ||A - B||^2
+// Because of the way psLib handles vectors/matrices, I never use this function in this implementation
+#if 0
+double psMMVectorNorm(const psVector *A,
+		      const psVector *B) {
+  // Need to add assertations here, including that we're dealing with F32s
+
+  // Math
+  long num = A->n;
+
+  // blas_dnrm2
+  double v = 0.0;
+  for (long i = 0; i < num; i++) {
+    v += A->data.F32[i] * B->data.F32[i];
+  }
+  return(v);
+}
+#endif
+
+// Calculate value of N-dimensional Gaussian of mean M and variance S at position X
+double psMMNDGaussian(const psVector *X,        //< Vector of length dim
+		      const psVector *m,        //< Vector of length dim
+		      const psImage  *S) {      //< Matrix of size dim x dim
+  // Assertions
+  // Are these all strictly necessary?
+  PS_ASSERT_VECTOR_NON_NULL(X,false);
+  PS_ASSERT_VECTOR_NON_NULL(m,false);
+  PS_ASSERT_VECTOR_TYPE(X,PS_TYPE_F32,false);
+  PS_ASSERT_VECTOR_TYPE(m,PS_TYPE_F32,false);
+  //  PS_ASSERT_VECTOR_SIZE_EQUAL(X,m,false);
+  PS_ASSERT_IMAGE_NON_NULL(S,false);
+  PS_ASSERT_IMAGE_TYPE(S,PS_TYPE_F32,false);
+  //  PS_ASSERT_IMAGE_SIZE(S,X->n,X->n,false);
+
+  // Initialize
+  long num = X->n;
+  float determinant;
+  psImage *invS = psMatrixInvert(NULL,S,&determinant);
+
+  // blas_dtrmv: S^-1 * (x-m)
+  psVector *SD = psVectorAlloc(num,PS_TYPE_F32);
+  for (int i = 0; i < num; i++) {
+    SD->data.F32[i] = 0;
+    for (int j = 0; j < num; j++) {
+      SD->data.F32[i] += invS->data.F32[i][j] * (X->data.F32[j] - m->data.F32[j]);
+    }
+  }
+
+  // blas_ddot: (x-m)^T * SD = (x-m)^T * S^-1 * (x-m)
+  double v = 0;
+  for (int i = 0; i < num; i++) {
+    v += SD->data.F32[i] * (X->data.F32[i] - m->data.F32[i]);
+  }
+
+  // G = (2 * pi)^(-0.5 * dim) * 1 /sqrt(det) * exp(-0.5 * v)
+  // Drop the 2pi term, as we only ever use this in ratios of constant dimension
+  double G = exp(-0.5 * v)/sqrt(determinant);
+
+  // Cleanup
+  psFree(SD);
+  psFree(invS);
+  return(G);
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////
+// External functions                                                          //
+/////////////////////////////////////////////////////////////////////////////////
+
+
+#define MAX_ITERATIONS 100
+#define THRESHOLD      1e-3
+
+
+bool psMMkmeans(psImage *D,
+		int dim,
+		long N,
+		psVector *modes,
+		psImage *means,
+		int m,
+		int *iterations,
+		double *V) {
+  // Assertions
+  PS_ASSERT_IMAGE_NON_NULL(D,false);
+  PS_ASSERT_IMAGE_TYPE(D,PS_TYPE_F32,false);
+  //  PS_ASSERT_IMAGE_SIZE(D,N,dim,false);
+
+  // Allocate things we can allocate here if they're not already allocated
+  if (!modes) {
+    modes = psVectorAlloc(m,PS_TYPE_F32);
+  }
+  if (!means) {
+    means = psImageAlloc(dim,m,PS_TYPE_F32);
+  }
+
+  PS_ASSERT_VECTOR_NON_NULL(modes,false);
+  PS_ASSERT_VECTOR_TYPE(modes,PS_TYPE_F32,false);
+  //  PS_ASSERT_VECTOR_SIZE(modes,m,false);
+
+  PS_ASSERT_IMAGE_NON_NULL(means,false);
+  PS_ASSERT_IMAGE_TYPE(means,PS_TYPE_F32,false);
+  //  PS_ASSERT_IMAGE_SIZE(means,m,dim,false);
+  
+  // Initialize
+  int error = 0;
+
+  int i,j,k;
+  psImage *oldMeans;
+  psVector *counts;
+  double R,diff;
+
+  // Allocations
+  oldMeans = psImageAlloc(dim,m,PS_TYPE_F32);
+  counts   = psVectorAlloc(m,PS_TYPE_F32);
+
+  // Initialize means to resonable starting points
+  psVector *minimums = psVectorAlloc(dim,PS_TYPE_F32);
+  psVector *maximums = psVectorAlloc(dim,PS_TYPE_F32);
+  psVector *temp = psVectorAlloc(N,PS_TYPE_F32);
+  psStats  *stats = psStatsAlloc(PS_STAT_MIN | PS_STAT_MAX);
+  for (j = 0; j < dim; j++) {
+    for (k = 0; k < N; k++) {
+      temp->data.F32[k] = D->data.F32[k][j];
+    }
+    psVectorStats(stats,temp,NULL,NULL,0);
+    minimums->data.F32[j] = stats->min;
+    maximums->data.F32[j] = stats->max;
+  }
+  psFree(temp);
+  psFree(stats);
+
+  if (m == 1) { // In the case of only one mode, set the mean to in the middle of the range
+    for (j = 0; j < dim; j++) {
+      means->data.F32[0][j] = (maximums->data.F32[j] + minimums->data.F32[j]) / 2;
+    }
+  }
+  else if (m == 2) { // For two modes, set one mode at each end point.
+    for (j = 0; j < dim; j++) { 
+      means->data.F32[0][j] = minimums->data.F32[j];
+      means->data.F32[1][j] = maximums->data.F32[j];
+    }
+  }
+  else { // Otherwise, just throw random points at it until we're done.
+    psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS);
+    for (i = 0; i < m; i++) {
+      for (j = 0; j < dim; j++) {
+	means->data.F32[i][j] = minimums->data.F32[j] +
+	  (psRandomUniform(rng) * (maximums->data.F32[j] - minimums->data.F32[j]));
+      }
+    }
+    psFree(rng);
+  }
+
+  psFree(minimums);
+  psFree(maximums);
+
+  // Clear assignments
+  for (k = 0; k < N; k++) {
+    modes->data.F32[k] = -1;
+  }
+  *iterations = 0;
+  do {
+    R = 0.0;
+
+    // Reset counts for each mode
+    for (i = 0; i < m; i++) {
+      counts->data.F32[i] = 0.0;
+    }
+    // Assign each datapoint to a mode
+    for (k = 0; k < N; k++) {
+      double d = 99e99;
+      double min_d = 99e99;
+      for (i = 0; i < m; i++) {
+	// Take the norm  of this point from the mode mean
+	d = 0;
+	for (j = 0; j < dim; j++) {
+	  d += PS_SQR(D->data.F32[k][j] - means->data.F32[i][j]);
+	}
+	if (d < min_d) {
+	  min_d = d;
+	  modes->data.F32[k] = i;
+	}
+      }
+      i = modes->data.F32[k];
+      counts->data.F32[i] += 1.0;
+    }
+
+    // Clear previous iteration mean values
+    for (i = 0; i < m; i++) {
+      for (j = 0; j < dim; j++) {
+	oldMeans->data.F32[i][j] = means->data.F32[i][j];
+	means->data.F32[i][j] = 0.0;
+      }
+    }
+
+    // Calculate new means
+    for (k = 0; k < N; k++) {
+      i = modes->data.F32[k];
+      for (j = 0; j < dim; j++) {
+	means->data.F32[i][j] += D->data.F32[k][j];
+      }
+    }
+
+    diff = 0.0;
+    for (i = 0; i < m; i++) {
+      for (j = 0; j < dim; j++) {
+	if (counts->data.F32[i] > 0.0) {
+	  means->data.F32[i][j] /= counts->data.F32[i];
+	}
+	else {
+	  means->data.F32[i][j] = 0.0;
+	}
+	diff += PS_SQR(means->data.F32[i][j] - oldMeans->data.F32[i][j]);
+      }
+    }
+
+    *iterations += 1;
+  } while ((*iterations < MAX_ITERATIONS)&&
+	   (diff > THRESHOLD));
+
+  *V = diff;
+
+  psFree(oldMeans);
+  psFree(counts);
+  
+  return(error); // Checked against stand alone code.  I believe these results. CZW 2013-04-10.
+}
+
+bool psMMGMM(psImage *D,
+	     int dim,
+	     long N,
+	     psVector *modes,
+	     psImage *means,
+	     psArray *sigma,
+	     psVector *pi,
+	     psImage *P,
+	     int m,
+	     int *iterations,
+	     double *V) {
+  // Assertions
+  PS_ASSERT_IMAGE_NON_NULL(D,false);
+  PS_ASSERT_IMAGE_TYPE(D,PS_TYPE_F32,false);
+  //  PS_ASSERT_IMAGE_SIZE(D,N,dim,false);
+
+  // GMM cannot initialize means from scratch, so require a guess
+  PS_ASSERT_IMAGE_NON_NULL(means,false);
+  PS_ASSERT_IMAGE_TYPE(means,PS_TYPE_F32,false);
+  //  PS_ASSERT_IMAGE_SIZE(means,m,dim,false);
+
+  // Allocate things we can allocate here if they're not already allocated
+  if (!modes) {
+    modes = psVectorAlloc(N,PS_TYPE_F32);
+  }
+  if (!pi) {
+    pi = psVectorAlloc(m,PS_TYPE_F32);
+  }
+  if (!P) {
+    P = psImageAlloc(m,N,PS_TYPE_F32);
+  }
+  
+  PS_ASSERT_VECTOR_NON_NULL(modes,false);
+  PS_ASSERT_VECTOR_TYPE(modes,PS_TYPE_F32,false);
+  //  PS_ASSERT_VECTOR_SIZE(modes,m,false);
+
+  PS_ASSERT_VECTOR_NON_NULL(pi,false);
+  PS_ASSERT_VECTOR_TYPE(pi,PS_TYPE_F32,false);
+  //  PS_ASSERT_VECTOR_SIZE(pi,m,false);
+
+  PS_ASSERT_IMAGE_NON_NULL(P,false);
+  PS_ASSERT_IMAGE_TYPE(P,PS_TYPE_F32,false);
+  //  PS_ASSERT_IMAGE_SIZE(P,N,m,false);
+
+  // Is this sufficient?  Should we check each mode's image?
+  PS_ASSERT_ARRAY_NON_NULL(sigma,false);
+
+  // Initialize 
+  int error = 0;
+
+  int i,j,k,jj;
+  double logL = -99e99;
+  double oldlogL = -99e99;
+  psVector *counts;
+  psVector *X = psVectorAlloc(dim,PS_TYPE_F32);
+  psVector *M = psVectorAlloc(dim,PS_TYPE_F32);
+
+  // Allocations
+  counts = psVectorAlloc(m,PS_TYPE_F32);
+
+  X      = psVectorAlloc(dim,PS_TYPE_F32);
+  M      = psVectorAlloc(dim,PS_TYPE_F32);
+  psVectorInit(counts,0.0);
+  psVectorInit(X,0.0);
+  psVectorInit(M,0.0);
+
+  // Do the first initialization.  We inherit means.
+  // Set pi
+  for (k = 0; k < N; k++) {
+    i = modes->data.F32[k];
+    counts->data.F32[i] += 1.0;
+  }
+  for (i = 0; i < m; i++) {
+    pi->data.F32[i] = counts->data.F32[i] / N;
+  }
+
+  // Set sigma
+  for (i = 0; i < m; i++) {
+    psImage *S = sigma->data[i];
+    psImageInit(S,0.0); // Clear old value
+    for (j = 0; j < dim; j++) {
+      S->data.F32[j][j] = 1.0; // Doesn't need to be a good guess
+    }
+  }
+
+  do {
+    oldlogL = logL;
+    logL = 0.0;
+    psImageInit(P,0.0); // Clear old probabilities
+
+    // Calculate P values
+    for (k = 0; k < N; k++) {
+      double norm_K = 0.0;
+
+      for (j = 0; j < dim; j++) { // VV
+	X->data.F32[j] = D->data.F32[k][j];
+      }
+      for (i = 0; i < m; i++) {
+	psImage *S = sigma->data[i];
+	for (j = 0; j < dim; j++) { // VV
+	  M->data.F32[j] = means->data.F32[i][j];
+	}
+	
+	P->data.F32[k][i] =
+	  pi->data.F32[i] * psMMNDGaussian(X,M,S);
+
+	logL += log(P->data.F32[k][i]);
+	norm_K += P->data.F32[k][i];
+      }
+      // Nomalize for each mode
+      for (i = 0; i < m; i++) {
+	if (norm_K != 0.0) {
+	  P->data.F32[k][i] /= norm_K;
+	}
+      }
+    }
+    
+    // Clear old M/S/pi
+    psVectorInit(pi,0.0);
+    psImageInit(means,0.0);
+    for (i = 0; i < m; i++) {
+      psImage *S = sigma->data[i];
+      psImageInit(S,0.0);
+    }
+
+    // Set means
+
+    psVectorInit(counts,0.0);
+    for (k = 0; k < N; k++) {
+
+      for (i = 0; i < m; i++) {
+	for (j = 0; j < dim; j++) {
+	  means->data.F32[i][j] += P->data.F32[k][i] * D->data.F32[k][j];
+	}
+	counts->data.F32[i] += P->data.F32[k][i];
+      }
+    }
+    double norm_N = 0;
+    for (i = 0; i < m; i++) {
+      for (j = 0; j < dim; j++) {
+	if (counts->data.F32[i] > 0.0) {
+	  means->data.F32[i][j] /= counts->data.F32[i];
+	}
+      }
+      norm_N += counts->data.F32[i];
+    }
+
+    // Set pi
+    for (i = 0; i < m; i++) {
+      pi->data.F32[i] = counts->data.F32[i] / N;
+    }
+
+    // Set covariance
+    for (i = 0; i < m; i++) {
+      psImage *S = sigma->data[i];
+
+      for (k = 0; k < N; k++) {
+	for (j = 0; j < dim; j++) {
+	  for (jj = 0; jj < dim; jj++) {
+	    // S = sum (weight^-1 * diff * diff^T)
+	    S->data.F32[j][jj] += 
+	      (P->data.F32[k][i]) *    // W^-1
+	      (D->data.F32[k][j]  - means->data.F32[i][j]) *  // diff
+	      (D->data.F32[k][jj] - means->data.F32[i][jj]);  // diff^T
+	  }
+	}
+      }
+      for (j = 0; j < dim; j++) {
+	for (jj = 0; jj < dim; jj++) {
+	  if (counts->data.F32[i] != 0.0) {
+	    S->data.F32[j][jj] /= counts->data.F32[i];
+	  }
+	}
+      }
+    }    
+  } while ((logL - oldlogL > 0)&&
+	   (*iterations < MAX_ITERATIONS));
+
+  psFree(counts);
+  psFree(X);
+  psFree(M);
+  *V = logL;
+  return(error);
+}
+
+// This is the expected public function, and as such, requires very little to be defined.
+bool psMMClass(psImage *D,
+	       int dim,
+	       long N,
+	       psVector *modes,
+	       psImage *means,
+	       psArray *sigma,
+	       psVector *pi,
+	       psImage *P,
+	       int m,
+	       double *Pval) {
+  // Assertions
+  PS_ASSERT_IMAGE_NON_NULL(D,false);
+  PS_ASSERT_IMAGE_TYPE(D,PS_TYPE_F32,false);
+  //  PS_ASSERT_IMAGE_SIZE(D,N,dim,false);
+  
+  // Is this sufficient?  Should we check each mode's image?
+  PS_ASSERT_ARRAY_NON_NULL(sigma,false);
+  
+  // Initialize
+  int iterations;
+  double V,V0;
+#ifdef TESTING
+  int i,j;
+#endif
+  if (!modes) {
+    modes = psVectorAlloc(N,PS_TYPE_F32);
+  }
+
+  // Do K-means/GMM iteration for m-1.
+  if (m > 1) { // Do a check of the smaller number of modes
+    if (!psMMkmeans(D,dim,N,modes,means,m-1,
+		    &iterations,&V)) {
+      // Error calculating k-means
+    }
+#ifdef TESTING
+    for (i = 0 ; i < m -1; i++) {
+      for (j = 0; j < dim; j++) {
+	fprintf(stderr,"KMEANS POST: (%d/%d) (%d/%d) %g\n",
+		i,m - 1,j,dim,means->data.F32[i][j]);
+      }
+    }
+#endif
+        
+    iterations = 0;
+    if (!psMMGMM(D,dim,N,modes,means,sigma,pi,P,
+		 m-1,&iterations,&V0)) {
+      // Error calculating GMM
+    }
+#ifdef TESTING
+    for (i = 0 ; i < m - 1; i++) {
+      for (j = 0; j < dim; j++) {
+	fprintf(stderr,"GMM POST: (%d/%d) (%d/%d) %g\n",
+		i,m - 1,j,dim,means->data.F32[i][j]);
+      }
+    }
+#endif
+  }
+  
+  // Do K-means/GMM iteration for m.
+  
+  iterations = 0;
+  
+  if (!psMMkmeans(D,dim,N,modes,means,m,
+		  &iterations,&V)) {
+    // Error calculating k-means
+  }
+#ifdef TESTING
+  for (i = 0 ; i < m; i++) {
+    for (j = 0; j < dim; j++) {
+      fprintf(stderr,"KMEANS POST: (%d/%d) (%d/%d) %g\n",
+	      i,m,j,dim,means->data.F32[i][j]);
+    }
+  }
+#endif
+  
+  iterations = 0;
+  if (!psMMGMM(D,dim,N,modes,means,sigma,pi,P,
+	       m,&iterations,&V)) {
+    // Error calculating GMM
+  }
+#ifdef TESTING
+  for (i = 0 ; i < m; i++) {
+    for (j = 0; j < dim; j++) {
+      fprintf(stderr,"GMM POST: (%d/%d) (%d/%d) %g\n",
+	      i,m,j,dim,means->data.F32[i][j]);
+    }
+  }
+#endif
+  
+  // Calculate utility of m modes over m-1 modes.
+  *Pval = gsl_cdf_chisq_Q(-2.0 * (V - V0), 3 * dim);
+  return(true);
+}
+
+bool psMM1Dkmeans(psVector *D,
+		  long N,
+		  psVector *modes,
+		  psVector *means,
+		  int m,
+		  int *iterations,
+		  double *V) {
+  int i,k;
+  psImage *DD = psImageAlloc(1,N,PS_TYPE_F32);
+  for (k = 0; k < N; k++) {
+    DD->data.F32[k][0] = D->data.F32[k];
+  }
+  psImage *MM = psImageAlloc(m,1,PS_TYPE_F32);
+  if (!psMMkmeans(DD,1,N,modes,MM,m,iterations,V)) {
+    // Error
+  }
+  psFree(DD);
+  for (i = 0; i < N; i++) {
+    means->data.F32[i] = MM->data.F32[i][0];
+  }
+  psFree(MM);
+  return(true);
+}
+
+bool psMM1DGMM(psVector *D,
+	       long N,
+	       psVector *modes,
+	       psVector *means,
+	       psVector *S,
+	       psVector *pi,
+	       psImage  *P,
+	       int m,
+	       int *iterations,
+	       double *V) {
+  int i,k;
+  psImage *DD = psImageAlloc(1,N,PS_TYPE_F32);
+  for (k = 0; k < N; k++) {
+    DD->data.F32[k][0] = D->data.F32[k];
+  }
+  psImage *MM = psImageAlloc(1,m,PS_TYPE_F32);
+  
+  psArray *sigma = psArrayAlloc(0);
+  for (k = 0; k < m; k++) {
+    psImage *Stmp = psImageAlloc(2,2,PS_TYPE_F32);
+    Stmp->data.F32[0][0] = S->data.F32[k];
+    psArrayAdd(sigma,0,S);
+  }
+  if (!psMMGMM(DD,1,N,modes,MM,sigma,pi,P,m,iterations,V)) {
+    // Error
+  }
+  psFree(DD);
+  for (i = 0; i < N; i++) {
+    means->data.F32[i] = MM->data.F32[i][0];
+  }
+  psFree(MM);
+  psFree(sigma);
+  return(true);
+}
+
+bool psMM1DClass(psVector *D,
+		 long N,
+		 psVector *modes,
+		 psVector *means,
+		 psVector *S,
+		 psVector *pi,
+		 psImage  *P,
+		 int m,
+		 double *Pval) {
+  int i,k;
+  psImage *DD = psImageAlloc(1,N,PS_TYPE_F32);
+  for (k = 0; k < N; k++) {
+    DD->data.F32[k][0] = D->data.F32[k];
+  }
+  psImage *MM = psImageAlloc(1,m,PS_TYPE_F32);
+  
+  psArray *sigma = psArrayAlloc(0);
+  for (i = 0; i < m; i++) {
+    psImage *Stmp = psImageAlloc(1,1,PS_TYPE_F32);
+    if (S->data.F32[i] != 0.0) {
+      Stmp->data.F32[0][0] = S->data.F32[i];
+    }
+    else {
+      Stmp->data.F32[0][0] = 1.0;
+    }
+    psArrayAdd(sigma,0,Stmp);
+  }
+  if (!psMMClass(DD,1,N,modes,MM,sigma,pi,P,m,Pval)) {
+    // Error
+  }
+  psFree(DD);
+  for (i = 0; i < m; i++) {
+    psImage *Stmp = sigma->data[i];
+    means->data.F32[i] = MM->data.F32[i][0];
+    S->data.F32[i]     = sqrt(Stmp->data.F32[0][0]); // GMM actually calculates the covariance, so take sqrt
+  }
+  psFree(MM);
+  psFree(sigma);
+  return(true);
+}
+
Index: /branches/eam_branches/ipp-20130307/psLib/src/math/psMixtureModels.h
===================================================================
--- /branches/eam_branches/ipp-20130307/psLib/src/math/psMixtureModels.h	(revision 35412)
+++ /branches/eam_branches/ipp-20130307/psLib/src/math/psMixtureModels.h	(revision 35412)
@@ -0,0 +1,67 @@
+#ifndef PS_MIXTUREMODELS_H
+#define PS_MIXTUREMODELS_H
+
+
+bool psMMkmeans(psImage *D,
+		int dim,
+		long N,
+		psVector *modes,
+		psImage *means,
+		int m,
+		int *iterations,
+		double *V);
+
+bool psMMGMM(psImage *D,
+	     int dim,
+	     long N,
+	     psVector *modes,
+	     psImage *means,
+	     psArray *sigma,
+	       psVector *pi,
+	     psImage *P,
+	     int m,
+	     int *iterations,
+	     double *V);
+
+bool psMMClass(psImage *D,
+	       int dim,
+	       long N,
+	       psVector *modes,
+	       psImage *means,
+	       psArray *sigma,
+	       psVector *pi,
+	       psImage *P,
+	       int m,
+	       double *Pval);
+  
+bool psMM1Dkmeans(psVector *D,
+		  long N,
+		  psVector *modes,
+		  psVector *means,
+		  int m,
+		  int *iterations,
+		  double *V);
+
+bool psMM1DGMM(psVector *D,
+	       long N,
+	       psVector *modes,
+	       psVector *means,
+	       psVector *S,
+	       psVector *pi,
+	       psImage  *P,
+	       int m,
+	       int *iterations,
+	       double *V);
+
+bool psMM1DClass(psVector *D,
+		 long N,
+		 psVector *modes,
+		 psVector *means,
+		 psVector *S,
+		 psVector *pi,
+		 psImage  *P,
+		 int m,
+		 double *Pval);
+    
+	
+#endif
Index: /branches/eam_branches/ipp-20130307/psLib/src/pslib_strict.h
===================================================================
--- /branches/eam_branches/ipp-20130307/psLib/src/pslib_strict.h	(revision 35411)
+++ /branches/eam_branches/ipp-20130307/psLib/src/pslib_strict.h	(revision 35412)
@@ -76,4 +76,5 @@
 #include "psMinimizePowell.h"
 #include "psMinimizePolyFit.h"
+#include "psMixtureModels.h"
 #include "psMutex.h"
 #include "psRandom.h"
Index: /branches/eam_branches/ipp-20130307/pstamp/scripts/psmkreq
===================================================================
--- /branches/eam_branches/ipp-20130307/pstamp/scripts/psmkreq	(revision 35411)
+++ /branches/eam_branches/ipp-20130307/pstamp/scripts/psmkreq	(revision 35412)
@@ -28,6 +28,10 @@
 my ($ra, $dec, $x, $y, $list, $output, $req_name, $req_name_base);
 
-my ($image, $mask, $variance, $cmf, $psf, $backmdl, $inverse);
-my ($unconvolved, $use_imfile_id, $no_wait);
+my ($image, $mask, $variance, $jpeg, $cmf, $psf, $backmdl, $inverse);
+my ($convolved, $unconvolved, $uncompressed, $use_imfile_id, $no_wait);
+
+# new header keywords for version 2
+my $action = 'PROCESS';
+my $email = 'null';
 
 my $default_size = 100;
@@ -52,4 +56,12 @@
 my $comment;
 
+# new request specification columns for version 2
+my $survey_name ='null';
+my $release_name = 'null';
+my $run_type ='null';
+my $fwhm_min = 0;
+my $fwhm_max = 0;
+
+
 my $missing_tools;
 my $pstamp_request_file  = can_run('pstamp_request_file')  or (warn "Can't find required program pstamp_request_file"  and $missing_tools = 1);
@@ -62,5 +74,5 @@
 GetOptions(
     'list=s'            => \$list,          # list of coordinates if undef ra and dec or x and y are required
-    'ra=s'              => \$ra,            # 
+    'ra=s'              => \$ra,
     'dec=s'             => \$dec,
     'x=s'               => \$x,
@@ -87,7 +99,14 @@
     'comment=s'         => \$comment,
 
+    'survey=s'          => \$survey_name,
+    'release=s'         => \$release_name,
+    'run_type=s'        => \$run_type,
+    'fwhm_min=s'        => \$fwhm_min,
+    'fwhm_max=s'        => \$fwhm_max,
+
     'option_mask=i'     => \$option_mask,
     'image'             => \$image,
     'mask'              => \$mask,
+    'jpeg'              => \$jpeg,
     'variance'          => \$variance,
     'cmf'               => \$cmf,
@@ -96,6 +115,11 @@
     'inverse'           => \$inverse,
     'unconvolved'       => \$unconvolved,
+    'convolved'         => \$convolved,
+    'uncompressed'      => \$uncompressed,
     'use_imfile_id'     => \$use_imfile_id,
     'do_not_wait'       => \$no_wait,
+
+    'action=s'          => \$action,
+    'email=s'           => \$email,
 
     'verbose'           => \$verbose,
@@ -156,4 +180,11 @@
 }
 
+if ($stage eq 'stack') {
+    # default is to do convolved stack
+    unless (defined $option_mask || $convolved) {
+        $unconvolved = 1;
+    }
+}
+
 checkFilter($filter, 'null', $filter)  if $filter;
 checkMJD($mjd_min, 0, "") if $mjd_min;
@@ -167,7 +198,9 @@
         $option_mask |= $PSTAMP_SELECT_MASK     if $mask;
         $option_mask |= $PSTAMP_SELECT_VARIANCE if $variance;
+        $option_mask |= $PSTAMP_SELECT_JPEG     if $jpeg;
+
+        # if no image was requested make a stamp of the image
         $option_mask = $PSTAMP_SELECT_IMAGE    if $option_mask == 0;
 
-        # if no image was requested make a stamp of the image
 
         $option_mask |= $PSTAMP_SELECT_CMF      if $cmf;
@@ -207,16 +240,18 @@
 } else {
     $rows = [];
-    push @$rows, buildRow("", $comment, $x, $y, $filter, $mjd_min, $mjd_max);
+    push @$rows, buildRow("", $comment, 1, $x, $y, $filter, $mjd_min, $mjd_max);
 }
 
 my ($tdf, $table_def_name) = tempfile ("/tmp/tabledef.XXXX", UNLINK => !$save_temps);
-print $tdf "$req_name 1\n";
+my $line = "$req_name 2 $action $email";
+print "$line\n" if $verbose;
+print $tdf "$line\n";
 my $rownum = 0;
 foreach my $row (@$rows) {
     $rownum++;
     my $line = "$rownum $row->{ra}\t$row->{dec}\t$width $height"
-        . " $coord_mask $job_type $option_mask $project $req_type"
+        . " $coord_mask $job_type $option_mask $project $survey_name $release_name $req_type"
         . " $stage $id $tess_id $component $data_group"
-        . " $row->{filter} $row->{mjd_min} $row->{mjd_max}";
+        . " $row->{filter} $row->{mjd_min} $row->{mjd_max} $run_type $fwhm_min $fwhm_max";
 
     if ($row->{comment} and $row->{comment} ne '') {
@@ -235,5 +270,5 @@
     $command .= " --output $output" if $output;
     my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
-        run(command => $command, verbose => 0);
+        run(command => $command, verbose => $verbose);
     unless ($success) {
         print STDERR @$stderr_buf;
@@ -274,9 +309,10 @@
 
     my $row = {};
-    $row->{ra}      = checkRA($vals[0], $linenumber);
-    $row->{dec}     = checkDEC($vals[1], $linenumber);
-    $row->{filter}  = checkFilter($vals[2], $filter, $linenumber);
-    $row->{mjd_min} = checkMJD($vals[3], $mjd_min, $linenumber);;
-    $row->{mjd_max} = checkMJD($vals[4], $mjd_max, $linenumber);;
+    $row->{rownum}  = checkRownum($vals[0], $linenumber);
+    $row->{ra}      = checkRA($vals[1], $linenumber);
+    $row->{dec}     = checkDEC($vals[2], $linenumber);
+    $row->{filter}  = checkFilter($vals[3], $filter, $linenumber);
+    $row->{mjd_min} = checkMJD($vals[4], $mjd_min, $linenumber);;
+    $row->{mjd_max} = checkMJD($vals[5], $mjd_max, $linenumber);;
     $row->{comment} = $comment;
 
@@ -305,5 +341,5 @@
     my $linenumber = shift;
 
-    my $result;
+   my $result;
     if ($c =~ /\:/) {
         # sexagesmial format not valid for pixel coordinates
@@ -329,4 +365,15 @@
 }
 
+sub checkRownum {
+    my $rownum = shift;
+    my $linenumber = shift;
+    die "rownum can not be null at $linenumber\n" unless defined $rownum;
+
+    # XXX: For now just check that rownum is defined and a single word
+    # extend this. Should we require a number?
+    my @words = split " ", $rownum;
+    die "$rownum is not a vaild rownum at $linenumber\n" unless (scalar @words) == 1;
+}
+
 sub checkRA {
     my $ra = shift;
@@ -335,4 +382,5 @@
 
     if ($ra =~ /\:/) {
+        # assume RA is in hours:minutes:seconds
         return $checked * 360. / 24.;
     } else {
Index: /branches/eam_branches/ipp-20130307/pstamp/scripts/psstatus
===================================================================
--- /branches/eam_branches/ipp-20130307/pstamp/scripts/psstatus	(revision 35411)
+++ /branches/eam_branches/ipp-20130307/pstamp/scripts/psstatus	(revision 35412)
@@ -68,4 +68,5 @@
     IFNULL(depcount, 0) AS 'Image updates'
     , timestamp AS 'last state change (UTC)'
+    , registered AS 'Submit time (UTC)'
 FROM (
     SELECT
@@ -77,8 +78,10 @@
         pstampRequest.fault,
         timestamp,
+        registered,
         IFNULL(priority,10000) AS priority
 FROM pstampRequest
 LEFT JOIN Label USING(label)
     WHERE pstampRequest.state = 'run' or pstampRequest.state ='new' 
+    	OR pstampRequest.state = 'parsed'
    --     OR pstampRequest.state = 'run.wait'
 ) as unfinishedReq
@@ -89,5 +92,6 @@
 FROM pstampRequest JOIN pstampJob USING(req_id)
     WHERE (pstampRequest.state = 'run' or pstampRequest.state = 'new' 
-        OR pstampRequest.state = 'run.wait')
+        OR pstampRequest.state = 'run.wait'
+        OR pstampRequest.state = 'parsed')
     GROUP BY req_id
 ) as rowCounts
@@ -101,4 +105,5 @@
     JOIN pstampDependent USING(dep_id) 
     WHERE (pstampRequest.state = 'run' or pstampRequest.state = 'new' 
+	    OR pstampRequest.state = 'parsed'
             OR pstampRequest.state = 'run.wait')
         AND dep_id > 0
@@ -178,5 +183,6 @@
     IFNULL(faulted,0) AS 'Faulted Jobs',
     IFNULL(depcount, 0) AS 'Image updates completed',
-    timestamp AS 'Completion Time (UTC)'
+    timestamp AS 'Completion Time (UTC)',
+    registered AS 'Submit Time (UTC)'
 FROM (
     SELECT
@@ -187,5 +193,6 @@
 --    pstampRequest.state,
 --    pstampRequest.fault,
-    timestamp
+    timestamp,
+    registered
 FROM pstampRequest
     WHERE pstampRequest.state = 'stop'
Index: /branches/eam_branches/ipp-20130307/pstamp/scripts/pstamp_cleanup.pl
===================================================================
--- /branches/eam_branches/ipp-20130307/pstamp/scripts/pstamp_cleanup.pl	(revision 35411)
+++ /branches/eam_branches/ipp-20130307/pstamp/scripts/pstamp_cleanup.pl	(revision 35412)
@@ -183,11 +183,19 @@
     }
 
-    my $command = "rm -r $dir";
+    # do an ls of the directory before starting
+#    print "directory listing for $dir\n";
+#    system "ls $dir";
+
+    my $command = "rm -rf $dir";
     unless ($no_update) {
         my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
             run(command => $command, verbose => $verbose);
         unless ($success) {
-            my $rc = $error_code >> 8;
-            my_die("Unable to perform $command return status: $rc", $req_id, $rc);
+            if (-e $dir) {
+                my $rc = $error_code >> 8;
+                my_die("Unable to perform $command return status: $rc", $req_id, $rc);
+            } else {
+                print STDERR "rm claimed to fail but directory no longer exists\n";
+            }
         }
     } else {
Index: /branches/eam_branches/ipp-20130307/pstamp/scripts/pstamp_finish.pl
===================================================================
--- /branches/eam_branches/ipp-20130307/pstamp/scripts/pstamp_finish.pl	(revision 35411)
+++ /branches/eam_branches/ipp-20130307/pstamp/scripts/pstamp_finish.pl	(revision 35412)
@@ -107,7 +107,5 @@
     my ($header, $rows) = read_request_file($req_file);
 
-    my $action = $header->{ACTION};
-
-    if (!$header or (($action eq 'PROCESS') and !$rows)) {
+    if (!$header or !$rows) {
         # Since a request got queued, the request file must have been readable at some point 
         my_die("failed to read request file $req_file", $req_id, $PS_EXIT_CONFIG_ERROR);
@@ -128,5 +126,5 @@
 
     my $request_fault = 0;
-    if ($action eq 'PROCESS') {
+    {
         # The results table definition file
         my ($tdf, $table_def_name) = tempfile ("$outdir/tabledef.XXXX", UNLINK => !$save_temps);
@@ -238,5 +236,5 @@
                 } else {
                     my_die("No reglist for successful job: $job_id", $req_id, $PS_EXIT_PROG_ERROR) 
-                        if $fault eq $PSTAMP_SUCCESS;
+                        if $job->{state} eq 'stop' and $fault eq $PSTAMP_SUCCESS;
                     print STDERR "no reglist file for job $job_id\n" if $verbose;
                     print $tdf "$rownum|$fault|$error_string|0|$job_id|";
@@ -273,8 +271,4 @@
             }
         }
-    } elsif ($action ne 'LIST') {
-        my_die("Unexpected action $action found", $req_id, $PS_EXIT_PROG_ERROR);
-    } else {
-        # pstampparse did all of the work
     }
 
Index: /branches/eam_branches/ipp-20130307/pstamp/scripts/pstamp_job_run.pl
===================================================================
--- /branches/eam_branches/ipp-20130307/pstamp/scripts/pstamp_job_run.pl	(revision 35411)
+++ /branches/eam_branches/ipp-20130307/pstamp/scripts/pstamp_job_run.pl	(revision 35412)
@@ -113,4 +113,5 @@
 
     if ($stage eq "raw") {
+        # zap options that don't apply to raw stage
         $options &= ~($PSTAMP_SELECT_MASK | $PSTAMP_SELECT_VARIANCE); 
     }
@@ -136,4 +137,22 @@
         $argString .= " -astrom $params->{astrom}";
         push @file_list, $params->{astrom};
+    }
+
+    if ($options & $PSTAMP_SELECT_SOURCES) {
+        # Extract sources from astrometry file if provided. This will be the smf for chip stage
+        # or the skycal cmf for stacks
+        if ($params->{astrom}) {
+            $argString .= " -write_cmf";
+            if ($stage eq 'stack') {
+                # Set psphot recipe to STACKPHOT so that the extended source paramters will
+                # be copied from the cmf file.
+                $argString .= " -recipe PSPHOT STACKPHOT"
+            }
+        } elsif ($params->{cmf}) {
+            $argString .= " -write_cmf";
+            push @file_list, $params->{cmf};
+        } else {
+            print "Could not find suitable sources file will not write cmf\n";
+        }
     }
 
@@ -254,7 +273,8 @@
                            $PSTAMP_SELECT_MASK     => "mk.fits",
                            $PSTAMP_SELECT_VARIANCE => "wt.fits",
+                           $PSTAMP_SELECT_SOURCES  => "cmf",
                            $PSTAMP_SELECT_JPEG     => "jpg");
 
-        my $output_mask = $options & ($PSTAMP_SELECT_IMAGE | $PSTAMP_SELECT_MASK | $PSTAMP_SELECT_VARIANCE | $PSTAMP_SELECT_JPEG);
+        my $output_mask = $options & ($PSTAMP_SELECT_IMAGE | $PSTAMP_SELECT_MASK | $PSTAMP_SELECT_VARIANCE | $PSTAMP_SELECT_JPEG | $PSTAMP_SELECT_SOURCES);
 
         foreach my $key (keys (%extensions)) {
@@ -400,8 +420,8 @@
         my $pattern_file = $params->{pattern} if ($options & $PSTAMP_SELECT_BACKMDL);
         my $cmf_file;
-        if ($stage ne 'chip') {
-            # we don't ship chip stage cmf files because they may not be censored
-            $cmf_file = $params->{cmf} if ($options & $PSTAMP_SELECT_CMF);
-        }
+#        if ($stage ne 'chip') {
+#            # we don't ship chip stage cmf files because they may not be censored
+#            $cmf_file = $params->{cmf} if ($options & $PSTAMP_SELECT_CMF);
+#        }
 
         my $outdir = dirname($output_base);
Index: /branches/eam_branches/ipp-20130307/pstamp/scripts/pstamp_parser_run.pl
===================================================================
--- /branches/eam_branches/ipp-20130307/pstamp/scripts/pstamp_parser_run.pl	(revision 35411)
+++ /branches/eam_branches/ipp-20130307/pstamp/scripts/pstamp_parser_run.pl	(revision 35412)
@@ -158,8 +158,12 @@
 my $request_fault = $PSTAMP_INVALID_REQUEST;
 
+# default action is to process the request after parsing. This can be overridden by
+# PREVIEW mode for pstamp requests
+my $action = 'PROCESS';
+
 if (-r $uri) {
     # run the appropriate parse command to parse the queue the jobs for this request
     # first check the extension header to find the EXTNAME
-    $request_type = find_request_type($uri);
+    $request_type = find_request_type($uri, \$action);
 
     if ($request_type) {
@@ -240,5 +244,13 @@
 
     if ($success) {
-        $newState = 'run';
+        # XXX: This bit of the postage stamp request API has slipped in here because we need to control
+        # the new state of the request
+        if ($action eq 'PROCESS') {
+            $newState = 'run';
+        } elsif ($action eq 'PREVIEW') {
+            $newState = 'parsed';
+        } else {
+            print STDERR "WARNING Ignoring unexpected value for ACTION found in request header: $action\n";
+        }
     } else {
         $fault = $error_code >> 8;
@@ -275,9 +287,15 @@
     # find the EXTNAME in the input fits table
     my $file_name = shift;
-    my $out = `echo $file_name | fields -x 0 EXTNAME`;
+    my $r_action = shift;
+
+    my $out = `echo $file_name | fields -x 0 EXTNAME ACTION`;
 
     if ($out) {
         # output from fields is filename value
-        my ($dummy, $extname) = split " ", $out;
+        my ($dummy, $extname, $action) = split " ", $out;
+
+        # Set the action if it is defined in the request header
+        # XXX:consider doing this only if extname is PS1_PS_REQUSET
+        $$r_action = $action if ($action);
 
         return $extname;
Index: /branches/eam_branches/ipp-20130307/pstamp/scripts/pstamp_request_file
===================================================================
--- /branches/eam_branches/ipp-20130307/pstamp/scripts/pstamp_request_file	(revision 35411)
+++ /branches/eam_branches/ipp-20130307/pstamp/scripts/pstamp_request_file	(revision 35412)
@@ -54,9 +54,9 @@
                     value => undef
         },
-        { name => 'USERNAME',
-                    writetype => TSTRING,
-                    comment => 'username for request (optional)',
-                    value => undef
-        },
+#        { name => 'USERNAME',
+#                    writetype => TSTRING,
+#                    comment => 'username for request (optional)',
+#                    value => undef
+#        },
         { name => 'EMAIL',
                     writetype => TSTRING,
@@ -97,5 +97,8 @@
         { name => 'MJD_MIN',    type => 'D',   writetype => TDOUBLE },
         { name => 'MJD_MAX',    type => 'D',   writetype => TDOUBLE },
+        # new in version 2
         { name => 'RUN_TYPE',   type => '16A', writetype => TSTRING },
+        { name => 'FWHM_MIN',   type => 'D',   writetype => TDOUBLE },
+        { name => 'FWHM_MAX',   type => 'D',   writetype => TDOUBLE },
 
         { name => 'COMMENT ',   type => '64A', writetype => TSTRING },
@@ -326,4 +329,6 @@
         pop @colData;
         pop @colData;
+        pop @colData;
+        pop @colData;
     }
 
@@ -346,5 +351,5 @@
         }
         # trim leading whitespace from comment
-        $comment =~ s/^\s+//;
+        $comment =~ s/^\s+// if $comment;
         if ($comment) {
             if ($comment =~ /#/) {
Index: /branches/eam_branches/ipp-20130307/pstamp/scripts/pstamp_webrequest.pl
===================================================================
--- /branches/eam_branches/ipp-20130307/pstamp/scripts/pstamp_webrequest.pl	(revision 35411)
+++ /branches/eam_branches/ipp-20130307/pstamp/scripts/pstamp_webrequest.pl	(revision 35412)
@@ -5,9 +5,4 @@
 #
 # The arguments are the command line parameters for the program psmkreq
-#
-# Unless the argument -list is provided the output is the request id for the resulting request
-#
-# If -list is the first argument, the request file is built and parsed and the
-# the selected "input" uris are listed on stdout.
 #
 # Note: Despite the name there nothing particularly web specific about this program.
@@ -23,12 +18,20 @@
 
 my $host = hostname();
-my $verbose = 1;
+my $verbose = 0;
 my $dbname;
 my $dbserver;
+my $pretend;
+my $label = 'WEB';
+my $req_name_prefix = 'web';
+my $username;
 
 GetOptions(
     'dbname=s'      =>  \$dbname,
     'dbserver=s'    =>  \$dbserver,
-    'verbose'       => \$verbose,
+    'label=s'       =>  \$label,
+    'username=s'    =>  \$username,
+    'prefix=s'      =>  \$req_name_prefix,
+    'pretend'       =>  \$pretend,
+    'verbose'       =>  \$verbose,
 );
 
@@ -36,6 +39,6 @@
 
 if ($verbose) {
-    print "\n\n";
-    print "Starting script $0 on $host\n\n";
+    print STDERR "\n\n";
+    print STDERR "Starting script $0 on $host\n\n";
 }
 
@@ -70,16 +73,19 @@
 # make a request file
 my $cur_dir = getcwd();
+
 #print STDERR "cur_dir is $cur_dir\n";
 
-my $datestr = strftime "%Y%m%d", gmtime;
+my $datestr = strftime "%Y/%m/%d", gmtime;
 my $datedir = "$cur_dir/webreq/$datestr";
 if (! -e $datedir ) {
-    if (!  mkdir $datedir ) {
-        print STDERR  "failed to create working directory $datedir";
+    my $rc = system "mkdir -p $datedir";
+    if ($rc) {
+        my $status = $rc >> 8;
+        print STDERR  "failed to create working directory $datedir: $rc $status";
         exit $PS_EXIT_CONFIG_ERROR;
     }
 }
 
-my $request_name = "web_" . get_webreq_num();
+my $request_name = $req_name_prefix . '_' . get_webreq_num();
 my $request_file = "$datedir/$request_name.fits";
 {
@@ -96,8 +102,9 @@
 # Queue the request
 my $req_id = 0;
-{
+unless ($pretend) {
 
     my $command = "$pstamptool -addreq -uri $request_file -ds_id 0";
-    $command .= " -label WEB";
+    $command .= " -label $label";
+    $command .= " -username $username" if $username;
     $command .= " -dbname $dbname" if $dbname;
     $command .= " -dbserver $dbserver" if $dbserver;
@@ -109,4 +116,5 @@
     }
     $req_id = ${$stdout_buf}[0];
+    chomp $req_id;
 }
 
Index: /branches/eam_branches/ipp-20130307/pstamp/scripts/pstampparse.pl
===================================================================
--- /branches/eam_branches/ipp-20130307/pstamp/scripts/pstampparse.pl	(revision 35411)
+++ /branches/eam_branches/ipp-20130307/pstamp/scripts/pstampparse.pl	(revision 35412)
@@ -27,5 +27,5 @@
 my $outdir;
 my $product;
-my $label;
+my $label = "";
 my $save_temps;
 my $no_update;
@@ -57,4 +57,8 @@
     die "outdir is required"  if !$outdir;
     die "product is required"  if !$product;
+} else {
+    $req_id = 0;
+    $outdir = "nowhere";
+    $product = "dummy";
 }
 
@@ -83,32 +87,46 @@
 $pstamptool .= " -dbserver $dbserver" if $dbserver;
 
-# list_job is a deugging mode
-$no_update = 1 if $mode eq "list_job";
+# If $mode is not queue_job we are using a debugging mode
+# do not update the database
+$no_update = 1 if $mode ne "queue_job";
 
 my $mdcParser = PS::IPP::Metadata::Config->new; # Parser for metadata config files
 
 #
-# get the data from the extension header
+# Read the keywords from the extension header
 #
 my $fields_output;
 {
-    my $command = "echo $request_file_name | $fields -x 0 EXTNAME EXTVER REQ_NAME ACTION USER EMAIL";
+    my $command = "echo $request_file_name | $fields -x 0 EXTNAME EXTVER REQ_NAME ACTION EMAIL";
     my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
         run(command => $command, verbose => $verbose);
-    # fields doesn't return zero when it succeeds
-    #unless ($success) {
-    #    print STDERR @$stderr_buf;
-    #}
+
+    # note fields doesn't return zero when it succeeds.
     $fields_output = join "", @$stdout_buf;
 }
-my (undef, $extname, $extver, $req_name, $action, $username, $email) = split " ", $fields_output;
+my (undef, $extname, $extver, $req_name, $action, $email) = split " ", $fields_output;
 
 # make sure the file contains what we are expecting
-# This program shouldn't have been run if the request file is bogus.
-# No need to notify the client
-my_die("$request_file_name is not a PS1_PS_REQEST", $PS_EXIT_PROG_ERROR) if $extname ne "PS1_PS_REQUEST";
-my_die("REQ_NAME not found in $request_file_name", $PS_EXIT_PROG_ERROR)  if (!$req_name);
-my_die("wrong EXTVER $extver found in $request_file_name", $PS_EXIT_PROG_ERROR) if ($extver ne "1" and $extver ne "2");
-
+# pstamp_parser_run.pl would not have run this program unless the request file was ok
+my_die("$request_file_name does not contain EXTNAME\n", $PS_EXIT_PROG_ERROR) if !$extname;
+my_die("$request_file_name is not a PS1_PS_REQUEST\n", $PS_EXIT_PROG_ERROR) if $extname ne "PS1_PS_REQUEST";
+my_die("REQ_NAME not found in $request_file_name\n", $PS_EXIT_PROG_ERROR)  if (!$req_name);
+my_die("wrong EXTVER $extver found in $request_file_name\n", $PS_EXIT_PROG_ERROR) if ($extver ne "1" and $extver ne "2");
+
+if ($extver >= 2) {
+    # We have a version 2 file. Require that the new keywords be supplied. 
+    my_die("action not supplied in version $extver request file $request_file_name\n", $PSTAMP_INVALID_REQUEST) unless defined $action;
+
+    my_die("invalid action: $action supplied in version $extver request file $request_file_name\n", $PSTAMP_INVALID_REQUEST) unless (uc($action) eq 'PROCESS' or uc($action) eq 'PREVIEW');
+
+    my_die("email not supplied in version $extver request file $request_file_name\n", $PSTAMP_INVALID_REQUEST) unless $email;
+    # XXX check for "valid" $email
+} else {
+    # for version 1 file the action is process and email is not used
+    $action = 'PROCESS';
+    $email = 'null';
+}
+
+print "Request Header Keywords EXTVER: $extver REQ_NAME: $req_name ACTION: $action EMAIL: $email\n";
 
 # check for duplicate request name
@@ -161,4 +179,5 @@
     # the output data store's product name
     my $command = "$pstamptool -updatereq -req_id $req_id  -set_name $req_name";
+    $command .= " -set_username $email" if $email ne 'null';
     $command .= " -set_outProduct $product";
     $command .= " -set_label $label" if $label_changed;
@@ -174,5 +193,5 @@
 
 #
-# now convert the request table to an array of metadata config docs
+# now convert the request table to an array of metadatas
 #
 
@@ -191,20 +210,30 @@
     my $dtime_request_file = gettimeofday() - $start_request_file;
     print "Time to read and parse request file: $dtime_request_file\n";
-
-}
-
-#
-# Loop over rows in the request file collecting consecutive rows that have the "same images of interest"
-# in the sense that their selection parameters will yield the same "Runs".
-# Process the groups of rows together to reduce lookup time and to potentially make multiple
-# stamps from the same ppstamp process.
-#
-my @rowList;
+}
+
+my $nRows = scalar @$rows;
+print "\n$nRows rows read from request file\n";
+
+
 my $num_jobs = 0;
 my $imageList;
 my $stage;
-my $need_magic;
 foreach my $row (@$rows) {
-    # santiy check the paramaters
+
+    if ($label eq 'WEB.UP' and ($nRows > 500 or $num_jobs > 500) and $req_id and !$no_update) {
+        # this is a big request and it came from the upload page and doesn't have a specific label assigned
+        # change it to the generic one that has lower with lower priority
+        $label = 'WEB.BIG';
+        print "\nChanging label for big WEB.UP request to $label\n";
+
+        my $command = "$pstamptool -updatereq -req_id $req_id  -set_label $label";
+        my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+            run(command => $command, verbose => $verbose);
+        unless ($success) {
+            my_die("$command failed", $PS_EXIT_UNKNOWN_ERROR);
+        }
+    }
+
+    # validate the paramaters
     if (!checkRow($row)) {
         # when it enconters an error checkRow adds a fake job with an appropriate error code to the database
@@ -216,27 +245,5 @@
     $row->{error_code} = 0;
 
-    if (scalar @rowList == 0) {
-        push @rowList, $row;
-        next;
-    }
-
-    my $firstRow = $rowList[0];
-    if (same_images_of_interest($firstRow, $row)) {
-        # add this row to the list and move on
-        push @rowList, $row;
-        next;
-    }
-
-    # the images of interest for this new row doesn't match the list. 
-    # process the list ...
-    $num_jobs += processRows($action, \@rowList);
-
-    # and reset the list to contain just the new row
-    @rowList = ($row);
-}
-
-# out of rows process the list
-if (scalar @rowList > 0) {
-    $num_jobs += processRows($action, \@rowList);
+    $num_jobs += processRow($action, $row);
 }
 
@@ -252,5 +259,7 @@
     my $row = shift;
 
+    # check validity of the paramters in a request specification
     # If we encounter an error for a particular row add a job with the proper fault code.
+    # also adjust some paramterers like filter and set defaults for some others
 
     my $stage = $row->{IMG_TYPE};
@@ -284,5 +293,4 @@
     }
 
-
     my $component = $row->{COMPONENT};
     if (!defined $component or (lc($component) eq "null") or (lc($component) eq "all")) {
@@ -314,4 +322,22 @@
         return 0;
     }
+
+    my $fwhm_min = $row->{FWHM_MIN};
+    if (!defined $fwhm_min) {
+        $row->{FWHM_MIN} = 0;
+    } elsif (!validNumber($fwhm_min)) {
+        print STDERR "$fwhm_min is not a valid FWHM_MIN\n";
+        insertFakeJobForRow($row, 1, $PSTAMP_INVALID_REQUEST);
+        return 0;
+    }
+    my $fwhm_max = $row->{FWHM_MAX};
+    if (!defined $fwhm_max) {
+        $row->{FWHM_MAX} = 0;
+    } elsif (!validNumber($fwhm_max)) {
+        print STDERR "$fwhm_max is not a valid FWHM_MAX\n";
+        insertFakeJobForRow($row, 1, $PSTAMP_INVALID_REQUEST);
+        return 0;
+    }
+
     my $data_group = $row->{DATA_GROUP};
     if (!defined $data_group) {
@@ -363,9 +389,4 @@
     }
 
-    # $mode list_uri is a debugging mode (it may used by the http interface)
-    # if this happens just croak
-   # my_die("job_type is list_uri but mode is $mode", $PS_EXIT_PROG_ERROR) if ($job_type eq "list_uri") and ($mode ne "list_uri");
-
-
     if ($req_type eq "bycoord") {
         if (!$skycenter) {
@@ -384,4 +405,5 @@
     }
 
+
     return 1;
 }
@@ -392,4 +414,65 @@
 
     $num_jobs = 1;
+    return $num_jobs;
+}
+
+sub processRow {
+    my $action  = shift;
+    my $row     = shift;
+
+    my $num_jobs = 0;
+
+    my $project  = $row->{PROJECT};
+
+    # note: resolve_project avoids running pstamptool every time by remembering the
+    # last project resolved
+    my $proj_hash = resolve_project($ipprc, $project, $dbname, $dbserver);
+    if (!$proj_hash) {
+        insertFakeJobForRow($row, 1, $PSTAMP_UNKNOWN_PROJECT);
+        $num_jobs++;
+        return $num_jobs;
+    }
+    my $image_db   = $proj_hash->{dbname};
+    my $camera     = $proj_hash->{camera};
+
+    my $req_type    = $row->{REQ_TYPE};
+    my $rownum      = $row->{ROWNUM};
+
+    # Since user can get unmagicked data "by coordinate" requests can go back in time
+    # to dredge unusable data from the "dark days"...
+    if ($req_type eq 'bycoord' and $row->{IMG_TYPE} ne 'stack' and $row->{MJD_MIN} == 0) {
+        # ... so unless the user sets mjd_min clamp it to 2009-04-01
+        # XXX: This value should live in the pstampProject table not be hardcoded here
+        $row->{MJD_MIN} = 54922;
+    }
+
+    if (($req_type eq 'byskycell') or ($req_type eq 'bycoord')) {
+        # avoid error from print below if $id isn't needed
+        $row->{ID} = "" if !$row->{ID};
+    }
+    
+    # Call PS::IPP::PStamp::Job locate_images subroutine to get the images for this
+    # request specification. An array reference is returned.
+    my $start_locate = gettimeofday();
+
+    print "\nCalling new_locate_images for row: $rownum\n";
+
+    $imageList = locate_images_for_row($ipprc, $image_db, $camera, $row, $verbose);
+
+    my $dtime_locate = gettimeofday() - $start_locate;
+    print "Time to locate_images for row $rownum $dtime_locate\n";
+
+    my @rowList = ($row);
+    $num_jobs += queueJobs($action, \@rowList, $imageList);
+
+    # if this row slipped through without a job being added add one. 
+    if ($row->{job_num} == 0) {
+        print "row $row->{ROWNUM} produced no jobs\n";
+        print STDERR "row $row->{ROWNUM} produced no jobs\n";
+        my $error_code = $row->{error_code};
+        $error_code =  $PSTAMP_NO_IMAGE_MATCH if !$error_code;
+        insertFakeJobForRow($row, ++$row->{job_num}, $error_code);
+    }
+
     return $num_jobs;
 }
@@ -401,4 +484,5 @@
 
     if ($action eq 'LIST') {
+        # LIST is not allowed by caller. Can't get here.
         return list_targets($rowList);
     }
@@ -420,5 +504,5 @@
     }
     my $req_type  = $row->{REQ_TYPE};
-    $stage        = $row->{IMG_TYPE};
+    my $stage     = $row->{IMG_TYPE};
     my $id        = $row->{ID};
     my $component = $row->{COMPONENT};
@@ -436,5 +520,5 @@
     my $image_db   = $proj_hash->{dbname};
     my $camera     = $proj_hash->{camera};
-    $need_magic    = $proj_hash->{need_magic};
+    my $need_magic    = $proj_hash->{need_magic};
     # Since user can get unmagicked data "by coordinate" requests can go back in time
     # to dredge unusable data from the "dark days"...
@@ -496,5 +580,5 @@
     # information required is contained there
 
-    $imageList = locate_images($ipprc, $image_db, \@rowList, $req_type, $stage, $id, $tess_id, $component,
+    $imageList = locate_images($ipprc, $image_db, $rowList, $req_type, $stage, $id, $tess_id, $component,
                 $option_mask, $need_magic, $mjd_min, $mjd_max, $filter, $data_group, $verbose);
 
@@ -506,8 +590,8 @@
     $row->{need_magic} = $need_magic;
 
-    $num_jobs += queueJobs($mode, \@rowList, $imageList);
+    $num_jobs += queueJobs($action, $rowList, $imageList);
 
     # if a row slipped through with no jobs add a faulted one
-    foreach my $row (@rowList) {
+    foreach my $row (@$rowList) {
         if ($row->{job_num} == 0) {
             print "row $row->{ROWNUM} produced no jobs\n";
@@ -528,5 +612,5 @@
     my $image = shift;
     my $need_magic = shift;
-    my $mode = shift;
+    my $action = shift;
 
     my $rownum = $row->{ROWNUM};
@@ -611,9 +695,9 @@
     write_params($output_base, $image);
 
-    my $newState = "run";
+    my $newState = $action eq 'PROCESS' ? "run" : "parsed";
     my $fault = 0;
     my $dep_id;
 
-    queueUpdatesIfNeeded($stage, $image, $option_mask, \$newState, \$fault, \$dep_id);
+    queueUpdatesIfNeeded($action, $stage, $image, $option_mask, \$newState, \$fault, \$dep_id);
 
     my $command = "$pstamptool -addjob  -req_id $req_id -job_type $row->{JOB_TYPE}"
@@ -644,9 +728,9 @@
 sub queueJobs
 {
-    my $mode = shift;
+    my $action = shift;
     my $rowList = shift;
     my $imageList = shift;
 
-    my $firstRow = $rowList[0];
+    my $firstRow = $rowList->[0];
     my $stage    = $firstRow->{IMG_TYPE};
     my $job_type = $firstRow->{JOB_TYPE};
@@ -656,6 +740,9 @@
 
     if ($mode eq "list_uri") {
+        $num_jobs = $imageList ? scalar @$imageList : 0;
+        print "List of $num_jobs Images selected for row: $firstRow->{ROWNUM}\n";
         foreach my $image (@$imageList) {
             print "$image->{image}\n";
+            ++$firstRow->{job_num};
         }
     } elsif ($job_type eq "get_image") {
@@ -664,5 +751,5 @@
         my_die( "error: unexpected number of rows for get_image request: $n", $PS_EXIT_PROG_ERROR) if $n != 1;
 
-        $num_jobs = queueGetImageJobs($firstRow, $imageList, $stage, $need_magic, $mode);
+        $num_jobs = queueGetImageJobs($firstRow, $imageList, $stage, $need_magic, $action);
 
     } else {
@@ -692,5 +779,5 @@
                 my $row = $rowList->[$i];
 
-                $num_jobs += queueJobForImage($row, $stage, $image, $need_magic, $mode);
+                $num_jobs += queueJobForImage($row, $stage, $image, $need_magic, $action);
             }
         }
@@ -706,5 +793,5 @@
     my $stage = shift;
     my $need_magic = shift;
-    my $mode = shift;
+    my $action = shift;
 
     my $num_jobs = 0;
@@ -753,9 +840,9 @@
         write_params($output_base, $image);
 
-        my $newState = "run";
+        my $newState = $action eq 'PROCESS' ? "run" : "parsed";
         my $fault = 0;
         my $dep_id;
 
-        queueUpdatesIfNeeded($stage, $image, $option_mask, \$newState, \$fault, \$dep_id);
+        queueUpdatesIfNeeded($action, $stage, $image, $option_mask, \$newState, \$fault, \$dep_id);
 
         $num_jobs++;
@@ -899,5 +986,5 @@
 sub get_dependent 
 {
-    my ($r_jobState, $r_fault, $r_dep_id, $imagedb, $state, $stage, $stage_id, $component, $need_magic) = @_;
+    my ($action, $r_jobState, $r_fault, $r_dep_id, $imagedb, $state, $stage, $stage_id, $component, $need_magic) = @_;
 
     # chipRun's can be in full state if destreaking is necessary
@@ -918,10 +1005,13 @@
     my $command = "$pstamptool -getdependent -stage $stage -stage_id $stage_id -imagedb $imagedb -component $component -outdir $outdir";
     $command .= " -need_magic" if $need_magic;
-
-    # compute rlabel for the run.
-    # XXX: This bit of policy shouldn't be buried so deeply in the code
-    # For now use one that implies 'postage stamp server' 'update' 'request_label"
-    my $rlabel = "ps_ud_" . $label if $label;
-    $command .= " -rlabel $rlabel" if $rlabel;
+    $command .= ' -hold' if $action eq 'PREVIEW';
+
+    if ($label) {
+        # compute rlabel for the run.
+        # XXX: This bit of policy shouldn't be buried so deeply in the code
+        # For now use one that implies 'postage stamp server' 'update' 'request_label"
+        my $rlabel = "ps_ud_" . $label;
+        $command .= " -rlabel $rlabel";
+    }
 
     if (!$no_update) {
@@ -931,7 +1021,7 @@
             my $fault = $error_code >> 8;
             print STDERR "$command failed with fault $fault\n";
-            if ($fault < 10) {
+            if ($fault < $PSTAMP_FIRST_ERROR_CODE) {
                 # pstamptool returns an error if an existing depenent is faulted
-                # Set the object to not available even if the fault < 10
+                # Set the object to not available even if the fault < $PSTAMP_FIRST_ERROR_CODE
                 # which is nominally a recoverable error in order to keep
                 # the request from faulting (which can be very expensive if
@@ -939,5 +1029,5 @@
                 $fault = $PSTAMP_NOT_AVAILABLE
             }
-            if ($fault >= 10) {
+            if ($fault >= $PSTAMP_FIRST_ERROR_CODE) {
                 $$r_dep_id = 0;
                 $$r_fault = $fault;
@@ -967,4 +1057,5 @@
 
 sub queueUpdatesIfNeeded {
+    my $action = shift;
     my $stage = shift;
     my $image = shift;
@@ -973,4 +1064,6 @@
     my $r_fault = shift;
     my $r_dep_id = shift;
+
+    my $need_magic = 0;
 
     if ($stage ne 'raw') {
@@ -1016,5 +1109,5 @@
                     # set up to queue an update run
                     my $require_magic = ($need_magic or $image->{magicked});
-                    get_dependent(\$$r_newState, \$$r_fault, $r_dep_id, $image->{imagedb}, 
+                    get_dependent($action, \$$r_newState, \$$r_fault, $r_dep_id, $image->{imagedb}, 
                         $run_state, $stage, $image->{stage_id}, $image->{component}, $require_magic );
                 }
@@ -1070,5 +1163,5 @@
     my $fault = shift;
 
-    carp $msg;
+    print STDERR $msg;
 
     # we don't fault the request here pstamp_parser_run.pl handles that if necessary
Index: /branches/eam_branches/ipp-20130307/pstamp/src/ppstampParseCamera.c
===================================================================
--- /branches/eam_branches/ipp-20130307/pstamp/src/ppstampParseCamera.c	(revision 35411)
+++ /branches/eam_branches/ipp-20130307/pstamp/src/ppstampParseCamera.c	(revision 35412)
@@ -95,6 +95,4 @@
     }
         
-
-    // XXX: create a filerule for PPSTAMP.ASTROM
     pmFPAfile *astrom = pmFPAfileDefineFromArgs(&status, config, "PSWARP.ASTROM", "ASTROM");
     if (!status) {
@@ -103,13 +101,8 @@
     }
     if (astrom) {
-        psLogMsg ("ppstamp", 3, "using supplied astrometry\n");
+        psLogMsg ("ppstamp", 3, "Using supplied astrometry\n");
     } else {
-        psLogMsg ("ppstamp", 3, "using header astrometry\n");
+        psLogMsg ("ppstamp", 3, "Using header astrometry\n");
     }
-
-#ifdef notyet
-    // add recipe options supplied on command line
-    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, RECIPE_NAME);
-#endif
 
     // Set up the output target
@@ -138,5 +131,6 @@
             }
         } else {
-            psLogMsg ("ppstamp", PS_LOG_INFO, "output sources file requested but no input supplied. Will try the supplied astrometry file.\n");
+            psLogMsg ("ppstamp", PS_LOG_INFO, "Output sources file requested but no -sources supplied.\n");
+            psLogMsg ("ppstamp", PS_LOG_INFO, "Will use the sources in the supplied astrometry file.\n");
         }
         
Index: /branches/eam_branches/ipp-20130307/tools/heathers_plots/deploy.sh
===================================================================
--- /branches/eam_branches/ipp-20130307/tools/heathers_plots/deploy.sh	(revision 35412)
+++ /branches/eam_branches/ipp-20130307/tools/heathers_plots/deploy.sh	(revision 35412)
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+cp -f heathers_plots.py $HOME/local/bin
+
Index: /branches/eam_branches/ipp-20130307/tools/heathers_plots/heathers_plots.py
===================================================================
--- /branches/eam_branches/ipp-20130307/tools/heathers_plots/heathers_plots.py	(revision 35411)
+++ /branches/eam_branches/ipp-20130307/tools/heathers_plots/heathers_plots.py	(revision 35412)
@@ -1,3 +1,3 @@
-#!/usr/bin env python
+#!/usr/local/bin/python2.7
 
 """
@@ -10,4 +10,5 @@
 import numpy as np
 import matplotlib as mpl
+mpl.use('Agg')
 import matplotlib.pyplot as plt
 import pylab
@@ -24,5 +25,7 @@
     IMAGES_DIRECTORY = "/data/ipp009.0/czartool_plots/heathers_plots"
     CAM_WEB_FILENAME = "/data/ipp009.0/czartool_plots/heathers_plots/cam.png"
+    CAM_MERGED_WEB_FILENAME = "/data/ipp009.0/czartool_plots/heathers_plots/cam_merged.png"
     SKYCAL_WEB_FILENAME = "/data/ipp009.0/czartool_plots/heathers_plots/skycal.png"
+    SKYCAL_MERGED_WEB_FILENAME = "/data/ipp009.0/czartool_plots/heathers_plots/skycal_merged.png"
 
     def __init__(self):
@@ -37,4 +40,17 @@
 WHERE stage = 'cam' and addRun.dvodb = 'LAP.20120706'
 """
+
+    CAM_MERGED_STATEMENT = """SELECT ra, decl, mergedvodbRun.state, mergedvodbProcessed.fault 
+FROM mergedvodbRun 
+ LEFT JOIN mergedvodbProcessed USING(merge_id)
+ LEFT JOIN minidvodbRun USING(minidvodb_id)
+ LEFT JOIN addRun USING(minidvodb_name)
+ LEFT JOIN addProcessedExp USING(add_id)
+ JOIN camRun ON stage_id = cam_id
+ JOIN chipRun USING(chip_id)
+ JOIN rawExp USING(exp_id)
+WHERE stage = 'cam' AND mergedvodbRun.mergedvodb = 'LAP.20120706'
+"""
+
     SKYCAL_STATEMENT = """SELECT radeg*3.1415927/180., decdeg*3.1415927/180., addRun.state, addProcessedExp.fault 
 FROM addRun
@@ -48,4 +64,18 @@
 WHERE stage = 'skycal' AND addRun.dvodb = 'LAP.20120706' 
 """
+
+    SKYCAL_MERGED_STATEMENT = """SELECT radeg*3.1415927/180., decdeg*3.1415927/180., mergedvodbRun.state, mergedvodbProcessed.fault
+FROM mergedvodbRun
+ LEFT JOIN mergedvodbProcessed USING(merge_id)
+ LEFT JOIN minidvodbRun USING(minidvodb_id)
+ LEFT JOIN addRun USING(minidvodb_name)
+ LEFT JOIN addProcessedExp USING(add_id)
+ JOIN skycalRun ON skycal_id = stage_id
+ JOIN skycalResult USING(skycal_id)
+ JOIN staticskyInput USING(sky_id, stack_id)
+ JOIN staticskyRun USING (sky_id)
+ JOIN stackRun using (stack_id)
+ JOIN skycell using (tess_id, skycell_id)
+WHERE stage = 'skycal' AND addRun.dvodb = 'LAP.20120706'"""
 
     def fetch_data(self, statement):
@@ -95,6 +125,6 @@
         try:
             os.unlink(web_filename)
-        except OSError: # No such file or directory
-            pass
+        except OSError, e: # No such file or directory
+            print e
         os.symlink(new_filename, web_filename)
 
@@ -115,4 +145,10 @@
         self.relink_webfiles(HeathersPlot.CAM_WEB_FILENAME, new_filename)
 
+    def update_cam_merged_plot(self):
+        HeathersPlot.mkdir(HeathersPlot.IMAGES_DIRECTORY)
+        (ras, decs, states) = self.fetch_data(HeathersPlot.CAM_MERGED_STATEMENT)
+        new_filename = self.plot(ras, decs, states, 'Camera_Merged')
+        self.relink_webfiles(HeathersPlot.CAM_MERGED_WEB_FILENAME, new_filename)
+
     def update_skycal_plot(self):
         HeathersPlot.mkdir(HeathersPlot.IMAGES_DIRECTORY)
@@ -121,6 +157,14 @@
         self.relink_webfiles(HeathersPlot.SKYCAL_WEB_FILENAME, new_filename)
 
+    def update_skycal_merged_plot(self):
+        HeathersPlot.mkdir(HeathersPlot.IMAGES_DIRECTORY)
+        (ras, decs, states) = self.fetch_data(HeathersPlot.SKYCAL_MERGED_STATEMENT)
+        new_filename = self.plot(ras, decs, states, 'SkyCal_Merged')
+        self.relink_webfiles(HeathersPlot.SKYCAL_MERGED_WEB_FILENAME, new_filename)
+
 if __name__ == "__main__":
     hp = HeathersPlot()
     hp.update_cam_plot()
     hp.update_skycal_plot()
+    hp.update_cam_merged_plot()
+    hp.update_skycal_merged_plot()
