Index: /qPloneGoogleSitemaps/tags/0.6+/Extensions/Install.py
===================================================================
--- /qPloneGoogleSitemaps/tags/0.6+/Extensions/Install.py	(revision 525)
+++ /qPloneGoogleSitemaps/tags/0.6+/Extensions/Install.py	(revision 525)
@@ -0,0 +1,97 @@
+import string
+from cStringIO import StringIO
+from Products.CMFCore.utils import getToolByName
+from Products.CMFCore.DirectoryView import addDirectoryViews
+from Products.qPloneGoogleSitemaps import qPGS_globals
+
+try:
+    from Products.CMFCore.permissions import ManagePortal
+except ImportError:
+    from Products.CMFCore.CMFCorePermissions import ManagePortal
+
+from OFS.ObjectManager import BadRequestException
+
+configlets = ({'id':'qPloneGoogleSitemaps',
+    'name':'Google Sitemaps',
+    'action':'string:${portal_url}/prefs_gsm_overview',
+    'condition':'',
+    'category':'Products',
+    'visible':1,
+    'appId':'qPloneGoogleSitemaps',
+    'permission':ManagePortal,
+    'imageUrl':'qplonegooglesitemaps.gif'},)
+
+def setupSkin(self, out, skinFolder):
+    skinstool=getToolByName(self, 'portal_skins')
+
+    addDirectoryViews(skinstool, 'skins', qPGS_globals)
+
+    for skin in skinstool.getSkinSelections():
+        path = skinstool.getSkinPath(skin)
+        path = map( string.strip, string.split( path,',' ) )
+
+        if not skinFolder in path:
+            try:
+                path.insert( path.index( 'custom')+1, skinFolder )
+            except ValueError:
+                path.append(skinFolder)
+            path = string.join( path, ', ' )
+            skinstool.addSkinSelection( skin, path )
+            out.write('  %s layer sucessfully installed into skin %s.\n' % (skinFolder, skin))
+        else:
+            out.write('  %s layer was already installed into skin %s.\n' % (skinFolder, skin))
+
+def install(self):
+    """ Install qPloneGoogleSitemaps """
+    out = StringIO()
+    if not hasattr(self.portal_properties, 'googlesitemap_properties'):
+        self.portal_properties.addPropertySheet('googlesitemap_properties', 'Google SiteMap properties')
+
+    props = self.portal_properties.googlesitemap_properties
+    portalTypes = ('Plone Folder', 'ATFolder')
+    new_portalTypes = ['Document', ]
+    sitemap_properties = (
+		('portalTypes', 'lines', new_portalTypes),
+		('states', 'lines', ['published', ]),
+    		('blackout_list', 'lines',[]),
+                ('reg_exp', 'lines',[]),
+		('urls', 'lines',[]),
+		('verification_filename','string','')
+	)
+        
+    types = self.portal_types.listContentTypes( by_metatype=1 )
+    for prop_id, prop_type, prop_value in sitemap_properties:
+        if not hasattr(props, prop_id):
+            props._setProperty(prop_id, prop_value, prop_type)
+
+    configTool = getToolByName(self, 'portal_controlpanel', None)
+    if configTool:
+        for conf in configlets:
+            configTool.registerConfiglet(**conf)
+            out.write('Added configlet %s\n' % conf['id'])
+
+    out.write('Call setupSkin... \n')
+    setupSkin(self, out, 'qPloneGoogleSitemaps')
+
+    return out.getvalue()
+
+def uninstall(self):
+    """ Uninstall qPloneGoogleSitemaps """
+    out = StringIO()
+
+    props = getToolByName(self,'portal_properties')
+    try:
+        props.manage_delObjects(['googlesitemap_properties',])
+    except BadRequestException: pass
+
+    configTool = getToolByName(self, 'portal_controlpanel', None)
+    if configTool:
+        for conf in configlets:
+            try:
+                configTool.unregisterConfiglet(conf['id'])
+            except BadRequestException,KeyError:
+                portal_icons = getToolByName(self,'portal_actionicons')
+                portal_icons.manage_removeActionIcon(conf['category'],conf['id'])
+            out.write('Removed configlet %s\n' % conf['id'])
+
+    return out.getvalue()
Index: /qPloneGoogleSitemaps/tags/0.6+/Extensions/__init__.py
===================================================================
--- /qPloneGoogleSitemaps/tags/0.6+/Extensions/__init__.py	(revision 525)
+++ /qPloneGoogleSitemaps/tags/0.6+/Extensions/__init__.py	(revision 525)
@@ -0,0 +1,1 @@
+# this file intentionally left blank
Index: /qPloneGoogleSitemaps/tags/0.6+/Extensions/ping_googlesitemap.py
===================================================================
--- /qPloneGoogleSitemaps/tags/0.6+/Extensions/ping_googlesitemap.py	(revision 525)
+++ /qPloneGoogleSitemaps/tags/0.6+/Extensions/ping_googlesitemap.py	(revision 525)
@@ -0,0 +1,7 @@
+from Products.qPloneGoogleSitemaps.utils import ping_google
+from Products.CMFCore.utils import getToolByName
+def  ping_googlesitemap(state_change):
+    """ping sitemap to Google when document has published"""
+    plone_home = getToolByName(state_change.object, 'portal_url').getPortalObject().absolute_url()
+    ping_google(plone_home)
+    return 0 
Index: /qPloneGoogleSitemaps/tags/0.6+/HISTORY.txt
===================================================================
--- /qPloneGoogleSitemaps/tags/0.6+/HISTORY.txt	(revision 525)
+++ /qPloneGoogleSitemaps/tags/0.6+/HISTORY.txt	(revision 525)
@@ -0,0 +1,47 @@
+0.6 Plone-3.0 compatibility
+
+  * Added plone-3 compatibility.
+
+0.5 Added tests
+
+  * Fix up bug in sed command s
+
+0.4.10 Configlet split into tabs
+
+  * Added workflow transitions configuration
+
+0.4.9 Introduced different sort options
+
+  * Added blackout list
+  
+  * Added opportunity to use sed command s
+
+0.4 Introduced sitemap ping to Google
+
+  * Added Google ping
+  
+  * Added configuration page
+  
+  * Added filter by content-types and states
+  
+0.3 Introduced product configlet 
+
+  * Added product configlet
+
+  * Added product usage docs on configlet
+
+0.2 Introduced XML format
+
+  * Moved to XML sitemaps format
+
+  * Added lastmod element to inform Google of object change date
+
+  * sitemap is comressed via HTTP gzip compression
+
+0.1 Initial version, proof of concept (i.e, Google working ;)
+
+  * plain text sitemaps format
+
+  * simple installer, no configuration
+
+  * no UI, just the working code ;)
Index: /qPloneGoogleSitemaps/tags/0.6+/README.txt
===================================================================
--- /qPloneGoogleSitemaps/tags/0.6+/README.txt	(revision 525)
+++ /qPloneGoogleSitemaps/tags/0.6+/README.txt	(revision 525)
@@ -0,0 +1,32 @@
+Quintagroup Plone Google Sitemaps
+
+  The product allows Plone websites to get better visibility for
+  Google search engine by providing it with complete listing of 
+  URLs to website content. See 
+  "Google Sitemaps":https://www.google.com/webmasters/sitemaps
+  website for more information.
+
+  "Product Homepage":http://quintagroup.com/services/plone-development/products/google-sitemaps |
+  "Download":http://sourceforge.net/projects/quintagroup
+  
+
+  (c) "Quintagroup":http://quintagroup.com/ , 2005. 
+
+  support@quintagroup.com * quintessence of modern business
+
+Usage
+
+  1. Install with Quick Installer. 
+  
+  2. Go to https://www.google.com/webmasters/sitemaps and
+     add http://your.site/google-sitemaps.
+
+  3. Should be working without any intervention.
+
+Authors
+
+  * Myroslav Opyr
+
+  * Nazar Ilchuk
+  
+  * Mykola Kharechko
Index: /qPloneGoogleSitemaps/tags/0.6+/TODO.txt
===================================================================
--- /qPloneGoogleSitemaps/tags/0.6+/TODO.txt	(revision 525)
+++ /qPloneGoogleSitemaps/tags/0.6+/TODO.txt	(revision 525)
@@ -0,0 +1,9 @@
+The items that are planned to implement within short timeframe
+
+* Provide changefreq and priority elements in url
+
+* pre-Compress the sitemaps
+
+* Make it possible to break sitemap into parts (with the use of siteindex)
+
+* implement several siteindex split policies: location, modification date, etc.
Index: /qPloneGoogleSitemaps/tags/0.6+/__init__.py
===================================================================
--- /qPloneGoogleSitemaps/tags/0.6+/__init__.py	(revision 525)
+++ /qPloneGoogleSitemaps/tags/0.6+/__init__.py	(revision 525)
@@ -0,0 +1,10 @@
+import Globals
+
+from Products.CMFCore.DirectoryView import registerDirectory
+from AccessControl import allow_module
+
+registerDirectory('skins', globals())
+qPGS_globals = globals()
+
+allow_module('Products.qPloneGoogleSitemaps.utils.py')
+allow_module('Products.qPloneGoogleSitemaps.config.py')
Index: /qPloneGoogleSitemaps/tags/0.6+/config.py
===================================================================
--- /qPloneGoogleSitemaps/tags/0.6+/config.py	(revision 525)
+++ /qPloneGoogleSitemaps/tags/0.6+/config.py	(revision 525)
@@ -0,0 +1,1 @@
+ping_googlesitemap = 'ping_googlesitemap'
Index: /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/google-sitemaps.pt
===================================================================
--- /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/google-sitemaps.pt	(revision 525)
+++ /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/google-sitemaps.pt	(revision 525)
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<urlset xmlns="http://www.google.com/schemas/sitemap/0.84"
+        xmlns:tal="http://xml.zope.org/namespaces/tal"
+        xmlns:metal="http://xml.zope.org/namespaces/metal"
+        tal:define="path python:'/'.join(here.getPhysicalPath());
+                    results python:container.searchForGoogleSitemapObjects(path);
+		    dummy python:request.RESPONSE.setHeader('Content-Type', 'text/xml');
+                    compress nocall:here/enableHTTPCompression | nothing;
+                    dummy python:compress and compress(request=request);
+		    additionalURLs python:modules['Products.qPloneGoogleSitemaps.utils'].additionalURLs"> 
+  <url tal:condition="results"
+       tal:repeat="result python:results.items()">
+    <loc tal:content="python:result[0]">http://www.yoursite.com/</loc>
+    <lastmod tal:content="python: DateTime(result[1].ModificationDate).HTML4()">2005-01-01</lastmod>
+  </url>
+  <url tal:define="URLs python:additionalURLs(context)"
+       tal:condition="URLs"
+       tal:repeat="URL URLs">
+    <loc tal:content="URL">http://www.yoursite.com/</loc>
+  </url>
+</urlset>
Index: /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/gsm_create_verify_file.cpy
===================================================================
--- /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/gsm_create_verify_file.cpy	(revision 525)
+++ /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/gsm_create_verify_file.cpy	(revision 525)
@@ -0,0 +1,23 @@
+## Script (Python) "create_verify_file"
+##bind container=container
+##bind context=context
+##bind namespace=
+##bind script=script
+##bind subpath=traverse_subpath
+##parameters=verify_filename
+##title=Create file for verification
+##
+
+from Products.CMFCore.utils import getToolByName
+from Products.qPloneGoogleSitemaps.utils import BadRequestException
+portal = getToolByName(context, 'portal_url').getPortalObject()
+try:
+    portal.manage_addFile(verify_filename,title='Verification File')
+    portal[verify_filename].manage_addProperty('CreatedBy','qPloneGoogleSitemaps','string')
+except BadRequestException:
+    pass
+props = getToolByName(context,'portal_properties').googlesitemap_properties
+props.manage_changeProperties(verification_filename = verify_filename)
+
+
+return state.set(portal_status_message = 'Plone Google Sitemap updated.')
Index: /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/gsm_create_verify_file.cpy.metadata
===================================================================
--- /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/gsm_create_verify_file.cpy.metadata	(revision 525)
+++ /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/gsm_create_verify_file.cpy.metadata	(revision 525)
@@ -0,0 +1,14 @@
+#
+# $$
+#
+[default]
+title=Create verify file
+
+[security]
+View=0:Authenticated
+
+[validators]
+
+[actions]
+action.success=traverse_to:string:prefs_gsm_verification
+action.failure=traverse_to:string:prefs_gsm_verification
Index: /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/gsm_delete_verify_file.cpy
===================================================================
--- /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/gsm_delete_verify_file.cpy	(revision 525)
+++ /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/gsm_delete_verify_file.cpy	(revision 525)
@@ -0,0 +1,23 @@
+## Script (Python) "create_verify_file"
+##bind container=container
+##bind context=context
+##bind namespace=
+##bind script=script
+##bind subpath=traverse_subpath
+##parameters=
+##title=Create file for verification
+##
+
+from Products.CMFCore.utils import getToolByName
+props = getToolByName(context,'portal_properties').googlesitemap_properties
+
+portal = getToolByName(context,'portal_url').getPortalObject()
+try:
+    if portal[props.verification_filename].CreatedBy == 'qPloneGoogleSitemaps':
+        portal.manage_delObjects(props.verification_filename)
+except:
+    pass
+
+props.manage_changeProperties(verification_filename = '')
+
+return state.set(portal_status_message = 'Plone Google Sitemap updated.')
Index: /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/gsm_delete_verify_file.cpy.metadata
===================================================================
--- /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/gsm_delete_verify_file.cpy.metadata	(revision 525)
+++ /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/gsm_delete_verify_file.cpy.metadata	(revision 525)
@@ -0,0 +1,14 @@
+#
+# $$
+#
+[default]
+title=Delete verify file
+
+[security]
+View=0:Authenticated
+
+[validators]
+
+[actions]
+action.success=traverse_to:string:prefs_gsm_verification
+action.failure=traverse_to:string:prefs_gsm_verification
Index: /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/gsm_edit_pinging.cpy
===================================================================
--- /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/gsm_edit_pinging.cpy	(revision 525)
+++ /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/gsm_edit_pinging.cpy	(revision 525)
@@ -0,0 +1,20 @@
+## Script (Python) "gsm_edit_pinging"
+##bind container=container
+##bind context=context
+##bind namespace=
+##bind script=script
+##bind subpath=traverse_subpath
+##parameters=transitions=[]
+##title=Configure Plone Google Sitemap
+##
+
+from Products.qPloneGoogleSitemaps.utils import setWorkflowTransitions
+from Products.CMFCore.utils import getToolByName
+
+if not transitions:
+    w_tool = getToolByName(context, "portal_workflow")
+    transitions = [w + "#" for w in w_tool.listWorkflows()]
+
+setWorkflowTransitions(context, transitions)
+
+return state.set(portal_status_message = "Plone Google Sitemap updated.")
Index: /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/gsm_edit_pinging.cpy.metadata
===================================================================
--- /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/gsm_edit_pinging.cpy.metadata	(revision 525)
+++ /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/gsm_edit_pinging.cpy.metadata	(revision 525)
@@ -0,0 +1,14 @@
+#
+# $$
+#
+[default]
+title= Save Propertiest
+
+[security]
+View=0:Authenticated
+
+[validators]
+
+[actions]
+action.success=traverse_to:string:prefs_gsm_pinging
+action.failure=traverse_to:string:prefs_gsm_pinging
Index: /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/gsm_edit_settings.cpy
===================================================================
--- /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/gsm_edit_settings.cpy	(revision 525)
+++ /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/gsm_edit_settings.cpy	(revision 525)
@@ -0,0 +1,20 @@
+## Script (Python) "gsm_edit_settings"
+##bind container=container
+##bind context=context
+##bind namespace=
+##bind script=script
+##bind subpath=traverse_subpath
+##parameters=states, portalTypes, blackout_list, reg_exp, urls
+##title=Configure Plone Google Sitemap
+##
+
+from Products.CMFCore.utils import getToolByName
+from Products.qPloneGoogleSitemaps.utils import setWorkflowTransitions
+import Products.qPloneGoogleSitemaps.config as config
+
+props = getToolByName(context,'portal_properties').googlesitemap_properties
+props.manage_changeProperties( states=states, portalTypes=portalTypes,
+                               blackout_list=blackout_list, reg_exp = reg_exp,
+                               urls = urls)
+
+return state.set(portal_status_message = 'Plone Google Sitemap updated.')
Index: /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/gsm_edit_settings.cpy.metadata
===================================================================
--- /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/gsm_edit_settings.cpy.metadata	(revision 525)
+++ /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/gsm_edit_settings.cpy.metadata	(revision 525)
@@ -0,0 +1,14 @@
+#
+# $$
+#
+[default]
+title= Save Propertiest
+
+[security]
+View=0:Authenticated
+
+[validators]
+
+[actions]
+action.success=traverse_to:string:prefs_gsm_settings
+action.failure=traverse_to:string:prefs_gsm_settings
Index: /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/ping_googlesitemaps.cpy
===================================================================
--- /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/ping_googlesitemaps.cpy	(revision 525)
+++ /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/ping_googlesitemaps.cpy	(revision 525)
@@ -0,0 +1,23 @@
+## Script (Python) "ping_googlesitemaps.cpy"
+##bind container=container
+##bind context=context
+##bind namespace=
+##bind script=script
+##bind subpath=traverse_subpath
+##parameters=
+##title=Ping information to Google
+##
+
+from Products.CMFCore.utils import getToolByName
+from Products.qPloneGoogleSitemaps.utils import ping_google
+
+url = getToolByName(context, 'portal_url')()
+
+portal_msg = "Google pinged. It will review your sitemap as soon as it will be able to."
+
+try:
+    ping_google(url)
+except:
+    portal_msg = "Cannot contact Google. Try again in a while."
+    
+return state.set(portal_status_message = portal_msg)
Index: /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/ping_googlesitemaps.cpy.metadata
===================================================================
--- /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/ping_googlesitemaps.cpy.metadata	(revision 525)
+++ /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/ping_googlesitemaps.cpy.metadata	(revision 525)
@@ -0,0 +1,13 @@
+#
+# $$
+#
+[default]
+title=Google Sitemap Ping
+
+[security]
+View=0:Authenticated
+
+[validators]
+
+[actions]
+action.success=traverse_to:string:prefs_gsm_pinging
Index: /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/prefs_gsm_overview.cpt
===================================================================
--- /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/prefs_gsm_overview.cpt	(revision 525)
+++ /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/prefs_gsm_overview.cpt	(revision 525)
@@ -0,0 +1,104 @@
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US"
+      xmlns:metal="http://xml.zope.org/namespaces/metal"
+      xmlns:tal="http://xml.zope.org/namespaces/tal"
+      lang="en-US"
+      metal:use-macro="here/prefs_main_template/macros/master"
+      i18n:domain="qPloneGoogleSitemaps"> 
+
+<body>
+  <div metal:fill-slot="prefs_configlet_main"
+       tal:define="errors python:request.get('errors', {})">
+
+    <div class="documentEditable">
+        <ul class="contentViews">
+            <li class="selected">
+                <a href=""
+                   tal:attributes="href string:${template/id}"
+                   i18n:translate="label_properties">Overview</a>
+            </li>
+
+            <li class="">
+                <a href=""
+                   tal:attributes="href string: prefs_gsm_verification"
+                   i18n:translate="label_properties">Verification</a>
+            </li>
+
+            <li class="">
+               <a href=""
+                  tal:attributes="href string: prefs_gsm_settings">
+                  Settings</a>
+            </li>
+
+            <li class="">
+               <a href=""
+                  tal:attributes="href string: prefs_gsm_pinging"
+                  i18n:translate="label_logs">Pinging</a>
+            </li>
+
+        </ul>
+
+        <div class="contentActions">
+        &nbsp;
+        </div>
+        <div class="documentContent">
+            <h1 i18n:translate="heading_plonegooglesitemaps">Plone Google Sitemaps</h1>
+            <a href=""
+            class="link-parent"
+            tal:attributes="href string: $portal_url/plone_control_panel"
+            i18n:translate="label_up_to_plone_setup">
+            Up to Plone Setup
+            </a>
+
+            <div class="documentDescription"
+                i18n:translate="description_plonegooglesitemaps">
+            Plone Google Sitemaps allows search engine to have better visibility of your 
+            <tal:url replace="portal_url" i18n:name="url">example.com</tal:url> 
+            Plone website.
+            </div>
+ 
+            <h2>Post-install instructions</h2>
+
+            <p>Congratulations, you've installed Plone Google Sitemaps product from 
+            Quintagroup.</p>
+
+<!--              -->
+            <dl>
+            <dt>First step</dt>
+            <dd>Your site is Google Sitemaps enabled already. Check 
+            <a href="google-sitemaps"
+                tal:attributes="href string:$portal_url/google-sitemaps">sitemap XML</a> 
+            to see generated sitemap document of your website. It should contain URLs of 
+            all published objects. If you see something that should not be indexed by 
+            Google, retract objects or exclude sections with robots.txt (that GoogleBot 
+            obey).
+            </dd>
+            <dt>Second step</dt>
+            <dd>Make Google know of your sitemap:
+            <ol>
+                <li>go to <a href="https://www.google.com/webmasters/sitemaps">Google 
+                Sitemaps Central</a> (logging in / signing up as necessary)</li>
+                <li>add your sitemap URL: 
+                <code tal:content="string:$portal_url/google-sitemaps">http://example.com/google-sitemaps</code>
+            </ol>
+            It takes a while for your sitemap to be processed by Google. 
+            Usually within 24 hours it processes hte sitemap so do not expect your 
+            submission to be processed instantly.
+            </dd>
+            <dl>
+            <h2>Helpful resources</h2>
+            <dl>
+            <dt><a href="http://groups-beta.google.com/group/google-sitemaps">google-sitemaps discussion group</a><dt>
+            <dd>As Google Sitemaps is emerging technology, we are all learning from it.
+            Google set up discussion group to find your ideas about it. You can find 
+            help from other webmasters as they usually found answers to questions that 
+            you have. If not you are free to ask, to praise and to ramble ;)</dd>
+            <dt><a href="http://plone.org/products/qplonegooglesitemaps">Plone Google Sitemaps 
+            product page</a></dt>
+            <dd>Stay tuned. We are preparing new and fresh releases. Product page will 
+            help you to keep informed about them.</dd>
+            </dl>
+        </div>
+    </div>
+  </div>
+</body>
+</html>
Index: /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/prefs_gsm_pinging.cpt
===================================================================
--- /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/prefs_gsm_pinging.cpt	(revision 525)
+++ /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/prefs_gsm_pinging.cpt	(revision 525)
@@ -0,0 +1,115 @@
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US"
+      xmlns:metal="http://xml.zope.org/namespaces/metal"
+      xmlns:tal="http://xml.zope.org/namespaces/tal"
+      lang="en-US"
+      metal:use-macro="here/prefs_main_template/macros/master"
+      i18n:domain="qPloneGoogleSitemaps"> 
+<body>
+    <div metal:fill-slot="prefs_configlet_main"
+        tal:define="errors python:request.get('errors', {})">
+
+        <div class="documentEditable">
+            <ul class="contentViews">
+                <li class="">
+                    <a href=""
+                    tal:attributes="href string: prefs_gsm_overview"
+                    i18n:translate="label_properties">Overview</a>
+                </li>
+
+                <li class="">
+                    <a href=""
+                    tal:attributes="href string:prefs_gsm_verification"
+                    i18n:translate="label_properties">Verification</a>
+                </li>
+
+                <li class="">
+                <a href=""
+                    tal:attributes="href string: prefs_gsm_settings">
+                    Settings</a>
+                </li>
+
+                <li class="selected">
+                <a href=""
+                    tal:attributes="href string: ${template/id}"
+                    i18n:translate="label_logs">Pinging</a>
+                </li>
+
+            </ul>
+
+            <div class="contentActions">
+            &nbsp;
+            </div>
+            <div class="documentContent">
+                <h1 i18n:translate="heading_plonegooglesitemaps">Plone Google Sitemaps</h1>
+                <a href=""
+                class="link-parent"
+                tal:attributes="href string: $portal_url/plone_control_panel"
+                i18n:translate="label_up_to_plone_setup">
+                Up to Plone Setup
+                </a>
+                <form>
+                    <fieldset>
+                        <legend>Google Ping</legend>
+                        <p>By pressing "Ping Google" button you inform Google that it
+                        should reread your sitemap as you did some modification on 
+                        the site. Google usually rereads your sitemap with it's 
+                        own schedule but you have possibility to hint it about best
+                        time to do that.</p>
+                        <div class="formControls">
+                            <input class="context"
+                                tabindex=""
+                                type="submit"
+                                name="form.button.Ping"
+                                value="Ping Google"
+                                i18n:attributes="value"
+                                tal:attributes="tabindex tabindex/next;" />
+                        </div>
+                    </fieldset>
+                    <div class="field"
+                         tal:define="portal_workflow portal/portal_workflow;
+                                     getWorkflowTransitions python:modules['Products.qPloneGoogleSitemaps.utils'].getWorkflowTransitions">
+                            <label for= "portal_workflow">
+                                        Workflows to ping
+                            </label>
+                            <div class="formHelp">
+                                        Transitions after which Google have been pinged
+                            </div>
+                            <fieldset class="workflow"
+                                      tal:repeat="workflow portal_workflow/listWorkflows">
+                                <legend tal:content="workflow">Workflow title (and id)</legend>
+                                <div class="field"
+                                    tal:repeat="transition python:getWorkflowTransitions(context,workflow)">
+                                <tal:transition define="enabled python:transition.after_script_name in ['', 'ping_googlesitemap'];
+                                    name string:${workflow}#${transition/id}">
+                                    <input type="checkbox"
+                                           name="transitions:list"
+                                           tal:attributes=" id name;
+                                                            value name;
+                                                            checked python:enabled and transition.after_script_name;
+                                                            disabled not:enabled"/>
+                                    <label tal:content="string:${transition/getId}: ${transition/title_or_id}"
+                                           tal:attributes="for name; class python:test(enabled, None, 'discreet')">Transition id
+                                    </label>
+                                    <span  class="discreet"
+                                            tal:condition="not:enabled"
+                                            tal:content="string:(${transition/after_script_name})" />
+                                </tal:transition>
+                            </div>
+                        </fieldset>
+                        <div class="formControls">
+                            <input class="context"
+                                tabindex=""
+                                type="submit"
+                                name="form.button.Save"
+                                value="Save"
+                                i18n:attributes="value"
+                                tal:attributes="tabindex tabindex/next;" />
+                        </div>
+                    </div>
+                    <input type="hidden" name="form.submitted" value="1" />
+                </form>
+            </div>
+        </div>
+    </div>
+</body>
+</html>
Index: /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/prefs_gsm_pinging.cpt.metadata
===================================================================
--- /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/prefs_gsm_pinging.cpt.metadata	(revision 525)
+++ /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/prefs_gsm_pinging.cpt.metadata	(revision 525)
@@ -0,0 +1,15 @@
+#
+# $$
+#
+[default]
+title=Plone Google Sitemap Configuration
+
+[security]
+View=0:Authenticated
+
+[validators]
+
+[actions]
+action.success..Ping=traverse_to:string:ping_googlesitemaps
+action.success..Save=traverse_to:string:gsm_edit_pinging
+action.failure=traverse_to:string:prefs_gsm_pinging
Index: /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/prefs_gsm_settings.cpt
===================================================================
--- /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/prefs_gsm_settings.cpt	(revision 525)
+++ /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/prefs_gsm_settings.cpt	(revision 525)
@@ -0,0 +1,176 @@
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US"
+      xmlns:metal="http://xml.zope.org/namespaces/metal"
+      xmlns:tal="http://xml.zope.org/namespaces/tal"
+      lang="en-US"
+      metal:use-macro="here/prefs_main_template/macros/master"
+      i18n:domain="qPloneGoogleSitemaps">
+<body>
+    <div metal:fill-slot="prefs_configlet_main"
+        tal:define="errors python:request.get('errors', {})">
+
+        <div class="documentEditable">
+            <ul class="contentViews">
+                <li class="">
+                    <a href=""
+                       tal:attributes="href string: prefs_gsm_overview">
+                       Overview</a>
+                </li>
+                <li class="">
+                    <a href=""
+                       tal:attributes="href string:prefs_gsm_verification">
+                       Verification</a>
+                </li>
+                <li class="selected">
+                <a href=""
+                   tal:attributes="href string:${template/id}">
+                   Settings</a>
+                </li>
+                <li class="">
+                <a href=""
+                   tal:attributes="href string: prefs_gsm_pinging">
+                   Pinging</a>
+                </li>
+            </ul>
+            <div class="contentActions">
+            &nbsp;
+            </div>
+            <div class="documentContent">
+                <h1 i18n:translate="heading_plonegooglesitemaps">Plone Google Sitemaps</h1>
+                <a href=""
+                   class="link-parent"
+                   tal:attributes="href string: $portal_url/plone_control_panel"
+                   i18n:translate="label_up_to_plone_setup">
+                   Up to Plone Setup
+                </a>
+                <form name="edit_form"
+                    action="."
+                    method="post"
+                    enctype="multipart/form-data"
+                    tal:attributes="action string:${here_url}/${template/getId}" >
+
+                <fieldset tal:define="props portal/portal_properties/googlesitemap_properties;
+                                      portal_types portal/portal_types;">
+                    <legend i18n:translate="legend_plonesitemap_configuration_details">
+                        Google SiteMap configuration
+                    </legend>
+                    <div class="field" 
+                        tal:define="portalTypes props/portalTypes;">
+                        <label for="portalTypes ">
+                            Define the types
+                        </label>
+                        <div class="formHelp">
+                            Define the types to be included in sitemap.
+                        </div>
+
+                        <select multiple="multiple"
+                                name="portalTypes"
+                                id="portalTypes"
+                                tal:attributes="tabindex tabindex/next;">
+
+                        <tal:contenttypes repeat="type python:portal_types.listContentTypes()">
+                            <option tal:define="type python:portal_types.getTypeInfo(type);
+                                                type_name type/Title;
+                                                portal_type type/getId"
+                                    tal:attributes="value portal_type;
+                                                    selected python: test(portal_type in portalTypes, 'selected', None)"
+                                    tal:content="type_name">
+                                Article
+                            </option>
+                        </tal:contenttypes>
+                        </select>
+                    </div>
+
+                    <div class="field" 
+                        tal:define="states props/states;">
+                        <label for="states ">
+                            Review status
+                        </label>
+
+                        <div class="formHelp">
+                            You may include items in sitemap depend of their review state.
+                        </div>
+
+                        <textarea name="states:lines" 
+                                id="states"
+                                cols="20"
+                                rows="8"
+                                tabindex=""
+                                tal:attributes="tabindex tabindex/next;"
+                                tal:define="content python:modules['string'].join(states,'\n');"
+                                tal:content="content">
+                        </textarea>
+                    </div>
+                    <div class="field" 
+                        tal:define="blackout_list props/blackout_list;">
+                        <label for="blackout_list ">
+                            Blackout entries
+                        </label>
+                        <div class="formHelp">
+                            The objects with the given ids will not be included in sitemap.
+                        </div>
+                        <textarea name="blackout_list:lines" 
+                                id="reg_exp"
+                                cols="20"
+                                rows="8"
+                                tabindex=""
+                                tal:attributes="tabindex tabindex/next;"
+                                tal:define="content python:modules['string'].join(blackout_list ,'\n');"
+                                tal:content="content">
+                        </textarea>
+                    </div>
+                    <div class="field" 
+                        tal:define="reg_exp props/reg_exp;">
+                        <label for="reg_exp">
+                            URL processing Regular Expressions
+                        </label>
+                        <div class="formHelp">
+                            Provide regular expressions (in Perl syntax), one per line to be applied to URLs before including them into Sitemap. For instance, "s/\/index_html//" will remove /index_html from URLs representing default documents.
+                        </div>
+
+                        <textarea name="reg_exp:lines" 
+                                id="reg_exp"
+                                cols="20"
+                                rows="8"
+                                tabindex=""
+                                tal:attributes="tabindex tabindex/next;"
+                                tal:define="content python:modules['string'].join(reg_exp ,'\n');"
+                                tal:content="content">
+                        </textarea>
+                    </div>
+                    <div class="field" 
+                        tal:define="urls props/urls;">
+                        <label for="urls"> Additional URLs
+                        </label>
+                        <div class="formHelp">
+                            Define additional URLs that are not objects and that should be included in sitemap.
+                        </div>
+                        <textarea name="urls:lines" 
+                                id="urls"
+                                cols="20"
+                                rows="8"
+                                tabindex=""
+                                tal:attributes="tabindex tabindex/next;"
+                                tal:define="content python:modules['string'].join(urls ,'\n');"
+                                tal:content="content">
+                        </textarea>
+                    </div>
+
+                    <div class="formControls"
+                        tal:define="process_creation request/process_creation|nothing;"
+                        i18n:domain="plone">
+                        <input class="context"
+                            tabindex=""
+                            type="submit"
+                            name="form.button.Save"
+                            value="Save"
+                            i18n:attributes="value"
+                            tal:attributes="tabindex tabindex/next;" />
+                    </div>
+                    </fieldset>
+                    <input type="hidden" name="form.submitted" value="1" />
+                </form>
+            </div>
+        </div>
+    </div>
+</body>
+</html>
Index: /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/prefs_gsm_settings.cpt.metadata
===================================================================
--- /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/prefs_gsm_settings.cpt.metadata	(revision 525)
+++ /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/prefs_gsm_settings.cpt.metadata	(revision 525)
@@ -0,0 +1,15 @@
+#
+# $$
+#
+[default]
+title=Plone Google Sitemap Configuration
+
+[security]
+View=0:Authenticated
+
+[validators]
+
+[actions]
+action.success..Save=traverse_to:string:gsm_edit_settings
+action.success=traverse_to:string:gsm_edit_settings
+action.failure=traverse_to:string:prefs_gsm_settings
Index: /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/prefs_gsm_verification.cpt
===================================================================
--- /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/prefs_gsm_verification.cpt	(revision 525)
+++ /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/prefs_gsm_verification.cpt	(revision 525)
@@ -0,0 +1,90 @@
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US"
+      xmlns:metal="http://xml.zope.org/namespaces/metal"
+      xmlns:tal="http://xml.zope.org/namespaces/tal"
+      lang="en-US"
+      metal:use-macro="here/prefs_main_template/macros/master"
+      i18n:domain="qPloneGoogleSitemaps"> 
+<body>
+    <div metal:fill-slot="prefs_configlet_main"
+        tal:define="errors python:request.get('errors', {});
+                    props portal/portal_properties/googlesitemap_properties">
+
+        <div class="documentEditable">
+            <ul class="contentViews">
+                <li class="">
+                    <a href=""
+                    tal:attributes="href string: prefs_gsm_overview"
+                    i18n:translate="label_properties">Overview</a>
+                </li>
+
+                <li class="selected">
+                    <a href=""
+                    tal:attributes="href string:${template/id}"
+                    i18n:translate="label_properties">Verification</a>
+                </li>
+
+                <li class="">
+                <a href=""
+                    tal:attributes="href string:prefs_gsm_settings">
+                    Settings</a>
+                </li>
+
+                <li class="">
+                <a href=""
+                    tal:attributes="href string: prefs_gsm_pinging"
+                    i18n:translate="label_logs">Pinging</a>
+                </li>
+
+            </ul>
+
+            <div class="contentActions">
+            &nbsp;
+            </div>
+            <div class="documentContent">
+                <h1 i18n:translate="heading_plonegooglesitemaps">Plone Google Sitemaps</h1>
+                <a href=""
+                class="link-parent"
+                tal:attributes="href string: $portal_url/plone_control_panel"
+                i18n:translate="label_up_to_plone_setup">
+                Up to Plone Setup
+                </a>
+
+                <form tal:define="file_provided props/verification_filename;
+                                  step1 python:test(file_provided, 'discreet', '');
+                                  step2 python:test(not file_provided, 'discreet', '')">
+                    <ol>
+                        <li tal:attributes="class step1">
+                            Go to <a href=""
+                                        tal:attributes="href string: https://www.google.com/webmasters/sitemaps/verify?siteUrl=${portal/absolute_url}&hl=en"
+                                        tal:omit-tag="step1">
+                        site verification page</a> and login if necessary.
+                        </li>
+                        <li tal:attributes="class step1">Provide verification file name:
+                            <p><input name="verify_filename" id="verify_filename" type="text"
+                                tal:attributes="value props/verification_filename;
+                                                disabled step1"
+                            ></p>
+                        </li>
+                        <li tal:attributes="class step1">
+                                <input name="form.button.CreateFile" id="create_file" type="submit" value="Create verification file"
+                                tal:attributes="disabled step1"/>
+                                <input type="hidden" name="form.submitted" value="1" />
+                        </li>
+                        <li class="discreet"
+                            tal:attributes="class step2">Go to <a href=""
+                                        tal:attributes="href string: https://www.google.com/webmasters/sitemaps/verify?siteUrl=${portal/absolute_url}&hl=en"
+                                        tal:omit-tag="step2">
+                        site verification page</a> and press "Check Status" button.
+                        </li>
+                        <li class="discreet"
+                            tal:attributes="class step2"><input name="form.button.DeleteFile" id="remove_file" type="submit" value="Remove verification file"
+                            tal:attributes="disabled step2;
+                                            value string:Remove ${file_provided} verifivation file"/>
+                        </li>
+                    </ol>
+                </form>
+            </div>
+        </div>
+    </div>
+</body>
+</html>
Index: /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/prefs_gsm_verification.cpt.metadata
===================================================================
--- /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/prefs_gsm_verification.cpt.metadata	(revision 525)
+++ /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/prefs_gsm_verification.cpt.metadata	(revision 525)
@@ -0,0 +1,15 @@
+#
+# $$
+#
+[default]
+title=verification
+
+[security]
+View=0:Authenticated
+
+[validators]
+
+[actions]
+action.success..CreateFile=traverse_to:string:gsm_create_verify_file
+action.success..DeleteFile=traverse_to:string:gsm_delete_verify_file
+action.failure=traverse_to:string:prefs_gsm_verification
Index: /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/searchForGoogleSitemapObjects.py
===================================================================
--- /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/searchForGoogleSitemapObjects.py	(revision 525)
+++ /qPloneGoogleSitemaps/tags/0.6+/skins/qPloneGoogleSitemaps/searchForGoogleSitemapObjects.py	(revision 525)
@@ -0,0 +1,30 @@
+## Script (Python) "searchForGoogleSitemapObjects"
+##bind container=
+##bind context=context
+##bind namespace=
+##bind script=script
+##bind subpath=traverse_subpath
+##parameters=path=None
+##
+from Products.CMFCore.utils import getToolByName
+from Products.qPloneGoogleSitemaps.utils import applyOperations
+from string import find
+
+if not path:
+    path = '/'.join(context.getPhysicalPath())
+
+catalog = getToolByName(context, 'portal_catalog')
+try:
+    props = getToolByName(context, 'portal_properties').googlesitemap_properties
+    objects = catalog(path = path,
+                portal_type = props.portalTypes,
+                review_state = props.states,)
+except AttributeError:
+    # We are run without being properly installed, do default processing
+    return applyOperations(catalog(path = path,
+                                   review_state = ['published'],),
+                                   [])
+
+blackout_list = props.blackout_list
+return applyOperations([ob for ob in objects if (ob.getId not in blackout_list)],
+                    props.getProperty('reg_exp'))
Index: /qPloneGoogleSitemaps/tags/0.6+/tests/XMLParser.py
===================================================================
--- /qPloneGoogleSitemaps/tags/0.6+/tests/XMLParser.py	(revision 525)
+++ /qPloneGoogleSitemaps/tags/0.6+/tests/XMLParser.py	(revision 525)
@@ -0,0 +1,23 @@
+from xml.parsers.expat import ParserCreate
+import re
+
+def parse(data):
+    def start_el(name, attrs):
+        ParsedXML['start'][name] = attrs
+
+    def char_handler(data):
+        patt = re.compile('\S+', re.UNICODE)
+        if patt.search(data):
+            ParsedXML['data'].append(data)
+
+    ParsedXML = {'start':{}, 'end':[], 'data':[]}
+    parser = ParserCreate()
+    parser.StartElementHandler = start_el
+    parser.CharacterDataHandler = char_handler
+    parser.Parse(data)
+    return ParsedXML
+
+def hasURL(xml, url):
+    parsed_sitemap = parse(xml)
+    data = parsed_sitemap['data']
+    return url in data
Index: /qPloneGoogleSitemaps/tags/0.6+/tests/framework.py
===================================================================
--- /qPloneGoogleSitemaps/tags/0.6+/tests/framework.py	(revision 525)
+++ /qPloneGoogleSitemaps/tags/0.6+/tests/framework.py	(revision 525)
@@ -0,0 +1,107 @@
+##############################################################################
+#
+# ZopeTestCase 
+#
+# COPY THIS FILE TO YOUR 'tests' DIRECTORY.
+#
+# This version of framework.py will use the SOFTWARE_HOME
+# environment variable to locate Zope and the Testing package.
+#
+# If the tests are run in an INSTANCE_HOME installation of Zope,
+# Products.__path__ and sys.path with be adjusted to include the
+# instance's Products and lib/python directories respectively.
+#
+# If you explicitly set INSTANCE_HOME prior to running the tests,
+# auto-detection is disabled and the specified path will be used 
+# instead.
+#
+# If the 'tests' directory contains a custom_zodb.py file, INSTANCE_HOME
+# will be adjusted to use it.
+#
+# If you set the ZEO_INSTANCE_HOME environment variable a ZEO setup 
+# is assumed, and you can attach to a running ZEO server (via the 
+# instance's custom_zodb.py).
+#
+##############################################################################
+#
+# The following code should be at the top of every test module:
+#
+# import os, sys
+# if __name__ == '__main__':
+#     execfile(os.path.join(sys.path[0], 'framework.py'))
+#
+# ...and the following at the bottom:
+#
+# if __name__ == '__main__':
+#     framework()
+#
+##############################################################################
+
+__version__ = '0.2.3'
+
+# Save start state
+#
+__SOFTWARE_HOME = os.environ.get('SOFTWARE_HOME', '')
+__INSTANCE_HOME = os.environ.get('INSTANCE_HOME', '')
+
+if __SOFTWARE_HOME.endswith(os.sep):
+    __SOFTWARE_HOME = os.path.dirname(__SOFTWARE_HOME)
+
+if __INSTANCE_HOME.endswith(os.sep):
+    __INSTANCE_HOME = os.path.dirname(__INSTANCE_HOME)
+
+# Find and import the Testing package
+#
+if not sys.modules.has_key('Testing'):
+    p0 = sys.path[0]
+    if p0 and __name__ == '__main__':
+        os.chdir(p0)
+        p0 = ''
+    s = __SOFTWARE_HOME
+    p = d = s and s or os.getcwd()
+    while d:
+        if os.path.isdir(os.path.join(p, 'Testing')):
+            zope_home = os.path.dirname(os.path.dirname(p))
+            sys.path[:1] = [p0, p, zope_home]
+            break
+        p, d = s and ('','') or os.path.split(p)
+    else:
+        print 'Unable to locate Testing package.',
+        print 'You might need to set SOFTWARE_HOME.'
+        sys.exit(1)
+
+import Testing, unittest
+execfile(os.path.join(os.path.dirname(Testing.__file__), 'common.py'))
+
+# Include ZopeTestCase support
+#
+if 1:   # Create a new scope
+
+    p = os.path.join(os.path.dirname(Testing.__file__), 'ZopeTestCase')
+
+    if not os.path.isdir(p):
+        print 'Unable to locate ZopeTestCase package.',
+        print 'You might need to install ZopeTestCase.'
+        sys.exit(1)
+
+    ztc_common = 'ztc_common.py'
+    ztc_common_global = os.path.join(p, ztc_common)
+
+    f = 0
+    if os.path.exists(ztc_common_global):
+        execfile(ztc_common_global)
+        f = 1
+    if os.path.exists(ztc_common):
+        execfile(ztc_common)
+        f = 1
+
+    if not f:
+        print 'Unable to locate %s.' % ztc_common
+        sys.exit(1)
+
+# Debug
+#
+print 'SOFTWARE_HOME: %s' % os.environ.get('SOFTWARE_HOME', 'Not set')
+print 'INSTANCE_HOME: %s' % os.environ.get('INSTANCE_HOME', 'Not set')
+sys.stdout.flush()
+
Index: /qPloneGoogleSitemaps/tags/0.6+/tests/runalltests.py
===================================================================
--- /qPloneGoogleSitemaps/tags/0.6+/tests/runalltests.py	(revision 525)
+++ /qPloneGoogleSitemaps/tags/0.6+/tests/runalltests.py	(revision 525)
@@ -0,0 +1,29 @@
+#
+# Runs all tests in the current directory
+#
+# Execute like:
+#   python runalltests.py
+#
+# Alternatively use the testrunner: 
+#   python /path/to/Zope/utilities/testrunner.py -qa
+#
+
+import os, sys
+if __name__ == '__main__':
+    execfile(os.path.join(sys.path[0], 'framework.py')) 
+
+import unittest
+TestRunner = unittest.TextTestRunner
+suite = unittest.TestSuite()
+
+tests = os.listdir(os.curdir)
+tests = [n[:-3] for n in tests if n.startswith('test') and n.endswith('.py')]
+
+for test in tests:
+    m = __import__(test)
+    if hasattr(m, 'test_suite'):
+        suite.addTest(m.test_suite())
+
+if __name__ == '__main__':
+    TestRunner().run(suite)
+
Index: /qPloneGoogleSitemaps/tags/0.6+/tests/testqPloneGoogleSitemaps.py
===================================================================
--- /qPloneGoogleSitemaps/tags/0.6+/tests/testqPloneGoogleSitemaps.py	(revision 525)
+++ /qPloneGoogleSitemaps/tags/0.6+/tests/testqPloneGoogleSitemaps.py	(revision 525)
@@ -0,0 +1,154 @@
+#
+# Tests for qPloneGoogleSitemaps
+#
+import os, sys
+if __name__ == '__main__':
+    execfile(os.path.join(sys.path[0], 'framework.py'))
+
+from Products.PloneTestCase import PloneTestCase
+from XMLParser import parse, hasURL
+
+PRODUCT = 'qPloneGoogleSitemaps'
+PRODUCTS = (PRODUCT,)
+PloneTestCase.installProduct(PRODUCT)
+PloneTestCase.setupPloneSite(products = PRODUCTS)
+
+class TestqPloneGoogleSitemaps(PloneTestCase.FunctionalTestCase):
+
+    def afterSetUp(self):
+        self.loginAsPortalOwner()
+
+        self.membership = self.portal.portal_membership
+        self.workflow = self.portal.portal_workflow
+        self.auth = 'admin:admin'
+        self.sitemapUrl = '/'+self.portal.absolute_url(1) + '/google-sitemaps'
+        self.membership.addMember('admin', 'admin', ('Manager',), [])
+
+        # Add testing document to portal
+        my_doc = self.portal.invokeFactory('Document', id='my_doc')
+        self.my_doc = self.portal['my_doc']
+        self.my_doc.edit(text_format='plain', text='hello world')
+
+    def testInstallation(self):
+        installed = self.portal.portal_quickinstaller.isProductInstalled(PRODUCT)
+        self.assert_(installed, 'Product not installed')
+
+    def testSitemap(self):
+        sitemap = self.publish(self.sitemapUrl, self.auth).getBody()
+        parsed_sitemap = parse(sitemap)
+        start = parsed_sitemap['start']
+        data = parsed_sitemap['data']
+        self.assertEqual(len(start.keys()), 1)
+        self.assert_('urlset' in start.keys())
+
+        self.workflow.doActionFor(self.my_doc, 'publish')
+
+        sitemap = self.publish(self.sitemapUrl, self.auth).getBody()
+        parsed_sitemap = parse(sitemap)
+        start = parsed_sitemap['start']
+        data = parsed_sitemap['data']
+        self.assertEqual(len(start.keys()), 4)
+        self.assert_('urlset' in start.keys())
+        self.assert_('url' in start.keys())
+        self.assert_('loc' in start.keys())
+        self.assert_('lastmod' in start.keys())
+
+        self.assert_(data[0] == self.my_doc.absolute_url(0), 'Incorect url')
+
+    def testVerificationFile(self):
+        self.portal.gsm_create_verify_file('verif_file')
+        
+        vf_created = hasattr(self.portal, 'verif_file')
+        self.assert_(vf_created, 'Verification file not created')
+
+        self.portal.gsm_delete_verify_file()
+        vf_created = hasattr(self.portal, 'verif_file')
+        self.assert_(not vf_created, 'Verification file not removed')
+
+class TestSettings(PloneTestCase.FunctionalTestCase):
+
+    def afterSetUp(self):
+        self.loginAsPortalOwner()
+
+        self.membership = self.portal.portal_membership
+        self.workflow = self.portal.portal_workflow
+        self.gsm_props = self.portal.portal_properties['googlesitemap_properties']
+        self.auth = 'admin:admin'
+        self.sitemapUrl = '/'+self.portal.absolute_url(1) + '/google-sitemaps'
+
+        self.membership.addMember('admin', 'admin', ('Manager',), [])
+
+        # Add testing document to portal
+        my_doc = self.portal.invokeFactory('Document', id='my_doc')
+        self.my_doc = self.portal['my_doc']
+        self.my_doc.edit(text_format='plain', text='hello world')
+        self.my_doc_url = self.my_doc.absolute_url()
+
+    def testMetaTypeToDig(self):
+        self.workflow.doActionFor(self.my_doc, 'publish')
+        sitemap = self.publish(self.sitemapUrl, self.auth).getBody()
+        self.assert_(hasURL(sitemap, self.my_doc_url))
+
+        self.gsm_props.manage_changeProperties(portalTypes = [])
+
+        sitemap = self.publish(self.sitemapUrl, self.auth).getBody()
+        self.assert_(not hasURL(sitemap, self.my_doc_url))
+
+        self.gsm_props.manage_changeProperties(portalTypes = ['Document'])
+
+        sitemap = self.publish(self.sitemapUrl, self.auth).getBody()
+        self.assert_(hasURL(sitemap, self.my_doc_url))
+
+    def testStates(self):
+        self.workflow.doActionFor(self.my_doc, 'publish')
+        self.gsm_props.manage_changeProperties(states = ['visible'])
+
+        sitemap = self.publish(self.sitemapUrl, self.auth).getBody()
+        self.assert_(not hasURL(sitemap, self.my_doc_url))
+
+        self.gsm_props.manage_changeProperties(states = ['published'])
+
+        sitemap = self.publish(self.sitemapUrl, self.auth).getBody()
+        self.assert_(hasURL(sitemap, self.my_doc_url))
+
+    def test_blackout_entries(self):
+        self.workflow.doActionFor(self.my_doc, 'publish')
+        self.gsm_props.manage_changeProperties(blackout_list = (self.my_doc.getId(),))
+        sitemap = self.publish(self.sitemapUrl, self.auth).getBody()
+        self.assert_(not hasURL(sitemap, self.my_doc_url))
+
+        self.gsm_props.manage_changeProperties(blackout_list = [])
+        sitemap = self.publish(self.sitemapUrl, self.auth).getBody()
+        self.assert_(hasURL(sitemap, self.my_doc_url))
+
+    def test_regexp(self):
+        self.workflow.doActionFor(self.my_doc, 'publish')
+        sitemap = self.publish(self.sitemapUrl, self.auth).getBody()
+        self.assert_(not hasURL(sitemap, self.portal.absolute_url()))
+
+        regexp = "s/\/%s//"%self.my_doc.getId()
+        self.gsm_props.manage_changeProperties(reg_exp = [regexp])
+
+        sitemap = self.publish(self.sitemapUrl, self.auth).getBody()
+        self.assert_(hasURL(sitemap, self.portal.absolute_url()))
+
+    def test_add_urls(self):
+        self.gsm_props.manage_changeProperties(urls = ['http://w1', 'w2', '/w3'])
+        w1_url = 'http://w1'
+        w2_url = self.portal.absolute_url() + '/w2'
+        w3_url = self.portal.getPhysicalRoot().absolute_url() + '/w3'
+        sitemap = self.publish(self.sitemapUrl, self.auth).getBody()
+
+        self.assert_(hasURL(sitemap, w1_url))
+        self.assert_(hasURL(sitemap, w2_url))
+        self.assert_(hasURL(sitemap, w3_url))
+
+def test_suite():
+    from unittest import TestSuite, makeSuite
+    suite = TestSuite()
+    suite.addTest(makeSuite(TestqPloneGoogleSitemaps))
+    suite.addTest(makeSuite(TestSettings))
+    return suite
+
+if __name__ == '__main__':
+    framework()
Index: /qPloneGoogleSitemaps/tags/0.6+/utils.py
===================================================================
--- /qPloneGoogleSitemaps/tags/0.6+/utils.py	(revision 525)
+++ /qPloneGoogleSitemaps/tags/0.6+/utils.py	(revision 525)
@@ -0,0 +1,108 @@
+from urllib2 import urlopen
+from urllib  import quote as urlquote
+from Products.CMFCore.utils import getToolByName
+import re
+import Products.qPloneGoogleSitemaps.config as config
+from OFS.ObjectManager import BadRequestException
+def ping_google(url):
+    """Ping sitemap to Google"""
+    sitemap_url = urlquote(url + "/google-sitemaps")
+    g = urlopen('http://www.google.com/webmasters/sitemaps/ping?sitemap='+sitemap_url)
+    result = g.read()
+    g.close()
+    return 0
+
+def searchAndReplace(string, what, with):
+    """Emulate sed command s/"""
+    res = re.sub(what,with,string)
+    return res
+
+OPERATORS = {'s': searchAndReplace,}
+
+def applyOperations(objects, operations):
+    """Parse Operations """
+    parse = re.compile(r"(.?[^\\])/(.*[^\\]|)/(.*[^\\]|)/")
+    operations=[parse.match(op).groups() for op in operations]
+    result={}
+    for ob in objects:
+        url = ob.getURL()
+        for operator, what, with in operations:
+            url = OPERATORS[operator](url, what, with.replace("\\", ""))
+        #TODO: Remove or replace following condition
+        #it is senseless in the case we need intelligent
+        #result set. Better condition would be to place
+        #freshest brain into result
+        if url in result.keys():
+            continue
+        #TODO: replace brain with only data necessary to 
+        #generate sitemap
+        result[url]=ob
+    return result
+
+def additionalURLs(self):
+    """Add URLs to sitemap that arn't objects"""
+    res = []
+    plone_home = getToolByName(self, 'portal_url').getPortalObject().absolute_url()
+    root = self.getPhysicalRoot().absolute_url()
+
+    props = getToolByName(self,'portal_properties')
+    try:
+        URLs = props.googlesitemap_properties.urls
+    except AttributeError:
+        URLs = []
+
+    add_zope = re.compile('^/')
+    add_plone= re.compile('^[^http://|https://|\\\]')
+    for url in URLs:
+        if add_zope.match(url):
+            res.append(root+url)
+        elif add_plone.match(url):
+            res.append(plone_home+'/'+url)
+        else:
+            res.append(url)
+    return res
+
+"""workflows & co"""
+def getWorkflowTransitions(self,workflow_id):
+    pw = getToolByName(self,'portal_workflow')
+    wf = pw.getWorkflowById(workflow_id)
+    if not wf:
+        return None
+    return wf.transitions.values()
+
+def setWorkflowTransitions(self,transitions):
+    """set workflow transitions properties"""
+    portal_workflow = getToolByName(self, 'portal_workflow')
+    transmap = {}
+    for key in transitions:
+        if key.find('#')>0:
+            ids = key.split('#')
+            wfid = ids[0]
+            if not wfid in transmap.keys():
+                transmap[wfid]=[]
+            transmap[wfid].append(ids[1])
+    for wfid in transmap.keys():
+        workflow = portal_workflow.getWorkflowById(wfid)
+        if config.ping_googlesitemap not in workflow.scripts.objectIds():
+            workflow.scripts.manage_addProduct['ExternalMethod'].manage_addExternalMethod(
+                                config.ping_googlesitemap,
+                                'Ping sitemap',
+                                'qPloneGoogleSitemaps.ping_googlesitemap',
+                                config.ping_googlesitemap)
+        transitions_set = transmap[wfid]
+        for transition in workflow.transitions.values():
+            trid = transition.id
+            tras = transition.after_script_name
+            if (tras == '') and (trid in transitions_set):
+                #set
+                after_script = config.ping_googlesitemap
+            elif (tras == config.ping_googlesitemap) and not (trid in transitions_set):
+                #reset
+                after_script = ''
+            else:
+                #avoid properties set
+                continue
+            transition.setProperties(title=transition.title,
+                                     new_state_id=transition.new_state_id,
+                                     after_script_name=after_script,
+                                     actbox_name=transition.actbox_name)
Index: /qPloneGoogleSitemaps/tags/0.6+/version.txt
===================================================================
--- /qPloneGoogleSitemaps/tags/0.6+/version.txt	(revision 525)
+++ /qPloneGoogleSitemaps/tags/0.6+/version.txt	(revision 525)
@@ -0,0 +1,1 @@
+0.6+
