add preview calculation
authorymh <ymh.work@gmail.com>
Sun, 08 Mar 2015 14:53:52 +0100
changeset 492 19220d52bce7
parent 491 8444b4f67e45
child 493 09aa28e25840
add preview calculation
.hgignore
.settings/org.eclipse.core.resources.prefs
src/hdalab/__init__.py
src/hdalab/celery.py
src/hdalab/config.py.tmpl
src/hdalab/management/commands/calculate_preview.py
src/hdalab/models/__init__.py
src/hdalab/models/renkan.py
src/hdalab/scripts/capture-phantomjs.js
src/hdalab/services.py
src/hdalab/settings.py
src/hdalab/signals.py
src/hdalab/tasks.py
src/hdalab/templates/renkan_view_full.html
src/hdalab/utils.py
virtualenv/res/lib/lib_create_env.py
virtualenv/res/src/SQLAlchemy-0.9.8.tar.gz
virtualenv/res/src/anyjson-0.3.3.tar.gz
virtualenv/res/src/billiard-3.3.0.19.tar.gz
virtualenv/res/src/celery-3.1.17.tar.gz
virtualenv/res/src/kombu-3.0.24.tar.gz
virtualenv/res/src/py-amqp-1.4.6.tar.gz
virtualenv/web/res/requirements.txt
--- a/.hgignore	Fri Mar 06 18:12:15 2015 +0100
+++ b/.hgignore	Sun Mar 08 14:53:52 2015 +0100
@@ -6,6 +6,7 @@
 syntax: regexp
 ^web/.htaccess$
 ^web/static/site$
+^web/static/media
 \.DS_Store
 ^virtualenv/web/project-boot\.py$
 ^web/index/.*$
@@ -19,4 +20,4 @@
 ^src/hdabo/config\.py$
 ^web/static/media/thumbnails/renkan/renkan_default_icon\.png\.100x100_q85\.png$
 ^src/hdalab/config\.py$
-^sbin/sync/config\.py$
\ No newline at end of file
+^sbin/sync/config\.py$
--- a/.settings/org.eclipse.core.resources.prefs	Fri Mar 06 18:12:15 2015 +0100
+++ b/.settings/org.eclipse.core.resources.prefs	Sun Mar 08 14:53:52 2015 +0100
@@ -32,10 +32,12 @@
 encoding//src/hdabo/views.py=utf-8
 encoding//src/hdabo/wp_utils.py=utf-8
 encoding//src/hdalab/__init__.py=utf-8
+encoding//src/hdalab/celery.py=utf-8
 encoding//src/hdalab/config.py=utf-8
 encoding//src/hdalab/fields.py=utf-8
 encoding//src/hdalab/forms.py=utf-8
 encoding//src/hdalab/manage.py=utf-8
+encoding//src/hdalab/management/commands/calculate_preview.py=utf-8
 encoding//src/hdalab/management/commands/export_tags_csv.py=utf-8
 encoding//src/hdalab/management/commands/export_wpcategory_csv.py=utf-8
 encoding//src/hdalab/management/commands/fill_tag_years.py=utf-8
@@ -66,6 +68,8 @@
 encoding//src/hdalab/models/renkan.py=utf-8
 encoding//src/hdalab/services.py=utf-8
 encoding//src/hdalab/settings.py=utf-8
+encoding//src/hdalab/signals.py=utf-8
+encoding//src/hdalab/tasks.py=utf-8
 encoding//src/hdalab/urls.py=utf-8
 encoding//src/hdalab/utils.py=utf-8
 encoding//src/hdalab/views/ajax.py=utf-8
--- a/src/hdalab/__init__.py	Fri Mar 06 18:12:15 2015 +0100
+++ b/src/hdalab/__init__.py	Sun Mar 08 14:53:52 2015 +0100
@@ -1,4 +1,6 @@
 # -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
 VERSION = (3, 0, 0, "alpha", 12)
 
 
@@ -13,5 +15,12 @@
             version = '%s-%s.%s' % (version, VERSION[3], VERSION[4])
     return version
 
+__version__ = get_version()
 
