Author: jmorliaguet
Date: Sat Apr  1 16:33:05 2006
New Revision: 2753

Added:
   cpsskins/branches/jmo-perspectives/browser/negotiation/plugins/engine.zcml   
(contents, props changed)
   cpsskins/branches/jmo-perspectives/browser/negotiation/plugins/page.zcml   
(contents, props changed)
   
cpsskins/branches/jmo-perspectives/browser/negotiation/plugins/perspective.zcml 
  (contents, props changed)
   cpsskins/branches/jmo-perspectives/browser/negotiation/plugins/theme.zcml   
(contents, props changed)
   cpsskins/branches/jmo-perspectives/configuration/negotiation/
   cpsskins/branches/jmo-perspectives/configuration/negotiation/__init__.py   
(contents, props changed)
   cpsskins/branches/jmo-perspectives/configuration/negotiation/meta.zcml   
(contents, props changed)
   
cpsskins/branches/jmo-perspectives/configuration/negotiation/metaconfigure.py   
(contents, props changed)
   
cpsskins/branches/jmo-perspectives/configuration/negotiation/metadirectives.py  
 (contents, props changed)
Modified:
   cpsskins/branches/jmo-perspectives/browser/negotiation/plugins/configure.zcml
   cpsskins/branches/jmo-perspectives/browser/negotiation/plugins/engine.py
   cpsskins/branches/jmo-perspectives/browser/negotiation/plugins/page.py
   cpsskins/branches/jmo-perspectives/browser/negotiation/plugins/perspective.py
   cpsskins/branches/jmo-perspectives/browser/negotiation/plugins/theme.py
   cpsskins/branches/jmo-perspectives/browser/negotiation/views.py
   cpsskins/branches/jmo-perspectives/configuration/meta.zcml
   cpsskins/branches/jmo-perspectives/thememanager.py
Log:

- negotation chains and negotiators are registered in zcml



Modified: 
cpsskins/branches/jmo-perspectives/browser/negotiation/plugins/configure.zcml
==============================================================================
--- 
cpsskins/branches/jmo-perspectives/browser/negotiation/plugins/configure.zcml   
    (original)
+++ 
cpsskins/branches/jmo-perspectives/browser/negotiation/plugins/configure.zcml   
    Sat Apr  1 16:33:05 2006
@@ -1,123 +1,23 @@
 <configure
     xmlns="http://namespaces.zope.org/zope";>
 
-  <!-- theme negotiators -->
+  <!-- theme negotiation chain -->
 
