Index: quintagroup.canonicalurl/tags/0.3/README.txt
===================================================================
--- quintagroup.canonicalurl/tags/0.3/README.txt	(revision 498)
+++ quintagroup.canonicalurl/tags/0.3/README.txt	(revision 498)
@@ -0,0 +1,2 @@
+Introduction
+============
Index: quintagroup.canonicalurl/tags/0.3/docs/HISTORY.txt
===================================================================
--- quintagroup.canonicalurl/tags/0.3/docs/HISTORY.txt	(revision 498)
+++ quintagroup.canonicalurl/tags/0.3/docs/HISTORY.txt	(revision 498)
@@ -0,0 +1,8 @@
+Changelog
+=========
+
+0.1 - Unreleased
+----------------
+
+* Initial release
+
Index: quintagroup.canonicalurl/tags/0.3/quintagroup.canonicalurl-configure.zcml
===================================================================
--- quintagroup.canonicalurl/tags/0.3/quintagroup.canonicalurl-configure.zcml	(revision 498)
+++ quintagroup.canonicalurl/tags/0.3/quintagroup.canonicalurl-configure.zcml	(revision 498)
@@ -0,0 +1,1 @@
+<include package="canonicalurl" />
Index: quintagroup.canonicalurl/tags/0.3/quintagroup/__init__.py
===================================================================
--- quintagroup.canonicalurl/tags/0.3/quintagroup/__init__.py	(revision 498)
+++ quintagroup.canonicalurl/tags/0.3/quintagroup/__init__.py	(revision 498)
@@ -0,0 +1,1 @@
+#
Index: quintagroup.canonicalurl/tags/0.3/quintagroup/canonicalurl/README.txt
===================================================================
--- quintagroup.canonicalurl/tags/0.3/quintagroup/canonicalurl/README.txt	(revision 498)
+++ quintagroup.canonicalurl/tags/0.3/quintagroup/canonicalurl/README.txt	(revision 498)
@@ -0,0 +1,14 @@
+quintagroup.canonicalurl Package Readme
+=========================
+
+Overview
+--------
+
+Calculate URL with Canonical URL property
+
+
+Your tests here
+---------------
+
+    >>> 1 + 1
+    3
Index: quintagroup.canonicalurl/tags/0.3/quintagroup/canonicalurl/__init__.py
===================================================================
--- quintagroup.canonicalurl/tags/0.3/quintagroup/canonicalurl/__init__.py	(revision 498)
+++ quintagroup.canonicalurl/tags/0.3/quintagroup/canonicalurl/__init__.py	(revision 498)
@@ -0,0 +1,29 @@
+#
+from ZPublisher.HTTPRequest import HTTPRequest
+from ZPublisher.BaseRequest import quote
+
+def physicalPathToURL(self, path, relative=0):
+    """ Convert a physical path into a URL in the current context """
+    url = self['SERVER_URL']
+    proto = url.split('://')[0]
+
+    if not type(path) == type(''):
+        path = '/'.join(path)
+
+    path_domain_map = getattr(self, 'path_domain_map', ())
+    for subpath, domain in path_domain_map:
+        if len(path) >= len(subpath) \
+           and (path == subpath \
+                or path.startswith(subpath+'/')):
+            url = "%s://%s" % (proto, domain)
+            path = path[len(subpath):]
+            break
+
+    path = self._script + map(quote, self.physicalPathToVirtualPath(path))
+    if relative:
+        path.insert(0, '')
+    else:
+        path.insert(0, url)
+    return '/'.join(path)
+
+HTTPRequest.physicalPathToURL = physicalPathToURL
Index: quintagroup.canonicalurl/tags/0.3/quintagroup/canonicalurl/adapters.py
===================================================================
--- quintagroup.canonicalurl/tags/0.3/quintagroup/canonicalurl/adapters.py	(revision 498)
+++ quintagroup.canonicalurl/tags/0.3/quintagroup/canonicalurl/adapters.py	(revision 498)
@@ -0,0 +1,61 @@
+from string import strip
+from time import time
+
+from zope.interface import implements
+from zope.component import adapts
+from plone.memoize import ram
+
+from Products.CMFCore.utils import getToolByName
+from Products.CMFPlone.interfaces import IPloneSiteRoot
+
+from interfaces import IDomainsMapExtractor
+
+
+def cache_key(*args, **kwargs):
+     return time() // (60 * 60)
+
+
+class DomainsMapExtractor(object):
+    implements(IDomainsMapExtractor)
+    adapts(IPloneSiteRoot)
+
+    def __init__(self, context):
+        self.context = context
+
+    def processData(self, value):
+        try:
+            pd_maps = map(lambda x: map(strip, x.split('::')), value)
+        except:
+            pd_maps = ()
+        else:
+            pd_maps.sort(lambda x,y: len(y[0])-len(x[0]))
+        return pd_maps
+
+
+    @ram.cache(cache_key)
+    def getDomainsMap(self):
+        """ Return sorted by sybpath length tupple
+            of (subpath, domain name) tuple.
+        """
+        portal = getToolByName(self.context, 'portal_url').getPortalObject()
+        pd_maps = portal.getProperty('path_domains_map', ())
+        return self.processData(pd_maps)
+
+    def setDomainsMap(self, value):
+        """ Set tupple of (subpath, domain name) tuples
+        """
+        if value:
+            prepared_value = self.processData(value)
+            portal = getToolByName(self.context, 'portal_url').getPortalObject()
+
+            if not portal.getPropertyType('path_domains_map') == 'lines':
+                if not portal.hasPropertyType('path_domains_map'):
+                    portal.manage_addProperty('path_domains_map', [], 'lines')
+                else:
+                    raise Exception("Wrong types of 'path_domains_map' " \
+                                    "portal property - should be list type")
+
+            update_value = ['::'.join(l) for l in prepared_value]
+            portal._updateProperty('path_domains_map', prepared_value)
+
+
Index: quintagroup.canonicalurl/tags/0.3/quintagroup/canonicalurl/config.py
===================================================================
--- quintagroup.canonicalurl/tags/0.3/quintagroup/canonicalurl/config.py	(revision 498)
+++ quintagroup.canonicalurl/tags/0.3/quintagroup/canonicalurl/config.py	(revision 498)
@@ -0,0 +1,1 @@
+DOES_PATCH_TRAVERSABLE = 1#True
Index: quintagroup.canonicalurl/tags/0.3/quintagroup/canonicalurl/configure.zcml
===================================================================
--- quintagroup.canonicalurl/tags/0.3/quintagroup/canonicalurl/configure.zcml	(revision 498)
+++ quintagroup.canonicalurl/tags/0.3/quintagroup/canonicalurl/configure.zcml	(revision 498)
@@ -0,0 +1,14 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:five="http://namespaces.zope.org/five"
+    xmlns:genericsetup="http://namespaces.zope.org/genericsetup">
+
+    <adapter factory=".adapters.DomainsMapExtractor" />
+
+    <subscriber
+        for="Products.CMFPlone.interfaces.IPloneSiteRoot
+             zope.app.publication.interfaces.IBeforeTraverseEvent"
+        handler=".subscribers.add_domains_map"
+        />
+
+</configure>
Index: quintagroup.canonicalurl/tags/0.3/quintagroup/canonicalurl/interfaces.py
===================================================================
--- quintagroup.canonicalurl/tags/0.3/quintagroup/canonicalurl/interfaces.py	(revision 498)
+++ quintagroup.canonicalurl/tags/0.3/quintagroup/canonicalurl/interfaces.py	(revision 498)
@@ -0,0 +1,11 @@
+from zope.interface import Interface
+
+class IDomainsMapExtractor(Interface):
+
+    def getDomainsMap():
+        """ Return sorted by sybpath length tupple
+            of (subpath, domain name) tuple.
+        """
+    def setDomainsMap():
+        """ Set tupple of (subpath, domain name) tuples
+        """
Index: quintagroup.canonicalurl/tags/0.3/quintagroup/canonicalurl/subscribers.py
===================================================================
--- quintagroup.canonicalurl/tags/0.3/quintagroup/canonicalurl/subscribers.py	(revision 498)
+++ quintagroup.canonicalurl/tags/0.3/quintagroup/canonicalurl/subscribers.py	(revision 498)
@@ -0,0 +1,13 @@
+from interfaces import IDomainsMapExtractor
+
+def add_domains_map(context, event):
+    """Add to request PATH-DOMAIN map.
+    """
+    pd_map = None
+    extractor = IDomainsMapExtractor(context, None)
+    if extractor is not None:
+        pd_map = extractor.getDomainsMap()
+
+    if pd_map is not None:
+        event.request.set('path_domain_map', pd_map)
+
Index: quintagroup.canonicalurl/tags/0.3/quintagroup/canonicalurl/tests.py
===================================================================
--- quintagroup.canonicalurl/tags/0.3/quintagroup/canonicalurl/tests.py	(revision 498)
+++ quintagroup.canonicalurl/tags/0.3/quintagroup/canonicalurl/tests.py	(revision 498)
@@ -0,0 +1,30 @@
+import unittest
+
+from zope.testing import doctestunit
+from zope.component import testing
+from Testing import ZopeTestCase as ztc
+
+def test_suite():
+    return unittest.TestSuite([
+
+        # Unit tests for your API
+        doctestunit.DocFileSuite(
+            'README.txt', package='quintagroup.canonicalurl',
+            setUp=testing.setUp, tearDown=testing.tearDown),
+
+        #doctestunit.DocTestSuite(
+        #    module='quintagroup.canonicalurl.mymodule',
+        #    setUp=testing.setUp, tearDown=testing.tearDown),
+
+        # Integration tests that use ZopeTestCase
+        #ztc.ZopeDocFileSuite(
+        #    'README.txt', package='quintagroup.canonicalurl',
+        #    setUp=testing.setUp, tearDown=testing.tearDown),
+
+        #ztc.FunctionalDocFileSuite(
+        #    'browser.txt', package='quintagroup.canonicalurl'),
+
+        ])
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')
Index: quintagroup.canonicalurl/tags/0.3/setup.cfg
===================================================================
--- quintagroup.canonicalurl/tags/0.3/setup.cfg	(revision 498)
+++ quintagroup.canonicalurl/tags/0.3/setup.cfg	(revision 498)
@@ -0,0 +1,3 @@
+[egg_info]
+tag_build = dev
+tag_svn_revision = true
Index: quintagroup.canonicalurl/tags/0.3/setup.py
===================================================================
--- quintagroup.canonicalurl/tags/0.3/setup.py	(revision 498)
+++ quintagroup.canonicalurl/tags/0.3/setup.py	(revision 498)
@@ -0,0 +1,32 @@
+from setuptools import setup, find_packages
+import os
+
+version = '0.3'
+
+setup(name='quintagroup.canonicalurl',
+      version=version,
+      description="Calculate URL with Canonical URL property",
+      long_description=open("README.txt").read() + "\n" +
+                       open(os.path.join("docs", "HISTORY.txt")).read(),
+      # Get more strings from http://www.python.org/pypi?%3Aaction=list_classifiers
+      classifiers=[
+        "Programming Language :: Python",
+        "Topic :: Software Development :: Libraries :: Python Modules",
+        ],
+      keywords='',
+      author='quintagroup',
+      author_email='support@quintagroup.com',
+      url='',
+      license='GPL',
+      packages=find_packages(exclude=['ez_setup']),
+      namespace_packages=['quintagroup'],
+      include_package_data=True,
+      zip_safe=False,
+      install_requires=[
+          'setuptools',
+          # -*- Extra requirements: -*-
+      ],
+      entry_points="""
+      # -*- Entry points: -*-
+      """,
+      )
