Index: main/waeup.kofa/branches/uli-zc-async/buildout-zeo.cfg
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/buildout-zeo.cfg	(revision 8863)
+++ main/waeup.kofa/branches/uli-zc-async/buildout-zeo.cfg	(revision 8864)
@@ -50,4 +50,7 @@
     </filestorage>
   </blobstorage>
+  <filestorage async>
+    path ${zope_conf:filestorage}/Data.async.fs
+  </filestorage>
   <eventlog>
     # This sets up logging to a file.
Index: main/waeup.kofa/branches/uli-zc-async/etc/site.zcml.in
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/etc/site.zcml.in	(revision 8863)
+++ main/waeup.kofa/branches/uli-zc-async/etc/site.zcml.in	(revision 8864)
@@ -5,4 +5,6 @@
   <include package="waeup.kofa" />
   <include package="waeup.kofa" file="mail.zcml" />
+  <!-- include package="zc.async" file="basic_dispatcher_policy.zcml" / -->
+  <include package="zc.async" file="multidb_dispatcher_policy.zcml" />
 
   <!-- Where should the datacenter reside by default? -->
Index: main/waeup.kofa/branches/uli-zc-async/etc/zeo2.ini.in
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/etc/zeo2.ini.in	(revision 8863)
+++ main/waeup.kofa/branches/uli-zc-async/etc/zeo2.ini.in	(revision 8864)
@@ -54,5 +54,5 @@
 use = egg:Paste#http
 host = ${kofa_params:host}
-port = ${kofa_params:zeo1_port}
+port = ${kofa_params:zeo2_port}
 threadpool_workers = ${kofa_params:threadpool_workers}
 use_threadpool = True
Index: main/waeup.kofa/branches/uli-zc-async/etc/zope.conf.in
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/etc/zope.conf.in	(revision 8863)
+++ main/waeup.kofa/branches/uli-zc-async/etc/zope.conf.in	(revision 8864)
@@ -28,4 +28,11 @@
 </zodb>
 
+<zodb async>
+  <filestorage>
+    # create true
+    path ${zope_conf:filestorage}/Data.async.fs
+  </filestorage>
+</zodb>
+
 <eventlog>
   # This sets up logging to a file.
Index: main/waeup.kofa/branches/uli-zc-async/etc/zope_zeo1.conf.in
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/etc/zope_zeo1.conf.in	(revision 8863)
+++ main/waeup.kofa/branches/uli-zc-async/etc/zope_zeo1.conf.in	(revision 8864)
@@ -26,5 +26,5 @@
     server localhost:8100
     storage 1
-    # ZEO client cache, in bytes
+     # ZEO client cache, in bytes
     cache-size 20MB
     # Uncomment to have a persistent disk cache
@@ -61,4 +61,16 @@
 </zodb>
 
+<zodb async>
+  <zeoclient>
+    server localhost:8100
+    storage async
+    name async
+    # ZEO client cache, in bytes
+    cache-size 20MB
+    # Uncomment to have a persistent disk cache
+    client ${zope_conf_zeo_1:filestorage}/zeo1_async
+  </zeoclient>
+</zodb>
+
 <eventlog>
   # This sets up logging to a file.
Index: main/waeup.kofa/branches/uli-zc-async/etc/zope_zeo2.conf.in
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/etc/zope_zeo2.conf.in	(revision 8863)
+++ main/waeup.kofa/branches/uli-zc-async/etc/zope_zeo2.conf.in	(revision 8864)
@@ -61,4 +61,17 @@
 </zodb>
 
+<zodb async>
+  <zeoclient>
+    server localhost:8100
+    storage async
+    name async
+    # ZEO client cache, in bytes
+    cache-size 20MB
+    # Uncomment to have a persistent disk cache
+    client ${zope_conf_zeo_1:filestorage}/zeo2_async
+  </zeoclient>
+</zodb>
+
+
 <eventlog>
   # This sets up logging to a file.
Index: main/waeup.kofa/branches/uli-zc-async/setup.py
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/setup.py	(revision 8863)
+++ main/waeup.kofa/branches/uli-zc-async/setup.py	(revision 8864)
@@ -37,4 +37,5 @@
     'zope.sendmail',
     'ulif.loghandlers',
