Index: trunk/ippScripts/scripts/dist_advancerun.pl
===================================================================
--- trunk/ippScripts/scripts/dist_advancerun.pl	(revision 36553)
+++ trunk/ippScripts/scripts/dist_advancerun.pl	(revision 36555)
@@ -69,4 +69,5 @@
 my $stacktool   = can_run('stacktool') or (warn "Can't find stacktool" and $missing_tools = 1);
 my $bgtool = can_run('bgtool') or (warn "Can't find bgtool" and $missing_tools = 1);
+my $fftool = can_run('fftool') or (warn "Can't find fftool" and $missing_tools = 1);
 my $staticskytool = can_run('staticskytool') or (warn "Can't find staticskytool" and $missing_tools = 1);
 if ($missing_tools) {
@@ -77,4 +78,5 @@
 
 my $tool_cmd;
+my $tool_cmd2;
 my $list_mode;
 my $component_key;
@@ -127,4 +129,9 @@
     $list_mode = "-diffskyfile";
     $component_key = "skycell_id";
+} elsif ($stage eq "ff") {
+    $tool_cmd = "$fftool -ff_id";
+    $list_mode = "-result";
+    $component_key = "dist_component";
+    $tool_cmd2 = "$fftool -summary -ff_id"
 } else {
     &my_die("Unexpected stage: $stage", $dist_id, $PS_EXIT_CONFIG_ERROR);
@@ -132,4 +139,5 @@
 
 $tool_cmd .= " $stage_id";
+$tool_cmd2 .= " $stage_id" if $tool_cmd2;
 
 my $exportarg = '-exportrun';
@@ -215,4 +223,26 @@
     my $components = parse_md_list($metadata) or
         &my_die("Unable to parse metadata list", $dist_id, $PS_EXIT_UNKNOWN_ERROR);
+
+    if ($tool_cmd2) {
+        my $command = "$tool_cmd2";
+        $command .= " -dbname $dbname" if defined $dbname;
+
+        my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+            run(command => $command, verbose => $verbose);
+            unless ($success) {
+            $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+            &my_die("Unable to perform $command: $error_code", $dist_id, $error_code);
+        }
+        if (@$stdout_buf == 0) {
+            &my_die("Unable to perform $command: $error_code", $dist_id, $error_code);
+        }
+        my $metadata = $mdcParser->parse(join "", @$stdout_buf) or
+            &my_die("Unable to parse metadata config doc", $dist_id, $PS_EXIT_UNKNOWN_ERROR);
+        my $more_components = parse_md_list($metadata) or
+            &my_die("Unable to parse metadata list", $dist_id, $PS_EXIT_UNKNOWN_ERROR);
+        if (scalar @$more_components) {
+            push @$components, @$more_components;
+        }
+    }
 
     open MANIFEST, ">$resolved" or
Index: trunk/ippScripts/scripts/dist_bundle.pl
===================================================================
--- trunk/ippScripts/scripts/dist_bundle.pl	(revision 36553)
+++ trunk/ippScripts/scripts/dist_bundle.pl	(revision 36555)
@@ -496,5 +496,5 @@
     } elsif ($stage eq "stack") {
         $type = $stack_cleaned{$rule};
-    } elsif ($stage eq "sky" or $stage eq 'skycal' or $stage eq 'stack_summary') {
+    } elsif ($stage eq "sky" or $stage eq 'skycal' or $stage eq 'stack_summary' or $stage eq 'ff') {
         $type = $empty_cleaned{$rule};
     } else {
@@ -588,4 +588,11 @@
         # stack_summary stage does not use a config dump file.
         return build_stack_summary_file_list($path_base, \@file_list);
+    } elsif ($stage eq "ff") {
+        if ($component eq 'summary') {
+            # full force summary does not use a config dump file. Cobble together a file list
+            return build_ff_summary_file_list($path_base, \@file_list);
+        } else {
+            $config_file_rule = "PSPHOT.SKY.CONFIG";
+        }
     } else {
         &my_die("$stage is not a valid stage", $component, $PS_EXIT_CONFIG_ERROR);
@@ -742,4 +749,21 @@
 }
 
