Index: trunk/FACT++/src/InterpreterV8.cc
===================================================================
--- trunk/FACT++/src/InterpreterV8.cc	(revision 14554)
+++ trunk/FACT++/src/InterpreterV8.cc	(revision 14555)
@@ -312,7 +312,8 @@
 
     Handle<ObjectTemplate> obj = ObjectTemplate::New();
-    obj->Set(String::New("time"),  date);
     obj->Set(String::New("index"), rc.index<=-256?Undefined():Integer::New(rc.index),       ReadOnly);
     obj->Set(String::New("name"),  rc.index<=-256?Undefined():String::New(rc.name.c_str()), ReadOnly);
+    if (rc.index>-256)
+        obj->Set(String::New("time"),  date);
     //obj->Set(String::New("toString"),  String::New(("[Object state "+string(*str)+":"+to_string(rc.index)+"]").c_str()));
 
@@ -663,4 +664,6 @@
     }
 
+    args.Holder()->Set(String::New("isOpen"), Boolean::New(false), ReadOnly);
+
     return Boolean::New(JsUnsubscribe(*str));
 }
@@ -781,10 +784,10 @@
         return;
 
+    Locker locker;
+
     const auto it = fReverseMap.find(service);
     if (it==fReverseMap.end())
         return;
 
-    Locker locker;
-
     const HandleScope handle_scope;
 
@@ -835,4 +838,86 @@
 }
 
+Handle<Value> InterpreterV8::OnChangeSet(Local<String> prop, Local< Value > value, const AccessorInfo &info)
+{
+    const HandleScope handle_scope;
+
+    // Returns the value if the setter intercepts the request. Otherwise, returns an empty handle.
+    const string server = *String::Utf8Value(prop);
+    auto it = fStateCallbacks.find(server);
+
+    if (it!=fStateCallbacks.end())
+    {
+        it->second.Dispose();
+        fStateCallbacks.erase(it);
+    }
+
+    if (value->IsFunction())
+        fStateCallbacks[server] = Persistent<Value>::New(value);
+
+    return Handle<Value>();
+}
+
+
+void InterpreterV8::JsHandleState(const std::string &server, const State &state)
+{
+    if (fThreadId<0)
+        return;
+
+    Locker locker;
+
+    auto it = fStateCallbacks.find(server);
+    if (it==fStateCallbacks.end())
+    {
+        it = fStateCallbacks.find("*");
+        if (it==fStateCallbacks.end())
+            return;
+    }
+
+    const HandleScope handle_scope;
+
+    if (it->second.IsEmpty() || !it->second->IsFunction())
+        return;
+
+    // -------------------------------------------------------------------
+    // We are not in a context... we need to get into one for Array::New
+
+    Persistent<Context> context = Context::New();
+    if (context.IsEmpty())
+        return;
+
+    const Context::Scope scope(context);
+
+    // -------------------------------------------------------------------
+
+    TryCatch exception;
+
+    // It is important to catch the exception thrown
+    // by Date::New in case of thread termination!
+    Local<Value> date = Date::New(state.time.JavaDate());
+
+    if (!exception.HasCaught())
+    {
+        Handle<ObjectTemplate> obj = ObjectTemplate::New();
+        obj->Set(String::New("index"),  state.index<=-256?Undefined():Integer::New(state.index),       ReadOnly);
+        obj->Set(String::New("name"),   state.index<=-256?Undefined():String::New(state.name.c_str()), ReadOnly);
+        obj->Set(String::New("server"), String::New(server.c_str()), ReadOnly);
+        if (state.index>-256)
+            obj->Set(String::New("time"), date);
+
+        Handle<Value> args[] = { obj->NewInstance() };
+
+        Handle<Function> fun = Handle<Function>::Cast(it->second);
+        fun->Call(fun, 1, args);
+    }
+
+    if (exception.HasCaught())
+        ReportException(&exception);
+
+    context.Dispose();
+
+    if (exception.HasCaught())
+        V8::TerminateExecution(fThreadId);
+}
+
 /*
 void Cleanup( Persistent<Value> object, void *parameter )
@@ -861,7 +946,8 @@
 
     Handle<ObjectTemplate> tem = ObjectTemplate::New();
-    tem->Set(String::New("get"),   FunctionTemplate::New(WrapGetData), ReadOnly);
-    tem->Set(String::New("close"), FunctionTemplate::New(WrapClose),   ReadOnly);
-    tem->Set(String::New("name"),  String::New(*str), ReadOnly);
+    tem->Set(String::New("get"),    FunctionTemplate::New(WrapGetData), ReadOnly);
+    tem->Set(String::New("close"),  FunctionTemplate::New(WrapClose),   ReadOnly);
+    tem->Set(String::New("name"),   String::New(*str), ReadOnly);
+    tem->Set(String::New("isOpen"), Boolean::New(true));
     tem->SetInternalFieldCount(1);
     //tem->Set(String::New("toString"), String::New(("[object Dim "+string(*str)+"]").c_str()), ReadOnly);
@@ -900,4 +986,8 @@
     dim->Set(String::New("database"), FunctionTemplate::New(WrapDatabase), ReadOnly);
 
+    Handle<ObjectTemplate> onchange = ObjectTemplate::New();
+    onchange->SetNamedPropertyHandler(OnChangeGet, WrapOnChangeSet);
+    dim->Set(v8::String::New("onchange"), onchange);
+
     Handle<ObjectTemplate> global = ObjectTemplate::New();
     global->Set(String::New("dim"), dim, ReadOnly);
@@ -943,4 +1033,8 @@
     //context->Exit();
 
+    for (auto it=fStateCallbacks.begin(); it!=fStateCallbacks.end(); it++)
+        it->second.Dispose();
+    fStateCallbacks.clear();
+
     for (auto it=fReverseMap.begin(); it!=fReverseMap.end(); it++)
         it->second.Dispose();
@@ -973,20 +1067,2 @@
 
 #endif
-
-/*
-#0  0x00007ffff5ae0e62 in ?? () from /usr/lib/libv8.so.3.7.12.22
-#1  0x00007ffff5ae1969 in ?? () from /usr/lib/libv8.so.3.7.12.22
-#2  0x00007ffff5af1976 in v8::V8::Dispose() () from /usr/lib/libv8.so.3.7.12.22
-#3  0x0000000000426459 in RemoteControl<Console>::~RemoteControl() ()
-#4  0x00007ffff51e9901 in __run_exit_handlers (status=3, listp=0x7ffff5566688, run_list_atexi
-#5  0x00007ffff51e9985 in __GI_exit (status=<optimized out>) at exit.c:100
-#6  0x00000000004374db in DimErrorRedirecter::exitHandler(int) ()
-#7  0x00007ffff66bce72 in exit_user_routine () from /home/fact/FACT++.in-run-fad-loss/.libs/l
-#8  0x00007ffff6477387 in recv_dns_dis_rout () from /home/fact/FACT++.in-run-fad-loss/.libs/l
-#9  0x00007ffff647b79f in ast_read_h () from /home/fact/FACT++.in-run-fad-loss/.libs/libDim.s
-#10 0x00007ffff647f388 in do_read () from /home/fact/FACT++.in-run-fad-loss/.libs/libDim.so
-#11 0x00007ffff647ff32 in tcpip_task () from /home/fact/FACT++.in-run-fad-loss/.libs/libDim.s
-#12 0x00007ffff6482c57 in dim_tcpip_thread () from /home/fact/FACT++.in-run-fad-loss/.libs/li
-#13 0x00007ffff7bc4e9a in start_thread (arg=0x7ffff13be700) at pthread_create.c:308
-#14 0x00007ffff52a1cbd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:112
-*/
Index: trunk/FACT++/src/InterpreterV8.h
===================================================================
--- trunk/FACT++/src/InterpreterV8.h	(revision 14554)
+++ trunk/FACT++/src/InterpreterV8.h	(revision 14555)
@@ -15,5 +15,5 @@
 
 class Database;
