diff --git a/.gitattributes b/.gitattributes
index c046c0903c09c46e62808f6659b2a510bbe35882..92787a485e7ffc08b07534f795ca728418b64653 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -2416,6 +2416,7 @@ LCU/checkhardware/lib/test_db.py -text
 LCU/checkhardware/lib/test_lib.py -text
 LCU/checkhardware/makeStationLogFile.py -text
 LCU/checkhardware/showTestResult.py -text
+LCU/checkhardware/updatePVSS.py -text
 MAC/APL/APLCommon/include/APL/APLCommon/AntennaField.h -text
 MAC/APL/APLCommon/src/AntennaField.cc -text
 MAC/APL/APLCommon/src/StartDaemon_Protocol.prot -text svneol=native#application/octet-stream
@@ -2429,6 +2430,8 @@ MAC/APL/APLCommon/test/tAntennaField.sh -text
 MAC/APL/APLCommon/test/tParentControl.cc -text
 MAC/APL/APLCommon/test/tParentControl.h -text
 MAC/APL/APLCommon/test/tParentControl.log_prop -text
+MAC/APL/Appl_Controller/src/forkexec.cc -text
+MAC/APL/Appl_Controller/src/forkexec.h -text
 MAC/APL/CASATools/include/CASATools/CasaConverter.h -text
 MAC/APL/CASATools/src/CasaConverter.cc -text
 MAC/APL/CASATools/test/tCasaConverter.cc -text
@@ -3268,6 +3271,7 @@ MAC/Navigator2/panels/objects/Hardware/TBB_MP.pnl -text
 MAC/Navigator2/panels/objects/Hardware/TBB_RSP.pnl -text
 MAC/Navigator2/panels/objects/Hardware/TBB_TP.pnl -text
 MAC/Navigator2/panels/objects/Hardware/TBB_flashImages.pnl -text
+MAC/Navigator2/panels/objects/Hardware/TBBmode_small.pnl -text
 MAC/Navigator2/panels/objects/Hardware/TBBoard.pnl -text
 MAC/Navigator2/panels/objects/Hardware/antennaBroken_Small.pnl -text
 MAC/Navigator2/panels/objects/Hardware/diskuse_small.pnl -text
@@ -4147,6 +4151,7 @@ SAS/OTDB/include/OTDB/DefaultTemplate.h -text
 SAS/OTDB/sql/assignProcessType_func.sql -text
 SAS/OTDB/sql/campaignAPI.sql -text
 SAS/OTDB/sql/create_rules.sql -text
+SAS/OTDB/sql/exportMetadata_func.sql -text
 SAS/OTDB/sql/exportResultTree_func.sql -text
 SAS/OTDB/sql/fresh_database -text
 SAS/OTDB/sql/fresh_sas001_database.sh -text
@@ -4164,6 +4169,7 @@ SAS/OTDB/sql/update_all_functions.sh -text svneol=unset#application/x-shellscrip
 SAS/OTDB/sql/upgradeOTDB.sql -text
 SAS/OTDB/src/DefaultTemplate.cc -text
 SAS/OTDB/test/tBrokenHardware.cc -text
+SAS/OTDB/test/tMetadata.cc -text
 SAS/OTDB/test/tQueryPIC.cc -text
 SDP/SPP/DSP[!!-~]BUILDER/myfilterbank.mdl -text
 SDP/SPP/MATLAB/gui2/gui_qt.fig -text svneol=unset#unset
diff --git a/CEP/DP3/DPPP/include/DPPP/StationAdder.h b/CEP/DP3/DPPP/include/DPPP/StationAdder.h
index 3cd95859eae663f27a826436276abb2a855a58b0..69c47ab4eab716c62e00d8a565c518a90239c9a5 100644
--- a/CEP/DP3/DPPP/include/DPPP/StationAdder.h
+++ b/CEP/DP3/DPPP/include/DPPP/StationAdder.h
@@ -1,4 +1,4 @@
-//# StationAdder.h: DPPP step class to add station to a superstation
+//# StationAdder.h: DPPP step class to add stations as a superstation
 //# Copyright (C) 2012
 //# ASTRON (Netherlands Institute for Radio Astronomy)
 //# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
@@ -25,7 +25,7 @@
 #define DPPP_STATIONADDER_H
 
 // @file
-// @brief DPPP step class to average in time and/or freq
+// @brief DPPP step class to add stations as a superstation
 
 #include <DPPP/DPInput.h>
 #include <DPPP/DPBuffer.h>
@@ -109,7 +109,8 @@ namespace LOFAR {
       vector<casa::Vector<int> > itsParts;  // the stations in each superstation
       vector<vector<int> > itsBufRows; // old baseline rows in each new baseline
       uint            itsMinNPoint  ;  // flag data if too few unflagged data
-      bool            itsMakeAutoCorr; // also form new autocorrelations?
+      bool            itsMakeAutoCorr; // also form new auto-correlations?
+      bool            itsSumAutoCorr;  // sum auto- or cross-correlations?
       bool            itsUseWeight;    // false = use weight 1 per station
       UVWCalculator   itsUVWCalc;
       NSTimer         itsTimer;
diff --git a/CEP/DP3/DPPP/src/StationAdder.cc b/CEP/DP3/DPPP/src/StationAdder.cc
index 1f6768bd5ac613488315620e3d7865763887c473..f4269c5279d6243c4a57f1d1eae6c980a6b6a3b7 100644
--- a/CEP/DP3/DPPP/src/StationAdder.cc
+++ b/CEP/DP3/DPPP/src/StationAdder.cc
@@ -1,4 +1,4 @@
-//# StationAdder.cc: DPPP step class to add station to a superstation
+//# StationAdder.cc: DPPP step class to add stations as a superstation
 //# Copyright (C) 2012
 //# ASTRON (Netherlands Institute for Radio Astronomy)
 //# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
@@ -55,6 +55,7 @@ namespace LOFAR {
         itsStatRec      (parset.getRecord(prefix+"stations")),
         itsMinNPoint    (parset.getUint  (prefix+"minpoints", 1)),
         itsMakeAutoCorr (parset.getBool  (prefix+"autocorr", false)),
+        itsSumAutoCorr  (parset.getBool  (prefix+"sumauto", true)),
         itsUseWeight    (parset.getBool  (prefix+"useweights", true))
     {
     }
@@ -204,11 +205,10 @@ namespace LOFAR {
           int  take   = 0;
           if (havea1) {
             // If both stations are in same superstation, only use them
-            // if it is an autocorrelation.
+            // if autocorrelations have to be made.
+            // Taking auto or cross depends on summing mode.
             if (havea2) {
-              if (itsMakeAutoCorr  &&  ant1[i] == ant2[i]) {
-                take = 1;
-              }
+              take = itsMakeAutoCorr  &&  itsSumAutoCorr == (ant1[i]==ant2[i]);
             } else {
               ant  = ant2[i];
               take = -1;            // conjugate has to be added
diff --git a/CEP/DP3/DPPP/test/tStationAdder.cc b/CEP/DP3/DPPP/test/tStationAdder.cc
index 5b21004c8541b6ef0d3fb5b999cb2971d8481bc2..cd6013906701754f29c542c3a4b4667a733aaaea 100644
--- a/CEP/DP3/DPPP/test/tStationAdder.cc
+++ b/CEP/DP3/DPPP/test/tStationAdder.cc
@@ -41,7 +41,6 @@ using namespace std;
 
 // Simple class to generate input arrays.
 // It can only set all flags to true or all to false.
-// Weights are always 1.
 // It can be used with different nr of times, channels, etc.
 class TestInput: public DPInput
 {
@@ -141,9 +140,9 @@ private:
 class TestOutput: public DPStep
 {
 public:
-  TestOutput(int ntime, int nbl, int nchan, int ncorr)
+  TestOutput(int ntime, int nbl, int nchan, int ncorr, bool sumauto)
     : itsCount(0), itsNTime(ntime), itsNBl(nbl), itsNChan(nchan),
-      itsNCorr(ncorr)
+      itsNCorr(ncorr), itsSumAuto(sumauto)
   {}
 private:
   void addData (Cube<Complex>& to, const Cube<Complex>& from, int bl)
@@ -164,9 +163,26 @@ private:
     indgen (weights, 0.5f, 0.01f);
     Cube<Complex> databl0 (itsNCorr, itsNChan, 1);
     Cube<Complex> databl1 (itsNCorr, itsNChan, 1);
-    addData (databl0, data, 0);
-    addData (databl0, data, 5);
-    addData (databl0, data, 15);
+    // "{ns:[rs01.s01, rs02.s01, cs01.s02]}" was given resulting in 2 new
+    // baselines (ns-ns and cs01.s01-ns). 
+    // Thus adding the baselines below.
+    float weight=0;
+    if (itsSumAuto) {
+      // add autocorr to form new autocorr
+      addData (databl0, data, 0);
+      addData (databl0, data, 5);
+      addData (databl0, data, 15);
+      weight = 3;
+    } else {
+      // add crosscorr to form new autocorr
+      addData (databl0, data, 1);
+      addData (databl0, data, 3);
+      addData (databl0, data, 4);
+      addData (databl0, data, 7);
+      addData (databl0, data, 12);
+      addData (databl0, data, 13);
+      weight = 6;
+    }
     addData (databl1, data, 8);
     addData (databl1, data, 9);
     addData (databl1, data, 11);
@@ -191,7 +207,7 @@ private:
     // Now check data of new baselines.
     end[2] = itsNBl;
     ASSERT (allNear (buf.getData()(IPosition(3,0,0,itsNBl), end), databl0, 1e-5));
-    ASSERT (allNear (buf.getWeights()(IPosition(3,0,0,itsNBl), end), 3.f, 1e-5));
+    ASSERT (allNear (buf.getWeights()(IPosition(3,0,0,itsNBl), end), weight, 1e-5));
     end[2] = itsNBl+1;
     ASSERT (allNear (buf.getData()(IPosition(3,0,0,itsNBl+1), end), databl1, 1e-5));
     ASSERT (allNear (buf.getWeights()(IPosition(3,0,0,itsNBl+1), end), 6.f, 1e-5));
@@ -234,6 +250,7 @@ private:
 
   int itsCount;
   int itsNTime, itsNBl, itsNChan, itsNCorr, itsNAvgTime, itsNAvgChan;
+  bool itsSumAuto;
 };
 
 // Class to check result of flagged, unaveraged TestInput run by test2.
@@ -275,6 +292,7 @@ private:
     Cube<Float> weightbl2 (itsNCorr, itsNChan, 1, 0.);
     Cube<Float> weightbl3 (itsNCorr, itsNChan, 1, 0.);
     Cube<Float> weightbl4 (itsNCorr, itsNChan, 1, 0.);
+    // "{ns1:[rs01.s01, rs02.s01], ns2:[cs01.s02, cs01.s01]}" was given.
     addData (databl0, data, weightbl0, weights, 8);
     addData (databl0, data, weightbl0, weights, 9);
     addData (databl1, data, weightbl1, weights, 12);
@@ -376,10 +394,10 @@ void execute (const DPStep::ShPtr& step1)
 }
 
 // Test adding 3 stations.
-void test1(int ntime, int nbl, int nchan, int ncorr)
+void test1(int ntime, int nbl, int nchan, int ncorr, bool sumauto)
 {
   cout << "test1: ntime=" << ntime << " nrbl=" << nbl << " nchan=" << nchan
-       << " ncorr=" << ncorr << endl;
+       << " ncorr=" << ncorr << " sumauto=" << sumauto << endl;
   // Create the steps.
   TestInput* in = new TestInput(ntime, nbl, nchan, ncorr);
   DPStep::ShPtr step1(in);
@@ -387,9 +405,12 @@ void test1(int ntime, int nbl, int nchan, int ncorr)
   parset.add ("stations",
               "{ns:[rs01.s01, rs02.s01, cs01.s02]}");
   parset.add ("autocorr", "true");
+  if (!sumauto) {
+    parset.add ("sumauto", "false");
+  }
   parset.add ("useweights", "false");
   DPStep::ShPtr step2(new StationAdder(in, parset, ""));
-  DPStep::ShPtr step3(new TestOutput(ntime, nbl, nchan, ncorr));
+  DPStep::ShPtr step3(new TestOutput(ntime, nbl, nchan, ncorr, sumauto));
   step1->setNextStep (step2);
   step2->setNextStep (step3);
   execute (step1);
@@ -462,7 +483,8 @@ int main()
     // Test the station selection patterns.
     testPatterns();
     // Test must be done with with 16 baselines.
-    test1( 10,  16, 32, 4);
+    test1( 10,  16, 32, 4, true);
+    test1( 10,  16, 32, 4, false);
     test2( 10,  16, 32, 4);
     // Unknown station.
     test3("{ns1:rs01.s1, ns2:[cs01.s02, cs01.s01]}");
diff --git a/CEP/Pipeline/framework/lofarpipe/support/loggingdecorators.py b/CEP/Pipeline/framework/lofarpipe/support/loggingdecorators.py
index 6ade4aadcc3da2c20d429dde4f6228d04911e527..4bca87d98b6d39ae9dfc9f7926ab2aec52ebc14d 100644
--- a/CEP/Pipeline/framework/lofarpipe/support/loggingdecorators.py
+++ b/CEP/Pipeline/framework/lofarpipe/support/loggingdecorators.py
@@ -141,7 +141,8 @@ def mail_log_on_exception(target):
             # Static list of mail to be send (could be made configurable,
             # but yeah temp mail functionality so...)
             mail_list = ["klijn@astron.nl", "frieswijk@astron.nl",
-                         "pizzo@astron.nl", "orru@astron.nl"
+                         "pizzo@astron.nl", "orru@astron.nl",
+                         "jong@astron.nl"
                          ]
 
             # get the active stack
diff --git a/LCU/checkhardware/checkHardware.py b/LCU/checkhardware/checkHardware.py
index 1433941752c667b0653a9d2a2ed0fc4bdd1dab0a..7f4b90453314cbf94c8fe67e0ea796e2f73ba071 100755
--- a/LCU/checkhardware/checkHardware.py
+++ b/LCU/checkhardware/checkHardware.py
@@ -20,7 +20,7 @@ def printHelp():
     print "----------------------------------------------------------------------------"
     print "Usage of arguments"
     print "-c   : clean test (do not use last test results)"
-    print "-l 2 : set level too 2 (default level is 0)"
+    print "-l=2 : set level too 2 (default level is 0)"
     print "       level 0   : manual tests, use keys listed below"
     print "       level 1..n: see checkhardware.conf file for tests done"
     print 
@@ -44,22 +44,14 @@ args = dict()
 def getArguments():
     global args
     args['L'] = 0 # default test level
-    i = 1
-    while i < len(sys.argv):
+
+    for i in range(len(sys.argv)):
         if sys.argv[i][0] == '-':
-            opt = sys.argv[i][1:].upper()
-            if opt in ('T','L'): # for testing
-                optval = sys.argv[i+1].upper()
-                args[opt] = optval
-                i += 2
+            valpos = sys.argv[i].find('=')
+            if valpos != -1:
+                args[sys.argv[i][1:valpos].upper()] = int(sys.argv[i][valpos+1:])
             else:
-                valpos = opt.find('=')
-                if valpos != -1:
-                    args[opt[:valpos]] = int(opt[valpos+1:])
-                    #print opt[:valpos], opt[valpos+1:]
-                else:
-                    args[opt] = '-'
-                i += 1       
+                args[sys.argv[i][1:].upper()]='-'
 
 def setLevelTests(conf):
     global args
@@ -117,10 +109,9 @@ def main():
     
     # Read in RemoteStation.conf 
     ID, nRSP, nTBB, nLBL, nLBH, nHBA = readStationConfig()
-    print  ID, nRSP, nTBB, nLBL, nLBH, nHBA
    
     # setup intern database
-    db = cDB(StID, nRSP, nTBB, nLBL, nLBH, nHBA, clean=args.has_key('C'))
+    db = cDB(StID, nRSP, nTBB, nLBL, nLBH, nHBA)
     
     logger.info('== START OF HARDWARE CHECK ==', screen=True)
     logger.resetStartTime(screen=True)
diff --git a/LCU/checkhardware/doFullStationTest.sh b/LCU/checkhardware/doFullStationTest.sh
index 77e98c2df382ff2735fc82097744ae0f264acde7..cba66455c44af4240ce2090724e55842f5816e5f 100755
--- a/LCU/checkhardware/doFullStationTest.sh
+++ b/LCU/checkhardware/doFullStationTest.sh
@@ -5,7 +5,7 @@ logdir="/globalhome/log/"
 host=`hostname -s`
 
 # Check hardware in CheckLevel 2, do all tests
-checkHardware.py -l 2
+checkHardware.py -l=2
 
 # Add to history
 filenameFrom=$logdir$host"_StationTest.csv"
@@ -13,8 +13,7 @@ filenameToo=$logdir$host"_StationTestHistory.csv"
 cat $filenameFrom >> $filenameToo
 
 # Add test results too PVSS
-pvssFile=$logdir$host"_StationTest_PVSS.log"
-setObjectState $pvssFile
+updatePVSS.py
 
 # Make old station log files
 makeStationLogFile.py
diff --git a/LCU/checkhardware/doShortStationTest.sh b/LCU/checkhardware/doShortStationTest.sh
index c88823c2f2881e47b9a398003546c137c1924d3c..e0006a6292e45544befebf8a03dbd296b3911e04 100755
--- a/LCU/checkhardware/doShortStationTest.sh
+++ b/LCU/checkhardware/doShortStationTest.sh
@@ -5,7 +5,7 @@ logdir="/globalhome/log/"
 host=`hostname -s`
 
 # Check hardware in CheckLevel 1, only antennas
-checkHardware.py -l 1
+checkHardware.py -l=1
 
 # Add too history
 filenameFrom=$logdir$host"_StationTest.csv"
@@ -13,8 +13,7 @@ filenameToo=$logdir$host"_StationTestHistory.csv"
 cat $filenameFrom >> $filenameToo
 
 # Add test results too PVSS
-pvssFile=$logdir$host"_StationTest_PVSS.log"
-setObjectState lofarsys $pvssFile
+updatePVSS.py
 
 # Make old station log files
 makeStationLogFile.py
diff --git a/LCU/checkhardware/lib/test_db.py b/LCU/checkhardware/lib/test_db.py
index 3f0af3c8e71d576a7a38c9ce2e90b63586abb2f5..d29932a3c406ccf45ae234a3f3175ef3fcb8c1ef 100644
--- a/LCU/checkhardware/lib/test_db.py
+++ b/LCU/checkhardware/lib/test_db.py
@@ -3,11 +3,8 @@
 from general_lib import *
 from lofar_lib import *
 
-# PVSS states
-State = dict({'OFF':0, 'OPERATIONAL':1, 'MAINTENANCE':2, 'TEST':3, 'SUSPICIOUS':4, 'BROKEN':5})
-    
 class cDB:
-    def __init__(self, StID, nRSP, nTBB, nLBL, nLBH, nHBA, clean=False):
+    def __init__(self, StID, nRSP, nTBB, nLBL, nLBH, nHBA):
         self.StID   = StID
         self.nr_rsp = nRSP
         self.nr_rcu = nRSP * 8
@@ -39,42 +36,8 @@ class cDB:
         self.lbl = self.cLBA(label='LBL', nr_antennas=nLBL, nr_offset=48)
         self.lbh = self.cLBA(label='LBH', nr_antennas=nLBH)
         self.hba = self.cHBA(nr_tiles=nHBA)
-                
-        # try to read in from last test file LBL, LBH and HBA status
-        try:
-            if not clean:
-                print "Import latest log file"
-                f = open("%s_StationTest.csv" %(self.StID), 'r')
-                data = f.readlines()
-                f.close()
-                for line in data:
-                    d = line.split(',')
-                    if d[1] == 'LBL':
-                        if d[2] != '---':
-                            nr = int(d[2])
-                            msg = d[3].strip()
-                            if msg in ('DOWN', 'FAIL', 'LOW_NOISE', 'HIGH_NOISE'):
-                                self.lbl.ant[nr].last_state = State['BROKEN']
-                    elif d[1] == 'LBH':
-                        if d[2] != '---':
-                            nr = int(d[2])
-                            msg = d[3].strip()
-                            if msg in ('DOWN', 'FAIL', 'LOW_NOISE', 'HIGH_NOISE'):
-                                self.lbh.ant[nr].last_state = State['BROKEN']
-                    elif d[1] == 'HBA':
-                        if d[2] != '---':
-                            nr = int(d[2])
-                            msg = d[3].strip()
-                            if msg in ('FAIL', 'LOW_NOISE', 'HIGH_NOISE'):
-                                self.hba.tile[nr].las_state = State['BROKEN']
-                                for elem in hba.tile[nr].element:
-                                    nr = elem.nr
-                                    if line.find('M%d=' %(nr)) > 0 or line.find('X%d=' %(nr)) > 0 or line.find('Y%d=' %(nr)) > 0:
-                                        elem.last_state = State['BROKEN']
-        except:
-            pass
-            
     
+    # test
     def test(self, logdir):
         if self.rspdriver_version != "ok" or self.rspctl_version != "ok":
             self.station_error = 1
@@ -114,7 +77,6 @@ class cDB:
         self.station_error = max(self.station_error, self.lbl.test(), self.lbh.test(), self.hba.test())
         
         self.makeLogFile(logdir)
-        self.makePVSSfile(logdir)      
         return (self.station_error)
     
     
@@ -249,47 +211,7 @@ class cDB:
                 if len(valstr):
                     log.addLine("%s,HBA,%03d,FAIL%s" %(date, tile.nr, valstr)) 
         return
-
-
-    # make log file for PVSS logging, use setObjectState to enter settings in PVSS              
-    """       
-    Syntax: /opt/lofar/sbin/setObjectState who datapoint stateNr
-    OR    /opt/lofar/sbin/setObjectState who filename
-    who        : Identification who changes the state, name of program or user
-    datapoint  : PVSS datapoint name including database name
-    stateNr    : 0 - Off
-                 1 - Operational
-                 2 - Maintenance
-                 3 - Test
-                 4 - Suspicious
-                 5 - Broken
-    """
-    def makePVSSfile(self, logdir):
-        pvss = cPVSSLogger(logdir)
-        
-        for ant in self.lbh.ant:
-            ant.testPVSS()
-            pvss.addLine("LOFAR_PIC_LBA%03d %d" %(ant.nr_total, ant.state))     
-            pvss.addLine("LOFAR_PIC_LBA%03d.X %d" %(ant.nr_total, ant.x_state))     
-            pvss.addLine("LOFAR_PIC_LBA%03d.Y %d" %(ant.nr_total, ant.y_state))     
-        
-        for ant in self.lbl.ant:
-            ant.testPVSS()
-            pvss.addLine("LOFAR_PIC_LBA%03d %d" %(ant.nr_total, ant.state))                
-            pvss.addLine("LOFAR_PIC_LBA%03d.X %d" %(ant.nr_total, ant.x_state))                
-            pvss.addLine("LOFAR_PIC_LBA%03d.Y %d" %(ant.nr_total, ant.y_state))                
-        
-        for tile in self.hba.tile:
-            tile.testPVSS()
-            pvss.addLine("LOFAR_PIC_HBA%02d %d" %(tile.nr, tile.state))
-            for elem in tile.element:
-                pvss.addLine("LOFAR_PIC_HBA%02d.element%02d %d" %(tile.nr, elem.nr, elem.state))
-                pvss.addLine("LOFAR_PIC_HBA%02d.element%02d.comm %d" %(tile.nr, elem.nr, elem.modem_state))
-                pvss.addLine("LOFAR_PIC_HBA%02d.element%02d.X %d" %(tile.nr, elem.nr, elem.x_state))
-                pvss.addLine("LOFAR_PIC_HBA%02d.element%02d.Y %d" %(tile.nr, elem.nr, elem.y_state))
-        return
                 
-    
     class cRSP:
         def __init__(self, nr):
             self.nr = nr
@@ -368,12 +290,6 @@ class cDB:
                 self.y_high_val   = 0.0
 
                 self.down = 0
-                
-                self.last_state = State['OFF']
-                # states for PVSS
-                self.x_state = State['OFF']
-                self.y_state = State['OFF']
-                self.state = State['OFF']
                 return
                 
             def test(self):
@@ -381,14 +297,6 @@ class cDB:
                 self.y_error = max(self.y_too_low, self.y_too_high, self.y_high_noise, self.y_low_noise, self.down)
                 return
             
-            def testPVSS(self):
-                if self.x_error:
-                    self.x_state = State['BROKEN']
-                if self.y_error:
-                    self.y_state = State['BROKEN']
-                self.state = max(self.last_state, self.state, self.x_state, self.y_state)
-                return
-            
     class cHBA:
         def __init__(self, nr_tiles):
             self.check_done = 0
@@ -442,9 +350,6 @@ class cDB:
                 self.element = list()
                 for i in range(self.nr_elements):
                     self.element.append(self.cElement(i))
-                
-                # states for PVSS
-                self.state = State['OFF']
                 return
             
             def test(self):
@@ -466,14 +371,10 @@ class cDB:
                     if elem.modem_error:
                         modem_err_cnt += 1
     
-                    #self.x_low_noise  = max(self.x_low_noise, elem.x_low_noise)
-                    #self.x_high_noise = max(self.x_high_noise, elem.x_high_noise)
-                    #self.y_low_noise  = max(self.y_low_noise, elem.y_low_noise)
-                    #self.y_high_noise = max(self.y_high_noise, elem.y_high_noise)
                     self.x_error = max(self.x_error, elem.x_error)
                     self.y_error = max(self.y_error, elem.y_error)
                     
-                if (no_modem_cnt >= 8) or (modem_err_cnt >= 8):
+                if (no_modem_cnt + modem_err_cnt) >= 15:
                     self.c_summator_error = 1
                 if no_power_cnt >= 15:
                     self.p_summator_error = 1
@@ -486,12 +387,6 @@ class cDB:
                 self.y_error = max(self.y_error, self.y_low_noise, self.y_high_noise, self.p_summator_error, self.c_summator_error) 
                 return
             
-            def testPVSS(self):
-                for elem in self.element:
-                    elem.testPVSS()
-                    self.state = max(self.state, elem.state)
-                return       
-                
             class cElement:
                 def __init__(self, nr):
                     self.nr = nr
@@ -519,12 +414,6 @@ class cDB:
                     self.no_modem = 0 # modem reponse = ??
                     self.modem_error = 0 # wrong response from modem
                     
-                    self.last_state = State['OFF']
-                    # states for PVSS
-                    self.modem_state = State['OFF']
-                    self.x_state = State['OFF']
-                    self.y_state = State['OFF']
-                    self.state = State['OFF']
                     return
                 
                 def test(self):
@@ -535,26 +424,6 @@ class cDB:
                                        self.no_power, self.no_modem, self.modem_error)
                     return
                 
-                # test for PVSS settings    
-                def testPVSS(self):
-                    self.state = self.last_state
-    
-                    if self.modem_error:
-                        self.modem_state = State['SUSPICIOUS']
-                    
-                    if self.no_modem:
-                        self.modem_state = State['BROKEN']
-                    
-                    if self.x_no_signal or self.x_too_low or self.x_low_noise or self.x_high_noise or self.no_power or self.no_modem or self.modem_error:
-                        self.x_state = State['BROKEN']
-                    
-                    if self.y_no_signal or self.y_too_low or self.y_low_noise or self.y_high_noise or self.no_power or self.no_modem or self.modem_error:
-                        self.y_state = State['BROKEN']
-                        
-                    self.state = max(self.state, self.x_state, self.y_state, self.modem_state)
-                    return 
-                        
-    
     class cTDS:
         def __init__(self):
             self.test_done = 0
diff --git a/LCU/checkhardware/makeStationLogFile.py b/LCU/checkhardware/makeStationLogFile.py
index f84ec0fb4334df6b2a7f0d15e40937a5e350f58a..a5fe4426a18cbdae5b4a205f4d1f54a859cd62f0 100755
--- a/LCU/checkhardware/makeStationLogFile.py
+++ b/LCU/checkhardware/makeStationLogFile.py
@@ -70,7 +70,13 @@ for line in testdata:
     
     if part == 'LBL':
         rcu = partNr * 2 
-        if msgType == 'FAIL':
+        if msgType == 'LOW_NOISE':
+    		log.addLine('LBAosc1>: Sv=normal  Pr=normal , LBA Outer (LBL) large oscillation (low noise): RCU: (%d,%d)' %\
+                        (partNr*2, partNr*2+1))
+        elif msgType == 'HIGH_NOISE':
+    		log.addLine('LBAosc1>: Sv=normal  Pr=normal , LBA Outer (LBL) large oscillation (high noise): RCU: (%d,%d)' %\
+                        (partNr*2, partNr*2+1))
+        elif msgType == 'FAIL':
             if keyinfo.has_key('X'):
                 log.addLine('LBAmd1>: Sv=normal  Pr=normal , LBA Outer (LBL) defect: RCU: %d factor: %3.1f' %\
                            (partNr*2, float(keyinfo['X'])))
@@ -88,13 +94,19 @@ for line in testdata:
                 log.addLine('LBAmd1>: Sv=normal  Pr=normal , LBA	levels to low!!!' )               
             
     if part == 'LBH':
-        if msgType == 'FAIL':
+        if msgType == 'LOW_NOISE':
+    		log.addLine('LBAosc3>: Sv=normal  Pr=normal , LBA Inner (LBH) large oscillation (low noise): RCU: (%d,%d)' %\
+                        (partNr*2, partNr*2+1))
+        elif msgType == 'HIGH_NOISE':
+    		log.addLine('LBAosc3>: Sv=normal  Pr=normal , LBA Inner (LBH) large oscillation (high noise): RCU: (%d,%d)' %\
+                        (partNr*2, partNr*2+1))
+        elif msgType == 'FAIL':
             if keyinfo.has_key('X'):
                 log.addLine('LBAmd3>: Sv=normal  Pr=normal , LBA Inner (LBH) defect: RCU: %s factor: %3.1f' %\
                            (partNr*2, float(keyinfo['X'])))
             if keyinfo.has_key('Y'):
                 log.addLine('LBAmd3>: Sv=normal  Pr=normal , LBA Inner (LBH) defect: RCU: %s factor: %3.1f' %\
-                           (partNr*2, float(keyinfo['Y'])))           
+                           (partNr*2+1, float(keyinfo['Y'])))           
         
         elif msgType == 'DOWN':
             log.addLine('LBAdn3>: Sv=normal  Pr=normal , LBA Inner (LBH) down: RCU: %d factor: %3.1f offset: %d' %\
@@ -106,16 +118,24 @@ for line in testdata:
                 log.addLine('LBAmd3>: Sv=normal  Pr=normal , LBA	levels to low!!!' )               
 
     if part == 'HBA':
-    	if msgType == 'C_SUMMATOR':
+    	if msgType == 'LOW_NOISE':
+    		log.addLine('HBAosc>: Sv=normal  Pr=normal , Tile %d - RCU (%d,%d); Large oscillation (low noise)' %\
+                        (partNr, partNr*2, partNr*2+1))
+        
+        elif msgType == 'HIGH_NOISE':
+    		log.addLine('HBAosc>: Sv=normal  Pr=normal , Tile %d - RCU (%d,%d); Large oscillation (high noise)' %\
+                        (partNr, partNr*2, partNr*2+1))                
+        
+        elif msgType == 'C_SUMMATOR':
     		last_c_summator = partNr
     		log.addLine('HBAmdt>: Sv=normal  Pr=normal , Tile %d - RCU %d; Broken. No modem communication' %\
                                 (partNr, partNr*2+1))
-        if last_c_summator != partNr and msgType == 'FAIL':
+        elif last_c_summator != partNr and msgType == 'FAIL':
             for elem_nr in range(1,17,1):
 
                 if keyinfo.has_key('M%d' %(elem_nr)):
                     val = keyinfo.get('M%d' %(elem_nr))
-                    log.addLine('HBAmdt>: Sv=normal  Pr=normal , Tile %d - RCU %d; Element %d Broken. No modem communication : (%s)' %\
+                    log.addLine('HBAmdt>: Sv=normal  Pr=normal , Tile %d - RCU %d; Element %s Broken. No modem communication : (%s)' %\
                                 (partNr, partNr*2+1, elem_nr, val))
 
                 if keyinfo.has_key('X%d' %(elem_nr)):
diff --git a/LCU/checkhardware/updatePVSS.py b/LCU/checkhardware/updatePVSS.py
new file mode 100755
index 0000000000000000000000000000000000000000..c48a0af7c258043b31a8b3715f9f594a58cdfebe
--- /dev/null
+++ b/LCU/checkhardware/updatePVSS.py
@@ -0,0 +1,255 @@
+#!/usr/bin/python
+#
+# read last test log file (.csv)
+# and send test result to PVSS,
+# and write to PVSS log file
+#
+# P.Donker
+
+import sys
+import os
+from time import sleep
+
+libPath = '/opt/stationtest/lib'
+sys.path.insert(0, libPath)
+
+from general_lib import *
+from lofar_lib import *
+
+args = dict()
+logdir = ""
+logger = 0
+nLBL = 0
+nLBH = 0
+nHBA = 0
+
+# PVSS states
+State = dict({'OFF':0, 'OPERATIONAL':1, 'MAINTENANCE':2, 'TEST':3, 'SUSPICIOUS':4, 'BROKEN':5})
+
+
+
+def main():
+    global args, logdir, logger, nLBL, nLBH, nHBA
+    args   = getArguments()
+    logdir = getLogDir()
+    ID, nRSP, nTBB, nLBL, nLBH, nHBA = readStationConfig()
+    logger = cPVSSLogger(logdir)
+
+    if args.has_key('RESET'):
+        resetPVSS(0)
+
+    else:
+        # read last log file from checkhardware
+        testfilename = '%s_StationTest.csv' %(getHostName())
+        fullFilename = os.path.join(logdir, testfilename)
+        f = open(fullFilename, 'r')
+        testdata = f.readlines()
+        f.close()
+
+        addDataToPVSS(testdata)
+
+# print help screen
+def printHelp():
+    print "----------------------------------------------------------------------------"
+    print "Usage of arguments"
+    print "-h     : this help screen"
+    print "-reset : clean all, set all antennas too ok"
+    print "-test  : do not send to PVSS"
+
+# get command line arguments
+def getArguments():
+    args = dict()
+    for i in range(len(sys.argv)):
+        if sys.argv[i][0] == '-':
+            if sys.argv[i].find('=') != -1:
+                args[sys.argv[i][1:valpos].upper()] = int(sys.argv[i][valpos+1:])
+            else:
+                args[sys.argv[i][1:].upper()]='-'
+
+        if args.has_key('H'):
+            printHelp()
+            sys.exit()
+    return(args)
+
+# get logdir from configuration file
+def getLogDir():
+    logdir = ""
+    # look for log directory
+    f = open("/opt/stationtest/checkHardware.conf", 'r')
+    data = f.readlines()
+    f.close()
+    for line in data:
+        if line.find('log-dir') != -1:
+            key, logdir = line.strip().split('=')
+    return(logdir)
+
+# send comment, key and value to PVSS and write to file
+def sendToPVSS(comment, pvss_key, value):
+    global logger
+    if len(comment) > 0:
+        comment = 'stationtest::'+comment
+    else:
+        comment = 'stationtest'
+    arguments = '%s %s %d' %(comment, pvss_key, value)
+    logger.addLine(arguments[11:])
+    if args.has_key('TEST'):
+        print arguments
+    else:
+        response = sendCmd('setObjectState', arguments)
+        sleep(0.05)
+        return(response)
+    return("")
+
+# set all antenna info to ok
+def resetPVSS(state=0):
+    global State, nLBL, nLBH, nHBA
+    
+    filename = "reset_pvss.log"
+    full_filename = os.path.join(libPath, filename)
+    f = open(full_filename, 'w')
+        
+    for ant in range(nLBH):
+        f.write("LOFAR_PIC_LBA%03d %d\n" %(ant, state))
+
+    for ant in range(nLBL):
+        f.write("LOFAR_PIC_LBA%03d %d\n" %(ant+48, state))
+
+    for tile in range(nHBA):
+        f.write("LOFAR_PIC_HBA%02d %d\n" %(tile, state))
+        
+        for elem in range(16):
+            f.write("LOFAR_PIC_HBA%02d.element%02d %d\n" %(tile, elem, state))
+            f.write("LOFAR_PIC_HBA%02d.element%02d.comm %d\n" %(tile, elem, state))
+            f.write("LOFAR_PIC_HBA%02d.element%02d.X %d\n" %(tile, elem, state))
+            f.write("LOFAR_PIC_HBA%02d.element%02d.Y %d\n" %(tile, elem, state))
+    
+    sendCmd("setObjectState", "stationtes:reset %s" %(full_filename))
+        
+# add result data from checkhardware to PVSS
+def addDataToPVSS(data):
+    global State
+    for line in data:
+        if line[0] == '#':
+            continue
+        keyinfo = dict()
+        info = line.split(',')
+        #print info
+        date    = info[0]
+        part    = info[1]
+        partNr = '---'
+        if info[2] != '---':
+            partNr  = int(info[2])
+        msgType = info[3].strip()
+        for i in range(4,len(info)):
+                if info[i].find('=') != -1:
+                    key, valstr = info[i].split('=')
+                    vallist = valstr.split()
+                    if len(vallist) == 1:
+                        keyinfo[key] = vallist[0]
+                    elif len(vallist) > 1:
+                        keyinfo[key] = vallist
+                else:
+                    keyinfo[info[i]] = '-'
+
+        if part == 'LBL':
+            if msgType == 'LOW_NOISE':
+                sendToPVSS("low-noise", "LOFAR_PIC_LBA%03d" %(partNr+48), State['BROKEN'])
+
+            elif msgType == 'HIGH_NOISE':
+                sendToPVSS("high-noise", "LOFAR_PIC_LBA%03d" %(partNr+48), State['BROKEN'])
+
+            if msgType == 'FAIL':
+                comment = "rf-fail-"
+                if keyinfo.has_key('X'):
+                    comment += "X"
+                    #sendToPVSS("rf-fail", "LOFAR_PIC_LBA%03d.X" %(partNr+48), State['BROKEN'])
+                if keyinfo.has_key('Y'):
+                    comment += "Y"
+                    #sendToPVSS("rf-fail", "LOFAR_PIC_LBA%03d.Y" %(partNr+48), State['BROKEN'])
+                sendToPVSS(comment, "LOFAR_PIC_LBA%03d" %(partNr+48), State['BROKEN'])
+                
+            elif msgType == 'DOWN':
+                sendToPVSS("down", "LOFAR_PIC_LBA%03d" %(partNr+48), State['BROKEN'])
+                #sendToPVSS("Down", "LOFAR_PIC_LBA%03d.X" %(partNr+48), State['BROKEN'])
+                #sendToPVSS("Down", "LOFAR_PIC_LBA%03d.Y" %(partNr+48), State['BROKEN'])
+
+        if part == 'LBH':
+            if msgType == 'LOW_NOISE':
+                sendToPVSS("low-noise", "LOFAR_PIC_LBA%03d" %(partNr), State['BROKEN'])
+
+            elif msgType == 'HIGH_NOISE':
+                sendToPVSS("high-noise", "LOFAR_PIC_LBA%03d" %(partNr), State['BROKEN'])
+
+            elif msgType == 'FAIL':
+                comment = "rf-fail-"
+                if keyinfo.has_key('X'):
+                    comment += "X"
+                    #sendToPVSS("rf-fail", "LOFAR_PIC_LBA%03d.X" %(partNr), State['BROKEN'])
+                if keyinfo.has_key('Y'):
+                    comment += "Y"
+                    #sendToPVSS("rf-fail", "LOFAR_PIC_LBA%03d.Y" %(partNr), State['BROKEN'])
+                sendToPVSS(comment, "LOFAR_PIC_LBA%03d" %(partNr), State['BROKEN'])
+            elif msgType == 'DOWN':
+                sendToPVSS("down", "LOFAR_PIC_LBA%03d" %(partNr), State['BROKEN'])
+                #sendToPVSS("Down", "LOFAR_PIC_LBA%03d.X" %(partNr), State['BROKEN'])
+                #sendToPVSS("Down", "LOFAR_PIC_LBA%03d.Y" %(partNr), State['BROKEN'])
+
+        if part == 'HBA':
+            if msgType == 'LOW_NOISE':
+                sendToPVSS("low-noise", "LOFAR_PIC_HBA%02d" %(partNr), State['BROKEN'])
+
+            elif msgType == 'HIGH_NOISE':
+                sendToPVSS("high-noise", "LOFAR_PIC_HBA%02d" %(partNr), State['BROKEN'])
+
+            elif msgType == 'C_SUMMATOR':
+                sendToPVSS("Moden-fail", "LOFAR_PIC_HBA%02d" %(partNr), State['BROKEN'])
+
+            elif msgType == 'FAIL':
+                sendToPVSS("", "LOFAR_PIC_HBA%02d" %(partNr), State['BROKEN'])
+                for elem_nr in range(1,17,1):
+
+                    if    keyinfo.has_key('M%d' %(elem_nr)) \
+                       or keyinfo.has_key('X%d' %(elem_nr)) \
+                       or keyinfo.has_key('Y%d' %(elem_nr)) \
+                       or keyinfo.has_key('LNX%d' %(elem_nr)) \
+                       or keyinfo.has_key('HNX%d' %(elem_nr)) \
+                       or keyinfo.has_key('LNY%d' %(elem_nr)) \
+                       or keyinfo.has_key('HNY%d' %(elem_nr)):
+                        sendToPVSS("rf-fail", "LOFAR_PIC_HBA%02d.element%02d" %(partNr, elem_nr-1), State['BROKEN'])
+
+                    if keyinfo.has_key('M%d' %(elem_nr)):
+                        sendToPVSS("rf-fail", "LOFAR_PIC_HBA%02d.element%02d.comm" %(partNr, elem_nr-1), State['BROKEN'])
+                    
+                    comment = ""
+                    if    keyinfo.has_key('X%d' %(elem_nr)) \
+                       or keyinfo.has_key('LNX%d' %(elem_nr)) \
+                       or keyinfo.has_key('HNX%d' %(elem_nr)):
+                        
+                        if keyinfo.has_key('X%d' %(elem_nr)):
+                            comment += "rf-fail&"
+    
+                        if keyinfo.has_key('LNX%d' %(elem_nr)):
+                            comment += "low-noise&"
+                        
+                        if keyinfo.has_key('HNX%d' %(elem_nr)):
+                            comment += "high-noise&"
+                        sendToPVSS(comment[:-1], "LOFAR_PIC_HBA%02d.element%02d.X" %(partNr, elem_nr-1), State['BROKEN'])
+                    
+                    comment = ""
+                    if    keyinfo.has_key('Y%d' %(elem_nr)) \
+                       or keyinfo.has_key('LNY%d' %(elem_nr)) \
+                       or keyinfo.has_key('HNY%d' %(elem_nr)):
+                        
+                        if keyinfo.has_key('Y%d' %(elem_nr)):
+                            comment += "rf-fail&"
+    
+                        if keyinfo.has_key('LNY%d' %(elem_nr)):
+                            comment += "low-noise&"
+                        
+                        if keyinfo.has_key('HNY%d' %(elem_nr)):
+                            comment += "high-noise&"
+                        sendToPVSS(comment[:-1], "LOFAR_PIC_HBA%02d.element%02d.Y" %(partNr, elem_nr-1), State['BROKEN'])
+
+
+if __name__ == "__main__":
+    main()
\ No newline at end of file
diff --git a/MAC/APL/Appl_Controller/CMakeLists.txt b/MAC/APL/Appl_Controller/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..1cdc000bb2b63e542833802dcce48852802db64f
--- /dev/null
+++ b/MAC/APL/Appl_Controller/CMakeLists.txt
@@ -0,0 +1,9 @@
+# $Id$
+
+lofar_package(Appl_Controller 2.0 DEPENDS Common MACIO ALC PLC)
+
+include(LofarFindPackage)
+lofar_find_package(Blitz REQUIRED)
+
+add_subdirectory(src)
+
diff --git a/MAC/APL/Appl_Controller/src/ACCmdImpl.cc b/MAC/APL/Appl_Controller/src/ACCmdImpl.cc
new file mode 100644
index 0000000000000000000000000000000000000000..ac5dac98d8be21aae014fcee38f93ad27948f002
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/ACCmdImpl.cc
@@ -0,0 +1,157 @@
+//#  ACCmdImpl.cc: The actual command implementation for the A. Controller
+//#
+//#  Copyright (C) 2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  $Id$
+
+//# Always #include <lofar_config.h> first!
+#include <lofar_config.h>
+
+//# Includes
+#include <Common/StringUtil.h>
+#include <Common/LofarLogger.h>
+#include <time.h>
+#include "ACCmdImpl.h"
+#include "APAdminPool.h"
+
+namespace LOFAR {
+  namespace ACC {
+
+ACCmdImpl::ACCmdImpl() :
+	ApplControl()
+{
+}
+
+// Destructor;
+ACCmdImpl::~ACCmdImpl() { };
+
+
+// Commands to control the application
+bool	ACCmdImpl::boot  (const time_t	/* scheduleTime */,
+						  const string& /* configID */ ) const
+{
+	LOG_WARN("boot: Should have been implemented in the statemachine");
+	return (true);
+}
+
+bool	ACCmdImpl::define(const time_t		scheduleTime) const
+{
+	LOG_DEBUG(formatString("define(%s)", timeString(scheduleTime).c_str()));
+	APAdminPool::getInstance().writeToAll(PCCmdDefine, "");
+	return (true);
+}
+
+bool	ACCmdImpl::init  (const time_t		scheduleTime) const
+{
+	LOG_DEBUG(formatString("init(%s)", timeString(scheduleTime).c_str()));
+	APAdminPool::getInstance().writeToAll(PCCmdInit, "");
+	return (true);
+}
+
+bool	ACCmdImpl::run 	 (const time_t		scheduleTime) const
+{
+	LOG_DEBUG(formatString("run(%s)", timeString(scheduleTime).c_str()));
+	APAdminPool::getInstance().writeToAll(PCCmdRun, "");
+	return (true);
+}
+
+bool	ACCmdImpl::pause (const time_t		scheduleTime,
+						  const time_t		waitTime,
+						  const	string&		condition) const
+{
+	LOG_DEBUG(formatString("pause(%s,%d,%s)", timeString(scheduleTime).c_str(),
+												waitTime, condition.c_str()));
+	APAdminPool::getInstance().writeToAll(PCCmdPause, condition);
+	return (true);
+}
+
+bool	ACCmdImpl::release  (const time_t		scheduleTime) const
+{
+	LOG_DEBUG(formatString("release(%s)", timeString(scheduleTime).c_str()));
+	APAdminPool::getInstance().writeToAll(PCCmdRelease, "");
+	return (true);
+}
+
+bool	ACCmdImpl::quit  (const time_t		scheduleTime) const
+{
+	LOG_DEBUG(formatString("quit(%s)", timeString(scheduleTime).c_str()));
+	APAdminPool::getInstance().writeToAll(PCCmdQuit, "");
+	return (true);
+}
+
+bool	ACCmdImpl::shutdown (const time_t/*	scheduleTime*/) const
+{
+	LOG_WARN("shutdown: Should have been implemented in the statemachine");
+	return (true);
+}
+
+bool	ACCmdImpl::snapshot (const time_t		scheduleTime,
+						     const string&		destination) const
+{
+	LOG_DEBUG(formatString("snapshot(%s,%s)", timeString(scheduleTime).c_str(),
+														destination.c_str()));
+	APAdminPool::getInstance().writeToAll(PCCmdSnapshot, destination);
+	return (true);
+}
+
+bool	ACCmdImpl::recover  (const time_t		scheduleTime,
+						     const string&		source) const
+{
+	LOG_DEBUG(formatString("recover(%s,%s)", timeString(scheduleTime).c_str(),
+														source.c_str()));
+	APAdminPool::getInstance().writeToAll(PCCmdRecover, source);
+	return (true);
+}
+
+
+bool	ACCmdImpl::reinit (const time_t		scheduleTime,
+						   const string&	configID) const
+{
+	LOG_DEBUG(formatString("reinit(%s,%s)", timeString(scheduleTime).c_str(),
+													configID.c_str()));
+	APAdminPool::getInstance().writeToAll(PCCmdReinit, configID);
+	return (true);
+}
+
+bool	ACCmdImpl::replace	 (const time_t		/*scheduleTime*/,
+						      const string&		/*processList*/,
+						      const string&		/*nodeList*/,
+						      const string&		/*configID*/) const
+{
+	// TODO
+	return (true);
+}
+
+bool	ACCmdImpl::cancelCmdQueue () const 
+{
+	THROW (Exception, "We should never come in ACCmdImpl::cancelCmdQueue");
+	return (true);
+}
+
+// Define a generic way to exchange info between client and server.
+string	ACCmdImpl::askInfo   (const string& 	/*keylist*/) const
+{
+	// TODO
+	return ("ACCmdImpl: askInfo not yet implemented");
+}
+
+
+
+  } // namespace ACC
+} // namespace LOFAR
diff --git a/MAC/APL/Appl_Controller/src/ACCmdImpl.h b/MAC/APL/Appl_Controller/src/ACCmdImpl.h
new file mode 100644
index 0000000000000000000000000000000000000000..45c707a3aee2b5981795164fa8fdaf2fd3ecf495
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/ACCmdImpl.h
@@ -0,0 +1,94 @@
+//#  ACCmdImpl.h: the implementation of the AC commands
+//#
+//#  Copyright (C) 2002-2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  Note: This source is read best with tabstop 4.
+//#
+//#  $Id$
+
+#ifndef LOFAR_ACCBIN_ACCMDIMPL_H
+#define LOFAR_ACCBIN_ACCMDIMPL_H
+
+// \file
+// The implementation of the AC commands from the Application Controller
+
+//# Never #include <config.h> or #include <lofar_config.h> in a header file!
+//# Includes
+#include <ALC/ApplControl.h>
+
+using namespace LOFAR::ACC::ALC;
+
+namespace LOFAR {
+  namespace ACC {
+
+// \addtogroup ACCbin
+// @{
+
+// This class implements the execution of the AC commands by the Application
+// Controller.
+class ACCmdImpl : public ApplControl
+{
+public:
+	// Default constructable
+	ACCmdImpl();
+
+	// Destructor
+	virtual ~ACCmdImpl();
+
+	// Commands to control the application
+	virtual bool	boot 	 (const time_t		scheduleTime,
+							  const string&		configID)     const;
+	virtual bool	define 	 (const time_t		scheduleTime) const;
+	virtual bool	init 	 (const time_t		scheduleTime) const;
+	virtual bool	run 	 (const time_t		scheduleTime) const;
+	virtual bool	pause  	 (const time_t		scheduleTime,
+							  const time_t		waitTime,
+							  const	string&		condition)    const;
+	virtual bool	release	 (const time_t		scheduleTime) const;
+	virtual bool	quit  	 (const time_t		scheduleTime) const;
+	virtual bool	shutdown (const time_t		scheduleTime) const;
+	virtual bool	snapshot (const time_t		scheduleTime,
+							  const string&		destination)  const;
+	virtual bool	recover  (const time_t		scheduleTime,
+							  const string&		source)       const;
+
+	virtual bool	reinit	 (const time_t		scheduleTime,
+							  const string&		configID)     const;
+	virtual bool	replace	 (const time_t		scheduleTime,
+							  const string&		processList,
+							  const string&		nodeList,
+							  const string&		configID)     const;
+	virtual bool	cancelCmdQueue () const;
+
+	// Define a generic way to exchange info between client and server.
+	string	askInfo   (const string& 	keylist) const;
+
+private:
+	// Copying is not allowed
+	ACCmdImpl(const ACCmdImpl& that);
+	ACCmdImpl& 	operator=(const ACCmdImpl& that);
+
+};
+
+
+// @} addtogroup
+  } // namespace ACC
+} // namespace LOFAR
+
+#endif
diff --git a/MAC/APL/Appl_Controller/src/ACDaemon.cc b/MAC/APL/Appl_Controller/src/ACDaemon.cc
new file mode 100644
index 0000000000000000000000000000000000000000..341312a856902b3b5c1f1fb943840e45b53f791f
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/ACDaemon.cc
@@ -0,0 +1,262 @@
+//#  ACDaemon.cc: launches Application Controllers on demand.
+//#
+//#  Copyright (C) 2002-2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  $Id$
+
+//# Always #include <lofar_config.h> first!
+#include <lofar_config.h>
+
+//# Includes
+#include <Common/LofarLogger.h>
+#include <Common/LofarLocators.h>
+#include <Common/SystemUtil.h>
+#include <ApplCommon/LofarDirs.h>
+#include <ALC/ACRequest.h>
+#include "ACDaemon.h"
+#include "ACDaemonComm.h"
+#include "forkexec.h"
+
+namespace LOFAR {
+  namespace ACC {
+
+ACDaemon::ACDaemon(const string&	progName) :
+	itsListener   (0),
+	itsPingSocket (0),
+	itsParamSet   (new ParameterSet),
+	itsACPool     (0)
+{
+	// Read in the parameterfile with network parameters.
+	ConfigLocator	aCL;
+	string			configFile(progName + ".conf");
+	LOG_DEBUG_STR("Using parameterfile: "<< configFile <<"-->"<< aCL.locate(configFile));
+	itsParamSet->adoptFile(aCL.locate(configFile));		// May throw
+
+	// Open listener for AC requests.
+	itsListener = new Socket("ACdaemon",
+							 itsParamSet->getString("ACDaemon.requestportnr"),
+							 Socket::TCP);
+
+	// Open listener for ping from AC's.
+	itsPingSocket = new Socket("ACdaemon",
+							 itsParamSet->getString("ACDaemon.pingportnr"),
+							 Socket::UDP);
+
+	// Try to read in an old administration if it is available.
+	itsACPool = new ACRequestPool(itsParamSet->getInt32("ACDaemon.ACpoolport"),
+								  itsParamSet->getInt32("ACDaemon.ACpoolsize"));
+	itsAdminFile = "../etc/" + itsParamSet->getString("ACDaemon.adminfile");
+	itsACPool->load(itsAdminFile);
+
+}
+
+ACDaemon::~ACDaemon()
+{
+	if (itsListener)   { delete itsListener; }
+	if (itsPingSocket) { delete itsPingSocket; }
+	if (itsParamSet)   { delete itsParamSet; }
+	if (itsACPool)     { delete itsACPool; }
+}
+
+void ACDaemon::doWork() throw (Exception)
+{
+	// Setup some values we need in the main loop
+	int32	cleanTime = itsParamSet->getTime("ACDaemon.alivetimeout");
+	int32	warnTime  = cleanTime / 2;
+
+	// Prepare a fd_set for select
+	itsConnSet.add(itsListener->getSid());
+	itsConnSet.add(itsPingSocket->getSid());
+
+	LOG_INFO ("ACDaemon: entering main loop");
+
+	while (true) {
+		// wait for request or ping
+		FdSet	readSet(itsConnSet);
+		struct timeval	tv;					// prepare select-timer
+		tv.tv_sec       = 60;				// this must be IN the while loop
+		tv.tv_usec      = 0;				// because select will change tv
+		int32 selResult = select(readSet.highest()+1, readSet.getSet(), 0, 0, &tv);
+
+		// -1 may be an interrupt or a program-error.
+		if ((selResult == -1) && (errno != EINTR)) {
+			THROW(Exception, "ACDaemon: 'select' returned serious error: " << 
+							  errno << ":" << strerror(errno));
+		}
+
+		if (selResult == -1) {		// EINTR: ignore
+			continue;
+		}
+
+		// Ping from an AC?
+		if (readSet.isSet(itsPingSocket->getSid())) {
+			handlePingMessage();
+		}
+
+		// Request for new AC?
+		if (readSet.isSet(itsListener->getSid())) {
+			handleACRequest();
+		}
+
+		// cleanup AC's that did not respond for 5 minutes.
+		if (itsACPool->cleanup(warnTime, cleanTime)) {
+			itsACPool->save(itsAdminFile);
+		}
+
+	} // while
+}
+
+//
+// handlePingMessage (on UDP socket)
+//
+void ACDaemon::handlePingMessage()
+{
+	LOG_TRACE_FLOW("Ping???");
+
+	// Read name of AC from ping message
+	char	buffer[ACREQUESTNAMESIZE+1];
+	int32 btsRead = itsPingSocket->read(static_cast<void*>(&buffer), 
+								  		ACREQUESTNAMESIZE+1);
+	if (btsRead != ACREQUESTNAMESIZE+1) {
+		LOG_TRACE_STAT_STR("Read on ping port retured: " << btsRead <<
+					   	   " iso " << ACREQUESTNAMESIZE+1);
+		return;
+	}
+
+	// search name in pool
+	ACRequest*	ACRPtr = itsACPool->search(&buffer[1]);
+	if (!ACRPtr) {
+		LOG_TRACE_RTTI_STR ("Received ping from unknown applicationcontroller: " 
+					  << buffer << " (ignoring)");
+		return;
+	}
+
+	if (buffer[0] == AC_LEAVING_SIGN) {
+		LOG_DEBUG_STR(&buffer[1] << " leaves ACDaemon pool");
+		itsACPool->remove(&buffer[1]);
+		itsACPool->save(itsAdminFile);
+		return;
+	}
+
+	// assume first char is a AC_ALIVE_SIGN, remember ping time, update state.
+	LOG_TRACE_COND_STR("AC " << ACRPtr->itsRequester << " is alive");
+	ACRPtr->itsPingtime = time(0);
+	ACRPtr->itsState    = ACRok;
+	
+}
+
+//
+// handleACRequest()
+//
+void ACDaemon::handleACRequest()
+{
+	// Accept the new connection
+	Socket*	dataSocket = itsListener->accept(-1);
+	ASSERTSTR(dataSocket,
+			  "Serious problems on listener socket, exiting! : " <<
+			  itsListener->errstr());
+
+	// read request which should come very soon.
+	ACRequest 	aRequest;
+	uint16		reqSize    = sizeof (ACRequest);
+	dataSocket->setBlocking(true);
+	uint32 btsRead = dataSocket->read(static_cast<void*>(&aRequest), reqSize);
+	if (btsRead != reqSize) {
+		LOG_INFO_STR ("ILLEGAL REQUEST SIZE (" << btsRead << 
+								" iso " << reqSize << "), IGNORING REQUEST");
+		delete dataSocket;
+		return;
+	}
+	aRequest.itsRequester[ACREQUESTNAMESIZE-1] = '\0'; // be save
+
+	// is ACuser already known? Its a reconnect, don't start the AC
+	ACRequest*	existingACR;
+	bool		startAC = true;
+	if ((existingACR = itsACPool->search(aRequest.itsRequester))) {
+		LOG_DEBUG_STR("Reconnect of " << aRequest.itsRequester);
+		aRequest = *existingACR;			// copy old info
+		existingACR->itsState    = ACRnew;	// reset ping state and time
+		existingACR->itsPingtime = time(0);	// to prevent early removal
+	}
+	else {
+		// Its an unknown ACuser, add it to the pool
+		// assignment of node and portnr based on request params
+		if (!itsACPool->assignNewPort(&aRequest)) {
+			aRequest.itsAddr = 0;			// return failure to user
+			aRequest.itsPort = 0;
+			startAC          = false;
+			LOG_ERROR("No more ports available for application controllers");
+		}
+		else {
+			// Register new AC in the pool and save the pool
+			aRequest.itsPingtime = time(0);
+			aRequest.itsState    = ACRnew;
+			itsACPool->add(aRequest);
+			itsACPool->save(itsAdminFile);
+		}
+	}
+
+	if (startAC) {
+		// Try to launch the AC, if it is already running the
+		// new one will fail and the user will reconnect on the old one.
+		constructACFile(&aRequest, string(LOFAR_SHARE_LOCATION) + "/" + aRequest.itsRequester+".param");
+		string	sysCommand = formatString(itsParamSet->getString("ACDaemon.command").c_str(), 
+										  aRequest.itsRequester);
+		LOG_DEBUG_STR("Executing '" << sysCommand << "'");
+		int32 result = forkexec (sysCommand.c_str());
+		LOG_DEBUG_STR ("result = " << result << ", errno = " << errno << ":" << strerror(errno));
+	}
+
+	// return the answer to the ACuser
+	uint32 btsWritten = dataSocket->write(static_cast<void*>(&aRequest), reqSize);
+	if (btsWritten != reqSize) {
+		LOG_WARN_STR ("REQUEST FOR " << aRequest.itsRequester << 
+					  " COULD NOT BE WRITTEN (" << btsWritten << " iso "  << reqSize << ")");
+	}
+
+	delete dataSocket;
+}
+
+//
+// constructACFile(filename)
+//
+void ACDaemon::constructACFile(const ACRequest*		anACR,
+							   const string&		aFilename) {
+	ParameterSet		ACPS;
+
+	uint16	backlog = anACR->itsNrProcs / 10;
+	backlog = MAX (5, MIN (backlog, 100));
+	
+	// TODO: Calculate processportnr
+
+	ACPS.add(KVpair("AC.backlog", 		backlog));
+	ACPS.add(KVpair("AC.node",	  		myHostname(false)));
+	ACPS.add(KVpair("AC.userportnr",    ntohs(anACR->itsPort)));
+	ACPS.add(KVpair("AC.processportnr", 100+ntohs(anACR->itsPort))); // TODO
+
+	ACPS.add("AC.pinghost",     myHostname(false));
+	ACPS.add("AC.pingportnr",   itsParamSet->getString("ACDaemon.pingportnr"));
+	ACPS.add("AC.pinginterval", itsParamSet->getString("ACDaemon.aliveinterval"));
+	ACPS.add("AC.pingID", 	    anACR->itsRequester);
+	
+	ACPS.writeFile (aFilename);
+}
+
+  } // namespace ACC
+} // namespace LOFAR
diff --git a/MAC/APL/Appl_Controller/src/ACDaemon.conf b/MAC/APL/Appl_Controller/src/ACDaemon.conf
new file mode 100644
index 0000000000000000000000000000000000000000..fa1b366bf8de7b9623ecb4059a5ffd3e5c38d0b6
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/ACDaemon.conf
@@ -0,0 +1,11 @@
+#
+# Parameter file for ACDaemon
+#
+ACDaemon.requestportnr = 3800		# for ACRequests (TCP)
+ACDaemon.pingportnr    = 3801		# for AC's to say they are alive (UDP)
+ACDaemon.ACpoolport    = 3820		# ports the AC may use.
+ACDaemon.ACpoolsize    = 30			# size of AC port pool
+ACDaemon.aliveinterval = 1 m		# for AC
+ACDaemon.alivetimeout  = 5 m		# remove AC after this period
+ACDaemon.adminfile     = ACD.admin	# file to survive power failures
+ACDaemon.command       = ./ApplController %s >&/dev/null &
diff --git a/MAC/APL/Appl_Controller/src/ACDaemon.h b/MAC/APL/Appl_Controller/src/ACDaemon.h
new file mode 100644
index 0000000000000000000000000000000000000000..a84c6777b6d31653d4184ed03233c1c1831c5381
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/ACDaemon.h
@@ -0,0 +1,101 @@
+//#  ACDaemon.h: Daemon for launching Application Controllers
+//#
+//#  Copyright (C) 2002-2005
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  Note: This source is read best with tabstop 4.
+//#
+//#  $Id$
+
+#ifndef LOFAR_ACCBIN_ACDAEMON_H
+#define LOFAR_ACCBIN_ACDAEMON_H
+
+// \file
+// Daemon for launching Application Controllers
+
+//# Never #include <config.h> or #include <lofar_config.h> in a header file!
+//# Includes
+#include <Common/Exception.h>
+#include <Common/Net/Socket.h>
+#include <Common/Net/FdSet.h>
+#include <Common/ParameterSet.h>
+#include "ACRequestPool.h"
+
+
+namespace LOFAR {
+  namespace ACC {
+// \addtogroup ACCbin
+// @{
+
+
+// The ACDaemon class implements a small daemon that wait for a request message
+// and starts up an Application controller according to the request.
+// The ACDaemon is fully controlled by the ParameterSet it receives during
+// startup.
+class ACDaemon
+{
+public:
+	// Creates an ACDaemon object that start listening on the port mentioned
+	// in the ParameterSet.
+	explicit ACDaemon(const string&	progName);
+
+	// Destructor.
+	~ACDaemon();
+
+	// Its normal (never ending) loop.
+	void doWork() throw (Exception);
+
+private:
+	// Construct a parameterfile for the AC controller.
+	void constructACFile(const ACRequest*	anACR,
+						 const string&	    aFilename);
+
+	void handlePingMessage();
+	void handleACRequest();
+
+	// Copying is not allowed
+	ACDaemon(const ACDaemon&	that);
+
+	// Copying is not allowed
+	ACDaemon& operator=(const ACDaemon& that);
+
+	//# --- Datamembers --- 
+	// The listener socket to receive the requests on.
+	Socket*			itsListener;
+
+	// The ping socket to receive the still-alive packages on.
+	Socket*			itsPingSocket;
+
+	// The parameterSet that was received during start up.
+	ParameterSet*	itsParamSet;
+
+	// The list with current active Application Controllers
+	ACRequestPool*	itsACPool;
+
+	// File descriptor set of connected sockets
+	FdSet			itsConnSet;
+
+	// Name of the administration file forr surviving restarts.
+	string			itsAdminFile;
+};
+
+// @} addgroup
+  } // namespace ACC
+} // namespace LOFAR
+
+#endif
diff --git a/MAC/APL/Appl_Controller/src/ACDaemon.log_prop b/MAC/APL/Appl_Controller/src/ACDaemon.log_prop
new file mode 100644
index 0000000000000000000000000000000000000000..f3755cbd6b73c997bf784c06d4ef9a18e0e18bdf
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/ACDaemon.log_prop
@@ -0,0 +1,24 @@
+
+# Configure the loggers
+log4cplus.rootLogger=INFO, STDOUT, FILE
+log4cplus.logger.TRC=INFO
+log4cplus.logger.LCS.Common=FATAL, STDOUT, FILE
+
+# Define the appenders
+log4cplus.appender.STDOUT=log4cplus::ConsoleAppender
+log4cplus.appender.STDOUT.layout=log4cplus::PatternLayout
+log4cplus.appender.STDOUT.layout.ConversionPattern=%D{%d-%m %H:%M:%S.%q} %-5p %c{3} - %m [%.25l]%n
+
+log4cplus.appender.STDERR=log4cplus::ConsoleAppender
+log4cplus.appender.STDERR.layout=log4cplus::PatternLayout
+log4cplus.appender.STDERR.layout.ConversionPattern=%D{%d-%m %H:%M:%S.%q} %-5p %c{3} - %m [%.25l]%n
+log4cplus.appender.STDERR.logToStdErr=true
+
+log4cplus.appender.FILE=log4cplus::RollingFileAppender
+log4cplus.appender.FILE.File=/opt/lofar/var/log/${LOG4CPLUS_LOGFILENAME}.log
+log4cplus.appender.FILE.MaxFileSize=10MB
+log4cplus.appender.FILE.MaxBackupIndex=2
+log4cplus.appender.FILE.layout=log4cplus::PatternLayout
+log4cplus.appender.FILE.layout.ConversionPattern=%x %D{%d-%m %H:%M:%S.%q} %-5p %c{3} - %m [%.25l]%n
+
+log4cplus.appender.DUMP=log4cplus::NullAppender
diff --git a/MAC/APL/Appl_Controller/src/ACDaemonComm.cc b/MAC/APL/Appl_Controller/src/ACDaemonComm.cc
new file mode 100644
index 0000000000000000000000000000000000000000..41e8a8e9cac1ccd01f9099b7da2c5465d9578bde
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/ACDaemonComm.cc
@@ -0,0 +1,69 @@
+//#  ACDaemonComm.cc: Communication from AC to ACD.
+//#
+//#  Copyright (C) 2005
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  Note: This source is read best with tabstop 4.
+//#
+//#  $Id$
+
+//# Always #include <lofar_config.h> first!
+#include <lofar_config.h>
+
+//# Includes
+#include <Common/LofarLogger.h>
+#include"ACDaemonComm.h"
+
+namespace LOFAR {
+  namespace ACC {
+
+ACDaemonComm::ACDaemonComm(const string&	host,
+				 		   const string&	port,
+				 		   const string&  	ID) :
+	itsDaemonSocket(new Socket("DaemonPing", host, port, Socket::UDP))
+{
+	ASSERTSTR(itsDaemonSocket->ok(), "Can't open ping socket with ACdaemon");
+
+	itsPingID[0] = AC_ALIVE_SIGN;
+	strncpy (&itsPingID[1], ID.c_str(), ACREQUESTNAMESIZE-1);
+	itsPingID [ACREQUESTNAMESIZE] = '\0';
+}
+
+ACDaemonComm::~ACDaemonComm()
+{
+	if (itsDaemonSocket) {
+		delete itsDaemonSocket;
+	}
+}
+
+bool	ACDaemonComm::sendPing()
+{
+	return (itsDaemonSocket->write(itsPingID, ACREQUESTNAMESIZE+1) == 
+														ACREQUESTNAMESIZE+1);
+}
+
+void	ACDaemonComm::unregister()
+{
+	itsPingID[0] = AC_LEAVING_SIGN;
+	sendPing();
+}
+
+
+
+  } // namespace ACC
+} // namespace LOFAR
diff --git a/MAC/APL/Appl_Controller/src/ACDaemonComm.h b/MAC/APL/Appl_Controller/src/ACDaemonComm.h
new file mode 100644
index 0000000000000000000000000000000000000000..9cd482827b1777315e23a63a8845fda1ecd2cce1
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/ACDaemonComm.h
@@ -0,0 +1,77 @@
+//#  ACDaemonComm.h: Communication with ACDaemon
+//#
+//#  Copyright (C) 2002-2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  Note: This source is read best with tabstop 4.
+//#
+//#  $Id$
+
+#ifndef LOFAR_ACCBIN_ACDAEMONCOMM_H
+#define LOFAR_ACCBIN_ACDAEMONCOMM_H
+
+// \file
+// Small class that implements the communication to the ACDaemon (from the
+// Application Controller).
+
+//# Never #include <config.h> or #include <lofar_config.h> in a header file!
+//# Includes
+#include <Common/Net/Socket.h>
+#include <ALC/ACRequest.h>
+
+using namespace LOFAR::ACC::ALC;
+
+namespace LOFAR {
+  namespace ACC {
+
+// \addtogroup ACCbin
+// @{
+
+//# used in ping command
+#define	AC_ALIVE_SIGN	' '
+#define AC_LEAVING_SIGN	'~'
+
+// Implements the communication from the Application Controller to the ACDaemon.
+// The Application Controller needs to send pings to the ACDaemon at regular
+// intervals and must unregister at the daemon when it stops.
+class ACDaemonComm
+{
+public:
+	ACDaemonComm(const string&	host,
+				 const string&	port,
+				 const string&  ID);
+	~ACDaemonComm();
+
+	bool	sendPing();
+	void	unregister();
+
+private:
+	// Copying is not allowed
+	ACDaemonComm(const ACDaemonComm&	that);
+	ACDaemonComm& operator=(const ACDaemonComm& that);
+
+	//# --- Datamembers ---
+	Socket*		itsDaemonSocket;
+	char		itsPingID [ACREQUESTNAMESIZE+1];
+};
+
+// @}	addtogroup
+  } // namespace ACC
+} // namespace LOFAR
+
+#endif
diff --git a/MAC/APL/Appl_Controller/src/ACDaemonMain.cc b/MAC/APL/Appl_Controller/src/ACDaemonMain.cc
new file mode 100644
index 0000000000000000000000000000000000000000..998e308fc81fa73a50ba0a035588b4892c315dcb
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/ACDaemonMain.cc
@@ -0,0 +1,99 @@
+//#  ACDaemonMain.cc: daemon for launching application controllers.
+//#
+//#  Copyright (C) 2002-2005
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  $Id$
+
+//# Always #include <lofar_config.h> first!
+#include <lofar_config.h>
+
+//# Includes
+#include <sys/stat.h>			// umask
+#include <unistd.h>                     // fork, basename
+#include <Common/LofarLogger.h>
+#include <Common/LofarLocators.h>
+#include <Common/Exception.h>
+#include "ACDaemon.h"
+
+using namespace LOFAR;
+using namespace LOFAR::ACC;
+
+// Use a terminate handler that can produce a backtrace.
+Exception::TerminateHandler t(Exception::terminate);
+
+//
+// MAIN (parameterfile)
+//
+int main (int /*argc*/, char* argv[]) {
+
+	// Always bring up the logger first
+	ConfigLocator	aCL;
+	string		progName = basename(argv[0]);
+#ifdef HAVE_LOG4CPLUS
+	string		logPropFile(progName + ".log_prop");
+#else
+	string		logPropFile(progName + ".debug");
+#endif
+#ifdef HAVE_LOG4CPLUS
+	INIT_VAR_LOGGER (aCL.locate(logPropFile).c_str(), progName);
+#else
+        INIT_LOGGER (aCL.locate(logPropFile).c_str());	
+	
+#endif	
+	LOG_DEBUG_STR("Initialized logsystem with: " << aCL.locate(logPropFile));
+
+	// Tell operator we are trying to start up.
+	LOG_INFO_STR("Starting up: " << argv[0]);
+
+	try {
+//#if REAL_DAEMON
+		pid_t pid = fork();
+		switch (pid) {
+		case -1:	// error
+			LOG_FATAL("Unable to fork daemon process, exiting.");
+			return (-1);
+		case 0:		// child (the real daemon)
+			// do nothing;
+			break;
+		default:	// parent
+			LOG_INFO_STR("Daemon succesfully started, pid = " << pid);
+			return (0);
+		}
+//#endif		
+		// TODO: active the next two calls.
+//		setsid();		// disconnect from terminalsession
+//		chdir("/");		// might be on a mounted file system
+		umask(0);		// no limits
+
+		ACDaemon	theDaemon(progName);
+
+		theDaemon.doWork();
+
+		LOG_INFO_STR("Shutting down: " << argv[0]);
+	}
+	catch (LOFAR::Exception&	ex) {
+		LOG_FATAL_STR("Caught exception: " << ex);
+		LOG_FATAL     ("Terminated by exception!");
+		return (1);
+	}
+
+	LOG_INFO("Terminated normally");
+	return (0);
+
+}
diff --git a/MAC/APL/Appl_Controller/src/ACRequestPool.cc b/MAC/APL/Appl_Controller/src/ACRequestPool.cc
new file mode 100644
index 0000000000000000000000000000000000000000..db0f73a09c642df08548fd669cf933133117b99c
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/ACRequestPool.cc
@@ -0,0 +1,271 @@
+//#  ACRequestPool.cc: one line description
+//#
+//#  Copyright (C) 2002-2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  Note: this source is read best with tabstop 4.
+//#
+//#  $Id$
+
+//# Always #include <lofar_config.h> first!
+#include <lofar_config.h>
+
+//# Includes
+#include <arpa/inet.h>
+#include <Common/LofarLogger.h>
+#include <Common/lofar_fstream.h>
+#include <Common/SystemUtil.h>
+#include <cstring>
+#include "ACRequestPool.h"
+
+namespace LOFAR {
+  namespace ACC {
+
+ACRequestPool::ACRequestPool(uint16			firstPortNr, 
+							 uint16			nrOfPorts) :
+	itsFirstPort(firstPortNr),
+	itsLastPort (firstPortNr+nrOfPorts-1),
+	itsNextPort (firstPortNr)
+{}
+
+ACRequestPool::~ACRequestPool()
+{}
+
+//
+// add(anACR)
+//
+// Add (a copy of) the given ACRequest to the pool
+//
+void	ACRequestPool::add    (const ACRequest&		anACR)
+{
+	LOG_TRACE_OBJ_STR("ACRPool: add " << anACR.itsRequester);
+
+	itsPool.push_back(new ACRequest(anACR));		// save ptr to copy
+}
+
+//
+// remove(anACRName)
+//
+// Remove the ACRequest with the given name from the pool
+//
+void	ACRequestPool::remove (const string&		anACRName)
+{
+	LOG_TRACE_OBJ_STR("ACRPool: remove " << anACRName);
+
+	ACRequest*	ACRPtr = search(anACRName);
+	if (ACRPtr) {
+		itsPool.remove(ACRPtr);			// remove ptr from pool
+		delete ACRPtr;					// remove object itself
+	}
+}
+
+//
+// search(anACRName)
+//
+// Searches for an ACRequest with the given name. Returns 0 if not found.
+//
+ACRequest*	ACRequestPool::search (const string&		anACRName)
+{
+	iterator	iter = itsPool.begin();
+
+	while (iter != itsPool.end()) {
+		// Does name match?
+		if (!strcmp(anACRName.c_str(), (*iter)->itsRequester)) {
+			return (*iter);
+		}
+		iter++;
+	}
+
+	return (0);		// No match found
+}
+
+//
+// save(filename)
+//
+// Save the pool to survive power failures.
+//
+bool	ACRequestPool::save (const string&		aFilename)
+{
+	static bool		showedWarning = false;
+
+	ofstream	oFile(aFilename.c_str(), ofstream::out | ofstream::trunc
+													   | ofstream::binary);
+
+	// If the file can not be opened warn the operator once.
+	if (!oFile) {
+		if (!showedWarning) {
+			LOG_WARN("ACDaemon is not powerfailure save!");
+			showedWarning = true;
+		}
+		return (false);
+	}
+
+	LOG_TRACE_RTTI_STR("Saving " << itsPool.size() << " ACrequests to file "
+					   << aFilename);
+
+	uint16	writeVersion = ACREQUEST_VERSION;
+	uint16  count = itsPool.size();
+	oFile.write((char*)(&writeVersion), sizeof(writeVersion));
+	oFile.write((char*)&count, sizeof(count));
+
+	iterator	iter = itsPool.begin();
+	while (iter != itsPool.end()) {
+		oFile.write((char*)(*iter), sizeof(ACRequest));
+		iter++;
+	}
+
+	oFile.close();
+	return (true);
+}
+
+//
+// load (filename)
+//
+// readin file with old admin info
+//
+bool	ACRequestPool::load (const string&		aFilename)
+{
+	ifstream	iFile(aFilename.c_str(), ifstream::in | ifstream::binary);
+	if (!iFile) {					// No file is OK
+		return (false);				// tell we did not load anything
+	}
+
+	uint16		count;
+	uint16		readVersion;
+
+	iFile.read((char*)&readVersion, sizeof(readVersion));// for future V. control
+	iFile.read((char*)&count, sizeof(count));			 // nr elements in file
+
+	LOG_INFO_STR("Loading " << count << " ACrequests from file "
+					   << aFilename);
+
+	while (count) {
+		ACRequest		ACR;
+
+		iFile.read((char*)&ACR, sizeof (ACRequest));
+		ACR.itsPingtime = time(0);				// reset pingtime
+		ACR.itsState = ACRloaded;
+	
+		// report what we loaded.
+		in_addr		IPaddr;
+		IPaddr.s_addr = ACR.itsAddr;
+		LOG_INFO_STR("Application " << ACR.itsRequester << " was at " << 
+							inet_ntoa(IPaddr) << "," << ntohs(ACR.itsPort));
+		add (ACR);
+		--count;
+	}
+
+	iFile.close();
+	return (true);
+}
+
+bool ACRequestPool::assignNewPort(ACRequest*	anACR) 
+{
+	// Controller always run on my own machine
+	anACR->itsAddr = myIPV4Address();	// network byte order
+
+	uint16	startingPort = itsNextPort;
+	uint16	freePort         = 0; // initialise, purely to avoid compiler warning
+	bool	found		 = false;
+	do {
+		// scan pool to see if number is (still) in use.
+		iterator	iter = itsPool.begin();
+		bool		inUse = false;
+		while (!inUse && iter != itsPool.end()) {
+			if ((*iter)->itsPort == itsNextPort) {
+				inUse = true;
+			}
+			++iter;
+		}
+		if ((found = !inUse)) {
+			freePort = itsNextPort;
+		}
+		itsNextPort++;				// increment nextPort for next round.
+		if (itsNextPort > itsLastPort) {
+			itsNextPort = itsFirstPort;
+		}
+	} while (!found && itsNextPort != startingPort);
+
+	if (!found) {
+		LOG_ERROR ("Pool of TCP portnumber of ACDaemon is full. "
+				   "Can not start a new Application Controller");
+		return (false);
+	}
+
+	// fill in portnumber
+	anACR->itsPort = htons(freePort);
+
+	// log assignment
+	in_addr		IPaddr;
+	IPaddr.s_addr = anACR->itsAddr;
+	LOG_INFO_STR (inet_ntoa(IPaddr) << ", " << freePort <<
+				   " assigned to " << anACR->itsRequester);
+
+	return (true);
+}
+
+//
+// cleanupACPool()
+//
+// Remove AC's that did not repsond for more than 5 minutes.
+// Returns true if one or more elements were removed from the pool.
+//
+bool ACRequestPool::cleanup(int32	warnTime, int32	cleanTime)
+{
+	LOG_TRACE_STAT("Checking sign of life of AC's");
+
+	time_t		curTime  = time(0);
+	bool    	modified = false;
+
+	iterator	iter     = itsPool.begin();
+	while (iter != itsPool.end()) {
+		// No sign of life for a long time anymore?? Remove from pool.
+		if ((curTime - (*iter)->itsPingtime) > cleanTime) {
+			// Don't complain about loaded (old) stuff
+			if ((*iter)->itsState != ACRloaded) {
+				LOG_INFO_STR ("No more pings from " << (*iter)->itsRequester <<
+						  ". Removing it from pool");
+			}
+			
+			// iter is destroyed in remove, prepare new iter.
+			iterator	tmp_iter = iter;
+			++tmp_iter;
+
+			// remove the AC from the pool
+			remove((*iter)->itsRequester);
+			modified = true;
+			iter = tmp_iter;
+		} 
+		else {	// When pings stay out a while inform operator
+			if ((curTime - (*iter)->itsPingtime) > warnTime) {
+				// Don't complain about loaded (old) stuff
+				if ((*iter)->itsState != ACRloaded) {
+					LOG_INFO_STR ("No sign of life from " <<
+								  (*iter)->itsRequester);
+					(*iter)->itsState = ACRlosing;
+				}
+			}
+			++iter;
+		}
+	}
+
+	return (modified);
+}
+
+  } // namespace ACC
+} // namespace LOFAR
diff --git a/MAC/APL/Appl_Controller/src/ACRequestPool.h b/MAC/APL/Appl_Controller/src/ACRequestPool.h
new file mode 100644
index 0000000000000000000000000000000000000000..435680c6d52257b686176190beea20ab06809572
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/ACRequestPool.h
@@ -0,0 +1,92 @@
+//#  ACRequestPool.h: small structure used for comm. with ACDaemon
+//#
+//#  Copyright (C) 2002-2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  Note: This source is read best with tabstop 4.
+//#
+//#  $Id$
+
+#ifndef LOFAR_ACCBIN_ACREQUESTPOOL_H
+#define LOFAR_ACCBIN_ACREQUESTPOOL_H
+
+// \file
+// Administrative pool of ACrequests used by the ACDaemon for managing the
+// Application Controllers.
+
+//# Never #include <config.h> or #include <lofar_config.h> in a header file!
+//# Includes
+#include <Common/lofar_list.h>
+#include <ALC/ACRequest.h>
+
+using namespace LOFAR::ACC::ALC;
+
+namespace LOFAR {
+  namespace ACC {
+// \addtogroup ACCbin
+// @{
+
+// The ACRequestPool is internally used by the ACDeamon to manage the
+// resources he owns.
+class ACRequestPool
+{
+public:
+	typedef list<ACRequest*>::iterator			iterator;
+	typedef list<ACRequest*>::const_iterator	const_iterator;
+
+	ACRequestPool(uint16			firstPortnr, 
+				  uint16			nrOfPorts);
+	~ACRequestPool();
+
+	// Element maintenance
+	void add    (const ACRequest&	anACR);
+	void remove (const string&		anACRName);
+
+	// Search for an ACRequest with the given name. If found a pointer to this
+	// ACRequest is returned, otherwise 0 is returned.
+	ACRequest*	search (const string&		anACRName);
+
+	// Store and retrieve whole pool to/from a file for own use.
+	bool save (const string&		aFilename);
+	bool load (const string&		aFilename);
+
+	bool assignNewPort (ACRequest*	anACR);
+	bool cleanup (int32	warnTime, int32	cleanTime);
+
+private:
+	// Not default constructable, need portnumbers.
+	ACRequestPool();
+
+	// Copying is not allowed
+	ACRequestPool(const ACRequestPool&	that);
+
+	// Copying is not allowed
+	ACRequestPool& operator=(const ACRequestPool& that);
+	
+	list<ACRequest*>	itsPool;
+	uint16				itsFirstPort;
+	uint16				itsLastPort;
+	uint16				itsNextPort;
+};
+
+
+// @} addgroup
+  } // namespace ACC
+} // namespace LOFAR
+
+#endif
diff --git a/MAC/APL/Appl_Controller/src/ACcli.cc b/MAC/APL/Appl_Controller/src/ACcli.cc
new file mode 100644
index 0000000000000000000000000000000000000000..dfcf191d466ee9de5d352658c49834c534b1341f
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/ACcli.cc
@@ -0,0 +1,137 @@
+//#  ACcli.cc: commandline client to the ApplicationController
+//#
+//#  Copyright (C) 2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  $Id$
+
+#include <lofar_config.h>
+#include <Common/LofarLogger.h>
+#include <Common/Exception.h>
+#include <ALC/ACSyncClient.h>
+
+using namespace LOFAR;
+using namespace LOFAR::ACC;
+using namespace LOFAR::ACC::ALC;
+
+// Use a terminate handler that can produce a backtrace.
+Exception::TerminateHandler t(Exception::terminate);
+
+void printUsage() {
+  cout << "This program is a commandline client to ACC. It can be used from shell scripts." << endl;
+  cout << endl;
+  cout << "  Usage :" << endl;
+  cout << "    ACcli <unique-id> <command> [options]" << endl;
+  cout << "    " << endl;
+  cout << "  where" << endl;
+  cout << "    <unique-id> is the unique identifier used to connect to a particular process. It should be equal to the identifier used when the process was started using ACcli." << endl;
+  cout << "    <command> is the command to be given to the process. It can be any of:" << endl;
+  cout << "      boot <paramfile>   get ready for starting the process. The next option should be the param file for that process." << endl;
+  cout << "      define             start the process and give it the define command" << endl;
+  cout << "      init   " << endl;
+  cout << "      run    " << endl;
+  cout << "      cancel " << endl;
+  cout << "      pause <condition>  tell the program to pause when the condition is true. The program itself must be able to recognize the string." << endl;
+  cout << "      release   " << endl;
+  cout << "      stop   " << endl;
+  cout << "    " << endl;
+}
+
+int main (int argc, char *argv[]) {
+#ifdef HAVE_LOG4CPLUS
+  INIT_VAR_LOGGER ("../etc/ACcli", basename(argv[0]));
+#else
+  INIT_LOGGER ("../etc/ACcli");	
+#endif
+
+  if (argc < 3) {
+    printUsage();
+    return 1;
+  }
+
+  string myUniqueName(argv[1]);
+  string command(argv[2]);
+
+  bool returnValue = true;
+
+  // Number of processes the user will start
+  // uint16	itsNrProcs;
+  // Expected lifetime of application in minutes
+  // uint32	itsLifetime;
+  // Activity of AC (1/2/3: low/medium/high)
+  // uint16	itsActivityLevel;
+  // Architecture code (0 = Intel, 1 = Blue Gene)
+  // uint16	itsArchitecture;
+
+  // Connect to AC
+  //ACSyncClient ACClient(myUniqueName, nProcs, lifeTime, activityLevel, arch);
+  ACSyncClient ACClient(myUniqueName, 10, 100, 1, 0);
+
+  if (command == "boot"){
+    // Boot(parameterfile): start nodes
+    if (argc < 4) {
+      printUsage();
+      return 1;
+    }
+    returnValue = ACClient.boot(time(0L), argv[3]);
+
+  } else if (command == "define") {
+    // Define : start processes
+    returnValue = ACClient.define(time(0L));
+
+  } else if (command == "init") {
+    // Init: let AP connect to each other
+    returnValue = ACClient.init(time(0L));
+
+  } else if (command == "run") {
+    // Run: do work
+    returnValue = ACClient.run(time(0L));
+
+  } else if (command == "cancel") {
+    // Cancel Command queue
+    returnValue = ACClient.cancelCmdQueue();
+
+  } else if (command == "pause") {
+    // Pause(condition,waitTime)
+    if (argc < 4) {
+      printUsage();
+      return 1;
+    }
+    returnValue = ACClient.pause(time(0), 30, argv[3]);
+
+  } else if (command == "release") {
+    // Cancel Command queue
+    returnValue = ACClient.release(time(0L));
+
+  } else if (command == "stop") {
+    // Quit: stop processes
+    returnValue = ACClient.quit(time(0));
+
+  } else {
+    printUsage();
+  }
+
+  if (returnValue) {
+      // everything ok
+      return 0;
+  } else {
+      // there was an error
+      return 1;
+  };
+}
+
diff --git a/MAC/APL/Appl_Controller/src/ACuserMenu.cc b/MAC/APL/Appl_Controller/src/ACuserMenu.cc
new file mode 100644
index 0000000000000000000000000000000000000000..434111e61c1a0b345972c6ce01da0137cf3e6881
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/ACuserMenu.cc
@@ -0,0 +1,360 @@
+//#  ACUserMenu.cc: Menu-program for manual testing an ACC controlled application.
+//#
+//#  Copyright (C) 2004-2007
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  $Id$
+
+//# Always #include <lofar_config.h> first!
+#include <lofar_config.h>
+
+#include <Common/LofarLogger.h>
+#include <Common/LofarLocators.h>
+#include <Common/Exception.h>
+#include <Common/hexdump.h>
+#include <Common/StringUtil.h>
+#include <ALC/ACSyncClient.h>
+#include <time.h>
+#include "myACClientFunctions.h"
+
+using namespace LOFAR;
+using namespace LOFAR::ACC;
+using namespace LOFAR::ACC::ALC;
+
+// Use a terminate handler that can produce a backtrace.
+Exception::TerminateHandler t(Exception::terminate);
+
+myACClientFunctions		myACF;
+ApplControlClient*		ACClient    = 0;
+bool					connected   = false;
+bool					IsSync		= false;
+time_t					delayTime	= 0;
+string					paramfile ("Observation-CygA.param");
+
+// Note: function does nothin on sync-connections
+void waitForAnswer()
+{
+	if (!IsSync) {
+		cout << "Waiting for result from command" << endl;
+		while (!ACClient->processACmsgFromServer()) {
+			;
+		}
+	}
+
+	if (delayTime) {
+		cout << "Command is placed on stack, waiting for real result" << endl;
+		while(!ACClient->processACmsgFromServer()) {
+			;
+		}
+	}
+}
+
+
+// enter delayTime
+void doDelayTime()
+{
+	cout << "Enter delaytime in seconds: ";
+	string	timeString;
+	cin >> timeString;
+	delayTime = atol(timeString.c_str());
+}
+
+// Connect to AC
+void doConnect()
+{
+	if (connected) {
+		cout << "Already connected!" << endl;
+		sleep (2);
+		return;
+	}
+
+	cout << "(A)sync connection or (S)ync connection? ";
+	char	comType;
+	cin >> comType;
+	
+	if (comType == 's' || comType == 'S') {
+		ACClient = new ACSyncClient("myUniqName", 10, 100, 1, 0);
+		IsSync = true;
+	}
+	else {
+		ACClient = new ACAsyncClient(&myACF, "myUniqName", 10, 100, 1, 0);
+		IsSync = false;
+	}
+
+	connected   = true;
+}
+
+// Disconnect from AC
+void doDisconnect()
+{
+	if (ACClient) {
+		delete ACClient;
+	}
+
+	connected = false;
+}
+
+// Boot(parameterfile): start nodes
+void doBoot()
+{
+	cout << "Enter name of parameterfile (" << paramfile << "): ";
+	string	aParFile;
+	cin.clear();
+	cin >> aParFile;
+	if (aParFile.length() > 2) {
+		paramfile = aParFile;
+	}
+
+	cout << "Sending boot command" << endl;
+	bool	result = ACClient->boot(time(0L)+delayTime, paramfile);
+	if (result) {
+		waitForAnswer();
+	}
+	if (result) {
+		cout << "Application processes should be running now" << endl;
+	}
+	else {
+		cout << "ERROR during boot command" << endl;
+		sleep (2);
+	}
+
+}
+
+// Define : start processes
+void doDefine()
+{
+	cout << "Sending define command" << endl;
+	bool result = ACClient->define(time(0L)+delayTime);
+	if (result) {
+		waitForAnswer();
+	}
+	if (result) {
+		cout << "Application processes should have claimed the resources" << endl;
+	}
+	else {
+		cout << "ERROR during define command" << endl;
+		sleep (2);
+	}
+}
+
+// Init: let AP connect to each other
+void doInit()
+{
+	cout << "Sending init command" << endl;
+	bool result = ACClient->init(time(0L)+delayTime);
+	if (result) {
+		waitForAnswer();
+	}
+	if (result) {
+		cout << "Application processes should be in hot-standby mode" << endl;
+	}
+	else {
+		cout << "ERROR during init command" << endl;
+		sleep (2);
+	}
+}
+
+// Run: do work
+void doRun()
+{
+	cout << "Sending run command" << endl;
+	bool result = ACClient->run(time(0L)+delayTime);
+	if (result) {
+		waitForAnswer();
+	}
+	if (result) {
+		cout << "Application processes must running now" << endl;
+	}
+	else {
+		cout << "ERROR during run command" << endl;
+		sleep (2);
+	}
+}
+
+// Cancel Command queue
+void doCancel()
+{
+	cout << "Sending CancelQueue command" << endl;
+	bool result = ACClient->cancelCmdQueue();
+	if (result) {
+		waitForAnswer();
+	}
+	if (result) {
+		cout << "Queue should be flushed by now." << endl;
+	}
+	else {
+		cout << "ERROR during cancelqueue command" << endl;
+		sleep (2);
+	}
+}
+
+// Pause(condition,waitTime)
+void doPause()
+{
+	string	answer;
+	string	option;
+
+	// ask user condition
+	answer.clear();
+	while (answer.empty()) {
+		cout << "What condition must be used? " << endl;
+		cout << "N	now -> immediately" << endl;
+		cout << "A	asap -> without corrupting anything" << endl;
+		cout << "T	timestamp -> at some defined time" << endl;
+		getline(cin, answer);
+		if (answer == "N") {
+			option="now";
+		}
+		else if (answer == "A") {
+			option = "asap";
+		}
+		else if (answer == "T") {
+			cout << "Over how many seconds should the application stop?" << endl;
+			cout << "  ( based on the timestamp off the datasamples)  : " << endl;
+			answer.clear();
+			getline(cin, answer);
+			uint32	sampleTime = time(0L) + atol(answer.c_str());
+			option = "timestamp=" + toString(sampleTime);
+		}
+	} 
+	
+	cout << "Sending pause(" << option << ") command" << endl;
+	bool result = ACClient->pause(time(0)+delayTime,30,option);
+	if (result) {
+		waitForAnswer();
+	}
+	if (result) {
+		cout << "Application processes should be paused by now" << endl;
+	}
+	else {
+		cout << "ERROR during pause command" << endl;
+		sleep (2);
+	}
+}
+
+// Release: free resources
+void doRelease()
+{
+	cout << "Sending release command" << endl;
+	bool result = ACClient->release(time(0)+delayTime);
+	if (result) {
+		waitForAnswer();
+	}
+	if (result) {
+		cout << "Application processes released their resources." << endl;
+	}
+	else {
+		cout << "ERROR during release command" << endl;
+		sleep (2);
+	}
+
+}
+
+
+// Quit: stop processes
+void doStop()
+{
+	cout << "Sending quit command" << endl;
+	bool result = ACClient->quit(time(0)+delayTime);
+	if (result) {
+		waitForAnswer();
+	}
+	if (result) {
+		cout << "Application processes should be killed by now" << endl;
+	}
+	else {
+		cout << "ERROR during quit command" << endl;
+		sleep (2);
+	}
+
+}
+
+
+void showMenu()
+{
+	cout << endl << endl << endl;
+	cout << formatString("%s connection with AC\n", 
+							connected ? (IsSync ? "Sync" : "Async") : "No");
+	cout << "Time delay: " << delayTime << endl << endl;
+		
+	
+	cout << "Commands" << endl;
+	if (!connected) {
+		cout << "c   Connect to AC" << endl << endl;
+	}
+	else {
+		cout << "D   Disconnect from AC" << endl << endl;
+	
+		cout << "T   Set delayTime for commands" << endl << endl;
+
+		cout << "b   Boot(parameterfile): start processes" << endl;
+		cout << "d   Define : allocate resources [CLAIM]" << endl;
+		cout << "i   Init   : Go to hot-standby  [PREPARE]" << endl;
+		cout << "r   Run    : do work            [RESUME]" << endl;
+		cout << "p   Pause(condition,waitTime)   [SUSPEND]" << endl;
+		cout << "R   Release: free resources     [RELEASE]" << endl;
+		cout << "s   Quit   : stop processes     [QUIT]" << endl << endl;
+		cout << "c   Cancel : Command Queue" << endl;
+	}
+
+	cout << "q   Quit this program" << endl << endl;
+
+	cout << "Enter letter of your choice: ";
+}
+
+int main (int /*argc*/, char *argv[]) {
+	ConfigLocator	aCL;
+	string			progName(basename(argv[0]));
+#ifdef HAVE_LOG4CPLUS
+        string			logPropFile(progName + ".log_prop");
+	INIT_LOGGER (aCL.locate(logPropFile).c_str());
+#else
+        string logPropFile(progName + ".debug");
+        INIT_LOGGER (aCL.locate(logPropFile).c_str());	
+#endif
+
+	char		aChoice = ' ';
+	while (aChoice != 'q') {
+		showMenu();
+		cin >> aChoice;
+		switch (aChoice) {
+		case 'C':
+		case 'c':	if (!connected) {
+						doConnect();
+					}
+					else {
+						doCancel();
+					}
+					break;
+		case 'D':	doDisconnect();		break;
+		case 'T':	doDelayTime();		break;
+		case 'b':	doBoot();			break;
+		case 'd':	doDefine();			break;
+		case 'i':	doInit();			break;
+		case 'r':	doRun();			break;
+		case 'p':	doPause();			break;
+		case 'R':	doRelease();		break;
+		case 's':	doStop();			break;
+		}
+	}
+
+	doDisconnect();
+
+}
+
+
diff --git a/MAC/APL/Appl_Controller/src/ACuserMenu.log_prop b/MAC/APL/Appl_Controller/src/ACuserMenu.log_prop
new file mode 100644
index 0000000000000000000000000000000000000000..c405e630daa8bd5eedb288ad866813771742b006
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/ACuserMenu.log_prop
@@ -0,0 +1,24 @@
+
+# Configure the loggers
+log4cplus.rootLogger=DEBUG, STDOUT, FILE
+log4cplus.logger.TRC=INFO
+log4cplus.logger.LCS.Common=FATAL, STDOUT, FILE
+
+# Define the appenders
+log4cplus.appender.STDOUT=log4cplus::ConsoleAppender
+log4cplus.appender.STDOUT.layout=log4cplus::PatternLayout
+log4cplus.appender.STDOUT.layout.ConversionPattern=%D{%d-%m %H:%M:%S.%q} %-5p %c{3} - %m [%.25l]%n
+
+log4cplus.appender.STDERR=log4cplus::ConsoleAppender
+log4cplus.appender.STDERR.layout=log4cplus::PatternLayout
+log4cplus.appender.STDERR.layout.ConversionPattern=%D{%d-%m %H:%M:%S.%q} %-5p %c{3} - %m [%.25l]%n
+log4cplus.appender.STDERR.logToStdErr=true
+
+log4cplus.appender.FILE=log4cplus::RollingFileAppender
+log4cplus.appender.FILE.File=/opt/lofar/var/log/${LOG4CPLUS_LOGFILENAME}.log
+log4cplus.appender.FILE.MaxFileSize=10MB
+log4cplus.appender.FILE.MaxBackupIndex=2
+log4cplus.appender.FILE.layout=log4cplus::PatternLayout
+log4cplus.appender.FILE.layout.ConversionPattern=%x %D{%d-%m %H:%M:%S.%q} %-5p %c{3} - %m [%.25l]%n
+
+log4cplus.appender.DUMP=log4cplus::NullAppender
diff --git a/MAC/APL/Appl_Controller/src/APAdmin.cc b/MAC/APL/Appl_Controller/src/APAdmin.cc
new file mode 100644
index 0000000000000000000000000000000000000000..7aab806a00273b08799df0457e93bb7ec3b7a350
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/APAdmin.cc
@@ -0,0 +1,150 @@
+//#  APAdmin.cc: Enables a poll on a collection of dataholders.
+//#
+//#  Copyright (C) 2002-2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  $Id$
+
+//# Always #include <lofar_config.h> first!
+#include <lofar_config.h>
+
+//# Includes
+#include <Common/LofarLogger.h>
+#include "APAdmin.h"
+
+namespace LOFAR {
+  namespace ACC {
+
+
+//
+// APAdmin(Socket*)
+//
+// Constructs a new APAdmin object including a blank DH_ProcControl. The given
+// Socket is attached to the APAdmin.
+//
+APAdmin::APAdmin(Socket*	aSocket) :
+	itsName			(""),
+	itsDHPC         (new DH_ProcControl),
+	itsSocket       (aSocket),
+	itsBytesToRead  (0),
+	itsReadOffset   (0),
+	itsReadingHeader(true),
+	itsState        (APSconn)
+{
+	itsBytesToRead = itsDHPC->getHeaderSize();	// always start with the header
+	itsDHPC->init();							// construct DH layout
+}
+
+//
+// ~APAdmin()
+//
+APAdmin::~APAdmin()
+{
+	if (itsDHPC) {				// the 'if's are superfluous but safer.
+		delete	itsDHPC;
+	}
+	if (itsSocket) {
+		delete	itsSocket;
+	}
+}
+
+
+//
+// bool read ()
+//
+// Tries to read the missing bytes from the Socket into the DataHolder.
+// When the DataHolder is full true is returned, otherwise false.
+//
+bool APAdmin::read()
+{
+	LOG_TRACE_RTTI ("APAdmin:read");
+
+	if (itsState == APSdiscon || itsState == APSfail) {
+		LOG_TRACE_RTTI ("APAdmin:read:Socket disconnected or in fail state");
+		return(false);
+	}
+
+	itsState = APSread;
+
+	int32	newBytes = itsSocket->read(
+				static_cast<char*>(itsDHPC->getDataPtr()) + itsReadOffset, 
+				itsBytesToRead);
+
+	if (newBytes < 0) {
+		if (newBytes != Socket::INCOMPLETE) { 	// serious error
+			LOG_TRACE_RTTI ("APAdmin:read:Setting socket in fail state");
+			itsState = APSfail;
+		}
+		return (false);
+	}
+
+	itsBytesToRead -= newBytes;				// update admin
+	itsReadOffset  += newBytes;
+
+	if (itsBytesToRead > 0) {				// still bytes missing?
+		return (false);
+	}
+
+	if (!itsReadingHeader) {							// Last part read?
+		itsBytesToRead   = itsDHPC->getHeaderSize();	// prepare for next msg
+		itsReadingHeader = true;
+		itsReadOffset    = 0;
+		itsDHPC->unpack();								// unpack the data
+		return (true);									// tell msg is avail.
+	}
+
+	// prepare for reading the remaining datapart.
+	itsReadingHeader     = false;
+	int32	totalMsgSize = DataHolder::getDataLength (itsDHPC->getDataPtr());
+	itsDHPC->resizeBuffer (totalMsgSize);
+	itsBytesToRead       = totalMsgSize - itsDHPC->getHeaderSize();
+
+	return (read());						// call ourself for last part
+}
+
+//
+// bool write (buffer, size)
+//
+// Write the given bytes to the Socket.
+// Returns false if socket is/turns_out_to_be disconnected.
+//
+bool APAdmin::write(void*		aBuffer,
+					int32		aSize)
+{
+	LOG_TRACE_RTTI ("APAdmin:write");
+
+	if (itsState == APSdiscon || itsState == APSfail) {		// check current state
+		LOG_TRACE_RTTI ("APAdmin:write:Socket disconnected or in fail state");
+		return(false);
+	}
+
+	int32 result = itsSocket->write(aBuffer, aSize);		// do write
+
+	if ((result < 0 ) && (result != Socket::INCOMPLETE)) {	// serious error?
+		LOG_TRACE_RTTI ("APAdmin:write:Setting socket in fail state");
+		itsState = APSfail;									// set failure
+		return (false);
+	}
+	
+	itsState = APSwrite;									// seems ok
+	return (true);
+}
+
+
+  } // namespace ACC
+} // namespace LOFAR
diff --git a/MAC/APL/Appl_Controller/src/APAdmin.h b/MAC/APL/Appl_Controller/src/APAdmin.h
new file mode 100644
index 0000000000000000000000000000000000000000..21de52204f9457cd0eb6bd660e88e90e940a035d
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/APAdmin.h
@@ -0,0 +1,164 @@
+//#  APAdmin.h: Internal administration of an AP for the Appl. Controller.
+//#
+//#  Copyright (C) 2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  Note: This source is read best with tabstop 4.
+//#
+//#  $Id$
+
+#ifndef LOFAR_ACCBIN_APADMIN_H
+#define LOFAR_ACCBIN_APADMIN_H
+
+// \file
+// Internal information of an Application Process used by the
+// Application Controller.
+
+//# Never #include <config.h> or #include <lofar_config.h> in a header file!
+//# Includes
+#include <Common/Net/Socket.h>
+#include <PLC/DH_ProcControl.h>
+
+using namespace LOFAR::ACC::PLC;
+
+namespace LOFAR {
+  namespace ACC {
+// \addtogroup ACCbin
+// @{
+
+// The APAdmin class uses a internal variable to register the state of the
+// Socket.
+enum APAState {
+		APSconn, APSdiscon, APSread, APSwrite, APSfail
+};
+
+// The APAdmin class is a collection of information the Application Controller
+// needs for its administration of the Application Processes (AP's). 
+// It consists of a dataholder for reading data from the AP, a Socket the AP 
+// is connected to, and some less important flags and values.
+class APAdmin
+{
+public:
+	// An APAdmin is always needed after a new Socket was created after a
+	// call on a listener socket. So the constructor always needs this Socket.
+	// An empty dataholder for the AP is constructed automatically.
+	explicit APAdmin (Socket*	aSocket);
+	
+	~APAdmin();
+
+	// \name Functions for reading and writing to the AP.
+	// @{
+
+	// Tries to read the missing bytes from the Socket into the DataHolder.
+	// When the dataholder is full \c true is returned, otherwise \c false.
+	bool 	read();
+
+	// Writes the contents of the dataHolder to the Socket. Returns \c false
+	// if the Socket is/turns out to be disconnected.
+	bool 	write(void*		aBuffer,
+				  int32		aSize);
+	// @}
+
+	// \name Accessor functions.
+	// @{
+	void				setName(const string&	aName);
+	string				getName()     const;
+	DH_ProcControl*		getDH()		  const;
+	int32				getSocketID() const;
+	APAState			getState()	  const;
+	// @}
+
+private:
+	// Not default constructable;
+	APAdmin();
+
+	// Copying is not allowed
+	APAdmin(const APAdmin&	that);
+
+	// Copying is not allowed
+	APAdmin& operator=(const APAdmin& that);
+
+	//# --- datamembers ---
+	// name of application process
+	string				itsName;			
+
+	// The dataholder used for reading from the AP.
+	DH_ProcControl*		itsDHPC;			
+
+	// Socket to AP is connected to
+	Socket*				itsSocket;			
+
+	// Number of bytes still to read
+	uint32				itsBytesToRead;		
+
+	// Readoffset in the buffer
+	uint32				itsReadOffset;		
+
+	// Reading header or data part
+	bool				itsReadingHeader;	
+
+	// State of APAdmin
+	APAState			itsState;			
+};
+
+//# -------------------- inline functions --------------------
+//#
+//# getDH()
+//#
+inline DH_ProcControl* APAdmin::getDH() const
+{
+	return (itsDHPC);
+}
+
+//#
+//# getSocketID()
+//#
+inline int32 APAdmin::getSocketID() const
+{
+	return (itsSocket->getSid());
+}
+
+//#
+//# getState()
+//#
+inline APAState APAdmin::getState() const
+{
+	return (itsState);
+}
+
+//#
+//# setName(name)
+//#
+inline void APAdmin::setName(const string&	aName) 
+{
+	itsName = aName;
+	itsState = APSconn;
+}
+
+//#
+//# getName()
+//#
+inline string	APAdmin::getName() const
+{
+	return (itsName);
+}
+
+// @} addgroup
+  } // namespace ACC
+} // namespace LOFAR
+#endif
diff --git a/MAC/APL/Appl_Controller/src/APAdminPool.cc b/MAC/APL/Appl_Controller/src/APAdminPool.cc
new file mode 100644
index 0000000000000000000000000000000000000000..7d44a541da44e9083444370024b28a339ce60aba
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/APAdminPool.cc
@@ -0,0 +1,216 @@
+//#  APAdminPool.cc: Enables a poll on a collection of dataholders.
+//#
+//#  Copyright (C) 2002-2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  $Id$
+
+//# Always #include <lofar_config.h> first!
+#include <lofar_config.h>
+
+//# Includes
+#include <Common/LofarLogger.h>
+#include "APAdminPool.h"
+
+namespace LOFAR {
+  namespace ACC {
+
+APAdminPool*		APAdminPool::theirAPAdminPool = 0;
+
+
+//
+// getInstance()
+//
+APAdminPool&	APAdminPool::getInstance() 
+{
+	LOG_TRACE_OBJ ("APAdminPool::getInstance()");
+
+	if (theirAPAdminPool == 0) {
+		theirAPAdminPool = new APAdminPool;
+	}
+
+	return (*theirAPAdminPool);
+}
+
+
+APAdminPool::APAdminPool() :
+	itsNrAcksToRecv(0),
+	itsLastCmd     (PCCmdNone),
+	itsCurElement  (0)
+{
+}
+
+APAdminPool::~APAdminPool()
+{}
+
+//
+// void add(APAdmin*)
+//
+void APAdminPool::add   (APAdmin*	anAPAdmin)
+{
+	LOG_TRACE_RTTI_STR ("APAdminPool::add(" << anAPAdmin << ")");
+
+	itsAPAPool.insert (itsAPAPool.begin(), anAPAdmin);
+	itsReadMask.add(anAPAdmin->getSocketID());		// schedule for read
+}
+
+//
+// void remove(APAdmin*)
+//
+void APAdminPool::remove(APAdmin*	anAPAdmin) throw(Exception)
+{
+	LOG_TRACE_RTTI_STR ("APAdminPool::remove(" << anAPAdmin << ")");
+
+	iterator	iter = itsAPAPool.begin();
+
+	while (iter != itsAPAPool.end()) {				// search dataholder
+		if (*iter == anAPAdmin) {
+			// Don't read, write or expect an Ack from this AP anymore
+			itsReadMask.remove(anAPAdmin->getSocketID());
+			markAsOffline(anAPAdmin);
+			registerAck  (itsLastCmd, *iter);
+			itsAPAPool.erase(iter);					// remove from pool
+			setCurElement(itsCurElement);			// boundary check
+			return;									// ready
+		}
+		++iter;
+	}
+	THROW(Exception, "DataHolder " << anAPAdmin << "not in pool");
+}
+
+// loop over all dataholders to see if data is ready.
+// Start scan where we stopped last time.
+// TODO:rewrite for select call
+APAdmin*	APAdminPool::poll(time_t		waitTime)
+{
+  (void)waitTime;
+
+	for (int i = itsCurElement; i < itsReadMask.count(); ++i) {
+		LOG_TRACE_COND_STR("poll at " << i);
+		if (itsAPAPool.at(i)->read()) {
+			setCurElement (i+1);
+			return (itsAPAPool.at(i));
+		}
+	}
+	itsCurElement = 0;
+	
+	return (0);
+}
+
+//
+// void writeToAll(command, options)
+//
+void APAdminPool::writeToAll(PCCmd			command,
+							 const string&	options)
+{
+	// Construct a APAdmin with the info to send to all processes.
+	DH_ProcControl      DHCommand;
+	DHCommand.init();
+	DHCommand.setCommand (command);
+	DHCommand.setOptions (options);
+	DHCommand.setResult  (0);
+	DHCommand.pack();           // Construct the messagebuffer
+
+	// Write the DataHolder to all Sockets in the pool.
+	void*		aBuffer = DHCommand.getDataPtr();
+	int32		aSize   = DHCommand.getDataSize();
+	iterator	iter    = itsAPAPool.begin();
+	while (iter != itsAPAPool.end()) {				// search dataholder
+		if (itsOnlineMask.isSet((*iter)->getSocketID())) {
+			// TODO: should we do something with the return value???
+			(*iter)->write(aBuffer, aSize);
+		}
+		++iter;
+	}
+
+	startAckCollection(command);
+}
+
+
+//
+// registerAck(command, apadmin)
+//
+bool APAdminPool::registerAck(PCCmd			aCommand,
+							  APAdmin*		anAPAdmin)
+{
+	if (aCommand != itsLastCmd) {
+		if (itsLastCmd == PCCmdNone) {
+			LOG_DEBUG_STR("Process " << anAPAdmin->getName() <<
+					  " is late, Ack received for " << PCCmdName(aCommand));
+		}
+		else {
+			LOG_WARN_STR("Process " << anAPAdmin->getName() <<
+					  " is out of sync, Ack received for " << PCCmdName(aCommand) << 
+					  " iso " << PCCmdName(itsLastCmd));
+		}
+		return (false);
+	}
+
+	if (itsAckList.isSet(anAPAdmin->getSocketID())) {
+		itsAckList.remove(anAPAdmin->getSocketID());
+		--itsNrAcksToRecv;
+	}
+	return (true);
+}
+
+// cleanup APAdmins that lost connection
+// When one is found the DH is removed from the pool, the search is stopped
+// and the DataHolder is returned to the user to do additional cleanup.
+//
+// NOTE: the algorithm is not very efficient because it exits on the first
+// APAdmin that is disconnected. Repeated calls to this routine will repeatedly
+// check the front of the pool.
+// A more efficient way to do this is with a 'cur' variable as it is solved
+// in the poll method.
+APAdmin* 	APAdminPool::cleanup()
+{
+	APAdmin*		anAPA;
+	for (int i = 0; i < itsReadMask.count(); ++i) {
+		anAPA = itsAPAPool.at(i);
+		if (anAPA->getState() == APSfail) {
+			LOG_DEBUG_STR("APAdminPool:cleanup " << i);
+			remove(anAPA);					// remove it from the pool also
+			return(anAPA);					// let user do other cleanup
+		}
+	}
+	return (0);								// nothing deleted.
+}
+
+//
+// operator<<
+//
+std::ostream&	operator<< (std::ostream& os, const APAdminPool& anAPAP)
+{
+	os << "Reading: " << const_cast<FdSet*>
+						(&(anAPAP.itsReadMask))->getSet()->fds_bits[0]   << 
+						"(" << anAPAP.itsReadMask.count()   << ")" << endl;
+	os << "Writing: " << const_cast<FdSet*>
+						(&(anAPAP.itsOnlineMask))->getSet()->fds_bits[0] << 
+						"(" << anAPAP.itsOnlineMask.count() << ")" << endl;
+	os << "AckColl: " << const_cast<FdSet*>
+						(&(anAPAP.itsAckList))->getSet()->fds_bits[0]    << 
+						"(" << anAPAP.itsNrAcksToRecv << ")" << endl;
+	if (anAPAP.itsLastCmd != PCCmdNone) {
+		os << "Command: " << anAPAP.itsLastCmd << endl;
+	}
+
+	return (os);
+}
+
+  } // namespace ACC
+} // namespace LOFAR
diff --git a/MAC/APL/Appl_Controller/src/APAdminPool.h b/MAC/APL/Appl_Controller/src/APAdminPool.h
new file mode 100644
index 0000000000000000000000000000000000000000..109e36f805ed5a64b515ab177db0bf4c59c4731d
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/APAdminPool.h
@@ -0,0 +1,256 @@
+//#  APAdminPool.h: Administation of the AP's for the Appl. controller
+//#
+//#  Copyright (C) 2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  Note: This source is read best with tabstop 4.
+//#
+//#  $Id$
+
+#ifndef LOFAR_ACCBIN_APADMINPOOL_H
+#define LOFAR_ACCBIN_APADMINPOOL_H
+
+// \file
+// Collection of APAdmin classes used by the Application Controller for
+// managing the Application Processes.
+
+//# Never #include <config.h> or #include <lofar_config.h> in a header file!
+//# Includes
+#include <Common/lofar_vector.h>
+#include <Common/Net/FdSet.h>
+#include "APAdmin.h"
+
+namespace LOFAR {
+  namespace ACC {
+// \addtogroup ACCbin
+// @{
+
+// The APAdminPool object manages a pool of APAdmin objects. An APAdmin object
+// is a pair of a DataHolder and a Socket. The surplus value of the APAdminPool
+// is that is can perform an action of all the APAdmin objects it holds.
+// Since the APAdminPool has knowledge of all the Processes and its connection
+// state it is extended with administrative functions for collecting ACK
+// messages.
+class APAdminPool
+{
+	typedef vector<APAdmin*>			APAList;
+	typedef vector<APAdmin*>::iterator	iterator;
+
+public:
+	// APAdminPool is a singleton class.
+	static APAdminPool&		getInstance();
+	virtual 				~APAdminPool();
+
+	// \name Maintenance on the APAdmin members
+	// Functions for maintaining the pool of APAdmin objects.
+	// @{
+
+	// Adds the given APAdmin to the pool.
+	void add   (APAdmin*	anAPAdmin);
+
+	// Removes the given APAdmin from the pool. Throws an exception if the
+	// APAdmin is not in the pool.
+	void remove(APAdmin*	anAPAdmin) throw(Exception);
+	// @}
+	
+	// \Managing process state
+	// The APAdminPool knows of every connected process if it is ready to
+	// receive messages of not.
+	// @{
+	
+	// The given APAdmin is ready to receive commands
+	void markAsOnline (APAdmin*		anAPAdmin);
+
+	// Don't send any more messages to this APAdmin.
+	void markAsOffline(APAdmin*		anAPAdmin);
+	// @}
+
+	// \name Functions for Ack administration
+	// @{
+
+	// When calling \c startAckCollection all processes that are marked as
+	// 'online' are also marked 'shouldSendAnAck'. The Acks that are send by
+	// the processes should be a respons on command \c aCommand.
+	void startAckCollection(PCCmd			aCommand);
+
+	// Tell the APAdminPool that on this APAdmin an Ack message was received
+	// for the given command. Tell the APAdminPool that on this APAdmin an Ack
+	// message was received. Registering an Ack for the wrong command has no 
+	// effect.
+	bool registerAck       (PCCmd			aCommand,
+							APAdmin*		anAPAdmin);
+
+	// Cancel the collection of Acks. When Acks are registered after this call
+	// they have no effect anymore.
+	void stopAckCollection ();
+
+	// Check if all Acks are received.
+	bool allAcksReceived   ();
+	// @}
+
+	// \name Actions on the pool
+	// The following actions are executed on all elements of the pool.
+	// @{
+
+	// Continues its previous poll-sequence on the elements in its pool.
+	// Returns with a pointer to the APAdmin that has received a complete
+	// message. Returns 0 if the end of the pool is reached.<br>
+	// To do a single read on all elements of the pool:
+	// \code
+	//   while ((activeAP = myAPAdminPool.poll()) {
+	//      ... do something with the data of the 'activeAP'
+	//   }
+	// \endcode
+	APAdmin*	poll        (time_t			waitTime);
+
+	// Continues its previous cleanup-sequence on the elements in its pool.
+	// Returns with a pointer to the APAdmin that has received a complete
+	// message. Returns 0 if the end of the pool is reached.<br>
+	// To do a single read on all elements of the pool:
+	// \code
+	//   while ((deadAP = myAPAdminPool.cleanup()) {
+	//      ... do some final task with 'deadAP'
+	//      delete deadAP
+	//   }
+	// \endcode
+	APAdmin*	cleanup     ();
+
+	// Contructs a DH_ProcControl object from the passed arguments and sends
+	// this dataholder to all elements in its pool.
+	// After sending it to all elements \c startAckCollection is called to
+	// remember from with processes a respons is expected.
+	void 		writeToAll(PCCmd			command,
+						   const string&	options);
+	// @}
+
+	// \name Accessor methods
+	// @{
+
+	// Returns the number of processes in its pool.
+	uint16		processCount();
+
+	// Returns the number of processes in its pool that have told that they
+	// are ready to receive data.
+	uint16		onlineCount ();
+	// @}
+
+	friend std::ostream& operator<< (std::ostream& os, const APAdminPool& anAPAP);
+
+private:
+	// Not default contructable.
+	APAdminPool();
+
+	// Copying is not allowed.
+	APAdminPool(const APAdminPool&	that);
+
+	// Copying is not allowed.
+	APAdminPool& operator=(const APAdminPool& that);
+
+	// Internal command for adjusting the index for the poll method.
+	void setCurElement(uint16	aValue);
+
+	// The APAdminPool is a singleton.
+	static		APAdminPool*		theirAPAdminPool;
+
+	APAList		itsAPAPool;			// vector of APAdmin objects
+	FdSet		itsReadMask;		// selector mask
+	FdSet		itsOnlineMask;		// Procs that are ready to receive commands
+	FdSet		itsAckList;			// Procs still to receive an Ack from
+	uint16		itsNrAcksToRecv;	// Nr of Acks still to receive.
+	PCCmd		itsLastCmd;			// Last/current outstanding AP command
+	uint16		itsCurElement;		// Last element we polled.
+};
+
+//# -------------------- inline functions --------------------
+//#
+//# setCurElement(value)
+//#
+inline void APAdminPool::setCurElement(uint16	aValue)
+{
+	if (aValue >= itsReadMask.count()) {		// check upper boundary
+		itsCurElement = 0;
+	}
+	else {
+		itsCurElement = aValue;
+	}
+}
+
+//#
+//# processCount
+//#
+inline uint16 APAdminPool::processCount()
+{
+	return (itsReadMask.count());
+}
+
+//#
+//# onlineCount
+//#
+inline uint16 APAdminPool::onlineCount()
+{
+	return (itsOnlineMask.count());
+}
+
+//#
+//# markAsOnline(APAdmin*)
+//#
+inline void APAdminPool::markAsOnline(APAdmin*		anAPAdmin)
+{
+	itsOnlineMask.add(anAPAdmin->getSocketID());		// schedule for writes
+}
+	
+//#
+//# markAsOffLine(apadmin)
+//#
+inline void APAdminPool::markAsOffline(APAdmin*		anAPAdmin)
+{
+	itsOnlineMask.remove(anAPAdmin->getSocketID());
+}
+	
+//#
+//# startAckColection(command)
+//#
+inline void APAdminPool::startAckCollection(PCCmd  aCommand) 
+{
+	itsAckList      = itsOnlineMask;
+	itsNrAcksToRecv = itsOnlineMask.count();
+	itsLastCmd      = aCommand;
+}
+
+//#
+//# stopAckCollection()
+//#
+inline void APAdminPool::stopAckCollection()
+{
+	itsAckList.clear();
+	itsNrAcksToRecv = 0;
+	itsLastCmd      = PCCmdNone;
+}
+
+//#
+//# allAcksReceived
+//#
+inline bool APAdminPool::allAcksReceived()
+{
+	return (itsLastCmd != PCCmdNone && itsNrAcksToRecv == 0);
+}
+
+// @} addgroup
+  } // namespace ACC
+} // namespace LOFAR
+#endif
diff --git a/MAC/APL/Appl_Controller/src/ApplController.cc b/MAC/APL/Appl_Controller/src/ApplController.cc
new file mode 100644
index 0000000000000000000000000000000000000000..e8a705370b1631223b91d3b58ccf90057a39a48e
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/ApplController.cc
@@ -0,0 +1,872 @@
+//#  ApplController.cc: Controls all processes of an application.
+//#
+//#  Copyright (C) 2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  $Id$
+
+//# Always #include <lofar_config.h> first!
+#include <lofar_config.h>
+
+//# Includes
+#include <Common/LofarLogger.h>
+#include <Common/LofarLocators.h>
+#include <Common/StringUtil.h>
+#include <ApplCommon/LofarDirs.h>
+#include <ALC/ACCmd.h>
+#include <PLC/ProcControlComm.h>
+#include <MACIO/MACServiceInfo.h>
+#include <MACIO/KVT_Protocol.ph>
+#include "ApplController.h"
+#include "PR_Shell.h"			// TODO: factory!
+#include "PR_MPI.h"				// TODO: factory!
+#include "PR_BGL.h"				// TODO: factory!
+#include "ItemList.h"			// @@
+
+namespace LOFAR {
+  using namespace MACIO;
+  namespace ACC {
+
+//
+// ApplController(Parameterset*		aPS)
+//
+ApplController::ApplController(const string&	configID) :
+	itsBootParamSet	 (new ParameterSet),
+	itsObsParamSet	 (new ParameterSet),
+	itsResultParamSet(new ParameterSet),
+	itsProcList		 (0),
+	itsACCmdImpl     (new ACCmdImpl),
+	itsCmdStack      (new CmdStack),
+	itsProcListener  (0),
+    itsAPAPool       (0),
+	itsServerStub	 (0),
+	itsDaemonComm	 (0),
+#ifdef KVLOGGER	
+	itsKVLogger		 (0),
+#endif	
+	itsCurTime       (0),
+	itsIsRunning     (false),
+	itsStateEngine   (new StateEngine),
+	itsCurState      (StateNone),
+	itsCurACMsg		 (0),
+	itsNrOfProcs	 (0)
+{
+	LOG_TRACE_OBJ ("ApplController constructor");
+
+	// Read in the parameterfile with network parameters
+	ConfigLocator		CL;
+	string	bootPSname = CL.locate (configID+".param");
+	LOG_INFO_STR("Booting from " << bootPSname);
+	itsBootParamSet->adoptFile(bootPSname);			// May throw
+
+	// Get pointer to singleton APAdminPool
+    itsAPAPool = &(APAdminPool::getInstance());
+
+}
+
+
+//
+// ApplController(Parameterset*		aPS)
+//
+ApplController::~ApplController()
+{
+	LOG_TRACE_OBJ ("ApplController destructor");
+
+	if (itsBootParamSet)   { delete itsBootParamSet;   }
+	if (itsObsParamSet)    { delete itsObsParamSet;    }
+	if (itsResultParamSet) { delete itsResultParamSet; }
+	if (itsProcList)       { delete itsProcList;       }
+	if (itsACCmdImpl)      { delete itsACCmdImpl;      }
+	if (itsCmdStack)       { delete itsCmdStack;       }
+	if (itsProcListener)   { delete itsProcListener;   }
+    if (itsAPAPool)        { delete itsAPAPool;        }
+	if (itsServerStub)     { delete itsServerStub;     }
+	if (itsDaemonComm)     { delete itsDaemonComm;     }
+#ifdef KVLOGGER	
+	if (itsKVLogger)	   { delete itsKVLogger;	   }
+#endif	
+	if (itsCurACMsg)	   { delete itsCurACMsg; 	   }
+	if (itsStateEngine)	   { delete itsStateEngine;    }
+
+}
+
+//
+// startupNetwork()
+//
+// Starts the listeners for the user side and the process side.
+//
+void ApplController::startupNetwork()
+{
+	LOG_TRACE_FLOW("ApplController:startupNetwork()");
+
+	// Setup listener for ACC user and wait (max 10 sec) for connection
+	itsServerStub = new ApplControlServer(
+									itsBootParamSet->getInt32("AC.userportnr"), 
+									itsACCmdImpl);
+
+	// Setup listener for application processes
+	itsProcListener = new Socket("APlistener", 
+							 itsBootParamSet->getString("AC.processportnr"),
+							 Socket::TCP, 
+							 itsBootParamSet->getInt32("AC.backlog"));
+	ASSERTSTR(itsProcListener->ok(), 
+						"Can't start listener for application processes");
+
+	// Setup communication channel with ACDaemon
+	itsDaemonComm = new ACDaemonComm(
+							itsBootParamSet->getString("AC.pinghost"),
+							itsBootParamSet->getString("AC.pingportnr"),
+							itsBootParamSet->getString("AC.pingID"));
+
+	// 												   client					synchrone
+#ifdef KVLOGGER
+	itsKVLogger = new EventPort(MAC_SVCMASK_KVTLOGGER, false, KVT_PROTOCOL, "", true);	
+	ASSERTSTR(itsKVLogger, "Can't connect to KeyValueLogger");
+#endif
+	itsIsRunning = true;
+}
+
+
+//
+// handleProcMessage(APAdmin*)
+//
+// Handles a message that was received from an application process
+//
+void ApplController::handleProcMessage(APAdmin*	anAP)
+{
+	LOG_TRACE_FLOW_STR("ApplController:handleProcMessage(" << anAP->getName() << ")");
+
+	DH_ProcControl*		DHProcPtr = anAP->getDH();
+	PCCmd				command   = DHProcPtr->getCommand();
+	bool				ack       = false;
+
+	if (command & PCCmdResult) {
+		command = static_cast<PCCmd>(command ^ PCCmdResult);
+		ack = true;
+		LOG_TRACE_VAR_STR("Ack on command: " << command);
+	}
+	else {
+		LOG_TRACE_VAR_STR("command=" << command);
+	}
+	LOG_TRACE_VAR_STR("  options=" << DHProcPtr->getOptions());
+
+	switch (command) {
+	case PCCmdInfo:
+		// TODO: AP asks for some info, we should answer this
+		break;
+
+	case PCCmdAnswer:
+		// TODO: AP returns an answer on a question we have sent it
+		break;
+
+	case PCCmdBoot:
+		// send by the AP as soon as it is on the air (registerAtAC).
+		anAP->setName(DHProcPtr->getOptions());	// register name
+		itsAPAPool->markAsOnline(anAP);			// mark it ready for reception
+		break;
+
+	case PCCmdReport:
+		// TODO: AM.report (.....);
+		break;
+
+	case PCCmdAsync:
+		// TODO: implement this
+		break;
+
+	case PCCmdParams: {
+		// TODO: Write this information to the >>>> KeyValueLogger <<<<
+		ParameterSet	resultParam;
+		resultParam.adoptBuffer(DHProcPtr->getOptions());
+		resultParam.writeFile(itsObsParamSet->getString("ApplCtrl.resultfile"), true);
+		sendToKVLogger(resultParam);
+		break;
+		}
+
+	case PCCmdQuit:	// send by UnregisterAtAC
+		LOG_TRACE_OBJ("PCCmdQuit received");
+		itsAPAPool->markAsOffline(anAP);		// don't send new commands
+		itsAPAPool->registerAck(command, anAP);
+		itsResultParamSet->adoptBuffer(DHProcPtr->getOptions());
+		break;
+
+	default:
+		// The rest of the command should be an Ack on the outstanding command.
+		if (ack) {
+			// always register ack.
+			bool	ackOnTime = itsAPAPool->registerAck(command, anAP);
+
+			// note: the process can return three values: Ok/NotSupported/Error
+			// Handle NotSupported as Ok.
+			uint16	result  = DHProcPtr->getResult();
+			bool	successful = ((result & (PcCmdMaskOk | PcCmdMaskNotSupported)) != 0);
+
+			if (ackOnTime && !successful) { 
+				sendExecutionResult(0, "Nack from process:" + anAP->getName());
+			}
+		}
+		else {
+			LOG_WARN(formatString(
+					"Unexpected command (%04X) received from process (%s)",
+					command, anAP->getName().c_str()));
+		}
+	} // switch
+}
+
+//
+// sendExecutionResult(result)
+//
+// Send the given result to the AC-side and clears the neccesary timers
+// and stacks so that further handling of the command is stopped.
+//
+void ApplController::sendExecutionResult(uint16			result,
+										 const string&	comment)
+{
+	LOG_DEBUG_STR("ApplController:sendExecutionResult(" << result << "," 
+															<< comment << ")");
+
+	// notify user
+	itsServerStub ->sendResult(itsCurACMsg->getCommand(), result, comment);	
+	itsAPAPool    ->stopAckCollection();			// stop collecting
+	itsCurState	  = StateNone;						// reset Cmd state
+	itsStateEngine->reset();						// reset state Engine
+	if (itsCurACMsg) {								// delete old command
+		delete itsCurACMsg;
+		itsCurACMsg = 0;
+	}
+}
+
+//
+// createParSubsets()
+//
+// Creates for each process of its ProcList a parameter file containing its
+// own parameters. All the parameters from one process are in the masterPS
+// at <procname_from_proclist>.xxx
+//
+//
+void ApplController::createParSubsets()
+{
+    // Step 1: A parameterset for a process is constructed from three set:
+    // [A] the default params for the set of proces procName[0]
+    // [B] for multiple cmdline processes of the same type, the params for 
+	//	   a specific process (procName[i]), these overule the previous set
+    // [C] additional info from the AC itself
+
+	// ApplCtrl.application = applName
+	string			applName = itsObsParamSet->getString("ApplCtrl.application");
+
+	// ApplCtrl.processes = [ procName ... ]
+	// procList contains a list of processes to control. Loop over this list
+	// and make a ProcRuler and ParsetFile for each process of this application.
+	string			prevProcName;
+	ParameterSet	basePS;
+	vector<string>	nodes;
+	vector<string>	procList = itsObsParamSet->getStringVector("ApplCtrl.processes");
+	LOG_TRACE_VAR_STR("Found " << procList.size() << " processes");
+	for (uint procIdx = 0; procIdx < procList.size(); procIdx++) {
+		LOG_TRACE_VAR_STR("Processing process:" << procList[procIdx]);
+
+		// procList[x] = processName(x) | processName
+		// procName  := processName
+		// nrProcs  := x | 0
+		string procName = procList[procIdx];
+		int32  nrProcs  = indexValue(procName, "()");
+		rtrim(procName, "()0123456789");
+		string procPrefix = applName +"." + procName;
+
+		if (nrProcs == 0) {
+			itsNrOfProcs++;
+		}
+		else {
+			itsNrOfProcs += nrProcs;
+		}
+
+		// The startstopType determines what information is put in the parsetfiles
+		// for the processes.
+		string startstopType = itsObsParamSet->getString(procPrefix+"._startstopType");
+		LOG_DEBUG_STR("Creating parameterfile for process " << procName);
+
+		// [A] Get the default parameters ( procName[0].* ) when procname changes
+		if (procName != prevProcName) {
+			LOG_TRACE_COND_STR("Making basePS for " << procName);
+			basePS.clear();
+			basePS.adoptCollection(*itsObsParamSet);
+//			basePS = itsObsParamSet->makeSubset(procPrefix, procPrefix);
+//			LOG_TRACE_VAR_STR(basePS);
+
+			// [C] additional info from the AC itself
+			basePS.replace(procPrefix+"._ACport", 
+											itsBootParamSet->getString("AC.processportnr"));
+			basePS.replace(procPrefix+"._ACnode", itsBootParamSet->getString("AC.node"));
+			basePS.replace("_parsetPrefix", procPrefix+".");
+			prevProcName = procName;
+		}
+
+		string fileName 	 = formatString("%s/%s-%s.parset", LOFAR_SHARE_LOCATION, procName.c_str(), basePS.getString("Observation.ObsID").c_str());
+
+		// --- cmdline ---
+		if (startstopType == "cmdline") {
+			if (nrProcs == 0) {
+				LOG_TRACE_COND_STR("Single cmdline process " << procName);
+				// This processSet is a single commandline process
+				// add procName.* params to parset for process.
+				ParameterSet myPS = itsObsParamSet->makeSubset(procPrefix+".",
+																	procPrefix+".");
+				LOG_TRACE_VAR_STR(myPS);
+				myPS.adoptCollection(basePS);
+				writeParSubset(myPS, procName, fileName);
+				
+				// construct ProcesRuler
+				itsProcRuler.add(PR_Shell(myPS.getString(procPrefix + "._hostname"),
+										  procName,
+										  myPS.getString(procPrefix + "._executable"),
+										  fileName));
+
+			} else {
+				// There are multiple processes of this type
+				nodes = basePS.getStringVector(procPrefix+"._nodes");
+				LOG_TRACE_COND_STR("Multiple(" << nrProcs << ") cmdline process " << procName);
+				for (int32 p = 1; p <= nrProcs; ++p) {
+					// [B] construct parameter subset with process specific settings
+					string pName      = formatString("%s%d", procName.c_str(), p);
+//					string oldPPrefix = formatString("%s[%d].", procPrefix.c_str(), p);
+//					ParameterSet myPS(basePS);
+//					myPS.adoptCollection(itsObsParamSet->makeSubset(oldPPrefix, 
+//																	   procPrefix+"."));
+					ParameterSet myPS = itsObsParamSet->makeSubset(procPrefix+".",
+																		procPrefix+".");
+					LOG_TRACE_VAR_STR(myPS);
+					myPS.adoptCollection(basePS);
+
+					// copy the default PS and give it a new prefix
+//					myPS.adoptCollection(itsObsParamSet->makeSubset(procPrefix+".",
+//																	procPrefix+"."));
+					fileName  = formatString("%s/%s-%s.parset", LOFAR_SHARE_LOCATION, pName.c_str(), basePS.getString("Observation.ObsID").c_str());
+					writeParSubset(myPS, pName, fileName);
+
+					// note: nodes[] may be smaller than nrProcs. by taking the remainder
+					// of nodes.size() the nodes[] is made cyclic.
+					itsProcRuler.add(PR_Shell(nodes[(p-1)%nodes.size()],
+											  pName,
+											  myPS.getString(procPrefix + "._executable"),
+											  fileName));
+				}
+			}
+			
+			// IONProc processes do not connect to the ApplController.
+			itsNrOfProcs -= nrProcs ? nrProcs : 1;
+		}
+
+		else if (startstopType == "mpirun") {
+			// This processSet is an MPI program
+			LOG_TRACE_COND_STR("mpi process " << procName);
+			// fill 'nodes' with all nodenames of variable _nodes.
+			nodes = basePS.getStringVector(procPrefix+"._nodes", true);// true:expand
+
+			itsProcRuler.add(PR_MPI(basePS.getString(procPrefix + "._hostname"),
+									procName,
+									nodes,
+									basePS.getString(procPrefix + "._executable"),
+									fileName,
+									nrProcs));
+			writeParSubset(basePS, procName, fileName);
+			// Storage processes do not connect to the ApplController.
+			itsNrOfProcs -= nrProcs ? nrProcs : 1;
+		}
+
+		// --- cn ---
+		else if (startstopType == "bgl") {
+			// This processSet is a BG/L job
+			LOG_TRACE_COND_STR("bgl process " << procName);
+			itsProcRuler.add(PR_BGL(procName,				    
+									basePS.getString(procPrefix + "._executable"),
+									basePS.getString(procPrefix + ".workingdir"),
+                                                                        basePS.getString("Observation.ObsID"),
+									fileName, 
+									nrProcs));
+			writeParSubset(basePS, procName, fileName);
+			// CN processes do now connect to the ApplController.
+			//itsNrOfProcs -= nrProcs ? nrProcs : 1;
+		}
+	} // for processes
+}
+
+//
+// writeParSubset(ps, procName, fileName)
+//
+void ApplController::writeParSubset(ParameterSet ps, const string& procName, const string& fileName){
+    // [C] Add AC parameters of any interest to process
+    // TODO add some more like hostname and others?
+
+    // append the new prefix
+    ps.replace("_processName", procName);
+
+    // Remove execute type from processes paramlist
+    ps.remove(procName+"._startstopType");
+    ps.remove(procName+"._executable");
+    
+    // Finally write process paramset to a file.
+    ps.writeFile(fileName);
+
+	LOG_DEBUG_STR("Create parameterfile " << fileName);
+}
+
+//
+// writeResultFile
+//
+// Write the collected (end) results of the processes to the resultfile.
+//
+void ApplController::writeResultFile()
+{
+	// Save results from the processes to a file (append).
+	if (itsResultParamSet && itsObsParamSet && 
+							 itsObsParamSet->isDefined("ApplCtrl.resultfile")) {
+	   itsResultParamSet->writeFile(
+							itsObsParamSet->getString("ApplCtrl.resultfile"),
+							true);
+	}
+}
+
+//
+// sendToKVLogger(parSet)
+//
+// Send the KV pairs to the KeyValueLogger
+//
+void ApplController::sendToKVLogger(ParameterSet&	aResultPS)
+{
+	// loop over PS and construct a msgpool event.
+	ParameterSet::iterator	iter = aResultPS.begin();
+	ParameterSet::iterator	end  = aResultPS.end();
+	KVTSendMsgPoolEvent		poolEvent;
+	poolEvent.seqnr = 1;
+	poolEvent.nrElements = 0;
+	while (iter != end) {
+		poolEvent.keys().push_back(iter->first);
+		poolEvent.values().push_back(iter->second);
+		poolEvent.nrElements++;
+		iter++;
+	}
+
+	// empty PS?
+	if (!poolEvent.nrElements) {
+		return;
+	}
+
+	// send message and wait for answer.
+#ifdef KVLOGGER
+	itsKVLogger->send(&poolEvent);
+	KVTSendMsgPoolAckEvent		poolAck(*(itsKVLogger->receive()));
+
+	if (poolAck.result != 0) {
+		LOG_ERROR_STR("Storing metadata in PVSS resulted in errorcode " << poolAck.result);
+	}
+#endif	
+}
+
+
+//
+// startState (newMsg)
+//
+// Used to start a new state of an AC command. When newMsg is pointing at a
+// received message the stateEngine is started for this new message.
+// Is newMsg NULL we are in the middle of an state sequence, the new state
+// is than already set in itsCurState.
+//
+// NOTE: A state is the handling of one command-reply sequence with the AP's.
+//
+void ApplController::startCmdState()
+{
+	LOG_TRACE_FLOW_STR ("ApplController:startCmdState(" << itsCurState << ")");
+
+	// execute the new state
+	switch (itsCurState) {
+	case StateNone:
+		break;
+	case StateInitController:
+		// read in the Application Parameter file
+		itsObsParamSet->adoptFile(itsCurACMsg->getOptions());// May throw
+		// CS1_HACK save name of parameterfile
+		itsObsPSfilename = itsCurACMsg->getOptions();
+		LOG_DEBUG_STR("Observation parsetfilename=" << itsObsPSfilename);
+		// StateEngine needs to know the timeout values for the states
+		itsStateEngine->init(itsObsParamSet);
+		itsStateEngine->ready();				// report this state is ready.
+		break;
+	case StateCreatePSubset:
+		createParSubsets();
+		itsStateEngine->ready();				// report this state is ready.
+		break;
+    case StateStartupAppl:
+		if (!itsProcRuler.startAll()) {
+			sendExecutionResult(0, "Startup failures");
+			itsStateEngine->reset();			// no further processing
+	 	}
+		// the incomming acks decide the result of the start action
+		break;
+	case StateKillAppl:
+		sleep (5);								// give procs some extra time
+		itsProcRuler.stopAll();
+		itsStateEngine->ready();				// report this state is ready.
+		break;
+	case StateInfoCmd:
+		itsServerStub->handleMessage(itsCurACMsg);
+		itsStateEngine->reset();				// no further processing
+		break;
+
+	case StateDefineCmd:
+	case StateInitCmd:
+    case StateRunCmd:
+	case StatePauseCmd:
+	case StateReleaseCmd:
+	case StateRecoverCmd:
+	case StateSnapshotCmd:
+	case StateReinitCmd:
+	case StateQuitCmd:
+		// if nothing is online we are ready
+		if (itsAPAPool->onlineCount() == 0) {
+			itsStateEngine->ready();
+			break;
+		}
+
+		if (itsCurState == StatePauseCmd) {
+			// overrule default wait time if set
+			if (itsCurACMsg->getWaitTime() > 0) {
+				itsStateEngine->setStateLifeTime(itsCurACMsg->getWaitTime());
+			}
+		}
+
+		// All these command must be sent to the AP's and the responses
+		// that come back will finally result in a Nack of the next state.
+		itsServerStub->handleMessage(itsCurACMsg);
+		break;
+	case NR_OF_STATES:		// satisfy compiler
+		break;
+	}
+}
+
+//
+// acceptOrRefuseACMsg(command, passOwnership)
+//
+// Decides whether or not the given command may be executed in this stage.
+// When execution is not allowed, e.g. because the previous command is still
+// running than a Nack is send to the ACuser. Otherwise the command is started.
+//
+void ApplController::acceptOrRefuseACMsg(DH_ApplControl*	anACMsg,
+										 bool				passOwnership) 
+{
+	// what command should we execute?
+	ACCmd newCmd = anACMsg->getCommand();
+
+	// Special case: flush command queue?
+	if (newCmd == ACCmdCancelQueue) {
+		itsCmdStack->clear();
+		// send result without doing anything else.
+		itsServerStub->sendResult(newCmd, AcCmdMaskOk, "Queue is flushed");	
+		return;
+	}
+
+	// still commands in progress?
+	if (itsCurState != StateNone) {
+		// some command is running, has new command overrule 'rights'?
+		if ((newCmd != ACCmdQuit) && (newCmd != ACCmdPause)){
+			// No overrule rights, reject new command
+			LOG_DEBUG_STR("Command rejected: Previous command is still running. itsCurState:" << itsCurState << ", newCmd:" << ACCmdName(newCmd));
+			sendExecutionResult (0, "Previous command is still running");
+			return;
+		}
+	}
+
+	// store a copy of this message for the further states.
+	if (itsCurACMsg) {
+		delete itsCurACMsg;			// delete previous message
+	}
+	if (passOwnership) {
+		itsCurACMsg = anACMsg;
+	}
+	else {
+		itsCurACMsg = anACMsg->makeDataCopy();
+	}
+
+	// Initialize the stateEngine and store our new state.
+	itsStateEngine->startSequence(newCmd);
+	itsCurState = itsStateEngine->getState();
+
+	// start appropriate action
+	startCmdState();
+}
+
+//
+// doEventLoop()
+//
+// (Almost) never ending loop that executes the Application Controller functions.
+//
+void ApplController::doEventLoop()
+{
+	// Loop optimalisation when not waiting for ACK's
+	const uint16	loopDiff = 1;			// poll AP 5 times less than AM
+	uint16			loopCounter = loopDiff;
+
+	// prepare ping information for ACDaemon
+	time_t		nextPing     = 0;
+	int32		pingInterval = itsBootParamSet->getTime("AC.pinginterval");
+
+	while (itsIsRunning) {
+		checkForACCommands();
+		// AP's are less important when no command is running.
+		if ((itsCurState != StateNone) || (loopCounter == 0)) {
+			checkForAPMessages();	
+			checkForConnectingAPs();
+			checkForDisconnectingAPs();	
+			checkAckCompletion();
+		}
+		checkStateTimer();
+		checkCmdStack();
+		checkStateEngine();
+
+		// Should daemon be tickled?
+		if (nextPing < time(0)) {
+			if (!itsDaemonComm->sendPing()) {
+				LOG_DEBUG("Ping message to ACD could not be written!");
+			}
+			nextPing = time(0) + pingInterval;
+		}
+
+		if (loopCounter == 0) {
+			loopCounter = loopDiff;
+		}
+		else {
+			--loopCounter;
+		}
+
+ 		// temp debug info
+		LOG_TRACE_FLOW_STR(*itsAPAPool);
+		LOG_TRACE_FLOW_STR(*itsStateEngine);
+		LOG_TRACE_FLOW_STR("Ping at: " << timeString(nextPing));
+
+		// Only sleep when idle
+		if (itsCurState == StateNone) {
+			sleep (1);
+		}
+	}
+
+	itsDaemonComm->unregister();
+}
+
+//
+// checkForACCommands()
+//
+// See if the AC has send us a new command the AP's should execute.
+// A received command may be scheduled or may start a new state-sequence.
+//
+void ApplController::checkForACCommands() 
+{
+	// NOTE: The AC should guard the connection with the AM. When the
+	// AM disconnects a reconnect-timer should be started allowed the
+	// AM some time to reconnect before shutting down everything.
+	// Since the Socket of the AM is hidden behind TH_stuff we don't
+	// know anything anymore about its connection state. So it is not
+	// possible to implement this feature when using TH technology.
+	//
+	// The pollForMessage call does a read on the DH which will always
+	// check its connection first, and tries to connect if there is no
+	// connection (yet/anymore). This will ensure that we at least will
+	// pickup a (re)connect from the AM.
+
+	LOG_TRACE_STAT("Polling user side");
+	if (itsServerStub->pollForMessage()) {			// new command received?
+		DH_ApplControl* newMsg   = itsServerStub->getDataHolder();
+		time_t          execTime = newMsg->getScheduleTime();
+		itsCurTime = time(0);
+		if (execTime <= itsCurTime) {			// execute immediately?
+			LOG_TRACE_FLOW("Immediate command");
+			acceptOrRefuseACMsg(newMsg, false);
+		}
+		else {									// future command
+			LOG_TRACE_FLOW("Scheduling command");
+			// schedule it.
+			itsCmdStack->add(newMsg->getScheduleTime(), newMsg);
+			// Tell user it is scheduled.
+			itsServerStub->sendResult(newMsg->getCommand(), 
+									  AcCmdMaskOk | AcCmdMaskScheduled,
+									  "Command is scheduled");
+		}
+	}
+}
+
+
+//
+// CheckForAPMessages()
+//
+// The AP's may sent Ack or other types of messages to us. Reroute them to the
+// right functions.
+//
+void ApplController::checkForAPMessages() 
+{
+	// Anything received from the application processes?
+	LOG_TRACE_STAT("Polling process side");
+	APAdmin*		activeAP;
+	while ((activeAP = itsAPAPool->poll(1000))) {
+		handleProcMessage(activeAP);	// handle it
+	}
+}
+
+
+//
+// checkForConnectingAPs()
+// 
+// Check the AP listener socket for new AP's that want to connect. New AP's are
+// added to the APAdminPool but they will not receive commands until they have
+// sent their StartCmd to acknowledge existance.
+//
+void ApplController::checkForConnectingAPs() 
+{
+	// Any new incomming connections from the appl. processes?
+	LOG_TRACE_STAT("New processes to connect?");
+	Socket*		newAPSocket;
+	while ((newAPSocket = itsProcListener->accept(100))) {
+		LOG_DEBUG("Incomming process connection");
+		APAdmin*	APAdminPtr = new APAdmin(newAPSocket);
+		itsAPAPool->add(APAdminPtr);
+	}
+}
+
+//
+// checkForDisconnectingAPs
+//
+// During a read the AP may have ended the connection. Clean up its mess.
+//
+void ApplController::checkForDisconnectingAPs() 
+{
+	// Check for disconnected client processes. During the read action
+	// it may have turned out that a process has dropped the connection
+	// this is registered in the Socket. Cleanup these APadmins.
+	LOG_TRACE_STAT("Cleaning process side");
+	while(APAdmin*	anAPA = itsAPAPool->cleanup()) {
+		// TODO: AM.report(anAPA->getName() << " has disconnected");
+		LOG_DEBUG_STR (anAPA->getName() << " has disconnected");
+		itsProcRuler.markAsStopped(anAPA->getName());
+		delete anAPA;		// finally delete it.
+	}
+}
+
+
+//
+// checkAckCompletion
+//
+// When the last ack on the outstanding command was received we should mark
+// this state ready. The stateEngine will decide somewhere else if there is
+// another state to execute or to sent an Ack to the AC user.
+void ApplController::checkAckCompletion() 
+{
+	LOG_TRACE_STAT("All ack's received?");
+
+	if (itsCurState == StateStartupAppl) {
+//		if (itsAPAPool->onlineCount() == itsProcRuler.size()) {
+//		if (itsAPAPool->onlineCount() == itsAPAPool->processCount()) {
+		if (itsAPAPool->onlineCount() == itsNrOfProcs) {
+			itsStateEngine->ready();
+		}
+		else {
+			LOG_TRACE_STAT_STR("Still waiting for: " << itsNrOfProcs << "-"
+					<< itsAPAPool->onlineCount() << "=" << itsNrOfProcs-itsAPAPool->onlineCount() 
+					<< " connections");
+		}
+		return;
+	}
+
+	if (itsAPAPool->allAcksReceived()) {
+		itsStateEngine->ready();		// report we are ready with this state.
+	}
+}
+
+
+//
+// checkCmdtimer()
+//
+// Every command has a certain lifetime. When its lifetime is expired the
+// ACuser should be informed on this with a Nack.
+//
+void ApplController::checkStateTimer() 
+{
+	LOG_TRACE_STAT("State timer still running?");
+
+	if (itsStateEngine->IsStateExpired()) {
+		// Special case: handle Quit command extras
+		// when quit state failed we must perform the kill state anyway.
+		if (itsCurState == StateQuitCmd) {
+			itsProcRuler.stopAll();
+			writeResultFile();
+			itsIsRunning = false;
+		}
+
+		sendExecutionResult(0, "Timed out");
+	}
+
+}
+
+
+//
+// checkCmdStack()
+//
+// Check if it is time to execute the command that is placed on the CmdStack.
+//
+void ApplController::checkCmdStack() 
+{
+	LOG_TRACE_STAT("Time for a stack command?");
+
+	if (itsCmdStack->timeExpired()) {
+		acceptOrRefuseACMsg(itsCmdStack->pop(), true);
+	}
+}
+
+//
+// checkStateEngine()
+//
+// Somewhere in the process the stateEngine may have been told the current
+// state is finished. If so, another state should be started or when the
+// last state of the sequence was finished the AC user must have an ACK msg.
+//
+void ApplController::checkStateEngine()
+{
+	LOG_TRACE_STAT("Time for next commmand phase?");
+	if (!itsStateEngine->isStateFinished()) {	
+		return;
+	}
+
+	// State was flagged ready, check if there is another state we should 
+	// execute.
+
+	// Special case: handle Quit command extras
+	if (itsCurState == StateKillAppl) {
+		writeResultFile();
+		itsIsRunning = false;
+	}
+
+	itsCurState = itsStateEngine->nextState();
+	if (itsCurState == StateNone) {
+		sendExecutionResult(AcCmdMaskOk, "Command ready");		// No more states
+		return;
+	}
+
+	// there is a next state, start it.
+	startCmdState();
+}
+
+
+  } // namespace ACC
+} // namespace LOFAR
+
diff --git a/MAC/APL/Appl_Controller/src/ApplController.h b/MAC/APL/Appl_Controller/src/ApplController.h
new file mode 100644
index 0000000000000000000000000000000000000000..a8a63fa87ade66f3d5c197f5628883e6c3f28e4c
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/ApplController.h
@@ -0,0 +1,127 @@
+//#  ApplController.h: Controls all processes of an application.
+//#
+//#  Copyright (C) 2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  Note: This source is read best with tabstop 4.
+//#
+//#  $Id$
+
+#ifndef LOFAR_ACCBIN_APPLCONTROLLER_H
+#define LOFAR_ACCBIN_APPLCONTROLLER_H
+
+// \file
+// This is the main 'engine' of the Application Controller. It manages
+// the communication with the ACuser, the Application Processes and the
+// ACDaemon. It guards the execution time of the commands and collects
+// messages, results and acknowledgements fromthe AP's.
+
+//# Never *include <config.h> or #include <lofar_config.h> in a header file!
+//# Includes
+#include <Common/Net/Socket.h>
+#include <Transport/TH_Socket.h>
+#include <ALC/ApplControlServer.h>	//# communication stub
+#include <PLC/DH_ProcControl.h>
+#include <Common/ParameterSet.h>
+#include <MACIO/EventPort.h>
+#include "ACCmdImpl.h"				//# the real implementation
+#include "ACDaemonComm.h"
+#include "CmdStack.h"
+#include "StateEngine.h"
+#include "APAdminPool.h"
+#include "ItemList.h"
+#include "ProcRuler.h"
+
+using namespace LOFAR::ACC::ALC;
+using namespace LOFAR::ACC::PLC;
+
+namespace LOFAR {
+  namespace ACC {
+// \addtogroup ACCbin
+// @{
+
+// This is the main 'engine' of the Application Controller. It manages
+// the communication with the ACuser, the Application Processes and the
+// ACDaemon. It guards the execution time of the commands and collects
+// messages, results and acknowledgements fromthe AP's.
+class ApplController
+{
+public:
+	ApplController	(const string&	configID);
+	~ApplController();
+
+	void startupNetwork();
+	void doEventLoop();
+
+private:
+	void handleProcMessage  (APAdmin*	        anAP);
+	void sendExecutionResult(uint16				result,
+							 const string&		comment);
+	void acceptOrRefuseACMsg(DH_ApplControl*	anACMsg,
+							 bool				passOwnership);
+	void startCmdState      ();
+	void createParSubsets   ();
+	// writeParSubset writes the parameterset to a file
+	// it is only meant to avoid code duplication in createParSubsets
+	void writeParSubset(ParameterSet ps, const string& procName, const string& fileName);
+	void writeResultFile    ();
+	void sendToKVLogger		(ParameterSet&	aResultPS);
+
+	void checkForACCommands();
+	void checkForAPMessages();
+	void checkForConnectingAPs();
+	void checkForDisconnectingAPs();
+	void checkAckCompletion();
+	void checkStateTimer();
+	void checkCmdStack();
+	void checkStateEngine();
+
+	// Datamembers
+	ParameterSet*		itsBootParamSet;	// Own PS, passed during birth
+	ParameterSet*		itsObsParamSet;	    // PS of observation, given by AM
+	ParameterSet*		itsResultParamSet;	// PS for collecting proc. results.
+	ItemList*			itsProcList;		// All AP's according to ObsParSet
+	ACCmdImpl*			itsACCmdImpl;		// The command implementation
+	CmdStack*			itsCmdStack;		// Future commands stack
+	Socket*				itsProcListener;	// For AP's to connect to
+	APAdminPool*		itsAPAPool;			// Communication with all AP's
+	ApplControlServer*	itsServerStub;		// Communication with AM
+	ACDaemonComm*		itsDaemonComm;    	// Communication with ACDaemon
+	MACIO::EventPort*	itsKVLogger;		// Connection to KeyValueLogger
+	time_t				itsCurTime;			// Current timestamp
+	bool				itsIsRunning;		// Alive or not
+
+	StateEngine*		itsStateEngine;		// State machine of the controller
+	ACState				itsCurState;		// State currently executing
+	DH_ApplControl*		itsCurACMsg;		// Command under handling
+
+	ProcRuler			itsProcRuler;		// Starts/stops all AP's
+
+	uint16				itsNrOfProcs;		// Nr of processes to manage.
+
+	// TODO: REMOVE THIS CS1 HACK
+	string				itsObsPSfilename;	// name of observation parameterset.
+};
+
+// @} addgroup
+  } // namespace ACC
+} // namespace LOFAR
+
+
+#endif
+
diff --git a/MAC/APL/Appl_Controller/src/ApplController.log_prop b/MAC/APL/Appl_Controller/src/ApplController.log_prop
new file mode 100644
index 0000000000000000000000000000000000000000..f3755cbd6b73c997bf784c06d4ef9a18e0e18bdf
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/ApplController.log_prop
@@ -0,0 +1,24 @@
+
+# Configure the loggers
+log4cplus.rootLogger=INFO, STDOUT, FILE
+log4cplus.logger.TRC=INFO
+log4cplus.logger.LCS.Common=FATAL, STDOUT, FILE
+
+# Define the appenders
+log4cplus.appender.STDOUT=log4cplus::ConsoleAppender
+log4cplus.appender.STDOUT.layout=log4cplus::PatternLayout
+log4cplus.appender.STDOUT.layout.ConversionPattern=%D{%d-%m %H:%M:%S.%q} %-5p %c{3} - %m [%.25l]%n
+
+log4cplus.appender.STDERR=log4cplus::ConsoleAppender
+log4cplus.appender.STDERR.layout=log4cplus::PatternLayout
+log4cplus.appender.STDERR.layout.ConversionPattern=%D{%d-%m %H:%M:%S.%q} %-5p %c{3} - %m [%.25l]%n
+log4cplus.appender.STDERR.logToStdErr=true
+
+log4cplus.appender.FILE=log4cplus::RollingFileAppender
+log4cplus.appender.FILE.File=/opt/lofar/var/log/${LOG4CPLUS_LOGFILENAME}.log
+log4cplus.appender.FILE.MaxFileSize=10MB
+log4cplus.appender.FILE.MaxBackupIndex=2
+log4cplus.appender.FILE.layout=log4cplus::PatternLayout
+log4cplus.appender.FILE.layout.ConversionPattern=%x %D{%d-%m %H:%M:%S.%q} %-5p %c{3} - %m [%.25l]%n
+
+log4cplus.appender.DUMP=log4cplus::NullAppender
diff --git a/MAC/APL/Appl_Controller/src/ApplControllerMain.cc b/MAC/APL/Appl_Controller/src/ApplControllerMain.cc
new file mode 100644
index 0000000000000000000000000000000000000000..2dfc8e7fcc23c14c55911027214e82f5c6471588
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/ApplControllerMain.cc
@@ -0,0 +1,99 @@
+//#  ApplControllerMain.cc: Executes the Application Controller.
+//#
+//#  Copyright (C) 2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  $Id$
+
+//# Always #include <lofar_config.h> first!
+#include <lofar_config.h>
+
+//# Includes
+#include <signal.h>
+#include <libgen.h>
+#include <Common/lofar_string.h>
+#include <Common/LofarLogger.h>
+#include <Common/LofarLocators.h>
+#include <Common/Exception.h>
+#include "ApplController.h"
+
+using namespace LOFAR;
+using namespace LOFAR::ACC;
+
+// Use a terminate handler that can produce a backtrace.
+Exception::TerminateHandler t(Exception::terminate);
+
+//
+// MAIN (ParameterFile)
+//
+int main (int	argc, char*	argv[]) 
+{
+
+	// close filedescriptors from our launcher
+//	for (int f = dup(2); f > 2; --f) {
+//		close(f);
+//	}
+
+	// Always bring up he logger first
+	ConfigLocator	aCL;
+	string			progName(basename(argv[0]));
+#ifdef HAVE_LOG4CPLUS
+        string			logPropFile(progName + ".log_prop");
+	INIT_VAR_LOGGER (aCL.locate(logPropFile).c_str(), progName + "-" + argv[1]);
+#elif HAVE_LOG4COUT        
+        INIT_LOGGER_WITH_SYSINFO(progName);
+#else
+        string logPropFile(progName + ".debug");
+        INIT_LOGGER (aCL.locate(logPropFile).c_str());	
+#endif
+	LOG_DEBUG_STR("Initialized logsystem with: " << aCL.locate(logPropFile));
+
+	// Check invocation syntax
+	if (argc < 2) {
+		LOG_FATAL_STR ("Invocation error, syntax: " << progName << " configID");
+		cout << "Invocation error, syntax: " << progName << " configID" << endl;
+		return (-1);
+	}
+
+	// Tell operator we are tryingto start up.
+	LOG_INFO_STR("Starting up: " << argv[0] << "(" << argv[1] << ")");
+
+	try {
+		signal (SIGPIPE, SIG_IGN);		// ignore write errors on sockets
+		// close filedescriptors from our launcher
+// 		for (int f = dup(2); f > 2; --f) {
+// 			close(f);
+// 		}
+
+		ApplController		theAC(argv[1]);
+
+		theAC.startupNetwork();
+
+		theAC.doEventLoop();
+		
+		LOG_INFO_STR("Shutting down: " << argv[0]);
+	}
+	catch (LOFAR::Exception&		ex) {
+		LOG_FATAL_STR("Caught exception: " << ex << endl);
+		LOG_FATAL 	 ("Terminated by exception!");
+		return(1);
+	}
+
+	LOG_INFO("Terminated normally");
+	return (0);
+}
diff --git a/MAC/APL/Appl_Controller/src/CMakeLists.txt b/MAC/APL/Appl_Controller/src/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ec1202d653397dac685ad435fa50aed90db651c3
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/CMakeLists.txt
@@ -0,0 +1,42 @@
+# $Id$
+
+lofar_add_bin_program(ApplController 
+  ApplControllerMain.cc
+  ACCmdImpl.cc
+  ACDaemonComm.cc
+  APAdmin.cc
+  APAdminPool.cc
+  CmdStack.cc
+  forkexec.cc
+  ItemList.cc
+  ProcRule.cc
+  ProcRuler.cc
+  PR_Shell.cc
+  PR_MPI.cc
+  PR_BGL.cc
+  StateEngine.cc
+  ApplController.cc)
+                                                  
+lofar_add_bin_program(ACDaemon 
+  ACDaemonMain.cc
+  ACRequestPool.cc
+  ACDaemon.cc
+  forkexec.cc)
+
+lofar_add_bin_program(ACcli ACcli.cc)
+
+lofar_add_bin_program(ACuserMenu ACuserMenu.cc)
+
+install(PROGRAMS 
+  startAP.sh
+  startMPI.sh
+  stopAP.sh
+  stopMPI.sh
+  DESTINATION bin)
+  
+install(FILES
+  ACDaemon.log_prop 
+  ACDaemon.conf
+  ApplController.log_prop
+  ACuserMenu.log_prop
+  DESTINATION etc)
diff --git a/MAC/APL/Appl_Controller/src/CmdStack.cc b/MAC/APL/Appl_Controller/src/CmdStack.cc
new file mode 100644
index 0000000000000000000000000000000000000000..daea49c28855e7a798ffe241374fb878f969ac98
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/CmdStack.cc
@@ -0,0 +1,91 @@
+//#  CmdStack.cc: Implements time ordered map of DH_ApplControl structs
+//#
+//#  Copyright (C) 2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  $Id$
+
+#include <lofar_config.h>
+
+//# Includes
+#include <Common/LofarLogger.h>
+#include <Common/Exception.h>
+#include <Common/StringUtil.h>
+#include "CmdStack.h"
+
+namespace LOFAR {
+  namespace ACC {
+
+CmdStack::CmdStack()
+{
+}
+
+CmdStack::~CmdStack()
+{
+	itsStack.clear();		// in case the destructor does not do this
+}
+
+void CmdStack::add(time_t				scheduleTime,
+				   DH_ApplControl*		aDHAC) 
+{
+	LOG_TRACE_RTTI_STR("CmdStack::add: " << timeString(scheduleTime) <<
+					   ", " << aDHAC);
+
+	pair < iterator, bool>	result;
+	DH_ApplControl*			newDHAC = aDHAC->makeDataCopy();
+	LOG_TRACE_RTTI_STR("newDHAC=" << newDHAC);
+
+	result = itsStack.insert(std::make_pair(scheduleTime, newDHAC));
+	if (!result.second) {
+		THROW (Exception, "insert in CmdStack failed");
+	}
+
+	LOG_DEBUG_STR("CmdStack:Cmd added with timestamp = " << 
+													timeString(scheduleTime));
+}
+ 
+DH_ApplControl*	CmdStack::pop()
+{
+	ASSERTSTR(!itsStack.empty(), "Cmdstack is empty");
+
+//	DH_ApplControl*		theCmd = itsStack.begin()->second;
+	DH_ApplControl*		theCmd = (itsStack.begin()->second)->makeDataCopy();
+	itsStack.erase(itsStack.begin());
+
+	LOG_DEBUG("CmdStack: pop()");
+
+	return (theCmd);
+}
+
+bool CmdStack::timeExpired()
+{
+	if (itsStack.empty()) {
+		return (false);
+	}
+
+	if (itsStack.begin()->first <= time(0)) {
+		LOG_DEBUG("CmdStack: time expired, returning command");
+		return (true);
+	}
+
+	return (false);
+}
+
+} // namespace ACC
+} // namespace LOFAR
+
diff --git a/MAC/APL/Appl_Controller/src/CmdStack.h b/MAC/APL/Appl_Controller/src/CmdStack.h
new file mode 100644
index 0000000000000000000000000000000000000000..3e6b0451c90025c90b2bc44d79b67453cd861e81
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/CmdStack.h
@@ -0,0 +1,89 @@
+//#  CmdStack.h: Time-ordered stack of DH_ApplControl structures
+//#
+//#  Copyright (C) 2002-2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  Note: This source is read best with tabstop 4.
+//#
+//#  $Id$
+
+#ifndef LOFAR_ACCBIN_CMDSTACK_H
+#define LOFAR_ACCBIN_CMDSTACK_H
+
+// \file
+// Time-ordered stack of DH_ApplControl structures used by the Application
+// Controller to hold future commands for a while.
+
+//# Never #include <config.h> or #include <lofar_config.h> in a header file!
+//# Includes
+#include <time.h>
+#include <ALC/DH_ApplControl.h>
+#include <Common/lofar_map.h>
+
+using namespace LOFAR::ACC::ALC;
+
+namespace LOFAR {
+  namespace ACC {
+// \addtogroup ACCbin
+// @{
+
+// Time-ordered stack of DH_ApplControl structure pointers.
+class CmdStack
+{
+public:
+	typedef map<time_t,	DH_ApplControl*>					DHACStack;
+	typedef map<time_t, DH_ApplControl*>::iterator			iterator;
+	typedef map<time_t, DH_ApplControl*>::const_iterator	const_iterator;
+
+	CmdStack ();
+	~CmdStack();
+
+	// Add the given DH_ApplControl pointer to the stack with the given time.
+	void			add(time_t	scheduleTime, DH_ApplControl*	aDHAC);
+
+	// Remove the top element from the stack and return a pointer to it.
+	DH_ApplControl*	pop();
+
+	// Returns true is the time of the top-element lays in the past.
+	bool			timeExpired();
+
+	// Removes all command from the Stack
+	void			clear();
+
+private:
+	// Who wants to copy a CmdStack?
+	CmdStack(const CmdStack&	that);
+
+	// Who wants to copy a CmdStack?
+	CmdStack& operator= (const CmdStack&	that);
+
+	//# --- DataMembers ---
+	// The map used for the storage.
+	DHACStack		itsStack;
+};
+
+inline void CmdStack::clear()
+{
+	itsStack.clear();
+}
+
+// @} addgroup
+  } // namespace ACC
+} // namespace LOFAR
+
+#endif
diff --git a/MAC/APL/Appl_Controller/src/ItemList.cc b/MAC/APL/Appl_Controller/src/ItemList.cc
new file mode 100644
index 0000000000000000000000000000000000000000..91e324e58894279dd158b01cdbcdf5fab40b3fd6
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/ItemList.cc
@@ -0,0 +1,72 @@
+//#  ItemList.cc: one line description
+//#
+//#  Copyright (C) 2002-2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  $Id$
+
+//# Always #include <lofar_config.h> first!
+#include <lofar_config.h>
+
+//# Includes
+#include <Common/LofarLogger.h>
+#include "ItemList.h"
+
+namespace LOFAR {
+  namespace ACC {
+
+ItemList::ItemList(const ParameterSet&	aPS,
+				   const string&		prefix)
+{
+	int32	nrProcs = aPS.getInt32(prefix+"[0].count");
+	string	procName;
+	for (int32 p = 1; p <= nrProcs; p++) {
+		procName = aPS.getString(formatString("%s[%d].ID", prefix.c_str(), p));
+		int32	nrOfProcs = indexValue(procName, "()");
+		if (nrOfProcs == 0) {
+			push_back(procName);			// add to collection
+			continue;
+		}
+
+		rtrim(procName, "(0123456789)");
+		for (int32 idx = 1; idx <= nrOfProcs; ++idx) {
+			push_back(formatString("%s[%d]", procName.c_str(), idx));
+		}
+	}
+}
+
+//ItemList::~ItemList()
+//{}
+
+bool ItemList::isInList(const string&	aProcName) const
+{
+	const_iterator		iter = begin();
+
+	while (iter != end()) {
+		if (*iter == aProcName) {
+			return (true);
+		}
+		++iter;
+	}
+
+	return (false);
+}
+
+
+  } // namespace ACC
+} // namespace LOFAR
diff --git a/MAC/APL/Appl_Controller/src/ItemList.h b/MAC/APL/Appl_Controller/src/ItemList.h
new file mode 100644
index 0000000000000000000000000000000000000000..590ce6d99238a465cdd4efc48650b13e63188b8b
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/ItemList.h
@@ -0,0 +1,65 @@
+//#  ItemList.h: one line description
+//#
+//#  Copyright (C) 2002-2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  Note: This source is read best with tabstop 4.
+//#
+//#  $Id$
+
+#ifndef LOFAR_ACCBIN_ITEMLIST_H
+#define LOFAR_ACCBIN_ITEMLIST_H
+
+// \file
+// Class that can substract and array of items from a parameter collection.
+
+//# Never #include <config.h> or #include <lofar_config.h> in a header file!
+//# Includes
+#include <Common/lofar_vector.h>
+#include <Common/ParameterSet.h>
+
+
+namespace LOFAR {
+  namespace ACC {
+// \addtogroup ACCbin
+// @{
+
+
+// Class that can substract and array of items from a parameter collection.
+class ItemList : public vector <string>
+{
+public:
+	typedef vector<string>::iterator		iterator;
+	typedef vector<string>::const_iterator	const_iterator;
+
+	// Constructs a vector of Values from the vector of keys with the name
+	// 'prefix' from the given ParameterSet. ( prefix[n] = )
+	ItemList(const ParameterSet&	aPS,
+			 const string&			prefix);
+
+	bool isInList(const string&	aItemName) const;
+
+private:
+	
+};
+
+// @} addgroup
+  } // namespace ACC
+} // namespace LOFAR
+
+#endif
diff --git a/MAC/APL/Appl_Controller/src/ObsA.param b/MAC/APL/Appl_Controller/src/ObsA.param
new file mode 100644
index 0000000000000000000000000000000000000000..159eb20e6cd5ca591dc41a68814cb38acac5019a
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/ObsA.param
@@ -0,0 +1,37 @@
+#
+# timeout values for the Applcontroller
+ApplCtrl.timeout_powerup      =  3 m
+ApplCtrl.timeout_powerdown    =  3 m
+ApplCtrl.timeout_createsubsets=  3 m
+ApplCtrl.timeout_exitdelay    = 15 m
+ApplCtrl.timeout_startup      =  2 m
+ApplCtrl.timeout_define       = 40
+ApplCtrl.timeout_init         = 40
+ApplCtrl.timeout_run          = 30
+ApplCtrl.timeout_pause        = 50
+ApplCtrl.timeout_release      = 50
+ApplCtrl.timeout_recover      = 50
+ApplCtrl.timeout_snapshot     = 30
+ApplCtrl.timeout_reinit       = 30
+ApplCtrl.timeout_info         = 30
+ApplCtrl.timeout_quit         = 60
+ApplCtrl.timeout_kill         = 60
+#
+# where the meta-data must be stored
+ApplCtrl.resultfile =./AC_result.log
+
+#
+# Application related information
+ApplCtrl.application= testAppl
+ApplCtrl.processes	= [ tPCclient(2), tAnother ]
+#
+# Process specific information
+testAppl.tPCclient._startstopType	= cmdline
+testAppl.tPCclient._executable		= ./APTest
+testAppl.tPCclient._hostname		= localhost
+testAppl.tPCclient._nodes			= [ localhost, localhost ]
+
+testAppl.tAnother._startstopType 	= cmdline
+testAppl.tAnother._executable 		= ./APTest
+testAppl.tAnother._hostname		= localhost
+
diff --git a/MAC/APL/Appl_Controller/src/PR_BGL.cc b/MAC/APL/Appl_Controller/src/PR_BGL.cc
new file mode 100644
index 0000000000000000000000000000000000000000..3530170128a488a780442859cb0503d4006bfb4f
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/PR_BGL.cc
@@ -0,0 +1,94 @@
+//#  PR_BGL.cc: ProcessRule based for BG/L jobs
+//#
+//#  Copyright (C) 2002-2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  $Id$
+
+//# Always #include <lofar_config.h> first!
+#include <lofar_config.h>
+
+//# Includes
+#include <Common/LofarLogger.h>
+
+#include <Common/StringUtil.h>
+#include "PR_BGL.h"
+#include "forkexec.h"
+
+namespace LOFAR {
+  namespace ACC {
+
+    PR_BGL::PR_BGL(const string&  aJobName,
+		   const string&  aExecutable,
+		   const string&  aWorkingDir,
+                   const string&  aObservationID,
+		   const string&  aParamFile,
+		   const uint numberOfNodes) :
+	ProcRule("BGLjob", aJobName, aExecutable, aParamFile)
+    {
+      itsStartCmd = formatString("./startBGL.sh %s %s %s %s %s %d", 
+				 aJobName.c_str(),
+				 aExecutable.c_str(),
+				 aWorkingDir.c_str(),
+				 aParamFile.c_str(),
+                                 aObservationID.c_str(),
+				 numberOfNodes);
+
+      itsStopCmd  = formatString("./stopBGL.sh %s %s", 
+				 aJobName.c_str(),
+                                 aObservationID.c_str());
+    }
+
+    PR_BGL::PR_BGL(const PR_BGL& other) :
+      ProcRule(other)
+    {}
+
+    bool PR_BGL::start() {
+      if (itsIsStarted) {
+	LOG_TRACE_OBJ_STR("PR_BGL:" << itsProcName << " is already started");
+	return (true);
+      }
+
+      LOG_TRACE_OBJ_STR ("PR_BGL: " << itsStartCmd);
+
+      int32 result = forkexec (itsStartCmd.c_str());
+
+      if (result == 0) {
+	itsIsStarted = true;
+      }
+
+      return (itsIsStarted);
+    }
+
+    bool PR_BGL::stop()
+    {
+      // Note: always execute the stop command because it may also cleanup
+      // some mess the process left behind.
+      LOG_TRACE_OBJ_STR ("PR_BGL: " << itsStopCmd);
+
+      int32 result = forkexec (itsStopCmd.c_str());
+
+      if (result == 0) {
+	itsIsStarted = false;
+      }
+
+      return (!itsIsStarted);
+    }
+
+  } // namespace ACC
+} // namespace LOFAR
diff --git a/MAC/APL/Appl_Controller/src/PR_BGL.h b/MAC/APL/Appl_Controller/src/PR_BGL.h
new file mode 100644
index 0000000000000000000000000000000000000000..15c8354686a3ac01012ac6a98155b5fb3b8454bc
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/PR_BGL.h
@@ -0,0 +1,74 @@
+//#  PR_BGL.h: ProcesRule based for BG/L jobs
+//#
+//#  Copyright (C) 2002-2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  Note: This source is read best with tabstop 4.
+//#
+//#  $Id$
+
+#ifndef LOFAR_ACCBIN_PR_BGL_H
+#define LOFAR_ACCBIN_PR_BGL_H
+
+// \file
+// ProcessRule based on shell scripts
+
+//# Never #include <config.h> or #include <lofar_config.h> in a header file!
+//# Includes
+#include "ProcRule.h"
+
+namespace LOFAR {
+  namespace ACC {
+    // \addtogroup ACCbin
+    // @{
+
+    // The PR_BGL class contains all information to (over)rule a process.
+    // Its known how to start and stop a process and knows its current state.
+    class PR_BGL : public ProcRule {
+    public:
+      PR_BGL(const string& aJobName, 
+	     const string& aExecutable,
+	     const string& aWorkingDir,
+             const string& aObservationID,
+	     const string& aParamfile,
+	     const uint numberOfNodes);
+
+      PR_BGL(const PR_BGL& that);
+
+      ~PR_BGL() {};
+
+      // Redefine the start and stop commands.
+      virtual bool start();
+      virtual bool stop();
+      virtual string getType() const
+	{ return ("PR_BGL"); }
+      virtual PR_BGL* clone() const
+	{ return (new PR_BGL(*this)); }
+
+    private:
+      // Default construction not allowed
+      PR_BGL();
+      
+      //# --- Datamembers ---
+    };
+
+    // @} addgroup
+  } // namespace ACC
+} // namespace LOFAR
+
+#endif
diff --git a/MAC/APL/Appl_Controller/src/PR_MPI.cc b/MAC/APL/Appl_Controller/src/PR_MPI.cc
new file mode 100644
index 0000000000000000000000000000000000000000..be17281808ebbbeeff797f64ac58681c167265d8
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/PR_MPI.cc
@@ -0,0 +1,156 @@
+//#  PR_MPI.cc: ProcessRule based on mpirun
+//#
+//#  Copyright (C) 2002-2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  $Id$
+
+//# Always #include <lofar_config.h> first!
+#include <lofar_config.h>
+
+//# Includes
+#include <Common/LofarLogger.h>
+#include <Common/lofar_fstream.h>
+#include <Common/SystemUtil.h>
+#include "PR_MPI.h"
+#include "forkexec.h"
+
+namespace LOFAR {
+  namespace ACC {
+
+//
+// PR_MPI(jobname, nodes, executable, paramfile)
+//
+PR_MPI::PR_MPI(const string&			aHostName,
+			   const string&  			aJobName,
+			   const vector<string>& 	nodes,
+			   const string&  			aExecutable,
+			   const string&  			aParamFile,
+			   uint16					nrProcs)
+	: ProcRule("MPIjob", aJobName, aExecutable, aParamFile)
+{
+	LOG_TRACE_OBJ_STR ("PR_MPI: constructor");
+	// create machinefile
+	string 		machinefileName(aJobName + ".machinefile");
+	ofstream 	machinefile;
+	machinefile.open(machinefileName.c_str(), ofstream::out);
+	vector<string>::const_iterator node;
+	for (node = nodes.begin(); node != nodes.end(); node++) {
+		machinefile << *node << endl;
+	}
+	machinefile.close();
+
+	// start processes on another node?
+	if (aHostName != myHostname(false) &&
+		aHostName != myHostname(true)) {
+		// copy files to other machine
+		remoteCopy(aParamFile, aHostName, aParamFile);
+		remoteCopy(machinefileName, aHostName, machinefileName);
+
+		itsStartCmd = formatString("ssh %s \"( cd /opt/lofar/bin ; ./startMPI.sh %s %s %s %s %d )\"", 
+									aHostName.c_str(),
+									aJobName.c_str(),
+									machinefileName.c_str(),
+									aExecutable.c_str(),
+									aParamFile.c_str(),
+									nrProcs);
+		itsStopCmd  = formatString("ssh %s \"( cd /opt/lofar/bin ; ./stopMPI.sh %s ) \"", 
+									aHostName.c_str(),
+									aExecutable.c_str());
+	}
+	else { // start/stop on local machine
+		itsStartCmd = formatString("./startMPI.sh %s %s %s %s %d", 
+									aJobName.c_str(),
+									machinefileName.c_str(),
+									aExecutable.c_str(),
+									aParamFile.c_str(),
+									nrProcs);
+		itsStopCmd  = formatString("./stopMPI.sh %s", 
+									aExecutable.c_str());
+	}
+}
+
+//
+// PR_MPI(PR_MPI&)
+//
+PR_MPI::PR_MPI(const PR_MPI& other)
+	: ProcRule(other)
+{
+	LOG_TRACE_OBJ_STR ("PR_MPI: copy constructor");
+}
+
+//
+// ~PR_MPI()
+//
+PR_MPI::~PR_MPI()
+{
+	LOG_TRACE_OBJ_STR ("PR_MPI: destructor");
+}
+
+//
+// start()
+//
+bool PR_MPI::start()
+{
+	if (itsIsStarted) {
+		LOG_TRACE_OBJ_STR("PR_MPI:" << itsProcName << " is already started");
+		return (true);
+	}
+
+	LOG_TRACE_OBJ_STR ("PR_MPI: " << itsStartCmd);
+
+	if (forkexec (itsStartCmd.c_str()) == 0) {
+		itsIsStarted = true;
+	}
+
+	return (itsIsStarted);
+}
+
+//
+// stop()
+//
+bool PR_MPI::stop()
+{
+	LOG_TRACE_OBJ_STR ("PR_MPI: " << itsStopCmd);
+
+	if (forkexec (itsStopCmd.c_str()) == 0) {
+		itsIsStarted = false;
+	}
+
+	return (!itsIsStarted);
+}
+
+//
+// getType()
+//
+string PR_MPI::getType() const
+{ 
+	return ("PR_MPI");
+}
+
+//
+// clone()
+//
+PR_MPI* PR_MPI::clone() const
+{ 
+	return (new PR_MPI(*this)); 
+}
+
+
+  } // namespace ACC
+} // namespace LOFAR
diff --git a/MAC/APL/Appl_Controller/src/PR_MPI.h b/MAC/APL/Appl_Controller/src/PR_MPI.h
new file mode 100644
index 0000000000000000000000000000000000000000..9dbe531055e042c0f0d2e7a5409ee7c9ec663002
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/PR_MPI.h
@@ -0,0 +1,80 @@
+//#  PR_MPI.h: ProcesRule based on mpirun
+//#
+//#  Copyright (C) 2002-2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  Note: This source is read best with tabstop 4.
+//#
+//#  $Id$
+
+#ifndef LOFAR_ACCBIN_PR_MPI_H
+#define LOFAR_ACCBIN_PR_MPI_H
+
+// \file
+// ProcessRule based on mpirun
+
+//# Never #include <config.h> or #include <lofar_config.h> in a header file!
+//# Includes
+
+#include <Common/lofar_vector.h>
+#include <Common/StringUtil.h>
+#include "ProcRule.h"
+
+namespace LOFAR {
+  namespace ACC {
+
+// \addtogroup ACCbin
+// @{
+
+// The PR_MPI starts and stop an mpi program. One MPI-job is 
+// controlled by one PR_MPI. This means there are usually multiple
+// processes on multiple hosts involved.
+
+// The PR_MPI class contains all information to (over)rule a process.
+// Its known how to start and stop a process and knows its current state.
+class PR_MPI : public ProcRule {
+public:
+	PR_MPI (const string&			aHostName,
+			const string& 			aJobName, 
+			const vector<string>& 	nodes,
+			const string& 			aExecutable,
+			const string& 			aParamfile,
+			uint16					nrProcs);
+
+	PR_MPI(const PR_MPI&	other);
+
+	~PR_MPI();
+
+	// Redefine the start and stop commands.
+	virtual bool start();
+	virtual bool stop();
+	virtual string getType() const;
+	virtual PR_MPI* clone() const;
+
+private:
+	// Default construction not allowed
+	PR_MPI();
+
+	//# --- Datamembers ---
+};
+
+	// @} addgroup
+  } // namespace ACC
+} // namespace LOFAR
+
+#endif
diff --git a/MAC/APL/Appl_Controller/src/PR_Shell.cc b/MAC/APL/Appl_Controller/src/PR_Shell.cc
new file mode 100644
index 0000000000000000000000000000000000000000..57f9e26f3e6d2eb78f0eff162efc1b17f56a071c
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/PR_Shell.cc
@@ -0,0 +1,104 @@
+//#  PR_Shell.cc: ProcessRule based on shell scripts
+//#
+//#  Copyright (C) 2002-2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  $Id$
+
+//# Always #include <lofar_config.h> first!
+#include <lofar_config.h>
+
+//# Includes
+#include <Common/LofarLogger.h>
+#include <Common/SystemUtil.h>
+#include <Common/StringUtil.h>
+#include "PR_Shell.h"
+#include "forkexec.h"
+
+namespace LOFAR {
+  namespace ACC {
+
+PR_Shell::PR_Shell(const string&  aNodeName,
+				   const string&  aProcName,
+				   const string&  aExecName,
+				   const string&  aParamFile) :
+	ProcRule(aNodeName, aProcName, aExecName, aParamFile)
+{
+	if (aNodeName != myHostname(false) &&
+		aNodeName != myHostname(true)  &&
+		aNodeName != "localhost") {
+		remoteCopy(aParamFile, aNodeName, aParamFile);
+
+		itsStartCmd = formatString("ssh %s \"( cd /opt/lofar/bin ; ./startAP.sh %s %s %s %s )\"", 
+									aNodeName.c_str(),
+									aNodeName.c_str(),
+									aProcName.c_str(),
+									aExecName.c_str(),
+									aParamFile.c_str());
+		itsStopCmd  = formatString("ssh %s \"( cd /opt/lofar/bin ; ./stopAP.sh %s %s )\"", 
+									aNodeName.c_str(),
+									aNodeName.c_str(),
+									aProcName.c_str());
+	}
+	else {	// execute on local machine
+		itsStartCmd = formatString("./startAP.sh %s %s %s %s", 
+									aNodeName.c_str(),
+									aProcName.c_str(),
+									aExecName.c_str(),
+									aParamFile.c_str());
+		itsStopCmd  = formatString("./stopAP.sh %s %s", 
+									aNodeName.c_str(),
+									aProcName.c_str());
+	}
+}
+
+bool PR_Shell::start()
+{
+	if (itsIsStarted) {
+		LOG_TRACE_OBJ_STR("PR_Shell:" << itsProcName << " is already started");
+		return (true);
+	}
+
+	LOG_TRACE_OBJ_STR ("PR_Shell: " << itsStartCmd);
+
+	int32 result = forkexec (itsStartCmd.c_str());
+
+	if (result == 0) {
+		itsIsStarted = true;
+	}
+
+	return (itsIsStarted);
+}
+
+bool PR_Shell::stop()
+{
+	// Note: always execute the stop command because it may also cleanup
+	// some mess the process left behind.
+	LOG_TRACE_OBJ_STR ("PR_Shell: " << itsStopCmd);
+
+	int32 result = forkexec (itsStopCmd.c_str());
+
+	if (result == 0) {
+		itsIsStarted = false;
+	}
+
+	return (!itsIsStarted);
+}
+
+  } // namespace ACC
+} // namespace LOFAR
diff --git a/MAC/APL/Appl_Controller/src/PR_Shell.h b/MAC/APL/Appl_Controller/src/PR_Shell.h
new file mode 100644
index 0000000000000000000000000000000000000000..dcad3f08d42b4843edfe563e697c1e3fbbe71861
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/PR_Shell.h
@@ -0,0 +1,70 @@
+//#  PR_Shell.h: ProcesRule based on shell scripts
+//#
+//#  Copyright (C) 2002-2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  Note: This source is read best with tabstop 4.
+//#
+//#  $Id$
+
+#ifndef LOFAR_ACCBIN_PR_SHELL_H
+#define LOFAR_ACCBIN_PR_SHELL_H
+
+// \file
+// ProcessRule based on shell scripts
+
+//# Never #include <config.h> or #include <lofar_config.h> in a header file!
+//# Includes
+#include "ProcRule.h"
+
+namespace LOFAR {
+  namespace ACC {
+// \addtogroup ACCbin
+// @{
+
+// The PR_Shell class contains all information to (over)rule a process.
+// Its known how to start and stop a process and knows its current state.
+class PR_Shell : public ProcRule
+{
+public:
+	PR_Shell(const string&	aNodeName, 
+			 const string&  aProcName,
+			 const string&  aExecName,
+			 const string&  aParamfile);
+	~PR_Shell() {};
+
+	// Redefine the start and stop commands.
+	virtual bool start();
+	virtual bool stop();
+	virtual string getType() const
+		{ return ("PR_Shell"); }
+	virtual PR_Shell* clone() const
+		{ return (new PR_Shell(*this)); }
+
+private:
+	// Default construction not allowed
+	PR_Shell();
+
+	//# --- Datamembers ---
+};
+
+// @} addgroup
+  } // namespace ACC
+} // namespace LOFAR
+
+#endif
diff --git a/MAC/APL/Appl_Controller/src/ProcRule.cc b/MAC/APL/Appl_Controller/src/ProcRule.cc
new file mode 100644
index 0000000000000000000000000000000000000000..60feaa63aeda3df3e198b6e46760392718467fda
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/ProcRule.cc
@@ -0,0 +1,56 @@
+//#  ProcRule.cc: one line description
+//#
+//#  Copyright (C) 2002-2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  $Id$
+
+//# Always #include <lofar_config.h> first!
+#include <lofar_config.h>
+
+//# Includes
+#include <Common/LofarLogger.h>
+#include "ProcRule.h"
+
+namespace LOFAR {
+  namespace ACC {
+
+ProcRule::ProcRule(const string&  aNodeName,
+				   const string&  aProcName,
+				   const string&  aExecName,
+				   const string&  aParamfile) :
+	itsNodeName (aNodeName),
+	itsProcName (aProcName),
+	itsExecName (aExecName),
+	itsParamfile(aParamfile),
+	itsIsStarted(false)
+{}
+
+std::ostream& operator<< (std::ostream& os, const ProcRule& aPR)
+{
+	os << "ProcName: " << aPR.itsProcName << endl;
+	os << "Type    : " << aPR.getType()   << endl;
+	os << "StartCmd: " << aPR.itsStartCmd << endl;
+	os << "StopCmd : " << aPR.itsStopCmd  << endl;
+	os << "NodeName: " << aPR.itsNodeName << endl;
+
+	return (os);
+}
+
+  } // namespace ACC
+} // namespace LOFAR
diff --git a/MAC/APL/Appl_Controller/src/ProcRule.h b/MAC/APL/Appl_Controller/src/ProcRule.h
new file mode 100644
index 0000000000000000000000000000000000000000..321fe545686f985c1855d401c1466515ac72c88b
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/ProcRule.h
@@ -0,0 +1,116 @@
+//#  ProcRule.h: information how to rule a process.
+//#
+//#  Copyright (C) 2002-2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  Note: This source is read best with tabstop 4.
+//#
+//#  $Id$
+
+#ifndef LOFAR_ACCBIN_PROCRULE_H
+#define LOFAR_ACCBIN_PROCRULE_H
+
+// \file
+// Information how to rule a process.
+
+//# Never #include <config.h> or #include <lofar_config.h> in a header file!
+//# Includes
+#include <Common/lofar_iostream.h>
+
+namespace LOFAR {
+  namespace ACC {
+// \addtogroup ACCbin
+// @{
+
+// The ProcRule class contains all information to (over)rule a process.
+// Its known how to start and stop a process and knows its current state.
+class ProcRule
+{
+public:
+	ProcRule(const string&	aNodeName,
+			 const string&  aProcName,
+			 const string&  aExecName,
+			 const string&  aParamfile);
+	virtual ~ProcRule() {};
+
+	// The start and stop commands to be implemented.
+	virtual bool  		start() = 0;
+	virtual bool  		stop()  = 0;
+	virtual string		getType() const = 0;
+	virtual ProcRule*	clone()   const = 0;
+
+	const string&	getName()   const;
+	const string&	getNodeName()   const;
+	const string&	getExecName()   const;
+	const string&	getParamFile()   const;
+	bool 			isStarted() const;
+	void 			markAsStopped();
+
+
+	friend std::ostream& operator<<(std::ostream& os, const ProcRule& aPR);
+
+protected:
+	// Default construction not allowed
+	ProcRule();
+
+
+	//# --- Datamembers ---
+	string		itsNodeName;
+	string		itsProcName;
+	string		itsExecName;
+	string		itsParamfile;
+	string		itsStartCmd;
+	string		itsStopCmd;
+	bool		itsIsStarted;
+};
+
+inline bool ProcRule::isStarted() const
+{
+	return (itsIsStarted);
+}
+
+inline const string& ProcRule::getName() const
+{
+	return (itsProcName);
+}
+
+inline const string& ProcRule::getNodeName() const
+{
+	return (itsNodeName);
+}
+
+inline const string& ProcRule::getExecName() const
+{
+	return (itsExecName);
+}
+
+inline const string& ProcRule::getParamFile() const
+{
+	return (itsParamfile);
+}
+
+inline void	ProcRule::markAsStopped()
+{
+	itsIsStarted = false;
+}
+
+// @} addgroup
+  } // namespace ACC
+} // namespace LOFAR
+
+#endif
diff --git a/MAC/APL/Appl_Controller/src/ProcRuler.cc b/MAC/APL/Appl_Controller/src/ProcRuler.cc
new file mode 100644
index 0000000000000000000000000000000000000000..b0a68008a865bf89c214a6693226f75d9c0ac3ff
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/ProcRuler.cc
@@ -0,0 +1,119 @@
+//#  ProcRuler.cc: one line description
+//#
+//#  Copyright (C) 2002-2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  $Id$
+
+//# Always #include <lofar_config.h> first!
+#include <lofar_config.h>
+
+//# Includes
+#include <Common/LofarLogger.h>
+#include "ProcRuler.h"
+
+namespace LOFAR {
+  namespace ACC {
+
+ProcRuler::ProcRuler()
+{}
+
+ProcRuler::~ProcRuler()
+{
+	itsProcPool.clear();
+}
+
+void ProcRuler::add   (const	ProcRule&	aProcRule)
+{
+	LOG_TRACE_OBJ_STR("ProcRuler add:" << aProcRule.getName());
+
+	itsProcPool.erase(aProcRule.getName());
+
+	itsProcPool.insert(make_pair(aProcRule.getName(), aProcRule.clone()));
+}
+
+void ProcRuler::remove(const	string&	    aProcName)
+{
+	itsProcPool.erase(aProcName);
+}
+
+bool ProcRuler::start(const string& aProcName)
+{
+	iterator iter = itsProcPool.find(aProcName);
+	if (iter == itsProcPool.end()) {
+		return (false);
+	}
+	
+	return (iter->second->start());
+}
+
+bool ProcRuler::stop (const string& aProcName)
+{
+	iterator iter = itsProcPool.find(aProcName);
+	if (iter == itsProcPool.end()) {
+		return (false);
+	}
+	
+	return (iter->second->stop());
+}
+
+bool ProcRuler::startAll()
+{
+	bool result = true;
+
+	iterator iter = itsProcPool.begin();
+	while (iter != itsProcPool.end()) {
+		result &= iter->second->start();
+		++iter;
+	}
+	return (result);
+}
+
+bool ProcRuler::stopAll()
+{
+	bool result = true;
+
+	iterator iter = itsProcPool.begin();
+	while (iter != itsProcPool.end()) {
+		result &= iter->second->stop();
+		++iter;
+	}
+	return (result);
+}
+
+void ProcRuler::markAsStopped(const string& aProcName)
+{
+	iterator iter = itsProcPool.find(aProcName);
+	if (iter != itsProcPool.end()) {
+		iter->second->markAsStopped();
+	}
+}
+
+// @@ TEMP
+void ProcRuler::show()
+{
+	iterator iter = itsProcPool.begin();
+	while (iter != itsProcPool.end()) {
+		cout << iter->second;
+		++iter;
+	}
+}
+
+
+  } // namespace ACC
+} // namespace LOFAR
diff --git a/MAC/APL/Appl_Controller/src/ProcRuler.h b/MAC/APL/Appl_Controller/src/ProcRuler.h
new file mode 100644
index 0000000000000000000000000000000000000000..a1450fdcfbae41d1cd474baeb295e69b689a5980
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/ProcRuler.h
@@ -0,0 +1,87 @@
+//#  ProcRuler.h: Controller to start/stop processes.
+//#
+//#  Copyright (C) 2002-2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  Note: This source is read best with tabstop 4.
+//#
+//#  $Id$
+
+#ifndef LOFAR_ACCBIN_PROCRULER_H
+#define LOFAR_ACCBIN_PROCRULER_H
+
+// \file
+// Controller to start/stop processes.
+
+//# Never #include <config.h> or #include <lofar_config.h> in a header file!
+//# Includes
+#include <Common/lofar_map.h>
+#include <Common/LofarTypes.h>
+#include "ProcRule.h"
+
+namespace LOFAR {
+  namespace ACC {
+// \addtogroup ACCbin
+// @{
+
+//# Forward Declarations
+//class forward;
+
+
+// Controller to start/stop processes.
+class ProcRuler
+{
+public:
+	typedef map<string, ProcRule*>::iterator		iterator;
+
+	ProcRuler();
+	~ProcRuler();
+
+	void add   (const	ProcRule&	aProcRule);
+	void remove(const	string&	    aProcName);
+
+	bool start(const string& aProcName);
+	bool stop (const string& aProcName);
+
+	bool startAll();
+	bool stopAll();
+
+	void markAsStopped(const string& aProcName);
+
+	uint16	size();
+
+	void show();	// TEMP
+private:
+	// Copying is not allowed
+	ProcRuler(const ProcRuler&	that);
+	ProcRuler& operator=(const ProcRuler& that);
+
+	//# Datamembers
+	map<string, ProcRule*>		itsProcPool;
+};
+
+inline uint16 ProcRuler::size()
+{
+	return (itsProcPool.size());
+}
+
+// @} addgroup
+  } // namespace ACC
+} // namespace LOFAR
+
+#endif
diff --git a/MAC/APL/Appl_Controller/src/StateEngine.cc b/MAC/APL/Appl_Controller/src/StateEngine.cc
new file mode 100644
index 0000000000000000000000000000000000000000..9dd434f59aa934a3e84825130a26a3915a3e1abf
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/StateEngine.cc
@@ -0,0 +1,214 @@
+//#  StateEngine.cc: (internal) command sequence definitions
+//#
+//#  Copyright (C) 2002-2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  $Id$
+
+//# Always #include <lofar_config.h> first!
+#include <lofar_config.h>
+
+//# Includes
+#include <Common/LofarLogger.h>
+#include "StateEngine.h"
+
+namespace LOFAR {
+  namespace ACC {
+
+const uint16	CMD_SEQ_LENGTH	=	4;
+
+typedef struct CmdSeq {
+	ACCmd		userCmd;
+	ACState		cmdSeq [CMD_SEQ_LENGTH];
+} CmdSeq_t;
+
+static CmdSeq_t theirCmdSeqTable[] = { 
+{ ACCmdNone,	
+	{ StateNone,		   StateNone,		  StateNone,          StateNone } },
+{ ACCmdBoot,	
+	{ StateInitController, StateCreatePSubset,StateStartupAppl,   StateNone } },
+{ ACCmdDefine,	
+	{ StateDefineCmd,	   StateNone,		  StateNone,          StateNone } },
+{ ACCmdInit,	
+	{ StateInitCmd,		   StateNone,		  StateNone,          StateNone } },
+{ ACCmdRun,		
+	{ StateRunCmd,		   StateNone,		  StateNone,          StateNone } },
+{ ACCmdPause,	
+	{ StatePauseCmd,	   StateNone,		  StateNone,          StateNone } },
+{ ACCmdRelease,	
+	{ StateReleaseCmd,	   StateNone,		  StateNone,          StateNone } },
+{ ACCmdSnapshot,{ 
+	StateSnapshotCmd,	   StateNone,		  StateNone,          StateNone } },
+{ ACCmdRecover,	
+	{ StateRecoverCmd,	   StateNone,		  StateNone,          StateNone } },
+{ ACCmdReinit,	// TODO
+	{ StateReinitCmd,	   StateNone,		  StateNone,          StateNone } },
+{ ACCmdInfo,	
+	{ StateInfoCmd,		   StateNone,		  StateNone,          StateNone } },
+{ ACCmdQuit,	
+	{ StateQuitCmd,		   StateKillAppl,	  StateNone,          StateNone } }
+};
+
+// Array with the max lifetime times of the states
+time_t	StateLifeTime [NR_OF_STATES];
+
+#define	CMD_SEQ_TABLE_SIZE	((sizeof(theirCmdSeqTable)/sizeof(CmdSeq_t)) - 1)
+
+StateEngine::StateEngine() :
+	itsSequence       (0),
+	itsStepNr         (0),
+	itsStateFinished  (false),
+	itsStateExpireTime(0)		
+{
+	// The state InitController runs before any timevalues are known.
+	StateLifeTime[StateInitController] = 900;
+}
+
+StateEngine::~StateEngine()
+{}
+
+void StateEngine::init(const ParameterSet*	aPS)
+{
+	// (constant) timer values for the states
+	StateLifeTime[StateCreatePSubset]= aPS->getTime("ApplCtrl.timeout_createsubsets");
+    StateLifeTime[StateStartupAppl]	 = aPS->getTime("ApplCtrl.timeout_startup");
+	StateLifeTime[StateDefineCmd]	 = aPS->getTime("ApplCtrl.timeout_define");
+	StateLifeTime[StateInitCmd]		 = aPS->getTime("ApplCtrl.timeout_init");
+    StateLifeTime[StateRunCmd]		 = aPS->getTime("ApplCtrl.timeout_run");
+	StateLifeTime[StatePauseCmd]	 = aPS->getTime("ApplCtrl.timeout_pause");
+	StateLifeTime[StateReleaseCmd]	 = aPS->getTime("ApplCtrl.timeout_release");
+	StateLifeTime[StateRecoverCmd]	 = aPS->getTime("ApplCtrl.timeout_recover");
+	StateLifeTime[StateSnapshotCmd]	 = aPS->getTime("ApplCtrl.timeout_snapshot");
+	StateLifeTime[StateReinitCmd]	 = aPS->getTime("ApplCtrl.timeout_reinit");
+	StateLifeTime[StateInfoCmd]		 = aPS->getTime("ApplCtrl.timeout_info");
+	StateLifeTime[StateQuitCmd]		 = aPS->getTime("ApplCtrl.timeout_quit");
+	StateLifeTime[StateKillAppl]	 = aPS->getTime("ApplCtrl.timeout_kill");
+}
+
+void StateEngine::reset()
+{
+	LOG_TRACE_STAT ("StateEngine:reset");
+
+	itsSequence        = 0;
+	itsStepNr          = 0;
+	itsStateFinished   = false;
+	itsStateExpireTime = 0;
+}
+
+ACState StateEngine::startSequence(ACCmd	aStartPoint) throw (Exception)
+{
+	// loop through SeqTable to find the given ACCmd.
+	for (int i = CMD_SEQ_TABLE_SIZE; i > 0; i--) {
+		if (theirCmdSeqTable[i].userCmd == aStartPoint) {
+			// startpoint of sequence found, start with first state
+			itsSequence     = i;
+			itsStepNr       = 0;
+			itsStateFinished= false;
+			ACState	stateNr = theirCmdSeqTable[itsSequence].cmdSeq[itsStepNr];
+
+			LOG_DEBUG (formatString("Start stateSequence[%d][%d]=%s, time=%d",
+							itsSequence, itsStepNr, 
+							stateStr(stateNr).c_str(),
+							StateLifeTime[stateNr]));
+
+			// start timer for this state
+			setStateLifeTime(StateLifeTime[stateNr]);
+			return (stateNr);
+		}
+	}
+	
+	THROW (Exception, "No command sequences start with command " << ACCmdName(aStartPoint));
+
+}
+
+ACState StateEngine::getState()
+{
+	return (theirCmdSeqTable[itsSequence].cmdSeq[itsStepNr]);
+}
+
+ACState StateEngine::nextState()
+{
+	itsStepNr++;
+	itsStateFinished = false;
+
+	ASSERTSTR(itsStepNr < CMD_SEQ_LENGTH, "itsStepNr became " << itsStepNr);
+
+	// end of sequence reached? Reset indices.
+	if (theirCmdSeqTable[itsSequence].cmdSeq[itsStepNr] == StateNone) {
+		reset();
+	}
+
+	ACState	stateNr = theirCmdSeqTable[itsSequence].cmdSeq[itsStepNr];
+
+	LOG_DEBUG (formatString("Next state[%d][%d]=%s, time=%d",
+							itsSequence, itsStepNr, 
+							stateStr(stateNr).c_str(),
+							StateLifeTime[stateNr]));
+
+	setStateLifeTime(StateLifeTime[stateNr]);
+
+	return (stateNr);
+}
+
+string StateEngine::stateStr(uint16	stateNr) const
+{
+	static const char* const stateNames[] = {
+		"Idle",
+		"InitController",
+		"CreatePSubset",
+		"StartupAppl",
+		"DefineState",
+		"InitState",
+		"RunState",
+		"PauseState",
+		"ReleaseState",
+		"RecoverState",
+		"SnapshotState",
+		"ReinitState",
+		"InfoState",
+		"QuitState",
+		"KillAppl"
+	};
+
+	if (stateNr >= NR_OF_STATES) {
+		return ("");
+	}
+
+	return (stateNames[stateNr]);
+}
+
+//
+// operator<<
+//
+std::ostream&	operator<< (std::ostream& os, const StateEngine& anEngine)
+{
+	if (anEngine.itsStateExpireTime) {
+		os << "Timer  : " << timeString(anEngine.itsStateExpireTime) << endl;
+	    os << "State  : " << 
+			anEngine.stateStr(theirCmdSeqTable[anEngine.itsSequence].cmdSeq[anEngine.itsStepNr]) << endl;
+
+	}
+	else {
+		os << "Timer  : off" << endl;
+	}
+
+	return (os);
+}
+
+  } // namespace ACC
+} // namespace LOFAR
diff --git a/MAC/APL/Appl_Controller/src/StateEngine.h b/MAC/APL/Appl_Controller/src/StateEngine.h
new file mode 100644
index 0000000000000000000000000000000000000000..8860093af673c512876b564bdbc13efc130afdd5
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/StateEngine.h
@@ -0,0 +1,150 @@
+//#  StateEngine.h: (internal) sequence definitions of the command states.
+//#
+//#  Copyright (C) 2002-2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  Note: This source is read best with tabstop 4.
+//#
+//#  $Id$
+
+#ifndef LOFAR_ACCBIN_STATEENGINE_H
+#define LOFAR_ACCBIN_STATEENGINE_H
+
+// \file
+// (internal) sequence definitions of the command states.
+
+//# Never #include <config.h> or #include <lofar_config.h> in a header file!
+//# Includes
+#include <Common/Exception.h>
+#include <ALC/DH_ApplControl.h>
+#include <Common/ParameterSet.h>
+
+using namespace LOFAR::ACC::ALC;
+
+namespace LOFAR {
+  namespace ACC {
+// \addtogroup ACCbin
+// @{
+
+// define application controller states.
+enum ACState {  StateNone = 0, StateInitController,
+		StateCreatePSubset, StateStartupAppl,  StateDefineCmd,
+		StateInitCmd,		StateRunCmd,       StatePauseCmd,
+		StateReleaseCmd,	StateRecoverCmd,   StateSnapshotCmd,  
+		StateReinitCmd, 	StateInfoCmd,	   StateQuitCmd,
+		StateKillAppl,
+		NR_OF_STATES
+};
+
+// The execution of an AC command is cut into several states that must be
+// performed consecutive. The StateEngine manages these sequences of states.
+class StateEngine
+{
+public:
+	StateEngine();
+	~StateEngine();
+
+	// Initialize the Engine with timer values.
+	void init(const ParameterSet* aPS);
+	
+	// Reset to original state.
+	void reset();
+
+	// Start a new state sequence. When the requested state is not a start of
+	// a sequence an exception is thrown.
+	ACState  startSequence(ACCmd  aStartPoint)		throw (Exception);
+
+	// Get current state.
+	ACState getState();
+
+	// Current state is finished, hop the next state and return its value.
+	ACState nextState();
+
+	// Report the current state is ready.
+	void	ready();
+
+	// Ask if the next state is waiting.
+	bool	isStateFinished();
+
+	// Command for handling the state expire timer
+	void setStateLifeTime	 (time_t		anInterval);
+	void resetStateExpireTime();
+	bool IsStateExpired      ();
+
+	// return name of state
+	string stateStr(uint16	stateNr) const;
+
+	friend std::ostream& operator<< (std::ostream& os, 
+									 const StateEngine& anEngine);
+private:
+	uint16		itsSequence;
+	uint16		itsStepNr;
+	bool		itsStateFinished;
+	
+	// GMT time the current state expires
+	time_t	itsStateExpireTime;		
+
+	// (constant) timer values for the states
+	time_t	itsCreatePSubsetTime;
+    time_t	itsStartupApplTime;
+	time_t	itsDefineCmdTime;
+	time_t	itsInitCmdTime;
+    time_t	itsRunCmdTime;
+	time_t	itsPauseCmdTime;
+	time_t	itsReleaseCmdTime;
+	time_t	itsRecoverCmdTime;
+	time_t	itsSnapshotCmdTime;
+	time_t	itsReinitCmdTime;
+	time_t	itsInfoCmdTime;
+	time_t	itsQuitCmdTime;
+	time_t	itsKillApplTime;
+};
+
+inline void StateEngine::ready()
+{
+//	LOG_TRACE_STAT ("StateEngine:ready");
+	LOG_DEBUG ("StateEngine:ready");
+	itsStateFinished   = true;
+	itsStateExpireTime = 0;
+}
+
+inline bool StateEngine::isStateFinished()
+{
+	return (itsStateFinished);
+}
+
+inline void StateEngine::setStateLifeTime(time_t		anInterval)
+{
+	itsStateExpireTime = time(0) + anInterval;
+}
+
+inline void StateEngine::resetStateExpireTime()
+{
+	itsStateExpireTime = 0;
+}
+
+inline bool StateEngine::IsStateExpired()
+{
+	return (itsStateExpireTime && (itsStateExpireTime < time(0)));
+}
+
+// @} addgroup
+  } // namespace ACC
+} // namespace LOFAR
+
+#endif
diff --git a/MAC/APL/Appl_Controller/src/forkexec.cc b/MAC/APL/Appl_Controller/src/forkexec.cc
new file mode 100644
index 0000000000000000000000000000000000000000..f026d94efea8e018858f1bc6839a34281c09e0cb
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/forkexec.cc
@@ -0,0 +1,74 @@
+//#  forkexec.cc: Custom fork/exec implementation for more control
+//#
+//#  Copyright (C) 2002-2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+
+//# Always #include <lofar_config.h> first!
+#include <lofar_config.h>
+
+//# Includes
+#include "forkexec.h"
+
+#include <unistd.h>
+#include <sys/wait.h>
+#include <errno.h>
+
+namespace LOFAR {
+  namespace ACC {
+
+int32 forkexec( const char *command )
+{
+  int status;
+  pid_t pid;
+
+  pid = fork();
+
+  switch (pid) {
+    case -1:
+      // error
+      return -1;
+
+    case 0:  
+      // child process
+
+      // close all filedescriptors
+      for (int f = dup(2); f > 2; --f) {
+        while ( close(f) == EINTR )
+          ;
+      }
+
+      execl("/bin/sh", "/bin/sh", "-c", command, static_cast<char*>(0));
+
+      // only reached if exec fails
+      _exit(1);
+
+    default:
+      // parent process
+      if (waitpid(pid, &status, 0) == -1) {
+        // error
+        return errno;
+      }
+
+      return WEXITSTATUS(status);
+  }
+}
+
+
+  } // namespace ACC
+} // namespace LOFAR
diff --git a/MAC/APL/Appl_Controller/src/forkexec.h b/MAC/APL/Appl_Controller/src/forkexec.h
new file mode 100644
index 0000000000000000000000000000000000000000..6c14b23d17668e264cb695ded15b005ff0c8b4b5
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/forkexec.h
@@ -0,0 +1,41 @@
+//#  PR_BGL.h: Custom fork/exec implementation for more control
+//#
+//#  Copyright (C) 2002-2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  Note: This source is read best with tabstop 4.
+//#
+//#  $Id: PR_BGL.h 10517 2007-09-17 07:54:57Z overeem $
+
+#ifndef LOFAR_ACCBIN_FORKEXEC_H
+#define LOFAR_ACCBIN_FORKEXEC_H
+
+//# Never #include <config.h> or #include <lofar_config.h> in a header file!
+//# Includes
+#include <Common/LofarTypes.h>
+
+namespace LOFAR {
+  namespace ACC {
+
+// a custom implementation of system( command )
+int32 forkexec( const char *command );
+
+  } // namespace ACC
+} // namespace LOFAR
+
+#endif
diff --git a/MAC/APL/Appl_Controller/src/myACClientFunctions.h b/MAC/APL/Appl_Controller/src/myACClientFunctions.h
new file mode 100644
index 0000000000000000000000000000000000000000..d0e23661822174f20d89eb29c587e39f4adfb552
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/myACClientFunctions.h
@@ -0,0 +1,59 @@
+//#  myACClientFunctions.h: Implements the async functions of the AC client
+//#
+//#  Copyright (C) 2002-2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  $Id$
+
+#ifndef ACC_MYACCLIENTFUNCTIONS_H
+#define ACC_MYACCLIENTFUNCTIONS_H
+
+//# Never #include <config.h> or #include <lofar_config.h> in a header file!
+
+//# Includes
+#include <ALC/ACAsyncClient.h>
+
+using namespace LOFAR::ACC::ALC;
+
+namespace LOFAR {
+namespace ACC {
+
+
+// Description of class.
+class myACClientFunctions : public ACClientFunctions
+{
+	string	supplyInfoFunc(const string&	/*keyList*/)
+		{ return ("myACClientFunctions::supplyInfo from ACClient was called"); }
+
+	void	handleAnswerMsg(const string&	answer)
+		{ cout << "myACClientFunctions::handleAnswerMessage from ACClient was called"; 
+		  cout << "Answer=" << answer << endl;
+	    }
+
+	void	handleAckMsg(ACCmd	cmd, uint16 result, const string& info)
+		{ cout << "myACClientFunctions::handleAckMessage was called" << endl; 
+		  cout << "command = " << ACCmdName(cmd) << ", result = " << result
+				<< ", info = " << info << endl;
+		}
+
+};
+
+} // namespace ACC
+} // namespace LOFAR
+
+#endif
diff --git a/MAC/APL/Appl_Controller/src/startAP.sh b/MAC/APL/Appl_Controller/src/startAP.sh
new file mode 100755
index 0000000000000000000000000000000000000000..ce8d145a1c57e8973112d16b82565aa61ec14b32
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/startAP.sh
@@ -0,0 +1,24 @@
+# startAP.sh nodename procID executable paramfile
+#
+# nodename		    hostname[.domain]
+# procID			processname<nr>
+# executable		processname
+# parameterfile		procID.ps
+#
+# start the given executable and creates a corresponding pid file for stopping the process.
+#
+
+# DISABLED this script: startBGL.sh starts all CEP processes
+exit
+
+# now all ACC processes expect to be started with "ACC" as first parameter
+
+# start process
+echo $3 ACC $4 $2 >../log/$2.startup
+$3 ACC $4 $2 & 
+
+# get its pid
+pid=`echo $!`
+
+# construct pid file for stop shell
+echo "$pid" > /opt/lofar/var/run/$2.pid
diff --git a/MAC/APL/Appl_Controller/src/startMPI.sh b/MAC/APL/Appl_Controller/src/startMPI.sh
new file mode 100755
index 0000000000000000000000000000000000000000..916102138184d96b9a1a52730435d3e671dbfdc9
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/startMPI.sh
@@ -0,0 +1,28 @@
+# startMPI.sh jobName machinefile executable paramfile noNodes
+#
+# $1 jobName             identifier for this job
+# $2 machinefile         procID.machinefile
+# $3 executable          processname
+# $4 parameterfile       procID.ps
+# $5 numberOfNodes
+#
+# calls mpirun and remembers the pid
+#
+
+# DISABLED this script: startBGL.sh starts all CEP processes
+exit
+
+# now all ACC processes expect to be started with ACC as first parameter
+
+# start process
+# TODO: on some hosts, mpirun has a different name (or a specific path)
+#       on some hosts, we should use -hostfile instead of -machinefile
+echo "mpirun -np $5 -machinefile $2 $3 ACC $4 " > startMPI.output
+( ( mpirun -np $5 -machinefile $2 $3 ACC $4 ) &> $1.output ) &
+fi
+
+# get its pid
+pid=`echo $!`
+
+# construct pid file for stop shell
+echo "$pid" > $4.pid
diff --git a/MAC/APL/Appl_Controller/src/stopAP.sh b/MAC/APL/Appl_Controller/src/stopAP.sh
new file mode 100755
index 0000000000000000000000000000000000000000..1984d5a8a53eaee28706a52c5e607adedf99c2aa
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/stopAP.sh
@@ -0,0 +1,14 @@
+# stopAP.sh nodename procID 
+#
+# nodename		    hostname[.domain]
+# procID			processname<nr>
+#
+# Stops the given process by killing the process whose pid is in the
+# proces.pid file.
+
+# DISABLED this script: startBGL.sh starts all CEP processes
+exit
+
+echo -n "Killing process "; cat /opt/lofar/var/run/$2.pid
+kill -9 `cat /opt/lofar/var/run/$2.pid`
+rm -f /opt/lofar/var/run/$2.pid /opt/lofar/var/run/$2.parset
diff --git a/MAC/APL/Appl_Controller/src/stopMPI.sh b/MAC/APL/Appl_Controller/src/stopMPI.sh
new file mode 100755
index 0000000000000000000000000000000000000000..63b6d6171a5b101c18911af1a6b10358fb404d74
--- /dev/null
+++ b/MAC/APL/Appl_Controller/src/stopMPI.sh
@@ -0,0 +1,16 @@
+# stopMPI.sh procID 
+#
+# procID			processname
+#
+# Stops the given process by killing the process whose pid is in the
+# proces.pid file.
+
+# DISABLED this script: startBGL.sh starts all CEP processes
+exit
+
+# TODO: for some mpi versions it is not enough to kill mpirun
+#       we could "killall executable", but that would also kill
+#       processes started by another ApplicationController
+echo -n "Killing process "; cat $1.pid
+kill -s 15 `cat $1.pid`
+rm -f $1.pid $1*.ps
diff --git a/MAC/APL/CEPCU/CMakeLists.txt b/MAC/APL/CEPCU/CMakeLists.txt
index 2d8bc3474a045b8af49b61220f85cbb7e6315da4..f7b97cd31136c339dbcd2294693f547b144465fd 100644
--- a/MAC/APL/CEPCU/CMakeLists.txt
+++ b/MAC/APL/CEPCU/CMakeLists.txt
@@ -1,7 +1,7 @@
 # $Id$
 
 # Do not split the following line, otherwise makeversion will fail!
-lofar_package(CEPCU 1.0 DEPENDS Common ApplCommon MACIO GCFTM GCFRTDB APLCommon RTDBCommon OTDB)
+lofar_package(CEPCU 1.0 DEPENDS Common ApplCommon MACIO GCFTM GCFRTDB APLCommon RTDBCommon OTDB Stream)
 
 include(LofarFindPackage)
 lofar_find_package(Boost REQUIRED COMPONENTS date_time)
diff --git a/MAC/APL/CEPCU/src/CEPlogProcessor/CEPlogProcessor.cc b/MAC/APL/CEPCU/src/CEPlogProcessor/CEPlogProcessor.cc
index 00700b2e544ea46d20b000ea60877c79aa71fed7..f038ccd6d2cdc178fe3f4c5a9d11f12dfe07b7a8 100644
--- a/MAC/APL/CEPCU/src/CEPlogProcessor/CEPlogProcessor.cc
+++ b/MAC/APL/CEPCU/src/CEPlogProcessor/CEPlogProcessor.cc
@@ -24,6 +24,7 @@
 #include <Common/LofarConstants.h>
 #include <Common/LofarLocators.h>
 #include <Common/StringUtil.h>
+#include <Stream/SocketStream.h>
 #include <ApplCommon/LofarDirs.h>
 #include <ApplCommon/Observation.h>
 #include <ApplCommon/StationInfo.h>
@@ -800,6 +801,16 @@ void CEPlogProcessor::unregisterObservation(int obsID)
   itsFeedback.erase(obsID);
 
   itsTempObsMapping.erase(obsID);
+
+  // signal to MAC that the observation is finished, see redmine ticket #4021
+  LOG_INFO_STR("Observation " << obsID << " finished, informing OnlineControl");
+  try {
+    SocketStream ss("localhost", 21000 + obsID % 1000, SocketStream::TCP, SocketStream::Client, time(0) + 30);
+    const char *status = "FINISHED"; // alternative: "ABORT"
+    ss.write(&status[0], strlen(status));
+  } catch(Exception &ex) {
+    LOG_ERROR_STR("Caught exception: " << ex);
+  }
 }
 
 
diff --git a/MAC/APL/CEPCU/src/OnlineControl/OnlineControl.cc b/MAC/APL/CEPCU/src/OnlineControl/OnlineControl.cc
index 8997d98f59ea295df9ec6edaf1a11ce7462e9cae..d8907b1f9b5fcabe40912347f8b40122455e5d7d 100644
--- a/MAC/APL/CEPCU/src/OnlineControl/OnlineControl.cc
+++ b/MAC/APL/CEPCU/src/OnlineControl/OnlineControl.cc
@@ -30,6 +30,7 @@
 #include <Common/ParameterRecord.h>
 #include <Common/Exceptions.h>
 #include <Common/SystemUtil.h>
+#include <Common/hexdump.h>
 #include <ApplCommon/StationInfo.h>
 #include <ApplCommon/Observation.h>
 #include <ApplCommon/LofarDirs.h>
@@ -47,6 +48,8 @@
 #include "Response.h"
 #include "forkexec.h"
 #include <OTDB/TreeValue.h>			// << need to include this after OnlineControl! ???
+#include <OTDB/TreeMaintenance.h>
+#include <OTDB/TreeStateConv.h>
 #include "PVSSDatapointDefs.h"
 
 using namespace LOFAR::GCF::PVSS;
@@ -78,13 +81,17 @@ OnlineControl::OnlineControl(const string&	cntlrName) :
 	itsTimerPort		(0),
 	itsLogControlPort	(0),
 	itsState			(CTState::NOSTATE),
+	itsFeedbackListener	(0),					// QUICK FIX #4022
+	itsFeedbackPort		(0),					// QUICK FIX #4022
+	itsFeedbackResult	(CT_RESULT_NO_ERROR),	// QUICK FIX #4022
 	itsTreePrefix       (""),
 	itsInstanceNr       (0),
 	itsStartTime        (),
 	itsStopTime         (),
 	itsStopTimerID      (0),
 	itsFinishTimerID 	(0),
-	itsInFinishState	(false)
+	itsInFinishState	(false),
+	itsFeedbackAvailable(false)
 {
 	LOG_TRACE_OBJ_STR (cntlrName << " construction");
 
@@ -107,6 +114,10 @@ OnlineControl::OnlineControl(const string&	cntlrName) :
 	// Controlport to logprocessor
 	itsLogControlPort = new GCFTCPPort(*this, MAC_SVCMASK_CEPLOGCONTROL, GCFPortInterface::SAP, CONTROLLER_PROTOCOL);
 
+	// QUICK FIX #4022
+	itsFeedbackListener = new GCFTCPPort (*this, "Feedbacklistener", GCFPortInterface::MSPP, CONTROLLER_PROTOCOL);
+	ASSERTSTR(itsFeedbackListener, "Cannot allocate TCP port for feedback");
+
 	// for debugging purposes
 	registerProtocol (CONTROLLER_PROTOCOL, CONTROLLER_PROTOCOL_STRINGS);
 	registerProtocol (DP_PROTOCOL, 		DP_PROTOCOL_STRINGS);
@@ -129,6 +140,11 @@ OnlineControl::~OnlineControl()
 	if (itsTimerPort) {
 		delete itsTimerPort;
 	}
+
+	if (itsFeedbackListener) {
+		itsFeedbackListener->close();
+		delete itsFeedbackListener;
+	}
 }
 
 //
@@ -139,15 +155,16 @@ void OnlineControl::signalHandler(int	signum)
 	LOG_INFO (formatString("SIGNAL %d detected", signum));
 
 	if (thisOnlineControl) {
-		thisOnlineControl->finish();
+		thisOnlineControl->finish(CT_RESULT_MANUAL_ABORT);
 	}
 }
 
 //
-// finish()
+// finish(result)
 //
-void OnlineControl::finish()
+void OnlineControl::finish(int	result)
 {
+	itsFeedbackResult = result;
 	TRAN(OnlineControl::finishing_state);
 }
 
@@ -246,10 +263,10 @@ GCFEvent::TResult OnlineControl::initial_state(GCFEvent& event, GCFPortInterface
 		break;
 
 	case F_CONNECTED:
-		ASSERTSTR (&port == itsParentPort, "F_CONNECTED event from port " << port.getName());
 		break;
 
 	case F_DISCONNECTED:
+		_handleDisconnect(port);
 		break;
 	
 	default:
@@ -274,7 +291,6 @@ GCFEvent::TResult OnlineControl::propset_state(GCFEvent& event, GCFPortInterface
 	switch (event.signal) {
 	case F_ENTRY: {
 		// Get access to my own propertyset.
-//		uint32	obsID = globalParameterSet()->getUint32("Observation.ObsID");
 		string obsDPname = globalParameterSet()->getString("_DPname");
 		string	propSetName(createPropertySetName(PSN_BGP_APPL, getName(), obsDPname));
 		LOG_DEBUG_STR ("Activating PropertySet: "<< propSetName);
@@ -297,7 +313,7 @@ GCFEvent::TResult OnlineControl::propset_state(GCFEvent& event, GCFPortInterface
 
 	case F_TIMER: {	// must be timer that PropSet is online.
 		// start StopTimer for safety.
-		LOG_INFO_STR("Starting QUIT timer that expires 5 seconds after end of observation");
+		LOG_INFO("Starting QUIT timer that expires 5 seconds after end of observation");
 		ptime	now(second_clock::universal_time());
 		itsStopTimerID = itsTimerPort->setTimer(time_duration(itsStopTime - now).total_seconds() + 5.0);
 
@@ -306,16 +322,22 @@ GCFEvent::TResult OnlineControl::propset_state(GCFEvent& event, GCFPortInterface
 		itsParentPort = itsParentControl->registerTask(this);
 		// results in CONTROL_CONNECT
 
+		// QUICK FIX #4022
+		uint32	obsID = globalParameterSet()->getUint32("Observation.ObsID");
+		LOG_INFO_STR("Openening feedback port for OLAP: " << MAC_ONLINE_FEEDBACK_QF + obsID%1000);
+		itsFeedbackListener->setPortNumber(MAC_ONLINE_FEEDBACK_QF + obsID%1000);
+		itsFeedbackListener->open();	// will result in F_CONN
+
 		LOG_DEBUG ("Going to operational state");
 		TRAN(OnlineControl::active_state);				// go to next state.
 		}
 		break;
 
 	case F_CONNECTED:
-		ASSERTSTR (&port == itsParentPort, "F_CONNECTED event from port " << port.getName());
 		break;
 
 	case F_DISCONNECTED:
+		_handleDisconnect(port);
 		break;
 	
 	default:
@@ -343,21 +365,26 @@ GCFEvent::TResult OnlineControl::active_state(GCFEvent& event, GCFPortInterface&
 		// update PVSS
 		itsPropertySet->setValue(PN_FSM_CURRENT_ACTION, GCFPVString("active"));
 		itsPropertySet->setValue(PN_FSM_ERROR, GCFPVString(""));
-	}
-	break;
+	} break;
 
-	case F_ACCEPT_REQ:
-		break;
+	// QUICKFIX #4022
+	case F_ACCEPT_REQ: {
+		_handleAcceptRequest(port);
+	} break;
 
 	case F_CONNECTED: {
-		ASSERTSTR (&port == itsParentPort, "F_CONNECTED event from port " << port.getName());
-	}
-	break;
+//		ASSERTSTR (&port == itsParentPort, "F_CONNECTED event from port " << port.getName());
+		LOG_INFO_STR("F_CONNECTED event from port " << port.getName());
+	} break;
 
 	case F_DISCONNECTED: {
-		port.close();
-	}
-	break;
+		_handleDisconnect(port);
+	} break;
+
+	// QUICKFIX #4022
+	case F_DATAIN: {
+		_handleDataIn(port);
+	} break;
 
 	case DP_CHANGED:
 		_databaseEventHandler(event);
@@ -368,7 +395,7 @@ GCFEvent::TResult OnlineControl::active_state(GCFEvent& event, GCFPortInterface&
 		if (timerEvent.id == itsStopTimerID) {
 			LOG_DEBUG("StopTimer expired, starting QUIT sequence");
 			itsStopTimerID = 0;
-			finish();
+			finish(itsFeedbackResult);
 //			itsFinishTimerID = itsTimerPort->setTimer(30.0);
 		}
 #if 0
@@ -387,6 +414,7 @@ GCFEvent::TResult OnlineControl::active_state(GCFEvent& event, GCFPortInterface&
 	case CONTROL_CONNECT: {
 		CONTROLConnectEvent		msg(event);
 		LOG_DEBUG_STR("Received CONNECT(" << msg.cntlrName << ")");
+		itsMyName = msg.cntlrName;
 		// first inform CEPlogProcessor
 		CONTROLAnnounceEvent		announce;
 		announce.observationID = toString(getObservationNr(msg.cntlrName));
@@ -455,7 +483,7 @@ GCFEvent::TResult OnlineControl::active_state(GCFEvent& event, GCFPortInterface&
 		CONTROLQuitEvent		msg(event);
 		LOG_DEBUG_STR("Received QUIT(" << msg.cntlrName << ")");
 		_setState(CTState::QUIT);
-		finish();
+		finish(itsFeedbackResult);
 		break;
 	}
 
@@ -488,7 +516,7 @@ GCFEvent::TResult OnlineControl::finishing_state(GCFEvent& event, GCFPortInterfa
 		itsTimerPort->cancelAllTimers();
 
 		// update PVSS
-		itsPropertySet->setValue(PN_FSM_CURRENT_ACTION, GCFPVString("finished"));
+		itsPropertySet->setValue(PN_FSM_CURRENT_ACTION, GCFPVString("stopping"));
 		itsPropertySet->setValue(PN_FSM_ERROR, GCFPVString(""));
 
 		ParameterSet*	thePS  = globalParameterSet();		// shortcut to global PS.
@@ -528,14 +556,23 @@ GCFEvent::TResult OnlineControl::finishing_state(GCFEvent& event, GCFPortInterfa
 		uint32	result = forkexec(startCmd.c_str());
 		LOG_INFO_STR ("Result of command = " << result);
 
-		itsTimerPort->setTimer(302.0); // IONProc, and thus CEPlogProcessor, can take up to 5 minutes to wrap up
+		if (itsFeedbackAvailable) {
+			TRAN(OnlineControl::completing_state);
+		}
 		break;
 	}
 
-	case F_TIMER:
-		_passMetadatToOTDB();
-		GCFScheduler::instance()->stop();
-		break;
+	case F_ACCEPT_REQ: {
+		_handleAcceptRequest(port);
+	} break;
+
+	case F_DISCONNECTED: {
+		_handleDisconnect(port);
+	} break;
+
+	case F_DATAIN: {
+		_handleDataIn(port);		// may switch to completing state
+	} break;
 
 	default:
 		LOG_DEBUG("finishing_state, default");
@@ -546,6 +583,51 @@ GCFEvent::TResult OnlineControl::finishing_state(GCFEvent& event, GCFPortInterfa
 	return (status);
 }
 
+//
+// completing_state(event, port)
+//
+//
+GCFEvent::TResult OnlineControl::completing_state(GCFEvent& event, GCFPortInterface& port)
+{
+	LOG_INFO_STR ("completing:" << eventName(event) << "@" << port.getName());
+
+	GCFEvent::TResult status = GCFEvent::HANDLED;
+
+	switch (event.signal) {
+	case F_ENTRY: {
+		// update PVSS
+		itsPropertySet->setValue(PN_FSM_CURRENT_ACTION, GCFPVString("completing"));
+		itsPropertySet->setValue(PN_FSM_ERROR, GCFPVString(""));
+
+		_passMetadatToOTDB();
+
+		itsPropertySet->setValue(PN_FSM_CURRENT_ACTION, GCFPVString("finished"));
+		itsPropertySet->setValue(PN_FSM_ERROR, GCFPVString(""));
+
+		CONTROLQuitedEvent      msg;
+		msg.cntlrName = itsMyName;
+		msg.result = itsFeedbackResult;
+		itsParentPort->send(msg);
+
+		itsTimerPort->setTimer(0.3);
+	} break;
+
+	case F_TIMER:
+		GCFScheduler::instance()->stop();
+		break;
+
+	case F_DISCONNECTED:
+		_handleDisconnect(port);
+		break;
+
+	case F_DATAIN:
+		_handleDataIn(port);
+		break;
+
+	}
+	return (status);
+}
+
 //
 // _setupBGPmappingTables
 //
@@ -713,97 +795,156 @@ uint32 OnlineControl::_doBoot()
 void OnlineControl::_passMetadatToOTDB()
 {
 	// No name specified?
+	bool	metadataFileAvailable (true);
 	uint32	obsID(globalParameterSet()->getUint32("Observation.ObsID", 0));
 	string  feedbackFile = observationParset(obsID)+"_feedback";
 	LOG_INFO_STR ("Expecting metadata to be in file " << feedbackFile);
 	if (feedbackFile.empty()) {
-		return;
+		metadataFileAvailable = false;
 	}
 
 	// read parameterset
-	try {
-		ParameterSet	metadata;
-		metadata.adoptFile(feedbackFile);
-
-		// Try to setup the connection with the database
-		string	confFile = globalParameterSet()->getString("OTDBconfFile", "SASGateway.conf");
-		ConfigLocator	CL;
-		string	filename = CL.locate(confFile);
-		LOG_INFO_STR("Trying to read database information from file " << filename);
-		ParameterSet	otdbconf;
-		otdbconf.adoptFile(filename);
-		string database = otdbconf.getString("SASGateway.OTDBdatabase");
-		string dbhost   = otdbconf.getString("SASGateway.OTDBhostname");
-		OTDBconnection  conn("paulus", "boskabouter", database, dbhost);
-		if (!conn.connect()) {
-			LOG_FATAL_STR("Cannot connect to database " << database << " on machine " << dbhost);
-			return;
-		}
-		LOG_INFO_STR("Connected to database " << database << " on machine " << dbhost);
-
-		TreeValue   tv(&conn, getObservationNr(getName()));
-
-		// Loop over the parameterset and send the information to the KVTlogger.
-		// During the transition phase from parameter-based to record-based storage in OTDB the
-		// nodenames ending in '_' are implemented both as parameter and as record.
-		ParameterSet::iterator		iter = metadata.begin();
-		ParameterSet::iterator		end  = metadata.end();
-		while (iter != end) {
-			string	key(iter->first);	// make destoyable copy
-			rtrim(key, "[]0123456789");
-	//		bool	doubleStorage(key[key.size()-1] == '_');
-			bool	isRecord(iter->second.isRecord());
-			//   isRecord  doubleStorage
-			// --------------------------------------------------------------
-			//      Y          Y           store as record and as parameters
-			//      Y          N           store as parameters
-			//      N          *           store parameter
-			if (!isRecord) {
-				LOG_DEBUG_STR("BASIC: " << iter->first << " = " << iter->second);
-				tv.addKVT(iter->first, iter->second, ptime(microsec_clock::local_time()));
-			}
-			else {
-	//			if (doubleStorage) {
-	//				LOG_DEBUG_STR("RECORD: " << iter->first << " = " << iter->second);
-	//				tv.addKVT(iter->first, iter->second, ptime(microsec_clock::local_time()));
-	//			}
-				// to store is a node/param values the last _ should be stipped of
-				key = iter->first;		// destroyable copy
-	//			string::size_type pos = key.find_last_of('_');
-	//			key.erase(pos,1);
-				ParameterRecord	pr(iter->second.getRecord());
-				ParameterRecord::const_iterator	prIter = pr.begin();
-				ParameterRecord::const_iterator	prEnd  = pr.end();
-				while (prIter != prEnd) {
-					LOG_DEBUG_STR("ELEMENT: " << key+"."+prIter->first << " = " << prIter->second);
-					tv.addKVT(key+"."+prIter->first, prIter->second, ptime(microsec_clock::local_time()));
-					prIter++;
+	// Try to setup the connection with the database
+	string	confFile = globalParameterSet()->getString("OTDBconfFile", "SASGateway.conf");
+	ConfigLocator	CL;
+	string	filename = CL.locate(confFile);
+	LOG_INFO_STR("Trying to read database information from file " << filename);
+	ParameterSet	otdbconf;
+	otdbconf.adoptFile(filename);
+	string database = otdbconf.getString("SASGateway.OTDBdatabase");
+	string dbhost   = otdbconf.getString("SASGateway.OTDBhostname");
+	OTDBconnection  conn("paulus", "boskabouter", database, dbhost);
+	if (!conn.connect()) {
+		LOG_FATAL_STR("Cannot connect to database " << database << " on machine " << dbhost);
+		// WE DO HAVE A PROBLEM HERE BECAUSE THIS PIPELINE CANNOT BE SET TO FINISHED IN SAS.
+		return;
+	}
+	LOG_INFO_STR("Connected to database " << database << " on machine " << dbhost);
+
+	if (metadataFileAvailable) {
+		try {
+			TreeValue   tv(&conn, getObservationNr(getName()));
+			ParameterSet	metadata;
+			metadata.adoptFile(feedbackFile);
+			// Loop over the parameterset and send the information to the KVTlogger.
+			// During the transition phase from parameter-based to record-based storage in OTDB the
+			// nodenames ending in '_' are implemented both as parameter and as record.
+			ParameterSet::iterator		iter = metadata.begin();
+			ParameterSet::iterator		end  = metadata.end();
+			while (iter != end) {
+				string	key(iter->first);	// make destoyable copy
+				rtrim(key, "[]0123456789");
+		//		bool	doubleStorage(key[key.size()-1] == '_');
+				bool	isRecord(iter->second.isRecord());
+				//   isRecord  doubleStorage
+				// --------------------------------------------------------------
+				//      Y          Y           store as record and as parameters
+				//      Y          N           store as parameters
+				//      N          *           store parameter
+				if (!isRecord) {
+					LOG_DEBUG_STR("BASIC: " << iter->first << " = " << iter->second);
+					tv.addKVT(iter->first, iter->second, ptime(microsec_clock::local_time()));
+				}
+				else {
+		//			if (doubleStorage) {
+		//				LOG_DEBUG_STR("RECORD: " << iter->first << " = " << iter->second);
+		//				tv.addKVT(iter->first, iter->second, ptime(microsec_clock::local_time()));
+		//			}
+					// to store is a node/param values the last _ should be stipped of
+					key = iter->first;		// destroyable copy
+		//			string::size_type pos = key.find_last_of('_');
+		//			key.erase(pos,1);
+					ParameterRecord	pr(iter->second.getRecord());
+					ParameterRecord::const_iterator	prIter = pr.begin();
+					ParameterRecord::const_iterator	prEnd  = pr.end();
+					while (prIter != prEnd) {
+						LOG_DEBUG_STR("ELEMENT: " << key+"."+prIter->first << " = " << prIter->second);
+						tv.addKVT(key+"."+prIter->first, prIter->second, ptime(microsec_clock::local_time()));
+						prIter++;
+					}
 				}
+				iter++;
 			}
-			iter++;
+			LOG_INFO_STR(metadata.size() << " metadata values send to SAS");
+		}
+		catch (APSException &e) {
+			// Parameterfile not found
+			LOG_FATAL(e.text());
 		}
-		LOG_INFO_STR(metadata.size() << " metadata values send to SAS");
-	}
-	catch (APSException &e) {
-		// Parameterfile not found
-		LOG_FATAL(e.text());
 	}
+
+	// finally report state to SAS
+	sleep (60);			/// AAARRRRGGGHH, make 'sure' we are later than the ObservationControl. #4022
+	TreeMaintenance	tm(&conn);
+	TreeStateConv	tsc(&conn);
+	tm.setTreeState(obsID, tsc.get("finished"));
 }
 // -------------------- Application-order administration --------------------
 
 //
-// _connectedHandler(port)
+// _handleDisconnect(port)
 //
-void OnlineControl::_connectedHandler(GCFPortInterface& /*port*/)
+void OnlineControl::_handleDisconnect(GCFPortInterface& port)
 {
+	port.close();
+	// QUICKFIX #4022
+	if (&port == itsFeedbackPort) {
+		LOG_FATAL_STR("Lost connection with Feedback of OLAP.");
+		delete itsFeedbackPort;
+		itsFeedbackPort = 0;
+	}
 }
 
 //
-// _disconnectedHandler(port)
+// _handleAcceptRequest(port)
 //
-void OnlineControl::_disconnectedHandler(GCFPortInterface& port)
+void OnlineControl::_handleAcceptRequest(GCFPortInterface& port)
 {
-	port.close();
+	ASSERTSTR(&port == itsFeedbackListener, "Incoming connection on main listener iso feedbackListener");
+	itsFeedbackPort = new GCFTCPPort();
+	itsFeedbackPort->init(*this, "feedback", GCFPortInterface::SPP, 0, true);   // raw port
+	if (!itsFeedbackListener->accept(*itsFeedbackPort)) {
+		delete itsFeedbackPort;
+		itsFeedbackPort = 0;
+		LOG_ERROR("Connection with Python feedback FAILED");
+	}
+	else {
+		LOG_INFO("Connection made on feedback port, accepting commands");
+	}
+}
+
+//
+// _handleDataIn(port)
+//
+void OnlineControl::_handleDataIn(GCFPortInterface& port)
+{
+	ASSERTSTR(&port == itsFeedbackPort, "Didn't expect raw data on port " << port.getName());
+	char    buf[1024];
+	ssize_t btsRead = port.recv((void*)&buf[0], 1023);
+	buf[btsRead] = '\0';
+	string  s;
+	hexdump(s, buf, btsRead);
+	LOG_INFO_STR("Received command on feedback port: " << s);
+
+	if (!strcmp(buf, "ABORT")) {
+		itsFeedbackResult = CT_RESULT_PIPELINE_FAILED;
+		itsFeedbackAvailable = true;
+	}
+	else if (!strcmp(buf, "FINISHED")) {
+		itsFeedbackAvailable = true;
+	}
+	else {
+		LOG_FATAL_STR("Received command on feedback port unrecognized");
+	}
+
+	if (itsFeedbackAvailable) {	// recognized command?
+		if (itsInFinishState) {	// already stopped BGP?
+			TRAN(OnlineControl::completing_state);	// pass metadata
+		}
+		else {
+			TRAN(OnlineControl::finishing_state);	// stop BGP first.
+		}
+	}
 }
 
 }; // CEPCU
diff --git a/MAC/APL/CEPCU/src/OnlineControl/OnlineControl.h b/MAC/APL/CEPCU/src/OnlineControl/OnlineControl.h
index 8383e92c5f6fe579dc72db7051005ed6a99c0ca3..3c1b8bcfae432352551f857767241787aa3e40a1 100644
--- a/MAC/APL/CEPCU/src/OnlineControl/OnlineControl.h
+++ b/MAC/APL/CEPCU/src/OnlineControl/OnlineControl.h
@@ -72,13 +72,13 @@ public:
 	// Connect to BGPAppl propset and start remaining tasks.
    	GCFEvent::TResult propset_state (GCFEvent& e, GCFPortInterface& p);
 	// Normal control mode. 
-   	GCFEvent::TResult active_state  (GCFEvent& e, GCFPortInterface& p);
-	// Finishing mode. 
-	GCFEvent::TResult finishing_state(GCFEvent& event, GCFPortInterface& port);
+   	GCFEvent::TResult active_state    (GCFEvent& e, GCFPortInterface& p);
+	GCFEvent::TResult finishing_state (GCFEvent& event, GCFPortInterface& port);
+	GCFEvent::TResult completing_state(GCFEvent& event, GCFPortInterface& port);
 	
 	// Interrupthandler for switching to finisingstate when exiting the program
 	static void signalHandler (int	signum);
-	void	    finish();
+	void	    finish(int	result);
 
 private:
 	// avoid defaultconstruction and copying
@@ -89,13 +89,15 @@ private:
 	uint32	_doBoot();
 	void	_setupBGPmappingTables();
 	void   	_finishController	 (uint16_t 				result);
-   	void	_connectedHandler	 (GCFPortInterface& 	port);
-   	void	_disconnectedHandler (GCFPortInterface& 	port);
+   	void	_handleDisconnect	 (GCFPortInterface& 	port);
+   	void	_handleAcceptRequest (GCFPortInterface& 	port);
+   	void	_handleDataIn		 (GCFPortInterface& 	port);
 	void	_setState	  		 (CTState::CTstateNr	newState);
 	void	_databaseEventHandler(GCFEvent&				event);
 	void	_passMetadatToOTDB   ();
 
 	// ----- datamembers -----
+	string						itsMyName;
    	RTDBPropertySet*           	itsPropertySet;
    	RTDBPropertySet*           	itsBGPApplPropSet;
 	bool					  	itsPropertySetInitialized;
@@ -112,6 +114,11 @@ private:
 
 	CTState::CTstateNr		itsState;
 
+	// QUICK FIX #4022
+	GCFTCPPort*				itsFeedbackListener;
+	GCFTCPPort*				itsFeedbackPort;
+	int						itsFeedbackResult;
+
 	// ParameterSet variables
 	string					itsTreePrefix;
 	uint32					itsInstanceNr;
@@ -120,6 +127,7 @@ private:
 	uint16					itsStopTimerID;
 	uint16					itsFinishTimerID;
 	bool					itsInFinishState;
+	bool					itsFeedbackAvailable;
 };
 
   };//CEPCU
diff --git a/MAC/APL/CEPCU/src/PythonControl/PythonControl.cc b/MAC/APL/CEPCU/src/PythonControl/PythonControl.cc
index 8a6878e91d2dec3cfeac2c4a946b1f87ccaea972..738d3e3a8bf5b10132f97d8e41f2f23445ec2076 100644
--- a/MAC/APL/CEPCU/src/PythonControl/PythonControl.cc
+++ b/MAC/APL/CEPCU/src/PythonControl/PythonControl.cc
@@ -46,6 +46,8 @@
 #include <APL/APLCommon/Controller_Protocol.ph>
 #include <APL/APLCommon/CTState.h>
 #include <OTDB/TreeValue.h>
+#include <OTDB/TreeMaintenance.h>
+#include <OTDB/TreeStateConv.h>
 
 #include "PythonControl.h"
 #include "PVSSDatapointDefs.h"
@@ -123,11 +125,15 @@ PythonControl::PythonControl(const string&	cntlrName) :
 PythonControl::~PythonControl()
 {
 	LOG_TRACE_OBJ_STR (getName() << " destruction");
-	if (itsListener) 
-		{ itsListener->close(); delete itsListener; }
+	if (itsListener) { 
+		itsListener->close(); 
+		delete itsListener; 
+	}
 
-	if (itsFeedbackListener) 	// QUICK FIX #3633
-		{ itsFeedbackListener->close(); delete itsFeedbackListener; }
+	if (itsFeedbackListener) { 	// QUICK FIX #3633
+		itsFeedbackListener->close(); 
+		delete itsFeedbackListener; 
+	}
 }
 
 //
@@ -756,28 +762,27 @@ GCFEvent::TResult PythonControl::finishing_state(GCFEvent& event, GCFPortInterfa
 //
 void PythonControl::_passMetadatToOTDB()
 {
+	bool	metadataFileAvailable (true);
+
 	// No name specified?
 	if (itsFeedbackFile.empty()) {
-		return;
+		metadataFileAvailable = false;
 	}
-
-	// Copy file form remote system to localsystem
-	ParameterSet*   thePS  = globalParameterSet();      // shortcut to global PS.
-	string  myPrefix  (thePS->locateModule("PythonControl")+"PythonControl.");
-	string	pythonHost(thePS->getString(myPrefix+"pythonHost","@pythonHost@"));
-	try {
-		if (copyFromRemote(realHostname(pythonHost), itsFeedbackFile, itsFeedbackFile) != 0) {
-			LOG_ERROR_STR("Failed to copy metadatafile " << itsFeedbackFile << " from host " << realHostname(pythonHost));
-			return;
+	else {
+		// Copy file from remote system to localsystem
+		ParameterSet*   thePS  = globalParameterSet();      // shortcut to global PS.
+		string  myPrefix  (thePS->locateModule("PythonControl")+"PythonControl.");
+		string	pythonHost(thePS->getString(myPrefix+"pythonHost","@pythonHost@"));
+		try {
+			if (copyFromRemote(realHostname(pythonHost), itsFeedbackFile, itsFeedbackFile) != 0) {
+				LOG_ERROR_STR("Failed to copy metadatafile " << itsFeedbackFile << " from host " << realHostname(pythonHost));
+				metadataFileAvailable = false;
+			}
+		}
+		catch (...) { 
+			metadataFileAvailable = false;
 		}
 	}
-	catch (...) { 
-		return;
-	}
-
-	// read parameterset
-	ParameterSet	metadata;
-	metadata.adoptFile(itsFeedbackFile);
 
 	// Try to setup the connection with the database
 	string	confFile = globalParameterSet()->getString("OTDBconfFile", "SASGateway.conf");
@@ -791,52 +796,65 @@ void PythonControl::_passMetadatToOTDB()
 	OTDBconnection  conn("paulus", "boskabouter", database, dbhost);
 	if (!conn.connect()) {
 		LOG_FATAL_STR("Cannot connect to database " << database << " on machine " << dbhost);
+		// WE DO HAVE A PROBLEM HERE BECAUSE THIS PIPELINE CANNOT BE SET TO FINISHED IN SAS.
 		return;
 	}
 	LOG_INFO_STR("Connected to database " << database << " on machine " << dbhost);
 
-	TreeValue   tv(&conn, getObservationNr(getName()));
-
-	// Loop over the parameterset and send the information to the KVTlogger.
-	// During the transition phase from parameter-based to record-based storage in OTDB the
-	// nodenames ending in '_' are implemented both as parameter and as record.
-	ParameterSet::iterator		iter = metadata.begin();
-	ParameterSet::iterator		end  = metadata.end();
-	while (iter != end) {
-		string	key(iter->first);	// make destoyable copy
-		rtrim(key, "[]0123456789");
-//		bool	doubleStorage(key[key.size()-1] == '_');
-		bool	isRecord(iter->second.isRecord());
-		//   isRecord  doubleStorage
-		// --------------------------------------------------------------
-		//      Y          Y           store as record and as parameters
-		//      Y          N           store as parameters
-		//      N          *           store parameter
-		if (!isRecord) {
-			LOG_DEBUG_STR("BASIC: " << iter->first << " = " << iter->second);
-			tv.addKVT(iter->first, iter->second, ptime(microsec_clock::local_time()));
-		}
-		else {
-//			if (doubleStorage) {
-//				LOG_DEBUG_STR("RECORD: " << iter->first << " = " << iter->second);
-//				tv.addKVT(iter->first, iter->second, ptime(microsec_clock::local_time()));
-//			}
-			// to store is a node/param values the last _ should be stipped of
-			key = iter->first;		// destroyable copy
-//			string::size_type pos = key.find_last_of('_');
-//			key.erase(pos,1);
-			ParameterRecord	pr(iter->second.getRecord());
-			ParameterRecord::const_iterator	prIter = pr.begin();
-			ParameterRecord::const_iterator	prEnd  = pr.end();
-			while (prIter != prEnd) {
-				LOG_DEBUG_STR("ELEMENT: " << key+"."+prIter->first << " = " << prIter->second);
-				tv.addKVT(key+"."+prIter->first, prIter->second, ptime(microsec_clock::local_time()));
-				prIter++;
+	int			obsID(getObservationNr(getName()));
+	TreeValue   tv(&conn, obsID);
+
+	if (metadataFileAvailable) {
+		// read parameterset
+		ParameterSet	metadata;
+		metadata.adoptFile(itsFeedbackFile);
+
+		// Loop over the parameterset and send the information to the KVTlogger.
+		// During the transition phase from parameter-based to record-based storage in OTDB the
+		// nodenames ending in '_' are implemented both as parameter and as record.
+		ParameterSet::iterator		iter = metadata.begin();
+		ParameterSet::iterator		end  = metadata.end();
+		while (iter != end) {
+			string	key(iter->first);	// make destoyable copy
+			rtrim(key, "[]0123456789");
+	//		bool	doubleStorage(key[key.size()-1] == '_');
+			bool	isRecord(iter->second.isRecord());
+			//   isRecord  doubleStorage
+			// --------------------------------------------------------------
+			//      Y          Y           store as record and as parameters
+			//      Y          N           store as parameters
+			//      N          *           store parameter
+			if (!isRecord) {
+				LOG_DEBUG_STR("BASIC: " << iter->first << " = " << iter->second);
+				tv.addKVT(iter->first, iter->second, ptime(microsec_clock::local_time()));
 			}
+			else {
+	//			if (doubleStorage) {
+	//				LOG_DEBUG_STR("RECORD: " << iter->first << " = " << iter->second);
+	//				tv.addKVT(iter->first, iter->second, ptime(microsec_clock::local_time()));
+	//			}
+				// to store is a node/param values the last _ should be stipped of
+				key = iter->first;		// destroyable copy
+	//			string::size_type pos = key.find_last_of('_');
+	//			key.erase(pos,1);
+				ParameterRecord	pr(iter->second.getRecord());
+				ParameterRecord::const_iterator	prIter = pr.begin();
+				ParameterRecord::const_iterator	prEnd  = pr.end();
+				while (prIter != prEnd) {
+					LOG_DEBUG_STR("ELEMENT: " << key+"."+prIter->first << " = " << prIter->second);
+					tv.addKVT(key+"."+prIter->first, prIter->second, ptime(microsec_clock::local_time()));
+					prIter++;
+				}
+			}
+			iter++;
 		}
-		iter++;
+		LOG_INFO_STR(metadata.size() << " metadata values send to SAS");
 	}
-	LOG_INFO_STR(metadata.size() << " metadata values send to SAS");
+
+	// finally report state to SAS
+	TreeMaintenance	tm(&conn);
+	TreeStateConv	tsc(&conn);
+	tm.setTreeState(obsID, tsc.get("finished"));
 }
 
 }; // CEPCU
diff --git a/MAC/APL/MainCU/src/MACScheduler/MACScheduler.cc b/MAC/APL/MainCU/src/MACScheduler/MACScheduler.cc
index a0420c85ebc0500f17e5a287cd5d1ca8e5420f09..36f93d4dfd75f335140cb1182987d77bfa162626 100644
--- a/MAC/APL/MainCU/src/MACScheduler/MACScheduler.cc
+++ b/MAC/APL/MainCU/src/MACScheduler/MACScheduler.cc
@@ -465,7 +465,7 @@ GCFEvent::TResult MACScheduler::active_state(GCFEvent& event, GCFPortInterface&
 		TreeStateConv			tsc(itsOTDBconnection);
 		// CT_RESULT_: MANUAL_REMOVED, MANUAL_ABORT, LOST_CONNECTION, NO_ERROR
 		if (quitedEvent.result == CT_RESULT_NO_ERROR) {
-			tm.setTreeState(theObs->second, tsc.get("finished"));
+			tm.setTreeState(theObs->second, tsc.get("completing"));
 		}
 		else {
 			tm.setTreeState(theObs->second, tsc.get("aborted"));
diff --git a/MAC/Deployment/data/OTDB/DPPP.comp b/MAC/Deployment/data/OTDB/DPPP.comp
index 97ad809f0e35a991a4e11f4914e7baeef70ce83b..5076a0ea326de806bad07a2777d4a20efd4af28f 100644
--- a/MAC/Deployment/data/OTDB/DPPP.comp
+++ b/MAC/Deployment/data/OTDB/DPPP.comp
@@ -180,6 +180,7 @@ par	type		I		text	-	10		0	"stationadder"	-	"Type of the step, do not change"
 par	stations        	I	text	-	10            0	""              -		"Stations to be added (in record-format)"
 par	minpoints	I      	int	-	10		0	1		-	"If fewer unflagged input points are available, the averaged point is flagged."
 par	autocorr	I		bool	-	10		0	F			-	"Add autocorrelations?"
+par	sumauto	I		bool	-	10		0      T			-	"Sum auto or cross for new autocorrelations?"
 par	useweights I		bool	-	10		0      T			-	"F = use weight 1"
 
 node	filter          	4.0.0	development	'node constraint'	"Selection"
diff --git a/MAC/Deployment/data/PVSS/data/PVSSbase.dpdef b/MAC/Deployment/data/PVSS/data/PVSSbase.dpdef
index 0d0b747aa585607b90a1fbacf29f85f867222d7c..8d70a53301d3ae34f9ab83cf158ae1ce15712364 100644
--- a/MAC/Deployment/data/PVSS/data/PVSSbase.dpdef
+++ b/MAC/Deployment/data/PVSS/data/PVSSbase.dpdef
@@ -64,6 +64,13 @@ NCFObjectState.NCFObjectState	1#
 	message	25#
 	force	23#
 
+TypeName
+NCFObjectStates.NCFObjectStates	1#
+	DPNames	9#
+	stateNrs	5#
+	messages	9#
+	force	7#
+
 TypeName
 ObjectStatus.ObjectStatus	1#
 	state	21#
@@ -123,6 +130,8 @@ DpName	TypeName
 ClaimManager	ClaimManager
 __navObjectState	NCFObjectState
 __resetObjectState	NCFObjectState
+__navObjectStates	NCFObjectStates
+__resetObjectStates	NCFObjectStates
 lofarSpeedTest	LofarSpeedTest
 scriptInfo	ScriptInfo
 
diff --git a/MAC/Deployment/data/PVSS/data/StationInfo.dpdef b/MAC/Deployment/data/PVSS/data/StationInfo.dpdef
index e924083b75ad439d6bb5421cfea6d3d2d3c2da23..20157640529e7c98c2f8501af1151ee3b538c2ea 100644
--- a/MAC/Deployment/data/PVSS/data/StationInfo.dpdef
+++ b/MAC/Deployment/data/PVSS/data/StationInfo.dpdef
@@ -13,7 +13,7 @@ Cabinet.X		float
 Cabinet.Y		float
 Cabinet.Z		float
 HBA.nrBroken		int
-HBA.pecent		float
+HBA.nrBrokenArchive	int
 HBA.centerX		float
 HBA.centerY		float
 HBA.centerZ		float
@@ -38,7 +38,7 @@ HBA.HBA1.RotationMatrix.Y	floatArr
 HBA.HBA1.RotationMatrix.Z	floatArr
 HBA.HBA1.rotation		float
 LBA.nrBroken		int
-LBA.pecentBroken		float
+LBA.nrBrokenArchive		int
 LBA.centerX		float
 LBA.centerY		float
 LBA.centerZ		float
@@ -60,16 +60,17 @@ LBA.RotationMatrix.Z	floatArr
 !_mp_StationInfo.datastream0	StationInfo	1	15		_ValueArchive_2
 !_mp_StationInfo.datastream1	StationInfo		45	1
 !_mp_StationInfo.datastream1	StationInfo	1	15		_ValueArchive_2
-!_mp_StationInfo.LBA.nrBroken	StationInfo		45	1
-!_mp_StationInfo.LBA.nrBroken	StationInfo	1	15		_ValueArchive_2
-!_mp_StationInfo.LBA.percentBroken	StationInfo		45	1
-!_mp_StationInfo.LBA.percentBroken	StationInfo	1	15		_ValueArchive_2
-!_mp_StationInfo.HBA.nrBroken	StationInfo		45	1
-!_mp_StationInfo.HBA.nrBroken	StationInfo	1	15		_ValueArchive_2
-!_mp_StationInfo.HBA.percentBroken	StationInfo		45	1
-!_mp_StationInfo.HBA.percentBroken	StationInfo	1	15		_ValueArchive_2
+!_mp_StationInfo.LBA.nrBrokenArchive	StationInfo		45	1
+!_mp_StationInfo.LBA.nrBrokenArchive	StationInfo	1	15		_ValueArchive_3
+!_mp_StationInfo.HBA.nrBrokenArchive	StationInfo		45	1
+!_mp_StationInfo.HBA.nrBrokenArchive	StationInfo	1	15		_ValueArchive_3
 !
 !# DpValue
 !ElementName	TypeName	_original.._value
-!_dt_StationInfo.Leaf	_DynamicDatapoints	"_mp_StationInfo.datastream0:_archive", "_mp_StationInfo.datastream1:_archive", "_mp_StationInfo.LBA.nrBroken:_archive", "_mp_StationInfo.LBA.percentBroken:_archive","_mp_StationInfo.HBA.nrBroken:_archive", "_mp_StationInfo.HBA.percentBroken:_archive"
-!_dt_StationInfo.DynamicAttribute	_DynamicDatapoints	"_da_none", "_da_none", "_da_none", "_da_none", "_da_none", "_da_none"
+!_dt_StationInfo.Leaf	_DynamicDatapoints	"_mp_StationInfo.datastream0:_archive", "_mp_StationInfo.datastream1:_archive", "_mp_StationInfo.LBA.nrBrokenArchive:_archive", "_mp_StationInfo.HBA.nrBrokenArchive:_archive", "_mp_StationInfo.HBA.nrBrokenArchive:_dp_fct", "_mp_StationInfo.LBA.nrBrokenArchive:_dp_fct"
+!_dt_StationInfo.DynamicAttribute	_DynamicDatapoints	"_da_none", "_da_none", "_da_none", "_da_none", "_da_dp_fct_variabel", "_da_dp_fct_variabel"
+
+!# DpFunction
+!ElementName	TypeName	_dp_fct.._type	_dp_fct.._param	_dp_fct.._fct	_dp_fct.._global	_dp_fct.._stat_type	_dp_fct.._interval	_dp_fct.._time
+!_mp_StationInfo.HBA.nrBrokenArchive	StationInfo	63		"g"	_mp_StationInfo.HBA.nrBroken:_original.._value		86400	82800
+!_mp_StationInfo.LBA.nrBrokenArchive	StationInfo	63		"g"	_mp_StationInfo.LBA.nrBroken:_original.._value		86400	82800
diff --git a/MAC/Deployment/data/PVSS/data/Stationbase.dpdef b/MAC/Deployment/data/PVSS/data/Stationbase.dpdef
index eead1cbd32c45adf169f50ca2076ae48bc67ad09..8d147968a90368b814bda42d7488e6c023807c8a 100644
--- a/MAC/Deployment/data/PVSS/data/Stationbase.dpdef
+++ b/MAC/Deployment/data/PVSS/data/Stationbase.dpdef
@@ -163,6 +163,7 @@ _CtrlDebug_CTRL_7	_CtrlDebug
 _CtrlDebug_CTRL_8	_CtrlDebug
 _CtrlDebug_CTRL_9	_CtrlDebug
 _CtrlDebug_CTRL_10	_CtrlDebug
+_CtrlDebug_CTRL_11	_CtrlDebug
 
 #Fill some defaults
 # DpValue
diff --git a/MAC/MACIO/include/MACIO/MACServiceInfo.h b/MAC/MACIO/include/MACIO/MACServiceInfo.h
index 1409e74783ea8e901de4be15957f7326eee9093e..14c25c57e7a832d0fb38830bfc79d526f211c6c1 100644
--- a/MAC/MACIO/include/MACIO/MACServiceInfo.h
+++ b/MAC/MACIO/include/MACIO/MACServiceInfo.h
@@ -44,6 +44,8 @@ namespace LOFAR {
 
 // QUICK FIX #3633
 #define MAC_PYTHON_FEEDBACK_QF			22000
+// Quick Fix #4022
+#define MAC_ONLINE_FEEDBACK_QF			21000
 
 // CEPlogprocessor needs fixed ports
 #define CEP_LOGPROC_LOGGING				23900
diff --git a/MAC/Navigator2/config/progs.dist.station b/MAC/Navigator2/config/progs.dist.station
index 756fc6af55d2f50cb4f397c3f681841f70d9deaf..34192b8fc51b393862a635e1d60c7de9e6815873 100644
--- a/MAC/Navigator2/config/progs.dist.station
+++ b/MAC/Navigator2/config/progs.dist.station
@@ -6,6 +6,7 @@ PVSS00pmon       | manual |      30 |        3 |        1 |
 PVSS00data       | always |      30 |        3 |        1 |
 PVSS00valarch    | always |      30 |        3 |        1 |-num 0
 PVSS00valarch    | always |      30 |        3 |        1 |-num 2
+PVSS00valarch    | always |      30 |        3 |        1 |-num 3
 PVSS00event      | always |      30 |        3 |        1 |
 PVSS00ctrl       | always |      30 |        3 |        1 |-f pvss_scripts.lst
 PVSS00sim        | always |      30 |        3 |        1 |
diff --git a/MAC/Navigator2/config/progs.standalone.station b/MAC/Navigator2/config/progs.standalone.station
index 8b56867e40eb12fa9cb71fc890594fa11d9e0d3f..c279f585a9898b7acb99a0a936cf4c1314228d2e 100644
--- a/MAC/Navigator2/config/progs.standalone.station
+++ b/MAC/Navigator2/config/progs.standalone.station
@@ -6,6 +6,7 @@ PVSS00pmon       | manual |      30 |        3 |        1 |
 PVSS00data       | always |      30 |        3 |        1 |
 PVSS00valarch    | always |      30 |        3 |        1 |-num 0
 PVSS00valarch    | always |      30 |        3 |        1 |-num 2
+PVSS00valarch    | always |      30 |        3 |        1 |-num 3
 PVSS00event      | always |      30 |        3 |        1 |
 PVSS00ctrl       | always |      30 |        3 |        1 |-f pvss_scripts.lst
 PVSS00sim        | always |      30 |        3 |        1 |
diff --git a/MAC/Navigator2/panels/objects/Hardware/Station_mainView.pnl b/MAC/Navigator2/panels/objects/Hardware/Station_mainView.pnl
index a99475bec81e15e3355a36b5b6a90ca5f508a399..666becfd57485167b539b67c0a422960cf774134 100644
--- a/MAC/Navigator2/panels/objects/Hardware/Station_mainView.pnl
+++ b/MAC/Navigator2/panels/objects/Hardware/Station_mainView.pnl
@@ -45,11 +45,11 @@ LANG:1 0
 0
 1 19 2 "" 0
 0
-1 20 3 "" 0
+1 20 4 "" 0
 0
-1 21 4 "" 0
+1 21 5 "" 0
 0
-1 22 5 "" 0
+1 22 6 "" 0
 0
 0
 LAYER, 1 
@@ -89,11 +89,6 @@ LANG:1 0
 2
 "$fullDP""LOFAR_PIC_StationInfo.power48On"
 "$station""$station"
-3 3 "PANEL_REF3" -1
-"objects\\genericOnOffView.pnl" 60 0 T 36 U 
-2
-"$fullDP""LOFAR_PIC_Cabinet0_Subrack0_RSPBoard0_RCU0.TBB.mode"
-"$station""$station"
 3 4 "PANEL_REF4" -1
 "objects\\Hardware\\antennaBroken_Small.pnl" 80 0 T 37 1 0 1 2 0
 2
@@ -104,4 +99,8 @@ LANG:1 0
 2
 "$antennaType""LBA"
 "$station""$station"
+3 6 "PANEL_REF6" -1
+"objects\\Hardware\\TBBmode_small.pnl" 60 0 T 39 U 
+1
+"$station""$station"
 0
diff --git a/MAC/Navigator2/panels/objects/Hardware/TBBmode_small.pnl b/MAC/Navigator2/panels/objects/Hardware/TBBmode_small.pnl
new file mode 100644
index 0000000000000000000000000000000000000000..6020c5a680ea1ddc1729f093e714a295bf7d42da
--- /dev/null
+++ b/MAC/Navigator2/panels/objects/Hardware/TBBmode_small.pnl
@@ -0,0 +1,100 @@
+V 11
+1
+LANG:1 0 
+PANEL,-1 -1 388 166 N "_3DFace" 1
+"$station"
+"main()
+{
+  station = $station+\":\";
+  baseDP = station+\"LOFAR_PIC_Cabinet0_Subrack0_RSPBoard0_RCU0\";
+  reload();
+}
+  
+private void reload() {
+  
+  // since 
+  // check if the required datapoint for this view are enabled and accessible
+  if (navFunct_dpReachable(baseDP+\".TBB.mode\")) {
+    if (dpConnect(\"updateTBBrecording\", baseDP +\".TBB.mode:_online.._value\",
+                                    baseDP +\".TBB.mode:_online.._invalid\") == -1) {
+      setValue(\"TBBrecording\", \"backCol\", \"Lofar_dpdoesnotexist\");
+    }
+  } else {
+    setValue(\"TBBrecording\", \"backCol\", \"Lofar_dpOffline\");
+
+  }	
+}
+
+updateTBBrecording(string dp1, string mode,
+                   string dp2, bool invalid)
+{
+
+  if (invalid) {
+    setValue(\"TBBrecording\", \"backCol\", \"Lofar_invalid\");
+    return;
+  }
+  
+  string color =  \"Lofar_broken\";
+  if (strtolower(mode) == \"recording\" ) color = \"Lofar_operational\";
+  
+  setValue(\"TBBrecording\",\"toolTipText\",station+\" TBBmode: \"+mode );
+  setValue(\"TBBrecording\", \"backCol\", color);
+ }" 0
+ E E E E 1 -1 -1 0  0 0
+""0  1
+E "#uses \"navPanel.ctl\"
+string station = \"\";
+string baseDP=\"\";
+" 0
+ 2
+"CBRef" "1"
+"EClose" E
+""
+DISPLAY_LAYER, 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
+LAYER, 0 
+1
+LANG:1 0 
+6 0
+"TBBrecording"
+""
+1 230 150 E E E 1 E 1 E N {0,0,0} E N {255,255,255} E E
+ E E
+0 0 0 0 0 0
+E E E
+0
+1
+LANG:1 0 
+
+1
+"dashclr"N "_Transparent"
+E E 0 1 1 2 1 E 1 0 1 0 -10 1 E 0 10 14 19
+0
+LAYER, 1 
+1
+LANG:1 0 
+0
+LAYER, 2 
+1
+LANG:1 0 
+0
+LAYER, 3 
+1
+LANG:1 0 
+0
+LAYER, 4 
+1
+LANG:1 0 
+0
+LAYER, 5 
+1
+LANG:1 0 
+0
+LAYER, 6 
+1
+LANG:1 0 
+0
+LAYER, 7 
+1
+LANG:1 0 
+0
+0
diff --git a/RTCP/RTCPTools/src/tbb-crc-test.cc b/RTCP/RTCPTools/src/tbb-crc-test.cc
index 975cb5b54725a390b808dd97fa60f9af76c5f1ae..958846d046129d70786c775462cb673bb34aef44 100644
--- a/RTCP/RTCPTools/src/tbb-crc-test.cc
+++ b/RTCP/RTCPTools/src/tbb-crc-test.cc
@@ -6,6 +6,7 @@
  */
 
 #include <stdint.h>
+#include <string.h>
 #include <endian.h>
 #if __BYTE_ORDER != __BIG_ENDIAN && __BYTE_ORDER != __LITTLE_ENDIAN
 #error Byte order is neither big endian nor little endian: not supported
@@ -43,7 +44,8 @@ struct TBB_Header {
 };
 
 #define MAX_TRANSIENT_NSAMPLES		1298 // based on frames stored by TBB and (un)packing
-#define DEFAULT_TRANSIENT_NSAMPLES	1024
+#define DEFAULT_TRANSIENT_NSAMPLES	1024 // int16_t
+#define DEFAULT_SPECTRAL_NSAMPLES	 487 // complex int16_t
 struct TBB_Payload {
 	// For transient data, we typically receive 1024 samples per frame.
 	// uint32_t crc comes right after, so cannot easily declare it after data[], hence + 2.
@@ -225,6 +227,22 @@ static int verify_crc(TBB_Frame& frame, size_t frameSize) {
 	if (!crc32tbb_boost( &frame.payload, ( frameSize - sizeof(TBB_Header) - sizeof(uint32_t) ) / sizeof(int16_t) )) {
 		cerr << "crc32tbb_boost(): Incorrect payload crc" << endl;
 		err = 1;
+
+#if 0 // this guessing doesn't work: the wrong crc32 is different every time, even on the same data
+		TBB_Payload p;
+		unsigned i;
+		for (i = 0; i < 487; i++) {
+			memcpy(&p, &frame.payload, i * 2 * sizeof(int16_t)); // data
+			memcpy((char*)&p + i * 2 * sizeof(int16_t), (char*)(&frame.payload.data[2*487 + 2]) - sizeof(uint32_t), sizeof(uint32_t)); // crc32
+			if (crc32tbb_boost(&p, 2 * i)) {
+				cerr << "found it: i=" << i << endl;
+				break;
+			} else {
+				cerr << "doesn't work either: " << i << endl;
+			}
+		}
+#endif
+
 	}
 
 	return err;
@@ -236,6 +254,22 @@ int main(int argc, char* argv[]) {
 		return 1;
 	}
 
+	bool transient;
+	ifstream iftype(argv[1], ios_base::binary);
+	if (!iftype) {
+		cerr << "Failed to open file " << argv[1] << endl;
+		return 1;
+	}
+	TBB_Header header;
+	iftype.read(reinterpret_cast<char*>(&header), sizeof header);
+	if (!iftype) {
+		cerr << "Failed to read first frame to determine transient or spectral mode" << endl;
+		return 1;
+	}
+	iftype.close();
+	transient = header.nOfFreqBands == 0;
+
+
 	ifstream ifs(argv[1], ios_base::binary);
 	if (!ifs) {
 		cerr << "Failed to open file " << argv[1] << endl;
@@ -245,7 +279,12 @@ int main(int argc, char* argv[]) {
 	int err = 0;
 
 	TBB_Frame frame;
-	size_t frameSize = sizeof(TBB_Header) + DEFAULT_TRANSIENT_NSAMPLES * sizeof(int16_t) + sizeof(uint32_t);
+	size_t frameSize;
+	if (transient) {
+		frameSize = sizeof(TBB_Header) + DEFAULT_TRANSIENT_NSAMPLES * sizeof(int16_t) + sizeof(uint32_t);
+	} else { // spectral
+		frameSize = sizeof(TBB_Header) + DEFAULT_SPECTRAL_NSAMPLES * 2 * sizeof(int16_t) + sizeof(uint32_t);
+	}
 
 	while (ifs.read(reinterpret_cast<char*>(&frame), frameSize)) {
 		err |= verify_crc(frame, frameSize);
diff --git a/RTCP/Run/src/LOFAR/Parset.py b/RTCP/Run/src/LOFAR/Parset.py
index 8a3ac9e36ff3d5bbc639d4069cc3033639f6f527..de3445852ba486a9ccbd94b957b2c15a79ceaa42 100644
--- a/RTCP/Run/src/LOFAR/Parset.py
+++ b/RTCP/Run/src/LOFAR/Parset.py
@@ -202,11 +202,13 @@ class Parset(util.Parset.Parset):
           self.setdefault("Observation.Beam[%s].tabRingSize" % (b,),0.0)
 
           dirtype = self["Observation.Beam[%s].directionType" % (b,)]  
+          center_angle1 = float(self["Observation.Beam[%s].angle1" % (b,)])
+          center_angle2 = float(self["Observation.Beam[%s].angle2" % (b,)])
           dm = int(self.get("OLAP.dispersionMeasure",0))
 
           nrrings = int(self["Observation.Beam[%s].nrTabRings" % (b,)]) 
           width   = float(self["Observation.Beam[%s].tabRingSize" % (b,)]) 
-          ringcoordinates = RingCoordinates( nrrings, width )
+          ringcoordinates = RingCoordinates( nrrings, width, (center_angle1, center_angle2), dirtype )
           ringset = [
             { "angle1": angle1,
               "angle2": angle2,
diff --git a/RTCP/Run/src/LOFAR/RingCoordinates.py b/RTCP/Run/src/LOFAR/RingCoordinates.py
index fc82d772aeae918391742c7ecfa355b0b4ec8d6a..02e52a3c2d1ffa9898b6f72f826d47ff1cac33dc 100644
--- a/RTCP/Run/src/LOFAR/RingCoordinates.py
+++ b/RTCP/Run/src/LOFAR/RingCoordinates.py
@@ -1,11 +1,28 @@
 #!/usr/bin/python
 
-from math import sqrt
+from math import sqrt, cos, pi
 
 class RingCoordinates:
-    def __init__(self, numrings, width):
+    def __init__(self, numrings, width, center, dirtype):
         self.numrings = numrings
         self.width    = width
+        self.center   = center
+        self.dirtype  = dirtype
+
+    def cos_adjust(self, offset):
+        if dirtype != "J2000" and dirtype != "B1950":
+          return offset
+
+        # warp coordinates closer to the NCP
+
+        cos_dec = cos(self.center[1] + offset[1])
+        epsilon = 0.0001
+
+        if cos_dec > epsilon:
+            return (offset[0]/cos_dec, offset[1])
+        else:
+            return offset
+
 
     def len_edge(self):
         """
@@ -120,5 +137,5 @@ class RingCoordinates:
               l += dl[side]
               m += dm[side]
 
-        return coordinates
+        return map(self.cos_adjust, coordinates)
 
diff --git a/RTCP/Storage/include/Storage/TBB_Writer.h b/RTCP/Storage/include/Storage/TBB_Writer.h
index 0b29e0854530d16d3ba02bea1128773f9c211f7e..6a1ed8d160b5682d0c5c009884069effcfe8d5d9 100644
--- a/RTCP/Storage/include/Storage/TBB_Writer.h
+++ b/RTCP/Storage/include/Storage/TBB_Writer.h
@@ -63,10 +63,7 @@ namespace RTCP {
  * available at: http://www.lofar.org/project/lofardoc/document.php
  * Old rev. 2.0 (2006-10-3): http://lus.lofar.org/wiki/lib/exe/fetch.php?media=documents:sdd:lofar-astron-sdd-047_tbb_design_description.pdf
  *
- * In TBB, each frame is 2040 bytes long, consisting of an 88 bytes header, and a 1952 bytes payload (both with their own checksum).
- * There are two types of data that can be transferred: transient data or spectral data.
- * However, incoming frame payloads are somewhat different from frame payloads stored at the TBB: data is transferred unpacked, directly followed by a crc32.
- * Everything is in little-endian byte order.
+ * There are two types of data that can be transferred: transient data and spectral (subband) data. Everything is in little-endian byte order.
  */
 struct TBB_Header {
 	uint8_t stationID;	// Data source station identifier
@@ -84,7 +81,6 @@ struct TBB_Header {
 
 		// In spectral mode indicates frequency band and slice (transform block of 1024 samples) of first payload sample.
 		uint32_t bandSliceNr; // bandNr[9:0] and sliceNr[31:10].
-		// Avoid bit fields, (portable) compilation support is messy. Instead use mask and shift to extract.
 #define TBB_BAND_NR_MASK	((1 << 10) - 1) 
 #define TBB_SLICE_NR_SHIFT	10
 	};
@@ -96,9 +92,6 @@ struct TBB_Header {
 
 	uint16_t spare;		// For future use. Set to 0.
 	uint16_t crc16;		// CRC16 over frame header, with seqNr set to 0.
-
-
-	std::string toString() const;
 };
 
 struct TBB_Payload {
@@ -114,21 +107,20 @@ struct TBB_Payload {
 #define MAX_TBB_SPECTRAL_NSAMPLES	(MAX_TBB_DATA_SIZE / (2 * sizeof(int16_t)))	// 487
 
 	// Unpacked, sign-extended (for transient) samples without padding, i.e. as received.
-	// Frames might not be full; the crc32 is always sent right after (no padding unlike as stored by TBB),
-	// so we include it in 'data', but note that the crc32 is a little endian uint32_t, hence ' + 2'.
+	// Frames might not be full; the doc says the crc32 is always sent right after (no padding), (but this is false for spectral),
+	// so we include the crc32 in 'data', but note that the crc32 is a little endian uint32_t, hence ' + 2'.
 #ifndef MAX
 #define MAX(a, b)	((a) > (b) ? (a) : (b))
 #endif
-	int16_t data[MAX(MAX_TBB_TRANSIENT_NSAMPLES, 2 * MAX_TBB_SPECTRAL_NSAMPLES) + 2];				
+	int16_t data[MAX(MAX_TBB_TRANSIENT_NSAMPLES, 2 * MAX_TBB_SPECTRAL_NSAMPLES) + 2];
 
 	// For transient, TBB always sends sends 1024 samples per frame (from the spec and from the data).
 	// For spectral, it depends on the nr of subbands (max is equal to MAX_TBB_SPECTRAL_NSAMPLES).
-	// TBB sends as many samples for all subbands as it can fit; e.g. with 5 subbands, each frame has 485 samples. TODO: correct?
+	// TBB sends as many samples for all subbands as it can fit; e.g. with 5 subbands, each frame has 485 samples.
 
-#define SPECTRAL_TRANSFORM_SIZE		1024						// RSP FFT block size
+#define SPECTRAL_TRANSFORM_SIZE		1024	// RSP FFT block size
 
-#define DEFAULT_TBB_TRANSIENT_NSAMPLES	1024
-#define DEFAULT_TBB_SPECTRAL_NSAMPLES	487
+#define DEFAULT_TBB_TRANSIENT_NSAMPLES	1024	// for spectral it depends on #subbands
 };
 
 struct TBB_Frame {
@@ -160,9 +152,9 @@ struct SubbandInfo {
 
 
 class TBB_Dipole {
-	dal::TBB_DipoleDataset* itsDataset;
-	LOFAR::FileStream*	itsRawOut;
-	std::vector<dal::Range> itsFlagOffsets;
+	LOFAR::FileStream*       itsRawOut;
+	dal::TBB_Dataset<short>* itsDataset;
+	std::vector<dal::Range>  itsFlagOffsets;
 
 	uint32_t itsSampleFreq; // Hz
 	unsigned itsNrSubbands; // spectral mode only, 0 in transient mode
@@ -176,7 +168,7 @@ class TBB_Dipole {
 
 	// Same truncated polynomial as standard crc32, but with initial_remainder=0, final_xor_value=0, reflected_input=false, reflected_remainder_output=false.
 	// The boost::crc_optimal<> declarations precompute lookup tables, so do not declare inside the checking routine. (Still, for every TBB_Dipole...)
-	boost::crc_optimal<32, 0x04C11DB7/*, 0, 0, false, false*/> itsCrc32gen; // instead of boost::crc_32_type
+	boost::crc_optimal<32, 0x04C11DB7/*, 0, 0, false, false*/> itsCrc32gen;
 
 	// do not use
 	TBB_Dipole& operator=(const TBB_Dipole& rhs);
@@ -189,7 +181,7 @@ public:
 	// Output threads
 	bool isInitialized() const;
 
-	// All TBB_Dipole objects are default constructed in a vector, so provide an init procedure.
+	// All TBB_Dipole objects are default constructed in a vector, so have init().
 	void init(const TBB_Header& header, const Parset& parset, const StationMetaData& stationMetaData,
               const SubbandInfo& subbandInfo, const std::string& rawFilename, dal::TBB_Station& station,
               Mutex& h5Mutex);
@@ -198,7 +190,7 @@ public:
 	void processSpectralFrameData(const TBB_Frame& frame, const SubbandInfo& subbandInfo);
 
 private:
-	void addFlags(size_t offset, size_t len);
+	void appendFlags(size_t offset, size_t len);
 	// initTBB_DipoleDataset() must be called with the global h5Mutex held.
 	void initTBB_DipoleDataset(const TBB_Header& header, const Parset& parset,
                                const StationMetaData& stationMetaData, const SubbandInfo& subbandInfo,
@@ -214,7 +206,7 @@ class TBB_Station {
 	std::vector<TBB_Dipole> itsDipoles;
 	const Parset& itsParset;
 	const StationMetaData& itsStationMetaData;
-	const SubbandInfo itsSubbandInfo; // relevant for spectral mode
+	const SubbandInfo itsSubbandInfo; // for spectral mode
 	const std::string itsH5Filename;
 
 	double getSubbandCentralFreq(unsigned subbandNr, unsigned nyquistZone, double sampleFreq) const;
@@ -268,23 +260,23 @@ class TBB_StreamWriter {
 	TBB_Frame* itsFrameBuffers;
 
 	// Queue pointers point into itsFrameBuffers.
-	Queue<TBB_Frame*> itsReceiveQueue; // input  thread -> output thread
-	Queue<TBB_Frame*> itsFreeQueue;    // output thread -> input  thread
+	Queue<TBB_Frame*> itsReceiveQueue; // input  -> output thread
+	Queue<TBB_Frame*> itsFreeQueue;    // output -> input  thread
 
 	TBB_Writer& itsWriter;
 	const std::string& itsInputStreamName;
-	const size_t itsExpFrameSize;
+	const unsigned itsExpFrameSize;
 	const std::string& itsLogPrefix;
 	int& itsInExitStatus;
 	int& itsOutExitStatus;
 
 	// See TBB_Writer_main.cc::doTBB_Run() why this is used racily for now.
-	// Inflate struct timeval to 64 bytes (typical LEVEL1_DCACHE_LINESIZE).
+	// Inflate struct timeval to 64 bytes (typical LEVEL1_DCACHE_LINESIZE). Unnecessary...
 	struct timeval itsTimeoutStamp __attribute__((aligned(64)));
 
-	boost::crc_optimal<16, 0x8005/*, 0, 0, false, false*/> itsCrc16gen; // instead of boost::crc_16_type
+	boost::crc_optimal<16, 0x8005/*, 0, 0, false, false*/> itsCrc16gen;
 
-#ifdef DUMP_RAW_STATION_DATA
+#ifdef DUMP_RAW_STATION_FRAMES
 	LOFAR::FileStream* itsRawStationData;
 #endif
 
@@ -319,7 +311,8 @@ private:
 };
 
 class TBB_Writer {
-	// Usually, we handle only 1 station, but we can handle multiple at a time.
+	// Usually, we handle only 1 station, but users have request to support multiple concurrently.
+	// The LOFAR system could better use different input streams (udp ports), but we/they are busy.
 	// map from stationID to a TBB_Station*
 	std::map<unsigned, TBB_Station*> itsStations;
 	Mutex itsStationsMutex;
@@ -330,7 +323,7 @@ class TBB_Writer {
 
 	const Parset& itsParset;
 	const StationMetaDataMap& itsStationMetaDataMap;
-	StationMetaData itsUnknownStationMetaData; // referred to for data from unknown stations
+	StationMetaData itsUnknownStationMetaData; // referred to for data from unknown stations (fallback)
 	const std::string& itsOutDir;
 
 	unsigned itsRunNr;
diff --git a/RTCP/Storage/src/CMakeLists.txt b/RTCP/Storage/src/CMakeLists.txt
index 3d4712b84de51c2da4db3359a6237159169d1c69..b8ba519997c986e61b83b0fd40d46aca83652465 100644
--- a/RTCP/Storage/src/CMakeLists.txt
+++ b/RTCP/Storage/src/CMakeLists.txt
@@ -17,7 +17,8 @@ lofar_add_library(storage
   Format.cc
   MeasurementSetFormat.cc
   TBB_StaticMapping.cc
-  TBB_Writer.cc)
+#  TBB_Writer.cc
+)
 
 install(PROGRAMS
   gnuplotMS.sh
@@ -31,5 +32,5 @@ lofar_add_bin_program(Storage_main Storage_main.cc)
 lofar_add_bin_program(createHeaders createHeaders.cc)
 lofar_add_bin_program(plotMS plotMS.cc)
 lofar_add_bin_program(versionstorage versionstorage.cc)
-lofar_add_bin_program(TBB_Writer_main TBB_Writer_main.cc)
+#lofar_add_bin_program(TBB_Writer_main TBB_Writer_main.cc)
 
diff --git a/RTCP/Storage/src/TBB_Writer.cc b/RTCP/Storage/src/TBB_Writer.cc
index 1c3af79eb332dd61b460c78a8bc262748e4cb8be..82d8be38ec88d302670fdf2b7653cda4a78f187c 100644
--- a/RTCP/Storage/src/TBB_Writer.cc
+++ b/RTCP/Storage/src/TBB_Writer.cc
@@ -25,6 +25,7 @@
 
 #define _FILE_OFFSET_BITS 64
 #include <cstddef>
+#include <cstring>
 #include <csignal>
 #include <ctime>
 #include <cerrno>
@@ -61,7 +62,7 @@
 #define TBB_TRANSIENT_MODE			1
 #define TBB_SPECTRAL_MODE			2
 
-#define RSP_NR_SUBBANDS				512		// nr of subbands produced by the RSP polyphase filter
+#define RSP_NR_SUBBANDS				512
 
 namespace LOFAR {
 namespace RTCP {
@@ -70,10 +71,7 @@ using namespace std;
 
 EXCEPTION_CLASS(TBB_MalformedFrameException, StorageException);
 
-/*
- * The output_format is without seconds. The output_size is including the terminating NUL char.
- * Helper for in filenames and for the FILEDATE attribute.
- */
+// The output_format is without seconds. The output_size is including the terminating NUL char.
 static string formatFilenameTimestamp(const struct timeval& tv, const char* output_format,
                                       const char* output_format_secs, size_t output_size) {
 	struct tm tm;
@@ -91,7 +89,7 @@ static string formatFilenameTimestamp(const struct timeval& tv, const char* outp
 	return string(&date[0]);
 }
 
-// FileStream doesn't do pwrite(2). Roll our own as nobody else needs it, but in the FileStream way, just in case.
+// FileStream doesn't do pwrite(2).
 static size_t tryPWrite(int fd, const void *ptr, size_t size, off_t offset) {
 	ssize_t bytes = ::pwrite(fd, ptr, size, offset);
 	if (bytes < 0)
@@ -108,48 +106,43 @@ static void pwrite(int fd, const void *ptr, size_t size, off_t offset) {
 	}
 }
 
-string TBB_Header::toString() const {
-	ostringstream oss;
-	oss << (unsigned)stationID << " " << (unsigned)rspID << " " << (unsigned)rcuID << " " << (unsigned)sampleFreq <<
-           " " << seqNr << " " << time << " " << (nOfFreqBands == 0 ? sampleNr : bandSliceNr) << " " << nOfSamplesPerFrame <<
-           " " << nOfFreqBands << " " << spare << " " << crc16; // casts uin8_t to unsigned to avoid printing as char
-	return oss.str();
+static ostream& operator<<(ostream& out, const TBB_Header& h) {
+	out << (unsigned)h.stationID << " " << (unsigned)h.rspID << " " << (unsigned)h.rcuID << " " << (unsigned)h.sampleFreq <<
+           " " << h.seqNr << " " << h.time << " " << (h.nOfFreqBands == 0 ? h.sampleNr : h.bandSliceNr) << " " << h.nOfSamplesPerFrame <<
+           " " << h.nOfFreqBands << " " << h.spare << " " << h.crc16; // casts uin8_t to unsigned to avoid printing as char
+	return out;
 }
 
 //////////////////////////////////////////////////////////////////////////////
 
 TBB_Dipole::TBB_Dipole()
-: itsDataset(NULL) // needed, setting the others is superfluous
-, itsRawOut(NULL)
+: itsRawOut(NULL) // needed, setting the others is superfluous
+, itsDataset(NULL)
 , itsFlagOffsets()
 , itsSampleFreq(0)
 , itsNrSubbands(0)
 , itsTime(0)
-, itsExpSampleNr(0) // also inits itsExpSliceNr
+, itsExpSampleNr(0)
 , itsDatasetLen(0)
 {
 }
 
 // Do not use. Only needed for vector<TBB_Dipole>(N).
 TBB_Dipole::TBB_Dipole(const TBB_Dipole& rhs)
-: itsDataset(rhs.itsDataset) // needed, setting the others is superfluous
-, itsRawOut(NULL) // Safe destr. FileStream has no copy constr, so disabled; also see comments in init()
+: itsRawOut(NULL) // idem. FileStream has no copy constr, but only copied before really set, so NULL is fine.
+, itsDataset(rhs.itsDataset)
 , itsFlagOffsets(rhs.itsFlagOffsets)
 , itsSampleFreq(rhs.itsSampleFreq)
 , itsNrSubbands(rhs.itsNrSubbands)
 , itsTime(rhs.itsTime)
-, itsExpSampleNr(rhs.itsExpSampleNr) // also inits itsExpSliceNr
+, itsExpSampleNr(rhs.itsExpSampleNr)
 , itsDatasetLen(rhs.itsDatasetLen)
 {
 }
 
 TBB_Dipole::~TBB_Dipole() {
-	/*
-	 * Set dataset len (if ext raw) and SPECTRAL_*, DATA_LENGTH and FLAG_OFFSETS attributes at the end.
-	 * Executed by the main thread after joined with all workers, so no need to lock or delay cancellation.
-	 * Skip on uninitialized (default constructed) objects.
-	 */
-	if (itsDataset != NULL) {
+	// Executed by the main thread after joined with all workers, so no need to lock or delay cancellation.
+	if (isInitialized()) {
 		try {
 			if (itsNrSubbands == 0) { // transient mode
 				itsDataset->resize1D(itsDatasetLen);
@@ -169,15 +162,14 @@ TBB_Dipole::~TBB_Dipole() {
 			LOG_WARN_STR("TBB: failed to set dipole DATA_LENGTH attribute: " << exc.what());
 		}
 		try {
-			itsDataset->flagOffsets().value = itsFlagOffsets;
+			itsDataset->flagOffsets().create(itsFlagOffsets.size()).set(itsFlagOffsets);
 		} catch (dal::DALException& exc) {
 			LOG_WARN_STR("TBB: failed to set dipole FLAG_OFFSETS attribute: " << exc.what());
 		}
 
 		delete itsDataset;
+		delete itsRawOut;
 	}
-
-	delete itsRawOut;
 }
 
 void TBB_Dipole::init(const TBB_Header& header, const Parset& parset,
@@ -185,7 +177,10 @@ void TBB_Dipole::init(const TBB_Header& header, const Parset& parset,
                             const SubbandInfo& subbandInfo, const string& rawFilename,
                             dal::TBB_Station& station, Mutex& h5Mutex) {
 	itsSampleFreq = static_cast<uint32_t>(header.sampleFreq) * 1000000;
-	itsNrSubbands = subbandInfo.centralFreqs.size();
+	itsNrSubbands = header.nOfFreqBands;
+	if (itsNrSubbands > subbandInfo.centralFreqs.size()) {
+		throw StorageException("TBB: dropping frame with invalid nOfFreqBands");
+	}
 
 	itsRawOut = new FileStream(rawFilename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
 
@@ -197,7 +192,7 @@ void TBB_Dipole::init(const TBB_Header& header, const Parset& parset,
 			/*
 			 * This nonsense is needed, because FileStream has no FileStream() and open() (and swap()),
 			 * and since we know the filename only at runtime (timestamp), we need itsRawOut to be a raw ptr.
-			 * We already have a raw ptr for itsDataset and >1 raw ptr in 1 C++ class becomes buggy or messy.
+			 * We already have a raw ptr for the dataset and >1 raw ptr in 1 C++ class becomes buggy or messy.
 			 */
 			delete itsRawOut;
 			itsRawOut = NULL;
@@ -211,18 +206,18 @@ void TBB_Dipole::init(const TBB_Header& header, const Parset& parset,
 	} else { // spectral mode
 		itsExpSliceNr  = header.bandSliceNr >> TBB_SLICE_NR_SHIFT;
 	}
-	itsDatasetLen = 0; // already 0, so just for completeness
+	itsDatasetLen = 0; // already 0, for completeness
 }
 
 bool TBB_Dipole::isInitialized() const {
-	return itsDataset != NULL; // constructed after itsRawOut so test itsDataset
+	return itsRawOut != NULL;
 }
 
-// Add a new flag range or extend the last stored flag range. 'len' may not be 0.
-void TBB_Dipole::addFlags(size_t offset, size_t len) {
+// Add a new flag range at the end or extend the last stored flag range. 'len' may not be 0.
+void TBB_Dipole::appendFlags(size_t offset, size_t len) {
 	if (itsFlagOffsets.empty() || offset > itsFlagOffsets.back().end) {
 		itsFlagOffsets.push_back(dal::Range(offset, offset + len));
-	} else { // extend flag range
+	} else { // extend
 		itsFlagOffsets.back().end += len;
 	}
 }
@@ -230,10 +225,10 @@ void TBB_Dipole::addFlags(size_t offset, size_t len) {
 void TBB_Dipole::processTransientFrameData(const TBB_Frame& frame) {
 	/*
 	 * Out-of-order or duplicate frames are very unlikely in the LOFAR TBB setup,
-	 * but let us know if it ever happens, then we will adapt this code and addFlags().
+	 * but let us know if it ever happens, then we will adapt this code and appendFlags().
 	 */
 	if (frame.header.time < itsTime || (frame.header.time == itsTime && frame.header.sampleNr < itsExpSampleNr)) {
-		LOG_WARN_STR("TBB: Please notify developer: unhandled out-of-order or duplicate TBB frame: " <<
+		LOG_WARN_STR("TBB: Unhandled out-of-order or duplicate frame: " <<
                      (unsigned)frame.header.stationID << " " << (unsigned)frame.header.rspID << " " << (unsigned)frame.header.rcuID <<
                      " " << frame.header.time << " " << itsTime << " " << frame.header.sampleNr << " " << itsExpSampleNr);
 		return;
@@ -256,11 +251,11 @@ void TBB_Dipole::processTransientFrameData(const TBB_Frame& frame) {
 
 	/*
 	 * Flag lost frame(s) (assume no out-of-order, see below). Assumes all frames have the same nr of samples.
-	 * Note: this cannot detect lost frames at the end of a dataset.
+	 * This cannot detect lost frames at the end of a dataset.
 	 */
 	size_t nskipped = offset - itsDatasetLen;
 	if (nskipped > 0) {
-		addFlags(itsDatasetLen, nskipped);
+		appendFlags(itsDatasetLen, nskipped);
 		itsRawOut->skip(nskipped * sizeof(frame.payload.data[0])); // skip space of lost frame(s)
 	}
 
@@ -269,11 +264,12 @@ void TBB_Dipole::processTransientFrameData(const TBB_Frame& frame) {
 	 * Flag zeroed payloads too, as incredibly unlikely to be correct, but not rejected by crc32tbb.
 	 */
 	if (!crc32tbb(&frame.payload, frame.header.nOfSamplesPerFrame)) {
-		addFlags(offset, frame.header.nOfSamplesPerFrame);
-		const uint32_t* crc32 = reinterpret_cast<const uint32_t*>(&frame.payload.data[frame.header.nOfSamplesPerFrame]);
-		LOG_INFO_STR("TBB: crc32: " << frame.header.toString() << " " << *crc32);
+		appendFlags(offset, frame.header.nOfSamplesPerFrame);
+		uint32_t crc32;
+		memcpy(&crc32, &frame.payload.data[frame.header.nOfSamplesPerFrame], sizeof crc32); // strict-aliasing safe
+		LOG_WARN_STR("TBB: crc32: " << frame.header << " " << crc32);
 	} else if (hasAllZeroDataSamples(frame.payload, frame.header.nOfSamplesPerFrame)) {
-		addFlags(offset, frame.header.nOfSamplesPerFrame);
+		appendFlags(offset, frame.header.nOfSamplesPerFrame);
 	}
 
 	// Since we are writing around HDF5, there is no need to lock. Resize the HDF5 dataset at the end (destr).
@@ -287,11 +283,11 @@ void TBB_Dipole::processTransientFrameData(const TBB_Frame& frame) {
 void TBB_Dipole::processSpectralFrameData(const TBB_Frame& frame, const SubbandInfo& subbandInfo) {
 	/*
 	 * Out-of-order or duplicate frames are very unlikely in the LOFAR TBB setup,
-	 * but let us know if it ever happens, then we will adapt this code and addFlags().
+	 * but let us know if it ever happens, then we will adapt this code and appendFlags().
 	 */
 	uint32_t sliceNr = frame.header.bandSliceNr >> TBB_SLICE_NR_SHIFT; // cannot sanitize fully: too large values indicate lost data: flag
 	if (frame.header.time < itsTime || (frame.header.time == itsTime && sliceNr < itsExpSliceNr)) {
-		LOG_WARN_STR("TBB: Please notify developer: unhandled out-of-order or duplicate TBB frame: " <<
+		LOG_WARN_STR("TBB: Unhandled out-of-order or duplicate frame: " <<
                      (unsigned)frame.header.stationID << " " << (unsigned)frame.header.rspID << " " << (unsigned)frame.header.rcuID <<
                      " " << frame.header.time << " " << itsTime << " " << frame.header.bandSliceNr << " " << itsExpSliceNr);
 		return;
@@ -310,45 +306,51 @@ void TBB_Dipole::processSpectralFrameData(const TBB_Frame& frame, const SubbandI
 	}
 
 	/*
-	 * Flag lost frame(s) (assume no out-of-order, see below). Assumes all frames have the same nr of samples.
-	 * Note: this cannot detect lost frames at the end of a dataset.
+	 * Flag lost frame(s) (assume no out-of-order, see below). Assumes all frames have the same nr of samples (fine).
+	 * This cannot detect lost frames at the end of a dataset.
 	 */
-	unsigned nSamplesPerSubband = frame.header.nOfSamplesPerFrame / itsNrSubbands; // TODO: remainder is zeroed??? chksum pos???
 	size_t nskipped = offset - itsDatasetLen;
 	if (nskipped > 0) {
-////		addFlags(itsDatasetLen, nskipped); // no need to skip/lseek; we use pwrite() below
+		appendFlags(itsDatasetLen, nskipped); // no need to skip/lseek; we use pwrite() below
 	}
 
 	/*
 	 * On a data checksum error, flag these samples.
 	 * Flag zeroed payloads too, as incredibly unlikely to be correct, but not rejected by crc32tbb.
 	 *
-	 * The spec says the crc32 is computed for transient data only, but it is also present and valid for spectral data.
+	 * TBB Design Doc states the crc32 is computed for transient data only, but it is also valid for spectral data.
+	 * Except that it looks invalid for the first spectral frame each second, so skip checking those. // TODO: enable 'sliceNr != 0 && ' below after verifying with recent real data
 	 */
-	if (!crc32tbb(&frame.payload, 2 * frame.header.nOfSamplesPerFrame)) {
-////		addFlags(offset, frame.header.nOfSamplesPerFrame);
-		const uint32_t* crc32 = reinterpret_cast<const uint32_t*>(&frame.payload.data[2 * frame.header.nOfSamplesPerFrame]);
-		LOG_INFO_STR("TBB: crc32: " << frame.header.toString() << " " << *crc32);
+	unsigned nSamplesPerSubband = frame.header.nOfSamplesPerFrame / itsNrSubbands; // any remainder is zeroed until the crc32
+	if (/*sliceNr != 0 && */!crc32tbb(&frame.payload, 2 * MAX_TBB_SPECTRAL_NSAMPLES)) {
+		appendFlags(offset, nSamplesPerSubband);
+		uint32_t crc32;
+		memcpy(&crc32, &frame.payload.data[2 * MAX_TBB_SPECTRAL_NSAMPLES], sizeof crc32); // strict-aliasing safe
+		LOG_WARN_STR("TBB: crc32: " << frame.header << " " << crc32);
 	} else if (hasAllZeroDataSamples(frame.payload, 2 * frame.header.nOfSamplesPerFrame)) {
-////		addFlags(offset, frame.header.nOfSamplesPerFrame);
+		appendFlags(offset, nSamplesPerSubband);
 	}
 
-	unsigned bandNr = frame.header.bandSliceNr & TBB_BAND_NR_MASK;
+	/*
+	 * In practice, each frame contains the same number of samples for all subbands, so the received band number is always 0.
+	 * Hence, disable support for cross-frame slices, such that in spectral mode we can also store flags in 1D.
+	 */
+	/*unsigned bandNr = frame.header.bandSliceNr & TBB_BAND_NR_MASK;
 	if (bandNr + itsNrSubbands >= RSP_NR_SUBBANDS) {
 		LOG_WARN("TBB: Incorrect band number has been corrected to 0");
-		bandNr = 0; // may also be wrong, but at least mem safe
-	}
+		bandNr = 0; // safe default
+	}*/
 	// Data arrives interleaved, so reorder, one sample at a time. Esp. inefficient if only 1 subband, but fast enough.
 	for (unsigned i = 0; i < nSamplesPerSubband; ++i) {
 		for (unsigned j = 0; j < itsNrSubbands; ++j) {
-			off_t sampleOffset = (offset + subbandInfo.storageIndices[bandNr + j] * SPECTRAL_TRANSFORM_SIZE) * 2 * sizeof(frame.payload.data[0]);
+			off_t sampleOffset = (offset + subbandInfo.storageIndices[j/*(bandNr + j) % itsNrSubbands*/] * SPECTRAL_TRANSFORM_SIZE) * 2 * sizeof(frame.payload.data[0]);
 			pwrite(itsRawOut->fd, &frame.payload.data[2 * (i * itsNrSubbands + j)], 2 * sizeof(frame.payload.data[0]), sampleOffset);
 		}
 		offset += 1;
 	}
 
 	itsTime       = frame.header.time;
-	itsExpSliceNr = sliceNr + frame.header.nOfSamplesPerFrame;
+	itsExpSliceNr = sliceNr + nSamplesPerSubband;
 	itsDatasetLen = offset;
 }
 
@@ -356,28 +358,29 @@ void TBB_Dipole::initTBB_DipoleDataset(const TBB_Header& header, const Parset& p
                                        const StationMetaData& stationMetaData,
                                        const SubbandInfo& subbandInfo,
                                        const string& rawFilename, dal::TBB_Station& station) {
-	itsDataset = new dal::TBB_DipoleDataset(station.dipole(header.stationID, header.rspID, header.rcuID)); // deleted in destr
-
-	// Create 1- or 2-dim, unbounded (-1) dataset. 
 	// Override endianess. TBB data is always stored little endian and also received as such, so written as-is on any platform.
 	if (subbandInfo.centralFreqs.empty()) { // transient mode
+		dal::TBB_DipoleDataset* dpDataset = new dal::TBB_DipoleDataset(station.dipole(header.stationID, header.rspID, header.rcuID));
+		itsDataset = static_cast<dal::TBB_Dataset<short>*>(dpDataset);
+
 		itsDataset->create1D(0, -1, LOFAR::basename(rawFilename), itsDataset->LITTLE);
 
-		itsDataset->sampleNumber().value = header.sampleNr;
+		dpDataset->sampleNumber().value = header.sampleNr;
 	} else { // spectral mode
+		dal::TBB_SubbandsDataset* sbDataset = new dal::TBB_SubbandsDataset(station.subbands(header.stationID, header.rspID, header.rcuID));
+		itsDataset = reinterpret_cast<dal::TBB_Dataset<short>*>(sbDataset); // not so nice
+
 		vector<ssize_t> dims(2), maxdims(2);
 		dims[0]    = 0;
-		dims[1]    = subbandInfo.centralFreqs.size();
+		dims[1]    = itsNrSubbands;
 		maxdims[0] = -1; // only the 1st dim can be extendible
-		maxdims[1] = subbandInfo.centralFreqs.size();
+		maxdims[1] = itsNrSubbands;
 		itsDataset->create(dims, maxdims, LOFAR::basename(rawFilename), itsDataset->LITTLE);
 
-// TODO: enable and add to DAL
-//		itsDataset->sliceNumber().value       = header.bandSliceNr >> TBB_SLICE_NR_SHIFT; // TODO: needed?
-
-//		itsDataset->spectralNofBands().value  = subbandInfo.centralFreqs.size();
-//		itsDataset->spectralBands().value     = subbandInfo.centralFreqs;
-//		itsDataset->spectralBandsUnit().value = "MHz";
+		sbDataset->sliceNumber()      .value = header.bandSliceNr >> TBB_SLICE_NR_SHIFT;
+		sbDataset->spectralNofBands() .value = itsNrSubbands;
+		sbDataset->spectralBands().create(itsNrSubbands).set(subbandInfo.centralFreqs);
+		sbDataset->spectralBandsUnit().value = "MHz";
 	}
 
 	itsDataset->groupType().value = "DipoleDataset";
@@ -392,7 +395,7 @@ void TBB_Dipole::initTBB_DipoleDataset(const TBB_Header& header, const Parset& p
 
 	itsDataset->samplesPerFrame().value     = header.nOfSamplesPerFrame; // possibly sanitized
 	//itsDataset->dataLength().value is set at the end (destr)
-	//itsDataset->flagOffsets().value is set at the end (destr) // TODO: remove
+	//itsDataset->flagOffsets().value is set at the end (destr) // TODO: attrib -> 1D dataset
 	itsDataset->nyquistZone().value         = parset.nyquistZone();
 
 //#include "MAC/APL/PIC/RSP_Driver/src/CableSettings.h" or "RCUCables.h"
@@ -420,14 +423,15 @@ elke .dat file bevat 96*512*2 doubles
 voor 96 rcus, 512 frequenties, een complexe waarde
 maar nu vraag ik me wel weer af of de frequenties of de rcus eerst komen
 */
+//NL stations: 768 kB, Int'l: 1.5 MB. Drop optional ASCI header. See also Station/StationCal/writeCalTable.m
 	//itsDataset->dipoleCalibrationDelay().value = ???; // Pim can compute this from the GainCurve below
 	//itsDataset->dipoleCalibrationDelayUnit().value = 's';
-	//itsDataset->dipoleCalibrationGainCurve().value = ???;
-
+	//itsDataset->dipoleCalibrationGainCurve().create(???.size()).set(???); // st cal table
+//write cal tables into proper n-dimensional h5 data set, not attribute! Add access functions to DAL?
 
 	// Skip if station is not participating in the observation (should not happen).
 	if (stationMetaData.available && 2u * 3u * header.rcuID + 2u < stationMetaData.antPositions.size()) {
-		/*
+		/*TODO
 		 * Selecting the right positions depends on the antenna set. Checking vs the tables in
 		 * lhn001:/home/veen/lus/src/code/data/lofar/antennapositions/ can help, but their repos may be outdated.
 		 */
@@ -435,7 +439,7 @@ maar nu vraag ik me wel weer af of de frequenties of de rcus eerst komen
 		antPos[0] = stationMetaData.antPositions[2u * 3u * header.rcuID];
 		antPos[1] = stationMetaData.antPositions[2u * 3u * header.rcuID + 1u];
 		antPos[2] = stationMetaData.antPositions[2u * 3u * header.rcuID + 2u];
-		itsDataset->antennaPosition()     .value = antPos; // absolute position
+		itsDataset->antennaPosition().create(antPos.size()).set(antPos); // absolute position
 
 		itsDataset->antennaPositionUnit() .value = "m";
 		itsDataset->antennaPositionFrame().value = parset.positionType(); // "ITRF"
@@ -445,17 +449,18 @@ maar nu vraag ik me wel weer af of de frequenties of de rcus eerst komen
 		 * but given the HBA0/HBA1 "ears" depending on antenna set, it was
 		 * decided to store them per antenna.
 		 */
-		itsDataset->antennaNormalVector()  .value = stationMetaData.normalVector;   // 3 doubles
-		itsDataset->antennaRotationMatrix().value = stationMetaData.rotationMatrix; // 9 doubles, 3x3, row-major
+		itsDataset->antennaNormalVector()  .create(stationMetaData.normalVector.size()).set(stationMetaData.normalVector);     // 3 doubles
+		itsDataset->antennaRotationMatrix().create(stationMetaData.rotationMatrix.size()).set(stationMetaData.rotationMatrix); // 9 doubles, 3x3, row-major
 	}
 
 	// Tile beam is the analog beam. Only HBA can have one analog beam; optional.
 	if (parset.haveAnaBeam()) {
-		itsDataset->tileBeam()     .value = parset.getAnaBeamDirection(); // always for beam 0
+		vector<double> anaBeamDir(parset.getAnaBeamDirection());
+		itsDataset->tileBeam()     .create(anaBeamDir.size()).set(anaBeamDir); // always for beam 0
 		itsDataset->tileBeamUnit() .value = "m";
 		itsDataset->tileBeamFrame().value = parset.getAnaBeamDirectionType(); // idem
 
-		//itsDataset->tileBeamDipoles().value = ???;
+		//itsDataset->tileBeamDipoles().create(???.size()).set(???);
 
 		//itsDataset->tileCoefUnit().value = ???;
 		//itsDataset->tileBeamCoefs().value = ???;
@@ -466,7 +471,7 @@ maar nu vraag ik me wel weer af of de frequenties of de rcus eerst komen
 		//itsDataset->tileDipolePositionFrame().value = ???;
 	}
 
-	itsDataset->dispersionMeasure()    .value = parset.dispersionMeasure(0, 0); // 0.0 if no dedispersion was done
+	itsDataset->dispersionMeasure()    .value = parset.dispersionMeasure(0, 0); // beam, pencil TODO: adapt too if >1 beam?
 	itsDataset->dispersionMeasureUnit().value = "pc/cm^3";
 }
 
@@ -502,10 +507,15 @@ TBB_Station::TBB_Station(const string& stationName, Mutex& h5Mutex, const Parset
 }
 
 TBB_Station::~TBB_Station() {
-	// Executed by the main thread after joined with all workers, so no need to lock or delay cancellation.
+	/*
+	 * Apart from the main thread, also potentially (rarely) executed by an output thread on failed
+	 * to insert new TBB_Station object into an std::map. For the output thread case, do dc and slH5.
+	 */
+	ScopedDelayCancellation dc;
 	try {
+		ScopedLock slH5(itsH5Mutex);
 		itsStation.nofDipoles().value = itsStation.dipoles().size();
-	} catch (dal::DALException& exc) {
+	} catch (exception& exc) { // dal::DALException or worse
 		LOG_WARN_STR("TBB: failed to set station NOF_DIPOLES attribute: " << exc.what());
 	}
 }
@@ -519,9 +529,9 @@ SubbandInfo TBB_Station::getSubbandInfo(const Parset& parset) const {
 
 	int operatingMode = itsParset.getInt("Observation.TBB.TBBsetting.operatingMode", 0);
 	if (operatingMode == TBB_SPECTRAL_MODE) {
-		vector<unsigned> tbbSubbandList(parset.getUint32Vector("Observation.TBB.TBBsetting.subbandList", true)); // TODO: what happens if key does not exists? exc? also test empty parset
+		vector<unsigned> tbbSubbandList(parset.getUint32Vector("Observation.TBB.TBBsetting.subbandList", true));
 		if (tbbSubbandList.empty() || tbbSubbandList.size() > MAX_TBB_SPECTRAL_NSAMPLES) {
-			throw InterfaceException("TBB: in spectral mode, the TBB subband list must be non-empty and not too long");
+			throw InterfaceException("TBB: spectral mode selected, but empty or too long subband list provided");
 		}
 		sort(tbbSubbandList.begin(), tbbSubbandList.end());
 
@@ -537,7 +547,7 @@ SubbandInfo TBB_Station::getSubbandInfo(const Parset& parset) const {
 		for (unsigned i = 0; i < tbbSubbandList.size(); ++i) {
 			unsigned sbNr = tbbSubbandList[i];
 			if (sbNr >= RSP_NR_SUBBANDS) {
-				throw InterfaceException("TBB: all indicated subband numbers must be < 512");
+				throw InterfaceException("TBB: indicated subband number too high");
 			}
 			info.storageIndices[sbNr] = i;
 		}
@@ -575,7 +585,6 @@ void TBB_Station::processPayload(const TBB_Frame& frame) {
 	}
 }
 
-// For timestamp attributes in UTC.
 string TBB_Station::utcTimeStr(double time) const {
 	time_t timeSec = static_cast<time_t>(floor(time));
 	unsigned long timeNSec = static_cast<unsigned long>(round( (time-floor(time))*1e9 ));
@@ -627,7 +636,8 @@ void TBB_Station::initCommonLofarAttributes() {
 	itsH5File.observationNofStations().value = itsParset.nrStations(); // TODO: SS beamformer?
 	// For the observation attribs, dump all stations participating in the observation (i.e. allStationNames(), not mergedStationNames()).
 	// This may not correspond to which station HDF5 groups will be written for TBB, but that is true anyway, regardless of any merging.
-	itsH5File.observationStationsList().value = itsParset.allStationNames(); // TODO: SS beamformer?
+	vector<string> allStNames(itsParset.allStationNames());
+	itsH5File.observationStationsList().create(allStNames.size()).set(allStNames); // TODO: SS beamformer?
 
 	double subbandBandwidth = itsParset.subbandBandwidth();
 	double channelBandwidth = itsParset.channelWidth();
@@ -662,7 +672,7 @@ void TBB_Station::initCommonLofarAttributes() {
 		targets[sap] = itsParset.beamTarget(sap);
 	}
 
-	itsH5File.targets().value = targets;
+	itsH5File.targets().create(targets.size()).set(targets);
 
 #ifndef TBB_WRITER_VERSION
 	itsH5File.systemVersion().value = LOFAR::StorageVersion::getVersion();
@@ -681,14 +691,14 @@ void TBB_Station::initTBB_RootAttributesAndGroups(const string& stName) {
 	int operatingMode = itsParset.getInt("Observation.TBB.TBBsetting.operatingMode", 0);
 	if (operatingMode == TBB_SPECTRAL_MODE) {
 		itsH5File.operatingMode().value = "spectral";
-//		itsH5File.spectralTransformSize().value = SPECTRAL_TRANSFORM_SIZE; // TODO: enable and add to DAL
+		itsH5File.spectralTransformSize().value = SPECTRAL_TRANSFORM_SIZE;
 	} else {
 		itsH5File.operatingMode().value = "transient";
 	}
 
 	itsH5File.nofStations().value = 1u;
 
-	// Find the station name we are looking for ("CS001" == "CS001HBA0") and retrieve its pos using the found idx.
+	// Find the station name we are looking for and retrieve its pos using the found idx.
 	vector<double> stPos;
 
 	vector<string> obsStationNames(itsParset.allStationNames());
@@ -723,14 +733,15 @@ void TBB_Station::initStationGroup(dal::TBB_Station& st, const string& stName,
 	st.stationName().value = stName;
 
 	if (!stPosition.empty()) {
-		st.stationPosition()     .value = stPosition;
+		st.stationPosition()     .create(stPosition.size()).set(stPosition);
 		st.stationPositionUnit() .value = "m";
 		st.stationPositionFrame().value = itsParset.positionType();
 	}
 
 	// digital beam(s)
 	if (itsParset.nrBeams() > 0) { // TODO: adapt DAL, so we can write all digital beams, analog too if tiles (HBA)
-		st.beamDirection()     .value = itsParset.getBeamDirection(0);
+		vector<double> beamDir(itsParset.getBeamDirection(0));
+		st.beamDirection()     .create(beamDir.size()).set(beamDir);
 		st.beamDirectionUnit() .value = "m";
 		st.beamDirectionFrame().value = itsParset.getBeamDirectionType(0);
 	}
@@ -741,7 +752,7 @@ void TBB_Station::initStationGroup(dal::TBB_Station& st, const string& stName,
 		st.clockOffset()    .value = clockCorr;
 		st.clockOffsetUnit().value = "s";
 	} catch (APSException& exc) {
-		LOG_WARN_STR("TBB: failed to write clock correction and offset attributes: " << exc);
+		LOG_WARN_STR("TBB: failed to write station clock offset and unit attributes: " << exc);
 	}
 
 	//st.nofDipoles.value is set at the end (destr)
@@ -821,8 +832,10 @@ TBB_StreamWriter::TBB_StreamWriter(TBB_Writer& writer, const string& inputStream
 		throw;
 	}
 
-#ifdef DUMP_RAW_STATION_DATA
-	string rawStDataFilename("station_data_" + formatString("%zu", itsFrameBuffers) + ".raw");
+#ifdef DUMP_RAW_STATION_FRAMES
+	struct timeval ts;
+	::gettimeofday(&ts, NULL);
+	string rawStDataFilename("tbb_raw_station_frames_" + formatString("%ld_%p", ts.tv_sec, (void*)itsFrameBuffers) + ".fraw");
 	try {
 		itsRawStationData = new FileStream(rawStDataFilename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
 	} catch (exception& exc) {
@@ -835,7 +848,7 @@ TBB_StreamWriter::~TBB_StreamWriter() {
 	// Only cancel the input thread, which will notify the output thread.
 	itsInputThread->cancel();
 
-#ifdef DUMP_RAW_STATION_DATA
+#ifdef DUMP_RAW_STATION_FRAMES
 	delete itsRawStationData;
 #endif
 	delete itsInputThread;
@@ -848,9 +861,9 @@ time_t TBB_StreamWriter::getTimeoutStampSec() const {
 }
 
 void TBB_StreamWriter::frameHeaderLittleToHost(TBB_Header& header) const {
-	header.seqNr              = le32toh(header.seqNr); // to be zeroed to check header crc; otherwise not so useful
+	header.seqNr              = le32toh(header.seqNr); // set to 0 for crc16, otherwise unused
 	header.time               = le32toh(header.time);
-	header.sampleNr           = le32toh(header.sampleNr); // also swaps header.bandSliceNr
+	header.sampleNr           = le32toh(header.sampleNr);
 	header.nOfSamplesPerFrame = le16toh(header.nOfSamplesPerFrame);
 	header.nOfFreqBands       = le16toh(header.nOfFreqBands);
 	header.spare              = le16toh(header.spare); // unused
@@ -877,19 +890,17 @@ void TBB_StreamWriter::correctSampleNr(TBB_Header& header) const {
 bool TBB_StreamWriter::crc16tbb(const TBB_Header* header) {
 	itsCrc16gen.reset();
 
-	/*
-	 * The header checksum is done like the data, i.e. on 16 bit little endian blocks at a time.
-	 * As with the data crc, both big and little endian CPUs need to byte swap.
-	 */
-	const int16_t* ptr = reinterpret_cast<const int16_t*>(header); // TODO: access cross-type through char or uchar ptrs (or memcpy), in all reint_cast cases in the code: unsigned char *ptr = (unsigned char*)&floatVar; // and then accessing ptr[0] to ptr[sizeof(floatVar)-1] is legal.
-	for (size_t i = 0; i < (sizeof(*header) - sizeof(header->crc16)) / sizeof(int16_t); i++) {
-		int16_t val = __bswap_16(ptr[i]);
-		itsCrc16gen.process_bytes(&val, sizeof(int16_t));
+	const char* ptr = reinterpret_cast<const char*>(header); // to char* for strict-aliasing
+	for (unsigned i = 0; i < sizeof(*header) - sizeof(header->crc16); i += 2) {
+		int16_t val;
+		memcpy(&val, &ptr[i], sizeof val); // strict-aliasing safe
+		val = __bswap_16(val);
+		itsCrc16gen.process_bytes(&val, sizeof val);
 	}
 
 	// It is also possible to process header->crc16 and see if checksum() equals 0.
 	uint16_t crc16val = header->crc16;
-#if __BYTE_ORDER == __BIG_ENDIAN
+#if __BYTE_ORDER == __BIG_ENDIAN || defined WORDS_BIGENDIAN // for cross-compilation on little endian; fails for big->little
 	crc16val = __bswap_16(crc16val);
 #endif
 	return itsCrc16gen.checksum() == crc16val;
@@ -902,19 +913,18 @@ bool TBB_StreamWriter::crc16tbb(const TBB_Header* header) {
 bool TBB_Dipole::crc32tbb(const TBB_Payload* payload, size_t nTrSamples) {
 	itsCrc32gen.reset();
 
-	/*
-	 * Both little and big endian CPUs need to byte swap, because the data always arrives
-	 * in little and the boost routines treat it as uint8_t[] (big).
-	 */
-	const int16_t* ptr = reinterpret_cast<const int16_t*>(payload->data);
-	for (size_t i = 0; i < nTrSamples; i++) {
-		int16_t val = __bswap_16(ptr[i]);
-		itsCrc32gen.process_bytes(&val, sizeof(int16_t));
+	const char* ptr = reinterpret_cast<const char*>(payload->data); // to char* for strict-aliasing
+	for (unsigned i = 0; i < nTrSamples * sizeof(int16_t); i += 2) {
+		int16_t val;
+		memcpy(&val, &ptr[i], sizeof val); // strict-aliasing safe
+		val = __bswap_16(val);
+		itsCrc32gen.process_bytes(&val, sizeof val);
 	}
 
 	// It is also possible to process crc32val and see if checksum() equals 0.
-	uint32_t crc32val = *reinterpret_cast<const uint32_t*>(&ptr[nTrSamples]);
-#if __BYTE_ORDER == __BIG_ENDIAN
+	uint32_t crc32val;
+	memcpy(&crc32val, &ptr[nTrSamples * sizeof(int16_t)], sizeof crc32val); // idem
+#if __BYTE_ORDER == __BIG_ENDIAN || defined WORDS_BIGENDIAN // for cross-compilation on little endian; fails for big->little
 	crc32val = __bswap_32(crc32val);
 #endif
 	return itsCrc32gen.checksum() == crc32val;
@@ -929,9 +939,9 @@ void TBB_StreamWriter::processHeader(TBB_Header& header, size_t recvPayloadSize)
 	if (!crc16tbb(&header)) {
 		/*
 		 * The TBB spec states that each frame has the same fixed length, so the previous values are a good base guess if the header crc fails.
-		 * But it is not clear if it is worth the effort to try to guess to fix something up. More likely there is a bug, so for now, drop the frame.
+		 * But it is not clear if it is worth the effort to try to guess to fix something up. For now, drop and log.
 		 */
-		throw TBB_MalformedFrameException("crc16: " + header.toString()); // printed header not bswapped on big endian
+		THROW(TBB_MalformedFrameException, "crc16: " << header); // header not yet bswapped on _big_ endian
 	}
 
 	/*
@@ -940,12 +950,12 @@ void TBB_StreamWriter::processHeader(TBB_Header& header, size_t recvPayloadSize)
 	 */
 	if (recvPayloadSize < 2 * sizeof(int16_t) + sizeof(uint32_t)) {
 		// Drop it. The data crc routine only works for at least 2 transient or 1 spectral sample(s) + a crc32.
-		throw TBB_MalformedFrameException("dropping too small frame: " + recvPayloadSize);
+		THROW(TBB_MalformedFrameException, "dropping too small frame: " << recvPayloadSize);
 	}
 	frameHeaderLittleToHost(header);
 	// Verify indicated sample freq, also to reject zeroed headers, which the crc16tbb does not reject.
 	if (header.sampleFreq != 200 && header.sampleFreq != 160) {
-		throw TBB_MalformedFrameException("invalid sample frequency in frame header: " + header.sampleFreq);
+		THROW(TBB_MalformedFrameException, "dropping frame with invalid sample frequency in frame header: " << header.sampleFreq);
 	}
 
 	size_t sampleSize;
@@ -960,7 +970,7 @@ void TBB_StreamWriter::processHeader(TBB_Header& header, size_t recvPayloadSize)
 }
 
 void TBB_StreamWriter::mainInputLoop() {
-	// Always (try to) notify output thread to stop at the end.
+	// Always (try to) notify output thread to stop at the end, else we may hang.
 	class NotifyOutputThread {
 		Queue<TBB_Frame*>& queue;
 	public:
@@ -979,7 +989,8 @@ void TBB_StreamWriter::mainInputLoop() {
 		stream = createStream(itsInputStreamName, true);
 	} catch (Exception& exc) { // SystemCallException or InterfaceException (or TimeOutException)
 		LOG_WARN_STR(itsLogPrefix << exc);
-		return; // do not set itsInExitStatus to 1: if not all files with "$" replaced exist, that's fine
+		itsInExitStatus = 1;
+		return;
 	}
 	LOG_INFO_STR(itsLogPrefix << "reading incoming data from " << itsInputStreamName);
 
@@ -987,21 +998,21 @@ void TBB_StreamWriter::mainInputLoop() {
 		TBB_Frame* frame;
 
 		try {
-			frame = itsFreeQueue.remove(); // may only throw SystemCallException
+			frame = itsFreeQueue.remove();
 
-			size_t nread = stream->tryRead(frame, itsExpFrameSize); // cannot simply retry until expected size: UDP used unless local test
+			size_t nread = stream->tryRead(frame, itsExpFrameSize); // read() once for udp
 
 			// Notify master that we are still busy. (Racy, but ok, see the timeoutstamp decl.)
 			::gettimeofday(&itsTimeoutStamp, NULL);
 
-#ifdef DUMP_RAW_STATION_DATA
+#ifdef DUMP_RAW_STATION_FRAMES
 			try {
 				itsRawStationData->write(frame, nread);
 			} catch (exception& exc) { /* open() probably failed, don't spam */ }
 #endif
 
 			if (nread < sizeof(TBB_Header)) {
-				throw TBB_MalformedFrameException("dropping too small TBB frame");
+				throw TBB_MalformedFrameException("dropping too small frame");
 			}
 			processHeader(frame->header, nread - sizeof(TBB_Header));
 
@@ -1086,7 +1097,6 @@ TBB_Writer::TBB_Writer(const vector<string>& inputStreamNames, const Parset& par
 , itsRunNr(0)
 {
 	// Mask all signals to inherit for workers. This forces signals to be delivered to the main thread.
-	// Wrap to make sure we always (try to) restore the signal mask.
 	struct SigMask {
 		sigset_t sigset_old;
 
@@ -1094,14 +1104,12 @@ TBB_Writer::TBB_Writer(const vector<string>& inputStreamNames, const Parset& par
 			sigset_t sigset_all_masked;
 			::sigfillset(&sigset_all_masked);
 			if (::pthread_sigmask(SIG_SETMASK, &sigset_all_masked, &sigset_old) != 0) {
-				// The LOFAR sys uses another way to control us, so do not make this fatal.
 				LOG_WARN_STR("TBB: pthread_sigmask() failed to mask signals to inherit for worker threads.");
 			}
 		}
 
 		~SigMask() {
 			if (::pthread_sigmask(SIG_SETMASK, &sigset_old, NULL) != 0) {
-				// No exc in destr. If restoring fails and keepRunning = true, we remain deaf.
 				LOG_WARN_STR("TBB: pthread_sigmask() failed to restore signals. We may be deaf to signals.");
 			}
 		}
@@ -1114,8 +1122,9 @@ TBB_Writer::TBB_Writer(const vector<string>& inputStreamNames, const Parset& par
 	if (operatingMode == TBB_TRANSIENT_MODE) {
 		expNTrSamples = DEFAULT_TBB_TRANSIENT_NSAMPLES;
 	} else if (operatingMode == TBB_SPECTRAL_MODE) {
-		expNTrSamples = 2 * DEFAULT_TBB_SPECTRAL_NSAMPLES;
+		expNTrSamples = 2 * MAX_TBB_SPECTRAL_NSAMPLES;
 	} else {
+		expNTrSamples = DEFAULT_TBB_TRANSIENT_NSAMPLES;
 		LOG_WARN("TBB: Failed to get operating mode from parset, assuming transient");
 	}
 
@@ -1154,10 +1163,15 @@ TBB_Station* TBB_Writer::getStation(const TBB_Header& header) {
 	TBB_Station* station;
 	{
 		ScopedLock slH5(itsH5Mutex);
-		station = new TBB_Station(stationName, itsH5Mutex, itsParset, stMetaData, h5Filename); // TODO: must guarantee insert() cannot fail, else leaks; destr here is unsafe
+		station = new TBB_Station(stationName, itsH5Mutex, itsParset, stMetaData, h5Filename);
 	}
 
-	return itsStations.insert(make_pair(header.stationID, station)).first->second;
+	try {
+		return itsStations.insert(make_pair(header.stationID, station)).first->second;
+	} catch (exception& exc) {
+		delete station;
+		throw;
+	}
 }
 
 string TBB_Writer::createNewTBB_H5Filename(const TBB_Header& header, const string& stationName) {
@@ -1183,7 +1197,7 @@ string TBB_Writer::createNewTBB_H5Filename(const TBB_Header& header, const strin
 	string triggerDateTime(formatFilenameTimestamp(tv, output_format, output_format_secs, sizeof(output_format_example)));
 	string h5Filename(itsOutDir + "L" + obsIDStr + "_" + stationName + "_" + triggerDateTime + "_" + typeExt);
 
-	// If the file already exists, add a run nr and retry. (seq race with DAL's open and doesn't check .raw, but good enough)
+	// If the file already exists, add a run nr and retry. (might race and doesn't check .raw, but good enough)
 	// If >1 stations per node, start at the prev run nr if any (hence itsRunNr).
 	if (itsRunNr == 0) {
 		if (::access(h5Filename.c_str(), F_OK) != 0 && errno == ENOENT) {
diff --git a/RTCP/Storage/src/TBB_Writer_main.cc b/RTCP/Storage/src/TBB_Writer_main.cc
index 22ad98aedac9be82acd0a422a0abb1b7400d195c..249543d948c511cdba6ef2599df4fcb5d3dee5d9 100644
--- a/RTCP/Storage/src/TBB_Writer_main.cc
+++ b/RTCP/Storage/src/TBB_Writer_main.cc
@@ -25,7 +25,7 @@
  * TBB writers written by Lars Baehren, Andreas Horneffer, and Joseph Masters.
  */
 
-#include <lofar_config.h>			// before any other include
+#include <lofar_config.h>		// before any other include
 
 #define _FILE_OFFSET_BITS 64
 #include <cstddef>
@@ -41,6 +41,7 @@
 #include <getopt.h>
 
 #include <iostream>
+#include <sstream>
 
 #include <boost/lexical_cast.hpp>
 
@@ -55,15 +56,16 @@
 
 #include <dal/lofar/StationNames.h>
 
-#define TBB_DEFAULT_BASE_PORT		0x7bb0	// i.e. tbb0
-#define TBB_DEFAULT_LAST_PORT		0x7bbb	// 0x7bbf for NL, 0x7bbb for int'l stations
+#define TBB_DEFAULT_BASE_PORT	0x7bb0	// i.e. tbb0
+#define TBB_DEFAULT_LAST_PORT	0x7bbb	// 0x7bbf for NL, 0x7bbb for int'l stations
 
-#define STDLOG_BUFFER_SIZE			1024
+#define STDLOG_BUFFER_SIZE	1024
 
 using namespace std;
 
 struct progArgs {
 	string parsetFilename;
+	string stCalTablesDir;
 	string antFieldDir;
 	string outputDir;
 	string input;
@@ -75,7 +77,6 @@ struct progArgs {
 static char stdoutbuf[STDLOG_BUFFER_SIZE];
 static char stderrbuf[STDLOG_BUFFER_SIZE];
 
-// Install a new handler to produce backtraces for std::bad_alloc.
 LOFAR::NewHandler badAllocExcHandler(LOFAR::BadAllocException::newHandler);
 
 static bool sigint_seen;
@@ -115,26 +116,34 @@ static vector<string> getTBB_InputStreamNames(const string& input, uint16_t port
 		LOFAR::StationConfig stConf;
 		nTbbBoards = stConf.nrTBBs;
 	} catch (LOFAR::AssertError& ) { // config file not found
-		LOG_DEBUG_STR("Falling back to up to " << TBB_DEFAULT_LAST_PORT - TBB_DEFAULT_BASE_PORT + 1 << " streams (1 per board)");
+		LOG_DEBUG_STR("Falling back to at most " << TBB_DEFAULT_LAST_PORT - TBB_DEFAULT_BASE_PORT + 1 << " input streams (1 per board)");
 		nTbbBoards = TBB_DEFAULT_LAST_PORT - TBB_DEFAULT_BASE_PORT + 1; // fallback
 	}
 
 	vector<string> allInputStreamNames;
 	if (input == "udp" || input == "tcp") {
 		for (uint16_t port = portsBase; port <= portsBase + nTbbBoards; ++port) {
-			// 0.0.0.0: could restrict to station IPs/network, but need netmask lookup and allow localhost. Not critical: we are on a separate VLAN.
+			// 0.0.0.0: could restrict to station IPs/network, but need netmask lookup and allow localhost. Not critical: data arrives on a separate VLAN.
 			string streamName(input + ":0.0.0.0:" + LOFAR::formatString("%hu", port));
 			allInputStreamNames.push_back(streamName);
 		}
 	} else { // file or named pipe input
+		size_t colonPos = input.find(':');
+		if (colonPos == string::npos) {
+			return allInputStreamNames;
+		}
 		size_t placeholderPos = input.find_last_of('%');
 		if (placeholderPos == string::npos) { // single input, no expansion needed
-			allInputStreamNames.push_back(input);
-		} else { // expand: replace e.g. file:x%y-%.raw by file:x%y-0.raw, file:x%y-1.raw, ..., file:x%y-11.raw
+			if (access(input.c_str() + colonPos + 1, R_OK) == 0) {
+				allInputStreamNames.push_back(input);
+			}
+		} else { // expand e.g. file:x%y-%.raw into {file:x%y-0.raw, file:x%y-1.raw, ..., file:x%y-11.raw}
 			for (int i = 0; i < nTbbBoards; ++i) {
 				string streamName(input);
 				streamName.replace(placeholderPos, 1, LOFAR::formatString("%u", i));
-				allInputStreamNames.push_back(streamName);
+				if (access(streamName.c_str() + colonPos + 1, R_OK) == 0) {
+					allInputStreamNames.push_back(streamName);
+				}
 			}
 		}
 	}
@@ -142,6 +151,44 @@ static vector<string> getTBB_InputStreamNames(const string& input, uint16_t port
 	return allInputStreamNames;
 }
 
+static void retrieveStationCalTables(string& stCalTablesDir) {
+	/*
+	 * Users need the station calibration tables included. This is a major pain, because
+	 * we figure out which station(s) we receive from at runtime (relying on the static
+	 * mapping is a disaster waiting to happen), we cannot ask the stations and the
+	 * alternative, from svn, is unreliable and races with (few) Science Support updates.
+	 * Not all users care about the race, a few do. Also, auth, and this exposes an internal
+	 * interface (cal tables) to users... Still do it: TBB is too low prio to get stuff nice.
+	 *
+	 * Get tables from all stations for the right cal mode (i.e. usually only verifies svn local copy),
+	 * Run 'svn cleanup' and 'svn upgrade' when needed, otherwise remove the local copies and re-retrieve.
+	 *
+
+	 */
+
+//svn checkout https://svn.astron.nl/Station/trunk/CalTables
+//but only the needed files
+//svn update
+//Ctrl-C doesn't seem to kill svn co/up (only pause/halt), so use Ctrl-\ (QUIT), then svn cleanup
+
+//svn: Working copy '.' locked
+//svn: run 'svn cleanup' to remove locks (type 'svn help cleanup' for details)
+//svn cleanup
+
+//rm -rf CalTables
+
+// Note: include the entire cal table as-is, because that easily allows users to just resort to the raw files
+
+//	- if stCalTablesDir.empty():
+
+//	- get station names, st cal mode
+//	- fork process (sh script), do data writes
+//	- sh script does svn checkout/update on req files only into ~/TBB_Writer-Station-CalTabs-localcopy/Station/CalTables/*
+//	- listen for tbb data. When data writes done, do timed wait() on script pid, and if ok, add cal tables.
+//	- if not ok: if timeout { signal script to abort and run svn cleanup, wait()}. Skip writing cal tabs, log warning + script output.
+
+}
+
 static int antSetName2AntFieldIndex(const string& antSetName) {
 	int idx;
 
@@ -235,7 +282,7 @@ static int doTBB_Run(const vector<string>& inputStreamNames, const LOFAR::RTCP::
 		 */
 		struct itimerval timer = {args.timeoutVal, args.timeoutVal};
 		if (setitimer(ITIMER_REAL, &timer, NULL) != 0) {
-			throw LOFAR::SystemCallException("setitimer failed");
+			throw LOFAR::SystemCallException("setitimer", errno, THROW_ARGS);
 		}
 
 		bool anyFrameReceived = false; // don't quit if there is no data immediately after starting
@@ -278,14 +325,10 @@ static int doTBB_Run(const vector<string>& inputStreamNames, const LOFAR::RTCP::
 	return err;
 }
 
-static int ensureOutputDirExists(string outputDir) {
+static int isExistingDirname(const string& dirname) {
 	struct stat st;
 
-	if (outputDir == "") {
-		outputDir = ".";
-	}
-
-	if (stat(outputDir.c_str(), &st) != 0) {
+	if (stat(dirname.c_str(), &st) != 0) {
 		return errno;
 	}
 
@@ -305,14 +348,15 @@ static void printUsage(const char* progname) {
 	cout << TBB_WRITER_VERSION;
 #endif
 	cout << endl;
-	cout << "Write incoming LOFAR TBB data with meta data to disk in HDF5 format." << endl;
-	cout << "Usage: " << progname << " --parsetfile=parsets/L12345.parset [OPTION]..." << endl;
+	cout << "Write incoming LOFAR TBB data with meta data to storage in HDF5 format." << endl;
+	cout << "Usage: " << progname << " -p parsets/L12345.parset [OPTION]..." << endl;
 	cout << endl;
 	cout << "Options:" << endl;
-	cout << "  -s, --parsetfile=L12345.parset      parset file (observation settings) (mandatory)" << endl;
+	cout << "  -p, --parset=L12345.parset          path to file with observation settings (mandatory)" << endl;
 	cout << endl;
-	cout << "  -a, --antfielddir=/d/AntennaFields  override $LOFARROOT and parset path for antenna field files (like CS001-AntennaField.conf)" << endl;
-	cout << "  -o, --outputdir=tbbout              output directory" << endl;
+	cout << "  -c, --stcaltablesdir=/c/CalTables   path to override SVN retrieval of station calibration tables (like CS001/CalTable_001_mode1.dat)" << endl;
+	cout << "  -a, --antfielddir=/a/AntennaFields  path to override $LOFARROOT and parset path for antenna field files (like CS001-AntennaField.conf)" << endl;
+	cout << "  -o, --outputdir=tbbout              existing output directory" << endl;
 	cout << "  -i, --input=tcp|udp                 input stream(s) or type (default: udp)" << endl;
 	cout << "              file:raw.dat                if file or pipe name has a '%'," << endl;
 	cout << "              pipe:named-%.pipe           then the last '%' is replaced by 0, 1, ..., 11" << endl;
@@ -326,11 +370,12 @@ static void printUsage(const char* progname) {
 }
 
 static int parseArgs(int argc, char *argv[], struct progArgs* args) {
-	int rv = 0;
+	int status = 0;
 
 	// Default values
 	args->parsetFilename = "";	// there is no default parset filename, so not passing it is fatal
-	args->antFieldDir = "";		// idem
+	args->stCalTablesDir = "";	// idem, but otherwise, retrieve from svn and not fatal
+	args->antFieldDir = "";		// idem, but otherwise, detect and not fatal
 
 	args->outputDir = "";
 	args->input = "udp";
@@ -340,48 +385,69 @@ static int parseArgs(int argc, char *argv[], struct progArgs* args) {
 	args->keepRunning = true;
 
 	static const struct option long_opts[] = {
+		// NOTE: If you change this, then also change the code below AND the printUsage() code above!
 		// {const char *name, int has_arg, int *flag, int val}
-		{"parsetfile",   required_argument, NULL, 's'}, // observation (s)ettings
-		{"antfielddir",  required_argument, NULL, 'a'},
-		{"outputdir",    required_argument, NULL, 'o'},
-		{"input",        required_argument, NULL, 'i'},
-		{"portbase",     required_argument, NULL, 'b'}, // port (b)ase
-		{"timeout",      required_argument, NULL, 't'},
+		{"parset",         required_argument, NULL, 'p'},
+		{"stcaltablesdir", required_argument, NULL, 'c'}, // station calibration tables
+		{"antfielddir",    required_argument, NULL, 'a'}, // antenna field info
+		{"outputdir",      required_argument, NULL, 'o'},
+		{"input",          required_argument, NULL, 'i'},
+		{"portbase",       required_argument, NULL, 'b'}, // port (b)ase
+		{"timeout",        required_argument, NULL, 't'},
 
-		{"keeprunning",  optional_argument, NULL, 'k'},
+		{"keeprunning",    optional_argument, NULL, 'k'},
 
-		{"help",         no_argument,       NULL, 'h'},
-		{"version",      no_argument,       NULL, 'v'},
+		{"help",           no_argument,       NULL, 'h'},
+		{"version",        no_argument,       NULL, 'v'},
 
 		{NULL, 0, NULL, 0}
 	};
 
 	opterr = 0; // prevent error printing to stderr by getopt_long()
-	int opt;
+	int opt, err;
 	while ((opt = getopt_long(argc, argv, "hvs:a:o:p:b:t:k::", long_opts, NULL)) != -1) {
 		switch (opt) {
-		case 's':
+		case 'p':
 			args->parsetFilename = optarg;
 			break;
+		case 'c':
+			args->stCalTablesDir = optarg;
+			if (args->stCalTablesDir[0] != '\0' && args->stCalTablesDir[args->stCalTablesDir.size() - 1] != '/') {
+				args->stCalTablesDir.push_back('/');
+			}
+			if ((err = isExistingDirname(args->stCalTablesDir)) != 0) {
+				LOG_FATAL_STR("TBB: station cal tab dir argument value " << optarg << ": " << strerror(err));
+				status = 1;
+			}
+			break;
 		case 'a':
 			args->antFieldDir = optarg;
-			if (args->antFieldDir[args->antFieldDir.size() - 1] != '/') {
+			if (args->antFieldDir[0] != '\0' && args->antFieldDir[args->antFieldDir.size() - 1] != '/') {
 				args->antFieldDir.push_back('/');
 			}
+			if ((err = isExistingDirname(args->antFieldDir)) != 0) {
+				LOG_FATAL_STR("TBB: antenna field dir argument value " << optarg << ": " << strerror(err));
+				status = 1;
+			}
 			break;
 		case 'o':
 			args->outputDir = optarg;
-			if (args->outputDir[args->outputDir.size() - 1] != '/') {
+			if (args->outputDir[0] != '\0' && args->outputDir[args->outputDir.size() - 1] != '/') {
 				args->outputDir.push_back('/');
 			}
+			if ((err = isExistingDirname(args->outputDir)) != 0) {
+				LOG_FATAL_STR("TBB: output dir argument value " << optarg << ": " << strerror(err));
+				status = 1;
+			}
 			break;
 		case 'i':
 			if (strcmp(optarg, "tcp") == 0 || strcmp(optarg, "udp") == 0 ||
-				strncmp(optarg, "file:", sizeof("file:")-1) == 0 || strncmp(optarg, "pipe:", sizeof("pipe:")-1) == 0) {
+					strncmp(optarg, "file:", sizeof("file:")-1) == 0 ||
+					strncmp(optarg, "pipe:", sizeof("pipe:")-1) == 0) {
 				args->input = optarg;
 			} else {
-				LOG_FATAL_STR("TBB: Invalid input option: " << optarg);
-				rv = 1;
+				LOG_FATAL_STR("TBB: Invalid input argument value: " << optarg);
+				status = 1;
 			}
 			break;
 		case 'b':
@@ -391,16 +457,16 @@ static int parseArgs(int argc, char *argv[], struct progArgs* args) {
 					throw boost::bad_lexical_cast(); // abuse exc type to have single catch
 				}
 			} catch (boost::bad_lexical_cast& /*exc*/) {
-				LOG_FATAL_STR("TBB: Invalid port option: " << optarg);
-				rv = 1;
+				LOG_FATAL_STR("TBB: Invalid port argument value: " << optarg);
+				status = 1;
 			}
 			break;
 		case 't':
 			try {
 				args->timeoutVal.tv_sec = boost::lexical_cast<unsigned long>(optarg);
 			} catch (boost::bad_lexical_cast& /*exc*/) {
-				LOG_FATAL_STR("TBB: Invalid timeout option: " << optarg);
-				rv = 1;
+				LOG_FATAL_STR("TBB: Invalid timeout argument value: " << optarg);
+				status = 1;
 			}
 			break;
 		case 'k':
@@ -411,31 +477,33 @@ static int parseArgs(int argc, char *argv[], struct progArgs* args) {
 			try {
 				args->keepRunning = boost::lexical_cast<bool>(optarg);
 			} catch (boost::bad_lexical_cast& /*exc*/) {
-				LOG_FATAL_STR("TBB: Invalid keeprunning option: " << optarg);
-				rv = 1;
+				LOG_FATAL_STR("TBB: Invalid keeprunning argument value: " << optarg);
+				status = 1;
 			}
 			break;
 		case 'h':
 		case 'v':
-			if (rv == 0) {
-				rv = 2;
+			if (status == 0) {
+				status = 2;
 			}
 			break;
 		default: // '?'
-			LOG_FATAL_STR("TBB: Invalid program argument: " << argv[optind-1]);
-			rv = 1;
+			LOG_FATAL_STR("TBB: Invalid program argument or missing argument value: " << argv[optind-1]);
+			status = 1;
 		}
 	}
 
 	if (optind < argc) {
-		LOG_FATAL("TBB: Failed to recognize options:");
+		ostringstream oss;
+		oss << "TBB: Failed to recognize arguments:";
 		while (optind < argc) {
-			LOG_FATAL_STR(" " << argv[optind++]);
+			oss << " " << argv[optind++]; // good enough
 		}
-		rv = 1;
+		LOG_FATAL_STR(oss.str());
+		status = 1;
 	}
 
-	return rv;
+	return status;
 }
 
 int main(int argc, char* argv[]) {
@@ -472,12 +540,13 @@ int main(int argc, char* argv[]) {
 
 	setTermSigsHandler();
 
-	if ((err = ensureOutputDirExists(args.outputDir)) != 0) {
-		LOG_FATAL_STR("TBB: output directory: " << strerror(err));
+	const vector<string> inputStreamNames(getTBB_InputStreamNames(args.input, args.port));
+	if (inputStreamNames.empty()) {
+		LOG_FATAL("TBB: none of the input streams is accessible to read from");
 		return 1;
 	}
 
-	const vector<string> inputStreamNames(getTBB_InputStreamNames(args.input, args.port));
+	retrieveStationCalTables(args.stCalTablesDir);
 
 	// We don't run alone, so try to increase the QoS we get from the OS to decrease the chance of data loss.
 	setIOpriority(); // reqs CAP_SYS_NICE or CAP_SYS_ADMIN
@@ -499,11 +568,11 @@ int main(int argc, char* argv[]) {
 
 	// Config exceptions (opening or parsing) are fatal. Too bad we cannot have it in one type.
 	} catch (LOFAR::RTCP::InterfaceException& exc) {
-		LOG_FATAL_STR("TBB: LOFAR::InterfaceException: parset: " << exc);
+		LOG_FATAL_STR("TBB: Required RTCP parset key/values missing: " << exc);
 	} catch (LOFAR::APSException& exc) {
-		LOG_FATAL_STR("TBB: LOFAR::APSException: parameterset: " << exc);
+		LOG_FATAL_STR("TBB: Parameterset error: " << exc);
 	} catch (LOFAR::RTCP::StorageException& exc) {
-		LOG_FATAL_STR("TBB: LOFAR::StorageException: antenna field files: " << exc);
+		LOG_FATAL_STR("TBB: Antenna field files: " << exc);
 	}
 
 	return err == 0 ? 0 : 1;
diff --git a/RTCP/Storage/test/tTBB_Writer-spectral.parset b/RTCP/Storage/test/tTBB_Writer-spectral.parset
index 16af39ad435f56656a00b8e670407a4ce02b029f..1df583842363fc76a1ec88f8857b497fe94df34b 100644
--- a/RTCP/Storage/test/tTBB_Writer-spectral.parset
+++ b/RTCP/Storage/test/tTBB_Writer-spectral.parset
@@ -430,8 +430,13 @@ Observation.TBB.TBBsetting.filter1_coeff3 = 0
 Observation.TBB.TBBsetting.operatingMode = 2
 Observation.TBB.TBBsetting.startlevel = 7
 Observation.TBB.TBBsetting.stoplevel = 7
-Observation.TBB.TBBsetting.subbandList = [0]
+Observation.TBB.TBBsetting.subbandList = [0..486]
 Observation.TBB.TBBsetting.subbandList2 = [175..418]
+Observation.TBB.TBBsetting.subbandListLBA30_ALL = [154-397]
+Observation.TBB.TBBsetting.subbandListHBA115_ALL = [77-320]
+Observation.TBB.TBBsetting.subbandListHBA148_ALL = [245-488]
+Observation.TBB.TBBsetting.subbandListHBA180_ALL = [128-371]
+Observation.TBB.TBBsetting.subbandListHBA210_ALL = [52-255]
 Observation.TBB.TBBsetting.triggerMode = 1
 Observation.TBB.TBBsetting.window = 1M
 Observation.VirtualInstrument.imageNodeList = []
diff --git a/SAS/OTB/jOTDB3/include/jOTDB3/nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance.h b/SAS/OTB/jOTDB3/include/jOTDB3/nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance.h
index 6aae1dfc7e91d1a83c7f7cc3600fa300afb13050..d2907d980f937fae66584829870b3a52830e82d3 100644
--- a/SAS/OTB/jOTDB3/include/jOTDB3/nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance.h
+++ b/SAS/OTB/jOTDB3/include/jOTDB3/nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance.h
@@ -1,62 +1,389 @@
-#ifndef __nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance__
-#define __nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance__
-
-#include <jni.h>
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-JNIEXPORT void JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_initTreeMaintenance (JNIEnv *env, jobject);
-JNIEXPORT jint JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_loadMasterFile (JNIEnv *env, jobject, jstring);
-JNIEXPORT jint JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_loadComponentFile__Ljava_lang_String_2Ljava_lang_String_2Ljava_lang_String_2 (JNIEnv *env, jobject, jstring, jstring, jstring);
-JNIEXPORT jint JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_loadComponentFile__Ljava_lang_String_2Ljava_lang_String_2 (JNIEnv *env, jobject, jstring, jstring);
-JNIEXPORT jint JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_loadComponentFile__Ljava_lang_String_2 (JNIEnv *env, jobject, jstring);
-JNIEXPORT jobject JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_getComponentList__Ljava_lang_String_2Z (JNIEnv *env, jobject, jstring, jboolean);
-JNIEXPORT jobject JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_getComponentList__Ljava_lang_String_2 (JNIEnv *env, jobject, jstring);
-JNIEXPORT jobject JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_getComponentList__ (JNIEnv *env, jobject);
-JNIEXPORT jobject JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_getComponentNode (JNIEnv *env, jobject, jint);
-JNIEXPORT jobject JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_getComponentParams (JNIEnv *env, jobject, jint);
-JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_saveComponentNode (JNIEnv *env, jobject, jobject);
-JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_isTopComponent (JNIEnv *env, jobject, jint);
-JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_deleteComponentNode (JNIEnv *env, jobject, jint);
-JNIEXPORT jstring JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_getFullComponentName (JNIEnv *env, jobject, jobject);
-JNIEXPORT jint JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_buildTemplateTree (JNIEnv *env, jobject, jint, jshort);
-JNIEXPORT jint JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_newTemplateTree (JNIEnv *env, jobject);
-JNIEXPORT jint JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_copyTemplateTree (JNIEnv *env, jobject, jint);
-JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_assignTemplateName (JNIEnv *env, jobject, jint, jstring);
-JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_assignProcessType (JNIEnv *env, jobject, jint, jstring, jstring, jstring);
-JNIEXPORT jobject JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_getNode (JNIEnv *env, jobject, jint, jint);
-JNIEXPORT jobject JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_getParam__II (JNIEnv *env, jobject, jint, jint);
-JNIEXPORT jobject JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_getParam__Lnl_astron_lofar_sas_otb_jotdb3_jOTDBnode_2 (JNIEnv *env, jobject, jobject);
-JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_saveParam (JNIEnv *env, jobject, jobject);
-JNIEXPORT jobject JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_getItemList__III (JNIEnv *env, jobject, jint, jint, jint);
-JNIEXPORT jobject JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_getItemList__ILjava_lang_String_2 (JNIEnv *env, jobject, jint, jstring);
-JNIEXPORT jint JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_dupNode (JNIEnv *env, jobject, jint, jint, jshort);
-JNIEXPORT jint JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_addComponent__IIILjava_lang_String_2 (JNIEnv *env, jobject, jint, jint, jint, jstring);
-JNIEXPORT jint JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_addComponent__III (JNIEnv *env, jobject, jint, jint, jint);
-JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_saveNode (JNIEnv *env, jobject, jobject);
-JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_saveNodeList (JNIEnv *env, jobject, jobject);
-JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_deleteNode (JNIEnv *env, jobject, jobject);
-JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_deleteNodeList (JNIEnv *env, jobject, jobject);
-JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_checkTreeConstraints__II (JNIEnv *env, jobject, jint, jint);
-JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_checkTreeConstraints__I (JNIEnv *env, jobject, jint);
-JNIEXPORT jint JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_instanciateTree (JNIEnv *env, jobject, jint);
-JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_pruneTree (JNIEnv *env, jobject, jint, jshort);
-JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_exportTree (JNIEnv *env, jobject, jint, jint, jstring);
-JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_exportResultTree (JNIEnv *env, jobject, jint, jint, jstring);
-JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_deleteTree (JNIEnv *env, jobject, jint);
-JNIEXPORT jobject JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_getTopNode (JNIEnv *env, jobject, jint);
-JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_setMomInfo (JNIEnv *env, jobject, jint, jint, jint, jstring);
-JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_setClassification (JNIEnv *env, jobject, jint, jshort);
-JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_setTreeState (JNIEnv *env, jobject, jint, jshort);
-JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_setDescription (JNIEnv *env, jobject, jint, jstring);
-JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_setSchedule (JNIEnv *env, jobject, jint, jstring, jstring);
-JNIEXPORT jstring JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_errorMsg (JNIEnv *env, jobject);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance__ */
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance */
+
+#ifndef _Included_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+#define _Included_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    initTreeMaintenance
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_initTreeMaintenance
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    loadMasterFile
+ * Signature: (Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_loadMasterFile
+  (JNIEnv *, jobject, jstring);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    loadComponentFile
+ * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_loadComponentFile__Ljava_lang_String_2Ljava_lang_String_2Ljava_lang_String_2
+  (JNIEnv *, jobject, jstring, jstring, jstring);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    loadComponentFile
+ * Signature: (Ljava/lang/String;Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_loadComponentFile__Ljava_lang_String_2Ljava_lang_String_2
+  (JNIEnv *, jobject, jstring, jstring);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    loadComponentFile
+ * Signature: (Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_loadComponentFile__Ljava_lang_String_2
+  (JNIEnv *, jobject, jstring);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    getComponentList
+ * Signature: (Ljava/lang/String;Z)Ljava/util/Vector;
+ */
+JNIEXPORT jobject JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_getComponentList__Ljava_lang_String_2Z
+  (JNIEnv *, jobject, jstring, jboolean);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    getComponentList
+ * Signature: (Ljava/lang/String;)Ljava/util/Vector;
+ */
+JNIEXPORT jobject JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_getComponentList__Ljava_lang_String_2
+  (JNIEnv *, jobject, jstring);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    getComponentList
+ * Signature: ()Ljava/util/Vector;
+ */
+JNIEXPORT jobject JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_getComponentList__
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    getComponentNode
+ * Signature: (I)Lnl/astron/lofar/sas/otb/jotdb3/jVICnodeDef;
+ */
+JNIEXPORT jobject JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_getComponentNode
+  (JNIEnv *, jobject, jint);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    getComponentParams
+ * Signature: (I)Ljava/util/Vector;
+ */
+JNIEXPORT jobject JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_getComponentParams
+  (JNIEnv *, jobject, jint);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    saveComponentNode
+ * Signature: (Lnl/astron/lofar/sas/otb/jotdb3/jVICnodeDef;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_saveComponentNode
+  (JNIEnv *, jobject, jobject);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    isTopComponent
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_isTopComponent
+  (JNIEnv *, jobject, jint);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    deleteComponentNode
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_deleteComponentNode
+  (JNIEnv *, jobject, jint);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    getFullComponentName
+ * Signature: (Lnl/astron/lofar/sas/otb/jotdb3/jVICnodeDef;)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_getFullComponentName
+  (JNIEnv *, jobject, jobject);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    buildTemplateTree
+ * Signature: (IS)I
+ */
+JNIEXPORT jint JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_buildTemplateTree
+  (JNIEnv *, jobject, jint, jshort);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    newTemplateTree
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_newTemplateTree
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    copyTemplateTree
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_copyTemplateTree
+  (JNIEnv *, jobject, jint);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    assignTemplateName
+ * Signature: (ILjava/lang/String;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_assignTemplateName
+  (JNIEnv *, jobject, jint, jstring);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    assignProcessType
+ * Signature: (ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_assignProcessType
+  (JNIEnv *, jobject, jint, jstring, jstring, jstring);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    getNode
+ * Signature: (II)Lnl/astron/lofar/sas/otb/jotdb3/jOTDBnode;
+ */
+JNIEXPORT jobject JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_getNode
+  (JNIEnv *, jobject, jint, jint);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    getParam
+ * Signature: (II)Lnl/astron/lofar/sas/otb/jotdb3/jOTDBparam;
+ */
+JNIEXPORT jobject JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_getParam__II
+  (JNIEnv *, jobject, jint, jint);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    getParam
+ * Signature: (Lnl/astron/lofar/sas/otb/jotdb3/jOTDBnode;)Lnl/astron/lofar/sas/otb/jotdb3/jOTDBparam;
+ */
+JNIEXPORT jobject JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_getParam__Lnl_astron_lofar_sas_otb_jotdb3_jOTDBnode_2
+  (JNIEnv *, jobject, jobject);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    saveParam
+ * Signature: (Lnl/astron/lofar/sas/otb/jotdb3/jOTDBparam;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_saveParam
+  (JNIEnv *, jobject, jobject);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    getItemList
+ * Signature: (III)Ljava/util/Vector;
+ */
+JNIEXPORT jobject JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_getItemList__III
+  (JNIEnv *, jobject, jint, jint, jint);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    getItemList
+ * Signature: (ILjava/lang/String;)Ljava/util/Vector;
+ */
+JNIEXPORT jobject JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_getItemList__ILjava_lang_String_2
+  (JNIEnv *, jobject, jint, jstring);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    dupNode
+ * Signature: (IIS)I
+ */
+JNIEXPORT jint JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_dupNode
+  (JNIEnv *, jobject, jint, jint, jshort);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    addComponent
+ * Signature: (IIILjava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_addComponent__IIILjava_lang_String_2
+  (JNIEnv *, jobject, jint, jint, jint, jstring);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    addComponent
+ * Signature: (III)I
+ */
+JNIEXPORT jint JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_addComponent__III
+  (JNIEnv *, jobject, jint, jint, jint);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    saveNode
+ * Signature: (Lnl/astron/lofar/sas/otb/jotdb3/jOTDBnode;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_saveNode
+  (JNIEnv *, jobject, jobject);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    saveNodeList
+ * Signature: (Ljava/util/Vector;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_saveNodeList
+  (JNIEnv *, jobject, jobject);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    deleteNode
+ * Signature: (Lnl/astron/lofar/sas/otb/jotdb3/jOTDBnode;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_deleteNode
+  (JNIEnv *, jobject, jobject);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    deleteNodeList
+ * Signature: (Ljava/util/Vector;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_deleteNodeList
+  (JNIEnv *, jobject, jobject);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    checkTreeConstraints
+ * Signature: (II)Z
+ */
+JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_checkTreeConstraints__II
+  (JNIEnv *, jobject, jint, jint);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    checkTreeConstraints
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_checkTreeConstraints__I
+  (JNIEnv *, jobject, jint);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    instanciateTree
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_instanciateTree
+  (JNIEnv *, jobject, jint);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    pruneTree
+ * Signature: (IS)Z
+ */
+JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_pruneTree
+  (JNIEnv *, jobject, jint, jshort);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    exportTree
+ * Signature: (IILjava/lang/String;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_exportTree
+  (JNIEnv *, jobject, jint, jint, jstring);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    exportResultTree
+ * Signature: (IILjava/lang/String;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_exportResultTree
+  (JNIEnv *, jobject, jint, jint, jstring);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    exportMetadata
+ * Signature: (ILjava/lang/String;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_exportMetadata
+  (JNIEnv *, jobject, jint, jstring);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    deleteTree
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_deleteTree
+  (JNIEnv *, jobject, jint);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    getTopNode
+ * Signature: (I)Lnl/astron/lofar/sas/otb/jotdb3/jOTDBnode;
+ */
+JNIEXPORT jobject JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_getTopNode
+  (JNIEnv *, jobject, jint);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    setMomInfo
+ * Signature: (IIILjava/lang/String;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_setMomInfo
+  (JNIEnv *, jobject, jint, jint, jint, jstring);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    setClassification
+ * Signature: (IS)Z
+ */
+JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_setClassification
+  (JNIEnv *, jobject, jint, jshort);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    setTreeState
+ * Signature: (IS)Z
+ */
+JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_setTreeState
+  (JNIEnv *, jobject, jint, jshort);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    setDescription
+ * Signature: (ILjava/lang/String;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_setDescription
+  (JNIEnv *, jobject, jint, jstring);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    setSchedule
+ * Signature: (ILjava/lang/String;Ljava/lang/String;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_setSchedule
+  (JNIEnv *, jobject, jint, jstring, jstring);
+
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    errorMsg
+ * Signature: ()Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_errorMsg
+  (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/SAS/OTB/jOTDB3/src/nl/astron/lofar/sas/otb/jotdb3/jTreeMaintenance.java b/SAS/OTB/jOTDB3/src/nl/astron/lofar/sas/otb/jotdb3/jTreeMaintenance.java
index 27decb792e5d95240030505f1726380631a13974..2d1e0229d55a878f7b62f6cde2bdb37fd8ba8911 100644
--- a/SAS/OTB/jOTDB3/src/nl/astron/lofar/sas/otb/jotdb3/jTreeMaintenance.java
+++ b/SAS/OTB/jOTDB3/src/nl/astron/lofar/sas/otb/jotdb3/jTreeMaintenance.java
@@ -195,6 +195,10 @@ public class jTreeMaintenance implements jTreeMaintenanceInterface
     @Override
     public native boolean exportResultTree (int aTreeID,int topItem,String filename) throws RemoteException;
 
+    // Export all reported metadata from the given VIC tree
+    @Override
+    public native boolean exportMetadata (int	aTreeID,String filename) throws RemoteException;
+
     //# --- Finally some general tree maintenance ---
     // Delete a tree (of any kind) from the database.
     @Override
diff --git a/SAS/OTB/jOTDB3/src/nl/astron/lofar/sas/otb/jotdb3/jTreeMaintenanceInterface.java b/SAS/OTB/jOTDB3/src/nl/astron/lofar/sas/otb/jotdb3/jTreeMaintenanceInterface.java
index ca9e2d4b5d1af8824f4bbe946492280093d7809d..ee319973b02ec3b01a1e5f79c2180c2f0eb9519e 100644
--- a/SAS/OTB/jOTDB3/src/nl/astron/lofar/sas/otb/jotdb3/jTreeMaintenanceInterface.java
+++ b/SAS/OTB/jOTDB3/src/nl/astron/lofar/sas/otb/jotdb3/jTreeMaintenanceInterface.java
@@ -149,6 +149,10 @@ public interface jTreeMaintenanceInterface extends Remote
     public boolean exportResultTree (int aTreeID,int topItem,String filename) throws RemoteException;
     //# --- Finally some general tree maintenance ---
     // Delete a tree (of any kind) from the database.
+    
+    // Export all reported metadata from the given VIC tree
+    public boolean exportMetadata (int	aTreeID,String filename) throws RemoteException;
+    
     public boolean deleteTree (int aTreeID) throws RemoteException;
 
     // Retrieve the topNode of any tree
diff --git a/SAS/OTB/jOTDB3/src/nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance.cc b/SAS/OTB/jOTDB3/src/nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance.cc
index f2c0607c9e4fce2a0b4fd41f06354d73b093c428..1630f03295a940a38b1ea6b88d4b57f82091be74 100644
--- a/SAS/OTB/jOTDB3/src/nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance.cc
+++ b/SAS/OTB/jOTDB3/src/nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance.cc
@@ -944,6 +944,27 @@ JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_
   return succes;
 }
 
+/*
+ * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
+ * Method:    exportMetadata
+ * Signature: (ILjava/lang/String;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance_exportMetadata(JNIEnv *env, jobject jTreeMaintenance, jint treeID, jstring aName) {
+  jboolean isCopy(0);
+  jboolean succes(0);
+  const char* name = env->GetStringUTFChars (aName, &isCopy);
+  try {
+    succes = ((TreeMaintenance*)getCObjectPtr(env,jTreeMaintenance,"_TreeMaintenance"))->exportMetadata (treeID, name);
+    env->ReleaseStringUTFChars (aName, name);
+  } catch (exception &ex) {
+    cout << "Exception during TreeMaintenance::exportMetadata(" << treeID << "," << name <<   ") "<< ex.what() << endl;
+    env->ReleaseStringUTFChars (aName, name);
+    env->ThrowNew(env->FindClass("java/lang/Exception"),ex.what());
+  }
+
+  return succes;
+}
+
 /*
  * Class:     nl_astron_lofar_sas_otb_jotdb3_jTreeMaintenance
  * Method:    deleteTree
diff --git a/SAS/OTB/pom.xml b/SAS/OTB/pom.xml
index 45775c4a89ed2ca194f5822ff0a6ba387c8f1eac..e2eb55cc86abc275bab6ab985a6c5ede7f831baf 100644
--- a/SAS/OTB/pom.xml
+++ b/SAS/OTB/pom.xml
@@ -22,7 +22,7 @@
   <!-- Properties that can be used throughout the POM as a substitution, 
     and are used as filters in resources if enabled. -->
   <properties>
-    <lofar.lib.version>1.9.0</lofar.lib.version>
+    <lofar.lib.version>1.10.0</lofar.lib.version>
   </properties>
 
 
diff --git a/SAS/OTDB/include/OTDB/TreeMaintenance.h b/SAS/OTDB/include/OTDB/TreeMaintenance.h
index 8d57d8223ea258f1774286a5b0198e908af31e2d..a75d963d85b223c99d933012e373c53e965e12de 100644
--- a/SAS/OTDB/include/OTDB/TreeMaintenance.h
+++ b/SAS/OTDB/include/OTDB/TreeMaintenance.h
@@ -190,6 +190,10 @@ public:
 							  nodeIDType		topItem,
 							  const string&		filename);
 
+	// Export all reported metadata from the given VIC tree
+	bool	exportMetadata (treeIDType			aTreeID,
+					  		const string&		filename);
+
 	//# --- Finally some general tree maintenance ---
 	// Delete a tree (of any kind) from the database.
 	bool		deleteTree(treeIDType		aTreeID);
diff --git a/SAS/OTDB/sql/create_OTDB.sql b/SAS/OTDB/sql/create_OTDB.sql
index 019f16400d1de7fc814c920131d3ab762700b9a8..ac7c834daded9505e135327b6fdc9e9e99d56aae 100644
--- a/SAS/OTDB/sql/create_OTDB.sql
+++ b/SAS/OTDB/sql/create_OTDB.sql
@@ -64,6 +64,7 @@
 \i getVHitemList_func.sql
 \i exportTree_func.sql
 \i exportResultTree_func.sql
+\i exportMetadata_func.sql
 \i searchVHinPeriod_func.sql
 \i setSchedule_func.sql
 
diff --git a/SAS/OTDB/sql/create_base_tables.sql b/SAS/OTDB/sql/create_base_tables.sql
index 3e204e95382ba36cbd4fed039524a6fcd9842a3d..ad1f6f228d0fdb109ddb22b0a39070c268869b9c 100644
--- a/SAS/OTDB/sql/create_base_tables.sql
+++ b/SAS/OTDB/sql/create_base_tables.sql
@@ -252,6 +252,7 @@ INSERT INTO treestate VALUES (350, 'prescheduled');
 INSERT INTO treestate VALUES (400, 'scheduled');
 INSERT INTO treestate VALUES (500, 'queued');
 INSERT INTO treestate VALUES (600, 'active');
+INSERT INTO treestate VALUES (900, 'completing');
 INSERT INTO treestate VALUES (1000, 'finished');
 INSERT INTO treestate VALUES (1100, 'aborted');
 INSERT INTO treestate VALUES (1150, 'error');
diff --git a/SAS/OTDB/sql/exportMetadata_func.sql b/SAS/OTDB/sql/exportMetadata_func.sql
new file mode 100644
index 0000000000000000000000000000000000000000..49c51727cbfc2460bb13290fc74bff9249bf40be
--- /dev/null
+++ b/SAS/OTDB/sql/exportMetadata_func.sql
@@ -0,0 +1,57 @@
+--
+--  exportMetadata.sql: makes an usenet format export of all Metadata info from a tree
+--
+--  Copyright (C) 2013
+--  ASTRON (Netherlands Foundation for Research in Astronomy)
+--  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+--
+--  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; either version 2 of the License, or
+--  (at your option) any later version.
+--
+--  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 this program; if not, write to the Free Software
+--  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+--
+--  $Id: exportTree_func.sql 20032 2012-02-07 07:10:34Z overeem $
+--
+
+--
+-- exportMetadata (treeID)
+--
+-- Makes a key-value list of all kvt values of a VIC tree
+--
+-- Authorisation: no
+--
+-- Tables:	VICkvt	read
+--
+-- Types:	none
+--
+CREATE OR REPLACE FUNCTION exportMetadata(INT4)
+  RETURNS TEXT AS $$
+    --  $Id: addComponentToVT_func.sql 19935 2012-01-25 09:06:14Z mol $
+	DECLARE
+		vResult			TEXT;
+		vRecord			RECORD;
+		vTreeID			ALIAS FOR $1;
+
+	BEGIN
+	  vResult := '';
+	  FOR vRecord IN
+		SELECT treeid,paramname,value,time
+		FROM   VICkvt
+		WHERE  treeID = vTreeID
+		ORDER BY paramname, time ASC
+		LOOP
+		  vResult := vResult || vRecord.paramname || '=' || vRecord.value || chr(10);
+		END LOOP;
+		RETURN vResult;
+	END;
+$$ LANGUAGE plpgsql;
+
diff --git a/SAS/OTDB/sql/getTreeGroup_func.sql b/SAS/OTDB/sql/getTreeGroup_func.sql
index c5e8b287a1011f2e842b5252582e43569b46b4ea..d154c4a9682ee9c21575dff5424498abdb9b4bf9 100644
--- a/SAS/OTDB/sql/getTreeGroup_func.sql
+++ b/SAS/OTDB/sql/getTreeGroup_func.sql
@@ -49,6 +49,7 @@ CREATE OR REPLACE FUNCTION getTreeGroup(INT, INT)
 		TSapproved		CONSTANT	INT2 := 300;
 		TSscheduled		CONSTANT	INT2 := 400;
 		TSqueued		CONSTANT	INT2 := 500;
+--		TScompleting	CONSTANT	INT2 := 900;
 		TSfinished		CONSTANT	INT2 := 1000;
 		TThierarchy		CONSTANT	INT2 := 30;
 		TCoperational	CONSTANT	INT2 := 3;
@@ -71,18 +72,18 @@ CREATE OR REPLACE FUNCTION getTreeGroup(INT, INT)
 		    vQuery := vQuery || ' AND t.state > ' || TSscheduled;
 		    vQuery := vQuery || ' AND t.state < ' || TSfinished;
 	      ELSE 
-                    IF $1 = 3 THEN
-                          vQuery := ' AND t.state >= ' || TSfinished;
-                          vQuery := vQuery || ' AND t.stoptime > now()-interval ' || chr(39) || $2 || ' minutes' || chr(39);
-                          vSortOrder := 't.stoptime, t.treeID';
-                ELSE
+            IF $1 = 3 THEN
+              vQuery := ' AND t.state >= ' || TSfinished;
+              vQuery := vQuery || ' AND t.stoptime > now()-interval ' || chr(39) || $2 || ' minutes' || chr(39);
+              vSortOrder := 't.stoptime, t.treeID';
+            ELSE
 		      IF $1 = 4 THEN
 		  	    vQuery := ' AND t.state >= ' || TSapproved;
 			    vQuery := vQuery || ' AND t.stoptime < now() ';
 			    vSortOrder := 't.treeID';
 		      ELSE
 			    RAISE EXCEPTION 'groupType must be 0,1,2,3 or 4 not %', $1;
-                      END IF;
+              END IF;
 		    END IF;
 		  END IF;
 	    END IF;
diff --git a/SAS/OTDB/sql/getVTitem_func.sql b/SAS/OTDB/sql/getVTitem_func.sql
index bf7a50c51dc50a481012e363e22d86a1b55e1382..aa9e3b7b0a0d962122337383c6d7df782cd7608b 100644
--- a/SAS/OTDB/sql/getVTitem_func.sql
+++ b/SAS/OTDB/sql/getVTitem_func.sql
@@ -76,7 +76,8 @@ CREATE OR REPLACE FUNCTION getVTitemRecursive(INT4, VARCHAR(150), INT4)
         FROM   VICtemplate
         WHERE  treeID = $1
         AND    name   = vParentName
-	AND    (index::VARCHAR(50) = vIndex OR index::VARCHAR(50) = vIndex2);
+		AND    (index::VARCHAR(50) = vIndex OR index::VARCHAR(50) = vIndex2)
+        ORDER BY index;
       ELSE
         SELECT nodeid,
                parentid,
@@ -91,8 +92,9 @@ CREATE OR REPLACE FUNCTION getVTitemRecursive(INT4, VARCHAR(150), INT4)
         FROM   VICtemplate
         WHERE  treeID = $1
         AND    name   = vParentName
-	    AND    (index::VARCHAR(50) = vIndex OR index::VARCHAR(50) = vIndex2)
-        AND    parentid = aParentID;
+		AND    (index::VARCHAR(50) = vIndex OR index::VARCHAR(50) = vIndex2)
+        AND    parentid = aParentID
+		ORDER BY index;
 	  END IF;
 
 	  IF FOUND AND NOT vChildName IS NULL THEN
diff --git a/SAS/OTDB/sql/misc_func.sql b/SAS/OTDB/sql/misc_func.sql
index ceb3f5327380dd732706d7e277af53f4827449b2..453140a226882c776ebaf366cbe567cadd165dc7 100644
--- a/SAS/OTDB/sql/misc_func.sql
+++ b/SAS/OTDB/sql/misc_func.sql
@@ -129,9 +129,9 @@ CREATE OR REPLACE FUNCTION VersionNrValue(VARCHAR(50))
 		vPatch			INT4;
 				
 	BEGIN
-		vRelease := substring($1 from '([0-9]+)\.[0-9]+\.[0-9]+');
-		vUpdate  := substring($1 from '[0-9]+\.([0-9]+)\.[0-9]+');
-		vPatch   := substring($1 from '[0-9]+\.[0-9]+\.([0-9]+)');
+		vRelease := substring($1 from E'([0-9]+)\.[0-9]+\.[0-9]+');
+		vUpdate  := substring($1 from E'[0-9]+\.([0-9]+)\.[0-9]+');
+		vPatch   := substring($1 from E'[0-9]+\.[0-9]+\.([0-9]+)');
 		
 		RETURN vRelease * 10000 + (vUpdate%100)*100 + vPatch%100;
 	END;
diff --git a/SAS/OTDB/sql/setDescription_func.sql b/SAS/OTDB/sql/setDescription_func.sql
index d9e9a597c57c648ab83f7be2ff56f4ae0969a856..2bbda61ffcfe71cfc5c2b0d1bb3817f13454980c 100644
--- a/SAS/OTDB/sql/setDescription_func.sql
+++ b/SAS/OTDB/sql/setDescription_func.sql
@@ -32,7 +32,7 @@
 -- Types:	none
 --
 CREATE OR REPLACE FUNCTION setDescription(INT4, INT4, TEXT)
-  RETURNS BOOLEAN AS '
+  RETURNS BOOLEAN AS $$
     --  $Id$
 	DECLARE
 		vFunction				INT2 := 1;
@@ -47,16 +47,17 @@ CREATE OR REPLACE FUNCTION setDescription(INT4, INT4, TEXT)
 		SELECT isAuthorized(vAuthToken, $2, vFunction, 0) 
 		INTO   vIsAuth;
 		IF NOT vIsAuth THEN
-			RAISE EXCEPTION \'Not authorized.\';
+			RAISE EXCEPTION 'Not authorized.';
 			RETURN FALSE;
 		END IF;
 
 		-- update the tree
-		vDescription := replace($3, \'\\\'\', \'\');
+		vDescription := replace($3, E'\\\'', E'');
+		-- vDescription := replace($3, \'\\\'\', \'\');
 		UPDATE	OTDBtree
 		SET		description = vDescription
 		WHERE	treeID = $2;
 
 		RETURN TRUE;
 	END;
-' LANGUAGE plpgsql;
+$$ LANGUAGE plpgsql;
diff --git a/SAS/OTDB/sql/updateVTnode_func.sql b/SAS/OTDB/sql/updateVTnode_func.sql
index b47ea4ffd95c10e2ef8693a489310541fa69f615..bd80cdafda3b252ededfa392e157e44a9dc0c631 100644
--- a/SAS/OTDB/sql/updateVTnode_func.sql
+++ b/SAS/OTDB/sql/updateVTnode_func.sql
@@ -35,7 +35,7 @@
 -- Types:	OTDBnode
 --
 CREATE OR REPLACE FUNCTION updateVTnode(INT4, INT4, INT4, INT2, TEXT)
-  RETURNS BOOLEAN AS '
+  RETURNS BOOLEAN AS $$
     --  $Id$
 	DECLARE
 		TTtemplate  CONSTANT	INT2 := 20;
@@ -52,7 +52,7 @@ CREATE OR REPLACE FUNCTION updateVTnode(INT4, INT4, INT4, INT2, TEXT)
 		SELECT isAuthorized(vAuthToken, $2, vFunction, 0) 
 		INTO   vIsAuth;
 		IF NOT vIsAuth THEN
-			RAISE EXCEPTION \'Not authorized\';
+			RAISE EXCEPTION 'Not authorized';
 			RETURN FALSE;
 		END IF;
 
@@ -62,36 +62,36 @@ CREATE OR REPLACE FUNCTION updateVTnode(INT4, INT4, INT4, INT2, TEXT)
 		FROM	OTDBtree
 		WHERE	treeID = $2;
 		IF NOT FOUND THEN
-		  RAISE EXCEPTION \'Tree % does not exist\', $1;
+		  RAISE EXCEPTION 'Tree % does not exist', $1;
 		END IF;
 
 		IF vTreeType = TTtemplate THEN
 			-- get ParentID of node to duplicate
-			vLimits := replace($5, \'\\\'\', \'\');
+			vLimits := replace($5, E'\\\'', E'');
 			UPDATE	VICtemplate
 			SET		instances = $4,
 					limits    = vLimits
 			WHERE	treeID = $2
 			AND 	nodeID = $3;
 			IF NOT FOUND THEN
-			  RAISE EXCEPTION \'Node % of template-tree could not be updated\', $3;
+			  RAISE EXCEPTION 'Node % of template-tree could not be updated', $3;
 			  RETURN FALSE;
 			END IF;
 		ELSEIF vTreeType = TThierarchy THEN
-			vLimits := replace($5, \'\\\'\', \'\');
+			vLimits := replace($5, E'\\\'', E'');
 			UPDATE	VIChierarchy
-			SET		value = vLimits
+			SET	value = vLimits
 			WHERE	treeID = $2
 			AND 	nodeID = $3;
 			IF NOT FOUND THEN
-			  RAISE EXCEPTION \'Node % of VIC-tree could not be updated\', $3;
+			  RAISE EXCEPTION 'Node % of VIC-tree could not be updated', $3;
 			  RETURN FALSE;
 			END IF;
 		ELSE
-			RAISE EXCEPTION \'Nodes of PIC trees can not be updated\';
+			RAISE EXCEPTION 'Nodes of PIC trees can not be updated';
 		END IF;
 
 		RETURN TRUE;
 	END;
-' LANGUAGE plpgsql;
+$$ LANGUAGE plpgsql;
 
diff --git a/SAS/OTDB/src/TreeMaintenance.cc b/SAS/OTDB/src/TreeMaintenance.cc
index 8445c95b2af593d818915d445839599cbd1083d9..9c44e093dff49e3ce5fb9e133a9b1dc01a5a1826 100644
--- a/SAS/OTDB/src/TreeMaintenance.cc
+++ b/SAS/OTDB/src/TreeMaintenance.cc
@@ -1023,6 +1023,49 @@ bool TreeMaintenance::exportResultTree (treeIDType			aTreeID,
 	return (false);
 }
 
+//
+// exportMetadata(treeID, filename): bool
+//
+// Export all Metadata of the given VIC tree
+//
+bool	TreeMaintenance::exportMetadata (treeIDType			aTreeID,
+										 const string&		filename)
+{
+	// Check connection
+	if (!itsConn->connect()) {
+		itsError = itsConn->errorMsg();
+		return (false);
+	}
+
+	LOG_TRACE_FLOW_STR("TM:exportMetadata(" << aTreeID << "," << filename << ")");
+
+	work	xAction(*(itsConn->getConn()), "exportMetadata");
+	try {
+		ofstream	outFile;
+		outFile.open (filename.c_str());
+		if (!outFile) {
+			LOG_ERROR_STR ("Cannot open exportfile: " << filename);
+			return (false);
+		}
+
+		result	res = xAction.exec("SELECT * from exportMetadata(" +
+									toString(aTreeID) + ")");
+		// Get result
+		string		params;
+		res[0]["exportmetadata"].to(params);
+		outFile << params;
+		outFile.close();
+		return (true);
+	}
+	catch (std::exception&	ex) {
+		itsError = string("Exception during exportMetadata:") + ex.what();
+		LOG_FATAL(itsError);
+		return (false);
+	}
+
+	return (false);
+}
+
 //# --- Finally some general tree maintenance ---
 // Delete a tree (of any kind) from the database.
 bool	TreeMaintenance::deleteTree(treeIDType		aTreeID)
diff --git a/SAS/OTDB/test/CMakeLists.txt b/SAS/OTDB/test/CMakeLists.txt
index 260c0ce9da6bae5405a0b7f3cc3ea69664b9ba77..688717095bdcbbba22f0a397d439d848546bedaf 100644
--- a/SAS/OTDB/test/CMakeLists.txt
+++ b/SAS/OTDB/test/CMakeLists.txt
@@ -11,5 +11,6 @@ lofar_add_test(tVICcomp tVICcomp.cc)
 lofar_add_test(tVTtree tVTtree.cc)
 lofar_add_test(tVHtree tVHtree.cc)
 lofar_add_test(tVHvalue tVHvalue.cc)
+lofar_add_executable(tMetadata tMetadata.cc)
 lofar_add_test(tConnection tConnection.cc)
 lofar_add_test(tParamTypeConv tParamTypeConv.cc)
diff --git a/SAS/OTDB/test/tCampaign.cc b/SAS/OTDB/test/tCampaign.cc
index 09604f66eb9277a1ef424a037183b4b722d1bd5a..2fc62047d491452a4b023481126f2b9e6fe3af14 100644
--- a/SAS/OTDB/test/tCampaign.cc
+++ b/SAS/OTDB/test/tCampaign.cc
@@ -111,9 +111,12 @@ int main (int	argc, char*	argv[]) {
 		showCampaignList(campList);
 		ASSERTSTR(campList.size(),"No campaign list found");
 
-		LOG_INFO("Adding 'my campaign'");
-		CampaignInfo	CI("my campaign", "campaign of me", "me", "no-one", "also me");
+		LOG_INFO("Adding 'ruud's campaign'");
+		CampaignInfo	CI("ruud's campaign", "campaign of me", "me", "no-one", "also me");
+		LOG_INFO_STR(CI);
 		LOG_INFO_STR("new recordID = " << camp.saveCampaign(CI));
+		LOG_INFO("AFTER SAVECAMPAIGN");
+#if 0
 		campList = camp.getCampaignList();
 		showCampaignList(campList);
 		ASSERTSTR(campList.size(),"No campaign list found");
@@ -134,6 +137,7 @@ int main (int	argc, char*	argv[]) {
 		showCampaignList(campList);
 		ASSERTSTR(campList.size(),"No campaign list found");
 
+#endif
 #if 0		
 		LOG_INFO("Trying to change the state of the tree to active(400)");
 		bool 	actionOK = tm.setTreeState(treeID, TSconv.get("active"));
diff --git a/SAS/OTDB/test/tMetadata.cc b/SAS/OTDB/test/tMetadata.cc
new file mode 100644
index 0000000000000000000000000000000000000000..1b0d6bca001898f97c3b203d05673d20894e2d86
--- /dev/null
+++ b/SAS/OTDB/test/tMetadata.cc
@@ -0,0 +1,81 @@
+//#  tMetadata: test the maintenance actions on the VH trees
+//#
+//#  Copyright (C) 2002-2004
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  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; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  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 this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  $Id: tVHtree.cc 23213 2012-12-07 13:00:09Z loose $
+
+//# Always #include <lofar_config.h> first!
+#include <lofar_config.h>
+
+//# Includes
+#include <Common/LofarLogger.h>
+#include <Common/lofar_fstream.h>
+#include <Common/StringUtil.h>
+#include <OTDB/TreeMaintenance.h>
+#include <OTDB/OTDBtypes.h>
+#include <OTDB/OTDBnode.h>
+#include <OTDB/OTDBparam.h>
+#include <libgen.h>             // for basename
+#include <cstring>
+
+
+using namespace LOFAR;
+using namespace LOFAR::OTDB;
+
+int main (int	argc, char*	argv[]) {
+
+	INIT_LOGGER(basename(argv[0]));
+	LOG_INFO_STR("Starting " << argv[0]);
+
+	if (argc != 3) {
+		cout << "Usage: tMetadata databasename VicTreeID " << endl;
+		return (1);
+	}
+
+	// try to resolve the database name
+	string 		dbName(argv[1]);
+	string		hostName("rs005.astron.nl");
+
+	// Open the database connection
+	OTDBconnection conn("paulus", "boskabouter", dbName, hostName);
+
+	try {
+
+		LOG_INFO("Trying to connect to the database");
+		ASSERTSTR(conn.connect(), "Connnection failed");
+		LOG_INFO_STR("Connection succesful: " << conn);
+
+		LOG_INFO("Trying to construct a TreeMaintenance object");
+		TreeMaintenance	tm(&conn);
+	
+		int		treeID  (atoi(argv[2]));
+		string 	filename(formatString("MD%d.txt", treeID));
+		LOG_INFO_STR("Creating metadatafile '" << filename << "'");
+		tm.exportMetadata(treeID, filename);
+
+	}
+	catch (std::exception&	ex) {
+		LOG_FATAL_STR("Unexpected exception: " << ex.what());
+		return (1);		// return !0 on failure
+	}
+
+	LOG_INFO_STR ("Terminated succesfully: " << argv[0]);
+
+	return (0);		// return 0 on succes
+}
diff --git a/SAS/OTDB/test/tVHvalue.in b/SAS/OTDB/test/tVHvalue.in
index 4ba78ba1c182f9414fe8a813fc2e3659c646b0c7..e0b5a4d6cd5d8a874ee59718186824519e58ede2 100644
--- a/SAS/OTDB/test/tVHvalue.in
+++ b/SAS/OTDB/test/tVHvalue.in
@@ -1,7 +1,7 @@
-TopNode.Observation.Virt Telescope.Rec Group.GFLOPS=2.0
-TopNode.Observation.Virt Telescope.Rec Group.GFLOPS{31536000}=2.5
-TopNode.Observation.Virt Telescope.Beamformer.Angle{1003456789}=0
-TopNode.Observation.Virt Telescope.Beamformer.Angle{1033456789}=1
-TopNode.Observation.Virt Telescope.Beamformer.Angle{1063456789}=3
-TopNode.Observation.Virt Telescope.Beamformer.Angle{1093456789}=5
-TopNode.Observation.Virt Telescope.Beamformer.Angle{1123456789}=7
+TopNode.Observation.Virt Telescope[0].Rec Group.GFLOPS=2.0
+TopNode.Observation.Virt Telescope[0].Rec Group.GFLOPS{31536000}=2.5
+TopNode.Observation.Virt Telescope[0].Beamformer.Angle{1003456789}=0
+TopNode.Observation.Virt Telescope[0].Beamformer.Angle{1033456789}=1
+TopNode.Observation.Virt Telescope[0].Beamformer.Angle{1063456789}=3
+TopNode.Observation.Virt Telescope[0].Beamformer.Angle{1093456789}=5
+TopNode.Observation.Virt Telescope[0].Beamformer.Angle{1123456789}=7