+# psphotFullForceSummary does not produce a config dump file cobble together a file list
+sub build_ff_summary_file_list {
+    my ($path_base, $file_list) = @_;
+
+    my %cmf ;
+    $cmf{file_rule} = "SOURCES";
+    $cmf{name} = "$path_base.cmf";
+    push @$file_list, \%cmf;
+
+    my %log;
+    $log{file_rule} = "LOG";
+    $log{name} = "$path_base.log";
+    push @$file_list, \%log;
+
+    return $file_list;
+}
+
 sub my_die
 {
Index: trunk/ippTasks/staticsky.pro
===================================================================
--- trunk/ippTasks/staticsky.pro	(revision 36553)
+++ trunk/ippTasks/staticsky.pro	(revision 36555)
@@ -64,4 +64,17 @@
 end
 
+$RA_POLL_MAX = 0
+
+macro set.ra.max
+    if ($0 != 2) 
+        echo "USAGE: set.ra.max (ra_max_deg)"
+        break
+    end
+    $RA_POLL_MAX = $1
+end
+macro get.ra.max
+    echo $RA_POLL_MAX
+end
+
 ### Load tasks for staticsky
 ### Tasks are loaded into staticskyResult.
@@ -80,4 +93,7 @@
     if ($LABEL:n == 0) break
     $run = staticskytool -todo
+    if ($RA_POLL_MAX > 0) 
+        $run = $run -ra_max $RA_POLL_MAX
+    end
     if ($DB:n == 0)
       option DEFAULT
Index: trunk/ippTools/share/Makefile.am
===================================================================
--- trunk/ippTools/share/Makefile.am	(revision 36553)
+++ trunk/ippTools/share/Makefile.am	(revision 36555)
@@ -190,4 +190,5 @@
 	disttool_definebyquery_diff.sql \
 	disttool_definebyquery_fake.sql \
+	disttool_definebyquery_ff.sql \
 	disttool_definebyquery_raw.sql \
 	disttool_definebyquery_raw_no_magic.sql \
@@ -207,4 +208,5 @@
 	disttool_pending_diff.sql \
 	disttool_pending_fake.sql \
+	disttool_pending_ff.sql \
 	disttool_pending_raw.sql \
 	disttool_pending_sky.sql \
@@ -498,4 +500,8 @@
 	fftool_todo.sql \
 	fftool_toadvance.sql \
+	fftool_export_run.sql \
+	fftool_export_input.sql \
+	fftool_export_result.sql \
+	fftool_export_summary.sql \
 	remotetool_definebyquery_chip.sql \
 	remotetool_definebyquery_cam.sql \
@@ -503,5 +509,2 @@
 	remotetool_definebyquery_stack.sql \
 	remotetool_updatepoll.sql
-
-
-
Index: trunk/ippTools/share/disttool_definebyquery_ff.sql
===================================================================
--- trunk/ippTools/share/disttool_definebyquery_ff.sql	(revision 36555)
+++ trunk/ippTools/share/disttool_definebyquery_ff.sql	(revision 36555)
@@ -0,0 +1,27 @@
+SELECT DISTINCT
+    'ff' as stage,
+    fullForceRun.ff_id AS stage_id,
+    CAST(0 AS SIGNED) AS magicked,
+    -- run tag in the form 'ff.$skycell_id.$ff_id'
+    CONCAT_WS('.', 'ff', stackRun.skycell_id, convert(fullForceRun.ff_id, CHAR)) as run_tag,
+    fullForceRun.label,
+    fullForceRun.data_group,
+    distTarget.dist_group,
+    distTarget.target_id,
+    distTarget.clean
+FROM fullForceRun
+JOIN skycalRun USING(skycal_id)
+JOIN stackRun using(stack_id)
+JOIN distTarget ON distTarget.stage = 'ff'
+    AND fullForceRun.dist_group = distTarget.dist_group
+JOIN rcInterest USING(target_id)
+LEFT JOIN distRun ON (distRun.stage_id = ff_id)
+    AND distRun.target_id = distTarget.target_id
+    -- JOIN hook %s
+WHERE  distTarget.state = 'enabled'
+    AND rcInterest.state = 'enabled'
+    AND distRun.dist_id IS NULL
+    AND fullForceRun.state = 'full'
+    AND stackRun.filter = distTarget.filter
+    -- we shouldn't need to check fault. If faulted it shouldn't be full
+    -- AND (skycalResult.fault = 0 AND skycalResult.quality = 0)
Index: trunk/ippTools/share/disttool_pending_ff.sql
===================================================================
--- trunk/ippTools/share/disttool_pending_ff.sql	(revision 36555)
+++ trunk/ippTools/share/disttool_pending_ff.sql	(revision 36555)
@@ -0,0 +1,86 @@
+-- look for fullForceResult components and a summary components
+SELECT * FROM
+(
+SELECT
+    distRun.dist_id,
+    distRun.label,
+    distTarget.dist_group,
+    stage,
+    stage_id,
+    CONCAT_WS('.', warp_id, stackRun.skycell_id) AS component,
+    exp_type,
+    clean,
+    rawExp.camera,
+    CONCAT_WS('.', outroot, CONVERT(distRun.dist_id, CHAR)) as outdir,
+    fullForceResult.path_base,
+    CAST(NULL AS CHAR(255)) as chip_path_base,
+    fullForceRun.state,
+    'full' AS data_state,
+    fullForceResult.quality,
+    distRun.no_magic,
+    warpRun.magicked,
+    IFNULL(Label.priority, 10000) AS priority
+FROM distRun
+JOIN distTarget USING(target_id, stage, clean)
+JOIN fullForceRun ON stage_id = ff_id
+JOIN skycalRun USING(skycal_id)
+JOIN stackRun USING(stack_id)
+JOIN fullForceResult USING(ff_id)
+JOIN warpRun USING(warp_id)
+JOIN fakeRun USING(fake_id)
+JOIN camRun USING(cam_id)
+JOIN chipRun ON camRun.chip_id = chipRun.chip_id
+JOIN rawExp using(exp_id)
+LEFT JOIN distComponent 
+    ON distRun.dist_id = distComponent.dist_id 
+    AND CONCAT_WS('.', warp_id, stackRun.skycell_id) = distComponent.component
+LEFT JOIN Label ON distRun.label = Label.label
+WHERE
+    distRun.state = 'new'
+    AND distRun.stage = 'ff'
+    AND distComponent.dist_id IS NULL
+    AND (Label.active OR Label.active IS NULL)
+UNION
+SELECT DISTINCT
+    distRun.dist_id,
+    distRun.label,
+    distTarget.dist_group,
+    stage,
+    stage_id,
+    'summary' AS component,
+    exp_type,
+    clean,
+    rawExp.camera,
+    CONCAT_WS('.', outroot, CONVERT(distRun.dist_id, CHAR)) as outdir,
+    fullForceSummary.path_base,
+    CAST(NULL AS CHAR(255)) as chip_path_base,
+    fullForceRun.state,
+    'full' AS data_state,
+    fullForceSummary.quality,
+    distRun.no_magic,
+    0 AS magicked,
+    IFNULL(Label.priority, 10000) AS priority
+FROM distRun
+JOIN distTarget USING(target_id, stage, clean)
+JOIN fullForceRun ON stage_id = ff_id
+JOIN fullForceSummary USING(ff_id)
+JOIN skycalRun USING(skycal_id)
+JOIN stackRun USING(stack_id)
+JOIN stackInputSkyfile USING(stack_id)
+JOIN warpRun USING(warp_id)
+JOIN fakeRun USING(fake_id)
+JOIN camRun USING(cam_id)
+JOIN chipRun ON camRun.chip_id = chipRun.chip_id
+JOIN rawExp using(exp_id)
+LEFT JOIN distComponent 
+    ON distRun.dist_id = distComponent.dist_id 
+    AND 'summary' = distComponent.component
+LEFT JOIN Label ON distRun.label = Label.label
+WHERE
+    distRun.state = 'new'
+    AND distRun.stage = 'ff'
+    AND distComponent.dist_id IS NULL
+    AND (Label.active OR Label.active IS NULL)
+) as distRun
+-- where arguments are appended here
+WHERE 1
Index: trunk/ippTools/share/disttool_toadvance.sql
===================================================================
--- trunk/ippTools/share/disttool_toadvance.sql	(revision 36553)
+++ trunk/ippTools/share/disttool_toadvance.sql	(revision 36555)
@@ -308,3 +308,33 @@
         COUNT(diffSkyfile.skycell_id) = COUNT(distComponent.component)
         AND SUM(distComponent.fault) = 0
+UNION
+-- ff stage
+SELECT
+    distRun.dist_id,
+    stage,
+    stage_id,
+    outroot,
+    distRun.label,
+    clean
+    -- ,COUNT(warp_id)
+    -- ,COUNT(ff_id)
+    FROM distRun
+    JOIN fullForceRun ON stage_id = ff_id
+    JOIN fullForceResult USING(ff_id)
+    JOIN skycalRun USING(skycal_id)
+    JOIN stackRun USING(stack_id)
+    LEFT JOIN distComponent
+        ON distRun.dist_id = distComponent.dist_id
+        AND distComponent.component = CONCAT_WS('.', warp_id, stackRun.skycell_id) 
+    WHERE
+        distRun.state = 'new'
+        AND distRun.fault = 0
+        AND distRun.stage = 'ff'
+    GROUP BY
+        distRun.dist_id,
+        ff_id
+    HAVING
+        -- number of dist components is the number of warps plus 1 (for the summary component)
+        COUNT(fullForceResult.ff_id) = COUNT(distComponent.component)
+        AND SUM(distComponent.fault) = 0
 ) as Foo
