diff --git a/.gitattributes b/.gitattributes
index bb4c77520ee86bc87430f9a5c454fb3477208235..8f36f63767cdda3b82e97ec6cfc5c84950f3fa35 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -71,6 +71,7 @@ CEP/BB/BBSKernel/test/tParmMerge.in_mep2/table.f0 -text svneol=unset#unset
 CEP/BB/BBSKernel/test/tParmMerge.in_mep2/table.f0i -text svneol=unset#unset
 CEP/BB/BBSKernel/test/tParmMerge.in_mep2/table.lock -text svneol=unset#unset
 CEP/BB/BB_GUI/make_jar.sh -text svneol=native#application/octet-stream
+CEP/BB/SourceDB/bootstrap -text
 CEP/CPA/PSS3/CAL/src/TEST.MEP/InitialValues/table.dat -text svneol=unset#unset
 CEP/CPA/PSS3/CAL/src/TEST.MEP/InitialValues/table.f0 -text svneol=unset#unset
 CEP/CPA/PSS3/CAL/src/TEST.MEP/InitialValues/table.f0i -text svneol=unset#unset
diff --git a/CEP/BB/SourceDB/Makefile.am b/CEP/BB/SourceDB/Makefile.am
new file mode 100644
index 0000000000000000000000000000000000000000..8e2f1e0543eedb242a0edf52e7b6fcf029c58fb8
--- /dev/null
+++ b/CEP/BB/SourceDB/Makefile.am
@@ -0,0 +1,14 @@
+SUBDIRS=src test include
+
+pkgextdir     = $(prefix)/config/$(PACKAGE)
+pkgext_DATA   = pkgext pkgextcppflags pkgextcxxflags pkgextldflags
+
+DISTCHECK_CONFIGURE_FLAGS=\
+      --with-common=$(prefix)
+
+EXTRA_DIST = \
+      Makefile.common \
+      SourceDB.spec \
+      autoconf_share/compiletool
+
+include $(top_srcdir)/Makefile.common
diff --git a/CEP/BB/SourceDB/bootstrap b/CEP/BB/SourceDB/bootstrap
new file mode 100755
index 0000000000000000000000000000000000000000..06f18cde1dbfd6912ef7d927c4d35d25c7137a62
--- /dev/null
+++ b/CEP/BB/SourceDB/bootstrap
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+../../../autoconf_share/bootstrap ../../../autoconf_share
diff --git a/CEP/BB/SourceDB/configure.in b/CEP/BB/SourceDB/configure.in
new file mode 100644
index 0000000000000000000000000000000000000000..9c5337f52ed9a53cffd1506355a306c29a0a9a1f
--- /dev/null
+++ b/CEP/BB/SourceDB/configure.in
@@ -0,0 +1,72 @@
+dnl
+dnl Process this file with autoconf to produce a configure script.
+dnl
+AC_INIT
+dnl AC_CONFIG_AUX_DIR(config)
+dnl AM_CONFIG_HEADER(config/config.h)
+AM_CONFIG_HEADER(config.h)
+AM_INIT_AUTOMAKE(SourceDB, 1.0, no-define)
+
+dnl Initialize for LOFAR (may set compilers)
+lofar_INIT
+
+dnl Checks for programs.
+AC_PROG_AWK
+AC_PROG_YACC
+AC_PROG_CC
+AC_PROG_CXX
+AM_PROG_LEX
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_DISABLE_SHARED
+AC_PROG_LIBTOOL
+
+dnl Checks for libraries.
+
+dnl dnl Replace `main' with a function in -lfl:
+dnl AC_CHECK_LIB(fl, main)
+dnl dnl Replace `main' with a function in -lcosev_r:
+dnl AC_CHECK_LIB(cosev_r, main)
+dnl dnl Replace `main' with a function in -lcosnm_r:
+dnl AC_CHECK_LIB(cosnm_r, main)
+dnl dnl Replace `main' with a function in -lorb_r:
+dnl AC_CHECK_LIB(orb_r, main)
+dnl dnl Replace `main' with a function in -lpthread:
+dnl AC_CHECK_LIB(pthread, main)
+dnl dnl Replace `main' with a function in -lvport_r:
+dnl AC_CHECK_LIB(vport_r, main)
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS(unistd.h)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_TYPE_SIZE_T
+
+dnl Checks for library functions.
+AC_FUNC_VPRINTF
+
+dnl
+dnl Check for LOFAR specific things
+dnl
+lofar_GENERAL
+lofar_INTERNAL(LCS/Blob,Blob,,1,Blob/BlobHeader.h)
+lofar_INTERNAL(LCS/Common,Common,,1,Common/LofarTypedefs.h,,)
+lofar_INTERNAL(CEP/BB/ParmDB,ParmDB,,1,ParmDB/ParmDB.h,,)
+lofar_AIPSPP(1,"-lmeasures -ltables -lscimath -lscimath_f -lcasa")
+
+lofar_EXTERNAL(pgsql,0,libpq-fe.h,pq)
+lofar_EXTERNAL(pqxx,0,pqxx/pqxx, pqxx)
+
+dnl
+dnl Output Makefiles
+dnl
+AC_OUTPUT(
+include/Makefile
+include/SourceDB/Makefile
+src/Makefile
+test/Makefile
+Makefile
+SourceDB.spec
+)
diff --git a/CEP/BB/SourceDB/include/Makefile.am b/CEP/BB/SourceDB/include/Makefile.am
new file mode 100644
index 0000000000000000000000000000000000000000..42f6a78d4d49b930e5702bfaf30efcaeebe9ac62
--- /dev/null
+++ b/CEP/BB/SourceDB/include/Makefile.am
@@ -0,0 +1,3 @@
+SUBDIRS	= SourceDB
+
+include $(top_srcdir)/Makefile.common
diff --git a/CEP/BB/SourceDB/include/SourceDB/Makefile.am b/CEP/BB/SourceDB/include/SourceDB/Makefile.am
new file mode 100644
index 0000000000000000000000000000000000000000..2d670f71e99e3cf3c9fb596d222a6d2d3ea47819
--- /dev/null
+++ b/CEP/BB/SourceDB/include/SourceDB/Makefile.am
@@ -0,0 +1,15 @@
+INSTHDRS = \
+SourceValue.h SourceDBMeta.h \
+SourceDB.h SourceDBAIPS.h 
+
+NOINSTHDRS =
+
+TCCHDRS =
+
+pkginclude_HEADERS = Package__Version.h  $(INSTHDRS) $(TCCHDRS)
+
+noinst_HEADERS = $(NOINSTHDRS)
+
+DOCHDRS = $(INSTHDRS) $(NOINSTHDRS)
+
+include $(top_srcdir)/Makefile.common
diff --git a/CEP/BB/SourceDB/include/SourceDB/SourceDB.h b/CEP/BB/SourceDB/include/SourceDB/SourceDB.h
new file mode 100644
index 0000000000000000000000000000000000000000..82254c07e1e6918f8e5f81653515fc078b618a63
--- /dev/null
+++ b/CEP/BB/SourceDB/include/SourceDB/SourceDB.h
@@ -0,0 +1,253 @@
+//# SourceDB.h: Abstract base class to hold sources in a data base.
+//#
+//# Copyright (C) 2008
+//# 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 LOFAR_SOURCEDB_SOURCEDB_H
+#define LOFAR_SOURCEDB_SOURCEDB_H
+
+// \file
+// Abstract base class to hold sources in a table.
+
+//# Includes
+#include <SourceDB/SourceValue.h>
+#include <SourceDB/SourceDBMeta.h>
+#include <ParmDB/ParmDB.h>
+#include <list>
+#include <vector>
+
+
+namespace LOFAR {
+namespace SourceDB {
+
+//# Forward Declarations.
+class SourceDB;
+
+// \ingroup SourceDB
+// @{
+
+class SourceDBRep
+{
+public:
+  SourceDBRep()
+    : itsCount(0)
+  {}
+
+  virtual ~SourceDBRep();
+
+  // Link to the DBRep by incrementing the count.
+  void link()
+    { itsCount++; }
+
+  // Unlink by decrementing the count.
+  int unlink()
+    { return --itsCount; }
+
+  // Writelock and unlock the database tables.
+  // The user does not need to lock/unlock, but it can increase performance
+  // if many small accesses have to be done.
+  // The default implementation does nothing.
+  // <group>
+  virtual void lock (bool lockForWrite);
+  virtual void unlock();
+  // </group>
+
+  // Get the sources with the given names.
+  // If the vector is empty, all names are retrieved.
+  virtual std::list<SourceValue> getSources
+                     (const std::vector<std::string>& sourceNames,
+		      const ParmDB::ParmDomain&) = 0;
+
+  // Get the sources in a circle around the given position.
+  // The position and radius have to be given in radians.
+  virtual std::list<SourceValue> getSources (double ra, double dec,
+					     double radius,
+					     const ParmDB::ParmDomain&) = 0;
+
+  // Add the given sources.
+  virtual void addSources (const std::list<SourceValue>& values) = 0;
+
+  // Update the values of the given source.
+  // It will check that it already exists.
+  virtual void updateSource (const SourceValue& value) = 0;
+
+  // Delete the given source record.
+  virtual void deleteSource (const SourceValue&) = 0;
+
+  // Delete the sources matching the given (filename like) pattern.
+  virtual void deleteSources (const std::string& sourceNamePattern,
+			      const ParmDB::ParmDomain&) = 0;
+
+  // Get the names of all sources matching the given (filename like) pattern.
+  virtual std::vector<std::string> getNames (const std::string& pattern) = 0;
+
+  // Clear the source data base tables.
+  virtual void clearTables() = 0;
+
+  // Find matching records from the other data base in this one.
+  // The records of other are written into the appropriate result data base.
+  // Also the matching records of this are written.
+  // This is useful to merge an LSM back into the GSM.
+  // Before doing the actual merge, the matches and non-matches can be
+  // inspected and possibly moved from match to non-match or vice-versa.
+  virtual void match (const SourceDB& other,
+		      SourceDB& match, SourceDB& nonMatch) = 0;
+
+  // Merge the other source data base into this one.
+  virtual void merge (const SourceDB& otherMatch,
+		      const SourceDB& otherNonMatch) = 0;
+
+  // Set or get the name and type.
+  // <group>
+  void setSourceDBMeta (const SourceDBMeta& ptm)
+    { itsPTM = ptm; }
+  const SourceDBMeta& getSourceDBMeta() const
+    { return itsPTM; }
+  // </group>
+
+private:
+  int          itsCount;
+  SourceDBMeta itsPTM;
+};
+
+
+  // Actions to perform on source DB:
+  //   get one or more sources based on name or cone
+  //   get A-team
+  //   match 2 catalogs
+  //   extract LSM from GSM
+  //   merge LSM back into GSM
+  //   generate ParmDB from LSM
+  //   update LSM from ParmDB
+  //   add/delete/update sources in LSM
+class SourceDB
+{
+public:
+  // Create or open the SourceDB object for the given database type.
+  // It is created if not existing or if forceNew=true.
+  explicit SourceDB (const SourceDBMeta& ptm, bool forceNew=false);
+
+  // Copy contructor has reference semantics.
+  SourceDB (const SourceDB&);
+
+  // Delete underlying object if no more references to it.
+  ~SourceDB()
+    { decrCount(); }
+
+  // Assignment has reference semantics.
+  SourceDB& operator= (const SourceDB&);
+
+  // Lock and unlock the database tables.
+  // The user does not need to lock/unlock, but it can increase performance
+  // if many small accesses have to be done.
+  // <group>
+  void lock (bool lockForWrite = true)
+    { itsRep->lock (lockForWrite); }
+  void unlock()
+    { itsRep->unlock(); }
+
+  // Get the sources with the given names.
+  // If the vector is empty, all names are retrieved.
+  std::list<SourceValue> getSources
+                  (const std::vector<std::string>& sourceNames,
+		   const ParmDB::ParmDomain& domain)
+    { return itsRep->getSources (sourceNames, domain); }
+
+  // Get the sources in a circle around the given position.
+  // The position and radius have to be given in radians.
+  std::list<SourceValue> getSources (double ra, double dec, double radius,
+				     const ParmDB::ParmDomain& domain)
+    { return itsRep->getSources (ra, dec, radius, domain); }
+
+  // Add the given sources.
+  void addSources (std::list<SourceValue> values)
+    { itsRep->addSources (values); }
+
+  // Add a single given source.
+  void addSource (const SourceValue& value);
+
+  // Update the values of the given source.
+  // It will check that it already exists.
+  void updateSource (const SourceValue& value)
+    { itsRep->updateSource (value); }
+
+  // Delete the given source record.
+  // Nothing is done if not found.
+  void deleteSource (const SourceValue& sourceValue)
+    { itsRep->deleteSource (sourceValue); }
+
+  // Delete the sources matching the given (filename like) pattern.
+  // Nothing is done if none found.
+  void deleteSources (const std::string& sourceNamePattern,
+		      const ParmDB::ParmDomain& domain)
+    { itsRep->deleteSources (sourceNamePattern, domain); }
+
+  // Get the names of all sources matching the given (filename like) pattern.
+  std::vector<std::string> getNames (const std::string& pattern)
+    { return itsRep->getNames (pattern); }
+
+  // Clear the source data base tables.
+  void clearTables()
+    { itsRep->clearTables(); }
+
+  // Find matching records from the other data base in this one.
+  // The records of other are written into the appropriate result data base.
+  // Also the matching records of this are written.
+  // This is useful to merge an LSM back into the GSM.
+  // Before doing the actual merge, the matches and non-matches can be
+  // inspected and possibly moved from match to non-match or vice-versa.
+  void match (const SourceDB& other, SourceDB& match, SourceDB& nonMatch)
+    { itsRep->match (other, match, nonMatch); }
+
+  // Merge the other source data base into this one.
+  void merge (const SourceDB& otherMatch, const SourceDB& otherNonMatch)
+    { itsRep->merge (otherMatch, otherNonMatch); }
+
+  // Create a parm data base from the source data base.
+  void createParmDB (ParmDB::ParmDB&);
+
+  // Merge a parm data base back into this source data base.
+  // It updates possibly changed parameters and adds new sources.
+  void mergeParmDB (const ParmDB::ParmDB&);
+
+private:
+  // Create a SourceDB object for an existing SourceDBRep.
+  SourceDB (SourceDBRep*);
+
+  // Decrement the refcount and delete if zero.
+  void decrCount();
+
+  // Put a single parameter.
+  void putParm (ParmDB::ParmDB& parmdb, ParmDB::ParmValue& pv,
+		const std::string& sourceName,
+		const std::string& parm,
+		const ParmDB::ParmDomain& domain,
+		double value, bool relativePert);
+
+  //# Data Members
+  SourceDBRep* itsRep;
+};
+
+// @}
+
+} // namespace SourceDB
+} // namespace LOFAR
+
+#endif
diff --git a/CEP/BB/SourceDB/include/SourceDB/SourceDBAIPS.h b/CEP/BB/SourceDB/include/SourceDB/SourceDBAIPS.h
new file mode 100644
index 0000000000000000000000000000000000000000..280c87a38c8604111be164ea6d3d6f0f65130ac6
--- /dev/null
+++ b/CEP/BB/SourceDB/include/SourceDB/SourceDBAIPS.h
@@ -0,0 +1,136 @@
+//# SourceDBAIPS.h: Class to hold sources in an AIPS++ table.
+//#
+//# Copyright (C) 2008
+//# 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 LOFAR_SOURCEDB_SOURCEDBAIPS_H
+#define LOFAR_SOURCEDB_SOURCEDBAIPS_H
+
+// \file
+// Class to hold sources in an AIPS++ table.
+
+//# Includes
+#include <SourceDB/SourceDB.h>
+#include <tables/Tables/Table.h>
+
+namespace LOFAR {
+namespace SourceDB {
+
+
+// \ingroup SourceDB
+// @{
+
+class SourceDBAIPS: public SourceDBRep
+{
+public:
+  SourceDBAIPS (const std::string& tableName, bool forceNew);
+
+  virtual ~SourceDBAIPS();
+
+  // Writelock and unlock the database tables.
+  // The user does not need to lock/unlock, but it can increase performance
+  // if many small accesses have to be done.
+  // The default implementation does nothing.
+  // <group>
+  virtual void lock (bool lockForWrite);
+  virtual void unlock();
+  // </group>
+
+  // Get the sources with the given names.
+  // If the vector is empty, all names are retrieved.
+  virtual std::list<SourceValue> getSources
+                     (const std::vector<std::string>& sourceNames,
+		      const ParmDB::ParmDomain&) ;
+
+  // Get the sources in a circle around the given position.
+  // The position and radius have to be given in radians.
+  virtual std::list<SourceValue> getSources (double ra, double dec,
+					     double radius,
+					     const ParmDB::ParmDomain&);
+
+  // Add the given sources.
+  virtual void addSources (const std::list<SourceValue>& values);
+
+  // Update the values of the given source.
+  // It will check that it already exists.
+  virtual void updateSource (const SourceValue& value);
+
+  // Delete the given source record.
+  virtual void deleteSource (const SourceValue&);
+
+  // Delete the sources matching the given (filename like) pattern.
+  virtual void deleteSources (const std::string& sourceNamePattern,
+			      const ParmDB::ParmDomain&);
+
+  // Get the names of all sources matching the given (filename like) pattern.
+  virtual std::vector<std::string> getNames (const std::string& pattern);
+
+  // Clear the source data base tables.
+  virtual void clearTables();
+
+  // Find matching records from the other data base in this one.
+  // The records of other are written into the appropriate result data base.
+  // Also the matching records of this are written.
+  // This is useful to merge an LSM back into the GSM.
+  // Before doing the actual merge, the matches and non-matches can be
+  // inspected and possibly moved from match to non-match or vice-versa.
+  virtual void match (const SourceDB& other,
+		      SourceDB& match, SourceDB& nonMatch);
+
+  // Merge the other source data base into this one.
+  virtual void merge (const SourceDB& otherMatch,
+		      const SourceDB& otherNonMatch);
+
+private:
+  // Create the tables.
+  void createTables (const std::string& tableName);
+
+  // Set the quantum units for a column.
+  void setQuant (casa::TableDesc& td, const casa::String& name,
+		 const casa::String& unit);
+
+  // Set the quantum units and measure Epoch for a column.
+  void setEpoch (casa::TableDesc& td, const casa::String& name);
+
+  // Append the source values from all rows in the table to the list.
+  void extractValues (std::list<SourceValue>& result, const casa::Table& tab);
+
+  // Put the source value into the given table row.
+  void putValue (casa::Table& tab, unsigned rownr, const SourceValue& pvalue);
+
+  // Create a select expression node on domain and parent id.
+  casa::TableExprNode makeExpr (const casa::Table& table,
+				const ParmDB::ParmDomain&) const;
+
+  // And two table select expressions, where the first one can be null.
+  void andExpr (casa::TableExprNode& expr,
+		const casa::TableExprNode& right) const;
+
+
+  //# Data members
+  casa::Table itsTable;
+};
+
+// @}
+
+} // namespace SourceDB
+} // namespace LOFAR
+
+#endif
diff --git a/CEP/BB/SourceDB/include/SourceDB/SourceDBMeta.h b/CEP/BB/SourceDB/include/SourceDB/SourceDBMeta.h
new file mode 100644
index 0000000000000000000000000000000000000000..14a6d770477e70171cfa346c02c054078435f982
--- /dev/null
+++ b/CEP/BB/SourceDB/include/SourceDB/SourceDBMeta.h
@@ -0,0 +1,92 @@
+//#  SourceDBMeta.h: one line description
+//#
+//#  Copyright (C) 2008
+//#  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 LOFAR_SOURCEDB_SOURCEDBMETA_H
+#define LOFAR_SOURCEDB_SOURCEDBMETA_H
+
+// \file
+// one line description.
+
+#include <Common/lofar_string.h>
+
+namespace LOFAR {
+//# Forward Declarations.
+class BlobOStream;
+class BlobIStream;
+
+namespace SourceDB {
+
+  // \addtogroup SourceDB
+  // @{
+
+  // Description of class.
+  class SourceDBMeta
+  {
+  public:
+    SourceDBMeta();
+
+    SourceDBMeta (const std::string& type, const std::string& tableName);
+
+    void setSQLMeta (const std::string& dbName, const std::string& userName,
+		     const std::string& dbPwd, const std::string& hostName);
+
+    const std::string& getType() const
+      { return itsType; }
+
+    const std::string& getTableName() const
+      { return itsTableName; }
+
+    const std::string& getDBName() const
+      { return itsDBName; }
+      
+    const std::string& getUserName() const
+      { return itsUserName; }
+      
+    const std::string& getDBPwd() const
+      { return itsDBPwd; }
+    
+    const std::string& getHostName() const
+      { return itsHostName; }
+    
+    // Write the object into a blob.
+    friend BlobOStream& operator<< (BlobOStream&, const SourceDBMeta&);
+
+    // Read the object from a blob.
+    friend BlobIStream& operator>> (BlobIStream&, SourceDBMeta&);
+
+  private:
+    //# Datamembers
+    std::string itsType;
+    std::string itsTableName;
+    // these options are used for sql databases
+    std::string itsDBName;
+    std::string itsUserName;
+    std::string itsDBPwd;
+    std::string itsHostName;
+  };
+
+  // @}
+
+} // namespace SourceDB
+} // namespace LOFAR
+
+#endif
diff --git a/CEP/BB/SourceDB/include/SourceDB/SourceValue.h b/CEP/BB/SourceDB/include/SourceDB/SourceValue.h
new file mode 100644
index 0000000000000000000000000000000000000000..4203ee4eb988955fe376a1370128b017e28861da
--- /dev/null
+++ b/CEP/BB/SourceDB/include/SourceDB/SourceValue.h
@@ -0,0 +1,131 @@
+//# SourceValue.h: The parameters of a single source
+//#
+//# Copyright (C) 2008
+//# 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 LOFAR_SOURCEDB_SOURCEVALUE_H
+#define LOFAR_SOURCEDB_SOURCEVALUE_H
+
+// \file
+// The parameters of a single source.
+
+//# Includes
+#include <ParmDB/ParmDomain.h>
+#include <string>
+#include <vector>
+
+namespace LOFAR {
+namespace SourceDB {
+
+// \ingroup SourceDB
+// @{
+
+// This class defines the parameters of a source.
+// The parameters can be frequency and time dependent.
+// By default the time and frequency range are infinite.
+
+class SourceValue
+{
+public:
+  // Create a default SourceValue object.
+  SourceValue();
+
+  // Set the various source parameters.
+  // <group>
+  void setPointSource (const std::string& name, double ra, double dec,
+		       double flux[4], double spectralIndex);
+  ///  void setGaussianSource ();
+  void setPos (double ra, double dec);
+  // </group>
+
+  // Set the domain.
+  // The domain can have 0, 1, or 2 axes (freq (Hz) and time (MJD seconds)).
+  void setDomain (const ParmDB::ParmDomain&);
+
+  // Set the frequency domain (in Hz) for which the parameters are valid.
+  void setFreqDomain (double startHz, double endHz);
+
+  // Set the time domain (in MJD seconds) for which the parameters are valid.
+  void setTimeDomain (double startMJD, double endMJD);
+
+  // Get the various source parameters.
+  // <group>
+  const std::string& getName() const
+    { return itsName; }
+  const std::string& getType() const
+    { return itsType; }
+  double getRA() const
+    { return itsRA; }
+  double getDEC() const
+    { return itsDEC; }
+  double getSpectralIndex() const
+    { return itsSpIndex; }
+  const double* getFlux() const
+    { return itsFlux; }
+  // </group>
+
+  // Get source parameters.
+  // <group>
+  void setRA (double ra)
+    { itsRA = ra; }
+  void setDEC (double dec)
+    { itsDEC = dec; }
+  void setFluxI (double flux)
+    { itsFlux[0] = flux; }
+  void setFluxQ (double flux)
+    { itsFlux[1] = flux; }
+  void setFluxU (double flux)
+    { itsFlux[2] = flux; }
+  void setFluxV (double flux)
+    { itsFlux[3] = flux; }
+  void setSpectralIndex (double spectralIndex)
+    { itsSpIndex = spectralIndex; }
+  // </group>
+
+  // Get the domain.
+  // <group>
+  const ParmDB::ParmDomain& getDomain() const
+    { return itsDomain; }
+  double getStartFreq() const
+    { return itsDomain.getStart()[0]; }
+  double getEndFreq() const
+    { return itsDomain.getEnd()[0]; }
+  double getStartTime() const
+    { return itsDomain.getStart()[1]; }
+  double getEndTime() const
+    { return itsDomain.getEnd()[1]; }
+  // </group>
+
+private:
+  std::string itsName;
+  std::string itsType;
+  double      itsRA;
+  double      itsDEC;
+  double      itsFlux[4];
+  double      itsSpIndex;
+  ParmDB::ParmDomain itsDomain;
+};
+
+// @}
+
+} // namespace SourceDB
+} // namespace LOFAR
+
+#endif
diff --git a/CEP/BB/SourceDB/src/Makefile.am b/CEP/BB/SourceDB/src/Makefile.am
new file mode 100644
index 0000000000000000000000000000000000000000..680a3471dfe33b2097417a321f8d27ec802b1fe8
--- /dev/null
+++ b/CEP/BB/SourceDB/src/Makefile.am
@@ -0,0 +1,27 @@
+lib_LTLIBRARIES         = libsourcedb.la
+
+libsourcedb_la_SOURCES = Package__Version.cc  \
+SourceValue.cc SourceDBMeta.cc \
+SourceDB.cc SourceDBAIPS.cc
+
+
+bin_PROGRAMS = versionsourcedb sourcedb
+
+versionsourcedb_SOURCES      = versionsourcedb.cc
+versionsourcedb_LDADD        = libsourcedb.la
+versionsourcedb_DEPENDENCIES = libsourcedb.la $(LOFAR_DEPEND)
+
+sourcedb_SOURCES	= sourcedb_main.cc
+sourcedb_LDADD		= libsourcedb.la
+sourcedb_DEPENDENCIES	= libsourcedb.la $(LOFAR_DEPEND)
+
+glishdir = $(libexecdir)/glish
+dist_glish_SCRIPTS = 
+
+pythondir = $(bindir)
+dist_python_SCRIPTS = 
+
+scriptdir = $(bindir)
+dist_script_SCRIPTS = 
+
+include $(top_srcdir)/Makefile.common
diff --git a/CEP/BB/SourceDB/src/SourceDB.cc b/CEP/BB/SourceDB/src/SourceDB.cc
new file mode 100644
index 0000000000000000000000000000000000000000..9b930e7a2e70ae1779f6ffcf34b04f67fe1fd968
--- /dev/null
+++ b/CEP/BB/SourceDB/src/SourceDB.cc
@@ -0,0 +1,161 @@
+//# SourceDB.cc: Class to hold source in a table.
+//#
+//# Copyright (C) 2008
+//# 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 <SourceDB/SourceDB.h>
+#include <SourceDB/SourceDBAIPS.h>
+#include <Common/LofarLogger.h>
+#include <casa/Utilities/Regex.h>
+#include <casa/Utilities/GenSort.h>
+
+using namespace std;
+using namespace casa;
+
+namespace LOFAR {
+namespace SourceDB {
+
+
+SourceDBRep::~SourceDBRep()
+{}
+
+void SourceDBRep::lock (bool)
+{}
+
+void SourceDBRep::unlock()
+{}
+
+
+
+SourceDB::SourceDB (const SourceDBMeta& ptm, bool forceNew)
+{
+  // Open the correct SourceDB.
+  if (ptm.getType() == "aips") {
+    itsRep = new SourceDBAIPS (ptm.getTableName(), forceNew);
+  } else if (ptm.getType() == "postgres") {
+#if defined(HAVE_PGSQL)
+    itsRep = new SourceDBPostgres(ptm.getDBName(),
+        ptm.getUserName(),
+        ptm.getDBPwd(),
+        ptm.getHostName(),
+        "");
+#else
+    ASSERTSTR(false, "unsupported sourceTableType: "<<ptm.getType());
+#endif
+  } else {
+    ASSERTSTR(false, "unknown sourceTableType: "<<ptm.getType());
+  }
+  itsRep->link();
+  itsRep->setSourceDBMeta (ptm);
+}
+
+SourceDB::SourceDB (SourceDBRep* rep)
+: itsRep (rep)
+{
+  itsRep->link();
+}
+
+SourceDB::SourceDB (const SourceDB& that)
+: itsRep (that.itsRep)
+{
+  itsRep->link();
+}
+
+SourceDB& SourceDB::operator= (const SourceDB& that)
+{
+  if (this != &that) {
+    decrCount();
+    itsRep = that.itsRep;
+    itsRep->link();
+  }
+  return *this;
+}
+
+void SourceDB::decrCount()
+{
+  if (itsRep->unlink() == 0) {
+    delete itsRep;
+    itsRep = 0;
+  }
+}
+
+void SourceDB::addSource (const SourceValue& value)
+{
+  list<SourceValue> values;
+  values.push_back (value);
+  addSources (values);
+}
+
+void SourceDB::createParmDB (ParmDB::ParmDB& parmdb)
+{
+  // Get all sources.
+  list<SourceValue> sources = getSources(vector<string>(),
+					 ParmDB::ParmDomain());
+  // Lock the ParmDB for the bulk update.
+  parmdb.lock (true);
+  // Create the parm object once.
+  ParmDB::ParmValue pv;
+  pv.setNewParm();
+  // Write them into the parameter database.
+  // So far, only point sources are handled.
+  for (list<SourceValue>::const_iterator iter = sources.begin();
+       iter != sources.end();
+       ++iter) {
+    vector<int> shape;     // empty shape is scalar
+    ASSERT (iter->getType() == "point");
+    putParm (parmdb, pv, iter->getName(), "RA", iter->getDomain(),
+	     iter->getRA(), false); 
+    putParm (parmdb, pv, iter->getName(), "DEC", iter->getDomain(),
+	     iter->getDEC(), false); 
+    putParm (parmdb, pv, iter->getName(), "SPINX", iter->getDomain(),
+	     iter->getSpectralIndex(), false); 
+    putParm (parmdb, pv, iter->getName(), "FLUXI", iter->getDomain(),
+	     iter->getFlux()[0], false); 
+    putParm (parmdb, pv, iter->getName(), "FLUXQ", iter->getDomain(),
+	     iter->getFlux()[1], false); 
+    putParm (parmdb, pv, iter->getName(), "FLUXU", iter->getDomain(),
+	     iter->getFlux()[2], false); 
+    putParm (parmdb, pv, iter->getName(), "FLUXV", iter->getDomain(),
+	     iter->getFlux()[3], false); 
+  }
+  parmdb.unlock();
+}
+
+void SourceDB::putParm (ParmDB::ParmDB& parmdb, ParmDB::ParmValue& pv,
+			const string& sourceName,
+			const string& parm,
+			const ParmDB::ParmDomain& domain,
+			double value, bool relativePert)
+{
+  pv.rep().setPerturbation (1e-6, relativePert);
+  pv.rep().setCoeff (&value, vector<int>());
+  pv.rep().setDomain (domain);
+  parmdb.putValue (sourceName+':'+parm, pv);
+}
+
+void SourceDB::mergeParmDB (const ParmDB::ParmDB&)
+{
+  ASSERTSTR (false, "SourceDB::mergeParmDB not implemented yet");
+}
+
+} // namespace SourceDB
+} // namespace LOFAR
diff --git a/CEP/BB/SourceDB/src/SourceDBAIPS.cc b/CEP/BB/SourceDB/src/SourceDBAIPS.cc
new file mode 100644
index 0000000000000000000000000000000000000000..a470919525f1cfd31eec0498a42293028db5a49e
--- /dev/null
+++ b/CEP/BB/SourceDB/src/SourceDBAIPS.cc
@@ -0,0 +1,361 @@
+//# SourceDBAIPS.cc: Class to hold sources in an AIPS++ table.
+//#
+//# Copyright (C) 2008
+//# 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 <SourceDB/SourceDBAIPS.h>
+#include <Common/LofarLogger.h>
+
+#include <tables/Tables/TableDesc.h>
+#include <tables/Tables/SetupNewTab.h>
+#include <tables/Tables/ExprNode.h>
+#include <tables/Tables/ExprNodeSet.h>
+#include <tables/Tables/ScalarColumn.h>
+#include <tables/Tables/ScaColDesc.h>
+#include <tables/Tables/ArrColDesc.h>
+#include <tables/Tables/ColumnDesc.h>
+#include <tables/Tables/TableIter.h>
+#include <tables/Tables/TableRecord.h>
+#include <tables/Tables/TableLocker.h>
+#include <measures/TableMeasures/TableQuantumDesc.h>
+#include <measures/TableMeasures/TableMeasDesc.h>
+#include <measures/Measures/MEpoch.h>
+#include <measures/Measures/MDirection.h>
+#include <casa/Arrays/Vector.h>
+#include <casa/Utilities/Regex.h>
+#include <casa/BasicMath/Math.h>
+#include <casa/OS/Time.h>
+#include <casa/Quanta/MVTime.h>
+
+using namespace casa;
+using namespace std;
+
+namespace LOFAR {
+namespace SourceDB {
+
+SourceDBAIPS::SourceDBAIPS (const string& tableName, bool forceNew)
+{
+  // Create the table if needed or if it does not exist yet.
+  if (forceNew  ||  !Table::isReadable (tableName)) {
+    createTables (tableName);
+  }
+  // Open the main table.
+  itsTable = Table(tableName, TableLock::UserLocking);
+}
+
+SourceDBAIPS::~SourceDBAIPS()
+{}
+
+void SourceDBAIPS::lock (bool lockForWrite)
+{
+  itsTable.lock (lockForWrite);
+}
+
+void SourceDBAIPS::unlock()
+{
+  itsTable.unlock();
+}
+
+void SourceDBAIPS::createTables (const string& tableName)
+{
+  TableDesc td("Source parameter table", TableDesc::Scratch);
+  td.comment() = String("Table containing parameters for sources");
+  td.addColumn (ScalarColumnDesc<String>("NAME"));
+  td.addColumn (ScalarColumnDesc<String>("TYPE"));
+  td.addColumn (ArrayColumnDesc<double> ("RADEC", IPosition(1,2),
+					 ColumnDesc::Direct));
+  td.addColumn (ScalarColumnDesc<double>("FLUXI"));
+  td.addColumn (ScalarColumnDesc<double>("FLUXQ"));
+  td.addColumn (ScalarColumnDesc<double>("FLUXU"));
+  td.addColumn (ScalarColumnDesc<double>("FLUXV"));
+  td.addColumn (ScalarColumnDesc<double>("SPINDEX"));
+  td.addColumn (ScalarColumnDesc<double>("STARTFREQ", 1));
+  td.addColumn (ScalarColumnDesc<double>("ENDFREQ", 1));
+  td.addColumn (ScalarColumnDesc<double>("STARTTIME", 1));
+  td.addColumn (ScalarColumnDesc<double>("ENDTIME", 1));
+  // Define units and measures.
+  setQuant (td, "FLUXI", "Jy");
+  setQuant (td, "FLUXQ", "Jy");
+  setQuant (td, "FLUXU", "Jy");
+  setQuant (td, "FLUXV", "Jy");
+  setQuant (td, "STARTFREQ", "Hz");
+  setQuant (td, "ENDFREQ", "Hz");
+  setEpoch (td, "STARTTIME");
+  setEpoch (td, "ENDTIME");
+  setQuant (td, "RADEC", "rad");
+  TableMeasRefDesc measRef(MDirection::J2000);
+  TableMeasValueDesc measVal(td, "RADEC");
+  TableMeasDesc<MDirection> tmd(measVal, measRef);
+  tmd.write(td);
+
+  SetupNewTable newtab(tableName, td, Table::New);
+  Table tab(newtab);
+
+  tab.tableInfo().setType ("SOURCES");
+  tab.tableInfo().readmeAddLine ("Source Parameter values");
+}
+
+void SourceDBAIPS::setQuant (TableDesc& td, const String& name,
+			     const String& unit)
+{
+  TableQuantumDesc tqd(td, name, Unit(unit));
+  tqd.write (td);
+}
+
+void SourceDBAIPS::setEpoch (TableDesc& td, const String& name)
+{
+  setQuant (td, name, "s");
+  TableMeasRefDesc measRef(MEpoch::UTC);
+  TableMeasValueDesc measVal(td, name);
+  TableMeasDesc<MEpoch> tmd(measVal, measRef);
+  tmd.write(td);
+}
+
+
+void SourceDBAIPS::clearTables()
+{
+  TableLocker locker(itsTable, FileLocker::Write);
+  Vector<uInt> rows = itsTable.rowNumbers();
+  itsTable.removeRow(rows);
+}
+
+list<SourceValue> SourceDBAIPS::getSources (const vector<string>& sourceNames,
+					    const ParmDB::ParmDomain& domain)
+{
+  TableLocker locker(itsTable, FileLocker::Read);
+  // Find all rows overlapping the requested domain.
+  TableExprNode expr = makeExpr (itsTable, domain);
+  if (sourceNames.size() > 0) {
+    Vector<String> nams(sourceNames.size());
+    for (unsigned i=0; i<sourceNames.size(); ++i) {
+      nams[i] = sourceNames[i];
+    }
+    andExpr (expr, itsTable.col("NAME").in (nams));
+  }
+  Table sel;
+  if (expr.isNull()) {
+    sel = itsTable;
+  } else {
+    sel = itsTable(expr);
+  }
+  list<SourceValue> result;
+  extractValues (result, sel);
+  return result;
+}
+
+list<SourceValue> SourceDBAIPS::getSources (double ra, double dec,
+					    double radius,
+					    const ParmDB::ParmDomain& domain)
+{
+  TableLocker locker(itsTable, FileLocker::Read);
+  // Find all rows overlapping the requested domain.
+  TableExprNode expr = makeExpr (itsTable, domain);
+  Vector<Double> rdr(3);
+  rdr[0] = ra;
+  rdr[1] = dec;
+  rdr[2] = radius;
+  andExpr (expr, anyCone(itsTable.col("RADEC"), rdr));
+  list<SourceValue> result;
+  extractValues (result, itsTable(expr));
+  return result;
+}
+
+void SourceDBAIPS::addSources (const list<SourceValue>& values)
+{
+  itsTable.reopenRW();
+  TableLocker locker(itsTable, FileLocker::Write);
+  for (list<SourceValue>::const_iterator iter = values.begin();
+       iter != values.end();
+       ++iter) {
+    itsTable.addRow();
+    putValue (itsTable, itsTable.nrow()-1, *iter);
+  }
+}
+
+void SourceDBAIPS::updateSource (const SourceValue& value)
+{
+  itsTable.reopenRW();
+  TableLocker locker(itsTable, FileLocker::Write);
+  Table sel = itsTable(itsTable.col("NAME") == String(value.getName())
+		       &&  itsTable.col("STARTFREQ") == value.getStartFreq()
+		       &&  itsTable.col("ENDFREQ") == value.getEndFreq()
+		       &&  itsTable.col("STARTTIME") == value.getStartTime()
+		       &&  itsTable.col("ENDTIME") == value.getEndTime());
+  ASSERT (sel.nrow() == 1);
+  putValue (sel, 0, value);
+}
+
+void SourceDBAIPS::deleteSource (const SourceValue& value)
+{
+  itsTable.reopenRW();
+  TableLocker locker(itsTable, FileLocker::Write);
+  // Find all rows.
+  Table sel = itsTable(itsTable.col("NAME") == String(value.getName())
+		       &&  itsTable.col("STARTFREQ") == value.getStartFreq()
+		       &&  itsTable.col("ENDFREQ") == value.getEndFreq()
+		       &&  itsTable.col("STARTTIME") == value.getStartTime()
+		       &&  itsTable.col("ENDTIME") == value.getEndTime());
+  // Delete all rows found.
+  itsTable.removeRow (sel.rowNumbers (itsTable));
+}
+
+void SourceDBAIPS::deleteSources (const string& sourceNamePattern,
+				  const ParmDB::ParmDomain& domain)
+{
+  itsTable.reopenRW();
+  TableLocker locker(itsTable, FileLocker::Write);
+  // Find all rows.
+  TableExprNode expr = makeExpr (itsTable, domain);
+  Regex regex(Regex::fromPattern(sourceNamePattern));
+  andExpr (expr, itsTable.col("NAME") == regex);
+  Table sel = itsTable(expr);
+  // Delete all rows found.
+  itsTable.removeRow (sel.rowNumbers (itsTable));
+}
+
+vector<string> SourceDBAIPS::getNames (const string& pattern)
+{
+  TableLocker locker(itsTable, FileLocker::Read);
+  vector<string> result;
+  // Find all rows.
+  Regex regex(Regex::fromPattern(pattern));
+  Table sel = itsTable(itsTable.col("NAME") == regex);
+  if (sel.nrow() > 0) {
+    // Sort them uniquely on name.
+    Table sor = sel.sort("NAME", Sort::Ascending,
+			 Sort::QuickSort | Sort::NoDuplicates);
+    ROScalarColumn<String> nameCol (sor, "NAME");
+    Vector<String> names = nameCol.getColumn();
+    result.resize (sor.nrow());
+    for (unsigned i=0; i<names.nelements(); ++i) {
+      result[i] = names[i];
+    }
+  }
+  return result;
+}
+
+void SourceDBAIPS::match (const SourceDB& other,
+			  SourceDB& match, SourceDB& nonMatch)
+{
+  ASSERTSTR (false, "SourceDBAIPS::match not implemented yet");
+}
+
+void SourceDBAIPS::merge (const SourceDB& otherMatch,
+			  const SourceDB& otherNonMatch)
+{
+  ASSERTSTR (false, "SourceDBAIPS::merge not implemented yet");
+}
+
+
+void SourceDBAIPS::extractValues (list<SourceValue>& result,
+				  const Table& tab)
+{
+  ROScalarColumn<String> nameCol (tab, "NAME");
+  ROScalarColumn<String> typeCol (tab, "TYPE");
+  ROArrayColumn <double> radecCol(tab, "RADEC");
+  ROScalarColumn<double> spCol   (tab, "SPINDEX");
+  ROScalarColumn<double> fiCol   (tab, "FLUXI");
+  ROScalarColumn<double> fqCol   (tab, "FLUXQ");
+  ROScalarColumn<double> fuCol   (tab, "FLUXU");
+  ROScalarColumn<double> fvCol   (tab, "FLUXV");
+  ROScalarColumn<double> sfCol   (tab, "STARTFREQ");
+  ROScalarColumn<double> efCol   (tab, "ENDFREQ");
+  ROScalarColumn<double> stCol   (tab, "STARTTIME");
+  ROScalarColumn<double> etCol   (tab, "ENDTIME");
+  double flux[4];
+  for (unsigned int i=0; i<tab.nrow(); i++) {
+    SourceValue pvalue;
+    flux[0] = fiCol(i);
+    flux[1] = fqCol(i);
+    flux[2] = fuCol(i);
+    flux[3] = fvCol(i);
+    Array<double> radec = radecCol(i);
+    pvalue.setPointSource (nameCol(i), radec.data()[0], radec.data()[1],
+			   flux, spCol(i));
+    pvalue.setDomain (ParmDB::ParmDomain(sfCol(i), efCol(i),
+					 stCol(i), etCol(i)));
+    result.push_back (pvalue);
+  }
+}
+
+void SourceDBAIPS::putValue (Table& tab,
+			     unsigned rownr,
+			     const SourceValue& pvalue)
+{
+  ScalarColumn<String> nameCol (tab, "NAME");
+  ScalarColumn<String> typeCol (tab, "TYPE");
+  ArrayColumn <double> radecCol(tab, "RADEC");
+  ScalarColumn<double> spCol   (tab, "SPINDEX");
+  ScalarColumn<double> fiCol   (tab, "FLUXI");
+  ScalarColumn<double> fqCol   (tab, "FLUXQ");
+  ScalarColumn<double> fuCol   (tab, "FLUXU");
+  ScalarColumn<double> fvCol   (tab, "FLUXV");
+  ScalarColumn<double> sfCol   (tab, "STARTFREQ");
+  ScalarColumn<double> efCol   (tab, "ENDFREQ");
+  ScalarColumn<double> stCol   (tab, "STARTTIME");
+  ScalarColumn<double> etCol   (tab, "ENDTIME");
+  Vector<double> radec(2);
+  radec(0) = pvalue.getRA();
+  radec(1) = pvalue.getDEC();
+  nameCol.put (rownr, pvalue.getName());
+  typeCol.put (rownr, pvalue.getType());
+  radecCol.put(rownr, radec);
+  spCol.put   (rownr, pvalue.getSpectralIndex());
+  fiCol.put   (rownr, pvalue.getFlux()[0]);
+  fqCol.put   (rownr, pvalue.getFlux()[1]);
+  fuCol.put   (rownr, pvalue.getFlux()[2]);
+  fvCol.put   (rownr, pvalue.getFlux()[3]);
+  sfCol.put   (rownr, pvalue.getStartFreq());
+  efCol.put   (rownr, pvalue.getEndFreq());
+  stCol.put   (rownr, pvalue.getStartTime());
+  etCol.put   (rownr, pvalue.getEndTime());
+}
+
+TableExprNode SourceDBAIPS::makeExpr (const Table& table,
+				      const ParmDB::ParmDomain& domain) const
+{
+  TableExprNode expr;
+  if (domain.getStart().size() > 0) {
+    andExpr (expr,
+	     domain.getStart()[0] < table.col("ENDFREQ")  &&
+             domain.getEnd()[0]   > table.col("STARTFREQ"));
+    if (domain.getStart().size() > 1) {
+      andExpr (expr,
+	       domain.getStart()[1] < table.col("ENDTIME")  &&
+	       domain.getEnd()[1]   > table.col("STARTTIME"));
+    }
+  }
+  return expr;
+}
+
+void SourceDBAIPS::andExpr (TableExprNode& expr,
+			    const TableExprNode& right) const
+{
+  if (expr.isNull()) {
+    expr = right;
+  } else {
+    expr = expr && right;
+  }
+}
+
+
+} // namespace SourceDB
+} // namespace LOFAR
diff --git a/CEP/BB/SourceDB/src/SourceDBMeta.cc b/CEP/BB/SourceDB/src/SourceDBMeta.cc
new file mode 100644
index 0000000000000000000000000000000000000000..5f4899d713630d9cb9cd39af27f2e2946ae88040
--- /dev/null
+++ b/CEP/BB/SourceDB/src/SourceDBMeta.cc
@@ -0,0 +1,70 @@
+//#  SourceDBMeta.cc: one line description
+//#
+//#  Copyright (C) 2008
+//#  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 <SourceDB/SourceDBMeta.h>
+#include <Blob/BlobOStream.h>
+#include <Blob/BlobIStream.h>
+
+
+namespace LOFAR {
+namespace SourceDB {
+
+  SourceDBMeta::SourceDBMeta()
+  {}
+
+  SourceDBMeta::SourceDBMeta (const std::string& type,
+			      const std::string& tableName)
+    : itsType      (type),
+      itsTableName (tableName)
+  {}
+
+  void SourceDBMeta::setSQLMeta (const std::string& dbName,
+				 const std::string& userName,
+				 const std::string& dbPwd,
+				 const std::string& hostName)
+  {
+    itsDBName   = dbName;
+    itsUserName = userName;
+    itsDBPwd    = dbPwd;
+    itsHostName = hostName;
+  }
+
+  BlobOStream& operator<< (BlobOStream& bos, const SourceDBMeta& pdm)
+  {
+    bos << pdm.itsType   << pdm.itsTableName
+	<< pdm.itsDBName << pdm.itsUserName
+	<< pdm.itsDBPwd  << pdm.itsHostName;
+    return bos;
+  }
+    
+  BlobIStream& operator>> (BlobIStream& bis, SourceDBMeta& pdm)
+  {
+    bis >> pdm.itsType >> pdm.itsTableName
+	>> pdm.itsDBName >> pdm.itsUserName
+	>> pdm.itsDBPwd >> pdm.itsHostName;
+    return bis;
+  }   
+
+} // namespace SourceDB
+} // namespace LOFAR
diff --git a/CEP/BB/SourceDB/src/SourceValue.cc b/CEP/BB/SourceDB/src/SourceValue.cc
new file mode 100644
index 0000000000000000000000000000000000000000..fb8487d22aeab59710cee2485a756b3f260a4fa5
--- /dev/null
+++ b/CEP/BB/SourceDB/src/SourceValue.cc
@@ -0,0 +1,93 @@
+//# SourceValue.cc: The parameters of a single source
+//#
+//# Copyright (C) 2008
+//# 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 <SourceDB/SourceValue.h>
+#include <Common/LofarLogger.h>
+
+namespace LOFAR {
+namespace SourceDB {
+
+  SourceValue::SourceValue()
+    : itsRA        (0),
+      itsDEC       (0),
+      itsSpIndex   (0),
+      itsDomain    (-1e30, 1e30, -1e30, 1e30)
+  {
+    itsFlux[0] = 1;
+    itsFlux[1] = 0;
+    itsFlux[2] = 0;
+    itsFlux[3] = 0;
+  }
+
+  void SourceValue::setPointSource (const std::string& name,
+				    double RA, double DEC,
+				    double flux[4], double spectralIndex)
+  {
+    itsName    = name;
+    itsType    = "point";
+    itsRA      = RA;
+    itsDEC     = DEC;
+    itsSpIndex = spectralIndex;
+    itsFlux[0] = flux[0];
+    itsFlux[1] = flux[1];
+    itsFlux[2] = flux[2];
+    itsFlux[3] = flux[3];
+  }
+
+  void SourceValue::setPos (double RA, double DEC)
+  {
+    itsRA  = RA;
+    itsDEC = DEC;
+  }
+
+  void SourceValue::setDomain (const ParmDB::ParmDomain& domain)
+  {
+    ASSERTSTR (domain.getStart().size() <= 2, "Domain has max. 2 axes");
+    if (domain.getStart().size() == 2) {
+      itsDomain = domain;
+    } else if (domain.getStart().size() == 1) {
+      itsDomain = ParmDB::ParmDomain (domain.getStart()[0],
+				      domain.getEnd()[0],
+				      -1e30, 1e30);
+    } else {
+      itsDomain = ParmDB::ParmDomain (-1e30, 1e30, -1e30, 1e30);
+    }
+  }
+
+  void SourceValue::setFreqDomain (double startHz, double endHz)
+  {
+    // Keep current time.
+    itsDomain = ParmDB::ParmDomain (startHz, endHz,
+				    itsDomain.getStart()[1],
+				    itsDomain.getEnd()[1]);
+  }
+
+  void SourceValue::setTimeDomain (double startMJD, double endMJD)
+  {
+    // Keep current freq.
+    itsDomain = ParmDB::ParmDomain (itsDomain.getStart()[0],
+				    itsDomain.getEnd()[0],
+				    startMJD, endMJD);
+  }
+
+} // namespace SourceDB
+} // namespace LOFAR
diff --git a/CEP/BB/SourceDB/src/sourcedb_main.cc b/CEP/BB/SourceDB/src/sourcedb_main.cc
new file mode 100644
index 0000000000000000000000000000000000000000..5e3b56ae09ac71f5052b7a013ceee9e3cc186c84
--- /dev/null
+++ b/CEP/BB/SourceDB/src/sourcedb_main.cc
@@ -0,0 +1,566 @@
+//# sourcedb.cc: put values in the database used for MNS
+//#
+//# 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 <SourceDB/SourceDB.h>
+#include <ParmDB/ParmDomain.h>
+#include <Blob/KeyValueMap.h>
+#include <Blob/KeyParser.h>
+#include <Common/StreamUtil.h>
+#include <Common/LofarLogger.h>
+
+#include <casa/Quanta/MVTime.h>
+#include <casa/Quanta/MVAngle.h>
+#include <casa/Utilities/MUString.h>
+#include <casa/Containers/Block.h>
+#include <iostream>
+#include <string>
+#include <pwd.h>
+#include <unistd.h>
+#include <libgen.h>
+
+using namespace std;
+using namespace casa;
+using namespace LOFAR;
+using namespace SourceDB;
+using namespace ParmDB;
+
+LOFAR::SourceDB::SourceDB* sourcetab;
+
+enum PTCommand {
+  NOCMD,
+  OPEN,
+  CREATE,
+  CLOSE,
+  CLEAR,
+  RANGE,
+  SHOW,
+  NAMES,
+  NEW,
+  UPD,
+  DEL,
+  QUIT
+};
+
+char bool2char (bool val)
+{
+  return (val  ?  'y' : 'n');
+}
+
+void showValues (std::ostream& os, const vector<double>& values,
+		 const vector<int>& shape)
+{
+  int n = values.size();
+  if (n > 0) {
+    os << values[0];
+    for (int i=1; i<n; i++) {
+      os << ',' << values[i];
+    }
+  }
+  os << "  shape=" << shape;
+}
+
+void showHelp()
+{
+  cerr << endl;
+  cerr << "Show and update contents of source tables containing the" << endl;
+  cerr << "source parameters." << endl;
+  cerr << " create db='username' dbtype='aips' tablename='sourcedb'" << endl;
+  cerr << " open   db='username' dbtype='aips' tablename='sourcedb'" << endl;
+  cerr << " quit  (or exit or stop)" << endl;
+  cerr << endl;
+  cerr << " show  [sourcename_pattern] [domain=spec,] [ra=, dec=, radius=1 (in arcsec)]" << endl;
+  cerr << " names [sourcename_pattern]" << endl;
+  cerr << " add sourcename domain=spec, valuespec" << endl;
+  cerr << " update sourcename_pattern [domain=spec,] valuespec" << endl;
+  cerr << " remove sourcename_pattern [domain=spec,]" << endl;
+  cerr << endl;
+  cerr << "  domain gives a 1-dim or 2-dim domain as:" << endl;
+  cerr << "      domain=[stfreq,endfreq,sttime,endtime]" << endl;
+  cerr << "   or domain=[st=[stf,stt],end=[endf,endt] or size=[sizef,sizet]]" << endl;
+  cerr << "  valuespec gives the values of the source attributes as" << endl;
+  cerr << "   key=value pairs separated by commas." << endl;
+  cerr << "  Attributes not given are not changed. Values shown are defaults when adding." << endl;
+  cerr << "   type='point'          (source type; default is point)" << endl;
+  cerr << "   ra=12:2:34.1          (ra in J2000)" << endl;
+  cerr << "   dec=12.2.34.1         (dec in J2000)" << endl;
+  cerr << "   flux=[1,0,0,0]        (flux I,Q,U,V; default of each is 0)" << endl;
+  cerr << endl;
+}
+
+PTCommand getCommand (char*& str)
+{
+  PTCommand cmd = NOCMD;
+  while (*str == ' ') {
+    str++;
+  }
+  const char* sstr = str;
+  while (*str != ' ' && *str != '\0') {
+    str++;
+  }
+  string sc(sstr, str-sstr);
+  if (sc == "show"  ||  sc == "list") {
+    cmd = SHOW;
+  } else if (sc == "names") {
+    cmd = NAMES;
+  } else if (sc == "new"  ||  sc == "insert"  ||  sc == "add") {
+    cmd = NEW;
+  } else if (sc == "update") {
+    cmd = UPD;
+  } else if (sc == "delete"  ||  sc == "remove"  || sc == "erase") {
+    cmd = DEL;
+  } else if (sc == "open") {
+    cmd = OPEN;
+  } else if (sc == "close") {
+    cmd = CLOSE;
+  } else if (sc == "clear") {
+    cmd = CLEAR;
+  } else if (sc == "create") {
+    cmd = CREATE;
+  } else if (sc == "stop"  ||  sc == "quit"  || sc == "exit") {
+    cmd = QUIT;
+  } 
+  return cmd;
+}
+
+std::string getUserName()
+{
+  // On Cray XT3 getpwuid is unavailable.
+#ifndef USE_NOSOCKETS
+  passwd* aPwd;
+  if ((aPwd = getpwuid(getuid())) != 0) {
+    return aPwd->pw_name;
+  }
+#endif
+  return "test";
+}
+
+
+std::string getSourceName (char*& str)
+{
+  while (*str == ' ') {
+    str++;
+  }
+  if (*str == '\0') {
+    return "";
+  }
+  char* sstr = str;
+  bool foundeq = false;
+  while (*str != ' ' && *str != '\0') {
+    if (*str == '=') {
+      foundeq = true;
+      break;
+    }
+    str++;
+  }
+  // If an = was found, no source is given.
+  if (foundeq) {
+    str = sstr;
+    return "";
+  }
+  return std::string(sstr, str-sstr);
+}
+
+vector<double> getArray (const KeyValueMap& kvmap, const std::string& arrName,
+			 uint size=0, double defaultValue = 1)
+{
+  vector<double> res(size, 0.);
+  KeyValueMap::const_iterator value = kvmap.find(arrName);
+  if (value == kvmap.end()) {
+    if (size > 0) res[0] = defaultValue;
+    return res;
+  }
+  vector<double> vec;
+  if (value->second.dataType() == KeyValue::DTValueVector) {
+    const vector<KeyValue>& vvec = value->second.getVector();
+    for (uint i=0; i<vvec.size(); i++) {
+      vec.push_back (vvec[i].getDouble());
+    }
+  } else {
+    value->second.get (vec);
+  }
+  if (size == 0) {
+    return vec;
+  }
+  ASSERTSTR (vec.size() <= size, "More than "<<size<<" values are given");
+  for (uint i=0; i<vec.size(); ++i) {
+    res[i] = vec[i];
+  }
+  return res;
+}
+
+bool getDomainVector (vector<double>& vec, const vector<KeyValue>& vals)
+{
+  vec.reserve (vals.size());
+  for (vector<KeyValue>::const_iterator iter = vals.begin();
+       iter != vals.end();
+       iter++) {
+    if (iter->dataType() == KeyValue::DTString) {
+      MUString str (iter->getString());
+      Quantity res;
+      if (MVTime::read (res, str)) {
+	vec.push_back (res.getValue("s"));
+      } else {
+	cout << "Error in interpreting " << iter->getString() << endl;
+	return false;
+      }
+    } else {
+      vec.push_back (iter->getDouble());
+    }
+  }
+  return true;
+}
+
+ParmDomain getDomain (const KeyValueMap& kvmap, int size=0)
+{
+  KeyValueMap::const_iterator value = kvmap.find("domain");
+  vector<double> st;
+  vector<double> end;
+  if (value != kvmap.end()) {
+    bool ok = false;
+    // See if given as domain=[start=[],end=[] or size=[]].
+    if (value->second.dataType() == KeyValue::DTValueMap) {
+      const KeyValueMap& kvm = value->second.getValueMap();
+      KeyValueMap::const_iterator key = kvm.find("st");
+      if (key != kvm.end()) {
+	bool okv = getDomainVector (st, key->second.getVector());
+	key = kvm.find("end");
+	bool hasend = (key != kvm.end());
+	if (hasend) okv = okv && getDomainVector (end, key->second.getVector());
+	key = kvm.find("size");
+	bool hassize = (key != kvm.end());
+	if (hassize) end = key->second.getVecDouble();
+	// end and size cannot be given both.
+	if (hasend != hassize) {
+	  if (st.size() == end.size()) {
+	    ok = okv;
+	    if (hassize) {
+	      for (uint i=0; i<end.size(); ++i) {
+		end[i] += st[i];
+	      }
+	    }
+	  }
+	}
+      }
+    } else {
+      // Given as a vector of values (as stx,endx,sty,endy,...).
+      vector<double> vec;
+      ok = getDomainVector (vec, value->second.getVector());
+      if (ok) {
+	if (vec.size() % 2 != 0) {
+	  ok = false;
+	} else {
+	  int nr = vec.size() / 2;
+	  st.resize(nr);
+	  end.resize(nr);
+	  for (int i=0; i<nr; ++i) {
+	    st[i] = vec[2*i];
+	    end[i] = vec[2*i + 1];
+	  }
+	}
+      }
+    }
+    ASSERTSTR (ok,
+	       "domain must be given as [[stf,endf],[stt,endt],...]\n"
+	       "or as [st=[stf,...],end=[endf,...] or size=[sizef,...]]");
+  }
+  if (size > 0) {
+    ASSERTSTR (int(st.size()) <= size, "Domain has too many axes");
+    int nr = size - st.size();
+    for (int i=0; i<nr; ++i) {
+      st.push_back (0);
+      end.push_back (1);
+    }
+  }
+  return ParmDomain(st, end);
+}
+
+void showDomain (const ParmDomain& domain)
+{
+  const vector<double>& st = domain.getStart();
+  const vector<double>& end = domain.getEnd();
+  if (st.size() == 2) {
+    cout << " freq=";
+    if (st[0] == -1e30  &&  end[0] == 1e30) {
+      cout << "all";
+    } else {
+      cout <<'[' << st[0]/1e6 << " MHz " << (end[0] - st[0] < 0 ? "-" : "+")
+	   << (end[0]-st[0])/1e3 << " KHz]";
+    }
+    cout << " time=";
+    if (st[1] == -1e30  &&  end[1] == 1e30) {
+      cout << "all";
+    } else {
+      cout << '[' << MVTime::Format(MVTime::YMD, 6)
+	   << MVTime(Quantity(st[1], "s")) << " "
+	   << (end[1] - st[1] < 0 ? "-" : "+") << (end[1] - st[1]) << " sec]";
+    }
+  } else {
+    for (uint i=0; i<st.size(); ++i) {
+      if (i != 0) cout << ',';
+      cout << '[' << st[i] << ',' << end[i] << ']';
+    }
+  }
+}
+
+// IMPLEMENTATION OF THE COMMANDS
+void showSource (const SourceValue& source, bool showAll)
+{
+  cout << source.getName();
+  cout << "  type=" << source.getType();
+  cout << "  ra=" << MVAngle::Format(MVAngle::TIME, 9)
+       << MVAngle(Quantity(source.getRA(), "rad"));
+  cout << " dec=" << MVAngle::Format(MVAngle::ANGLE, 9)
+       << MVAngle(Quantity(source.getDEC(), "rad"));
+  cout << endl;
+  if (showAll) {
+    cout << "  spectralindex=" << source.getSpectralIndex();
+    cout << "  domain:";
+    showDomain (source.getDomain());
+    cout << endl;
+  }
+}
+
+void showSources (const list<SourceValue>& sourceSet, bool showAll)
+{
+  int nr=0;
+  for (list<SourceValue>::const_iterator iter = sourceSet.begin();
+       iter != sourceSet.end();
+       iter++) {
+    showSource (*iter, showAll);
+    ++nr;
+  }
+  if (nr != 1) {
+    cout << nr << " source records found" << endl;
+  }
+}
+
+void newSource (const std::string& sourceName, const ParmDomain& domain,
+		const KeyValueMap& kvmap)
+{
+  SourceValue pvalue;
+  string type = kvmap.getString("type", "point");
+  ASSERTSTR (type=="point", "Currently only point surces can be given");
+  ASSERTSTR (kvmap.isDefined("ra"),  "Keyword 'ra' not given");
+  ASSERTSTR (kvmap.isDefined("dec"), "Keyword 'dec' not given");
+  double ra  = kvmap.getDouble("ra", 0);
+  double dec = kvmap.getDouble("dec", 0);
+  double spindex = kvmap.getDouble ("spindex", 1);
+  vector<double> vflux = getArray (kvmap, "flux", 4);
+  double flux[4] = {1,0,0,0};
+  if (vflux.size() > 0) flux[0] = vflux[0];
+  if (vflux.size() > 1) flux[1] = vflux[1];
+  if (vflux.size() > 2) flux[2] = vflux[2];
+  if (vflux.size() > 3) flux[3] = vflux[3];
+  pvalue.setPointSource (sourceName, ra, dec, flux, spindex);
+  pvalue.setDomain (domain);
+  showSource (pvalue, true);
+  sourcetab->addSource (pvalue);
+  cout << "Wrote new record for source " << sourceName << endl;
+}
+
+void updateSource (SourceValue& pvalue, const KeyValueMap& kvmap)
+{
+  if (kvmap.isDefined("ra")) {
+    pvalue.setRA (kvmap.getDouble("ra", 0));
+  }
+  if (kvmap.isDefined("dec")) {
+    pvalue.setDEC (kvmap.getDouble("dec", 0));
+  }
+  if (kvmap.isDefined("spindex")) {
+    pvalue.setSpectralIndex (kvmap.getDouble("spindex", 0));
+  }
+  if (kvmap.isDefined("flux")) {
+    vector<double> vflux = getArray (kvmap, "flux", 4);
+    if (vflux.size() > 0) pvalue.setFluxI (vflux[0]);
+    if (vflux.size() > 1) pvalue.setFluxQ (vflux[1]);
+    if (vflux.size() > 2) pvalue.setFluxU (vflux[2]);
+    if (vflux.size() > 3) pvalue.setFluxV (vflux[3]);
+  }
+  showSource (pvalue, true);
+}
+
+void updateSources (list<SourceValue>& sourceSet, KeyValueMap& kvmap)
+{
+  for (list<SourceValue>::iterator iter = sourceSet.begin();
+       iter != sourceSet.end();
+       iter++) {
+    updateSource (*iter, kvmap);
+  }
+  sourcetab->lock();
+  for (list<SourceValue>::iterator iter = sourceSet.begin();
+       iter != sourceSet.end();
+       iter++) {
+    sourcetab->updateSource (*iter);
+  }
+  sourcetab->unlock();
+}
+
+
+void doIt (bool noPrompt)
+{
+  sourcetab = 0;
+  const int buffersize = 1024000;
+  char cstra[buffersize];
+  // Loop until stop is given.
+  while (true) {
+    try {
+      if (!noPrompt) {
+	cerr << "Command: ";
+      }
+      char* cstr = cstra;
+      if (! cin.getline (cstr, buffersize)) {
+	cerr << "Error while reading command" << endl;
+	break;
+      } 
+      while (*cstr == ' ') {
+	cstr++;
+      }
+      // Skip empty lines and comment lines.
+      if (cstr[0] == 0  ||  cstr[0] == '#') {
+	continue;
+      }
+      if (cstr[0] == '?') {
+	showHelp();
+      } else {
+	PTCommand cmd = getCommand (cstr);
+	ASSERTSTR(cmd!=NOCMD, "invalid command given: " << cstr);
+	if (cmd == QUIT) {
+	  break;
+	}
+	string sourceName;
+	if (cmd == OPEN) {
+	  ASSERTSTR(sourcetab==0, "OPEN or CREATE already done");
+	  // Connect to database.
+	  KeyValueMap kvmap = KeyParser::parse (cstr);
+	  string dbUser = kvmap.getString ("user", getUserName());
+	  string dbHost = kvmap.getString ("host", "dop50.astron.nl");
+	  string dbName = kvmap.getString ("db", dbUser);
+	  string dbType = kvmap.getString ("dbtype", "aips");
+	  string tableName = kvmap.getString ("tablename", "MeqSource");
+	  SourceDBMeta meta (dbType, tableName);
+	  meta.setSQLMeta (dbName, dbUser, "", dbHost);
+	  sourcetab = new LOFAR::SourceDB::SourceDB (meta);
+	} else if (cmd == CREATE)  {
+	  ASSERTSTR(sourcetab==0, "OPEN or CREATE already done");
+	  // create dataBase
+	  KeyValueMap kvmap = KeyParser::parse (cstr);
+	  string dbUser = kvmap.getString ("user", getUserName());
+	  string dbHost = kvmap.getString ("host", "dop50.astron.nl");
+	  string dbName = kvmap.getString ("db", dbUser);
+	  string dbType = kvmap.getString ("dbtype", "aips");
+	  string tableName = kvmap.getString ("tablename", "MeqSource");
+	  SourceDBMeta meta (dbType, tableName);
+	  meta.setSQLMeta (dbName, dbUser, "", dbHost);
+	  sourcetab = new LOFAR::SourceDB::SourceDB (meta, true);
+	} else {
+	  ASSERTSTR(sourcetab!=0, "OPEN or CREATE not done yet");
+	  if (cmd == CLOSE)  {
+	    delete sourcetab;
+	    sourcetab = 0;
+	  } else if (cmd == CLEAR)  {
+	    // clear database tables
+	    sourcetab->clearTables();
+	  } else {
+	    // Other commands expect a possible sourcename and keywords
+	    sourceName = getSourceName (cstr);
+	    KeyValueMap kvmap = KeyParser::parse (cstr);
+	    // For list functions the sourcename defaults to *.
+	    // Otherwise a sourcename or pattern must be given.
+	    if (cmd!=SHOW && cmd!=NAMES) {
+	      ASSERTSTR (!sourceName.empty(), "No source name given");
+	    } else if (sourceName.empty()) {
+	      sourceName = "*";
+	    }
+	    if (cmd==NEW || cmd==UPD || cmd==DEL) {
+	      // Read the given parameters and domains.
+	      ParmDomain domain = getDomain(kvmap);
+	      list<SourceValue> sourceset;
+	      vector<string> names (sourcetab->getNames(sourceName));
+	      if (!names.empty()) {
+		sourceset = sourcetab->getSources (names, domain);
+	      }
+	      int nrsource = sourceset.size();
+	      if (cmd == NEW) {
+		ASSERTSTR (sourceset.empty(),
+			   "the source/domain already exists");
+		newSource (sourceName, domain, kvmap);
+	      } else if (cmd == UPD) {
+		ASSERTSTR (! sourceset.empty(), "source/domain not found");
+		updateSources (sourceset, kvmap);
+		cout << "Updated " << nrsource << " source record(s)" << endl;
+	      } else if (cmd == DEL) {
+		ASSERTSTR (! sourceset.empty(), "parameter/domain not found");
+		sourcetab->deleteSources (sourceName, domain);
+		cout << "Deleted " << nrsource << " source record(s)" << endl;
+	      }
+	    } else if (cmd == SHOW) {
+	      ParmDomain domain = getDomain(kvmap);
+	      list<SourceValue> sourceset;
+	      if (kvmap.isDefined("ra") && kvmap.isDefined("dec")) {
+		double ra     = kvmap.getDouble("ra", 0);
+		double dec    = kvmap.getDouble("dec", 0);
+		double radius = kvmap.getDouble("radius", 1);
+		radius = Quantity(radius, "arcsec").getValue("rad");
+		sourceset = sourcetab->getSources (ra, dec, radius, domain);
+	      } else {
+		// Read the given parameters and domains.
+		vector<string> names (sourcetab->getNames(sourceName));
+		if (!names.empty()) {
+		  sourceset = sourcetab->getSources (names, domain);
+		}
+	      }
+	      showSources (sourceset, true);
+	    } else if (cmd==NAMES)  {
+	      // show names matching the pattern.
+	      cout << "names: "
+		   << sourcetab->getNames(sourceName) << endl;
+	    } else {
+	      cerr << "Unknown command given (type ? for help)" << endl;
+	    }
+	  }
+	}
+      }
+    } catch (std::exception& x) {
+      cerr << "Exception: " << x.what() << endl;
+    }
+  }
+  delete sourcetab;
+  sourcetab = 0;
+}
+
+int main (int argc, char *argv[])
+{
+  const char* progName = basename(argv[0]);
+  INIT_LOGGER(progName);
+  
+  try {
+    doIt (argc > 1);
+  } catch (std::exception& x) {
+    std::cerr << "Caught exception: " << x.what() << std::endl;
+    return 1;
+  }
+  
+  return 0;
+}
diff --git a/CEP/BB/SourceDB/src/versionsourcedb.cc b/CEP/BB/SourceDB/src/versionsourcedb.cc
new file mode 100644
index 0000000000000000000000000000000000000000..b5450496b5cdd0c89acaacf0a34ca7ee239f50b9
--- /dev/null
+++ b/CEP/BB/SourceDB/src/versionsourcedb.cc
@@ -0,0 +1,17 @@
+//# Print revision info; generated by autoconf_share/makeversion
+
+#include <SourceDB/Package__Version.h>
+#include <Common/Version.h>
+#include <iostream>
+
+using namespace LOFAR;
+
+int main (int argc, const char* argv[])
+{
+  std::string type = "brief";
+  if (argc > 1) {
+    type = argv[1];
+  }
+  Version::show<SourceDBVersion> (std::cout, "SourceDB", type);
+  return 0;
+}