restructure webif, add automake/autoconf
authorFelix Domke <tmbinc@elitedvb.net>
Thu, 11 Jan 2007 14:33:43 +0000 (14:33 +0000)
committerFelix Domke <tmbinc@elitedvb.net>
Thu, 11 Jan 2007 14:33:43 +0000 (14:33 +0000)
66 files changed:
Makefile.am
configure.ac
webinterface/Makefile.am [new file with mode: 0644]
webinterface/src/Makefile.am [new file with mode: 0644]
webinterface/src/WebComponents/Converter/Makefile.am [new file with mode: 0644]
webinterface/src/WebComponents/Converter/VolumeToText.py [new file with mode: 0644]
webinterface/src/WebComponents/Converter/__init__.py [new file with mode: 0644]
webinterface/src/WebComponents/Makefile.am [new file with mode: 0644]
webinterface/src/WebComponents/Sources/EPG.py [new file with mode: 0644]
webinterface/src/WebComponents/Sources/Makefile.am [new file with mode: 0644]
webinterface/src/WebComponents/Sources/Timer.py [new file with mode: 0644]
webinterface/src/WebComponents/Sources/Volume.py [new file with mode: 0644]
webinterface/src/WebComponents/Sources/__init__.py [new file with mode: 0644]
webinterface/src/__init__.py [new file with mode: 0644]
webinterface/src/plugin.py [new file with mode: 0644]
webinterface/src/usr/lib/enigma2/python/Components/Converter/.cvsignore [deleted file]
webinterface/src/usr/lib/enigma2/python/Components/Converter/VolumeToText.py [deleted file]
webinterface/src/usr/lib/enigma2/python/Components/Renderer/.cvsignore [deleted file]
webinterface/src/usr/lib/enigma2/python/Components/Sources/.cvsignore [deleted file]
webinterface/src/usr/lib/enigma2/python/Components/Sources/EPG.py [deleted file]
webinterface/src/usr/lib/enigma2/python/Components/Sources/Timer.py [deleted file]
webinterface/src/usr/lib/enigma2/python/Components/Sources/Volume.py [deleted file]
webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/.cvsignore [deleted file]
webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/__init__.py [deleted file]
webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/plugin.py [deleted file]
webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web-data/gfx/led_off.png [deleted file]
webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web-data/gfx/led_on.png [deleted file]
webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web-data/gfx/speak_off.png [deleted file]
webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web-data/gfx/speak_on.png [deleted file]
webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web-data/prototype.js [deleted file]
webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web-data/rico.js [deleted file]
webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web-data/theme.css [deleted file]
webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web-data/tools.js [deleted file]
webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web/epgnownext.xml [deleted file]
webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web/epgsearch.xml [deleted file]
webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web/epgservice.xml [deleted file]
webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web/fetchchannels.xml [deleted file]
webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web/index.html.xml [deleted file]
webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web/stream.m3u.xml [deleted file]
webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web/stream.xml [deleted file]
webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web/timerlist.xml [deleted file]
webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web/vol.xml [deleted file]
webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web/zap.xml [deleted file]
webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/webif.py [deleted file]
webinterface/src/web-data/Makefile.am [new file with mode: 0644]
webinterface/src/web-data/gfx/Makefile.am [new file with mode: 0644]
webinterface/src/web-data/gfx/led_off.png [new file with mode: 0644]
webinterface/src/web-data/gfx/led_on.png [new file with mode: 0644]
webinterface/src/web-data/gfx/speak_off.png [new file with mode: 0644]
webinterface/src/web-data/gfx/speak_on.png [new file with mode: 0644]
webinterface/src/web-data/prototype.js [new file with mode: 0644]
webinterface/src/web-data/rico.js [new file with mode: 0644]
webinterface/src/web-data/theme.css [new file with mode: 0644]
webinterface/src/web-data/tools.js [new file with mode: 0644]
webinterface/src/web/Makefile.am [new file with mode: 0644]
webinterface/src/web/epgnownext.xml [new file with mode: 0644]
webinterface/src/web/epgsearch.xml [new file with mode: 0644]
webinterface/src/web/epgservice.xml [new file with mode: 0644]
webinterface/src/web/fetchchannels.xml [new file with mode: 0644]
webinterface/src/web/index.html.xml [new file with mode: 0644]
webinterface/src/web/stream.m3u.xml [new file with mode: 0644]
webinterface/src/web/stream.xml [new file with mode: 0644]
webinterface/src/web/timerlist.xml [new file with mode: 0644]
webinterface/src/web/vol.xml [new file with mode: 0644]
webinterface/src/web/zap.xml [new file with mode: 0644]
webinterface/src/webif.py [new file with mode: 0644]

index 0a06e63..f1ec7a8 100644 (file)
@@ -1,3 +1,2 @@
 AUTOMAKE_OPTIONS = gnu
-SUBDIRS = antiscrollbar
-# movietagger webinterface
+SUBDIRS = antiscrollbar movietagger webinterface
index 168a435..150ba7a 100644 (file)
@@ -13,4 +13,13 @@ movietagger/Makefile
 movietagger/etc/Makefile
 movietagger/src/Makefile
 
+webinterface/Makefile
+webinterface/src/Makefile
+webinterface/src/web-data/Makefile
+webinterface/src/web-data/gfx/Makefile
+webinterface/src/web/Makefile
+webinterface/src/Components/Makefile
+webinterface/src/Components/Converter/Makefile
+webinterface/src/Components/Sources/Makefile
+
 ])
diff --git a/webinterface/Makefile.am b/webinterface/Makefile.am
new file mode 100644 (file)
index 0000000..af437a6
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = src
diff --git a/webinterface/src/Makefile.am b/webinterface/src/Makefile.am
new file mode 100644 (file)
index 0000000..3ed385c
--- /dev/null
@@ -0,0 +1,5 @@
+installdir = /usr/lib/enigma2/python/Plugins/Extensions/WebInterface/
+
+install_PYTHON = __init__.py plugin.py webif.py
+
+SUBDIRS = web web-data Components
diff --git a/webinterface/src/WebComponents/Converter/Makefile.am b/webinterface/src/WebComponents/Converter/Makefile.am
new file mode 100644 (file)
index 0000000..f0b15a4
--- /dev/null
@@ -0,0 +1,3 @@
+installdir = /usr/lib/enigma2/python/Plugins/Extensions/WebInterface/Components/Converter/
+
+install_PYTHON = __init__.py VolumeToText.py
diff --git a/webinterface/src/WebComponents/Converter/VolumeToText.py b/webinterface/src/WebComponents/Converter/VolumeToText.py
new file mode 100644 (file)
index 0000000..b06f75e
--- /dev/null
@@ -0,0 +1,21 @@
+from Converter import Converter
+from Components.config import *
+from enigma import eDVBVolumecontrol #this is not nice
+class VolumeToText(Converter, object):
+    
+    def __init__(self, type):
+        Converter.__init__(self, type)
+        self.volctrl = eDVBVolumecontrol.getInstance() # this is not nice
+        
+    def getHTML(self, id):
+        return self.getText() # encode & etc. here!
+    def getText(self):
+        r = "%s\n"%config.audio.volume.value
+        if self.volctrl.isMuted():
+            r+="muted"
+        else:
+            r+="notmuted"
+        return r
+        
+
+    text = property(getText)
diff --git a/webinterface/src/WebComponents/Converter/__init__.py b/webinterface/src/WebComponents/Converter/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/webinterface/src/WebComponents/Makefile.am b/webinterface/src/WebComponents/Makefile.am
new file mode 100644 (file)
index 0000000..b0eaeb6
--- /dev/null
@@ -0,0 +1,5 @@
+installdir = /usr/lib/enigma2/python/Plugins/Extensions/WebInterface/Components/
+
+install_PYTHON = __init__.py
+
+SUBDIRS = Converter Sources
diff --git a/webinterface/src/WebComponents/Sources/EPG.py b/webinterface/src/WebComponents/Sources/EPG.py
new file mode 100644 (file)
index 0000000..99e5db1
--- /dev/null
@@ -0,0 +1,69 @@
+from enigma import *
+
+from Source import Source
+from ServiceReference import ServiceReference
+
+class EPG( Source):
+    NOWNEXT=0
+    SERVICE=1
+    TITLE=2
+    
+    def __init__(self, navcore,func=NOWNEXT):
+        self.func = func
+        Source.__init__(self)        
+        self.navcore = navcore
+        self.epgcache = eEPGCache.getInstance()
+        
+    def handleCommand(self,cmd):
+        self.command = cmd
+
+    def do_func(self):
+        if self.func is self.TITLE:
+            func = self.searchEvent
+        elif self.func is self.SERVICE:
+            func = self.getEPGofService
+        else:
+            func = self.getEPGNowNext
+            
+        return func(self.command)
+    
+    def getEPGNowNext(self,cmd):
+        print "getting EPG NOWNEXT", cmd
+        events = self.epgcache.lookupEvent(['IBDTSERN',(cmd,0,0,-1)]);
+        if events:
+                return self.convert(events)
+        else:
+                return []
+    
+    def getEPGofService(self,cmd):
+        print "getting EPG of Service", cmd
+        events = self.epgcache.lookupEvent(['IBDTSERN',(cmd,0,-1,-1)]);
+        if events:
+                return self.convert(events) 
+        else:
+                return []
+    
+    def searchEvent(self,cmd):
+        print "getting EPG by title",cmd
+        events = self.epgcache.search(('IBDTSERN',1024,eEPGCache.PARTIAL_TITLE_SEARCH,cmd,1));
+        if events:
+            
+            return self.convert(events)
+        else:
+            return []
+    
+    def convert(self,input):
+        #this is not nice, but ",',<,> and & are controlchars in xml and must be replaced
+        output = []
+        for i in input:
+            o = []
+            for key in i:
+                o.append(str(key).replace("<","&lt;").replace(">","&gt;").replace("&","&amp;").replace("\"","&quot;").replace("'","&apos;"))
+            output.append(o)
+            
+        return output
+    
+    list = property(do_func)
+    lut = {"EventID": 0, "TimeStart": 1,"Duration": 2, "Title": 3, "Description": 4, "DescriptionExtended": 5, "ServiceReference": 6, "ServiceName": 7}
+
+    
\ No newline at end of file
diff --git a/webinterface/src/WebComponents/Sources/Makefile.am b/webinterface/src/WebComponents/Sources/Makefile.am
new file mode 100644 (file)
index 0000000..8a112af
--- /dev/null
@@ -0,0 +1,3 @@
+installdir = /usr/lib/enigma2/python/Plugins/Extensions/WebInterface/Components/Sources/
+
+install_PYTHON = __init__.py EPG.py Timer.py Volume.py
diff --git a/webinterface/src/WebComponents/Sources/Timer.py b/webinterface/src/WebComponents/Sources/Timer.py
new file mode 100644 (file)
index 0000000..acf47d9
--- /dev/null
@@ -0,0 +1,81 @@
+from enigma import *
+
+from Source import Source
+from ServiceReference import ServiceReference
+from enigma import eServiceReference 
+class Timer( Source):
+    
+    def __init__(self, session):
+        #self.func = func
+        Source.__init__(self)        
+        self.session = session
+        self.recordtimer = session.nav.RecordTimer
+        
+#    def handleCommand(self,cmd):
+#        self.command = cmd
+
+    
+    def command(self):
+        timerlist = []
+        for item in self.recordtimer.timer_list+self.recordtimer.processed_timers:
+            timer = []
+            timer.append(item.service_ref)
+            timer.append(item.service_ref.getServiceName())
+            timer.append(item.eit)
+            timer.append(self.convert(item.name))
+            timer.append(self.convert(item.description))
+            timer.append(item.disabled)
+            timer.append(item.begin)
+            timer.append(item.end)
+            timer.append(item.end-item.begin)
+            timer.append(item.start_prepare)
+            timer.append(item.justplay)
+            timer.append(item.afterEvent)
+            timer.append(item.log_entries)
+            try: 
+                timer.append(item.Filename)
+            except AttributeError:
+                timer.append("")
+            
+            timer.append(item.backoff)       
+            try:
+                timer.append(item.next_activation)
+            except AttributeError:
+                timer.append("")
+            timer.append(item.first_try_prepare)  
+            timer.append(item.state)  
+            timer.append(item.repeated)
+            timer.append(item.dontSave)
+            timer.append(item.cancelled)
+            timerlist.append(timer) 
+            
+        return timerlist
+    
+    def convert(self,input):
+        #this is not nice, but ",',<,> and & are controlchars in xml and must be replaced
+        return input.replace("<","&lt;").replace(">","&gt;").replace("&","&amp;").replace("\"","&quot;").replace("'","&apos;")
+        
+    list = property(command)
+    lut = {"ServiceReference": 0
+           ,"ServiceName": 1
+           ,"EIT":2
+           ,"Name":3
+           ,"Description":4
+           ,"Disabled":5
+           ,"TimeBegin":6
+           ,"TimeEnd":7
+           ,"Duration":8
+           ,"startPrepare":9
+           ,"justPlay":10
+           ,"afterEvent":11
+           ,"LogEntries":12
+           ,"Filename":13
+           ,"Backoff":14
+           ,"nextActivation":15
+           ,"firstTryPrepare":16
+           ,"State":17
+           ,"Repeated":18
+           ,"dontSave":19
+           ,"Cancled":20
+           }
+
diff --git a/webinterface/src/WebComponents/Sources/Volume.py b/webinterface/src/WebComponents/Sources/Volume.py
new file mode 100644 (file)
index 0000000..7d8d5fe
--- /dev/null
@@ -0,0 +1,23 @@
+from Source import Source
+from GlobalActions import globalActionMap
+
+from time import time
+
+class Volume( Source):
+    def __init__(self, navcore):
+        Source.__init__(self)
+        
+        
+    def handleCommand(self, cmd):
+        global globalActionMap
+        if cmd == "up":
+            globalActionMap.actions["volumeUp"]()
+        elif cmd == "down":
+            globalActionMap.actions["volumeDown"]()
+        elif cmd == "mute":
+            globalActionMap.actions["volumeMute"]()
+        elif cmd == "value":
+            pass 
+        else:
+            print "unknow Volume handle command",cmd
+        
\ No newline at end of file
diff --git a/webinterface/src/WebComponents/Sources/__init__.py b/webinterface/src/WebComponents/Sources/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/webinterface/src/__init__.py b/webinterface/src/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/webinterface/src/plugin.py b/webinterface/src/plugin.py
new file mode 100644 (file)
index 0000000..bd1ec49
--- /dev/null
@@ -0,0 +1,69 @@
+from Plugins.Plugin import PluginDescriptor
+
+sessions = [ ]
+
+def startWebserver():
+       from twisted.internet import reactor
+       from twisted.web2 import server, channel, static, resource, stream, http_headers, responsecode, http
+       from twisted.python import util
+       import webif
+
+       class ScreenPage(resource.Resource):
+               def __init__(self, path):
+                       self.path = path
+                       
+               def render(self, req):
+                       global sessions
+                       if sessions == [ ]:
+                               return http.Response(200, stream="please wait until enigma has booted")
+
+                       class myProducerStream(stream.ProducerStream):
+                               closed_callback = None
+
+                               def close(self):
+                                       if self.closed_callback:
+                                               self.closed_callback()
+                                       stream.ProducerStream.close(self)
+
+                       s = myProducerStream()
+                       webif.renderPage(s, self.path, req, sessions[0])  # login?
+
+                       return http.Response(stream=s)
+
+               def locateChild(self, request, segments):
+                       path = '/'.join(["web"] + segments)
+                       if path[-1:] == "/":
+                               path += "index.html"
+
+                       path += ".xml"
+                       return ScreenPage(path), ()
+
+       class Toplevel(resource.Resource):
+               addSlash = True
+
+               def render(self, req):
+                       return http.Response(responsecode.OK, {'Content-type': http_headers.MimeType('text', 'html')},
+                               stream='Hello! You want go to <a href="/web/">OSD</a> instead.')
+
+               child_web = ScreenPage("/") # "/web"
+               child_hdd = static.File("/hdd")
+               child_webdata = static.File(util.sibpath(__file__, "web-data")) # FIXME: web-data appears as webdata
+
+       site = server.Site(Toplevel())
+
+       reactor.listenTCP(80, channel.HTTPFactory(site))
+
+def autostart(reason, **kwargs):
+       if "session" in kwargs:
+               global sessions
+               sessions.append(kwargs["session"])
+               return
+
+       if reason == 0:
+               try:
+                       startWebserver()
+               except ImportError:
+                       print "twisted not available, not starting web services"
+
+def Plugins(**kwargs):
+       return PluginDescriptor(where = [PluginDescriptor.WHERE_SESSIONSTART, PluginDescriptor.WHERE_AUTOSTART], fnc = autostart)
diff --git a/webinterface/src/usr/lib/enigma2/python/Components/Converter/.cvsignore b/webinterface/src/usr/lib/enigma2/python/Components/Converter/.cvsignore
deleted file mode 100644 (file)
index 52e4e61..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-*.pyc
-*.pyo
diff --git a/webinterface/src/usr/lib/enigma2/python/Components/Converter/VolumeToText.py b/webinterface/src/usr/lib/enigma2/python/Components/Converter/VolumeToText.py
deleted file mode 100644 (file)
index b06f75e..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-from Converter import Converter
-from Components.config import *
-from enigma import eDVBVolumecontrol #this is not nice
-class VolumeToText(Converter, object):
-    
-    def __init__(self, type):
-        Converter.__init__(self, type)
-        self.volctrl = eDVBVolumecontrol.getInstance() # this is not nice
-        
-    def getHTML(self, id):
-        return self.getText() # encode & etc. here!
-    def getText(self):
-        r = "%s\n"%config.audio.volume.value
-        if self.volctrl.isMuted():
-            r+="muted"
-        else:
-            r+="notmuted"
-        return r
-        
-
-    text = property(getText)
diff --git a/webinterface/src/usr/lib/enigma2/python/Components/Renderer/.cvsignore b/webinterface/src/usr/lib/enigma2/python/Components/Renderer/.cvsignore
deleted file mode 100644 (file)
index 52e4e61..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-*.pyc
-*.pyo
diff --git a/webinterface/src/usr/lib/enigma2/python/Components/Sources/.cvsignore b/webinterface/src/usr/lib/enigma2/python/Components/Sources/.cvsignore
deleted file mode 100644 (file)
index 52e4e61..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-*.pyc
-*.pyo
diff --git a/webinterface/src/usr/lib/enigma2/python/Components/Sources/EPG.py b/webinterface/src/usr/lib/enigma2/python/Components/Sources/EPG.py
deleted file mode 100644 (file)
index 99e5db1..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-from enigma import *
-
-from Source import Source
-from ServiceReference import ServiceReference
-
-class EPG( Source):
-    NOWNEXT=0
-    SERVICE=1
-    TITLE=2
-    
-    def __init__(self, navcore,func=NOWNEXT):
-        self.func = func
-        Source.__init__(self)        
-        self.navcore = navcore
-        self.epgcache = eEPGCache.getInstance()
-        
-    def handleCommand(self,cmd):
-        self.command = cmd
-
-    def do_func(self):
-        if self.func is self.TITLE:
-            func = self.searchEvent
-        elif self.func is self.SERVICE:
-            func = self.getEPGofService
-        else:
-            func = self.getEPGNowNext
-            
-        return func(self.command)
-    
-    def getEPGNowNext(self,cmd):
-        print "getting EPG NOWNEXT", cmd
-        events = self.epgcache.lookupEvent(['IBDTSERN',(cmd,0,0,-1)]);
-        if events:
-                return self.convert(events)
-        else:
-                return []
-    
-    def getEPGofService(self,cmd):
-        print "getting EPG of Service", cmd
-        events = self.epgcache.lookupEvent(['IBDTSERN',(cmd,0,-1,-1)]);
-        if events:
-                return self.convert(events) 
-        else:
-                return []
-    
-    def searchEvent(self,cmd):
-        print "getting EPG by title",cmd
-        events = self.epgcache.search(('IBDTSERN',1024,eEPGCache.PARTIAL_TITLE_SEARCH,cmd,1));
-        if events:
-            
-            return self.convert(events)
-        else:
-            return []
-    
-    def convert(self,input):
-        #this is not nice, but ",',<,> and & are controlchars in xml and must be replaced
-        output = []
-        for i in input:
-            o = []
-            for key in i:
-                o.append(str(key).replace("<","&lt;").replace(">","&gt;").replace("&","&amp;").replace("\"","&quot;").replace("'","&apos;"))
-            output.append(o)
-            
-        return output
-    
-    list = property(do_func)
-    lut = {"EventID": 0, "TimeStart": 1,"Duration": 2, "Title": 3, "Description": 4, "DescriptionExtended": 5, "ServiceReference": 6, "ServiceName": 7}
-
-    
\ No newline at end of file
diff --git a/webinterface/src/usr/lib/enigma2/python/Components/Sources/Timer.py b/webinterface/src/usr/lib/enigma2/python/Components/Sources/Timer.py
deleted file mode 100644 (file)
index acf47d9..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-from enigma import *
-
-from Source import Source
-from ServiceReference import ServiceReference
-from enigma import eServiceReference 
-class Timer( Source):
-    
-    def __init__(self, session):
-        #self.func = func
-        Source.__init__(self)        
-        self.session = session
-        self.recordtimer = session.nav.RecordTimer
-        
-#    def handleCommand(self,cmd):
-#        self.command = cmd
-
-    
-    def command(self):
-        timerlist = []
-        for item in self.recordtimer.timer_list+self.recordtimer.processed_timers:
-            timer = []
-            timer.append(item.service_ref)
-            timer.append(item.service_ref.getServiceName())
-            timer.append(item.eit)
-            timer.append(self.convert(item.name))
-            timer.append(self.convert(item.description))
-            timer.append(item.disabled)
-            timer.append(item.begin)
-            timer.append(item.end)
-            timer.append(item.end-item.begin)
-            timer.append(item.start_prepare)
-            timer.append(item.justplay)
-            timer.append(item.afterEvent)
-            timer.append(item.log_entries)
-            try: 
-                timer.append(item.Filename)
-            except AttributeError:
-                timer.append("")
-            
-            timer.append(item.backoff)       
-            try:
-                timer.append(item.next_activation)
-            except AttributeError:
-                timer.append("")
-            timer.append(item.first_try_prepare)  
-            timer.append(item.state)  
-            timer.append(item.repeated)
-            timer.append(item.dontSave)
-            timer.append(item.cancelled)
-            timerlist.append(timer) 
-            
-        return timerlist
-    
-    def convert(self,input):
-        #this is not nice, but ",',<,> and & are controlchars in xml and must be replaced
-        return input.replace("<","&lt;").replace(">","&gt;").replace("&","&amp;").replace("\"","&quot;").replace("'","&apos;")
-        
-    list = property(command)
-    lut = {"ServiceReference": 0
-           ,"ServiceName": 1
-           ,"EIT":2
-           ,"Name":3
-           ,"Description":4
-           ,"Disabled":5
-           ,"TimeBegin":6
-           ,"TimeEnd":7
-           ,"Duration":8
-           ,"startPrepare":9
-           ,"justPlay":10
-           ,"afterEvent":11
-           ,"LogEntries":12
-           ,"Filename":13
-           ,"Backoff":14
-           ,"nextActivation":15
-           ,"firstTryPrepare":16
-           ,"State":17
-           ,"Repeated":18
-           ,"dontSave":19
-           ,"Cancled":20
-           }
-
diff --git a/webinterface/src/usr/lib/enigma2/python/Components/Sources/Volume.py b/webinterface/src/usr/lib/enigma2/python/Components/Sources/Volume.py
deleted file mode 100644 (file)
index 7d8d5fe..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-from Source import Source
-from GlobalActions import globalActionMap
-
-from time import time
-
-class Volume( Source):
-    def __init__(self, navcore):
-        Source.__init__(self)
-        
-        
-    def handleCommand(self, cmd):
-        global globalActionMap
-        if cmd == "up":
-            globalActionMap.actions["volumeUp"]()
-        elif cmd == "down":
-            globalActionMap.actions["volumeDown"]()
-        elif cmd == "mute":
-            globalActionMap.actions["volumeMute"]()
-        elif cmd == "value":
-            pass 
-        else:
-            print "unknow Volume handle command",cmd
-        
\ No newline at end of file
diff --git a/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/.cvsignore b/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/.cvsignore
deleted file mode 100644 (file)
index 52e4e61..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-*.pyc
-*.pyo
diff --git a/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/__init__.py b/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/plugin.py b/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/plugin.py
deleted file mode 100644 (file)
index bd1ec49..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-from Plugins.Plugin import PluginDescriptor
-
-sessions = [ ]
-
-def startWebserver():
-       from twisted.internet import reactor
-       from twisted.web2 import server, channel, static, resource, stream, http_headers, responsecode, http
-       from twisted.python import util
-       import webif
-
-       class ScreenPage(resource.Resource):
-               def __init__(self, path):
-                       self.path = path
-                       
-               def render(self, req):
-                       global sessions
-                       if sessions == [ ]:
-                               return http.Response(200, stream="please wait until enigma has booted")
-
-                       class myProducerStream(stream.ProducerStream):
-                               closed_callback = None
-
-                               def close(self):
-                                       if self.closed_callback:
-                                               self.closed_callback()
-                                       stream.ProducerStream.close(self)
-
-                       s = myProducerStream()
-                       webif.renderPage(s, self.path, req, sessions[0])  # login?
-
-                       return http.Response(stream=s)
-
-               def locateChild(self, request, segments):
-                       path = '/'.join(["web"] + segments)
-                       if path[-1:] == "/":
-                               path += "index.html"
-
-                       path += ".xml"
-                       return ScreenPage(path), ()
-
-       class Toplevel(resource.Resource):
-               addSlash = True
-
-               def render(self, req):
-                       return http.Response(responsecode.OK, {'Content-type': http_headers.MimeType('text', 'html')},
-                               stream='Hello! You want go to <a href="/web/">OSD</a> instead.')
-
-               child_web = ScreenPage("/") # "/web"
-               child_hdd = static.File("/hdd")
-               child_webdata = static.File(util.sibpath(__file__, "web-data")) # FIXME: web-data appears as webdata
-
-       site = server.Site(Toplevel())
-
-       reactor.listenTCP(80, channel.HTTPFactory(site))
-
-def autostart(reason, **kwargs):
-       if "session" in kwargs:
-               global sessions
-               sessions.append(kwargs["session"])
-               return
-
-       if reason == 0:
-               try:
-                       startWebserver()
-               except ImportError:
-                       print "twisted not available, not starting web services"
-
-def Plugins(**kwargs):
-       return PluginDescriptor(where = [PluginDescriptor.WHERE_SESSIONSTART, PluginDescriptor.WHERE_AUTOSTART], fnc = autostart)
diff --git a/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web-data/gfx/led_off.png b/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web-data/gfx/led_off.png
deleted file mode 100644 (file)
index 69ca2cd..0000000
Binary files a/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web-data/gfx/led_off.png and /dev/null differ
diff --git a/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web-data/gfx/led_on.png b/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web-data/gfx/led_on.png
deleted file mode 100644 (file)
index 3d3d29d..0000000
Binary files a/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web-data/gfx/led_on.png and /dev/null differ
diff --git a/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web-data/gfx/speak_off.png b/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web-data/gfx/speak_off.png
deleted file mode 100644 (file)
index 8823ac3..0000000
Binary files a/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web-data/gfx/speak_off.png and /dev/null differ
diff --git a/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web-data/gfx/speak_on.png b/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web-data/gfx/speak_on.png
deleted file mode 100644 (file)
index 5ded98c..0000000
Binary files a/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web-data/gfx/speak_on.png and /dev/null differ
diff --git a/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web-data/prototype.js b/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web-data/prototype.js
deleted file mode 100644 (file)
index 0e85338..0000000
+++ /dev/null
@@ -1,1781 +0,0 @@
-/*  Prototype JavaScript framework, version 1.4.0
- *  (c) 2005 Sam Stephenson <sam@conio.net>
- *
- *  Prototype is freely distributable under the terms of an MIT-style license.
- *  For details, see the Prototype web site: http://prototype.conio.net/
- *
-/*--------------------------------------------------------------------------*/
-
-var Prototype = {
-  Version: '1.4.0',
-  ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
-
-  emptyFunction: function() {},
-  K: function(x) {return x}
-}
-
-var Class = {
-  create: function() {
-    return function() {
-      this.initialize.apply(this, arguments);
-    }
-  }
-}
-
-var Abstract = new Object();
-
-Object.extend = function(destination, source) {
-  for (property in source) {
-    destination[property] = source[property];
-  }
-  return destination;
-}
-
-Object.inspect = function(object) {
-  try {
-    if (object == undefined) return 'undefined';
-    if (object == null) return 'null';
-    return object.inspect ? object.inspect() : object.toString();
-  } catch (e) {
-    if (e instanceof RangeError) return '...';
-    throw e;
-  }
-}
-
-Function.prototype.bind = function() {
-  var __method = this, args = $A(arguments), object = args.shift();
-  return function() {
-    return __method.apply(object, args.concat($A(arguments)));
-  }
-}
-
-Function.prototype.bindAsEventListener = function(object) {
-  var __method = this;
-  return function(event) {
-    return __method.call(object, event || window.event);
-  }
-}
-
-Object.extend(Number.prototype, {
-  toColorPart: function() {
-    var digits = this.toString(16);
-    if (this < 16) return '0' + digits;
-    return digits;
-  },
-
-  succ: function() {
-    return this + 1;
-  },
-
-  times: function(iterator) {
-    $R(0, this, true).each(iterator);
-    return this;
-  }
-});
-
-var Try = {
-  these: function() {
-    var returnValue;
-
-    for (var i = 0; i < arguments.length; i++) {
-      var lambda = arguments[i];
-      try {
-        returnValue = lambda();
-        break;
-      } catch (e) {}
-    }
-
-    return returnValue;
-  }
-}
-
-/*--------------------------------------------------------------------------*/
-
-var PeriodicalExecuter = Class.create();
-PeriodicalExecuter.prototype = {
-  initialize: function(callback, frequency) {
-    this.callback = callback;
-    this.frequency = frequency;
-    this.currentlyExecuting = false;
-
-    this.registerCallback();
-  },
-
-  registerCallback: function() {
-    setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
-  },
-
-  onTimerEvent: function() {
-    if (!this.currentlyExecuting) {
-      try {
-        this.currentlyExecuting = true;
-        this.callback();
-      } finally {
-        this.currentlyExecuting = false;
-      }
-    }
-  }
-}
-
-/*--------------------------------------------------------------------------*/
-
-function $() {
-  var elements = new Array();
-
-  for (var i = 0; i < arguments.length; i++) {
-    var element = arguments[i];
-    if (typeof element == 'string')
-      element = document.getElementById(element);
-
-    if (arguments.length == 1)
-      return element;
-
-    elements.push(element);
-  }
-
-  return elements;
-}
-Object.extend(String.prototype, {
-  stripTags: function() {
-    return this.replace(/<\/?[^>]+>/gi, '');
-  },
-
-  stripScripts: function() {
-    return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
-  },
-
-  extractScripts: function() {
-    var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
-    var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
-    return (this.match(matchAll) || []).map(function(scriptTag) {
-      return (scriptTag.match(matchOne) || ['', ''])[1];
-    });
-  },
-
-  evalScripts: function() {
-    return this.extractScripts().map(eval);
-  },
-
-  escapeHTML: function() {
-    var div = document.createElement('div');
-    var text = document.createTextNode(this);
-    div.appendChild(text);
-    return div.innerHTML;
-  },
-
-  unescapeHTML: function() {
-    var div = document.createElement('div');
-    div.innerHTML = this.stripTags();
-    return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
-  },
-
-  toQueryParams: function() {
-    var pairs = this.match(/^\??(.*)$/)[1].split('&');
-    return pairs.inject({}, function(params, pairString) {
-      var pair = pairString.split('=');
-      params[pair[0]] = pair[1];
-      return params;
-    });
-  },
-
-  toArray: function() {
-    return this.split('');
-  },
-
-  camelize: function() {
-    var oStringList = this.split('-');
-    if (oStringList.length == 1) return oStringList[0];
-
-    var camelizedString = this.indexOf('-') == 0
-      ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
-      : oStringList[0];
-
-    for (var i = 1, len = oStringList.length; i < len; i++) {
-      var s = oStringList[i];
-      camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
-    }
-
-    return camelizedString;
-  },
-
-  inspect: function() {
-    return "'" + this.replace('\\', '\\\\').replace("'", '\\\'') + "'";
-  }
-});
-
-String.prototype.parseQuery = String.prototype.toQueryParams;
-
-var $break    = new Object();
-var $continue = new Object();
-
-var Enumerable = {
-  each: function(iterator) {
-    var index = 0;
-    try {
-      this._each(function(value) {
-        try {
-          iterator(value, index++);
-        } catch (e) {
-          if (e != $continue) throw e;
-        }
-      });
-    } catch (e) {
-      if (e != $break) throw e;
-    }
-  },
-
-  all: function(iterator) {
-    var result = true;
-    this.each(function(value, index) {
-      result = result && !!(iterator || Prototype.K)(value, index);
-      if (!result) throw $break;
-    });
-    return result;
-  },
-
-  any: function(iterator) {
-    var result = true;
-    this.each(function(value, index) {
-      if (result = !!(iterator || Prototype.K)(value, index))
-        throw $break;
-    });
-    return result;
-  },
-
-  collect: function(iterator) {
-    var results = [];
-    this.each(function(value, index) {
-      results.push(iterator(value, index));
-    });
-    return results;
-  },
-
-  detect: function (iterator) {
-    var result;
-    this.each(function(value, index) {
-      if (iterator(value, index)) {
-        result = value;
-        throw $break;
-      }
-    });
-    return result;
-  },
-
-  findAll: function(iterator) {
-    var results = [];
-    this.each(function(value, index) {
-      if (iterator(value, index))
-        results.push(value);
-    });
-    return results;
-  },
-
-  grep: function(pattern, iterator) {
-    var results = [];
-    this.each(function(value, index) {
-      var stringValue = value.toString();
-      if (stringValue.match(pattern))
-        results.push((iterator || Prototype.K)(value, index));
-    })
-    return results;
-  },
-
-  include: function(object) {
-    var found = false;
-    this.each(function(value) {
-      if (value == object) {
-        found = true;
-        throw $break;
-      }
-    });
-    return found;
-  },
-
-  inject: function(memo, iterator) {
-    this.each(function(value, index) {
-      memo = iterator(memo, value, index);
-    });
-    return memo;
-  },
-
-  invoke: function(method) {
-    var args = $A(arguments).slice(1);
-    return this.collect(function(value) {
-      return value[method].apply(value, args);
-    });
-  },
-
-  max: function(iterator) {
-    var result;
-    this.each(function(value, index) {
-      value = (iterator || Prototype.K)(value, index);
-      if (value >= (result || value))
-        result = value;
-    });
-    return result;
-  },
-
-  min: function(iterator) {
-    var result;
-    this.each(function(value, index) {
-      value = (iterator || Prototype.K)(value, index);
-      if (value <= (result || value))
-        result = value;
-    });
-    return result;
-  },
-
-  partition: function(iterator) {
-    var trues = [], falses = [];
-    this.each(function(value, index) {
-      ((iterator || Prototype.K)(value, index) ?
-        trues : falses).push(value);
-    });
-    return [trues, falses];
-  },
-
-  pluck: function(property) {
-    var results = [];
-    this.each(function(value, index) {
-      results.push(value[property]);
-    });
-    return results;
-  },
-
-  reject: function(iterator) {
-    var results = [];
-    this.each(function(value, index) {
-      if (!iterator(value, index))
-        results.push(value);
-    });
-    return results;
-  },
-
-  sortBy: function(iterator) {
-    return this.collect(function(value, index) {
-      return {value: value, criteria: iterator(value, index)};
-    }).sort(function(left, right) {
-      var a = left.criteria, b = right.criteria;
-      return a < b ? -1 : a > b ? 1 : 0;
-    }).pluck('value');
-  },
-
-  toArray: function() {
-    return this.collect(Prototype.K);
-  },
-
-  zip: function() {
-    var iterator = Prototype.K, args = $A(arguments);
-    if (typeof args.last() == 'function')
-      iterator = args.pop();
-
-    var collections = [this].concat(args).map($A);
-    return this.map(function(value, index) {
-      iterator(value = collections.pluck(index));
-      return value;
-    });
-  },
-
-  inspect: function() {
-    return '#<Enumerable:' + this.toArray().inspect() + '>';
-  }
-}
-
-Object.extend(Enumerable, {
-  map:     Enumerable.collect,
-  find:    Enumerable.detect,
-  select:  Enumerable.findAll,
-  member:  Enumerable.include,
-  entries: Enumerable.toArray
-});
-var $A = Array.from = function(iterable) {
-  if (!iterable) return [];
-  if (iterable.toArray) {
-    return iterable.toArray();
-  } else {
-    var results = [];
-    for (var i = 0; i < iterable.length; i++)
-      results.push(iterable[i]);
-    return results;
-  }
-}
-
-Object.extend(Array.prototype, Enumerable);
-
-Array.prototype._reverse = Array.prototype.reverse;
-
-Object.extend(Array.prototype, {
-  _each: function(iterator) {
-    for (var i = 0; i < this.length; i++)
-      iterator(this[i]);
-  },
-
-  clear: function() {
-    this.length = 0;
-    return this;
-  },
-
-  first: function() {
-    return this[0];
-  },
-
-  last: function() {
-    return this[this.length - 1];
-  },
-
-  compact: function() {
-    return this.select(function(value) {
-      return value != undefined || value != null;
-    });
-  },
-
-  flatten: function() {
-    return this.inject([], function(array, value) {
-      return array.concat(value.constructor == Array ?
-        value.flatten() : [value]);
-    });
-  },
-
-  without: function() {
-    var values = $A(arguments);
-    return this.select(function(value) {
-      return !values.include(value);
-    });
-  },
-
-  indexOf: function(object) {
-    for (var i = 0; i < this.length; i++)
-      if (this[i] == object) return i;
-    return -1;
-  },
-
-  reverse: function(inline) {
-    return (inline !== false ? this : this.toArray())._reverse();
-  },
-
-  shift: function() {
-    var result = this[0];
-    for (var i = 0; i < this.length - 1; i++)
-      this[i] = this[i + 1];
-    this.length--;
-    return result;
-  },
-
-  inspect: function() {
-    return '[' + this.map(Object.inspect).join(', ') + ']';
-  }
-});
-var Hash = {
-  _each: function(iterator) {
-    for (key in this) {
-      var value = this[key];
-      if (typeof value == 'function') continue;
-
-      var pair = [key, value];
-      pair.key = key;
-      pair.value = value;
-      iterator(pair);
-    }
-  },
-
-  keys: function() {
-    return this.pluck('key');
-  },
-
-  values: function() {
-    return this.pluck('value');
-  },
-
-  merge: function(hash) {
-    return $H(hash).inject($H(this), function(mergedHash, pair) {
-      mergedHash[pair.key] = pair.value;
-      return mergedHash;
-    });
-  },
-
-  toQueryString: function() {
-    return this.map(function(pair) {
-      return pair.map(encodeURIComponent).join('=');
-    }).join('&');
-  },
-
-  inspect: function() {
-    return '#<Hash:{' + this.map(function(pair) {
-      return pair.map(Object.inspect).join(': ');
-    }).join(', ') + '}>';
-  }
-}
-
-function $H(object) {
-  var hash = Object.extend({}, object || {});
-  Object.extend(hash, Enumerable);
-  Object.extend(hash, Hash);
-  return hash;
-}
-ObjectRange = Class.create();
-Object.extend(ObjectRange.prototype, Enumerable);
-Object.extend(ObjectRange.prototype, {
-  initialize: function(start, end, exclusive) {
-    this.start = start;
-    this.end = end;
-    this.exclusive = exclusive;
-  },
-
-  _each: function(iterator) {
-    var value = this.start;
-    do {
-      iterator(value);
-      value = value.succ();
-    } while (this.include(value));
-  },
-
-  include: function(value) {
-    if (value < this.start)
-      return false;
-    if (this.exclusive)
-      return value < this.end;
-    return value <= this.end;
-  }
-});
-
-var $R = function(start, end, exclusive) {
-  return new ObjectRange(start, end, exclusive);
-}
-
-var Ajax = {
-  getTransport: function() {
-    return Try.these(
-      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
-      function() {return new ActiveXObject('Microsoft.XMLHTTP')},
-      function() {return new XMLHttpRequest()}
-    ) || false;
-  },
-
-  activeRequestCount: 0
-}
-
-Ajax.Responders = {
-  responders: [],
-
-  _each: function(iterator) {
-    this.responders._each(iterator);
-  },
-
-  register: function(responderToAdd) {
-    if (!this.include(responderToAdd))
-      this.responders.push(responderToAdd);
-  },
-
-  unregister: function(responderToRemove) {
-    this.responders = this.responders.without(responderToRemove);
-  },
-
-  dispatch: function(callback, request, transport, json) {
-    this.each(function(responder) {
-      if (responder[callback] && typeof responder[callback] == 'function') {
-        try {
-          responder[callback].apply(responder, [request, transport, json]);
-        } catch (e) {}
-      }
-    });
-  }
-};
-
-Object.extend(Ajax.Responders, Enumerable);
-
-Ajax.Responders.register({
-  onCreate: function() {
-    Ajax.activeRequestCount++;
-  },
-
-  onComplete: function() {
-    Ajax.activeRequestCount--;
-  }
-});
-
-Ajax.Base = function() {};
-Ajax.Base.prototype = {
-  setOptions: function(options) {
-    this.options = {
-      method:       'post',
-      asynchronous: true,
-      parameters:   ''
-    }
-    Object.extend(this.options, options || {});
-  },
-
-  responseIsSuccess: function() {
-    return this.transport.status == undefined
-        || this.transport.status == 0
-        || (this.transport.status >= 200 && this.transport.status < 300);
-  },
-
-  responseIsFailure: function() {
-    return !this.responseIsSuccess();
-  }
-}
-
-Ajax.Request = Class.create();
-Ajax.Request.Events =
-  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
-
-Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
-  initialize: function(url, options) {
-    this.transport = Ajax.getTransport();
-    this.setOptions(options);
-    this.request(url);
-  },
-
-  request: function(url) {
-    var parameters = this.options.parameters || '';
-    if (parameters.length > 0) parameters += '&_=';
-
-    try {
-      this.url = url;
-      if (this.options.method == 'get' && parameters.length > 0)
-        this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;
-
-      Ajax.Responders.dispatch('onCreate', this, this.transport);
-
-      this.transport.open(this.options.method, this.url,
-        this.options.asynchronous);
-
-      if (this.options.asynchronous) {
-        this.transport.onreadystatechange = this.onStateChange.bind(this);
-        setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10);
-      }
-
-      this.setRequestHeaders();
-
-      var body = this.options.postBody ? this.options.postBody : parameters;
-      this.transport.send(this.options.method == 'post' ? body : null);
-
-    } catch (e) {
-      this.dispatchException(e);
-    }
-  },
-
-  setRequestHeaders: function() {
-    var requestHeaders =
-      ['X-Requested-With', 'XMLHttpRequest',
-       'X-Prototype-Version', Prototype.Version];
-
-    if (this.options.method == 'post') {
-      requestHeaders.push('Content-type',
-        'application/x-www-form-urlencoded');
-
-      /* Force "Connection: close" for Mozilla browsers to work around
-       * a bug where XMLHttpReqeuest sends an incorrect Content-length
-       * header. See Mozilla Bugzilla #246651.
-       */
-      if (this.transport.overrideMimeType)
-        requestHeaders.push('Connection', 'close');
-    }
-
-    if (this.options.requestHeaders)
-      requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);
-
-    for (var i = 0; i < requestHeaders.length; i += 2)
-      this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]);
-  },
-
-  onStateChange: function() {
-    var readyState = this.transport.readyState;
-    if (readyState != 1)
-      this.respondToReadyState(this.transport.readyState);
-  },
-
-  header: function(name) {
-    try {
-      return this.transport.getResponseHeader(name);
-    } catch (e) {}
-  },
-
-  evalJSON: function() {
-    try {
-      return eval(this.header('X-JSON'));
-    } catch (e) {}
-  },
-
-  evalResponse: function() {
-    try {
-      return eval(this.transport.responseText);
-    } catch (e) {
-      this.dispatchException(e);
-    }
-  },
-
-  respondToReadyState: function(readyState) {
-    var event = Ajax.Request.Events[readyState];
-    var transport = this.transport, json = this.evalJSON();
-
-    if (event == 'Complete') {
-      try {
-        (this.options['on' + this.transport.status]
-         || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
-         || Prototype.emptyFunction)(transport, json);
-      } catch (e) {
-        this.dispatchException(e);
-      }
-
-      if ((this.header('Content-type') || '').match(/^text\/javascript/i))
-        this.evalResponse();
-    }
-
-    try {
-      (this.options['on' + event] || Prototype.emptyFunction)(transport, json);
-      Ajax.Responders.dispatch('on' + event, this, transport, json);
-    } catch (e) {
-      this.dispatchException(e);
-    }
-
-    /* Avoid memory leak in MSIE: clean up the oncomplete event handler */
-    if (event == 'Complete')
-      this.transport.onreadystatechange = Prototype.emptyFunction;
-  },
-
-  dispatchException: function(exception) {
-    (this.options.onException || Prototype.emptyFunction)(this, exception);
-    Ajax.Responders.dispatch('onException', this, exception);
-  }
-});
-
-Ajax.Updater = Class.create();
-
-Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
-  initialize: function(container, url, options) {
-    this.containers = {
-      success: container.success ? $(container.success) : $(container),
-      failure: container.failure ? $(container.failure) :
-        (container.success ? null : $(container))
-    }
-
-    this.transport = Ajax.getTransport();
-    this.setOptions(options);
-
-    var onComplete = this.options.onComplete || Prototype.emptyFunction;
-    this.options.onComplete = (function(transport, object) {
-      this.updateContent();
-      onComplete(transport, object);
-    }).bind(this);
-
-    this.request(url);
-  },
-
-  updateContent: function() {
-    var receiver = this.responseIsSuccess() ?
-      this.containers.success : this.containers.failure;
-    var response = this.transport.responseText;
-
-    if (!this.options.evalScripts)
-      response = response.stripScripts();
-
-    if (receiver) {
-      if (this.options.insertion) {
-        new this.options.insertion(receiver, response);
-      } else {
-        Element.update(receiver, response);
-      }
-    }
-
-    if (this.responseIsSuccess()) {
-      if (this.onComplete)
-        setTimeout(this.onComplete.bind(this), 10);
-    }
-  }
-});
-
-Ajax.PeriodicalUpdater = Class.create();
-Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
-  initialize: function(container, url, options) {
-    this.setOptions(options);
-    this.onComplete = this.options.onComplete;
-
-    this.frequency = (this.options.frequency || 2);
-    this.decay = (this.options.decay || 1);
-
-    this.updater = {};
-    this.container = container;
-    this.url = url;
-
-    this.start();
-  },
-
-  start: function() {
-    this.options.onComplete = this.updateComplete.bind(this);
-    this.onTimerEvent();
-  },
-
-  stop: function() {
-    this.updater.onComplete = undefined;
-    clearTimeout(this.timer);
-    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
-  },
-
-  updateComplete: function(request) {
-    if (this.options.decay) {
-      this.decay = (request.responseText == this.lastText ?
-        this.decay * this.options.decay : 1);
-
-      this.lastText = request.responseText;
-    }
-    this.timer = setTimeout(this.onTimerEvent.bind(this),
-      this.decay * this.frequency * 1000);
-  },
-
-  onTimerEvent: function() {
-    this.updater = new Ajax.Updater(this.container, this.url, this.options);
-  }
-});
-document.getElementsByClassName = function(className, parentElement) {
-  var children = ($(parentElement) || document.body).getElementsByTagName('*');
-  return $A(children).inject([], function(elements, child) {
-    if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
-      elements.push(child);
-    return elements;
-  });
-}
-
-/*--------------------------------------------------------------------------*/
-
-if (!window.Element) {
-  var Element = new Object();
-}
-
-Object.extend(Element, {
-  visible: function(element) {
-    return $(element).style.display != 'none';
-  },
-
-  toggle: function() {
-    for (var i = 0; i < arguments.length; i++) {
-      var element = $(arguments[i]);
-      Element[Element.visible(element) ? 'hide' : 'show'](element);
-    }
-  },
-
-  hide: function() {
-    for (var i = 0; i < arguments.length; i++) {
-      var element = $(arguments[i]);
-      element.style.display = 'none';
-    }
-  },
-
-  show: function() {
-    for (var i = 0; i < arguments.length; i++) {
-      var element = $(arguments[i]);
-      element.style.display = '';
-    }
-  },
-
-  remove: function(element) {
-    element = $(element);
-    element.parentNode.removeChild(element);
-  },
-
-  update: function(element, html) {
-    $(element).innerHTML = html.stripScripts();
-    setTimeout(function() {html.evalScripts()}, 10);
-  },
-
-  getHeight: function(element) {
-    element = $(element);
-    return element.offsetHeight;
-  },
-
-  classNames: function(element) {
-    return new Element.ClassNames(element);
-  },
-
-  hasClassName: function(element, className) {
-    if (!(element = $(element))) return;
-    return Element.classNames(element).include(className);
-  },
-
-  addClassName: function(element, className) {
-    if (!(element = $(element))) return;
-    return Element.classNames(element).add(className);
-  },
-
-  removeClassName: function(element, className) {
-    if (!(element = $(element))) return;
-    return Element.classNames(element).remove(className);
-  },
-
-  // removes whitespace-only text node children
-  cleanWhitespace: function(element) {
-    element = $(element);
-    for (var i = 0; i < element.childNodes.length; i++) {
-      var node = element.childNodes[i];
-      if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
-        Element.remove(node);
-    }
-  },
-
-  empty: function(element) {
-    return $(element).innerHTML.match(/^\s*$/);
-  },
-
-  scrollTo: function(element) {
-    element = $(element);
-    var x = element.x ? element.x : element.offsetLeft,
-        y = element.y ? element.y : element.offsetTop;
-    window.scrollTo(x, y);
-  },
-
-  getStyle: function(element, style) {
-    element = $(element);
-    var value = element.style[style.camelize()];
-    if (!value) {
-      if (document.defaultView && document.defaultView.getComputedStyle) {
-        var css = document.defaultView.getComputedStyle(element, null);
-        value = css ? css.getPropertyValue(style) : null;
-      } else if (element.currentStyle) {
-        value = element.currentStyle[style.camelize()];
-      }
-    }
-
-    if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
-      if (Element.getStyle(element, 'position') == 'static') value = 'auto';
-
-    return value == 'auto' ? null : value;
-  },
-
-  setStyle: function(element, style) {
-    element = $(element);
-    for (name in style)
-      element.style[name.camelize()] = style[name];
-  },
-
-  getDimensions: function(element) {
-    element = $(element);
-    if (Element.getStyle(element, 'display') != 'none')
-      return {width: element.offsetWidth, height: element.offsetHeight};
-
-    // All *Width and *Height properties give 0 on elements with display none,
-    // so enable the element temporarily
-    var els = element.style;
-    var originalVisibility = els.visibility;
-    var originalPosition = els.position;
-    els.visibility = 'hidden';
-    els.position = 'absolute';
-    els.display = '';
-    var originalWidth = element.clientWidth;
-    var originalHeight = element.clientHeight;
-    els.display = 'none';
-    els.position = originalPosition;
-    els.visibility = originalVisibility;
-    return {width: originalWidth, height: originalHeight};
-  },
-
-  makePositioned: function(element) {
-    element = $(element);
-    var pos = Element.getStyle(element, 'position');
-    if (pos == 'static' || !pos) {
-      element._madePositioned = true;
-      element.style.position = 'relative';
-      // Opera returns the offset relative to the positioning context, when an
-      // element is position relative but top and left have not been defined
-      if (window.opera) {
-        element.style.top = 0;
-        element.style.left = 0;
-      }
-    }
-  },
-
-  undoPositioned: function(element) {
-    element = $(element);
-    if (element._madePositioned) {
-      element._madePositioned = undefined;
-      element.style.position =
-        element.style.top =
-        element.style.left =
-        element.style.bottom =
-        element.style.right = '';
-    }
-  },
-
-  makeClipping: function(element) {
-    element = $(element);
-    if (element._overflow) return;
-    element._overflow = element.style.overflow;
-    if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
-      element.style.overflow = 'hidden';
-  },
-
-  undoClipping: function(element) {
-    element = $(element);
-    if (element._overflow) return;
-    element.style.overflow = element._overflow;
-    element._overflow = undefined;
-  }
-});
-
-var Toggle = new Object();
-Toggle.display = Element.toggle;
-
-/*--------------------------------------------------------------------------*/
-
-Abstract.Insertion = function(adjacency) {
-  this.adjacency = adjacency;
-}
-
-Abstract.Insertion.prototype = {
-  initialize: function(element, content) {
-    this.element = $(element);
-    this.content = content.stripScripts();
-
-    if (this.adjacency && this.element.insertAdjacentHTML) {
-      try {
-        this.element.insertAdjacentHTML(this.adjacency, this.content);
-      } catch (e) {
-        if (this.element.tagName.toLowerCase() == 'tbody') {
-          this.insertContent(this.contentFromAnonymousTable());
-        } else {
-          throw e;
-        }
-      }
-    } else {
-      this.range = this.element.ownerDocument.createRange();
-      if (this.initializeRange) this.initializeRange();
-      this.insertContent([this.range.createContextualFragment(this.content)]);
-    }
-
-    setTimeout(function() {content.evalScripts()}, 10);
-  },
-
-  contentFromAnonymousTable: function() {
-    var div = document.createElement('div');
-    div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
-    return $A(div.childNodes[0].childNodes[0].childNodes);
-  }
-}
-
-var Insertion = new Object();
-
-Insertion.Before = Class.create();
-Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
-  initializeRange: function() {
-    this.range.setStartBefore(this.element);
-  },
-
-  insertContent: function(fragments) {
-    fragments.each((function(fragment) {
-      this.element.parentNode.insertBefore(fragment, this.element);
-    }).bind(this));
-  }
-});
-
-Insertion.Top = Class.create();
-Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
-  initializeRange: function() {
-    this.range.selectNodeContents(this.element);
-    this.range.collapse(true);
-  },
-
-  insertContent: function(fragments) {
-    fragments.reverse(false).each((function(fragment) {
-      this.element.insertBefore(fragment, this.element.firstChild);
-    }).bind(this));
-  }
-});
-
-Insertion.Bottom = Class.create();
-Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
-  initializeRange: function() {
-    this.range.selectNodeContents(this.element);
-    this.range.collapse(this.element);
-  },
-
-  insertContent: function(fragments) {
-    fragments.each((function(fragment) {
-      this.element.appendChild(fragment);
-    }).bind(this));
-  }
-});
-
-Insertion.After = Class.create();
-Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
-  initializeRange: function() {
-    this.range.setStartAfter(this.element);
-  },
-
-  insertContent: function(fragments) {
-    fragments.each((function(fragment) {
-      this.element.parentNode.insertBefore(fragment,
-        this.element.nextSibling);
-    }).bind(this));
-  }
-});
-
-/*--------------------------------------------------------------------------*/
-
-Element.ClassNames = Class.create();
-Element.ClassNames.prototype = {
-  initialize: function(element) {
-    this.element = $(element);
-  },
-
-  _each: function(iterator) {
-    this.element.className.split(/\s+/).select(function(name) {
-      return name.length > 0;
-    })._each(iterator);
-  },
-
-  set: function(className) {
-    this.element.className = className;
-  },
-
-  add: function(classNameToAdd) {
-    if (this.include(classNameToAdd)) return;
-    this.set(this.toArray().concat(classNameToAdd).join(' '));
-  },
-
-  remove: function(classNameToRemove) {
-    if (!this.include(classNameToRemove)) return;
-    this.set(this.select(function(className) {
-      return className != classNameToRemove;
-    }).join(' '));
-  },
-
-  toString: function() {
-    return this.toArray().join(' ');
-  }
-}
-
-Object.extend(Element.ClassNames.prototype, Enumerable);
-var Field = {
-  clear: function() {
-    for (var i = 0; i < arguments.length; i++)
-      $(arguments[i]).value = '';
-  },
-
-  focus: function(element) {
-    $(element).focus();
-  },
-
-  present: function() {
-    for (var i = 0; i < arguments.length; i++)
-      if ($(arguments[i]).value == '') return false;
-    return true;
-  },
-
-  select: function(element) {
-    $(element).select();
-  },
-
-  activate: function(element) {
-    element = $(element);
-    element.focus();
-    if (element.select)
-      element.select();
-  }
-}
-
-/*--------------------------------------------------------------------------*/
-
-var Form = {
-  serialize: function(form) {
-    var elements = Form.getElements($(form));
-    var queryComponents = new Array();
-
-    for (var i = 0; i < elements.length; i++) {
-      var queryComponent = Form.Element.serialize(elements[i]);
-      if (queryComponent)
-        queryComponents.push(queryComponent);
-    }
-
-    return queryComponents.join('&');
-  },
-
-  getElements: function(form) {
-    form = $(form);
-    var elements = new Array();
-
-    for (tagName in Form.Element.Serializers) {
-      var tagElements = form.getElementsByTagName(tagName);
-      for (var j = 0; j < tagElements.length; j++)
-        elements.push(tagElements[j]);
-    }
-    return elements;
-  },
-
-  getInputs: function(form, typeName, name) {
-    form = $(form);
-    var inputs = form.getElementsByTagName('input');
-
-    if (!typeName && !name)
-      return inputs;
-
-    var matchingInputs = new Array();
-    for (var i = 0; i < inputs.length; i++) {
-      var input = inputs[i];
-      if ((typeName && input.type != typeName) ||
-          (name && input.name != name))
-        continue;
-      matchingInputs.push(input);
-    }
-
-    return matchingInputs;
-  },
-
-  disable: function(form) {
-    var elements = Form.getElements(form);
-    for (var i = 0; i < elements.length; i++) {
-      var element = elements[i];
-      element.blur();
-      element.disabled = 'true';
-    }
-  },
-
-  enable: function(form) {
-    var elements = Form.getElements(form);
-    for (var i = 0; i < elements.length; i++) {
-      var element = elements[i];
-      element.disabled = '';
-    }
-  },
-
-  findFirstElement: function(form) {
-    return Form.getElements(form).find(function(element) {
-      return element.type != 'hidden' && !element.disabled &&
-        ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
-    });
-  },
-
-  focusFirstElement: function(form) {
-    Field.activate(Form.findFirstElement(form));
-  },
-
-  reset: function(form) {
-    $(form).reset();
-  }
-}
-
-Form.Element = {
-  serialize: function(element) {
-    element = $(element);
-    var method = element.tagName.toLowerCase();
-    var parameter = Form.Element.Serializers[method](element);
-
-    if (parameter) {
-      var key = encodeURIComponent(parameter[0]);
-      if (key.length == 0) return;
-
-      if (parameter[1].constructor != Array)
-        parameter[1] = [parameter[1]];
-
-      return parameter[1].map(function(value) {
-        return key + '=' + encodeURIComponent(value);
-      }).join('&');
-    }
-  },
-
-  getValue: function(element) {
-    element = $(element);
-    var method = element.tagName.toLowerCase();
-    var parameter = Form.Element.Serializers[method](element);
-
-    if (parameter)
-      return parameter[1];
-  }
-}
-
-Form.Element.Serializers = {
-  input: function(element) {
-    switch (element.type.toLowerCase()) {
-      case 'submit':
-      case 'hidden':
-      case 'password':
-      case 'text':
-        return Form.Element.Serializers.textarea(element);
-      case 'checkbox':
-      case 'radio':
-        return Form.Element.Serializers.inputSelector(element);
-    }
-    return false;
-  },
-
-  inputSelector: function(element) {
-    if (element.checked)
-      return [element.name, element.value];
-  },
-
-  textarea: function(element) {
-    return [element.name, element.value];
-  },
-
-  select: function(element) {
-    return Form.Element.Serializers[element.type == 'select-one' ?
-      'selectOne' : 'selectMany'](element);
-  },
-
-  selectOne: function(element) {
-    var value = '', opt, index = element.selectedIndex;
-    if (index >= 0) {
-      opt = element.options[index];
-      value = opt.value;
-      if (!value && !('value' in opt))
-        value = opt.text;
-    }
-    return [element.name, value];
-  },
-
-  selectMany: function(element) {
-    var value = new Array();
-    for (var i = 0; i < element.length; i++) {
-      var opt = element.options[i];
-      if (opt.selected) {
-        var optValue = opt.value;
-        if (!optValue && !('value' in opt))
-          optValue = opt.text;
-        value.push(optValue);
-      }
-    }
-    return [element.name, value];
-  }
-}
-
-/*--------------------------------------------------------------------------*/
-
-var $F = Form.Element.getValue;
-
-/*--------------------------------------------------------------------------*/
-
-Abstract.TimedObserver = function() {}
-Abstract.TimedObserver.prototype = {
-  initialize: function(element, frequency, callback) {
-    this.frequency = frequency;
-    this.element   = $(element);
-    this.callback  = callback;
-
-    this.lastValue = this.getValue();
-    this.registerCallback();
-  },
-
-  registerCallback: function() {
-    setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
-  },
-
-  onTimerEvent: function() {
-    var value = this.getValue();
-    if (this.lastValue != value) {
-      this.callback(this.element, value);
-      this.lastValue = value;
-    }
-  }
-}
-
-Form.Element.Observer = Class.create();
-Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
-  getValue: function() {
-    return Form.Element.getValue(this.element);
-  }
-});
-
-Form.Observer = Class.create();
-Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
-  getValue: function() {
-    return Form.serialize(this.element);
-  }
-});
-
-/*--------------------------------------------------------------------------*/
-
-Abstract.EventObserver = function() {}
-Abstract.EventObserver.prototype = {
-  initialize: function(element, callback) {
-    this.element  = $(element);
-    this.callback = callback;
-
-    this.lastValue = this.getValue();
-    if (this.element.tagName.toLowerCase() == 'form')
-      this.registerFormCallbacks();
-    else
-      this.registerCallback(this.element);
-  },
-
-  onElementEvent: function() {
-    var value = this.getValue();
-    if (this.lastValue != value) {
-      this.callback(this.element, value);
-      this.lastValue = value;
-    }
-  },
-
-  registerFormCallbacks: function() {
-    var elements = Form.getElements(this.element);
-    for (var i = 0; i < elements.length; i++)
-      this.registerCallback(elements[i]);
-  },
-
-  registerCallback: function(element) {
-    if (element.type) {
-      switch (element.type.toLowerCase()) {
-        case 'checkbox':
-        case 'radio':
-          Event.observe(element, 'click', this.onElementEvent.bind(this));
-          break;
-        case 'password':
-        case 'text':
-        case 'textarea':
-        case 'select-one':
-        case 'select-multiple':
-          Event.observe(element, 'change', this.onElementEvent.bind(this));
-          break;
-      }
-    }
-  }
-}
-
-Form.Element.EventObserver = Class.create();
-Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
-  getValue: function() {
-    return Form.Element.getValue(this.element);
-  }
-});
-
-Form.EventObserver = Class.create();
-Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
-  getValue: function() {
-    return Form.serialize(this.element);
-  }
-});
-if (!window.Event) {
-  var Event = new Object();
-}
-
-Object.extend(Event, {
-  KEY_BACKSPACE: 8,
-  KEY_TAB:       9,
-  KEY_RETURN:   13,
-  KEY_ESC:      27,
-  KEY_LEFT:     37,
-  KEY_UP:       38,
-  KEY_RIGHT:    39,
-  KEY_DOWN:     40,
-  KEY_DELETE:   46,
-
-  element: function(event) {
-    return event.target || event.srcElement;
-  },
-
-  isLeftClick: function(event) {
-    return (((event.which) && (event.which == 1)) ||
-            ((event.button) && (event.button == 1)));
-  },
-
-  pointerX: function(event) {
-    return event.pageX || (event.clientX +
-      (document.documentElement.scrollLeft || document.body.scrollLeft));
-  },
-
-  pointerY: function(event) {
-    return event.pageY || (event.clientY +
-      (document.documentElement.scrollTop || document.body.scrollTop));
-  },
-
-  stop: function(event) {
-    if (event.preventDefault) {
-      event.preventDefault();
-      event.stopPropagation();
-    } else {
-      event.returnValue = false;
-      event.cancelBubble = true;
-    }
-  },
-
-  // find the first node with the given tagName, starting from the
-  // node the event was triggered on; traverses the DOM upwards
-  findElement: function(event, tagName) {
-    var element = Event.element(event);
-    while (element.parentNode && (!element.tagName ||
-        (element.tagName.toUpperCase() != tagName.toUpperCase())))
-      element = element.parentNode;
-    return element;
-  },
-
-  observers: false,
-
-  _observeAndCache: function(element, name, observer, useCapture) {
-    if (!this.observers) this.observers = [];
-    if (element.addEventListener) {
-      this.observers.push([element, name, observer, useCapture]);
-      element.addEventListener(name, observer, useCapture);
-    } else if (element.attachEvent) {
-      this.observers.push([element, name, observer, useCapture]);
-      element.attachEvent('on' + name, observer);
-    }
-  },
-
-  unloadCache: function() {
-    if (!Event.observers) return;
-    for (var i = 0; i < Event.observers.length; i++) {
-      Event.stopObserving.apply(this, Event.observers[i]);
-      Event.observers[i][0] = null;
-    }
-    Event.observers = false;
-  },
-
-  observe: function(element, name, observer, useCapture) {
-    var element = $(element);
-    useCapture = useCapture || false;
-
-    if (name == 'keypress' &&
-        (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
-        || element.attachEvent))
-      name = 'keydown';
-
-    this._observeAndCache(element, name, observer, useCapture);
-  },
-
-  stopObserving: function(element, name, observer, useCapture) {
-    var element = $(element);
-    useCapture = useCapture || false;
-
-    if (name == 'keypress' &&
-        (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
-        || element.detachEvent))
-      name = 'keydown';
-
-    if (element.removeEventListener) {
-      element.removeEventListener(name, observer, useCapture);
-    } else if (element.detachEvent) {
-      element.detachEvent('on' + name, observer);
-    }
-  }
-});
-
-/* prevent memory leaks in IE */
-Event.observe(window, 'unload', Event.unloadCache, false);
-var Position = {
-  // set to true if needed, warning: firefox performance problems
-  // NOT neeeded for page scrolling, only if draggable contained in
-  // scrollable elements
-  includeScrollOffsets: false,
-
-  // must be called before calling withinIncludingScrolloffset, every time the
-  // page is scrolled
-  prepare: function() {
-    this.deltaX =  window.pageXOffset
-                || document.documentElement.scrollLeft
-                || document.body.scrollLeft
-                || 0;
-    this.deltaY =  window.pageYOffset
-                || document.documentElement.scrollTop
-                || document.body.scrollTop
-                || 0;
-  },
-
-  realOffset: function(element) {
-    var valueT = 0, valueL = 0;
-    do {
-      valueT += element.scrollTop  || 0;
-      valueL += element.scrollLeft || 0;
-      element = element.parentNode;
-    } while (element);
-    return [valueL, valueT];
-  },
-
-  cumulativeOffset: function(element) {
-    var valueT = 0, valueL = 0;
-    do {
-      valueT += element.offsetTop  || 0;
-      valueL += element.offsetLeft || 0;
-      element = element.offsetParent;
-    } while (element);
-    return [valueL, valueT];
-  },
-
-  positionedOffset: function(element) {
-    var valueT = 0, valueL = 0;
-    do {
-      valueT += element.offsetTop  || 0;
-      valueL += element.offsetLeft || 0;
-      element = element.offsetParent;
-      if (element) {
-        p = Element.getStyle(element, 'position');
-        if (p == 'relative' || p == 'absolute') break;
-      }
-    } while (element);
-    return [valueL, valueT];
-  },
-
-  offsetParent: function(element) {
-    if (element.offsetParent) return element.offsetParent;
-    if (element == document.body) return element;
-
-    while ((element = element.parentNode) && element != document.body)
-      if (Element.getStyle(element, 'position') != 'static')
-        return element;
-
-    return document.body;
-  },
-
-  // caches x/y coordinate pair to use with overlap
-  within: function(element, x, y) {
-    if (this.includeScrollOffsets)
-      return this.withinIncludingScrolloffsets(element, x, y);
-    this.xcomp = x;
-    this.ycomp = y;
-    this.offset = this.cumulativeOffset(element);
-
-    return (y >= this.offset[1] &&
-            y <  this.offset[1] + element.offsetHeight &&
-            x >= this.offset[0] &&
-            x <  this.offset[0] + element.offsetWidth);
-  },
-
-  withinIncludingScrolloffsets: function(element, x, y) {
-    var offsetcache = this.realOffset(element);
-
-    this.xcomp = x + offsetcache[0] - this.deltaX;
-    this.ycomp = y + offsetcache[1] - this.deltaY;
-    this.offset = this.cumulativeOffset(element);
-
-    return (this.ycomp >= this.offset[1] &&
-            this.ycomp <  this.offset[1] + element.offsetHeight &&
-            this.xcomp >= this.offset[0] &&
-            this.xcomp <  this.offset[0] + element.offsetWidth);
-  },
-
-  // within must be called directly before
-  overlap: function(mode, element) {
-    if (!mode) return 0;
-    if (mode == 'vertical')
-      return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
-        element.offsetHeight;
-    if (mode == 'horizontal')
-      return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
-        element.offsetWidth;
-  },
-
-  clone: function(source, target) {
-    source = $(source);
-    target = $(target);
-    target.style.position = 'absolute';
-    var offsets = this.cumulativeOffset(source);
-    target.style.top    = offsets[1] + 'px';
-    target.style.left   = offsets[0] + 'px';
-    target.style.width  = source.offsetWidth + 'px';
-    target.style.height = source.offsetHeight + 'px';
-  },
-
-  page: function(forElement) {
-    var valueT = 0, valueL = 0;
-
-    var element = forElement;
-    do {
-      valueT += element.offsetTop  || 0;
-      valueL += element.offsetLeft || 0;
-
-      // Safari fix
-      if (element.offsetParent==document.body)
-        if (Element.getStyle(element,'position')=='absolute') break;
-
-    } while (element = element.offsetParent);
-
-    element = forElement;
-    do {
-      valueT -= element.scrollTop  || 0;
-      valueL -= element.scrollLeft || 0;
-    } while (element = element.parentNode);
-
-    return [valueL, valueT];
-  },
-
-  clone: function(source, target) {
-    var options = Object.extend({
-      setLeft:    true,
-      setTop:     true,
-      setWidth:   true,
-      setHeight:  true,
-      offsetTop:  0,
-      offsetLeft: 0
-    }, arguments[2] || {})
-
-    // find page position of source
-    source = $(source);
-    var p = Position.page(source);
-
-    // find coordinate system to use
-    target = $(target);
-    var delta = [0, 0];
-    var parent = null;
-    // delta [0,0] will do fine with position: fixed elements,
-    // position:absolute needs offsetParent deltas
-    if (Element.getStyle(target,'position') == 'absolute') {
-      parent = Position.offsetParent(target);
-      delta = Position.page(parent);
-    }
-
-    // correct by body offsets (fixes Safari)
-    if (parent == document.body) {
-      delta[0] -= document.body.offsetLeft;
-      delta[1] -= document.body.offsetTop;
-    }
-
-    // set position
-    if(options.setLeft)   target.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';
-    if(options.setTop)    target.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';
-    if(options.setWidth)  target.style.width = source.offsetWidth + 'px';
-    if(options.setHeight) target.style.height = source.offsetHeight + 'px';
-  },
-
-  absolutize: function(element) {
-    element = $(element);
-    if (element.style.position == 'absolute') return;
-    Position.prepare();
-
-    var offsets = Position.positionedOffset(element);
-    var top     = offsets[1];
-    var left    = offsets[0];
-    var width   = element.clientWidth;
-    var height  = element.clientHeight;
-
-    element._originalLeft   = left - parseFloat(element.style.left  || 0);
-    element._originalTop    = top  - parseFloat(element.style.top || 0);
-    element._originalWidth  = element.style.width;
-    element._originalHeight = element.style.height;
-
-    element.style.position = 'absolute';
-    element.style.top    = top + 'px';;
-    element.style.left   = left + 'px';;
-    element.style.width  = width + 'px';;
-    element.style.height = height + 'px';;
-  },
-
-  relativize: function(element) {
-    element = $(element);
-    if (element.style.position == 'relative') return;
-    Position.prepare();
-
-    element.style.position = 'relative';
-    var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0);
-    var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
-
-    element.style.top    = top + 'px';
-    element.style.left   = left + 'px';
-    element.style.height = element._originalHeight;
-    element.style.width  = element._originalWidth;
-  }
-}
-
-// Safari returns margins on body which is incorrect if the child is absolutely
-// positioned.  For performance reasons, redefine Position.cumulativeOffset for
-// KHTML/WebKit only.
-if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
-  Position.cumulativeOffset = function(element) {
-    var valueT = 0, valueL = 0;
-    do {
-      valueT += element.offsetTop  || 0;
-      valueL += element.offsetLeft || 0;
-      if (element.offsetParent == document.body)
-        if (Element.getStyle(element, 'position') == 'absolute') break;
-
-      element = element.offsetParent;
-    } while (element);
-
-    return [valueL, valueT];
-  }
-}
\ No newline at end of file
diff --git a/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web-data/rico.js b/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web-data/rico.js
deleted file mode 100644 (file)
index 65bcb48..0000000
+++ /dev/null
@@ -1,2818 +0,0 @@
-/**
-  *
-  *  Copyright 2005 Sabre Airline Solutions
-  *
-  *  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
-  *  file except in compliance with the License. You may obtain a copy of the License at
-  *
-  *         http://www.apache.org/licenses/LICENSE-2.0
-  *
-  *  Unless required by applicable law or agreed to in writing, software distributed under the
-  *  License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
-  *  either express or implied. See the License for the specific language governing permissions
-  *  and limitations under the License.
-  **/
-
-
-//-------------------- rico.js
-var Rico = {
-  Version: '1.1.2',
-  prototypeVersion: parseFloat(Prototype.Version.split(".")[0] + "." + Prototype.Version.split(".")[1])
-}
-
-if((typeof Prototype=='undefined') || Rico.prototypeVersion < 1.3)
-      throw("Rico requires the Prototype JavaScript framework >= 1.3");
-
-Rico.ArrayExtensions = new Array();
-
-if (Object.prototype.extend) {
-   Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Object.prototype.extend;
-}else{
-  Object.prototype.extend = function(object) {
-    return Object.extend.apply(this, [this, object]);
-  }
-  Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Object.prototype.extend;
-}
-
-if (Array.prototype.push) {
-   Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.push;
-}
-
-if (!Array.prototype.remove) {
-   Array.prototype.remove = function(dx) {
-      if( isNaN(dx) || dx > this.length )
-         return false;
-      for( var i=0,n=0; i<this.length; i++ )
-         if( i != dx )
-            this[n++]=this[i];
-      this.length-=1;
-   };
-  Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.remove;
-}
-
-if (!Array.prototype.removeItem) {
-   Array.prototype.removeItem = function(item) {
-      for ( var i = 0 ; i < this.length ; i++ )
-         if ( this[i] == item ) {
-            this.remove(i);
-            break;
-         }
-   };
-  Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.removeItem;
-}
-
-if (!Array.prototype.indices) {
-   Array.prototype.indices = function() {
-      var indexArray = new Array();
-      for ( index in this ) {
-         var ignoreThis = false;
-         for ( var i = 0 ; i < Rico.ArrayExtensions.length ; i++ ) {
-            if ( this[index] == Rico.ArrayExtensions[i] ) {
-               ignoreThis = true;
-               break;
-            }
-         }
-         if ( !ignoreThis )
-            indexArray[ indexArray.length ] = index;
-      }
-      return indexArray;
-   }
-  Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.indices;
-}
-
-// Create the loadXML method and xml getter for Mozilla
-if ( window.DOMParser &&
-         window.XMLSerializer &&
-         window.Node && Node.prototype && Node.prototype.__defineGetter__ ) {
-
-   if (!Document.prototype.loadXML) {
-      Document.prototype.loadXML = function (s) {
-         var doc2 = (new DOMParser()).parseFromString(s, "text/xml");
-         while (this.hasChildNodes())
-            this.removeChild(this.lastChild);
-
-         for (var i = 0; i < doc2.childNodes.length; i++) {
-            this.appendChild(this.importNode(doc2.childNodes[i], true));
-         }
-      };
-       }
-
-       Document.prototype.__defineGetter__( "xml",
-          function () {
-                  return (new XMLSerializer()).serializeToString(this);
-          }
-        );
-}
-
-document.getElementsByTagAndClassName = function(tagName, className) {
-  if ( tagName == null )
-     tagName = '*';
-
-  var children = document.getElementsByTagName(tagName) || document.all;
-  var elements = new Array();
-
-  if ( className == null )
-    return children;
-
-  for (var i = 0; i < children.length; i++) {
-    var child = children[i];
-    var classNames = child.className.split(' ');
-    for (var j = 0; j < classNames.length; j++) {
-      if (classNames[j] == className) {
-        elements.push(child);
-        break;
-      }
-    }
-  }
-
-  return elements;
-}
-
-
-//-------------------- ricoAccordion.js
-Rico.Accordion = Class.create();
-
-Rico.Accordion.prototype = {
-
-   initialize: function(container, options) {
-      this.container            = $(container);
-      this.lastExpandedTab      = null;
-      this.accordionTabs        = new Array();
-      this.setOptions(options);
-      this._attachBehaviors();
-      if(!container) return;
-
-      this.container.style.borderBottom = '1px solid ' + this.options.borderColor;
-      // validate onloadShowTab
-       if (this.options.onLoadShowTab >= this.accordionTabs.length)
-        this.options.onLoadShowTab = 0;
-
-      // set the initial visual state...
-      for ( var i=0 ; i < this.accordionTabs.length ; i++ )
-      {
-        if (i != this.options.onLoadShowTab){
-         this.accordionTabs[i].collapse();
-         this.accordionTabs[i].content.style.display = 'none';
-        }
-      }
-      this.lastExpandedTab = this.accordionTabs[this.options.onLoadShowTab];
-      if (this.options.panelHeight == 'auto'){
-          var tabToCheck = (this.options.onloadShowTab === 0)? 1 : 0;
-          var titleBarSize = parseInt(RicoUtil.getElementsComputedStyle(this.accordionTabs[tabToCheck].titleBar, 'height'));
-          if (isNaN(titleBarSize))
-            titleBarSize = this.accordionTabs[tabToCheck].titleBar.offsetHeight;
-          
-          var totalTitleBarSize = this.accordionTabs.length * titleBarSize;
-          var parentHeight = parseInt(RicoUtil.getElementsComputedStyle(this.container.parentNode, 'height'));
-          if (isNaN(parentHeight))
-            parentHeight = this.container.parentNode.offsetHeight;
-          
-          this.options.panelHeight = parentHeight - totalTitleBarSize-2;
-      }
-      
-      this.lastExpandedTab.content.style.height = this.options.panelHeight + "px";
-      this.lastExpandedTab.showExpanded();
-      this.lastExpandedTab.titleBar.style.fontWeight = this.options.expandedFontWeight;
-
-   },
-
-   setOptions: function(options) {
-      this.options = {
-         expandedBg          : '#63699c',
-         hoverBg             : '#63699c',
-         collapsedBg         : '#6b79a5',
-         expandedTextColor   : '#ffffff',
-         expandedFontWeight  : 'bold',
-         hoverTextColor      : '#ffffff',
-         collapsedTextColor  : '#ced7ef',
-         collapsedFontWeight : 'normal',
-         hoverTextColor      : '#ffffff',
-         borderColor         : '#1f669b',
-         panelHeight         : 200,
-         onHideTab           : null,
-         onShowTab           : null,
-         onLoadShowTab       : 0
-      }
-      Object.extend(this.options, options || {});
-   },
-
-   showTabByIndex: function( anIndex, animate ) {
-      var doAnimate = arguments.length == 1 ? true : animate;
-      this.showTab( this.accordionTabs[anIndex], doAnimate );
-   },
-
-   showTab: function( accordionTab, animate ) {
-     if ( this.lastExpandedTab == accordionTab )
-        return;
-
-      var doAnimate = arguments.length == 1 ? true : animate;
-
-      if ( this.options.onHideTab )
-         this.options.onHideTab(this.lastExpandedTab);
-
-      this.lastExpandedTab.showCollapsed(); 
-      var accordion = this;
-      var lastExpandedTab = this.lastExpandedTab;
-
-      this.lastExpandedTab.content.style.height = (this.options.panelHeight - 1) + 'px';
-      accordionTab.content.style.display = '';
-
-      accordionTab.titleBar.style.fontWeight = this.options.expandedFontWeight;
-
-      if ( doAnimate ) {
-         new Rico.Effect.AccordionSize( this.lastExpandedTab.content,
-                                   accordionTab.content,
-                                   1,
-                                   this.options.panelHeight,
-                                   100, 10,
-                                   { complete: function() {accordion.showTabDone(lastExpandedTab)} } );
-         this.lastExpandedTab = accordionTab;
-      }
-      else {
-         this.lastExpandedTab.content.style.height = "1px";
-         accordionTab.content.style.height = this.options.panelHeight + "px";
-         this.lastExpandedTab = accordionTab;
-         this.showTabDone(lastExpandedTab);
-      }
-   },
-
-   showTabDone: function(collapsedTab) {
-      collapsedTab.content.style.display = 'none';
-      this.lastExpandedTab.showExpanded();
-      if ( this.options.onShowTab )
-         this.options.onShowTab(this.lastExpandedTab);
-   },
-
-   _attachBehaviors: function() {
-      var panels = this._getDirectChildrenByTag(this.container, 'DIV');
-      for ( var i = 0 ; i < panels.length ; i++ ) {
-
-         var tabChildren = this._getDirectChildrenByTag(panels[i],'DIV');
-         if ( tabChildren.length != 2 )
-            continue; // unexpected
-
-         var tabTitleBar   = tabChildren[0];
-         var tabContentBox = tabChildren[1];
-         this.accordionTabs.push( new Rico.Accordion.Tab(this,tabTitleBar,tabContentBox) );
-      }
-   },
-
-   _getDirectChildrenByTag: function(e, tagName) {
-      var kids = new Array();
-      var allKids = e.childNodes;
-      for( var i = 0 ; i < allKids.length ; i++ )
-         if ( allKids[i] && allKids[i].tagName && allKids[i].tagName == tagName )
-            kids.push(allKids[i]);
-      return kids;
-   }
-
-};
-
-Rico.Accordion.Tab = Class.create();
-
-Rico.Accordion.Tab.prototype = {
-
-   initialize: function(accordion, titleBar, content) {
-      this.accordion = accordion;
-      this.titleBar  = titleBar;
-      this.content   = content;
-      this._attachBehaviors();
-   },
-
-   collapse: function() {
-      this.showCollapsed();
-      this.content.style.height = "1px";
-   },
-
-   showCollapsed: function() {
-      this.expanded = false;
-      this.titleBar.style.backgroundColor = this.accordion.options.collapsedBg;
-      this.titleBar.style.color           = this.accordion.options.collapsedTextColor;
-      this.titleBar.style.fontWeight      = this.accordion.options.collapsedFontWeight;
-      this.content.style.overflow = "hidden";
-   },
-
-   showExpanded: function() {
-      this.expanded = true;
-      this.titleBar.style.backgroundColor = this.accordion.options.expandedBg;
-      this.titleBar.style.color           = this.accordion.options.expandedTextColor;
-      this.content.style.overflow         = "auto";
-   },
-
-   titleBarClicked: function(e) {
-      if ( this.accordion.lastExpandedTab == this )
-         return;
-      this.accordion.showTab(this);
-   },
-
-   hover: function(e) {
-               this.titleBar.style.backgroundColor = this.accordion.options.hoverBg;
-               this.titleBar.style.color           = this.accordion.options.hoverTextColor;
-   },
-
-   unhover: function(e) {
-      if ( this.expanded ) {
-         this.titleBar.style.backgroundColor = this.accordion.options.expandedBg;
-         this.titleBar.style.color           = this.accordion.options.expandedTextColor;
-      }
-      else {
-         this.titleBar.style.backgroundColor = this.accordion.options.collapsedBg;
-         this.titleBar.style.color           = this.accordion.options.collapsedTextColor;
-      }
-   },
-
-   _attachBehaviors: function() {
-      this.content.style.border = "1px solid " + this.accordion.options.borderColor;
-      this.content.style.borderTopWidth    = "0px";
-      this.content.style.borderBottomWidth = "0px";
-      this.content.style.margin            = "0px";
-
-      this.titleBar.onclick     = this.titleBarClicked.bindAsEventListener(this);
-      this.titleBar.onmouseover = this.hover.bindAsEventListener(this);
-      this.titleBar.onmouseout  = this.unhover.bindAsEventListener(this);
-   }
-
-};
-
-
-//-------------------- ricoAjaxEngine.js
-Rico.AjaxEngine = Class.create();
-
-Rico.AjaxEngine.prototype = {
-
-   initialize: function() {
-      this.ajaxElements = new Array();
-      this.ajaxObjects  = new Array();
-      this.requestURLS  = new Array();
-      this.options = {};
-   },
-
-   registerAjaxElement: function( anId, anElement ) {
-      if ( !anElement )
-         anElement = $(anId);
-      this.ajaxElements[anId] = anElement;
-   },
-
-   registerAjaxObject: function( anId, anObject ) {
-      this.ajaxObjects[anId] = anObject;
-   },
-
-   registerRequest: function (requestLogicalName, requestURL) {
-      this.requestURLS[requestLogicalName] = requestURL;
-   },
-
-   sendRequest: function(requestName, options) {
-      // Allow for backwards Compatibility
-      if ( arguments.length >= 2 )
-       if (typeof arguments[1] == 'string')
-         options = {parameters: this._createQueryString(arguments, 1)};
-      this.sendRequestWithData(requestName, null, options);
-   },
-
-   sendRequestWithData: function(requestName, xmlDocument, options) {
-      var requestURL = this.requestURLS[requestName];
-      if ( requestURL == null )
-         return;
-
-      // Allow for backwards Compatibility
-      if ( arguments.length >= 3 )
-        if (typeof arguments[2] == 'string')
-          options.parameters = this._createQueryString(arguments, 2);
-
-      new Ajax.Request(requestURL, this._requestOptions(options,xmlDocument));
-   },
-
-   sendRequestAndUpdate: function(requestName,container,options) {
-      // Allow for backwards Compatibility
-      if ( arguments.length >= 3 )
-        if (typeof arguments[2] == 'string')
-          options.parameters = this._createQueryString(arguments, 2);
-
-      this.sendRequestWithDataAndUpdate(requestName, null, container, options);
-   },
-
-   sendRequestWithDataAndUpdate: function(requestName,xmlDocument,container,options) {
-      var requestURL = this.requestURLS[requestName];
-      if ( requestURL == null )
-         return;
-
-      // Allow for backwards Compatibility
-      if ( arguments.length >= 4 )
-        if (typeof arguments[3] == 'string')
-          options.parameters = this._createQueryString(arguments, 3);
-
-      var updaterOptions = this._requestOptions(options,xmlDocument);
-
-      new Ajax.Updater(container, requestURL, updaterOptions);
-   },
-
-   // Private -- not part of intended engine API --------------------------------------------------------------------
-
-   _requestOptions: function(options,xmlDoc) {
-      var requestHeaders = ['X-Rico-Version', Rico.Version ];
-      var sendMethod = 'post';
-      if ( xmlDoc == null )
-        if (Rico.prototypeVersion < 1.4)
-        requestHeaders.push( 'Content-type', 'text/xml' );
-      else
-          sendMethod = 'get';
-      (!options) ? options = {} : '';
-
-      if (!options._RicoOptionsProcessed){
-      // Check and keep any user onComplete functions
-        if (options.onComplete)
-             options.onRicoComplete = options.onComplete;
-        // Fix onComplete
-        if (options.overrideOnComplete)
-          options.onComplete = options.overrideOnComplete;
-        else
-          options.onComplete = this._onRequestComplete.bind(this);
-        options._RicoOptionsProcessed = true;
-      }
-
-     // Set the default options and extend with any user options
-     this.options = {
-                     requestHeaders: requestHeaders,
-                     parameters:     options.parameters,
-                     postBody:       xmlDoc,
-                     method:         sendMethod,
-                     onComplete:     options.onComplete
-                    };
-     // Set any user options:
-     Object.extend(this.options, options);
-     return this.options;
-   },
-
-   _createQueryString: function( theArgs, offset ) {
-      var queryString = ""
-      for ( var i = offset ; i < theArgs.length ; i++ ) {
-          if ( i != offset )
-            queryString += "&";
-
-          var anArg = theArgs[i];
-
-          if ( anArg.name != undefined && anArg.value != undefined ) {
-            queryString += anArg.name +  "=" + escape(anArg.value);
-          }
-          else {
-             var ePos  = anArg.indexOf('=');
-             var argName  = anArg.substring( 0, ePos );
-             var argValue = anArg.substring( ePos + 1 );
-             queryString += argName + "=" + escape(argValue);
-          }
-      }
-      return queryString;
-   },
-
-   _onRequestComplete : function(request) {
-      if(!request)
-          return;
-      // User can set an onFailure option - which will be called by prototype
-      if (request.status != 200)
-        return;
-
-      var response = request.responseXML.getElementsByTagName("ajax-response");
-      if (response == null || response.length != 1)
-         return;
-      this._processAjaxResponse( response[0].childNodes );
-      
-      // Check if user has set a onComplete function
-      var onRicoComplete = this.options.onRicoComplete;
-      if (onRicoComplete != null)
-          onRicoComplete();
-   },
-
-   _processAjaxResponse: function( xmlResponseElements ) {
-      for ( var i = 0 ; i < xmlResponseElements.length ; i++ ) {
-         var responseElement = xmlResponseElements[i];
-
-         // only process nodes of type element.....
-         if ( responseElement.nodeType != 1 )
-            continue;
-
-         var responseType = responseElement.getAttribute("type");
-         var responseId   = responseElement.getAttribute("id");
-
-         if ( responseType == "object" )
-            this._processAjaxObjectUpdate( this.ajaxObjects[ responseId ], responseElement );
-         else if ( responseType == "element" )
-            this._processAjaxElementUpdate( this.ajaxElements[ responseId ], responseElement );
-         else
-            alert('unrecognized AjaxResponse type : ' + responseType );
-      }
-   },
-
-   _processAjaxObjectUpdate: function( ajaxObject, responseElement ) {
-      ajaxObject.ajaxUpdate( responseElement );
-   },
-
-   _processAjaxElementUpdate: function( ajaxElement, responseElement ) {
-      ajaxElement.innerHTML = RicoUtil.getContentAsString(responseElement);
-   }
-
-}
-
-var ajaxEngine = new Rico.AjaxEngine();
-
-
-//-------------------- ricoColor.js
-Rico.Color = Class.create();
-
-Rico.Color.prototype = {
-
-   initialize: function(red, green, blue) {
-      this.rgb = { r: red, g : green, b : blue };
-   },
-
-   setRed: function(r) {
-      this.rgb.r = r;
-   },
-
-   setGreen: function(g) {
-      this.rgb.g = g;
-   },
-
-   setBlue: function(b) {
-      this.rgb.b = b;
-   },
-
-   setHue: function(h) {
-
-      // get an HSB model, and set the new hue...
-      var hsb = this.asHSB();
-      hsb.h = h;
-
-      // convert back to RGB...
-      this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
-   },
-
-   setSaturation: function(s) {
-      // get an HSB model, and set the new hue...
-      var hsb = this.asHSB();
-      hsb.s = s;
-
-      // convert back to RGB and set values...
-      this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
-   },
-
-   setBrightness: function(b) {
-      // get an HSB model, and set the new hue...
-      var hsb = this.asHSB();
-      hsb.b = b;
-
-      // convert back to RGB and set values...
-      this.rgb = Rico.Color.HSBtoRGB( hsb.h, hsb.s, hsb.b );
-   },
-
-   darken: function(percent) {
-      var hsb  = this.asHSB();
-      this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.max(hsb.b - percent,0));
-   },
-
-   brighten: function(percent) {
-      var hsb  = this.asHSB();
-      this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.min(hsb.b + percent,1));
-   },
-
-   blend: function(other) {
-      this.rgb.r = Math.floor((this.rgb.r + other.rgb.r)/2);
-      this.rgb.g = Math.floor((this.rgb.g + other.rgb.g)/2);
-      this.rgb.b = Math.floor((this.rgb.b + other.rgb.b)/2);
-   },
-
-   isBright: function() {
-      var hsb = this.asHSB();
-      return this.asHSB().b > 0.5;
-   },
-
-   isDark: function() {
-      return ! this.isBright();
-   },
-
-   asRGB: function() {
-      return "rgb(" + this.rgb.r + "," + this.rgb.g + "," + this.rgb.b + ")";
-   },
-
-   asHex: function() {
-      return "#" + this.rgb.r.toColorPart() + this.rgb.g.toColorPart() + this.rgb.b.toColorPart();
-   },
-
-   asHSB: function() {
-      return Rico.Color.RGBtoHSB(this.rgb.r, this.rgb.g, this.rgb.b);
-   },
-
-   toString: function() {
-      return this.asHex();
-   }
-
-};
-
-Rico.Color.createFromHex = function(hexCode) {
-  if(hexCode.length==4) {
-    var shortHexCode = hexCode; 
-    var hexCode = '#';
-    for(var i=1;i<4;i++) hexCode += (shortHexCode.charAt(i) + 
-shortHexCode.charAt(i));
-  }
-   if ( hexCode.indexOf('#') == 0 )
-      hexCode = hexCode.substring(1);
-   var red   = hexCode.substring(0,2);
-   var green = hexCode.substring(2,4);
-   var blue  = hexCode.substring(4,6);
-   return new Rico.Color( parseInt(red,16), parseInt(green,16), parseInt(blue,16) );
-}
-
-/**
- * Factory method for creating a color from the background of
- * an HTML element.
- */
-Rico.Color.createColorFromBackground = function(elem) {
-
-   var actualColor = RicoUtil.getElementsComputedStyle($(elem), "backgroundColor", "background-color");
-
-   if ( actualColor == "transparent" && elem.parentNode )
-      return Rico.Color.createColorFromBackground(elem.parentNode);
-
-   if ( actualColor == null )
-      return new Rico.Color(255,255,255);
-
-   if ( actualColor.indexOf("rgb(") == 0 ) {
-      var colors = actualColor.substring(4, actualColor.length - 1 );
-      var colorArray = colors.split(",");
-      return new Rico.Color( parseInt( colorArray[0] ),
-                            parseInt( colorArray[1] ),
-                            parseInt( colorArray[2] )  );
-
-   }
-   else if ( actualColor.indexOf("#") == 0 ) {
-      return Rico.Color.createFromHex(actualColor);
-   }
-   else
-      return new Rico.Color(255,255,255);
-}
-
-Rico.Color.HSBtoRGB = function(hue, saturation, brightness) {
-
-   var red   = 0;
-       var green = 0;
-       var blue  = 0;
-
-   if (saturation == 0) {
-      red = parseInt(brightness * 255.0 + 0.5);
-          green = red;
-          blue = red;
-       }
-       else {
-      var h = (hue - Math.floor(hue)) * 6.0;
-      var f = h - Math.floor(h);
-      var p = brightness * (1.0 - saturation);
-      var q = brightness * (1.0 - saturation * f);
-      var t = brightness * (1.0 - (saturation * (1.0 - f)));
-
-      switch (parseInt(h)) {
-         case 0:
-            red   = (brightness * 255.0 + 0.5);
-            green = (t * 255.0 + 0.5);
-            blue  = (p * 255.0 + 0.5);
-            break;
-         case 1:
-            red   = (q * 255.0 + 0.5);
-            green = (brightness * 255.0 + 0.5);
-            blue  = (p * 255.0 + 0.5);
-            break;
-         case 2:
-            red   = (p * 255.0 + 0.5);
-            green = (brightness * 255.0 + 0.5);
-            blue  = (t * 255.0 + 0.5);
-            break;
-         case 3:
-            red   = (p * 255.0 + 0.5);
-            green = (q * 255.0 + 0.5);
-            blue  = (brightness * 255.0 + 0.5);
-            break;
-         case 4:
-            red   = (t * 255.0 + 0.5);
-            green = (p * 255.0 + 0.5);
-            blue  = (brightness * 255.0 + 0.5);
-            break;
-          case 5:
-            red   = (brightness * 255.0 + 0.5);
-            green = (p * 255.0 + 0.5);
-            blue  = (q * 255.0 + 0.5);
-            break;
-           }
-       }
-
-   return { r : parseInt(red), g : parseInt(green) , b : parseInt(blue) };
-}
-
-Rico.Color.RGBtoHSB = function(r, g, b) {
-
-   var hue;
-   var saturation;
-   var brightness;
-
-   var cmax = (r > g) ? r : g;
-   if (b > cmax)
-      cmax = b;
-
-   var cmin = (r < g) ? r : g;
-   if (b < cmin)
-      cmin = b;
-
-   brightness = cmax / 255.0;
-   if (cmax != 0)
-      saturation = (cmax - cmin)/cmax;
-   else
-      saturation = 0;
-
-   if (saturation == 0)
-      hue = 0;
-   else {
-      var redc   = (cmax - r)/(cmax - cmin);
-       var greenc = (cmax - g)/(cmax - cmin);
-       var bluec  = (cmax - b)/(cmax - cmin);
-
-       if (r == cmax)
-          hue = bluec - greenc;
-       else if (g == cmax)
-          hue = 2.0 + redc - bluec;
-      else
-          hue = 4.0 + greenc - redc;
-
-       hue = hue / 6.0;
-       if (hue < 0)
-          hue = hue + 1.0;
-   }
-
-   return { h : hue, s : saturation, b : brightness };
-}
-
-
-//-------------------- ricoCorner.js
-Rico.Corner = {
-
-   round: function(e, options) {
-      var e = $(e);
-      this._setOptions(options);
-
-      var color = this.options.color;
-      if ( this.options.color == "fromElement" )
-         color = this._background(e);
-
-      var bgColor = this.options.bgColor;
-      if ( this.options.bgColor == "fromParent" )
-         bgColor = this._background(e.offsetParent);
-
-      this._roundCornersImpl(e, color, bgColor);
-   },
-
-   _roundCornersImpl: function(e, color, bgColor) {
-      if(this.options.border)
-         this._renderBorder(e,bgColor);
-      if(this._isTopRounded())
-         this._roundTopCorners(e,color,bgColor);
-      if(this._isBottomRounded())
-         this._roundBottomCorners(e,color,bgColor);
-   },
-
-   _renderBorder: function(el,bgColor) {
-      var borderValue = "1px solid " + this._borderColor(bgColor);
-      var borderL = "border-left: "  + borderValue;
-      var borderR = "border-right: " + borderValue;
-      var style   = "style='" + borderL + ";" + borderR +  "'";
-      el.innerHTML = "<div " + style + ">" + el.innerHTML + "</div>"
-   },
-
-   _roundTopCorners: function(el, color, bgColor) {
-      var corner = this._createCorner(bgColor);
-      for(var i=0 ; i < this.options.numSlices ; i++ )
-         corner.appendChild(this._createCornerSlice(color,bgColor,i,"top"));
-      el.style.paddingTop = 0;
-      el.insertBefore(corner,el.firstChild);
-   },
-
-   _roundBottomCorners: function(el, color, bgColor) {
-      var corner = this._createCorner(bgColor);
-      for(var i=(this.options.numSlices-1) ; i >= 0 ; i-- )
-         corner.appendChild(this._createCornerSlice(color,bgColor,i,"bottom"));
-      el.style.paddingBottom = 0;
-      el.appendChild(corner);
-   },
-
-   _createCorner: function(bgColor) {
-      var corner = document.createElement("div");
-      corner.style.backgroundColor = (this._isTransparent() ? "transparent" : bgColor);
-      return corner;
-   },
-
-   _createCornerSlice: function(color,bgColor, n, position) {
-      var slice = document.createElement("span");
-
-      var inStyle = slice.style;
-      inStyle.backgroundColor = color;
-      inStyle.display  = "block";
-      inStyle.height   = "1px";
-      inStyle.overflow = "hidden";
-      inStyle.fontSize = "1px";
-
-      var borderColor = this._borderColor(color,bgColor);
-      if ( this.options.border && n == 0 ) {
-         inStyle.borderTopStyle    = "solid";
-         inStyle.borderTopWidth    = "1px";
-         inStyle.borderLeftWidth   = "0px";
-         inStyle.borderRightWidth  = "0px";
-         inStyle.borderBottomWidth = "0px";
-         inStyle.height            = "0px"; // assumes css compliant box model
-         inStyle.borderColor       = borderColor;
-      }
-      else if(borderColor) {
-         inStyle.borderColor = borderColor;
-         inStyle.borderStyle = "solid";
-         inStyle.borderWidth = "0px 1px";
-      }
-
-      if ( !this.options.compact && (n == (this.options.numSlices-1)) )
-         inStyle.height = "2px";
-
-      this._setMargin(slice, n, position);
-      this._setBorder(slice, n, position);
-      return slice;
-   },
-
-   _setOptions: function(options) {
-      this.options = {
-         corners : "all",
-         color   : "fromElement",
-         bgColor : "fromParent",
-         blend   : true,
-         border  : false,
-         compact : false
-      }
-      Object.extend(this.options, options || {});
-
-      this.options.numSlices = this.options.compact ? 2 : 4;
-      if ( this._isTransparent() )
-         this.options.blend = false;
-   },
-
-   _whichSideTop: function() {
-      if ( this._hasString(this.options.corners, "all", "top") )
-         return "";
-
-      if ( this.options.corners.indexOf("tl") >= 0 && this.options.corners.indexOf("tr") >= 0 )
-         return "";
-
-      if (this.options.corners.indexOf("tl") >= 0)
-         return "left";
-      else if (this.options.corners.indexOf("tr") >= 0)
-          return "right";
-      return "";
-   },
-
-   _whichSideBottom: function() {
-      if ( this._hasString(this.options.corners, "all", "bottom") )
-         return "";
-
-      if ( this.options.corners.indexOf("bl")>=0 && this.options.corners.indexOf("br")>=0 )
-         return "";
-
-      if(this.options.corners.indexOf("bl") >=0)
-         return "left";
-      else if(this.options.corners.indexOf("br")>=0)
-         return "right";
-      return "";
-   },
-
-   _borderColor : function(color,bgColor) {
-      if ( color == "transparent" )
-         return bgColor;
-      else if ( this.options.border )
-         return this.options.border;
-      else if ( this.options.blend )
-         return this._blend( bgColor, color );
-      else
-         return "";
-   },
-
-
-   _setMargin: function(el, n, corners) {
-      var marginSize = this._marginSize(n);
-      var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom();
-
-      if ( whichSide == "left" ) {
-         el.style.marginLeft = marginSize + "px"; el.style.marginRight = "0px";
-      }
-      else if ( whichSide == "right" ) {
-         el.style.marginRight = marginSize + "px"; el.style.marginLeft  = "0px";
-      }
-      else {
-         el.style.marginLeft = marginSize + "px"; el.style.marginRight = marginSize + "px";
-      }
-   },
-
-   _setBorder: function(el,n,corners) {
-      var borderSize = this._borderSize(n);
-      var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom();
-      if ( whichSide == "left" ) {
-         el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = "0px";
-      }
-      else if ( whichSide == "right" ) {
-         el.style.borderRightWidth = borderSize + "px"; el.style.borderLeftWidth  = "0px";
-      }
-      else {
-         el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = borderSize + "px";
-      }
-      if (this.options.border != false)
-        el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = borderSize + "px";
-   },
-
-   _marginSize: function(n) {
-      if ( this._isTransparent() )
-         return 0;
-
-      var marginSizes          = [ 5, 3, 2, 1 ];
-      var blendedMarginSizes   = [ 3, 2, 1, 0 ];
-      var compactMarginSizes   = [ 2, 1 ];
-      var smBlendedMarginSizes = [ 1, 0 ];
-
-      if ( this.options.compact && this.options.blend )
-         return smBlendedMarginSizes[n];
-      else if ( this.options.compact )
-         return compactMarginSizes[n];
-      else if ( this.options.blend )
-         return blendedMarginSizes[n];
-      else
-         return marginSizes[n];
-   },
-
-   _borderSize: function(n) {
-      var transparentBorderSizes = [ 5, 3, 2, 1 ];
-      var blendedBorderSizes     = [ 2, 1, 1, 1 ];
-      var compactBorderSizes     = [ 1, 0 ];
-      var actualBorderSizes      = [ 0, 2, 0, 0 ];
-
-      if ( this.options.compact && (this.options.blend || this._isTransparent()) )
-         return 1;
-      else if ( this.options.compact )
-         return compactBorderSizes[n];
-      else if ( this.options.blend )
-         return blendedBorderSizes[n];
-      else if ( this.options.border )
-         return actualBorderSizes[n];
-      else if ( this._isTransparent() )
-         return transparentBorderSizes[n];
-      return 0;
-   },
-
-   _hasString: function(str) { for(var i=1 ; i<arguments.length ; i++) if (str.indexOf(arguments[i]) >= 0) return true; return false; },
-   _blend: function(c1, c2) { var cc1 = Rico.Color.createFromHex(c1); cc1.blend(Rico.Color.createFromHex(c2)); return cc1; },
-   _background: function(el) { try { return Rico.Color.createColorFromBackground(el).asHex(); } catch(err) { return "#ffffff"; } },
-   _isTransparent: function() { return this.options.color == "transparent"; },
-   _isTopRounded: function() { return this._hasString(this.options.corners, "all", "top", "tl", "tr"); },
-   _isBottomRounded: function() { return this._hasString(this.options.corners, "all", "bottom", "bl", "br"); },
-   _hasSingleTextChild: function(el) { return el.childNodes.length == 1 && el.childNodes[0].nodeType == 3; }
-}
-
-
-//-------------------- ricoDragAndDrop.js
-Rico.DragAndDrop = Class.create();
-
-Rico.DragAndDrop.prototype = {
-
-   initialize: function() {
-      this.dropZones                = new Array();
-      this.draggables               = new Array();
-      this.currentDragObjects       = new Array();
-      this.dragElement              = null;
-      this.lastSelectedDraggable    = null;
-      this.currentDragObjectVisible = false;
-      this.interestedInMotionEvents = false;
-      this._mouseDown = this._mouseDownHandler.bindAsEventListener(this);
-      this._mouseMove = this._mouseMoveHandler.bindAsEventListener(this);
-      this._mouseUp = this._mouseUpHandler.bindAsEventListener(this);
-   },
-
-   registerDropZone: function(aDropZone) {
-      this.dropZones[ this.dropZones.length ] = aDropZone;
-   },
-
-   deregisterDropZone: function(aDropZone) {
-      var newDropZones = new Array();
-      var j = 0;
-      for ( var i = 0 ; i < this.dropZones.length ; i++ ) {
-         if ( this.dropZones[i] != aDropZone )
-            newDropZones[j++] = this.dropZones[i];
-      }
-
-      this.dropZones = newDropZones;
-   },
-
-   clearDropZones: function() {
-      this.dropZones = new Array();
-   },
-
-   registerDraggable: function( aDraggable ) {
-      this.draggables[ this.draggables.length ] = aDraggable;
-      this._addMouseDownHandler( aDraggable );
-   },
-
-   clearSelection: function() {
-      for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
-         this.currentDragObjects[i].deselect();
-      this.currentDragObjects = new Array();
-      this.lastSelectedDraggable = null;
-   },
-
-   hasSelection: function() {
-      return this.currentDragObjects.length > 0;
-   },
-
-   setStartDragFromElement: function( e, mouseDownElement ) {
-      this.origPos = RicoUtil.toDocumentPosition(mouseDownElement);
-      this.startx = e.screenX - this.origPos.x
-      this.starty = e.screenY - this.origPos.y
-      //this.startComponentX = e.layerX ? e.layerX : e.offsetX;
-      //this.startComponentY = e.layerY ? e.layerY : e.offsetY;
-      //this.adjustedForDraggableSize = false;
-
-      this.interestedInMotionEvents = this.hasSelection();
-      this._terminateEvent(e);
-   },
-
-   updateSelection: function( draggable, extendSelection ) {
-      if ( ! extendSelection )
-         this.clearSelection();
-
-      if ( draggable.isSelected() ) {
-         this.currentDragObjects.removeItem(draggable);
-         draggable.deselect();
-         if ( draggable == this.lastSelectedDraggable )
-            this.lastSelectedDraggable = null;
-      }
-      else {
-         this.currentDragObjects[ this.currentDragObjects.length ] = draggable;
-         draggable.select();
-         this.lastSelectedDraggable = draggable;
-      }
-   },
-
-   _mouseDownHandler: function(e) {
-      if ( arguments.length == 0 )
-         e = event;
-
-      // if not button 1 ignore it...
-      var nsEvent = e.which != undefined;
-      if ( (nsEvent && e.which != 1) || (!nsEvent && e.button != 1))
-         return;
-
-      var eventTarget      = e.target ? e.target : e.srcElement;
-      var draggableObject  = eventTarget.draggable;
-
-      var candidate = eventTarget;
-      while (draggableObject == null && candidate.parentNode) {
-         candidate = candidate.parentNode;
-         draggableObject = candidate.draggable;
-      }
-   
-      if ( draggableObject == null )
-         return;
-
-      this.updateSelection( draggableObject, e.ctrlKey );
-
-      // clear the drop zones postion cache...
-      if ( this.hasSelection() )
-         for ( var i = 0 ; i < this.dropZones.length ; i++ )
-            this.dropZones[i].clearPositionCache();
-
-      this.setStartDragFromElement( e, draggableObject.getMouseDownHTMLElement() );
-   },
-
-
-   _mouseMoveHandler: function(e) {
-      var nsEvent = e.which != undefined;
-      if ( !this.interestedInMotionEvents ) {
-         //this._terminateEvent(e);
-         return;
-      }
-
-      if ( ! this.hasSelection() )
-         return;
-
-      if ( ! this.currentDragObjectVisible )
-         this._startDrag(e);
-
-      if ( !this.activatedDropZones )
-         this._activateRegisteredDropZones();
-
-      //if ( !this.adjustedForDraggableSize )
-      //   this._adjustForDraggableSize(e);
-
-      this._updateDraggableLocation(e);
-      this._updateDropZonesHover(e);
-
-      this._terminateEvent(e);
-   },
-
-   _makeDraggableObjectVisible: function(e)
-   {
-      if ( !this.hasSelection() )
-         return;
-
-      var dragElement;
-      if ( this.currentDragObjects.length > 1 )
-         dragElement = this.currentDragObjects[0].getMultiObjectDragGUI(this.currentDragObjects);
-      else
-         dragElement = this.currentDragObjects[0].getSingleObjectDragGUI();
-
-      // go ahead and absolute position it...
-      if ( RicoUtil.getElementsComputedStyle(dragElement, "position")  != "absolute" )
-         dragElement.style.position = "absolute";
-
-      // need to parent him into the document...
-      if ( dragElement.parentNode == null || dragElement.parentNode.nodeType == 11 )
-         document.body.appendChild(dragElement);
-
-      this.dragElement = dragElement;
-      this._updateDraggableLocation(e);
-
-      this.currentDragObjectVisible = true;
-   },
-
-   /**
-   _adjustForDraggableSize: function(e) {
-      var dragElementWidth  = this.dragElement.offsetWidth;
-      var dragElementHeight = this.dragElement.offsetHeight;
-      if ( this.startComponentX > dragElementWidth )
-         this.startx -= this.startComponentX - dragElementWidth + 2;
-      if ( e.offsetY ) {
-         if ( this.startComponentY > dragElementHeight )
-            this.starty -= this.startComponentY - dragElementHeight + 2;
-      }
-      this.adjustedForDraggableSize = true;
-   },
-   **/
-
-   _leftOffset: function(e) {
-          return e.offsetX ? document.body.scrollLeft : 0
-       },
-
-   _topOffset: function(e) {
-          return e.offsetY ? document.body.scrollTop:0
-       },
-
-               
-   _updateDraggableLocation: function(e) {
-      var dragObjectStyle = this.dragElement.style;
-      dragObjectStyle.left = (e.screenX + this._leftOffset(e) - this.startx) + "px"
-      dragObjectStyle.top  = (e.screenY + this._topOffset(e) - this.starty) + "px";
-   },
-
-   _updateDropZonesHover: function(e) {
-      var n = this.dropZones.length;
-      for ( var i = 0 ; i < n ; i++ ) {
-         if ( ! this._mousePointInDropZone( e, this.dropZones[i] ) )
-            this.dropZones[i].hideHover();
-      }
-
-      for ( var i = 0 ; i < n ; i++ ) {
-         if ( this._mousePointInDropZone( e, this.dropZones[i] ) ) {
-            if ( this.dropZones[i].canAccept(this.currentDragObjects) )
-               this.dropZones[i].showHover();
-         }
-      }
-   },
-
-   _startDrag: function(e) {
-      for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
-         this.currentDragObjects[i].startDrag();
-
-      this._makeDraggableObjectVisible(e);
-   },
-
-   _mouseUpHandler: function(e) {
-      if ( ! this.hasSelection() )
-         return;
-
-      var nsEvent = e.which != undefined;
-      if ( (nsEvent && e.which != 1) || (!nsEvent && e.button != 1))
-         return;
-
-      this.interestedInMotionEvents = false;
-
-      if ( this.dragElement == null ) {
-         this._terminateEvent(e);
-         return;
-      }
-
-      if ( this._placeDraggableInDropZone(e) )
-         this._completeDropOperation(e);
-      else {
-         this._terminateEvent(e);
-         new Rico.Effect.Position( this.dragElement,
-                              this.origPos.x,
-                              this.origPos.y,
-                              200,
-                              20,
-                              { complete : this._doCancelDragProcessing.bind(this) } );
-      }
-
-     Event.stopObserving(document.body, "mousemove", this._mouseMove);
-     Event.stopObserving(document.body, "mouseup",  this._mouseUp);
-   },
-
-   _retTrue: function () {
-      return true;
-   },
-
-   _completeDropOperation: function(e) {
-      if ( this.dragElement != this.currentDragObjects[0].getMouseDownHTMLElement() ) {
-         if ( this.dragElement.parentNode != null )
-            this.dragElement.parentNode.removeChild(this.dragElement);
-      }
-
-      this._deactivateRegisteredDropZones();
-      this._endDrag();
-      this.clearSelection();
-      this.dragElement = null;
-      this.currentDragObjectVisible = false;
-      this._terminateEvent(e);
-   },
-
-   _doCancelDragProcessing: function() {
-      this._cancelDrag();
-
-        if ( this.dragElement != this.currentDragObjects[0].getMouseDownHTMLElement() && this.dragElement)
-           if ( this.dragElement.parentNode != null )
-              this.dragElement.parentNode.removeChild(this.dragElement);
-
-
-      this._deactivateRegisteredDropZones();
-      this.dragElement = null;
-      this.currentDragObjectVisible = false;
-   },
-
-   _placeDraggableInDropZone: function(e) {
-      var foundDropZone = false;
-      var n = this.dropZones.length;
-      for ( var i = 0 ; i < n ; i++ ) {
-         if ( this._mousePointInDropZone( e, this.dropZones[i] ) ) {
-            if ( this.dropZones[i].canAccept(this.currentDragObjects) ) {
-               this.dropZones[i].hideHover();
-               this.dropZones[i].accept(this.currentDragObjects);
-               foundDropZone = true;
-               break;
-            }
-         }
-      }
-
-      return foundDropZone;
-   },
-
-   _cancelDrag: function() {
-      for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
-         this.currentDragObjects[i].cancelDrag();
-   },
-
-   _endDrag: function() {
-      for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
-         this.currentDragObjects[i].endDrag();
-   },
-
-   _mousePointInDropZone: function( e, dropZone ) {
-
-      var absoluteRect = dropZone.getAbsoluteRect();
-
-      return e.clientX  > absoluteRect.left + this._leftOffset(e) &&
-             e.clientX  < absoluteRect.right + this._leftOffset(e) &&
-             e.clientY  > absoluteRect.top + this._topOffset(e)   &&
-             e.clientY  < absoluteRect.bottom + this._topOffset(e);
-   },
-
-   _addMouseDownHandler: function( aDraggable )
-   {
-       htmlElement  = aDraggable.getMouseDownHTMLElement();
-      if ( htmlElement  != null ) { 
-         htmlElement.draggable = aDraggable;
-         Event.observe(htmlElement , "mousedown", this._onmousedown.bindAsEventListener(this));
-         Event.observe(htmlElement, "mousedown", this._mouseDown);
-      }
-   },
-
-   _activateRegisteredDropZones: function() {
-      var n = this.dropZones.length;
-      for ( var i = 0 ; i < n ; i++ ) {
-         var dropZone = this.dropZones[i];
-         if ( dropZone.canAccept(this.currentDragObjects) )
-            dropZone.activate();
-      }
-
-      this.activatedDropZones = true;
-   },
-
-   _deactivateRegisteredDropZones: function() {
-      var n = this.dropZones.length;
-      for ( var i = 0 ; i < n ; i++ )
-         this.dropZones[i].deactivate();
-      this.activatedDropZones = false;
-   },
-
-   _onmousedown: function () {
-     Event.observe(document.body, "mousemove", this._mouseMove);
-     Event.observe(document.body, "mouseup",  this._mouseUp);
-   },
-
-   _terminateEvent: function(e) {
-      if ( e.stopPropagation != undefined )
-         e.stopPropagation();
-      else if ( e.cancelBubble != undefined )
-         e.cancelBubble = true;
-
-      if ( e.preventDefault != undefined )
-         e.preventDefault();
-      else
-         e.returnValue = false;
-   },
-
-
-          initializeEventHandlers: function() {
-             if ( typeof document.implementation != "undefined" &&
-                document.implementation.hasFeature("HTML",   "1.0") &&
-                document.implementation.hasFeature("Events", "2.0") &&
-                document.implementation.hasFeature("CSS",    "2.0") ) {
-                document.addEventListener("mouseup",   this._mouseUpHandler.bindAsEventListener(this),  false);
-                document.addEventListener("mousemove", this._mouseMoveHandler.bindAsEventListener(this), false);
-             }
-             else {
-                document.attachEvent( "onmouseup",   this._mouseUpHandler.bindAsEventListener(this) );
-                document.attachEvent( "onmousemove", this._mouseMoveHandler.bindAsEventListener(this) );
-             }
-          }
-       }
-
-       var dndMgr = new Rico.DragAndDrop();
-       dndMgr.initializeEventHandlers();
-
-
-//-------------------- ricoDraggable.js
-Rico.Draggable = Class.create();
-
-Rico.Draggable.prototype = {
-
-   initialize: function( type, htmlElement ) {
-      this.type          = type;
-      this.htmlElement   = $(htmlElement);
-      this.selected      = false;
-   },
-
-   /**
-    *   Returns the HTML element that should have a mouse down event
-    *   added to it in order to initiate a drag operation
-    *
-    **/
-   getMouseDownHTMLElement: function() {
-      return this.htmlElement;
-   },
-
-   select: function() {
-      this.selected = true;
-
-      if ( this.showingSelected )
-         return;
-
-      var htmlElement = this.getMouseDownHTMLElement();
-
-      var color = Rico.Color.createColorFromBackground(htmlElement);
-      color.isBright() ? color.darken(0.033) : color.brighten(0.033);
-
-      this.saveBackground = RicoUtil.getElementsComputedStyle(htmlElement, "backgroundColor", "background-color");
-      htmlElement.style.backgroundColor = color.asHex();
-      this.showingSelected = true;
-   },
-
-   deselect: function() {
-      this.selected = false;
-      if ( !this.showingSelected )
-         return;
-
-      var htmlElement = this.getMouseDownHTMLElement();
-
-      htmlElement.style.backgroundColor = this.saveBackground;
-      this.showingSelected = false;
-   },
-
-   isSelected: function() {
-      return this.selected;
-   },
-
-   startDrag: function() {
-   },
-
-   cancelDrag: function() {
-   },
-
-   endDrag: function() {
-   },
-
-   getSingleObjectDragGUI: function() {
-      return this.htmlElement;
-   },
-
-   getMultiObjectDragGUI: function( draggables ) {
-      return this.htmlElement;
-   },
-
-   getDroppedGUI: function() {
-      return this.htmlElement;
-   },
-
-   toString: function() {
-      return this.type + ":" + this.htmlElement + ":";
-   }
-
-}
-
-
-//-------------------- ricoDropzone.js
-Rico.Dropzone = Class.create();
-
-Rico.Dropzone.prototype = {
-
-   initialize: function( htmlElement ) {
-      this.htmlElement  = $(htmlElement);
-      this.absoluteRect = null;
-   },
-
-   getHTMLElement: function() {
-      return this.htmlElement;
-   },
-
-   clearPositionCache: function() {
-      this.absoluteRect = null;
-   },
-
-   getAbsoluteRect: function() {
-      if ( this.absoluteRect == null ) {
-         var htmlElement = this.getHTMLElement();
-         var pos = RicoUtil.toViewportPosition(htmlElement);
-
-         this.absoluteRect = {
-            top:    pos.y,
-            left:   pos.x,
-            bottom: pos.y + htmlElement.offsetHeight,
-            right:  pos.x + htmlElement.offsetWidth
-         };
-      }
-      return this.absoluteRect;
-   },
-
-   activate: function() {
-      var htmlElement = this.getHTMLElement();
-      if (htmlElement == null  || this.showingActive)
-         return;
-
-      this.showingActive = true;
-      this.saveBackgroundColor = htmlElement.style.backgroundColor;
-
-      var fallbackColor = "#ffea84";
-      var currentColor = Rico.Color.createColorFromBackground(htmlElement);
-      if ( currentColor == null )
-         htmlElement.style.backgroundColor = fallbackColor;
-      else {
-         currentColor.isBright() ? currentColor.darken(0.2) : currentColor.brighten(0.2);
-         htmlElement.style.backgroundColor = currentColor.asHex();
-      }
-   },
-
-   deactivate: function() {
-      var htmlElement = this.getHTMLElement();
-      if (htmlElement == null || !this.showingActive)
-         return;
-
-      htmlElement.style.backgroundColor = this.saveBackgroundColor;
-      this.showingActive = false;
-      this.saveBackgroundColor = null;
-   },
-
-   showHover: function() {
-      var htmlElement = this.getHTMLElement();
-      if ( htmlElement == null || this.showingHover )
-         return;
-
-      this.saveBorderWidth = htmlElement.style.borderWidth;
-      this.saveBorderStyle = htmlElement.style.borderStyle;
-      this.saveBorderColor = htmlElement.style.borderColor;
-
-      this.showingHover = true;
-      htmlElement.style.borderWidth = "1px";
-      htmlElement.style.borderStyle = "solid";
-      //htmlElement.style.borderColor = "#ff9900";
-      htmlElement.style.borderColor = "#ffff00";
-   },
-
-   hideHover: function() {
-      var htmlElement = this.getHTMLElement();
-      if ( htmlElement == null || !this.showingHover )
-         return;
-
-      htmlElement.style.borderWidth = this.saveBorderWidth;
-      htmlElement.style.borderStyle = this.saveBorderStyle;
-      htmlElement.style.borderColor = this.saveBorderColor;
-      this.showingHover = false;
-   },
-
-   canAccept: function(draggableObjects) {
-      return true;
-   },
-
-   accept: function(draggableObjects) {
-      var htmlElement = this.getHTMLElement();
-      if ( htmlElement == null )
-         return;
-
-      n = draggableObjects.length;
-      for ( var i = 0 ; i < n ; i++ )
-      {
-         var theGUI = draggableObjects[i].getDroppedGUI();
-         if ( RicoUtil.getElementsComputedStyle( theGUI, "position" ) == "absolute" )
-         {
-            theGUI.style.position = "static";
-            theGUI.style.top = "";
-            theGUI.style.top = "";
-         }
-         htmlElement.appendChild(theGUI);
-      }
-   }
-}
-
-
-//-------------------- ricoEffects.js
-
-Rico.Effect = {};
-
-Rico.Effect.SizeAndPosition = Class.create();
-Rico.Effect.SizeAndPosition.prototype = {
-
-   initialize: function(element, x, y, w, h, duration, steps, options) {
-      this.element = $(element);
-      this.x = x;
-      this.y = y;
-      this.w = w;
-      this.h = h;
-      this.duration = duration;
-      this.steps    = steps;
-      this.options  = arguments[7] || {};
-
-      this.sizeAndPosition();
-   },
-
-   sizeAndPosition: function() {
-      if (this.isFinished()) {
-         if(this.options.complete) this.options.complete(this);
-         return;
-      }
-
-      if (this.timer)
-         clearTimeout(this.timer);
-
-      var stepDuration = Math.round(this.duration/this.steps) ;
-
-      // Get original values: x,y = top left corner;  w,h = width height
-      var currentX = this.element.offsetLeft;
-      var currentY = this.element.offsetTop;
-      var currentW = this.element.offsetWidth;
-      var currentH = this.element.offsetHeight;
-
-      // If values not set, or zero, we do not modify them, and take original as final as well
-      this.x = (this.x) ? this.x : currentX;
-      this.y = (this.y) ? this.y : currentY;
-      this.w = (this.w) ? this.w : currentW;
-      this.h = (this.h) ? this.h : currentH;
-
-      // how much do we need to modify our values for each step?
-      var difX = this.steps >  0 ? (this.x - currentX)/this.steps : 0;
-      var difY = this.steps >  0 ? (this.y - currentY)/this.steps : 0;
-      var difW = this.steps >  0 ? (this.w - currentW)/this.steps : 0;
-      var difH = this.steps >  0 ? (this.h - currentH)/this.steps : 0;
-
-      this.moveBy(difX, difY);
-      this.resizeBy(difW, difH);
-
-      this.duration -= stepDuration;
-      this.steps--;
-
-      this.timer = setTimeout(this.sizeAndPosition.bind(this), stepDuration);
-   },
-
-   isFinished: function() {
-      return this.steps <= 0;
-   },
-
-   moveBy: function( difX, difY ) {
-      var currentLeft = this.element.offsetLeft;
-      var currentTop  = this.element.offsetTop;
-      var intDifX     = parseInt(difX);
-      var intDifY     = parseInt(difY);
-
-      var style = this.element.style;
-      if ( intDifX != 0 )
-         style.left = (currentLeft + intDifX) + "px";
-      if ( intDifY != 0 )
-         style.top  = (currentTop + intDifY) + "px";
-   },
-
-   resizeBy: function( difW, difH ) {
-      var currentWidth  = this.element.offsetWidth;
-      var currentHeight = this.element.offsetHeight;
-      var intDifW       = parseInt(difW);
-      var intDifH       = parseInt(difH);
-
-      var style = this.element.style;
-      if ( intDifW != 0 )
-         style.width   = (currentWidth  + intDifW) + "px";
-      if ( intDifH != 0 )
-         style.height  = (currentHeight + intDifH) + "px";
-   }
-}
-
-Rico.Effect.Size = Class.create();
-Rico.Effect.Size.prototype = {
-
-   initialize: function(element, w, h, duration, steps, options) {
-      new Rico.Effect.SizeAndPosition(element, null, null, w, h, duration, steps, options);
-  }
-}
-
-Rico.Effect.Position = Class.create();
-Rico.Effect.Position.prototype = {
-
-   initialize: function(element, x, y, duration, steps, options) {
-      new Rico.Effect.SizeAndPosition(element, x, y, null, null, duration, steps, options);
-  }
-}
-
-Rico.Effect.Round = Class.create();
-Rico.Effect.Round.prototype = {
-
-   initialize: function(tagName, className, options) {
-      var elements = document.getElementsByTagAndClassName(tagName,className);
-      for ( var i = 0 ; i < elements.length ; i++ )
-         Rico.Corner.round( elements[i], options );
-   }
-};
-
-Rico.Effect.FadeTo = Class.create();
-Rico.Effect.FadeTo.prototype = {
-
-   initialize: function( element, opacity, duration, steps, options) {
-      this.element  = $(element);
-      this.opacity  = opacity;
-      this.duration = duration;
-      this.steps    = steps;
-      this.options  = arguments[4] || {};
-      this.fadeTo();
-   },
-
-   fadeTo: function() {
-      if (this.isFinished()) {
-         if(this.options.complete) this.options.complete(this);
-         return;
-      }
-
-      if (this.timer)
-         clearTimeout(this.timer);
-
-      var stepDuration = Math.round(this.duration/this.steps) ;
-      var currentOpacity = this.getElementOpacity();
-      var delta = this.steps > 0 ? (this.opacity - currentOpacity)/this.steps : 0;
-
-      this.changeOpacityBy(delta);
-      this.duration -= stepDuration;
-      this.steps--;
-
-      this.timer = setTimeout(this.fadeTo.bind(this), stepDuration);
-   },
-
-   changeOpacityBy: function(v) {
-      var currentOpacity = this.getElementOpacity();
-      var newOpacity = Math.max(0, Math.min(currentOpacity+v, 1));
-      this.element.ricoOpacity = newOpacity;
-
-      this.element.style.filter = "alpha(opacity:"+Math.round(newOpacity*100)+")";
-      this.element.style.opacity = newOpacity; /*//*/;
-   },
-
-   isFinished: function() {
-      return this.steps <= 0;
-   },
-
-   getElementOpacity: function() {
-      if ( this.element.ricoOpacity == undefined ) {
-         var opacity = RicoUtil.getElementsComputedStyle(this.element, 'opacity');
-         this.element.ricoOpacity = opacity != undefined ? opacity : 1.0;
-      }
-      return parseFloat(this.element.ricoOpacity);
-   }
-}
-
-Rico.Effect.AccordionSize = Class.create();
-
-Rico.Effect.AccordionSize.prototype = {
-
-   initialize: function(e1, e2, start, end, duration, steps, options) {
-      this.e1       = $(e1);
-      this.e2       = $(e2);
-      this.start    = start;
-      this.end      = end;
-      this.duration = duration;
-      this.steps    = steps;
-      this.options  = arguments[6] || {};
-
-      this.accordionSize();
-   },
-
-   accordionSize: function() {
-
-      if (this.isFinished()) {
-         // just in case there are round errors or such...
-         this.e1.style.height = this.start + "px";
-         this.e2.style.height = this.end + "px";
-
-         if(this.options.complete)
-            this.options.complete(this);
-         return;
-      }
-
-      if (this.timer)
-         clearTimeout(this.timer);
-
-      var stepDuration = Math.round(this.duration/this.steps) ;
-
-      var diff = this.steps > 0 ? (parseInt(this.e1.offsetHeight) - this.start)/this.steps : 0;
-      this.resizeBy(diff);
-
-      this.duration -= stepDuration;
-      this.steps--;
-
-      this.timer = setTimeout(this.accordionSize.bind(this), stepDuration);
-   },
-
-   isFinished: function() {
-      return this.steps <= 0;
-   },
-
-   resizeBy: function(diff) {
-      var h1Height = this.e1.offsetHeight;
-      var h2Height = this.e2.offsetHeight;
-      var intDiff = parseInt(diff);
-      if ( diff != 0 ) {
-         this.e1.style.height = (h1Height - intDiff) + "px";
-         this.e2.style.height = (h2Height + intDiff) + "px";
-      }
-   }
-
-};
-
-
-//-------------------- ricoLiveGrid.js
-// Rico.LiveGridMetaData -----------------------------------------------------
-
-Rico.LiveGridMetaData = Class.create();
-
-Rico.LiveGridMetaData.prototype = {
-
-   initialize: function( pageSize, totalRows, columnCount, options ) {
-      this.pageSize  = pageSize;
-      this.totalRows = totalRows;
-      this.setOptions(options);
-      this.ArrowHeight = 16;
-      this.columnCount = columnCount;
-   },
-
-   setOptions: function(options) {
-      this.options = {
-         largeBufferSize    : 7.0,   // 7 pages
-         nearLimitFactor    : 0.2    // 20% of buffer
-      };
-      Object.extend(this.options, options || {});
-   },
-
-   getPageSize: function() {
-      return this.pageSize;
-   },
-
-   getTotalRows: function() {
-      return this.totalRows;
-   },
-
-   setTotalRows: function(n) {
-      this.totalRows = n;
-   },
-
-   getLargeBufferSize: function() {
-      return parseInt(this.options.largeBufferSize * this.pageSize);
-   },
-
-   getLimitTolerance: function() {
-      return parseInt(this.getLargeBufferSize() * this.options.nearLimitFactor);
-   }
-};
-
-// Rico.LiveGridScroller -----------------------------------------------------
-
-Rico.LiveGridScroller = Class.create();
-
-Rico.LiveGridScroller.prototype = {
-
-   initialize: function(liveGrid, viewPort) {
-      this.isIE = navigator.userAgent.toLowerCase().indexOf("msie") >= 0;
-      this.liveGrid = liveGrid;
-      this.metaData = liveGrid.metaData;
-      this.createScrollBar();
-      this.scrollTimeout = null;
-      this.lastScrollPos = 0;
-      this.viewPort = viewPort;
-      this.rows = new Array();
-   },
-
-   isUnPlugged: function() {
-      return this.scrollerDiv.onscroll == null;
-   },
-
-   plugin: function() {
-      this.scrollerDiv.onscroll = this.handleScroll.bindAsEventListener(this);
-   },
-
-   unplug: function() {
-      this.scrollerDiv.onscroll = null;
-   },
-
-   sizeIEHeaderHack: function() {
-      if ( !this.isIE ) return;
-      var headerTable = $(this.liveGrid.tableId + "_header");
-      if ( headerTable )
-         headerTable.rows[0].cells[0].style.width =
-            (headerTable.rows[0].cells[0].offsetWidth + 1) + "px";
-   },
-
-   createScrollBar: function() {
-      var visibleHeight = this.liveGrid.viewPort.visibleHeight();
-      // create the outer div...
-      this.scrollerDiv  = document.createElement("div");
-      var scrollerStyle = this.scrollerDiv.style;
-      scrollerStyle.borderRight = this.liveGrid.options.scrollerBorderRight;
-      scrollerStyle.position    = "relative";
-      scrollerStyle.left        = this.isIE ? "-6px" : "-3px";
-      scrollerStyle.width       = "19px";
-      scrollerStyle.height      = visibleHeight + "px";
-      scrollerStyle.overflow    = "auto";
-
-      // create the inner div...
-      this.heightDiv = document.createElement("div");
-      this.heightDiv.style.width  = "1px";
-
-      this.heightDiv.style.height = parseInt(visibleHeight *
-                        this.metaData.getTotalRows()/this.metaData.getPageSize()) + "px" ;
-      this.scrollerDiv.appendChild(this.heightDiv);
-      this.scrollerDiv.onscroll = this.handleScroll.bindAsEventListener(this);
-
-     var table = this.liveGrid.table;
-     table.parentNode.parentNode.insertBefore( this.scrollerDiv, table.parentNode.nextSibling );
-         var eventName = this.isIE ? "mousewheel" : "DOMMouseScroll";
-         Event.observe(table, eventName, 
-                       function(evt) {
-                          if (evt.wheelDelta>=0 || evt.detail < 0) //wheel-up
-                             this.scrollerDiv.scrollTop -= (2*this.viewPort.rowHeight);
-                          else
-                             this.scrollerDiv.scrollTop += (2*this.viewPort.rowHeight);
-                          this.handleScroll(false);
-                       }.bindAsEventListener(this), 
-                       false);
-     },
-
-   updateSize: function() {
-      var table = this.liveGrid.table;
-      var visibleHeight = this.viewPort.visibleHeight();
-      this.heightDiv.style.height = parseInt(visibleHeight *
-                                  this.metaData.getTotalRows()/this.metaData.getPageSize()) + "px";
-   },
-
-   rowToPixel: function(rowOffset) {
-      return (rowOffset / this.metaData.getTotalRows()) * this.heightDiv.offsetHeight
-   },
-   
-   moveScroll: function(rowOffset) {
-      this.scrollerDiv.scrollTop = this.rowToPixel(rowOffset);
-      if ( this.metaData.options.onscroll )
-         this.metaData.options.onscroll( this.liveGrid, rowOffset );
-   },
-
-   handleScroll: function() {
-     if ( this.scrollTimeout )
-         clearTimeout( this.scrollTimeout );
-
-    var scrollDiff = this.lastScrollPos-this.scrollerDiv.scrollTop;
-    if (scrollDiff != 0.00) {
-       var r = this.scrollerDiv.scrollTop % this.viewPort.rowHeight;
-       if (r != 0) {
-          this.unplug();
-          if ( scrollDiff < 0 ) {
-             this.scrollerDiv.scrollTop += (this.viewPort.rowHeight-r);
-          } else {
-             this.scrollerDiv.scrollTop -= r;
-          }
-          this.plugin();
-       }
-    }
-    var contentOffset = parseInt(this.scrollerDiv.scrollTop / this.viewPort.rowHeight);
-    this.liveGrid.requestContentRefresh(contentOffset);
-    this.viewPort.scrollTo(this.scrollerDiv.scrollTop);
-
-    if ( this.metaData.options.onscroll )
-       this.metaData.options.onscroll( this.liveGrid, contentOffset );
-
-    this.scrollTimeout = setTimeout(this.scrollIdle.bind(this), 1200 );
-    this.lastScrollPos = this.scrollerDiv.scrollTop;
-
-   },
-
-   scrollIdle: function() {
-      if ( this.metaData.options.onscrollidle )
-         this.metaData.options.onscrollidle();
-   }
-};
-
-// Rico.LiveGridBuffer -----------------------------------------------------
-
-Rico.LiveGridBuffer = Class.create();
-
-Rico.LiveGridBuffer.prototype = {
-
-   initialize: function(metaData, viewPort) {
-      this.startPos = 0;
-      this.size     = 0;
-      this.metaData = metaData;
-      this.rows     = new Array();
-      this.updateInProgress = false;
-      this.viewPort = viewPort;
-      this.maxBufferSize = metaData.getLargeBufferSize() * 2;
-      this.maxFetchSize = metaData.getLargeBufferSize();
-      this.lastOffset = 0;
-   },
-
-   getBlankRow: function() {
-      if (!this.blankRow ) {
-         this.blankRow = new Array();
-         for ( var i=0; i < this.metaData.columnCount ; i++ ) 
-            this.blankRow[i] = "&nbsp;";
-     }
-     return this.blankRow;
-   },
-
-   loadRows: function(ajaxResponse) {
-      var rowsElement = ajaxResponse.getElementsByTagName('rows')[0];
-      this.updateUI = rowsElement.getAttribute("update_ui") == "true"
-      var newRows = new Array()
-      var trs = rowsElement.getElementsByTagName("tr");
-      for ( var i=0 ; i < trs.length; i++ ) {
-         var row = newRows[i] = new Array(); 
-         var cells = trs[i].getElementsByTagName("td");
-         for ( var j=0; j < cells.length ; j++ ) {
-            var cell = cells[j];
-            var convertSpaces = cell.getAttribute("convert_spaces") == "true";
-            var cellContent = RicoUtil.getContentAsString(cell);
-            row[j] = convertSpaces ? this.convertSpaces(cellContent) : cellContent;
-            if (!row[j]) 
-               row[j] = '&nbsp;';
-         }
-      }
-      return newRows;
-   },
-      
-   update: function(ajaxResponse, start) {
-     var newRows = this.loadRows(ajaxResponse);
-      if (this.rows.length == 0) { // initial load
-         this.rows = newRows;
-         this.size = this.rows.length;
-         this.startPos = start;
-         return;
-      }
-      if (start > this.startPos) { //appending
-         if (this.startPos + this.rows.length < start) {
-            this.rows =  newRows;
-            this.startPos = start;//
-         } else {
-              this.rows = this.rows.concat( newRows.slice(0, newRows.length));
-            if (this.rows.length > this.maxBufferSize) {
-               var fullSize = this.rows.length;
-               this.rows = this.rows.slice(this.rows.length - this.maxBufferSize, this.rows.length)
-               this.startPos = this.startPos +  (fullSize - this.rows.length);
-            }
-         }
-      } else { //prepending
-         if (start + newRows.length < this.startPos) {
-            this.rows =  newRows;
-         } else {
-            this.rows = newRows.slice(0, this.startPos).concat(this.rows);
-            if (this.rows.length > this.maxBufferSize) 
-               this.rows = this.rows.slice(0, this.maxBufferSize)
-         }
-         this.startPos =  start;
-      }
-      this.size = this.rows.length;
-   },
-   
-   clear: function() {
-      this.rows = new Array();
-      this.startPos = 0;
-      this.size = 0;
-   },
-
-   isOverlapping: function(start, size) {
-      return ((start < this.endPos()) && (this.startPos < start + size)) || (this.endPos() == 0)
-   },
-
-   isInRange: function(position) {
-      return (position >= this.startPos) && (position + this.metaData.getPageSize() <= this.endPos()); 
-             //&& this.size()  != 0;
-   },
-
-   isNearingTopLimit: function(position) {
-      return position - this.startPos < this.metaData.getLimitTolerance();
-   },
-
-   endPos: function() {
-      return this.startPos + this.rows.length;
-   },
-   
-   isNearingBottomLimit: function(position) {
-      return this.endPos() - (position + this.metaData.getPageSize()) < this.metaData.getLimitTolerance();
-   },
-
-   isAtTop: function() {
-      return this.startPos == 0;
-   },
-
-   isAtBottom: function() {
-      return this.endPos() == this.metaData.getTotalRows();
-   },
-
-   isNearingLimit: function(position) {
-      return ( !this.isAtTop()    && this.isNearingTopLimit(position)) ||
-             ( !this.isAtBottom() && this.isNearingBottomLimit(position) )
-   },
-
-   getFetchSize: function(offset) {
-      var adjustedOffset = this.getFetchOffset(offset);
-      var adjustedSize = 0;
-      if (adjustedOffset >= this.startPos) { //apending
-         var endFetchOffset = this.maxFetchSize  + adjustedOffset;
-         if (endFetchOffset > this.metaData.totalRows)
-            endFetchOffset = this.metaData.totalRows;
-         adjustedSize = endFetchOffset - adjustedOffset;  
-                       if(adjustedOffset == 0 && adjustedSize < this.maxFetchSize){
-                          adjustedSize = this.maxFetchSize;
-                       }
-      } else {//prepending
-         var adjustedSize = this.startPos - adjustedOffset;
-         if (adjustedSize > this.maxFetchSize)
-            adjustedSize = this.maxFetchSize;
-      }
-      return adjustedSize;
-   }, 
-
-   getFetchOffset: function(offset) {
-      var adjustedOffset = offset;
-      if (offset > this.startPos)  //apending
-         adjustedOffset = (offset > this.endPos()) ? offset :  this.endPos(); 
-      else { //prepending
-         if (offset + this.maxFetchSize >= this.startPos) {
-            var adjustedOffset = this.startPos - this.maxFetchSize;
-            if (adjustedOffset < 0)
-               adjustedOffset = 0;
-         }
-      }
-      this.lastOffset = adjustedOffset;
-      return adjustedOffset;
-   },
-
-   getRows: function(start, count) {
-      var begPos = start - this.startPos
-      var endPos = begPos + count
-
-      // er? need more data...
-      if ( endPos > this.size )
-         endPos = this.size
-
-      var results = new Array()
-      var index = 0;
-      for ( var i=begPos ; i < endPos; i++ ) {
-         results[index++] = this.rows[i]
-      }
-      return results
-   },
-
-   convertSpaces: function(s) {
-      return s.split(" ").join("&nbsp;");
-   }
-
-};
-
-
-//Rico.GridViewPort --------------------------------------------------
-Rico.GridViewPort = Class.create();
-
-Rico.GridViewPort.prototype = {
-
-   initialize: function(table, rowHeight, visibleRows, buffer, liveGrid) {
-      this.lastDisplayedStartPos = 0;
-      this.div = table.parentNode;
-      this.table = table
-      this.rowHeight = rowHeight;
-      this.div.style.height = (this.rowHeight * visibleRows) + "px";
-      this.div.style.overflow = "hidden";
-      this.buffer = buffer;
-      this.liveGrid = liveGrid;
-      this.visibleRows = visibleRows + 1;
-      this.lastPixelOffset = 0;
-      this.startPos = 0;
-   },
-
-   populateRow: function(htmlRow, row) {
-      for (var j=0; j < row.length; j++) {
-         htmlRow.cells[j].innerHTML = row[j]
-      }
-   },
-   
-   bufferChanged: function() {
-      this.refreshContents( parseInt(this.lastPixelOffset / this.rowHeight));
-   },
-   
-   clearRows: function() {
-      if (!this.isBlank) {
-         this.liveGrid.table.className = this.liveGrid.options.loadingClass;
-         for (var i=0; i < this.visibleRows; i++)
-            this.populateRow(this.table.rows[i], this.buffer.getBlankRow());
-         this.isBlank = true;
-      }
-   },
-   
-   clearContents: function() {   
-      this.clearRows();
-      this.scrollTo(0);
-      this.startPos = 0;
-      this.lastStartPos = -1;   
-   },
-   
-   refreshContents: function(startPos) {
-      if (startPos == this.lastRowPos && !this.isPartialBlank && !this.isBlank) {
-         return;
-      }
-      if ((startPos + this.visibleRows < this.buffer.startPos)  
-          || (this.buffer.startPos + this.buffer.size < startPos) 
-          || (this.buffer.size == 0)) {
-         this.clearRows();
-         return;
-      }
-      this.isBlank = false;
-      var viewPrecedesBuffer = this.buffer.startPos > startPos
-      var contentStartPos = viewPrecedesBuffer ? this.buffer.startPos: startPos; 
-      var contentEndPos = (this.buffer.startPos + this.buffer.size < startPos + this.visibleRows) 
-                                 ? this.buffer.startPos + this.buffer.size
-                                 : startPos + this.visibleRows;
-      var rowSize = contentEndPos - contentStartPos;
-      var rows = this.buffer.getRows(contentStartPos, rowSize ); 
-      var blankSize = this.visibleRows - rowSize;
-      var blankOffset = viewPrecedesBuffer ? 0: rowSize;
-      var contentOffset = viewPrecedesBuffer ? blankSize: 0;
-
-      for (var i=0; i < rows.length; i++) {//initialize what we have
-        this.populateRow(this.table.rows[i + contentOffset], rows[i]);
-      }
-      for (var i=0; i < blankSize; i++) {// blank out the rest 
-        this.populateRow(this.table.rows[i + blankOffset], this.buffer.getBlankRow());
-      }
-      this.isPartialBlank = blankSize > 0;
-      this.lastRowPos = startPos;
-
-       this.liveGrid.table.className = this.liveGrid.options.tableClass;
-       // Check if user has set a onRefreshComplete function
-       var onRefreshComplete = this.liveGrid.options.onRefreshComplete;
-       if (onRefreshComplete != null)
-           onRefreshComplete();
-   },
-
-   scrollTo: function(pixelOffset) {      
-      if (this.lastPixelOffset == pixelOffset)
-         return;
-
-      this.refreshContents(parseInt(pixelOffset / this.rowHeight))
-      this.div.scrollTop = pixelOffset % this.rowHeight        
-      
-      this.lastPixelOffset = pixelOffset;
-   },
-   
-   visibleHeight: function() {
-      return parseInt(RicoUtil.getElementsComputedStyle(this.div, 'height'));
-   }
-
-};
-
-
-Rico.LiveGridRequest = Class.create();
-Rico.LiveGridRequest.prototype = {
-   initialize: function( requestOffset, options ) {
-      this.requestOffset = requestOffset;
-   }
-};
-
-// Rico.LiveGrid -----------------------------------------------------
-
-Rico.LiveGrid = Class.create();
-
-Rico.LiveGrid.prototype = {
-
-   initialize: function( tableId, visibleRows, totalRows, url, options, ajaxOptions ) {
-
-     this.options = {
-                tableClass:           $(tableId).className,
-                loadingClass:         $(tableId).className,
-                scrollerBorderRight: '1px solid #ababab',
-                bufferTimeout:        20000,
-                sortAscendImg:        'images/sort_asc.gif',
-                sortDescendImg:       'images/sort_desc.gif',
-                sortImageWidth:       9,
-                sortImageHeight:      5,
-                ajaxSortURLParms:     [],
-                onRefreshComplete:    null,
-                requestParameters:    null,
-                inlineStyles:         true
-                };
-      Object.extend(this.options, options || {});
-
-      this.ajaxOptions = {parameters: null};
-      Object.extend(this.ajaxOptions, ajaxOptions || {});
-
-      this.tableId     = tableId; 
-      this.table       = $(tableId);
-
-      this.addLiveGridHtml();
-
-      var columnCount  = this.table.rows[0].cells.length;
-      this.metaData    = new Rico.LiveGridMetaData(visibleRows, totalRows, columnCount, options);
-      this.buffer      = new Rico.LiveGridBuffer(this.metaData);
-
-      var rowCount = this.table.rows.length;
-      this.viewPort =  new Rico.GridViewPort(this.table, 
-                                            this.table.offsetHeight/rowCount,
-                                            visibleRows,
-                                            this.buffer, this);
-      this.scroller    = new Rico.LiveGridScroller(this,this.viewPort);
-      this.options.sortHandler = this.sortHandler.bind(this);
-
-      if ( $(tableId + '_header') )
-         this.sort = new Rico.LiveGridSort(tableId + '_header', this.options)
-
-      this.processingRequest = null;
-      this.unprocessedRequest = null;
-
-      this.initAjax(url);
-      if ( this.options.prefetchBuffer || this.options.prefetchOffset > 0) {
-         var offset = 0;
-         if (this.options.offset ) {
-            offset = this.options.offset;            
-            this.scroller.moveScroll(offset);
-            this.viewPort.scrollTo(this.scroller.rowToPixel(offset));            
-         }
-         if (this.options.sortCol) {
-             this.sortCol = options.sortCol;
-             this.sortDir = options.sortDir;
-         }
-         this.requestContentRefresh(offset);
-      }
-   },
-
-   addLiveGridHtml: function() {
-     // Check to see if need to create a header table.
-     if (this.table.getElementsByTagName("thead").length > 0){
-       // Create Table this.tableId+'_header'
-       var tableHeader = this.table.cloneNode(true);
-       tableHeader.setAttribute('id', this.tableId+'_header');
-       tableHeader.setAttribute('class', this.table.className+'_header');
-
-       // Clean up and insert
-       for( var i = 0; i < tableHeader.tBodies.length; i++ ) 
-       tableHeader.removeChild(tableHeader.tBodies[i]);
-       this.table.deleteTHead();
-       this.table.parentNode.insertBefore(tableHeader,this.table);
-     }
-
-    new Insertion.Before(this.table, "<div id='"+this.tableId+"_container'></div>");
-    this.table.previousSibling.appendChild(this.table);
-    new Insertion.Before(this.table,"<div id='"+this.tableId+"_viewport' style='float:left;'></div>");
-    this.table.previousSibling.appendChild(this.table);
-   },
-
-
-   resetContents: function() {
-      this.scroller.moveScroll(0);
-      this.buffer.clear();
-      this.viewPort.clearContents();
-   },
-   
-   sortHandler: function(column) {
-          if(!column) return ;
-      this.sortCol = column.name;
-      this.sortDir = column.currentSort;
-
-      this.resetContents();
-      this.requestContentRefresh(0) 
-   },
-
-   adjustRowSize: function() {
-         
-       },
-       
-   setTotalRows: function( newTotalRows ) {
-      this.resetContents();
-      this.metaData.setTotalRows(newTotalRows);
-      this.scroller.updateSize();
-   },
-
-   initAjax: function(url) {
-      ajaxEngine.registerRequest( this.tableId + '_request', url );
-      ajaxEngine.registerAjaxObject( this.tableId + '_updater', this );
-   },
-
-   invokeAjax: function() {
-   },
-
-   handleTimedOut: function() {
-      //server did not respond in 4 seconds... assume that there could have been
-      //an error or something, and allow requests to be processed again...
-      this.processingRequest = null;
-      this.processQueuedRequest();
-   },
-
-   fetchBuffer: function(offset) {
-      if ( this.buffer.isInRange(offset) &&
-         !this.buffer.isNearingLimit(offset)) {
-         return;
-         }
-      if (this.processingRequest) {
-          this.unprocessedRequest = new Rico.LiveGridRequest(offset);
-         return;
-      }
-      var bufferStartPos = this.buffer.getFetchOffset(offset);
-      this.processingRequest = new Rico.LiveGridRequest(offset);
-      this.processingRequest.bufferOffset = bufferStartPos;   
-      var fetchSize = this.buffer.getFetchSize(offset);
-      var partialLoaded = false;
-      
-      var queryString
-      if (this.options.requestParameters)
-         queryString = this._createQueryString(this.options.requestParameters, 0);
-
-        queryString = (queryString == null) ? '' : queryString+'&';
-        queryString  = queryString+'id='+this.tableId+'&page_size='+fetchSize+'&offset='+bufferStartPos;
-        if (this.sortCol)
-            queryString = queryString+'&sort_col='+escape(this.sortCol)+'&sort_dir='+this.sortDir;
-
-        this.ajaxOptions.parameters = queryString;
-
-       ajaxEngine.sendRequest( this.tableId + '_request', this.ajaxOptions );
-
-       this.timeoutHandler = setTimeout( this.handleTimedOut.bind(this), this.options.bufferTimeout);
-
-   },
-
-   setRequestParams: function() {
-      this.options.requestParameters = [];
-      for ( var i=0 ; i < arguments.length ; i++ )
-         this.options.requestParameters[i] = arguments[i];
-   },
-
-   requestContentRefresh: function(contentOffset) {
-      this.fetchBuffer(contentOffset);
-   },
-
-   ajaxUpdate: function(ajaxResponse) {
-      try {
-         clearTimeout( this.timeoutHandler );
-         this.buffer.update(ajaxResponse,this.processingRequest.bufferOffset);
-         this.viewPort.bufferChanged();
-      }
-      catch(err) {}
-      finally {this.processingRequest = null; }
-      this.processQueuedRequest();
-   },
-
-   _createQueryString: function( theArgs, offset ) {
-      var queryString = ""
-      if (!theArgs)
-          return queryString;
-
-      for ( var i = offset ; i < theArgs.length ; i++ ) {
-          if ( i != offset )
-            queryString += "&";
-
-          var anArg = theArgs[i];
-
-          if ( anArg.name != undefined && anArg.value != undefined ) {
-            queryString += anArg.name +  "=" + escape(anArg.value);
-          }
-          else {
-             var ePos  = anArg.indexOf('=');
-             var argName  = anArg.substring( 0, ePos );
-             var argValue = anArg.substring( ePos + 1 );
-             queryString += argName + "=" + escape(argValue);
-          }
-      }
-      return queryString;
-   },
-
-   processQueuedRequest: function() {
-      if (this.unprocessedRequest != null) {
-         this.requestContentRefresh(this.unprocessedRequest.requestOffset);
-         this.unprocessedRequest = null
-      }
-   }
-};
-
-
-//-------------------- ricoLiveGridSort.js
-Rico.LiveGridSort = Class.create();
-
-Rico.LiveGridSort.prototype = {
-
-   initialize: function(headerTableId, options) {
-      this.headerTableId = headerTableId;
-      this.headerTable   = $(headerTableId);
-      this.options = options;
-      this.setOptions();
-      this.applySortBehavior();
-
-      if ( this.options.sortCol ) {
-         this.setSortUI( this.options.sortCol, this.options.sortDir );
-      }
-   },
-
-   setSortUI: function( columnName, sortDirection ) {
-      var cols = this.options.columns;
-      for ( var i = 0 ; i < cols.length ; i++ ) {
-         if ( cols[i].name == columnName ) {
-            this.setColumnSort(i, sortDirection);
-            break;
-         }
-      }
-   },
-
-   setOptions: function() {
-      // preload the images...
-      new Image().src = this.options.sortAscendImg;
-      new Image().src = this.options.sortDescendImg;
-
-      this.sort = this.options.sortHandler;
-      if ( !this.options.columns )
-         this.options.columns = this.introspectForColumnInfo();
-      else {
-         // allow client to pass { columns: [ ["a", true], ["b", false] ] }
-         // and convert to an array of Rico.TableColumn objs...
-         this.options.columns = this.convertToTableColumns(this.options.columns);
-      }
-   },
-
-   applySortBehavior: function() {
-      var headerRow   = this.headerTable.rows[0];
-      var headerCells = headerRow.cells;
-      for ( var i = 0 ; i < headerCells.length ; i++ ) {
-         this.addSortBehaviorToColumn( i, headerCells[i] );
-      }
-   },
-
-   addSortBehaviorToColumn: function( n, cell ) {
-      if ( this.options.columns[n].isSortable() ) {
-         cell.id            = this.headerTableId + '_' + n;
-         cell.style.cursor  = 'pointer';
-         cell.onclick       = this.headerCellClicked.bindAsEventListener(this);
-         cell.innerHTML     = cell.innerHTML + '<span id="' + this.headerTableId + '_img_' + n + '">'
-                           + '&nbsp;&nbsp;&nbsp;</span>';
-      }
-   },
-
-   // event handler....
-   headerCellClicked: function(evt) {
-      var eventTarget = evt.target ? evt.target : evt.srcElement;
-      var cellId = eventTarget.id;
-      var columnNumber = parseInt(cellId.substring( cellId.lastIndexOf('_') + 1 ));
-      var sortedColumnIndex = this.getSortedColumnIndex();
-      if ( sortedColumnIndex != -1 ) {
-         if ( sortedColumnIndex != columnNumber ) {
-            this.removeColumnSort(sortedColumnIndex);
-            this.setColumnSort(columnNumber, Rico.TableColumn.SORT_ASC);
-         }
-         else
-            this.toggleColumnSort(sortedColumnIndex);
-      }
-      else
-         this.setColumnSort(columnNumber, Rico.TableColumn.SORT_ASC);
-
-      if (this.options.sortHandler) {
-         this.options.sortHandler(this.options.columns[columnNumber]);
-      }
-   },
-
-   removeColumnSort: function(n) {
-      this.options.columns[n].setUnsorted();
-      this.setSortImage(n);
-   },
-
-   setColumnSort: function(n, direction) {
-       if(isNaN(n)) return ;
-      this.options.columns[n].setSorted(direction);
-      this.setSortImage(n);
-   },
-
-   toggleColumnSort: function(n) {
-      this.options.columns[n].toggleSort();
-      this.setSortImage(n);
-   },
-
-   setSortImage: function(n) {
-      var sortDirection = this.options.columns[n].getSortDirection();
-
-      var sortImageSpan = $( this.headerTableId + '_img_' + n );
-      if ( sortDirection == Rico.TableColumn.UNSORTED )
-         sortImageSpan.innerHTML = '&nbsp;&nbsp;';
-      else if ( sortDirection == Rico.TableColumn.SORT_ASC )
-         sortImageSpan.innerHTML = '&nbsp;&nbsp;<img width="'  + this.options.sortImageWidth    + '" ' +
-                                                     'height="'+ this.options.sortImageHeight   + '" ' +
-                                                     'src="'   + this.options.sortAscendImg + '"/>';
-      else if ( sortDirection == Rico.TableColumn.SORT_DESC )
-         sortImageSpan.innerHTML = '&nbsp;&nbsp;<img width="'  + this.options.sortImageWidth    + '" ' +
-                                                     'height="'+ this.options.sortImageHeight   + '" ' +
-                                                     'src="'   + this.options.sortDescendImg + '"/>';
-   },
-
-   getSortedColumnIndex: function() {
-      var cols = this.options.columns;
-      for ( var i = 0 ; i < cols.length ; i++ ) {
-         if ( cols[i].isSorted() )
-            return i;
-      }
-
-      return -1;
-   },
-
-   introspectForColumnInfo: function() {
-      var columns = new Array();
-      var headerRow   = this.headerTable.rows[0];
-      var headerCells = headerRow.cells;
-      for ( var i = 0 ; i < headerCells.length ; i++ )
-         columns.push( new Rico.TableColumn( this.deriveColumnNameFromCell(headerCells[i],i), true ) );
-      return columns;
-   },
-
-   convertToTableColumns: function(cols) {
-      var columns = new Array();
-      for ( var i = 0 ; i < cols.length ; i++ )
-         columns.push( new Rico.TableColumn( cols[i][0], cols[i][1] ) );
-      return columns;
-   },
-
-   deriveColumnNameFromCell: function(cell,columnNumber) {
-      var cellContent = cell.innerText != undefined ? cell.innerText : cell.textContent;
-      return cellContent ? cellContent.toLowerCase().split(' ').join('_') : "col_" + columnNumber;
-   }
-};
-
-Rico.TableColumn = Class.create();
-
-Rico.TableColumn.UNSORTED  = 0;
-Rico.TableColumn.SORT_ASC  = "ASC";
-Rico.TableColumn.SORT_DESC = "DESC";
-
-Rico.TableColumn.prototype = {
-   initialize: function(name, sortable) {
-      this.name        = name;
-      this.sortable    = sortable;
-      this.currentSort = Rico.TableColumn.UNSORTED;
-   },
-
-   isSortable: function() {
-      return this.sortable;
-   },
-
-   isSorted: function() {
-      return this.currentSort != Rico.TableColumn.UNSORTED;
-   },
-
-   getSortDirection: function() {
-      return this.currentSort;
-   },
-
-   toggleSort: function() {
-      if ( this.currentSort == Rico.TableColumn.UNSORTED || this.currentSort == Rico.TableColumn.SORT_DESC )
-         this.currentSort = Rico.TableColumn.SORT_ASC;
-      else if ( this.currentSort == Rico.TableColumn.SORT_ASC )
-         this.currentSort = Rico.TableColumn.SORT_DESC;
-   },
-
-   setUnsorted: function(direction) {
-      this.setSorted(Rico.TableColumn.UNSORTED);
-   },
-
-   setSorted: function(direction) {
-      // direction must by one of Rico.TableColumn.UNSORTED, .SORT_ASC, or .SORT_DESC...
-      this.currentSort = direction;
-   }
-
-};
-
-
-//-------------------- ricoUtil.js
-var RicoUtil = {
-
-   getElementsComputedStyle: function ( htmlElement, cssProperty, mozillaEquivalentCSS) {
-      if ( arguments.length == 2 )
-         mozillaEquivalentCSS = cssProperty;
-
-      var el = $(htmlElement);
-      if ( el.currentStyle )
-         return el.currentStyle[cssProperty];
-      else
-         return document.defaultView.getComputedStyle(el, null).getPropertyValue(mozillaEquivalentCSS);
-   },
-
-   createXmlDocument : function() {
-      if (document.implementation && document.implementation.createDocument) {
-         var doc = document.implementation.createDocument("", "", null);
-
-         if (doc.readyState == null) {
-            doc.readyState = 1;
-            doc.addEventListener("load", function () {
-               doc.readyState = 4;
-               if (typeof doc.onreadystatechange == "function")
-                  doc.onreadystatechange();
-            }, false);
-         }
-
-         return doc;
-      }
-
-      if (window.ActiveXObject)
-          return Try.these(
-            function() { return new ActiveXObject('MSXML2.DomDocument')   },
-            function() { return new ActiveXObject('Microsoft.DomDocument')},
-            function() { return new ActiveXObject('MSXML.DomDocument')    },
-            function() { return new ActiveXObject('MSXML3.DomDocument')   }
-          ) || false;
-
-      return null;
-   },
-
-   getContentAsString: function( parentNode ) {
-      return parentNode.xml != undefined ? 
-         this._getContentAsStringIE(parentNode) :
-         this._getContentAsStringMozilla(parentNode);
-   },
-
-  _getContentAsStringIE: function(parentNode) {
-     var contentStr = "";
-     for ( var i = 0 ; i < parentNode.childNodes.length ; i++ ) {
-         var n = parentNode.childNodes[i];
-         if (n.nodeType == 4) {
-             contentStr += n.nodeValue;
-         }
-         else {
-           contentStr += n.xml;
-       }
-     }
-     return contentStr;
-  },
-
-  _getContentAsStringMozilla: function(parentNode) {
-     var xmlSerializer = new XMLSerializer();
-     var contentStr = "";
-     for ( var i = 0 ; i < parentNode.childNodes.length ; i++ ) {
-          var n = parentNode.childNodes[i];
-          if (n.nodeType == 4) { // CDATA node
-              contentStr += n.nodeValue;
-          }
-          else {
-            contentStr += xmlSerializer.serializeToString(n);
-        }
-     }
-     return contentStr;
-  },
-
-   toViewportPosition: function(element) {
-      return this._toAbsolute(element,true);
-   },
-
-   toDocumentPosition: function(element) {
-      return this._toAbsolute(element,false);
-   },
-
-   /**
-    *  Compute the elements position in terms of the window viewport
-    *  so that it can be compared to the position of the mouse (dnd)
-    *  This is additions of all the offsetTop,offsetLeft values up the
-    *  offsetParent hierarchy, ...taking into account any scrollTop,
-    *  scrollLeft values along the way...
-    *
-    * IE has a bug reporting a correct offsetLeft of elements within a
-    * a relatively positioned parent!!!
-    **/
-   _toAbsolute: function(element,accountForDocScroll) {
-
-      if ( navigator.userAgent.toLowerCase().indexOf("msie") == -1 )
-         return this._toAbsoluteMozilla(element,accountForDocScroll);
-
-      var x = 0;
-      var y = 0;
-      var parent = element;
-      while ( parent ) {
-
-         var borderXOffset = 0;
-         var borderYOffset = 0;
-         if ( parent != element ) {
-            var borderXOffset = parseInt(this.getElementsComputedStyle(parent, "borderLeftWidth" ));
-            var borderYOffset = parseInt(this.getElementsComputedStyle(parent, "borderTopWidth" ));
-            borderXOffset = isNaN(borderXOffset) ? 0 : borderXOffset;
-            borderYOffset = isNaN(borderYOffset) ? 0 : borderYOffset;
-         }
-
-         x += parent.offsetLeft - parent.scrollLeft + borderXOffset;
-         y += parent.offsetTop - parent.scrollTop + borderYOffset;
-         parent = parent.offsetParent;
-      }
-
-      if ( accountForDocScroll ) {
-         x -= this.docScrollLeft();
-         y -= this.docScrollTop();
-      }
-
-      return { x:x, y:y };
-   },
-
-   /**
-    *  Mozilla did not report all of the parents up the hierarchy via the
-    *  offsetParent property that IE did.  So for the calculation of the
-    *  offsets we use the offsetParent property, but for the calculation of
-    *  the scrollTop/scrollLeft adjustments we navigate up via the parentNode
-    *  property instead so as to get the scroll offsets...
-    *
-    **/
-   _toAbsoluteMozilla: function(element,accountForDocScroll) {
-      var x = 0;
-      var y = 0;
-      var parent = element;
-      while ( parent ) {
-         x += parent.offsetLeft;
-         y += parent.offsetTop;
-         parent = parent.offsetParent;
-      }
-
-      parent = element;
-      while ( parent &&
-              parent != document.body &&
-              parent != document.documentElement ) {
-         if ( parent.scrollLeft  )
-            x -= parent.scrollLeft;
-         if ( parent.scrollTop )
-            y -= parent.scrollTop;
-         parent = parent.parentNode;
-      }
-
-      if ( accountForDocScroll ) {
-         x -= this.docScrollLeft();
-         y -= this.docScrollTop();
-      }
-
-      return { x:x, y:y };
-   },
-
-   docScrollLeft: function() {
-      if ( window.pageXOffset )
-         return window.pageXOffset;
-      else if ( document.documentElement && document.documentElement.scrollLeft )
-         return document.documentElement.scrollLeft;
-      else if ( document.body )
-         return document.body.scrollLeft;
-      else
-         return 0;
-   },
-
-   docScrollTop: function() {
-      if ( window.pageYOffset )
-         return window.pageYOffset;
-      else if ( document.documentElement && document.documentElement.scrollTop )
-         return document.documentElement.scrollTop;
-      else if ( document.body )
-         return document.body.scrollTop;
-      else
-         return 0;
-   }
-
-};
diff --git a/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web-data/theme.css b/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web-data/theme.css
deleted file mode 100644 (file)
index 3dc0435..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-body { background-color:#445566; color:#FFCC99; }
-a:link { color:#FF9966; }
-a:visited { color:#FF9900; }
-a:active { color:#FFFFFF; }
-
-       /* allow room for 3 columns */
-ol
-{
-       width: 45em;
-}
-
-       /* float and allow room for the widest item */
-ol li
-{
-       float: left;
-       width: 15em;
-}
-
-/* stop the float */
-br
-{
-       clear: left;
-}
-
-       /* separate the list from subsequent markup */
-div.wrapper
-{
-       margin-bottom: 1em;
-}
-
diff --git a/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web-data/tools.js b/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web-data/tools.js
deleted file mode 100644 (file)
index 75f46f0..0000000
+++ /dev/null
@@ -1,411 +0,0 @@
-var url_getvolume = '/web/vol?set=info'; 
-var url_setvolume = '/web/vol?set=set'; // plus new value eq. set=set15
-var url_volumeup = '/web/vol?set=up';
-var url_volumedown = '/web/vol?set=down';
-var url_volumemute = '/web/vol?set=mute';
-
-var url_epgservice = "/web/epgservice?ref="; // plus serviceRev
-var url_epgsearch = "/web/epgsearch?search="; // plus serviceRev
-var url_epgnownext = "/web/epgnownext?ref="; // plus serviceRev
-
-function debug(text){
-       //$('debug').innerHTML += "DEBUG: "+text+"<br>";
-}
-function set(what, value)
-{
-       //debug(what+"-"+value);
-       element = document.getElementById(what);
-       element.innerHTML = value;
-       $('scriptzone').innerHTML = ""; // deleting set() from page, to keep the page short and to save memory
-}
-
-function zap(li)
-{
-       var request = getHTTPObject();
-       var url = "/web/zap?ZapTo=" + escape(li.id);
-       //debug("requesting "+url);
-       new Ajax.Request( url,
-                       {
-                               method: 'get' 
-                               
-                       });
-               
-}
-
-function getHTTPObject() 
-{
-       var xmlhttp; 
-       /*@cc_on 
-       @if (@_jscript_version >= 5) 
-       try 
-       { 
-               xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); 
-       } 
-       catch (e) 
-       { 
-               try 
-               { 
-                       xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); 
-               } 
-               catch (E) 
-               { 
-                       xmlhttp = false; 
-               } 
-       } 
-       @else 
-       xmlhttp = false; 
-       @end @*/ 
-       if (!xmlhttp && typeof XMLHttpRequest != 'undefined') 
-       { 
-               try 
-               { 
-                       xmlhttp = new XMLHttpRequest(); 
-               } 
-               catch (e) 
-               {
-                       xmlhttp = false; 
-               }
-       } 
-       return xmlhttp; 
-}
-
-
-//+++++++++++++++++++++++++++++++++++++++++++++++++++++
-//+++++++++++++++++++++++++++++++++++++++++++++++++++++
-//++++ EPG functions                               ++++
-//+++++++++++++++++++++++++++++++++++++++++++++++++++++
-//+++++++++++++++++++++++++++++++++++++++++++++++++++++
-var EPGList = Class.create();
-EPGList.prototype = {
-       //contructor
-       initialize: function(){
-               debug("init class EPGList");
-       },
-       getBySearchString: function(string,element){
-               debug("requesting "+ url_epgsearch+string);
-               targetElement = element;
-               new Ajax.Request( url_epgsearch+string,
-                       {
-                               method: 'get', 
-                               onComplete: this.incomingEPGrequest
-                       });
-               
-       },
-       getByServiceReference: function(serviceRef,element){
-               targetElement = element;
-               new Ajax.Request(url_epgservice+serviceRef,
-                       {
-                               method: 'get', 
-                               onComplete: this.incomingEPGrequest
-                       });
-               
-       },
-       renderTable: function(epglist){
-               debug("rendering Table with "+epglist.length+" events");
-               var html="<table width='100%'>";
-               for (var i=0; i<epglist.length;i++){
-                       var item = epglist[i];
-                       html +="<tr  bgcolor='gray'>";
-                       html +="<td>"+item.getTimeDay()+"</td>";
-                       html +="<td>"+item.getTimeStartString()+"</td>";
-                       html +="<td>"+item.getTimeEndString()+"</td>";
-                       html +="<td>"+item.getTitle()+"</td>";
-                       html +="<td>"+item.getDescription()+"</td>";
-                       html +="<td>"+item.getDescriptionExtended()+"</td>";
-                       html +="<td>"+(item.getDuration()/60000)+" min.</td>";
-                       html +="<td>"+item.getServiceName()+"</td>";
-                       html +="</tr>";
-               }
-               html +="</table>";
-               targetElement.innerHTML = html;
-               
-       },
-       incomingEPGrequest: function(originalRequest){
-               debug("incoming request" +originalRequest.readyState);          
-               if (originalRequest.readyState == 4)
-               {
-                       if (originalRequest.responseXML!="no data")
-                       {
-                               var EPGItems = originalRequest.responseXML.getElementsByTagName("e2eventlist").item(0).getElementsByTagName("e2event");
-                               debug("have "+EPGItems.length+" e2events");
-                               epglist = new Array();
-                               for(var i=0;i<EPGItems.length;i++)
-                               {       
-                                       epglist.push(new EPGEvent(EPGItems.item(i)));
-                               }
-                               EPGList.prototype.renderTable(epglist);
-                               
-                       }                               
-               }
-       }
-       
-}
-
-function EPGEvent(element){    
-       // parsing values from xml-element
-       this.eventID= element.getElementsByTagName('e2eventid').item(0).firstChild.data;
-       this.startTime= element.getElementsByTagName('e2eventstart').item(0).firstChild.data;
-       this.duration= element.getElementsByTagName('e2eventduration').item(0).firstChild.data;
-       this.title= element.getElementsByTagName('e2eventtitle').item(0).firstChild.data;
-       this.description= element.getElementsByTagName('e2eventdescription').item(0).firstChild.data;
-       this.descriptionE= element.getElementsByTagName('e2eventdescriptionextended').item(0).firstChild.data;
-       this.serviceRef= element.getElementsByTagName('e2eventservicereference').item(0).firstChild.data;
-       this.serviceName= element.getElementsByTagName('e2eventservicename').item(0).firstChild.data;
-
-       this.getEventId = function ()
-       {
-               return this.eventID;
-       }
-       this.getTimeStart = function ()
-       {
-               var date = new Date(parseInt(this.startTime)*1000);
-               return date;
-       }
-       this.getTimeStartString = function ()
-       {
-               var h = this.getTimeStart().getHours();
-               var m = this.getTimeStart().getMinutes();
-               if (m < 10){
-                       m="0"+m;
-               }
-               return h+":"+m;
-       }
-       this.getTimeDay = function ()
-       {
-               var Wochentag = new Array("So", "Mo", "Di", "Mi", "Do", "Fr", "Sa");
-               var wday = Wochentag[this.getTimeStart().getDay()];
-               var day = this.getTimeStart().getDate();
-               var month = this.getTimeStart().getMonth()+1;
-               var year = this.getTimeStart().getFullYear();
-               
-               return wday+".&nbsp;"+day+"."+month+"."+year;
-       }
-       this.getTimeEnd = function ()
-       {
-               var date = new Date((parseInt(this.startTime)+parseInt(this.duration))*1000);
-               return date;
-       }
-       this.getTimeEndString = function ()
-       {
-               var h = this.getTimeEnd().getHours();
-               var m = this.getTimeEnd().getMinutes();
-               if (m < 10){
-                       m="0"+m;
-               }
-               return h+":"+m;
-       }
-       this.getDuration = function ()
-       {
-               return  new Date(parseInt(this.duration)*1000);
-       }
-       this.getTitle = function ()
-       {
-               return this.title;
-       }
-       this.getDescription = function ()
-       {
-               return this.description;
-       }
-       this.getDescriptionExtended = function ()
-       {
-               return this.descriptionE;
-       }
-       this.getServiceReference = function ()
-       {
-               return this.serviceRef;
-       }
-       this.getServiceName = function ()
-       {
-               return this.serviceName.replace(" ","&nbsp;");
-       }
-}//END class EPGEvent
-//+++++++++++++++++++++++++++++++++++++++++++++++++++++
-//+++++++++++++++++++++++++++++++++++++++++++++++++++++
-//++++ GUI functions                               ++++
-//+++++++++++++++++++++++++++++++++++++++++++++++++++++
-//+++++++++++++++++++++++++++++++++++++++++++++++++++++
-var currentBodyMainElement = null
-
-function setBodyMainContent(newelementname){
-       newelement =document.getElementById(newelementname);
-       if(currentBodyMainElement != null){
-               currentBodyMainElement.style.display = "none";
-               
-       }
-       newelement.style.display = "inline";
-       currentBodyMainElement = newelement;
-}
-function doRequest(url,readyFunction){
-       
-       http_request =getHTTPObject();
-       if(readyFunction){
-               http_request.onreadystatechange = readyFunction;
-       }
-       http_request.open('GET', url, true);
-       http_request.send(null);
-       return http_request;
-}
-//+++++++++++++++++++++++++++++++++++++++++++++++++++++
-//+++++++++++++++++++++++++++++++++++++++++++++++++++++
-//++++ volume functions                            ++++
-//+++++++++++++++++++++++++++++++++++++++++++++++++++++
-//+++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-
-function getVolume()
-{
-       doRequest(url_getvolume,handleVolumeRequest);
-}
-function setVolume(newvalue)
-{
-               doRequest(url_setvolume+newvalue,handleVolumeRequest);
-}
-function volumeUp()
-{
-               doRequest(url_volumeup,handleVolumeRequest);
-}
-function volumeDown()
-{
-               doRequest(url_volumedown,handleVolumeRequest);  
-}
-function volumeMute()
-{
-               doRequest(url_volumemute,handleVolumeRequest);
-}
-function handleVolumeRequest(){
-               if (http_request.readyState == 4) {
-                               var a = http_request.responseText.split("\n");
-                               var newvalue = a[1];
-                       var mute=a[2];
-                               set("Volume_Current",newvalue);
-                               for (var i = 1; i <= 10; i++)
-                               {
-                                       if ( (newvalue/10)>=i){
-                                               $("volume"+i).src = "/webdata/gfx/led_on.png";
-                                       }else{
-                                               $("volume"+i).src = "/webdata/gfx/led_off.png";
-                                       }
-                               }
-                               if (mute == "notmuted"){
-                                       $("speaker").src = "/webdata/gfx/speak_on.png";
-                               }else{
-                                       $("speaker").src = "/webdata/gfx/speak_off.png";
-                               }
-                       }       
-}
-//+++++++++++++++++++++++++++++++++++++++++++++++++++++
-//+++++++++++++++++++++++++++++++++++++++++++++++++++++
-//++++ Bouqet managing functions                   ++++
-//+++++++++++++++++++++++++++++++++++++++++++++++++++++
-//+++++++++++++++++++++++++++++++++++++++++++++++++++++
-       function loadRootTVBouqet(){
-               //rootB = '/web/fetchchannels?ServiceListBrowse='+escape('1:7:1:0:0:0:0:0:0:0:(type == 1) FROM BOUQUET "bouquets.tv" ORDER BY bouquet');
-       rootB = '/web/fetchchannels?ServiceListBrowse='+escape('1:7:1:0:0:0:0:0:0:0:(type == 1) || (type == 17) || (type == 195) || (type == 25)  FROM BOUQUET &quot;bouquets.tv&quot; ORDER BY bouquet');
-               
-                
-               loadRootBouqet(rootB);
-       }
-  function loadRootBouqet(rootB){
-               
-               t =getHTTPObject();
-               t.onreadystatechange = incomingResult;
-               t.open('GET', rootB, true);
-               t.send(null);
-               
-       }
-       function incomingResult(){
-               if((t.readyState == 4) && (t.status == 200)) {
-       // perfekt!
-                       var r = t.responseXML;
-                       
-                       var b = r.getElementsByTagName("e2servicelist").item(0).getElementsByTagName("e2service");
-
-                       bouquets = new Array();
-                       for ( var i=0; i < b.length; i++){
-                               bRef = b.item(i).getElementsByTagName('e2servicereference').item(0).firstChild.data;
-                               bName = b.item(i).getElementsByTagName('e2servicename').item(0).firstChild.data;
-                               
-                               bu = new Array(bName,bRef);
-                               bouquets.push(bu)
-                       }
-                       refreshSelect(bouquets);
-               } else {
-       // die Anfrage enthielt Fehler;
-       // die Antwort war z.B. 404 (nicht gefunden)
-       // oder 500 (interner Server-Fehler)
-               }
-               
-       }
-       // to add the bouqetts to the list
-       function refreshSelect(arraybouqet){
-               
-               sel = document.getElementById("accordionMenueBouqetContent");
-               // options neu eintragen
-               html = "<table>";
-                       for ( var i = 0 ; i < arraybouqet.length ; i++ ){
-                       if(arraybouqet[i][0] && arraybouqet[i][1]){
-                               html+="<tr><td>";
-                               html+="<a  onclick=\"bouqetSelected(this); setBodyMainContent('BodyContentChannellist');\" id='";
-                               html+= arraybouqet[i][1];
-                               html+="'>";
-                               html+= arraybouqet[i][0];
-                               html+="</a>";
-                               html+="</td></tr>";
-                       }
-               }
-               html+="</table>";
-               sel.innerHTML=html;
-               refreshChannellist(arraybouqet[0][0],arraybouqet[0][1]);
-       }
-       //++++++++++++++++++++++
-       function bouqetSelected(element){
-               refreshChannellist(element.value,element.id)
-       }
-       
-       function refreshChannellist(bname,bref){
-               urlx = '/web/fetchchannels?ServiceListBrowse='+escape(bref);
-               w =getHTTPObject();
-               w.onreadystatechange = incomingChannellist;
-         w.open('GET', urlx, true);
-         w.send(null);
-         
-               
-               
-       }
-               function incomingChannellist(){
-                       if (w.readyState == 4) {
-               // alles in Ordnung, Antwort wurde empfangen
-                       if (w.responseXML != "no data"){        
-                               var services = w.responseXML.getElementsByTagName("e2servicelist").item(0).getElementsByTagName("e2service");
-                               listerHtml = "<table id=\"ChannelSelect\" >";
-                       
-                               for ( var i = 0; i < (services.length ); i++){
-                                       sRef = services.item(i).getElementsByTagName('e2servicereference').item(0).firstChild.data;
-                                       sName = services.item(i).getElementsByTagName('e2servicename').item(0).firstChild.data;
-
-                                       listerHtml += '<tr bgcolor="gray"><td><div onclick=\"zap(this)\" id="';
-                                       listerHtml += sRef;
-                                       listerHtml += '">';
-                                       listerHtml += sName;
-                                       listerHtml += '</div></td>';
-                                       listerHtml += '<td><a onclick=\"new EPGList().getByServiceReference(this.id,$(\'BodyEPGPanel\'));setBodyMainContent(\'BodyEPGPanel\');\" id="';
-                                       listerHtml += sRef;
-                                       listerHtml += '" >EPG</div><div><a target=\"blank" href=\"stream.m3u?ref=';
-                                       listerHtml += sRef;
-                                       listerHtml += '\">Stream</a></div></td>';
-                                       listerHtml += '</tr>';
-                               }
-                               listerHtml += "</table>";
-                               document.getElementById("BodyContentChannellist").innerHTML = listerHtml;
-                               setBodyMainContent('BodyContentChannellist');
-                       } else {
-               // die Anfrage enthielt Fehler;
-               // die Antwort war z.B. 404 (nicht gefunden)
-               // oder 500 (interner Server-Fehler)
-                       }
-               }       
-                       
-       }
-
-
-
diff --git a/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web/epgnownext.xml b/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web/epgnownext.xml
deleted file mode 100644 (file)
index db606c7..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-<e2:screen name="TestScreen">&lt;?xml version="1.0" encoding="utf-8"?>
-&lt;e2eventlist><e2:element source="EPGNOWNEXT" id="ref"><e2:convert type="web:ListFiller" >
-       &lt;e2event>
-               &lt;e2eventid><e2:item name="EventID" /> &lt;/e2eventid>
-               &lt;e2eventstart><e2:item name="TimeStart"/> &lt;/e2eventstart>
-               &lt;e2eventduration><e2:item name="Duration"/> &lt;/e2eventduration>
-               &lt;e2eventtitle><e2:item name="Title"/> &lt;/e2eventtitle>
-               &lt;e2eventdescription><e2:item name="Description"/> &lt;/e2eventdescription>
-               &lt;e2eventdescriptionextended><e2:item name="DescriptionExtended"/> &lt;/e2eventdescriptionextended>
-               &lt;e2eventservicereference><e2:item name="ServiceReference"/> &lt;/e2eventservicereference>
-               &lt;e2eventservicename><e2:item name="ServiceName"/> &lt;/e2eventservicename>
-       &lt;/e2event></e2:convert><e2:convert type="web:TextToHTML" /></e2:element>
-&lt;/e2eventlist>
-</e2:screen>
\ No newline at end of file
diff --git a/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web/epgsearch.xml b/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web/epgsearch.xml
deleted file mode 100644 (file)
index dcb8067..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-<e2:screen name="TestScreen">&lt;?xml version="1.0"?>
-&lt;e2eventlist><e2:element source="EPGTITLE" id="search"><e2:convert type="web:ListFiller" >
-       &lt;e2event>
-               &lt;e2eventid><e2:item name="EventID" /> &lt;/e2eventid>
-               &lt;e2eventstart><e2:item name="TimeStart"/> &lt;/e2eventstart>
-               &lt;e2eventduration><e2:item name="Duration"/> &lt;/e2eventduration>
-               &lt;e2eventtitle><e2:item name="Title"/> &lt;/e2eventtitle>
-               &lt;e2eventdescription><e2:item name="Description"/> &lt;/e2eventdescription>
-               &lt;e2eventdescriptionextended><e2:item name="DescriptionExtended"/> &lt;/e2eventdescriptionextended>
-               &lt;e2eventservicereference><e2:item name="ServiceReference"/> &lt;/e2eventservicereference>
-               &lt;e2eventservicename><e2:item name="ServiceName"/> &lt;/e2eventservicename>
-       &lt;/e2event></e2:convert><e2:convert type="web:TextToHTML" /></e2:element>
-&lt;/e2eventlist>
-</e2:screen>
\ No newline at end of file
diff --git a/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web/epgservice.xml b/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web/epgservice.xml
deleted file mode 100644 (file)
index 919ff1b..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-<e2:screen name="TestScreen">&lt;?xml version="1.0" encoding="utf-8"?>
-&lt;e2eventlist><e2:element source="EPGSERVICE" id="ref"><e2:convert type="web:ListFiller" >
-       &lt;e2event>
-               &lt;e2eventid><e2:item name="EventID" /> &lt;/e2eventid>
-               &lt;e2eventstart><e2:item name="TimeStart"/> &lt;/e2eventstart>
-               &lt;e2eventduration><e2:item name="Duration"/> &lt;/e2eventduration>
-               &lt;e2eventtitle><e2:item name="Title"/> &lt;/e2eventtitle>
-               &lt;e2eventdescription><e2:item name="Description"/> &lt;/e2eventdescription>
-               &lt;e2eventdescriptionextended><e2:item name="DescriptionExtended"/> &lt;/e2eventdescriptionextended>
-               &lt;e2eventservicereference><e2:item name="ServiceReference"/> &lt;/e2eventservicereference>
-               &lt;e2eventservicename><e2:item name="ServiceName"/> &lt;/e2eventservicename>
-       &lt;/e2event></e2:convert><e2:convert type="web:TextToHTML" /></e2:element>
-&lt;/e2eventlist>
-</e2:screen>
\ No newline at end of file
diff --git a/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web/fetchchannels.xml b/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web/fetchchannels.xml
deleted file mode 100644 (file)
index 724aec9..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-<e2:screen name="TestScreen">&lt;?xml version="1.0" encoding="UTF-8"?>
-<e2servicelist>
-<e2:element source="ServiceListBrowse">                                
-       <e2:convert type="web:ListFiller">
-       &lt;e2service>
-               &lt;e2servicereference><e2:item name="Reference" />&lt;/e2servicereference>
-               &lt;e2servicename><e2:item name="Name"/>&lt;/e2servicename>
-       &lt;/e2service>
-       </e2:convert>
-       <e2:convert type="web:TextToHTML" />                    
-</e2:element>
-</e2servicelist>       
-</e2:screen>
\ No newline at end of file
diff --git a/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web/index.html.xml b/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web/index.html.xml
deleted file mode 100644 (file)
index 8368c9c..0000000
+++ /dev/null
@@ -1,311 +0,0 @@
-<e2:screen name="TestScreen">&lt;html>
-<head>
-       <meta content="text/html; charset=UTF-8" http-equiv="content-type"/>
-       <title>Enigma2 Webinterface</title>
-       <script src="/webdata/prototype.js" type="text/javascript"/>
-    <script src="/webdata/rico.js" type="text/javascript"/>
-       <script src="/webdata/tools.js" type="text/javascript" />
-       <link  href="/webdata/theme.css" rel="stylesheet" type="text/css" />                                      
-</head>
-
-<body>
-<div id="debug"></div>
-
-<table id="htmlDesignTable"  width="100%" border="0">
-<tr><td>
-<!-- START SITE HEADER //-->
-               <table width="100%" border="0">
-                       <tr>
-                               <td width="10%"  rowspan="2">
-                                       <div id="Current_Channel_Box" class="roundme" >
-                                       <nobr><div id="CurrentService"  > </div></nobr>
-                                       <div id="CurrentServiceProvider" > </div>
-                                       </div>
-                               </td>
-                               <td width="80%">
-                                       <span id="Event_Now_Name"  onclick="setBodyMainContent('BodyContentEPGNow')"> </span>
-                               </td>
-                               <td width="150" rowspan="2">
-                                       <div id="Info_Box"  class="roundme">
-                                               <table width="100">
-                                                       <tr><td colspan="2"><div id="CurrentTime"> </div></td></tr>
-                                                       <tr><td>SNR:</td><td><div id="SNR"></div></td></tr>
-                                                       <tr><td>BER:</td><td><div id="BER"></div></td></tr>
-                                                       <tr><td>AGC:</td><td><div id="AGC"></div></td></tr>
-                                               </table>
-                                       </div>
-                               </td>
-                               </tr><tr>
-                               
-                               <td width="80%">
-                                               <span id="Event_Next_Name"  onclick="setBodyMainContent('BodyContentEPGNext')"> </span>
-                               </td>
-                       </tr>
-                       <tr><td colspan="2">
-                               Volume <span id="Volume_Current" >..</span>
-                               <span onclick="volumeUp()" >++</span>
-                               <span onclick="volumeDown()" >--</span>
-                               <span onclick="volumeMute()" >xx</span>
-                               <img src="/webdata/gfx/led_off.png" id="volume1" onclick="setVolume(10)"/>
-                               <img src="/webdata/gfx/led_off.png" id="volume2" onclick="setVolume(20)"/>
-                               <img src="/webdata/gfx/led_off.png" id="volume3" onclick="setVolume(30)"/>
-                               <img src="/webdata/gfx/led_off.png" id="volume4" onclick="setVolume(40)"/>
-                               <img src="/webdata/gfx/led_off.png" id="volume5" onclick="setVolume(50)"/>
-                               <img src="/webdata/gfx/led_off.png" id="volume6" onclick="setVolume(60)"/>
-                               <img src="/webdata/gfx/led_off.png" id="volume7" onclick="setVolume(70)"/>
-                               <img src="/webdata/gfx/led_off.png" id="volume8" onclick="setVolume(80)"/>
-                               <img src="/webdata/gfx/led_off.png" id="volume9" onclick="setVolume(90)"/>
-                               <img src="/webdata/gfx/led_off.png" id="volume10" onclick="setVolume(100)"/>
-                               <img src="/webdata/gfx/speak_on.png" id="speaker"  onclick="volumeMute()" />
-                               </td>
-                               <td>
-                                       <form onSubmit="new EPGList().getBySearchString($('searchText').value,$('BodyEPGPanel')); setBodyMainContent('BodyEPGPanel'); return false;">
-                                               <input type="text" id="searchText" onfocus="this.value=''" value="EPG suchen"/>                                 
-                                       </form>
-                               </td>                                   
-                       </tr>
-               </table>
-               
-<!-- END SITE HEADER //-->
-</td></tr>
-<tr><td>
-<!-- START SITE BODY //-->
-       <table id="htmlDesignTableBody"   width="100%" border="0">
-       <tr>
-               <td id="htmlDesignTableBodyMenue" width="150" valign="top">
-               <!-- START BODY MENUE //-->
-                       <div id="accordionMenue">
-                       <div id="accordionMenueBouqetPanel">
-                       <div id="accordionMenueBouqetHeader">
-                               Bouquets
-               </div>
-               <div id="accordionMenueBouqetContent">
-                               
-               </div>
-                       </div>
-                       <!--<div id="accordionMenueControlPanel">
-                       <div id="accordionMenueControlHeader">
-                               Control
-               </div>
-               <div id="accordionMenueControlContent">
-                       <table>
-                               <tr><td><a onclick="setBodyMainContent('BodyContentMessageform')">Nachricht</a></td></tr>
-                               <tr><td><a onclick="setBodyMainContent('BodyContentPower')">Shutdown</a></td></tr>
-                               <tr><td><a onclick="setBodyMainContent('BodyContentHDD')">HDD</a></td></tr>
-                               <tr><td><a onclick="setBodyMainContent('BodyContentDebugbox')">JscriptDebug</a></td></tr>
-                               </table>
-               </div>
-                       </div>//-->
-                       </div>
-               
-               <!-- END BODY MENUE //-->
-               </td>
-               <td id="htmlDesignTableBodyMain" valign="top" witdh="100%" >
-               <!-- START BODY MAIN //-->
-                               <!-- START BodyContentEPGNext //-->       
-                               <div id="BodyContentEPGNext" style="display:none;" >
-                                       <div id="Event_Next_Box">
-                                               <table id="Event_Table_Next"  width="100%" border="1">
-                                                       <tr>
-                                                               <td>
-                                                                       <span id="Event_Next_Begin"></span> bis <span id="Event_Next_End"></span>
-                                                               </td>
-                                                               <td>
-                                                                       <span id="Event_Next_Name"  onclick="setBodyMainContent('BodyContentEPGNext')"> </span>
-                                                                       <a href="javascript:imdb()">...</a>                             
-                                                               </td>
-                                                               <td>
-                                                                       <span id="Event_Next_Remaining"> </span>
-                                                               </td>
-                                                       </tr>
-                                                       <tr>    
-                                                               <td colspan="3">
-                                                                       <div id="Event_Next_Description"> </div>
-                                                               </td>
-                                                       </tr>
-                                                       <tr>    
-                                                               <td colspan="3">
-                                                                       <div id="Event_Next_Extended_Description"> </div>
-                                                               </td>
-                                                       </tr>
-                                               </table>
-                                       </div>
-                               </div>
-                               <!-- ENDE BodyContentEPGNext //-->       
-                               <!-- START BodyContentEPGNow //-->       
-                               <div id="BodyContentEPGNow" style="display:none;">
-                                       <div id="Event_Now_Box">
-                                               <table id="Event_Table_Now"  width="100%" border="1">
-                                                       <tr>
-                                                               <td>
-                                                                       <span id="Event_Now_Begin"></span> bis <span id="Event_Now_End"></span>
-                                                               </td>
-                                                               <td>
-                                                                       <span id="Event_Now_Name"  onclick="setBodyMainContent('BodyContentEPGNow')"> </span>
-                                                                       <a href="javascript:imdb()">...</a>                             
-                                                               </td>
-                                                               <td>
-                                                                       <span id="Event_Now_Remaining"> </span>
-                                                               </td>
-                                                       </tr>
-                                                       <tr>    
-                                                               <td colspan="3">
-                                                                       <div id="Event_Now_Description"> </div>
-                                                               </td>
-                                                       </tr>
-                                                       <tr>    
-                                                               <td colspan="3">
-                                                                       <div id="Event_Now_Extended_Description"> </div>
-                                                               </td>
-                                                       </tr>
-                                               </table>
-                                       </div>
-                               </div>
-                               <!-- END BodyContentEPGNow //-->       
-                               <!-- START BodyContentChannellist //-->       
-                                       <div id="BodyContentChannellist" style="display:none;"></div>
-                               <!-- END BodyContentChannellist //--> 
-                               <!-- START BodyContentMessageform //-->       
-                                       <div id="BodyContentMessageform" style="display:none;">
-                                                                               BodyContentText BodyContentText BodyContentText BodyContentText
-                                       </div>
-                               <!-- END BodyContentMessageform //-->       
-                               <!-- START BodyContentPower //-->       
-                                       <div id="BodyContentPower" style="display:none;">
-                                               standby, Poweroff, E2restart
-                                       </div>
-                               <!-- END BodyContentPower //-->       
-                               <!-- START BodyContentHDD //-->       
-                               <div id="BodyContentHDD" style="display:none;">
-                                       <iframe src="/hdd/" width="100%" height="400"/>
-                               </div>
-                               <!-- END BodyContentHDD //-->       
-                               <!-- START BodyContentDebugbox //-->       
-                               <div id="BodyContentDebugbox" style="display:none;">
-                                       
-                               </div>
-                               <!-- END BodyContentDebugbox //-->       
-                               <!-- START BodyEPGPanel //-->       
-                               <div id="BodyEPGPanel" style="display:none;">
-                                       
-                               </div>
-                               <!-- END BodyEPGPanel //-->       
-                                                                                       
-                               <!-- END CHANNELLIST //-->       
-               <!-- END BODY MAIN //-->                                
-               </td>
-       </tr>
-       </table>
-<!-- END SITE BODY //-->
-</td></tr>
-</table>
-
-
-<script type="text/javascript" >
-// HTML Effekts by wwwopenrico.org
-new Rico.Effect.Round('div','roundme' );
-new Rico.Effect.Round('div','button' );
-new Rico.Accordion( $('accordionMenue') );
-//
-getVolume();
-loadRootTVBouqet();
-//loadRootRadioBouqet();
-setBodyMainContent('BodyContentChannellist');
-function updatePage()
-{
-} 
-
-function imdb()
-{
-       w = window.open("http://www.imdb.com/find?s=all&amp;q=" + escape(document.getElementById("Event_Now_Name").innerHTML));
-       w.focus();
-}
-
-</script>
-</body>
-&lt;div id="scriptzone">
-<!-- realtime updates follow -->
-<e2:element source="CurrentTime" streaming="yes">
-  <e2:convert type="ClockToText">WithSeconds</e2:convert>
-       <e2:convert type="web:JavascriptUpdate" />
-</e2:element>
-<e2:element source="CurrentService" streaming="yes">
-       <e2:convert type="ServiceName">Name</e2:convert>
-       <e2:convert type="web:JavascriptUpdate" />
-</e2:element>
-<e2:element source="Event_Now" id="Event_Now_Name" streaming="yes">
-       <e2:convert type="EventName">Name</e2:convert>
-       <e2:convert type="web:JavascriptUpdate" />
-</e2:element>
-<e2:element source="Event_Now" id="Event_Now_Description" streaming="yes">
-       <e2:convert type="EventName">Description</e2:convert>
-       <e2:convert type="web:JavascriptUpdate" />
-</e2:element>
-<e2:element source="Event_Now" id="Event_Now_Extended_Description" streaming="yes">
-       <e2:convert type="EventName">ExtendedDescription</e2:convert>
-       <e2:convert type="web:JavascriptUpdate" />
-</e2:element>
-<e2:element source="Event_Now" id="Event_Now_Begin" streaming="yes">
-       <e2:convert type="EventTime">StartTime</e2:convert>
-  <e2:convert type="ClockToText">Default</e2:convert>
-       <e2:convert type="web:JavascriptUpdate" />
-</e2:element>
-<e2:element source="Event_Now" id="Event_Now_End" streaming="yes">
-       <e2:convert type="EventTime">EndTime</e2:convert>
-  <e2:convert type="ClockToText">Default</e2:convert>
-       <e2:convert type="web:JavascriptUpdate" />
-</e2:element>
-<e2:element source="Event_Now" id="Event_Now_Remaining" streaming="yes">
-       <e2:convert type="EventTime">Remaining</e2:convert>
-       <e2:convert type="RemainingToText">InMinutes</e2:convert>
-       <e2:convert type="web:JavascriptUpdate" />
-</e2:element>
-
-
-<e2:element source="Event_Next" id="Event_Next_Name" streaming="yes">
-  <e2:convert type="EventName">Name</e2:convert>
-  <e2:convert type="web:JavascriptUpdate" />
-</e2:element>
-<e2:element source="Event_Next" id="Event_Next_Begin" streaming="yes">
-       <e2:convert type="EventTime">StartTime</e2:convert>
-       <e2:convert type="ClockToText">Default</e2:convert>
-       <e2:convert type="web:JavascriptUpdate" />
-</e2:element>
-<e2:element source="Event_Next" id="Event_Next_End" streaming="yes">
-       <e2:convert type="EventTime">EndTime</e2:convert>
-  <e2:convert type="ClockToText">Default</e2:convert>
-       <e2:convert type="web:JavascriptUpdate" />
-</e2:element>
-<e2:element source="Event_Next" id="Event_Next_Remaining" streaming="yes">
-  <e2:convert type="EventTime">Remaining</e2:convert>
-  <e2:convert type="RemainingToText">InMinutes</e2:convert>
-  <e2:convert type="web:JavascriptUpdate" />
-</e2:element>
-<e2:element source="Event_Next" id="Event_Next_Extended_Description" streaming="yes">
-       <e2:convert type="EventName">ExtendedDescription</e2:convert>
-       <e2:convert type="web:JavascriptUpdate" />
-</e2:element>
-
-
-<e2:element source="FrontendStatus"  id="SNR" streaming="yes">
-       <e2:convert type="FrontendInfo">SNR</e2:convert>
-       <e2:convert type="web:JavascriptUpdate" />
-</e2:element>
-<e2:element source="FrontendStatus"  id="BER" streaming="yes">
-       <e2:convert type="FrontendInfo">BER</e2:convert>
-       <e2:convert type="web:JavascriptUpdate" />
-</e2:element>
-<e2:element source="FrontendStatus"  id="AGC" streaming="yes">
-       <e2:convert type="FrontendInfo">AGC</e2:convert>
-       <e2:convert type="web:JavascriptUpdate" />
-</e2:element>
-
-
-<e2:element source="CurrentService" id="CurrentServiceProvider" streaming="yes">
-       <e2:convert type="ServiceName">Provider</e2:convert>
-        <e2:convert type="web:JavascriptUpdate" />
-</e2:element>
-                
-                
-
-</e2:screen>
diff --git a/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web/stream.m3u.xml b/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web/stream.m3u.xml
deleted file mode 100644 (file)
index 2aa4957..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-<e2:screen name="StreamingM3U">#EXTM3U
-#EXTVLCOPT--http-reconnect=true
-http://<e2:element source="localip" />:8001/<e2:element source="ref"><e2:convert type="web:TextToHTML" /></e2:element>
-</e2:screen>
diff --git a/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web/stream.xml b/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web/stream.xml
deleted file mode 100644 (file)
index c0a3d1a..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-<e2:screen name="Streaming"><e2:element source="StreamService" streaming="yes">
-<e2:convert type="Streaming" />
-<e2:convert type="web:TextToHTML" />
-</e2:element></e2:screen>
diff --git a/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web/timerlist.xml b/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web/timerlist.xml
deleted file mode 100644 (file)
index a579e12..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-<e2:screen name="TestScreen">&lt;?xml version="1.0" encoding="utf-8"?>
-&lt;e2timerlist><e2:element source="TimerList" ><e2:convert type="web:ListFiller" >
-       &lt;e2timer>
-               &lt;e2servicereference><e2:item name="ServiceReference" />&lt;/e2servicereference>
-               &lt;e2servicename><e2:item name="ServiceName" />&lt;/e2servicename>
-               &lt;e2eit><e2:item name="EIT" />&lt;/e2eit>
-               &lt;e2name><e2:item name="Name" />&lt;/e2name>
-               &lt;e2description><e2:item name="Description" />&lt;/e2description>
-               &lt;e2disabled><e2:item name="Disabled" />&lt;/e2disabled>
-               &lt;e2timebegin><e2:item name="TimeBegin" />&lt;/e2timebegin>
-               &lt;e2timeend><e2:item name="TimeEnd" />&lt;/e2timeend>
-               &lt;e2duration><e2:item name="Duration" />&lt;/e2duration>
-               &lt;e2startprepare><e2:item name="startPrepare" />&lt;/e2startprepare>
-               &lt;e2justplay><e2:item name="justPlay" />&lt;/e2justplay>
-               &lt;e2afterevent><e2:item name="afterEvent" />&lt;/e2afterevent>
-               &lt;e2logentries><e2:item name="LogEntries" />&lt;/e2logentries>
-               &lt;e2filename><e2:item name="Filename" />&lt;/e2filename>
-               &lt;e2backoff><e2:item name="Backoff" />&lt;/e2backoff>
-               &lt;e2nextactivation><e2:item name="nextActivation" />&lt;/e2nextactivation>
-               &lt;e2firsttryprepare><e2:item name="firstTryPrepare" />&lt;/e2firsttryprepare>
-               &lt;e2state><e2:item name="State" />&lt;/e2state>
-               &lt;e2repeated><e2:item name="Repeated" />&lt;/e2repeated>
-               &lt;e2dontsave><e2:item name="dontSave" />&lt;/e2dontsave>
-               &lt;e2cancled><e2:item name="Cancled" />&lt;/e2cancled>
-       &lt;/e2timer>
-       </e2:convert>
-       <e2:convert type="web:TextToHTML" /></e2:element>
-&lt;/e2timerlist>
-</e2:screen>
\ No newline at end of file
diff --git a/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web/vol.xml b/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web/vol.xml
deleted file mode 100644 (file)
index fb8d463..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-<e2:screen name="TestScreen">
-<e2:element source="Volume" id="set">
-<e2:convert type="VolumeToText">CurrentVolume</e2:convert>
-</e2:element>
-</e2:screen>
diff --git a/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web/zap.xml b/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web/zap.xml
deleted file mode 100644 (file)
index 5739cd9..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-<e2:screen name="TestScreen"><e2:element source="ServiceList" id="ZapTo">
-       <e2:convert type="web:Null" />
-</e2:element></e2:screen>
diff --git a/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/webif.py b/webinterface/src/usr/lib/enigma2/python/Plugins/Extensions/WebInterface/webif.py
deleted file mode 100644 (file)
index 57b8395..0000000
+++ /dev/null
@@ -1,371 +0,0 @@
-#
-# OK, this is more than a proof of concept
-# things to improve:
-#  - nicer code
-#  - screens need to be defined somehow else. 
-#    I don't know how, yet. Probably each in an own file.
-#  - more components, like the channellist
-#  - better error handling
-#  - use namespace parser
-
-from Screens.Screen import Screen
-from Tools.Import import my_import
-
-# for our testscreen
-from Screens.InfoBarGenerics import InfoBarServiceName, InfoBarEvent, InfoBarTuner
-
-from Components.Sources.Clock import Clock
-from Components.Sources.ServiceList import ServiceList
-from Components.Sources.Volume import Volume
-from Components.Sources.EPG import EPG
-from Components.Sources.Timer import Timer
-from Components.Sources.FrontendStatus import FrontendStatus
-
-from Components.Converter.Converter import Converter
-from Components.Converter.VolumeToText import VolumeToText 
-
-from Components.Element import Element
-
-from xml.sax import make_parser
-from xml.sax.handler import ContentHandler, feature_namespaces
-from twisted.python import util
-import sys
-import time
-# prototype of the new web frontend template system.
-
-class WebScreen(Screen):
-       def __init__(self, session):
-               Screen.__init__(self, session)
-               self.stand_alone = True
-
-# a test screen
-class TestScreen(InfoBarServiceName, InfoBarEvent,InfoBarTuner, WebScreen,Volume):
-       def __init__(self, session):
-               WebScreen.__init__(self, session)
-               InfoBarServiceName.__init__(self)
-               InfoBarEvent.__init__(self)
-               InfoBarTuner.__init__(self)
-               Volume.__init__(self,session);
-               self["CurrentTime"] = Clock()
-#              self["TVSystem"] = Config(config.av.tvsystem)
-#              self["OSDLanguage"] = Config(config.osd.language)
-#              self["FirstRun"] = Config(config.misc.firstrun)
-               from enigma import eServiceReference
-               fav = eServiceReference('1:7:1:0:0:0:0:0:0:0:(type == 1) || (type == 17) || (type == 195) || (type == 25) FROM BOUQUET "bouquets.tv" ORDER BY bouquet')
-               self["ServiceList"] = ServiceList(fav, command_func = self.zapTo, validate_commands=False)
-               self["ServiceListBrowse"] = ServiceList(fav, command_func = self.browseTo)
-               self["Volume"] = Volume(session)
-               self["EPGTITLE"] = EPG(session,func=EPG.TITLE)
-               self["EPGSERVICE"] = EPG(session,func=EPG.SERVICE)
-               self["EPGNOWNEXT"] = EPG(session,func=EPG.NOWNEXT)
-               self["TimerList"] = Timer(session)
-
-       def browseTo(self, reftobrowse):
-               self["ServiceListBrowse"].root = reftobrowse
-
-       def zapTo(self, reftozap):
-               self.session.nav.playService(reftozap)
-
-# TODO: (really.) put screens into own files.
-class Streaming(WebScreen):
-       def __init__(self, session):
-               WebScreen.__init__(self, session)
-               from Components.Sources.StreamService import StreamService
-               self["StreamService"] = StreamService(self.session.nav)
-
-class StreamingM3U(WebScreen):
-       def __init__(self, session):
-               WebScreen.__init__(self, session)
-               from Components.Sources.StaticText import StaticText
-               from Components.Sources.Config import Config
-               from Components.config import config
-               
-               self["ref"] = StaticText()
-               self["localip"] = Config(config.network.ip)
-
-# implements the 'render'-call.
-# this will act as a downstream_element, like a renderer.
-class OneTimeElement(Element):
-       def __init__(self, id):
-               Element.__init__(self)
-               self.source_id = id
-
-       # CHECKME: is this ok performance-wise?
-       def handleCommand(self, args):
-               for c in args.get(self.source_id, []):
-                       self.source.handleCommand(c)
-
-       def render(self, stream):
-               t = self.source.getHTML(self.source_id)
-               if isinstance(t, unicode):
-                       t = t.encode("utf-8")
-               stream.write(t)
-
-       def execBegin(self):
-               pass
-       
-       def execEnd(self):
-               pass
-       
-       def onShow(self):
-               pass
-
-       def onHide(self):
-               pass
-       
-       def destroy(self):
-               pass
-
-class StreamingElement(OneTimeElement):
-       def __init__(self, id):
-               OneTimeElement.__init__(self, id)
-               self.stream = None
-
-       def changed(self, what):
-               if self.stream:
-                       self.render(self.stream)
-
-       def setStream(self, stream):
-               self.stream = stream
-
-# a to-be-filled list item
-class ListItem:
-       def __init__(self, name):
-               self.name = name
-
-class TextToHTML(Converter):
-       def __init__(self, arg):
-               Converter.__init__(self, arg)
-
-       def getHTML(self, id):
-               return self.source.text # encode & etc. here!
-
-# a null-output. Useful if you only want to issue a command.
-class Null(Converter):
-       def __init__(self, arg):
-               Converter.__init__(self, arg)
-
-       def getHTML(self, id):
-               return ""
-
-def escape(s):
-       return s.replace("\\", "\\\\").replace("\n", "\\n").replace('"', '\\"')
-
-class JavascriptUpdate(Converter):
-       def __init__(self, arg):
-               Converter.__init__(self, arg)
-
-       def getHTML(self, id):
-               return '<script>set("' + id + '", "' + escape(self.source.text) + '");</script>\n'
-
-# the performant 'listfiller'-engine (plfe)
-class ListFiller(Converter):
-       def __init__(self, arg):
-               Converter.__init__(self, arg)
-
-       def getText(self):
-               l = self.source.list
-               lut = self.source.lut
-               
-               # now build a ["string", 1, "string", 2]-styled list, with indices into the 
-               # list to avoid lookup of item name for each entry
-               lutlist = []
-               for element in self.converter_arguments:
-                       if isinstance(element, str):
-                               lutlist.append(element)
-                       elif isinstance(element, ListItem):
-                               lutlist.append(lut[element.name])
-               
-               # now, for the huge list, do:
-               res = ""
-               for item in l:
-                       for element in lutlist:
-                               if isinstance(element, str):
-                                       res += element
-                               else:
-                                       res += str(item[element])
-               # (this will be done in c++ later!)
-               return res
-               
-       text = property(getText)
-
-class webifHandler(ContentHandler):
-       def __init__(self, session):
-               self.res = [ ]
-               self.mode = 0
-               self.screen = None
-               self.session = session
-               self.screens = [ ]
-       
-       def startElement(self, name, attrs):
-               if name == "e2:screen":
-                       self.screen = eval(attrs["name"])(self.session) # fixme
-                       self.screens.append(self.screen)
-                       return
-       
-               if name[:3] == "e2:":
-                       self.mode += 1
-               
-               tag = "<" + name + ''.join([' ' + key + '="' + val + '"' for (key, val) in attrs.items()]) + ">"
-               tag = tag.encode("UTF-8")
-               
-               if self.mode == 0:
-                       self.res.append(tag)
-               elif self.mode == 1: # expect "<e2:element>"
-                       assert name == "e2:element", "found %s instead of e2:element" % name
-                       source = attrs["source"]
-                       self.source_id = str(attrs.get("id", source))
-                       self.source = self.screen[source]
-                       self.is_streaming = "streaming" in attrs
-               elif self.mode == 2: # expect "<e2:convert>"
-                       if name[:3] == "e2:":
-                               assert name == "e2:convert"
-                               
-                               ctype = attrs["type"]
-                               if ctype[:4] == "web:": # for now
-                                       self.converter = eval(ctype[4:])
-                               else:
-                                       self.converter = my_import('.'.join(["Components", "Converter", ctype])).__dict__.get(ctype)
-                               self.sub = [ ]
-                       else:
-                               self.sub.append(tag)
-               elif self.mode == 3:
-                       assert name == "e2:item", "found %s instead of e2:item!" % name
-                       assert "name" in attrs, "e2:item must have a name= attribute!"
-                       self.sub.append(ListItem(attrs["name"]))
-
-       def endElement(self, name):
-               if name == "e2:screen":
-                       self.screen = None
-                       return
-
-               tag = "</" + name + ">"
-               if self.mode == 0:
-                       self.res.append(tag)
-               elif self.mode == 2 and name[:3] != "e2:":
-                       self.sub.append(tag)
-               elif self.mode == 2: # closed 'convert' -> sub
-                       self.sub = lreduce(self.sub)
-                       if len(self.sub) == 1:
-                               self.sub = self.sub[0]
-                       c = self.converter(self.sub)
-                       c.connect(self.source)
-                       self.source = c
-                       
-                       del self.sub
-               elif self.mode == 1: # closed 'element'
-                       # instatiate either a StreamingElement or a OneTimeElement, depending on what's required.
-                       if not self.is_streaming:
-                               c = OneTimeElement(self.source_id)
-                       else:
-                               c = StreamingElement(self.source_id)
-                       
-                       c.connect(self.source)
-                       self.res.append(c)
-                       self.screen.renderer.append(c)
-                       del self.source
-
-               if name[:3] == "e2:":
-                       self.mode -= 1
-
-       def processingInstruction(self, target, data):
-               self.res.append('<?' + target + ' ' + data + '>')
-       
-       def characters(self, ch):
-               ch = ch.encode("UTF-8")
-               if self.mode == 0:
-                       self.res.append(ch)
-               elif self.mode == 2:
-                       self.sub.append(ch)
-       
-       def startEntity(self, name):
-               self.res.append('&' + name + ';');
-
-       def execBegin(self):
-               for screen in self.screens:
-                       screen.execBegin()
-
-       def cleanup(self):
-               print "screen cleanup!"
-               for screen in self.screens:
-                       screen.execEnd()
-                       screen.doClose()
-               self.screens = [ ]
-
-def lreduce(list):
-       # ouch, can be made better
-       res = [ ]
-       string = None
-       for x in list:
-               if isinstance(x, str) or isinstance(x, unicode):
-                       if isinstance(x, unicode):
-                               x = x.encode("UTF-8")
-                       if string is None:
-                               string = x
-                       else:
-                               string += x
-               else:
-                       if string is not None:
-                               res.append(string)
-                               string = None
-                       res.append(x)
-       if string is not None:
-               res.append(string)
-               string = None
-       return res
-
-def renderPage(stream, path, req, session):
-       
-       # read in the template, create required screens
-       # we don't have persistense yet.
-       # if we had, this first part would only be done once.
-       handler = webifHandler(session)
-       parser = make_parser()
-       parser.setFeature(feature_namespaces, 0)
-       parser.setContentHandler(handler)
-       parser.parse(open(util.sibpath(__file__, path)))
-       
-       # by default, we have non-streaming pages
-       finish = True
-       
-       # first, apply "commands" (aka. URL argument)
-       for x in handler.res:
-               if isinstance(x, Element):
-                       x.handleCommand(req.args)
-
-       handler.execBegin()
-
-       # now, we have a list with static texts mixed
-       # with non-static Elements.
-       # flatten this list, write into the stream.
-       for x in lreduce(handler.res):
-               if isinstance(x, Element):
-                       if isinstance(x, StreamingElement):
-                               finish = False
-                               x.setStream(stream)
-                       x.render(stream)
-               else:
-                       stream.write(str(x))
-
-       def ping(s):
-               from twisted.internet import reactor
-               s.write("\n");
-               reactor.callLater(3, ping, s)
-
-       # if we met a "StreamingElement", there is at least one
-       # element which wants to output data more than once,
-       # i.e. on host-originated changes.
-       # in this case, don't finish yet, don't cleanup yet,
-       # but instead do that when the client disconnects.
-       if finish:
-               handler.cleanup()
-               stream.finish()
-       else:
-               # ok.
-               # you *need* something which constantly sends something in a regular interval,
-               # in order to detect disconnected clients.
-               # i agree that this "ping" sucks terrible, so better be sure to have something 
-               # similar. A "CurrentTime" is fine. Or anything that creates *some* output.
-               ping(stream)
-               stream.closed_callback = lambda: handler.cleanup()
diff --git a/webinterface/src/web-data/Makefile.am b/webinterface/src/web-data/Makefile.am
new file mode 100644 (file)
index 0000000..0c9d9e1
--- /dev/null
@@ -0,0 +1,5 @@
+installdir = /usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web-data/
+
+install_DATA = *.js
+
+SUBDIRS = gfx
diff --git a/webinterface/src/web-data/gfx/Makefile.am b/webinterface/src/web-data/gfx/Makefile.am
new file mode 100644 (file)
index 0000000..9d21b33
--- /dev/null
@@ -0,0 +1,3 @@
+installdir = /usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web-data/gfx/
+
+install_DATA = *.png
diff --git a/webinterface/src/web-data/gfx/led_off.png b/webinterface/src/web-data/gfx/led_off.png
new file mode 100644 (file)
index 0000000..69ca2cd
Binary files /dev/null and b/webinterface/src/web-data/gfx/led_off.png differ
diff --git a/webinterface/src/web-data/gfx/led_on.png b/webinterface/src/web-data/gfx/led_on.png
new file mode 100644 (file)
index 0000000..3d3d29d
Binary files /dev/null and b/webinterface/src/web-data/gfx/led_on.png differ
diff --git a/webinterface/src/web-data/gfx/speak_off.png b/webinterface/src/web-data/gfx/speak_off.png
new file mode 100644 (file)
index 0000000..8823ac3
Binary files /dev/null and b/webinterface/src/web-data/gfx/speak_off.png differ
diff --git a/webinterface/src/web-data/gfx/speak_on.png b/webinterface/src/web-data/gfx/speak_on.png
new file mode 100644 (file)
index 0000000..5ded98c
Binary files /dev/null and b/webinterface/src/web-data/gfx/speak_on.png differ
diff --git a/webinterface/src/web-data/prototype.js b/webinterface/src/web-data/prototype.js
new file mode 100644 (file)
index 0000000..0e85338
--- /dev/null
@@ -0,0 +1,1781 @@
+/*  Prototype JavaScript framework, version 1.4.0
+ *  (c) 2005 Sam Stephenson <sam@conio.net>
+ *
+ *  Prototype is freely distributable under the terms of an MIT-style license.
+ *  For details, see the Prototype web site: http://prototype.conio.net/
+ *
+/*--------------------------------------------------------------------------*/
+
+var Prototype = {
+  Version: '1.4.0',
+  ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
+
+  emptyFunction: function() {},
+  K: function(x) {return x}
+}
+
+var Class = {
+  create: function() {
+    return function() {
+      this.initialize.apply(this, arguments);
+    }
+  }
+}
+
+var Abstract = new Object();
+
+Object.extend = function(destination, source) {
+  for (property in source) {
+    destination[property] = source[property];
+  }
+  return destination;
+}
+
+Object.inspect = function(object) {
+  try {
+    if (object == undefined) return 'undefined';
+    if (object == null) return 'null';
+    return object.inspect ? object.inspect() : object.toString();
+  } catch (e) {
+    if (e instanceof RangeError) return '...';
+    throw e;
+  }
+}
+
+Function.prototype.bind = function() {
+  var __method = this, args = $A(arguments), object = args.shift();
+  return function() {
+    return __method.apply(object, args.concat($A(arguments)));
+  }
+}
+
+Function.prototype.bindAsEventListener = function(object) {
+  var __method = this;
+  return function(event) {
+    return __method.call(object, event || window.event);
+  }
+}
+
+Object.extend(Number.prototype, {
+  toColorPart: function() {
+    var digits = this.toString(16);
+    if (this < 16) return '0' + digits;
+    return digits;
+  },
+
+  succ: function() {
+    return this + 1;
+  },
+
+  times: function(iterator) {
+    $R(0, this, true).each(iterator);
+    return this;
+  }
+});
+
+var Try = {
+  these: function() {
+    var returnValue;
+
+    for (var i = 0; i < arguments.length; i++) {
+      var lambda = arguments[i];
+      try {
+        returnValue = lambda();
+        break;
+      } catch (e) {}
+    }
+
+    return returnValue;
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var PeriodicalExecuter = Class.create();
+PeriodicalExecuter.prototype = {
+  initialize: function(callback, frequency) {
+    this.callback = callback;
+    this.frequency = frequency;
+    this.currentlyExecuting = false;
+
+    this.registerCallback();
+  },
+
+  registerCallback: function() {
+    setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
+  },
+
+  onTimerEvent: function() {
+    if (!this.currentlyExecuting) {
+      try {
+        this.currentlyExecuting = true;
+        this.callback();
+      } finally {
+        this.currentlyExecuting = false;
+      }
+    }
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+
+function $() {
+  var elements = new Array();
+
+  for (var i = 0; i < arguments.length; i++) {
+    var element = arguments[i];
+    if (typeof element == 'string')
+      element = document.getElementById(element);
+
+    if (arguments.length == 1)
+      return element;
+
+    elements.push(element);
+  }
+
+  return elements;
+}
+Object.extend(String.prototype, {
+  stripTags: function() {
+    return this.replace(/<\/?[^>]+>/gi, '');
+  },
+
+  stripScripts: function() {
+    return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
+  },
+
+  extractScripts: function() {
+    var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
+    var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
+    return (this.match(matchAll) || []).map(function(scriptTag) {
+      return (scriptTag.match(matchOne) || ['', ''])[1];
+    });
+  },
+
+  evalScripts: function() {
+    return this.extractScripts().map(eval);
+  },
+
+  escapeHTML: function() {
+    var div = document.createElement('div');
+    var text = document.createTextNode(this);
+    div.appendChild(text);
+    return div.innerHTML;
+  },
+
+  unescapeHTML: function() {
+    var div = document.createElement('div');
+    div.innerHTML = this.stripTags();
+    return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
+  },
+
+  toQueryParams: function() {
+    var pairs = this.match(/^\??(.*)$/)[1].split('&');
+    return pairs.inject({}, function(params, pairString) {
+      var pair = pairString.split('=');
+      params[pair[0]] = pair[1];
+      return params;
+    });
+  },
+
+  toArray: function() {
+    return this.split('');
+  },
+
+  camelize: function() {
+    var oStringList = this.split('-');
+    if (oStringList.length == 1) return oStringList[0];
+
+    var camelizedString = this.indexOf('-') == 0
+      ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
+      : oStringList[0];
+
+    for (var i = 1, len = oStringList.length; i < len; i++) {
+      var s = oStringList[i];
+      camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
+    }
+
+    return camelizedString;
+  },
+
+  inspect: function() {
+    return "'" + this.replace('\\', '\\\\').replace("'", '\\\'') + "'";
+  }
+});
+
+String.prototype.parseQuery = String.prototype.toQueryParams;
+
+var $break    = new Object();
+var $continue = new Object();
+
+var Enumerable = {
+  each: function(iterator) {
+    var index = 0;
+    try {
+      this._each(function(value) {
+        try {
+          iterator(value, index++);
+        } catch (e) {
+          if (e != $continue) throw e;
+        }
+      });
+    } catch (e) {
+      if (e != $break) throw e;
+    }
+  },
+
+  all: function(iterator) {
+    var result = true;
+    this.each(function(value, index) {
+      result = result && !!(iterator || Prototype.K)(value, index);
+      if (!result) throw $break;
+    });
+    return result;
+  },
+
+  any: function(iterator) {
+    var result = true;
+    this.each(function(value, index) {
+      if (result = !!(iterator || Prototype.K)(value, index))
+        throw $break;
+    });
+    return result;
+  },
+
+  collect: function(iterator) {
+    var results = [];
+    this.each(function(value, index) {
+      results.push(iterator(value, index));
+    });
+    return results;
+  },
+
+  detect: function (iterator) {
+    var result;
+    this.each(function(value, index) {
+      if (iterator(value, index)) {
+        result = value;
+        throw $break;
+      }
+    });
+    return result;
+  },
+
+  findAll: function(iterator) {
+    var results = [];
+    this.each(function(value, index) {
+      if (iterator(value, index))
+        results.push(value);
+    });
+    return results;
+  },
+
+  grep: function(pattern, iterator) {
+    var results = [];
+    this.each(function(value, index) {
+      var stringValue = value.toString();
+      if (stringValue.match(pattern))
+        results.push((iterator || Prototype.K)(value, index));
+    })
+    return results;
+  },
+
+  include: function(object) {
+    var found = false;
+    this.each(function(value) {
+      if (value == object) {
+        found = true;
+        throw $break;
+      }
+    });
+    return found;
+  },
+
+  inject: function(memo, iterator) {
+    this.each(function(value, index) {
+      memo = iterator(memo, value, index);
+    });
+    return memo;
+  },
+
+  invoke: function(method) {
+    var args = $A(arguments).slice(1);
+    return this.collect(function(value) {
+      return value[method].apply(value, args);
+    });
+  },
+
+  max: function(iterator) {
+    var result;
+    this.each(function(value, index) {
+      value = (iterator || Prototype.K)(value, index);
+      if (value >= (result || value))
+        result = value;
+    });
+    return result;
+  },
+
+  min: function(iterator) {
+    var result;
+    this.each(function(value, index) {
+      value = (iterator || Prototype.K)(value, index);
+      if (value <= (result || value))
+        result = value;
+    });
+    return result;
+  },
+
+  partition: function(iterator) {
+    var trues = [], falses = [];
+    this.each(function(value, index) {
+      ((iterator || Prototype.K)(value, index) ?
+        trues : falses).push(value);
+    });
+    return [trues, falses];
+  },
+
+  pluck: function(property) {
+    var results = [];
+    this.each(function(value, index) {
+      results.push(value[property]);
+    });
+    return results;
+  },
+
+  reject: function(iterator) {
+    var results = [];
+    this.each(function(value, index) {
+      if (!iterator(value, index))
+        results.push(value);
+    });
+    return results;
+  },
+
+  sortBy: function(iterator) {
+    return this.collect(function(value, index) {
+      return {value: value, criteria: iterator(value, index)};
+    }).sort(function(left, right) {
+      var a = left.criteria, b = right.criteria;
+      return a < b ? -1 : a > b ? 1 : 0;
+    }).pluck('value');
+  },
+
+  toArray: function() {
+    return this.collect(Prototype.K);
+  },
+
+  zip: function() {
+    var iterator = Prototype.K, args = $A(arguments);
+    if (typeof args.last() == 'function')
+      iterator = args.pop();
+
+    var collections = [this].concat(args).map($A);
+    return this.map(function(value, index) {
+      iterator(value = collections.pluck(index));
+      return value;
+    });
+  },
+
+  inspect: function() {
+    return '#<Enumerable:' + this.toArray().inspect() + '>';
+  }
+}
+
+Object.extend(Enumerable, {
+  map:     Enumerable.collect,
+  find:    Enumerable.detect,
+  select:  Enumerable.findAll,
+  member:  Enumerable.include,
+  entries: Enumerable.toArray
+});
+var $A = Array.from = function(iterable) {
+  if (!iterable) return [];
+  if (iterable.toArray) {
+    return iterable.toArray();
+  } else {
+    var results = [];
+    for (var i = 0; i < iterable.length; i++)
+      results.push(iterable[i]);
+    return results;
+  }
+}
+
+Object.extend(Array.prototype, Enumerable);
+
+Array.prototype._reverse = Array.prototype.reverse;
+
+Object.extend(Array.prototype, {
+  _each: function(iterator) {
+    for (var i = 0; i < this.length; i++)
+      iterator(this[i]);
+  },
+
+  clear: function() {
+    this.length = 0;
+    return this;
+  },
+
+  first: function() {
+    return this[0];
+  },
+
+  last: function() {
+    return this[this.length - 1];
+  },
+
+  compact: function() {
+    return this.select(function(value) {
+      return value != undefined || value != null;
+    });
+  },
+
+  flatten: function() {
+    return this.inject([], function(array, value) {
+      return array.concat(value.constructor == Array ?
+        value.flatten() : [value]);
+    });
+  },
+
+  without: function() {
+    var values = $A(arguments);
+    return this.select(function(value) {
+      return !values.include(value);
+    });
+  },
+
+  indexOf: function(object) {
+    for (var i = 0; i < this.length; i++)
+      if (this[i] == object) return i;
+    return -1;
+  },
+
+  reverse: function(inline) {
+    return (inline !== false ? this : this.toArray())._reverse();
+  },
+
+  shift: function() {
+    var result = this[0];
+    for (var i = 0; i < this.length - 1; i++)
+      this[i] = this[i + 1];
+    this.length--;
+    return result;
+  },
+
+  inspect: function() {
+    return '[' + this.map(Object.inspect).join(', ') + ']';
+  }
+});
+var Hash = {
+  _each: function(iterator) {
+    for (key in this) {
+      var value = this[key];
+      if (typeof value == 'function') continue;
+
+      var pair = [key, value];
+      pair.key = key;
+      pair.value = value;
+      iterator(pair);
+    }
+  },
+
+  keys: function() {
+    return this.pluck('key');
+  },
+
+  values: function() {
+    return this.pluck('value');
+  },
+
+  merge: function(hash) {
+    return $H(hash).inject($H(this), function(mergedHash, pair) {
+      mergedHash[pair.key] = pair.value;
+      return mergedHash;
+    });
+  },
+
+  toQueryString: function() {
+    return this.map(function(pair) {
+      return pair.map(encodeURIComponent).join('=');
+    }).join('&');
+  },
+
+  inspect: function() {
+    return '#<Hash:{' + this.map(function(pair) {
+      return pair.map(Object.inspect).join(': ');
+    }).join(', ') + '}>';
+  }
+}
+
+function $H(object) {
+  var hash = Object.extend({}, object || {});
+  Object.extend(hash, Enumerable);
+  Object.extend(hash, Hash);
+  return hash;
+}
+ObjectRange = Class.create();
+Object.extend(ObjectRange.prototype, Enumerable);
+Object.extend(ObjectRange.prototype, {
+  initialize: function(start, end, exclusive) {
+    this.start = start;
+    this.end = end;
+    this.exclusive = exclusive;
+  },
+
+  _each: function(iterator) {
+    var value = this.start;
+    do {
+      iterator(value);
+      value = value.succ();
+    } while (this.include(value));
+  },
+
+  include: function(value) {
+    if (value < this.start)
+      return false;
+    if (this.exclusive)
+      return value < this.end;
+    return value <= this.end;
+  }
+});
+
+var $R = function(start, end, exclusive) {
+  return new ObjectRange(start, end, exclusive);
+}
+
+var Ajax = {
+  getTransport: function() {
+    return Try.these(
+      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
+      function() {return new ActiveXObject('Microsoft.XMLHTTP')},
+      function() {return new XMLHttpRequest()}
+    ) || false;
+  },
+
+  activeRequestCount: 0
+}
+
+Ajax.Responders = {
+  responders: [],
+
+  _each: function(iterator) {
+    this.responders._each(iterator);
+  },
+
+  register: function(responderToAdd) {
+    if (!this.include(responderToAdd))
+      this.responders.push(responderToAdd);
+  },
+
+  unregister: function(responderToRemove) {
+    this.responders = this.responders.without(responderToRemove);
+  },
+
+  dispatch: function(callback, request, transport, json) {
+    this.each(function(responder) {
+      if (responder[callback] && typeof responder[callback] == 'function') {
+        try {
+          responder[callback].apply(responder, [request, transport, json]);
+        } catch (e) {}
+      }
+    });
+  }
+};
+
+Object.extend(Ajax.Responders, Enumerable);
+
+Ajax.Responders.register({
+  onCreate: function() {
+    Ajax.activeRequestCount++;
+  },
+
+  onComplete: function() {
+    Ajax.activeRequestCount--;
+  }
+});
+
+Ajax.Base = function() {};
+Ajax.Base.prototype = {
+  setOptions: function(options) {
+    this.options = {
+      method:       'post',
+      asynchronous: true,
+      parameters:   ''
+    }
+    Object.extend(this.options, options || {});
+  },
+
+  responseIsSuccess: function() {
+    return this.transport.status == undefined
+        || this.transport.status == 0
+        || (this.transport.status >= 200 && this.transport.status < 300);
+  },
+
+  responseIsFailure: function() {
+    return !this.responseIsSuccess();
+  }
+}
+
+Ajax.Request = Class.create();
+Ajax.Request.Events =
+  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
+
+Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
+  initialize: function(url, options) {
+    this.transport = Ajax.getTransport();
+    this.setOptions(options);
+    this.request(url);
+  },
+
+  request: function(url) {
+    var parameters = this.options.parameters || '';
+    if (parameters.length > 0) parameters += '&_=';
+
+    try {
+      this.url = url;
+      if (this.options.method == 'get' && parameters.length > 0)
+        this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;
+
+      Ajax.Responders.dispatch('onCreate', this, this.transport);
+
+      this.transport.open(this.options.method, this.url,
+        this.options.asynchronous);
+
+      if (this.options.asynchronous) {
+        this.transport.onreadystatechange = this.onStateChange.bind(this);
+        setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10);
+      }
+
+      this.setRequestHeaders();
+
+      var body = this.options.postBody ? this.options.postBody : parameters;
+      this.transport.send(this.options.method == 'post' ? body : null);
+
+    } catch (e) {
+      this.dispatchException(e);
+    }
+  },
+
+  setRequestHeaders: function() {
+    var requestHeaders =
+      ['X-Requested-With', 'XMLHttpRequest',
+       'X-Prototype-Version', Prototype.Version];
+
+    if (this.options.method == 'post') {
+      requestHeaders.push('Content-type',
+        'application/x-www-form-urlencoded');
+
+      /* Force "Connection: close" for Mozilla browsers to work around
+       * a bug where XMLHttpReqeuest sends an incorrect Content-length
+       * header. See Mozilla Bugzilla #246651.
+       */
+      if (this.transport.overrideMimeType)
+        requestHeaders.push('Connection', 'close');
+    }
+
+    if (this.options.requestHeaders)
+      requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);
+
+    for (var i = 0; i < requestHeaders.length; i += 2)
+      this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]);
+  },
+
+  onStateChange: function() {
+    var readyState = this.transport.readyState;
+    if (readyState != 1)
+      this.respondToReadyState(this.transport.readyState);
+  },
+
+  header: function(name) {
+    try {
+      return this.transport.getResponseHeader(name);
+    } catch (e) {}
+  },
+
+  evalJSON: function() {
+    try {
+      return eval(this.header('X-JSON'));
+    } catch (e) {}
+  },
+
+  evalResponse: function() {
+    try {
+      return eval(this.transport.responseText);
+    } catch (e) {
+      this.dispatchException(e);
+    }
+  },
+
+  respondToReadyState: function(readyState) {
+    var event = Ajax.Request.Events[readyState];
+    var transport = this.transport, json = this.evalJSON();
+
+    if (event == 'Complete') {
+      try {
+        (this.options['on' + this.transport.status]
+         || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
+         || Prototype.emptyFunction)(transport, json);
+      } catch (e) {
+        this.dispatchException(e);
+      }
+
+      if ((this.header('Content-type') || '').match(/^text\/javascript/i))
+        this.evalResponse();
+    }
+
+    try {
+      (this.options['on' + event] || Prototype.emptyFunction)(transport, json);
+      Ajax.Responders.dispatch('on' + event, this, transport, json);
+    } catch (e) {
+      this.dispatchException(e);
+    }
+
+    /* Avoid memory leak in MSIE: clean up the oncomplete event handler */
+    if (event == 'Complete')
+      this.transport.onreadystatechange = Prototype.emptyFunction;
+  },
+
+  dispatchException: function(exception) {
+    (this.options.onException || Prototype.emptyFunction)(this, exception);
+    Ajax.Responders.dispatch('onException', this, exception);
+  }
+});
+
+Ajax.Updater = Class.create();
+
+Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
+  initialize: function(container, url, options) {
+    this.containers = {
+      success: container.success ? $(container.success) : $(container),
+      failure: container.failure ? $(container.failure) :
+        (container.success ? null : $(container))
+    }
+
+    this.transport = Ajax.getTransport();
+    this.setOptions(options);
+
+    var onComplete = this.options.onComplete || Prototype.emptyFunction;
+    this.options.onComplete = (function(transport, object) {
+      this.updateContent();
+      onComplete(transport, object);
+    }).bind(this);
+
+    this.request(url);
+  },
+
+  updateContent: function() {
+    var receiver = this.responseIsSuccess() ?
+      this.containers.success : this.containers.failure;
+    var response = this.transport.responseText;
+
+    if (!this.options.evalScripts)
+      response = response.stripScripts();
+
+    if (receiver) {
+      if (this.options.insertion) {
+        new this.options.insertion(receiver, response);
+      } else {
+        Element.update(receiver, response);
+      }
+    }
+
+    if (this.responseIsSuccess()) {
+      if (this.onComplete)
+        setTimeout(this.onComplete.bind(this), 10);
+    }
+  }
+});
+
+Ajax.PeriodicalUpdater = Class.create();
+Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
+  initialize: function(container, url, options) {
+    this.setOptions(options);
+    this.onComplete = this.options.onComplete;
+
+    this.frequency = (this.options.frequency || 2);
+    this.decay = (this.options.decay || 1);
+
+    this.updater = {};
+    this.container = container;
+    this.url = url;
+
+    this.start();
+  },
+
+  start: function() {
+    this.options.onComplete = this.updateComplete.bind(this);
+    this.onTimerEvent();
+  },
+
+  stop: function() {
+    this.updater.onComplete = undefined;
+    clearTimeout(this.timer);
+    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
+  },
+
+  updateComplete: function(request) {
+    if (this.options.decay) {
+      this.decay = (request.responseText == this.lastText ?
+        this.decay * this.options.decay : 1);
+
+      this.lastText = request.responseText;
+    }
+    this.timer = setTimeout(this.onTimerEvent.bind(this),
+      this.decay * this.frequency * 1000);
+  },
+
+  onTimerEvent: function() {
+    this.updater = new Ajax.Updater(this.container, this.url, this.options);
+  }
+});
+document.getElementsByClassName = function(className, parentElement) {
+  var children = ($(parentElement) || document.body).getElementsByTagName('*');
+  return $A(children).inject([], function(elements, child) {
+    if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
+      elements.push(child);
+    return elements;
+  });
+}
+
+/*--------------------------------------------------------------------------*/
+
+if (!window.Element) {
+  var Element = new Object();
+}
+
+Object.extend(Element, {
+  visible: function(element) {
+    return $(element).style.display != 'none';
+  },
+
+  toggle: function() {
+    for (var i = 0; i < arguments.length; i++) {
+      var element = $(arguments[i]);
+      Element[Element.visible(element) ? 'hide' : 'show'](element);
+    }
+  },
+
+  hide: function() {
+    for (var i = 0; i < arguments.length; i++) {
+      var element = $(arguments[i]);
+      element.style.display = 'none';
+    }
+  },
+
+  show: function() {
+    for (var i = 0; i < arguments.length; i++) {
+      var element = $(arguments[i]);
+      element.style.display = '';
+    }
+  },
+
+  remove: function(element) {
+    element = $(element);
+    element.parentNode.removeChild(element);
+  },
+
+  update: function(element, html) {
+    $(element).innerHTML = html.stripScripts();
+    setTimeout(function() {html.evalScripts()}, 10);
+  },
+
+  getHeight: function(element) {
+    element = $(element);
+    return element.offsetHeight;
+  },
+
+  classNames: function(element) {
+    return new Element.ClassNames(element);
+  },
+
+  hasClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    return Element.classNames(element).include(className);
+  },
+
+  addClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    return Element.classNames(element).add(className);
+  },
+
+  removeClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    return Element.classNames(element).remove(className);
+  },
+
+  // removes whitespace-only text node children
+  cleanWhitespace: function(element) {
+    element = $(element);
+    for (var i = 0; i < element.childNodes.length; i++) {
+      var node = element.childNodes[i];
+      if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
+        Element.remove(node);
+    }
+  },
+
+  empty: function(element) {
+    return $(element).innerHTML.match(/^\s*$/);
+  },
+
+  scrollTo: function(element) {
+    element = $(element);
+    var x = element.x ? element.x : element.offsetLeft,
+        y = element.y ? element.y : element.offsetTop;
+    window.scrollTo(x, y);
+  },
+
+  getStyle: function(element, style) {
+    element = $(element);
+    var value = element.style[style.camelize()];
+    if (!value) {
+      if (document.defaultView && document.defaultView.getComputedStyle) {
+        var css = document.defaultView.getComputedStyle(element, null);
+        value = css ? css.getPropertyValue(style) : null;
+      } else if (element.currentStyle) {
+        value = element.currentStyle[style.camelize()];
+      }
+    }
+
+    if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
+      if (Element.getStyle(element, 'position') == 'static') value = 'auto';
+
+    return value == 'auto' ? null : value;
+  },
+
+  setStyle: function(element, style) {
+    element = $(element);
+    for (name in style)
+      element.style[name.camelize()] = style[name];
+  },
+
+  getDimensions: function(element) {
+    element = $(element);
+    if (Element.getStyle(element, 'display') != 'none')
+      return {width: element.offsetWidth, height: element.offsetHeight};
+
+    // All *Width and *Height properties give 0 on elements with display none,
+    // so enable the element temporarily
+    var els = element.style;
+    var originalVisibility = els.visibility;
+    var originalPosition = els.position;
+    els.visibility = 'hidden';
+    els.position = 'absolute';
+    els.display = '';
+    var originalWidth = element.clientWidth;
+    var originalHeight = element.clientHeight;
+    els.display = 'none';
+    els.position = originalPosition;
+    els.visibility = originalVisibility;
+    return {width: originalWidth, height: originalHeight};
+  },
+
+  makePositioned: function(element) {
+    element = $(element);
+    var pos = Element.getStyle(element, 'position');
+    if (pos == 'static' || !pos) {
+      element._madePositioned = true;
+      element.style.position = 'relative';
+      // Opera returns the offset relative to the positioning context, when an
+      // element is position relative but top and left have not been defined
+      if (window.opera) {
+        element.style.top = 0;
+        element.style.left = 0;
+      }
+    }
+  },
+
+  undoPositioned: function(element) {
+    element = $(element);
+    if (element._madePositioned) {
+      element._madePositioned = undefined;
+      element.style.position =
+        element.style.top =
+        element.style.left =
+        element.style.bottom =
+        element.style.right = '';
+    }
+  },
+
+  makeClipping: function(element) {
+    element = $(element);
+    if (element._overflow) return;
+    element._overflow = element.style.overflow;
+    if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
+      element.style.overflow = 'hidden';
+  },
+
+  undoClipping: function(element) {
+    element = $(element);
+    if (element._overflow) return;
+    element.style.overflow = element._overflow;
+    element._overflow = undefined;
+  }
+});
+
+var Toggle = new Object();
+Toggle.display = Element.toggle;
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.Insertion = function(adjacency) {
+  this.adjacency = adjacency;
+}
+
+Abstract.Insertion.prototype = {
+  initialize: function(element, content) {
+    this.element = $(element);
+    this.content = content.stripScripts();
+
+    if (this.adjacency && this.element.insertAdjacentHTML) {
+      try {
+        this.element.insertAdjacentHTML(this.adjacency, this.content);
+      } catch (e) {
+        if (this.element.tagName.toLowerCase() == 'tbody') {
+          this.insertContent(this.contentFromAnonymousTable());
+        } else {
+          throw e;
+        }
+      }
+    } else {
+      this.range = this.element.ownerDocument.createRange();
+      if (this.initializeRange) this.initializeRange();
+      this.insertContent([this.range.createContextualFragment(this.content)]);
+    }
+
+    setTimeout(function() {content.evalScripts()}, 10);
+  },
+
+  contentFromAnonymousTable: function() {
+    var div = document.createElement('div');
+    div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
+    return $A(div.childNodes[0].childNodes[0].childNodes);
+  }
+}
+
+var Insertion = new Object();
+
+Insertion.Before = Class.create();
+Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
+  initializeRange: function() {
+    this.range.setStartBefore(this.element);
+  },
+
+  insertContent: function(fragments) {
+    fragments.each((function(fragment) {
+      this.element.parentNode.insertBefore(fragment, this.element);
+    }).bind(this));
+  }
+});
+
+Insertion.Top = Class.create();
+Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
+  initializeRange: function() {
+    this.range.selectNodeContents(this.element);
+    this.range.collapse(true);
+  },
+
+  insertContent: function(fragments) {
+    fragments.reverse(false).each((function(fragment) {
+      this.element.insertBefore(fragment, this.element.firstChild);
+    }).bind(this));
+  }
+});
+
+Insertion.Bottom = Class.create();
+Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
+  initializeRange: function() {
+    this.range.selectNodeContents(this.element);
+    this.range.collapse(this.element);
+  },
+
+  insertContent: function(fragments) {
+    fragments.each((function(fragment) {
+      this.element.appendChild(fragment);
+    }).bind(this));
+  }
+});
+
+Insertion.After = Class.create();
+Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
+  initializeRange: function() {
+    this.range.setStartAfter(this.element);
+  },
+
+  insertContent: function(fragments) {
+    fragments.each((function(fragment) {
+      this.element.parentNode.insertBefore(fragment,
+        this.element.nextSibling);
+    }).bind(this));
+  }
+});
+
+/*--------------------------------------------------------------------------*/
+
+Element.ClassNames = Class.create();
+Element.ClassNames.prototype = {
+  initialize: function(element) {
+    this.element = $(element);
+  },
+
+  _each: function(iterator) {
+    this.element.className.split(/\s+/).select(function(name) {
+      return name.length > 0;
+    })._each(iterator);
+  },
+
+  set: function(className) {
+    this.element.className = className;
+  },
+
+  add: function(classNameToAdd) {
+    if (this.include(classNameToAdd)) return;
+    this.set(this.toArray().concat(classNameToAdd).join(' '));
+  },
+
+  remove: function(classNameToRemove) {
+    if (!this.include(classNameToRemove)) return;
+    this.set(this.select(function(className) {
+      return className != classNameToRemove;
+    }).join(' '));
+  },
+
+  toString: function() {
+    return this.toArray().join(' ');
+  }
+}
+
+Object.extend(Element.ClassNames.prototype, Enumerable);
+var Field = {
+  clear: function() {
+    for (var i = 0; i < arguments.length; i++)
+      $(arguments[i]).value = '';
+  },
+
+  focus: function(element) {
+    $(element).focus();
+  },
+
+  present: function() {
+    for (var i = 0; i < arguments.length; i++)
+      if ($(arguments[i]).value == '') return false;
+    return true;
+  },
+
+  select: function(element) {
+    $(element).select();
+  },
+
+  activate: function(element) {
+    element = $(element);
+    element.focus();
+    if (element.select)
+      element.select();
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var Form = {
+  serialize: function(form) {
+    var elements = Form.getElements($(form));
+    var queryComponents = new Array();
+
+    for (var i = 0; i < elements.length; i++) {
+      var queryComponent = Form.Element.serialize(elements[i]);
+      if (queryComponent)
+        queryComponents.push(queryComponent);
+    }
+
+    return queryComponents.join('&');
+  },
+
+  getElements: function(form) {
+    form = $(form);
+    var elements = new Array();
+
+    for (tagName in Form.Element.Serializers) {
+      var tagElements = form.getElementsByTagName(tagName);
+      for (var j = 0; j < tagElements.length; j++)
+        elements.push(tagElements[j]);
+    }
+    return elements;
+  },
+
+  getInputs: function(form, typeName, name) {
+    form = $(form);
+    var inputs = form.getElementsByTagName('input');
+
+    if (!typeName && !name)
+      return inputs;
+
+    var matchingInputs = new Array();
+    for (var i = 0; i < inputs.length; i++) {
+      var input = inputs[i];
+      if ((typeName && input.type != typeName) ||
+          (name && input.name != name))
+        continue;
+      matchingInputs.push(input);
+    }
+
+    return matchingInputs;
+  },
+
+  disable: function(form) {
+    var elements = Form.getElements(form);
+    for (var i = 0; i < elements.length; i++) {
+      var element = elements[i];
+      element.blur();
+      element.disabled = 'true';
+    }
+  },
+
+  enable: function(form) {
+    var elements = Form.getElements(form);
+    for (var i = 0; i < elements.length; i++) {
+      var element = elements[i];
+      element.disabled = '';
+    }
+  },
+
+  findFirstElement: function(form) {
+    return Form.getElements(form).find(function(element) {
+      return element.type != 'hidden' && !element.disabled &&
+        ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
+    });
+  },
+
+  focusFirstElement: function(form) {
+    Field.activate(Form.findFirstElement(form));
+  },
+
+  reset: function(form) {
+    $(form).reset();
+  }
+}
+
+Form.Element = {
+  serialize: function(element) {
+    element = $(element);
+    var method = element.tagName.toLowerCase();
+    var parameter = Form.Element.Serializers[method](element);
+
+    if (parameter) {
+      var key = encodeURIComponent(parameter[0]);
+      if (key.length == 0) return;
+
+      if (parameter[1].constructor != Array)
+        parameter[1] = [parameter[1]];
+
+      return parameter[1].map(function(value) {
+        return key + '=' + encodeURIComponent(value);
+      }).join('&');
+    }
+  },
+
+  getValue: function(element) {
+    element = $(element);
+    var method = element.tagName.toLowerCase();
+    var parameter = Form.Element.Serializers[method](element);
+
+    if (parameter)
+      return parameter[1];
+  }
+}
+
+Form.Element.Serializers = {
+  input: function(element) {
+    switch (element.type.toLowerCase()) {
+      case 'submit':
+      case 'hidden':
+      case 'password':
+      case 'text':
+        return Form.Element.Serializers.textarea(element);
+      case 'checkbox':
+      case 'radio':
+        return Form.Element.Serializers.inputSelector(element);
+    }
+    return false;
+  },
+
+  inputSelector: function(element) {
+    if (element.checked)
+      return [element.name, element.value];
+  },
+
+  textarea: function(element) {
+    return [element.name, element.value];
+  },
+
+  select: function(element) {
+    return Form.Element.Serializers[element.type == 'select-one' ?
+      'selectOne' : 'selectMany'](element);
+  },
+
+  selectOne: function(element) {
+    var value = '', opt, index = element.selectedIndex;
+    if (index >= 0) {
+      opt = element.options[index];
+      value = opt.value;
+      if (!value && !('value' in opt))
+        value = opt.text;
+    }
+    return [element.name, value];
+  },
+
+  selectMany: function(element) {
+    var value = new Array();
+    for (var i = 0; i < element.length; i++) {
+      var opt = element.options[i];
+      if (opt.selected) {
+        var optValue = opt.value;
+        if (!optValue && !('value' in opt))
+          optValue = opt.text;
+        value.push(optValue);
+      }
+    }
+    return [element.name, value];
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var $F = Form.Element.getValue;
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.TimedObserver = function() {}
+Abstract.TimedObserver.prototype = {
+  initialize: function(element, frequency, callback) {
+    this.frequency = frequency;
+    this.element   = $(element);
+    this.callback  = callback;
+
+    this.lastValue = this.getValue();
+    this.registerCallback();
+  },
+
+  registerCallback: function() {
+    setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
+  },
+
+  onTimerEvent: function() {
+    var value = this.getValue();
+    if (this.lastValue != value) {
+      this.callback(this.element, value);
+      this.lastValue = value;
+    }
+  }
+}
+
+Form.Element.Observer = Class.create();
+Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
+  getValue: function() {
+    return Form.Element.getValue(this.element);
+  }
+});
+
+Form.Observer = Class.create();
+Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
+  getValue: function() {
+    return Form.serialize(this.element);
+  }
+});
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.EventObserver = function() {}
+Abstract.EventObserver.prototype = {
+  initialize: function(element, callback) {
+    this.element  = $(element);
+    this.callback = callback;
+
+    this.lastValue = this.getValue();
+    if (this.element.tagName.toLowerCase() == 'form')
+      this.registerFormCallbacks();
+    else
+      this.registerCallback(this.element);
+  },
+
+  onElementEvent: function() {
+    var value = this.getValue();
+    if (this.lastValue != value) {
+      this.callback(this.element, value);
+      this.lastValue = value;
+    }
+  },
+
+  registerFormCallbacks: function() {
+    var elements = Form.getElements(this.element);
+    for (var i = 0; i < elements.length; i++)
+      this.registerCallback(elements[i]);
+  },
+
+  registerCallback: function(element) {
+    if (element.type) {
+      switch (element.type.toLowerCase()) {
+        case 'checkbox':
+        case 'radio':
+          Event.observe(element, 'click', this.onElementEvent.bind(this));
+          break;
+        case 'password':
+        case 'text':
+        case 'textarea':
+        case 'select-one':
+        case 'select-multiple':
+          Event.observe(element, 'change', this.onElementEvent.bind(this));
+          break;
+      }
+    }
+  }
+}
+
+Form.Element.EventObserver = Class.create();
+Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
+  getValue: function() {
+    return Form.Element.getValue(this.element);
+  }
+});
+
+Form.EventObserver = Class.create();
+Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
+  getValue: function() {
+    return Form.serialize(this.element);
+  }
+});
+if (!window.Event) {
+  var Event = new Object();
+}
+
+Object.extend(Event, {
+  KEY_BACKSPACE: 8,
+  KEY_TAB:       9,
+  KEY_RETURN:   13,
+  KEY_ESC:      27,
+  KEY_LEFT:     37,
+  KEY_UP:       38,
+  KEY_RIGHT:    39,
+  KEY_DOWN:     40,
+  KEY_DELETE:   46,
+
+  element: function(event) {
+    return event.target || event.srcElement;
+  },
+
+  isLeftClick: function(event) {
+    return (((event.which) && (event.which == 1)) ||
+            ((event.button) && (event.button == 1)));
+  },
+
+  pointerX: function(event) {
+    return event.pageX || (event.clientX +
+      (document.documentElement.scrollLeft || document.body.scrollLeft));
+  },
+
+  pointerY: function(event) {
+    return event.pageY || (event.clientY +
+      (document.documentElement.scrollTop || document.body.scrollTop));
+  },
+
+  stop: function(event) {
+    if (event.preventDefault) {
+      event.preventDefault();
+      event.stopPropagation();
+    } else {
+      event.returnValue = false;
+      event.cancelBubble = true;
+    }
+  },
+
+  // find the first node with the given tagName, starting from the
+  // node the event was triggered on; traverses the DOM upwards
+  findElement: function(event, tagName) {
+    var element = Event.element(event);
+    while (element.parentNode && (!element.tagName ||
+        (element.tagName.toUpperCase() != tagName.toUpperCase())))
+      element = element.parentNode;
+    return element;
+  },
+
+  observers: false,
+
+  _observeAndCache: function(element, name, observer, useCapture) {
+    if (!this.observers) this.observers = [];
+    if (element.addEventListener) {
+      this.observers.push([element, name, observer, useCapture]);
+      element.addEventListener(name, observer, useCapture);
+    } else if (element.attachEvent) {
+      this.observers.push([element, name, observer, useCapture]);
+      element.attachEvent('on' + name, observer);
+    }
+  },
+
+  unloadCache: function() {
+    if (!Event.observers) return;
+    for (var i = 0; i < Event.observers.length; i++) {
+      Event.stopObserving.apply(this, Event.observers[i]);
+      Event.observers[i][0] = null;
+    }
+    Event.observers = false;
+  },
+
+  observe: function(element, name, observer, useCapture) {
+    var element = $(element);
+    useCapture = useCapture || false;
+
+    if (name == 'keypress' &&
+        (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
+        || element.attachEvent))
+      name = 'keydown';
+
+    this._observeAndCache(element, name, observer, useCapture);
+  },
+
+  stopObserving: function(element, name, observer, useCapture) {
+    var element = $(element);
+    useCapture = useCapture || false;
+
+    if (name == 'keypress' &&
+        (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
+        || element.detachEvent))
+      name = 'keydown';
+
+    if (element.removeEventListener) {
+      element.removeEventListener(name, observer, useCapture);
+    } else if (element.detachEvent) {
+      element.detachEvent('on' + name, observer);
+    }
+  }
+});
+
+/* prevent memory leaks in IE */
+Event.observe(window, 'unload', Event.unloadCache, false);
+var Position = {
+  // set to true if needed, warning: firefox performance problems
+  // NOT neeeded for page scrolling, only if draggable contained in
+  // scrollable elements
+  includeScrollOffsets: false,
+
+  // must be called before calling withinIncludingScrolloffset, every time the
+  // page is scrolled
+  prepare: function() {
+    this.deltaX =  window.pageXOffset
+                || document.documentElement.scrollLeft
+                || document.body.scrollLeft
+                || 0;
+    this.deltaY =  window.pageYOffset
+                || document.documentElement.scrollTop
+                || document.body.scrollTop
+                || 0;
+  },
+
+  realOffset: function(element) {
+    var valueT = 0, valueL = 0;
+    do {
+      valueT += element.scrollTop  || 0;
+      valueL += element.scrollLeft || 0;
+      element = element.parentNode;
+    } while (element);
+    return [valueL, valueT];
+  },
+
+  cumulativeOffset: function(element) {
+    var valueT = 0, valueL = 0;
+    do {
+      valueT += element.offsetTop  || 0;
+      valueL += element.offsetLeft || 0;
+      element = element.offsetParent;
+    } while (element);
+    return [valueL, valueT];
+  },
+
+  positionedOffset: function(element) {
+    var valueT = 0, valueL = 0;
+    do {
+      valueT += element.offsetTop  || 0;
+      valueL += element.offsetLeft || 0;
+      element = element.offsetParent;
+      if (element) {
+        p = Element.getStyle(element, 'position');
+        if (p == 'relative' || p == 'absolute') break;
+      }
+    } while (element);
+    return [valueL, valueT];
+  },
+
+  offsetParent: function(element) {
+    if (element.offsetParent) return element.offsetParent;
+    if (element == document.body) return element;
+
+    while ((element = element.parentNode) && element != document.body)
+      if (Element.getStyle(element, 'position') != 'static')
+        return element;
+
+    return document.body;
+  },
+
+  // caches x/y coordinate pair to use with overlap
+  within: function(element, x, y) {
+    if (this.includeScrollOffsets)
+      return this.withinIncludingScrolloffsets(element, x, y);
+    this.xcomp = x;
+    this.ycomp = y;
+    this.offset = this.cumulativeOffset(element);
+
+    return (y >= this.offset[1] &&
+            y <  this.offset[1] + element.offsetHeight &&
+            x >= this.offset[0] &&
+            x <  this.offset[0] + element.offsetWidth);
+  },
+
+  withinIncludingScrolloffsets: function(element, x, y) {
+    var offsetcache = this.realOffset(element);
+
+    this.xcomp = x + offsetcache[0] - this.deltaX;
+    this.ycomp = y + offsetcache[1] - this.deltaY;
+    this.offset = this.cumulativeOffset(element);
+
+    return (this.ycomp >= this.offset[1] &&
+            this.ycomp <  this.offset[1] + element.offsetHeight &&
+            this.xcomp >= this.offset[0] &&
+            this.xcomp <  this.offset[0] + element.offsetWidth);
+  },
+
+  // within must be called directly before
+  overlap: function(mode, element) {
+    if (!mode) return 0;
+    if (mode == 'vertical')
+      return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
+        element.offsetHeight;
+    if (mode == 'horizontal')
+      return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
+        element.offsetWidth;
+  },
+
+  clone: function(source, target) {
+    source = $(source);
+    target = $(target);
+    target.style.position = 'absolute';
+    var offsets = this.cumulativeOffset(source);
+    target.style.top    = offsets[1] + 'px';
+    target.style.left   = offsets[0] + 'px';
+    target.style.width  = source.offsetWidth + 'px';
+    target.style.height = source.offsetHeight + 'px';
+  },
+
+  page: function(forElement) {
+    var valueT = 0, valueL = 0;
+
+    var element = forElement;
+    do {
+      valueT += element.offsetTop  || 0;
+      valueL += element.offsetLeft || 0;
+
+      // Safari fix
+      if (element.offsetParent==document.body)
+        if (Element.getStyle(element,'position')=='absolute') break;
+
+    } while (element = element.offsetParent);
+
+    element = forElement;
+    do {
+      valueT -= element.scrollTop  || 0;
+      valueL -= element.scrollLeft || 0;
+    } while (element = element.parentNode);
+
+    return [valueL, valueT];
+  },
+
+  clone: function(source, target) {
+    var options = Object.extend({
+      setLeft:    true,
+      setTop:     true,
+      setWidth:   true,
+      setHeight:  true,
+      offsetTop:  0,
+      offsetLeft: 0
+    }, arguments[2] || {})
+
+    // find page position of source
+    source = $(source);
+    var p = Position.page(source);
+
+    // find coordinate system to use
+    target = $(target);
+    var delta = [0, 0];
+    var parent = null;
+    // delta [0,0] will do fine with position: fixed elements,
+    // position:absolute needs offsetParent deltas
+    if (Element.getStyle(target,'position') == 'absolute') {
+      parent = Position.offsetParent(target);
+      delta = Position.page(parent);
+    }
+
+    // correct by body offsets (fixes Safari)
+    if (parent == document.body) {
+      delta[0] -= document.body.offsetLeft;
+      delta[1] -= document.body.offsetTop;
+    }
+
+    // set position
+    if(options.setLeft)   target.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';
+    if(options.setTop)    target.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';
+    if(options.setWidth)  target.style.width = source.offsetWidth + 'px';
+    if(options.setHeight) target.style.height = source.offsetHeight + 'px';
+  },
+
+  absolutize: function(element) {
+    element = $(element);
+    if (element.style.position == 'absolute') return;
+    Position.prepare();
+
+    var offsets = Position.positionedOffset(element);
+    var top     = offsets[1];
+    var left    = offsets[0];
+    var width   = element.clientWidth;
+    var height  = element.clientHeight;
+
+    element._originalLeft   = left - parseFloat(element.style.left  || 0);
+    element._originalTop    = top  - parseFloat(element.style.top || 0);
+    element._originalWidth  = element.style.width;
+    element._originalHeight = element.style.height;
+
+    element.style.position = 'absolute';
+    element.style.top    = top + 'px';;
+    element.style.left   = left + 'px';;
+    element.style.width  = width + 'px';;
+    element.style.height = height + 'px';;
+  },
+
+  relativize: function(element) {
+    element = $(element);
+    if (element.style.position == 'relative') return;
+    Position.prepare();
+
+    element.style.position = 'relative';
+    var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0);
+    var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
+
+    element.style.top    = top + 'px';
+    element.style.left   = left + 'px';
+    element.style.height = element._originalHeight;
+    element.style.width  = element._originalWidth;
+  }
+}
+
+// Safari returns margins on body which is incorrect if the child is absolutely
+// positioned.  For performance reasons, redefine Position.cumulativeOffset for
+// KHTML/WebKit only.
+if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
+  Position.cumulativeOffset = function(element) {
+    var valueT = 0, valueL = 0;
+    do {
+      valueT += element.offsetTop  || 0;
+      valueL += element.offsetLeft || 0;
+      if (element.offsetParent == document.body)
+        if (Element.getStyle(element, 'position') == 'absolute') break;
+
+      element = element.offsetParent;
+    } while (element);
+
+    return [valueL, valueT];
+  }
+}
\ No newline at end of file
diff --git a/webinterface/src/web-data/rico.js b/webinterface/src/web-data/rico.js
new file mode 100644 (file)
index 0000000..65bcb48
--- /dev/null
@@ -0,0 +1,2818 @@
+/**
+  *
+  *  Copyright 2005 Sabre Airline Solutions
+  *
+  *  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
+  *  file except in compliance with the License. You may obtain a copy of the License at
+  *
+  *         http://www.apache.org/licenses/LICENSE-2.0
+  *
+  *  Unless required by applicable law or agreed to in writing, software distributed under the
+  *  License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+  *  either express or implied. See the License for the specific language governing permissions
+  *  and limitations under the License.
+  **/
+
+
+//-------------------- rico.js
+var Rico = {
+  Version: '1.1.2',
+  prototypeVersion: parseFloat(Prototype.Version.split(".")[0] + "." + Prototype.Version.split(".")[1])
+}
+
+if((typeof Prototype=='undefined') || Rico.prototypeVersion < 1.3)
+      throw("Rico requires the Prototype JavaScript framework >= 1.3");
+
+Rico.ArrayExtensions = new Array();
+
+if (Object.prototype.extend) {
+   Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Object.prototype.extend;
+}else{
+  Object.prototype.extend = function(object) {
+    return Object.extend.apply(this, [this, object]);
+  }
+  Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Object.prototype.extend;
+}
+
+if (Array.prototype.push) {
+   Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.push;
+}
+
+if (!Array.prototype.remove) {
+   Array.prototype.remove = function(dx) {
+      if( isNaN(dx) || dx > this.length )
+         return false;
+      for( var i=0,n=0; i<this.length; i++ )
+         if( i != dx )
+            this[n++]=this[i];
+      this.length-=1;
+   };
+  Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.remove;
+}
+
+if (!Array.prototype.removeItem) {
+   Array.prototype.removeItem = function(item) {
+      for ( var i = 0 ; i < this.length ; i++ )
+         if ( this[i] == item ) {
+            this.remove(i);
+            break;
+         }
+   };
+  Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.removeItem;
+}
+
+if (!Array.prototype.indices) {
+   Array.prototype.indices = function() {
+      var indexArray = new Array();
+      for ( index in this ) {
+         var ignoreThis = false;
+         for ( var i = 0 ; i < Rico.ArrayExtensions.length ; i++ ) {
+            if ( this[index] == Rico.ArrayExtensions[i] ) {
+               ignoreThis = true;
+               break;
+            }
+         }
+         if ( !ignoreThis )
+            indexArray[ indexArray.length ] = index;
+      }
+      return indexArray;
+   }
+  Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.indices;
+}
+
+// Create the loadXML method and xml getter for Mozilla
+if ( window.DOMParser &&
+         window.XMLSerializer &&
+         window.Node && Node.prototype && Node.prototype.__defineGetter__ ) {
+
+   if (!Document.prototype.loadXML) {
+      Document.prototype.loadXML = function (s) {
+         var doc2 = (new DOMParser()).parseFromString(s, "text/xml");
+         while (this.hasChildNodes())
+            this.removeChild(this.lastChild);
+
+         for (var i = 0; i < doc2.childNodes.length; i++) {
+            this.appendChild(this.importNode(doc2.childNodes[i], true));
+         }
+      };
+       }
+
+       Document.prototype.__defineGetter__( "xml",
+          function () {
+                  return (new XMLSerializer()).serializeToString(this);
+          }
+        );
+}
+
+document.getElementsByTagAndClassName = function(tagName, className) {
+  if ( tagName == null )
+     tagName = '*';
+
+  var children = document.getElementsByTagName(tagName) || document.all;
+  var elements = new Array();
+
+  if ( className == null )
+    return children;
+
+  for (var i = 0; i < children.length; i++) {
+    var child = children[i];
+    var classNames = child.className.split(' ');
+    for (var j = 0; j < classNames.length; j++) {
+      if (classNames[j] == className) {
+        elements.push(child);
+        break;
+      }
+    }
+  }
+
+  return elements;
+}
+
+
+//-------------------- ricoAccordion.js
+Rico.Accordion = Class.create();
+
+Rico.Accordion.prototype = {
+
+   initialize: function(container, options) {
+      this.container            = $(container);
+      this.lastExpandedTab      = null;
+      this.accordionTabs        = new Array();
+      this.setOptions(options);
+      this._attachBehaviors();
+      if(!container) return;
+
+      this.container.style.borderBottom = '1px solid ' + this.options.borderColor;
+      // validate onloadShowTab
+       if (this.options.onLoadShowTab >= this.accordionTabs.length)
+        this.options.onLoadShowTab = 0;
+
+      // set the initial visual state...
+      for ( var i=0 ; i < this.accordionTabs.length ; i++ )
+      {
+        if (i != this.options.onLoadShowTab){
+         this.accordionTabs[i].collapse();
+         this.accordionTabs[i].content.style.display = 'none';
+        }
+      }
+      this.lastExpandedTab = this.accordionTabs[this.options.onLoadShowTab];
+      if (this.options.panelHeight == 'auto'){
+          var tabToCheck = (this.options.onloadShowTab === 0)? 1 : 0;
+          var titleBarSize = parseInt(RicoUtil.getElementsComputedStyle(this.accordionTabs[tabToCheck].titleBar, 'height'));
+          if (isNaN(titleBarSize))
+            titleBarSize = this.accordionTabs[tabToCheck].titleBar.offsetHeight;
+          
+          var totalTitleBarSize = this.accordionTabs.length * titleBarSize;
+          var parentHeight = parseInt(RicoUtil.getElementsComputedStyle(this.container.parentNode, 'height'));
+          if (isNaN(parentHeight))
+            parentHeight = this.container.parentNode.offsetHeight;
+          
+          this.options.panelHeight = parentHeight - totalTitleBarSize-2;
+      }
+      
+      this.lastExpandedTab.content.style.height = this.options.panelHeight + "px";
+      this.lastExpandedTab.showExpanded();
+      this.lastExpandedTab.titleBar.style.fontWeight = this.options.expandedFontWeight;
+
+   },
+
+   setOptions: function(options) {
+      this.options = {
+         expandedBg          : '#63699c',
+         hoverBg             : '#63699c',
+         collapsedBg         : '#6b79a5',
+         expandedTextColor   : '#ffffff',
+         expandedFontWeight  : 'bold',
+         hoverTextColor      : '#ffffff',
+         collapsedTextColor  : '#ced7ef',
+         collapsedFontWeight : 'normal',
+         hoverTextColor      : '#ffffff',
+         borderColor         : '#1f669b',
+         panelHeight         : 200,
+         onHideTab           : null,
+         onShowTab           : null,
+         onLoadShowTab       : 0
+      }
+      Object.extend(this.options, options || {});
+   },
+
+   showTabByIndex: function( anIndex, animate ) {
+      var doAnimate = arguments.length == 1 ? true : animate;
+      this.showTab( this.accordionTabs[anIndex], doAnimate );
+   },
+
+   showTab: function( accordionTab, animate ) {
+     if ( this.lastExpandedTab == accordionTab )
+        return;
+
+      var doAnimate = arguments.length == 1 ? true : animate;
+
+      if ( this.options.onHideTab )
+         this.options.onHideTab(this.lastExpandedTab);
+
+      this.lastExpandedTab.showCollapsed(); 
+      var accordion = this;
+      var lastExpandedTab = this.lastExpandedTab;
+
+      this.lastExpandedTab.content.style.height = (this.options.panelHeight - 1) + 'px';
+      accordionTab.content.style.display = '';
+
+      accordionTab.titleBar.style.fontWeight = this.options.expandedFontWeight;
+
+      if ( doAnimate ) {
+         new Rico.Effect.AccordionSize( this.lastExpandedTab.content,
+                                   accordionTab.content,
+                                   1,
+                                   this.options.panelHeight,
+                                   100, 10,
+                                   { complete: function() {accordion.showTabDone(lastExpandedTab)} } );
+         this.lastExpandedTab = accordionTab;
+      }
+      else {
+         this.lastExpandedTab.content.style.height = "1px";
+         accordionTab.content.style.height = this.options.panelHeight + "px";
+         this.lastExpandedTab = accordionTab;
+         this.showTabDone(lastExpandedTab);
+      }
+   },
+
+   showTabDone: function(collapsedTab) {
+      collapsedTab.content.style.display = 'none';
+      this.lastExpandedTab.showExpanded();
+      if ( this.options.onShowTab )
+         this.options.onShowTab(this.lastExpandedTab);
+   },
+
+   _attachBehaviors: function() {
+      var panels = this._getDirectChildrenByTag(this.container, 'DIV');
+      for ( var i = 0 ; i < panels.length ; i++ ) {
+
+         var tabChildren = this._getDirectChildrenByTag(panels[i],'DIV');
+         if ( tabChildren.length != 2 )
+            continue; // unexpected
+
+         var tabTitleBar   = tabChildren[0];
+         var tabContentBox = tabChildren[1];
+         this.accordionTabs.push( new Rico.Accordion.Tab(this,tabTitleBar,tabContentBox) );
+      }
+   },
+
+   _getDirectChildrenByTag: function(e, tagName) {
+      var kids = new Array();
+      var allKids = e.childNodes;
+      for( var i = 0 ; i < allKids.length ; i++ )
+         if ( allKids[i] && allKids[i].tagName && allKids[i].tagName == tagName )
+            kids.push(allKids[i]);
+      return kids;
+   }
+
+};
+
+Rico.Accordion.Tab = Class.create();
+
+Rico.Accordion.Tab.prototype = {
+
+   initialize: function(accordion, titleBar, content) {
+      this.accordion = accordion;
+      this.titleBar  = titleBar;
+      this.content   = content;
+      this._attachBehaviors();
+   },
+
+   collapse: function() {
+      this.showCollapsed();
+      this.content.style.height = "1px";
+   },
+
+   showCollapsed: function() {
+      this.expanded = false;
+      this.titleBar.style.backgroundColor = this.accordion.options.collapsedBg;
+      this.titleBar.style.color           = this.accordion.options.collapsedTextColor;
+      this.titleBar.style.fontWeight      = this.accordion.options.collapsedFontWeight;
+      this.content.style.overflow = "hidden";
+   },
+
+   showExpanded: function() {
+      this.expanded = true;
+      this.titleBar.style.backgroundColor = this.accordion.options.expandedBg;
+      this.titleBar.style.color           = this.accordion.options.expandedTextColor;
+      this.content.style.overflow         = "auto";
+   },
+
+   titleBarClicked: function(e) {
+      if ( this.accordion.lastExpandedTab == this )
+         return;
+      this.accordion.showTab(this);
+   },
+
+   hover: function(e) {
+               this.titleBar.style.backgroundColor = this.accordion.options.hoverBg;
+               this.titleBar.style.color           = this.accordion.options.hoverTextColor;
+   },
+
+   unhover: function(e) {
+      if ( this.expanded ) {
+         this.titleBar.style.backgroundColor = this.accordion.options.expandedBg;
+         this.titleBar.style.color           = this.accordion.options.expandedTextColor;
+      }
+      else {
+         this.titleBar.style.backgroundColor = this.accordion.options.collapsedBg;
+         this.titleBar.style.color           = this.accordion.options.collapsedTextColor;
+      }
+   },
+
+   _attachBehaviors: function() {
+      this.content.style.border = "1px solid " + this.accordion.options.borderColor;
+      this.content.style.borderTopWidth    = "0px";
+      this.content.style.borderBottomWidth = "0px";
+      this.content.style.margin            = "0px";
+
+      this.titleBar.onclick     = this.titleBarClicked.bindAsEventListener(this);
+      this.titleBar.onmouseover = this.hover.bindAsEventListener(this);
+      this.titleBar.onmouseout  = this.unhover.bindAsEventListener(this);
+   }
+
+};
+
+
+//-------------------- ricoAjaxEngine.js
+Rico.AjaxEngine = Class.create();
+
+Rico.AjaxEngine.prototype = {
+
+   initialize: function() {
+      this.ajaxElements = new Array();
+      this.ajaxObjects  = new Array();
+      this.requestURLS  = new Array();
+      this.options = {};
+   },
+
+   registerAjaxElement: function( anId, anElement ) {
+      if ( !anElement )
+         anElement = $(anId);
+      this.ajaxElements[anId] = anElement;
+   },
+
+   registerAjaxObject: function( anId, anObject ) {
+      this.ajaxObjects[anId] = anObject;
+   },
+
+   registerRequest: function (requestLogicalName, requestURL) {
+      this.requestURLS[requestLogicalName] = requestURL;
+   },
+
+   sendRequest: function(requestName, options) {
+      // Allow for backwards Compatibility
+      if ( arguments.length >= 2 )
+       if (typeof arguments[1] == 'string')
+         options = {parameters: this._createQueryString(arguments, 1)};
+      this.sendRequestWithData(requestName, null, options);
+   },
+
+   sendRequestWithData: function(requestName, xmlDocument, options) {
+      var requestURL = this.requestURLS[requestName];
+      if ( requestURL == null )
+         return;
+
+      // Allow for backwards Compatibility
+      if ( arguments.length >= 3 )
+        if (typeof arguments[2] == 'string')
+          options.parameters = this._createQueryString(arguments, 2);
+
+      new Ajax.Request(requestURL, this._requestOptions(options,xmlDocument));
+   },
+
+   sendRequestAndUpdate: function(requestName,container,options) {
+      // Allow for backwards Compatibility
+      if ( arguments.length >= 3 )
+        if (typeof arguments[2] == 'string')
+          options.parameters = this._createQueryString(arguments, 2);
+
+      this.sendRequestWithDataAndUpdate(requestName, null, container, options);
+   },
+
+   sendRequestWithDataAndUpdate: function(requestName,xmlDocument,container,options) {
+      var requestURL = this.requestURLS[requestName];
+      if ( requestURL == null )
+         return;
+
+      // Allow for backwards Compatibility
+      if ( arguments.length >= 4 )
+        if (typeof arguments[3] == 'string')
+          options.parameters = this._createQueryString(arguments, 3);
+
+      var updaterOptions = this._requestOptions(options,xmlDocument);
+
+      new Ajax.Updater(container, requestURL, updaterOptions);
+   },
+
+   // Private -- not part of intended engine API --------------------------------------------------------------------
+
+   _requestOptions: function(options,xmlDoc) {
+      var requestHeaders = ['X-Rico-Version', Rico.Version ];
+      var sendMethod = 'post';
+      if ( xmlDoc == null )
+        if (Rico.prototypeVersion < 1.4)
+        requestHeaders.push( 'Content-type', 'text/xml' );
+      else
+          sendMethod = 'get';
+      (!options) ? options = {} : '';
+
+      if (!options._RicoOptionsProcessed){
+      // Check and keep any user onComplete functions
+        if (options.onComplete)
+             options.onRicoComplete = options.onComplete;
+        // Fix onComplete
+        if (options.overrideOnComplete)
+          options.onComplete = options.overrideOnComplete;
+        else
+          options.onComplete = this._onRequestComplete.bind(this);
+        options._RicoOptionsProcessed = true;
+      }
+
+     // Set the default options and extend with any user options
+     this.options = {
+                     requestHeaders: requestHeaders,
+                     parameters:     options.parameters,
+                     postBody:       xmlDoc,
+                     method:         sendMethod,
+                     onComplete:     options.onComplete
+                    };
+     // Set any user options:
+     Object.extend(this.options, options);
+     return this.options;
+   },
+
+   _createQueryString: function( theArgs, offset ) {
+      var queryString = ""
+      for ( var i = offset ; i < theArgs.length ; i++ ) {
+          if ( i != offset )
+            queryString += "&";
+
+          var anArg = theArgs[i];
+
+          if ( anArg.name != undefined && anArg.value != undefined ) {
+            queryString += anArg.name +  "=" + escape(anArg.value);
+          }
+          else {
+             var ePos  = anArg.indexOf('=');
+             var argName  = anArg.substring( 0, ePos );
+             var argValue = anArg.substring( ePos + 1 );
+             queryString += argName + "=" + escape(argValue);
+          }
+      }
+      return queryString;
+   },
+
+   _onRequestComplete : function(request) {
+      if(!request)
+          return;
+      // User can set an onFailure option - which will be called by prototype
+      if (request.status != 200)
+        return;
+
+      var response = request.responseXML.getElementsByTagName("ajax-response");
+      if (response == null || response.length != 1)
+         return;
+      this._processAjaxResponse( response[0].childNodes );
+      
+      // Check if user has set a onComplete function
+      var onRicoComplete = this.options.onRicoComplete;
+      if (onRicoComplete != null)
+          onRicoComplete();
+   },
+
+   _processAjaxResponse: function( xmlResponseElements ) {
+      for ( var i = 0 ; i < xmlResponseElements.length ; i++ ) {
+         var responseElement = xmlResponseElements[i];
+
+         // only process nodes of type element.....
+         if ( responseElement.nodeType != 1 )
+            continue;
+
+         var responseType = responseElement.getAttribute("type");
+         var responseId   = responseElement.getAttribute("id");
+
+         if ( responseType == "object" )
+            this._processAjaxObjectUpdate( this.ajaxObjects[ responseId ], responseElement );
+         else if ( responseType == "element" )
+            this._processAjaxElementUpdate( this.ajaxElements[ responseId ], responseElement );
+         else
+            alert('unrecognized AjaxResponse type : ' + responseType );
+      }
+   },
+
+   _processAjaxObjectUpdate: function( ajaxObject, responseElement ) {
+      ajaxObject.ajaxUpdate( responseElement );
+   },
+
+   _processAjaxElementUpdate: function( ajaxElement, responseElement ) {
+      ajaxElement.innerHTML = RicoUtil.getContentAsString(responseElement);
+   }
+
+}
+
+var ajaxEngine = new Rico.AjaxEngine();
+
+
+//-------------------- ricoColor.js
+Rico.Color = Class.create();
+
+Rico.Color.prototype = {
+
+   initialize: function(red, green, blue) {
+      this.rgb = { r: red, g : green, b : blue };
+   },
+
+   setRed: function(r) {
+      this.rgb.r = r;
+   },
+
+   setGreen: function(g) {
+      this.rgb.g = g;
+   },
+
+   setBlue: function(b) {
+      this.rgb.b = b;
+   },
+
+   setHue: function(h) {
+
+      // get an HSB model, and set the new hue...
+      var hsb = this.asHSB();
+      hsb.h = h;
+
+      // convert back to RGB...
+      this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
+   },
+
+   setSaturation: function(s) {
+      // get an HSB model, and set the new hue...
+      var hsb = this.asHSB();
+      hsb.s = s;
+
+      // convert back to RGB and set values...
+      this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
+   },
+
+   setBrightness: function(b) {
+      // get an HSB model, and set the new hue...
+      var hsb = this.asHSB();
+      hsb.b = b;
+
+      // convert back to RGB and set values...
+      this.rgb = Rico.Color.HSBtoRGB( hsb.h, hsb.s, hsb.b );
+   },
+
+   darken: function(percent) {
+      var hsb  = this.asHSB();
+      this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.max(hsb.b - percent,0));
+   },
+
+   brighten: function(percent) {
+      var hsb  = this.asHSB();
+      this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.min(hsb.b + percent,1));
+   },
+
+   blend: function(other) {
+      this.rgb.r = Math.floor((this.rgb.r + other.rgb.r)/2);
+      this.rgb.g = Math.floor((this.rgb.g + other.rgb.g)/2);
+      this.rgb.b = Math.floor((this.rgb.b + other.rgb.b)/2);
+   },
+
+   isBright: function() {
+      var hsb = this.asHSB();
+      return this.asHSB().b > 0.5;
+   },
+
+   isDark: function() {
+      return ! this.isBright();
+   },
+
+   asRGB: function() {
+      return "rgb(" + this.rgb.r + "," + this.rgb.g + "," + this.rgb.b + ")";
+   },
+
+   asHex: function() {
+      return "#" + this.rgb.r.toColorPart() + this.rgb.g.toColorPart() + this.rgb.b.toColorPart();
+   },
+
+   asHSB: function() {
+      return Rico.Color.RGBtoHSB(this.rgb.r, this.rgb.g, this.rgb.b);
+   },
+
+   toString: function() {
+      return this.asHex();
+   }
+
+};
+
+Rico.Color.createFromHex = function(hexCode) {
+  if(hexCode.length==4) {
+    var shortHexCode = hexCode; 
+    var hexCode = '#';
+    for(var i=1;i<4;i++) hexCode += (shortHexCode.charAt(i) + 
+shortHexCode.charAt(i));
+  }
+   if ( hexCode.indexOf('#') == 0 )
+      hexCode = hexCode.substring(1);
+   var red   = hexCode.substring(0,2);
+   var green = hexCode.substring(2,4);
+   var blue  = hexCode.substring(4,6);
+   return new Rico.Color( parseInt(red,16), parseInt(green,16), parseInt(blue,16) );
+}
+
+/**
+ * Factory method for creating a color from the background of
+ * an HTML element.
+ */
+Rico.Color.createColorFromBackground = function(elem) {
+
+   var actualColor = RicoUtil.getElementsComputedStyle($(elem), "backgroundColor", "background-color");
+
+   if ( actualColor == "transparent" && elem.parentNode )
+      return Rico.Color.createColorFromBackground(elem.parentNode);
+
+   if ( actualColor == null )
+      return new Rico.Color(255,255,255);
+
+   if ( actualColor.indexOf("rgb(") == 0 ) {
+      var colors = actualColor.substring(4, actualColor.length - 1 );
+      var colorArray = colors.split(",");
+      return new Rico.Color( parseInt( colorArray[0] ),
+                            parseInt( colorArray[1] ),
+                            parseInt( colorArray[2] )  );
+
+   }
+   else if ( actualColor.indexOf("#") == 0 ) {
+      return Rico.Color.createFromHex(actualColor);
+   }
+   else
+      return new Rico.Color(255,255,255);
+}
+
+Rico.Color.HSBtoRGB = function(hue, saturation, brightness) {
+
+   var red   = 0;
+       var green = 0;
+       var blue  = 0;
+
+   if (saturation == 0) {
+      red = parseInt(brightness * 255.0 + 0.5);
+          green = red;
+          blue = red;
+       }
+       else {
+      var h = (hue - Math.floor(hue)) * 6.0;
+      var f = h - Math.floor(h);
+      var p = brightness * (1.0 - saturation);
+      var q = brightness * (1.0 - saturation * f);
+      var t = brightness * (1.0 - (saturation * (1.0 - f)));
+
+      switch (parseInt(h)) {
+         case 0:
+            red   = (brightness * 255.0 + 0.5);
+            green = (t * 255.0 + 0.5);
+            blue  = (p * 255.0 + 0.5);
+            break;
+         case 1:
+            red   = (q * 255.0 + 0.5);
+            green = (brightness * 255.0 + 0.5);
+            blue  = (p * 255.0 + 0.5);
+            break;
+         case 2:
+            red   = (p * 255.0 + 0.5);
+            green = (brightness * 255.0 + 0.5);
+            blue  = (t * 255.0 + 0.5);
+            break;
+         case 3:
+            red   = (p * 255.0 + 0.5);
+            green = (q * 255.0 + 0.5);
+            blue  = (brightness * 255.0 + 0.5);
+            break;
+         case 4:
+            red   = (t * 255.0 + 0.5);
+            green = (p * 255.0 + 0.5);
+            blue  = (brightness * 255.0 + 0.5);
+            break;
+          case 5:
+            red   = (brightness * 255.0 + 0.5);
+            green = (p * 255.0 + 0.5);
+            blue  = (q * 255.0 + 0.5);
+            break;
+           }
+       }
+
+   return { r : parseInt(red), g : parseInt(green) , b : parseInt(blue) };
+}
+
+Rico.Color.RGBtoHSB = function(r, g, b) {
+
+   var hue;
+   var saturation;
+   var brightness;
+
+   var cmax = (r > g) ? r : g;
+   if (b > cmax)
+      cmax = b;
+
+   var cmin = (r < g) ? r : g;
+   if (b < cmin)
+      cmin = b;
+
+   brightness = cmax / 255.0;
+   if (cmax != 0)
+      saturation = (cmax - cmin)/cmax;
+   else
+      saturation = 0;
+
+   if (saturation == 0)
+      hue = 0;
+   else {
+      var redc   = (cmax - r)/(cmax - cmin);
+       var greenc = (cmax - g)/(cmax - cmin);
+       var bluec  = (cmax - b)/(cmax - cmin);
+
+       if (r == cmax)
+          hue = bluec - greenc;
+       else if (g == cmax)
+          hue = 2.0 + redc - bluec;
+      else
+          hue = 4.0 + greenc - redc;
+
+       hue = hue / 6.0;
+       if (hue < 0)
+          hue = hue + 1.0;
+   }
+
+   return { h : hue, s : saturation, b : brightness };
+}
+
+
+//-------------------- ricoCorner.js
+Rico.Corner = {
+
+   round: function(e, options) {
+      var e = $(e);
+      this._setOptions(options);
+
+      var color = this.options.color;
+      if ( this.options.color == "fromElement" )
+         color = this._background(e);
+
+      var bgColor = this.options.bgColor;
+      if ( this.options.bgColor == "fromParent" )
+         bgColor = this._background(e.offsetParent);
+
+      this._roundCornersImpl(e, color, bgColor);
+   },
+
+   _roundCornersImpl: function(e, color, bgColor) {
+      if(this.options.border)
+         this._renderBorder(e,bgColor);
+      if(this._isTopRounded())
+         this._roundTopCorners(e,color,bgColor);
+      if(this._isBottomRounded())
+         this._roundBottomCorners(e,color,bgColor);
+   },
+
+   _renderBorder: function(el,bgColor) {
+      var borderValue = "1px solid " + this._borderColor(bgColor);
+      var borderL = "border-left: "  + borderValue;
+      var borderR = "border-right: " + borderValue;
+      var style   = "style='" + borderL + ";" + borderR +  "'";
+      el.innerHTML = "<div " + style + ">" + el.innerHTML + "</div>"
+   },
+
+   _roundTopCorners: function(el, color, bgColor) {
+      var corner = this._createCorner(bgColor);
+      for(var i=0 ; i < this.options.numSlices ; i++ )
+         corner.appendChild(this._createCornerSlice(color,bgColor,i,"top"));
+      el.style.paddingTop = 0;
+      el.insertBefore(corner,el.firstChild);
+   },
+
+   _roundBottomCorners: function(el, color, bgColor) {
+      var corner = this._createCorner(bgColor);
+      for(var i=(this.options.numSlices-1) ; i >= 0 ; i-- )
+         corner.appendChild(this._createCornerSlice(color,bgColor,i,"bottom"));
+      el.style.paddingBottom = 0;
+      el.appendChild(corner);
+   },
+
+   _createCorner: function(bgColor) {
+      var corner = document.createElement("div");
+      corner.style.backgroundColor = (this._isTransparent() ? "transparent" : bgColor);
+      return corner;
+   },
+
+   _createCornerSlice: function(color,bgColor, n, position) {
+      var slice = document.createElement("span");
+
+      var inStyle = slice.style;
+      inStyle.backgroundColor = color;
+      inStyle.display  = "block";
+      inStyle.height   = "1px";
+      inStyle.overflow = "hidden";
+      inStyle.fontSize = "1px";
+
+      var borderColor = this._borderColor(color,bgColor);
+      if ( this.options.border && n == 0 ) {
+         inStyle.borderTopStyle    = "solid";
+         inStyle.borderTopWidth    = "1px";
+         inStyle.borderLeftWidth   = "0px";
+         inStyle.borderRightWidth  = "0px";
+         inStyle.borderBottomWidth = "0px";
+         inStyle.height            = "0px"; // assumes css compliant box model
+         inStyle.borderColor       = borderColor;
+      }
+      else if(borderColor) {
+         inStyle.borderColor = borderColor;
+         inStyle.borderStyle = "solid";
+         inStyle.borderWidth = "0px 1px";
+      }
+
+      if ( !this.options.compact && (n == (this.options.numSlices-1)) )
+         inStyle.height = "2px";
+
+      this._setMargin(slice, n, position);
+      this._setBorder(slice, n, position);
+      return slice;
+   },
+
+   _setOptions: function(options) {
+      this.options = {
+         corners : "all",
+         color   : "fromElement",
+         bgColor : "fromParent",
+         blend   : true,
+         border  : false,
+         compact : false
+      }
+      Object.extend(this.options, options || {});
+
+      this.options.numSlices = this.options.compact ? 2 : 4;
+      if ( this._isTransparent() )
+         this.options.blend = false;
+   },
+
+   _whichSideTop: function() {
+      if ( this._hasString(this.options.corners, "all", "top") )
+         return "";
+
+      if ( this.options.corners.indexOf("tl") >= 0 && this.options.corners.indexOf("tr") >= 0 )
+         return "";
+
+      if (this.options.corners.indexOf("tl") >= 0)
+         return "left";
+      else if (this.options.corners.indexOf("tr") >= 0)
+          return "right";
+      return "";
+   },
+
+   _whichSideBottom: function() {
+      if ( this._hasString(this.options.corners, "all", "bottom") )
+         return "";
+
+      if ( this.options.corners.indexOf("bl")>=0 && this.options.corners.indexOf("br")>=0 )
+         return "";
+
+      if(this.options.corners.indexOf("bl") >=0)
+         return "left";
+      else if(this.options.corners.indexOf("br")>=0)
+         return "right";
+      return "";
+   },
+
+   _borderColor : function(color,bgColor) {
+      if ( color == "transparent" )
+         return bgColor;
+      else if ( this.options.border )
+         return this.options.border;
+      else if ( this.options.blend )
+         return this._blend( bgColor, color );
+      else
+         return "";
+   },
+
+
+   _setMargin: function(el, n, corners) {
+      var marginSize = this._marginSize(n);
+      var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom();
+
+      if ( whichSide == "left" ) {
+         el.style.marginLeft = marginSize + "px"; el.style.marginRight = "0px";
+      }
+      else if ( whichSide == "right" ) {
+         el.style.marginRight = marginSize + "px"; el.style.marginLeft  = "0px";
+      }
+      else {
+         el.style.marginLeft = marginSize + "px"; el.style.marginRight = marginSize + "px";
+      }
+   },
+
+   _setBorder: function(el,n,corners) {
+      var borderSize = this._borderSize(n);
+      var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom();
+      if ( whichSide == "left" ) {
+         el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = "0px";
+      }
+      else if ( whichSide == "right" ) {
+         el.style.borderRightWidth = borderSize + "px"; el.style.borderLeftWidth  = "0px";
+      }
+      else {
+         el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = borderSize + "px";
+      }
+      if (this.options.border != false)
+        el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = borderSize + "px";
+   },
+
+   _marginSize: function(n) {
+      if ( this._isTransparent() )
+         return 0;
+
+      var marginSizes          = [ 5, 3, 2, 1 ];
+      var blendedMarginSizes   = [ 3, 2, 1, 0 ];
+      var compactMarginSizes   = [ 2, 1 ];
+      var smBlendedMarginSizes = [ 1, 0 ];
+
+      if ( this.options.compact && this.options.blend )
+         return smBlendedMarginSizes[n];
+      else if ( this.options.compact )
+         return compactMarginSizes[n];
+      else if ( this.options.blend )
+         return blendedMarginSizes[n];
+      else
+         return marginSizes[n];
+   },
+
+   _borderSize: function(n) {
+      var transparentBorderSizes = [ 5, 3, 2, 1 ];
+      var blendedBorderSizes     = [ 2, 1, 1, 1 ];
+      var compactBorderSizes     = [ 1, 0 ];
+      var actualBorderSizes      = [ 0, 2, 0, 0 ];
+
+      if ( this.options.compact && (this.options.blend || this._isTransparent()) )
+         return 1;
+      else if ( this.options.compact )
+         return compactBorderSizes[n];
+      else if ( this.options.blend )
+         return blendedBorderSizes[n];
+      else if ( this.options.border )
+         return actualBorderSizes[n];
+      else if ( this._isTransparent() )
+         return transparentBorderSizes[n];
+      return 0;
+   },
+
+   _hasString: function(str) { for(var i=1 ; i<arguments.length ; i++) if (str.indexOf(arguments[i]) >= 0) return true; return false; },
+   _blend: function(c1, c2) { var cc1 = Rico.Color.createFromHex(c1); cc1.blend(Rico.Color.createFromHex(c2)); return cc1; },
+   _background: function(el) { try { return Rico.Color.createColorFromBackground(el).asHex(); } catch(err) { return "#ffffff"; } },
+   _isTransparent: function() { return this.options.color == "transparent"; },
+   _isTopRounded: function() { return this._hasString(this.options.corners, "all", "top", "tl", "tr"); },
+   _isBottomRounded: function() { return this._hasString(this.options.corners, "all", "bottom", "bl", "br"); },
+   _hasSingleTextChild: function(el) { return el.childNodes.length == 1 && el.childNodes[0].nodeType == 3; }
+}
+
+
+//-------------------- ricoDragAndDrop.js
+Rico.DragAndDrop = Class.create();
+
+Rico.DragAndDrop.prototype = {
+
+   initialize: function() {
+      this.dropZones                = new Array();
+      this.draggables               = new Array();
+      this.currentDragObjects       = new Array();
+      this.dragElement              = null;
+      this.lastSelectedDraggable    = null;
+      this.currentDragObjectVisible = false;
+      this.interestedInMotionEvents = false;
+      this._mouseDown = this._mouseDownHandler.bindAsEventListener(this);
+      this._mouseMove = this._mouseMoveHandler.bindAsEventListener(this);
+      this._mouseUp = this._mouseUpHandler.bindAsEventListener(this);
+   },
+
+   registerDropZone: function(aDropZone) {
+      this.dropZones[ this.dropZones.length ] = aDropZone;
+   },
+
+   deregisterDropZone: function(aDropZone) {
+      var newDropZones = new Array();
+      var j = 0;
+      for ( var i = 0 ; i < this.dropZones.length ; i++ ) {
+         if ( this.dropZones[i] != aDropZone )
+            newDropZones[j++] = this.dropZones[i];
+      }
+
+      this.dropZones = newDropZones;
+   },
+
+   clearDropZones: function() {
+      this.dropZones = new Array();
+   },
+
+   registerDraggable: function( aDraggable ) {
+      this.draggables[ this.draggables.length ] = aDraggable;
+      this._addMouseDownHandler( aDraggable );
+   },
+
+   clearSelection: function() {
+      for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
+         this.currentDragObjects[i].deselect();
+      this.currentDragObjects = new Array();
+      this.lastSelectedDraggable = null;
+   },
+
+   hasSelection: function() {
+      return this.currentDragObjects.length > 0;
+   },
+
+   setStartDragFromElement: function( e, mouseDownElement ) {
+      this.origPos = RicoUtil.toDocumentPosition(mouseDownElement);
+      this.startx = e.screenX - this.origPos.x
+      this.starty = e.screenY - this.origPos.y
+      //this.startComponentX = e.layerX ? e.layerX : e.offsetX;
+      //this.startComponentY = e.layerY ? e.layerY : e.offsetY;
+      //this.adjustedForDraggableSize = false;
+
+      this.interestedInMotionEvents = this.hasSelection();
+      this._terminateEvent(e);
+   },
+
+   updateSelection: function( draggable, extendSelection ) {
+      if ( ! extendSelection )
+         this.clearSelection();
+
+      if ( draggable.isSelected() ) {
+         this.currentDragObjects.removeItem(draggable);
+         draggable.deselect();
+         if ( draggable == this.lastSelectedDraggable )
+            this.lastSelectedDraggable = null;
+      }
+      else {
+         this.currentDragObjects[ this.currentDragObjects.length ] = draggable;
+         draggable.select();
+         this.lastSelectedDraggable = draggable;
+      }
+   },
+
+   _mouseDownHandler: function(e) {
+      if ( arguments.length == 0 )
+         e = event;
+
+      // if not button 1 ignore it...
+      var nsEvent = e.which != undefined;
+      if ( (nsEvent && e.which != 1) || (!nsEvent && e.button != 1))
+         return;
+
+      var eventTarget      = e.target ? e.target : e.srcElement;
+      var draggableObject  = eventTarget.draggable;
+
+      var candidate = eventTarget;
+      while (draggableObject == null && candidate.parentNode) {
+         candidate = candidate.parentNode;
+         draggableObject = candidate.draggable;
+      }
+   
+      if ( draggableObject == null )
+         return;
+
+      this.updateSelection( draggableObject, e.ctrlKey );
+
+      // clear the drop zones postion cache...
+      if ( this.hasSelection() )
+         for ( var i = 0 ; i < this.dropZones.length ; i++ )
+            this.dropZones[i].clearPositionCache();
+
+      this.setStartDragFromElement( e, draggableObject.getMouseDownHTMLElement() );
+   },
+
+
+   _mouseMoveHandler: function(e) {
+      var nsEvent = e.which != undefined;
+      if ( !this.interestedInMotionEvents ) {
+         //this._terminateEvent(e);
+         return;
+      }
+
+      if ( ! this.hasSelection() )
+         return;
+
+      if ( ! this.currentDragObjectVisible )
+         this._startDrag(e);
+
+      if ( !this.activatedDropZones )
+         this._activateRegisteredDropZones();
+
+      //if ( !this.adjustedForDraggableSize )
+      //   this._adjustForDraggableSize(e);
+
+      this._updateDraggableLocation(e);
+      this._updateDropZonesHover(e);
+
+      this._terminateEvent(e);
+   },
+
+   _makeDraggableObjectVisible: function(e)
+   {
+      if ( !this.hasSelection() )
+         return;
+
+      var dragElement;
+      if ( this.currentDragObjects.length > 1 )
+         dragElement = this.currentDragObjects[0].getMultiObjectDragGUI(this.currentDragObjects);
+      else
+         dragElement = this.currentDragObjects[0].getSingleObjectDragGUI();
+
+      // go ahead and absolute position it...
+      if ( RicoUtil.getElementsComputedStyle(dragElement, "position")  != "absolute" )
+         dragElement.style.position = "absolute";
+
+      // need to parent him into the document...
+      if ( dragElement.parentNode == null || dragElement.parentNode.nodeType == 11 )
+         document.body.appendChild(dragElement);
+
+      this.dragElement = dragElement;
+      this._updateDraggableLocation(e);
+
+      this.currentDragObjectVisible = true;
+   },
+
+   /**
+   _adjustForDraggableSize: function(e) {
+      var dragElementWidth  = this.dragElement.offsetWidth;
+      var dragElementHeight = this.dragElement.offsetHeight;
+      if ( this.startComponentX > dragElementWidth )
+         this.startx -= this.startComponentX - dragElementWidth + 2;
+      if ( e.offsetY ) {
+         if ( this.startComponentY > dragElementHeight )
+            this.starty -= this.startComponentY - dragElementHeight + 2;
+      }
+      this.adjustedForDraggableSize = true;
+   },
+   **/
+
+   _leftOffset: function(e) {
+          return e.offsetX ? document.body.scrollLeft : 0
+       },
+
+   _topOffset: function(e) {
+          return e.offsetY ? document.body.scrollTop:0
+       },
+
+               
+   _updateDraggableLocation: function(e) {
+      var dragObjectStyle = this.dragElement.style;
+      dragObjectStyle.left = (e.screenX + this._leftOffset(e) - this.startx) + "px"
+      dragObjectStyle.top  = (e.screenY + this._topOffset(e) - this.starty) + "px";
+   },
+
+   _updateDropZonesHover: function(e) {
+      var n = this.dropZones.length;
+      for ( var i = 0 ; i < n ; i++ ) {
+         if ( ! this._mousePointInDropZone( e, this.dropZones[i] ) )
+            this.dropZones[i].hideHover();
+      }
+
+      for ( var i = 0 ; i < n ; i++ ) {
+         if ( this._mousePointInDropZone( e, this.dropZones[i] ) ) {
+            if ( this.dropZones[i].canAccept(this.currentDragObjects) )
+               this.dropZones[i].showHover();
+         }
+      }
+   },
+
+   _startDrag: function(e) {
+      for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
+         this.currentDragObjects[i].startDrag();
+
+      this._makeDraggableObjectVisible(e);
+   },
+
+   _mouseUpHandler: function(e) {
+      if ( ! this.hasSelection() )
+         return;
+
+      var nsEvent = e.which != undefined;
+      if ( (nsEvent && e.which != 1) || (!nsEvent && e.button != 1))
+         return;
+
+      this.interestedInMotionEvents = false;
+
+      if ( this.dragElement == null ) {
+         this._terminateEvent(e);
+         return;
+      }
+
+      if ( this._placeDraggableInDropZone(e) )
+         this._completeDropOperation(e);
+      else {
+         this._terminateEvent(e);
+         new Rico.Effect.Position( this.dragElement,
+                              this.origPos.x,
+                              this.origPos.y,
+                              200,
+                              20,
+                              { complete : this._doCancelDragProcessing.bind(this) } );
+      }
+
+     Event.stopObserving(document.body, "mousemove", this._mouseMove);
+     Event.stopObserving(document.body, "mouseup",  this._mouseUp);
+   },
+
+   _retTrue: function () {
+      return true;
+   },
+
+   _completeDropOperation: function(e) {
+      if ( this.dragElement != this.currentDragObjects[0].getMouseDownHTMLElement() ) {
+         if ( this.dragElement.parentNode != null )
+            this.dragElement.parentNode.removeChild(this.dragElement);
+      }
+
+      this._deactivateRegisteredDropZones();
+      this._endDrag();
+      this.clearSelection();
+      this.dragElement = null;
+      this.currentDragObjectVisible = false;
+      this._terminateEvent(e);
+   },
+
+   _doCancelDragProcessing: function() {
+      this._cancelDrag();
+
+        if ( this.dragElement != this.currentDragObjects[0].getMouseDownHTMLElement() && this.dragElement)
+           if ( this.dragElement.parentNode != null )
+              this.dragElement.parentNode.removeChild(this.dragElement);
+
+
+      this._deactivateRegisteredDropZones();
+      this.dragElement = null;
+      this.currentDragObjectVisible = false;
+   },
+
+   _placeDraggableInDropZone: function(e) {
+      var foundDropZone = false;
+      var n = this.dropZones.length;
+      for ( var i = 0 ; i < n ; i++ ) {
+         if ( this._mousePointInDropZone( e, this.dropZones[i] ) ) {
+            if ( this.dropZones[i].canAccept(this.currentDragObjects) ) {
+               this.dropZones[i].hideHover();
+               this.dropZones[i].accept(this.currentDragObjects);
+               foundDropZone = true;
+               break;
+            }
+         }
+      }
+
+      return foundDropZone;
+   },
+
+   _cancelDrag: function() {
+      for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
+         this.currentDragObjects[i].cancelDrag();
+   },
+
+   _endDrag: function() {
+      for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
+         this.currentDragObjects[i].endDrag();
+   },
+
+   _mousePointInDropZone: function( e, dropZone ) {
+
+      var absoluteRect = dropZone.getAbsoluteRect();
+
+      return e.clientX  > absoluteRect.left + this._leftOffset(e) &&
+             e.clientX  < absoluteRect.right + this._leftOffset(e) &&
+             e.clientY  > absoluteRect.top + this._topOffset(e)   &&
+             e.clientY  < absoluteRect.bottom + this._topOffset(e);
+   },
+
+   _addMouseDownHandler: function( aDraggable )
+   {
+       htmlElement  = aDraggable.getMouseDownHTMLElement();
+      if ( htmlElement  != null ) { 
+         htmlElement.draggable = aDraggable;
+         Event.observe(htmlElement , "mousedown", this._onmousedown.bindAsEventListener(this));
+         Event.observe(htmlElement, "mousedown", this._mouseDown);
+      }
+   },
+
+   _activateRegisteredDropZones: function() {
+      var n = this.dropZones.length;
+      for ( var i = 0 ; i < n ; i++ ) {
+         var dropZone = this.dropZones[i];
+         if ( dropZone.canAccept(this.currentDragObjects) )
+            dropZone.activate();
+      }
+
+      this.activatedDropZones = true;
+   },
+
+   _deactivateRegisteredDropZones: function() {
+      var n = this.dropZones.length;
+      for ( var i = 0 ; i < n ; i++ )
+         this.dropZones[i].deactivate();
+      this.activatedDropZones = false;
+   },
+
+   _onmousedown: function () {
+     Event.observe(document.body, "mousemove", this._mouseMove);
+     Event.observe(document.body, "mouseup",  this._mouseUp);
+   },
+
+   _terminateEvent: function(e) {
+      if ( e.stopPropagation != undefined )
+         e.stopPropagation();
+      else if ( e.cancelBubble != undefined )
+         e.cancelBubble = true;
+
+      if ( e.preventDefault != undefined )
+         e.preventDefault();
+      else
+         e.returnValue = false;
+   },
+
+
+          initializeEventHandlers: function() {
+             if ( typeof document.implementation != "undefined" &&
+                document.implementation.hasFeature("HTML",   "1.0") &&
+                document.implementation.hasFeature("Events", "2.0") &&
+                document.implementation.hasFeature("CSS",    "2.0") ) {
+                document.addEventListener("mouseup",   this._mouseUpHandler.bindAsEventListener(this),  false);
+                document.addEventListener("mousemove", this._mouseMoveHandler.bindAsEventListener(this), false);
+             }
+             else {
+                document.attachEvent( "onmouseup",   this._mouseUpHandler.bindAsEventListener(this) );
+                document.attachEvent( "onmousemove", this._mouseMoveHandler.bindAsEventListener(this) );
+             }
+          }
+       }
+
+       var dndMgr = new Rico.DragAndDrop();
+       dndMgr.initializeEventHandlers();
+
+
+//-------------------- ricoDraggable.js
+Rico.Draggable = Class.create();
+
+Rico.Draggable.prototype = {
+
+   initialize: function( type, htmlElement ) {
+      this.type          = type;
+      this.htmlElement   = $(htmlElement);
+      this.selected      = false;
+   },
+
+   /**
+    *   Returns the HTML element that should have a mouse down event
+    *   added to it in order to initiate a drag operation
+    *
+    **/
+   getMouseDownHTMLElement: function() {
+      return this.htmlElement;
+   },
+
+   select: function() {
+      this.selected = true;
+
+      if ( this.showingSelected )
+         return;
+
+      var htmlElement = this.getMouseDownHTMLElement();
+
+      var color = Rico.Color.createColorFromBackground(htmlElement);
+      color.isBright() ? color.darken(0.033) : color.brighten(0.033);
+
+      this.saveBackground = RicoUtil.getElementsComputedStyle(htmlElement, "backgroundColor", "background-color");
+      htmlElement.style.backgroundColor = color.asHex();
+      this.showingSelected = true;
+   },
+
+   deselect: function() {
+      this.selected = false;
+      if ( !this.showingSelected )
+         return;
+
+      var htmlElement = this.getMouseDownHTMLElement();
+
+      htmlElement.style.backgroundColor = this.saveBackground;
+      this.showingSelected = false;
+   },
+
+   isSelected: function() {
+      return this.selected;
+   },
+
+   startDrag: function() {
+   },
+
+   cancelDrag: function() {
+   },
+
+   endDrag: function() {
+   },
+
+   getSingleObjectDragGUI: function() {
+      return this.htmlElement;
+   },
+
+   getMultiObjectDragGUI: function( draggables ) {
+      return this.htmlElement;
+   },
+
+   getDroppedGUI: function() {
+      return this.htmlElement;
+   },
+
+   toString: function() {
+      return this.type + ":" + this.htmlElement + ":";
+   }
+
+}
+
+
+//-------------------- ricoDropzone.js
+Rico.Dropzone = Class.create();
+
+Rico.Dropzone.prototype = {
+
+   initialize: function( htmlElement ) {
+      this.htmlElement  = $(htmlElement);
+      this.absoluteRect = null;
+   },
+
+   getHTMLElement: function() {
+      return this.htmlElement;
+   },
+
+   clearPositionCache: function() {
+      this.absoluteRect = null;
+   },
+
+   getAbsoluteRect: function() {
+      if ( this.absoluteRect == null ) {
+         var htmlElement = this.getHTMLElement();
+         var pos = RicoUtil.toViewportPosition(htmlElement);
+
+         this.absoluteRect = {
+            top:    pos.y,
+            left:   pos.x,
+            bottom: pos.y + htmlElement.offsetHeight,
+            right:  pos.x + htmlElement.offsetWidth
+         };
+      }
+      return this.absoluteRect;
+   },
+
+   activate: function() {
+      var htmlElement = this.getHTMLElement();
+      if (htmlElement == null  || this.showingActive)
+         return;
+
+      this.showingActive = true;
+      this.saveBackgroundColor = htmlElement.style.backgroundColor;
+
+      var fallbackColor = "#ffea84";
+      var currentColor = Rico.Color.createColorFromBackground(htmlElement);
+      if ( currentColor == null )
+         htmlElement.style.backgroundColor = fallbackColor;
+      else {
+         currentColor.isBright() ? currentColor.darken(0.2) : currentColor.brighten(0.2);
+         htmlElement.style.backgroundColor = currentColor.asHex();
+      }
+   },
+
+   deactivate: function() {
+      var htmlElement = this.getHTMLElement();
+      if (htmlElement == null || !this.showingActive)
+         return;
+
+      htmlElement.style.backgroundColor = this.saveBackgroundColor;
+      this.showingActive = false;
+      this.saveBackgroundColor = null;
+   },
+
+   showHover: function() {
+      var htmlElement = this.getHTMLElement();
+      if ( htmlElement == null || this.showingHover )
+         return;
+
+      this.saveBorderWidth = htmlElement.style.borderWidth;
+      this.saveBorderStyle = htmlElement.style.borderStyle;
+      this.saveBorderColor = htmlElement.style.borderColor;
+
+      this.showingHover = true;
+      htmlElement.style.borderWidth = "1px";
+      htmlElement.style.borderStyle = "solid";
+      //htmlElement.style.borderColor = "#ff9900";
+      htmlElement.style.borderColor = "#ffff00";
+   },
+
+   hideHover: function() {
+      var htmlElement = this.getHTMLElement();
+      if ( htmlElement == null || !this.showingHover )
+         return;
+
+      htmlElement.style.borderWidth = this.saveBorderWidth;
+      htmlElement.style.borderStyle = this.saveBorderStyle;
+      htmlElement.style.borderColor = this.saveBorderColor;
+      this.showingHover = false;
+   },
+
+   canAccept: function(draggableObjects) {
+      return true;
+   },
+
+   accept: function(draggableObjects) {
+      var htmlElement = this.getHTMLElement();
+      if ( htmlElement == null )
+         return;
+
+      n = draggableObjects.length;
+      for ( var i = 0 ; i < n ; i++ )
+      {
+         var theGUI = draggableObjects[i].getDroppedGUI();
+         if ( RicoUtil.getElementsComputedStyle( theGUI, "position" ) == "absolute" )
+         {
+            theGUI.style.position = "static";
+            theGUI.style.top = "";
+            theGUI.style.top = "";
+         }
+         htmlElement.appendChild(theGUI);
+      }
+   }
+}
+
+
+//-------------------- ricoEffects.js
+
+Rico.Effect = {};
+
+Rico.Effect.SizeAndPosition = Class.create();
+Rico.Effect.SizeAndPosition.prototype = {
+
+   initialize: function(element, x, y, w, h, duration, steps, options) {
+      this.element = $(element);
+      this.x = x;
+      this.y = y;
+      this.w = w;
+      this.h = h;
+      this.duration = duration;
+      this.steps    = steps;
+      this.options  = arguments[7] || {};
+
+      this.sizeAndPosition();
+   },
+
+   sizeAndPosition: function() {
+      if (this.isFinished()) {
+         if(this.options.complete) this.options.complete(this);
+         return;
+      }
+
+      if (this.timer)
+         clearTimeout(this.timer);
+
+      var stepDuration = Math.round(this.duration/this.steps) ;
+
+      // Get original values: x,y = top left corner;  w,h = width height
+      var currentX = this.element.offsetLeft;
+      var currentY = this.element.offsetTop;
+      var currentW = this.element.offsetWidth;
+      var currentH = this.element.offsetHeight;
+
+      // If values not set, or zero, we do not modify them, and take original as final as well
+      this.x = (this.x) ? this.x : currentX;
+      this.y = (this.y) ? this.y : currentY;
+      this.w = (this.w) ? this.w : currentW;
+      this.h = (this.h) ? this.h : currentH;
+
+      // how much do we need to modify our values for each step?
+      var difX = this.steps >  0 ? (this.x - currentX)/this.steps : 0;
+      var difY = this.steps >  0 ? (this.y - currentY)/this.steps : 0;
+      var difW = this.steps >  0 ? (this.w - currentW)/this.steps : 0;
+      var difH = this.steps >  0 ? (this.h - currentH)/this.steps : 0;
+
+      this.moveBy(difX, difY);
+      this.resizeBy(difW, difH);
+
+      this.duration -= stepDuration;
+      this.steps--;
+
+      this.timer = setTimeout(this.sizeAndPosition.bind(this), stepDuration);
+   },
+
+   isFinished: function() {
+      return this.steps <= 0;
+   },
+
+   moveBy: function( difX, difY ) {
+      var currentLeft = this.element.offsetLeft;
+      var currentTop  = this.element.offsetTop;
+      var intDifX     = parseInt(difX);
+      var intDifY     = parseInt(difY);
+
+      var style = this.element.style;
+      if ( intDifX != 0 )
+         style.left = (currentLeft + intDifX) + "px";
+      if ( intDifY != 0 )
+         style.top  = (currentTop + intDifY) + "px";
+   },
+
+   resizeBy: function( difW, difH ) {
+      var currentWidth  = this.element.offsetWidth;
+      var currentHeight = this.element.offsetHeight;
+      var intDifW       = parseInt(difW);
+      var intDifH       = parseInt(difH);
+
+      var style = this.element.style;
+      if ( intDifW != 0 )
+         style.width   = (currentWidth  + intDifW) + "px";
+      if ( intDifH != 0 )
+         style.height  = (currentHeight + intDifH) + "px";
+   }
+}
+
+Rico.Effect.Size = Class.create();
+Rico.Effect.Size.prototype = {
+
+   initialize: function(element, w, h, duration, steps, options) {
+      new Rico.Effect.SizeAndPosition(element, null, null, w, h, duration, steps, options);
+  }
+}
+
+Rico.Effect.Position = Class.create();
+Rico.Effect.Position.prototype = {
+
+   initialize: function(element, x, y, duration, steps, options) {
+      new Rico.Effect.SizeAndPosition(element, x, y, null, null, duration, steps, options);
+  }
+}
+
+Rico.Effect.Round = Class.create();
+Rico.Effect.Round.prototype = {
+
+   initialize: function(tagName, className, options) {
+      var elements = document.getElementsByTagAndClassName(tagName,className);
+      for ( var i = 0 ; i < elements.length ; i++ )
+         Rico.Corner.round( elements[i], options );
+   }
+};
+
+Rico.Effect.FadeTo = Class.create();
+Rico.Effect.FadeTo.prototype = {
+
+   initialize: function( element, opacity, duration, steps, options) {
+      this.element  = $(element);
+      this.opacity  = opacity;
+      this.duration = duration;
+      this.steps    = steps;
+      this.options  = arguments[4] || {};
+      this.fadeTo();
+   },
+
+   fadeTo: function() {
+      if (this.isFinished()) {
+         if(this.options.complete) this.options.complete(this);
+         return;
+      }
+
+      if (this.timer)
+         clearTimeout(this.timer);
+
+      var stepDuration = Math.round(this.duration/this.steps) ;
+      var currentOpacity = this.getElementOpacity();
+      var delta = this.steps > 0 ? (this.opacity - currentOpacity)/this.steps : 0;
+
+      this.changeOpacityBy(delta);
+      this.duration -= stepDuration;
+      this.steps--;
+
+      this.timer = setTimeout(this.fadeTo.bind(this), stepDuration);
+   },
+
+   changeOpacityBy: function(v) {
+      var currentOpacity = this.getElementOpacity();
+      var newOpacity = Math.max(0, Math.min(currentOpacity+v, 1));
+      this.element.ricoOpacity = newOpacity;
+
+      this.element.style.filter = "alpha(opacity:"+Math.round(newOpacity*100)+")";
+      this.element.style.opacity = newOpacity; /*//*/;
+   },
+
+   isFinished: function() {
+      return this.steps <= 0;
+   },
+
+   getElementOpacity: function() {
+      if ( this.element.ricoOpacity == undefined ) {
+         var opacity = RicoUtil.getElementsComputedStyle(this.element, 'opacity');
+         this.element.ricoOpacity = opacity != undefined ? opacity : 1.0;
+      }
+      return parseFloat(this.element.ricoOpacity);
+   }
+}
+
+Rico.Effect.AccordionSize = Class.create();
+
+Rico.Effect.AccordionSize.prototype = {
+
+   initialize: function(e1, e2, start, end, duration, steps, options) {
+      this.e1       = $(e1);
+      this.e2       = $(e2);
+      this.start    = start;
+      this.end      = end;
+      this.duration = duration;
+      this.steps    = steps;
+      this.options  = arguments[6] || {};
+
+      this.accordionSize();
+   },
+
+   accordionSize: function() {
+
+      if (this.isFinished()) {
+         // just in case there are round errors or such...
+         this.e1.style.height = this.start + "px";
+         this.e2.style.height = this.end + "px";
+
+         if(this.options.complete)
+            this.options.complete(this);
+         return;
+      }
+
+      if (this.timer)
+         clearTimeout(this.timer);
+
+      var stepDuration = Math.round(this.duration/this.steps) ;
+
+      var diff = this.steps > 0 ? (parseInt(this.e1.offsetHeight) - this.start)/this.steps : 0;
+      this.resizeBy(diff);
+
+      this.duration -= stepDuration;
+      this.steps--;
+
+      this.timer = setTimeout(this.accordionSize.bind(this), stepDuration);
+   },
+
+   isFinished: function() {
+      return this.steps <= 0;
+   },
+
+   resizeBy: function(diff) {
+      var h1Height = this.e1.offsetHeight;
+      var h2Height = this.e2.offsetHeight;
+      var intDiff = parseInt(diff);
+      if ( diff != 0 ) {
+         this.e1.style.height = (h1Height - intDiff) + "px";
+         this.e2.style.height = (h2Height + intDiff) + "px";
+      }
+   }
+
+};
+
+
+//-------------------- ricoLiveGrid.js
+// Rico.LiveGridMetaData -----------------------------------------------------
+
+Rico.LiveGridMetaData = Class.create();
+
+Rico.LiveGridMetaData.prototype = {
+
+   initialize: function( pageSize, totalRows, columnCount, options ) {
+      this.pageSize  = pageSize;
+      this.totalRows = totalRows;
+      this.setOptions(options);
+      this.ArrowHeight = 16;
+      this.columnCount = columnCount;
+   },
+
+   setOptions: function(options) {
+      this.options = {
+         largeBufferSize    : 7.0,   // 7 pages
+         nearLimitFactor    : 0.2    // 20% of buffer
+      };
+      Object.extend(this.options, options || {});
+   },
+
+   getPageSize: function() {
+      return this.pageSize;
+   },
+
+   getTotalRows: function() {
+      return this.totalRows;
+   },
+
+   setTotalRows: function(n) {
+      this.totalRows = n;
+   },
+
+   getLargeBufferSize: function() {
+      return parseInt(this.options.largeBufferSize * this.pageSize);
+   },
+
+   getLimitTolerance: function() {
+      return parseInt(this.getLargeBufferSize() * this.options.nearLimitFactor);
+   }
+};
+
+// Rico.LiveGridScroller -----------------------------------------------------
+
+Rico.LiveGridScroller = Class.create();
+
+Rico.LiveGridScroller.prototype = {
+
+   initialize: function(liveGrid, viewPort) {
+      this.isIE = navigator.userAgent.toLowerCase().indexOf("msie") >= 0;
+      this.liveGrid = liveGrid;
+      this.metaData = liveGrid.metaData;
+      this.createScrollBar();
+      this.scrollTimeout = null;
+      this.lastScrollPos = 0;
+      this.viewPort = viewPort;
+      this.rows = new Array();
+   },
+
+   isUnPlugged: function() {
+      return this.scrollerDiv.onscroll == null;
+   },
+
+   plugin: function() {
+      this.scrollerDiv.onscroll = this.handleScroll.bindAsEventListener(this);
+   },
+
+   unplug: function() {
+      this.scrollerDiv.onscroll = null;
+   },
+
+   sizeIEHeaderHack: function() {
+      if ( !this.isIE ) return;
+      var headerTable = $(this.liveGrid.tableId + "_header");
+      if ( headerTable )
+         headerTable.rows[0].cells[0].style.width =
+            (headerTable.rows[0].cells[0].offsetWidth + 1) + "px";
+   },
+
+   createScrollBar: function() {
+      var visibleHeight = this.liveGrid.viewPort.visibleHeight();
+      // create the outer div...
+      this.scrollerDiv  = document.createElement("div");
+      var scrollerStyle = this.scrollerDiv.style;
+      scrollerStyle.borderRight = this.liveGrid.options.scrollerBorderRight;
+      scrollerStyle.position    = "relative";
+      scrollerStyle.left        = this.isIE ? "-6px" : "-3px";
+      scrollerStyle.width       = "19px";
+      scrollerStyle.height      = visibleHeight + "px";
+      scrollerStyle.overflow    = "auto";
+
+      // create the inner div...
+      this.heightDiv = document.createElement("div");
+      this.heightDiv.style.width  = "1px";
+
+      this.heightDiv.style.height = parseInt(visibleHeight *
+                        this.metaData.getTotalRows()/this.metaData.getPageSize()) + "px" ;
+      this.scrollerDiv.appendChild(this.heightDiv);
+      this.scrollerDiv.onscroll = this.handleScroll.bindAsEventListener(this);
+
+     var table = this.liveGrid.table;
+     table.parentNode.parentNode.insertBefore( this.scrollerDiv, table.parentNode.nextSibling );
+         var eventName = this.isIE ? "mousewheel" : "DOMMouseScroll";
+         Event.observe(table, eventName, 
+                       function(evt) {
+                          if (evt.wheelDelta>=0 || evt.detail < 0) //wheel-up
+                             this.scrollerDiv.scrollTop -= (2*this.viewPort.rowHeight);
+                          else
+                             this.scrollerDiv.scrollTop += (2*this.viewPort.rowHeight);
+                          this.handleScroll(false);
+                       }.bindAsEventListener(this), 
+                       false);
+     },
+
+   updateSize: function() {
+      var table = this.liveGrid.table;
+      var visibleHeight = this.viewPort.visibleHeight();
+      this.heightDiv.style.height = parseInt(visibleHeight *
+                                  this.metaData.getTotalRows()/this.metaData.getPageSize()) + "px";
+   },
+
+   rowToPixel: function(rowOffset) {
+      return (rowOffset / this.metaData.getTotalRows()) * this.heightDiv.offsetHeight
+   },
+   
+   moveScroll: function(rowOffset) {
+      this.scrollerDiv.scrollTop = this.rowToPixel(rowOffset);
+      if ( this.metaData.options.onscroll )
+         this.metaData.options.onscroll( this.liveGrid, rowOffset );
+   },
+
+   handleScroll: function() {
+     if ( this.scrollTimeout )
+         clearTimeout( this.scrollTimeout );
+
+    var scrollDiff = this.lastScrollPos-this.scrollerDiv.scrollTop;
+    if (scrollDiff != 0.00) {
+       var r = this.scrollerDiv.scrollTop % this.viewPort.rowHeight;
+       if (r != 0) {
+          this.unplug();
+          if ( scrollDiff < 0 ) {
+             this.scrollerDiv.scrollTop += (this.viewPort.rowHeight-r);
+          } else {
+             this.scrollerDiv.scrollTop -= r;
+          }
+          this.plugin();
+       }
+    }
+    var contentOffset = parseInt(this.scrollerDiv.scrollTop / this.viewPort.rowHeight);
+    this.liveGrid.requestContentRefresh(contentOffset);
+    this.viewPort.scrollTo(this.scrollerDiv.scrollTop);
+
+    if ( this.metaData.options.onscroll )
+       this.metaData.options.onscroll( this.liveGrid, contentOffset );
+
+    this.scrollTimeout = setTimeout(this.scrollIdle.bind(this), 1200 );
+    this.lastScrollPos = this.scrollerDiv.scrollTop;
+
+   },
+
+   scrollIdle: function() {
+      if ( this.metaData.options.onscrollidle )
+         this.metaData.options.onscrollidle();
+   }
+};
+
+// Rico.LiveGridBuffer -----------------------------------------------------
+
+Rico.LiveGridBuffer = Class.create();
+
+Rico.LiveGridBuffer.prototype = {
+
+   initialize: function(metaData, viewPort) {
+      this.startPos = 0;
+      this.size     = 0;
+      this.metaData = metaData;
+      this.rows     = new Array();
+      this.updateInProgress = false;
+      this.viewPort = viewPort;
+      this.maxBufferSize = metaData.getLargeBufferSize() * 2;
+      this.maxFetchSize = metaData.getLargeBufferSize();
+      this.lastOffset = 0;
+   },
+
+   getBlankRow: function() {
+      if (!this.blankRow ) {
+         this.blankRow = new Array();
+         for ( var i=0; i < this.metaData.columnCount ; i++ ) 
+            this.blankRow[i] = "&nbsp;";
+     }
+     return this.blankRow;
+   },
+
+   loadRows: function(ajaxResponse) {
+      var rowsElement = ajaxResponse.getElementsByTagName('rows')[0];
+      this.updateUI = rowsElement.getAttribute("update_ui") == "true"
+      var newRows = new Array()
+      var trs = rowsElement.getElementsByTagName("tr");
+      for ( var i=0 ; i < trs.length; i++ ) {
+         var row = newRows[i] = new Array(); 
+         var cells = trs[i].getElementsByTagName("td");
+         for ( var j=0; j < cells.length ; j++ ) {
+            var cell = cells[j];
+            var convertSpaces = cell.getAttribute("convert_spaces") == "true";
+            var cellContent = RicoUtil.getContentAsString(cell);
+            row[j] = convertSpaces ? this.convertSpaces(cellContent) : cellContent;
+            if (!row[j]) 
+               row[j] = '&nbsp;';
+         }
+      }
+      return newRows;
+   },
+      
+   update: function(ajaxResponse, start) {
+     var newRows = this.loadRows(ajaxResponse);
+      if (this.rows.length == 0) { // initial load
+         this.rows = newRows;
+         this.size = this.rows.length;
+         this.startPos = start;
+         return;
+      }
+      if (start > this.startPos) { //appending
+         if (this.startPos + this.rows.length < start) {
+            this.rows =  newRows;
+            this.startPos = start;//
+         } else {
+              this.rows = this.rows.concat( newRows.slice(0, newRows.length));
+            if (this.rows.length > this.maxBufferSize) {
+               var fullSize = this.rows.length;
+               this.rows = this.rows.slice(this.rows.length - this.maxBufferSize, this.rows.length)
+               this.startPos = this.startPos +  (fullSize - this.rows.length);
+            }
+         }
+      } else { //prepending
+         if (start + newRows.length < this.startPos) {
+            this.rows =  newRows;
+         } else {
+            this.rows = newRows.slice(0, this.startPos).concat(this.rows);
+            if (this.rows.length > this.maxBufferSize) 
+               this.rows = this.rows.slice(0, this.maxBufferSize)
+         }
+         this.startPos =  start;
+      }
+      this.size = this.rows.length;
+   },
+   
+   clear: function() {
+      this.rows = new Array();
+      this.startPos = 0;
+      this.size = 0;
+   },
+
+   isOverlapping: function(start, size) {
+      return ((start < this.endPos()) && (this.startPos < start + size)) || (this.endPos() == 0)
+   },
+
+   isInRange: function(position) {
+      return (position >= this.startPos) && (position + this.metaData.getPageSize() <= this.endPos()); 
+             //&& this.size()  != 0;
+   },
+
+   isNearingTopLimit: function(position) {
+      return position - this.startPos < this.metaData.getLimitTolerance();
+   },
+
+   endPos: function() {
+      return this.startPos + this.rows.length;
+   },
+   
+   isNearingBottomLimit: function(position) {
+      return this.endPos() - (position + this.metaData.getPageSize()) < this.metaData.getLimitTolerance();
+   },
+
+   isAtTop: function() {
+      return this.startPos == 0;
+   },
+
+   isAtBottom: function() {
+      return this.endPos() == this.metaData.getTotalRows();
+   },
+
+   isNearingLimit: function(position) {
+      return ( !this.isAtTop()    && this.isNearingTopLimit(position)) ||
+             ( !this.isAtBottom() && this.isNearingBottomLimit(position) )
+   },
+
+   getFetchSize: function(offset) {
+      var adjustedOffset = this.getFetchOffset(offset);
+      var adjustedSize = 0;
+      if (adjustedOffset >= this.startPos) { //apending
+         var endFetchOffset = this.maxFetchSize  + adjustedOffset;
+         if (endFetchOffset > this.metaData.totalRows)
+            endFetchOffset = this.metaData.totalRows;
+         adjustedSize = endFetchOffset - adjustedOffset;  
+                       if(adjustedOffset == 0 && adjustedSize < this.maxFetchSize){
+                          adjustedSize = this.maxFetchSize;
+                       }
+      } else {//prepending
+         var adjustedSize = this.startPos - adjustedOffset;
+         if (adjustedSize > this.maxFetchSize)
+            adjustedSize = this.maxFetchSize;
+      }
+      return adjustedSize;
+   }, 
+
+   getFetchOffset: function(offset) {
+      var adjustedOffset = offset;
+      if (offset > this.startPos)  //apending
+         adjustedOffset = (offset > this.endPos()) ? offset :  this.endPos(); 
+      else { //prepending
+         if (offset + this.maxFetchSize >= this.startPos) {
+            var adjustedOffset = this.startPos - this.maxFetchSize;
+            if (adjustedOffset < 0)
+               adjustedOffset = 0;
+         }
+      }
+      this.lastOffset = adjustedOffset;
+      return adjustedOffset;
+   },
+
+   getRows: function(start, count) {
+      var begPos = start - this.startPos
+      var endPos = begPos + count
+
+      // er? need more data...
+      if ( endPos > this.size )
+         endPos = this.size
+
+      var results = new Array()
+      var index = 0;
+      for ( var i=begPos ; i < endPos; i++ ) {
+         results[index++] = this.rows[i]
+      }
+      return results
+   },
+
+   convertSpaces: function(s) {
+      return s.split(" ").join("&nbsp;");
+   }
+
+};
+
+
+//Rico.GridViewPort --------------------------------------------------
+Rico.GridViewPort = Class.create();
+
+Rico.GridViewPort.prototype = {
+
+   initialize: function(table, rowHeight, visibleRows, buffer, liveGrid) {
+      this.lastDisplayedStartPos = 0;
+      this.div = table.parentNode;
+      this.table = table
+      this.rowHeight = rowHeight;
+      this.div.style.height = (this.rowHeight * visibleRows) + "px";
+      this.div.style.overflow = "hidden";
+      this.buffer = buffer;
+      this.liveGrid = liveGrid;
+      this.visibleRows = visibleRows + 1;
+      this.lastPixelOffset = 0;
+      this.startPos = 0;
+   },
+
+   populateRow: function(htmlRow, row) {
+      for (var j=0; j < row.length; j++) {
+         htmlRow.cells[j].innerHTML = row[j]
+      }
+   },
+   
+   bufferChanged: function() {
+      this.refreshContents( parseInt(this.lastPixelOffset / this.rowHeight));
+   },
+   
+   clearRows: function() {
+      if (!this.isBlank) {
+         this.liveGrid.table.className = this.liveGrid.options.loadingClass;
+         for (var i=0; i < this.visibleRows; i++)
+            this.populateRow(this.table.rows[i], this.buffer.getBlankRow());
+         this.isBlank = true;
+      }
+   },
+   
+   clearContents: function() {   
+      this.clearRows();
+      this.scrollTo(0);
+      this.startPos = 0;
+      this.lastStartPos = -1;   
+   },
+   
+   refreshContents: function(startPos) {
+      if (startPos == this.lastRowPos && !this.isPartialBlank && !this.isBlank) {
+         return;
+      }
+      if ((startPos + this.visibleRows < this.buffer.startPos)  
+          || (this.buffer.startPos + this.buffer.size < startPos) 
+          || (this.buffer.size == 0)) {
+         this.clearRows();
+         return;
+      }
+      this.isBlank = false;
+      var viewPrecedesBuffer = this.buffer.startPos > startPos
+      var contentStartPos = viewPrecedesBuffer ? this.buffer.startPos: startPos; 
+      var contentEndPos = (this.buffer.startPos + this.buffer.size < startPos + this.visibleRows) 
+                                 ? this.buffer.startPos + this.buffer.size
+                                 : startPos + this.visibleRows;
+      var rowSize = contentEndPos - contentStartPos;
+      var rows = this.buffer.getRows(contentStartPos, rowSize ); 
+      var blankSize = this.visibleRows - rowSize;
+      var blankOffset = viewPrecedesBuffer ? 0: rowSize;
+      var contentOffset = viewPrecedesBuffer ? blankSize: 0;
+
+      for (var i=0; i < rows.length; i++) {//initialize what we have
+        this.populateRow(this.table.rows[i + contentOffset], rows[i]);
+      }
+      for (var i=0; i < blankSize; i++) {// blank out the rest 
+        this.populateRow(this.table.rows[i + blankOffset], this.buffer.getBlankRow());
+      }
+      this.isPartialBlank = blankSize > 0;
+      this.lastRowPos = startPos;
+
+       this.liveGrid.table.className = this.liveGrid.options.tableClass;
+       // Check if user has set a onRefreshComplete function
+       var onRefreshComplete = this.liveGrid.options.onRefreshComplete;
+       if (onRefreshComplete != null)
+           onRefreshComplete();
+   },
+
+   scrollTo: function(pixelOffset) {      
+      if (this.lastPixelOffset == pixelOffset)
+         return;
+
+      this.refreshContents(parseInt(pixelOffset / this.rowHeight))
+      this.div.scrollTop = pixelOffset % this.rowHeight        
+      
+      this.lastPixelOffset = pixelOffset;
+   },
+   
+   visibleHeight: function() {
+      return parseInt(RicoUtil.getElementsComputedStyle(this.div, 'height'));
+   }
+
+};
+
+
+Rico.LiveGridRequest = Class.create();
+Rico.LiveGridRequest.prototype = {
+   initialize: function( requestOffset, options ) {
+      this.requestOffset = requestOffset;
+   }
+};
+
+// Rico.LiveGrid -----------------------------------------------------
+
+Rico.LiveGrid = Class.create();
+
+Rico.LiveGrid.prototype = {
+
+   initialize: function( tableId, visibleRows, totalRows, url, options, ajaxOptions ) {
+
+     this.options = {
+                tableClass:           $(tableId).className,
+                loadingClass:         $(tableId).className,
+                scrollerBorderRight: '1px solid #ababab',
+                bufferTimeout:        20000,
+                sortAscendImg:        'images/sort_asc.gif',
+                sortDescendImg:       'images/sort_desc.gif',
+                sortImageWidth:       9,
+                sortImageHeight:      5,
+                ajaxSortURLParms:     [],
+                onRefreshComplete:    null,
+                requestParameters:    null,
+                inlineStyles:         true
+                };
+      Object.extend(this.options, options || {});
+
+      this.ajaxOptions = {parameters: null};
+      Object.extend(this.ajaxOptions, ajaxOptions || {});
+
+      this.tableId     = tableId; 
+      this.table       = $(tableId);
+
+      this.addLiveGridHtml();
+
+      var columnCount  = this.table.rows[0].cells.length;
+      this.metaData    = new Rico.LiveGridMetaData(visibleRows, totalRows, columnCount, options);
+      this.buffer      = new Rico.LiveGridBuffer(this.metaData);
+
+      var rowCount = this.table.rows.length;
+      this.viewPort =  new Rico.GridViewPort(this.table, 
+                                            this.table.offsetHeight/rowCount,
+                                            visibleRows,
+                                            this.buffer, this);
+      this.scroller    = new Rico.LiveGridScroller(this,this.viewPort);
+      this.options.sortHandler = this.sortHandler.bind(this);
+
+      if ( $(tableId + '_header') )
+         this.sort = new Rico.LiveGridSort(tableId + '_header', this.options)
+
+      this.processingRequest = null;
+      this.unprocessedRequest = null;
+
+      this.initAjax(url);
+      if ( this.options.prefetchBuffer || this.options.prefetchOffset > 0) {
+         var offset = 0;
+         if (this.options.offset ) {
+            offset = this.options.offset;            
+            this.scroller.moveScroll(offset);
+            this.viewPort.scrollTo(this.scroller.rowToPixel(offset));            
+         }
+         if (this.options.sortCol) {
+             this.sortCol = options.sortCol;
+             this.sortDir = options.sortDir;
+         }
+         this.requestContentRefresh(offset);
+      }
+   },
+
+   addLiveGridHtml: function() {
+     // Check to see if need to create a header table.
+     if (this.table.getElementsByTagName("thead").length > 0){
+       // Create Table this.tableId+'_header'
+       var tableHeader = this.table.cloneNode(true);
+       tableHeader.setAttribute('id', this.tableId+'_header');
+       tableHeader.setAttribute('class', this.table.className+'_header');
+
+       // Clean up and insert
+       for( var i = 0; i < tableHeader.tBodies.length; i++ ) 
+       tableHeader.removeChild(tableHeader.tBodies[i]);
+       this.table.deleteTHead();
+       this.table.parentNode.insertBefore(tableHeader,this.table);
+     }
+
+    new Insertion.Before(this.table, "<div id='"+this.tableId+"_container'></div>");
+    this.table.previousSibling.appendChild(this.table);
+    new Insertion.Before(this.table,"<div id='"+this.tableId+"_viewport' style='float:left;'></div>");
+    this.table.previousSibling.appendChild(this.table);
+   },
+
+
+   resetContents: function() {
+      this.scroller.moveScroll(0);
+      this.buffer.clear();
+      this.viewPort.clearContents();
+   },
+   
+   sortHandler: function(column) {
+          if(!column) return ;
+      this.sortCol = column.name;
+      this.sortDir = column.currentSort;
+
+      this.resetContents();
+      this.requestContentRefresh(0) 
+   },
+
+   adjustRowSize: function() {
+         
+       },
+       
+   setTotalRows: function( newTotalRows ) {
+      this.resetContents();
+      this.metaData.setTotalRows(newTotalRows);
+      this.scroller.updateSize();
+   },
+
+   initAjax: function(url) {
+      ajaxEngine.registerRequest( this.tableId + '_request', url );
+      ajaxEngine.registerAjaxObject( this.tableId + '_updater', this );
+   },
+
+   invokeAjax: function() {
+   },
+
+   handleTimedOut: function() {
+      //server did not respond in 4 seconds... assume that there could have been
+      //an error or something, and allow requests to be processed again...
+      this.processingRequest = null;
+      this.processQueuedRequest();
+   },
+
+   fetchBuffer: function(offset) {
+      if ( this.buffer.isInRange(offset) &&
+         !this.buffer.isNearingLimit(offset)) {
+         return;
+         }
+      if (this.processingRequest) {
+          this.unprocessedRequest = new Rico.LiveGridRequest(offset);
+         return;
+      }
+      var bufferStartPos = this.buffer.getFetchOffset(offset);
+      this.processingRequest = new Rico.LiveGridRequest(offset);
+      this.processingRequest.bufferOffset = bufferStartPos;   
+      var fetchSize = this.buffer.getFetchSize(offset);
+      var partialLoaded = false;
+      
+      var queryString
+      if (this.options.requestParameters)
+         queryString = this._createQueryString(this.options.requestParameters, 0);
+
+        queryString = (queryString == null) ? '' : queryString+'&';
+        queryString  = queryString+'id='+this.tableId+'&page_size='+fetchSize+'&offset='+bufferStartPos;
+        if (this.sortCol)
+            queryString = queryString+'&sort_col='+escape(this.sortCol)+'&sort_dir='+this.sortDir;
+
+        this.ajaxOptions.parameters = queryString;
+
+       ajaxEngine.sendRequest( this.tableId + '_request', this.ajaxOptions );
+
+       this.timeoutHandler = setTimeout( this.handleTimedOut.bind(this), this.options.bufferTimeout);
+
+   },
+
+   setRequestParams: function() {
+      this.options.requestParameters = [];
+      for ( var i=0 ; i < arguments.length ; i++ )
+         this.options.requestParameters[i] = arguments[i];
+   },
+
+   requestContentRefresh: function(contentOffset) {
+      this.fetchBuffer(contentOffset);
+   },
+
+   ajaxUpdate: function(ajaxResponse) {
+      try {
+         clearTimeout( this.timeoutHandler );
+         this.buffer.update(ajaxResponse,this.processingRequest.bufferOffset);
+         this.viewPort.bufferChanged();
+      }
+      catch(err) {}
+      finally {this.processingRequest = null; }
+      this.processQueuedRequest();
+   },
+
+   _createQueryString: function( theArgs, offset ) {
+      var queryString = ""
+      if (!theArgs)
+          return queryString;
+
+      for ( var i = offset ; i < theArgs.length ; i++ ) {
+          if ( i != offset )
+            queryString += "&";
+
+          var anArg = theArgs[i];
+
+          if ( anArg.name != undefined && anArg.value != undefined ) {
+            queryString += anArg.name +  "=" + escape(anArg.value);
+          }
+          else {
+             var ePos  = anArg.indexOf('=');
+             var argName  = anArg.substring( 0, ePos );
+             var argValue = anArg.substring( ePos + 1 );
+             queryString += argName + "=" + escape(argValue);
+          }
+      }
+      return queryString;
+   },
+
+   processQueuedRequest: function() {
+      if (this.unprocessedRequest != null) {
+         this.requestContentRefresh(this.unprocessedRequest.requestOffset);
+         this.unprocessedRequest = null
+      }
+   }
+};
+
+
+//-------------------- ricoLiveGridSort.js
+Rico.LiveGridSort = Class.create();
+
+Rico.LiveGridSort.prototype = {
+
+   initialize: function(headerTableId, options) {
+      this.headerTableId = headerTableId;
+      this.headerTable   = $(headerTableId);
+      this.options = options;
+      this.setOptions();
+      this.applySortBehavior();
+
+      if ( this.options.sortCol ) {
+         this.setSortUI( this.options.sortCol, this.options.sortDir );
+      }
+   },
+
+   setSortUI: function( columnName, sortDirection ) {
+      var cols = this.options.columns;
+      for ( var i = 0 ; i < cols.length ; i++ ) {
+         if ( cols[i].name == columnName ) {
+            this.setColumnSort(i, sortDirection);
+            break;
+         }
+      }
+   },
+
+   setOptions: function() {
+      // preload the images...
+      new Image().src = this.options.sortAscendImg;
+      new Image().src = this.options.sortDescendImg;
+
+      this.sort = this.options.sortHandler;
+      if ( !this.options.columns )
+         this.options.columns = this.introspectForColumnInfo();
+      else {
+         // allow client to pass { columns: [ ["a", true], ["b", false] ] }
+         // and convert to an array of Rico.TableColumn objs...
+         this.options.columns = this.convertToTableColumns(this.options.columns);
+      }
+   },
+
+   applySortBehavior: function() {
+      var headerRow   = this.headerTable.rows[0];
+      var headerCells = headerRow.cells;
+      for ( var i = 0 ; i < headerCells.length ; i++ ) {
+         this.addSortBehaviorToColumn( i, headerCells[i] );
+      }
+   },
+
+   addSortBehaviorToColumn: function( n, cell ) {
+      if ( this.options.columns[n].isSortable() ) {
+         cell.id            = this.headerTableId + '_' + n;
+         cell.style.cursor  = 'pointer';
+         cell.onclick       = this.headerCellClicked.bindAsEventListener(this);
+         cell.innerHTML     = cell.innerHTML + '<span id="' + this.headerTableId + '_img_' + n + '">'
+                           + '&nbsp;&nbsp;&nbsp;</span>';
+      }
+   },
+
+   // event handler....
+   headerCellClicked: function(evt) {
+      var eventTarget = evt.target ? evt.target : evt.srcElement;
+      var cellId = eventTarget.id;
+      var columnNumber = parseInt(cellId.substring( cellId.lastIndexOf('_') + 1 ));
+      var sortedColumnIndex = this.getSortedColumnIndex();
+      if ( sortedColumnIndex != -1 ) {
+         if ( sortedColumnIndex != columnNumber ) {
+            this.removeColumnSort(sortedColumnIndex);
+            this.setColumnSort(columnNumber, Rico.TableColumn.SORT_ASC);
+         }
+         else
+            this.toggleColumnSort(sortedColumnIndex);
+      }
+      else
+         this.setColumnSort(columnNumber, Rico.TableColumn.SORT_ASC);
+
+      if (this.options.sortHandler) {
+         this.options.sortHandler(this.options.columns[columnNumber]);
+      }
+   },
+
+   removeColumnSort: function(n) {
+      this.options.columns[n].setUnsorted();
+      this.setSortImage(n);
+   },
+
+   setColumnSort: function(n, direction) {
+       if(isNaN(n)) return ;
+      this.options.columns[n].setSorted(direction);
+      this.setSortImage(n);
+   },
+
+   toggleColumnSort: function(n) {
+      this.options.columns[n].toggleSort();
+      this.setSortImage(n);
+   },
+
+   setSortImage: function(n) {
+      var sortDirection = this.options.columns[n].getSortDirection();
+
+      var sortImageSpan = $( this.headerTableId + '_img_' + n );
+      if ( sortDirection == Rico.TableColumn.UNSORTED )
+         sortImageSpan.innerHTML = '&nbsp;&nbsp;';
+      else if ( sortDirection == Rico.TableColumn.SORT_ASC )
+         sortImageSpan.innerHTML = '&nbsp;&nbsp;<img width="'  + this.options.sortImageWidth    + '" ' +
+                                                     'height="'+ this.options.sortImageHeight   + '" ' +
+                                                     'src="'   + this.options.sortAscendImg + '"/>';
+      else if ( sortDirection == Rico.TableColumn.SORT_DESC )
+         sortImageSpan.innerHTML = '&nbsp;&nbsp;<img width="'  + this.options.sortImageWidth    + '" ' +
+                                                     'height="'+ this.options.sortImageHeight   + '" ' +
+                                                     'src="'   + this.options.sortDescendImg + '"/>';
+   },
+
+   getSortedColumnIndex: function() {
+      var cols = this.options.columns;
+      for ( var i = 0 ; i < cols.length ; i++ ) {
+         if ( cols[i].isSorted() )
+            return i;
+      }
+
+      return -1;
+   },
+
+   introspectForColumnInfo: function() {
+      var columns = new Array();
+      var headerRow   = this.headerTable.rows[0];
+      var headerCells = headerRow.cells;
+      for ( var i = 0 ; i < headerCells.length ; i++ )
+         columns.push( new Rico.TableColumn( this.deriveColumnNameFromCell(headerCells[i],i), true ) );
+      return columns;
+   },
+
+   convertToTableColumns: function(cols) {
+      var columns = new Array();
+      for ( var i = 0 ; i < cols.length ; i++ )
+         columns.push( new Rico.TableColumn( cols[i][0], cols[i][1] ) );
+      return columns;
+   },
+
+   deriveColumnNameFromCell: function(cell,columnNumber) {
+      var cellContent = cell.innerText != undefined ? cell.innerText : cell.textContent;
+      return cellContent ? cellContent.toLowerCase().split(' ').join('_') : "col_" + columnNumber;
+   }
+};
+
+Rico.TableColumn = Class.create();
+
+Rico.TableColumn.UNSORTED  = 0;
+Rico.TableColumn.SORT_ASC  = "ASC";
+Rico.TableColumn.SORT_DESC = "DESC";
+
+Rico.TableColumn.prototype = {
+   initialize: function(name, sortable) {
+      this.name        = name;
+      this.sortable    = sortable;
+      this.currentSort = Rico.TableColumn.UNSORTED;
+   },
+
+   isSortable: function() {
+      return this.sortable;
+   },
+
+   isSorted: function() {
+      return this.currentSort != Rico.TableColumn.UNSORTED;
+   },
+
+   getSortDirection: function() {
+      return this.currentSort;
+   },
+
+   toggleSort: function() {
+      if ( this.currentSort == Rico.TableColumn.UNSORTED || this.currentSort == Rico.TableColumn.SORT_DESC )
+         this.currentSort = Rico.TableColumn.SORT_ASC;
+      else if ( this.currentSort == Rico.TableColumn.SORT_ASC )
+         this.currentSort = Rico.TableColumn.SORT_DESC;
+   },
+
+   setUnsorted: function(direction) {
+      this.setSorted(Rico.TableColumn.UNSORTED);
+   },
+
+   setSorted: function(direction) {
+      // direction must by one of Rico.TableColumn.UNSORTED, .SORT_ASC, or .SORT_DESC...
+      this.currentSort = direction;
+   }
+
+};
+
+
+//-------------------- ricoUtil.js
+var RicoUtil = {
+
+   getElementsComputedStyle: function ( htmlElement, cssProperty, mozillaEquivalentCSS) {
+      if ( arguments.length == 2 )
+         mozillaEquivalentCSS = cssProperty;
+
+      var el = $(htmlElement);
+      if ( el.currentStyle )
+         return el.currentStyle[cssProperty];
+      else
+         return document.defaultView.getComputedStyle(el, null).getPropertyValue(mozillaEquivalentCSS);
+   },
+
+   createXmlDocument : function() {
+      if (document.implementation && document.implementation.createDocument) {
+         var doc = document.implementation.createDocument("", "", null);
+
+         if (doc.readyState == null) {
+            doc.readyState = 1;
+            doc.addEventListener("load", function () {
+               doc.readyState = 4;
+               if (typeof doc.onreadystatechange == "function")
+                  doc.onreadystatechange();
+            }, false);
+         }
+
+         return doc;
+      }
+
+      if (window.ActiveXObject)
+          return Try.these(
+            function() { return new ActiveXObject('MSXML2.DomDocument')   },
+            function() { return new ActiveXObject('Microsoft.DomDocument')},
+            function() { return new ActiveXObject('MSXML.DomDocument')    },
+            function() { return new ActiveXObject('MSXML3.DomDocument')   }
+          ) || false;
+
+      return null;
+   },
+
+   getContentAsString: function( parentNode ) {
+      return parentNode.xml != undefined ? 
+         this._getContentAsStringIE(parentNode) :
+         this._getContentAsStringMozilla(parentNode);
+   },
+
+  _getContentAsStringIE: function(parentNode) {
+     var contentStr = "";
+     for ( var i = 0 ; i < parentNode.childNodes.length ; i++ ) {
+         var n = parentNode.childNodes[i];
+         if (n.nodeType == 4) {
+             contentStr += n.nodeValue;
+         }
+         else {
+           contentStr += n.xml;
+       }
+     }
+     return contentStr;
+  },
+
+  _getContentAsStringMozilla: function(parentNode) {
+     var xmlSerializer = new XMLSerializer();
+     var contentStr = "";
+     for ( var i = 0 ; i < parentNode.childNodes.length ; i++ ) {
+          var n = parentNode.childNodes[i];
+          if (n.nodeType == 4) { // CDATA node
+              contentStr += n.nodeValue;
+          }
+          else {
+            contentStr += xmlSerializer.serializeToString(n);
+        }
+     }
+     return contentStr;
+  },
+
+   toViewportPosition: function(element) {
+      return this._toAbsolute(element,true);
+   },
+
+   toDocumentPosition: function(element) {
+      return this._toAbsolute(element,false);
+   },
+
+   /**
+    *  Compute the elements position in terms of the window viewport
+    *  so that it can be compared to the position of the mouse (dnd)
+    *  This is additions of all the offsetTop,offsetLeft values up the
+    *  offsetParent hierarchy, ...taking into account any scrollTop,
+    *  scrollLeft values along the way...
+    *
+    * IE has a bug reporting a correct offsetLeft of elements within a
+    * a relatively positioned parent!!!
+    **/
+   _toAbsolute: function(element,accountForDocScroll) {
+
+      if ( navigator.userAgent.toLowerCase().indexOf("msie") == -1 )
+         return this._toAbsoluteMozilla(element,accountForDocScroll);
+
+      var x = 0;
+      var y = 0;
+      var parent = element;
+      while ( parent ) {
+
+         var borderXOffset = 0;
+         var borderYOffset = 0;
+         if ( parent != element ) {
+            var borderXOffset = parseInt(this.getElementsComputedStyle(parent, "borderLeftWidth" ));
+            var borderYOffset = parseInt(this.getElementsComputedStyle(parent, "borderTopWidth" ));
+            borderXOffset = isNaN(borderXOffset) ? 0 : borderXOffset;
+            borderYOffset = isNaN(borderYOffset) ? 0 : borderYOffset;
+         }
+
+         x += parent.offsetLeft - parent.scrollLeft + borderXOffset;
+         y += parent.offsetTop - parent.scrollTop + borderYOffset;
+         parent = parent.offsetParent;
+      }
+
+      if ( accountForDocScroll ) {
+         x -= this.docScrollLeft();
+         y -= this.docScrollTop();
+      }
+
+      return { x:x, y:y };
+   },
+
+   /**
+    *  Mozilla did not report all of the parents up the hierarchy via the
+    *  offsetParent property that IE did.  So for the calculation of the
+    *  offsets we use the offsetParent property, but for the calculation of
+    *  the scrollTop/scrollLeft adjustments we navigate up via the parentNode
+    *  property instead so as to get the scroll offsets...
+    *
+    **/
+   _toAbsoluteMozilla: function(element,accountForDocScroll) {
+      var x = 0;
+      var y = 0;
+      var parent = element;
+      while ( parent ) {
+         x += parent.offsetLeft;
+         y += parent.offsetTop;
+         parent = parent.offsetParent;
+      }
+
+      parent = element;
+      while ( parent &&
+              parent != document.body &&
+              parent != document.documentElement ) {
+         if ( parent.scrollLeft  )
+            x -= parent.scrollLeft;
+         if ( parent.scrollTop )
+            y -= parent.scrollTop;
+         parent = parent.parentNode;
+      }
+
+      if ( accountForDocScroll ) {
+         x -= this.docScrollLeft();
+         y -= this.docScrollTop();
+      }
+
+      return { x:x, y:y };
+   },
+
+   docScrollLeft: function() {
+      if ( window.pageXOffset )
+         return window.pageXOffset;
+      else if ( document.documentElement && document.documentElement.scrollLeft )
+         return document.documentElement.scrollLeft;
+      else if ( document.body )
+         return document.body.scrollLeft;
+      else
+         return 0;
+   },
+
+   docScrollTop: function() {
+      if ( window.pageYOffset )
+         return window.pageYOffset;
+      else if ( document.documentElement && document.documentElement.scrollTop )
+         return document.documentElement.scrollTop;
+      else if ( document.body )
+         return document.body.scrollTop;
+      else
+         return 0;
+   }
+
+};
diff --git a/webinterface/src/web-data/theme.css b/webinterface/src/web-data/theme.css
new file mode 100644 (file)
index 0000000..3dc0435
--- /dev/null
@@ -0,0 +1,30 @@
+body { background-color:#445566; color:#FFCC99; }
+a:link { color:#FF9966; }
+a:visited { color:#FF9900; }
+a:active { color:#FFFFFF; }
+
+       /* allow room for 3 columns */
+ol
+{
+       width: 45em;
+}
+
+       /* float and allow room for the widest item */
+ol li
+{
+       float: left;
+       width: 15em;
+}
+
+/* stop the float */
+br
+{
+       clear: left;
+}
+
+       /* separate the list from subsequent markup */
+div.wrapper
+{
+       margin-bottom: 1em;
+}
+
diff --git a/webinterface/src/web-data/tools.js b/webinterface/src/web-data/tools.js
new file mode 100644 (file)
index 0000000..75f46f0
--- /dev/null
@@ -0,0 +1,411 @@
+var url_getvolume = '/web/vol?set=info'; 
+var url_setvolume = '/web/vol?set=set'; // plus new value eq. set=set15
+var url_volumeup = '/web/vol?set=up';
+var url_volumedown = '/web/vol?set=down';
+var url_volumemute = '/web/vol?set=mute';
+
+var url_epgservice = "/web/epgservice?ref="; // plus serviceRev
+var url_epgsearch = "/web/epgsearch?search="; // plus serviceRev
+var url_epgnownext = "/web/epgnownext?ref="; // plus serviceRev
+
+function debug(text){
+       //$('debug').innerHTML += "DEBUG: "+text+"<br>";
+}
+function set(what, value)
+{
+       //debug(what+"-"+value);
+       element = document.getElementById(what);
+       element.innerHTML = value;
+       $('scriptzone').innerHTML = ""; // deleting set() from page, to keep the page short and to save memory
+}
+
+function zap(li)
+{
+       var request = getHTTPObject();
+       var url = "/web/zap?ZapTo=" + escape(li.id);
+       //debug("requesting "+url);
+       new Ajax.Request( url,
+                       {
+                               method: 'get' 
+                               
+                       });
+               
+}
+
+function getHTTPObject() 
+{
+       var xmlhttp; 
+       /*@cc_on 
+       @if (@_jscript_version >= 5) 
+       try 
+       { 
+               xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); 
+       } 
+       catch (e) 
+       { 
+               try 
+               { 
+                       xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); 
+               } 
+               catch (E) 
+               { 
+                       xmlhttp = false; 
+               } 
+       } 
+       @else 
+       xmlhttp = false; 
+       @end @*/ 
+       if (!xmlhttp && typeof XMLHttpRequest != 'undefined') 
+       { 
+               try 
+               { 
+                       xmlhttp = new XMLHttpRequest(); 
+               } 
+               catch (e) 
+               {
+                       xmlhttp = false; 
+               }
+       } 
+       return xmlhttp; 
+}
+
+
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++
+//++++ EPG functions                               ++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++
+var EPGList = Class.create();
+EPGList.prototype = {
+       //contructor
+       initialize: function(){
+               debug("init class EPGList");
+       },
+       getBySearchString: function(string,element){
+               debug("requesting "+ url_epgsearch+string);
+               targetElement = element;
+               new Ajax.Request( url_epgsearch+string,
+                       {
+                               method: 'get', 
+                               onComplete: this.incomingEPGrequest
+                       });
+               
+       },
+       getByServiceReference: function(serviceRef,element){
+               targetElement = element;
+               new Ajax.Request(url_epgservice+serviceRef,
+                       {
+                               method: 'get', 
+                               onComplete: this.incomingEPGrequest
+                       });
+               
+       },
+       renderTable: function(epglist){
+               debug("rendering Table with "+epglist.length+" events");
+               var html="<table width='100%'>";
+               for (var i=0; i<epglist.length;i++){
+                       var item = epglist[i];
+                       html +="<tr  bgcolor='gray'>";
+                       html +="<td>"+item.getTimeDay()+"</td>";
+                       html +="<td>"+item.getTimeStartString()+"</td>";
+                       html +="<td>"+item.getTimeEndString()+"</td>";
+                       html +="<td>"+item.getTitle()+"</td>";
+                       html +="<td>"+item.getDescription()+"</td>";
+                       html +="<td>"+item.getDescriptionExtended()+"</td>";
+                       html +="<td>"+(item.getDuration()/60000)+" min.</td>";
+                       html +="<td>"+item.getServiceName()+"</td>";
+                       html +="</tr>";
+               }
+               html +="</table>";
+               targetElement.innerHTML = html;
+               
+       },
+       incomingEPGrequest: function(originalRequest){
+               debug("incoming request" +originalRequest.readyState);          
+               if (originalRequest.readyState == 4)
+               {
+                       if (originalRequest.responseXML!="no data")
+                       {
+                               var EPGItems = originalRequest.responseXML.getElementsByTagName("e2eventlist").item(0).getElementsByTagName("e2event");
+                               debug("have "+EPGItems.length+" e2events");
+                               epglist = new Array();
+                               for(var i=0;i<EPGItems.length;i++)
+                               {       
+                                       epglist.push(new EPGEvent(EPGItems.item(i)));
+                               }
+                               EPGList.prototype.renderTable(epglist);
+                               
+                       }                               
+               }
+       }
+       
+}
+
+function EPGEvent(element){    
+       // parsing values from xml-element
+       this.eventID= element.getElementsByTagName('e2eventid').item(0).firstChild.data;
+       this.startTime= element.getElementsByTagName('e2eventstart').item(0).firstChild.data;
+       this.duration= element.getElementsByTagName('e2eventduration').item(0).firstChild.data;
+       this.title= element.getElementsByTagName('e2eventtitle').item(0).firstChild.data;
+       this.description= element.getElementsByTagName('e2eventdescription').item(0).firstChild.data;
+       this.descriptionE= element.getElementsByTagName('e2eventdescriptionextended').item(0).firstChild.data;
+       this.serviceRef= element.getElementsByTagName('e2eventservicereference').item(0).firstChild.data;
+       this.serviceName= element.getElementsByTagName('e2eventservicename').item(0).firstChild.data;
+
+       this.getEventId = function ()
+       {
+               return this.eventID;
+       }
+       this.getTimeStart = function ()
+       {
+               var date = new Date(parseInt(this.startTime)*1000);
+               return date;
+       }
+       this.getTimeStartString = function ()
+       {
+               var h = this.getTimeStart().getHours();
+               var m = this.getTimeStart().getMinutes();
+               if (m < 10){
+                       m="0"+m;
+               }
+               return h+":"+m;
+       }
+       this.getTimeDay = function ()
+       {
+               var Wochentag = new Array("So", "Mo", "Di", "Mi", "Do", "Fr", "Sa");
+               var wday = Wochentag[this.getTimeStart().getDay()];
+               var day = this.getTimeStart().getDate();
+               var month = this.getTimeStart().getMonth()+1;
+               var year = this.getTimeStart().getFullYear();
+               
+               return wday+".&nbsp;"+day+"."+month+"."+year;
+       }
+       this.getTimeEnd = function ()
+       {
+               var date = new Date((parseInt(this.startTime)+parseInt(this.duration))*1000);
+               return date;
+       }
+       this.getTimeEndString = function ()
+       {
+               var h = this.getTimeEnd().getHours();
+               var m = this.getTimeEnd().getMinutes();
+               if (m < 10){
+                       m="0"+m;
+               }
+               return h+":"+m;
+       }
+       this.getDuration = function ()
+       {
+               return  new Date(parseInt(this.duration)*1000);
+       }
+       this.getTitle = function ()
+       {
+               return this.title;
+       }
+       this.getDescription = function ()
+       {
+               return this.description;
+       }
+       this.getDescriptionExtended = function ()
+       {
+               return this.descriptionE;
+       }
+       this.getServiceReference = function ()
+       {
+               return this.serviceRef;
+       }
+       this.getServiceName = function ()
+       {
+               return this.serviceName.replace(" ","&nbsp;");
+       }
+}//END class EPGEvent
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++
+//++++ GUI functions                               ++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++
+var currentBodyMainElement = null
+
+function setBodyMainContent(newelementname){
+       newelement =document.getElementById(newelementname);
+       if(currentBodyMainElement != null){
+               currentBodyMainElement.style.display = "none";
+               
+       }
+       newelement.style.display = "inline";
+       currentBodyMainElement = newelement;
+}
+function doRequest(url,readyFunction){
+       
+       http_request =getHTTPObject();
+       if(readyFunction){
+               http_request.onreadystatechange = readyFunction;
+       }
+       http_request.open('GET', url, true);
+       http_request.send(null);
+       return http_request;
+}
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++
+//++++ volume functions                            ++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+
+function getVolume()
+{
+       doRequest(url_getvolume,handleVolumeRequest);
+}
+function setVolume(newvalue)
+{
+               doRequest(url_setvolume+newvalue,handleVolumeRequest);
+}
+function volumeUp()
+{
+               doRequest(url_volumeup,handleVolumeRequest);
+}
+function volumeDown()
+{
+               doRequest(url_volumedown,handleVolumeRequest);  
+}
+function volumeMute()
+{
+               doRequest(url_volumemute,handleVolumeRequest);
+}
+function handleVolumeRequest(){
+               if (http_request.readyState == 4) {
+                               var a = http_request.responseText.split("\n");
+                               var newvalue = a[1];
+                       var mute=a[2];
+                               set("Volume_Current",newvalue);
+                               for (var i = 1; i <= 10; i++)
+                               {
+                                       if ( (newvalue/10)>=i){
+                                               $("volume"+i).src = "/webdata/gfx/led_on.png";
+                                       }else{
+                                               $("volume"+i).src = "/webdata/gfx/led_off.png";
+                                       }
+                               }
+                               if (mute == "notmuted"){
+                                       $("speaker").src = "/webdata/gfx/speak_on.png";
+                               }else{
+                                       $("speaker").src = "/webdata/gfx/speak_off.png";
+                               }
+                       }       
+}
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++
+//++++ Bouqet managing functions                   ++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++
+       function loadRootTVBouqet(){
+               //rootB = '/web/fetchchannels?ServiceListBrowse='+escape('1:7:1:0:0:0:0:0:0:0:(type == 1) FROM BOUQUET "bouquets.tv" ORDER BY bouquet');
+       rootB = '/web/fetchchannels?ServiceListBrowse='+escape('1:7:1:0:0:0:0:0:0:0:(type == 1) || (type == 17) || (type == 195) || (type == 25)  FROM BOUQUET &quot;bouquets.tv&quot; ORDER BY bouquet');
+               
+                
+               loadRootBouqet(rootB);
+       }
+  function loadRootBouqet(rootB){
+               
+               t =getHTTPObject();
+               t.onreadystatechange = incomingResult;
+               t.open('GET', rootB, true);
+               t.send(null);
+               
+       }
+       function incomingResult(){
+               if((t.readyState == 4) && (t.status == 200)) {
+       // perfekt!
+                       var r = t.responseXML;
+                       
+                       var b = r.getElementsByTagName("e2servicelist").item(0).getElementsByTagName("e2service");
+
+                       bouquets = new Array();
+                       for ( var i=0; i < b.length; i++){
+                               bRef = b.item(i).getElementsByTagName('e2servicereference').item(0).firstChild.data;
+                               bName = b.item(i).getElementsByTagName('e2servicename').item(0).firstChild.data;
+                               
+                               bu = new Array(bName,bRef);
+                               bouquets.push(bu)
+                       }
+                       refreshSelect(bouquets);
+               } else {
+       // die Anfrage enthielt Fehler;
+       // die Antwort war z.B. 404 (nicht gefunden)
+       // oder 500 (interner Server-Fehler)
+               }
+               
+       }
+       // to add the bouqetts to the list
+       function refreshSelect(arraybouqet){
+               
+               sel = document.getElementById("accordionMenueBouqetContent");
+               // options neu eintragen
+               html = "<table>";
+                       for ( var i = 0 ; i < arraybouqet.length ; i++ ){
+                       if(arraybouqet[i][0] && arraybouqet[i][1]){
+                               html+="<tr><td>";
+                               html+="<a  onclick=\"bouqetSelected(this); setBodyMainContent('BodyContentChannellist');\" id='";
+                               html+= arraybouqet[i][1];
+                               html+="'>";
+                               html+= arraybouqet[i][0];
+                               html+="</a>";
+                               html+="</td></tr>";
+                       }
+               }
+               html+="</table>";
+               sel.innerHTML=html;
+               refreshChannellist(arraybouqet[0][0],arraybouqet[0][1]);
+       }
+       //++++++++++++++++++++++
+       function bouqetSelected(element){
+               refreshChannellist(element.value,element.id)
+       }
+       
+       function refreshChannellist(bname,bref){
+               urlx = '/web/fetchchannels?ServiceListBrowse='+escape(bref);
+               w =getHTTPObject();
+               w.onreadystatechange = incomingChannellist;
+         w.open('GET', urlx, true);
+         w.send(null);
+         
+               
+               
+       }
+               function incomingChannellist(){
+                       if (w.readyState == 4) {
+               // alles in Ordnung, Antwort wurde empfangen
+                       if (w.responseXML != "no data"){        
+                               var services = w.responseXML.getElementsByTagName("e2servicelist").item(0).getElementsByTagName("e2service");
+                               listerHtml = "<table id=\"ChannelSelect\" >";
+                       
+                               for ( var i = 0; i < (services.length ); i++){
+                                       sRef = services.item(i).getElementsByTagName('e2servicereference').item(0).firstChild.data;
+                                       sName = services.item(i).getElementsByTagName('e2servicename').item(0).firstChild.data;
+
+                                       listerHtml += '<tr bgcolor="gray"><td><div onclick=\"zap(this)\" id="';
+                                       listerHtml += sRef;
+                                       listerHtml += '">';
+                                       listerHtml += sName;
+                                       listerHtml += '</div></td>';
+                                       listerHtml += '<td><a onclick=\"new EPGList().getByServiceReference(this.id,$(\'BodyEPGPanel\'));setBodyMainContent(\'BodyEPGPanel\');\" id="';
+                                       listerHtml += sRef;
+                                       listerHtml += '" >EPG</div><div><a target=\"blank" href=\"stream.m3u?ref=';
+                                       listerHtml += sRef;
+                                       listerHtml += '\">Stream</a></div></td>';
+                                       listerHtml += '</tr>';
+                               }
+                               listerHtml += "</table>";
+                               document.getElementById("BodyContentChannellist").innerHTML = listerHtml;
+                               setBodyMainContent('BodyContentChannellist');
+                       } else {
+               // die Anfrage enthielt Fehler;
+               // die Antwort war z.B. 404 (nicht gefunden)
+               // oder 500 (interner Server-Fehler)
+                       }
+               }       
+                       
+       }
+
+
+
diff --git a/webinterface/src/web/Makefile.am b/webinterface/src/web/Makefile.am
new file mode 100644 (file)
index 0000000..8e95205
--- /dev/null
@@ -0,0 +1,3 @@
+installdir = /usr/lib/enigma2/python/Plugins/Extensions/WebInterface/web/
+
+install_DATA = *.xml
diff --git a/webinterface/src/web/epgnownext.xml b/webinterface/src/web/epgnownext.xml
new file mode 100644 (file)
index 0000000..db606c7
--- /dev/null
@@ -0,0 +1,14 @@
+<e2:screen name="TestScreen">&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;e2eventlist><e2:element source="EPGNOWNEXT" id="ref"><e2:convert type="web:ListFiller" >
+       &lt;e2event>
+               &lt;e2eventid><e2:item name="EventID" /> &lt;/e2eventid>
+               &lt;e2eventstart><e2:item name="TimeStart"/> &lt;/e2eventstart>
+               &lt;e2eventduration><e2:item name="Duration"/> &lt;/e2eventduration>
+               &lt;e2eventtitle><e2:item name="Title"/> &lt;/e2eventtitle>
+               &lt;e2eventdescription><e2:item name="Description"/> &lt;/e2eventdescription>
+               &lt;e2eventdescriptionextended><e2:item name="DescriptionExtended"/> &lt;/e2eventdescriptionextended>
+               &lt;e2eventservicereference><e2:item name="ServiceReference"/> &lt;/e2eventservicereference>
+               &lt;e2eventservicename><e2:item name="ServiceName"/> &lt;/e2eventservicename>
+       &lt;/e2event></e2:convert><e2:convert type="web:TextToHTML" /></e2:element>
+&lt;/e2eventlist>
+</e2:screen>
\ No newline at end of file
diff --git a/webinterface/src/web/epgsearch.xml b/webinterface/src/web/epgsearch.xml
new file mode 100644 (file)
index 0000000..dcb8067
--- /dev/null
@@ -0,0 +1,14 @@
+<e2:screen name="TestScreen">&lt;?xml version="1.0"?>
+&lt;e2eventlist><e2:element source="EPGTITLE" id="search"><e2:convert type="web:ListFiller" >
+       &lt;e2event>
+               &lt;e2eventid><e2:item name="EventID" /> &lt;/e2eventid>
+               &lt;e2eventstart><e2:item name="TimeStart"/> &lt;/e2eventstart>
+               &lt;e2eventduration><e2:item name="Duration"/> &lt;/e2eventduration>
+               &lt;e2eventtitle><e2:item name="Title"/> &lt;/e2eventtitle>
+               &lt;e2eventdescription><e2:item name="Description"/> &lt;/e2eventdescription>
+               &lt;e2eventdescriptionextended><e2:item name="DescriptionExtended"/> &lt;/e2eventdescriptionextended>
+               &lt;e2eventservicereference><e2:item name="ServiceReference"/> &lt;/e2eventservicereference>
+               &lt;e2eventservicename><e2:item name="ServiceName"/> &lt;/e2eventservicename>
+       &lt;/e2event></e2:convert><e2:convert type="web:TextToHTML" /></e2:element>
+&lt;/e2eventlist>
+</e2:screen>
\ No newline at end of file
diff --git a/webinterface/src/web/epgservice.xml b/webinterface/src/web/epgservice.xml
new file mode 100644 (file)
index 0000000..919ff1b
--- /dev/null
@@ -0,0 +1,14 @@
+<e2:screen name="TestScreen">&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;e2eventlist><e2:element source="EPGSERVICE" id="ref"><e2:convert type="web:ListFiller" >
+       &lt;e2event>
+               &lt;e2eventid><e2:item name="EventID" /> &lt;/e2eventid>
+               &lt;e2eventstart><e2:item name="TimeStart"/> &lt;/e2eventstart>
+               &lt;e2eventduration><e2:item name="Duration"/> &lt;/e2eventduration>
+               &lt;e2eventtitle><e2:item name="Title"/> &lt;/e2eventtitle>
+               &lt;e2eventdescription><e2:item name="Description"/> &lt;/e2eventdescription>
+               &lt;e2eventdescriptionextended><e2:item name="DescriptionExtended"/> &lt;/e2eventdescriptionextended>
+               &lt;e2eventservicereference><e2:item name="ServiceReference"/> &lt;/e2eventservicereference>
+               &lt;e2eventservicename><e2:item name="ServiceName"/> &lt;/e2eventservicename>
+       &lt;/e2event></e2:convert><e2:convert type="web:TextToHTML" /></e2:element>
+&lt;/e2eventlist>
+</e2:screen>
\ No newline at end of file
diff --git a/webinterface/src/web/fetchchannels.xml b/webinterface/src/web/fetchchannels.xml
new file mode 100644 (file)
index 0000000..724aec9
--- /dev/null
@@ -0,0 +1,13 @@
+<e2:screen name="TestScreen">&lt;?xml version="1.0" encoding="UTF-8"?>
+<e2servicelist>
+<e2:element source="ServiceListBrowse">                                
+       <e2:convert type="web:ListFiller">
+       &lt;e2service>
+               &lt;e2servicereference><e2:item name="Reference" />&lt;/e2servicereference>
+               &lt;e2servicename><e2:item name="Name"/>&lt;/e2servicename>
+       &lt;/e2service>
+       </e2:convert>
+       <e2:convert type="web:TextToHTML" />                    
+</e2:element>
+</e2servicelist>       
+</e2:screen>
\ No newline at end of file
diff --git a/webinterface/src/web/index.html.xml b/webinterface/src/web/index.html.xml
new file mode 100644 (file)
index 0000000..8368c9c
--- /dev/null
@@ -0,0 +1,311 @@
+<e2:screen name="TestScreen">&lt;html>
+<head>
+       <meta content="text/html; charset=UTF-8" http-equiv="content-type"/>
+       <title>Enigma2 Webinterface</title>
+       <script src="/webdata/prototype.js" type="text/javascript"/>
+    <script src="/webdata/rico.js" type="text/javascript"/>
+       <script src="/webdata/tools.js" type="text/javascript" />
+       <link  href="/webdata/theme.css" rel="stylesheet" type="text/css" />                                      
+</head>
+
+<body>
+<div id="debug"></div>
+
+<table id="htmlDesignTable"  width="100%" border="0">
+<tr><td>
+<!-- START SITE HEADER //-->
+               <table width="100%" border="0">
+                       <tr>
+                               <td width="10%"  rowspan="2">
+                                       <div id="Current_Channel_Box" class="roundme" >
+                                       <nobr><div id="CurrentService"  > </div></nobr>
+                                       <div id="CurrentServiceProvider" > </div>
+                                       </div>
+                               </td>
+                               <td width="80%">
+                                       <span id="Event_Now_Name"  onclick="setBodyMainContent('BodyContentEPGNow')"> </span>
+                               </td>
+                               <td width="150" rowspan="2">
+                                       <div id="Info_Box"  class="roundme">
+                                               <table width="100">
+                                                       <tr><td colspan="2"><div id="CurrentTime"> </div></td></tr>
+                                                       <tr><td>SNR:</td><td><div id="SNR"></div></td></tr>
+                                                       <tr><td>BER:</td><td><div id="BER"></div></td></tr>
+                                                       <tr><td>AGC:</td><td><div id="AGC"></div></td></tr>
+                                               </table>
+                                       </div>
+                               </td>
+                               </tr><tr>
+                               
+                               <td width="80%">
+                                               <span id="Event_Next_Name"  onclick="setBodyMainContent('BodyContentEPGNext')"> </span>
+                               </td>
+                       </tr>
+                       <tr><td colspan="2">
+                               Volume <span id="Volume_Current" >..</span>
+                               <span onclick="volumeUp()" >++</span>
+                               <span onclick="volumeDown()" >--</span>
+                               <span onclick="volumeMute()" >xx</span>
+                               <img src="/webdata/gfx/led_off.png" id="volume1" onclick="setVolume(10)"/>
+                               <img src="/webdata/gfx/led_off.png" id="volume2" onclick="setVolume(20)"/>
+                               <img src="/webdata/gfx/led_off.png" id="volume3" onclick="setVolume(30)"/>
+                               <img src="/webdata/gfx/led_off.png" id="volume4" onclick="setVolume(40)"/>
+                               <img src="/webdata/gfx/led_off.png" id="volume5" onclick="setVolume(50)"/>
+                               <img src="/webdata/gfx/led_off.png" id="volume6" onclick="setVolume(60)"/>
+                               <img src="/webdata/gfx/led_off.png" id="volume7" onclick="setVolume(70)"/>
+                               <img src="/webdata/gfx/led_off.png" id="volume8" onclick="setVolume(80)"/>
+                               <img src="/webdata/gfx/led_off.png" id="volume9" onclick="setVolume(90)"/>
+                               <img src="/webdata/gfx/led_off.png" id="volume10" onclick="setVolume(100)"/>
+                               <img src="/webdata/gfx/speak_on.png" id="speaker"  onclick="volumeMute()" />
+                               </td>
+                               <td>
+                                       <form onSubmit="new EPGList().getBySearchString($('searchText').value,$('BodyEPGPanel')); setBodyMainContent('BodyEPGPanel'); return false;">
+                                               <input type="text" id="searchText" onfocus="this.value=''" value="EPG suchen"/>                                 
+                                       </form>
+                               </td>                                   
+                       </tr>
+               </table>
+               
+<!-- END SITE HEADER //-->
+</td></tr>
+<tr><td>
+<!-- START SITE BODY //-->
+       <table id="htmlDesignTableBody"   width="100%" border="0">
+       <tr>
+               <td id="htmlDesignTableBodyMenue" width="150" valign="top">
+               <!-- START BODY MENUE //-->
+                       <div id="accordionMenue">
+                       <div id="accordionMenueBouqetPanel">
+                       <div id="accordionMenueBouqetHeader">
+                               Bouquets
+               </div>
+               <div id="accordionMenueBouqetContent">
+                               
+               </div>
+                       </div>
+                       <!--<div id="accordionMenueControlPanel">
+                       <div id="accordionMenueControlHeader">
+                               Control
+               </div>
+               <div id="accordionMenueControlContent">
+                       <table>
+                               <tr><td><a onclick="setBodyMainContent('BodyContentMessageform')">Nachricht</a></td></tr>
+                               <tr><td><a onclick="setBodyMainContent('BodyContentPower')">Shutdown</a></td></tr>
+                               <tr><td><a onclick="setBodyMainContent('BodyContentHDD')">HDD</a></td></tr>
+                               <tr><td><a onclick="setBodyMainContent('BodyContentDebugbox')">JscriptDebug</a></td></tr>
+                               </table>
+               </div>
+                       </div>//-->
+                       </div>
+               
+               <!-- END BODY MENUE //-->
+               </td>
+               <td id="htmlDesignTableBodyMain" valign="top" witdh="100%" >
+               <!-- START BODY MAIN //-->
+                               <!-- START BodyContentEPGNext //-->       
+                               <div id="BodyContentEPGNext" style="display:none;" >
+                                       <div id="Event_Next_Box">
+                                               <table id="Event_Table_Next"  width="100%" border="1">
+                                                       <tr>
+                                                               <td>
+                                                                       <span id="Event_Next_Begin"></span> bis <span id="Event_Next_End"></span>
+                                                               </td>
+                                                               <td>
+                                                                       <span id="Event_Next_Name"  onclick="setBodyMainContent('BodyContentEPGNext')"> </span>
+                                                                       <a href="javascript:imdb()">...</a>                             
+                                                               </td>
+                                                               <td>
+                                                                       <span id="Event_Next_Remaining"> </span>
+                                                               </td>
+                                                       </tr>
+                                                       <tr>    
+                                                               <td colspan="3">
+                                                                       <div id="Event_Next_Description"> </div>
+                                                               </td>
+                                                       </tr>
+                                                       <tr>    
+                                                               <td colspan="3">
+                                                                       <div id="Event_Next_Extended_Description"> </div>
+                                                               </td>
+                                                       </tr>
+                                               </table>
+                                       </div>
+                               </div>
+                               <!-- ENDE BodyContentEPGNext //-->       
+                               <!-- START BodyContentEPGNow //-->       
+                               <div id="BodyContentEPGNow" style="display:none;">
+                                       <div id="Event_Now_Box">
+                                               <table id="Event_Table_Now"  width="100%" border="1">
+                                                       <tr>
+                                                               <td>
+                                                                       <span id="Event_Now_Begin"></span> bis <span id="Event_Now_End"></span>
+                                                               </td>
+                                                               <td>
+                                                                       <span id="Event_Now_Name"  onclick="setBodyMainContent('BodyContentEPGNow')"> </span>
+                                                                       <a href="javascript:imdb()">...</a>                             
+                                                               </td>
+                                                               <td>
+                                                                       <span id="Event_Now_Remaining"> </span>
+                                                               </td>
+                                                       </tr>
+                                                       <tr>    
+                                                               <td colspan="3">
+                                                                       <div id="Event_Now_Description"> </div>
+                                                               </td>
+                                                       </tr>
+                                                       <tr>    
+                                                               <td colspan="3">
+                                                                       <div id="Event_Now_Extended_Description"> </div>
+                                                               </td>
+                                                       </tr>
+                                               </table>
+                                       </div>
+                               </div>
+                               <!-- END BodyContentEPGNow //-->       
+                               <!-- START BodyContentChannellist //-->       
+                                       <div id="BodyContentChannellist" style="display:none;"></div>
+                               <!-- END BodyContentChannellist //--> 
+                               <!-- START BodyContentMessageform //-->       
+                                       <div id="BodyContentMessageform" style="display:none;">
+                                                                               BodyContentText BodyContentText BodyContentText BodyContentText
+                                       </div>
+                               <!-- END BodyContentMessageform //-->       
+                               <!-- START BodyContentPower //-->       
+                                       <div id="BodyContentPower" style="display:none;">
+                                               standby, Poweroff, E2restart
+                                       </div>
+                               <!-- END BodyContentPower //-->       
+                               <!-- START BodyContentHDD //-->       
+                               <div id="BodyContentHDD" style="display:none;">
+                                       <iframe src="/hdd/" width="100%" height="400"/>
+                               </div>
+                               <!-- END BodyContentHDD //-->       
+                               <!-- START BodyContentDebugbox //-->       
+                               <div id="BodyContentDebugbox" style="display:none;">
+                                       
+                               </div>
+                               <!-- END BodyContentDebugbox //-->       
+                               <!-- START BodyEPGPanel //-->       
+                               <div id="BodyEPGPanel" style="display:none;">
+                                       
+                               </div>
+                               <!-- END BodyEPGPanel //-->       
+                                                                                       
+                               <!-- END CHANNELLIST //-->       
+               <!-- END BODY MAIN //-->                                
+               </td>
+       </tr>
+       </table>
+<!-- END SITE BODY //-->
+</td></tr>
+</table>
+
+
+<script type="text/javascript" >
+// HTML Effekts by wwwopenrico.org
+new Rico.Effect.Round('div','roundme' );
+new Rico.Effect.Round('div','button' );
+new Rico.Accordion( $('accordionMenue') );
+//
+getVolume();
+loadRootTVBouqet();
+//loadRootRadioBouqet();
+setBodyMainContent('BodyContentChannellist');
+function updatePage()
+{
+} 
+
+function imdb()
+{
+       w = window.open("http://www.imdb.com/find?s=all&amp;q=" + escape(document.getElementById("Event_Now_Name").innerHTML));
+       w.focus();
+}
+
+</script>
+</body>
+&lt;div id="scriptzone">
+<!-- realtime updates follow -->
+<e2:element source="CurrentTime" streaming="yes">
+  <e2:convert type="ClockToText">WithSeconds</e2:convert>
+       <e2:convert type="web:JavascriptUpdate" />
+</e2:element>
+<e2:element source="CurrentService" streaming="yes">
+       <e2:convert type="ServiceName">Name</e2:convert>
+       <e2:convert type="web:JavascriptUpdate" />
+</e2:element>
+<e2:element source="Event_Now" id="Event_Now_Name" streaming="yes">
+       <e2:convert type="EventName">Name</e2:convert>
+       <e2:convert type="web:JavascriptUpdate" />
+</e2:element>
+<e2:element source="Event_Now" id="Event_Now_Description" streaming="yes">
+       <e2:convert type="EventName">Description</e2:convert>
+       <e2:convert type="web:JavascriptUpdate" />
+</e2:element>
+<e2:element source="Event_Now" id="Event_Now_Extended_Description" streaming="yes">
+       <e2:convert type="EventName">ExtendedDescription</e2:convert>
+       <e2:convert type="web:JavascriptUpdate" />
+</e2:element>
+<e2:element source="Event_Now" id="Event_Now_Begin" streaming="yes">
+       <e2:convert type="EventTime">StartTime</e2:convert>
+  <e2:convert type="ClockToText">Default</e2:convert>
+       <e2:convert type="web:JavascriptUpdate" />
+</e2:element>
+<e2:element source="Event_Now" id="Event_Now_End" streaming="yes">
+       <e2:convert type="EventTime">EndTime</e2:convert>
+  <e2:convert type="ClockToText">Default</e2:convert>
+       <e2:convert type="web:JavascriptUpdate" />
+</e2:element>
+<e2:element source="Event_Now" id="Event_Now_Remaining" streaming="yes">
+       <e2:convert type="EventTime">Remaining</e2:convert>
+       <e2:convert type="RemainingToText">InMinutes</e2:convert>
+       <e2:convert type="web:JavascriptUpdate" />
+</e2:element>
+
+
+<e2:element source="Event_Next" id="Event_Next_Name" streaming="yes">
+  <e2:convert type="EventName">Name</e2:convert>
+  <e2:convert type="web:JavascriptUpdate" />
+</e2:element>
+<e2:element source="Event_Next" id="Event_Next_Begin" streaming="yes">
+       <e2:convert type="EventTime">StartTime</e2:convert>
+       <e2:convert type="ClockToText">Default</e2:convert>
+       <e2:convert type="web:JavascriptUpdate" />
+</e2:element>
+<e2:element source="Event_Next" id="Event_Next_End" streaming="yes">
+       <e2:convert type="EventTime">EndTime</e2:convert>
+  <e2:convert type="ClockToText">Default</e2:convert>
+       <e2:convert type="web:JavascriptUpdate" />
+</e2:element>
+<e2:element source="Event_Next" id="Event_Next_Remaining" streaming="yes">
+  <e2:convert type="EventTime">Remaining</e2:convert>
+  <e2:convert type="RemainingToText">InMinutes</e2:convert>
+  <e2:convert type="web:JavascriptUpdate" />
+</e2:element>
+<e2:element source="Event_Next" id="Event_Next_Extended_Description" streaming="yes">
+       <e2:convert type="EventName">ExtendedDescription</e2:convert>
+       <e2:convert type="web:JavascriptUpdate" />
+</e2:element>
+
+
+<e2:element source="FrontendStatus"  id="SNR" streaming="yes">
+       <e2:convert type="FrontendInfo">SNR</e2:convert>
+       <e2:convert type="web:JavascriptUpdate" />
+</e2:element>
+<e2:element source="FrontendStatus"  id="BER" streaming="yes">
+       <e2:convert type="FrontendInfo">BER</e2:convert>
+       <e2:convert type="web:JavascriptUpdate" />
+</e2:element>
+<e2:element source="FrontendStatus"  id="AGC" streaming="yes">
+       <e2:convert type="FrontendInfo">AGC</e2:convert>
+       <e2:convert type="web:JavascriptUpdate" />
+</e2:element>
+
+
+<e2:element source="CurrentService" id="CurrentServiceProvider" streaming="yes">
+       <e2:convert type="ServiceName">Provider</e2:convert>
+        <e2:convert type="web:JavascriptUpdate" />
+</e2:element>
+                
+                
+
+</e2:screen>
diff --git a/webinterface/src/web/stream.m3u.xml b/webinterface/src/web/stream.m3u.xml
new file mode 100644 (file)
index 0000000..2aa4957
--- /dev/null
@@ -0,0 +1,4 @@
+<e2:screen name="StreamingM3U">#EXTM3U
+#EXTVLCOPT--http-reconnect=true
+http://<e2:element source="localip" />:8001/<e2:element source="ref"><e2:convert type="web:TextToHTML" /></e2:element>
+</e2:screen>
diff --git a/webinterface/src/web/stream.xml b/webinterface/src/web/stream.xml
new file mode 100644 (file)
index 0000000..c0a3d1a
--- /dev/null
@@ -0,0 +1,4 @@
+<e2:screen name="Streaming"><e2:element source="StreamService" streaming="yes">
+<e2:convert type="Streaming" />
+<e2:convert type="web:TextToHTML" />
+</e2:element></e2:screen>
diff --git a/webinterface/src/web/timerlist.xml b/webinterface/src/web/timerlist.xml
new file mode 100644 (file)
index 0000000..a579e12
--- /dev/null
@@ -0,0 +1,29 @@
+<e2:screen name="TestScreen">&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;e2timerlist><e2:element source="TimerList" ><e2:convert type="web:ListFiller" >
+       &lt;e2timer>
+               &lt;e2servicereference><e2:item name="ServiceReference" />&lt;/e2servicereference>
+               &lt;e2servicename><e2:item name="ServiceName" />&lt;/e2servicename>
+               &lt;e2eit><e2:item name="EIT" />&lt;/e2eit>
+               &lt;e2name><e2:item name="Name" />&lt;/e2name>
+               &lt;e2description><e2:item name="Description" />&lt;/e2description>
+               &lt;e2disabled><e2:item name="Disabled" />&lt;/e2disabled>
+               &lt;e2timebegin><e2:item name="TimeBegin" />&lt;/e2timebegin>
+               &lt;e2timeend><e2:item name="TimeEnd" />&lt;/e2timeend>
+               &lt;e2duration><e2:item name="Duration" />&lt;/e2duration>
+               &lt;e2startprepare><e2:item name="startPrepare" />&lt;/e2startprepare>
+               &lt;e2justplay><e2:item name="justPlay" />&lt;/e2justplay>
+               &lt;e2afterevent><e2:item name="afterEvent" />&lt;/e2afterevent>
+               &lt;e2logentries><e2:item name="LogEntries" />&lt;/e2logentries>
+               &lt;e2filename><e2:item name="Filename" />&lt;/e2filename>
+               &lt;e2backoff><e2:item name="Backoff" />&lt;/e2backoff>
+               &lt;e2nextactivation><e2:item name="nextActivation" />&lt;/e2nextactivation>
+               &lt;e2firsttryprepare><e2:item name="firstTryPrepare" />&lt;/e2firsttryprepare>
+               &lt;e2state><e2:item name="State" />&lt;/e2state>
+               &lt;e2repeated><e2:item name="Repeated" />&lt;/e2repeated>
+               &lt;e2dontsave><e2:item name="dontSave" />&lt;/e2dontsave>
+               &lt;e2cancled><e2:item name="Cancled" />&lt;/e2cancled>
+       &lt;/e2timer>
+       </e2:convert>
+       <e2:convert type="web:TextToHTML" /></e2:element>
+&lt;/e2timerlist>
+</e2:screen>
\ No newline at end of file
diff --git a/webinterface/src/web/vol.xml b/webinterface/src/web/vol.xml
new file mode 100644 (file)
index 0000000..fb8d463
--- /dev/null
@@ -0,0 +1,5 @@
+<e2:screen name="TestScreen">
+<e2:element source="Volume" id="set">
+<e2:convert type="VolumeToText">CurrentVolume</e2:convert>
+</e2:element>
+</e2:screen>
diff --git a/webinterface/src/web/zap.xml b/webinterface/src/web/zap.xml
new file mode 100644 (file)
index 0000000..5739cd9
--- /dev/null
@@ -0,0 +1,3 @@
+<e2:screen name="TestScreen"><e2:element source="ServiceList" id="ZapTo">
+       <e2:convert type="web:Null" />
+</e2:element></e2:screen>
diff --git a/webinterface/src/webif.py b/webinterface/src/webif.py
new file mode 100644 (file)
index 0000000..57b8395
--- /dev/null
@@ -0,0 +1,371 @@
+#
+# OK, this is more than a proof of concept
+# things to improve:
+#  - nicer code
+#  - screens need to be defined somehow else. 
+#    I don't know how, yet. Probably each in an own file.
+#  - more components, like the channellist
+#  - better error handling
+#  - use namespace parser
+
+from Screens.Screen import Screen
+from Tools.Import import my_import
+
+# for our testscreen
+from Screens.InfoBarGenerics import InfoBarServiceName, InfoBarEvent, InfoBarTuner
+
+from Components.Sources.Clock import Clock
+from Components.Sources.ServiceList import ServiceList
+from Components.Sources.Volume import Volume
+from Components.Sources.EPG import EPG
+from Components.Sources.Timer import Timer
+from Components.Sources.FrontendStatus import FrontendStatus
+
+from Components.Converter.Converter import Converter
+from Components.Converter.VolumeToText import VolumeToText 
+
+from Components.Element import Element
+
+from xml.sax import make_parser
+from xml.sax.handler import ContentHandler, feature_namespaces
+from twisted.python import util
+import sys
+import time
+# prototype of the new web frontend template system.
+
+class WebScreen(Screen):
+       def __init__(self, session):
+               Screen.__init__(self, session)
+               self.stand_alone = True
+
+# a test screen
+class TestScreen(InfoBarServiceName, InfoBarEvent,InfoBarTuner, WebScreen,Volume):
+       def __init__(self, session):
+               WebScreen.__init__(self, session)
+               InfoBarServiceName.__init__(self)
+               InfoBarEvent.__init__(self)
+               InfoBarTuner.__init__(self)
+               Volume.__init__(self,session);
+               self["CurrentTime"] = Clock()
+#              self["TVSystem"] = Config(config.av.tvsystem)
+#              self["OSDLanguage"] = Config(config.osd.language)
+#              self["FirstRun"] = Config(config.misc.firstrun)
+               from enigma import eServiceReference
+               fav = eServiceReference('1:7:1:0:0:0:0:0:0:0:(type == 1) || (type == 17) || (type == 195) || (type == 25) FROM BOUQUET "bouquets.tv" ORDER BY bouquet')
+               self["ServiceList"] = ServiceList(fav, command_func = self.zapTo, validate_commands=False)
+               self["ServiceListBrowse"] = ServiceList(fav, command_func = self.browseTo)
+               self["Volume"] = Volume(session)
+               self["EPGTITLE"] = EPG(session,func=EPG.TITLE)
+               self["EPGSERVICE"] = EPG(session,func=EPG.SERVICE)
+               self["EPGNOWNEXT"] = EPG(session,func=EPG.NOWNEXT)
+               self["TimerList"] = Timer(session)
+
+       def browseTo(self, reftobrowse):
+               self["ServiceListBrowse"].root = reftobrowse
+
+       def zapTo(self, reftozap):
+               self.session.nav.playService(reftozap)
+
+# TODO: (really.) put screens into own files.
+class Streaming(WebScreen):
+       def __init__(self, session):
+               WebScreen.__init__(self, session)
+               from Components.Sources.StreamService import StreamService
+               self["StreamService"] = StreamService(self.session.nav)
+
+class StreamingM3U(WebScreen):
+       def __init__(self, session):
+               WebScreen.__init__(self, session)
+               from Components.Sources.StaticText import StaticText
+               from Components.Sources.Config import Config
+               from Components.config import config
+               
+               self["ref"] = StaticText()
+               self["localip"] = Config(config.network.ip)
+
+# implements the 'render'-call.
+# this will act as a downstream_element, like a renderer.
+class OneTimeElement(Element):
+       def __init__(self, id):
+               Element.__init__(self)
+               self.source_id = id
+
+       # CHECKME: is this ok performance-wise?
+       def handleCommand(self, args):
+               for c in args.get(self.source_id, []):
+                       self.source.handleCommand(c)
+
+       def render(self, stream):
+               t = self.source.getHTML(self.source_id)
+               if isinstance(t, unicode):
+                       t = t.encode("utf-8")
+               stream.write(t)
+
+       def execBegin(self):
+               pass
+       
+       def execEnd(self):
+               pass
+       
+       def onShow(self):
+               pass
+
+       def onHide(self):
+               pass
+       
+       def destroy(self):
+               pass
+
+class StreamingElement(OneTimeElement):
+       def __init__(self, id):
+               OneTimeElement.__init__(self, id)
+               self.stream = None
+
+       def changed(self, what):
+               if self.stream:
+                       self.render(self.stream)
+
+       def setStream(self, stream):
+               self.stream = stream
+
+# a to-be-filled list item
+class ListItem:
+       def __init__(self, name):
+               self.name = name
+
+class TextToHTML(Converter):
+       def __init__(self, arg):
+               Converter.__init__(self, arg)
+
+       def getHTML(self, id):
+               return self.source.text # encode & etc. here!
+
+# a null-output. Useful if you only want to issue a command.
+class Null(Converter):
+       def __init__(self, arg):
+               Converter.__init__(self, arg)
+
+       def getHTML(self, id):
+               return ""
+
+def escape(s):
+       return s.replace("\\", "\\\\").replace("\n", "\\n").replace('"', '\\"')
+
+class JavascriptUpdate(Converter):
+       def __init__(self, arg):
+               Converter.__init__(self, arg)
+
+       def getHTML(self, id):
+               return '<script>set("' + id + '", "' + escape(self.source.text) + '");</script>\n'
+
+# the performant 'listfiller'-engine (plfe)
+class ListFiller(Converter):
+       def __init__(self, arg):
+               Converter.__init__(self, arg)
+
+       def getText(self):
+               l = self.source.list
+               lut = self.source.lut
+               
+               # now build a ["string", 1, "string", 2]-styled list, with indices into the 
+               # list to avoid lookup of item name for each entry
+               lutlist = []
+               for element in self.converter_arguments:
+                       if isinstance(element, str):
+                               lutlist.append(element)
+                       elif isinstance(element, ListItem):
+                               lutlist.append(lut[element.name])
+               
+               # now, for the huge list, do:
+               res = ""
+               for item in l:
+                       for element in lutlist:
+                               if isinstance(element, str):
+                                       res += element
+                               else:
+                                       res += str(item[element])
+               # (this will be done in c++ later!)
+               return res
+               
+       text = property(getText)
+
+class webifHandler(ContentHandler):
+       def __init__(self, session):
+               self.res = [ ]
+               self.mode = 0
+               self.screen = None
+               self.session = session
+               self.screens = [ ]
+       
+       def startElement(self, name, attrs):
+               if name == "e2:screen":
+                       self.screen = eval(attrs["name"])(self.session) # fixme
+                       self.screens.append(self.screen)
+                       return
+       
+               if name[:3] == "e2:":
+                       self.mode += 1
+               
+               tag = "<" + name + ''.join([' ' + key + '="' + val + '"' for (key, val) in attrs.items()]) + ">"
+               tag = tag.encode("UTF-8")
+               
+               if self.mode == 0:
+                       self.res.append(tag)
+               elif self.mode == 1: # expect "<e2:element>"
+                       assert name == "e2:element", "found %s instead of e2:element" % name
+                       source = attrs["source"]
+                       self.source_id = str(attrs.get("id", source))
+                       self.source = self.screen[source]
+                       self.is_streaming = "streaming" in attrs
+               elif self.mode == 2: # expect "<e2:convert>"
+                       if name[:3] == "e2:":
+                               assert name == "e2:convert"
+                               
+                               ctype = attrs["type"]
+                               if ctype[:4] == "web:": # for now
+                                       self.converter = eval(ctype[4:])
+                               else:
+                                       self.converter = my_import('.'.join(["Components", "Converter", ctype])).__dict__.get(ctype)
+                               self.sub = [ ]
+                       else:
+                               self.sub.append(tag)
+               elif self.mode == 3:
+                       assert name == "e2:item", "found %s instead of e2:item!" % name
+                       assert "name" in attrs, "e2:item must have a name= attribute!"
+                       self.sub.append(ListItem(attrs["name"]))
+
+       def endElement(self, name):
+               if name == "e2:screen":
+                       self.screen = None
+                       return
+
+               tag = "</" + name + ">"
+               if self.mode == 0:
+                       self.res.append(tag)
+               elif self.mode == 2 and name[:3] != "e2:":
+                       self.sub.append(tag)
+               elif self.mode == 2: # closed 'convert' -> sub
+                       self.sub = lreduce(self.sub)
+                       if len(self.sub) == 1:
+                               self.sub = self.sub[0]
+                       c = self.converter(self.sub)
+                       c.connect(self.source)
+                       self.source = c
+                       
+                       del self.sub
+               elif self.mode == 1: # closed 'element'
+                       # instatiate either a StreamingElement or a OneTimeElement, depending on what's required.
+                       if not self.is_streaming:
+                               c = OneTimeElement(self.source_id)
+                       else:
+                               c = StreamingElement(self.source_id)
+                       
+                       c.connect(self.source)
+                       self.res.append(c)
+                       self.screen.renderer.append(c)
+                       del self.source
+
+               if name[:3] == "e2:":
+                       self.mode -= 1
+
+       def processingInstruction(self, target, data):
+               self.res.append('<?' + target + ' ' + data + '>')
+       
+       def characters(self, ch):
+               ch = ch.encode("UTF-8")
+               if self.mode == 0:
+                       self.res.append(ch)
+               elif self.mode == 2:
+                       self.sub.append(ch)
+       
+       def startEntity(self, name):
+               self.res.append('&' + name + ';');
+
+       def execBegin(self):
+               for screen in self.screens:
+                       screen.execBegin()
+
+       def cleanup(self):
+               print "screen cleanup!"
+               for screen in self.screens:
+                       screen.execEnd()
+                       screen.doClose()
+               self.screens = [ ]
+
+def lreduce(list):
+       # ouch, can be made better
+       res = [ ]
+       string = None
+       for x in list:
+               if isinstance(x, str) or isinstance(x, unicode):
+                       if isinstance(x, unicode):
+                               x = x.encode("UTF-8")
+                       if string is None:
+                               string = x
+                       else:
+                               string += x
+               else:
+                       if string is not None:
+                               res.append(string)
+                               string = None
+                       res.append(x)
+       if string is not None:
+               res.append(string)
+               string = None
+       return res
+
+def renderPage(stream, path, req, session):
+       
+       # read in the template, create required screens
+       # we don't have persistense yet.
+       # if we had, this first part would only be done once.
+       handler = webifHandler(session)
+       parser = make_parser()
+       parser.setFeature(feature_namespaces, 0)
+       parser.setContentHandler(handler)
+       parser.parse(open(util.sibpath(__file__, path)))
+       
+       # by default, we have non-streaming pages
+       finish = True
+       
+       # first, apply "commands" (aka. URL argument)
+       for x in handler.res:
+               if isinstance(x, Element):
+                       x.handleCommand(req.args)
+
+       handler.execBegin()
+
+       # now, we have a list with static texts mixed
+       # with non-static Elements.
+       # flatten this list, write into the stream.
+       for x in lreduce(handler.res):
+               if isinstance(x, Element):
+                       if isinstance(x, StreamingElement):
+                               finish = False
+                               x.setStream(stream)
+                       x.render(stream)
+               else:
+                       stream.write(str(x))
+
+       def ping(s):
+               from twisted.internet import reactor
+               s.write("\n");
+               reactor.callLater(3, ping, s)
+
+       # if we met a "StreamingElement", there is at least one
+       # element which wants to output data more than once,
+       # i.e. on host-originated changes.
+       # in this case, don't finish yet, don't cleanup yet,
+       # but instead do that when the client disconnects.
+       if finish:
+               handler.cleanup()
+               stream.finish()
+       else:
+               # ok.
+               # you *need* something which constantly sends something in a regular interval,
+               # in order to detect disconnected clients.
+               # i agree that this "ping" sucks terrible, so better be sure to have something 
+               # similar. A "CurrentTime" is fine. Or anything that creates *some* output.
+               ping(stream)
+               stream.closed_callback = lambda: handler.cleanup()