-#include<iostream>
+
 class InterpreterV8
 {
@@ -29,4 +29,7 @@
     // subscription exists for that object)
     std::map<std::string, v8::Persistent<v8::Object>> fReverseMap;
+
+    // Lookup table for the callbacks in cases of state changes
+    std::map<std::string, v8::Persistent<v8::Value>>  fStateCallbacks;
 
 #ifdef HAVE_SQL
@@ -57,4 +60,5 @@
     v8::Handle<v8::Value> FuncDbQuery(const v8::Arguments &args);
     v8::Handle<v8::Value> FuncDbClose(const v8::Arguments &args);
+    v8::Handle<v8::Value> OnChangeSet(v8::Local<v8::String>, v8::Local<v8::Value>, const v8::AccessorInfo &);
 
     static v8::Handle<v8::Value> FuncVersion(const v8::Arguments&);
@@ -75,4 +79,13 @@
     static v8::Handle<v8::Value> WrapDbQuery(const v8::Arguments &args)  { if (This) return This->FuncDbQuery(args);  else return v8::Undefined(); }
     static v8::Handle<v8::Value> WrapDbClose(const v8::Arguments &args)  { if (This) return This->FuncDbClose(args);  else return v8::Undefined(); }
+    static v8::Handle<v8::Value> WrapOnChangeSet(v8::Local<v8::String> prop, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
+    {
+        if (This) return This->OnChangeSet(prop, value, info);  else return v8::Undefined();
+    }
+
+    static v8::Handle<v8::Value> OnChangeGet(v8::Local<v8::String>, const v8::AccessorInfo &)
+    {
+        return v8::Handle<v8::Value>();
+    }
 
     static v8::Handle<v8::Value> Convert(char type, const char* &ptr);
@@ -113,4 +126,5 @@
 
     void JsHandleEvent(const EventImp &, uint64_t, const std::string &);
+    void JsHandleState(const std::string &, const State &);
 
     bool JsRun(const std::string &, const std::map<std::string,std::string> & = std::map<std::string,std::string>());