-  <adapter
-      factory=".theme.QueryParameter"
-      provides=".interfaces.IQueryParameterNegotiator"
-      for="cpsskins.elements.interfaces.IElement
-           cpsskins.interfaces.IThemeManagementFolder
-           zope.publisher.interfaces.IRequest"
-      name="theme"
-  />
-
-  <adapter
-      factory=".theme.Cookie"
-      provides=".interfaces.ICookieNegotiator"
-      for="cpsskins.elements.interfaces.IElement
-           cpsskins.interfaces.IThemeManagementFolder
-           zope.publisher.interfaces.IRequest"
-      name="theme"
-  />
-
-  <adapter
-      factory=".theme.Local"
-      provides=".interfaces.ILocalNegotiator"
-      for="cpsskins.elements.interfaces.IElement
-           cpsskins.interfaces.IThemeManagementFolder
-           zope.publisher.interfaces.IRequest"
-      name="theme"
-  />
-
-  <adapter
-      factory=".theme.Default"
-      provides=".interfaces.IDefaultNegotiator"
-      for="cpsskins.elements.interfaces.IElement
-           cpsskins.interfaces.IThemeManagementFolder
-           zope.publisher.interfaces.IRequest"
-      name="theme"
-  />
-
-  <adapter
-      factory=".theme.Context"
-      provides=".interfaces.IContextNegotiator"
-      for="cpsskins.elements.interfaces.IElement
-           cpsskins.interfaces.IThemeManagementFolder
-           zope.publisher.interfaces.IRequest"
-      name="theme"
-  />
-
-
-  <!-- page negotiators -->
-
-  <adapter
-      factory=".page.QueryParameter"
-      provides=".interfaces.IQueryParameterNegotiator"
-      for="cpsskins.elements.interfaces.IElement
-           cpsskins.interfaces.IThemeManagementFolder
-           zope.publisher.interfaces.IRequest"
-      name="page"
-  />
-
-  <adapter
-      factory=".page.Cookie"
-      provides=".interfaces.ICookieNegotiator"
-      for="cpsskins.elements.interfaces.IElement
-           cpsskins.interfaces.IThemeManagementFolder
-           zope.publisher.interfaces.IRequest"
-      name="page"
-  />
-
-  <adapter
-      factory=".page.Local"
-      provides=".interfaces.ILocalNegotiator"
-      for="cpsskins.elements.interfaces.IElement
-           cpsskins.interfaces.IThemeManagementFolder
-           zope.publisher.interfaces.IRequest"
-      name="page"
-  />
-
-  <adapter
-      factory=".page.Default"
-      provides=".interfaces.IDefaultNegotiator"
-      for="cpsskins.elements.interfaces.IElement
-           cpsskins.interfaces.IThemeManagementFolder
-           zope.publisher.interfaces.IRequest"
-      name="page"
-  />
-
-  <adapter
-      factory=".page.Context"
-      provides=".interfaces.IContextNegotiator"
-      for="cpsskins.elements.interfaces.IElement
-           cpsskins.interfaces.IThemeManagementFolder
-           zope.publisher.interfaces.IRequest"
-      name="page"
-  />
-
-
-  <!-- perspective negotiators -->
-
-  <adapter
-      factory=".perspective.Session"
-      provides=".interfaces.ISessionNegotiator"
-      for="cpsskins.elements.interfaces.IElement
-           cpsskins.interfaces.IThemeManagementFolder
-           zope.publisher.interfaces.IRequest"
-      name="perspective"
-  />
-
-
-  <!-- engine negotiators -->
-
-  <adapter
-      factory=".engine.Request"
-      provides=".interfaces.IRequestNegotiator"
-      for="cpsskins.elements.interfaces.IElement
-           cpsskins.interfaces.IThemeManagementFolder
-           zope.publisher.interfaces.IRequest"
-      name="engine"
-  />
+  <include file="theme.zcml" />
+
+
+  <!-- page negotiation chain -->
+
+  <include file="page.zcml" />
+
+
+  <!-- perspective negotiation chain  -->
+
+  <include file="perspective.zcml" />
+
+
+  <!-- engine negotiation chain -->
+
+  <include file="engine.zcml" />
 
 </configure>

Modified: 
cpsskins/branches/jmo-perspectives/browser/negotiation/plugins/engine.py
==============================================================================
--- cpsskins/branches/jmo-perspectives/browser/negotiation/plugins/engine.py    
(original)
+++ cpsskins/branches/jmo-perspectives/browser/negotiation/plugins/engine.py    
Sat Apr  1 16:33:05 2006
@@ -17,10 +17,8 @@
 """
 __docformat__ = "reStructuredText"
 
-from zope.component import provideUtility
 from zope.interface import implements
 
-from cpsskins.browser.negotiation.interfaces import INegotiationChain
 from cpsskins.browser.negotiation.negotiator import Negotiator
 from cpsskins.browser.negotiation.plugins.interfaces import IRequestNegotiator
 
@@ -32,12 +30,3 @@
     def __call__(self):
         return self.request.annotations.get('cpsskins.engine', 'default')
 
-class EngineNegotiationChain:
-
-    implements(INegotiationChain)
-
-    def __call__(self):
-
-        return (IRequestNegotiator, )
-
-provideUtility(EngineNegotiationChain(), INegotiationChain, 'engine')

Added: 
cpsskins/branches/jmo-perspectives/browser/negotiation/plugins/engine.zcml
==============================================================================
--- (empty file)
+++ cpsskins/branches/jmo-perspectives/browser/negotiation/plugins/engine.zcml  
Sat Apr  1 16:33:05 2006
@@ -0,0 +1,13 @@
+<configure
+    xmlns="http://namespaces.zope.org/cpsskins";>
+
+  <negotiationchain name="engine">
+
+    <negotiator
+        factory=".engine.Request"
+        interface=".interfaces.IRequestNegotiator"
+    />
+
+  </negotiationchain>
+
+</configure>

Modified: cpsskins/branches/jmo-perspectives/browser/negotiation/plugins/page.py
==============================================================================
--- cpsskins/branches/jmo-perspectives/browser/negotiation/plugins/page.py      
(original)
+++ cpsskins/branches/jmo-perspectives/browser/negotiation/plugins/page.py      
Sat Apr  1 16:33:05 2006
@@ -17,11 +17,9 @@
 """
 __docformat__ = "reStructuredText"
 
