Index: /trunk/ippToPsps/perl/ippToPsps/DetectionBatch.pm
===================================================================
--- /trunk/ippToPsps/perl/ippToPsps/DetectionBatch.pm	(revision 29235)
+++ /trunk/ippToPsps/perl/ippToPsps/DetectionBatch.pm	(revision 29236)
@@ -82,4 +82,5 @@
     # get real filename from neb 'key'
     my $fpaObjects = $self->{_ipprc}->filename("PSASTRO.OUTPUT",$nebPath) or return undef;
+
     return $self->{_ipprc}->file_resolve($fpaObjects);
 }
Index: /trunk/ippToPsps/perl/ippToPsps/StackBatch.pm
===================================================================
--- /trunk/ippToPsps/perl/ippToPsps/StackBatch.pm	(revision 29236)
+++ /trunk/ippToPsps/perl/ippToPsps/StackBatch.pm	(revision 29236)
@@ -0,0 +1,130 @@
+#!/usr/bin/perl -w
+
+package ippToPsps::StackBatch;
+
+use warnings;
+use strict;
+use File::Basename;
+use File::Temp qw(tempfile);
+use XML::LibXML;
+
+use ippToPsps::Batch;
+our @ISA = qw(ippToPsps::Batch);    # inherits from Batch class
+
+
+###########################################################################
+#
+# Constructor (overrides superclass)
+#
+###########################################################################
+sub existing {
+    my ($class) = @_;
+
+    # Call the constructor of the parent class
+    my $self = $class->SUPER::existing(
+            $_[1],  # camera
+            $_[2],  # gpc1Db
+            $_[3],  # batchId
+            $_[4],  # ippToPspsDb
+            $_[5],  # path
+            $_[6],  # verbose
+            $_[7]   # save_temps
+            );
+
+    bless $self, $class;
+    return $self;
+}
+
+
+###########################################################################
+#
+# Constructor (overrides superclass)
+#
+###########################################################################
+sub new {
+    my ($class) = @_;
+
+    # Call the constructor of the parent class
+    my $self = $class->SUPER::create(
+            "ST",   # type 
+            $_[2],  # camera
+            $_[3],  # gpc1Db
+            $_[4],  # ippToPspsDb
+            $_[5],  # path
+            $_[6],  # datastore
+            0,  # expId
+            "NULL",  # expName
+            $_[7],  # dvoDb
+            $_[8],  # dvoPath
+            "NULL", # distGroup
+            $_[9], # dontTarBall
+            $_[10], # verbose
+            $_[11]  # save_temps
+            );
+
+
+    $self->{_skyId} = $_[1]; 
+
+    bless $self, $class;
+    $self->process();
+    return $self;
+}
+
+#######################################################################################
+# 
+# Locates the relevant smf file for this exposure and writes the path to the file passed-in
+#
+#######################################################################################
+sub createInputFileList {
+    my ($self, $inputFile) = @_;
+
+    my ($nebPath, $numInputs);
+    if (!$self->{_gpc1Db}->getStackStageCmfs($self->{_skyId}, \$nebPath, \$numInputs)){
+
+        print "* No cmf files found for this skyId ($self->{_skyId})\n"; 
+        return 0;
+    }
+    # loop round all cmf files
+    my $i;
+    for ($i = 0; $i<$numInputs; $i++) {
+
+        # get real filename from neb 'key' TODO neater exit
+        my $fpaObjects = $self->{_ipprc}->filename("PSPHOT.STACK.OUTPUT",$nebPath, $i) or last;
+        my $cmf = $self->{_ipprc}->file_resolve($fpaObjects) or return 0;
+
+        print $inputFile $cmf . "\n";
+    }
+
+    return 1;
+}
+
+#######################################################################################
+#
+# - Reads results from processing (min/max obj ID etc)
+# - writes to Db
+# - writes manifest file
+#
+#######################################################################################
+sub parseResults {
+    my ($self, $resultsFilePath) = @_;
+
+    my($filename, $minObjId, $maxObjId, $totalDetections);
+
+    # read results of FITS creation from XML file
+    my $parser = XML::LibXML->new;
+    my $doc = $parser->parse_file($resultsFilePath);
+    $filename = $doc->findvalue('//filename');
+    $minObjId = $doc->findvalue('//minObjID');
+    $maxObjId = $doc->findvalue('//maxObjID');
+    $totalDetections = $doc->findvalue('//totalDetections');
+
+    # write results to database
+    $self->{_ippToPspsDb}->setAsProcessed($self->{_batchId}, $self->{_expId}, $totalDetections, $minObjId, $maxObjId);
+
+    # write batch manifest
+    if (!$self->writeManifest($filename, $minObjId, $maxObjId)) {return 0;}
+
+    return 1;
+}
+1;
+
Index: /trunk/ippToPsps/perl/makeStacks.pl
===================================================================
--- /trunk/ippToPsps/perl/makeStacks.pl	(revision 29236)
+++ /trunk/ippToPsps/perl/makeStacks.pl	(revision 29236)
@@ -0,0 +1,105 @@
+#!/usr/bin/env perl
+
+use warnings;
+use strict;
+
+use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt );
+use File::Basename;
+
+# local classes
+use ippToPsps::Gpc1Db;
+use ippToPsps::IppToPspsDb;
+use ippToPsps::Datastore;
+use ippToPsps::StackBatch;
+
+# globals
+my $camera = undef;
+my $dvoDb = undef;
+my $dvoPath = undef;
+my $verbose = undef;
+my $save_temps = undef; 
+my $output = undef;
+my $datastoreProduct = undef;
+my $force = undef;
+my $dontTarball = undef;
+my $datastore = undef;
+
+# get user args
+GetOptions(
+        'camera|c' => \$camera,
+        'output|o=s' => \$output,
+        'dvodb|d=s' => \$dvoDb,
+        'dvolocation|l=s' => \$dvoPath,
+        'product|p=s' => \$datastoreProduct,
+        'verbose|v' => \$verbose,
+        'save_temps|t' => \$save_temps,
+        'force|f' => \$force,
+        'tarnzip|z' => \$dontTarball,
+        );
+
+my $quit = 0;
+print "\n*******************************************************************************\n";
+print "* \n";
+if (@ARGV) {
+    $quit=1;
+    print "* UNKNKOWN: option                          @ARGV\n";
+}
+if (!defined $output) {
+    $quit=1;
+    print "* REQUIRED: need to provide an output path  -o <path>\n";
+}
+if (!defined $dvoDb) {
+    $quit=1;
+    print "* REQUIRED: need to provide a DVO Db        -d <dvoDb>\n";
+}
+if (!defined $dvoPath) {
+    $quit=1;
+    print "* REQUIRED: need to provide a DVO location  -l <dvoLocation>\n";
+}
+if (!defined $camera) {
+    $camera = "GPC1";
+    print "* OPTIONAL: select a camera                 -c                   (default = $camera)\n";
+}
+if (!defined $datastoreProduct) {
+
+    print "* OPTIONAL: datastore product               -p <product>         (default = none, i.e. data will not be published)\n";
+}
+if (!defined $verbose) {
+    $verbose = 0;
+    print "* OPTIONAL: run in verbose mode             -v                   (default = $verbose)\n";
+}
+if (!defined $save_temps) {
+    $save_temps = 0;
+    print "* OPTIONAL: keep temp files                 -t                   (default = $save_temps)\n";
+}
+if (!defined $force) {
+    $force = 0;
+    print "* OPTIONAL: force if already processed      -f                   (default = $force)\n";
+}
+if (!defined $dontTarball) {
+    $dontTarball = 0;
+    print "* OPTIONAL: don't tar and zip output        -z                   (default = $dontTarball)\n";
+}
+print "*\n*******************************************************************************\n";
+
+if ($quit) { exit; }
+
+
+my $gpc1Db = new ippToPsps::Gpc1Db("gpc1", "ippdb01", "ippuser", "ippuser", $verbose, $save_temps);
+my $ippToPspsDb = new ippToPsps::IppToPspsDb("ippToPsps", "ippdb01", "ipp", "ipp", $verbose, $save_temps);
+if ($datastoreProduct) {$datastore = new ippToPsps::Datastore($datastoreProduct, $verbose, $save_temps);}
+
+
+my $stackBatch = new ippToPsps::StackBatch(
+        11, # sky_id
+        $camera, 
+        $gpc1Db, 
+        $ippToPspsDb, 
+        $output, 
+        $datastore, 
+        $dvoDb,
+        $dvoPath,
+        $dontTarball,
+        $verbose, 
+        $save_temps);
+
