Index: /Chief/Chief.cc
===================================================================
--- /Chief/Chief.cc	(revision 228)
+++ /Chief/Chief.cc	(revision 229)
@@ -14,4 +14,6 @@
 #define SERVER_NAME "Chief"
 #include "Evidence.h"
+
+using namespace std;
 
 // ========= Class Declarations =========
@@ -38,5 +40,5 @@
 	
 	DimService *LastRunNumber;
-	char *RunNumFilename;
+	string RunNumFilename;
 	int RunNumber;
 };
@@ -70,7 +72,7 @@
   
   // Open file containing last run number
-  FILE *RunNumFile = fopen(Chief->RunNumFilename, "r+");
+  FILE *RunNumFile = fopen(Chief->RunNumFilename.c_str(), "r+");
   if(RunNumFile == NULL) {
-    Chief->Message(Chief->ERROR, "Could not open file '%s' that contains the last run number (%s)", Chief->RunNumFilename, strerror(errno));
+    Chief->Message(Chief->ERROR, "Could not open file '%s' that contains the last run number (%s)", Chief->RunNumFilename.c_str(), strerror(errno));
 	OK = false;
   }
@@ -78,5 +80,5 @@
 	// Read last run number
 	if(fscanf(RunNumFile,"%d", &RunNumber) != 1 ) {
-      Chief->Message(Chief->ERROR, "Could not read run number from file '%s'", Chief->RunNumFilename);
+      Chief->Message(Chief->ERROR, "Could not read run number from file '%s'", Chief->RunNumFilename.c_str());
 	  OK = false;
 	}
@@ -86,5 +88,5 @@
 	rewind(RunNumFile);
 	if(OK && fprintf(RunNumFile,"%.8u   ",RunNumber) < 0) {
-      Chief->Message(Chief->ERROR, "Could not write to run number file '%s'", Chief->RunNumFilename);
+      Chief->Message(Chief->ERROR, "Could not write to run number file '%s'", Chief->RunNumFilename.c_str());
 	  OK = false;
 	}
@@ -92,5 +94,5 @@
 	// Close run number file
 	if(fclose(RunNumFile) != 0) {
-      Chief->Message(Chief->ERROR, "Could not close run number file '%s'", Chief->RunNumFilename);
+      Chief->Message(Chief->ERROR, "Could not close run number file '%s'", Chief->RunNumFilename.c_str());
 	  OK = false;
 	}
Index: /Evidence/Alarm.cc
===================================================================
--- /Evidence/Alarm.cc	(revision 228)
+++ /Evidence/Alarm.cc	(revision 229)
@@ -80,14 +80,11 @@
 
   // Get DIM servers to observe
-  char *Token = strtok(GetConfig("servers"), " \t");
-  int Pos;
-  while (Token != NULL) {
+  vector<string> Token = Tokenize(GetConfig("servers"));
+
+  for (int i=0; i<Token.size(); i++) {
 	// Extract server name and email
-	N.Server = Token;
-	Pos = N.Server.find(':');
-	if (Pos > 0 && Pos < N.Server.size()-2) {
-	  N.Email = N.Server.substr(Pos+1, string::npos);
-	  N.Server = N.Server.substr(0, Pos);	
-	}
+	vector<string> A = Tokenize(Token[i], ":");
+	N.Server = A[0];
+	if (A.size() == 2) N.Email = A[1];
 	else N.Email = string();
 
@@ -102,5 +99,4 @@
 
 	List.push_back(N);
-    Token = strtok(NULL, " \t");     
   }
 
@@ -247,5 +243,5 @@
     
     Alarm.UpdateAlarmSummary();
-    sleep(atoi(Alarm.GetConfig("period")));
-  }
-}
+    sleep(atoi(Alarm.GetConfig("period").c_str()));
+  }
+}
Index: /Evidence/Bridge.cc
===================================================================
--- /Evidence/Bridge.cc	(revision 228)
+++ /Evidence/Bridge.cc	(revision 229)
@@ -24,10 +24,8 @@
 using namespace std;
 
-
 // Class declaration
 class Bridge: public DimClient, public EvidenceServer {
 
 	struct Item {
-	  string Name;
 	  DimCommand *Command;
 	  DimStampedInfo *DataItem;
@@ -35,5 +33,5 @@
 	  char *Data;
 	};
-	vector<struct Item> List;
+	map<string, struct Item> Map;
 
 	DimInfo *ServerList;
@@ -41,7 +39,9 @@
     void infoHandler();
     void commandHandler();
+	public:
 	void AddService(string, char *, int);
 	void RemoveService(string);
-   
+	void BugFix();
+
   public:
     Bridge(char *, int);
@@ -63,5 +63,5 @@
 Bridge::~Bridge() {
 
-  while (List.size() != 0) RemoveService(List[0].Name);  
+  while (Map.size() != 0) RemoveService((*Map.begin()).first);  
   delete ServerList;
 }
@@ -77,5 +77,6 @@
 
   // If service is DIS_DNS/SERVER_LIST, subscribe to all SERVICE_LIST services
-  if (strcmp(I->getName(), "DIS_DNS/SERVER_LIST") == 0) {	
+  if (strcmp(I->getName(), "DIS_DNS/SERVER_LIST") == 0) {
+    printf("DIS_DNS/SERVER_LIST: '%s'\n", I->getString());
 	char *Token = strtok(I->getString(), "+-!@");	
 	while (Token != NULL) {
@@ -94,4 +95,13 @@
   // If service is SERVICE_LIST, scan and subscribe/unsubscribe to services
   if (strstr(I->getName(), "/SERVICE_LIST") != NULL) {
+
+	// Bug fix for empty SERVICE_LIST
+	if (strlen(I->getString()) == 0) {
+	  string Tmp(I->getName());
+	  RemoveService(I->getName());
+	  AddService(Tmp.c_str(), (char *) "C", DimSERVICE);
+	  return;
+	}
+
 	char *Format, *Name = strtok(I->getString(), "+-!|");
 	while (Name != NULL) {
@@ -131,17 +141,16 @@
   }
 
-  // Identify service and repeat to secondary DNS
-  for (int Service=0; Service<List.size(); Service++) if (I == List[Service].DataItem) {
-
-    // Copy service data
-    delete[] List[Service].Data;
-    List[Service].Data = new char [I->getSize()];
-    memcpy(List[Service].Data, I->getData(), I->getSize());
-
-	// Set new service properties and update service
-    List[Service].Service->setQuality(I->getQuality());
-    List[Service].Service->setTimestamp(I->getTimestamp(), I->getTimestampMillisecs());	
-	List[Service].Service->updateService(List[Service].Data, I->getSize());
-  }
+  // Check if service known and repeat to secondary DNS
+  if (Map.count(I->getName()) == 0) return;
+
+  // Copy service data
+  delete[] Map[I->getName()].Data;
+  Map[I->getName()].Data = new char [I->getSize()];
+  memcpy(Map[I->getName()].Data, I->getData(), I->getSize());
+
+  // Set new service properties and update service
+  Map[I->getName()].Service->setQuality(I->getQuality());
+  Map[I->getName()].Service->setTimestamp(I->getTimestamp(), I->getTimestampMillisecs());	
+  Map[I->getName()].Service->updateService(Map[I->getName()].Data, I->getSize());
 }
 
@@ -161,18 +170,17 @@
 
   // Check if already subscribed to this service
-  for (int i=0; i<List.size(); i++) {
-	if (Name == List[i].Name) return;
-  }
+  if (Map.count(Name) != 0) return;
 
   // Create subscription and service to secondary DNS or new command
-  struct Item New = {Name, NULL, NULL, NULL, NULL};
-
+  Map[Name].Command = NULL;
+  Map[Name].DataItem = NULL;
+  Map[Name].Service = NULL;
+  Map[Name].Data = NULL;
+  
   if  (Type == DimSERVICE) {  
-	New.Service = new DimService(Name.c_str(), (char *) Format, New.Data, 0);
-	New.DataItem = new DimStampedInfo(Name.c_str(), NO_LINK, this);
-  }
-  else if (Type == DimCOMMAND) New.Command = new DimCommand(Name.c_str(), Format, this);
-
-  List.push_back(New);
+	Map[Name].Service = new DimService(Name.c_str(), (char *) Format, Map[Name].Data, 0);
+	Map[Name].DataItem = new DimStampedInfo(Name.c_str(), NO_LINK, this);
+  }
+  else if (Type == DimCOMMAND) Map[Name].Command = new DimCommand(Name.c_str(), Format, this);
 }
 
@@ -181,13 +189,13 @@
 void Bridge::RemoveService(string Name) {
 
-  vector<struct Item>::iterator E;
-  for (E=List.begin(); E<List.end(); ++E) if (Name == (*E).Name) {
-	delete (*E).DataItem;
-	delete (*E).Service;
-	delete[] (*E).Data;
-	delete (*E).Command;
-
-	List.erase(E);
-  }
+  // Check if actually subscribed to service  
+  if (Map.count(Name) == 0) return;
+
+  delete Map[Name].DataItem;
+  delete Map[Name].Service;
+  delete[] Map[Name].Data;
+  delete Map[Name].Command;
+
+  Map.erase(Name);
 }
 
@@ -206,4 +214,4 @@
   
   // Sleep until signal caught
-  pause();
-}
+  while (!Class.ExitRequest) pause();
+}
Index: /Evidence/Config.cc
===================================================================
--- /Evidence/Config.cc	(revision 228)
+++ /Evidence/Config.cc	(revision 229)
@@ -67,4 +67,7 @@
   FileContent = NULL;
 