Index: trunk/ippTools/share/fftool_export_input.sql
===================================================================
--- trunk/ippTools/share/fftool_export_input.sql	(revision 36555)
+++ trunk/ippTools/share/fftool_export_input.sql	(revision 36555)
@@ -0,0 +1,3 @@
+SELECT
+    fullForceInput.*
+FROM fullForceInput
Index: trunk/ippTools/share/fftool_export_result.sql
===================================================================
--- trunk/ippTools/share/fftool_export_result.sql	(revision 36555)
+++ trunk/ippTools/share/fftool_export_result.sql	(revision 36555)
@@ -0,0 +1,3 @@
+SELECT
+    fullForceResult.*
+FROM fullForceResult
Index: trunk/ippTools/share/fftool_export_run.sql
===================================================================
--- trunk/ippTools/share/fftool_export_run.sql	(revision 36555)
+++ trunk/ippTools/share/fftool_export_run.sql	(revision 36555)
@@ -0,0 +1,3 @@
+SELECT
+    fullForceRun.*
+FROM fullForceRun
Index: trunk/ippTools/share/fftool_export_summary.sql
===================================================================
--- trunk/ippTools/share/fftool_export_summary.sql	(revision 36555)
+++ trunk/ippTools/share/fftool_export_summary.sql	(revision 36555)
@@ -0,0 +1,3 @@
+SELECT
+    fullForceSummary.*
+FROM fullForceSummary
Index: trunk/ippTools/share/fftool_result.sql
===================================================================
--- trunk/ippTools/share/fftool_result.sql	(revision 36553)
+++ trunk/ippTools/share/fftool_result.sql	(revision 36555)
@@ -1,7 +1,10 @@
 SELECT
     fullForceResult.*,