-__version__ = get_version()
+try:
+    from .celery import app as celery_app
+except:
+    pass
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hdalab/celery.py	Sun Mar 08 14:53:52 2015 +0100
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+'''
+Created on Mar 7, 2015
+
+@author: ymh
+'''
+from __future__ import absolute_import
+
+import os
+
+from django.conf import settings
+
+from celery import Celery
+
+# set the default Django settings module for the 'celery' program.
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'hdalab.settings')
+
+app = Celery('hdalab')
+
+# Using a string here means the worker will not have to
+# pickle the object when using Windows.
+app.config_from_object('django.conf:settings')
+app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
--- a/src/hdalab/config.py.tmpl	Fri Mar 06 18:12:15 2015 +0100
+++ b/src/hdalab/config.py.tmpl	Sun Mar 08 14:53:52 2015 +0100
@@ -123,3 +123,7 @@
 }
 
 DEFAULT_FROM_EMAIL = "do-not-reply@iri-research.org"
+
+RENKAN_PREVIEW_PHANTOMJS_PATH = 'phantomjs'
+
+BROKER_URL = 'sqla+sqlite:///'+os.path.abspath(os.path.join(BASE_DIR,"../../run/celerydb.sqlite"))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hdalab/management/commands/calculate_preview.py	Sun Mar 08 14:53:52 2015 +0100
@@ -0,0 +1,59 @@
+# -*- coding: utf-8 -*-
+'''
+Created on Jan 30, 2012
+
+@author: ymh
+'''
+
+import logging
+from optparse import make_option
+
+from django.conf import settings
+from django.core.management.base import NoArgsCommand
+from django.core.management.color import no_style
+
+from hdabo.utils import show_progress
+from hdalab.models.renkan import HdalabRenkan
+from hdalab.services import renkan_capture_preview
+
+
+logger = logging.getLogger(__name__)
+
+class Command(NoArgsCommand):
+    '''
+    calculate renkan preview.
+    '''
+    options = ''
+    help = """calculate renkan preview."""
+    
+    option_list = NoArgsCommand.option_list + (
+        make_option('--all',
+            action='store_true',
+            dest='all',
+            default=False,
+            help='force all tags to be updated, not only those not yet processed'),
+    )
+    
+
+    def handle_noargs(self, **options):
+                
+        self.style = no_style()
+        
+        self.all = options.get('all', False)
+
+        queryset = HdalabRenkan.objects.filter(state=HdalabRenkan.PUBLISHED)
+        
+        if not self.all:
+            queryset = queryset.filter(renkan__image = settings.DEFAULT_RENKAN_ICON)
+
+        count = queryset.count()
+
+        writer = None
+        for i,hdalab_renkan in enumerate(queryset.select_related()):
+            writer = show_progress(i+1, count, hdalab_renkan.renkan.title, 50, writer)
+            if hdalab_renkan.renkan.image and hdalab_renkan.renkan.image != settings.DEFAULT_RENKAN_ICON:
+                hdalab_renkan.renkan.image.delete(False)
+                hdalab_renkan.renkan.image.delete_thumbnails()
+
+            renkan_capture_preview(hdalab_renkan)
+
--- a/src/hdalab/models/__init__.py	Fri Mar 06 18:12:15 2015 +0100
+++ b/src/hdalab/models/__init__.py	Sun Mar 08 14:53:52 2015 +0100
@@ -3,4 +3,6 @@
 from hdalab.models.dataviz import TagYears, Country, GeoInclusion, TagLinks, DbpediaFields, HdaSession, InseeCoords, DatasheetExtras, DbpediaFieldsTranslation
 from hdalab.models.renkan import HdalabRenkan, HdalabRenkanStateTransition
 
-__all__ = ['WpCategory', 'InfoboxParameter', 'TagInfobox', 'TagWpCategory', 'TagYears', 'Country', 'GeoInclusion', 'TagLinks', 'DbpediaFields', 'DbpediaFieldsTranslation', 'HdaSession', 'InseeCoords', 'DatasheetExtras', 'WpCategoryInclusion', 'HdalabRenkan', 'HdalabRenkanStateTransition']
\ No newline at end of file
+__all__ = ['WpCategory', 'InfoboxParameter', 'TagInfobox', 'TagWpCategory', 'TagYears', 'Country', 'GeoInclusion', 'TagLinks', 'DbpediaFields', 'DbpediaFieldsTranslation', 'HdaSession', 'InseeCoords', 'DatasheetExtras', 'WpCategoryInclusion', 'HdalabRenkan', 'HdalabRenkanStateTransition']
+
+import hdalab.signals
\ No newline at end of file
--- a/src/hdalab/models/renkan.py	Fri Mar 06 18:12:15 2015 +0100
+++ b/src/hdalab/models/renkan.py	Sun Mar 08 14:53:52 2015 +0100
@@ -8,12 +8,7 @@
 from renkanmanager.models import Renkan
 
 from django.conf import settings