+  // Signaling interferes with inotify() mechnism
+  signal(SIGUSR2, SIG_IGN);
+  
   // Initialise mutex (errno is not set by pthread_mutex_init())
   if (pthread_mutex_init(&Mutex, NULL) != 0) {
@@ -266,10 +269,9 @@
 	  Notify = -1;
   }
- 
+
   // Sleep until file changes or signal caught 
   while (!Config.ExitRequest) {
     if (Notify != -1) {
-	  read(Notify, &Event, sizeof(Event));
-	  Config.ConfigChanged();
+	  if (read(Notify, &Event, sizeof(Event)) == sizeof(Event)) Config.ConfigChanged();
 	}
     else pause();	  
Index: /Evidence/DColl.cc
===================================================================
--- /Evidence/DColl.cc	(revision 228)
+++ /Evidence/DColl.cc	(revision 229)
@@ -19,4 +19,5 @@
 #include <string>
 #include <sstream>
+#include <iostream>
 #include <vector>
 #include <sys/stat.h>
@@ -44,12 +45,9 @@
 	float DataSizeMB, LogSizeMB;
 	int DataSizeLastUpdate, LogSizeLastUpdate;
-	char *BaseDir;
     DimService *LogSizeService, *DataSizeService, *DataFilename;
-	int SizeUpdateDelay;
 	int TimeForNextFile;
-	int RollOver;
 
 	vector<regex_t> RegEx;
-	
+
     void infoHandler();
     void commandHandler();
@@ -57,5 +55,6 @@
 	void RemoveService(string);
 	off_t FileSize(FILE *);
-   
+    void ConfigChanged();
+
   public:
     DataHandler();
@@ -63,4 +62,8 @@
 }; 
 
+void DataHandler::ConfigChanged() {
+  //printf("Handler called in PID %u\n", pthread_self());
+}
+
 //
 // Constructor
@@ -80,14 +83,14 @@
   TimeForNextFile = 0;
 
-  // Request configuration data
-  BaseDir = GetConfig("basedir");
-  SizeUpdateDelay = atoi(GetConfig("sizeupdate"));
-  RollOver = atoi(GetConfig("rollover"));
+  // Request configuration data / initialise for later non-blocking updates
+  GetConfig("basedir");
+  GetConfig("sizeupdate");
+  GetConfig("rollover");
 
   // Open log file