-    fullForceRun.skycal_id,
+    fullForceRun.state,
     fullForceRun.label,
     fullForceRun.data_group,
+    fullForceRun.skycal_id,
+    fullForceRun.workdir,
+    CONCAT_WS('.', warp_id, skycell_id) AS dist_component,
     stackRun.tess_id,
     stackRun.skycell_id,
Index: trunk/ippTools/share/fftool_summary.sql
===================================================================
--- trunk/ippTools/share/fftool_summary.sql	(revision 36553)
+++ trunk/ippTools/share/fftool_summary.sql	(revision 36555)
@@ -5,4 +5,6 @@
     fullForceRun.data_group,
     fullForceRun.skycal_id,
+    fullForceRun.workdir,
+    'summary' AS dist_component,
     stackRun.tess_id,
     stackRun.skycell_id,
Index: trunk/ippTools/src/disttool.c
===================================================================
--- trunk/ippTools/src/disttool.c	(revision 36553)
+++ trunk/ippTools/src/disttool.c	(revision 36555)
@@ -413,4 +413,21 @@
 
       magic = false;
+    } else if (!strcmp(stage, "ff")) {
+      runJoinStr = "fullForceRun.ff_id";
+      query = pxDataGet("disttool_definebyquery_ff.sql");
+      if (!query) {
+        psError(PXTOOLS_ERR_SYS, false, "failed to retrieve SQL statement");
+        psFree(where);
+        return(false);
+      }
+
+      if (label) {
+        psStringAppend(&query, " AND (fullForceRun.label = '%s') ", label);
+      }
+      if (dist_group) {
+        psStringAppend(&query, " AND (fullForceRun.dist_group = '%s') ", dist_group);
+      }
+
+      magic = false;
     } else {
         psError(PS_ERR_UNKNOWN, true, "unknown value for stage: %s", stage);
Index: trunk/ippTools/src/fftool.c
===================================================================
--- trunk/ippTools/src/fftool.c	(revision 36553)
+++ trunk/ippTools/src/fftool.c	(revision 36555)
@@ -44,4 +44,7 @@
 static bool updatesummaryMode(pxConfig *config);
 static bool summaryMode(pxConfig *config);
+static bool exportrunMode(pxConfig *config);
+static bool importrunMode(pxConfig *config);
+static bool summaryMode(pxConfig *config);
 
 static bool setfullForceRunState(pxConfig *config, psS64 sky_id, const char *state);
@@ -77,4 +80,6 @@
         MODECASE(FFTOOL_MODE_UPDATESUMMARY,     updatesummaryMode);
         MODECASE(FFTOOL_MODE_SUMMARY,           summaryMode);
+        MODECASE(FFTOOL_MODE_EXPORTRUN,         exportrunMode);
+        MODECASE(FFTOOL_MODE_IMPORTRUN,         importrunMode);
         default:
             psAbort("invalid option (this should not happen)");
@@ -134,7 +139,7 @@
 
     psMetadata *warpWhereMD = psMetadataAlloc();
-    pxAddLabelSearchArgs(config, warpWhereMD, "-select_warp_label",     "warpRun.label",           "LIKE");
-    pxAddLabelSearchArgs(config, warpWhereMD, "-select_warp_data_group","warpRun.data_group",      "LIKE");
-    PXOPT_COPY_S64(config->args, warpWhereMD, "-select_warp_id",        "warpRun.warp_id",         "==");
+    pxAddLabelSearchArgs(config, warpWhereMD, "-select_warp_label",     "fullForceRun.label",           "LIKE");
+    pxAddLabelSearchArgs(config, warpWhereMD, "-select_warp_data_group","fullForceRun.data_group",      "LIKE");
+    PXOPT_COPY_S64(config->args, warpWhereMD, "-select_warp_id",        "fullForceRun.warp_id",         "==");
     if (!psListLength(warpWhereMD->list)) {
         psError(PXTOOLS_ERR_CONFIG, false, "warp search parameters are required");
@@ -150,6 +155,6 @@
     }
 
-    PXOPT_COPY_STR(config->args, warpWhereMD, "-select_tess_id",       "warpRun.tess_id",         "==");
-    pxAddLabelSearchArgs(config, warpWhereMD, "-select_filter",        "warpRun.filter",          "LIKE");
+    PXOPT_COPY_STR(config->args, warpWhereMD, "-select_tess_id",       "fullForceRun.tess_id",         "==");
+    pxAddLabelSearchArgs(config, warpWhereMD, "-select_filter",        "fullForceRun.filter",          "LIKE");
     if (!pxskycellAddWhere(config, warpWhereMD)) {
         psError(PXTOOLS_ERR_CONFIG, false, "failed to add skycell search arguments");
@@ -504,4 +509,5 @@
     PXOPT_COPY_STR(config->args, where, "-tess_id",    "stackRun.tess_id", "LIKE");
     PXOPT_COPY_STR(config->args, where, "-skycell_id", "stackRun.skycell_id", "LIKE");
+    PXOPT_COPY_STR(config->args, where, "-filter",      "stackRun.filter", "LIKE");
     PXOPT_COPY_S16(config->args, where, "-fault",      "staticskyResult.fault", "==");
     pxskycellAddWhere(config, where);
@@ -864,4 +870,5 @@
     PXOPT_COPY_STR(config->args, where, "-tess_id",    "stackRun.tess_id", "LIKE");
     PXOPT_COPY_STR(config->args, where, "-skycell_id", "stackRun.skycell_id", "LIKE");
+    PXOPT_COPY_STR(config->args, where, "-filter",     "stackRun.filter", "LIKE");
     PXOPT_COPY_S16(config->args, where, "-fault",      "staticskyResult.fault", "==");
     pxskycellAddWhere(config, where);
@@ -933,2 +940,176 @@
     return true;
 }
+
+bool exportrunMode(pxConfig *config)
+{
+  typedef struct ExportTable {
+    char tableName[80];
+    char sqlFilename[80];
+  } ExportTable;
+
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    // PXOPT_LOOKUP_S64(det_id,  config->args, "-warp_id", true,  false);
+    PXOPT_LOOKUP_STR(outfile, config->args, "-outfile", true,  false);
+    PXOPT_LOOKUP_U64(limit,   config->args, "-limit",   false, false);
+//    PXOPT_LOOKUP_BOOL(clean,  config->args, "-clean", false);
+
+    FILE *f = fopen (outfile, "w");
+    if (f == NULL) {
+        psError(PS_ERR_UNKNOWN, false, "failed to open output file");
+        return false;
+    }
+
+    if (!pxExportVersion(config, f)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to write dbversion output file");
+        return false;
+    }
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-ff_id", "ff_id", "==");
+
+    ExportTable tables [] = {
+      {"fullForceRun", "fftool_export_run.sql"},
+      {"fullForceInput", "fftool_export_input.sql"},
+      {"fullForceResult", "fftool_export_result.sql"},
+      {"fullForceSummary", "fftool_export_summary.sql"},
+    };
+
+    int numTables = sizeof(tables)/sizeof(tables[0]);
+
+    for (int i=0; i < numTables; i++) {
+      psString query = pxDataGet(tables[i].sqlFilename);
+      if (!query) {
+          psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
+          return false;
+      }
+
+      if (where && psListLength(where->list)) {
+          psString whereClause = psDBGenerateWhereSQL(where, NULL);
+          psStringAppend(&query, " %s", whereClause);
+          psFree(whereClause);
+      }
+
+      // 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)) {
+        psError(PS_ERR_UNKNOWN, true, "no rows found");
+        psFree(output);
+        return false;
+      }
+
+      // we must write the export table in non-simple (true) format
+      if (!ippdbPrintMetadatas(f, output, tables[i].tableName, true)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+      }
+      psFree(output);
+    }
+
+    fclose (f);
+
+    return true;
+}
+
+bool importrunMode(pxConfig *config)
+{
+  unsigned int nFail;
+
+  int numImportTables = 3;
+
+  char tables[3] [80] = {"fullForceInput", "fullForceResult", "fullForceSummary"};
+
+  PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+  PXOPT_LOOKUP_STR(infile, config->args, "-infile", true,  false);
+
+  psMetadata *input = psMetadataConfigRead (NULL, &nFail, infile, false);
+
+#ifdef notdef
+  fprintf (stderr, "---- input ----\n");
+  psMetadataPrint (stderr, input, 1);
+#endif
+
+  if (!pxCheckImportVersion(config, input)) {
+      psError(PS_ERR_UNKNOWN, false, "pxCheckImportVersion failed");
+      return false;
+  }
+
+  psMetadataItem *item = psMetadataLookup (input, "fullForceRun");
+  psAssert (item, "entry not in input?");
+  psAssert (item->type == PS_DATA_METADATA_MULTI, "entry not multi?");
+
+  psMetadataItem *entry = psListGet (item->data.list, 0);
+  assert (entry);
+  assert (entry->type == PS_DATA_METADATA);
+  fullForceRunRow *fullForceRun = fullForceRunObjectFromMetadata (entry->data.md);
+  fullForceRunInsertObject (config->dbh, fullForceRun);
+
+  // fprintf (stdout, "---- warp run ----\n");
+  // psMetadataPrint (stderr, entry->data.md, 1);
+
+  for (int i = 0; i < numImportTables; i++) {
+    item = psMetadataLookup (input, tables[i]);
+    psAssert (item, "entry not in input?");
+    psAssert (item->type == PS_DATA_METADATA_MULTI, "entry not multi?");
+
+    switch (i) {
+      case 0:
+        for (int i = 0; i < item->data.list->n; i++) {
+          entry = psListGet (item->data.list, i);
+          assert (entry);
+          assert (entry->type == PS_DATA_METADATA);
+          fullForceInputRow *fullForceInput = fullForceInputObjectFromMetadata (entry->data.md);
+          fullForceInputInsertObject (config->dbh, fullForceInput);
+
+          // fprintf (stdout, "---- row %d ----\n", i);
+          // psMetadataPrint (stderr, entry->data.md, 1);
+        }
+        break;
+
+      case 1:
+        for (int i = 0; i < item->data.list->n; i++) {
+          entry = psListGet (item->data.list, i);
+          assert (entry);
+          assert (entry->type == PS_DATA_METADATA);
+          fullForceResultRow *fullForceResult = fullForceResultObjectFromMetadata (entry->data.md);
+          fullForceResultInsertObject (config->dbh, fullForceResult);
+
+          // fprintf (stdout, "---- row %d ----\n", i);
+          // psMetadataPrint (stderr, entry->data.md, 1);
+        }
+        break;
+
+      case 2:
+        for (int i = 0; i < item->data.list->n; i++) {
+          entry = psListGet (item->data.list, i);
+          assert (entry);
+          assert (entry->type == PS_DATA_METADATA);
+          fullForceSummaryRow *fullForceSummary = fullForceSummaryObjectFromMetadata (entry->data.md);
+          fullForceSummaryInsertObject (config->dbh, fullForceSummary);
+
+          // fprintf (stdout, "---- row %d ----\n", i);
+          // psMetadataPrint (stderr, entry->data.md, 1);
+        }
+        break;
+    }
+  }
+  return true;
+}
Index: trunk/ippTools/src/fftool.h
===================================================================
--- trunk/ippTools/src/fftool.h	(revision 36553)
+++ trunk/ippTools/src/fftool.h	(revision 36555)
@@ -36,5 +36,7 @@
     FFTOOL_MODE_REVERTSUMMARY,
     FFTOOL_MODE_UPDATESUMMARY,
