Index: /trunk/ippTools/notes.txt
===================================================================
--- /trunk/ippTools/notes.txt	(revision 19091)
+++ /trunk/ippTools/notes.txt	(revision 19092)
@@ -1,2 +1,31 @@
+
+2008.07.19 EAM
+
+  * need to add cleanup modes to all stages.  here is the minimum list
+    of stages that need the cleanups:
+
+    * chiptool - DONE
+    * camtool 
+    * faketool
+    * warptool
+    * difftool
+    * stacktool
+    * dettool processedimfile
+    * dettool processedexp
+    * dettool stackedimfile
+    * dettool normalizedstat
+    * dettool normalizedimfile
+    * dettool normalizedexp
+    * dettool residimfile
+    * dettool residexp
+
+    * I am modifiying the tools to use the new states: new, full, goto_cleaned, etc.
+      I am NOT changing: regtool, pztool, magictool, flatcorr, pxregister, pstamptool
+
+    * for dettool, I have added a new field, 'data_state' to the
+      detRunSummary.  My plan here is that a complete detRunIteration
+      is cleaned at once.  I've added functions to all of the dettool
+      major modes to list pending entries to be cleaned and a function
+      to update the data_state when cleaning is done.
 
 2008.07.11 EAM 
Index: /trunk/ippTools/share/Makefile.am
===================================================================
--- /trunk/ippTools/share/Makefile.am	(revision 19091)
+++ /trunk/ippTools/share/Makefile.am	(revision 19092)
@@ -1,128 +1,156 @@
 dist_pkgdata_DATA = \
-	camtool_find_chip_id.sql \
-	camtool_find_pendingexp.sql \
-	camtool_find_pendingimfile.sql \
-	camtool_find_processedexp.sql \
-	camtool_queue_chip_id.sql \
-	camtool_reset_faulted_runs.sql \
-	camtool_revertprocessedexp.sql \
-	chiptool_completely_processed_exp.sql \
-	chiptool_donecleanup.sql \
-	chiptool_find_rawexp.sql \
-	chiptool_pendingcleanupimfile.sql \
-	chiptool_pendingcleanuprun.sql \
-	chiptool_pendingimfile.sql \
-	chiptool_processedimfile.sql \
-	chiptool_revertprocessedimfile.sql \
-	chiptool_run.sql \
-	chiptool_unmasked.sql \
-	detselect_search.sql \
-	detselect_select.sql \
-        dettool_addprocessedexp.sql \
-        dettool_childlessrun.sql \
-        dettool_definebydetrun.sql \
-        dettool_detrunsummary.sql \
-	dettool_find_completed_runs.sql \
-        dettool_input.sql \
-        dettool_normalizedexp.sql \
-        dettool_normalizedimfile.sql \
-	dettool_normalizedstat.sql \
-        dettool_pending.sql \
-        dettool_processedimfile.sql \
-	dettool_raw.sql \
-        dettool_residexp.sql \
-        dettool_residimfile.sql \
-	dettool_revertdetrunsummary.sql \
-	dettool_revertnormalizedexp.sql \
-	dettool_revertnormalizedimfile.sql \
-	dettool_revertnormalizedstat.sql \
-	dettool_revertprocessedexp.sql \
-	dettool_revertprocessedimfile.sql \
-	dettool_revertresidexp.sql \
-	dettool_revertresidimfile.sql\
-	dettool_revertstacked.sql \
-	dettool_runs.sql \
-        dettool_stacked.sql \
-	dettool_start_new_iteration.sql \
-	dettool_stop_completed_correct_runs.sql \
-	dettool_tocorrectexp.sql \
-	dettool_tocorrectimfile.sql \
-	dettool_todetrunsummary.sql \
-        dettool_tonormalize.sql \
-	dettool_tonormalizedexp.sql \
-	dettool_tonormalizedstat.sql \
-	dettool_toprocessedexp.sql \
-	dettool_toprocessedimfile.sql \
-	dettool_toresidexp.sql \
-	dettool_toresidimfile.sql \
-	dettool_tostacked.sql \
-	difftool_inputskyfile.sql \
-	difftool_definebyquery.sql \
-	difftool_revertdiffskyfile_update.sql \
-	difftool_revertdiffskyfile_delete.sql \
-	difftool_skyfile.sql \
-	difftool_todiffskyfile.sql \
-	faketool_completely_processed_exp.sql \
-	faketool_find_camrun.sql \
-	faketool_find_pendingexp.sql \
-	faketool_pendingimfile.sql \
-	faketool_processedimfile.sql \
-	faketool_queue_cam_id.sql \
-	faketool_revertprocessedimfile.sql \
-	faketool_unmasked.sql \
-	flatcorr_completely_processed_chiprun.sql \
-	flatcorr_create_tmp_chiprundone.sql \
-	flatcorr_find_completed_floatcorruns.sql \
-	flatcorr_find_processedimfiles.sql \
-        flatcorr_pending.sql \
-	magictool_definebyquery_temp_create.sql \
-	magictool_definebyquery_temp_insert.sql \
-	magictool_definebyquery_temp_insert_groupby.sql \
-	magictool_definebyquery_select_part1.sql \
-	magictool_definebyquery_select_part2.sql \
-	magictool_definebyquery_insert.sql \
-	magictool_inputskyfile.sql \
-	magictool_totree.sql \
-	magictool_tomask.sql \
-	magictool_toprocess_inputs.sql \
-	magictool_toprocess_tree.sql \
-	magictool_toskyfilemask.sql \
-	magictool_inputs.sql \
-	magictool_addmask.sql \
-	magictool_mask.sql \
-        pstamptool_addjob_otherjob.sql \
-        pstamptool_addjob_stampjob.sql \
-        pstamptool_datastore.sql \
-        pstamptool_pendingjob.sql \
-        pstamptool_pendingreq.sql \
-	pxadmin_create_tables.sql \
-	pxadmin_drop_tables.sql \
-	pztool_find_completed_exp.sql \
-	pztool_pendingimfile.sql \
-	pztool_revert_downloadimfile_faults.sql \
-	pztool_revert_fileset_faults.sql \
-	pztool_revertcopied.sql \
-	regtool_create_dup_table.sql \
-	regtool_pendingexp.sql \
-	regtool_pendingimfile.sql \
-	regtool_populate_dup_table.sql \
-	regtool_processedexp.sql \
-	regtool_processedimfile.sql \
-	regtool_revertprocessedexp.sql \
-	regtool_revertprocessedimfile.sql \
-	stacktool_definebyquery_part1.sql \
-	stacktool_definebyquery_part2.sql \
-	stacktool_definebyquery_insert.sql \
-	stacktool_definebyquery_insert_random.sql \
-	stacktool_inputskyfile.sql \
-	stacktool_revertsumskyfile_update.sql \
-	stacktool_revertsumskyfile_delete.sql \
-	stacktool_sumskyfile.sql \
-	stacktool_tosum.sql \
-	warptool_exp.sql \
-	warptool_imfile.sql \
-	warptool_revertwarped.sql \
-	warptool_scmap.sql \
-	warptool_tooverlap.sql \
-	warptool_towarped.sql \
-	warptool_warped.sql
+     camtool_donecleanup.sql \
+     camtool_find_chip_id.sql \
+     camtool_find_pendingexp.sql \
+     camtool_find_pendingimfile.sql \
+     camtool_find_processedexp.sql \
+     camtool_pendingcleanupexp.sql \
+     camtool_pendingcleanuprun.sql \
+     camtool_queue_chip_id.sql \
+     camtool_reset_faulted_runs.sql \
+     camtool_revertprocessedexp.sql \
+     chiptool_completely_processed_exp.sql \
+     chiptool_donecleanup.sql \
+     chiptool_find_rawexp.sql \
+     chiptool_pendingcleanupimfile.sql \
+     chiptool_pendingcleanuprun.sql \
+     chiptool_pendingimfile.sql \
+     chiptool_processedimfile.sql \
+     chiptool_revertprocessedimfile.sql \
+     chiptool_run.sql \
+     chiptool_unmasked.sql \
+     detselect_search.sql \
+     detselect_select.sql \
+     dettool_addprocessedexp.sql \
+     dettool_childlessrun.sql \
+     dettool_definebydetrun.sql \
+     dettool_detrunsummary.sql \
+     dettool_find_completed_runs.sql \
+     dettool_input.sql \
+     dettool_normalizedexp.sql \
+     dettool_normalizedimfile.sql \
+     dettool_normalizedstat.sql \
+     dettool_pending.sql \
+     dettool_pendingcleanup_normalizedexp.sql \
+     dettool_pendingcleanup_normalizedimfile.sql \
+     dettool_pendingcleanup_normalizedstat.sql \
+     dettool_pendingcleanup_processedexp.sql \
+     dettool_pendingcleanup_processedimfile.sql \
+     dettool_pendingcleanup_residexp.sql \
+     dettool_pendingcleanup_residimfile.sql \
+     dettool_pendingcleanup_stacked.sql \
+     dettool_processedimfile.sql \
+     dettool_raw.sql \
+     dettool_residexp.sql \
+     dettool_residimfile.sql \
+     dettool_revertdetrunsummary.sql \
+     dettool_revertnormalizedexp.sql \
+     dettool_revertnormalizedimfile.sql \
+     dettool_revertnormalizedstat.sql \
+     dettool_revertprocessedexp.sql \
+     dettool_revertprocessedimfile.sql \
+     dettool_revertresidexp.sql \
+     dettool_revertresidimfile.sql \
+     dettool_revertstacked.sql \
+     dettool_runs.sql \
+     dettool_stacked.sql \
+     dettool_start_new_iteration.sql \
+     dettool_stop_completed_correct_runs.sql \
+     dettool_tocorrectexp.sql \
+     dettool_tocorrectimfile.sql \
+     dettool_todetrunsummary.sql \
+     dettool_tonormalize.sql \
+     dettool_tonormalizedexp.sql \
+     dettool_tonormalizedstat.sql \
+     dettool_toprocessedexp.sql \
+     dettool_toprocessedimfile.sql \
+     dettool_toresidexp.sql \
+     dettool_toresidimfile.sql \
+     dettool_tostacked.sql \
+     difftool_definebyquery.sql \
+     difftool_donecleanup.sql \
+     difftool_inputskyfile.sql \
+     difftool_pendingcleanuprun.sql \
+     difftool_pendingcleanupskyfile.sql \
+     difftool_revertdiffskyfile_delete.sql \
+     difftool_revertdiffskyfile_update.sql \
+     difftool_skyfile.sql \
+     difftool_todiffskyfile.sql \
+     faketool_completely_processed_exp.sql \
+     faketool_donecleanup.sql \
+     faketool_find_camrun.sql \
+     faketool_find_pendingexp.sql \
+     faketool_pendingcleanupimfile.sql \
+     faketool_pendingcleanuprun.sql \
+     faketool_pendingimfile.sql \
+     faketool_processedimfile.sql \
+     faketool_queue_cam_id.sql \
+     faketool_revertprocessedimfile.sql \
+     faketool_unmasked.sql \
+     flatcorr_completely_processed_chiprun.sql \
+     flatcorr_create_tmp_chiprundone.sql \
+     flatcorr_find_completed_floatcorruns.sql \
+     flatcorr_find_processedimfiles.sql \
+     flatcorr_pending.sql \
+     magictool_addmask.sql \
+     magictool_create_tmp_warpcomplete.sql \
+     magictool_definebyquery.sql \
+     magictool_definebyquery_insert.sql \
+     magictool_definebyquery_select_part1.sql \
+     magictool_definebyquery_select_part2.sql \
+     magictool_definebyquery_select_test.sql \
+     magictool_definebyquery_temp_create.sql \
+     magictool_definebyquery_temp_insert.sql \
+     magictool_definebyquery_temp_insert_groupby.sql \
+     magictool_inputs.sql \
+     magictool_inputskyfile.sql \
+     magictool_mask.sql \
+     magictool_tomask.sql \
+     magictool_toprocess_inputs.sql \
+     magictool_toprocess_tree.sql \
+     magictool_toskyfilemask.sql \
+     magictool_totree.sql \
+     pstamptool_addjob_otherjob.sql \
+     pstamptool_addjob_stampjob.sql \
+     pstamptool_datastore.sql \
+     pstamptool_pendingjob.sql \
+     pstamptool_pendingreq.sql \
+     pxadmin_create_tables.sql \
+     pxadmin_drop_tables.sql \
+     pztool_find_completed_exp.sql \
+     pztool_pendingimfile.sql \
+     pztool_revert_downloadimfile_faults.sql \
+     pztool_revert_fileset_faults.sql \
+     pztool_revertcopied.sql \
+     regtool_create_dup_table.sql \
+     regtool_pendingexp.sql \
+     regtool_pendingimfile.sql \
+     regtool_populate_dup_table.sql \
+     regtool_processedexp.sql \
+     regtool_processedimfile.sql \
+     regtool_revertprocessedexp.sql \
+     regtool_revertprocessedimfile.sql \
+     stacktool_definebyquery_insert.sql \
+     stacktool_definebyquery_insert_random.sql \
+     stacktool_definebyquery_part1.sql \
+     stacktool_definebyquery_part2.sql \
+     stacktool_definebyquery_test.sql \
+     stacktool_donecleanup.sql \
+     stacktool_find_complete_warps.sql \
+     stacktool_inputskyfile.sql \
+     stacktool_pendingcleanuprun.sql \
+     stacktool_pendingcleanupskyfile.sql \
+     stacktool_revertsumskyfile_delete.sql \
+     stacktool_revertsumskyfile_update.sql \
+     stacktool_sumskyfile.sql \
+     stacktool_tosum.sql \
+     warptool_donecleanup.sql \
+     warptool_exp.sql \
+     warptool_imfile.sql \
+     warptool_pendingcleanuprun.sql \
+     warptool_pendingcleanupskyfile.sql \
+     warptool_revertwarped.sql \
+     warptool_scmap.sql \
+     warptool_tooverlap.sql \
+     warptool_towarped.sql \
+     warptool_warped.sql
Index: /trunk/ippTools/share/camtool_donecleanup.sql
===================================================================
--- /trunk/ippTools/share/camtool_donecleanup.sql	(revision 19092)
+++ /trunk/ippTools/share/camtool_donecleanup.sql	(revision 19092)
@@ -0,0 +1,5 @@
+SELECT
+    camRun.*
+FROM camRun
+WHERE
+    camRun.state = 'cleaned'
Index: /trunk/ippTools/share/camtool_find_pendingexp.sql
===================================================================
--- /trunk/ippTools/share/camtool_find_pendingexp.sql	(revision 19091)
+++ /trunk/ippTools/share/camtool_find_pendingexp.sql	(revision 19092)
@@ -25,5 +25,5 @@
     WHERE
         chipRun.state = 'full'
-        AND camRun.state = 'run'
+        AND camRun.state = 'new'
         AND camMask.label IS NULL
         AND camProcessedExp.cam_id IS NULL
Index: /trunk/ippTools/share/camtool_pendingcleanupexp.sql
===================================================================
--- /trunk/ippTools/share/camtool_pendingcleanupexp.sql	(revision 19092)
+++ /trunk/ippTools/share/camtool_pendingcleanupexp.sql	(revision 19092)
@@ -0,0 +1,15 @@
+SELECT
+    camProcessedExp.*,
+    camRun.state,
+    camRun.workdir,
+    camRun.label,
+    camRun.reduction,
+    camRun.expgroup,
+    camRun.dvodb,
+    camRun.tess_id,
+    camRun.end_stage
+FROM camRun
+JOIN camProcessedExp
+    USING(cam_id)
+WHERE
+    camRun.state = 'goto_cleaned'
Index: /trunk/ippTools/share/camtool_pendingcleanuprun.sql
===================================================================
--- /trunk/ippTools/share/camtool_pendingcleanuprun.sql	(revision 19092)
+++ /trunk/ippTools/share/camtool_pendingcleanuprun.sql	(revision 19092)
@@ -0,0 +1,11 @@
+SELECT
+    camRun.cam_id,
+    rawExp.camera,
+    camRun.state
+FROM camRun
+JOIN chipRun
+USING (chip_id)
+JOIN rawExp 
+USING (exp_id)
+WHERE
+    camRun.state = 'goto_cleaned'
Index: /trunk/ippTools/share/camtool_reset_faulted_runs.sql
===================================================================
--- /trunk/ippTools/share/camtool_reset_faulted_runs.sql	(revision 19091)
+++ /trunk/ippTools/share/camtool_reset_faulted_runs.sql	(revision 19092)
@@ -1,4 +1,4 @@
 UPDATE camRun, camProcessedExp, chipRun, rawExp
-SET camRun.state = 'run'
+SET camRun.state = 'new'
 WHERE
     camRun.cam_id = camProcessedExp.cam_id
Index: /trunk/ippTools/share/dettool_addprocessedexp.sql
===================================================================
--- /trunk/ippTools/share/dettool_addprocessedexp.sql	(revision 19091)
+++ /trunk/ippTools/share/dettool_addprocessedexp.sql	(revision 19092)
@@ -25,6 +25,6 @@
   AND detProcessedExp.exp_id IS NULL
   AND detInputExp.include = 1
-  AND detRun.det_id = %s
-  AND detProcessedImfile.exp_id = '%s'
+  AND detRun.det_id = %lld
+  AND detProcessedImfile.exp_id = %lld
 GROUP BY
    detProcessedImfile.class_id,
Index: /trunk/ippTools/share/dettool_definebydetrun.sql
===================================================================
--- /trunk/ippTools/share/dettool_definebydetrun.sql	(revision 19091)
+++ /trunk/ippTools/share/dettool_definebydetrun.sql	(revision 19092)
@@ -3,5 +3,5 @@
 INSERT INTO detInputExp
    SELECT
-       %d,
+       %lld,
        0,
        detResidExp.exp_id,
@@ -10,3 +10,3 @@
    JOIN rawExp
        USING(exp_id)
-   WHERE det_id = %d
+   WHERE det_id = %lld
Index: /trunk/ippTools/share/dettool_pendingcleanup_normalizedexp.sql
===================================================================
--- /trunk/ippTools/share/dettool_pendingcleanup_normalizedexp.sql	(revision 19092)
+++ /trunk/ippTools/share/dettool_pendingcleanup_normalizedexp.sql	(revision 19092)
@@ -0,0 +1,9 @@
+SELECT
+    detNormalizedExp.*,
+    detRunSummary.data_state
+FROM detRunSummary
+JOIN detNormalizedExp
+    USING(det_id,iteration)
+WHERE
+    detRunSummary.data_state = 'goto_cleaned'
+AND detNormalizedExp.data_state = 'full'
Index: /trunk/ippTools/share/dettool_pendingcleanup_normalizedimfile.sql
===================================================================
--- /trunk/ippTools/share/dettool_pendingcleanup_normalizedimfile.sql	(revision 19092)
+++ /trunk/ippTools/share/dettool_pendingcleanup_normalizedimfile.sql	(revision 19092)
@@ -0,0 +1,9 @@
+SELECT
+    detNormalizedImfile.*,
+    detRunSummary.data_state
+FROM detRunSummary
+JOIN detNormalizedImfile
+    USING(det_id,iteration)
+WHERE
+    detRunSummary.data_state = 'goto_cleaned'
+AND detNormalizedImfile.data_state = 'full'
Index: /trunk/ippTools/share/dettool_pendingcleanup_normalizedstat.sql
===================================================================
--- /trunk/ippTools/share/dettool_pendingcleanup_normalizedstat.sql	(revision 19092)
+++ /trunk/ippTools/share/dettool_pendingcleanup_normalizedstat.sql	(revision 19092)
@@ -0,0 +1,9 @@
+SELECT
+    detNormalizedStatImfile.*,
+    detRunSummary.data_state
+FROM detRunSummary
+JOIN detNormalizedStatImfile
+    USING(det_id,iteration)
+WHERE
+    detRunSummary.data_state = 'goto_cleaned'
+AND detNormalizedStatImfile.data_state = 'full'
Index: /trunk/ippTools/share/dettool_pendingcleanup_processedexp.sql
===================================================================
--- /trunk/ippTools/share/dettool_pendingcleanup_processedexp.sql	(revision 19092)
+++ /trunk/ippTools/share/dettool_pendingcleanup_processedexp.sql	(revision 19092)
@@ -0,0 +1,10 @@
+-- need to restrict to a single detRunSummary (require all to say 'cleaned'?)
+SELECT
+    detProcessedExp.*,
+    detRunSummary.data_state
+FROM detRunSummary
+JOIN detProcessedExp
+    USING(det_id)
+WHERE
+    detRunSummary.data_state = 'goto_cleaned'
+AND detProcessedExp.data_state = 'full'
Index: /trunk/ippTools/share/dettool_pendingcleanup_processedimfile.sql
===================================================================
--- /trunk/ippTools/share/dettool_pendingcleanup_processedimfile.sql	(revision 19092)
+++ /trunk/ippTools/share/dettool_pendingcleanup_processedimfile.sql	(revision 19092)
@@ -0,0 +1,10 @@
+-- need to restrict to a single detRunSummary (require all to say 'cleaned'?)
+SELECT
+    detProcessedImfile.*,
+    detRunSummary.data_state
+FROM detRunSummary
+JOIN detProcessedImfile
+    USING(det_id)
+WHERE
+    detRunSummary.data_state = 'goto_cleaned'
+AND detProcessedImfile.data_state = 'full'
Index: /trunk/ippTools/share/dettool_pendingcleanup_residexp.sql
===================================================================
--- /trunk/ippTools/share/dettool_pendingcleanup_residexp.sql	(revision 19092)
+++ /trunk/ippTools/share/dettool_pendingcleanup_residexp.sql	(revision 19092)
@@ -0,0 +1,9 @@
+SELECT
+    detResidExp.*,
+    detRunSummary.data_state
+FROM detRunSummary
+JOIN detResidExp
+    USING(det_id,iteration)
+WHERE
+    detRunSummary.data_state = 'goto_cleaned'
+AND detResidExp.data_state = 'full'
Index: /trunk/ippTools/share/dettool_pendingcleanup_residimfile.sql
===================================================================
--- /trunk/ippTools/share/dettool_pendingcleanup_residimfile.sql	(revision 19092)
+++ /trunk/ippTools/share/dettool_pendingcleanup_residimfile.sql	(revision 19092)
@@ -0,0 +1,9 @@
+SELECT
+    detResidImfile.*,
+    detRunSummary.data_state
+FROM detRunSummary
+JOIN detResidImfile
+    USING(det_id,iteration)
+WHERE
+    detRunSummary.data_state = 'goto_cleaned'
+AND detResidImfile.data_state = 'full'
Index: /trunk/ippTools/share/dettool_pendingcleanup_stacked.sql
===================================================================
--- /trunk/ippTools/share/dettool_pendingcleanup_stacked.sql	(revision 19092)
+++ /trunk/ippTools/share/dettool_pendingcleanup_stacked.sql	(revision 19092)
@@ -0,0 +1,9 @@
+SELECT
+    detStackedImfile.*,
+    detRunSummary.data_state
+FROM detRunSummary
+JOIN detStackedImfile
+    USING(det_id,iteration)
+WHERE
+    detRunSummary.data_state = 'goto_cleaned'
+AND detStackedImfile.data_state = 'full'
Index: /trunk/ippTools/share/difftool_donecleanup.sql
===================================================================
--- /trunk/ippTools/share/difftool_donecleanup.sql	(revision 19092)
+++ /trunk/ippTools/share/difftool_donecleanup.sql	(revision 19092)
@@ -0,0 +1,5 @@
+SELECT
+    diffRun.*
+FROM diffRun
+WHERE
+    diffRun.state = 'cleaned'
Index: /trunk/ippTools/share/difftool_inputskyfile.sql
===================================================================
--- /trunk/ippTools/share/difftool_inputskyfile.sql	(revision 19091)
+++ /trunk/ippTools/share/difftool_inputskyfile.sql	(revision 19092)
@@ -30,8 +30,8 @@
         ON chipRun.exp_id = rawExp.exp_id
     WHERE
-        diffRun.state = 'run'
-        AND warpRun.state = 'stop'
-        AND fakeRun.state = 'stop'
-        AND camRun.state = 'stop'
+        diffRun.state = 'new'
+        AND warpRun.state = 'full'
+        AND fakeRun.state = 'full'
+        AND camRun.state = 'full'
         AND chipRun.state = 'full'
     UNION
@@ -66,8 +66,8 @@
         ON chipRun.exp_id = rawExp.exp_id
     WHERE
-        diffRun.state = 'run'
-        AND warpRun.state = 'stop'
-        AND fakeRun.state = 'stop'
-        AND camRun.state = 'stop'
+        diffRun.state = 'new'
+        AND warpRun.state = 'full'
+        AND fakeRun.state = 'full'
+        AND camRun.state = 'full'
         AND chipRun.state = 'full'
     ) as Foo
Index: /trunk/ippTools/share/difftool_pendingcleanuprun.sql
===================================================================
--- /trunk/ippTools/share/difftool_pendingcleanuprun.sql	(revision 19092)
+++ /trunk/ippTools/share/difftool_pendingcleanuprun.sql	(revision 19092)
@@ -0,0 +1,25 @@
+-- does this result in too many entries (one for each diffInputSkyfile?)
+-- all of this is just to get the camera used for the diff run
+SELECT
+    diffRun.diff_id,
+    rawExp.camera,
+    diffRun.state
+FROM diffRun
+JOIN diffInputSkyfile
+    USING(diff_id)
+JOIN warpSkyfile
+    ON  diffInputSkyfile.warp_id    = warpSkyfile.warp_id
+    AND diffInputSkyfile.skycell_id = warpSkyfile.skycell_id
+    AND diffInputSkyfile.tess_id    = warpSkyfile.tess_id
+JOIN warpRun
+    ON warpRun.warp_id = warpSkyfile.warp_id
+JOIN fakeRun
+    USING(fake_id)
+JOIN camRun
+    USING(cam_id)
+JOIN chipRun
+    USING(chip_id)
+JOIN rawExp
+    USING(exp_id)
+WHERE
+    diffRun.state = 'goto_cleaned'
Index: /trunk/ippTools/share/difftool_pendingcleanupskyfile.sql
===================================================================
--- /trunk/ippTools/share/difftool_pendingcleanupskyfile.sql	(revision 19092)
+++ /trunk/ippTools/share/difftool_pendingcleanupskyfile.sql	(revision 19092)
@@ -0,0 +1,11 @@
+SELECT
+    diffSkyfile.*,
+    diffRun.state,
+    diffRun.workdir,
+    diffRun.dvodb,
+    diffRun.tess_id
+FROM diffRun
+JOIN diffSkyfile
+    USING(diff_id)
+WHERE
+    diffRun.state = 'goto_cleaned'
Index: /trunk/ippTools/share/difftool_skyfile.sql
===================================================================
--- /trunk/ippTools/share/difftool_skyfile.sql	(revision 19091)
+++ /trunk/ippTools/share/difftool_skyfile.sql	(revision 19092)
@@ -9,5 +9,5 @@
 JOIN diffSkyfile
     USING(diff_id)
--- my new stuff begins here
+-- WS: my new stuff begins here
 JOIN diffInputSkyfile
     ON diffInputSkyfile.diff_id = diffRun.diff_id
@@ -23,7 +23,7 @@
 JOIN rawExp
     ON chipRun.exp_id = rawExp.exp_id
--- my new stuff ends here
+-- WS: my new stuff ends here
     WHERE
     -- bogus test to allow appending conditionals
+    -- XXX EAM : this is not needed if we modify the difftool.c code : fix
     diffRun.diff_id IS NOT NULL
-
Index: /trunk/ippTools/share/difftool_todiffskyfile.sql
===================================================================
--- /trunk/ippTools/share/difftool_todiffskyfile.sql	(revision 19091)
+++ /trunk/ippTools/share/difftool_todiffskyfile.sql	(revision 19092)
@@ -25,8 +25,8 @@
     ON diffInputSkyfile.diff_id = diffSkyfile.diff_id
 WHERE
-  diffRun.state = 'run'
-  AND warpRun.state = 'stop'
-  AND fakeRun.state = 'stop'
-  AND camRun.state = 'stop'
+  diffRun.state = 'new'
+  AND warpRun.state = 'full'
+  AND fakeRun.state = 'full'
+  AND camRun.state = 'full'
   AND chipRun.state = 'full'
   AND diffSkyfile.diff_id IS NULL
Index: /trunk/ippTools/share/faketool_completely_processed_exp.sql
===================================================================
--- /trunk/ippTools/share/faketool_completely_processed_exp.sql	(revision 19091)
+++ /trunk/ippTools/share/faketool_completely_processed_exp.sql	(revision 19092)
@@ -31,5 +31,5 @@
         AND rawImfile.class_id = fakeProcessedImfile.class_id
     WHERE
-        fakeRun.state = 'run'
+        fakeRun.state = 'new'
     GROUP BY
         fakeRun.fake_id,
Index: /trunk/ippTools/share/faketool_donecleanup.sql
===================================================================
--- /trunk/ippTools/share/faketool_donecleanup.sql	(revision 19092)
+++ /trunk/ippTools/share/faketool_donecleanup.sql	(revision 19092)
@@ -0,0 +1,5 @@
+SELECT
+    fakeRun.*
+FROM fakeRun
+WHERE
+    fakeRun.state = 'cleaned'
Index: /trunk/ippTools/share/faketool_find_camrun.sql
===================================================================
--- /trunk/ippTools/share/faketool_find_camrun.sql	(revision 19091)
+++ /trunk/ippTools/share/faketool_find_camrun.sql	(revision 19092)
@@ -32,5 +32,5 @@
         using(exp_id)
     WHERE
-        camRun.state = 'stop'
+        camRun.state = 'full'
         AND chipRun.state = 'full'
 ) as Foo
Index: /trunk/ippTools/share/faketool_find_pendingexp.sql
===================================================================
--- /trunk/ippTools/share/faketool_find_pendingexp.sql	(revision 19091)
+++ /trunk/ippTools/share/faketool_find_pendingexp.sql	(revision 19092)
@@ -25,6 +25,6 @@
         ON fakeRun.label = fakeMask.label
     WHERE
-        fakeRun.state = 'run'
-        AND camRun.state = 'stop'
+        fakeRun.state = 'new'
+        AND camRun.state = 'full'
         AND chipRun.state = 'full'
         AND fakeMask.label IS NULL
Index: /trunk/ippTools/share/faketool_pendingcleanupimfile.sql
===================================================================
--- /trunk/ippTools/share/faketool_pendingcleanupimfile.sql	(revision 19092)
+++ /trunk/ippTools/share/faketool_pendingcleanupimfile.sql	(revision 19092)
@@ -0,0 +1,15 @@
+SELECT
+    fakeProcessedImfile.*,
+    fakeRun.state,
+    fakeRun.workdir,
+    fakeRun.label,
+    fakeRun.reduction,
+    fakeRun.expgroup,
+    fakeRun.dvodb,
+    fakeRun.tess_id,
+    fakeRun.end_stage
+FROM fakeRun
+JOIN fakeProcessedImfile
+    USING(fake_id)
+WHERE
+    fakeRun.state = 'goto_cleaned'
Index: /trunk/ippTools/share/faketool_pendingcleanuprun.sql
===================================================================
--- /trunk/ippTools/share/faketool_pendingcleanuprun.sql	(revision 19092)
+++ /trunk/ippTools/share/faketool_pendingcleanuprun.sql	(revision 19092)
@@ -0,0 +1,13 @@
+SELECT
+    fakeRun.fake_id,
+    rawExp.camera,
+    fakeRun.state
+FROM fakeRun
+JOIN camRun
+USING (cam_id)
+JOIN chipRun
+USING (chip_id)
+JOIN rawExp 
+USING (exp_id)
+WHERE
+    fakeRun.state = 'goto_cleaned'
Index: /trunk/ippTools/share/faketool_queue_cam_id.sql
===================================================================
--- /trunk/ippTools/share/faketool_queue_cam_id.sql	(revision 19091)
+++ /trunk/ippTools/share/faketool_queue_cam_id.sql	(revision 19092)
@@ -14,4 +14,4 @@
     FROM camRun
     WHERE
-        camRun.state = 'stop'
+        camRun.state = 'full'
         AND camRun.cam_id = %lld
Index: /trunk/ippTools/share/pxadmin_create_tables.sql
===================================================================
--- /trunk/ippTools/share/pxadmin_create_tables.sql	(revision 19091)
+++ /trunk/ippTools/share/pxadmin_create_tables.sql	(revision 19092)
@@ -485,4 +485,5 @@
     user_5 DOUBLE,
     path_base VARCHAR(255),
+    data_state VARCHAR(64),
     fault SMALLINT NOT NULL,
     PRIMARY KEY(det_id, exp_id, class_id),
@@ -512,4 +513,5 @@
     user_5 DOUBLE,
     path_base VARCHAR(255),
+    data_state VARCHAR(64),
     fault SMALLINT NOT NULL,
     PRIMARY KEY(det_id, exp_id),
@@ -535,4 +537,5 @@
     user_4 DOUBLE,
     user_5 DOUBLE,
+    data_state VARCHAR(64),
     fault SMALLINT NOT NULL,
     PRIMARY KEY(det_id, iteration, class_id),
@@ -549,4 +552,5 @@
     class_id VARCHAR(64),
     norm FLOAT,
+    data_state VARCHAR(64),
     fault SMALLINT NOT NULL,
     PRIMARY KEY(det_id, iteration, class_id),
@@ -572,4 +576,5 @@
     user_5 DOUBLE,
     path_base VARCHAR(255),
+    data_state VARCHAR(64),
     fault SMALLINT NOT NULL,
     PRIMARY KEY(det_id, iteration, class_id),
@@ -595,4 +600,5 @@
     user_5 DOUBLE,
     path_base VARCHAR(255),
+    data_state VARCHAR(64),
     fault SMALLINT NOT NULL,
     PRIMARY KEY(det_id, iteration),
@@ -629,4 +635,5 @@
     user_5 DOUBLE,
     path_base VARCHAR(255),
+    data_state VARCHAR(64),
     fault SMALLINT NOT NULL,
     PRIMARY KEY(det_id, iteration, exp_id, class_id),
@@ -641,7 +648,77 @@
 ) ENGINE=innodb DEFAULT CHARSET=latin1;
 
-CREATE TABLE detResidExp (det_id BIGINT, iteration INT, exp_id BIGINT, recipe VARCHAR(64), bg DOUBLE, bg_stdev DOUBLE, bg_mean_stdev DOUBLE, bg_skewness DOUBLE, bg_kurtosis DOUBLE, bin_stdev DOUBLE, fringe_0 DOUBLE, fringe_1 DOUBLE, fringe_2 DOUBLE, fringe_resid_0 DOUBLE, fringe_resid_1 DOUBLE, fringe_resid_2 DOUBLE, user_1 DOUBLE, user_2 DOUBLE, user_3 DOUBLE, user_4 DOUBLE, user_5 DOUBLE, path_base VARCHAR(255), accept TINYINT, fault SMALLINT NOT NULL, PRIMARY KEY(det_id, iteration, exp_id), KEY(fault), INDEX(det_id, iteration), FOREIGN KEY (det_id, iteration, exp_id)  REFERENCES  detInputExp(det_id, iteration, exp_id), FOREIGN KEY (det_id, iteration, exp_id)  REFERENCES  detResidImfile(det_id, iteration, exp_id)) ENGINE=innodb DEFAULT CHARSET=latin1;
-CREATE TABLE detRunSummary (det_id BIGINT, iteration INT, bg DOUBLE, bg_stdev DOUBLE, bg_mean_stdev DOUBLE, accept TINYINT, fault SMALLINT NOT NULL, PRIMARY KEY(det_id, iteration), KEY(fault), FOREIGN KEY (det_id, iteration)  REFERENCES  detInputExp(det_id, iteration), FOREIGN KEY (det_id, iteration)  REFERENCES  detResidExp(det_id, iteration)) ENGINE=innodb DEFAULT CHARSET=latin1;
-CREATE TABLE detRegisteredImfile (det_id BIGINT, iteration INT, class_id VARCHAR(64), uri VARCHAR(255), bg DOUBLE, bg_stdev DOUBLE, bg_mean_stdev DOUBLE, user_1 DOUBLE, user_2 DOUBLE, user_3 DOUBLE, user_4 DOUBLE, user_5 DOUBLE, path_base VARCHAR(255), fault SMALLINT NOT NULL, PRIMARY KEY(det_id, iteration, class_id), KEY(fault), FOREIGN KEY (det_id, iteration)  REFERENCES  detRun(det_id, iteration)) ENGINE=innodb DEFAULT CHARSET=latin1;
+CREATE TABLE detResidExp (
+       det_id BIGINT, 
+       iteration INT, 
+       exp_id BIGINT, 
+       recipe VARCHAR(64), 
+       bg DOUBLE, 
+       bg_stdev DOUBLE, 
+       bg_mean_stdev DOUBLE, 
+       bg_skewness DOUBLE, 
+       bg_kurtosis DOUBLE, 
+       bin_stdev DOUBLE, 
+       fringe_0 DOUBLE, 
+       fringe_1 DOUBLE, 
+       fringe_2 DOUBLE, 
+       fringe_resid_0 DOUBLE, 
+       fringe_resid_1 DOUBLE, 
+       fringe_resid_2 DOUBLE, 
+       user_1 DOUBLE, 
+       user_2 DOUBLE, 
+       user_3 DOUBLE, 
+       user_4 DOUBLE, 
+       user_5 DOUBLE, 
+       path_base VARCHAR(255), 
+       data_state VARCHAR(64),
+       accept TINYINT, 
+       fault SMALLINT NOT NULL, 
+       PRIMARY KEY(det_id, iteration, exp_id), 
+       KEY(fault), 
+       INDEX(det_id, iteration), 
+       FOREIGN KEY (det_id, iteration, exp_id)  
+       REFERENCES  detInputExp(det_id, iteration, exp_id), 
+       FOREIGN KEY (det_id, iteration, exp_id)  
+       REFERENCES  detResidImfile(det_id, iteration, exp_id)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+CREATE TABLE detRunSummary (
+       det_id BIGINT, 
+       iteration INT, 
+       data_state VARCHAR(64), 
+       bg DOUBLE, 
+       bg_stdev DOUBLE, 
+       bg_mean_stdev DOUBLE, 
+       accept TINYINT, 
+       fault SMALLINT NOT NULL, 
+       PRIMARY KEY(det_id, iteration), 
+       KEY(fault), 
+       FOREIGN KEY (det_id, iteration)  
+         REFERENCES  detInputExp(det_id, iteration), 
+       FOREIGN KEY (det_id, iteration)  
+         REFERENCES  detResidExp(det_id, iteration)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+CREATE TABLE detRegisteredImfile (
+       det_id BIGINT, 
+       iteration INT, 
+       class_id VARCHAR(64), 
+       uri VARCHAR(255), 
+       bg DOUBLE, 
+       bg_stdev DOUBLE, 
+       bg_mean_stdev DOUBLE, 
+       user_1 DOUBLE, 
+       user_2 DOUBLE, 
+       user_3 DOUBLE, 
+       user_4 DOUBLE, 
+       user_5 DOUBLE, 
+       path_base VARCHAR(255),
+       data_state VARCHAR(64),
+       fault SMALLINT NOT NULL, 
+       PRIMARY KEY(det_id, iteration, class_id), 
+       KEY(fault), 
+       FOREIGN KEY (det_id, iteration)  
+         REFERENCES  detRun(det_id, iteration)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
 
 CREATE TABLE warpRun (
Index: /trunk/ippTools/share/stacktool_definebyquery_part1.sql
===================================================================
--- /trunk/ippTools/share/stacktool_definebyquery_part1.sql	(revision 19091)
+++ /trunk/ippTools/share/stacktool_definebyquery_part1.sql	(revision 19092)
@@ -23,5 +23,5 @@
         JOIN rawExp USING(exp_id, tess_id)
     WHERE
-        warpRun.state = 'stop'
+        warpRun.state = 'full'
     AND warpSkyfile.ignored = 0
     AND warpSkyfile.fault = 0
Index: /trunk/ippTools/share/stacktool_definebyquery_test.sql
===================================================================
--- /trunk/ippTools/share/stacktool_definebyquery_test.sql	(revision 19091)
+++ /trunk/ippTools/share/stacktool_definebyquery_test.sql	(revision 19092)
@@ -30,5 +30,5 @@
         JOIN rawExp USING(exp_id, tess_id)
     WHERE
-        warpRun.state = 'stop'
+        warpRun.state = 'full'
     AND warpSkyfile.ignored = 0
     AND warpSkyfile.fault = 0
Index: /trunk/ippTools/share/stacktool_donecleanup.sql
===================================================================
--- /trunk/ippTools/share/stacktool_donecleanup.sql	(revision 19092)
+++ /trunk/ippTools/share/stacktool_donecleanup.sql	(revision 19092)
@@ -0,0 +1,5 @@
+SELECT
+    stackRun.*
+FROM stackRun
+WHERE
+    stackRun.state = 'cleaned'
Index: /trunk/ippTools/share/stacktool_find_complete_warps.sql
===================================================================
--- /trunk/ippTools/share/stacktool_find_complete_warps.sql	(revision 19091)
+++ /trunk/ippTools/share/stacktool_find_complete_warps.sql	(revision 19092)
@@ -23,5 +23,5 @@
     AND stackRun.stack_id = stackInputSkyfile.stack_id
 WHERE
-    warpRun.state = 'stop'
+    warpRun.state = 'full'
     AND warpSkyfile.ignored = 0
 GROUP BY
Index: /trunk/ippTools/share/stacktool_inputskyfile.sql
===================================================================
--- /trunk/ippTools/share/stacktool_inputskyfile.sql	(revision 19091)
+++ /trunk/ippTools/share/stacktool_inputskyfile.sql	(revision 19092)
@@ -22,3 +22,3 @@
     ON chipProcessedImfile.exp_id = rawExp.exp_id
 WHERE
-    stackRun.state = 'run'
+    stackRun.state = 'new'
Index: /trunk/ippTools/share/stacktool_pendingcleanuprun.sql
===================================================================
--- /trunk/ippTools/share/stacktool_pendingcleanuprun.sql	(revision 19092)
+++ /trunk/ippTools/share/stacktool_pendingcleanuprun.sql	(revision 19092)
@@ -0,0 +1,26 @@
+-- results in too many output files
+-- is the camera needed for this?
+-- is the camera unique for this?
+SELECT
+    stackRun.stack_id,
+    rawExp.camera,
+    stackRun.state
+FROM stackRun
+JOIN stackInputSkyfile
+    USING(stack_id)
+JOIN warpSkyfile
+    ON  stackInputSkyfile.warp_id = warpSkyfile.warp_id
+    AND stackRun.skycell_id       = warpSkyfile.skycell_id
+    AND stackRun.tess_id          = warpSkyfile.tess_id
+JOIN warpRun
+    ON warpRun.warp_id = warpSkyfile.warp_id
+JOIN fakeRun
+    USING(fake_id)
+JOIN camRun
+    USING(cam_id)
+JOIN chipRun
+    USING(chip_id)
+JOIN rawExp 
+     USING (exp_id)
+WHERE
+    stackRun.state = 'goto_cleaned'
Index: /trunk/ippTools/share/stacktool_pendingcleanupskyfile.sql
===================================================================
--- /trunk/ippTools/share/stacktool_pendingcleanupskyfile.sql	(revision 19092)
+++ /trunk/ippTools/share/stacktool_pendingcleanupskyfile.sql	(revision 19092)
@@ -0,0 +1,11 @@
+SELECT
+    stackSumSkyfile.*,
+    stackRun.state,
+    stackRun.workdir,
+    stackRun.dvodb,
+    stackRun.tess_id
+FROM stackRun
+JOIN stackSumSkyfile
+    USING(stack_id)
+WHERE
+    stackRun.state = 'goto_cleaned'
Index: /trunk/ippTools/share/stacktool_sumskyfile.sql
===================================================================
--- /trunk/ippTools/share/stacktool_sumskyfile.sql	(revision 19091)
+++ /trunk/ippTools/share/stacktool_sumskyfile.sql	(revision 19092)
@@ -20,3 +20,4 @@
 WHERE
 -- bogus test; just here so there there is a 'WHERE' stmt to append conditionals too
+-- XXX EAM : this is not needed : fix the stacktool code.
     stackRun.stack_id is NOT NULL
Index: /trunk/ippTools/share/stacktool_tosum.sql
===================================================================
--- /trunk/ippTools/share/stacktool_tosum.sql	(revision 19091)
+++ /trunk/ippTools/share/stacktool_tosum.sql	(revision 19092)
@@ -25,4 +25,4 @@
     USING(stack_id)
 WHERE
-    stackRun.state = 'run'
+    stackRun.state = 'new'
     AND stackSumSkyfile.stack_id IS NULL
Index: /trunk/ippTools/share/warptool_donecleanup.sql
===================================================================
--- /trunk/ippTools/share/warptool_donecleanup.sql	(revision 19092)
+++ /trunk/ippTools/share/warptool_donecleanup.sql	(revision 19092)
@@ -0,0 +1,5 @@
+SELECT
+    warpRun.*
+FROM warpRun
+WHERE
+    warpRun.state = 'cleaned'
Index: /trunk/ippTools/share/warptool_exp.sql
===================================================================
--- /trunk/ippTools/share/warptool_exp.sql	(revision 19091)
+++ /trunk/ippTools/share/warptool_exp.sql	(revision 19092)
@@ -5,4 +5,4 @@
     USING(fake_id)
 WHERE
-    warpRun.state = 'run'
-    AND fakeRun.state = 'stop'
+    warpRun.state = 'new'
+    AND fakeRun.state = 'full'
Index: /trunk/ippTools/share/warptool_imfile.sql
===================================================================
--- /trunk/ippTools/share/warptool_imfile.sql	(revision 19091)
+++ /trunk/ippTools/share/warptool_imfile.sql	(revision 19092)
@@ -21,7 +21,7 @@
     AND chipProcessedImfile.class_id = rawImfile.class_id 
 WHERE
-    warpRun.state = 'run'
-    AND fakeRun.state = 'stop'
-    AND camRun.state = 'stop'
+    warpRun.state = 'new'
+    AND fakeRun.state = 'full'
+    AND camRun.state = 'full'
     AND chipRun.state = 'full'
 
Index: /trunk/ippTools/share/warptool_pendingcleanuprun.sql
===================================================================
--- /trunk/ippTools/share/warptool_pendingcleanuprun.sql	(revision 19092)
+++ /trunk/ippTools/share/warptool_pendingcleanuprun.sql	(revision 19092)
@@ -0,0 +1,15 @@
+SELECT
+    warpRun.warp_id,
+    rawExp.camera,
+    warpRun.state
+FROM warpRun
+JOIN fakeRun
+USING (fake_id)
+JOIN camRun
+USING (cam_id)
+JOIN chipRun
+USING (chip_id)
+JOIN rawExp 
+USING (exp_id)
+WHERE
+    warpRun.state = 'goto_cleaned'
Index: /trunk/ippTools/share/warptool_pendingcleanupskyfile.sql
===================================================================
--- /trunk/ippTools/share/warptool_pendingcleanupskyfile.sql	(revision 19092)
+++ /trunk/ippTools/share/warptool_pendingcleanupskyfile.sql	(revision 19092)
@@ -0,0 +1,15 @@
+SELECT
+    warpSkyfile.*,
+    warpRun.state,
+    warpRun.workdir,
+    warpRun.label,
+    warpRun.reduction,
+    warpRun.expgroup,
+    warpRun.dvodb,
+    warpRun.tess_id,
+    warpRun.end_stage
+FROM warpRun
+JOIN warpSkyfile
+    USING(warp_id)
+WHERE
+    warpRun.state = 'goto_cleaned'
Index: /trunk/ippTools/share/warptool_scmap.sql
===================================================================
--- /trunk/ippTools/share/warptool_scmap.sql	(revision 19091)
+++ /trunk/ippTools/share/warptool_scmap.sql	(revision 19092)
@@ -19,6 +19,6 @@
     AND warpSkyCellMap.class_id = chipProcessedImfile.class_id
 WHERE
---    warpRun.state = 'run'
-    fakeRun.state = 'stop'
-    AND camRun.state = 'stop'
+--    warpRun.state = 'new'
+    fakeRun.state = 'full'
+    AND camRun.state = 'full'
     AND chipRun.state = 'full'
Index: /trunk/ippTools/share/warptool_tooverlap.sql
===================================================================
--- /trunk/ippTools/share/warptool_tooverlap.sql	(revision 19091)
+++ /trunk/ippTools/share/warptool_tooverlap.sql	(revision 19092)
@@ -23,7 +23,7 @@
     ON warpRun.label = warpMask.label
 WHERE
-    warpRun.state = 'run'
-    AND fakeRun.state = 'stop'
-    AND camRun.state = 'stop'
+    warpRun.state = 'new'
+    AND fakeRun.state = 'full'
+    AND camRun.state = 'full'
     AND chipRun.state = 'full'
     AND warpSkyCellMap.warp_id IS NULL
Index: /trunk/ippTools/share/warptool_towarped.sql
===================================================================
--- /trunk/ippTools/share/warptool_towarped.sql	(revision 19091)
+++ /trunk/ippTools/share/warptool_towarped.sql	(revision 19092)
@@ -27,7 +27,7 @@
     ON warpRun.label = warpMask.label
 WHERE
-    warpRun.state = 'run'
-    AND fakeRun.state = 'stop'
-    AND camRun.state = 'stop'
+    warpRun.state = 'new'
+    AND fakeRun.state = 'full'
+    AND camRun.state = 'full'
     AND chipRun.state = 'full'
     AND warpSkyfile.warp_id IS NULL
Index: /trunk/ippTools/share/warptool_warped.sql
===================================================================
--- /trunk/ippTools/share/warptool_warped.sql	(revision 19091)
+++ /trunk/ippTools/share/warptool_warped.sql	(revision 19092)
@@ -17,3 +17,4 @@
 WHERE
 -- bogus test; just here so there there is a 'WHERE' stmt to append conditionals too
+-- XXX EAM : not needed: fix warptool.c
     warpRun.warp_id is NOT NULL
Index: /trunk/ippTools/src/Makefile.am
===================================================================
--- /trunk/ippTools/src/Makefile.am	(revision 19091)
+++ /trunk/ippTools/src/Makefile.am	(revision 19092)
@@ -173,5 +173,14 @@
     dettool.c \
     dettoolConfig.c \
-    dettool_correction.c
+    dettool_correction.c \
+    dettool_detrunsummary.c \
+    dettool_normalizedexp.c \
+    dettool_normalizedimfile.c \
+    dettool_normalizedstat.c \
+    dettool_processedexp.c \
+    dettool_processedimfile.c \
+    dettool_residexp.c \
+    dettool_residimfile.c \
+    dettool_stack.c
 
 detselect_CFLAGS = $(PSLIB_CFLAGS) $(PSMODULES_CFLAGS) $(IPPDB_CFLAGS)
Index: /trunk/ippTools/src/camtool.c
===================================================================
--- /trunk/ippTools/src/camtool.c	(revision 19091)
+++ /trunk/ippTools/src/camtool.c	(revision 19092)
@@ -41,4 +41,7 @@
 static bool maskedMode(pxConfig *config);
 static bool unblockMode(pxConfig *config);
+static bool pendingcleanuprunMode(pxConfig *config);
+static bool pendingcleanupexpMode(pxConfig *config);
+static bool donecleanupMode(pxConfig *config);
 
 # define MODECASE(caseName, func) \
@@ -71,4 +74,7 @@
         MODECASE(CAMTOOL_MODE_MASKED,               maskedMode);
         MODECASE(CAMTOOL_MODE_UNBLOCK,              unblockMode);
+        MODECASE(CAMTOOL_MODE_PENDINGCLEANUPRUN,    pendingcleanuprunMode);
+        MODECASE(CAMTOOL_MODE_PENDINGCLEANUPEXP,    pendingcleanupexpMode);
+        MODECASE(CAMTOOL_MODE_DONECLEANUP,          donecleanupMode);
         default:
             psAbort("invalid option (this should not happen)");
@@ -570,5 +576,5 @@
 
     // since there is only one exp per 'run' set camRun.state = 'stop'
-    if (!pxcamRunSetState(config, row->cam_id, "stop")) {
+    if (!pxcamRunSetState(config, row->cam_id, "full")) {
         psError(PS_ERR_UNKNOWN, false, "failed to change camRun.state for cam_id: %" PRId64, row->cam_id);
         psFree(row);
@@ -914,2 +920,188 @@
     return true;
 }
+
+static bool pendingcleanuprunMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_STR(config->args, where, "-label", "label", "==");
+
+    psString query = pxDataGet("camtool_pendingcleanuprun.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("camtool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "camPendingCleanupRun", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+
+static bool pendingcleanupexpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_S64(cam_id, config->args, "-cam_id", false, false);
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    if (cam_id) {
+        PXOPT_COPY_S64(config->args, where, "-cam_id", "cam_id", "==");
+    }
+    PXOPT_COPY_STR(config->args, where, "-label", "label", "==");
+
+    psString query = pxDataGet("camtool_pendingcleanupexp.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("chiptool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "camPendingCleanupExp", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+
+static bool donecleanupMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_STR(config->args, where, "-label", "label", "==");
+
+    psString query = pxDataGet("camtool_donecleanup.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("camtool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "camDoneCleanup", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
Index: /trunk/ippTools/src/camtool.h
===================================================================
--- /trunk/ippTools/src/camtool.h	(revision 19091)
+++ /trunk/ippTools/src/camtool.h	(revision 19092)
@@ -35,5 +35,8 @@
     CAMTOOL_MODE_BLOCK,
     CAMTOOL_MODE_MASKED,
-    CAMTOOL_MODE_UNBLOCK
+    CAMTOOL_MODE_UNBLOCK,
+    CAMTOOL_MODE_PENDINGCLEANUPRUN,
+    CAMTOOL_MODE_PENDINGCLEANUPEXP,
+    CAMTOOL_MODE_DONECLEANUP,
 } camtoolMode;
 
Index: /trunk/ippTools/src/camtoolConfig.c
===================================================================
--- /trunk/ippTools/src/camtoolConfig.c	(revision 19091)
+++ /trunk/ippTools/src/camtoolConfig.c	(revision 19092)
@@ -274,18 +274,41 @@
     psMetadataAddStr(unblockArgs, PS_LIST_TAIL, "-label",  0,            "name of a label to unmask (required)", NULL);
 
+    // -pendingcleanuprun
+    psMetadata *pendingcleanuprunArgs = psMetadataAlloc();
+    psMetadataAddStr(pendingcleanuprunArgs, PS_LIST_TAIL, "-label",  0,            "list blocks for specified label", NULL);
+    psMetadataAddBool(pendingcleanuprunArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(pendingcleanuprunArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+
+    // -pendingcleanupexp
+    psMetadata *pendingcleanupexpArgs = psMetadataAlloc();
+    psMetadataAddStr(pendingcleanupexpArgs, PS_LIST_TAIL, "-label",  0,            "list blocks for specified label", NULL);
+    psMetadataAddS64(pendingcleanupexpArgs, PS_LIST_TAIL, "-cam_id", 0,            "search by camera ID", 0);
+    psMetadataAddStr(pendingcleanupexpArgs, PS_LIST_TAIL, "-exp_id",                 0,            "search by exp_id", NULL);
+    psMetadataAddBool(pendingcleanupexpArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(pendingcleanupexpArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+
+    // -donecleanup
+    psMetadata *donecleanupArgs = psMetadataAlloc();
+    psMetadataAddStr(donecleanupArgs, PS_LIST_TAIL, "-label",  0,            "list blocks for specified label", NULL);
+    psMetadataAddBool(donecleanupArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(donecleanupArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+
     psMetadata *argSets = psMetadataAlloc();
     psMetadata *modes = psMetadataAlloc();
 
-    PXOPT_ADD_MODE("-definebyquery",       "", CAMTOOL_MODE_DEFINEBYQUERY, definebydefinebyqueryArgs);
-    PXOPT_ADD_MODE("-updaterun",           "", CAMTOOL_MODE_UPDATERUN,      updaterunArgs);
-    PXOPT_ADD_MODE("-pendingexp",          "", CAMTOOL_MODE_PENDINGEXP,    pendingexpArgs);
-    PXOPT_ADD_MODE("-pendingimfile",       "", CAMTOOL_MODE_PENDINGIMFILE, pendingimfileArgs);
-    PXOPT_ADD_MODE("-addprocessedexp",     "", CAMTOOL_MODE_ADDPROCESSEDEXP, addprocessedexpArgs);
-    PXOPT_ADD_MODE("-processedexp",        "", CAMTOOL_MODE_PROCESSEDEXP,  processedexpArgs);
-    PXOPT_ADD_MODE("-revertprocessedexp",  "", CAMTOOL_MODE_REVERTPROCESSEDEXP,  revertprocessedexpArgs);
-    PXOPT_ADD_MODE("-updateprocessedexp",  "", CAMTOOL_MODE_UPDATEPROCESSEDEXP,updateprocessedexpArgs);
-    PXOPT_ADD_MODE("-block",               "", CAMTOOL_MODE_BLOCK,         blockArgs);
-    PXOPT_ADD_MODE("-masked",              "", CAMTOOL_MODE_MASKED,        maskedArgs);
-    PXOPT_ADD_MODE("-unblock",             "", CAMTOOL_MODE_UNBLOCK,       unblockArgs);
+    PXOPT_ADD_MODE("-definebyquery",        "create runs from chip stage",    	    CAMTOOL_MODE_DEFINEBYQUERY, definebydefinebyqueryArgs);
+    PXOPT_ADD_MODE("-updaterun",            "change cam run properties",      	    CAMTOOL_MODE_UPDATERUN,      updaterunArgs);
+    PXOPT_ADD_MODE("-pendingexp",           "show pending exposures",         	    CAMTOOL_MODE_PENDINGEXP,    pendingexpArgs);
+    PXOPT_ADD_MODE("-pendingimfile",        "show pending imfiles",           	    CAMTOOL_MODE_PENDINGIMFILE, pendingimfileArgs);
+    PXOPT_ADD_MODE("-addprocessedexp",      "add a processed exposure",       	    CAMTOOL_MODE_ADDPROCESSEDEXP, addprocessedexpArgs);
+    PXOPT_ADD_MODE("-processedexp",         "show processed exposures",       	    CAMTOOL_MODE_PROCESSEDEXP,  processedexpArgs);
+    PXOPT_ADD_MODE("-revertprocessedexp",   "change procesed exp properties", 	    CAMTOOL_MODE_REVERTPROCESSEDEXP,  revertprocessedexpArgs);
+    PXOPT_ADD_MODE("-updateprocessedexp",   "undo a processed exposure",      	    CAMTOOL_MODE_UPDATEPROCESSEDEXP,updateprocessedexpArgs);
+    PXOPT_ADD_MODE("-block",                "set a label block",    		    CAMTOOL_MODE_BLOCK,         blockArgs);
+    PXOPT_ADD_MODE("-masked",               "show blocked labels",  		    CAMTOOL_MODE_MASKED,        maskedArgs);
+    PXOPT_ADD_MODE("-unblock",              "remove a label block", 		    CAMTOOL_MODE_UNBLOCK,       unblockArgs);
+    PXOPT_ADD_MODE("-pendingcleanuprun",    "show runs that need to be cleaned up", CAMTOOL_MODE_PENDINGCLEANUPRUN, pendingcleanuprunArgs);
+    PXOPT_ADD_MODE("-pendingcleanupexp",    "show exposures for cleanup runs",      CAMTOOL_MODE_PENDINGCLEANUPEXP, pendingcleanupexpArgs);
+    PXOPT_ADD_MODE("-donecleanup",          "show runs that have been cleaned",     CAMTOOL_MODE_DONECLEANUP,       donecleanupArgs);
 
     if (!pxGetOptions(stderr, argc, argv, config, modes, argSets)) {
Index: /trunk/ippTools/src/chiptoolConfig.c
===================================================================
--- /trunk/ippTools/src/chiptoolConfig.c	(revision 19091)
+++ /trunk/ippTools/src/chiptoolConfig.c	(revision 19092)
@@ -280,14 +280,13 @@
     psMetadataAddU64(pendingcleanuprunArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
 
-    // -pendingcleanupifmile
+    // -pendingcleanupimfile
     psMetadata *pendingcleanupimfileArgs = psMetadataAlloc();
     psMetadataAddStr(pendingcleanupimfileArgs, PS_LIST_TAIL, "-label",  0,            "list blocks for specified label", NULL);
-    psMetadataAddS64(pendingcleanupimfileArgs, PS_LIST_TAIL, "-chip_id", 0,
-        "search by chip ID", 0);
+    psMetadataAddS64(pendingcleanupimfileArgs, PS_LIST_TAIL, "-chip_id", 0,          "search by chip ID", 0);
     psMetadataAddStr(pendingcleanupimfileArgs, PS_LIST_TAIL, "-exp_id",                 0,            "search by exp_id", NULL);
     psMetadataAddBool(pendingcleanupimfileArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
     psMetadataAddU64(pendingcleanupimfileArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
 
-    // -doneclenaup
+    // -donecleanup
     psMetadata *donecleanupArgs = psMetadataAlloc();
     psMetadataAddStr(donecleanupArgs, PS_LIST_TAIL, "-label",  0,            "list blocks for specified label", NULL);
Index: /trunk/ippTools/src/dettool.c
===================================================================
--- /trunk/ippTools/src/dettool.c	(revision 19091)
+++ /trunk/ippTools/src/dettool.c	(revision 19092)
@@ -28,51 +28,5 @@
 static bool inputMode(pxConfig *config);
 static bool rawMode(pxConfig *config);
-// processedimfile
-static bool toprocessedimfileMode(pxConfig *config);
-static bool addprocessedimfileMode(pxConfig *config);
-static bool processedimfileMode(pxConfig *config);
-static bool revertprocessedimfileMode(pxConfig *config);
-// processedexp
-static bool toprocessedexpMode(pxConfig *config);
-static bool addprocessedexpMode(pxConfig *config);
-static bool processedexpMode(pxConfig *config);
-static bool revertprocessedexpMode(pxConfig *config);
-// stackedimfile
-static bool tostackedMode(pxConfig *config);
-static bool addstackedMode(pxConfig *config);
-static bool stackedMode(pxConfig *config);
-static bool revertstackedMode(pxConfig *config);
-// normalizedstat
-static bool tonormalizedstatMode(pxConfig *config);
-static bool addnormalizedstatMode(pxConfig *config);
-static bool normalizedstatMode(pxConfig *config);
-static bool revertnormalizedstatMode(pxConfig *config);
-// normalizedimfile
-static bool tonormalizeMode(pxConfig *config);
-static bool addnormalizedimfileMode(pxConfig *config);
-static bool normalizedimfileMode(pxConfig *config);
-static bool revertnormalizedimfileMode(pxConfig *config);
-// normalizedexp
-static bool tonormalizedexpMode(pxConfig *config);
-static bool addnormalizedexpMode(pxConfig *config);
-static bool normalizedexpMode(pxConfig *config);
-static bool revertnormalizedexpMode(pxConfig *config);
-// residimfile
-static bool toresidimfileMode(pxConfig *config);
-static bool addresidimfileMode(pxConfig *config);
-static bool residimfileMode(pxConfig *config);
-static bool revertresidimfileMode(pxConfig *config);
-// residexp
-static bool toresidexpMode(pxConfig *config);
-static bool addresidexpMode(pxConfig *config);
-static bool residexpMode(pxConfig *config);
-static bool revertresidexpMode(pxConfig *config);
-static bool updateresidexpMode(pxConfig *config);
-// detrunsummary
-static bool todetrunsummaryMode(pxConfig *config);
-static bool adddetrunsummaryMode(pxConfig *config);
-static bool detrunsummaryMode(pxConfig *config);
-static bool revertdetrunsummaryMode(pxConfig *config);
-static bool updatedetrunsummaryMode(pxConfig *config);
+
 // run
 static bool updatedetrunMode(pxConfig *config);
@@ -81,13 +35,8 @@
 static bool register_detrendMode(pxConfig *config);
 
-static detRunSummaryRow *mdToDetRunSummary(pxConfig *config, psMetadata *row);
 //static psArray *validDetInputClassIds(pxConfig *config, const char *det_id);
 //static psArray *searchInputImfiles(pxConfig *config, const char *det_id);
 static detInputExpRow *rawDetrenTodetInputExpRow(rawExpRow *rawExp, psS64 det_id, psS32 iteration);
-static psArray *searchRawImfiles(pxConfig *config);
-static bool startNewIteration(pxConfig *config, psS64 det_id);
 static psS32 incrementIteration(pxConfig *config, psS64 det_id);
-static bool setDetRunState(pxConfig *config, psS64 det_id, const char *state);
-static bool isValidMode(pxConfig *config, const char *mode);
 
 # define MODECASE(caseName, func) \
@@ -127,4 +76,7 @@
         MODECASE(DETTOOL_MODE_PROCESSEDIMFILE,  processedimfileMode);
         MODECASE(DETTOOL_MODE_REVERTPROCESSEDIMFILE, revertprocessedimfileMode);
+        MODECASE(DETTOOL_MODE_UPDATEPROCESSEDIMFILE, updateprocessedimfileMode);
+        MODECASE(DETTOOL_MODE_PENDINGCLEANUP_PROCESSEDIMFILE, pendingcleanup_processedimfileMode);
+        MODECASE(DETTOOL_MODE_DONECLEANUP_PROCESSEDIMFILE, donecleanup_processedimfileMode);
         // exp
         MODECASE(DETTOOL_MODE_TOPROCESSEDEXP,   toprocessedexpMode);
@@ -132,4 +84,7 @@
         MODECASE(DETTOOL_MODE_PROCESSEDEXP,     processedexpMode);
         MODECASE(DETTOOL_MODE_REVERTPROCESSEDEXP, revertprocessedexpMode);
+        MODECASE(DETTOOL_MODE_UPDATEPROCESSEDEXP, updateprocessedexpMode);
+        MODECASE(DETTOOL_MODE_PENDINGCLEANUP_PROCESSEDEXP, pendingcleanup_processedexpMode);
+        MODECASE(DETTOOL_MODE_DONECLEANUP_PROCESSEDEXP, donecleanup_processedexpMode);
         // stacked
         MODECASE(DETTOOL_MODE_TOSTACKED,        tostackedMode);
@@ -137,4 +92,7 @@
         MODECASE(DETTOOL_MODE_STACKED,          stackedMode);
         MODECASE(DETTOOL_MODE_REVERTSTACKED,    revertstackedMode);
+        MODECASE(DETTOOL_MODE_UPDATESTACKED,    updatestackedMode);
+        MODECASE(DETTOOL_MODE_PENDINGCLEANUP_STACKED, pendingcleanup_stackedMode);
+        MODECASE(DETTOOL_MODE_DONECLEANUP_STACKED, donecleanup_stackedMode);
         // normalizedstat
         MODECASE(DETTOOL_MODE_TONORMALIZEDSTAT, tonormalizedstatMode);
@@ -142,4 +100,7 @@
         MODECASE(DETTOOL_MODE_NORMALIZEDSTAT,   normalizedstatMode);
         MODECASE(DETTOOL_MODE_REVERTNORMALIZEDSTAT, revertnormalizedstatMode);
+        MODECASE(DETTOOL_MODE_UPDATENORMALIZEDSTAT, updatenormalizedstatMode);
+        MODECASE(DETTOOL_MODE_PENDINGCLEANUP_NORMALIZEDSTAT, pendingcleanup_normalizedstatMode);
+        MODECASE(DETTOOL_MODE_DONECLEANUP_NORMALIZEDSTAT, donecleanup_normalizedstatMode);
         // normalizedimfile
         MODECASE(DETTOOL_MODE_TONORMALIZE,      tonormalizeMode);
@@ -147,4 +108,7 @@
         MODECASE(DETTOOL_MODE_NORMALIZEDIMFILE, normalizedimfileMode);
         MODECASE(DETTOOL_MODE_REVERTNORMALIZEDIMFILE, revertnormalizedimfileMode);
+        MODECASE(DETTOOL_MODE_UPDATENORMALIZEDIMFILE, updatenormalizedimfileMode);
+        MODECASE(DETTOOL_MODE_PENDINGCLEANUP_NORMALIZEDIMFILE, pendingcleanup_normalizedimfileMode);
+        MODECASE(DETTOOL_MODE_DONECLEANUP_NORMALIZEDIMFILE, donecleanup_normalizedimfileMode);
         // normalizedexp
         MODECASE(DETTOOL_MODE_TONORMALIZEDEXP,  tonormalizedexpMode);
@@ -152,4 +116,7 @@
         MODECASE(DETTOOL_MODE_NORMALIZEDEXP,    normalizedexpMode);
         MODECASE(DETTOOL_MODE_REVERTNORMALIZEDEXP, revertnormalizedexpMode);
+        MODECASE(DETTOOL_MODE_UPDATENORMALIZEDEXP, updatenormalizedexpMode);
+        MODECASE(DETTOOL_MODE_PENDINGCLEANUP_NORMALIZEDEXP, pendingcleanup_normalizedexpMode);
+        MODECASE(DETTOOL_MODE_DONECLEANUP_NORMALIZEDEXP, donecleanup_normalizedexpMode);
         // residimfile
         MODECASE(DETTOOL_MODE_TORESIDIMFILE,    toresidimfileMode);
@@ -157,4 +124,7 @@
         MODECASE(DETTOOL_MODE_RESIDIMFILE,      residimfileMode);
         MODECASE(DETTOOL_MODE_REVERTRESIDIMFILE,revertresidimfileMode);
+        MODECASE(DETTOOL_MODE_UPDATERESIDIMFILE, updateresidimfileMode);
+        MODECASE(DETTOOL_MODE_PENDINGCLEANUP_RESIDIMFILE, pendingcleanup_residimfileMode);
+        MODECASE(DETTOOL_MODE_DONECLEANUP_RESIDIMFILE, donecleanup_residimfileMode);
         // residexp
         MODECASE(DETTOOL_MODE_TORESIDEXP,       toresidexpMode);
@@ -163,4 +133,6 @@
         MODECASE(DETTOOL_MODE_REVERTRESIDEXP,   revertresidexpMode);
         MODECASE(DETTOOL_MODE_UPDATERESIDEXP,   updateresidexpMode);
+        MODECASE(DETTOOL_MODE_PENDINGCLEANUP_RESIDEXP, pendingcleanup_residexpMode);
+        MODECASE(DETTOOL_MODE_DONECLEANUP_RESIDEXP, donecleanup_residexpMode);
         // detrunsummary
         MODECASE(DETTOOL_MODE_TODETRUNSUMMARY,  todetrunsummaryMode);
@@ -208,5 +180,5 @@
     
     psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-exp_id", "exp_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-exp_id", "exp_id", "==");
     PXOPT_COPY_STR(config->args, where, "-exp_type", "exp_type", "==");
     PXOPT_COPY_STR(config->args, where, "-inst", "camera", "==");
@@ -722,5 +694,5 @@
 
     
-    PXOPT_LOOKUP_STR(det_id, config->args, "-det_id", true, false); // required
+    PXOPT_LOOKUP_S64(det_id, config->args, "-det_id", true, false); // required
     PXOPT_LOOKUP_STR(det_type, config->args, "-set_det_type", false, false); // optional
     PXOPT_LOOKUP_STR(mode, config->args, "-set_mode", false, false); // optional
@@ -758,5 +730,5 @@
     {
         psMetadata *where = psMetadataAlloc();
-        psMetadataAddS64(where, PS_LIST_TAIL, "det_id", 0, "==", (psS64)atoll(det_id));
+        psMetadataAddS64(where, PS_LIST_TAIL, "det_id", 0, "==", det_id);
         detRuns = detRunSelectRowObjects(config->dbh, where, 0);
         psFree(where);
@@ -768,5 +740,5 @@
     // sanity check the result... we should have only found one det_id
     if (psArrayLength(detRuns) != 1) {
-        psAbort("found more then one detRun matching det_id %" PRId64 " (this should not happen)", (psS64)atoll(det_id));
+        psAbort("found more then one detRun matching det_id %" PRId64 " (this should not happen)", det_id);
         return false;                   // unreachable
     }
@@ -939,5 +911,5 @@
     psFree(time_filter);
 
-    if (!p_psDBRunQuery(config->dbh, query, (psS64)newDet_id, (psS64)atoll(det_id))) {
+    if (!p_psDBRunQuery(config->dbh, query, (long long) newDet_id, (long long) det_id)) {
         psError(PS_ERR_UNKNOWN, false, "database error");
         psFree(query);
@@ -987,5 +959,5 @@
     psMetadata *where = psMetadataAlloc();
     PXOPT_COPY_STR(config->args, where, "-det_type", "det_type", "==");
-    PXOPT_COPY_STR(config->args, where, "-det_id",   "det_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-det_id",   "det_id", "==");
 
     PXOPT_COPY_STR(config->args, where, "-inst", "camera", "==");
@@ -1152,5 +1124,5 @@
 
     psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",    "det_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-det_id",    "det_id", "==");
     PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
     PXOPT_COPY_S64(config->args, where, "-exp_id",    "exp_id", "==");
@@ -1251,2351 +1223,9 @@
 }
 
-static bool toprocessedimfileMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",   "det_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-exp_id",   "exp_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-class_id", "class_id", "==");
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-
-    psString query = pxDataGet("dettool_toprocessedimfile.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, "rawImfile");
-        psStringAppend(&query, " AND %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree (where);
-
-    // treat limit == 0 as "no limit"
-    if (limit) {
-        psString limitString = psDBGenerateLimitSQL(limit);
-        psStringAppend(&query, " %s", limitString);
-        psFree(limitString);
-    }
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    psArray *output = p_psDBFetchResult(config->dbh);
-    if (!output) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-    if (!psArrayLength(output)) {
-        psTrace("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "detPendingProcessedImfile", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-static bool addprocessedimfileMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    // det_id, exp_id, class_id, uri, recipe, -bg, -bg_stdev are required
-    PXOPT_LOOKUP_STR(det_id, config->args, "-det_id", true, false);
-    PXOPT_LOOKUP_STR(exp_id, config->args, "-exp_id", true, false);
-    PXOPT_LOOKUP_STR(class_id, config->args, "-class_id", true, false);
-
-    // default values
-    PXOPT_LOOKUP_S16(code, config->args, "-code", false, false);
-
-    // Required if code == 0
-    PXOPT_LOOKUP_STR(uri, config->args, "-uri", (code == 0), false);
-    PXOPT_LOOKUP_STR(recipe, config->args, "-recip", (code == 0), false);
-
-    // optional
-    PXOPT_LOOKUP_F64(bg, config->args, "-bg", false, false);
-    PXOPT_LOOKUP_F64(bg_stdev, config->args, "-bg_stdev", false, false);
-    PXOPT_LOOKUP_F64(bg_mean_stdev, config->args, "-bg_mean_stdev", false, false);
-    PXOPT_LOOKUP_F64(fringe_0, config->args, "-fringe_0", false, false);
-    PXOPT_LOOKUP_F64(fringe_1, config->args, "-fringe_1", false, false);
-    PXOPT_LOOKUP_F64(fringe_2, config->args, "-fringe_2", false, false);
-    PXOPT_LOOKUP_F64(user_1, config->args, "-user_1", false, false);
-    PXOPT_LOOKUP_F64(user_2, config->args, "-user_2", false, false);
-    PXOPT_LOOKUP_F64(user_3, config->args, "-user_3", false, false);
-    PXOPT_LOOKUP_F64(user_4, config->args, "-user_4", false, false);
-    PXOPT_LOOKUP_F64(user_5, config->args, "-user_5", false, false);
-    PXOPT_LOOKUP_STR(path_base, config->args, "-path_base", false, false);
-
-    // find the matching rawImfile by exp_id/class_id
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-exp_id",   "exp_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-class_id", "class_id", "==");
-
-    psArray *rawImfiles = rawImfileSelectRowObjects(config->dbh, where, 0);
-    psFree(where);
-
-    if (!rawImfiles) {
-        psError(PS_ERR_UNKNOWN, false, "no rawImfile rows found ");
-        return false;
-    }
-
-    // create a new detProcessedImfile object
-    detProcessedImfileRow *detRow = detProcessedImfileRowAlloc(
-        (psS64)atoll(det_id),
-        (psS64)atoll(exp_id),
-        class_id,
-        uri,
-        recipe,
-        bg,
-        bg_stdev,
-        bg_mean_stdev,
-        fringe_0,
-        fringe_1,
-        fringe_2,
-        user_1,
-        user_2,
-        user_3,
-        user_4,
-        user_5,
-        path_base,
-        code
-    );
-    psFree(rawImfiles);
-
-    // insert the new row into the detProcessedImfile table
-    if (!detProcessedImfileInsertObject(config->dbh, detRow)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(detRow);
-        return false;
-    }
-
-    psFree(detRow);
-
-    return true;
-}
-
-static bool processedimfileMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    char *value = NULL;
-
-    PXOPT_LOOKUP_BOOL(included, config->args, "-included", false);
-    PXOPT_LOOKUP_BOOL(faulted, config->args, "-faulted", false);
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id", "det_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-exp_id", "exp_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-class_id", "class_id", "==");
-
-    psString query = pxDataGet("dettool_processedimfile.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        psFree(where);
-        return false;
-    }
-
-    // add the two required restrictions: detRun.state and detRun.mode
-    // NOTE the above query requires one of the following two WHERE statements
-    {
-        bool status;
-        if ((value = psMetadataLookupStr(&status, config->args, "-select_state"))) {
-            psStringAppend(&query, " WHERE detRun.state = '%s'", value);
-        } else {
-            psStringAppend(&query, " WHERE detRun.state = 'run'");
-        }
-        if ((value = psMetadataLookupStr(&status, config->args, "-select_mode"))) {
-            psStringAppend(&query, " AND detRun.mode = '%s'", value);
-        } else {
-            psStringAppend(&query, " AND detRun.mode = 'master'");
-        }
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, "detProcessedImfile");
-        psStringAppend(&query, " AND %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree (where);
-
-    // restrict search to included imfiles
-    if (included) {
-	psStringAppend(&query, " AND detInputExp.include = 1");
-    }
-
-    if (faulted) {
-        // list only faulted rows
-        psStringAppend(&query, " %s", "AND detProcessedImfile.fault != 0");
-    } else {
-        // don't list faulted rows
-        psStringAppend(&query, " %s", "AND detProcessedImfile.fault = 0");
-    }
-
-    // treat limit == 0 as "no limit"
-    if (limit) {
-        psString limitString = psDBGenerateLimitSQL(limit);
-        psStringAppend(&query, " %s", limitString);
-        psFree(limitString);
-    }
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    psArray *output = p_psDBFetchResult(config->dbh);
-    if (!output) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-    if (!psArrayLength(output)) {
-        psTrace("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "rawImfile", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-static bool revertprocessedimfileMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id", "det_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-exp_id", "exp_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-class_id", "class_id", "==");
-    PXOPT_COPY_S16(config->args, where, "-code", "fault", "==");
-
-    psString query = pxDataGet("dettool_revertprocessedimfile.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, "detProcessedImfile");
-        psStringAppend(&query, " AND %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree(where);
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    if (psDBAffectedRows(config->dbh) < 1) {
-        psError(PS_ERR_UNKNOWN, false, "should have affected atleast 1 row");
-        return false;
-    }
-
-    return true;
-}
-
-static bool toprocessedexpMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-
-    psString query = pxDataGet("dettool_toprocessedexp.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    // treat limit == 0 as "no limit"
-    if (limit) {
-        psString limitString = psDBGenerateLimitSQL(limit);
-        psStringAppend(&query, " %s", limitString);
-        psFree(limitString);
-    }
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    psArray *output = p_psDBFetchResult(config->dbh);
-    if (!output) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-    if (!psArrayLength(output)) {
-        psTrace("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "detPendingProcessedExp", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-static bool addprocessedexpMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    // det_id, exp_id, recip, -bg, -bg_stdev
-    // are required
-    PXOPT_LOOKUP_STR(det_id, config->args, "-det_id", true, false);
-    PXOPT_LOOKUP_STR(exp_id, config->args, "-exp_id", true, false);
-
-    // default values
-    PXOPT_LOOKUP_S16(code, config->args, "-code", false, false);
-
-    // Required if code == 0
-    PXOPT_LOOKUP_STR(recipe, config->args, "-recip", (code == 0), false);
-
-    // optional
-    PXOPT_LOOKUP_F64(bg, config->args, "-bg", false, false);
-    PXOPT_LOOKUP_F64(bg_stdev, config->args, "-bg_stdev", false, false);
-    PXOPT_LOOKUP_F64(bg_mean_stdev, config->args, "-bg_mean_stdev", false, false);
-    PXOPT_LOOKUP_F64(fringe_0, config->args, "-fringe_0", false, false);
-    PXOPT_LOOKUP_F64(fringe_1, config->args, "-fringe_1", false, false);
-    PXOPT_LOOKUP_F64(fringe_2, config->args, "-fringe_2", false, false);
-    PXOPT_LOOKUP_F64(user_1, config->args, "-user_1", false, false);
-    PXOPT_LOOKUP_F64(user_2, config->args, "-user_2", false, false);
-    PXOPT_LOOKUP_F64(user_3, config->args, "-user_3", false, false);
-    PXOPT_LOOKUP_F64(user_4, config->args, "-user_4", false, false);
-    PXOPT_LOOKUP_F64(user_5, config->args, "-user_5", false, false);
-    PXOPT_LOOKUP_STR(path_base, config->args, "-path_base", true, false);
-
-    psString query = pxDataGet("dettool_addprocessedexp.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (!p_psDBRunQuery(config->dbh, query, det_id, exp_id)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    psArray *output = p_psDBFetchResult(config->dbh);
-    if (!output) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-    if (!psArrayLength(output)) {
-        psTrace("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-    psFree(output);
-
-    // create a new detProcessedImfile object
-    detProcessedExpRow *detRow = detProcessedExpRowAlloc(
-        (psS64)atoll(det_id),
-        (psS64)atoll(exp_id),
-        recipe,
-        bg,
-        bg_stdev,
-        bg_mean_stdev,
-        fringe_0,
-        fringe_1,
-        fringe_2,
-        user_1,
-        user_2,
-        user_3,
-        user_4,
-        user_5,
-        path_base,
-        code
-    );
-
-    // insert the new row into the detProcessedImfile table
-    if (!detProcessedExpInsertObject(config->dbh, detRow)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(detRow);
-        return false;
-    }
-
-    psFree(detRow);
-
-    return true;
-}
-
-static bool processedexpMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id", "det_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-exp_id", "exp_id", "==");
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(faulted, config->args, "-faulted", false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-
-    psString query = psStringCopy("SELECT * FROM detProcessedExp");
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereSQL(where, NULL);
-        psStringAppend(&query, " %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree(where);
-
-    if (faulted) {
-        // list only faulted rows
-        psStringAppend(&query, " %s", "AND detProcessedExp.fault != 0");
-    } else {
-        // don't list faulted rows
-        psStringAppend(&query, " %s", "AND detProcessedExp.fault = 0");
-    }
-
-    // treat limit == 0 as "no limit"
-    if (limit) {
-        psString limitString = psDBGenerateLimitSQL(limit);
-        psStringAppend(&query, " %s", limitString);
-        psFree(limitString);
-    }
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    psArray *output = p_psDBFetchResult(config->dbh);
-    if (!output) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-    if (!psArrayLength(output)) {
-        psTrace("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "detProcessedExp", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-
-static bool revertprocessedexpMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id", "det_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-exp_id", "exp_id", "==");
-    PXOPT_COPY_S16(config->args, where, "-code",   "fault", "==");
-
-    psString query = pxDataGet("dettool_revertprocessedexp.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, "detProcessedExp");
-        psStringAppend(&query, " AND %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree(where);
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    if (psDBAffectedRows(config->dbh) < 1) {
-        psError(PS_ERR_UNKNOWN, false, "should have affected atleast 1 row");
-        return false;
-    }
-
-    return true;
-}
-
-
-static bool tostackedMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-
-    psString query = pxDataGet("dettool_tostacked.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    // treat limit == 0 as "no limit"
-    if (limit) {
-        psString limitString = psDBGenerateLimitSQL(limit);
-        psStringAppend(&query, " %s", limitString);
-        psFree(limitString);
-    }
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    psArray *output = p_psDBFetchResult(config->dbh);
-    if (!output) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-    if (!psArrayLength(output)) {
-        psTrace("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "detPendingStackedImfile", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-// this is NOT a command-line mode : it is used by 'addstackedMode'
-static psArray *searchRawImfiles(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, NULL);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",    "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-
-    // select exp_ids from detInputExp matching det_id & iteration
-    // where query should be pre-generated
-    psArray *detInputExp = detInputExpSelectRowObjects(config->dbh, where, 0);
-    psFree (where);
-
-    if (!detInputExp) {
-        psError(PS_ERR_UNKNOWN, false, "no rawExp rows found");
-        return NULL;
-    }
-
-    // generate where query with just the exp_ids
-    psMetadata *where_exp_ids = psMetadataAlloc();
-    for (long i = 0; i < psArrayLength(detInputExp); i++) {
-        detInputExpRow *row = detInputExp->data[i];
-        if (!psMetadataAddS64(where_exp_ids, PS_LIST_TAIL, "exp_id",
-                PS_META_DUPLICATE_OK, "==", row->exp_id)
-        ) {
-            psError(PS_ERR_UNKNOWN, false, "failed to add item exp_id");
-            psFree(detInputExp);
-            psFree(where_exp_ids);
-            return NULL;
-        }
-    }
-    psFree(detInputExp);
-
-    // select rawImfiles with matching exp_ids
-    psArray *rawImfiles =
-        rawImfileSelectRowObjects(config->dbh, where_exp_ids, 0);
-    psFree(where_exp_ids);
-    if (!rawImfiles) {
-        psError(PS_ERR_UNKNOWN, false, "no rawImfile rows found");
-        return NULL;
-    }
-
-    return rawImfiles;
-}
-
-static bool addstackedMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    // det_id, iteration, class_id, uri, & recipe are required
-    PXOPT_LOOKUP_STR(det_id, config->args, "-det_id", true, false);
-    PXOPT_LOOKUP_S32(iteration, config->args, "-iteration", true, false);
-    PXOPT_LOOKUP_STR(class_id, config->args, "-class_id", true, false);
-
-    PXOPT_LOOKUP_S16(code, config->args, "-code", false, false);
-
-    // Required if code == 0
-    PXOPT_LOOKUP_STR(uri, config->args, "-uri", (code == 0), false);
-    PXOPT_LOOKUP_STR(recipe, config->args, "-recip", (code == 0), false);
-
-    // optional
-    PXOPT_LOOKUP_F64(bg, config->args, "-bg", false, false);
-    PXOPT_LOOKUP_F64(bg_stdev, config->args, "-bg_stdev", false, false);
-    PXOPT_LOOKUP_F64(bg_mean_stdev, config->args, "-bg_mean_stdev", false, false);
-    PXOPT_LOOKUP_F64(user_1, config->args, "-user_1", false, false);
-    PXOPT_LOOKUP_F64(user_2, config->args, "-user_2", false, false);
-    PXOPT_LOOKUP_F64(user_3, config->args, "-user_3", false, false);
-    PXOPT_LOOKUP_F64(user_4, config->args, "-user_4", false, false);
-    PXOPT_LOOKUP_F64(user_5, config->args, "-user_5", false, false);
-
-    // correlate the class_id against the input exposure(s)
-    // searchRawImfiles defines a where clause to search by det_id and iteration
-    psArray *rawImfiles = searchRawImfiles(config);
-
-    if (!rawImfiles) {
-        psError(PS_ERR_UNKNOWN, false, "failed to get rawImfiles from db");
-        return false;
-    }
-
-    bool valid_class_id = false;
-    if (rawImfiles) {
-        for (long i = 0; i < psArrayLength(rawImfiles); i++) {
-            if (!rawImfiles->data[i]) {
-                fprintf (stderr, "*");
-                continue;
-            }
-            if (strcmp(class_id, ((rawImfileRow *)rawImfiles->data[i])->class_id) == 0) {
-                valid_class_id = true;
-                break;
-            }
-        }
-        psFree(rawImfiles);
-    }
-
-    if (!valid_class_id) {
-        psError(PS_ERR_UNKNOWN, true,
-            "class_id can not be correlated with the input exposures");
-        return false;
-    }
-
-    // create a new detStackedImfile object
-    detStackedImfileRow *stackedImfile = detStackedImfileRowAlloc(
-            (psS64)atoll(det_id),
-            iteration,
-            class_id,
-            uri,
-            recipe,
-            bg,
-            bg_stdev,
-            bg_mean_stdev,
-            user_1,
-            user_2,
-            user_3,
-            user_4,
-            user_5,
-            code
-        );
-
-    // insert the new row into the detProcessedImfile table
-    if (!detStackedImfileInsertObject(config->dbh, stackedImfile)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(stackedImfile);
-        return false;
-    }
-
-    psFree(stackedImfile);
-
-    return true;
-}
-
-static bool stackedMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",    "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-    PXOPT_COPY_STR(config->args, where, "-class_id",  "class_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-recip",     "recipe", "==");
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(faulted, config->args, "-faulted", false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-
-    psString query = pxDataGet("dettool_stacked.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        psFree(where);
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, "detStackedImfile");
-        psStringAppend(&query, " AND %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree(where);
-
-    if (faulted) {
-        // list only faulted rows
-        psStringAppend(&query, " %s", "AND detStackedImfile.fault != 0");
-    } else {
-        // don't list faulted rows
-        psStringAppend(&query, " %s", "AND detStackedImfile.fault = 0");
-    }
-
-    // treat limit == 0 as "no limit"
-    if (limit) {
-        psString limitString = psDBGenerateLimitSQL(limit);
-        psStringAppend(&query, " %s", limitString);
-        psFree(limitString);
-    }
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    psArray *output = p_psDBFetchResult(config->dbh);
-    if (!output) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-    if (!psArrayLength(output)) {
-        psTrace("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "rawImfile", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-
-static bool revertstackedMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",    "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-    PXOPT_COPY_STR(config->args, where, "-class_id",  "class_id", "==");
-    PXOPT_COPY_S16(config->args, where, "-code",      "fault", "==");
-
-    psString query = pxDataGet("dettool_revertstacked.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, "detStackedImfile");
-        psStringAppend(&query, " AND %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree(where);
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    if (psDBAffectedRows(config->dbh) < 1) {
-        psError(PS_ERR_UNKNOWN, false, "should have affected atleast 1 row");
-        return false;
-    }
-
-    return true;
-}
-
-static bool tonormalizedstatMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-
-    psString query = pxDataGet("dettool_tonormalizedstat.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    // treat limit == 0 as "no limit"
-    if (limit) {
-        psString limitString = psDBGenerateLimitSQL(limit);
-        psStringAppend(&query, " %s", limitString);
-        psFree(limitString);
-    }
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    psArray *output = p_psDBFetchResult(config->dbh);
-    if (!output) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-    if (!psArrayLength(output)) {
-        psTrace("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "detPendingNormStatImfile", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-static bool addnormalizedstatMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, NULL);
-
-    // required
-    PXOPT_LOOKUP_STR(det_id, config->args, "-det_id", true, false);
-    PXOPT_LOOKUP_STR(class_id, config->args, "-class_id", true, false);
-
-    // optional
-    PXOPT_LOOKUP_F32(norm, config->args, "-norm", false, false);
-
-    // default
-    PXOPT_LOOKUP_S32(iteration, config->args, "-iteration", false, false);
-    PXOPT_LOOKUP_S16(code, config->args, "-code", false, false);
-
-    if (!detNormalizedStatImfileInsert(config->dbh,
-        (psS64)atoll(det_id),
-        iteration,
-        class_id,
-        norm,
-        code
-    )) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-
-    return true;
-}
-
-
-static bool normalizedstatMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",    "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-    PXOPT_COPY_STR(config->args, where, "-class_id",  "class_id", "==");
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(faulted, config->args, "-faulted", false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-
-    psString query = pxDataGet("dettool_normalizedstat.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (faulted) {
-        // list only faulted rows
-        psStringAppend(&query, " %s", "WHERE fault != 0");
-    } else {
-        // don't list faulted rows
-        psStringAppend(&query, " %s", "WHERE fault = 0");
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
-        psStringAppend(&query, " AND %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree(where);
-
-    // treat limit == 0 as "no limit"
-    if (limit) {
-        psString limitString = psDBGenerateLimitSQL(limit);
-        psStringAppend(&query, " %s", limitString);
-        psFree(limitString);
-    }
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    psArray *output = p_psDBFetchResult(config->dbh);
-    if (!output) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-    if (!psArrayLength(output)) {
-        psTrace("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "detNormalizedStatImfile", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-static bool revertnormalizedstatMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",    "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-    PXOPT_COPY_STR(config->args, where, "-class_id",  "class_id", "==");
-    PXOPT_COPY_S16(config->args, where, "-code",      "fault", "==");
-
-    psString query = pxDataGet("dettool_revertnormalizedstat.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, "detNormalizedStatImfile");
-        psStringAppend(&query, " AND %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree(where);
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    if (psDBAffectedRows(config->dbh) < 1) {
-        psError(PS_ERR_UNKNOWN, false, "should have affected atleast 1 row");
-        return false;
-    }
-
-    return true;
-}
-
-static bool tonormalizeMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-
-    psString query = pxDataGet("dettool_tonormalize.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    // treat limit == 0 as "no limit"
-    if (limit) {
-        psString limitString = psDBGenerateLimitSQL(limit);
-        psStringAppend(&query, " %s", limitString);
-        psFree(limitString);
-    }
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    psArray *output = p_psDBFetchResult(config->dbh);
-    if (!output) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-    if (!psArrayLength(output)) {
-        psTrace("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "detPendingNormImfile", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-static bool addnormalizedimfileMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    // required
-    PXOPT_LOOKUP_STR(det_id, config->args, "-det_id", true, false);
-    PXOPT_LOOKUP_S32(iteration, config->args, "-iteration", false, false);
-    PXOPT_LOOKUP_STR(class_id, config->args, "-class_id", true, false);
-
-    PXOPT_LOOKUP_S16(code, config->args, "-code", false, false);
-
-    // Required if code == 0
-    PXOPT_LOOKUP_STR(uri, config->args, "-uri", (code == 0), false);
-
-    // optional
-    PXOPT_LOOKUP_F64(bg, config->args, "-bg", false, false);
-    PXOPT_LOOKUP_F64(bg_stdev, config->args, "-bg_stdev", false, false);
-    PXOPT_LOOKUP_F64(bg_mean_stdev, config->args, "-bg_mean_stdev", false, false);
-    PXOPT_LOOKUP_F64(user_1, config->args, "-user_1", false, false);
-    PXOPT_LOOKUP_F64(user_2, config->args, "-user_2", false, false);
-    PXOPT_LOOKUP_F64(user_3, config->args, "-user_3", false, false);
-    PXOPT_LOOKUP_F64(user_4, config->args, "-user_4", false, false);
-    PXOPT_LOOKUP_F64(user_5, config->args, "-user_5", false, false);
-    PXOPT_LOOKUP_STR(path_base, config->args, "-path_base", false, false);
-
-    if (!detNormalizedImfileInsert(config->dbh,
-        (psS64)atoll(det_id),
-        iteration,
-        class_id,
-        uri,
-        bg,
-        bg_stdev,
-        bg_mean_stdev,
-        user_1,
-        user_2,
-        user_3,
-        user_4,
-        user_5,
-        path_base,
-        code
-    )) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-
-    return true;
-}
-
-static bool normalizedimfileMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",    "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-    PXOPT_COPY_STR(config->args, where, "-class_id",  "class_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-recip",     "recipe", "==");
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-    PXOPT_LOOKUP_BOOL(faulted, config->args, "-faulted", false);
-
-    psString query = pxDataGet("dettool_normalizedimfile.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, "detNormalizedImfile");
-        psStringAppend(&query, " AND %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree(where);
-
-    if (faulted) {
-        // list only faulted rows
-        psStringAppend(&query, " %s", "AND detNormalizedImfile.fault != 0");
-    } else {
-        // don't list faulted rows
-        psStringAppend(&query, " %s", "AND detNormalizedImfile.fault = 0");
-    }
-
-    // treat limit == 0 as "no limit"
-    if (limit) {
-        psString limitString = psDBGenerateLimitSQL(limit);
-        psStringAppend(&query, " %s", limitString);
-        psFree(limitString);
-    }
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    psArray *output = p_psDBFetchResult(config->dbh);
-    if (!output) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-    if (!psArrayLength(output)) {
-        psTrace("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "detNormalizedImfile", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-
-static bool revertnormalizedimfileMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",    "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-    PXOPT_COPY_STR(config->args, where, "-class_id",  "class_id", "==");
-    PXOPT_COPY_S16(config->args, where, "-code",      "fault", "==");
-
-    psString query = pxDataGet("dettool_revertnormalizedimfile.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, "detNormalizedImfile");
-        psStringAppend(&query, " AND %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree(where);
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    if (psDBAffectedRows(config->dbh) < 1) {
-        psError(PS_ERR_UNKNOWN, false, "should have affected atleast 1 row");
-        return false;
-    }
-
-    return true;
-}
-
-static bool tonormalizedexpMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-
-    psString query = pxDataGet("dettool_tonormalizedexp.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    // treat limit == 0 as "no limit"
-    if (limit) {
-        psString limitString = psDBGenerateLimitSQL(limit);
-        psStringAppend(&query, " %s", limitString);
-        psFree(limitString);
-    }
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    psArray *output = p_psDBFetchResult(config->dbh);
-    if (!output) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-    if (!psArrayLength(output)) {
-        psTrace("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "detPendingNormExp", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-static bool addnormalizedexpMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-    
-    PXOPT_LOOKUP_STR(det_id, config->args, "-det_id", true, false); // required
-    PXOPT_LOOKUP_S32(iteration, config->args, "-iteration", false, false);
-    PXOPT_LOOKUP_S16(code, config->args, "-code", false, false);
-    PXOPT_LOOKUP_STR(recipe, config->args, "-recip", (code == 0), false); // Required if code == 0
-    PXOPT_LOOKUP_F64(bg, config->args, "-bg", false, false);
-    PXOPT_LOOKUP_F64(bg_stdev, config->args, "-bg_stdev", false, false);
-    PXOPT_LOOKUP_F64(bg_mean_stdev, config->args, "-bg_mean_stdev", false, false);
-    PXOPT_LOOKUP_F64(user_1, config->args, "-user_1", false, false);
-    PXOPT_LOOKUP_F64(user_2, config->args, "-user_2", false, false);
-    PXOPT_LOOKUP_F64(user_3, config->args, "-user_3", false, false);
-    PXOPT_LOOKUP_F64(user_4, config->args, "-user_4", false, false);
-    PXOPT_LOOKUP_F64(user_5, config->args, "-user_5", false, false);
-    PXOPT_LOOKUP_STR(path_base, config->args, "-path_base", false, false);
-
-    psString query = pxDataGet("dettool_tonormalizedexp.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    // XXX in some other places, we put the arguments in the .sql and supply them to RunQuery
-    psStringAppend(&query, " WHERE det_id = %s AND iteration = %d", det_id, iteration);
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    psArray *output = p_psDBFetchResult(config->dbh);
-    if (!output) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-    if (!psArrayLength(output)) {
-        psTrace("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-    psFree(output);
-
-    // insert the new row into the detProcessedImfile table
-    if (!detNormalizedExpInsert(config->dbh,
-        (psS64)atoll(det_id),
-        iteration,
-        recipe,
-        bg,
-        bg_stdev,
-        bg_mean_stdev,
-        user_1,
-        user_2,
-        user_3,
-        user_4,
-        user_5,
-        path_base,
-        code
-    )) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-
-    return true;
-}
-
-
-static bool normalizedexpMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",    "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-    PXOPT_COPY_STR(config->args, where, "-recip",  "recipe", "==");
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-    PXOPT_LOOKUP_BOOL(faulted, config->args, "-faulted", false);
-
-    psString query = pxDataGet("dettool_normalizedexp.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereSQL(where, NULL);
-        psStringAppend(&query, " %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree(where);
-
-    if (faulted) {
-        // list only faulted rows
-        psStringAppend(&query, " %s", "AND detNormalizedExp.fault != 0");
-    } else {
-        // don't list faulted rows
-        psStringAppend(&query, " %s", "AND detNormalizedExp.fault = 0");
-    }
-
-    // treat limit == 0 as "no limit"
-    if (limit) {
-        psString limitString = psDBGenerateLimitSQL(limit);
-        psStringAppend(&query, " %s", limitString);
-        psFree(limitString);
-    }
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    psArray *output = p_psDBFetchResult(config->dbh);
-    if (!output) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-    if (!psArrayLength(output)) {
-        psTrace("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "detNormalizedExp", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-
-
-static bool revertnormalizedexpMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",    "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-    PXOPT_COPY_S16(config->args, where, "-code",      "fault", "==");
-
-    psString query = pxDataGet("dettool_revertnormalizedexp.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, "detNormalizedExp");
-        psStringAppend(&query, " AND %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree(where);
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    if (psDBAffectedRows(config->dbh) < 1) {
-        psError(PS_ERR_UNKNOWN, false, "should have affected atleast 1 row");
-        return false;
-    }
-
-    return true;
-}
-
-
-static bool toresidimfileMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-
-    psString query = pxDataGet("dettool_toresidimfile.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    // treat limit == 0 as "no limit"
-    if (limit) {
-        psString limitString = psDBGenerateLimitSQL(limit);
-        psStringAppend(&query, " %s", limitString);
-        psFree(limitString);
-    }
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    psArray *output = p_psDBFetchResult(config->dbh);
-    if (!output) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-    if (!psArrayLength(output)) {
-        psTrace("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "detPendingResidImfile", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-
-static bool addresidimfileMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    
-    PXOPT_LOOKUP_STR(det_id, config->args, "-det_id", true, false); // required
-    PXOPT_LOOKUP_S32(iteration, config->args, "-iteration", false, false);
-    PXOPT_LOOKUP_STR(exp_id, config->args, "-exp_id", true, false); // required
-    PXOPT_LOOKUP_STR(class_id, config->args, "-class_id", true, false); // required
-    PXOPT_LOOKUP_S16(code, config->args, "-code", false, false);
-    PXOPT_LOOKUP_STR(uri, config->args, "-uri", (code == 0), false); // Required if code == 0
-    PXOPT_LOOKUP_STR(recipe, config->args, "-recip", (code == 0), false); // Required if code == 0
-    PXOPT_LOOKUP_F64(bg, config->args, "-bg", false, false);
-    PXOPT_LOOKUP_F64(bg_stdev, config->args, "-bg_stdev", false, false);
-    PXOPT_LOOKUP_F64(bg_mean_stdev, config->args, "-bg_mean_stdev", false, false);
-    PXOPT_LOOKUP_F64(bg_skewness, config->args, "-bg_skewness", false, false);
-    PXOPT_LOOKUP_F64(bg_kurtosis, config->args, "-bg_kurtosis", false, false);
-    PXOPT_LOOKUP_F64(bin_stdev, config->args, "-bin_stdev", false, false);
-    PXOPT_LOOKUP_F64(fringe_0, config->args, "-fringe_0", false, false);
-    PXOPT_LOOKUP_F64(fringe_1, config->args, "-fringe_1", false, false);
-    PXOPT_LOOKUP_F64(fringe_2, config->args, "-fringe_2", false, false);
-    PXOPT_LOOKUP_F64(fringe_resid_0, config->args, "-fringe_resid_0", false, false);
-    PXOPT_LOOKUP_F64(fringe_resid_1, config->args, "-fringe_resid_1", false, false);
-    PXOPT_LOOKUP_F64(fringe_resid_2, config->args, "-fringe_resid_2", false, false);
-    PXOPT_LOOKUP_F64(user_1, config->args, "-user_1", false, false);
-    PXOPT_LOOKUP_F64(user_2, config->args, "-user_2", false, false);
-    PXOPT_LOOKUP_F64(user_3, config->args, "-user_3", false, false);
-    PXOPT_LOOKUP_F64(user_4, config->args, "-user_4", false, false);
-    PXOPT_LOOKUP_F64(user_5, config->args, "-user_5", false, false);
-    PXOPT_LOOKUP_STR(path_base, config->args, "-path_base", false, false);
-
-    if (!detResidImfileInsert(config->dbh,
-            (psS64)atoll(det_id),
-            iteration,
-            (psS64)atoll(exp_id),
-            class_id,
-            uri,
-            recipe,
-            bg,
-            bg_stdev,
-            bg_mean_stdev,
-            bg_skewness,
-            bg_kurtosis,
-            bin_stdev,
-            fringe_0,
-            fringe_1,
-            fringe_2,
-            fringe_resid_0,
-            fringe_resid_1,
-            fringe_resid_2,
-            user_1,
-            user_2,
-            user_3,
-            user_4,
-            user_5,
-            path_base,
-            code
-    )) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-
-    return true;
-}
-
-
-static bool residimfileMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",     "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration",  "iteration", "==");
-    PXOPT_COPY_STR(config->args, where, "-exp_id",     "exp_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-class_id",   "class_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-recip",      "recipe", "==");
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-    PXOPT_LOOKUP_BOOL(faulted, config->args, "-faulted", false);
-
-    psString query = pxDataGet("dettool_residimfile.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    // NOTE: the query ends in a WHERE, add the required restriction on detRun.state
-    char *value = NULL;
-    bool status;
-    if ((value = psMetadataLookupStr(&status, config->args, "-select_state"))) {
-        psStringAppend(&query, " detRun.state = '%s'", value);
-    } else {
-        psStringAppend(&query, " detRun.state = 'run'");
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, "detResidImfile");
-        psStringAppend(&query, " AND %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree(where);
-
-    if (faulted) {
-        // list only faulted rows
-        psStringAppend(&query, " %s", "AND detResidImfile.fault != 0");
-    } else {
-        // don't list faulted rows
-        psStringAppend(&query, " %s", "AND detResidImfile.fault = 0");
-    }
-
-    // treat limit == 0 as "no limit"
-    if (limit) {
-        psString limitString = psDBGenerateLimitSQL(limit);
-        psStringAppend(&query, " %s", limitString);
-        psFree(limitString);
-    }
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    psArray *output = p_psDBFetchResult(config->dbh);
-    if (!output) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-    if (!psArrayLength(output)) {
-        psTrace("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "rawResidImfile", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-
-static bool revertresidimfileMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",    "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-    PXOPT_COPY_STR(config->args, where, "-exp_id",  "exp_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-class_id",  "class_id", "==");
-    PXOPT_COPY_S16(config->args, where, "-code",      "fault", "==");
-
-    psString query = pxDataGet("dettool_revertresidimfile.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, "detResidImfile");
-        psStringAppend(&query, " AND %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree(where);
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    if (psDBAffectedRows(config->dbh) < 1) {
-        psError(PS_ERR_UNKNOWN, false, "should have affected atleast 1 row");
-        return false;
-    }
-
-    return true;
-}
-
-
-/*
-  The SQL returns a list of exposures for which all component class ids have had residuals
-  created.  This list includes the detrend id, iteration, exposure id, detrend type, and
-  whether the exposure was included in the stack for this iteration.
-*/
-
-static bool toresidexpMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-
-    psString query = pxDataGet("dettool_toresidexp.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    // treat limit == 0 as "no limit"
-    if (limit) {
-        psString limitString = psDBGenerateLimitSQL(limit);
-        psStringAppend(&query, " %s", limitString);
-        psFree(limitString);
-    }
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    psArray *output = p_psDBFetchResult(config->dbh);
-    if (!output) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-    if (!psArrayLength(output)) {
-        psTrace("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "detPendingResidExp", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-/*
-  The SQL returns a list of exposures for which all component class ids have had residuals
-  created.  This list includes the detrend id, iteration, exposure id, detrend type, and
-  whether the exposure was included in the stack for this iteration.
-*/
-
-static bool addresidexpMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    // limit search by det_id, iteration, exp_id
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id", "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-    PXOPT_COPY_STR(config->args, where, "-exp_id", "exp_id", "==");
-
-    PXOPT_LOOKUP_STR(det_id, config->args, "-det_id", true, false); // required
-    PXOPT_LOOKUP_S32(iteration, config->args, "-iteration", false, false);
-    PXOPT_LOOKUP_STR(exp_id, config->args, "-exp_id", true, false); // required
-    PXOPT_LOOKUP_S16(code, config->args, "-code", false, false);
-    PXOPT_LOOKUP_STR(recipe, config->args, "-recip", (code == 0), false); // Required if code == 0
-    PXOPT_LOOKUP_F64(bg, config->args, "-bg", false, false);
-    PXOPT_LOOKUP_F64(bg_stdev, config->args, "-bg_stdev", false, false);
-    PXOPT_LOOKUP_F64(bg_mean_stdev, config->args, "-bg_mean_stdev", false, false);
-    PXOPT_LOOKUP_F64(bg_skewness, config->args, "-bg_skewness", false, false);
-    PXOPT_LOOKUP_F64(bg_kurtosis, config->args, "-bg_kurtosis", false, false);
-    PXOPT_LOOKUP_F64(bin_stdev, config->args, "-bin_stdev", false, false);
-    PXOPT_LOOKUP_F64(fringe_0, config->args, "-fringe_0", false, false);
-    PXOPT_LOOKUP_F64(fringe_1, config->args, "-fringe_1", false, false);
-    PXOPT_LOOKUP_F64(fringe_2, config->args, "-fringe_2", false, false);
-    PXOPT_LOOKUP_F64(fringe_resid_0, config->args, "-fringe_resid_0", false, false);
-    PXOPT_LOOKUP_F64(fringe_resid_1, config->args, "-fringe_resid_1", false, false);
-    PXOPT_LOOKUP_F64(fringe_resid_2, config->args, "-fringe_resid_2", false, false);
-    PXOPT_LOOKUP_F64(user_1, config->args, "-user_1", false, false);
-    PXOPT_LOOKUP_F64(user_2, config->args, "-user_2", false, false);
-    PXOPT_LOOKUP_F64(user_3, config->args, "-user_3", false, false);
-    PXOPT_LOOKUP_F64(user_4, config->args, "-user_4", false, false);
-    PXOPT_LOOKUP_F64(user_5, config->args, "-user_5", false, false);
-    PXOPT_LOOKUP_STR(path_base, config->args, "-path_base", false, false);
-    PXOPT_LOOKUP_BOOL(reject, config->args, "-reject", false);
-
-    psString query = pxDataGet("dettool_toresidexp.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-	psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
-	psStringAppend(&query, " WHERE %s", whereClause);
-	psFree(whereClause);
-    }
-    psFree(where);
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    psArray *output = p_psDBFetchResult(config->dbh);
-    if (!output) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-    if (!psArrayLength(output)) {
-        // XXX check psError here
-        psError(PS_ERR_UNKNOWN, false, "no detResidImfile rows found");
-        psFree(output);
-        return false;
-    }
-    psFree(output);
-
-    if (!detResidExpInsert(config->dbh,
-            (psS64)atoll(det_id),
-            iteration,
-            (psS64)atoll(exp_id),
-            recipe,
-            bg,
-            bg_stdev,
-            bg_mean_stdev,
-            bg_skewness,
-            bg_kurtosis,
-            bin_stdev,
-            fringe_0,
-            fringe_1,
-            fringe_2,
-            fringe_resid_0,
-            fringe_resid_1,
-            fringe_resid_2,
-            user_1,
-            user_2,
-            user_3,
-            user_4,
-            user_5,
-            path_base,
-            !reject,
-            code
-        )) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-
-    return true;
-}
-
-static bool residexpMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",    "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-    PXOPT_COPY_STR(config->args, where, "-exp_id",    "exp_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-recip",     "recipe", "==");
-
-    PXOPT_LOOKUP_U64(limit,    config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(simple,  config->args, "-simple", false);
-    PXOPT_LOOKUP_BOOL(faulted, config->args, "-faulted", false);
-    PXOPT_LOOKUP_BOOL(reject,  config->args, "-reject", false);
-
-    psString query = pxDataGet("dettool_residexp.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, "detResidExp");
-        psStringAppend(&query, " AND %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree(where);
-
-    if (faulted) {
-        // list only faulted rows
-        psStringAppend(&query, " %s", "AND detResidExp.fault != 0");
-    } else {
-        // don't list faulted rows
-        psStringAppend(&query, " %s", "AND detResidExp.fault = 0");
-    }
-
-    // list only accepted rows
-    // XXX the usage of this flag is unclear : -reject means "accepted"?
-    if (reject) {
-        psStringAppend(&query, " %s", "AND detResidExp.accept != 0");
-    } 
-
-    // treat limit == 0 as "no limit"
-    if (limit) {
-        psString limitString = psDBGenerateLimitSQL(limit);
-        psStringAppend(&query, " %s", limitString);
-        psFree(limitString);
-    }
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    psArray *output = p_psDBFetchResult(config->dbh);
-    if (!output) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-    if (!psArrayLength(output)) {
-        psTrace("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "detResidExp", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-
-static bool revertresidexpMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",    "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-    PXOPT_COPY_STR(config->args, where, "-exp_id",    "exp_id", "==");
-    PXOPT_COPY_S16(config->args, where, "-code",      "fault", "==");
-
-    psString query = pxDataGet("dettool_revertresidexp.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, "detResidExp");
-        psStringAppend(&query, " AND %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree(where);
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    if (psDBAffectedRows(config->dbh) < 1) {
-        psError(PS_ERR_UNKNOWN, false, "should have affected atleast 1 row");
-        return false;
-    }
-
-    return true;
-}
-
-
-static bool updateresidexpMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    PXOPT_LOOKUP_BOOL(reject, config->args, "-reject", false);
-
-    // build a query to search by det_id, iteration, exp_id
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id", "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-    PXOPT_COPY_STR(config->args, where, "-exp_id", "exp_id", "==");
-
-    // find the values we're going to set
-    // copy everything but det_id, iteration, & exp_id from the args and
-    // remove the '-' prefix
-    psMetadata *set = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, set, "-recip", "recipe", "==");
-    PXOPT_COPY_F64(config->args, set, "-bg", "bg", "==");
-    PXOPT_COPY_F64(config->args, set, "-bg_stdev", "bg_stdev", "==");
-    PXOPT_COPY_F64(config->args, set, "-bg_mean_stdev", "bg_mean_stdev", "==");
-    PXOPT_COPY_STR(config->args, set, "-path_base", "path_base", "==");
-
-    // this can't be PXOPT_ macro-ized as reject is !'d
-    if (!psMetadataAddBool(set, PS_LIST_TAIL, "accept", 0, "==", !reject)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item accept");
-        psFree(set);
-        psFree(where);
-        return false;
-    }
-
-    long changed = psDBUpdateRows(config->dbh, "detResidExp", where, set);
-    psFree(set);
-    psFree(where);
-
-    if (changed < 0) {
-        psError(PS_ERR_UNKNOWN, false, "no rows were updated");
-        return false;
-    }
-
-    return true;
-}
-
-/* The SQL returns a list of detrend runs (with detrend id, iteration and detrend type) which
- * have completed all residexps.
- */
-
-static bool todetrunsummaryMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-
-    psString query = pxDataGet("dettool_todetrunsummary.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    // treat limit == 0 as "no limit"
-    if (limit) {
-        psString limitString = psDBGenerateLimitSQL(limit);
-        psStringAppend(&query, " %s", limitString);
-        psFree(limitString);
-    }
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    psArray *output = p_psDBFetchResult(config->dbh);
-    if (!output) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-    if (!psArrayLength(output)) {
-        psTrace("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "detRejectExp", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-// this function is used to generate the detrunSummary entries used below
-// XXX why is this a separate function?  roll it back into adddetrunsummary?
-static detRunSummaryRow *mdToDetRunSummary(pxConfig *config, psMetadata *row)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    bool status = false;
-    // from row
-    psS64 det_id = psMetadataLookupS64(&status, row, "det_id");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for det_id");
-        return false;
-    }
-    psS32 iteration = psMetadataLookupS32(&status, row, "iteration");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for iteration");
-        return false;
-    }
-
-    // optional
-    PXOPT_LOOKUP_F64(bg, config->args, "-bg", false, false);
-    PXOPT_LOOKUP_F64(bg_stdev, config->args, "-bg_stdev", false, false);
-    PXOPT_LOOKUP_F64(bg_mean_stdev, config->args, "-bg_mean_stdev", false, false);
-
-    // default values
-    PXOPT_LOOKUP_S16(code, config->args, "-code", false, false);
-    PXOPT_LOOKUP_BOOL(accept, config->args, "-accept", false);
-
-    return detRunSummaryRowAlloc(
-            det_id,
-            iteration,
-            bg,
-            bg_stdev,
-            bg_mean_stdev,
-            accept,
-            code
-        );
-}
-
-static bool adddetrunsummaryMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-    
-    // build a query to search by det_id, iteration, exp_id
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id", "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-
-    PXOPT_LOOKUP_STR(det_id, config->args, "-det_id", true, false); // required
-    PXOPT_LOOKUP_BOOL(again, config->args, "-again", false);
-
-    // The values supplied as arguments on the command (eg, -bg) are parsed 
-    // by mdToDetRunSummary below. 
-    // XXX why is there ever more than one?
-
-    psString query = pxDataGet("dettool_find_completed_runs.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
-	psStringAppend(&query, " WHERE %s", whereClause);
-	psFree(whereClause);
-    }
-    psFree(where);
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    psArray *output = p_psDBFetchResult(config->dbh);
-    if (!output) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-    if (!psArrayLength(output)) {
-        psTrace("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // start a transaction so it's all rows or nothing
-    if (!psDBTransaction(config->dbh)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(output);
-        return false;
-    }
-
-    // XXX why is there ever more than one result here?
-    for (long i = 0; i < psArrayLength(output); i++) {
-        psMetadata *row = output->data[i];
-        // convert metadata into a detResidExp object
-        detRunSummaryRow *runSummary = mdToDetRunSummary(config, row);
-        if (!runSummary) {
-            if (!psDBRollback(config->dbh)) {
-                psError(PS_ERR_UNKNOWN, false, "database error");
-            }
-            psError(PS_ERR_UNKNOWN, false, "failed to convert metadata to detResidExp");
-            psFree(output);
-            return false;
-        }
-        // insert detResidExp object into the database
-        if (!detRunSummaryInsertObject(config->dbh, runSummary)) {
-            if (!psDBRollback(config->dbh)) {
-                psError(PS_ERR_UNKNOWN, false, "database error");
-            }
-            psError(PS_ERR_UNKNOWN, false, "database error");
-            psFree(runSummary);
-            psFree(output);
-            return false;
-        }
-        psFree(runSummary);
-    }
-
-    psFree(output);
-
-    // XXX this logic does not deal with the case of -code being set
-    // XXX it should be an error for -again and -code to both be set
-    if (again) {
-        if (!startNewIteration(config, (psS64)atoll(det_id))) {
-            if (!psDBRollback(config->dbh)) {
-                psError(PS_ERR_UNKNOWN, false, "database error");
-            }
-            psError(PS_ERR_UNKNOWN, false, "failed to start new iteration");
-            return false;
-        }
-    } else {
-        // set detRun.state to stop
-        if (!setDetRunState(config, (psS64)atoll(det_id), "stop")) {
-            if (!psDBRollback(config->dbh)) {
-                psError(PS_ERR_UNKNOWN, false, "database error");
-            }
-            psError(PS_ERR_UNKNOWN, false, "failed to set detRun.state");
-            return false;
-        }
-    }
-
-    if (!psDBCommit(config->dbh)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-    return true;
-}
-
-static bool detrunsummaryMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",    "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-    PXOPT_LOOKUP_BOOL(faulted, config->args, "-faulted", false);
-
-    psString query = pxDataGet("dettool_detrunsummary.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        psFree(where);
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, "NULL");
-        psStringAppend(&query, " AND %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree(where);
-
-    if (faulted) {
-        // list only faulted rows
-        psStringAppend(&query, " %s", "AND detRunSummary.fault != 0");
-    } else {
-        // don't list faulted rows
-        psStringAppend(&query, " %s", "AND detRunSummary.fault = 0");
-    }
-
-    // treat limit == 0 as "no limit"
-    if (limit) {
-        psString limitString = psDBGenerateLimitSQL(limit);
-        psStringAppend(&query, " %s", limitString);
-        psFree(limitString);
-    }
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    psArray *output = p_psDBFetchResult(config->dbh);
-    if (!output) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-    if (!psArrayLength(output)) {
-        psTrace("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "rawDetrendImfile", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-
-static bool revertdetrunsummaryMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",    "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-    PXOPT_COPY_STR(config->args, where, "-code",      "fault", "==");
-
-    psString query = pxDataGet("dettool_revertdetrunsummary.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, "detRunSummary");
-        psStringAppend(&query, " AND %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree(where);
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    if (psDBAffectedRows(config->dbh) < 1) {
-        psError(PS_ERR_UNKNOWN, false, "should have affected atleast 1 row");
-        return false;
-    }
-
-    return true;
-}
-
-
-static bool updatedetrunsummaryMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-    
-    PXOPT_LOOKUP_STR(det_id, config->args, "-det_id", true, false); // required
-    PXOPT_LOOKUP_BOOL(accept, config->args, "-accept", false);
-    PXOPT_LOOKUP_BOOL(reject, config->args, "-reject", false);
-
-    if (accept && reject) {
-        psError(PS_ERR_UNKNOWN, true, "-accept and -reject are exclusive");
-        return false;
-    }
-
-    if (!(accept || reject)) {
-        psError(PS_ERR_UNKNOWN, true, "either -accept or -reject is required");
-        return false;
-    }
-
-    char *query = "UPDATE detRunSummary SET accept = %d WHERE det_id = %"PRId64; 
-    if (!p_psDBRunQuery(config->dbh, query, accept, (psS64)atoll(det_id))) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-
-    return true;
-}
-
-
 static bool updatedetrunMode(pxConfig *config)
 {
     PS_ASSERT_PTR_NON_NULL(config, false);
 
-    PXOPT_LOOKUP_STR(det_id, config->args, "-det_id", true, false); // required
+    PXOPT_LOOKUP_S64(det_id, config->args, "-det_id", true, false); // required
     PXOPT_LOOKUP_BOOL(again, config->args, "-again", false);
     PXOPT_LOOKUP_STR(state, config->args, "-state", false, false);
@@ -3613,10 +1243,10 @@
     if (state) {
         // set detRun.state to state
-        return setDetRunState(config, (psS64)atoll(det_id), state);
+        return setDetRunState(config, det_id, state);
     }
 
     // else
     // -again
-    if (!startNewIteration(config, (psS64)atoll(det_id))) {
+    if (!startNewIteration(config, det_id)) {
         psError(PS_ERR_UNKNOWN, false, "failed to start new iteration");
         return false;
@@ -3627,5 +1257,5 @@
 
 // used by updatedetrunMode 
-static bool startNewIteration(pxConfig *config, psS64 det_id)
+bool startNewIteration(pxConfig *config, psS64 det_id)
 {
     PS_ASSERT_PTR_NON_NULL(config, false);
@@ -3739,5 +1369,5 @@
 
     // det_id is required
-    PXOPT_LOOKUP_STR(det_id, config->args, "-det_id", true, false);
+    PXOPT_LOOKUP_S64(det_id, config->args, "-det_id", true, false);
 
     // we have to support multipe exp_ids
@@ -3784,6 +1414,5 @@
 
     // add the det_id & iteration == 0 to the where clause
-    if (!psMetadataAddS64(where, PS_LIST_TAIL, "det_id", 0, "==",
-                (psS64)atoll(det_id))) {
+    if (!psMetadataAddS64(where, PS_LIST_TAIL, "det_id", 0, "==", det_id)) {
         psError(PS_ERR_UNKNOWN, false, "failed to add item det_id");
         psFree(where);
@@ -3822,5 +1451,5 @@
 
     // up the detRuns iteration count
-    psS32 newIteration = incrementIteration(config, (psS64)atoll(det_id));
+    psS32 newIteration = incrementIteration(config, det_id);
     if (!newIteration) {
         // rollback
@@ -3846,5 +1475,5 @@
             }
             // invalid exp_id
-            psError(PS_ERR_UNKNOWN, false, "exp_id %s is invalid for det_id %s",
+            psError(PS_ERR_UNKNOWN, false, "exp_id %s is invalid for det_id %" PRId64,
                     (char *)mItem->data.V, det_id);
             psFree(iter);
@@ -3853,5 +1482,5 @@
         }
         detInputExpRow *newInputExp = detInputExpRowAlloc(
-            (psS64)atoll(det_id),
+	    det_id,
             newIteration,
             inputExp->exp_id,
@@ -3912,5 +1541,5 @@
     PXOPT_LOOKUP_TIME(use_begin, config->args, "-use_begin", false, false);
     PXOPT_LOOKUP_TIME(use_end, config->args, "-use_end", false, false);
-    PXOPT_LOOKUP_STR(parent, config->args, "-parent", false, false);
+    PXOPT_LOOKUP_S64(parent, config->args, "-parent", false, false);
     PXOPT_LOOKUP_STR(label, config->args, "-label", false, false);
     PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
@@ -3950,5 +1579,5 @@
                       solang_max,
                       label,      // label
-                      parent ? (psS64)atoll(parent) : 0
+                      parent
             )) {
         psError(PS_ERR_UNKNOWN, false, "database error");
@@ -4001,5 +1630,5 @@
     PS_ASSERT_PTR_NON_NULL(config, false);
     
-    PXOPT_LOOKUP_STR(det_id, config->args, "-det_id", true, false); // required
+    PXOPT_LOOKUP_S64(det_id, config->args, "-det_id", true, false); // required
     PXOPT_LOOKUP_STR(class_id, config->args, "-class_id", true, false); // required
     PXOPT_LOOKUP_STR(uri, config->args, "-uri", true, false); // required
@@ -4015,19 +1644,20 @@
 
     if (!detRegisteredImfileInsert(config->dbh,
-        (psS64)atoll(det_id),
-        0,  // the iteration is fixed at 0
-        class_id,
-        uri,
-        bg,
-        bg_stdev,
-        bg_mean_stdev,
-        user_1,
-        user_2,
-        user_3,
-        user_4,
-        user_5,
-        path_base,
-        0       // fault code
-    )) {
+				   det_id,
+				   0,  // the iteration is fixed at 0
+				   class_id,
+				   uri,
+				   bg,
+				   bg_stdev,
+				   bg_mean_stdev,
+				   user_1,
+				   user_2,
+				   user_3,
+				   user_4,
+				   user_5,
+				   path_base,
+				   "full",				   
+				   0       // fault code
+	    )) {
         psError(PS_ERR_UNKNOWN, false, "database error");
         return false;
@@ -4075,5 +1705,5 @@
 }
 
-static bool setDetRunState(pxConfig *config, psS64 det_id, const char *state)
+bool setDetRunState(pxConfig *config, psS64 det_id, const char *state)
 {
     PS_ASSERT_PTR_NON_NULL(config, false);
@@ -4103,5 +1733,17 @@
 }
 
-static bool isValidMode(pxConfig *config, const char *mode)
+bool isValidDataState (const char *data_state) {
+
+    // check that state is a valid string value
+    if (!strncmp(data_state, "run", 4)) return true;
+    if (!strncmp(data_state, "stop", 5)) return true;
+    if (!strncmp(data_state, "drop", 5)) return true;
+    if (!strncmp(data_state, "register", 4)) return true;
+
+    psError(PS_ERR_UNKNOWN, true, "invalid data state: %s", data_state);
+    return false;
+}
+
+bool isValidMode(pxConfig *config, const char *mode)
 {
     PS_ASSERT_PTR_NON_NULL(config, false);
@@ -4122,4 +1764,177 @@
 }
 
+
+bool setProcessedImfileDataState(pxConfig *config, psS64 det_id, psS64 exp_id, const char *class_id, const char *data_state)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+    PS_ASSERT_PTR_NON_NULL(data_state, false);
+    PS_ASSERT_PTR_NON_NULL(class_id, false);
+
+    if (!isValidDataState (data_state)) return false;
+
+    char *query = "UPDATE detProcessedImfile SET data_state = '%s'"
+	" WHERE det_id = %" PRId64
+	" AND exp_id = %" PRId64 
+	" AND class_id = '%s'";
+    if (!p_psDBRunQuery(config->dbh, query, data_state, det_id, exp_id, class_id)) {
+        psError(PS_ERR_UNKNOWN, false,
+                "failed to change state for det_id %" PRId64 ", exp_id %" PRId64 ", class_id %s", 
+		det_id, exp_id, class_id);
+        return false;
+    }
+
+    return true;
+}
+
+bool setProcessedExpDataState(pxConfig *config, psS64 det_id, psS64 exp_id, const char *data_state)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+    PS_ASSERT_PTR_NON_NULL(data_state, false);
+
+    if (!isValidDataState (data_state)) return false;
+
+    char *query = "UPDATE detProcessedExp SET data_state = '%s'"
+	" WHERE det_id = %" PRId64
+	" AND exp_id = %" PRId64;
+    if (!p_psDBRunQuery(config->dbh, query, data_state, det_id, exp_id)) {
+        psError(PS_ERR_UNKNOWN, false,
+                "failed to change state for det_id %" PRId64 ", exp_id %" PRId64, 
+		det_id, exp_id);
+        return false;
+    }
+
+    return true;
+}
+
+
+bool setStackedImfileDataState(pxConfig *config, psS64 det_id, psS32 iteration, const char *class_id, const char *data_state)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+    PS_ASSERT_PTR_NON_NULL(class_id, false);
+    PS_ASSERT_PTR_NON_NULL(data_state, false);
+
+    if (!isValidDataState (data_state)) return false;
+
+    char *query = "UPDATE detStackedImfile SET data_state = '%s'"
+	" WHERE det_id = %" PRId64
+	" AND iteration = %" PRId32
+	" AND class_id = %s";
+    if (!p_psDBRunQuery(config->dbh, query, data_state, det_id, iteration, class_id)) {
+        psError(PS_ERR_UNKNOWN, false,
+                "failed to change state for det_id %" PRId64 ", iteration %" PRId32 "class_id %s", 
+		det_id, iteration, class_id);
+        return false;
+    }
+
+    return true;
+}
+
+bool setNormStatImfileDataState(pxConfig *config, psS64 det_id, psS32 iteration, const char *class_id, const char *data_state)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+    PS_ASSERT_PTR_NON_NULL(class_id, false);
+    PS_ASSERT_PTR_NON_NULL(data_state, false);
+
+    if (!isValidDataState (data_state)) return false;
+
+    char *query = "UPDATE detNormalizedStatImfile SET data_state = '%s'"
+	" WHERE det_id = %" PRId64
+	" AND iteration = %" PRId32
+	" AND class_id = %s";
+    if (!p_psDBRunQuery(config->dbh, query, data_state, det_id, iteration)) {
+        psError(PS_ERR_UNKNOWN, false,
+                "failed to change state for det_id %" PRId64 ", iteration %" PRId32, 
+		det_id, iteration);
+        return false;
+    }
+
+    return true;
+}
+
+bool setNormImfileDataState(pxConfig *config, psS64 det_id, psS32 iteration, const char *class_id, const char *data_state)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+    PS_ASSERT_PTR_NON_NULL(class_id, false);
+    PS_ASSERT_PTR_NON_NULL(data_state, false);
+
+    if (!isValidDataState (data_state)) return false;
+
+    char *query = "UPDATE detNormalizedImfile SET data_state = '%s'"
+	" WHERE det_id = %" PRId64
+	" AND iteration = %" PRId32
+	" AND class_id = %s";
+    if (!p_psDBRunQuery(config->dbh, query, data_state, det_id, iteration, class_id)) {
+        psError(PS_ERR_UNKNOWN, false,
+                "failed to change state for det_id %" PRId64 ", iteration %" PRId32 " class %s", 
+		det_id, iteration, class_id);
+        return false;
+    }
+
+    return true;
+}
+
+bool setNormExpDataState(pxConfig *config, psS64 det_id, psS32 iteration, const char *data_state)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+    PS_ASSERT_PTR_NON_NULL(data_state, false);
+
+    if (!isValidDataState (data_state)) return false;
+
+    char *query = "UPDATE detNormalizedExp SET data_state = '%s'"
+	" WHERE det_id = %" PRId64
+	" AND iteration = %" PRId32;
+    if (!p_psDBRunQuery(config->dbh, query, data_state, det_id, iteration)) {
+        psError(PS_ERR_UNKNOWN, false,
+                "failed to change state for det_id %" PRId64 ", iteration %" PRId32, 
+		det_id, iteration);
+        return false;
+    }
+
+    return true;
+}
+
+bool setResidImfileDataState(pxConfig *config, psS64 det_id, psS32 iteration, psS64 exp_id, const char *class_id, const char *data_state)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+    PS_ASSERT_PTR_NON_NULL(data_state, false);
+    PS_ASSERT_PTR_NON_NULL(class_id, false);
+
+    if (!isValidDataState (data_state)) return false;
+
+    char *query = "UPDATE detResidImfile SET data_state = '%s'"
+	" WHERE det_id = %" PRId64
+	" AND iteration = %" PRId32 
+	" AND exp_id = %" PRId64 
+	" AND class_id = '%s'";
+    if (!p_psDBRunQuery(config->dbh, query, data_state, det_id, iteration, exp_id, class_id)) {
+        psError(PS_ERR_UNKNOWN, false,
+                "failed to change state for det_id %" PRId64 ", iteration %" PRId32 ", exp_id %" PRId64 ", class_id %s", 
+		det_id, iteration, exp_id, class_id);
+        return false;
+    }
+
+    return true;
+}
+
+bool setResidExpDataState(pxConfig *config, psS64 det_id, psS32 iteration, psS64 exp_id, const char *data_state)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+    PS_ASSERT_PTR_NON_NULL(data_state, false);
+
+    if (!isValidDataState (data_state)) return false;
+
+    char *query = "UPDATE detResidExp SET data_state = '%s'"
+	" WHERE det_id = %" PRId64
+	" AND iteration = %" PRId32 
+	" AND exp_id = %" PRId64;
+    if (!p_psDBRunQuery(config->dbh, query, data_state, det_id, iteration, exp_id)) {
+        psError(PS_ERR_UNKNOWN, false,
+                "failed to change state for det_id %" PRId64 ", iteration %" PRId32 ", exp_id %" PRId64, 
+		det_id, iteration, exp_id);
+        return false;
+    }
+
+    return true;
+}
 
 #if 0
Index: /trunk/ippTools/src/dettool.h
===================================================================
--- /trunk/ippTools/src/dettool.h	(revision 19091)
+++ /trunk/ippTools/src/dettool.h	(revision 19092)
@@ -41,41 +41,73 @@
     DETTOOL_MODE_INPUT,
     DETTOOL_MODE_RAW,
+
     DETTOOL_MODE_TOPROCESSEDIMFILE,
     DETTOOL_MODE_ADDPROCESSEDIMFILE,
     DETTOOL_MODE_PROCESSEDIMFILE,
     DETTOOL_MODE_REVERTPROCESSEDIMFILE,
+    DETTOOL_MODE_UPDATEPROCESSEDIMFILE,
+    DETTOOL_MODE_PENDINGCLEANUP_PROCESSEDIMFILE,
+    DETTOOL_MODE_DONECLEANUP_PROCESSEDIMFILE,
+
     DETTOOL_MODE_TOPROCESSEDEXP,
     DETTOOL_MODE_ADDPROCESSEDEXP,
     DETTOOL_MODE_PROCESSEDEXP,
     DETTOOL_MODE_REVERTPROCESSEDEXP,
+    DETTOOL_MODE_UPDATEPROCESSEDEXP,
+    DETTOOL_MODE_PENDINGCLEANUP_PROCESSEDEXP,
+    DETTOOL_MODE_DONECLEANUP_PROCESSEDEXP,
+
     DETTOOL_MODE_TOSTACKED,
     DETTOOL_MODE_ADDSTACKED,
     DETTOOL_MODE_STACKED,
     DETTOOL_MODE_REVERTSTACKED,
+    DETTOOL_MODE_UPDATESTACKED,
+    DETTOOL_MODE_PENDINGCLEANUP_STACKED,
+    DETTOOL_MODE_DONECLEANUP_STACKED,
+
     DETTOOL_MODE_TONORMALIZEDSTAT,
     DETTOOL_MODE_ADDNORMALIZEDSTAT,
     DETTOOL_MODE_NORMALIZEDSTAT,
     DETTOOL_MODE_REVERTNORMALIZEDSTAT,
+    DETTOOL_MODE_UPDATENORMALIZEDSTAT,
+    DETTOOL_MODE_PENDINGCLEANUP_NORMALIZEDSTAT,
+    DETTOOL_MODE_DONECLEANUP_NORMALIZEDSTAT,
+
     DETTOOL_MODE_TONORMALIZE,
     DETTOOL_MODE_ADDNORMALIZEDIMFILE,
     DETTOOL_MODE_NORMALIZEDIMFILE,
     DETTOOL_MODE_REVERTNORMALIZEDIMFILE,
+    DETTOOL_MODE_UPDATENORMALIZEDIMFILE,
+    DETTOOL_MODE_PENDINGCLEANUP_NORMALIZEDIMFILE,
+    DETTOOL_MODE_DONECLEANUP_NORMALIZEDIMFILE,
+
     DETTOOL_MODE_TONORMALIZEDEXP,
     DETTOOL_MODE_ADDNORMALIZEDEXP,
     DETTOOL_MODE_NORMALIZEDEXP,
     DETTOOL_MODE_REVERTNORMALIZEDEXP,
+    DETTOOL_MODE_UPDATENORMALIZEDEXP,
+    DETTOOL_MODE_PENDINGCLEANUP_NORMALIZEDEXP,
+    DETTOOL_MODE_DONECLEANUP_NORMALIZEDEXP,
+
     DETTOOL_MODE_TORESIDIMFILE,
     DETTOOL_MODE_ADDRESIDIMFILE,
     DETTOOL_MODE_RESIDIMFILE,
     DETTOOL_MODE_REVERTRESIDIMFILE,
+    DETTOOL_MODE_UPDATERESIDIMFILE,
+    DETTOOL_MODE_PENDINGCLEANUP_RESIDIMFILE,
+    DETTOOL_MODE_DONECLEANUP_RESIDIMFILE,
+
     DETTOOL_MODE_TORESIDEXP,
     DETTOOL_MODE_ADDRESIDEXP,
     DETTOOL_MODE_RESIDEXP,
     DETTOOL_MODE_REVERTRESIDEXP,
+    DETTOOL_MODE_UPDATERESIDEXP,
+    DETTOOL_MODE_PENDINGCLEANUP_RESIDEXP,
+    DETTOOL_MODE_DONECLEANUP_RESIDEXP,
+
     DETTOOL_MODE_TODETRUNSUMMARY,
     DETTOOL_MODE_ADDDETRUNSUMMARY,
     DETTOOL_MODE_DETRUNSUMMARY,
     DETTOOL_MODE_REVERTDETRUNSUMMARY,
-    DETTOOL_MODE_UPDATERESIDEXP,
     DETTOOL_MODE_UPDATEDETRUNSUMMARY,
     DETTOOL_MODE_UPDATEDETRUN,
@@ -92,6 +124,102 @@
 bool tocorrectimfileMode(pxConfig *config);
 bool addcorrectimfileMode(pxConfig *config);
+
 // register
 bool register_detrend_imfileMode(pxConfig *config);
 
+// processedimfile
+bool toprocessedimfileMode(pxConfig *config);
+bool addprocessedimfileMode(pxConfig *config);
+bool processedimfileMode(pxConfig *config);
+bool revertprocessedimfileMode(pxConfig *config);
+bool updateprocessedimfileMode(pxConfig *config);
+bool pendingcleanup_processedimfileMode(pxConfig *config);
+bool donecleanup_processedimfileMode(pxConfig *config);
+
+// processedexp
+bool toprocessedexpMode(pxConfig *config);
+bool addprocessedexpMode(pxConfig *config);
+bool processedexpMode(pxConfig *config);
+bool revertprocessedexpMode(pxConfig *config);
+bool updateprocessedexpMode(pxConfig *config);
+bool pendingcleanup_processedexpMode(pxConfig *config);
+bool donecleanup_processedexpMode(pxConfig *config);
+
+// stackedimfile
+bool tostackedMode(pxConfig *config);
+bool addstackedMode(pxConfig *config);
+bool stackedMode(pxConfig *config);
+bool revertstackedMode(pxConfig *config);
+bool updatestackedMode(pxConfig *config);
+bool pendingcleanup_stackedMode(pxConfig *config);
+bool donecleanup_stackedMode(pxConfig *config);
+
+// normalizedstat
+bool tonormalizedstatMode(pxConfig *config);
+bool addnormalizedstatMode(pxConfig *config);
+bool normalizedstatMode(pxConfig *config);
+bool revertnormalizedstatMode(pxConfig *config);
+bool updatenormalizedstatMode(pxConfig *config);
+bool pendingcleanup_normalizedstatMode(pxConfig *config);
+bool donecleanup_normalizedstatMode(pxConfig *config);
+
+// normalizedimfile
+bool tonormalizeMode(pxConfig *config);
+bool addnormalizedimfileMode(pxConfig *config);
+bool normalizedimfileMode(pxConfig *config);
+bool revertnormalizedimfileMode(pxConfig *config);
+bool updatenormalizedimfileMode(pxConfig *config);
+bool pendingcleanup_normalizedimfileMode(pxConfig *config);
+bool donecleanup_normalizedimfileMode(pxConfig *config);
+
+// normalizedexp
+bool tonormalizedexpMode(pxConfig *config);
+bool addnormalizedexpMode(pxConfig *config);
+bool normalizedexpMode(pxConfig *config);
+bool revertnormalizedexpMode(pxConfig *config);
+bool updatenormalizedexpMode(pxConfig *config);
+bool pendingcleanup_normalizedexpMode(pxConfig *config);
+bool donecleanup_normalizedexpMode(pxConfig *config);
+
+// residimfile
+bool toresidimfileMode(pxConfig *config);
+bool addresidimfileMode(pxConfig *config);
+bool residimfileMode(pxConfig *config);
+bool revertresidimfileMode(pxConfig *config);
+bool updateresidimfileMode(pxConfig *config);
+bool pendingcleanup_residimfileMode(pxConfig *config);
+bool donecleanup_residimfileMode(pxConfig *config);
+
+// residexp
+bool toresidexpMode(pxConfig *config);
+bool addresidexpMode(pxConfig *config);
+bool residexpMode(pxConfig *config);
+bool revertresidexpMode(pxConfig *config);
+bool updateresidexpMode(pxConfig *config);
+bool pendingcleanup_residexpMode(pxConfig *config);
+bool donecleanup_residexpMode(pxConfig *config);
+
+// detrunsummary
+bool todetrunsummaryMode(pxConfig *config);
+bool adddetrunsummaryMode(pxConfig *config);
+bool detrunsummaryMode(pxConfig *config);
+bool revertdetrunsummaryMode(pxConfig *config);
+bool updatedetrunsummaryMode(pxConfig *config);
+
+// other utilities
+bool startNewIteration(pxConfig *config, psS64 det_id);
+bool setDetRunState(pxConfig *config, psS64 det_id, const char *state);
+bool isValidDataState (const char *data_state);
+bool isValidMode(pxConfig *config, const char *mode);
+
+// functions to set the 'data_state' for stages
+bool setProcessedImfileDataState(pxConfig *config, psS64 det_id, psS64 exp_id, const char *class_id, const char *data_state);
+bool setProcessedExpDataState(pxConfig *config, psS64 det_id, psS64 exp_id, const char *data_state);
+bool setStackedImfileDataState(pxConfig *config, psS64 det_id, psS32 iteration, const char *class_id, const char *data_state);
+bool setNormStatImfileDataState(pxConfig *config, psS64 det_id, psS32 iteration, const char *class_id, const char *data_state);
+bool setNormImfileDataState(pxConfig *config, psS64 det_id, psS32 iteration, const char *class_id, const char *data_state);
+bool setNormExpDataState(pxConfig *config, psS64 det_id, psS32 iteration, const char *data_state);
+bool setResidImfileDataState(pxConfig *config, psS64 det_id, psS32 iteration, psS64 exp_id, const char *class_id, const char *data_state);
+bool setResidExpDataState(pxConfig *config, psS64 det_id, psS32 iteration, psS64 exp_id, const char *data_state);
+
 #endif // DETTOOL_H
Index: /trunk/ippTools/src/dettoolConfig.c
===================================================================
--- /trunk/ippTools/src/dettoolConfig.c	(revision 19091)
+++ /trunk/ippTools/src/dettoolConfig.c	(revision 19092)
@@ -41,5 +41,5 @@
     // XXX EAM : is this used?  does it make sense?
     psMetadata *pendingArgs = psMetadataAlloc();
-    psMetadataAddStr(pendingArgs, PS_LIST_TAIL, "-exp_id",  0,            "search by exposure ID", NULL);
+    psMetadataAddS64(pendingArgs, PS_LIST_TAIL, "-exp_id",  0,            "search by exposure ID", 0);
     psMetadataAddStr(pendingArgs, PS_LIST_TAIL, "-exp_type",  0,            "search by exposure type", NULL);
     psMetadataAddStr(pendingArgs, PS_LIST_TAIL, "-inst",  0,            "search by camera", NULL);
@@ -51,5 +51,5 @@
     // -definebytag
     psMetadata *definebytagArgs = psMetadataAlloc();
-    psMetadataAddStr(definebytagArgs, PS_LIST_TAIL, "-exp_id",            PS_META_DUPLICATE_OK,           "include this exposure (multiple OK, required)", NULL);
+    psMetadataAddS64(definebytagArgs, PS_LIST_TAIL, "-exp_id",            PS_META_DUPLICATE_OK,           "include this exposure (multiple OK, required)", 0);
     psMetadataAddStr(definebytagArgs, PS_LIST_TAIL, "-det_type",  0,            "define the type of detrend run (required)", NULL);
     psMetadataAddStr(definebytagArgs, PS_LIST_TAIL, "-mode",  0,            "define the mode of this detrend run", "master");
@@ -132,5 +132,5 @@
     // -definebydetrun
     psMetadata *definebydetrunArgs = psMetadataAlloc();
-    psMetadataAddStr(definebydetrunArgs, PS_LIST_TAIL, "-det_id",  0,            "det ID to base a new detRun on (required)", NULL);
+    psMetadataAddS64(definebydetrunArgs, PS_LIST_TAIL, "-det_id",  0,            "det ID to base a new detRun on (required)", 0);
     psMetadataAddStr(definebydetrunArgs, PS_LIST_TAIL, "-set_det_type",  0,            "define the type of detrend run", NULL);
     psMetadataAddStr(definebydetrunArgs, PS_LIST_TAIL, "-set_mode",  0,            "define the mode of this detrend run", "master");
@@ -163,5 +163,5 @@
     // -makecorrection
     psMetadata *makecorrectionArgs = psMetadataAlloc();
-    psMetadataAddStr(makecorrectionArgs, PS_LIST_TAIL, "-det_id",  0,            "det ID to be corrected (required)", NULL);
+    psMetadataAddS64(makecorrectionArgs, PS_LIST_TAIL, "-det_id",  0,            "det ID to be corrected (required)", 0);
     psMetadataAddBool(makecorrectionArgs, PS_LIST_TAIL, "-simple", 0,            "use the simple output format", false);
 
@@ -173,5 +173,5 @@
     // -tocorrectimfile
     psMetadata *tocorrectimfileArgs = psMetadataAlloc();
-    psMetadataAddStr(tocorrectimfileArgs, PS_LIST_TAIL, "-det_id", 0,            "search for detrend ID", NULL);
+    psMetadataAddS64(tocorrectimfileArgs, PS_LIST_TAIL, "-det_id", 0,            "search for detrend ID", 0);
     psMetadataAddU64(tocorrectimfileArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
     psMetadataAddBool(tocorrectimfileArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
@@ -179,5 +179,5 @@
     // -addcorrectimfile
     psMetadata *addcorrectimfileArgs = psMetadataAlloc();
-    psMetadataAddStr(addcorrectimfileArgs, PS_LIST_TAIL, "-det_id",  0,            "define detrend ID (required)", NULL);
+    psMetadataAddS64(addcorrectimfileArgs, PS_LIST_TAIL, "-det_id",  0,            "define detrend ID (required)", 0);
     psMetadataAddStr(addcorrectimfileArgs, PS_LIST_TAIL, "-class_id",  0,            "search for class ID (required)", NULL);
     psMetadataAddStr(addcorrectimfileArgs, PS_LIST_TAIL, "-uri",  0,            "define resid file URI", NULL);
@@ -195,5 +195,5 @@
     psMetadata *runsArgs = psMetadataAlloc();
     psMetadataAddStr(runsArgs, PS_LIST_TAIL, "-det_type",  0,            "search for type of detrend run", NULL);
-    psMetadataAddStr(runsArgs, PS_LIST_TAIL, "-det_id", 0,            "search for detrend ID", NULL);
+    psMetadataAddS64(runsArgs, PS_LIST_TAIL, "-det_id", 0,            "search for detrend ID", 0);
     psMetadataAddStr(runsArgs, PS_LIST_TAIL, "-inst", 0,            "search for camera (instrument)", NULL);
     psMetadataAddStr(runsArgs, PS_LIST_TAIL, "-telescope", 0,            "search for telescope", NULL);
@@ -215,5 +215,5 @@
     // -input
     psMetadata *inputArgs = psMetadataAlloc();
-    psMetadataAddStr(inputArgs, PS_LIST_TAIL, "-det_id", 0,            "search for detrend ID", NULL);
+    psMetadataAddS64(inputArgs, PS_LIST_TAIL, "-det_id", 0,            "search for detrend ID", 0);
     psMetadataAddS32(inputArgs, PS_LIST_TAIL, "-iteration",  0,            "define iteration number", 0);
     psMetadataAddS64(inputArgs, PS_LIST_TAIL, "-exp_id",  0,            "search for exp ID", 0);
@@ -226,6 +226,6 @@
     // -toprocessedimfile
     psMetadata *toprocessedimfileArgs = psMetadataAlloc();
-    psMetadataAddStr(toprocessedimfileArgs, PS_LIST_TAIL, "-det_id",  0,            "search for detrend ID", NULL);
-    psMetadataAddStr(toprocessedimfileArgs, PS_LIST_TAIL, "-exp_id",  0,            "search for exp ID", NULL);
+    psMetadataAddS64(toprocessedimfileArgs, PS_LIST_TAIL, "-det_id",  0,            "search for detrend ID", 0);
+    psMetadataAddS64(toprocessedimfileArgs, PS_LIST_TAIL, "-exp_id",  0,            "search for exp ID", 0);
     psMetadataAddStr(toprocessedimfileArgs, PS_LIST_TAIL, "-class_id",  0,            "search for class ID", NULL);
     psMetadataAddU64(toprocessedimfileArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
@@ -234,6 +234,6 @@
     // -addprocessedimfile
     psMetadata *addprocessedimfileArgs = psMetadataAlloc();
-    psMetadataAddStr(addprocessedimfileArgs, PS_LIST_TAIL, "-det_id",  0,            "define detrend ID (required)", NULL);
-    psMetadataAddStr(addprocessedimfileArgs, PS_LIST_TAIL, "-exp_id",  0,            "define exp ID (required)", NULL);
+    psMetadataAddS64(addprocessedimfileArgs, PS_LIST_TAIL, "-det_id",  0,            "define detrend ID (required)", 0);
+    psMetadataAddS64(addprocessedimfileArgs, PS_LIST_TAIL, "-exp_id",  0,            "define exp ID (required)", 0);
     psMetadataAddStr(addprocessedimfileArgs, PS_LIST_TAIL, "-class_id",  0,            "define class ID (required)", NULL);
     psMetadataAddS16(addprocessedimfileArgs, PS_LIST_TAIL, "-code",  0,            "set fault code", 0);
@@ -255,6 +255,6 @@
     // -processedimfile
     psMetadata *processedimfileArgs = psMetadataAlloc();
-    psMetadataAddStr(processedimfileArgs, PS_LIST_TAIL, "-det_id",  0,            "search for detrend ID", NULL);
-    psMetadataAddStr(processedimfileArgs, PS_LIST_TAIL, "-exp_id",  0,            "search for exp ID", NULL);
+    psMetadataAddS64(processedimfileArgs, PS_LIST_TAIL, "-det_id",  0,            "search for detrend ID", 0);
+    psMetadataAddS64(processedimfileArgs, PS_LIST_TAIL, "-exp_id",  0,            "search for exp ID", 0);
     psMetadataAddStr(processedimfileArgs, PS_LIST_TAIL, "-class_id",  0,            "search for class ID", NULL);
     psMetadataAddStr(processedimfileArgs, PS_LIST_TAIL, "-select_state",  0,            "search for state", NULL);
@@ -265,14 +265,33 @@
     psMetadataAddBool(processedimfileArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
 
-    // XXX these don't seem to be used anymore
-    // psMetadataAddBool(processedimfileArgs, PS_LIST_TAIL, "-chip",  0,            "restrict results to completed 'chip' sets", false);
-    // psMetadataAddBool(processedimfileArgs, PS_LIST_TAIL, "-exp",  0,            "restrict results to complete 'exposures'", false);
-
     // -revertprocessedimfile
     psMetadata *revertprocessedimfileArgs = psMetadataAlloc();
-    psMetadataAddStr(revertprocessedimfileArgs, PS_LIST_TAIL, "-det_id",  0,            "search for detrend ID", NULL);
-    psMetadataAddStr(revertprocessedimfileArgs, PS_LIST_TAIL, "-exp_id",  0,            "search by exposure ID", NULL);
+    psMetadataAddS64(revertprocessedimfileArgs, PS_LIST_TAIL, "-det_id",  0,            "search for detrend ID (required)", 0);
+    psMetadataAddS64(revertprocessedimfileArgs, PS_LIST_TAIL, "-exp_id",  0,            "search by exposure ID", 0);
     psMetadataAddStr(revertprocessedimfileArgs, PS_LIST_TAIL, "-class_id",  0,            "search by class ID", NULL);
     psMetadataAddS16(revertprocessedimfileArgs, PS_LIST_TAIL, "-code",  0,            "search by fault code", 0);
+
+    // -updateprocessedimfile
+    psMetadata *updateprocessedimfileArgs = psMetadataAlloc();
+    psMetadataAddS64(updateprocessedimfileArgs, PS_LIST_TAIL, "-det_id",               0,            "search by chip ID", 0);
+    psMetadataAddS64(updateprocessedimfileArgs, PS_LIST_TAIL, "-exp_id",               0,            "search by exp_id", 0);
+    psMetadataAddStr(updateprocessedimfileArgs, PS_LIST_TAIL, "-class_id",             0,            "search by exp_name", NULL);
+    psMetadataAddStr(updateprocessedimfileArgs, PS_LIST_TAIL, "-data_state",           0,            "search for telescope", NULL);
+
+    // -pendingcleanup_processedimfile
+    psMetadata *pendingcleanup_processedimfileArgs = psMetadataAlloc();
+    psMetadataAddBool(pendingcleanup_processedimfileArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(pendingcleanup_processedimfileArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+    psMetadataAddS64(pendingcleanup_processedimfileArgs, PS_LIST_TAIL, "-det_id",               0,            "search by chip ID", 0);
+    psMetadataAddS64(pendingcleanup_processedimfileArgs, PS_LIST_TAIL, "-exp_id",  0,            "search by exposure ID", 0);
+    psMetadataAddStr(pendingcleanup_processedimfileArgs, PS_LIST_TAIL, "-class_id",  0,            "search by class ID", NULL);
+
+    // -donecleanup_processedimfile
+    psMetadata *donecleanup_processedimfileArgs = psMetadataAlloc();
+    psMetadataAddBool(donecleanup_processedimfileArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(donecleanup_processedimfileArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+    psMetadataAddS64(donecleanup_processedimfileArgs, PS_LIST_TAIL, "-det_id",               0,            "search by chip ID", 0);
+    psMetadataAddS64(donecleanup_processedimfileArgs, PS_LIST_TAIL, "-exp_id",  0,            "search by exposure ID", 0);
+    psMetadataAddStr(donecleanup_processedimfileArgs, PS_LIST_TAIL, "-class_id",  0,            "search by class ID", NULL);
 
     // -toprocessedexp
@@ -283,6 +302,6 @@
     // -addproccessedexp
     psMetadata *addprocessedexpArgs = psMetadataAlloc();
-    psMetadataAddStr(addprocessedexpArgs, PS_LIST_TAIL, "-det_id",  0,            "define detrend ID (required)", NULL);
-    psMetadataAddStr(addprocessedexpArgs, PS_LIST_TAIL, "-exp_id",  0,            "define detrend ID (required)", NULL);
+    psMetadataAddS64(addprocessedexpArgs, PS_LIST_TAIL, "-det_id",  0,            "define detrend ID (required)", 0);
+    psMetadataAddS64(addprocessedexpArgs, PS_LIST_TAIL, "-exp_id",  0,            "define detrend ID (required)", 0);
     psMetadataAddStr(addprocessedexpArgs, PS_LIST_TAIL, "-recip",  0,            "define recipe", NULL);
     psMetadataAddF64(addprocessedexpArgs, PS_LIST_TAIL, "-bg",  0,            "define exposure background", NAN);
@@ -302,6 +321,6 @@
     // -proccessedexp
     psMetadata *processedexpArgs = psMetadataAlloc();
-    psMetadataAddStr(processedexpArgs, PS_LIST_TAIL, "-det_id",  0,            "search by detrend ID", NULL);
-    psMetadataAddStr(processedexpArgs, PS_LIST_TAIL, "-exp_id",  0,            "search by exp ID", NULL);
+    psMetadataAddS64(processedexpArgs, PS_LIST_TAIL, "-det_id",  0,            "search by detrend ID", 0);
+    psMetadataAddS64(processedexpArgs, PS_LIST_TAIL, "-exp_id",  0,            "search by exp ID", 0);
     psMetadataAddU64(processedexpArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
     psMetadataAddBool(processedexpArgs, PS_LIST_TAIL, "-faulted",  0,            "only return imfiles with a fault status set", false);
@@ -310,7 +329,27 @@
     // -revertprocessedexp
     psMetadata *revertprocessedexpArgs = psMetadataAlloc();
-    psMetadataAddStr(revertprocessedexpArgs, PS_LIST_TAIL, "-det_id",  0,            "search by detrend ID (required)", NULL);
-    psMetadataAddStr(revertprocessedexpArgs, PS_LIST_TAIL, "-exp_id",  0,            "search by exposure ID", NULL);
+    psMetadataAddS64(revertprocessedexpArgs, PS_LIST_TAIL, "-det_id",  0,            "search by detrend ID (required)", 0);
+    psMetadataAddS64(revertprocessedexpArgs, PS_LIST_TAIL, "-exp_id",  0,            "search by exposure ID", 0);
     psMetadataAddS16(revertprocessedexpArgs, PS_LIST_TAIL, "-code",  0,            "search by fault code", 0);
+
+    // -updateprocessedexp
+    psMetadata *updateprocessedexpArgs = psMetadataAlloc();
+    psMetadataAddS64(updateprocessedexpArgs, PS_LIST_TAIL, "-det_id",               0,            "search by chip ID", 0);
+    psMetadataAddS64(updateprocessedexpArgs, PS_LIST_TAIL, "-exp_id",               0,            "search by exp_id", 0);
+    psMetadataAddStr(updateprocessedexpArgs, PS_LIST_TAIL, "-data_state",           0,            "search for telescope", NULL);
+
+    // -pendingcleanup_processedexp
+    psMetadata *pendingcleanup_processedexpArgs = psMetadataAlloc();
+    psMetadataAddBool(pendingcleanup_processedexpArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(pendingcleanup_processedexpArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+    psMetadataAddS64(pendingcleanup_processedexpArgs, PS_LIST_TAIL, "-det_id",               0,            "search by chip ID", 0);
+    psMetadataAddS64(pendingcleanup_processedexpArgs, PS_LIST_TAIL, "-exp_id",               0,            "search by exp_id", 0);
+
+    // -donecleanup_processedexp
+    psMetadata *donecleanup_processedexpArgs = psMetadataAlloc();
+    psMetadataAddBool(donecleanup_processedexpArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(donecleanup_processedexpArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+    psMetadataAddS64(donecleanup_processedexpArgs, PS_LIST_TAIL, "-det_id",               0,            "search by chip ID", 0);
+    psMetadataAddS64(donecleanup_processedexpArgs, PS_LIST_TAIL, "-exp_id",               0,            "search by exp_id", 0);
 
     // -tostacked
@@ -321,5 +360,5 @@
     // -addstacked
     psMetadata *addstackedArgs = psMetadataAlloc();
-    psMetadataAddStr(addstackedArgs, PS_LIST_TAIL, "-det_id",  0,            "define detrend ID (required)", NULL);
+    psMetadataAddS64(addstackedArgs, PS_LIST_TAIL, "-det_id",  0,            "define detrend ID (required)", 0);
     psMetadataAddS32(addstackedArgs, PS_LIST_TAIL, "-iteration",  0,            "define iteration number (required)", 0);
     psMetadataAddStr(addstackedArgs, PS_LIST_TAIL, "-class_id",  0,            "define class ID (required)", NULL);
@@ -338,5 +377,5 @@
     // -stacked
     psMetadata *stackedArgs = psMetadataAlloc();
-    psMetadataAddStr(stackedArgs, PS_LIST_TAIL, "-det_id",  0,            "search for detrend ID", NULL);
+    psMetadataAddS64(stackedArgs, PS_LIST_TAIL, "-det_id",  0,            "search for detrend ID", 0);
     psMetadataAddS32(stackedArgs, PS_LIST_TAIL, "-iteration",  0,            "search for iteration number", 0);
     psMetadataAddStr(stackedArgs, PS_LIST_TAIL, "-class_id",  0,            "search for class ID", NULL);
@@ -348,8 +387,31 @@
     // -revertstacked
     psMetadata *revertstackedArgs= psMetadataAlloc();
-    psMetadataAddStr(revertstackedArgs, PS_LIST_TAIL, "-det_id",  0,            "search for detrend ID (required)", NULL);
+    psMetadataAddS64(revertstackedArgs, PS_LIST_TAIL, "-det_id",  0,            "search for detrend ID (required)", 0);
     psMetadataAddS32(revertstackedArgs, PS_LIST_TAIL, "-iteration",  0,            "search by iteration number", 0);
     psMetadataAddStr(revertstackedArgs, PS_LIST_TAIL, "-class_id",  0,            "search by class ID", NULL);
     psMetadataAddS16(revertstackedArgs, PS_LIST_TAIL, "-code",  0,            "search by fault code", 0);
+
+    // -updatestacked
+    psMetadata *updatestackedArgs = psMetadataAlloc();
+    psMetadataAddS64(updatestackedArgs, PS_LIST_TAIL, "-det_id",               0,            "search by chip ID", 0);
+    psMetadataAddS32(updatestackedArgs, PS_LIST_TAIL, "-iteration",  0,            "search by iteration number", 0);
+    psMetadataAddStr(updatestackedArgs, PS_LIST_TAIL, "-class_id",  0,            "search by class ID", NULL);
+    psMetadataAddStr(updatestackedArgs, PS_LIST_TAIL, "-data_state",           0,            "search for telescope", NULL);
+
+    // -pendingcleanup_stacked
+    psMetadata *pendingcleanup_stackedArgs = psMetadataAlloc();
+    psMetadataAddBool(pendingcleanup_stackedArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(pendingcleanup_stackedArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+    psMetadataAddS64(pendingcleanup_stackedArgs, PS_LIST_TAIL, "-det_id",               0,            "search by chip ID", 0);
+    psMetadataAddS32(pendingcleanup_stackedArgs, PS_LIST_TAIL, "-iteration",  0,            "search by iteration number", 0);
+    psMetadataAddStr(pendingcleanup_stackedArgs, PS_LIST_TAIL, "-class_id",  0,            "search by class ID", NULL);
+
+    // -donecleanup_stacked
+    psMetadata *donecleanup_stackedArgs = psMetadataAlloc();
+    psMetadataAddBool(donecleanup_stackedArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(donecleanup_stackedArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+    psMetadataAddS64(donecleanup_stackedArgs, PS_LIST_TAIL, "-det_id",               0,            "search by chip ID", 0);
+    psMetadataAddS32(donecleanup_stackedArgs, PS_LIST_TAIL, "-iteration",  0,            "search by iteration number", 0);
+    psMetadataAddStr(donecleanup_stackedArgs, PS_LIST_TAIL, "-class_id",  0,            "search by class ID", NULL);
 
     // -tonormalizedstat
@@ -360,5 +422,5 @@
     // -addnormalizedstat
     psMetadata *addnormstatArgs = psMetadataAlloc();
-    psMetadataAddStr(addnormstatArgs, PS_LIST_TAIL, "-det_id",  0,            "define detrend ID (required)", NULL);
+    psMetadataAddS64(addnormstatArgs, PS_LIST_TAIL, "-det_id",  0,            "define detrend ID (required)", 0);
     psMetadataAddS32(addnormstatArgs, PS_LIST_TAIL, "-iteration",  0,            "define iteration number", 0);
     psMetadataAddStr(addnormstatArgs, PS_LIST_TAIL, "-class_id",  0,            "define class ID (required)", NULL);
@@ -368,5 +430,5 @@
     // -normalizedstat
     psMetadata *normalizedstatArgs = psMetadataAlloc();
-    psMetadataAddStr(normalizedstatArgs, PS_LIST_TAIL, "-det_id",  0,            "search by detrend ID", NULL);
+    psMetadataAddS64(normalizedstatArgs, PS_LIST_TAIL, "-det_id",  0,            "search by detrend ID", 0);
     psMetadataAddS32(normalizedstatArgs, PS_LIST_TAIL, "-iteration",  0,            "search by iteration number", 0);
     psMetadataAddStr(normalizedstatArgs, PS_LIST_TAIL, "-class_id",  0,            "search by class ID", NULL);
@@ -377,8 +439,31 @@
     // -revertnormalizedstat
     psMetadata *revertnormalizedstatArgs= psMetadataAlloc();
-    psMetadataAddStr(revertnormalizedstatArgs, PS_LIST_TAIL, "-det_id",  0,            "search by detrend ID (required)", NULL);
+    psMetadataAddS64(revertnormalizedstatArgs, PS_LIST_TAIL, "-det_id",  0,            "search by detrend ID (required)", 0);
     psMetadataAddS32(revertnormalizedstatArgs, PS_LIST_TAIL, "-iteration",  0,            "search by iteration number", 0);
     psMetadataAddStr(revertnormalizedstatArgs, PS_LIST_TAIL, "-class_id",  0,            "search by class ID", NULL);
     psMetadataAddS16(revertnormalizedstatArgs, PS_LIST_TAIL, "-code",  0,            "search by fault code", 0);
+
+    // -updatenormalizedstat
+    psMetadata *updatenormalizedstatArgs = psMetadataAlloc();
+    psMetadataAddS64(updatenormalizedstatArgs, PS_LIST_TAIL, "-det_id",               0,            "search by chip ID", 0);
+    psMetadataAddS32(updatenormalizedstatArgs, PS_LIST_TAIL, "-iteration",  0,            "search by iteration number", 0);
+    psMetadataAddStr(updatenormalizedstatArgs, PS_LIST_TAIL, "-class_id",             0,            "search by exp_name", NULL);
+    psMetadataAddStr(updatenormalizedstatArgs, PS_LIST_TAIL, "-data_state",           0,            "search for telescope", NULL);
+
+    // -pendingcleanup_normalizedstat
+    psMetadata *pendingcleanup_normalizedstatArgs = psMetadataAlloc();
+    psMetadataAddBool(pendingcleanup_normalizedstatArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(pendingcleanup_normalizedstatArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+    psMetadataAddS64(pendingcleanup_normalizedstatArgs, PS_LIST_TAIL, "-det_id",               0,            "search by chip ID", 0);
+    psMetadataAddS32(pendingcleanup_normalizedstatArgs, PS_LIST_TAIL, "-iteration",  0,            "search by iteration number", 0);
+    psMetadataAddStr(pendingcleanup_normalizedstatArgs, PS_LIST_TAIL, "-class_id",             0,            "search by exp_name", NULL);
+
+    // -donecleanup_normalizedstat
+    psMetadata *donecleanup_normalizedstatArgs = psMetadataAlloc();
+    psMetadataAddBool(donecleanup_normalizedstatArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(donecleanup_normalizedstatArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+    psMetadataAddS64(donecleanup_normalizedstatArgs, PS_LIST_TAIL, "-det_id",               0,            "search by chip ID", 0);
+    psMetadataAddS32(donecleanup_normalizedstatArgs, PS_LIST_TAIL, "-iteration",  0,            "search by iteration number", 0);
+    psMetadataAddStr(donecleanup_normalizedstatArgs, PS_LIST_TAIL, "-class_id",             0,            "search by exp_name", NULL);
 
     // -tonormalize
@@ -389,5 +474,5 @@
     // -addnormalizedimfile
     psMetadata *addnormalizedimfileArgs = psMetadataAlloc();
-    psMetadataAddStr(addnormalizedimfileArgs, PS_LIST_TAIL, "-det_id", 0,            "define detrend ID (required)", NULL);
+    psMetadataAddS64(addnormalizedimfileArgs, PS_LIST_TAIL, "-det_id", 0,            "define detrend ID (required)", 0);
     psMetadataAddS32(addnormalizedimfileArgs, PS_LIST_TAIL, "-iteration", 0,            "define iteration number", 0);
     psMetadataAddStr(addnormalizedimfileArgs, PS_LIST_TAIL, "-class_id", 0,            "define class ID (required)", NULL);
@@ -406,5 +491,5 @@
     // -normalizedimfile
     psMetadata *normalizedimfileArgs = psMetadataAlloc();
-    psMetadataAddStr(normalizedimfileArgs, PS_LIST_TAIL, "-det_id",  0,            "search for detrend ID", NULL);
+    psMetadataAddS64(normalizedimfileArgs, PS_LIST_TAIL, "-det_id",  0,            "search for detrend ID", 0);
     psMetadataAddS32(normalizedimfileArgs, PS_LIST_TAIL, "-iteration",  0,            "search for iteration number", 0);
     psMetadataAddStr(normalizedimfileArgs, PS_LIST_TAIL, "-class_id",  0,            "search for class ID", NULL);
@@ -416,8 +501,31 @@
     // -revertnormalizedimfile
     psMetadata *revertnormalizedimfileArgs = psMetadataAlloc();
-    psMetadataAddStr(revertnormalizedimfileArgs, PS_LIST_TAIL, "-det_id", 0,            "search by detrend ID (required)", NULL);
+    psMetadataAddS64(revertnormalizedimfileArgs, PS_LIST_TAIL, "-det_id", 0,            "search by detrend ID (required)", 0);
     psMetadataAddS32(revertnormalizedimfileArgs, PS_LIST_TAIL, "-iteration", 0,            "search by iteration number", 0);
     psMetadataAddStr(revertnormalizedimfileArgs, PS_LIST_TAIL, "-class_id", 0,            "search by class ID", NULL);
     psMetadataAddS16(revertnormalizedimfileArgs, PS_LIST_TAIL, "-code",  0,            "search by fault code", 0);
+
+    // -updatenormalizedimfile
+    psMetadata *updatenormalizedimfileArgs = psMetadataAlloc();
+    psMetadataAddS64(updatenormalizedimfileArgs, PS_LIST_TAIL, "-det_id",               0,            "search by chip ID", 0);
+    psMetadataAddS32(updatenormalizedimfileArgs, PS_LIST_TAIL, "-iteration", 0,            "search by iteration number", 0);
+    psMetadataAddStr(updatenormalizedimfileArgs, PS_LIST_TAIL, "-class_id",             0,            "search by exp_name", NULL);
+    psMetadataAddStr(updatenormalizedimfileArgs, PS_LIST_TAIL, "-data_state",           0,            "search for telescope", NULL);
+
+    // -pendingcleanup_normalizedimfile
+    psMetadata *pendingcleanup_normalizedimfileArgs = psMetadataAlloc();
+    psMetadataAddBool(pendingcleanup_normalizedimfileArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(pendingcleanup_normalizedimfileArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+    psMetadataAddS64(pendingcleanup_normalizedimfileArgs, PS_LIST_TAIL, "-det_id",               0,            "search by chip ID", 0);
+    psMetadataAddS32(pendingcleanup_normalizedimfileArgs, PS_LIST_TAIL, "-iteration", 0,            "search by iteration number", 0);
+    psMetadataAddStr(pendingcleanup_normalizedimfileArgs, PS_LIST_TAIL, "-class_id",             0,            "search by exp_name", NULL);
+
+    // -donecleanup_normalizedimfile
+    psMetadata *donecleanup_normalizedimfileArgs = psMetadataAlloc();
+    psMetadataAddBool(donecleanup_normalizedimfileArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(donecleanup_normalizedimfileArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+    psMetadataAddS64(donecleanup_normalizedimfileArgs, PS_LIST_TAIL, "-det_id",               0,            "search by chip ID", 0);
+    psMetadataAddS32(donecleanup_normalizedimfileArgs, PS_LIST_TAIL, "-iteration", 0,            "search by iteration number", 0);
+    psMetadataAddStr(donecleanup_normalizedimfileArgs, PS_LIST_TAIL, "-class_id",             0,            "search by exp_name", NULL);
 
     // -tonormalizedexp
@@ -428,5 +536,5 @@
     // -addnormalizedexp
     psMetadata *addnormalizedexpArgs = psMetadataAlloc();
-    psMetadataAddStr(addnormalizedexpArgs, PS_LIST_TAIL, "-det_id",  0,            "define detrend ID (required)", NULL);
+    psMetadataAddS64(addnormalizedexpArgs, PS_LIST_TAIL, "-det_id",  0,            "define detrend ID (required)", 0);
     psMetadataAddS32(addnormalizedexpArgs, PS_LIST_TAIL, "-iteration",  0,            "define iteration number", 0);
     psMetadataAddS16(addnormalizedexpArgs, PS_LIST_TAIL, "-code",  0,            "set fault code", 0);
@@ -444,5 +552,5 @@
     // -normalizedexp
     psMetadata *normalizedexpArgs = psMetadataAlloc();
-    psMetadataAddStr(normalizedexpArgs, PS_LIST_TAIL, "-det_id",  0,            "search by detrend ID", NULL);
+    psMetadataAddS64(normalizedexpArgs, PS_LIST_TAIL, "-det_id",  0,            "search by detrend ID", 0);
     psMetadataAddS32(normalizedexpArgs, PS_LIST_TAIL, "-iteration",  0,            "search by iteration number", 0);
     psMetadataAddStr(normalizedexpArgs, PS_LIST_TAIL, "-recip",  0,            "search for recipe", NULL);
@@ -453,7 +561,27 @@
     // -revertnormalizedexp
     psMetadata *revertnormalizedexpArgs = psMetadataAlloc();
-    psMetadataAddStr(revertnormalizedexpArgs, PS_LIST_TAIL, "-det_id", 0,            "search by detrend ID (required)", NULL);
+    psMetadataAddS64(revertnormalizedexpArgs, PS_LIST_TAIL, "-det_id", 0,            "search by detrend ID (required)", 0);
     psMetadataAddS32(revertnormalizedexpArgs, PS_LIST_TAIL, "-iteration", 0,            "search by iteration number", 0);
     psMetadataAddS16(revertnormalizedexpArgs, PS_LIST_TAIL, "-code",  0,            "search by fault code", 0);
+
+    // -updatenormalizedexp
+    psMetadata *updatenormalizedexpArgs = psMetadataAlloc();
+    psMetadataAddS64(updatenormalizedexpArgs, PS_LIST_TAIL, "-det_id",               0,            "search by chip ID", 0);
+    psMetadataAddS32(updatenormalizedexpArgs, PS_LIST_TAIL, "-iteration", 0,            "search by iteration number", 0);
+    psMetadataAddStr(updatenormalizedexpArgs, PS_LIST_TAIL, "-data_state",           0,            "search for telescope", NULL);
+
+    // -pendingcleanup_normalizedexp
+    psMetadata *pendingcleanup_normalizedexpArgs = psMetadataAlloc();
+    psMetadataAddBool(pendingcleanup_normalizedexpArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(pendingcleanup_normalizedexpArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+    psMetadataAddS64(pendingcleanup_normalizedexpArgs, PS_LIST_TAIL, "-det_id",               0,            "search by chip ID", 0);
+    psMetadataAddS32(pendingcleanup_normalizedexpArgs, PS_LIST_TAIL, "-iteration", 0,            "search by iteration number", 0);
+
+    // -donecleanup_normalizedexp
+    psMetadata *donecleanup_normalizedexpArgs = psMetadataAlloc();
+    psMetadataAddBool(donecleanup_normalizedexpArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(donecleanup_normalizedexpArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+    psMetadataAddS64(donecleanup_normalizedexpArgs, PS_LIST_TAIL, "-det_id",               0,            "search by chip ID", 0);
+    psMetadataAddS32(donecleanup_normalizedexpArgs, PS_LIST_TAIL, "-iteration", 0,            "search by iteration number", 0);
 
     // -toresidimfile
@@ -464,7 +592,7 @@
     // -addresidimfile
     psMetadata *addresidimfileArgs = psMetadataAlloc();
-    psMetadataAddStr(addresidimfileArgs, PS_LIST_TAIL, "-det_id",  0,            "define detrend ID (required)", NULL);
+    psMetadataAddS64(addresidimfileArgs, PS_LIST_TAIL, "-det_id",  0,            "define detrend ID (required)", 0);
     psMetadataAddS32(addresidimfileArgs, PS_LIST_TAIL, "-iteration",  0,            "define iteration number", 0);
-    psMetadataAddStr(addresidimfileArgs, PS_LIST_TAIL, "-exp_id",  0,            "define detrend ID (required)", NULL);
+    psMetadataAddS64(addresidimfileArgs, PS_LIST_TAIL, "-exp_id",  0,            "define detrend ID (required)", 0);
     psMetadataAddStr(addresidimfileArgs, PS_LIST_TAIL, "-class_id",  0,            "define class ID (required)", NULL);
     psMetadataAddS16(addresidimfileArgs, PS_LIST_TAIL, "-code",  0,            "set fault code", 0);
@@ -492,7 +620,7 @@
     // -residimfile
     psMetadata *residimfileArgs = psMetadataAlloc();
-    psMetadataAddStr(residimfileArgs, PS_LIST_TAIL, "-det_id",  0,            "search for detrend ID", NULL);
+    psMetadataAddS64(residimfileArgs, PS_LIST_TAIL, "-det_id",  0,            "search for detrend ID", 0);
     psMetadataAddS32(residimfileArgs, PS_LIST_TAIL, "-iteration",  0,            "search for iteration number", 0);
-    psMetadataAddStr(residimfileArgs, PS_LIST_TAIL, "-exp_id",  0,            "search by detrend ID", NULL);
+    psMetadataAddS64(residimfileArgs, PS_LIST_TAIL, "-exp_id",  0,            "search by detrend ID", 0);
     psMetadataAddStr(residimfileArgs, PS_LIST_TAIL, "-class_id",  0,            "search for class ID", NULL);
     psMetadataAddStr(residimfileArgs, PS_LIST_TAIL, "-recip",  0,            "search for recipe", NULL);
@@ -504,9 +632,35 @@
     // -revertresidimfile
     psMetadata *revertresidimfileArgs =  psMetadataAlloc();
-    psMetadataAddStr(revertresidimfileArgs, PS_LIST_TAIL, "-det_id", 0,          "search by detrend ID (required)", NULL);
+    psMetadataAddS64(revertresidimfileArgs, PS_LIST_TAIL, "-det_id", 0,          "search by detrend ID (required)", 0);
     psMetadataAddS32(revertresidimfileArgs, PS_LIST_TAIL, "-iteration", 0,       "search by iteration number", 0);
-    psMetadataAddStr(revertresidimfileArgs, PS_LIST_TAIL, "-exp_id",  0,         "search by detrend ID", NULL);
+    psMetadataAddS64(revertresidimfileArgs, PS_LIST_TAIL, "-exp_id",  0,         "search by detrend ID", 0);
     psMetadataAddStr(revertresidimfileArgs, PS_LIST_TAIL, "-class_id",  0,       "search for class ID", NULL);
     psMetadataAddS16(revertresidimfileArgs, PS_LIST_TAIL, "-code",  0,           "search by fault code", 0);
+
+    // -updateresidimfile
+    psMetadata *updateresidimfileArgs = psMetadataAlloc();
+    psMetadataAddS64(updateresidimfileArgs, PS_LIST_TAIL, "-det_id",               0,            "search by chip ID", 0);
+    psMetadataAddS32(updateresidimfileArgs, PS_LIST_TAIL, "-iteration", 0,       "search by iteration number", 0);
+    psMetadataAddS64(updateresidimfileArgs, PS_LIST_TAIL, "-exp_id",               0,            "search by exp_id", 0);
+    psMetadataAddStr(updateresidimfileArgs, PS_LIST_TAIL, "-class_id",             0,            "search by exp_name", NULL);
+    psMetadataAddStr(updateresidimfileArgs, PS_LIST_TAIL, "-data_state",           0,            "search for telescope", NULL);
+
+    // -pendingcleanup_residimfile
+    psMetadata *pendingcleanup_residimfileArgs = psMetadataAlloc();
+    psMetadataAddBool(pendingcleanup_residimfileArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(pendingcleanup_residimfileArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+    psMetadataAddS64(pendingcleanup_residimfileArgs, PS_LIST_TAIL, "-det_id",               0,            "search by chip ID", 0);
+    psMetadataAddS32(pendingcleanup_residimfileArgs, PS_LIST_TAIL, "-iteration", 0,       "search by iteration number", 0);
+    psMetadataAddS64(pendingcleanup_residimfileArgs, PS_LIST_TAIL, "-exp_id",               0,            "search by exp_id", 0);
+    psMetadataAddStr(pendingcleanup_residimfileArgs, PS_LIST_TAIL, "-class_id",             0,            "search by exp_name", NULL);
+
+    // -donecleanup_residimfile
+    psMetadata *donecleanup_residimfileArgs = psMetadataAlloc();
+    psMetadataAddBool(donecleanup_residimfileArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(donecleanup_residimfileArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+    psMetadataAddS64(donecleanup_residimfileArgs, PS_LIST_TAIL, "-det_id",               0,            "search by chip ID", 0);
+    psMetadataAddS32(donecleanup_residimfileArgs, PS_LIST_TAIL, "-iteration", 0,       "search by iteration number", 0);
+    psMetadataAddS64(donecleanup_residimfileArgs, PS_LIST_TAIL, "-exp_id",               0,            "search by exp_id", 0);
+    psMetadataAddStr(donecleanup_residimfileArgs, PS_LIST_TAIL, "-class_id",             0,            "search by exp_name", NULL);
 
     // -toresidexp
@@ -517,7 +671,7 @@
     // -addresidexp
     psMetadata *addresidexpArgs = psMetadataAlloc();
-    psMetadataAddStr(addresidexpArgs, PS_LIST_TAIL, "-det_id",  0,            "define detrend ID (required)", NULL);
+    psMetadataAddS64(addresidexpArgs, PS_LIST_TAIL, "-det_id",  0,            "define detrend ID (required)", 0);
     psMetadataAddS32(addresidexpArgs, PS_LIST_TAIL, "-iteration",  0,            "define iteration number", 0);
-    psMetadataAddStr(addresidexpArgs, PS_LIST_TAIL, "-exp_id",  0,            "define detrend ID (required)", NULL);
+    psMetadataAddS64(addresidexpArgs, PS_LIST_TAIL, "-exp_id",  0,            "define detrend ID (required)", 0);
     psMetadataAddS16(addresidexpArgs, PS_LIST_TAIL, "-code",  0,            "set fault code", 0);
     psMetadataAddStr(addresidexpArgs, PS_LIST_TAIL, "-recip",  0,            "define recipe", NULL);
@@ -544,7 +698,7 @@
     // -residexp
     psMetadata *residexpArgs = psMetadataAlloc();
-    psMetadataAddStr(residexpArgs, PS_LIST_TAIL, "-det_id",  0,            "search for detrend ID", NULL);
+    psMetadataAddS64(residexpArgs, PS_LIST_TAIL, "-det_id",  0,            "search for detrend ID", 0);
     psMetadataAddS32(residexpArgs, PS_LIST_TAIL, "-iteration",  0,            "search for iteration number", 0);
-    psMetadataAddStr(residexpArgs, PS_LIST_TAIL, "-exp_id",  0,            "search for exp ID", NULL);
+    psMetadataAddS64(residexpArgs, PS_LIST_TAIL, "-exp_id",  0,            "search for exp ID", 0);
     psMetadataAddStr(residexpArgs, PS_LIST_TAIL, "-recip",  0,            "search for recipe", NULL);
     psMetadataAddBool(residexpArgs, PS_LIST_TAIL, "-reject",  0,            "search for acceptable residuals", false);
@@ -555,14 +709,14 @@
     // -revertresidexp
     psMetadata *revertresidexpArgs = psMetadataAlloc();
-    psMetadataAddStr(revertresidexpArgs, PS_LIST_TAIL, "-det_id", 0,            "search by detrend ID (required)", NULL);
+    psMetadataAddS64(revertresidexpArgs, PS_LIST_TAIL, "-det_id", 0,            "search by detrend ID (required)", 0);
     psMetadataAddS32(revertresidexpArgs, PS_LIST_TAIL, "-iteration", 0,            "search by iteration number", 0);
-    psMetadataAddStr(revertresidexpArgs, PS_LIST_TAIL, "-exp_id",  0,            "search by detrend ID", NULL);
+    psMetadataAddS64(revertresidexpArgs, PS_LIST_TAIL, "-exp_id",  0,            "search by detrend ID", 0);
     psMetadataAddS16(revertresidexpArgs, PS_LIST_TAIL, "-code",  0,            "search by fault code", 0);
 
     // -updateresidexp
     psMetadata *updateresidexpArgs = psMetadataAlloc();
-    psMetadataAddStr(updateresidexpArgs, PS_LIST_TAIL, "-det_id",  0,            "define detrend ID", NULL);
+    psMetadataAddS64(updateresidexpArgs, PS_LIST_TAIL, "-det_id",  0,            "define detrend ID", 0);
     psMetadataAddS32(updateresidexpArgs, PS_LIST_TAIL, "-iteration",  0,            "define iteration number", 0);
-    psMetadataAddStr(updateresidexpArgs, PS_LIST_TAIL, "-exp_id",  0,            "define exp ID", NULL);
+    psMetadataAddS64(updateresidexpArgs, PS_LIST_TAIL, "-exp_id",  0,            "define exp ID", 0);
     psMetadataAddStr(updateresidexpArgs, PS_LIST_TAIL, "-recip",  0,            "define recipe", NULL);
     psMetadataAddF64(updateresidexpArgs, PS_LIST_TAIL, "-bg",  0,            "define exposure background", NAN);
@@ -571,4 +725,21 @@
     psMetadataAddStr(updateresidexpArgs, PS_LIST_TAIL, "-path_base",  0,            "define base output location", NULL);
     psMetadataAddBool(updateresidexpArgs, PS_LIST_TAIL, "-reject",  0,            "exposure is not to be stacked in the next iteration", false);
+    psMetadataAddStr(updateresidexpArgs, PS_LIST_TAIL, "-data_state",           0,            "search for telescope", NULL);
+
+    // -pendingcleanup_residexp
+    psMetadata *pendingcleanup_residexpArgs = psMetadataAlloc();
+    psMetadataAddBool(pendingcleanup_residexpArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(pendingcleanup_residexpArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+    psMetadataAddS64(pendingcleanup_residexpArgs, PS_LIST_TAIL, "-det_id", 0,            "search by detrend ID (required)", 0);
+    psMetadataAddS32(pendingcleanup_residexpArgs, PS_LIST_TAIL, "-iteration", 0,            "search by iteration number", 0);
+    psMetadataAddS64(pendingcleanup_residexpArgs, PS_LIST_TAIL, "-exp_id",  0,            "search by detrend ID", 0);
+
+    // -donecleanup_residexp
+    psMetadata *donecleanup_residexpArgs = psMetadataAlloc();
+    psMetadataAddBool(donecleanup_residexpArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(donecleanup_residexpArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+    psMetadataAddS64(donecleanup_residexpArgs, PS_LIST_TAIL, "-det_id", 0,            "search by detrend ID (required)", 0);
+    psMetadataAddS32(donecleanup_residexpArgs, PS_LIST_TAIL, "-iteration", 0,            "search by iteration number", 0);
+    psMetadataAddS64(donecleanup_residexpArgs, PS_LIST_TAIL, "-exp_id",  0,            "search by detrend ID", 0);
 
     // -todetrunsummary
@@ -579,5 +750,5 @@
     // -adddetrunsummary
     psMetadata *adddetrunsummaryArgs = psMetadataAlloc();
-    psMetadataAddStr(adddetrunsummaryArgs, PS_LIST_TAIL, "-det_id",  0,            "define detrend ID (required)", NULL);
+    psMetadataAddS64(adddetrunsummaryArgs, PS_LIST_TAIL, "-det_id",  0,            "define detrend ID (required)", 0);
     psMetadataAddS32(adddetrunsummaryArgs, PS_LIST_TAIL, "-iteration",  0,            "define iteration number", 0);
     psMetadataAddF64(adddetrunsummaryArgs, PS_LIST_TAIL, "-bg",  0,            "define exposure background", NAN);
@@ -590,5 +761,5 @@
     // -detrunsummary
     psMetadata *detrunsummaryArgs = psMetadataAlloc();
-    psMetadataAddStr(detrunsummaryArgs, PS_LIST_TAIL, "-det_id",  0,            "search for detrend ID", NULL);
+    psMetadataAddS64(detrunsummaryArgs, PS_LIST_TAIL, "-det_id",  0,            "search for detrend ID", 0);
     psMetadataAddS32(detrunsummaryArgs, PS_LIST_TAIL, "-iteration",  0,            "search for iteration number", 0);
     psMetadataAddU64(detrunsummaryArgs, PS_LIST_TAIL, "-limit",  0,                     "limit result set to N items", 0);
@@ -599,5 +770,5 @@
     // -revertdetrunsummary
     psMetadata *revertdetrunsummaryArgs = psMetadataAlloc();
-    psMetadataAddStr(revertdetrunsummaryArgs, PS_LIST_TAIL, "-det_id", 0,            "search by detrend ID (required)", NULL);
+    psMetadataAddS64(revertdetrunsummaryArgs, PS_LIST_TAIL, "-det_id", 0,            "search by detrend ID (required)", 0);
     psMetadataAddS32(revertdetrunsummaryArgs, PS_LIST_TAIL, "-iteration", 0,            "search by iteration number", 0);
     psMetadataAddS16(revertdetrunsummaryArgs, PS_LIST_TAIL, "-code",  0,            "search by fault code", 0);
@@ -605,5 +776,5 @@
     // -updatedetrunsummary
     psMetadata *updatedetrunsummaryArgs = psMetadataAlloc();
-    psMetadataAddStr(updatedetrunsummaryArgs, PS_LIST_TAIL, "-det_id",  0,            "search for detrend master for detrend ID (required)", NULL);
+    psMetadataAddS64(updatedetrunsummaryArgs, PS_LIST_TAIL, "-det_id",  0,            "search for detrend master for detrend ID (required)", 0);
     psMetadataAddBool(updatedetrunsummaryArgs, PS_LIST_TAIL, "-accept",  0,            "declare that this detrun iteration is accepted as a master", false);
     psMetadataAddBool(updatedetrunsummaryArgs, PS_LIST_TAIL, "-reject",  0,            "reject this detrun iteration as a master", false);
@@ -611,5 +782,5 @@
     // -updatedetrun
     psMetadata *updatedetrunArgs = psMetadataAlloc();
-    psMetadataAddStr(updatedetrunArgs, PS_LIST_TAIL, "-det_id",  0,            "search for detrend master for detrend ID (required)", NULL);
+    psMetadataAddS64(updatedetrunArgs, PS_LIST_TAIL, "-det_id",  0,            "search for detrend master for detrend ID (required)", 0);
     psMetadataAddBool(updatedetrunArgs, PS_LIST_TAIL, "-again",  0,            "start a new iteration of this detrend run", false);
     psMetadataAddStr(updatedetrunArgs, PS_LIST_TAIL, "-state",  0,            "set the state of this detrend run", false);
@@ -617,6 +788,6 @@
     // -rerun
     psMetadata *rerunArgs = psMetadataAlloc();
-    psMetadataAddStr(rerunArgs, PS_LIST_TAIL, "-det_id",  0,            "search for detrend master for detrend ID (required)", NULL);
-    psMetadataAddStr(rerunArgs, PS_LIST_TAIL, "-exp_id",  PS_META_DUPLICATE_OK,            "include this exposure (multiple OK, required)", NULL);
+    psMetadataAddS64(rerunArgs, PS_LIST_TAIL, "-det_id",  0,            "search for detrend master for detrend ID (required)", 0);
+    psMetadataAddS64(rerunArgs, PS_LIST_TAIL, "-exp_id",  PS_META_DUPLICATE_OK,            "include this exposure (multiple OK, required)", 0);
 
     // -register_detrend
@@ -644,5 +815,5 @@
     psMetadataAddTime(register_detrendArgs, PS_LIST_TAIL, "-use_begin",  0,            "start of detrend run applicable period", NULL);
     psMetadataAddTime(register_detrendArgs, PS_LIST_TAIL, "-use_end",  0,            "end of detrend run applicable period", NULL);
-    psMetadataAddStr(register_detrendArgs, PS_LIST_TAIL, "-parent",  0,            "define parent det_id", NULL);
+    psMetadataAddS64(register_detrendArgs, PS_LIST_TAIL, "-parent",  0,            "define parent det_id", 0);
     psMetadataAddStr(register_detrendArgs, PS_LIST_TAIL, "-label",  0,            "define detrun label", NULL);
     psMetadataAddBool(register_detrendArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
@@ -650,5 +821,5 @@
     // -register_detrend_imfile
     psMetadata *register_detrend_imfileArgs = psMetadataAlloc();
-    psMetadataAddStr(register_detrend_imfileArgs, PS_LIST_TAIL, "-det_id",  0,            "define detrend ID (required)", NULL);
+    psMetadataAddS64(register_detrend_imfileArgs, PS_LIST_TAIL, "-det_id",  0,            "define detrend ID (required)", 0);
     psMetadataAddStr(register_detrend_imfileArgs, PS_LIST_TAIL, "-class_id",  0,            "search for class ID (required)", NULL);
     psMetadataAddStr(register_detrend_imfileArgs, PS_LIST_TAIL, "-uri",  0,            "define resid file URI (required)", NULL);
@@ -680,43 +851,75 @@
     PXOPT_ADD_MODE("-childlessrun",    "", DETTOOL_MODE_CHILDLESSRUN,  childlessrunArgs);
     PXOPT_ADD_MODE("-input",           "", DETTOOL_MODE_INPUT,         inputArgs);
-    PXOPT_ADD_MODE("-toprocessedimfile", "", DETTOOL_MODE_TOPROCESSEDIMFILE, toprocessedimfileArgs);
-    PXOPT_ADD_MODE("-addprocessedimfile", "", DETTOOL_MODE_ADDPROCESSEDIMFILE,  addprocessedimfileArgs);
-    PXOPT_ADD_MODE("-processedimfile", "", DETTOOL_MODE_PROCESSEDIMFILE, processedimfileArgs);
-    PXOPT_ADD_MODE("-revertprocessedimfile", "", DETTOOL_MODE_REVERTPROCESSEDIMFILE, revertprocessedimfileArgs);
+
+    PXOPT_ADD_MODE("-toprocessedimfile", "",  		  DETTOOL_MODE_TOPROCESSEDIMFILE, toprocessedimfileArgs);
+    PXOPT_ADD_MODE("-addprocessedimfile", "", 		  DETTOOL_MODE_ADDPROCESSEDIMFILE,  addprocessedimfileArgs);
+    PXOPT_ADD_MODE("-processedimfile", "",    		  DETTOOL_MODE_PROCESSEDIMFILE, processedimfileArgs);
+    PXOPT_ADD_MODE("-revertprocessedimfile", "", 	  DETTOOL_MODE_REVERTPROCESSEDIMFILE, revertprocessedimfileArgs);
+    PXOPT_ADD_MODE("-updateprocessedimfile", "", 	  DETTOOL_MODE_UPDATEPROCESSEDIMFILE, updateprocessedimfileArgs);
+    PXOPT_ADD_MODE("-pendingcleanup_processedimfile", "", DETTOOL_MODE_PENDINGCLEANUP_PROCESSEDIMFILE, pendingcleanup_processedimfileArgs);
+    PXOPT_ADD_MODE("-donecleanup_processedimfile", "",    DETTOOL_MODE_DONECLEANUP_PROCESSEDIMFILE, donecleanup_processedimfileArgs);
+
     PXOPT_ADD_MODE("-toprocessedexp",  "", DETTOOL_MODE_TOPROCESSEDEXP,  toprocessedexpArgs);
     PXOPT_ADD_MODE("-addprocessedexp", "", DETTOOL_MODE_ADDPROCESSEDEXP, addprocessedexpArgs);
+    PXOPT_ADD_MODE("-processedexp",    "", DETTOOL_MODE_PROCESSEDEXP, processedexpArgs);
     PXOPT_ADD_MODE("-revertprocessedexp", "", DETTOOL_MODE_REVERTPROCESSEDEXP, revertprocessedexpArgs);
-    PXOPT_ADD_MODE("-processedexp",    "", DETTOOL_MODE_PROCESSEDEXP, processedexpArgs);
+    PXOPT_ADD_MODE("-updateprocessedexp", "", DETTOOL_MODE_UPDATEPROCESSEDEXP, updateprocessedexpArgs);
+    PXOPT_ADD_MODE("-pendingcleanup_processedexp", "", DETTOOL_MODE_PENDINGCLEANUP_PROCESSEDEXP, pendingcleanup_processedexpArgs);
+    PXOPT_ADD_MODE("-donecleanup_processedexp", "",    DETTOOL_MODE_DONECLEANUP_PROCESSEDEXP, donecleanup_processedexpArgs);
+
     PXOPT_ADD_MODE("-tostacked",       "", DETTOOL_MODE_TOSTACKED,     tostackedArgs);
     PXOPT_ADD_MODE("-addstacked",      "", DETTOOL_MODE_ADDSTACKED,    addstackedArgs);
     PXOPT_ADD_MODE("-stacked",         "", DETTOOL_MODE_STACKED,       stackedArgs);
     PXOPT_ADD_MODE("-revertstacked",   "", DETTOOL_MODE_REVERTSTACKED,  revertstackedArgs);
+    PXOPT_ADD_MODE("-updatestacked",   "", DETTOOL_MODE_UPDATESTACKED,  updatestackedArgs);
+    PXOPT_ADD_MODE("-pendingcleanup_stacked", "", DETTOOL_MODE_PENDINGCLEANUP_STACKED, pendingcleanup_stackedArgs);
+    PXOPT_ADD_MODE("-donecleanup_stacked", "",    DETTOOL_MODE_DONECLEANUP_STACKED, donecleanup_stackedArgs);
+
+    PXOPT_ADD_MODE("-tonormalizedstat",      "", DETTOOL_MODE_TONORMALIZEDSTAT,    tonormalizedstatArgs);
+    PXOPT_ADD_MODE("-addnormalizedstat",     "", DETTOOL_MODE_ADDNORMALIZEDSTAT,   addnormstatArgs);
+    PXOPT_ADD_MODE("-normalizedstat",        "", DETTOOL_MODE_NORMALIZEDSTAT,   normalizedstatArgs);
+    PXOPT_ADD_MODE("-revertnormalizedstat",  "", DETTOOL_MODE_REVERTNORMALIZEDSTAT,   revertnormalizedstatArgs);
+    PXOPT_ADD_MODE("-updatenormalizedstat",  "", DETTOOL_MODE_UPDATENORMALIZEDSTAT,   updatenormalizedstatArgs);
+    PXOPT_ADD_MODE("-pendingcleanup_normalizedstat", "", DETTOOL_MODE_PENDINGCLEANUP_NORMALIZEDSTAT, pendingcleanup_normalizedstatArgs);
+    PXOPT_ADD_MODE("-donecleanup_normalizedstat", "",    DETTOOL_MODE_DONECLEANUP_NORMALIZEDSTAT, donecleanup_normalizedstatArgs);
+
     PXOPT_ADD_MODE("-tonormalize",     "", DETTOOL_MODE_TONORMALIZE,   tonormalizeArgs);
-    PXOPT_ADD_MODE("-addnormalizedstat",     "", DETTOOL_MODE_ADDNORMALIZEDSTAT,   addnormstatArgs);
-    PXOPT_ADD_MODE("-normalizedstat",  "", DETTOOL_MODE_NORMALIZEDSTAT,   normalizedstatArgs);
-    PXOPT_ADD_MODE("-revertnormalizedstat",  "", DETTOOL_MODE_REVERTNORMALIZEDSTAT,   revertnormalizedstatArgs);
-
-    PXOPT_ADD_MODE("-tonormalizedstat",      "", DETTOOL_MODE_TONORMALIZEDSTAT,    tonormalizedstatArgs);
     PXOPT_ADD_MODE("-addnormalizedimfile", "", DETTOOL_MODE_ADDNORMALIZEDIMFILE,addnormalizedimfileArgs);
     PXOPT_ADD_MODE("-normalizedimfile","", DETTOOL_MODE_NORMALIZEDIMFILE, normalizedimfileArgs);
     PXOPT_ADD_MODE("-revertnormalizedimfile","", DETTOOL_MODE_REVERTNORMALIZEDIMFILE, revertnormalizedimfileArgs);
+    PXOPT_ADD_MODE("-updatenormalizedimfile","", DETTOOL_MODE_UPDATENORMALIZEDIMFILE, updatenormalizedimfileArgs);
+    PXOPT_ADD_MODE("-pendingcleanup_normalizedimfile", "", DETTOOL_MODE_PENDINGCLEANUP_NORMALIZEDIMFILE, pendingcleanup_normalizedimfileArgs);
+    PXOPT_ADD_MODE("-donecleanup_normalizedimfile", "",    DETTOOL_MODE_DONECLEANUP_NORMALIZEDIMFILE, donecleanup_normalizedimfileArgs);
+
     PXOPT_ADD_MODE("-tonormalizedexp", "", DETTOOL_MODE_TONORMALIZEDEXP, tonormalizedexpArgs);
     PXOPT_ADD_MODE("-addnormalizedexp", "", DETTOOL_MODE_ADDNORMALIZEDEXP, addnormalizedexpArgs);
     PXOPT_ADD_MODE("-normalizedexp",   "", DETTOOL_MODE_NORMALIZEDEXP, normalizedexpArgs);
     PXOPT_ADD_MODE("-revertnormalizedexp","", DETTOOL_MODE_REVERTNORMALIZEDEXP, revertnormalizedexpArgs);
+    PXOPT_ADD_MODE("-updatenormalizedexp","", DETTOOL_MODE_UPDATENORMALIZEDEXP, updatenormalizedexpArgs);
+    PXOPT_ADD_MODE("-pendingcleanup_normalizedexp", "", DETTOOL_MODE_PENDINGCLEANUP_NORMALIZEDEXP, pendingcleanup_normalizedexpArgs);
+    PXOPT_ADD_MODE("-donecleanup_normalizedexp", "",    DETTOOL_MODE_DONECLEANUP_NORMALIZEDEXP, donecleanup_normalizedexpArgs);
+
     PXOPT_ADD_MODE("-toresidimfile",   "", DETTOOL_MODE_TORESIDIMFILE, toresidimfileArgs);
     PXOPT_ADD_MODE("-addresidimfile",  "", DETTOOL_MODE_ADDRESIDIMFILE, addresidimfileArgs);
     PXOPT_ADD_MODE("-residimfile",     "", DETTOOL_MODE_RESIDIMFILE, residimfileArgs);
     PXOPT_ADD_MODE("-revertresidimfile", "", DETTOOL_MODE_REVERTRESIDIMFILE, revertresidimfileArgs);
+    PXOPT_ADD_MODE("-updateresidimfile", "", DETTOOL_MODE_UPDATERESIDIMFILE, updateresidimfileArgs);
+    PXOPT_ADD_MODE("-pendingcleanup_residimfile", "", DETTOOL_MODE_PENDINGCLEANUP_RESIDIMFILE, pendingcleanup_residimfileArgs);
+    PXOPT_ADD_MODE("-donecleanup_residimfile", "",    DETTOOL_MODE_DONECLEANUP_RESIDIMFILE, donecleanup_residimfileArgs);
+
     PXOPT_ADD_MODE("-toresidexp",      "", DETTOOL_MODE_TORESIDEXP,    toresidexpArgs);
     PXOPT_ADD_MODE("-addresidexp",     "", DETTOOL_MODE_ADDRESIDEXP,  addresidexpArgs);
     PXOPT_ADD_MODE("-residexp",        "", DETTOOL_MODE_RESIDEXP,     residexpArgs);
     PXOPT_ADD_MODE("-revertresidexp",  "", DETTOOL_MODE_REVERTRESIDEXP, revertresidexpArgs);
+    PXOPT_ADD_MODE("-updateresidexp",  "", DETTOOL_MODE_UPDATERESIDEXP, updateresidexpArgs);
+    PXOPT_ADD_MODE("-pendingcleanup_residexp", "", DETTOOL_MODE_PENDINGCLEANUP_RESIDEXP, pendingcleanup_residexpArgs);
+    PXOPT_ADD_MODE("-donecleanup_residexp", "",    DETTOOL_MODE_DONECLEANUP_RESIDEXP, donecleanup_residexpArgs);
+
     PXOPT_ADD_MODE("-todetrunsummary",  "", DETTOOL_MODE_TODETRUNSUMMARY,  todetrunsummaryArgs);
-    PXOPT_ADD_MODE("-updateresidexp", "", DETTOOL_MODE_UPDATERESIDEXP,updateresidexpArgs);
     PXOPT_ADD_MODE("-adddetrunsummary", "", DETTOOL_MODE_ADDDETRUNSUMMARY,adddetrunsummaryArgs);
     PXOPT_ADD_MODE("-detrunsummary", "", DETTOOL_MODE_DETRUNSUMMARY,detrunsummaryArgs);
     PXOPT_ADD_MODE("-revertdetrunsummary", "", DETTOOL_MODE_REVERTDETRUNSUMMARY, revertdetrunsummaryArgs);
     PXOPT_ADD_MODE("-updatedetrunsummary", "", DETTOOL_MODE_UPDATEDETRUNSUMMARY, updatedetrunsummaryArgs);
+
     PXOPT_ADD_MODE("-updatedetrun", "", DETTOOL_MODE_UPDATEDETRUN, updatedetrunArgs);
     PXOPT_ADD_MODE("-rerun",           "", DETTOOL_MODE_RERUN,         rerunArgs);
Index: /trunk/ippTools/src/dettool_correction.c
===================================================================
--- /trunk/ippTools/src/dettool_correction.c	(revision 19091)
+++ /trunk/ippTools/src/dettool_correction.c	(revision 19092)
@@ -24,10 +24,10 @@
     PS_ASSERT_PTR_NON_NULL(config, false);
 
-    PXOPT_LOOKUP_STR(det_id, config->args, "-det_id", true, false); // required
+    PXOPT_LOOKUP_S64(det_id, config->args, "-det_id", true, false); // required
     PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false); // optional
 
     // build the needed where 
     psMetadata *where = psMetadataAlloc();
-    psMetadataAddS64(where, PS_LIST_TAIL, "det_id", 0, "==", (psS64)atoll(det_id));
+    psMetadataAddS64(where, PS_LIST_TAIL, "det_id", 0, "==", det_id);
     psArray *runs = detRunSelectRowObjects(config->dbh, where, 1);
     psFree (where);
Index: /trunk/ippTools/src/dettool_detrunsummary.c
===================================================================
--- /trunk/ippTools/src/dettool_detrunsummary.c	(revision 19092)
+++ /trunk/ippTools/src/dettool_detrunsummary.c	(revision 19092)
@@ -0,0 +1,366 @@
+/*
+ * dettool_detrunsummary.c
+ *
+ * Copyright (C) 2006  Joshua Hoblitt & EAM; IfA
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "dettool.h"
+
+static detRunSummaryRow *mdToDetRunSummary(pxConfig *config, psMetadata *row);
+
+/* The SQL returns a list of detrend runs (with detrend id, iteration and detrend type) which
+ * have completed all residexps.
+ */
+
+bool todetrunsummaryMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psString query = pxDataGet("dettool_todetrunsummary.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "detRejectExp", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+// this function is used to generate the detrunSummary entries used below
+// XXX why is this a separate function?  roll it back into adddetrunsummary?
+static detRunSummaryRow *mdToDetRunSummary(pxConfig *config, psMetadata *row)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    bool status = false;
+    // from row
+    psS64 det_id = psMetadataLookupS64(&status, row, "det_id");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for det_id");
+        return false;
+    }
+    psS32 iteration = psMetadataLookupS32(&status, row, "iteration");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for iteration");
+        return false;
+    }
+
+    // optional
+    PXOPT_LOOKUP_F64(bg, config->args, "-bg", false, false);
+    PXOPT_LOOKUP_F64(bg_stdev, config->args, "-bg_stdev", false, false);
+    PXOPT_LOOKUP_F64(bg_mean_stdev, config->args, "-bg_mean_stdev", false, false);
+
+    // default values
+    PXOPT_LOOKUP_S16(code, config->args, "-code", false, false);
+    PXOPT_LOOKUP_BOOL(accept, config->args, "-accept", false);
+
+    return detRunSummaryRowAlloc(
+            det_id,
+            iteration,
+	    "full",
+            bg,
+            bg_stdev,
+            bg_mean_stdev,
+            accept,
+            code
+        );
+}
+
+// XXX data_state should be set to 'full' here
+bool adddetrunsummaryMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+    
+    // build a query to search by det_id, iteration, exp_id
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id", "det_id", "==");
+    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
+
+    PXOPT_LOOKUP_S64(det_id, config->args, "-det_id", true, false); // required
+    PXOPT_LOOKUP_BOOL(again, config->args, "-again", false);
+
+    // The values supplied as arguments on the command (eg, -bg) are parsed 
+    // by mdToDetRunSummary below. 
+    // XXX why is there ever more than one?
+
+    psString query = pxDataGet("dettool_find_completed_runs.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+	psStringAppend(&query, " WHERE %s", whereClause);
+	psFree(whereClause);
+    }
+    psFree(where);
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // start a transaction so it's all rows or nothing
+    if (!psDBTransaction(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(output);
+        return false;
+    }
+
+    // XXX why is there ever more than one result here?
+    for (long i = 0; i < psArrayLength(output); i++) {
+        psMetadata *row = output->data[i];
+        // convert metadata into a detResidExp object
+        detRunSummaryRow *runSummary = mdToDetRunSummary(config, row);
+        if (!runSummary) {
+            if (!psDBRollback(config->dbh)) {
+                psError(PS_ERR_UNKNOWN, false, "database error");
+            }
+            psError(PS_ERR_UNKNOWN, false, "failed to convert metadata to detResidExp");
+            psFree(output);
+            return false;
+        }
+        // insert detResidExp object into the database
+        if (!detRunSummaryInsertObject(config->dbh, runSummary)) {
+            if (!psDBRollback(config->dbh)) {
+                psError(PS_ERR_UNKNOWN, false, "database error");
+            }
+            psError(PS_ERR_UNKNOWN, false, "database error");
+            psFree(runSummary);
+            psFree(output);
+            return false;
+        }
+        psFree(runSummary);
+    }
+
+    psFree(output);
+
+    // XXX this logic does not deal with the case of -code being set
+    // XXX it should be an error for -again and -code to both be set
+    if (again) {
+        if (!startNewIteration(config, det_id)) {
+            if (!psDBRollback(config->dbh)) {
+                psError(PS_ERR_UNKNOWN, false, "database error");
+            }
+            psError(PS_ERR_UNKNOWN, false, "failed to start new iteration");
+            return false;
+        }
+    } else {
+        // set detRun.state to stop
+        if (!setDetRunState(config, det_id, "stop")) {
+            if (!psDBRollback(config->dbh)) {
+                psError(PS_ERR_UNKNOWN, false, "database error");
+            }
+            psError(PS_ERR_UNKNOWN, false, "failed to set detRun.state");
+            return false;
+        }
+    }
+
+    if (!psDBCommit(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    return true;
+}
+
+bool detrunsummaryMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id",    "det_id", "==");
+    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+    PXOPT_LOOKUP_BOOL(faulted, config->args, "-faulted", false);
+
+    psString query = pxDataGet("dettool_detrunsummary.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        psFree(where);
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, "NULL");
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (faulted) {
+        // list only faulted rows
+        psStringAppend(&query, " %s", "AND detRunSummary.fault != 0");
+    } else {
+        // don't list faulted rows
+        psStringAppend(&query, " %s", "AND detRunSummary.fault = 0");
+    }
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "rawDetrendImfile", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+
+bool revertdetrunsummaryMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id",    "det_id", "==");
+    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
+    PXOPT_COPY_STR(config->args, where, "-code",      "fault", "==");
+
+    psString query = pxDataGet("dettool_revertdetrunsummary.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, "detRunSummary");
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    if (psDBAffectedRows(config->dbh) < 1) {
+        psError(PS_ERR_UNKNOWN, false, "should have affected atleast 1 row");
+        return false;
+    }
+
+    return true;
+}
+
+// XXX need to add -data_state here
+bool updatedetrunsummaryMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+    
+    PXOPT_LOOKUP_S64(det_id, config->args, "-det_id", true, false); // required
+    PXOPT_LOOKUP_BOOL(accept, config->args, "-accept", false);
+    PXOPT_LOOKUP_BOOL(reject, config->args, "-reject", false);
+
+    if (accept && reject) {
+        psError(PS_ERR_UNKNOWN, true, "-accept and -reject are exclusive");
+        return false;
+    }
+
+    if (!(accept || reject)) {
+        psError(PS_ERR_UNKNOWN, true, "either -accept or -reject is required");
+        return false;
+    }
+
+    char *query = "UPDATE detRunSummary SET accept = %d WHERE det_id = %"PRId64; 
+    if (!p_psDBRunQuery(config->dbh, query, accept, det_id)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+
+    return true;
+}
+
+
Index: /trunk/ippTools/src/dettool_normalizedexp.c
===================================================================
--- /trunk/ippTools/src/dettool_normalizedexp.c	(revision 19092)
+++ /trunk/ippTools/src/dettool_normalizedexp.c	(revision 19092)
@@ -0,0 +1,389 @@
+/*
+ * dettool_normalizedexp.c
+ *
+ * Copyright (C) 2006  Joshua Hoblitt & EAM; IfA
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "dettool.h"
+
+bool tonormalizedexpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psString query = pxDataGet("dettool_tonormalizedexp.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "detPendingNormExp", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+bool addnormalizedexpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+    
+    PXOPT_LOOKUP_S64(det_id, config->args, "-det_id", true, false); // required
+    PXOPT_LOOKUP_S32(iteration, config->args, "-iteration", false, false);
+    PXOPT_LOOKUP_S16(code, config->args, "-code", false, false);
+    PXOPT_LOOKUP_STR(recipe, config->args, "-recip", (code == 0), false); // Required if code == 0
+    PXOPT_LOOKUP_F64(bg, config->args, "-bg", false, false);
+    PXOPT_LOOKUP_F64(bg_stdev, config->args, "-bg_stdev", false, false);
+    PXOPT_LOOKUP_F64(bg_mean_stdev, config->args, "-bg_mean_stdev", false, false);
+    PXOPT_LOOKUP_F64(user_1, config->args, "-user_1", false, false);
+    PXOPT_LOOKUP_F64(user_2, config->args, "-user_2", false, false);
+    PXOPT_LOOKUP_F64(user_3, config->args, "-user_3", false, false);
+    PXOPT_LOOKUP_F64(user_4, config->args, "-user_4", false, false);
+    PXOPT_LOOKUP_F64(user_5, config->args, "-user_5", false, false);
+    PXOPT_LOOKUP_STR(path_base, config->args, "-path_base", false, false);
+
+    psString query = pxDataGet("dettool_tonormalizedexp.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    // XXX in some other places, we put the arguments in the .sql and supply them to RunQuery
+    psStringAppend(&query, " WHERE det_id = %" PRId64 " AND iteration = %d", det_id, iteration);
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+    psFree(output);
+
+    // insert the new row into the detProcessedImfile table
+    if (!detNormalizedExpInsert(
+	    config->dbh,
+	    det_id,
+	    iteration,
+	    recipe,
+	    bg,
+	    bg_stdev,
+	    bg_mean_stdev,
+	    user_1,
+	    user_2,
+	    user_3,
+	    user_4,
+	    user_5,
+	    path_base,
+	    "full",
+	    code
+	    )) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+
+    return true;
+}
+
+
+bool normalizedexpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id",    "det_id", "==");
+    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
+    PXOPT_COPY_STR(config->args, where, "-recip",  "recipe", "==");
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+    PXOPT_LOOKUP_BOOL(faulted, config->args, "-faulted", false);
+
+    psString query = pxDataGet("dettool_normalizedexp.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereSQL(where, NULL);
+        psStringAppend(&query, " %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (faulted) {
+        // list only faulted rows
+        psStringAppend(&query, " %s", "AND detNormalizedExp.fault != 0");
+    } else {
+        // don't list faulted rows
+        psStringAppend(&query, " %s", "AND detNormalizedExp.fault = 0");
+    }
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "detNormalizedExp", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+
+
+bool revertnormalizedexpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id",    "det_id", "==");
+    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
+    PXOPT_COPY_S16(config->args, where, "-code",      "fault", "==");
+
+    psString query = pxDataGet("dettool_revertnormalizedexp.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, "detNormalizedExp");
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    if (psDBAffectedRows(config->dbh) < 1) {
+        psError(PS_ERR_UNKNOWN, false, "should have affected atleast 1 row");
+        return false;
+    }
+
+    return true;
+}
+
+bool updatenormalizedexpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_S64(det_id, config->args, "-det_id", true, false);
+    PXOPT_LOOKUP_S32(iteration, config->args, "-iteration", true, false);
+    PXOPT_LOOKUP_STR(data_state, config->args, "-data_state", true, false);
+
+    if (!setNormExpDataState(config, det_id, iteration, data_state)) {
+	return false;
+    }
+    return true;
+}
+
+bool pendingcleanup_normalizedexpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id", "detNormalizedExp.det_id", "==");
+    PXOPT_COPY_S32(config->args, where, "-iteration", "detNormalizedExp.iteration", "==");
+
+    psString query = pxDataGet("dettool_pendingcleanup_normalizedexp.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "detCleanupNormExp", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+
+bool donecleanup_normalizedexpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id", "detNormalizedExp.det_id", "==");
+    PXOPT_COPY_S32(config->args, where, "-iteration", "detNormalizedExp.iteration", "==");
+
+    psString query = pxDataGet("dettool_donecleanup_normalizedexp.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "detDoneCleanup_normalizedexp", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
Index: /trunk/ippTools/src/dettool_normalizedimfile.c
===================================================================
--- /trunk/ippTools/src/dettool_normalizedimfile.c	(revision 19092)
+++ /trunk/ippTools/src/dettool_normalizedimfile.c	(revision 19092)
@@ -0,0 +1,372 @@
+/*
+ * dettool_normalizedimfile.c
+ *
+ * Copyright (C) 2006  Joshua Hoblitt & EAM; IfA
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "dettool.h"
+
+// XXX this one is inconsistent - rename 'tonormalizedimfile' and change ipp_serial_detrend.pl and detrend.norm.pro
+bool tonormalizeMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psString query = pxDataGet("dettool_tonormalize.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "detPendingNormImfile", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+bool addnormalizedimfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    // required
+    PXOPT_LOOKUP_S64(det_id, config->args, "-det_id", true, false);
+    PXOPT_LOOKUP_S32(iteration, config->args, "-iteration", false, false);
+    PXOPT_LOOKUP_STR(class_id, config->args, "-class_id", true, false);
+
+    PXOPT_LOOKUP_S16(code, config->args, "-code", false, false);
+
+    // Required if code == 0
+    PXOPT_LOOKUP_STR(uri, config->args, "-uri", (code == 0), false);
+
+    // optional
+    PXOPT_LOOKUP_F64(bg, config->args, "-bg", false, false);
+    PXOPT_LOOKUP_F64(bg_stdev, config->args, "-bg_stdev", false, false);
+    PXOPT_LOOKUP_F64(bg_mean_stdev, config->args, "-bg_mean_stdev", false, false);
+    PXOPT_LOOKUP_F64(user_1, config->args, "-user_1", false, false);
+    PXOPT_LOOKUP_F64(user_2, config->args, "-user_2", false, false);
+    PXOPT_LOOKUP_F64(user_3, config->args, "-user_3", false, false);
+    PXOPT_LOOKUP_F64(user_4, config->args, "-user_4", false, false);
+    PXOPT_LOOKUP_F64(user_5, config->args, "-user_5", false, false);
+    PXOPT_LOOKUP_STR(path_base, config->args, "-path_base", false, false);
+
+    if (!detNormalizedImfileInsert(
+	    config->dbh,
+	    det_id,
+	    iteration,
+	    class_id,
+	    uri,
+	    bg,
+	    bg_stdev,
+	    bg_mean_stdev,
+	    user_1,
+	    user_2,
+	    user_3,
+	    user_4,
+	    user_5,
+	    path_base,
+	    "full",
+	    code
+	    )) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+
+    return true;
+}
+
+bool normalizedimfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id",    "det_id", "==");
+    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
+    PXOPT_COPY_STR(config->args, where, "-class_id",  "class_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-recip",     "recipe", "==");
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+    PXOPT_LOOKUP_BOOL(faulted, config->args, "-faulted", false);
+
+    psString query = pxDataGet("dettool_normalizedimfile.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, "detNormalizedImfile");
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (faulted) {
+        // list only faulted rows
+        psStringAppend(&query, " %s", "AND detNormalizedImfile.fault != 0");
+    } else {
+        // don't list faulted rows
+        psStringAppend(&query, " %s", "AND detNormalizedImfile.fault = 0");
+    }
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "detNormalizedImfile", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+bool revertnormalizedimfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id",    "det_id", "==");
+    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
+    PXOPT_COPY_STR(config->args, where, "-class_id",  "class_id", "==");
+    PXOPT_COPY_S16(config->args, where, "-code",      "fault", "==");
+
+    psString query = pxDataGet("dettool_revertnormalizedimfile.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, "detNormalizedImfile");
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    if (psDBAffectedRows(config->dbh) < 1) {
+        psError(PS_ERR_UNKNOWN, false, "should have affected atleast 1 row");
+        return false;
+    }
+
+    return true;
+}
+
+bool updatenormalizedimfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_S64(det_id, config->args, "-det_id", true, false);
+    PXOPT_LOOKUP_S32(iteration, config->args, "-iteration", true, false);
+    PXOPT_LOOKUP_STR(class_id, config->args, "-class_id",  true, false);
+    PXOPT_LOOKUP_STR(data_state, config->args, "-data_state", true, false);
+
+    if (!setNormImfileDataState(config, det_id, iteration, class_id, data_state)) {
+	return false;
+    }
+    return true;
+}
+
+bool pendingcleanup_normalizedimfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id", "detNormalizedImfile.det_id", "==");
+    PXOPT_COPY_S32(config->args, where, "-iteration", "detNormalizedImfile.iteration", "==");
+    PXOPT_COPY_STR(config->args, where, "-class_id", "detNormalizedImfile.det_id", "==");
+
+    psString query = pxDataGet("dettool_pendingcleanup_normalizedimfile.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "detCleanupNormImfile", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+
+bool donecleanup_normalizedimfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id", "detNormalizedImfile.det_id", "==");
+    PXOPT_COPY_S32(config->args, where, "-iteration", "detNormalizedImfile.iteration", "==");
+    PXOPT_COPY_STR(config->args, where, "-class_id", "detNormalizedImfile.det_id", "==");
+
+    psString query = pxDataGet("dettool_donecleanup_normalizedimfile.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "detDoneCleanup_normalizedimfile", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
Index: /trunk/ippTools/src/dettool_normalizedstat.c
===================================================================
--- /trunk/ippTools/src/dettool_normalizedstat.c	(revision 19092)
+++ /trunk/ippTools/src/dettool_normalizedstat.c	(revision 19092)
@@ -0,0 +1,352 @@
+/*
+ * dettool_normalizedstat.c
+ *
+ * Copyright (C) 2006  Joshua Hoblitt & EAM; IfA
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "dettool.h"
+
+bool tonormalizedstatMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psString query = pxDataGet("dettool_tonormalizedstat.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "detPendingNormStatImfile", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+bool addnormalizedstatMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    // required
+    PXOPT_LOOKUP_S64(det_id, config->args, "-det_id", true, false);
+    PXOPT_LOOKUP_STR(class_id, config->args, "-class_id", true, false);
+
+    // optional
+    PXOPT_LOOKUP_F32(norm, config->args, "-norm", false, false);
+
+    // default
+    PXOPT_LOOKUP_S32(iteration, config->args, "-iteration", false, false);
+    PXOPT_LOOKUP_S16(code, config->args, "-code", false, false);
+
+    detNormalizedStatImfileRow *row = detNormalizedStatImfileRowAlloc
+	(det_id,
+	 iteration,
+	 class_id,
+	 norm,
+	 "full",
+	 code);
+									 
+    if (!detNormalizedStatImfileInsertObject(config->dbh, row)) {
+	psError(PS_ERR_UNKNOWN, false, "database error");
+	return false;
+    }
+
+    return true;
+}
+
+
+bool normalizedstatMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id",    "det_id", "==");
+    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
+    PXOPT_COPY_STR(config->args, where, "-class_id",  "class_id", "==");
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(faulted, config->args, "-faulted", false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psString query = pxDataGet("dettool_normalizedstat.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (faulted) {
+        // list only faulted rows
+        psStringAppend(&query, " %s", "WHERE fault != 0");
+    } else {
+        // don't list faulted rows
+        psStringAppend(&query, " %s", "WHERE fault = 0");
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "detNormalizedStatImfile", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+bool revertnormalizedstatMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id",    "det_id", "==");
+    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
+    PXOPT_COPY_STR(config->args, where, "-class_id",  "class_id", "==");
+    PXOPT_COPY_S16(config->args, where, "-code",      "fault", "==");
+
+    psString query = pxDataGet("dettool_revertnormalizedstat.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, "detNormalizedStatImfile");
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    if (psDBAffectedRows(config->dbh) < 1) {
+        psError(PS_ERR_UNKNOWN, false, "should have affected atleast 1 row");
+        return false;
+    }
+
+    return true;
+}
+
+bool updatenormalizedstatMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_S64(det_id, config->args, "-det_id", true, false);
+    PXOPT_LOOKUP_S32(iteration, config->args, "-iteration", true, false);
+    PXOPT_LOOKUP_STR(class_id, config->args, "-class_id",  true, false);
+    PXOPT_LOOKUP_STR(data_state, config->args, "-data_state", true, false);
+
+    if (!setNormStatImfileDataState(config, det_id, iteration, class_id, data_state)) {
+	return false;
+    }
+    return true;
+}
+
+bool pendingcleanup_normalizedstatMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id", "detNormalizedStatImfile.det_id", "==");
+    PXOPT_COPY_S32(config->args, where, "-iteration", "detNormalizedStatImfile.iteration", "==");
+    PXOPT_COPY_STR(config->args, where, "-class_id", "detNormalizedStatImfile.det_id", "==");
+
+    psString query = pxDataGet("dettool_pendingcleanup_normalizedstat.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "detCleanupNormStatImfile", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+
+bool donecleanup_normalizedstatMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id", "detNormalizedStatImfile.det_id", "==");
+    PXOPT_COPY_S32(config->args, where, "-iteration", "detNormalizedStatImfile.iteration", "==");
+    PXOPT_COPY_STR(config->args, where, "-class_id", "detNormalizedStatImfile.det_id", "==");
+
+    psString query = pxDataGet("dettool_donecleanup_normalizedstat.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "detDoneCleanup_normalizedstat", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
Index: /trunk/ippTools/src/dettool_processedexp.c
===================================================================
--- /trunk/ippTools/src/dettool_processedexp.c	(revision 19092)
+++ /trunk/ippTools/src/dettool_processedexp.c	(revision 19092)
@@ -0,0 +1,398 @@
+/*
+ * dettool_processedexp.c
+ *
+ * Copyright (C) 2006  Joshua Hoblitt & EAM; IfA
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "dettool.h"
+
+bool toprocessedexpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psString query = pxDataGet("dettool_toprocessedexp.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "detPendingProcessedExp", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+bool addprocessedexpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    // det_id, exp_id, recip, -bg, -bg_stdev
+    // are required
+    PXOPT_LOOKUP_S64(det_id, config->args, "-det_id", true, false);
+    PXOPT_LOOKUP_S64(exp_id, config->args, "-exp_id", true, false);
+
+    // default values
+    PXOPT_LOOKUP_S16(code, config->args, "-code", false, false);
+
+    // Required if code == 0
+    PXOPT_LOOKUP_STR(recipe, config->args, "-recip", (code == 0), false);
+
+    // optional
+    PXOPT_LOOKUP_F64(bg, config->args, "-bg", false, false);
+    PXOPT_LOOKUP_F64(bg_stdev, config->args, "-bg_stdev", false, false);
+    PXOPT_LOOKUP_F64(bg_mean_stdev, config->args, "-bg_mean_stdev", false, false);
+    PXOPT_LOOKUP_F64(fringe_0, config->args, "-fringe_0", false, false);
+    PXOPT_LOOKUP_F64(fringe_1, config->args, "-fringe_1", false, false);
+    PXOPT_LOOKUP_F64(fringe_2, config->args, "-fringe_2", false, false);
+    PXOPT_LOOKUP_F64(user_1, config->args, "-user_1", false, false);
+    PXOPT_LOOKUP_F64(user_2, config->args, "-user_2", false, false);
+    PXOPT_LOOKUP_F64(user_3, config->args, "-user_3", false, false);
+    PXOPT_LOOKUP_F64(user_4, config->args, "-user_4", false, false);
+    PXOPT_LOOKUP_F64(user_5, config->args, "-user_5", false, false);
+    PXOPT_LOOKUP_STR(path_base, config->args, "-path_base", true, false);
+
+    psString query = pxDataGet("dettool_addprocessedexp.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query, (long long) det_id, (long long) exp_id)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+    psFree(output);
+
+    // create a new detProcessedImfile object
+    detProcessedExpRow *detRow = detProcessedExpRowAlloc(
+        det_id,
+        exp_id,
+        recipe,
+        bg,
+        bg_stdev,
+        bg_mean_stdev,
+        fringe_0,
+        fringe_1,
+        fringe_2,
+        user_1,
+        user_2,
+        user_3,
+        user_4,
+        user_5,
+        path_base,
+	"full",
+        code
+    );
+
+    // insert the new row into the detProcessedImfile table
+    if (!detProcessedExpInsertObject(config->dbh, detRow)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(detRow);
+        return false;
+    }
+
+    psFree(detRow);
+
+    return true;
+}
+
+bool processedexpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id", "det_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-exp_id", "exp_id", "==");
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(faulted, config->args, "-faulted", false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psString query = psStringCopy("SELECT * FROM detProcessedExp");
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereSQL(where, NULL);
+        psStringAppend(&query, " %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (faulted) {
+        // list only faulted rows
+        psStringAppend(&query, " %s", "AND detProcessedExp.fault != 0");
+    } else {
+        // don't list faulted rows
+        psStringAppend(&query, " %s", "AND detProcessedExp.fault = 0");
+    }
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "detProcessedExp", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+
+bool revertprocessedexpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id", "det_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-exp_id", "exp_id", "==");
+    PXOPT_COPY_S16(config->args, where, "-code",   "fault", "==");
+
+    psString query = pxDataGet("dettool_revertprocessedexp.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, "detProcessedExp");
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    if (psDBAffectedRows(config->dbh) < 1) {
+        psError(PS_ERR_UNKNOWN, false, "should have affected atleast 1 row");
+        return false;
+    }
+
+    return true;
+}
+
+bool updateprocessedexpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_S64(det_id, config->args, "-det_id", true, false);
+    PXOPT_LOOKUP_S64(exp_id, config->args, "-exp_id", true, false);
+    PXOPT_LOOKUP_STR(data_state, config->args, "-data_state", true, false);
+    if (!setProcessedExpDataState(config, det_id, exp_id, data_state)) {
+	return false;
+    }
+    return true;
+}
+
+bool pendingcleanup_processedexpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id", "det_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-exp_id", "exp_id", "==");
+
+    psString query = pxDataGet("dettool_pendingcleanup_processedexp.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "detCleanupProcessedExp", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+// XXX SQL missing
+bool donecleanup_processedexpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id", "det_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-exp_id", "exp_id", "==");
+
+    psString query = pxDataGet("dettool_donecleanup_processedexp.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "detDoneCleanupProcessedExp", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
Index: /trunk/ippTools/src/dettool_processedimfile.c
===================================================================
--- /trunk/ippTools/src/dettool_processedimfile.c	(revision 19092)
+++ /trunk/ippTools/src/dettool_processedimfile.c	(revision 19092)
@@ -0,0 +1,436 @@
+/*
+ * dettool_processedimfile.c
+ *
+ * Copyright (C) 2006  Joshua Hoblitt & EAM; IfA
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "dettool.h"
+
+bool toprocessedimfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id",   "det_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-exp_id",   "exp_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-class_id", "class_id", "==");
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psString query = pxDataGet("dettool_toprocessedimfile.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, "rawImfile");
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree (where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "detPendingProcessedImfile", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+bool addprocessedimfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    // det_id, exp_id, class_id, uri, recipe, -bg, -bg_stdev are required
+    PXOPT_LOOKUP_S64(det_id, config->args, "-det_id", true, false);
+    PXOPT_LOOKUP_S64(exp_id, config->args, "-exp_id", true, false);
+    PXOPT_LOOKUP_STR(class_id, config->args, "-class_id", true, false);
+
+    // default values
+    PXOPT_LOOKUP_S16(code, config->args, "-code", false, false);
+
+    // Required if code == 0
+    PXOPT_LOOKUP_STR(uri, config->args, "-uri", (code == 0), false);
+    PXOPT_LOOKUP_STR(recipe, config->args, "-recip", (code == 0), false);
+
+    // optional
+    PXOPT_LOOKUP_F64(bg, config->args, "-bg", false, false);
+    PXOPT_LOOKUP_F64(bg_stdev, config->args, "-bg_stdev", false, false);
+    PXOPT_LOOKUP_F64(bg_mean_stdev, config->args, "-bg_mean_stdev", false, false);
+    PXOPT_LOOKUP_F64(fringe_0, config->args, "-fringe_0", false, false);
+    PXOPT_LOOKUP_F64(fringe_1, config->args, "-fringe_1", false, false);
+    PXOPT_LOOKUP_F64(fringe_2, config->args, "-fringe_2", false, false);
+    PXOPT_LOOKUP_F64(user_1, config->args, "-user_1", false, false);
+    PXOPT_LOOKUP_F64(user_2, config->args, "-user_2", false, false);
+    PXOPT_LOOKUP_F64(user_3, config->args, "-user_3", false, false);
+    PXOPT_LOOKUP_F64(user_4, config->args, "-user_4", false, false);
+    PXOPT_LOOKUP_F64(user_5, config->args, "-user_5", false, false);
+    PXOPT_LOOKUP_STR(path_base, config->args, "-path_base", false, false);
+
+    // find the matching rawImfile by exp_id/class_id
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-exp_id",   "exp_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-class_id", "class_id", "==");
+
+    psArray *rawImfiles = rawImfileSelectRowObjects(config->dbh, where, 0);
+    psFree(where);
+
+    if (!rawImfiles) {
+        psError(PS_ERR_UNKNOWN, false, "no rawImfile rows found ");
+        return false;
+    }
+
+    // create a new detProcessedImfile object
+    detProcessedImfileRow *detRow = detProcessedImfileRowAlloc(
+        det_id,
+        exp_id,
+        class_id,
+        uri,
+        recipe,
+        bg,
+        bg_stdev,
+        bg_mean_stdev,
+        fringe_0,
+        fringe_1,
+        fringe_2,
+        user_1,
+        user_2,
+        user_3,
+        user_4,
+        user_5,
+        path_base,
+	"full",
+        code
+    );
+    psFree(rawImfiles);
+
+    // insert the new row into the detProcessedImfile table
+    if (!detProcessedImfileInsertObject(config->dbh, detRow)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(detRow);
+        return false;
+    }
+
+    psFree(detRow);
+
+    return true;
+}
+
+bool processedimfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    char *value = NULL;
+
+    PXOPT_LOOKUP_BOOL(included, config->args, "-included", false);
+    PXOPT_LOOKUP_BOOL(faulted, config->args, "-faulted", false);
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id", "det_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-exp_id", "exp_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-class_id", "class_id", "==");
+
+    psString query = pxDataGet("dettool_processedimfile.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        psFree(where);
+        return false;
+    }
+
+    // add the two required restrictions: detRun.state and detRun.mode
+    // NOTE the above query requires one of the following two WHERE statements
+    {
+        bool status;
+        if ((value = psMetadataLookupStr(&status, config->args, "-select_state"))) {
+            psStringAppend(&query, " WHERE detRun.state = '%s'", value);
+        } else {
+            psStringAppend(&query, " WHERE detRun.state = 'run'");
+        }
+        if ((value = psMetadataLookupStr(&status, config->args, "-select_mode"))) {
+            psStringAppend(&query, " AND detRun.mode = '%s'", value);
+        } else {
+            psStringAppend(&query, " AND detRun.mode = 'master'");
+        }
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, "detProcessedImfile");
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree (where);
+
+    // restrict search to included imfiles
+    if (included) {
+	psStringAppend(&query, " AND detInputExp.include = 1");
+    }
+
+    if (faulted) {
+        // list only faulted rows
+        psStringAppend(&query, " %s", "AND detProcessedImfile.fault != 0");
+    } else {
+        // don't list faulted rows
+        psStringAppend(&query, " %s", "AND detProcessedImfile.fault = 0");
+    }
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "rawImfile", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+bool revertprocessedimfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id", "det_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-exp_id", "exp_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-class_id", "class_id", "==");
+    PXOPT_COPY_S16(config->args, where, "-code", "fault", "==");
+
+    psString query = pxDataGet("dettool_revertprocessedimfile.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, "detProcessedImfile");
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    if (psDBAffectedRows(config->dbh) < 1) {
+        psError(PS_ERR_UNKNOWN, false, "should have affected atleast 1 row");
+        return false;
+    }
+
+    return true;
+}
+
+bool updateprocessedimfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_S64(det_id, config->args, "-det_id", true, false);
+    PXOPT_LOOKUP_S64(exp_id, config->args, "-exp_id", true, false);
+    PXOPT_LOOKUP_STR(class_id, config->args, "-class_id", true, false);
+    PXOPT_LOOKUP_STR(data_state, config->args, "-data_state", true, false);
+
+    if (!setProcessedImfileDataState(config, det_id, exp_id, class_id, data_state)) {
+	return false;
+    }
+    return true;
+}
+
+bool pendingcleanup_processedimfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id", "det_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-exp_id", "exp_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-class_id", "class_id", "==");
+
+    psString query = pxDataGet("dettool_pendingcleanup_processedimfile.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "detCleanupProcessedImfile", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+// XXX SQL missing
+bool donecleanup_processedimfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id", "det_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-exp_id", "exp_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-class_id", "class_id", "==");
+
+    psString query = pxDataGet("dettool_donecleanup_processedimfile.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "detDoneCleanup_processedimfile", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
Index: /trunk/ippTools/src/dettool_residexp.c
===================================================================
--- /trunk/ippTools/src/dettool_residexp.c	(revision 19092)
+++ /trunk/ippTools/src/dettool_residexp.c	(revision 19092)
@@ -0,0 +1,479 @@
+/*
+ * dettool_residexp.c
+ *
+ * Copyright (C) 2006  Joshua Hoblitt & EAM; IfA
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "dettool.h"
+
+/*
+  The SQL returns a list of exposures for which all component class ids have had residuals
+  created.  This list includes the detrend id, iteration, exposure id, detrend type, and
+  whether the exposure was included in the stack for this iteration.
+*/
+
+bool toresidexpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psString query = pxDataGet("dettool_toresidexp.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "detPendingResidExp", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+/*
+  The SQL returns a list of exposures for which all component class ids have had residuals
+  created.  This list includes the detrend id, iteration, exposure id, detrend type, and
+  whether the exposure was included in the stack for this iteration.
+*/
+
+bool addresidexpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    // limit search by det_id, iteration, exp_id
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id", "det_id", "==");
+    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
+    PXOPT_COPY_S64(config->args, where, "-exp_id", "exp_id", "==");
+
+    PXOPT_LOOKUP_S64(det_id, config->args, "-det_id", true, false); // required
+    PXOPT_LOOKUP_S32(iteration, config->args, "-iteration", false, false);
+    PXOPT_LOOKUP_S64(exp_id, config->args, "-exp_id", true, false); // required
+    PXOPT_LOOKUP_S16(code, config->args, "-code", false, false);
+    PXOPT_LOOKUP_STR(recipe, config->args, "-recip", (code == 0), false); // Required if code == 0
+    PXOPT_LOOKUP_F64(bg, config->args, "-bg", false, false);
+    PXOPT_LOOKUP_F64(bg_stdev, config->args, "-bg_stdev", false, false);
+    PXOPT_LOOKUP_F64(bg_mean_stdev, config->args, "-bg_mean_stdev", false, false);
+    PXOPT_LOOKUP_F64(bg_skewness, config->args, "-bg_skewness", false, false);
+    PXOPT_LOOKUP_F64(bg_kurtosis, config->args, "-bg_kurtosis", false, false);
+    PXOPT_LOOKUP_F64(bin_stdev, config->args, "-bin_stdev", false, false);
+    PXOPT_LOOKUP_F64(fringe_0, config->args, "-fringe_0", false, false);
+    PXOPT_LOOKUP_F64(fringe_1, config->args, "-fringe_1", false, false);
+    PXOPT_LOOKUP_F64(fringe_2, config->args, "-fringe_2", false, false);
+    PXOPT_LOOKUP_F64(fringe_resid_0, config->args, "-fringe_resid_0", false, false);
+    PXOPT_LOOKUP_F64(fringe_resid_1, config->args, "-fringe_resid_1", false, false);
+    PXOPT_LOOKUP_F64(fringe_resid_2, config->args, "-fringe_resid_2", false, false);
+    PXOPT_LOOKUP_F64(user_1, config->args, "-user_1", false, false);
+    PXOPT_LOOKUP_F64(user_2, config->args, "-user_2", false, false);
+    PXOPT_LOOKUP_F64(user_3, config->args, "-user_3", false, false);
+    PXOPT_LOOKUP_F64(user_4, config->args, "-user_4", false, false);
+    PXOPT_LOOKUP_F64(user_5, config->args, "-user_5", false, false);
+    PXOPT_LOOKUP_STR(path_base, config->args, "-path_base", false, false);
+    PXOPT_LOOKUP_BOOL(reject, config->args, "-reject", false);
+
+    psString query = pxDataGet("dettool_toresidexp.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+	psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+	psStringAppend(&query, " WHERE %s", whereClause);
+	psFree(whereClause);
+    }
+    psFree(where);
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        // XXX check psError here
+        psError(PS_ERR_UNKNOWN, false, "no detResidImfile rows found");
+        psFree(output);
+        return false;
+    }
+    psFree(output);
+
+    if (!detResidExpInsert(
+	    config->dbh,
+            det_id,
+            iteration,
+            exp_id,
+            recipe,
+            bg,
+            bg_stdev,
+            bg_mean_stdev,
+            bg_skewness,
+            bg_kurtosis,
+            bin_stdev,
+            fringe_0,
+            fringe_1,
+            fringe_2,
+            fringe_resid_0,
+            fringe_resid_1,
+            fringe_resid_2,
+            user_1,
+            user_2,
+            user_3,
+            user_4,
+            user_5,
+            path_base,
+	    "full",
+            !reject,
+            code
+        )) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+
+    return true;
+}
+
+bool residexpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id",    "det_id", "==");
+    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
+    PXOPT_COPY_S64(config->args, where, "-exp_id",    "exp_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-recip",     "recipe", "==");
+
+    PXOPT_LOOKUP_U64(limit,    config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple,  config->args, "-simple", false);
+    PXOPT_LOOKUP_BOOL(faulted, config->args, "-faulted", false);
+    PXOPT_LOOKUP_BOOL(reject,  config->args, "-reject", false);
+
+    psString query = pxDataGet("dettool_residexp.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, "detResidExp");
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (faulted) {
+        // list only faulted rows
+        psStringAppend(&query, " %s", "AND detResidExp.fault != 0");
+    } else {
+        // don't list faulted rows
+        psStringAppend(&query, " %s", "AND detResidExp.fault = 0");
+    }
+
+    // list only accepted rows
+    // XXX the usage of this flag is unclear : -reject means "accepted"?
+    if (reject) {
+        psStringAppend(&query, " %s", "AND detResidExp.accept != 0");
+    } 
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "detResidExp", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+
+bool revertresidexpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id",    "det_id", "==");
+    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
+    PXOPT_COPY_S64(config->args, where, "-exp_id",    "exp_id", "==");
+    PXOPT_COPY_S16(config->args, where, "-code",      "fault", "==");
+
+    psString query = pxDataGet("dettool_revertresidexp.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, "detResidExp");
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    if (psDBAffectedRows(config->dbh) < 1) {
+        psError(PS_ERR_UNKNOWN, false, "should have affected atleast 1 row");
+        return false;
+    }
+
+    return true;
+}
+
+
+bool updateresidexpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    PXOPT_LOOKUP_BOOL(reject, config->args, "-reject", false);
+
+    // build a query to search by det_id, iteration, exp_id
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id", "det_id", "==");
+    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
+    PXOPT_COPY_S64(config->args, where, "-exp_id", "exp_id", "==");
+
+    // find the values we're going to set
+    // copy everything but det_id, iteration, & exp_id from the args and
+    // remove the '-' prefix
+    psMetadata *set = psMetadataAlloc();
+    PXOPT_COPY_STR(config->args, set, "-recip", "recipe", "==");
+    PXOPT_COPY_F64(config->args, set, "-bg", "bg", "==");
+    PXOPT_COPY_F64(config->args, set, "-bg_stdev", "bg_stdev", "==");
+    PXOPT_COPY_F64(config->args, set, "-bg_mean_stdev", "bg_mean_stdev", "==");
+    PXOPT_COPY_STR(config->args, set, "-path_base", "path_base", "==");
+    PXOPT_COPY_STR(config->args, set, "-data_state", "data_state", "==");
+
+    // double-check the allowed data_state values
+    PXOPT_LOOKUP_STR(data_state, config->args, "-data_state", false, false);
+    if (data_state) {
+	if (!isValidDataState (data_state)) return false;
+    }
+
+    // this can't be PXOPT_ macro-ized as reject is !'d
+    if (!psMetadataAddBool(set, PS_LIST_TAIL, "accept", 0, "==", !reject)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item accept");
+        psFree(set);
+        psFree(where);
+        return false;
+    }
+
+    long changed = psDBUpdateRows(config->dbh, "detResidExp", where, set);
+    psFree(set);
+    psFree(where);
+
+    if (changed < 0) {
+        psError(PS_ERR_UNKNOWN, false, "no rows were updated");
+        return false;
+    }
+
+    return true;
+}
+
+bool pendingcleanup_residexpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id", "det_id", "==");
+    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
+    PXOPT_COPY_S64(config->args, where, "-exp_id",    "exp_id", "==");
+
+    psString query = pxDataGet("dettool_pendingcleanup_residexp.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "detCleanupResidExp", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+
+bool donecleanup_residexpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id", "det_id", "==");
+    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
+    PXOPT_COPY_S64(config->args, where, "-exp_id",    "exp_id", "==");
+
+    psString query = pxDataGet("dettool_donecleanup_residexp.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "detDoneCleanup_residexp", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
Index: /trunk/ippTools/src/dettool_residimfile.c
===================================================================
--- /trunk/ippTools/src/dettool_residimfile.c	(revision 19092)
+++ /trunk/ippTools/src/dettool_residimfile.c	(revision 19092)
@@ -0,0 +1,404 @@
+/*
+ * dettool_residimfile.c
+ *
+ * Copyright (C) 2006  Joshua Hoblitt & EAM; IfA
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "dettool.h"
+
+bool toresidimfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psString query = pxDataGet("dettool_toresidimfile.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "detPendingResidImfile", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+
+bool addresidimfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    
+    PXOPT_LOOKUP_S64(det_id, config->args, "-det_id", true, false); // required
+    PXOPT_LOOKUP_S32(iteration, config->args, "-iteration", false, false);
+    PXOPT_LOOKUP_S64(exp_id, config->args, "-exp_id", true, false); // required
+    PXOPT_LOOKUP_STR(class_id, config->args, "-class_id", true, false); // required
+    PXOPT_LOOKUP_S16(code, config->args, "-code", false, false);
+    PXOPT_LOOKUP_STR(uri, config->args, "-uri", (code == 0), false); // Required if code == 0
+    PXOPT_LOOKUP_STR(recipe, config->args, "-recip", (code == 0), false); // Required if code == 0
+    PXOPT_LOOKUP_F64(bg, config->args, "-bg", false, false);
+    PXOPT_LOOKUP_F64(bg_stdev, config->args, "-bg_stdev", false, false);
+    PXOPT_LOOKUP_F64(bg_mean_stdev, config->args, "-bg_mean_stdev", false, false);
+    PXOPT_LOOKUP_F64(bg_skewness, config->args, "-bg_skewness", false, false);
+    PXOPT_LOOKUP_F64(bg_kurtosis, config->args, "-bg_kurtosis", false, false);
+    PXOPT_LOOKUP_F64(bin_stdev, config->args, "-bin_stdev", false, false);
+    PXOPT_LOOKUP_F64(fringe_0, config->args, "-fringe_0", false, false);
+    PXOPT_LOOKUP_F64(fringe_1, config->args, "-fringe_1", false, false);
+    PXOPT_LOOKUP_F64(fringe_2, config->args, "-fringe_2", false, false);
+    PXOPT_LOOKUP_F64(fringe_resid_0, config->args, "-fringe_resid_0", false, false);
+    PXOPT_LOOKUP_F64(fringe_resid_1, config->args, "-fringe_resid_1", false, false);
+    PXOPT_LOOKUP_F64(fringe_resid_2, config->args, "-fringe_resid_2", false, false);
+    PXOPT_LOOKUP_F64(user_1, config->args, "-user_1", false, false);
+    PXOPT_LOOKUP_F64(user_2, config->args, "-user_2", false, false);
+    PXOPT_LOOKUP_F64(user_3, config->args, "-user_3", false, false);
+    PXOPT_LOOKUP_F64(user_4, config->args, "-user_4", false, false);
+    PXOPT_LOOKUP_F64(user_5, config->args, "-user_5", false, false);
+    PXOPT_LOOKUP_STR(path_base, config->args, "-path_base", false, false);
+
+    if (!detResidImfileInsert(
+	    config->dbh,
+            det_id,
+            iteration,
+            exp_id,
+            class_id,
+            uri,
+            recipe,
+            bg,
+            bg_stdev,
+            bg_mean_stdev,
+            bg_skewness,
+            bg_kurtosis,
+            bin_stdev,
+            fringe_0,
+            fringe_1,
+            fringe_2,
+            fringe_resid_0,
+            fringe_resid_1,
+            fringe_resid_2,
+            user_1,
+            user_2,
+            user_3,
+            user_4,
+            user_5,
+            path_base,
+	    "full",
+            code
+    )) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+
+    return true;
+}
+
+
+bool residimfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id",     "det_id", "==");
+    PXOPT_COPY_S32(config->args, where, "-iteration",  "iteration", "==");
+    PXOPT_COPY_S64(config->args, where, "-exp_id",     "exp_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-class_id",   "class_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-recip",      "recipe", "==");
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+    PXOPT_LOOKUP_BOOL(faulted, config->args, "-faulted", false);
+
+    psString query = pxDataGet("dettool_residimfile.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    // NOTE: the query ends in a WHERE, add the required restriction on detRun.state
+    char *value = NULL;
+    bool status;
+    if ((value = psMetadataLookupStr(&status, config->args, "-select_state"))) {
+        psStringAppend(&query, " detRun.state = '%s'", value);
+    } else {
+        psStringAppend(&query, " detRun.state = 'run'");
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, "detResidImfile");
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (faulted) {
+        // list only faulted rows
+        psStringAppend(&query, " %s", "AND detResidImfile.fault != 0");
+    } else {
+        // don't list faulted rows
+        psStringAppend(&query, " %s", "AND detResidImfile.fault = 0");
+    }
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "rawResidImfile", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+
+bool revertresidimfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id",    "det_id", "==");
+    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
+    PXOPT_COPY_S64(config->args, where, "-exp_id",  "exp_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-class_id",  "class_id", "==");
+    PXOPT_COPY_S16(config->args, where, "-code",      "fault", "==");
+
+    psString query = pxDataGet("dettool_revertresidimfile.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, "detResidImfile");
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    if (psDBAffectedRows(config->dbh) < 1) {
+        psError(PS_ERR_UNKNOWN, false, "should have affected atleast 1 row");
+        return false;
+    }
+
+    return true;
+}
+
+bool updateresidimfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_S64(det_id, config->args, "-det_id", true, false);
+    PXOPT_LOOKUP_S32(iteration, config->args, "-iteration", true, false);
+    PXOPT_LOOKUP_S64(exp_id, config->args, "-exp_id", true, false);
+    PXOPT_LOOKUP_STR(class_id, config->args, "-class_id", true, false);
+    PXOPT_LOOKUP_STR(data_state, config->args, "-data_state", true, false);
+    if (!setResidImfileDataState(config, det_id, iteration, exp_id, class_id, data_state)) {
+	return false;
+    }
+    return true;
+}
+
+bool pendingcleanup_residimfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id",    "det_id", "==");
+    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
+    PXOPT_COPY_S64(config->args, where, "-exp_id",  "exp_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-class_id",  "class_id", "==");
+
+    psString query = pxDataGet("dettool_pendingcleanup_residimfile.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "detCleanupResidImfile", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+
+bool donecleanup_residimfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id",    "det_id", "==");
+    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
+    PXOPT_COPY_S64(config->args, where, "-exp_id",  "exp_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-class_id",  "class_id", "==");
+
+    psString query = pxDataGet("dettool_donecleanup_residimfile.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "detDoneCleanup_residimfile", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
Index: /trunk/ippTools/src/dettool_stack.c
===================================================================
--- /trunk/ippTools/src/dettool_stack.c	(revision 19092)
+++ /trunk/ippTools/src/dettool_stack.c	(revision 19092)
@@ -0,0 +1,457 @@
+/*
+ * dettool_stack.c
+ *
+ * Copyright (C) 2006  Joshua Hoblitt & EAM; IfA
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "dettool.h"
+
+static psArray *searchRawImfiles(pxConfig *config);
+
+bool tostackedMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psString query = pxDataGet("dettool_tostacked.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "detPendingStackedImfile", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+// this is NOT a command-line mode : it is used by 'addstackedMode'
+static psArray *searchRawImfiles(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id",    "det_id", "==");
+    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
+
+    // select exp_ids from detInputExp matching det_id & iteration
+    // where query should be pre-generated
+    psArray *detInputExp = detInputExpSelectRowObjects(config->dbh, where, 0);
+    psFree (where);
+
+    if (!detInputExp) {
+        psError(PS_ERR_UNKNOWN, false, "no rawExp rows found");
+        return NULL;
+    }
+
+    // generate where query with just the exp_ids
+    psMetadata *where_exp_ids = psMetadataAlloc();
+    for (long i = 0; i < psArrayLength(detInputExp); i++) {
+        detInputExpRow *row = detInputExp->data[i];
+        if (!psMetadataAddS64(where_exp_ids, PS_LIST_TAIL, "exp_id",
+                PS_META_DUPLICATE_OK, "==", row->exp_id)
+        ) {
+            psError(PS_ERR_UNKNOWN, false, "failed to add item exp_id");
+            psFree(detInputExp);
+            psFree(where_exp_ids);
+            return NULL;
+        }
+    }
+    psFree(detInputExp);
+
+    // select rawImfiles with matching exp_ids
+    psArray *rawImfiles =
+        rawImfileSelectRowObjects(config->dbh, where_exp_ids, 0);
+    psFree(where_exp_ids);
+    if (!rawImfiles) {
+        psError(PS_ERR_UNKNOWN, false, "no rawImfile rows found");
+        return NULL;
+    }
+
+    return rawImfiles;
+}
+
+bool addstackedMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    // det_id, iteration, class_id, uri, & recipe are required
+    PXOPT_LOOKUP_S64(det_id, config->args, "-det_id", true, false);
+    PXOPT_LOOKUP_S32(iteration, config->args, "-iteration", true, false);
+    PXOPT_LOOKUP_STR(class_id, config->args, "-class_id", true, false);
+
+    PXOPT_LOOKUP_S16(code, config->args, "-code", false, false);
+
+    // Required if code == 0
+    PXOPT_LOOKUP_STR(uri, config->args, "-uri", (code == 0), false);
+    PXOPT_LOOKUP_STR(recipe, config->args, "-recip", (code == 0), false);
+
+    // optional
+    PXOPT_LOOKUP_F64(bg, config->args, "-bg", false, false);
+    PXOPT_LOOKUP_F64(bg_stdev, config->args, "-bg_stdev", false, false);
+    PXOPT_LOOKUP_F64(bg_mean_stdev, config->args, "-bg_mean_stdev", false, false);
+    PXOPT_LOOKUP_F64(user_1, config->args, "-user_1", false, false);
+    PXOPT_LOOKUP_F64(user_2, config->args, "-user_2", false, false);
+    PXOPT_LOOKUP_F64(user_3, config->args, "-user_3", false, false);
+    PXOPT_LOOKUP_F64(user_4, config->args, "-user_4", false, false);
+    PXOPT_LOOKUP_F64(user_5, config->args, "-user_5", false, false);
+
+    // correlate the class_id against the input exposure(s)
+    // searchRawImfiles defines a where clause to search by det_id and iteration
+    psArray *rawImfiles = searchRawImfiles(config);
+
+    if (!rawImfiles) {
+        psError(PS_ERR_UNKNOWN, false, "failed to get rawImfiles from db");
+        return false;
+    }
+
+    bool valid_class_id = false;
+    if (rawImfiles) {
+        for (long i = 0; i < psArrayLength(rawImfiles); i++) {
+            if (!rawImfiles->data[i]) {
+                fprintf (stderr, "*");
+                continue;
+            }
+            if (strcmp(class_id, ((rawImfileRow *)rawImfiles->data[i])->class_id) == 0) {
+                valid_class_id = true;
+                break;
+            }
+        }
+        psFree(rawImfiles);
+    }
+
+    if (!valid_class_id) {
+        psError(PS_ERR_UNKNOWN, true,
+            "class_id can not be correlated with the input exposures");
+        return false;
+    }
+
+    // create a new detStackedImfile object
+    detStackedImfileRow *stackedImfile = detStackedImfileRowAlloc(
+            det_id,
+            iteration,
+            class_id,
+            uri,
+            recipe,
+            bg,
+            bg_stdev,
+            bg_mean_stdev,
+            user_1,
+            user_2,
+            user_3,
+            user_4,
+            user_5,
+	    "full",
+            code
+        );
+
+    // insert the new row into the detProcessedImfile table
+    if (!detStackedImfileInsertObject(config->dbh, stackedImfile)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(stackedImfile);
+        return false;
+    }
+
+    psFree(stackedImfile);
+
+    return true;
+}
+
+bool stackedMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id",    "det_id", "==");
+    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
+    PXOPT_COPY_STR(config->args, where, "-class_id",  "class_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-recip",     "recipe", "==");
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(faulted, config->args, "-faulted", false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psString query = pxDataGet("dettool_stacked.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        psFree(where);
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, "detStackedImfile");
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (faulted) {
+        // list only faulted rows
+        psStringAppend(&query, " %s", "AND detStackedImfile.fault != 0");
+    } else {
+        // don't list faulted rows
+        psStringAppend(&query, " %s", "AND detStackedImfile.fault = 0");
+    }
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "rawImfile", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+
+bool revertstackedMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id",    "det_id", "==");
+    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
+    PXOPT_COPY_STR(config->args, where, "-class_id",  "class_id", "==");
+    PXOPT_COPY_S16(config->args, where, "-code",      "fault", "==");
+
+    psString query = pxDataGet("dettool_revertstacked.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, "detStackedImfile");
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    if (psDBAffectedRows(config->dbh) < 1) {
+        psError(PS_ERR_UNKNOWN, false, "should have affected atleast 1 row");
+        return false;
+    }
+
+    return true;
+}
+
+bool updatestackedMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_S64(det_id, config->args, "-det_id", true, false);
+    PXOPT_LOOKUP_S32(iteration, config->args, "-iteration", true, false);
+    PXOPT_LOOKUP_STR(class_id, config->args, "-class_id", true, false);
+    PXOPT_LOOKUP_STR(data_state, config->args, "-data_state", true, false);
+
+    if (!setStackedImfileDataState(config, det_id, iteration, class_id, data_state)) {
+	return false;
+    }
+    return true;
+}
+
+bool pendingcleanup_stackedMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id", "detStackedImfile.det_id", "==");
+    PXOPT_COPY_S32(config->args, where, "-iteration", "detStackedImfile.iteration", "==");
+    PXOPT_COPY_STR(config->args, where, "-class_id", "detStackedImfile.class_id", "==");
+
+    psString query = pxDataGet("dettool_pendingcleanup_stacked.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "detCleanupStackedImfile", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+// XXX SQL missing
+bool donecleanup_stackedMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-det_id", "detStackedImfile.det_id", "==");
+    PXOPT_COPY_S32(config->args, where, "-iteration", "detStackedImfile.iteration", "==");
+    PXOPT_COPY_STR(config->args, where, "-class_id", "detStackedImfile.class_id", "==");
+
+    psString query = pxDataGet("dettool_donecleanup_stacked.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("dettool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "detDoneCleanup_stacked", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
Index: /trunk/ippTools/src/difftool.c
===================================================================
--- /trunk/ippTools/src/difftool.c	(revision 19091)
+++ /trunk/ippTools/src/difftool.c	(revision 19092)
@@ -41,4 +41,7 @@
 static bool definepoprunMode(pxConfig *config);
 static bool definebyqueryMode(pxConfig *config);
+static bool pendingcleanuprunMode(pxConfig *config);
+static bool pendingcleanupskyfileMode(pxConfig *config);
+static bool donecleanupMode(pxConfig *config);
 
 static bool setdiffRunState(pxConfig *config, psS64 diff_id, const char *state);
@@ -62,14 +65,17 @@
 
     switch (config->mode) {
-        MODECASE(DIFFTOOL_MODE_DEFINERUN,         definerunMode);
-        MODECASE(DIFFTOOL_MODE_UPDATERUN,         updaterunMode);
-        MODECASE(DIFFTOOL_MODE_ADDINPUTSKYFILE,   addinputskyfileMode);
-        MODECASE(DIFFTOOL_MODE_INPUTSKYFILE,      inputskyfileMode);
-        MODECASE(DIFFTOOL_MODE_TODIFFSKYFILE,     todiffskyfileMode);
-        MODECASE(DIFFTOOL_MODE_ADDDIFFSKYFILE,    adddiffskyfileMode);
-        MODECASE(DIFFTOOL_MODE_DIFFSKYFILE,       diffskyfileMode);
-        MODECASE(DIFFTOOL_MODE_REVERTDIFFSKYFILE, revertdiffskyfileMode);
-        MODECASE(DIFFTOOL_MODE_DEFINEPOPRUN,      definepoprunMode);
-        MODECASE(DIFFTOOL_MODE_DEFINEBYQUERY,             definebyqueryMode);
+        MODECASE(DIFFTOOL_MODE_DEFINERUN,             definerunMode);
+        MODECASE(DIFFTOOL_MODE_UPDATERUN,             updaterunMode);
+        MODECASE(DIFFTOOL_MODE_ADDINPUTSKYFILE,       addinputskyfileMode);
+        MODECASE(DIFFTOOL_MODE_INPUTSKYFILE,          inputskyfileMode);
+        MODECASE(DIFFTOOL_MODE_TODIFFSKYFILE,         todiffskyfileMode);
+        MODECASE(DIFFTOOL_MODE_ADDDIFFSKYFILE,        adddiffskyfileMode);
+        MODECASE(DIFFTOOL_MODE_DIFFSKYFILE,           diffskyfileMode);
+        MODECASE(DIFFTOOL_MODE_REVERTDIFFSKYFILE,     revertdiffskyfileMode);
+        MODECASE(DIFFTOOL_MODE_DEFINEPOPRUN,          definepoprunMode);
+        MODECASE(DIFFTOOL_MODE_DEFINEBYQUERY,         definebyqueryMode);
+        MODECASE(DIFFTOOL_MODE_PENDINGCLEANUPRUN,     pendingcleanuprunMode);
+        MODECASE(DIFFTOOL_MODE_PENDINGCLEANUPSKYFILE, pendingcleanupskyfileMode);
+        MODECASE(DIFFTOOL_MODE_DONECLEANUP,           donecleanupMode);
         default:
             psAbort("invalid option (this should not happen)");
@@ -259,5 +265,5 @@
 
     if (count == 2) {
-        if (!setdiffRunState(config, diff_id, "run")) {
+        if (!setdiffRunState(config, diff_id, "new")) {
             if (!psDBRollback(config->dbh)) {
                 psError(PS_ERR_UNKNOWN, false, "database error");
@@ -496,5 +502,5 @@
     }
 
-    if (!setdiffRunState(config, diff_id, "stop")) {
+    if (!setdiffRunState(config, diff_id, "full")) {
         if (!psDBRollback(config->dbh)) {
             psError(PS_ERR_UNKNOWN, false, "database error");
@@ -696,12 +702,6 @@
 
     // check that state is a valid string value
-    if (!(
-            (strncmp(state, "run", 4) == 0)
-            || (strncmp(state, "stop", 5) == 0)
-            || (strncmp(state, "reg", 4) == 0)
-        )
-    ) {
-        psError(PS_ERR_UNKNOWN, false,
-                "invalid diffRun state: %s", state);
+    if (!pxIsValidState(state)) {
+        psError(PS_ERR_UNKNOWN, false, "invalid diffRun state: %s", state);
         return false;
     }
@@ -1008,2 +1008,186 @@
     return true;
 }
+
+static bool pendingcleanuprunMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_STR(config->args, where, "-label", "label", "==");
+
+    psString query = pxDataGet("difftool_pendingcleanuprun.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("difftool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "diffPendingCleanupRun", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+
+static bool pendingcleanupskyfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_S64(diff_id, config->args, "-diff_id", false, false);
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    if (diff_id) {
+        PXOPT_COPY_S64(config->args, where, "-diff_id", "diff_id", "==");
+    }
+    PXOPT_COPY_STR(config->args, where, "-label", "label", "==");
+
+    psString query = pxDataGet("difftool_pendingcleanupskyfile.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("difftool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "diffPendingCleanupSkyfile", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+    return true;
+}
+
+
+static bool donecleanupMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_STR(config->args, where, "-label", "label", "==");
+
+    psString query = pxDataGet("difftool_donecleanup.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("difftool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "diffDoneCleanup", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+    return true;
+}
Index: /trunk/ippTools/src/difftool.h
===================================================================
--- /trunk/ippTools/src/difftool.h	(revision 19091)
+++ /trunk/ippTools/src/difftool.h	(revision 19092)
@@ -35,4 +35,7 @@
     DIFFTOOL_MODE_DEFINEPOPRUN,
     DIFFTOOL_MODE_DEFINEBYQUERY,
+    DIFFTOOL_MODE_PENDINGCLEANUPRUN,
+    DIFFTOOL_MODE_PENDINGCLEANUPSKYFILE,
+    DIFFTOOL_MODE_DONECLEANUP,
 } difftoolMode;
 
Index: /trunk/ippTools/src/difftoolConfig.c
===================================================================
--- /trunk/ippTools/src/difftoolConfig.c	(revision 19091)
+++ /trunk/ippTools/src/difftoolConfig.c	(revision 19092)
@@ -140,4 +140,23 @@
     psMetadataAddBool(definebyqueryArgs, PS_LIST_TAIL, "-simple", 0, "use the simple output format", false);
 
+    // -pendingcleanuprun
+    psMetadata *pendingcleanuprunArgs = psMetadataAlloc();
+    psMetadataAddStr(pendingcleanuprunArgs, PS_LIST_TAIL, "-label",  0,            "list blocks for specified label", NULL);
+    psMetadataAddBool(pendingcleanuprunArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(pendingcleanuprunArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+
+    // -pendingcleanupskyfile
+    psMetadata *pendingcleanupskyfileArgs = psMetadataAlloc();
+    psMetadataAddStr(pendingcleanupskyfileArgs, PS_LIST_TAIL, "-label",  0,            "list blocks for specified label", NULL);
+    psMetadataAddS64(pendingcleanupskyfileArgs, PS_LIST_TAIL, "-diff_id", 0,          "search by diff ID", 0);
+    psMetadataAddBool(pendingcleanupskyfileArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(pendingcleanupskyfileArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+
+    // -donecleanup
+    psMetadata *donecleanupArgs = psMetadataAlloc();
+    psMetadataAddStr(donecleanupArgs, PS_LIST_TAIL, "-label",  0,            "list blocks for specified label", NULL);
+    psMetadataAddBool(donecleanupArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(donecleanupArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+
     psFree(now);
 
@@ -155,4 +174,7 @@
     PXOPT_ADD_MODE("-definepoprun",     "", DIFFTOOL_MODE_DEFINEPOPRUN,      definepoprunArgs);
     PXOPT_ADD_MODE("-definebyquery",    "", DIFFTOOL_MODE_DEFINEBYQUERY,     definebyqueryArgs);
+    PXOPT_ADD_MODE("-pendingcleanuprun",     "show runs that need to be cleaned up", DIFFTOOL_MODE_PENDINGCLEANUPRUN,    pendingcleanuprunArgs);
+    PXOPT_ADD_MODE("-pendingcleanupskyfile", "show runs that need to be cleaned up", DIFFTOOL_MODE_PENDINGCLEANUPSKYFILE, pendingcleanupskyfileArgs);
+    PXOPT_ADD_MODE("-donecleanup",           "show runs that have been cleaned",     DIFFTOOL_MODE_DONECLEANUP,          donecleanupArgs);
 
     if (!pxGetOptions(stderr, argc, argv, config, modes, argSets)) {
Index: /trunk/ippTools/src/faketool.c
===================================================================
--- /trunk/ippTools/src/faketool.c	(revision 19091)
+++ /trunk/ippTools/src/faketool.c	(revision 19092)
@@ -45,4 +45,7 @@
 static bool unmaskedMode(pxConfig *config);
 static bool unblockMode(pxConfig *config);
+static bool pendingcleanuprunMode(pxConfig *config);
+static bool pendingcleanupimfileMode(pxConfig *config);
+static bool donecleanupMode(pxConfig *config);
 
 static bool fakeProcessedCompleteExp(pxConfig *config);
@@ -65,5 +68,5 @@
 
     switch (config->mode) {
-        MODECASE(FAKETOOL_MODE_DEFINEBYQUERY,                   definebyqueryMode);
+        MODECASE(FAKETOOL_MODE_DEFINEBYQUERY,           definebyqueryMode);
         MODECASE(FAKETOOL_MODE_UPDATERUN,               updaterunMode);
         MODECASE(FAKETOOL_MODE_PENDINGEXP,              pendingexpMode);
@@ -72,9 +75,12 @@
         MODECASE(FAKETOOL_MODE_PROCESSEDIMFILE,         processedimfileMode);
         MODECASE(FAKETOOL_MODE_REVERTPROCESSEDIMFILE,   revertprocessedimfileMode);
-        MODECASE(FAKETOOL_MODE_UPDATEPROCESSEDIMFILE,updateprocessedimfileMode);
+        MODECASE(FAKETOOL_MODE_UPDATEPROCESSEDIMFILE,   updateprocessedimfileMode);
         MODECASE(FAKETOOL_MODE_BLOCK,                   blockMode);
         MODECASE(FAKETOOL_MODE_MASKED,                  maskedMode);
         MODECASE(FAKETOOL_MODE_UNMASKED,                unmaskedMode);
         MODECASE(FAKETOOL_MODE_UNBLOCK,                 unblockMode);
+        MODECASE(FAKETOOL_MODE_PENDINGCLEANUPRUN,       pendingcleanuprunMode);
+        MODECASE(FAKETOOL_MODE_PENDINGCLEANUPIMFILE,    pendingcleanupimfileMode);
+        MODECASE(FAKETOOL_MODE_DONECLEANUP,             donecleanupMode);
         default:
             psAbort("invalid option (this should not happen)");
@@ -854,4 +860,189 @@
 }
 
+static bool pendingcleanuprunMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_STR(config->args, where, "-label", "label", "==");
+
+    psString query = pxDataGet("faketool_pendingcleanuprun.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("faketool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "fakePendingCleanupRun", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+
+static bool pendingcleanupimfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_S64(fake_id, config->args, "-fake_id", false, false);
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    if (fake_id) {
+        PXOPT_COPY_S64(config->args, where, "-fake_id", "fake_id", "==");
+    }
+    PXOPT_COPY_STR(config->args, where, "-label", "label", "==");
+
+    psString query = pxDataGet("faketool_pendingcleanupimfile.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("faketool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "fakePendingCleanupImfile", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+
+static bool donecleanupMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_STR(config->args, where, "-label", "label", "==");
+
+    psString query = pxDataGet("faketool_donecleanup.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("faketool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "fakeDoneCleanup", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
 
 static bool fakeProcessedCompleteExp(pxConfig *config)
@@ -889,6 +1080,6 @@
 
         fakeRunRow *fakeRun = fakeRunObjectFromMetadata(row);
-        // set fakeRun.state to 'stop'
-        if (!pxfakeRunSetState(config, fakeRun->fake_id, "stop")) {
+        // set fakeRun.state to 'full'
+        if (!pxfakeRunSetState(config, fakeRun->fake_id, "full")) {
             psError(PS_ERR_UNKNOWN, false, "failed to change fakeRun.state for fake_id: %" PRId64, fakeRun->fake_id);
             psFree(fakeRun);
Index: /trunk/ippTools/src/faketool.h
===================================================================
--- /trunk/ippTools/src/faketool.h	(revision 19091)
+++ /trunk/ippTools/src/faketool.h	(revision 19092)
@@ -38,5 +38,6 @@
     FAKETOOL_MODE_UNBLOCK,
     FAKETOOL_MODE_RETRYPROCESSEDIMFILE,
-    FAKETOOL_MODE_PENDINGCLEANUP,
+    FAKETOOL_MODE_PENDINGCLEANUPRUN,
+    FAKETOOL_MODE_PENDINGCLEANUPIMFILE,
     FAKETOOL_MODE_DONECLEANUP,
 } FAKETOOLMode;
Index: /trunk/ippTools/src/faketoolConfig.c
===================================================================
--- /trunk/ippTools/src/faketoolConfig.c	(revision 19091)
+++ /trunk/ippTools/src/faketoolConfig.c	(revision 19092)
@@ -47,403 +47,248 @@
     psMetadata *queueArgs = psMetadataAlloc();
     // XXX need to allow multiple exp_ids
-    psMetadataAddS64(queueArgs, PS_LIST_TAIL, "-exp_id",  0,
-            "search by exp_id", 0);
-    psMetadataAddStr(queueArgs, PS_LIST_TAIL, "-exp_name",  0,
-            "search by exp_name", NULL);
-    psMetadataAddStr(queueArgs, PS_LIST_TAIL, "-inst",  0,
-            "search for camera", NULL);
-    psMetadataAddStr(queueArgs, PS_LIST_TAIL, "-telescope",  0,
-            "search for telescope", NULL);
-    psMetadataAddTime(queueArgs, PS_LIST_TAIL, "-dateobs_begin", 0,
-            "search for exposures by time (>=)", NULL);
-    psMetadataAddTime(queueArgs, PS_LIST_TAIL, "-dateobs_end", 0,
-            "search for exposures by time (<)", NULL);
-    psMetadataAddStr(queueArgs, PS_LIST_TAIL, "-exp_tag",  0,
-            "search by exp_tag", NULL);
-    psMetadataAddStr(queueArgs, PS_LIST_TAIL, "-exp_type",  0,
-            "search by exp_type", "object");
-    psMetadataAddStr(queueArgs, PS_LIST_TAIL, "-filelevel",  0,
-            "search by filelevel", NULL);
-    psMetadataAddStr(queueArgs, PS_LIST_TAIL, "-reduction",  0,
-            "search by reduction class", NULL);
-    psMetadataAddStr(queueArgs, PS_LIST_TAIL, "-filter",  0,
-            "search for filter", NULL);
-    psMetadataAddF32(queueArgs, PS_LIST_TAIL, "-airmass_min",  0,
-            "define min airmass", NAN);
-    psMetadataAddF32(queueArgs, PS_LIST_TAIL, "-airmass_max",  0,
-            "define max airmass", NAN);
-    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-ra_min",  0,
-            "define min", NAN);
-    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-ra_max",  0,
-            "define max", NAN);
-    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-decl_min",  0,
-            "define min", NAN);
-    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-decl_max",  0,
-            "define max", NAN);
-    psMetadataAddF32(queueArgs, PS_LIST_TAIL, "-exp_time_min",  0,
-            "define min", NAN);
-    psMetadataAddF32(queueArgs, PS_LIST_TAIL, "-exp_time_max",  0,
-            "define max", NAN);
-    psMetadataAddF32(queueArgs, PS_LIST_TAIL, "-sat_pixel_frac_min",  0,
-            "define max fraction of saturated pixels", NAN);
-    psMetadataAddF32(queueArgs, PS_LIST_TAIL, "-sat_pixel_frac_max",  0,
-            "define min fraction of saturated pixels", NAN);
-    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-bg_min",  0,
-            "define max", NAN);
-    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-bg_max",  0,
-            "define max", NAN);
-    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-bg_stdev_min",  0,
-            "define max", NAN);
-    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-bg_stdev_max",  0,
-            "define max", NAN);
-    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-bg_mean_stdev_min",  0,
-            "define max", NAN);
-    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-bg_mean_stdev_max",  0,
-            "define max", NAN);
-    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-alt_min",  0,
-            "define min", NAN);
-    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-alt_max",  0,
-            "define max", NAN);
-    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-az_min",  0,
-            "define min", NAN);
-    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-az_max",  0,
-            "define max", NAN);
-    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-ccd_temp_min",  0,
-            "define min ccd tempature", NAN);
-    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-ccd_temp_max",  0,
-            "define max ccd tempature", NAN);
-    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-posang_min",  0,
-            "define min rotator position angle", NAN);
-    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-posang_max",  0,
-            "define max rotator position angle", NAN);
-    psMetadataAddStr(queueArgs, PS_LIST_TAIL, "-object",  0,
-            "search by exposure object", NULL);
-    psMetadataAddF32(queueArgs, PS_LIST_TAIL, "-solang_min",  0,
-            "define min solar angle", NAN);
-    psMetadataAddF32(queueArgs, PS_LIST_TAIL, "-solang_max",  0,
-            "define max solar angle", NAN);
-    psMetadataAddStr(queueArgs, PS_LIST_TAIL, "-set_workdir",  0,
-            "define workdir", NULL);
-    psMetadataAddStr(queueArgs, PS_LIST_TAIL, "-set_label",  0,
-            "define label", NULL);
-    psMetadataAddStr(queueArgs, PS_LIST_TAIL, "-set_reduction",  0,
-            "define reduction class", NULL);
-    psMetadataAddStr(queueArgs, PS_LIST_TAIL, "-set_expgroup",  0,
-            "define exposure group", NULL);
-    psMetadataAddStr(queueArgs, PS_LIST_TAIL, "-set_dvodb",  0,
-            "define DVO db", NULL);
-    psMetadataAddStr(queueArgs, PS_LIST_TAIL, "-set_tess_id",  0,
-            "define tessellation identifier", NULL);
-    psMetadataAddStr(queueArgs, PS_LIST_TAIL, "-set_end_stage",  0,
-            "define end stage", NULL);
-    psMetadataAddBool(queueArgs, PS_LIST_TAIL, "-pretend",  0,
-            "do not actually modify the database", false);
-    psMetadataAddBool(queueArgs, PS_LIST_TAIL, "-all",  0,
-            "allow everything to be queued without search terms", false);
+    psMetadataAddS64(queueArgs, PS_LIST_TAIL, "-exp_id",  0,            "search by exp_id", 0);
+    psMetadataAddStr(queueArgs, PS_LIST_TAIL, "-exp_name",  0,            "search by exp_name", NULL);
+    psMetadataAddStr(queueArgs, PS_LIST_TAIL, "-inst",  0,            "search for camera", NULL);
+    psMetadataAddStr(queueArgs, PS_LIST_TAIL, "-telescope",  0,            "search for telescope", NULL);
+    psMetadataAddTime(queueArgs, PS_LIST_TAIL, "-dateobs_begin", 0,            "search for exposures by time (>=)", NULL);
+    psMetadataAddTime(queueArgs, PS_LIST_TAIL, "-dateobs_end", 0,            "search for exposures by time (<)", NULL);
+    psMetadataAddStr(queueArgs, PS_LIST_TAIL, "-exp_tag",  0,            "search by exp_tag", NULL);
+    psMetadataAddStr(queueArgs, PS_LIST_TAIL, "-exp_type",  0,            "search by exp_type", "object");
+    psMetadataAddStr(queueArgs, PS_LIST_TAIL, "-filelevel",  0,            "search by filelevel", NULL);
+    psMetadataAddStr(queueArgs, PS_LIST_TAIL, "-reduction",  0,            "search by reduction class", NULL);
+    psMetadataAddStr(queueArgs, PS_LIST_TAIL, "-filter",  0,            "search for filter", NULL);
+    psMetadataAddF32(queueArgs, PS_LIST_TAIL, "-airmass_min",  0,            "define min airmass", NAN);
+    psMetadataAddF32(queueArgs, PS_LIST_TAIL, "-airmass_max",  0,            "define max airmass", NAN);
+    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-ra_min",  0,            "define min", NAN);
+    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-ra_max",  0,            "define max", NAN);
+    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-decl_min",  0,            "define min", NAN);
+    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-decl_max",  0,            "define max", NAN);
+    psMetadataAddF32(queueArgs, PS_LIST_TAIL, "-exp_time_min",  0,            "define min", NAN);
+    psMetadataAddF32(queueArgs, PS_LIST_TAIL, "-exp_time_max",  0,            "define max", NAN);
+    psMetadataAddF32(queueArgs, PS_LIST_TAIL, "-sat_pixel_frac_min",  0,            "define max fraction of saturated pixels", NAN);
+    psMetadataAddF32(queueArgs, PS_LIST_TAIL, "-sat_pixel_frac_max",  0,            "define min fraction of saturated pixels", NAN);
+    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-bg_min",  0,            "define max", NAN);
+    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-bg_max",  0,            "define max", NAN);
+    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-bg_stdev_min",  0,            "define max", NAN);
+    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-bg_stdev_max",  0,            "define max", NAN);
+    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-bg_mean_stdev_min",  0,            "define max", NAN);
+    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-bg_mean_stdev_max",  0,            "define max", NAN);
+    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-alt_min",  0,            "define min", NAN);
+    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-alt_max",  0,            "define max", NAN);
+    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-az_min",  0,            "define min", NAN);
+    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-az_max",  0,            "define max", NAN);
+    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-ccd_temp_min",  0,            "define min ccd tempature", NAN);
+    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-ccd_temp_max",  0,            "define max ccd tempature", NAN);
+    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-posang_min",  0,            "define min rotator position angle", NAN);
+    psMetadataAddF64(queueArgs, PS_LIST_TAIL, "-posang_max",  0,            "define max rotator position angle", NAN);
+    psMetadataAddStr(queueArgs, PS_LIST_TAIL, "-object",  0,            "search by exposure object", NULL);
+    psMetadataAddF32(queueArgs, PS_LIST_TAIL, "-solang_min",  0,            "define min solar angle", NAN);
+    psMetadataAddF32(queueArgs, PS_LIST_TAIL, "-solang_max",  0,            "define max solar angle", NAN);
+    psMetadataAddStr(queueArgs, PS_LIST_TAIL, "-set_workdir",  0,            "define workdir", NULL);
+    psMetadataAddStr(queueArgs, PS_LIST_TAIL, "-set_label",  0,            "define label", NULL);
+    psMetadataAddStr(queueArgs, PS_LIST_TAIL, "-set_reduction",  0,            "define reduction class", NULL);
+    psMetadataAddStr(queueArgs, PS_LIST_TAIL, "-set_expgroup",  0,            "define exposure group", NULL);
+    psMetadataAddStr(queueArgs, PS_LIST_TAIL, "-set_dvodb",  0,            "define DVO db", NULL);
+    psMetadataAddStr(queueArgs, PS_LIST_TAIL, "-set_tess_id",  0,            "define tessellation identifier", NULL);
+    psMetadataAddStr(queueArgs, PS_LIST_TAIL, "-set_end_stage",  0,            "define end stage", NULL);
+    psMetadataAddBool(queueArgs, PS_LIST_TAIL, "-pretend",  0,            "do not actually modify the database", false);
+    psMetadataAddBool(queueArgs, PS_LIST_TAIL, "-all",  0,            "allow everything to be queued without search terms", false);
 
 
     // -updaterun
     psMetadata *updaterunArgs = psMetadataAlloc();
-    psMetadataAddS64(updaterunArgs, PS_LIST_TAIL, "-fake_id", 0,
-            "search by fake ID", 0);
-    psMetadataAddS64(updaterunArgs, PS_LIST_TAIL, "-exp_id",  0,
-            "search by exp_id", 0);
-    psMetadataAddStr(updaterunArgs, PS_LIST_TAIL, "-exp_name",  0,
-            "search by exp_name", NULL);
-    psMetadataAddStr(updaterunArgs, PS_LIST_TAIL, "-inst",  0,
-            "search for camera", NULL);
-    psMetadataAddStr(updaterunArgs, PS_LIST_TAIL, "-telescope",  0,
-            "search for telescope", NULL);
-    psMetadataAddTime(updaterunArgs, PS_LIST_TAIL, "-dateobs_begin", 0,
-            "search for exposures by time (>=)", NULL);
-    psMetadataAddTime(updaterunArgs, PS_LIST_TAIL, "-dateobs_end", 0,
-            "search for exposures by time (<)", NULL);
-    psMetadataAddStr(updaterunArgs, PS_LIST_TAIL, "-exp_tag",  0,
-            "search by exp_tag", NULL);
-    psMetadataAddStr(updaterunArgs, PS_LIST_TAIL, "-exp_type",  0,
-            "search by exp_type", "object");
-    psMetadataAddStr(updaterunArgs, PS_LIST_TAIL, "-filelevel",  0,
-            "search by filelevel", NULL);
-    psMetadataAddStr(updaterunArgs, PS_LIST_TAIL, "-reduction",  0,
-            "search by reduction class", NULL);
-    psMetadataAddStr(updaterunArgs, PS_LIST_TAIL, "-filter",  0,
-            "search for filter", NULL);
-    psMetadataAddF32(updaterunArgs, PS_LIST_TAIL, "-airmass_min",  0,
-            "define min airmass", NAN);
-    psMetadataAddF32(updaterunArgs, PS_LIST_TAIL, "-airmass_max",  0,
-            "define max airmass", NAN);
-    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-ra_min",  0,
-            "define min", NAN);
-    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-ra_max",  0,
-            "define max", NAN);
-    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-decl_min",  0,
-            "define min", NAN);
-    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-decl_max",  0,
-            "define max", NAN);
-    psMetadataAddF32(updaterunArgs, PS_LIST_TAIL, "-exp_time_min",  0,
-            "define min", NAN);
-    psMetadataAddF32(updaterunArgs, PS_LIST_TAIL, "-exp_time_max",  0,
-            "define max", NAN);
-    psMetadataAddF32(updaterunArgs, PS_LIST_TAIL, "-sat_pixel_frac_min",  0,
-            "define max fraction of saturated pixels", NAN);
-    psMetadataAddF32(updaterunArgs, PS_LIST_TAIL, "-sat_pixel_frac_max",  0,
-            "define min fraction of saturated pixels", NAN);
-    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-bg_min",  0,
-            "define max", NAN);
-    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-bg_max",  0,
-            "define max", NAN);
-    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-bg_stdev_min",  0,
-            "define max", NAN);
-    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-bg_stdev_max",  0,
-            "define max", NAN);
-    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-bg_mean_stdev_min",  0,
-            "define max", NAN);
-    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-bg_mean_stdev_max",  0,
-            "define max", NAN);
-    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-alt_min",  0,
-            "define min", NAN);
-    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-alt_max",  0,
-            "define max", NAN);
-    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-az_min",  0,
-            "define min", NAN);
-    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-az_max",  0,
-            "define max", NAN);
-    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-ccd_temp_min",  0,
-            "define min ccd tempature", NAN);
-    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-ccd_temp_max",  0,
-            "define max ccd tempature", NAN);
-    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-posang_min",  0,
-            "define min rotator position angle", NAN);
-    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-posang_max",  0,
-            "define max rotator position angle", NAN);
-    psMetadataAddStr(updaterunArgs, PS_LIST_TAIL, "-object",  0,
-            "search by exposure object", NULL);
-    psMetadataAddF32(updaterunArgs, PS_LIST_TAIL, "-solang_min",  0,
-            "define min solar angle", NAN);
-    psMetadataAddF32(updaterunArgs, PS_LIST_TAIL, "-solang_max",  0,
-            "define max solar angle", NAN);
-
-    psMetadataAddStr(updaterunArgs, PS_LIST_TAIL, "-state", 0,
-            "set state", NULL);
-    psMetadataAddStr(updaterunArgs, PS_LIST_TAIL, "-label", 0,
-            "set label", NULL);
-    psMetadataAddBool(updaterunArgs, PS_LIST_TAIL, "-all",  0,
-            "allow everything to be queued without search terms", false);
+    psMetadataAddS64(updaterunArgs, PS_LIST_TAIL, "-fake_id", 0,            "search by fake ID", 0);
+    psMetadataAddS64(updaterunArgs, PS_LIST_TAIL, "-exp_id",  0,            "search by exp_id", 0);
+    psMetadataAddStr(updaterunArgs, PS_LIST_TAIL, "-exp_name",  0,            "search by exp_name", NULL);
+    psMetadataAddStr(updaterunArgs, PS_LIST_TAIL, "-inst",  0,            "search for camera", NULL);
+    psMetadataAddStr(updaterunArgs, PS_LIST_TAIL, "-telescope",  0,            "search for telescope", NULL);
+    psMetadataAddTime(updaterunArgs, PS_LIST_TAIL, "-dateobs_begin", 0,            "search for exposures by time (>=)", NULL);
+    psMetadataAddTime(updaterunArgs, PS_LIST_TAIL, "-dateobs_end", 0,            "search for exposures by time (<)", NULL);
+    psMetadataAddStr(updaterunArgs, PS_LIST_TAIL, "-exp_tag",  0,            "search by exp_tag", NULL);
+    psMetadataAddStr(updaterunArgs, PS_LIST_TAIL, "-exp_type",  0,            "search by exp_type", "object");
+    psMetadataAddStr(updaterunArgs, PS_LIST_TAIL, "-filelevel",  0,            "search by filelevel", NULL);
+    psMetadataAddStr(updaterunArgs, PS_LIST_TAIL, "-reduction",  0,            "search by reduction class", NULL);
+    psMetadataAddStr(updaterunArgs, PS_LIST_TAIL, "-filter",  0,            "search for filter", NULL);
+    psMetadataAddF32(updaterunArgs, PS_LIST_TAIL, "-airmass_min",  0,            "define min airmass", NAN);
+    psMetadataAddF32(updaterunArgs, PS_LIST_TAIL, "-airmass_max",  0,            "define max airmass", NAN);
+    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-ra_min",  0,            "define min", NAN);
+    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-ra_max",  0,            "define max", NAN);
+    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-decl_min",  0,            "define min", NAN);
+    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-decl_max",  0,            "define max", NAN);
+    psMetadataAddF32(updaterunArgs, PS_LIST_TAIL, "-exp_time_min",  0,            "define min", NAN);
+    psMetadataAddF32(updaterunArgs, PS_LIST_TAIL, "-exp_time_max",  0,            "define max", NAN);
+    psMetadataAddF32(updaterunArgs, PS_LIST_TAIL, "-sat_pixel_frac_min",  0,            "define max fraction of saturated pixels", NAN);
+    psMetadataAddF32(updaterunArgs, PS_LIST_TAIL, "-sat_pixel_frac_max",  0,            "define min fraction of saturated pixels", NAN);
+    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-bg_min",  0,            "define max", NAN);
+    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-bg_max",  0,            "define max", NAN);
+    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-bg_stdev_min",  0,            "define max", NAN);
+    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-bg_stdev_max",  0,            "define max", NAN);
+    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-bg_mean_stdev_min",  0,            "define max", NAN);
+    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-bg_mean_stdev_max",  0,            "define max", NAN);
+    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-alt_min",  0,            "define min", NAN);
+    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-alt_max",  0,            "define max", NAN);
+    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-az_min",  0,            "define min", NAN);
+    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-az_max",  0,            "define max", NAN);
+    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-ccd_temp_min",  0,            "define min ccd tempature", NAN);
+    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-ccd_temp_max",  0,            "define max ccd tempature", NAN);
+    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-posang_min",  0,            "define min rotator position angle", NAN);
+    psMetadataAddF64(updaterunArgs, PS_LIST_TAIL, "-posang_max",  0,            "define max rotator position angle", NAN);
+    psMetadataAddStr(updaterunArgs, PS_LIST_TAIL, "-object",  0,            "search by exposure object", NULL);
+    psMetadataAddF32(updaterunArgs, PS_LIST_TAIL, "-solang_min",  0,            "define min solar angle", NAN);
+    psMetadataAddF32(updaterunArgs, PS_LIST_TAIL, "-solang_max",  0,            "define max solar angle", NAN);
+
+    psMetadataAddStr(updaterunArgs, PS_LIST_TAIL, "-state", 0,            "set state", NULL);
+    psMetadataAddStr(updaterunArgs, PS_LIST_TAIL, "-label", 0,            "set label", NULL);
+    psMetadataAddBool(updaterunArgs, PS_LIST_TAIL, "-all",  0,            "allow everything to be queued without search terms", false);
 
     // -pendingexp
     psMetadata *pendingexpArgs = psMetadataAlloc();
-    psMetadataAddS64(pendingexpArgs, PS_LIST_TAIL, "-fake_id", 0,
-            "search by fake ID", 0);
-    psMetadataAddS64(pendingexpArgs, PS_LIST_TAIL, "-cam_id", 0,
-            "search by camtool ID", 0);
-    psMetadataAddS64(pendingexpArgs, PS_LIST_TAIL, "-chip_id", 0,
-            "search by chiptool ID", 0);
-    psMetadataAddU64(pendingexpArgs, PS_LIST_TAIL, "-limit",  0,
-            "limit result set to N items", 0);
-    psMetadataAddBool(pendingexpArgs, PS_LIST_TAIL, "-simple", 0,
-            "use the simple output format", false);
+    psMetadataAddS64(pendingexpArgs, PS_LIST_TAIL, "-fake_id", 0,            "search by fake ID", 0);
+    psMetadataAddS64(pendingexpArgs, PS_LIST_TAIL, "-cam_id", 0,            "search by camtool ID", 0);
+    psMetadataAddS64(pendingexpArgs, PS_LIST_TAIL, "-chip_id", 0,            "search by chiptool ID", 0);
+    psMetadataAddU64(pendingexpArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+    psMetadataAddBool(pendingexpArgs, PS_LIST_TAIL, "-simple", 0,            "use the simple output format", false);
 
     // -pendingimfile
     psMetadata *pendingimfileArgs = psMetadataAlloc();
-    psMetadataAddS64(pendingimfileArgs, PS_LIST_TAIL, "-fake_id",  0,
-            "search by fake ID", 0);
-    psMetadataAddS64(pendingimfileArgs, PS_LIST_TAIL, "-exp_id",  0,
-            "search by exposure ID", 0);
-    psMetadataAddStr(pendingimfileArgs, PS_LIST_TAIL, "-class_id",  0,
-            "search by class ID", NULL);
-    psMetadataAddStr(pendingimfileArgs, PS_LIST_TAIL, "-inst",  0,
-            "search by camera of interest", NULL);
-    psMetadataAddStr(pendingimfileArgs, PS_LIST_TAIL, "-filter",  0,
-            "search by filter of interest", NULL);
-    psMetadataAddU64(pendingimfileArgs, PS_LIST_TAIL, "-limit",  0,
-            "limit result set to N items", 0);
-    psMetadataAddBool(pendingimfileArgs, PS_LIST_TAIL, "-simple",  0,
-            "use the simple output format", false);
+    psMetadataAddS64(pendingimfileArgs, PS_LIST_TAIL, "-fake_id",  0,            "search by fake ID", 0);
+    psMetadataAddS64(pendingimfileArgs, PS_LIST_TAIL, "-exp_id",  0,            "search by exposure ID", 0);
+    psMetadataAddStr(pendingimfileArgs, PS_LIST_TAIL, "-class_id",  0,            "search by class ID", NULL);
+    psMetadataAddStr(pendingimfileArgs, PS_LIST_TAIL, "-inst",  0,            "search by camera of interest", NULL);
+    psMetadataAddStr(pendingimfileArgs, PS_LIST_TAIL, "-filter",  0,            "search by filter of interest", NULL);
+    psMetadataAddU64(pendingimfileArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+    psMetadataAddBool(pendingimfileArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
 
     // -addprocessedimfile
     psMetadata *addprocessedimfileArgs = psMetadataAlloc();
-    psMetadataAddS64(addprocessedimfileArgs, PS_LIST_TAIL, "-fake_id",  0,
-            "define fake ID (required)", 0);
-    psMetadataAddS64(addprocessedimfileArgs, PS_LIST_TAIL, "-exp_id",  0,
-            "define exposure ID (required)", 0);
-    psMetadataAddStr(addprocessedimfileArgs, PS_LIST_TAIL, "-class_id",  0,
-            "define class ID (required)", NULL);
-    psMetadataAddStr(addprocessedimfileArgs, PS_LIST_TAIL, "-uri",  0,
-            "define URL", NULL);
-    psMetadataAddF32(addprocessedimfileArgs, PS_LIST_TAIL, "-dtime_fake",  0,
-            "define elapsed time for detrend (seconds)", NAN);
-    psMetadataAddStr(addprocessedimfileArgs, PS_LIST_TAIL, "-hostname",  0,
-            "define hostname", NULL);
-    psMetadataAddStr(addprocessedimfileArgs, PS_LIST_TAIL, "-path_base",  0,
-            "define base output location", NULL);
-    psMetadataAddS16(addprocessedimfileArgs, PS_LIST_TAIL, "-code",  0,
-            "set fault code", 0);
+    psMetadataAddS64(addprocessedimfileArgs, PS_LIST_TAIL, "-fake_id",  0,            "define fake ID (required)", 0);
+    psMetadataAddS64(addprocessedimfileArgs, PS_LIST_TAIL, "-exp_id",  0,            "define exposure ID (required)", 0);
+    psMetadataAddStr(addprocessedimfileArgs, PS_LIST_TAIL, "-class_id",  0,            "define class ID (required)", NULL);
+    psMetadataAddStr(addprocessedimfileArgs, PS_LIST_TAIL, "-uri",  0,            "define URL", NULL);
+    psMetadataAddF32(addprocessedimfileArgs, PS_LIST_TAIL, "-dtime_fake",  0,            "define elapsed time for detrend (seconds)", NAN);
+    psMetadataAddStr(addprocessedimfileArgs, PS_LIST_TAIL, "-hostname",  0,            "define hostname", NULL);
+    psMetadataAddStr(addprocessedimfileArgs, PS_LIST_TAIL, "-path_base",  0,            "define base output location", NULL);
+    psMetadataAddS16(addprocessedimfileArgs, PS_LIST_TAIL, "-code",  0,            "set fault code", 0);
 
     // -processedimfile
     psMetadata *processedimfileArgs = psMetadataAlloc();
-    psMetadataAddS64(processedimfileArgs, PS_LIST_TAIL, "-fake_id",  0,
-            "define fake ID", 0);
-    psMetadataAddS64(processedimfileArgs, PS_LIST_TAIL, "-exp_id",  0,
-            "define exposure ID", 0);
-    psMetadataAddStr(processedimfileArgs, PS_LIST_TAIL, "-class_id",  0,
-            "define class ID", NULL);
-    psMetadataAddStr(processedimfileArgs, PS_LIST_TAIL, "-inst",  0,
-            "define camera of interest", NULL);
-    psMetadataAddStr(processedimfileArgs, PS_LIST_TAIL, "-filter",  0,
-            "define filter of interest", NULL);
-    psMetadataAddU64(processedimfileArgs, PS_LIST_TAIL, "-limit",  0,
-            "limit result set to N items", 0);
-    psMetadataAddBool(processedimfileArgs, PS_LIST_TAIL, "-faulted",  0,
-            "only return imfiles with a fault status set", false);
-    psMetadataAddBool(processedimfileArgs, PS_LIST_TAIL, "-simple",  0,
-            "use the simple output format", false);
+    psMetadataAddS64(processedimfileArgs, PS_LIST_TAIL, "-fake_id",  0,            "define fake ID", 0);
+    psMetadataAddS64(processedimfileArgs, PS_LIST_TAIL, "-exp_id",  0,            "define exposure ID", 0);
+    psMetadataAddStr(processedimfileArgs, PS_LIST_TAIL, "-class_id",  0,            "define class ID", NULL);
+    psMetadataAddStr(processedimfileArgs, PS_LIST_TAIL, "-inst",  0,            "define camera of interest", NULL);
+    psMetadataAddStr(processedimfileArgs, PS_LIST_TAIL, "-filter",  0,            "define filter of interest", NULL);
+    psMetadataAddU64(processedimfileArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+    psMetadataAddBool(processedimfileArgs, PS_LIST_TAIL, "-faulted",  0,            "only return imfiles with a fault status set", false);
+    psMetadataAddBool(processedimfileArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
 
     // -updateprocessedimfile
     psMetadata *updateprocessedimfileArgs = psMetadataAlloc();
-    psMetadataAddS64(updateprocessedimfileArgs, PS_LIST_TAIL, "-fake_id",  0,
-            "search by fake ID", 0);
-    psMetadataAddS64(updateprocessedimfileArgs, PS_LIST_TAIL, "-exp_id",  0,
-            "search by exposure ID", 0);
-    psMetadataAddStr(updateprocessedimfileArgs, PS_LIST_TAIL, "-class_id",  0,
-            "search by class ID", NULL);
-    psMetadataAddS16(updateprocessedimfileArgs, PS_LIST_TAIL, "-code",  0,
-            "set fault code (required)", 0);
+    psMetadataAddS64(updateprocessedimfileArgs, PS_LIST_TAIL, "-fake_id",  0,            "search by fake ID", 0);
+    psMetadataAddS64(updateprocessedimfileArgs, PS_LIST_TAIL, "-exp_id",  0,            "search by exposure ID", 0);
+    psMetadataAddStr(updateprocessedimfileArgs, PS_LIST_TAIL, "-class_id",  0,            "search by class ID", NULL);
+    psMetadataAddS16(updateprocessedimfileArgs, PS_LIST_TAIL, "-code",  0,            "set fault code (required)", 0);
 
     // -revertprocessedimfile
     psMetadata *revertprocessedimfileArgs = psMetadataAlloc();
-    psMetadataAddS64(revertprocessedimfileArgs, PS_LIST_TAIL, "-fake_id", 0,
-            "search by fake ID", 0);
-    psMetadataAddS64(revertprocessedimfileArgs, PS_LIST_TAIL, "-exp_id",  0,
-            "search by exp_id", 0);
-    psMetadataAddStr(revertprocessedimfileArgs, PS_LIST_TAIL, "-exp_name",  0,
-            "search by exp_name", NULL);
-    psMetadataAddStr(revertprocessedimfileArgs, PS_LIST_TAIL, "-inst",  0,
-            "search for camera", NULL);
-    psMetadataAddStr(revertprocessedimfileArgs, PS_LIST_TAIL, "-telescope",  0,
-            "search for telescope", NULL);
-    psMetadataAddTime(revertprocessedimfileArgs, PS_LIST_TAIL, "-dateobs_begin", 0,
-            "search for exposures by time (>=)", NULL);
-    psMetadataAddTime(revertprocessedimfileArgs, PS_LIST_TAIL, "-dateobs_end", 0,
-            "search for exposures by time (<)", NULL);
-    psMetadataAddStr(revertprocessedimfileArgs, PS_LIST_TAIL, "-exp_tag",  0,
-            "search by exp_tag", NULL);
-    psMetadataAddStr(revertprocessedimfileArgs, PS_LIST_TAIL, "-exp_type",  0,
-            "search by exp_type", "object");
-    psMetadataAddStr(revertprocessedimfileArgs, PS_LIST_TAIL, "-filelevel",  0,
-            "search by filelevel", NULL);
-    psMetadataAddStr(revertprocessedimfileArgs, PS_LIST_TAIL, "-reduction",  0,
-            "search by reduction class", NULL);
-    psMetadataAddStr(revertprocessedimfileArgs, PS_LIST_TAIL, "-filter",  0,
-            "search for filter", NULL);
-    psMetadataAddF32(revertprocessedimfileArgs, PS_LIST_TAIL, "-airmass_min",  0,
-            "define min airmass", NAN);
-    psMetadataAddF32(revertprocessedimfileArgs, PS_LIST_TAIL, "-airmass_max",  0,
-            "define max airmass", NAN);
-    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-ra_min",  0,
-            "define min", NAN);
-    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-ra_max",  0,
-            "define max", NAN);
-    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-decl_min",  0,
-            "define min", NAN);
-    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-decl_max",  0,
-            "define max", NAN);
-    psMetadataAddF32(revertprocessedimfileArgs, PS_LIST_TAIL, "-exp_time_min",  0,
-            "define min", NAN);
-    psMetadataAddF32(revertprocessedimfileArgs, PS_LIST_TAIL, "-exp_time_max",  0,
-            "define max", NAN);
-    psMetadataAddF32(revertprocessedimfileArgs, PS_LIST_TAIL, "-sat_pixel_frac_min",  0,
-            "define max fraction of saturated pixels", NAN);
-    psMetadataAddF32(revertprocessedimfileArgs, PS_LIST_TAIL, "-sat_pixel_frac_max",  0,
-            "define min fraction of saturated pixels", NAN);
-    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-bg_min",  0,
-            "define max", NAN);
-    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-bg_max",  0,
-            "define max", NAN);
-    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-bg_stdev_min",  0,
-            "define max", NAN);
-    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-bg_stdev_max",  0,
-            "define max", NAN);
-    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-bg_mean_stdev_min",  0,
-            "define max", NAN);
-    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-bg_mean_stdev_max",  0,
-            "define max", NAN);
-    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-alt_min",  0,
-            "define min", NAN);
-    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-alt_max",  0,
-            "define max", NAN);
-    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-az_min",  0,
-            "define min", NAN);
-    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-az_max",  0,
-            "define max", NAN);
-    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-ccd_temp_min",0,
-            "define min ccd tempature", NAN);
-    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-ccd_temp_max",0,
-            "define max ccd tempature", NAN);
-    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-posang_min",  0,
-            "define min rotator position angle", NAN);
-    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-posang_max",  0,
-            "define max rotator position angle", NAN);
-    psMetadataAddStr(revertprocessedimfileArgs, PS_LIST_TAIL, "-object",  0,
-            "search by exposure object", NULL);
-    psMetadataAddF32(revertprocessedimfileArgs, PS_LIST_TAIL, "-solang_min",  0,
-            "define min solar angle", NAN);
-    psMetadataAddF32(revertprocessedimfileArgs, PS_LIST_TAIL, "-solang_max",  0,
-            "define max solar angle", NAN);
-
-    psMetadataAddBool(revertprocessedimfileArgs, PS_LIST_TAIL, "-all",  0,
-            "allow everything to be queued without search terms", false);
-    psMetadataAddS16(revertprocessedimfileArgs, PS_LIST_TAIL, "-code",  0,
-            "search by fault code", 0);
+    psMetadataAddS64(revertprocessedimfileArgs, PS_LIST_TAIL, "-fake_id", 0,            "search by fake ID", 0);
+    psMetadataAddS64(revertprocessedimfileArgs, PS_LIST_TAIL, "-exp_id",  0,            "search by exp_id", 0);
+    psMetadataAddStr(revertprocessedimfileArgs, PS_LIST_TAIL, "-exp_name",  0,            "search by exp_name", NULL);
+    psMetadataAddStr(revertprocessedimfileArgs, PS_LIST_TAIL, "-inst",  0,            "search for camera", NULL);
+    psMetadataAddStr(revertprocessedimfileArgs, PS_LIST_TAIL, "-telescope",  0,            "search for telescope", NULL);
+    psMetadataAddTime(revertprocessedimfileArgs, PS_LIST_TAIL, "-dateobs_begin", 0,            "search for exposures by time (>=)", NULL);
+    psMetadataAddTime(revertprocessedimfileArgs, PS_LIST_TAIL, "-dateobs_end", 0,            "search for exposures by time (<)", NULL);
+    psMetadataAddStr(revertprocessedimfileArgs, PS_LIST_TAIL, "-exp_tag",  0,            "search by exp_tag", NULL);
+    psMetadataAddStr(revertprocessedimfileArgs, PS_LIST_TAIL, "-exp_type",  0,            "search by exp_type", "object");
+    psMetadataAddStr(revertprocessedimfileArgs, PS_LIST_TAIL, "-filelevel",  0,            "search by filelevel", NULL);
+    psMetadataAddStr(revertprocessedimfileArgs, PS_LIST_TAIL, "-reduction",  0,            "search by reduction class", NULL);
+    psMetadataAddStr(revertprocessedimfileArgs, PS_LIST_TAIL, "-filter",  0,            "search for filter", NULL);
+    psMetadataAddF32(revertprocessedimfileArgs, PS_LIST_TAIL, "-airmass_min",  0,            "define min airmass", NAN);
+    psMetadataAddF32(revertprocessedimfileArgs, PS_LIST_TAIL, "-airmass_max",  0,            "define max airmass", NAN);
+    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-ra_min",  0,            "define min", NAN);
+    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-ra_max",  0,            "define max", NAN);
+    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-decl_min",  0,            "define min", NAN);
+    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-decl_max",  0,            "define max", NAN);
+    psMetadataAddF32(revertprocessedimfileArgs, PS_LIST_TAIL, "-exp_time_min",  0,            "define min", NAN);
+    psMetadataAddF32(revertprocessedimfileArgs, PS_LIST_TAIL, "-exp_time_max",  0,            "define max", NAN);
+    psMetadataAddF32(revertprocessedimfileArgs, PS_LIST_TAIL, "-sat_pixel_frac_min",  0,            "define max fraction of saturated pixels", NAN);
+    psMetadataAddF32(revertprocessedimfileArgs, PS_LIST_TAIL, "-sat_pixel_frac_max",  0,            "define min fraction of saturated pixels", NAN);
+    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-bg_min",  0,            "define max", NAN);
+    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-bg_max",  0,            "define max", NAN);
+    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-bg_stdev_min",  0,            "define max", NAN);
+    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-bg_stdev_max",  0,            "define max", NAN);
+    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-bg_mean_stdev_min",  0,            "define max", NAN);
+    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-bg_mean_stdev_max",  0,            "define max", NAN);
+    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-alt_min",  0,            "define min", NAN);
+    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-alt_max",  0,            "define max", NAN);
+    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-az_min",  0,            "define min", NAN);
+    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-az_max",  0,            "define max", NAN);
+    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-ccd_temp_min",0,            "define min ccd tempature", NAN);
+    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-ccd_temp_max",0,            "define max ccd tempature", NAN);
+    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-posang_min",  0,            "define min rotator position angle", NAN);
+    psMetadataAddF64(revertprocessedimfileArgs, PS_LIST_TAIL, "-posang_max",  0,            "define max rotator position angle", NAN);
+    psMetadataAddStr(revertprocessedimfileArgs, PS_LIST_TAIL, "-object",  0,            "search by exposure object", NULL);
+    psMetadataAddF32(revertprocessedimfileArgs, PS_LIST_TAIL, "-solang_min",  0,            "define min solar angle", NAN);
+    psMetadataAddF32(revertprocessedimfileArgs, PS_LIST_TAIL, "-solang_max",  0,            "define max solar angle", NAN);
+
+    psMetadataAddBool(revertprocessedimfileArgs, PS_LIST_TAIL, "-all",  0,            "allow everything to be queued without search terms", false);
+    psMetadataAddS16(revertprocessedimfileArgs, PS_LIST_TAIL, "-code",  0,            "search by fault code", 0);
 
     // -block
     psMetadata *blockArgs = psMetadataAlloc();
-    psMetadataAddStr(blockArgs, PS_LIST_TAIL, "-label",  0,
-            "name of a label to mask out (required)", NULL);
+    psMetadataAddStr(blockArgs, PS_LIST_TAIL, "-label",  0,            "name of a label to mask out (required)", NULL);
 
     // -masked
     psMetadata *maskedArgs = psMetadataAlloc();
-    psMetadataAddStr(maskedArgs, PS_LIST_TAIL, "-label",  0,
-            "list blocks for specified label", NULL);
-    psMetadataAddBool(maskedArgs, PS_LIST_TAIL, "-simple",  0,
-            "use the simple output format", false);
-    psMetadataAddU64(maskedArgs, PS_LIST_TAIL, "-limit",  0,
-            "limit result set to N items", 0);
+    psMetadataAddStr(maskedArgs, PS_LIST_TAIL, "-label",  0,            "list blocks for specified label", NULL);
+    psMetadataAddBool(maskedArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(maskedArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
 
     // -unmasked
     psMetadata *unmaskedArgs = psMetadataAlloc();
-    psMetadataAddStr(unmaskedArgs, PS_LIST_TAIL, "-label",  0,
-            "restrict to specified label", NULL);
-    psMetadataAddBool(unmaskedArgs, PS_LIST_TAIL, "-simple",  0,
-            "use the simple output format", false);
-    psMetadataAddU64(unmaskedArgs, PS_LIST_TAIL, "-limit",  0,
-            "limit result set to N items", 0);
+    psMetadataAddStr(unmaskedArgs, PS_LIST_TAIL, "-label",  0,            "restrict to specified label", NULL);
+    psMetadataAddBool(unmaskedArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(unmaskedArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
 
     // -unblock
     psMetadata *unblockArgs = psMetadataAlloc();
-    psMetadataAddStr(unblockArgs, PS_LIST_TAIL, "-label",  0,
-            "name of a label to unmask (required)", NULL);
+    psMetadataAddStr(unblockArgs, PS_LIST_TAIL, "-label",  0,            "name of a label to unmask (required)", NULL);
+
+    // -pendingcleanuprun
+    psMetadata *pendingcleanuprunArgs = psMetadataAlloc();
+    psMetadataAddStr(pendingcleanuprunArgs,  PS_LIST_TAIL, "-label",  0,            "list blocks for specified label", NULL);
+    psMetadataAddBool(pendingcleanuprunArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(pendingcleanuprunArgs,  PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+
+    // -pendingcleanupimfile
+    psMetadata *pendingcleanupimfileArgs = psMetadataAlloc();
+    psMetadataAddStr(pendingcleanupimfileArgs, PS_LIST_TAIL, "-label",  0,            "list blocks for specified label", NULL);
+    psMetadataAddS64(pendingcleanupimfileArgs, PS_LIST_TAIL, "-fake_id", 0,          "search by chip ID", 0);
+    psMetadataAddBool(pendingcleanupimfileArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(pendingcleanupimfileArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+
+    // -donecleanup
+    psMetadata *donecleanupArgs = psMetadataAlloc();
+    psMetadataAddStr(donecleanupArgs, PS_LIST_TAIL, "-label",  0,            "list blocks for specified label", NULL);
+    psMetadataAddBool(donecleanupArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(donecleanupArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
 
     psMetadata *argSets = psMetadataAlloc();
     psMetadata *modes = psMetadataAlloc();
 
-    PXOPT_ADD_MODE("-definebyquery",                 "create runs from raw exposures",
-        FAKETOOL_MODE_DEFINEBYQUERY,                    queueArgs);
-    PXOPT_ADD_MODE("-updaterun",             "change fake run properties",
-        FAKETOOL_MODE_UPDATERUN,                updaterunArgs);
-    PXOPT_ADD_MODE("-pendingexp",           "show pending exposures",
-        FAKETOOL_MODE_PENDINGEXP,               pendingexpArgs);
-    PXOPT_ADD_MODE("-pendingimfile",         "show pending imfiles",
-        FAKETOOL_MODE_PENDINGIMFILE,            pendingimfileArgs);
-    PXOPT_ADD_MODE("-addprocessedimfile",    "add a processed imfile",
-        FAKETOOL_MODE_ADDPROCESSEDIMFILE,       addprocessedimfileArgs);
-    PXOPT_ADD_MODE("-processedimfile",       "show processed imfiles",
-        FAKETOOL_MODE_PROCESSEDIMFILE,          processedimfileArgs);
-    PXOPT_ADD_MODE("-updateprocessedimfile","change procesed imfile properties",        FAKETOOL_MODE_UPDATEPROCESSEDIMFILE,    updateprocessedimfileArgs);
-    PXOPT_ADD_MODE("-revertprocessedimfile", "undo a processed imfile",
-        FAKETOOL_MODE_REVERTPROCESSEDIMFILE,    revertprocessedimfileArgs);
-    PXOPT_ADD_MODE("-block",                 "set a label block", FAKETOOL_MODE_BLOCK,          blockArgs);
-    PXOPT_ADD_MODE("-masked",                "show blocked labels", FAKETOOL_MODE_MASKED,         maskedArgs);
-    PXOPT_ADD_MODE("-unmasked",              "", FAKETOOL_MODE_UNMASKED,       unmaskedArgs);
-    PXOPT_ADD_MODE("-unblock",               "remove a label block", FAKETOOL_MODE_UNBLOCK,        unblockArgs);
+    PXOPT_ADD_MODE("-definebyquery",         "create runs from raw exposures",       FAKETOOL_MODE_DEFINEBYQUERY,                    queueArgs);
+    PXOPT_ADD_MODE("-updaterun",             "change fake run properties",           FAKETOOL_MODE_UPDATERUN,                updaterunArgs);
+    PXOPT_ADD_MODE("-pendingexp",            "show pending exposures",               FAKETOOL_MODE_PENDINGEXP,               pendingexpArgs);
+    PXOPT_ADD_MODE("-pendingimfile",         "show pending imfiles",                 FAKETOOL_MODE_PENDINGIMFILE,            pendingimfileArgs);
+    PXOPT_ADD_MODE("-addprocessedimfile",    "add a processed imfile",               FAKETOOL_MODE_ADDPROCESSEDIMFILE,       addprocessedimfileArgs);
+    PXOPT_ADD_MODE("-processedimfile",       "show processed imfiles",               FAKETOOL_MODE_PROCESSEDIMFILE,          processedimfileArgs);
+    PXOPT_ADD_MODE("-updateprocessedimfile","change procesed imfile properties",     FAKETOOL_MODE_UPDATEPROCESSEDIMFILE,    updateprocessedimfileArgs);
+    PXOPT_ADD_MODE("-revertprocessedimfile", "undo a processed imfile",              FAKETOOL_MODE_REVERTPROCESSEDIMFILE,    revertprocessedimfileArgs);
+    PXOPT_ADD_MODE("-block",                 "set a label block",                    FAKETOOL_MODE_BLOCK,          blockArgs);
+    PXOPT_ADD_MODE("-masked",                "show blocked labels",                  FAKETOOL_MODE_MASKED,         maskedArgs);
+    PXOPT_ADD_MODE("-unmasked",              "",                                     FAKETOOL_MODE_UNMASKED,       unmaskedArgs);
+    PXOPT_ADD_MODE("-unblock",               "remove a label block",                 FAKETOOL_MODE_UNBLOCK,        unblockArgs);
+    PXOPT_ADD_MODE("-pendingcleanuprun",     "show runs that need to be cleaned up", FAKETOOL_MODE_PENDINGCLEANUPRUN,    pendingcleanuprunArgs);
+    PXOPT_ADD_MODE("-pendingcleanupimfile",  "show runs that need to be cleaned up", FAKETOOL_MODE_PENDINGCLEANUPIMFILE, pendingcleanupimfileArgs);
+    PXOPT_ADD_MODE("-donecleanup",           "show runs that have been cleaned",     FAKETOOL_MODE_DONECLEANUP,          donecleanupArgs);
 
     if (!pxGetOptions(stderr, argc, argv, config, modes, argSets)) {
Index: unk/ippTools/src/guidetool.c
===================================================================
--- /trunk/ippTools/src/guidetool.c	(revision 19091)
+++ 	(revision )
@@ -1,221 +1,0 @@
-/*
- * guidetool.c
- *
- * Copyright (C) 2006  Joshua Hoblitt
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * program; see the file COPYING. If not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdlib.h>
-
-#include "pxtools.h"
-#include "guidetool.h"
-
-static bool pendingMode(pxConfig *config);
-static bool defineMode(pxConfig *config);
-static guidePendingExpRow *rawScienceToguidePendingExp(pxConfig *config, rawScienceExpRow *exp);
-
-int main(int argc, char **argv)
-{
-    pxConfig *config = guidetoolConfig(NULL, argc, argv);
-
-    switch (config->mode) {
-        case PX_MODE_PENDING:
-            if (!pendingMode(config)) {
-                goto FAIL;
-            }
-            break;
-        case PX_MODE_DEFINE:
-            if (!defineMode(config)) {
-                goto FAIL;
-            }
-            break;
-        default:
-            psAbort("invalid option (this should not happen)");
-    }
-
-    exit(EXIT_SUCCESS);
-
-FAIL:
-    psFree(config);
-    exit(EXIT_FAILURE);
-}
-
-static bool pendingMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-exp_id",        "exp_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-inst",          "camera", "==");
-    PXOPT_COPY_STR(config->args, where, "-telescope", 	  "telescope", "==");
-    PXOPT_COPY_STR(config->args, where, "-exp_type",  	  "exp_type", "==");
-    PXOPT_COPY_S32(config->args, where, "-imfiles",   	  "imfiles", "==");
-    PXOPT_COPY_STR(config->args, where, "-filter",    	  "filter", "==");
-    PXOPT_COPY_STR(config->args, where, "-recip",         "recipe", "==");
-    PXOPT_COPY_S32(config->args, where, "-guide_version", "guide_version", "==");
-    if (!psListLength(where->list)) {
-	psFree (where);
-	where = NULL;
-    }
-
-    // return all guidePendingExp rows unless there CLI search options
-    psArray *guidePendingExp = guidePendingExpSelectRowObjects(config->dbh, where, 0);
-    psFree (where);
-
-    if (!guidePendingExp) {
-        psError(PS_ERR_UNKNOWN, false, "no guidePendingExp found");
-        return false;
-    }
-    psMetadata *output = psMetadataAlloc();
-
-    for (long i = 0; i < psArrayLength(guidePendingExp); i++) {
-        psMetadata *md = guidePendingExpMetadataFromObject(guidePendingExp->data[i]);
-        psMetadataAddMetadata(output, PS_LIST_TAIL, "guidePendingExp",
-            PS_META_DUPLICATE_OK, NULL, md);
-        psFree(md);
-    }
-
-    psString str = psMetadataConfigFormat(output);
-    psFree(output);
-
-    fprintf(stdout, "%s\n", str);
-    psFree(str);
-
-    return true;
-}
-
-static bool defineMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-    
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-exp_id",        "exp_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-inst",          "camera", "==");
-    PXOPT_COPY_STR(config->args, where, "-telescope", 	  "telescope", "==");
-    PXOPT_COPY_STR(config->args, where, "-exp_type",  	  "exp_type", "==");
-    PXOPT_COPY_S32(config->args, where, "-imfiles",   	  "imfiles", "==");
-    PXOPT_COPY_STR(config->args, where, "-filter",    	  "filter", "==");
-    if (!psListLength(where->list)) {
-	psFree (where);
-	where = NULL;
-    }
-
-    // return all rawScienceExp rows unless there CLI search options
-    psArray *rawScienceExps = rawScienceExpSelectRowObjects(config->dbh, where, 0);
-    psFree (where);
-    
-    if (!rawScienceExps) {
-        psError(PS_ERR_UNKNOWN, false, "no rawScienceExp rows found");
-        return true;
-    }
-
-    // insert the rawScienceExps into guidePendingExp
-    // XXX for the being we're going to skip checking for duplicate entries
-    // XXX this will have to implimented unless duplicate key insertion 
-    // XXX support is implimented in psDB
-    for (long i = 0; i < psArrayLength(rawScienceExps); i++) {
-        guidePendingExpRow * new = rawScienceToguidePendingExp(
-                                            config, rawScienceExps->data[i]);
-        if (!guidePendingExpInsertObject(config->dbh, new)) {
-            psError(PS_ERR_UNKNOWN, false, "dbh access failed");
-            return false; 
-        }
-        psFree(new);
-    }
-
-    return true;
-}
-
-static guidePendingExpRow *rawScienceToguidePendingExp(pxConfig *config, rawScienceExpRow *exp)
-{
-    PS_ASSERT_PTR_NON_NULL(config, NULL);
-    PS_ASSERT_PTR_NON_NULL(exp, NULL);
-
-    bool status = false;
-    psString filter = psMetadataLookupStr(&status, config->args, "-filter");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -filter");
-        return false;
-    }
-    if (!filter) {
-        psError(PS_ERR_UNKNOWN, true, "-filter is required");
-        return false;
-    }
-    psF32 airmass = psMetadataLookupF32(&status, config->args, "-airmass");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -airmass");
-        return false;
-    }
-    if (!airmass) {
-        psError(PS_ERR_UNKNOWN, true, "-airmass is required");
-        return false;
-    }
-    psF64 ra = psMetadataLookupF64(&status, config->args, "-ra");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -ra");
-        return false;
-    }
-    if (!ra) {
-        psError(PS_ERR_UNKNOWN, true, "-airmass is required");
-        return false;
-    }
-    psF64 dec = psMetadataLookupF64(&status, config->args, "-dec");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -dec");
-        return false;
-    }
-    if (!dec) {
-        psError(PS_ERR_UNKNOWN, true, "-dec is required");
-        return false;
-    }
-    psF32 exp_time = psMetadataLookupF32(&status, config->args, "-exp_time");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -exp_time");
-        return false;
-    }
-    if (!exp_time) {
-        psError(PS_ERR_UNKNOWN, true, "-exp_time is required");
-        return false;
-    }
-    psF64 background = psMetadataLookupF64(&status, config->args, "-background");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -background");
-        return false;
-    }
-    if (!exp_time) {
-        psError(PS_ERR_UNKNOWN, true, "-background is required");
-        return false;
-    }
-
-    return guidePendingExpRowAlloc(
-        exp->exp_id,
-        exp->camera,
-        exp->telescope,
-        exp->exp_type,
-        exp->imfiles,
-        filter,
-        airmass,
-        ra,
-        dec,
-        exp_time,
-        background,
-        "my recipe",
-        0xff // XXX calc version number
-    );
-}
Index: unk/ippTools/src/guidetool.h
===================================================================
--- /trunk/ippTools/src/guidetool.h	(revision 19091)
+++ 	(revision )
@@ -1,27 +1,0 @@
-/*
- * guidetool.h
- *
- * Copyright (C) 2006  Joshua Hoblitt
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * program; see the file COPYING. If not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef GUIDETOOL_H
-#define GUIDETOOL_H 1
-
-#include "pxtools.h"
-
-pxConfig *guidetoolConfig(pxConfig *config, int argc, char **argv);
-
-#endif // GUIDETOOL_H
Index: unk/ippTools/src/guidetoolConfig.c
===================================================================
--- /trunk/ippTools/src/guidetoolConfig.c	(revision 19091)
+++ 	(revision )
@@ -1,140 +1,0 @@
-/*
- * guidetoolConfig.c
- *
- * Copyright (C) 2006  Joshua Hoblitt
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * program; see the file COPYING. If not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <psmodules.h>
-
-#include "pxtools.h"
-
-// this function can not fail -- exits on error
-
-pxConfig *guidetoolConfig(pxConfig *config, int argc, char **argv) {
-    if (!config) {
-        config = pxConfigAlloc();
-    }
-
-    pmConfigReadParamsSet(false);
-
-    // setup site config
-    config->modules = pmConfigRead(&argc, argv);
-    if (!config->modules) {
-        psError(PS_ERR_UNKNOWN, false, "Can't find site configuration");
-        exit(EXIT_FAILURE);
-    }
-
-    // CLI options
-    // modes
-    psMetadata *args = psMetadataAlloc();
-    psMetadataAddStr(args , PS_LIST_TAIL, "-pending", 0,
-        "examine pending image table, write ppImage output", NULL);
-    psMetadataAddStr(args , PS_LIST_TAIL, "-define",  0,
-        "update pending image table", NULL);
-
-    // -pending search
-    psMetadata *pendingArgs = psMetadataAlloc();
-    psMetadataAddStr(pendingArgs, PS_LIST_TAIL, "-exp_id",  0,        "define exposure ID", NULL);
-    psMetadataAddStr(pendingArgs, PS_LIST_TAIL, "-inst",  0,        "define camera of interest", NULL);
-    psMetadataAddStr(pendingArgs, PS_LIST_TAIL, "-telescope",  0,        "define telescope of interest", NULL);
-    psMetadataAddStr(pendingArgs, PS_LIST_TAIL, "-exp_type",  0,        "define exposure type", NULL);
-    psMetadataAddS32(pendingArgs, PS_LIST_TAIL, "-imfiles",  0,        "define number of imfiles", 0);
-    psMetadataAddStr(pendingArgs, PS_LIST_TAIL, "-filter",  0,        "define filter of interest", NULL);
-    psMetadataAddStr(pendingArgs, PS_LIST_TAIL, "-recipe",  0,        "define recipe of interest", NULL);
-    psMetadataAddS32(pendingArgs, PS_LIST_TAIL, "-guide_version",  0,        "define guide_version of interest", 0);
-
-    // -define inputs
-    psMetadata *defineArgs = psMetadataAlloc();
-    psMetadataAddStr(defineArgs, PS_LIST_TAIL, "-exp_id",  0,        "define class", NULL);
-    psMetadataAddStr(defineArgs, PS_LIST_TAIL, "-inst",  0,        "define camera of interest", NULL);
-    psMetadataAddStr(defineArgs, PS_LIST_TAIL, "-telescope",  0,        "define camera of interest", NULL);
-    psMetadataAddStr(defineArgs, PS_LIST_TAIL, "-exp_type",  0,        "define class", NULL);
-    psMetadataAddS32(defineArgs, PS_LIST_TAIL, "-imfiles",  0,        "define number of imfiles", 0);
-    psMetadataAddStr(defineArgs, PS_LIST_TAIL, "-filter",  0,        "define filter of interest", NULL);
-    // these two are inputs NOT search parameters
-    psMetadataAddStr(defineArgs, PS_LIST_TAIL, "-recipe",  0,        "define recipe of interest", NULL);
-    psMetadataAddS32(defineArgs, PS_LIST_TAIL, "-guide_version",  0,        "define guide_version of interest", 0);
-
-    // find which mode we're running under
-    int N = 0;
-    config->mode = PX_MODE_NONE;
-    if ((N = psArgumentGet (argc, argv, "-pending"))) {
-        psArgumentRemove (N, &argc, argv);
-        if (config->mode) {
-            psError(PS_ERR_UNKNOWN, true, "only one mode selection is allowed");
-        }
-        config->mode = PX_MODE_PENDING;
-    }
-    if ((N = psArgumentGet (argc, argv, "-define"))) {
-        psArgumentRemove (N, &argc, argv);
-        if (config->mode) {
-            psError(PS_ERR_UNKNOWN, true, "only one mode selection is allowed");
-        }
-        config->mode = PX_MODE_DEFINE;
-    }
-
-    // parse CLI for these options
-    switch (config->mode) {
-        case PX_MODE_PENDING:
-            config->args = psMemIncrRefCounter(pendingArgs);
-            break;
-        case PX_MODE_DEFINE:
-            config->args = psMemIncrRefCounter(defineArgs);
-            break;
-        default:
-            config->args = psMemIncrRefCounter(args);
-    }
-
-    bool argErr = false;
-    if (config->mode == PX_MODE_NONE) {
-        argErr = true;
-        fprintf (stderr, "mode argument is required\n");
-    } else if (! psArgumentParse(config->args, &argc, argv) || argc != 1) {
-        argErr = true;
-        fprintf (stderr, "error parsing arguments\n");
-    }
-
-    if (argErr) {
-        printf("\nPan-STARRS Guide Star Tool\n");
-        printf("Usage: %s <mode> [<options>]\n\n", argv[0]);
-        printf(" <mode> : -pending | -define\n\n");
-        fprintf (stdout, "-pending ");
-        psArgumentHelp(pendingArgs);
-        fprintf (stdout, "-define ");
-        psArgumentHelp(defineArgs);
-        psFree(args);
-        psFree(pendingArgs);
-        psFree(defineArgs);
-        exit(EXIT_FAILURE);
-    }
-
-    psFree(args);
-    psFree(pendingArgs);
-    psFree(defineArgs);
-
-    // define Database handle, if used
-    config->dbh = psMemIncrRefCounter(pmConfigDB(config->modules));
-    if (!config->dbh) {
-        psError(PS_ERR_UNKNOWN, false, "Can't configure database");
-        exit(EXIT_FAILURE);
-    }
-
-    return config;
-}
Index: /trunk/ippTools/src/pxcam.c
===================================================================
--- /trunk/ippTools/src/pxcam.c	(revision 19091)
+++ /trunk/ippTools/src/pxcam.c	(revision 19092)
@@ -35,10 +35,5 @@
 
     // check that state is a valid string value
-    if (!(
-            (strncmp(state, "run", 4) == 0)
-            || (strncmp(state, "stop", 5) == 0)
-            || (strncmp(state, "reg", 4) == 0)
-        )
-    ) {
+    if (!pxIsValidState(state)) {
         psError(PS_ERR_UNKNOWN, false,
                 "invalid camRun state: %s", state);
@@ -63,10 +58,5 @@
 
     // check that state is a valid string value
-    if (!(
-            (strncmp(state, "run", 4) == 0)
-            || (strncmp(state, "stop", 5) == 0)
-            || (strncmp(state, "reg", 4) == 0)
-        )
-    ) {
+    if (!pxIsValidState(state)) {
         psError(PS_ERR_UNKNOWN, false,
                 "invalid chipRun state: %s", state);
@@ -108,5 +98,4 @@
     return true;
 }
-
 
 bool pxcamRunSetLabelByQuery(pxConfig *config, psMetadata *where, const char *label)
@@ -162,5 +151,5 @@
     // different on 32/64
     if (!p_psDBRunQuery(config->dbh, query,
-                "run", // state
+                "new", // state
                 workdir  ? workdir  : "NULL",
                 "dirty", //workdir_state
Index: /trunk/ippTools/src/pxfake.c
===================================================================
--- /trunk/ippTools/src/pxfake.c	(revision 19091)
+++ /trunk/ippTools/src/pxfake.c	(revision 19092)
@@ -35,10 +35,5 @@
 
     // check that state is a valid string value
-    if (!(
-            (strncmp(state, "run", 4) == 0)
-            || (strncmp(state, "stop", 5) == 0)
-            || (strncmp(state, "reg", 4) == 0)
-        )
-    ) {
+    if (!pxIsValidState(state)) {
         psError(PS_ERR_UNKNOWN, false,
                 "invalid fakeRun state: %s", state);
@@ -63,10 +58,5 @@
 
     // check that state is a valid string value
-    if (!(
-            (strncmp(state, "run", 4) == 0)
-            || (strncmp(state, "stop", 5) == 0)
-            || (strncmp(state, "reg", 4) == 0)
-        )
-    ) {
+    if (!pxIsValidState(state)) {
         psError(PS_ERR_UNKNOWN, false,
                 "invalid fakeRun state: %s", state);
@@ -164,5 +154,5 @@
     // different on 32/64
     if (!p_psDBRunQuery(config->dbh, query,
-                "run", // state
+                "new", // state
                 workdir  ? workdir  : "NULL",
                 label    ? label    : "NULL",
Index: /trunk/ippTools/src/pxtools.c
===================================================================
--- /trunk/ippTools/src/pxtools.c	(revision 19091)
+++ /trunk/ippTools/src/pxtools.c	(revision 19092)
@@ -29,6 +29,9 @@
 {
     PS_ASSERT_PTR_NON_NULL(state, false);
+    
+    // XXX replace strncmp with strcmp
 
     if (!((strncmp(state, "new", 4) == 0)
+    || (strncmp(state, "reg", 3) == 0)
     || (strncmp(state, "full", 5) == 0)
     || (strncmp(state, "goto_cleaned", 8) == 0)
Index: /trunk/ippTools/src/pxwarp.c
===================================================================
--- /trunk/ippTools/src/pxwarp.c	(revision 19091)
+++ /trunk/ippTools/src/pxwarp.c	(revision 19092)
@@ -35,12 +35,6 @@
 
     // check that state is a valid string value
-    if (!(
-            (strncmp(state, "run", 4) == 0)
-            || (strncmp(state, "stop", 5) == 0)
-            || (strncmp(state, "reg", 4) == 0)
-        )
-    ) {
-        psError(PS_ERR_UNKNOWN, false,
-                "invalid warpRun state: %s", state);
+    if (!pxIsValidState(state)) {
+        psError(PS_ERR_UNKNOWN, false, "invalid warpRun state: %s", state);
         return false;
     }
@@ -63,12 +57,6 @@
 
     // check that state is a valid string value
-    if (!(
-            (strncmp(state, "run", 4) == 0)
-            || (strncmp(state, "stop", 5) == 0)
-            || (strncmp(state, "reg", 4) == 0)
-        )
-    ) {
-        psError(PS_ERR_UNKNOWN, false,
-                "invalid chipRun state: %s", state);
+    if (!pxIsValidState(state)) {
+        psError(PS_ERR_UNKNOWN, false, "invalid chipRun state: %s", state);
         return false;
     }
@@ -152,5 +140,5 @@
         fake_id,
         "warp",     // mode
-        "run",      // state
+        "new",      // state
         workdir,
         "dirty",    // workdir_state
Index: /trunk/ippTools/src/stacktool.c
===================================================================
--- /trunk/ippTools/src/stacktool.c	(revision 19091)
+++ /trunk/ippTools/src/stacktool.c	(revision 19092)
@@ -40,4 +40,7 @@
 static bool sumskyfileMode(pxConfig *config);
 static bool revertsumskyfileMode(pxConfig *config);
+static bool pendingcleanuprunMode(pxConfig *config);
+static bool pendingcleanupskyfileMode(pxConfig *config);
+static bool donecleanupMode(pxConfig *config);
 
 static bool setstackRunState(pxConfig *config, psS64 stack_id, const char *state);
@@ -61,13 +64,16 @@
 
     switch (config->mode) {
-        MODECASE(STACKTOOL_MODE_DEFINEBYQUERY,              definebyqueryMode);
-        MODECASE(STACKTOOL_MODE_DEFINERUN,          definerunMode);
-        MODECASE(STACKTOOL_MODE_UPDATERUN,          updaterunMode);
-        MODECASE(STACKTOOL_MODE_ADDINPUTSKYFILE,    addinputskyfileMode);
-        MODECASE(STACKTOOL_MODE_INPUTSKYFILE,       inputskyfileMode);
-        MODECASE(STACKTOOL_MODE_TOSUM,              tosumMode);
-        MODECASE(STACKTOOL_MODE_ADDSUMSKYFILE,      addsumskyfileMode);
-        MODECASE(STACKTOOL_MODE_SUMSKYFILE,         sumskyfileMode);
-        MODECASE(STACKTOOL_MODE_REVERTSUMSKYFILE,   revertsumskyfileMode);
+        MODECASE(STACKTOOL_MODE_DEFINEBYQUERY,         definebyqueryMode);
+        MODECASE(STACKTOOL_MODE_DEFINERUN,             definerunMode);
+        MODECASE(STACKTOOL_MODE_UPDATERUN,             updaterunMode);
+        MODECASE(STACKTOOL_MODE_ADDINPUTSKYFILE,       addinputskyfileMode);
+        MODECASE(STACKTOOL_MODE_INPUTSKYFILE,          inputskyfileMode);
+        MODECASE(STACKTOOL_MODE_TOSUM,                 tosumMode);
+        MODECASE(STACKTOOL_MODE_ADDSUMSKYFILE,         addsumskyfileMode);
+        MODECASE(STACKTOOL_MODE_SUMSKYFILE,            sumskyfileMode);
+        MODECASE(STACKTOOL_MODE_REVERTSUMSKYFILE,      revertsumskyfileMode);
+        MODECASE(STACKTOOL_MODE_PENDINGCLEANUPRUN,     pendingcleanuprunMode);
+        MODECASE(STACKTOOL_MODE_PENDINGCLEANUPSKYFILE, pendingcleanupskyfileMode);
+        MODECASE(STACKTOOL_MODE_DONECLEANUP,           donecleanupMode);
         default:
             psAbort("invalid option (this should not happen)");
@@ -288,5 +294,14 @@
 
         // create a new stackRun for this stack
-        stackRunRow *run = stackRunRowAlloc(0, "run", workdir, NULL, registered, skycell_id, tess_id, filter);
+        stackRunRow *run = stackRunRowAlloc(
+	    0, 				// ID
+	    "new", 			// state
+	    workdir, 
+	    NULL, 			// workdir_state
+	    registered, 
+	    skycell_id, 
+	    tess_id, 
+	    filter);
+
         if (!stackRunInsertObject(config->dbh, run)) {
             if (!psDBRollback(config->dbh)) {
@@ -343,9 +358,8 @@
     if (!stackRunPrintObjects(stdout, list, !simple)) {
         psError(PS_ERR_UNKNOWN, false, "failed to print object");
-        return false;
-    }
-
+        psFree(list);
+        return false;
+    }
     psFree(list);
-
     return true;
 }
@@ -374,5 +388,14 @@
     }
 
-    stackRunRow *run = stackRunRowAlloc(0, "run", workdir, NULL, registered, skycell_id, tess_id, filter);
+    stackRunRow *run = stackRunRowAlloc(
+	0, 				// ID
+	"new", 				// state
+	workdir, 
+	NULL, 				// workdir_state
+	registered, 
+	skycell_id, 
+	tess_id, 
+	filter);
+
     if (!run) {
         psError(PS_ERR_UNKNOWN, false, "failed to alloc stackRun object");
@@ -667,5 +690,5 @@
     }
 
-    if (!setstackRunState(config, stack_id, "stop")) {
+    if (!setstackRunState(config, stack_id, "full")) {
         if (!psDBRollback(config->dbh)) {
             psError(PS_ERR_UNKNOWN, false, "database error");
@@ -869,12 +892,6 @@
 
     // check that state is a valid string value
-    if (!(
-            (strncmp(state, "run", 4) == 0)
-            || (strncmp(state, "stop", 5) == 0)
-            || (strncmp(state, "reg", 4) == 0)
-        )
-    ) {
-        psError(PS_ERR_UNKNOWN, false,
-                "invalid warpRun state: %s", state);
+    if (!pxIsValidState(state)) {
+        psError(PS_ERR_UNKNOWN, false, "invalid stackRun state: %s", state);
         return false;
     }
@@ -889,2 +906,187 @@
     return true;
 }
+
+static bool pendingcleanuprunMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_STR(config->args, where, "-label", "label", "==");
+
+    psString query = pxDataGet("stacktool_pendingcleanuprun.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("stacktool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "stackPendingCleanupRun", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+static bool pendingcleanupskyfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_S64(stack_id, config->args, "-stack_id", false, false);
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    if (stack_id) {
+        PXOPT_COPY_S64(config->args, where, "-stack_id", "stack_id", "==");
+    }
+    PXOPT_COPY_STR(config->args, where, "-label", "label", "==");
+
+    psString query = pxDataGet("stacktool_pendingcleanupskyfile.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("stacktool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "stackPendingCleanupSkyfile", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+
+static bool donecleanupMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_STR(config->args, where, "-label", "label", "==");
+
+    psString query = pxDataGet("stacktool_donecleanup.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("stacktool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "stackDoneCleanup", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
Index: /trunk/ippTools/src/stacktool.h
===================================================================
--- /trunk/ippTools/src/stacktool.h	(revision 19091)
+++ /trunk/ippTools/src/stacktool.h	(revision 19092)
@@ -34,4 +34,7 @@
     STACKTOOL_MODE_SUMSKYFILE,
     STACKTOOL_MODE_REVERTSUMSKYFILE,
+    STACKTOOL_MODE_PENDINGCLEANUPRUN,
+    STACKTOOL_MODE_PENDINGCLEANUPSKYFILE,
+    STACKTOOL_MODE_DONECLEANUP,
 } stacktoolMode;
 
Index: /trunk/ippTools/src/stacktoolConfig.c
===================================================================
--- /trunk/ippTools/src/stacktoolConfig.c	(revision 19091)
+++ /trunk/ippTools/src/stacktoolConfig.c	(revision 19092)
@@ -136,4 +136,23 @@
     psMetadataAddS16(revertsumskyfileArgs, PS_LIST_TAIL, "-code",  0,            "search by fault code", 0);
 
+    // -pendingcleanuprun
+    psMetadata *pendingcleanuprunArgs = psMetadataAlloc();
+    psMetadataAddStr(pendingcleanuprunArgs, PS_LIST_TAIL, "-label",  0,            "list blocks for specified label", NULL);
+    psMetadataAddBool(pendingcleanuprunArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(pendingcleanuprunArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+
+    // -pendingcleanupskyfile
+    psMetadata *pendingcleanupskyfileArgs = psMetadataAlloc();
+    psMetadataAddStr(pendingcleanupskyfileArgs, PS_LIST_TAIL, "-label",  0,            "list blocks for specified label", NULL);
+    psMetadataAddS64(pendingcleanupskyfileArgs, PS_LIST_TAIL, "-stack_id", 0,          "search by stack ID", 0);
+    psMetadataAddBool(pendingcleanupskyfileArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(pendingcleanupskyfileArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+
+    // -donecleanup
+    psMetadata *donecleanupArgs = psMetadataAlloc();
+    psMetadataAddStr(donecleanupArgs, PS_LIST_TAIL, "-label",  0,            "list blocks for specified label", NULL);
+    psMetadataAddBool(donecleanupArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(donecleanupArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+
     psFree(now);
 
@@ -150,4 +169,7 @@
     PXOPT_ADD_MODE("-sumskyfile",      "list results of stackRun", STACKTOOL_MODE_SUMSKYFILE,      sumskyfileArgs);
     PXOPT_ADD_MODE("-revertsumskyfile","", STACKTOOL_MODE_REVERTSUMSKYFILE,      revertsumskyfileArgs);
+    PXOPT_ADD_MODE("-pendingcleanuprun",     "show runs that need to be cleaned up", STACKTOOL_MODE_PENDINGCLEANUPRUN,    pendingcleanuprunArgs);
+    PXOPT_ADD_MODE("-pendingcleanupskyfile", "show runs that need to be cleaned up", STACKTOOL_MODE_PENDINGCLEANUPSKYFILE, pendingcleanupskyfileArgs);
+    PXOPT_ADD_MODE("-donecleanup",           "show runs that have been cleaned",     STACKTOOL_MODE_DONECLEANUP,          donecleanupArgs);
 
     if (!pxGetOptions(stderr, argc, argv, config, modes, argSets)) {
Index: /trunk/ippTools/src/warptool.c
===================================================================
--- /trunk/ippTools/src/warptool.c	(revision 19091)
+++ /trunk/ippTools/src/warptool.c	(revision 19092)
@@ -46,4 +46,7 @@
 static bool maskedMode(pxConfig *config);
 static bool unblockMode(pxConfig *config);
+static bool pendingcleanuprunMode(pxConfig *config);
+static bool pendingcleanupwarpMode(pxConfig *config);
+static bool donecleanupMode(pxConfig *config);
 
 static bool parseAndInsertSkyCellMap(pxConfig *config, const char *mapfile);
@@ -69,18 +72,21 @@
 
     switch (config->mode) {
-        MODECASE(WARPTOOL_MODE_DEFINERUN,         definerunMode);
-        MODECASE(WARPTOOL_MODE_UPDATERUN,         updaterunMode);
-        MODECASE(WARPTOOL_MODE_EXP,               expMode);
-        MODECASE(WARPTOOL_MODE_IMFILE,            imfileMode);
-        MODECASE(WARPTOOL_MODE_TOOVERLAP,         tooverlapMode);
-        MODECASE(WARPTOOL_MODE_ADDOVERLAP,        addoverlapMode);
-        MODECASE(WARPTOOL_MODE_SCMAP,             scmapMode);
-        MODECASE(WARPTOOL_MODE_TOWARPED,          towarpedMode);
-        MODECASE(WARPTOOL_MODE_ADDWARPED,         addwarpedMode);
-        MODECASE(WARPTOOL_MODE_WARPED,            warpedMode);
-        MODECASE(WARPTOOL_MODE_REVERTWARPED,      revertwarpedMode);
-        MODECASE(WARPTOOL_MODE_BLOCK,             blockMode);
-        MODECASE(WARPTOOL_MODE_MASKED,            maskedMode);
-        MODECASE(WARPTOOL_MODE_UNBLOCK,           unblockMode);
+        MODECASE(WARPTOOL_MODE_DEFINERUN,          definerunMode);
+        MODECASE(WARPTOOL_MODE_UPDATERUN,          updaterunMode);
+        MODECASE(WARPTOOL_MODE_EXP,                expMode);
+        MODECASE(WARPTOOL_MODE_IMFILE,             imfileMode);
+        MODECASE(WARPTOOL_MODE_TOOVERLAP,          tooverlapMode);
+        MODECASE(WARPTOOL_MODE_ADDOVERLAP,         addoverlapMode);
+        MODECASE(WARPTOOL_MODE_SCMAP,              scmapMode);
+        MODECASE(WARPTOOL_MODE_TOWARPED,           towarpedMode);
+        MODECASE(WARPTOOL_MODE_ADDWARPED,          addwarpedMode);
+        MODECASE(WARPTOOL_MODE_WARPED,             warpedMode);
+        MODECASE(WARPTOOL_MODE_REVERTWARPED,       revertwarpedMode);
+        MODECASE(WARPTOOL_MODE_BLOCK,              blockMode);
+        MODECASE(WARPTOOL_MODE_MASKED,             maskedMode);
+        MODECASE(WARPTOOL_MODE_UNBLOCK,            unblockMode);
+        MODECASE(WARPTOOL_MODE_PENDINGCLEANUPRUN,  pendingcleanuprunMode);
+        MODECASE(WARPTOOL_MODE_PENDINGCLEANUPSKYFILE, pendingcleanupwarpMode);
+        MODECASE(WARPTOOL_MODE_DONECLEANUP,        donecleanupMode);
 
         default:
@@ -131,5 +137,5 @@
             fake_id,
             mode,
-            "run",      // state
+            "new",      // state
             workdir,
             "dirty",    // workdir_state
@@ -1122,5 +1128,4 @@
 }
 
-
 static bool unblockMode(pxConfig *config)
 {
@@ -1139,4 +1144,189 @@
 }
 
+static bool pendingcleanuprunMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_STR(config->args, where, "-label", "label", "==");
+
+    psString query = pxDataGet("warptool_pendingcleanuprun.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("warptool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "warpPendingCleanupRun", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+
+static bool pendingcleanupwarpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_S64(warp_id, config->args, "-warp_id", false, false);
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    if (warp_id) {
+        PXOPT_COPY_S64(config->args, where, "-warp_id", "warp_id", "==");
+    }
+    PXOPT_COPY_STR(config->args, where, "-label", "label", "==");
+
+    psString query = pxDataGet("warptool_pendingcleanupskyfile.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("warptool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "warpPendingCleanupWarp", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+
+static bool donecleanupMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_STR(config->args, where, "-label", "label", "==");
+
+    psString query = pxDataGet("warptool_donecleanup.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("warptool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "warpDoneCleanup", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
 
 static bool isValidMode(pxConfig *config, const char *mode)
Index: /trunk/ippTools/src/warptool.h
===================================================================
--- /trunk/ippTools/src/warptool.h	(revision 19091)
+++ /trunk/ippTools/src/warptool.h	(revision 19092)
@@ -41,4 +41,7 @@
     WARPTOOL_MODE_MASKED,
     WARPTOOL_MODE_UNBLOCK,
+    WARPTOOL_MODE_PENDINGCLEANUPRUN,
+    WARPTOOL_MODE_PENDINGCLEANUPSKYFILE,
+    WARPTOOL_MODE_DONECLEANUP,
 } warptoolMode;
 
Index: /trunk/ippTools/src/warptoolConfig.c
===================================================================
--- /trunk/ippTools/src/warptoolConfig.c	(revision 19091)
+++ /trunk/ippTools/src/warptoolConfig.c	(revision 19092)
@@ -252,4 +252,23 @@
     psMetadataAddStr(unblockArgs, PS_LIST_TAIL, "-label",  0,            "name of a label to unmask (required)", NULL);
 
+    // -pendingcleanuprun
+    psMetadata *pendingcleanuprunArgs = psMetadataAlloc();
+    psMetadataAddStr(pendingcleanuprunArgs, PS_LIST_TAIL, "-label",  0,            "list blocks for specified label", NULL);
+    psMetadataAddBool(pendingcleanuprunArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(pendingcleanuprunArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+
+    // -pendingcleanupskyfile
+    psMetadata *pendingcleanupskyfileArgs = psMetadataAlloc();
+    psMetadataAddStr(pendingcleanupskyfileArgs, PS_LIST_TAIL, "-label",  0,            "list blocks for specified label", NULL);
+    psMetadataAddS64(pendingcleanupskyfileArgs, PS_LIST_TAIL, "-warp_id", 0,          "search by warp ID", 0);
+    psMetadataAddBool(pendingcleanupskyfileArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(pendingcleanupskyfileArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+
+    // -donecleanup
+    psMetadata *donecleanupArgs = psMetadataAlloc();
+    psMetadataAddStr(donecleanupArgs, PS_LIST_TAIL, "-label",  0,            "list blocks for specified label", NULL);
+    psMetadataAddBool(donecleanupArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(donecleanupArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+
     psFree(now);
     psMetadata *argSets = psMetadataAlloc();
@@ -267,7 +286,10 @@
     PXOPT_ADD_MODE("-warped",          "", WARPTOOL_MODE_WARPED,         warpedArgs);
     PXOPT_ADD_MODE("-revertwarped",    "", WARPTOOL_MODE_REVERTWARPED,   revertwarpedArgs);
-    PXOPT_ADD_MODE("-block",           "set a label block", WARPTOOL_MODE_BLOCK,          blockArgs);
-    PXOPT_ADD_MODE("-masked",          "show blocked lables", WARPTOOL_MODE_MASKED,         maskedArgs);
-    PXOPT_ADD_MODE("-unblock",         "remove a label block", WARPTOOL_MODE_UNBLOCK,        unblockArgs);
+    PXOPT_ADD_MODE("-block",                 "set a label block",                    WARPTOOL_MODE_BLOCK,          blockArgs);
+    PXOPT_ADD_MODE("-masked",                "show blocked lables",                  WARPTOOL_MODE_MASKED,         maskedArgs);
+    PXOPT_ADD_MODE("-unblock",               "remove a label block",                 WARPTOOL_MODE_UNBLOCK,        unblockArgs);
+    PXOPT_ADD_MODE("-pendingcleanuprun",     "show runs that need to be cleaned up", WARPTOOL_MODE_PENDINGCLEANUPRUN,    pendingcleanuprunArgs);
+    PXOPT_ADD_MODE("-pendingcleanupskyfile", "show runs that need to be cleaned up", WARPTOOL_MODE_PENDINGCLEANUPSKYFILE, pendingcleanupskyfileArgs);
+    PXOPT_ADD_MODE("-donecleanup",           "show runs that have been cleaned",     WARPTOOL_MODE_DONECLEANUP,          donecleanupArgs);
 
     if (!pxGetOptions(stderr, argc, argv, config, modes, argSets)) {