-from django.core.mail.message import EmailMultiAlternatives
 from django.db import models
-from django.db.models.signals import post_save
-from django.template.base import TemplateDoesNotExist
-from django.template.loader import render_to_string
-from django.utils.html import strip_tags
 from django.utils.translation import ugettext as _
 
 
@@ -50,7 +45,7 @@
 
 class HdalabRenkanStateTransition(models.Model):
 
-    renkan = models.ForeignKey(HdalabRenkan, blank=False, null=False)
+    renkan = models.ForeignKey(HdalabRenkan, blank=False, null=False, related_name='states')
     from_state = models.IntegerField(choices=HdalabRenkan.STATE_CHOICES, default=1, blank=False, null=False)
     to_state = models.IntegerField(choices=HdalabRenkan.STATE_CHOICES, default=1, blank=False, null=False)
     ts = models.DateTimeField(auto_now_add=True, blank=False, null=False)
@@ -59,50 +54,4 @@
     
     class Meta:
         app_label = 'hdalab'
-
-MAIL_TEMPLATES = {
-    (HdalabRenkan.MODERATED,HdalabRenkan.PUBLISHED): ("mails/published_renkan", "Renkan publié"),
-    (HdalabRenkan.MODERATED,HdalabRenkan.REJECTED): ("mails/rejected_renkan", "Renkan rejeté"),
-    (HdalabRenkan.PUBLISHED, HdalabRenkan.EDITION): ("mails/unpublished_renkan", "Renkan dépublié"),
-}
-
-
-#TODO put into queue
-def send_renkan_moderation_messages(sender, **kwargs):
-    renkan_state = kwargs.get('instance', None)
-    if not renkan_state or (renkan_state.from_state,renkan_state.to_state) not in MAIL_TEMPLATES:
-        return
-
-    template_key = (renkan_state.from_state,renkan_state.to_state)
-    msg_txt = ""
-    msg_html = ""
-    subject = ""
-    try:
-        template_name, subject = MAIL_TEMPLATES[template_key]
-#        template = loader.get_template(template_name)
-        context = {'renkan_state': renkan_state, 'WEB_URL': settings.WEB_URL}
-        msg_html = render_to_string(template_name+".txt", context)
-        msg_txt = render_to_string(template_name+".html", context)
-    except TemplateDoesNotExist:
-        logger.error("Mail template %s for state %s not found", MAIL_TEMPLATES[template_key], HdalabRenkan.STATE_CHOICES_DICT[renkan_state.to_state])
-        return
-    except Exception as e:
-        logger.error("Error rendering template %s for state %s : %r", MAIL_TEMPLATES[template_key], HdalabRenkan.STATE_CHOICES_DICT[renkan_state.to_state], e)
-    
-    if msg_txt and msg_html and renkan_state.renkan and renkan_state.renkan.renkan and renkan_state.renkan.renkan.owner and renkan_state.renkan.renkan.owner.email:
-        logger.debug("Sending following mail to %s : %s", renkan_state.renkan.renkan.owner.email, msg_txt)
-        emsg = EmailMultiAlternatives(subject, strip_tags(msg_txt), settings.DEFAULT_FROM_EMAIL, [renkan_state.renkan.renkan.owner.email])
-        emsg.attach_alternative(msg_html, "text/html")
-        emsg.send(fail_silently=True)
-
-
-def queue_renkan_rendering(sender, **kwargs):
-    pass
-    #check state
-    #queue renkan for endering
-    
-    
-RENKAN_MODERATION_UUID = "e2f84503-609b-4efa-819d-908e2efe7b1b"
-RENKAN_RENDERING_UUID = "b8830748-be2b-479a-8aef-c8d952437b2f"
-
-post_save.connect(send_renkan_moderation_messages, sender=HdalabRenkanStateTransition, dispatch_uid=RENKAN_MODERATION_UUID)
+        ordering = ["-ts"]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hdalab/scripts/capture-phantomjs.js	Sun Mar 08 14:53:52 2015 +0100
@@ -0,0 +1,56 @@
+//from https://github.com/makinacorpus/django-screamshot
+
+var page = require('webpage').create(),
+    system = require('system');
+
+/** 
+ * arguments:
+ * [1] => URL
+ * [2] => output. Use /dev/stdout if you want to capture.
+ * [3] => size
+ */
+
+var address = system.args[1],
+    output  = system.args[2];
+
+config = {}
+system.args.forEach(function(arg, i) {
+    if (i > 2) {
+        namev = arg.split('=');
+        config[namev[0].replace('--', '')] = namev[1];
+    }
+});
+
+var method = config.method || 'get',
+     width = config.width || 1400,
+    height = config.height || 1,
+      wait = config.wait || 200;
+
+/**
+ * please note: the default height is intentionaly left as 1.
+ * the thing is, if you skip the height, phantomjs falls back
+ * to some default viewport. and that's not what we want. we
+ * want to set the width, and let the height auto-calculate.
+ */
+page.viewportSize = {width: width, height: height}
+
+format = config.format || 'png';
+
+if (format == 'pdf') {
+    page.paperSize = {
+        format: 'A4',
+        orientation: config.orientation || 'portrait',
+        margin: config.margin || '0cm'
+    }
+}
+
+page.settings.resourceTimeout = 10000;
+
+page.open(address, function(status){
+    if (status == 'success') {
+        setTimeout(function(){
+            page.render(output, {format: format});
+            phantom.exit();
+        }, wait);
+    }
+});
--- a/src/hdalab/services.py	Fri Mar 06 18:12:15 2015 +0100
+++ b/src/hdalab/services.py	Sun Mar 08 14:53:52 2015 +0100
@@ -5,12 +5,20 @@
 @author: ymh
 '''
 import logging
+import os
 
+from django.conf import settings
+from django.core.urlresolvers import reverse
 from django.db import transaction
 
 from hdalab.models.renkan import HdalabRenkanStateTransition
 
 
+from subprocess import check_call
+
+
+
+
 logger = logging.getLogger(__name__)
 
 @transaction.atomic
@@ -22,3 +30,42 @@
         hda_renkan.state = state
         hda_renkan.save()
         
+
+def renkan_capture_preview(hdalab_renkan):
+    #get last state date or last modification date
+    #states are ordered by ts
+    folder_date = hdalab_renkan.renkan.modification_date
+    states = hdalab_renkan.states
+    state = None
+    if states.count() > 0:
+        state = states.all()[0]
+    if state:
+        folder_date =  state.ts
+
+    rel_export_path_dir = "thumbnails/renkan/%04d/%02d/%02d" % (folder_date.year, folder_date.month, folder_date.day)
+    export_path_dir = os.path.join(settings.MEDIA_ROOT,rel_export_path_dir)
+    export_filename = "%s.png" % hdalab_renkan.renkan.rk_id
+    
+    export_path = os.path.join(export_path_dir, export_filename)
+    rel_export_path = os.path.join(rel_export_path_dir, export_filename)
+    
+    if not os.path.exists(export_path_dir):
+        os.makedirs(export_path_dir)
+        
+    preview_dim = getattr(settings, 'RENKAN_PREVIEW_DIM', (500,500))
+    preview_wait = getattr(settings, 'RENKAN_PREVIEW_WAIT', 5000)
+
+    preview_args = [
+        getattr(settings,'RENKAN_PREVIEW_PHANTOMJS_PATH','phantomjs'),
+        os.path.join(os.path.dirname(os.path.abspath(__file__)),'scripts/capture-phantomjs.js'),
+        "%s%shdalab%s?rk_id=%s" % (settings.WEB_URL, settings.BASE_URL, reverse('renkan_full'),hdalab_renkan.renkan.rk_id),
+        export_path,
+        "--width=%d" % preview_dim[0],
+        "--height=%d" % preview_dim[1],
+        "--wait=%d" % preview_wait
+    ]
+    check_call(preview_args)
+    
+    hdalab_renkan.renkan.image = rel_export_path
+    hdalab_renkan.renkan.save()
+
--- a/src/hdalab/settings.py	Fri Mar 06 18:12:15 2015 +0100
+++ b/src/hdalab/settings.py	Sun Mar 08 14:53:52 2015 +0100
@@ -177,6 +177,11 @@
 
 LOCALE_PATHS = ()
 
+RENKAN_PREVIEW_DIM = (500,500)
+RENKAN_PREVIEW_WAIT = 5000
+
+CELERY_TASK_SERIALIZER = 'json'
+CELERY_ACCEPT_CONTENT = ['json', 'msgpack', 'yaml']
 
 from hdalab.config import * #@UnusedWildImport
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hdalab/signals.py	Sun Mar 08 14:53:52 2015 +0100
@@ -0,0 +1,88 @@
+# -*- coding: utf-8 -*-
+'''
+Created on Mar 8, 2015
+
+@author: ymh
+'''
+import logging
+
+from django.conf import settings
+from django.core.mail.message import EmailMultiAlternatives
+from django.db.models.signals import post_save, pre_delete
+from django.template.base import TemplateDoesNotExist
+from django.template.loader import render_to_string
+from django.utils.html import strip_tags
+
+from hdalab.models.renkan import HdalabRenkan, HdalabRenkanStateTransition
+from renkanmanager.models import Renkan
+
+
+logger = logging.getLogger(__name__)
+
+MAIL_TEMPLATES = {
+    (HdalabRenkan.MODERATED,HdalabRenkan.PUBLISHED): ("mails/published_renkan", "Renkan publié"),
+    (HdalabRenkan.MODERATED,HdalabRenkan.REJECTED): ("mails/rejected_renkan", "Renkan rejeté"),
+    (HdalabRenkan.PUBLISHED, HdalabRenkan.EDITION): ("mails/unpublished_renkan", "Renkan dépublié"),
+}
+
+
+#TODO put into queue
+def send_renkan_moderation_messages(sender, **kwargs):
+    renkan_state = kwargs.get('instance', None)
+    if not renkan_state or (renkan_state.from_state,renkan_state.to_state) not in MAIL_TEMPLATES:
+        return
+
+    template_key = (renkan_state.from_state,renkan_state.to_state)
+    msg_txt = ""
+    msg_html = ""
+    subject = ""
+    try:
+        template_name, subject = MAIL_TEMPLATES[template_key]
+#        template = loader.get_template(template_name)
+        context = {'renkan_state': renkan_state, 'WEB_URL': settings.WEB_URL}
+        msg_html = render_to_string(template_name+".txt", context)
+        msg_txt = render_to_string(template_name+".html", context)
+    except TemplateDoesNotExist:
+        logger.error("Mail template %s for state %s not found", MAIL_TEMPLATES[template_key], HdalabRenkan.STATE_CHOICES_DICT[renkan_state.to_state])
+        return
+    except Exception as e:
+        logger.error("Error rendering template %s for state %s : %r", MAIL_TEMPLATES[template_key], HdalabRenkan.STATE_CHOICES_DICT[renkan_state.to_state], e)
+    
+    if msg_txt and msg_html and renkan_state.renkan and renkan_state.renkan.renkan and renkan_state.renkan.renkan.owner and renkan_state.renkan.renkan.owner.email:
+        logger.debug("Sending following mail to %s : %s", renkan_state.renkan.renkan.owner.email, msg_txt)
+        emsg = EmailMultiAlternatives(subject, strip_tags(msg_txt), settings.DEFAULT_FROM_EMAIL, [renkan_state.renkan.renkan.owner.email])
+        emsg.attach_alternative(msg_html, "text/html")
+        emsg.send(fail_silently=True)
+
+
+def queue_renkan_rendering(sender, **kwargs):
+    renkan_state = kwargs.get('instance', None)
+    if not renkan_state:
+        return
+    
+    if renkan_state.from_state == HdalabRenkan.PUBLISHED and renkan_state.renkan.renkan.image != settings.DEFAULT_RENKAN_ICON:
+        if renkan_state.renkan.renkan.image:
+            renkan_state.renkan.renkan.image.delete(False)
+            renkan_state.renkan.renkan.image.delete_thumbnails()
+        renkan_state.renkan.renkan.image = settings.DEFAULT_RENKAN_ICON
+        renkan_state.renkan.renkan.save()
+    elif renkan_state.to_state == HdalabRenkan.PUBLISHED:
+        from hdalab.tasks import capture_preview
+        capture_preview.delay(renkan_state.renkan.renkan.rk_id)  # @UndefinedVariable
+
+def renkan_delete_image(sender, **kwargs):
+    renkan = kwargs.get('instance', None)
+    if not renkan or not renkan.image or renkan.image == settings.DEFAULT_RENKAN_ICON:
+        return
+    renkan.image.delete(False)
+    renkan.image.delete_thumbnails()
+
+    
+RENKAN_MODERATION_UUID = "e2f84503-609b-4efa-819d-908e2efe7b1b"
+RENKAN_RENDERING_UUID = "b8830748-be2b-479a-8aef-c8d952437b2f"
+RENKAN_DELETE_UUID = "09c23ca2-4d59-4c29-b94a-2c2672d5a89b"
+
+post_save.connect(send_renkan_moderation_messages, sender=HdalabRenkanStateTransition, dispatch_uid=RENKAN_MODERATION_UUID)
+post_save.connect(queue_renkan_rendering, sender=HdalabRenkanStateTransition, dispatch_uid=RENKAN_RENDERING_UUID)
+pre_delete.connect(renkan_delete_image, sender=Renkan, dispatch_uid=RENKAN_DELETE_UUID)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hdalab/tasks.py	Sun Mar 08 14:53:52 2015 +0100
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+'''
+Created on Mar 7, 2015
+
+@author: ymh
+'''
+from __future__ import absolute_import
+
+from celery import shared_task
+from hdalab.models.renkan import HdalabRenkan
+from hdalab.services import renkan_capture_preview
+
+@shared_task
+def capture_preview(rk_id):
+    
+    hdalab_renkan = HdalabRenkan.objects.filter(renkan__rk_id=rk_id).select_related().get()
+    
+    renkan_capture_preview(hdalab_renkan)
\ No newline at end of file
--- a/src/hdalab/templates/renkan_view_full.html	Fri Mar 06 18:12:15 2015 +0100
+++ b/src/hdalab/templates/renkan_view_full.html	Sun Mar 08 14:53:52 2015 +0100
@@ -34,6 +34,8 @@
                     editor_mode: false,
                     show_bins: false,
                     show_export_button: false,
+                    show_top_bar: false,
+                    show_minimap: false,
                     language: "fr"
                 });
                 Rkns.jsonIO(_renkan, {
--- a/src/hdalab/utils.py	Fri Mar 06 18:12:15 2015 +0100
+++ b/src/hdalab/utils.py	Sun Mar 08 14:53:52 2015 +0100
@@ -4,12 +4,14 @@
 
 @author: ymh and tc
 '''