-    FFTOOL_MODE_SUMMARY
+    FFTOOL_MODE_SUMMARY,
+    FFTOOL_MODE_EXPORTRUN,
+    FFTOOL_MODE_IMPORTRUN,
 } fftoolMode;
 
Index: trunk/ippTools/src/fftoolConfig.c
===================================================================
--- trunk/ippTools/src/fftoolConfig.c	(revision 36553)
+++ trunk/ippTools/src/fftoolConfig.c	(revision 36555)
@@ -186,4 +186,17 @@
     pxskycellAddArguments(revertsummaryArgs);
 
+    // -exportrun
+    psMetadata *exportrunArgs = psMetadataAlloc();
+    psMetadataAddS64(exportrunArgs, PS_LIST_TAIL, "-ff_id", 0,          "export this full force ID (required)", 0);
+    psMetadataAddStr(exportrunArgs, PS_LIST_TAIL, "-outfile", 0,          "export to this file (required)", NULL);
+    psMetadataAddU64(exportrunArgs, PS_LIST_TAIL, "-limit",   0,          "limit result set to N items", 0);
+//    psMetadataAddBool(exportrunArgs, PS_LIST_TAIL, "-clean",  0,          "export run in cleaned state", false);
+
+    // -importrun
+    psMetadata *importrunArgs = psMetadataAlloc();
+    psMetadataAddStr(importrunArgs, PS_LIST_TAIL, "-infile",  0,          "import from this file (required)", NULL);
+
+
+
     psFree(now);
 