+    'zc.async[z3]',
     ],
 
Index: main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/async.pt
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/async.pt	(revision 8864)
+++ main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/async.pt	(revision 8864)
@@ -0,0 +1,53 @@
+<html>
+  <head>
+    <title>Async testing</title>
+    <script type="text/javascript">
+$(document).ready(function() {
+  var myLoadingDiv = $("#progressbar");
+  var mySpinner = $("#loadspinner");
+  myLoadingDiv.progressbar({disabled:true});
+  function update() {
+  $.getJSON("status?",  {jobid: "4",}, function(data) {
+    if (data == null) {
+      myLoadingDiv.progressbar("disable");
+      myLoadingDiv.progressbar("value", 0);
+      mySpinner.html('No Data');
+      $("#msg").html("Syncing...");
+      clearInterval(intervalID);
+      //alert('No Data'):
+      }
+    else {
+      myLoadingDiv.progressbar("enable");
+      myLoadingDiv.progressbar("value", data.percent);
+      $("#msg").html(data.msg + ' (' + data.status + ') ');
+      //alert(data.msg);
+      if (data.percent == 100) {
+        mySpinner.html('Job finished.')
+        clearInterval(intervalID);
+        }
+      }
+  });}
+  intervalID = setInterval(update, 500);
+  //update();
+});
+    </script>
+  </head>
+  <body>
+    <h1>Async stuff</h1>
+    <div>Dispatcher: <span tal:content="view/dispatcher"></span></div>
+    <div>Queue: <span tal:content="view/queue"></span></div>
+    <div>Jobs: <span tal:content="structure view/job_status"></span></div>
+    <form method="POST">
+      <input type="submit" name="reload" value="reload" />
+      <input type="submit" name="start" value="start up" />
+    </form>
+    <div id="progressbar"
+	 class="ui-progressbar ui-widget ui-widget-content ui-corner-all">
+    </div>
+    <div id="msg">Hi there</div>
+    <div id="loadspinner">
+      <img src="" alt="Please wait..."
+	   tal:attributes="src view/spinner_url" />
+    </div>
+  </body>
+</html>
Index: main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/async.py
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/async.py	(revision 8864)
+++ main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/async.py	(revision 8864)
@@ -0,0 +1,249 @@
+import datetime
+import grok
+import os
+import time
+import zc.async.dispatcher
+from cgi import escape
+from pytz import utc
+from zc.async.interfaces import IQueue
+from zc.async.job import Job as AsyncJob
+from zc.async.queue import getDefaultQueue
+from waeup.kofa.interfaces import IUniversity
+from hurry.jqueryui import jqueryui, base, blitzer, ui_lightness, humanity
+from hurry.jquery import jquery
+from zc.async.interfaces import COMPLETED, NEW, PENDING, ACTIVE, ASSIGNED
+
+
+def compute(num):
+    start = time.time()
+    duration = 60
+    end = start + duration
+    print "MyJob starts computation at ", start
+    #from zc.async.local import getJob, getQueue
+    myjob = zc.async.local.getJob()
+    print "MyJob's job: ", zc.async.local.getJob()
+    print "MyJob's queue: ", zc.async.local.getQueue(), list(
+        zc.async.local.getQueue())
+    while True:
+	if time.time() > end:
+	    break
+	time.sleep(1)
+        percent = (time.time() - start) * 100.0 / duration
+        if percent > 100.0:
+            percent = 100.0
+        print "MyJob percent: ", percent
+        zc.async.local.setLiveAnnotation('percent', percent)
+	print "MyJob does something at %s of %s" % (
+            time.time() - start, duration)
+        print "MyJob's annotations: %r" % dict(myjob.annotations)
+        print "MyJob's percent: %r" % zc.async.local.getLiveAnnotation(
+            'percent')
+    return num * 2
+
+def get_next_num(context):
+    num = 1
+    print "KEYS: ", [x for x in context['jobs'].keys()]
+    while str(num) in [x for x in context['jobs'].keys()]:
+        num += 1
+    print "NEXT: ", str(num)
+    return str(num)
+
+class Job(AsyncJob):
+    percent = None
+    pass
+
+grok.templatedir('.') #os.path.dirname(__file__))
+class ASyncView(grok.View):
+    grok.context(IUniversity)
+    grok.name('async')
+    grok.template('async')
+
+    def update(self,  start=None, DELETE=None, REMOVE=None, *args, **kw):
+        humanity.need()
+        jqueryui.need()
+        # the image was created via http://ajaxload.info/
+        self.spinner_url = self.url(
+            grok.getSite()) + '/@@/waeup.kofa.browser/square_circles_black.gif'
+        print args, kw
+        self.dispatcher = zc.async.dispatcher.get()
+        site = grok.getSite()
+        newq = site.__parent__._p_jar.root()['zc.async'].items()[0][1]
+        print "NEW: ", newq, list(newq)
+
+
+        print "DISP LEN: ", dir(self.dispatcher), self.dispatcher.getStatusInfo(), self.dispatcher.getStatistics(), self.dispatcher.jobs.items() # self.dispatcher.getJobInfo()
+        self.queue = IQueue(self.context)
+        self.dispatcher2 = self.queue.dispatchers[zc.async.instanceuuid.UUID]
+        print "JOBS: ", self.dispatcher.jobs.keys(), self.dispatcher.jobs.values()
+        print "DISPATCHERS: ", self.dispatcher, self.dispatcher2
+        print "QUEUES: ", self.dispatcher.queues
+        print "QUEUE1: ", list(self.dispatcher.queues[''])
+        print "QUEUE: ", list(self.queue)
+        #print "DISPATCHERS: ", self.queue.dispatchers.items()
+        print "DEFAULT: ", getDefaultQueue(self.context), len(getDefaultQueue(self.context))
+        print "DELETE: ", DELETE
+        if DELETE is not None:
+            if DELETE in self.context['jobs']:
+                job = self.context['jobs'][DELETE]
+                from zc.async.interfaces import COMPLETED, NEW, PENDING
+                if job.status in (COMPLETED, NEW):
+                    del self.context['jobs'][DELETE]
+                    print "DELETED %s" % job
+                else:
+                    if job in self.queue:
+                        print "JOB IN ", self.queue, "!!!!!!!!!!!!!!!!!!"
+                        print "QUEUE BEFORE: ", list(self.queue)
+                        try:
+                            self.queue.remove(job)
+                        except:
+                            "COULDN'T REMOVE ANYWAY!!"
+                        print "QUEUE AFTER: ", list(self.queue)
+                        self.queue.pull()
+                        print "QUEUE AFTER2: ", list(self.queue)
+                    #job_queue = job.queue
+                    #agent = job.agent
+                    #print "JOB AGENT: ", agent, dir(agent)
+                    #print "JOB AGENT QUEUE: ", agent.queue, list(agent.queue)
+                    #print "JOB QUEUE: ", job_queue, list(job_queue)
+                    #if job in list(job_queue) or True:
+                    #    agent.remove(job)
+                    #    #job.queue.remove(job)
+                    #    print "REMOVED %s from queue %s" % (
+                    #        job, job_queue)
+                    else:
+                        print "CANT FIND JOB in QUEUE"
+
+        #import pdb; pdb.set_trace()
+        if start:
+            start_time = datetime.datetime.utcnow()
+            start_time += datetime.timedelta(seconds=10)
+            start_time = utc.localize(start_time)
+            print "START"
+            print "STARTTIME: ", start_time
+            import transaction
+            transaction.begin()
+            job = self.queue.put(Job(compute, 21),
+                                 begin_after=start_time)
+            job.annotations['percent'] = 0.0
+            print " started: ", job.status, type(job)
+            if 'jobs' not in self.context:
+                self.context['jobs'] = grok.Container()
+            job_id = get_next_num(self.context)
+            print "JOB ID: ", job_id, dir(job)
+            self.context['jobs'][job_id] = job
+            transaction.commit()
+            time.sleep(0.5)
+            self.redirect(self.url())
+
+    def job_status(self):
+        if 'jobs' not in self.context:
+            return ''
+        result = ""
+        #for num, job in enumerate(self.queue):
+        for num, job in self.context['jobs'].items():
+            result += '<div><form>'
+            if job.status in ('completed-status', 'new-status'):
+                result += '<a href="?DELETE=%s">delete</a>' %(
+                    num)
+            else: # job.status == 'pendig-status' or (
+                # job.status == 'active-status'):
+                result += '<a href="?DELETE=%s">remove from queue</a>' % (
+                    num)
+            result += '<input type="checkbox" name="remove" />%s %s, %s, %r</form></div>' % (
+                num,
+                escape('%r' % job),
+                job.status,
+                dict(job.annotations))
+            print "job in queue: ", job, type(job)
+        return result
+
+    def NOrender(self):
+        print "RENDER: ", self.namespace().items(), type(self.namespace)
+        return grok.PageTemplate('Hallo!')
+        #print "RENDER: ", self.static['square_circles_black.gif']
+        #return r'''
+        return '''
+<html>
+<head>
+<title>Async testing</title>
+<script type="text/javascript">
+$(document).ready(function() {
+  var myLoadingDiv = $("#progressbar");
+  var mySpinner = $("#loadspinner");
+  myLoadingDiv.progressbar({disabled:true});
+  function update() {
+  $.getJSON("status?",  {jobid: "4",}, function(data) {
+    if (data == null) {
+      myLoadingDiv.progressbar("disable");
+      myLoadingDiv.progressbar("value", 0);
+      $("#msg").html("Syncing...");
+      clearInterval(intervalID);
+      //alert('No Data'):
+      }
+    else {
+      myLoadingDiv.progressbar("enable");
+      myLoadingDiv.progressbar("value", data.percent);
+      $("#msg").html(data.msg + ' (' + data.status + ') ');
+      //alert(data.msg);
+      if (data.percent == 100) {
+        clearInterval(intervalID);
+        }
+      }
+  });}
+  intervalID = setInterval(update, 500);
+  //update();
+});
+</script>
+</head>
+<body>
+<h1>Async stuff</h1>
+<div>Dispatcher: %s</div>
+<div>Queue: %s</div>
+<div>Jobs: %s</div>
+<form method="POST">
+  <input type="submit" name="reload" value="reload" />
+  <input type="submit" name="start" value="start up" />
+</form>
+<div id="progressbar"
+     class="ui-progressbar ui-widget ui-widget-content ui-corner-all">
+       <div id="msg">Hi there</div>
+</div>
+<div id="loadspinner">
+</div>
+</body>
+</htlm>
+''' % (
+   escape('%r' % self.dispatcher),
+   escape('%r' % self.queue),
+   self.job_status(),
+   )
+
+
+class ASyncJSON(grok.JSON):
+    grok.context(IUniversity)
+
+    def status(self, jobid):
+        print "request for ", jobid
+        msg = 'please wait...'
+        job = self.context['jobs'].get(jobid, None)
+        if not job:
+            return
+        percent = job.annotations.get('percent', None)
+        if not percent:
+            return
+        percent = int(percent+0.5)
+        print "percent: ", percent
+        if percent >= 100:
+            percent = 100
+            msg = 'done.'
+        status_map = {
+            NEW: 'new',
+            COMPLETED: 'completed',
+            PENDING: 'pending',
+            ACTIVE: 'active',
+            ASSIGNED: 'assigned',
+            }
+        return {'msg': msg,
+                'percent': percent,
+                'status': status_map.get(job.status, 'unknown'),
+                }
Index: main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/configure.zcml
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/configure.zcml	(revision 8863)
+++ main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/configure.zcml	(revision 8864)
@@ -17,5 +17,5 @@
   <grok:grok package="." />
 
-
+  <!-- include package="." file="async.zcml" / -->
   <includeOverrides package="waeup.kofa.widgets" file="overrides.zcml" />
   <includeOverrides package="waeup.kofa.utils" file="overrides.zcml" />