+import hashlib
+import logging
+import re
+
 from django.core.cache import cache
 from django.utils.encoding import smart_str
-import hashlib
-import re
 
-import logging
+
 logger = logging.getLogger(__name__)
 
 
@@ -29,4 +31,7 @@
     while n > 0:
         digits.insert(0, n % b)
         n  = n // b
-    return digits
\ No newline at end of file
+    return digits
+
+    
+    
\ No newline at end of file
--- a/virtualenv/res/lib/lib_create_env.py	Fri Mar 06 18:12:15 2015 +0100
+++ b/virtualenv/res/lib/lib_create_env.py	Sun Mar 08 14:53:52 2015 +0100
@@ -50,6 +50,11 @@
     'REDLAND_BINDINGS': { 'setup': 'redland_bindings', 'url':'redland-bindings-1.0.17.1.tar.gz', 'local':"redland-bindings-1.0.17.1.tar.gz", 'install': {'method': 'install_redland_bindings', 'option_str': None, 'dict_extra_env': None}},
     'UNIDECODE': { 'setup': 'unidecode', 'url':'https://pypi.python.org/packages/source/U/Unidecode/Unidecode-0.04.17.tar.gz', 'local':"Unidecode-0.04.17.tar.gz", 'install': {'method': 'pip', 'option_str': None, 'dict_extra_env': None}},
     'PYTZ': { 'setup': 'pytz', 'url':'https://pypi.python.org/packages/source/p/pytz/pytz-2014.10.tar.bz2', 'local':"pytz-2014.10.tar.bz2", 'install': {'method': 'pip', 'option_str': None, 'dict_extra_env': None}},