@@ -203,4 +216,6 @@
     PXOPT_ADD_MODE("-revertsummary", "revert faulted summary", FFTOOL_MODE_REVERTSUMMARY,  revertsummaryArgs);
     PXOPT_ADD_MODE("-summary",       "list summary results", FFTOOL_MODE_SUMMARY,  summaryArgs);
+    PXOPT_ADD_MODE("-exportrun",     "list summary results", FFTOOL_MODE_EXPORTRUN,  exportrunArgs);
+    PXOPT_ADD_MODE("-importrun",     "list summary results", FFTOOL_MODE_IMPORTRUN,  importrunArgs);
 
     if (!pxGetOptions(stderr, argc, argv, config, modes, argSets)) {
Index: trunk/ippTools/src/laptool.c
===================================================================
--- trunk/ippTools/src/laptool.c	(revision 36553)
+++ trunk/ippTools/src/laptool.c	(revision 36555)
@@ -1170,5 +1170,7 @@
   // we only want projection cells which do not already of an entry
   psStringAppend(&query, "\nWHERE lapGroup.projection_cell IS NULL\n");
-  psStringAppend(&query, "\nORDER by projection_cell\n");
+  // Projection cell's don't have a convienient order. Queue runs in the order of lap_id
+  // psStringAppend(&query, "\nORDER by projection_cell\n");
+  psStringAppend(&query, "\nORDER by lap_id_0\n");
 
   if (limit) {
@@ -1289,4 +1291,5 @@
     psFree(whereClause);
   }
+  psStringAppend(&query, "\nGROUP by projection_cell ORDER by MIN(lap_id)");
   if (limit) {
     psString limitString = psDBGenerateLimitSQL(limit);
Index: trunk/psphot/src/psphotCleanup.c
===================================================================
--- trunk/psphot/src/psphotCleanup.c	(revision 36553)
+++ trunk/psphot/src/psphotCleanup.c	(revision 36555)
@@ -22,6 +22,9 @@
     pmVisualCleanup ();
     psLibFinalize();
+#if (PS_TRACE_ON)
+    // don't display memory leaks unless trace is on. 
     // fprintf (stderr, "found %d leaks at %s\n", psMemCheckLeaks (0, NULL, NULL, false), "psphot");
     fprintf (stderr, "found %d leaks at %s\n", psMemCheckLeaks (0, NULL, stdout, false), "psphot");
+#endif
     return;
 }