-  if ((LogFile = fopen((string(BaseDir)+"/"+LOG_FILENAME).c_str(), "a")) == NULL) {
+  if ((LogFile = fopen((GetConfig("basedir")+"/"+LOG_FILENAME).c_str(), "a")) == NULL) {
     Message(FATAL, "Could not open log file (%s)", strerror(errno));
   }
-              
+             
   // Create services for file sizes and data file name
   DataSizeMB = 0;
@@ -100,20 +103,18 @@
 
   // Compile regular expressions
-  char *Exclude = GetConfig("exclude");
-  char *Token = strtok(Exclude, "\t ");
   regex_t R;
-
-  while (Token != NULL) {
-	int Ret = regcomp(&R, Token, REG_EXTENDED|REG_NOSUB);
+  vector<string> Exclude = Tokenize(GetConfig("exclude"), " \t");
+  for (int i=0; i<Exclude.size(); i++) {
+	printf("'%s'\n",Exclude[i].c_str());
+
+	int Ret = regcomp(&R, Exclude[i].c_str(), REG_EXTENDED|REG_NOSUB);
 	if (Ret != 0) {
 	  char Err[200];
 	  regerror(Ret, &R, Err, sizeof(Err));
-	  Message(ERROR, "Error compiling regular expression '%s' (%s)", Token, Err);
+	  Message(ERROR, "Error compiling regular expression '%s' (%s)", Exclude[i].c_str(), Err);
 	}
 	else RegEx.push_back(R);
-
-	Token = strtok(NULL, "\t ");
-  }
-  
+  }
+
   // Provide logging command   
   LogCommand = new DimCommand("DColl/Log", (char *) "C", this);
@@ -158,7 +159,6 @@
 void DataHandler::infoHandler() {
 
+  // Check if service available
   DimInfo *I = getInfo();
-
-  // Check if service available
   if (!ServiceOK(I)) return;
 
@@ -166,5 +166,5 @@
   // ====== Part A: Handle service subscriptions ===
   //
-  // Services are added here, removal only in constructor.
+  // Services are added here, removal only in destructor.
   
   // If service is DIS_DNS/SERVER_LIST, subscribe to all SERVICE_LIST services
@@ -182,4 +182,13 @@
   // Subscribe to all services (but not to commands and RPCs)
   if (strstr(I->getName(), "/SERVICE_LIST") != NULL) {
+
+	// Bug fix for empty SERVICE_LIST
+	if (strlen(I->getString()) == 0) {
+	  string Tmp(I->getName());
+	  RemoveService(I->getName());
+	  AddService(Tmp.c_str());
+	  return;
+	}
+
 	char *Name = strtok(I->getString(), "+-!|");
 	while (Name != NULL) {
@@ -211,10 +220,10 @@
 
 	// Get time structure with date rollover
-	if (T->tm_hour >= RollOver) T->tm_mday++;
+	if (T->tm_hour >= atoi(GetConfig("rollover").c_str())) T->tm_mday++;
 	if (mktime(T) == -1) Message(ERROR, "mktime() failed, check filename");
 
 	// Create direcory if not existing (ignore error if already existing)
 	char *Dir;
-	if (asprintf(&Dir, "%s/%d", BaseDir, T->tm_year+1900) == -1) {
+	if (asprintf(&Dir, "%s/%d", GetConfig("basedir").c_str(), T->tm_year+1900) == -1) {
 	  Message(FATAL, "asprintf() failed, could not create direcory name");	
 	}
@@ -240,5 +249,5 @@
 	T->tm_sec = 0;
 	T->tm_min = 0;
-	T->tm_hour = RollOver;
+	T->tm_hour = atoi(GetConfig("rollover").c_str());
 	TimeForNextFile = mktime(T);
   }
@@ -261,17 +270,14 @@
 
 	// Translate data into ASCII
-	char *Text = EvidenceServer::ToString(I);
-
-	if (Text != NULL) {
+	string Text = EvidenceServer::ToString(I);
+
+	if (!Text.empty()) {
 	  // Replace new line by '\' and all other control characters by white space
-	  for (int i=0; i<strlen(Text); i++) {
+	  for (int i=0; i<Text.size(); i++) {
 		if (Text[i] == '\n') Text[i] = '\\';
 		else if (iscntrl(Text[i])) Text[i] = ' ';
 	  }
-
 	  // Write to file
-      fprintf(DataFile, "%s\n", Text);
-
-	  free(Text);
+      fprintf(DataFile, "%s\n", Text.c_str());
 	}
 	else fprintf(DataFile, "Cannot interpret format identifier\n");
@@ -286,5 +292,5 @@
 
 	// Update datafile size service (not every time to avoid infinite loop)
-	if (time(NULL) - DataSizeLastUpdate > SizeUpdateDelay) {
+	if (time(NULL) - DataSizeLastUpdate > max(atoi(GetConfig("sizeupdate").c_str()), 1)) {
       fflush(DataFile); // not continuously to reduce load
 
@@ -300,5 +306,5 @@
 //
 void DataHandler::commandHandler() {
- 
+ return;
   if (getCommand() != LogCommand || LogFile == NULL) return;
 
@@ -326,6 +332,6 @@
   }
     
-  // Update logfile size service
-  if (time(NULL) - LogSizeLastUpdate > SizeUpdateDelay) {
+  // Update logfile size service (not every time to avoid infinite loop)
+  if (time(NULL) - LogSizeLastUpdate > atoi(GetConfig("sizeupdate").c_str())) {
 	LogSizeMB = FileSize(LogFile)/1024.0/1024.0;
 	LogSizeService->updateService();
@@ -396,5 +402,5 @@
   static DataHandler DataInstance;
   
-  // Sleep until signal caught
-  pause();
-}
+  // Sleep until exit requested
+  while (!DataInstance.ExitRequest) pause();
+}
Index: /Evidence/Edd/Edd.cc
===================================================================
--- /Evidence/Edd/Edd.cc	(revision 228)
+++ /Evidence/Edd/Edd.cc	(revision 229)
@@ -27,17 +27,26 @@
 QWidget *OpenHistory(char *Service, int Index) {
 
+  QString Format;
+  DimBrowser Browser;
   class EvidenceHistory *Hist = Handler->GetHistory(Service);
 
-  // Check if hitory service available
+  // Check if history service available
   if (Hist == NULL || Hist->GetFormat() == NULL) {
 	QMessageBox::warning(NULL, "Edd Message", QString("Could not retrieve history for service ") + Service ,QMessageBox::Ok);
-	Handler->DropHistory(Service);
-	return NULL;
-  }
-
-  QString Format = Hist->GetFormat();
+
+	// If service currently available, take its format
+	char *Name, *Fmt;
+
+	Browser.getServices(Service);
+	if (Browser.getNextService(Name, Fmt) != 0) Format = QString(Fmt);
+	else {
+	  Handler->DropHistory(Service);
+	  return NULL;
+	}
+  }
+
+  if (Format.isEmpty()) Format = Hist->GetFormat();
   Handler->DropHistory(Service);
   
-  //if (strlen(Hist->GetFormat()) == 1 && *Hist->GetFormat() != 'C') return new EddPlot(Service, Index);
   if (Format.size() == 1 && Format[0] != 'C') return new EddPlot(Service, Index);
   else return new EddText(Service);
@@ -68,5 +77,5 @@
 	QLineEdit(P), ServiceName(Name), Index(Index) {
 
- LastHist = NULL;
+  LastHist = NULL;
  
   // Widget properties
@@ -112,4 +121,5 @@
 	return;
   }
+  else Pal.setColor(QPalette::Base, Qt::white);
 
   // Message service backgound colour determined by severity 
@@ -933,7 +943,9 @@
   if (!EvidenceServer::ServiceOK(getInfo())) YEP(getInfo()->getName(), -1);
   else {
-	char *Text = EvidenceServer::ToString(getInfo());
-	YEP(getInfo()->getName(), getInfo()->getTimestamp(), QByteArray((char *) getInfo()->getData(), getInfo()->getSize()), getInfo()->getFormat(), Text);
-	free(Text);
+	YEP(getInfo()->getName(),
+		getInfo()->getTimestamp(),
+		QByteArray((char *) getInfo()->getData(), 
+		getInfo()->getSize()), getInfo()->getFormat(),
+		QString::fromStdString(EvidenceServer::ToString(getInfo())));
   }
 }
@@ -1183,9 +1195,13 @@
     Plot->AddService("ARDUINO/Data", i);
   }
-  Layout->addWidget(Plot, 0, 2, 8, 7);      
+  Layout->addWidget(Plot, 0, 2, 9, 7);      
 
   // Night sky monitor
+  Line = new EddLineDisplay("SQM/Message");
+  Line->setMaximumWidth(200);
+  Layout->addWidget(Line, 6, 0, 1, 2);      
+
   Line = new EddLineDisplay("SQM/NSB");
-  Layout->addWidget(Line, 6, 0, 1, 1);          
+  Layout->addWidget(Line, 7, 0, 1, 1);          
 }
 
@@ -1554,5 +1570,5 @@
   bool OK;
 
-  // Find all services that are not history services and sort
+  // Find all DIM services and sort
   getServices("*");
   while ((Type = getNextService(Name, Format)) != 0) {
Index: /Evidence/Edd/Edd.pro
===================================================================
--- /Evidence/Edd/Edd.pro	(revision 228)
+++ /Evidence/Edd/Edd.pro	(revision 229)
@@ -6,8 +6,8 @@
 TARGET = 
 DEPENDPATH += .
-INCLUDEPATH += . .. /ihp/local/qwt-5.2.1/include $(DIMDIR)/dim ../../drsdaq ../../pixelmap
+INCLUDEPATH += . .. $(QWTDIR)/include $(DIMDIR)/dim ../../drsdaq ../../pixelmap
 
 # Input
 HEADERS += Edd.h
 SOURCES += Edd.cc ../Evidence.cc ../../drsdaq/RawDataCTX.cc ../../pixelmap/Pixel.cc ../../pixelmap/PixelMap.cc
-LIBS += -L/ihp/local/qwt-5.2.1/lib -lqwt $(DIMDIR)/linux/libdim.a
+LIBS += -L$(QWTDIR)/lib -lqwt $(DIMDIR)/linux/libdim.a
Index: /Evidence/Edd/INSTALL
===================================================================
--- /Evidence/Edd/INSTALL	(revision 229)
+++ /Evidence/Edd/INSTALL	(revision 229)
@@ -0,0 +1,44 @@
+Installation instructions for the Evidence Data Display Edd
+
+A) The packages Qt, Qwt and DIM are needed
+
+1. Qt can be downloaded from http://qt.nokia.com/. 
+
+   Test have been made with version 4.6.2 which can be downloaded aat
+   ftp://ftp.qt.nokia.com/qt/source/qt-everywhere-opensource-src-4.6.2.tar.gz.
+   It should well work with later version as well. 
+   
+   Installation instruction are given in the package. Usually, they amount on
+   Linux to executing './configure', then 'gmake all' followed by 
+   'gmake install', all done within the unpacked directory.
+ 
+   Before the following steps, it should be assured that the right version
+   of qmake is used, as many Linux installations include an older version
+   of Qt. Use 'qmake -version' to check and adjust your PATH variable if
+   necessary.
+    
+2. Qwt can be downloaded from http://sourceforge.net/projects/qwt/.
+   
+   Tests were made with version 5.2.1. Installation should simply be done
+   by executing 'qmake', then 'make', and finally 'make install'.
+
+3. DIM can be downloaded from http://dim.web.cern.ch/dim/.
+
+   The latest available version should be fine. Follow the installation
+   instruction on the web site given at the download link. Note that the
+   command line option in 'unzip -a' is mandatory. Compiling is done
+   with 'gmake all'.
+
+
+B) Compiling Edd
+
+An environment variable QWTDIR should point to the Qwt installation,
+and DIMDIR to the DIM installation.
+
+The subversion repository should preferably be checked out fully, as
+the class describing the M0 raw data format is currently needed.
+
+Issue 'qmake', then 'make' will build the executable Edd.
+
+To start, the environment variable LD_LIBRARY_PATH needs to include the
+location of the Qwt shared library. 
Index: /Evidence/Evidence.cc
===================================================================
--- /Evidence/Evidence.cc	(revision 228)
+++ /Evidence/Evidence.cc	(revision 229)
@@ -9,15 +9,15 @@
   - If the severity of a Message() call is FATAL, exit() will be called (with
     this severity, the call to Message() is guranteed not to return).
-  - Configuration data can be requested by GetConfig(). 
+  - Configuration data can be requested by GetConfig() and non-blocking by GetConfigNB().
+  - If the configuration file changes the signal SIGUSR1 is emitted which is caught by the standard
+    signal handler. The handler invokes ConfigChanged() which can be redefined by the user application.
+	The signal is delivered only to the main thread (where the constructor is executed) and thus
+	blocking rpc can be made from it.
   - Signal handlers to ignore common signals are installed.
     These signals will then cause pause() to return which can be used
 	by the application to terminate gracefully.
-  - The static method ToString() converts the contents of a
-    DIMInfo service into text
+  - The static method ToString() converts the contents of a DIMInfo service into text
   - A terminate-handler is installed for catching unhandled C++ exceptions.
 
-  Memory allocated by the non-static methods will be freed by the
-  class destructor.
-  
   Oliver Grimm, June 2010
  
@@ -27,12 +27,159 @@
 using namespace std;
 
+EvidenceServer *ThisServer;
+
+//
+// Internal configuration class of EvidenceServer
+//
+// Data that might be accessed by two threads are protected by mutex
+
+// Constructor
+EvidenceServer::Config::Config(string Name): DimRpcInfo("ConfigRequest", NO_LINK), Name(Name) {
+
+  // Initialise
+  int Ret;
+  if ((Ret = pthread_mutex_init(&Mutex, NULL)) != 0) {
+    ThisServer->Message(ThisServer->FATAL, "pthread_mutex_init() failed in Config constructor (%s)", strerror(Ret));
+  }
+  CurrentItem = string();
+  ConfigTimeStamp = 0;
+  
+  // SIGUSR2 delivered to this thread if configuration file changes 
+  ThreadID = pthread_self();
+
+  // Subscribe to be informed on configuration file change
+  Service = new DimInfo("Config/ModifyTime", NO_LINK, this);
+}
+
+// Destructor
+EvidenceServer::Config::~Config() {
+  
+  delete Service;
+
+  int Ret;
+  if ((Ret = pthread_mutex_destroy(&Mutex)) != 0) {
+	ThisServer->Message(ThisServer->ERROR, "pthread_mutex_destroy() failed in Config destructor (%s)", strerror(Ret));
+  }
+}
+
+// Track last modification time of configuration file
+void EvidenceServer::Config::infoHandler() {
+
+  Lock();
+  ConfigTimeStamp = getInfo()->getInt();
+  Unlock();
+
+  if (pthread_kill(ThreadID, SIGUSR2) != 0) {
+	ThisServer->Message(ThisServer->WARN, "Could not send signal SIGUSR2 to main thread");
+  }
+}
+
+// Receive answer to remote procedure call
+void EvidenceServer::Config::rpcInfoHandler(){
+
+  Lock();
+  // Update map
+  List[CurrentItem].Value = string(getString(), getSize()-1);
+  List[CurrentItem].Time = ConfigTimeStamp;
+  // Clear to allow new rpc call
+  CurrentItem.clear(); 
+  Unlock();
+}
+
+// Return configuration data if still up to date or empty string otherwise
+string EvidenceServer::Config::GetConfig(string Item, string Default) {
+
+  string Result;
+
+  // If up-to-date data in configuration list available, return this
+  Lock();
+  if ((List.count(Item) > 0) && (List[Item].Time >= ConfigTimeStamp)) Result = List[Item].Value;
+  Unlock();
+  if (!Result.empty()) return Result;
+
+  // Blocking configuration request if in main thread
+  if (pthread_self() == ThreadID) {
+	DimRpcInfo Config((char *) "ConfigRequest", NO_LINK);
+	Config.setData((char *) (Name + " " + Item).c_str());
+
+	// Check if successful
+	if (!EvidenceServer::ServiceOK(&Config)) {
+      if (Default.empty()) {
+		ThisServer->Message(ThisServer->FATAL, "Configuration server unreachable, can't retrieve '%s'", Item.c_str());
+	  }
+	  else Result = Default;
+	}
+	else {
+	  if (Config.getSize() == 0) Result = Default;
+	  else Result = string(Config.getString(), Config.getSize()-1); // Retrieve string safely
+    }
+
+	// Update configuration map	
+	if (!Result.empty()) {
+	  Lock();
+	  List[Item].Value = Result;
+	  List[Item].Time = ConfigTimeStamp;
+	  Unlock();
+	}	
+  }
+
+  // Non-blocking configuration request fro other threads
+  if (pthread_self() != ThreadID) {
+ 	Lock();
+	if (List.count(Item) > 0) {
+	  // New request possible only when answer to previous request received
+	  if (CurrentItem.empty()) {
+		CurrentItem = Item;
+		setData(((char *) (Name + " " + Item).c_str()));
+	  }
+
+	  // Return current value
+	  Result = List[Item].Value;
+	  Unlock();
+	}
+  }
+
+  return Result;
+}
+
+// Locking and unlocking for list access. Signal SIGUSR2 is also blocked.
+void EvidenceServer::Config::Lock() {
+
+  int Ret = 0;
+  sigset_t Set;
+  //printf("Locking %u\n", pthread_self());
+  Ret += abs(sigemptyset(&Set));
+  Ret += abs(sigaddset(&Set, SIGUSR2));
+  Ret += abs(pthread_sigmask(SIG_BLOCK, &Set, NULL));
+  Ret += abs(pthread_mutex_lock(&Mutex));
+  
+  if (Ret != 0) {
+	ThisServer->Message(ThisServer->FATAL, "Thread related call failed in Config::Lock()");
+  }
+}
+
+void EvidenceServer::Config::Unlock() {
+
+  int Ret = 0;
+  sigset_t Set;
+  //printf("  Unlocking %u\n", pthread_self());
+
+  Ret += abs(pthread_mutex_unlock(&Mutex));
+  Ret += abs(sigemptyset(&Set));
+  Ret += abs(sigaddset(&Set, SIGUSR2));
+  Ret += abs(pthread_sigmask(SIG_UNBLOCK, &Set, NULL));
+
+  if (Ret != 0) {
+	ThisServer->Message(ThisServer->FATAL, "Thread related call failed in Config::Unlock()");
+  }
+}
+
+
 //////////////////////////
 // EvidenceServer Class //
 //////////////////////////
 
-EvidenceServer *ThisServer;
-
 // Constructor starts server with given name
-EvidenceServer::EvidenceServer(const char *Name) {
+EvidenceServer::EvidenceServer(const char *ServerName): Name(ServerName) {
 
   // Initialize
@@ -41,5 +188,4 @@
   ExitRequest = false;
   ThisServer = this;
-  ServerName = Name;
 
   // Catch some signals
@@ -48,13 +194,18 @@
   signal(SIGINT, &SignalHandler);   // CTRL-C
   signal(SIGHUP, &SignalHandler);   // Terminal closed
+  
+  struct sigaction S;
+  S.sa_handler = &SignalHandler;
+  S.sa_flags = SA_RESTART;
+  sigaction(SIGUSR2, &S, NULL);
 
   // Catch C++ unhandled exceptions
   set_terminate(Terminate);
 
-  // Subscribe to modify service for keeping track of config file changes
-  ModifyInfo = new class ConfigUpdate();
+  // Configuration class (instantiate after signal handling for SIGUSR2 installed)
+  ConfClass = new class Config(Name);
 
   // Message service and initial message
-  MessageService = new DimService((ServerName+"/Message").c_str(), (char *) "I:1;C", NULL, 0);
+  MessageService = new DimService((Name+"/Message").c_str(), (char *) "I:1;C", NULL, 0);
 
   string Rev(EVIDENCE_REVISION); 
@@ -62,6 +213,6 @@
 
   // Start server
-  start(Name);
-  addExitHandler(this);  
+  start(ServerName);
+  addExitHandler(this);
 }
 
@@ -71,6 +222,5 @@
   Message(INFO, "Server stopped");
   
-  for (unsigned int i=0; i<ConfigList.size(); i++) delete[] ConfigList[i].Value;
-  delete ModifyInfo;
+  delete ConfClass;
   delete MessageService;
   delete MessageData;
@@ -152,54 +302,11 @@
 // Program terminates if data is missing and no default given. Actual configuration
 // request will be made only if config file has modification since last request.
-// The memory allocated by all calls to this function will be freed by
-// the destructor.
-char* EvidenceServer::GetConfig(string Item, const char *Default) {
-  
-  int ItemNo = -1;
-  
-  // Check if configuration request already in list
-  for (unsigned int i=0; i<ConfigList.size(); i++) if (ConfigList[i].Name == Item) {
-	// Return original value if still up to date
-	if (ConfigList[i].Time >= ModifyInfo->LastModifyTime) return ConfigList[i].Value;
-
-	// Otherwise, free memory of old value
-	delete[] ConfigList[i].Value;
-	ItemNo = i;
-	break;
-  } 
-
-  // Make configuration request
-  DimRpcInfo Config((char *) "ConfigRequest", NO_LINK);
-  Config.setData((char *) (ServerName + " " + Item).c_str());
-  char *Result = Config.getString();
-
-  // Terminate if not successful
-  if (!EvidenceServer::ServiceOK(&Config)) {
-    if (Default == NULL) Message(FATAL, "Configuration server unreachable, can't get '%s'", Item.c_str());
-	Result = (char *) Default;
-  }
-
-  if (strlen(Result) == 0) {
-    if (Default == NULL) Message(FATAL, "Missing configuration data '%s'", Item.c_str());
-	Result = (char *) Default;
-  }
-
-  // Enlarge list if necessary
-  if (ItemNo == -1) {
-    struct ConfigItem New;
-    ConfigList.push_back(New);
-	ItemNo = ConfigList.size()-1;
-  }
-
-  // Create new entry in item list, allocate memory and copy data to this memory
-  ConfigList[ItemNo].Name = Item;
-  ConfigList[ItemNo].Value = new char [strlen(Result)+1];
-  strcpy(ConfigList[ItemNo].Value, Result);
-  ConfigList[ItemNo].Time = ModifyInfo->LastModifyTime;
-
-  // Return address to configuration value  
-  return ConfigList[ItemNo].Value;
-}
-
+// If called from infoHandler(), a non-blocking request will be made
+string EvidenceServer::GetConfig(string Item, string Default) {
+
+  string Result = ConfClass->GetConfig(Item, Default);
+  if (Result.empty()) Message(FATAL, "Missing configuration data '%s'", Item.c_str());
+  return Result;
+}
 
 // ====== Static methods ======
@@ -209,4 +316,10 @@
 
   static bool Called = false;
+
+  // If SIGUSR2, invoke call-back for configuraton change
+  if (Signal == SIGUSR2) {
+    ThisServer->ConfigChanged();
+	return;
+  }
 
   // At first invocation just request exit
@@ -261,49 +374,41 @@
 
 
-// Translates DIMInfo to string (memory has to be freed by caller)
-// Static method, cannot report memory allocation errors via Message() but returns NULL
-char *EvidenceServer::ToString(DimInfo *Item) {
-
-  char *Text;
-
+// Translates DIMInfo safely to string (assures no inivalid memory accesses are made)
+string EvidenceServer::ToString(DimInfo *I) {
+
+  ostringstream Text;
+  
   // Safety check
-  if (Item->getSize() < 1) return NULL;
-
-  // Message structure format handled
-  if (strcmp(Item->getFormat(), "I:1;C") == 0) {
-	struct Message *Msg = (struct Message *) Item->getData();
-	if (asprintf(&Text, "%d %s", Msg->Severity, Msg->Text) == -1) return NULL;
-	else return Text;
-  }
-  
-  // Structure: print hex representation (3 characters per byte)  
-  if (strlen(Item->getFormat()) != 1) {
-    int Size = 3*Item->getSize()+1, N;
-    if ((Text = (char *) malloc(Size)) == NULL) return NULL;
-	
-	char *CurrPos = Text;
-	for (int i=0; i<Item->getSize(); i++) {
-	  N = snprintf(CurrPos, Size, "%02x ", *((char *) Item->getData() + i));
-	  if (N<0 || N>=Size) {
-	    free(Text);
-		if (asprintf(&Text, "Structure length %d bytes, buffer overflow in ToString()", Item->getSize()) == -1) return NULL;
-		else return Text;
-	  }
-	  Size -= N;
-	  CurrPos += N;
+  if (I->getSize() < 1) return string();
+
+  // 'Message' service format handled here
+  if (strcmp(I->getFormat(), "I:1;C") == 0 && I->getSize()>=(int) sizeof(struct Message)) {
+	struct Message *Msg = (struct Message *) I->getData();
+	// Safely extract string and limit to length of C string (padding might make it longer)
+	string MsgText(Msg->Text, I->getSize()-sizeof(struct Message));
+    //MsgText.erase(strlen(MsgText.c_str()));
+	Text << Msg->Severity << " " << MsgText.erase(strlen(MsgText.c_str()));
+
+	return Text.str();
+  }
+  
+  // Structure: print hex representation 
+  if (strlen(I->getFormat()) != 1) {
+	for (int i=0; i<I->getSize(); i++) {
+	  Text << setw(2) << hex << *((char *) I->getData() + i) << " ";
 	} 
-	return Text;
-  }
-
-  // String: terminating \0 is enforced
-  if (toupper(*(Item->getFormat())) == 'C') {  
-    *(Item->getString() + Item->getSize() - 1) = '\0'; 
-	if (asprintf(&Text, "%s", Item->getString()) == -1) return NULL;
-	return Text;
+	return Text.str();
+  }
+
+  // String if format "C" and terminated with \0
+  if (strcmp(I->getFormat(),"C")==0 && *((char *) I->getData()+I->getSize()-1)=='\0') {  
+    Text << I->getString(); 
+	return Text.str();
   }
 
   // Number array
   int Size;
-  switch (toupper(*(Item->getFormat()))) {
+  switch (*(I->getFormat())) {
+    case 'C': Size = sizeof(char);		break;
     case 'I':
     case 'L': Size = sizeof(int);		break;
@@ -312,34 +417,32 @@
     case 'D': Size = sizeof(double);	break;
     case 'X': Size = sizeof(long long);	break;
-    default: return NULL;
-  }
-
-  int Max, Mem = Item->getSize()*Size*4+1;
-  char *Pos;
-
-  if ((Text = (char *) malloc(Mem)) == NULL) return NULL;
-
-  *Text = '\0';
-  for (int i=0; i<Item->getSize()/Size; i++) {
-	Pos = Text+strlen(Text);
-	Max = Mem-strlen(Text);
-
-	switch (toupper(*(Item->getFormat()))) {
+    default: return string();
+  }
+
+  for (int i=0; i<I->getSize()/Size; i++) {
+	// Space between entries
+    if (i != 0) Text << " ";
+
+	// Translate data
+	switch (*(I->getFormat())) {
+      case 'C': Text << *((char *) I->getData() + i);
+				break;
       case 'I':
-      case 'L': snprintf(Pos, Max, "%d ", *((int *) Item->getData() + i));
+      case 'L': Text << *((int *) I->getData() + i);
 				break;
-      case 'S': snprintf(Pos, Max, "%hd ", *((short *) Item->getData() + i));
+      case 'S': Text << *((short *) I->getData() + i);
 				break;
-      case 'F': snprintf(Pos, Max, "%.5f ", *((float *) Item->getData() + i));
+      case 'F': Text << *((float *) I->getData() + i);
 				break;
-      case 'D': snprintf(Pos, Max, "%.5f ", *((double *) Item->getData() + i));
+      case 'D': Text << *((double *) I->getData() + i);
 				break;
-      case 'X': snprintf(Pos, Max, "%lld ", *((long long *) Item->getData() + i));
+      case 'X': Text << *((long long *) I->getData() + i);
 				break;
 	}
   }
   
-  return Text;
-}
+  return Text.str();
+}
+
 
 // Checks if service contents indicates not available
@@ -355,4 +458,27 @@
 	  (memcmp(Item->getData(), NO_LINK, Item->getSize()) == 0));
 }
+
+
+// Tokenize std::string using given delimeter list
+vector<string> EvidenceServer::Tokenize(const string &String, const string &Delimiters) {
+
+  vector<string> Tokens;
+  string::size_type Next, EndNext=0;
+    
+  while (EndNext != string::npos) {
+    // Find next token
+    Next = String.find_first_not_of(Delimiters, EndNext);
+    EndNext = String.find_first_of(Delimiters, Next);
+
+	// Stop if end of string reached
+	if (Next == string::npos) break;
+
+    // Add token to vector.
+    Tokens.push_back(String.substr(Next, EndNext - Next));
+  }
+  
+  return Tokens;
+}
+
 
 ///////////////////////////
Index: /Evidence/Evidence.h
===================================================================
--- /Evidence/Evidence.h	(revision 228)
+++ /Evidence/Evidence.h	(revision 229)
@@ -5,6 +5,10 @@
 #include <stdarg.h>
 #include <string>
+#include <sstream>
+#include <iomanip>
 #include <errno.h>
 #include <vector>
+#include <map>
+
 #include <exception>
 #include <cxxabi.h>
@@ -17,44 +21,34 @@
 #define EVIDENCE_REVISION "$Revision$"
 
+
 // Class declation of Evidence server
 class EvidenceServer: public DimServer {
 
-  private:
-	// This class will contain in LastModifyTime always
-	// the unix time of the last config file update 
-	class ConfigUpdate: public DimClient, public DimRpcInfo {
- 	  DimInfo *ModifyInfo;
-	  
+	// Internal class for configuration requests
+	class Config: public DimClient, public DimRpcInfo {
+
+		pthread_mutex_t Mutex;
+		std::string Name;
+		DimInfo *Service;
+		int ConfigTimeStamp;
+		std::string CurrentItem;
+		pthread_t ThreadID;
+
+		struct Item {
+		  std::string Value;
+		  int Time;
+		};
+		std::map<std::string, struct Item> List;
+
 	  public:
-	    ConfigUpdate(): DimRpcInfo("ConfigRequest", NO_LINK) {
-	      LastModifyTime = 0;
-		  ModifyInfo = new DimInfo("Config/ModifyTime", NO_LINK, this);
-	    }
-		~ConfigUpdate() {
-		  delete ModifyInfo;
-		}
-	    void Request(const char *What){
-	      setData((char *) What);
-	    }
+		Config(std::string);
+		~Config();
 
-	    void infoHandler(){
-	      if (EvidenceServer::ServiceOK(getInfo())) LastModifyTime = getInfo()->getInt();
-	    }
-
-	    void rpcInfoHandler(){
-		  //printf("Received %s\n", getString());
-	    }
-
-		int LastModifyTime;
+		std::string GetConfig(std::string, std::string);
+		void Lock();
+		void Unlock();
+		void infoHandler();
+		void rpcInfoHandler();
 	};
-
-  private:
-
-	struct ConfigItem {
-	  std::string Name;
-	  char *Value;
-	  int Time;
-	};
-	std::vector<struct ConfigItem> ConfigList;
 
 	struct Message {
@@ -63,8 +57,8 @@
 	};
 
-	std::string ServerName;
+	std::string Name;
     DimService *MessageService;
 	struct Message *MessageData;
-	class ConfigUpdate *ModifyInfo;
+	class Config *ConfClass;
 	
     static void SignalHandler(int); // static for signal()
@@ -72,5 +66,6 @@
 	void errorHandler(int, int, char *);
 	void exitHandler(int);
-	
+	virtual void ConfigChanged() {};
+
   public:
     EvidenceServer(const char *);
@@ -81,8 +76,9 @@
 	void Message(MessageType, const char *, ...);
 	void SendToLog(const char *, ...);
-	char* GetConfig(std::string, const char * = NULL);
-	static char* ToString(DimInfo *);
+	std::string GetConfig(std::string, std::string = std::string());
+	static std::string ToString(DimInfo *);
 	static bool ServiceOK(DimInfo *);
 	static bool ServiceOK(DimRpcInfo *);
+	static std::vector<std::string> Tokenize(const std::string &, const std::string & = " ");
 
     bool ExitRequest;
Index: /Evidence/History.cc
===================================================================
--- /Evidence/History.cc	(revision 228)
+++ /Evidence/History.cc	(revision 229)
@@ -23,8 +23,10 @@
 
 #include <string>
-#include <vector>
+#include <sstream>
+#include <map>
 #include <math.h>
 #include <float.h>
 #include <sys/stat.h>
+#include <sys/time.h>
 
 using namespace std;
@@ -43,9 +45,9 @@
 	  string Format;
 	};
-	vector<struct Item> List;
+	map<string, struct Item> Map;
 	
 	DimInfo *ServerList;
 	char *Directory;
-	char *Change;
+	string Change;
 
     void infoHandler();
@@ -67,5 +69,5 @@
 							 Directory(Dir) {
 
-  // List of minimum required change for addition to history buffer 
+  // Map of minimum required change for addition to history buffer 
   Change = GetConfig("minchange", " ");
 
@@ -79,5 +81,5 @@
 
   delete ServerList;
-  while (List.size() != 0) RemoveService(List[0].DataItem->getName());
+  while (Map.size() != 0) RemoveService((*Map.begin()).first);
 }
 
@@ -106,4 +108,13 @@
   // If service is SERVICE_LIST, scan and subscribe/unsubscribe to services
   if (strstr(I->getName(), "/SERVICE_LIST") != NULL) {
+
+	// Bug fix for empty SERVICE_LIST
+	if (strlen(I->getString()) == 0) {
+	  string Tmp(I->getName());
+	  RemoveService(I->getName());
+	  AddService(Tmp.c_str(), (char *) "C");
+	  return;
+	}
+
 	char *Type, *Name = strtok(I->getString(), "+-!|");
 	while (Name != NULL) {
@@ -124,44 +135,39 @@
   // ====== Part B: Handle history service ===
 
-  // Identify index of service
-  int Service;
-  for (Service=0; Service<List.size(); Service++) if (I == List[Service].DataItem) break;
-  if (Service == List.size()) return;  // Service not found
-
-  // Ignore empty services
-  if (I->getSize()==0 || I->getTimestamp()==0) return;
-
+  char *Service = I->getName();
+
+  // Check if service known and ignore empty service
+  if (Map.count(Service) == 0 || I->getSize()==0 || I->getTimestamp()==0) return;
+  
   // Resize buffer if necessary
-  if (List[Service].Buffer.size() < REQUEST_NUM*I->getSize()) {
-	if (REQUEST_NUM*I->getSize() < MAX_SIZE_KB*1024) List[Service].Buffer.resize(REQUEST_NUM*I->getSize());
-  }
-
-  // If data is number of single type, a minumum change might be requested before addind to history
-  if (strcmp(I->getFormat(),"C") != 0 && strlen(I->getFormat())==1) {
+  if (Map[Service].Buffer.size() < REQUEST_NUM*I->getSize()) {
+	if (REQUEST_NUM*I->getSize() < MAX_SIZE_KB*1024) Map[Service].Buffer.resize(REQUEST_NUM*I->getSize());
+  }
+
+  // If data is number of single type, check minumum change before adding to history
+  if (strcmp(I->getFormat(), "C") != 0) {
 	// Calculate sum of all number in array
-	char *Text = EvidenceServer::ToString(I);
-	char *Token = strtok(Text, " ");
-	double Sum = 0;
-	while (Token != NULL) {
-	  Sum += atof(Token);
-      Token = strtok(NULL, " ");
-	}
-	free(Text);
+	istringstream Text(EvidenceServer::ToString(I));
+	double Num, Sum = 0;
+	while (Text.good()) {
+	  Text >> Num;
+	  Sum += fabs(Num);
+	}
 
 	// Minimum change?
-	if (fabs(Sum-List[Service].LastValue) < fabs(List[Service].MinAbsChange)) return;
-	List[Service].LastValue = Sum;
+	if (fabs(Sum-Map[Service].LastValue) < fabs(Map[Service].MinAbsChange)) return;
+	Map[Service].LastValue = Sum;
   }
   
   // Check if data fits into buffer
-  if (List[Service].Buffer.size() < I->getSize() + sizeof(int)+ 2*sizeof(EvidenceHistory::Item)) return;
-
-  int Size = I->getSize() + 2*sizeof(EvidenceHistory::Item), Next = List[Service].Next;
+  if (Map[Service].Buffer.size() < I->getSize() + sizeof(int)+ 2*sizeof(EvidenceHistory::Item)) return;
+
+  int Size = I->getSize() + 2*sizeof(EvidenceHistory::Item), Next = Map[Service].Next;
   void *WrapPos = NULL;
-  char *Buffer = &List[Service].Buffer[0];
+  char *Buffer = &Map[Service].Buffer[0];
   int Oldest = *(int *) Buffer;
 
   // Check if buffer wrap-around (write wrap mark after Oldest is adjusted)
-  if (Next + Size >= List[Service].Buffer.size()) {
+  if (Next + Size >= Map[Service].Buffer.size()) {
     WrapPos = Buffer + Next;
     Next = sizeof(int);
@@ -199,5 +205,5 @@
   memcpy(Buffer + Next, &EvidenceHistory::EndMark, sizeof(EvidenceHistory::EndMark));
   
-  List[Service].Next = Next;
+  Map[Service].Next = Next;
 }
 
@@ -206,19 +212,18 @@
 void History::rpcHandler() {
 
-  // Search for history buffer
-  for (int i=0; i<List.size(); i++) {
-    if (strcmp(List[i].DataItem->getName(), getString()) == 0) {
-	  char *Buffer = new char [List[i].Format.size()+1+List[i].Buffer.size()];
-	  strcpy(Buffer, List[i].Format.c_str());
-	  memcpy(Buffer+List[i].Format.size()+1, &List[i].Buffer[0], List[i].Buffer.size());
-//	  setData((void *) &List[i].Buffer[0], List[i].Buffer.size());
-	  setData((void *) Buffer, List[i].Format.size()+1+List[i].Buffer.size());
-	  delete[] Buffer;
-	  return;
-	}
+  char *Name = getString();
+  
+  // Search for history buffer in memory
+  if (Map.count(Name) == 1) {
+	char *Buffer = new char [Map[Name].Format.size()+1+Map[Name].Buffer.size()];
+	strcpy(Buffer, Map[Name].Format.c_str());
+	memcpy(Buffer+Map[Name].Format.size()+1, &Map[Name].Buffer[0], Map[Name].Buffer.size());
+	setData((void *) Buffer, Map[Name].Format.size()+1+Map[Name].Buffer.size());
+	delete[] Buffer;
+	return;
   }
 
   // Try to open history file if not found in memory
-  FILE *File = OpenFile(getString(), "rb");
+  FILE *File = OpenFile(Name, "rb");
   if (File == NULL) {
     setData(NULL, 0);
@@ -232,5 +237,5 @@
 	fseek(File, sizeof(int), SEEK_SET); // Skip 'Next' pointer
 	if ((fread(Buffer, sizeof(char), Size-sizeof(int), File) != Size-sizeof(int)) || (ferror(File) != 0)) {
-	  Message(WARN, "Error reading history file '%s' in rpcHandler()", getString());
+	  Message(WARN, "Error reading history file '%s' in rpcHandler()", Name);
 	  setData(NULL, 0);		// Default response
 	}
@@ -239,5 +244,5 @@
   }
   
-  if (fclose(File) != 0) Message(WARN, "Error closing history file '%s' in rpcHandler()", getString());
+  if (fclose(File) != 0) Message(WARN, "Error closing history file '%s' in rpcHandler()", Name);
 }
 
@@ -248,18 +253,15 @@
 void History::AddService(string Name, const char *Format) {
 
-  // Check if already subscribed to this service
-  for (int i=0; i<List.size(); i++) {
-	if (Name == List[i].DataItem->getName()) return;
-  }
-
-  struct Item New;
-  New.LastValue = DBL_MAX;
-  New.Format = Format;
-
+  // Return if already subscribed to this service
+  if (Map.count(Name) != 0) return;
+
+  // Create new service subscription
+  Map[Name].LastValue =  DBL_MAX;
+  Map[Name].Format = Format;
+  Map[Name].MinAbsChange = 0.0;
+  
   // Set minimum required change if given in configuratrion
-  char *Pnt = strstr(Change, Name.c_str());
-
-  if (Pnt != NULL && *(Pnt+Name.size()) == ':') New.MinAbsChange = atof(Pnt+Name.size()+1);
-  else New.MinAbsChange = 0;
+  size_t Pos = Change.find(Name+":");
+  if (Pos != string::npos) Map[Name].MinAbsChange = atof(Change.c_str() + Pos + Name.size() + 1);
 
   // Load history buffer from file if existing
@@ -270,16 +272,16 @@
 
     // If current buffer too small, resize
-	if (Size > New.Buffer.size()) New.Buffer.resize(Size);
+	if (Size > Map[Name].Buffer.size()) Map[Name].Buffer.resize(Size);
 
 	// Read next pointer
-    fread(&New.Next, sizeof(New.Next), 1, File);
+    fread(&Map[Name].Next, sizeof(Map[Name].Next), 1, File);
 	// Skip format string
 	while (fgetc(File) != 0 && feof(File) == 0) {}
 	// Read buffer
-    fread(&New.Buffer[0], sizeof(char), Size, File);
+    fread(&Map[Name].Buffer[0], sizeof(char), Size, File);
 
 	if (ferror(File) != 0) {
 	  Message(WARN, "Error reading history file '%s' in AddService()", Name.c_str());
-	  New.Buffer.clear();
+	  Map[Name].Buffer.clear();
 	}
     if (fclose(File) != 0) Message(WARN, "Error closing history file '%s' in AddService()", Name.c_str());;
@@ -287,15 +289,13 @@
 
   // If no buffer loaded, allocate empty buffer
-  if (New.Buffer.empty()) {
-	New.Buffer.resize(MIN_SIZE_KB*1024);
-	memset(&New.Buffer[0], 0, New.Buffer.size());
-	*(int *) &New.Buffer[0] = 4;
-	New.Next = 4;
+  if (Map[Name].Buffer.empty()) {
+	Map[Name].Buffer.resize(MIN_SIZE_KB*1024);
+	memset(&Map[Name].Buffer[0], 0, Map[Name].Buffer.size());
+	*(int *) &Map[Name].Buffer[0] = 4;
+	Map[Name].Next = 4;
   }
   
   // Subscribe to service
-  New.DataItem = new DimStampedInfo(Name.c_str(), NO_LINK, this);
-
-  List.push_back(New);
+  Map[Name].DataItem = new DimStampedInfo(Name.c_str(), NO_LINK, this);
 }
 
@@ -306,27 +306,26 @@
 void History::RemoveService(string Name) {
 
-  // Find service index
-  vector<struct Item>::iterator E;
-  for (E=List.begin(); E<List.end(); ++E) if (Name == (*E).DataItem->getName()) {
-	// Delete subscription first so handler and not called anymore
-	delete (*E).DataItem;
-
-	// Save history buffer
-	FILE *File = OpenFile(Name, "wb");
-	if (File != NULL) {
-      fwrite(&(*E).Next, sizeof((*E).Next), 1, File);					// Next pointer
-      fwrite((*E).Format.c_str(), (*E).Format.size()+1, 1, File);		// Format
-      fwrite(&(*E).Buffer[0], sizeof(char), (*E).Buffer.size(), File);	// Buffer
-
-	  // If error, try to delete (possibly erroneous) file 
-	  if (ferror(File) != 0) {
-		if (remove(Name.c_str()) == -1) Message(WARN, "Error writing history file '%s' in RemoveService(), could also not delete file", Name.c_str());
-		else Message(WARN, "Error writing history file '%s' in RemoveService(), deleted file", Name.c_str());
-	  }
-      if (fclose(File) != 0) Message(WARN, "Error closing history file '%s' in RemoveService()", Name.c_str());;
-	}
-	
-	List.erase(E);
-  }
+  // Check if actually subscribed to service  
+  if (Map.count(Name) == 0) return;
+
+  // Delete subscription first so handler and not called anymore
+  delete Map[Name].DataItem;
+
+  // Save history buffer
+  FILE *File = OpenFile(Name, "wb");
+  if (File != NULL) {
+    fwrite(&Map[Name].Next, sizeof(Map[Name].Next), 1, File);					// Next pointer
+    fwrite(Map[Name].Format.c_str(), Map[Name].Format.size()+1, 1, File);		// Format
+    fwrite(&Map[Name].Buffer[0], sizeof(char), Map[Name].Buffer.size(), File);	// Buffer
+
+	// If error, try to delete (possibly erroneous) file 
+	if (ferror(File) != 0) {
+	  if (remove(Name.c_str()) == -1) Message(WARN, "Error writing history file '%s' in RemoveService(), could also not delete file", Name.c_str());
+	  else Message(WARN, "Error writing history file '%s' in RemoveService(), deleted file", Name.c_str());
+	}
+    if (fclose(File) != 0) Message(WARN, "Error closing history file '%s' in RemoveService()", Name.c_str());;
+  }
+
+  Map.erase(Name);
 }
 
@@ -377,4 +376,4 @@
   
   // Sleep until signal caught
-  pause();
-}
+  while (!Hist.ExitRequest) pause();
+}
Index: /Evidence/readme.txt
===================================================================
--- /Evidence/readme.txt	(revision 228)
+++ /Evidence/readme.txt	(revision 229)
@@ -20,5 +20,4 @@
 to run.
 
-- Oliver Grimm, 18/1/2010
 
 Version history
@@ -44,4 +43,11 @@
 			service for each observed server SERVERNAME/AlarmLevel contains the highest
 			level that occurred in the past. Reset of alarm level only via a DIM command.
+19/6/2010	ToString() now returns std::string
+23/6/2010	GetConfig() returns std::string. Non-blocking configuration request in case
+			GetConfig() not called from main thread. Access to configuration information
+			internally mutex protected. Signal SIGUSR2 send to main thread upon configuration
+			file change, signal handler invokes (virtual) method ConfigChanged().
+24/6/2010	Workaround for erroneous /SERVICE_LIST updates. Added static tokenize method to
+			Evidence class.
 
 
Index: /drsdaq/DAQReadout.cc
===================================================================
--- /drsdaq/DAQReadout.cc	(revision 228)
+++ /drsdaq/DAQReadout.cc	(revision 229)
@@ -90,12 +90,14 @@
   MinDelay  			= 1;
 
-  // Get configuration data
-  fRawDataPath = GetConfig("RawDataPath");
-  fCalibDataPath = GetConfig("CalibDataPath");
-  fFirstSample = atoi(GetConfig("FirstSample"));
-  fSamples = atoi(GetConfig("Samples"));
-  fMinDiskSpaceMB = atoi(GetConfig("MinDiskSpaceMB"));
-  fMaxFileSizeMB = atoi(GetConfig("MaxFileSizeMB"));
-  fDefaultFrequency = atof(GetConfig("DefaultFrequency"));
+  // Get configuration data (static needed for c_str() pointers to remain valid after constructor finished)
+  static std::string _RawDataPath = GetConfig("RawDataPath");
+  static std::string _CalibDataPath = GetConfig("CalibDataPath");
+  fRawDataPath = _RawDataPath.c_str();
+  fCalibDataPath = _CalibDataPath.c_str();
+  fFirstSample = atoi(GetConfig("FirstSample").c_str());
+  fSamples = atoi(GetConfig("Samples").c_str());
+  fMinDiskSpaceMB = atoi(GetConfig("MinDiskSpaceMB").c_str());
+  fMaxFileSizeMB = atoi(GetConfig("MaxFileSizeMB").c_str());
+  fDefaultFrequency = atof(GetConfig("DefaultFrequency").c_str());
 
   if (fFirstSample < 0 || fFirstSample > kNumberOfBins || fSamples > kNumberOfBins) {
@@ -1417,5 +1419,5 @@
 
 // Return current available storage space in given directory
-int CheckDisk(char *Directory) {
+int CheckDisk(const char *Directory) {
   struct statfs FileSystemStats;
 
Index: /drsdaq/DAQReadout.h
===================================================================
--- /drsdaq/DAQReadout.h	(revision 228)
+++ /drsdaq/DAQReadout.h	(revision 229)
@@ -52,6 +52,6 @@
 
     // Configuration data
-    char *fCalibDataPath;
-    char *fRawDataPath;
+    const char *fCalibDataPath;
+    const char *fRawDataPath;
     int fMinDiskSpaceMB;   // Minimum required disk space in MBytes
     int fMaxFileSizeMB;    // Maximum File size in Bytes 
@@ -145,5 +145,5 @@
 bool Match(const char*, const char*);
 int ParseInput(char*, const char *Param[]);
-int CheckDisk(char*);
+int CheckDisk(const char*);
 
 #endif
Index: /drsdaq/HVFeedback.cc
===================================================================
--- /drsdaq/HVFeedback.cc	(revision 228)
+++ /drsdaq/HVFeedback.cc	(revision 229)
@@ -22,4 +22,6 @@
 };
 
+using namespace std;
+
 //
 // Constructor: Initialise feedback 
@@ -45,32 +47,30 @@
 
   // Get configuration data
-  fLedTrigBoard = atoi(m->GetConfig("TrigBoard"));
-  fLedTrigChannel = atoi(m->GetConfig("TrigChannel"));
-  fLedTrigChip = atoi(m->GetConfig("TrigChip"));
-  fLedTrigSample = atoi(m->GetConfig("TrigSample"));
-  fLedTrigThreshold = atoi(m->GetConfig("TrigThreshold"));
-  fLedSignalSample = atoi(m->GetConfig("SignalSample"));
-  fLedBaselineSample = atoi(m->GetConfig("BaselineSample"));
-  fIntHalfWidth = atoi(m->GetConfig("IntHalfWidth"));
-  fDefaultNumAverage = atoi(m->GetConfig("DefaultNumAverage"));
-
-  char *Token = strtok(m->GetConfig("DefaultResponse"), " \t");
+  fLedTrigBoard = atoi(m->GetConfig("TrigBoard").c_str());
+  fLedTrigChannel = atoi(m->GetConfig("TrigChannel").c_str());
+  fLedTrigChip = atoi(m->GetConfig("TrigChip").c_str());
+  fLedTrigSample = atoi(m->GetConfig("TrigSample").c_str());
+  fLedTrigThreshold = atoi(m->GetConfig("TrigThreshold").c_str());
+  fLedSignalSample = atoi(m->GetConfig("SignalSample").c_str());
+  fLedBaselineSample = atoi(m->GetConfig("BaselineSample").c_str());
+  fIntHalfWidth = atoi(m->GetConfig("IntHalfWidth").c_str());
+  fDefaultNumAverage = atoi(m->GetConfig("DefaultNumAverage").c_str());
+
+  vector<string> Token = m->Tokenize(m->GetConfig("DefaultResponse"), " \t");
+  unsigned int N = 0;
   for (int i=0; i<m->NumBoards; i++) {
 	for (int j=0; j<fNumberOfChips; j++) {
 	  for (int k=0; k<fNumberOfChannels; k++) {
-		if (Token == NULL) break;
-    	Response[i][j][k] = (float) atof(Token);
-		Token = strtok(NULL, " \t");
+		if (N < Token.size()) Response[i][j][k] = (float) atof(Token[N++].c_str());
 	  }
 	}
   }
 
-  Token = strtok(m->GetConfig("DefaultTarget"), " \t");
+  Token = m->Tokenize(m->GetConfig("DefaultTarget"), " \t");
+  N = 0;
   for (int i=0; i<m->NumBoards; i++) {
 	for (int j=0; j<fNumberOfChips; j++) {
 	  for (int k=0; k<fNumberOfChannels; k++) {
-		if (Token == NULL) break;
-    	Target[i][j][k] = (float) atof(Token);
-		Token = strtok(NULL, " \t");
+		if (N < Token.size()) Target[i][j][k] = (float) atof(Token[N++].c_str());
 	  }
 	}
@@ -87,5 +87,5 @@
 
   // Initial state
-  Gain = atof(m->GetConfig("DefaultGain"));
+  Gain = atof(m->GetConfig("DefaultGain").c_str());
   SetFBMode(FB_Off);
   SetNumAverages(fDefaultNumAverage);
Index: /drsdaq/HVFeedback.h
===================================================================
--- /drsdaq/HVFeedback.h	(revision 228)
+++ /drsdaq/HVFeedback.h	(revision 229)
@@ -7,4 +7,5 @@
 #include <math.h>
 #include <sstream>
+#include <vector>
 
 #include "RawDataCTX.h"
Index: /hvcontrol/src/HV.cc
===================================================================
--- /hvcontrol/src/HV.cc	(revision 228)
+++ /hvcontrol/src/HV.cc	(revision 229)
@@ -14,30 +14,24 @@
 #include "ProcessIO.h" // Must be not in HV.h to avoid problem with declaring class ProcessIO
 
+using namespace std;
+
 // Constructor
-HVBoard::HVBoard(int DeviceNumber, char *DeviceName, class ProcessIO *PIO) {
+HVBoard::HVBoard(int DeviceNumber, string Name, class ProcessIO *PIO) {
    
-  char *Buffer;
   struct termios tio;
  
   m = PIO;
-
   SetTimeOut(m->fTimeOut);
   BoardNumber = DeviceNumber;
-  BoardName = DeviceName;
-  
+  BoardName = new char [Name.size()+1];
+  strcpy(BoardName, Name.c_str());
+  
+  stringstream Buf;
+  Buf << setw(2) << BoardNumber;
+  string Result =Buf.str();
+
   // Create DIM services
-  if (asprintf(&Buffer, SERVER_NAME"/NAME/ID%.2d", BoardNumber) == -1) {
-    m->PrintMessage(All, "asprintf() failed for DIM service name creation\n");
-	return;
-  }
-  Name = new DimService (Buffer, BoardName);
-  free(Buffer);
-  
-  if (asprintf(&Buffer, SERVER_NAME"/VOLT/ID%.2d", BoardNumber) == -1) {
-    m->PrintMessage(All, "asprintf() failed for DIM service name creation\n");
-	return;
-  }
-  BiasVolt = new DimService (Buffer, "D", HVV, NUM_CHAINS*NUM_CHANNELS*sizeof(double));
-  free(Buffer);
+  NameService = new DimService ((SERVER_NAME"/NAME/ID"+Result).c_str(), BoardName);
+  BiasVolt = new DimService ((char *) (SERVER_NAME"/VOLT/ID"+Result).c_str(), (char *) "D", HVV, NUM_CHAINS*NUM_CHANNELS*sizeof(double));
 
   for (int i=0; i<NUM_CHAINS; i++) Overcurrent[i] = false;
@@ -49,15 +43,8 @@
   ClearVoltageArrays();
 
-  // Open device (do not warn on non-existing device)
-  if (asprintf(&Buffer, "/dev/%s",DeviceName) == -1) {
-    m->PrintMessage(All, "asprintf() failed for device name creation\n");
-	return;
-  }
-  if ((fDescriptor = open(Buffer, O_RDWR|O_NOCTTY|O_NDELAY)) == -1) {
-    if(errno != 2) m->PrintMessage(All, "Error: Could not open device %d/%s (%s)\n", DeviceNumber,DeviceName, strerror(errno));
-	free(Buffer);
+  if ((fDescriptor = open(("/dev/"+Name).c_str(), O_RDWR|O_NOCTTY|O_NDELAY)) == -1) {
+    if(errno != 2) m->PrintMessage(All, "Error: Could not open device %d/%s (%s)\n", DeviceNumber, Name.c_str(), strerror(errno));
     return;
   }
-  free(Buffer);
 
   // Get current serial port settings
@@ -96,6 +83,7 @@
   }
 
-  delete Name;
+  delete NameService;
   delete BiasVolt;
+  delete[] BoardName;
 }
 
Index: /hvcontrol/src/HV.h
===================================================================
--- /hvcontrol/src/HV.h	(revision 228)
+++ /hvcontrol/src/HV.h	(revision 229)
@@ -8,4 +8,5 @@
 #include <unistd.h>
 #include <sys/ioctl.h>
+#include <string>
 
 #include "dis.hxx"
@@ -39,5 +40,5 @@
  public:
   
-   HVBoard(int, char *, class ProcessIO *);
+   HVBoard(int, std::string, class ProcessIO *);
    ~HVBoard();
 
@@ -54,5 +55,5 @@
    double HVV[NUM_CHAINS][NUM_CHANNELS];  // HV value in volts
 
-   DimService *Name;
+   DimService *NameService;
    DimService *BiasVolt;
 
Index: /hvcontrol/src/ProcessIO.cc
===================================================================
--- /hvcontrol/src/ProcessIO.cc	(revision 228)
+++ /hvcontrol/src/ProcessIO.cc	(revision 229)
@@ -12,5 +12,5 @@
 #include "ProcessIO.h"
 
-static char* state_str[]    = {"active", "stopped", "n.a."};
+static const char* state_str[]    = {"active", "stopped", "n.a."};
 
 // Branch table for command evaluation
@@ -63,30 +63,28 @@
 
   // Get configuration data
-  char *Boards = GetConfig("Boards");
+  vector<string> Boards = Tokenize(GetConfig("Boards"), " \t");
   fPixMapTable = GetConfig("PixMapTable");
-  fTimeOut = atof(GetConfig("TimeOut"));
-  fStatusRefreshRate = atof(GetConfig("StatusRefreshRate"));
-  DACMin = atoi(GetConfig("DACMin"));
-  DACMax = atoi(GetConfig("DACMax"));
-  fHVCalibOffset = atof(GetConfig("HVCalibOffset"));
-  fHVCalibSlope = atof(GetConfig("HVCalibSlope"));
-  fHVMaxDiff = atoi(GetConfig("HVMaxDiff"));
+  fTimeOut = atof(GetConfig("TimeOut").c_str());
+  fStatusRefreshRate = atof(GetConfig("StatusRefreshRate").c_str());
+  DACMin = atoi(GetConfig("DACMin").c_str());
+  DACMax = atoi(GetConfig("DACMax").c_str());
+  fHVCalibOffset = atof(GetConfig("HVCalibOffset").c_str());
+  fHVCalibSlope = atof(GetConfig("HVCalibSlope").c_str());
+  fHVMaxDiff = atoi(GetConfig("HVMaxDiff").c_str());
 
   if (fStatusRefreshRate < MIN_RATE || fStatusRefreshRate > MAX_RATE)  fStatusRefreshRate = 1;
 
   // Open HV devices
-  fHVBoard = new HVBoard* [strlen(Boards)]; 
-  char *Token = strtok(Boards, " \t");
-  while (Token != NULL) {
-    fHVBoard[NumHVBoards] = new HVBoard(NumHVBoards, Token, this);
+  fHVBoard = new HVBoard* [Boards.size()]; 
+  for (unsigned int i=0; i<Boards.size(); i++) {
+    fHVBoard[NumHVBoards] = new HVBoard(NumHVBoards, Boards[i], this);
     if(fHVBoard[NumHVBoards]->fDescriptor >= 0) {
-       PrintMessage("Synchronized and reset board %d (%s)\n",NumHVBoards,fHVBoard[NumHVBoards]->BoardName);
+       PrintMessage("Synchronized and reset board %d (%s)\n", NumHVBoards, fHVBoard[NumHVBoards]->BoardName);
        NumHVBoards++;
     }
     else {
-      PrintMessage(All, "Failed to synchronize board %d (%s)\n",NumHVBoards,fHVBoard[NumHVBoards]->BoardName);
+      PrintMessage(All, "Failed to synchronize board %d (%s)\n", NumHVBoards, fHVBoard[NumHVBoards]->BoardName);
       delete fHVBoard[NumHVBoards];
     }
-	Token = strtok(NULL, " \t");
   }
   LastBoard = NumHVBoards-1;
@@ -199,5 +197,5 @@
 
   PrintMessage( " Pixel map table:   %s\n"
-    	    	" %d USB devices:\n", fPixMapTable, NumHVBoards);  
+    	    	" %d USB devices:\n", fPixMapTable.c_str(), NumHVBoards);  
 
   for (int i=0; i<NumHVBoards; i++) PrintMessage(" Board %d: %s\n", i, fHVBoard[i]->BoardName);
Index: /hvcontrol/src/ProcessIO.h
===================================================================
--- /hvcontrol/src/ProcessIO.h	(revision 228)
+++ /hvcontrol/src/ProcessIO.h	(revision 229)
@@ -7,4 +7,5 @@
 #include <math.h>
 #include <signal.h>
+#include <string>
 
 #define SERVER_NAME "Bias"       // Name to use in DIM
@@ -46,5 +47,5 @@
 
 	// Configuration data
-	char *fPixMapTable;
+	std::string fPixMapTable;
 	float fTimeOut;
 	float fStatusRefreshRate;
Index: /tools/ListenToArduino/ListenToArduino.cc
===================================================================
--- /tools/ListenToArduino/ListenToArduino.cc	(revision 228)
+++ /tools/ListenToArduino/ListenToArduino.cc	(revision 229)
@@ -117,5 +117,5 @@
 	Data.updateService();
 
-	usleep(atoi(Srv.GetConfig("Period", "10")) * 1000000);	
+	usleep(atoi(Srv.GetConfig("Period", "10").c_str()) * 1000000);	
   } // while()
        
Index: /tools/Scripts/Logon
===================================================================
--- /tools/Scripts/Logon	(revision 228)
+++ /tools/Scripts/Logon	(revision 229)
@@ -7,6 +7,7 @@
 export DIM_HOST_NODE=$HOST.ethz.ch
 if [ -z "$DIMDIR" ]; then export DIMDIR=/usr/local/dim/; fi
+if [ -z "$QWTDIR" ]; then export QWTDIR=/usr/local/qwt/; fi
 
-export LD_LIBRARY_PATH=/usr/local/qwt-5.2.0/lib:$DIMDIR/linux:$LD_LIBRARY_PATH
+export LD_LIBRARY_PATH=$QWTDIR/lib:$DIMDIR/linux:$LD_LIBRARY_PATH
 export PATH=$DIMDIR/linux:$REPOS_DIR/tools/Scripts:/usr/local/Trolltech/Qt-4.4.3/bin:.:$PATH
 
Index: /tools/SkyQualityMonitor/sqm.cpp
===================================================================
--- /tools/SkyQualityMonitor/sqm.cpp	(revision 228)
+++ /tools/SkyQualityMonitor/sqm.cpp	(revision 229)
@@ -34,6 +34,6 @@
   // Start server and request configuration data
   EvidenceServer Srv(SERVER_NAME);
-  char *Address = Srv.GetConfig("address");
-  unsigned int Port = atoi(Srv.GetConfig("port"));
+  const char *Address = Srv.GetConfig("address").c_str();
+  unsigned int Port = atoi(Srv.GetConfig("port").c_str());
     
   // Open socket descriptor
@@ -69,5 +69,5 @@
   while(!Srv.ExitRequest) {
 	// Request measurement period  
-    Period = atoi(Srv.GetConfig("period"));
+    Period = atoi(Srv.GetConfig("period").c_str());
 
     // Write read command to socket
Index: /tools/ddd/ddd.pro
===================================================================
--- /tools/ddd/ddd.pro	(revision 228)
+++ /tools/ddd/ddd.pro	(revision 229)
@@ -6,9 +6,9 @@
 TARGET = 
 DEPENDPATH += .
-INCLUDEPATH += . /usr/local/qwt-5.2.0/include
+INCLUDEPATH += . /ihp/local/qwt-5.2.1/include
 
 # Input
 HEADERS += GUI.h ../../pixelmap/Pixel.h ../../pixelmap/PixelMap.h ../../drsdaq/RawDataCTX.h
 SOURCES += Functions.cpp GUI.cpp ../../pixelmap/Pixel.cc ../../pixelmap/PixelMap.cc ../../drsdaq/RawDataCTX.cc
-LIBS += -L/usr/local/qwt-5.2.0/lib -lqwt
+LIBS += -L/ihp/local/qwt-5.2.1/lib -lqwt
 QT += network