+    'KOMBU': { 'setup': 'kombu', 'url':'https://github.com/celery/kombu/archive/v3.0.24.tar.gz', 'local':"kombu-3.0.24.tar.gz", 'install': {'method': 'pip', 'option_str': None, 'dict_extra_env': None}},
+    'AMQP': { 'setup': 'amqp', 'url':'https://github.com/celery/py-amqp/archive/v1.4.6.tar.gz', 'local':"py-amqp-1.4.6.tar.gz", 'install': {'method': 'pip', 'option_str': None, 'dict_extra_env': None}},
+    'ANYJSON': { 'setup': 'anyjson', 'url':'https://bitbucket.org/runeh/anyjson/get/0.3.3.tar.gz', 'local':"anyjson-0.3.3.tar.gz", 'install': {'method': 'pip', 'option_str': None, 'dict_extra_env': None}},
+    'BILLIARD': { 'setup': 'billiard', 'url':'https://github.com/celery/billiard/archive/v3.3.0.19.tar.gz', 'local':"billiard-3.3.0.19.tar.gz", 'install': {'method': 'pip', 'option_str': None, 'dict_extra_env': None}},
+    'CELERY': { 'setup': 'celery', 'url':'https://github.com/celery/celery/archive/v3.1.17.tar.gz', 'local':"celery-3.1.17.tar.gz", 'install': {'method': 'pip', 'option_str': None, 'dict_extra_env': None}},
 }
 
 