-from zope.component import queryUtility, provideUtility
 from zope.interface import implements
+from zope.component import queryUtility
 
-from cpsskins.browser.negotiation.interfaces import INegotiator
-from cpsskins.browser.negotiation.interfaces import INegotiationChain
 from cpsskins.browser.negotiation.negotiator import Negotiator
 from cpsskins.browser.negotiation.plugins.interfaces import (
     IQueryParameterNegotiator, ICookieNegotiator, ILocalNegotiator,
@@ -58,7 +56,7 @@
     implements(ILocalNegotiator)
 
     def __call__(self):
-        return queryUtility(IPage, context=self.context)
+        return queryUtility(IThemePage, context=self.context)
 
 class Default(Negotiator):
     """Look for a default page
@@ -74,19 +72,7 @@
     implements(IContextNegotiator)
 
     def __call__(self):
-        if IThemePage.implementedBy(self.context):
+        if IThemePage.providedBy(self.context):
             return self.context
         return None
 
-
-class PageNegotiationChain:
-
-    implements(INegotiationChain)
-
-    def __call__(self):
-
-        return (IQueryParameterNegotiator, ICookieNegotiator,
-                IContextNegotiator, ILocalNegotiator, IDefaultNegotiator,
-               )
-
-provideUtility(PageNegotiationChain(), INegotiationChain, 'page')

Added: cpsskins/branches/jmo-perspectives/browser/negotiation/plugins/page.zcml
==============================================================================
--- (empty file)
+++ cpsskins/branches/jmo-perspectives/browser/negotiation/plugins/page.zcml    
Sat Apr  1 16:33:05 2006
@@ -0,0 +1,33 @@
+<configure
+    xmlns="http://namespaces.zope.org/cpsskins";>
+
+  <negotiationchain name="page">
+
+    <negotiator
+        factory=".page.QueryParameter"
+        interface=".interfaces.IQueryParameterNegotiator"
+    />
+
+    <negotiator
+        factory=".page.Cookie"
+        interface=".interfaces.ICookieNegotiator"
+    />
+
+    <negotiator
+        factory=".page.Local"
+        interface=".interfaces.ILocalNegotiator"
+    />
+
+    <negotiator
+        factory=".page.Default"
+        interface=".interfaces.IDefaultNegotiator"
+    />
+
+    <negotiator
+        factory=".page.Context"
+        interface=".interfaces.IContextNegotiator"
+    />
+
+  </negotiationchain>
+
+</configure>

Modified: 
cpsskins/branches/jmo-perspectives/browser/negotiation/plugins/perspective.py
==============================================================================
--- 
cpsskins/branches/jmo-perspectives/browser/negotiation/plugins/perspective.py   
    (original)
+++ 
cpsskins/branches/jmo-perspectives/browser/negotiation/plugins/perspective.py   
    Sat Apr  1 16:33:05 2006
@@ -18,10 +18,8 @@
 __docformat__ = "reStructuredText"
 
 from zope.app.session.interfaces import ISession
-from zope.component import provideUtility
 from zope.interface import implements
 
-from cpsskins.browser.negotiation.interfaces import INegotiationChain
 from cpsskins.browser.negotiation.negotiator import Negotiator
 from cpsskins.browser.negotiation.plugins.interfaces import ISessionNegotiator
 
@@ -39,12 +37,3 @@
             perspective = None
         return perspective
 
-class PerspectiveNegotiationChain:
-
-    implements(INegotiationChain)
-
-    def __call__(self):
-
-        return (ISessionNegotiator, )
-
-provideUtility(PerspectiveNegotiationChain(), INegotiationChain, 'perspective')

Added: 
cpsskins/branches/jmo-perspectives/browser/negotiation/plugins/perspective.zcml
==============================================================================
--- (empty file)
+++ 
cpsskins/branches/jmo-perspectives/browser/negotiation/plugins/perspective.zcml 
    Sat Apr  1 16:33:05 2006
@@ -0,0 +1,13 @@
+<configure
+    xmlns="http://namespaces.zope.org/cpsskins";>
+
+  <negotiationchain name="perspective">
+
+    <negotiator
+        factory=".perspective.Session"
+        interface=".interfaces.ISessionNegotiator"
+    />
+
+  </negotiationchain>
+
+</configure>

Modified: 
cpsskins/branches/jmo-perspectives/browser/negotiation/plugins/theme.py
==============================================================================
--- cpsskins/branches/jmo-perspectives/browser/negotiation/plugins/theme.py     
(original)
+++ cpsskins/branches/jmo-perspectives/browser/negotiation/plugins/theme.py     
Sat Apr  1 16:33:05 2006
@@ -17,11 +17,9 @@
 """
 __docformat__ = "reStructuredText"
 
-from zope.component import queryUtility, provideUtility
+from zope.component import queryUtility
 from zope.interface import implements
 
-from cpsskins.browser.negotiation.interfaces import INegotiator
-from cpsskins.browser.negotiation.interfaces import INegotiationChain
 from cpsskins.browser.negotiation.negotiator import Negotiator
 from cpsskins.browser.negotiation.plugins.interfaces import (
     IQueryParameterNegotiator, ICookieNegotiator, ILocalNegotiator,
@@ -47,7 +45,7 @@
     implements(ICookieNegotiator)
 
     def __call__(self):
-        name = self.request.cookies.get('cpsskins_work_theme')
+        name = self.request.cookies.get('cpsskins_theme')
         if not name:
             return None
         return self.manager.getThemeByName(name)
@@ -74,18 +72,7 @@
     implements(IContextNegotiator)
 
     def __call__(self):
-        if ITheme.implementedBy(self.context):
+        if ITheme.providedBy(self.context):
             return self.context
         return None
 
-class ThemeNegotiationChain:
-
-    implements(INegotiationChain)
-
-    def __call__(self):
-
-        return (IQueryParameterNegotiator, ICookieNegotiator,
-                IContextNegotiator, ILocalNegotiator, IDefaultNegotiator,
-               )
-
-provideUtility(ThemeNegotiationChain(), INegotiationChain, 'theme')

Added: cpsskins/branches/jmo-perspectives/browser/negotiation/plugins/theme.zcml
==============================================================================
--- (empty file)
+++ cpsskins/branches/jmo-perspectives/browser/negotiation/plugins/theme.zcml   
Sat Apr  1 16:33:05 2006
@@ -0,0 +1,33 @@
+<configure
+    xmlns="http://namespaces.zope.org/cpsskins";>
+
+  <negotiationchain name="theme">
+
+    <negotiator
+        factory=".theme.QueryParameter"
+        interface=".interfaces.IQueryParameterNegotiator"
+    />
+
+    <negotiator
+        factory=".theme.Cookie"
+        interface=".interfaces.ICookieNegotiator"
+    />
+
+    <negotiator
+        factory=".theme.Local"
+        interface=".interfaces.ILocalNegotiator"
+    />
+
+    <negotiator
+        factory=".theme.Default"
+        interface=".interfaces.IDefaultNegotiator"
+    />
+
+    <negotiator
+        factory=".theme.Context"
+        interface=".interfaces.IContextNegotiator"
+    />
+
+  </negotiationchain>
+
+</configure>

Modified: cpsskins/branches/jmo-perspectives/browser/negotiation/views.py
==============================================================================
--- cpsskins/branches/jmo-perspectives/browser/negotiation/views.py     
(original)
+++ cpsskins/branches/jmo-perspectives/browser/negotiation/views.py     Sat Apr 
 1 16:33:05 2006
@@ -33,7 +33,7 @@
     implements(INegotiation)
 
     def negotiate(self, type):
-        chain = zapi.getUtility(interface=INegotiationChain, name=type)()
+        chain = self.getChain(type)
         negotiation_context = (self.context, getThemeManager(), self.request)
         for negotiator in chain:
             result = getMultiAdapter(negotiation_context,
@@ -42,6 +42,9 @@
                 return result
         return None
 
+    def getChain(self, type):
+        return zapi.getUtility(interface=INegotiationChain, name=type)()
+
     ###################################################################
     # Themes and pages
     ###################################################################
@@ -56,7 +59,7 @@
         """Set the work theme.
         """
         response = self.request.response
-        response.setCookie('cpsskins_work_theme', name)
+        response.setCookie('cpsskins_theme', name)
         response.redirect('.')
 
     def getPage(self):
@@ -86,3 +89,17 @@
     def getPageViewer(self):
         page = self.getPage()
         return zapi.getMultiAdapter((page, self.request), IViewer)
+
+class NegotiationChain:
+
+    implements(INegotiationChain)
+
+    def __init__(self):
+        self.chain = ()
+
+    def add(self, negotiator):
+        self.chain += negotiator,
+
+    def __call__(self):
+        return self.chain
+

Modified: cpsskins/branches/jmo-perspectives/configuration/meta.zcml
==============================================================================
--- cpsskins/branches/jmo-perspectives/configuration/meta.zcml  (original)
+++ cpsskins/branches/jmo-perspectives/configuration/meta.zcml  Sat Apr  1 
16:33:05 2006
@@ -10,6 +10,8 @@
 
   <include package=".presentations" file="meta.zcml" />
 
+  <include package=".negotiation" file="meta.zcml" />
+
   <include package=".displays" file="meta.zcml" />
 
   <include package=".formats" file="meta.zcml" />

Added: cpsskins/branches/jmo-perspectives/configuration/negotiation/__init__.py
==============================================================================
--- (empty file)
+++ cpsskins/branches/jmo-perspectives/configuration/negotiation/__init__.py    
Sat Apr  1 16:33:05 2006
@@ -0,0 +1,19 @@
+##############################################################################
+#
+# Copyright (c) 2005-2006 Nuxeo and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+

Added: cpsskins/branches/jmo-perspectives/configuration/negotiation/meta.zcml
==============================================================================
--- (empty file)
+++ cpsskins/branches/jmo-perspectives/configuration/negotiation/meta.zcml      
Sat Apr  1 16:33:05 2006
@@ -0,0 +1,21 @@
+
+<configure xmlns="http://namespaces.zope.org/meta";>
+
+  <directives namespace="http://namespaces.zope.org/cpsskins";>
+
+    <complexDirective
+        name="negotiationchain"
+        schema=".metadirectives.INegotiationChainDirective"
+        handler=".metaconfigure.negotiationchain"
+        >
+
+      <subdirective
+          name="negotiator"
+          schema=".metadirectives.INegotiatorDirective"
+      />
+
+    </complexDirective>
+
+  </directives>
+
+</configure>

Added: 
cpsskins/branches/jmo-perspectives/configuration/negotiation/metaconfigure.py
==============================================================================
--- (empty file)
+++ 
cpsskins/branches/jmo-perspectives/configuration/negotiation/metaconfigure.py   
    Sat Apr  1 16:33:05 2006
@@ -0,0 +1,66 @@
+##############################################################################
+#
+# Copyright (c) 2005-2006 Nuxeo and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+
+from zope.app.component.metaconfigure import adapter
+from zope.configuration.exceptions import ConfigurationError
+from zope.publisher.interfaces.browser import IBrowserRequest
+from zope.component import provideUtility
+
+from cpsskins.browser.negotiation.interfaces import INegotiator
+from cpsskins.interfaces import IThemeManagementFolder
+from cpsskins.browser.negotiation.interfaces import INegotiationChain
+from cpsskins.browser.negotiation.views import NegotiationChain
+
+chains = {}
+
+class negotiationchain(object):
+
+    def __init__(self, _context, name=u''):
+        self.name = name
+        chain = chains[name] = NegotiationChain()
+        provideUtility(chain, INegotiationChain, name)
+
+    def negotiator(self, _context, factory=None, interface=None):
+        if not interface:
+            raise ConfigurationError("Must specify a negotiator interface.")
+        return negotiator(_context, name=self.name, factory=factory,
+                          interface=interface)
+
+def negotiator(_context, name=u'', factory=None, interface=None):
+
+    if not factory:
+        raise ConfigurationError("Must specify a negotiator factory.")
+
+    if not interface.extends(INegotiator):
+        raise ConfigurationError(
+            "A negotiator interface must extend INegotiator.")
+
+    if not INegotiator.implementedBy(factory):
+        raise ConfigurationError("A negotiator must implement INegotiator.")
+
+    # register the negotiator
+    adapts = (None, IThemeManagementFolder, IBrowserRequest)
+
+    # zope:adapter
+    adapter(_context=_context, factory=(factory,), provides=interface,
+            for_=adapts, name=name)
+
+    # add the negotiator to the chain
+    chains[name].add(interface)
+

Added: 
cpsskins/branches/jmo-perspectives/configuration/negotiation/metadirectives.py
==============================================================================
--- (empty file)
+++ 
cpsskins/branches/jmo-perspectives/configuration/negotiation/metadirectives.py  
    Sat Apr  1 16:33:05 2006
@@ -0,0 +1,47 @@
+##############################################################################
+#
+# Copyright (c) 2005-2006 Nuxeo and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+
+from zope.configuration.fields import GlobalObject
+from zope.interface import Interface
+from zope.i18nmessageid import MessageFactory
+from zope.schema import TextLine
+
+_ = MessageFactory("cpsskins")
+
+class INegotiationChainDirective(Interface):
+
+    name = TextLine(
+        title=_(u"The chain's name"),
+        description=_(u"The name of the negotiation chain."),
+        required=False,
+        )
+
+class INegotiatorDirective(Interface):
+
+    factory = GlobalObject(
+        title=_(u"The negotiator's factory"),
+        description=_(u"The factory used to create the negotiator."),
+        required=False,
+        )
+
+    interface = GlobalObject(
+        title=_(u"The negotiator's interface"),
+        description=_(u"The interface implemented by the negotiator."),
+        required=False,
+        )

Modified: cpsskins/branches/jmo-perspectives/thememanager.py
==============================================================================
--- cpsskins/branches/jmo-perspectives/thememanager.py  (original)
+++ cpsskins/branches/jmo-perspectives/thememanager.py  Sat Apr  1 16:33:05 2006
@@ -164,6 +164,14 @@
                 return v
         return None
 
+    def getPageByName(self, name=u''):
+        """Return a page by its name.
+        """
+        for k, v in getUtilitiesFor(IThemePage, self):
+            if k == name:
+                return v
+        return None
+
     def isDefault(self, object=None):
         """Return True if the element is used by default
         """
-- 
http://lists.nuxeo.com/mailman/listinfo/z3lab-checkins

Reply via email to