Binary file virtualenv/res/src/SQLAlchemy-0.9.8.tar.gz has changed
Binary file virtualenv/res/src/anyjson-0.3.3.tar.gz has changed
Binary file virtualenv/res/src/billiard-3.3.0.19.tar.gz has changed
Binary file virtualenv/res/src/celery-3.1.17.tar.gz has changed
Binary file virtualenv/res/src/kombu-3.0.24.tar.gz has changed
Binary file virtualenv/res/src/py-amqp-1.4.6.tar.gz has changed
--- a/virtualenv/web/res/requirements.txt	Fri Mar 06 18:12:15 2015 +0100
+++ b/virtualenv/web/res/requirements.txt	Sun Mar 08 14:53:52 2015 +0100
@@ -1,3 +1,4 @@
+#-e git+git://github.com/IRI-Research/rdflib.git@96c30f98bbb628e13aaa32c9c392584b0fbf8788#egg=rdflib
 #STATIC_DEPS=true LIBXML2_VERSION=2.9.2 LIBXSLT_VERSION=1.1.28 LIBICONV_VERSION=1.14 pip install --no-index -r requirements.txt
 -f ../../res/src
 Django==1.6.10
@@ -5,27 +6,32 @@
 PyYAML==3.11
 SPARQLWrapper==1.6.4
 South==1.0.1
+Unidecode==0.04.17
 Whoosh==2.5.7
-easy-thumbnails==2.2
+amqp==1.4.6
+anyjson==0.3.3
+billiard==3.3.0.19
+celery==3.1.17
 django-extensions==1.4.4
 django-haystack==2.2.0
-django-registration==1.1
+django-registration-redux==1.1
+easy-thumbnails==2.2
+elasticsearch==1.2.0
+html5lib==0.999
 httplib2==0.9
-html5lib==0.999
 isodate==0.5.1
+kombu==3.0.24
 lxml==3.4.0
 psycopg2==2.5.4
 pycrypto==2.6.1
-elasticsearch==1.2.0
 pyparsing==2.0.3
+pytz==2014.10
+rdflib==4.2.0-dev
 requests==2.4.3
 simplejson==3.6.5
 six==1.8.0
-rdflib==4.2-dev
-#-e git+git://github.com/IRI-Research/rdflib.git@96c30f98bbb628e13aaa32c9c392584b0fbf8788#egg=rdflib
+sqlalchemy==0.9.8
 urllib3==1.9.1
 wikitools==1.2
 wsgiref==0.1.2
-Unidecode==0.04.17
-pytz==2014.10