Index: qPloneSkinDump/trunk/Extensions/Install.py
===================================================================
--- qPloneSkinDump/trunk/Extensions/Install.py	(revision 72)
+++ qPloneSkinDump/trunk/Extensions/Install.py	(revision 74)
@@ -1,5 +1,8 @@
 from Products.Archetypes.Extensions.utils import install_subskin
-from Products.CMFCore.CMFCorePermissions import ManagePortal
 from Products.CMFCore.utils import getToolByName
+try:
+    from Products.CMFCore.permissions import ManagePortal
+except:
+    from Products.CMFCore.CMFCorePermissions import ManagePortal
 
 from Products.qPloneSkinDump.config import *
Index: qPloneSkinDump/trunk/HISTORY.txt
===================================================================
--- qPloneSkinDump/trunk/HISTORY.txt	(revision 72)
+++ qPloneSkinDump/trunk/HISTORY.txt	(revision 74)
@@ -1,4 +1,21 @@
-qPloneSkinDump 0.7.4
-    - Prevent copying .svn directories on skin product creating
+qPloneSkinDump 0.8.4
+    
+    - Implemented correct installation/uninstallation
+      for generated skin product
+    - Prevent copying .svn directory into generated skin product
+      from template
+    - Added "Destination directory" field to skin dump form.
+      Allow change destination directory for generated product
+
+
+qPloneSkinDump 0.8.1
+
+    - essential improvements of dumping portlets
+
+qPloneSkinDump 0.8.0
+    - configlet form improvement
+    - fixed migration bugs to plone3
+    - added support for plone_view_customizations dump
+    - refactor old-style installer to portal_setup
 
 qPloneSkinDump 0.7.3
Index: qPloneSkinDump/trunk/TODO.txt
===================================================================
--- qPloneSkinDump/trunk/TODO.txt	(revision 72)
+++ qPloneSkinDump/trunk/TODO.txt	(revision 74)
@@ -1,3 +1,11 @@
-*** Under consideration ***
+*** TODO LIST ***
 
-  - Create more usable interface.
+  - improvements in resource dumping
+  - refactor portal_view_customizations dump
+  - add dump of portal_properties
+  - add dump of viewlets.xml
+  - add dump of portlets.xml
+  - core refactorization, divide into small chunks all functionality (too difficult to upgrade current skindump structure)
+       * maybe using zope 3 component architecture
+maybe in future:
+  - refactor qPloneSkinDump to work with python paster package, for use ZopeSkel templates styling
Index: qPloneSkinDump/trunk/config.py
===================================================================
--- qPloneSkinDump/trunk/config.py	(revision 72)
+++ qPloneSkinDump/trunk/config.py	(revision 74)
@@ -1,12 +1,12 @@
 import re, os
 try:
-    from Products.CMFCore import CMFCorePermissions
-except ImportError:
-    from Products.CMFCore import permissions as CMFCorePermissions
+    from Products.CMFCore import permissions
+except:
+    from Products.CMFCore import CMFCorePermissions as permissions
 
 ## Base Product Constants
 GLOBALS = globals()
 PROJECTNAME = "qPloneSkinDump"
-ADD_CONTENT_PERMISSION = CMFCorePermissions.AddPortalContent
+ADD_CONTENT_PERMISSION = permissions.AddPortalContent
 CONFIGURATION_CONFIGLET = "qploneskindump_configuration"
 
@@ -27,5 +27,5 @@
 DEFAULT_IMPORTING_POLICY = "only_new"
 FORBIDDEN_EXP_PREFIXES = re.compile('^(portal_)')
-FORBIDDEN_EXP_NAMES = ["MailHost", "HTTPCache", "Members", "RAMCache", "acl_users",\
+FORBIDDEN_EXP_NAMES = ["ResourceRegistryCache", "MailHost", "HTTPCache", "Members", "RAMCache", "acl_users",\
                        "archetype_tool", "caching_policy_manager", "content_type_registry", \
                        "cookie_authentication", "error_log", "kupu_library_tool",\
Index: qPloneSkinDump/trunk/configure.zcml
===================================================================
--- qPloneSkinDump/trunk/configure.zcml	(revision 74)
+++ qPloneSkinDump/trunk/configure.zcml	(revision 74)
@@ -0,0 +1,3 @@
+<configure xmlns="http://namespaces.zope.org/zope">
+
+</configure>
Index: qPloneSkinDump/trunk/exportingObjects.py
===================================================================
--- qPloneSkinDump/trunk/exportingObjects.py	(revision 72)
+++ qPloneSkinDump/trunk/exportingObjects.py	(revision 74)
@@ -6,4 +6,5 @@
 import os, os.path
 osp = os.path
+from config import PRODUCTS_PATH
 
 def copyFile(src_dir, dst_dir, f_name):
@@ -33,10 +34,11 @@
 ##                         EXPORTING                         ##
 ###############################################################
-def exportObjects(context, doesExportObjects, exporting_objects, product_name):
+def exportObjects(context, doesExportObjects, exporting_objects,
+                  fs_dest_directory, product_name):
     # Check whether should perform exporting
     if not doesExportObjects:
         return None
     # Get Instance's exported and Product's imoprt pathes
-    instance_epath, product_epath = getImportedPathes(product_name)
+    instance_epath, product_epath = getImportedPathes(fs_dest_directory, product_name)
     # Move same named files from Instance export dir to Temp dir
     temp_dir_path, product_elist = moveSameFilesToTemp(instance_epath, product_epath, exporting_objects)
@@ -62,9 +64,9 @@
     return fail_export
 
-def getImportedPathes(product_name):
+def getImportedPathes(fs_dest_directory, product_name):
     # Based on instance path, construct import pathes 
     cfg = getConfiguration()
     instance_epath = cfg.clienthome
-    product_epath = osp.join(cfg.instancehome, 'Products', product_name, "import")
+    product_epath = osp.join(fs_dest_directory, product_name, "import")
     # Check presence of Product import directory
     if not osp.isdir(product_epath):        
Index: qPloneSkinDump/trunk/qPloneSkinDump.py
===================================================================
--- qPloneSkinDump/trunk/qPloneSkinDump.py	(revision 72)
+++ qPloneSkinDump/trunk/qPloneSkinDump.py	(revision 74)
@@ -8,4 +8,8 @@
 
 security = ModuleSecurityInfo( 'Products.qPloneSkinDump.qPloneSkinDump' )
+
+security.declarePublic('getProductsPath')
+def getProductsPath():
+    return PRODUCTS_PATH
 
 security.declarePublic('getExportingData')
@@ -35,8 +39,17 @@
 
 security.declarePublic('isValidProductName')
-def isValidProductName(product_name):
+def isValidProductName(product_name, fs_dest_directory):
     """ Check for product presence in installed products list"""
-    return (product_name not in get_product_listdirs() \
-            and isValidDirName(product_name))
+    if not fs_dest_directory==PRODUCTS_PATH:
+       return (not product_name in os.listdir(fs_dest_directory)) \
+              and isValidDirName(product_name)
+
+    return (not product_name in get_product_listdirs()) \
+           and isValidDirName(product_name)
+
+security.declarePublic('isValidDestinationDir')
+def isValidDestinationDir(destination_dir):
+    """ Check for existance of destination directory."""
+    return os.path.isdir(destination_dir)
 
 DIR_NAME_PATTERN = re.compile("^[a-zA-Z]+[a-zA-Z0-9_]*[a-zA-Z0-9]$")
@@ -49,7 +62,8 @@
 security.declarePublic('createProduct')
 def createProduct(context, \
-                  zmi_skin_name='custom', \
+                  zmi_skin_names=['custom',], \
                   zmi_base_skin_name='', \
                   subdir=None,\
+                  fs_dest_directory=PRODUCTS_PATH, \
                   fs_skin_directory='custom',\
                   fs_product_name='QSkinTemplate',\
@@ -64,14 +78,17 @@
                   exporting_objects=[], \
                   dump_CSS=True, \
-                  dump_JS=True ):
+                  dump_JS=True, \
+                  dump_portlets=0, \
+                  dump_policy='root', \
+                  dump_portlets_selection=[], \
+                  dump_custom_views=False):
     """ Main Skin Product creating procedure."""
-    makeNewProduct(context, fs_product_name, fs_skin_directory, \
-                   zmi_skin_name, zmi_base_skin_name, subdir, \
+    makeNewProduct(context, fs_dest_directory, fs_product_name, fs_skin_directory, \
+                   zmi_skin_names, zmi_base_skin_name, subdir, \
                    doesCustomizeSlots, left_slots, right_slots, slot_forming, main_column, \
                    doesExportObjects, import_policy, \
-                   dump_CSS, dump_JS )
-    dumpSkin(context, zmi_skin_name, subdir, fs_skin_directory.lower(),
-             fs_product_name, erase_from_skin)
-    result = exportObjects(context, doesExportObjects, exporting_objects, fs_product_name)
+                   dump_CSS, dump_JS, dump_portlets, dump_policy, dump_portlets_selection, dump_custom_views)
+    dumpSkin(context, zmi_skin_names, fs_dest_directory, fs_product_name, erase_from_skin)
+    result = exportObjects(context, doesExportObjects, exporting_objects, fs_dest_directory, fs_product_name)
     return result
 
Index: qPloneSkinDump/trunk/skin_template/Extensions/Install.py
===================================================================
--- qPloneSkinDump/trunk/skin_template/Extensions/Install.py	(revision 72)
+++ qPloneSkinDump/trunk/skin_template/Extensions/Install.py	(revision 74)
@@ -1,126 +1,25 @@
-import string
-from StringIO import StringIO
-from zLOG import LOG, INFO
 from Products.CMFCore.utils import getToolByName
-from Products.%(SKIN_PRODUCT_NAME)s.config import *
-from Products.%(SKIN_PRODUCT_NAME)s.Extensions.utils import *
 
-CHECKED_MESSAGE = "The base installation checkings completed."
+from Products.%(product_name)s.config import GS_INSTALL_PROFILE
+from Products.%(product_name)s.config import GS_AFTERINSTALL_PROFILE
+from Products.%(product_name)s.config import GS_UNINSTALL_PROFILE
 
-def prepareInstallation(portal, pp, product, out):
-    checkSuccessInstall(product)
-    uninstallOtherSkinProducts(portal)
-    if not ('uninstall_properties' in pp.objectIds()) :
-        pp.addPropertySheet(id='uninstall_properties', title= 'uninstall_properties')
-        print >> out, "Created 'portal_properties.uninstall_properties' PropertySheet (UP) for backup purpose"
+def install(self, reinstall=False):
+    """ Install skin with GenericSetup install profile
+    """
+    ps = getToolByName(self, 'portal_setup')
+    (ps.aq_base).__of__(self).runAllImportStepsFromProfile(GS_INSTALL_PROFILE)
 
-def checkSuccessInstall(product):
-    # Check for successfully completed 1 installation step
-    transcript = getattr(product,'transcript',None)
-    if transcript:
-        msg = str(transcript[0]['msg'])
-        if msg.find(CHECKED_MESSAGE) < 0 :
-            product.log("First part installation procedure not completed - installation terminated.")
-            raise
+def afterInstall(self, reinstall, product):
+    """ Install zexp objects and other dependent objects.
+        Perform this step here for prevent removing objects on uninstallation.
+    """
+    ps = getToolByName(self, 'portal_setup')
+    (ps.aq_base).__of__(self).runAllImportStepsFromProfile(GS_AFTERINSTALL_PROFILE)
 
-def uninstallOtherSkinProducts(portal):
-    qi=getToolByName(portal, 'portal_quickinstaller', None)
-    if not qi:
-        raise Exception("Can't work without QuickInstaller tool.")
-    # Get installed products
-    installed_products = [getattr(qi, p_dict['id']) \
-                          for p_dict in qi.listInstalledProducts()
-                          if p_dict['id'] != PRODUCT_NAME]
-    seek_str = "%%s generated product" %% GENERATOR_PRODUCT
-    installed_skin_products = []
-    # Looking for installed skin-products
-    for p in installed_products:
-        transcript = p.getTranscriptAsText()
-        if transcript.find(seek_str) >= 0 :
-            installed_skin_products.append(p.getId())
-    # Uninstall found skin-products
-    if installed_skin_products:
-        qi.uninstallProducts(products=installed_skin_products)
-
-def install(self):
-    # Checking base condition for installation
-    skinsTool = getToolByName(self, 'portal_skins')
-    # Checking for BASE_SKIN_NAME presenting in portal
-    skin_names = skinsTool.getSkinSelections()
-    if not BASE_SKIN_NAME in skin_names:
-        raise AttributeError("Impossible installation without %%s skin." %% BASE_SKIN_NAME)
-    # Checking for presenting lower_SKIN_NAME directory in portal skins
-    lower_SKIN_NAME = string.lower(SKIN_NAME)
-    if lower_SKIN_NAME in skinsTool.objectIds():
-        raise AttributeError("%%s skin layer already exist in portal skins. Installation Impossible." %% lower_SKIN_NAME)
-    return CHECKED_MESSAGE
-
-# For prevent quickInstaller's intervention in uninstall process - use afterInstall
-def afterInstall(self,product,reinstall):
-    out=StringIO()
-    # get all needed tools and some portal's core objects
-    portal = getToolByName(self, 'portal_url').getPortalObject()
-    pp = getToolByName(portal, 'portal_properties')
-    portal_css = getToolByName(portal, 'portal_css', None)
-    portal_js = getToolByName(portal, 'portal_javascripts', None)
-    # Make main prepare procedures
-    prepareInstallation(portal, pp, product, out)
-    pp_up = pp.uninstall_properties
-    # Install skin
-    installSkin(portal, pp_up, out)
-    # Register css resources
-    if portal_css and DOES_COSTOMIZE_CSS:
-        registerResource(pp_up, portal_css, portal_css.registerStylesheet, out \
-                        ,CSS_LIST, SKIN_CSS_REGDATA, 'q_registered_css', CSS_REG_PROPS)
-        print >> out, "Completed tuning CSS registry for new skin needs."
-    # Register js resources
-    if portal_js and DOES_COSTOMIZE_JS:
-        registerResource(pp_up, portal_js, portal_js.registerScript, out \
-                        ,JS_LIST, SKIN_JS_REGDATA, 'q_registered_js', JS_REG_PROPS)#---installJS---
-        print >> out, "Completed tuning JS registry for new skin needs."
-    # Customize slots    
-    if LEFT_SLOTS or RIGHT_SLOTS:
-        customizeSlots(portal, pp_up, out)
-    # Import object(s) to portal
-    if checkIfImport():
-        res_import = performImportToPortal(portal)
-        print >> out, res_import
-    # FINAL customization call additional functions from config 
-    if FINAL_CUSTOMIZATION_FUNCTIONS:
-        dummy = [func(portal, out) for func in FINAL_CUSTOMIZATION_FUNCTIONS]
-    print >> out, "%%s generated product." %% GENERATOR_PRODUCT
-    print >> out, '=== Installation successfully completed. ==='
-    product.log(out.getvalue())
-    product._p_changed = 1 #XXX:NEED for stable writing 'out' log to qi on afterinstallation.
-    return out.getvalue()
-
-def uninstall(self):
-    # get all needed tools and some portal's core objects
-    portal = self.portal_url.getPortalObject()
-    skinsTool = getToolByName(portal, 'portal_skins')
-    pp = getToolByName(portal, 'portal_properties')
-    portal_css = getToolByName(portal, 'portal_css', None)
-    portal_js = getToolByName(portal, 'portal_javascripts', None)
-    # Get all properies, saving during installation, for uninstalling
-    actual_skin_name = getProperty(pp, 'uninstall_properties', 'q_actual_skin_name',default=SKIN_NAME)
-    initial_skin = getProperty(pp, 'uninstall_properties', 'q_default_skin',default="")
-    original_css_list = getProperty(pp, 'uninstall_properties', 'q_registered_css')
-    original_js_list = getProperty(pp, 'uninstall_properties', 'q_registered_js')
-    orig_left_slots = getProperty(pp, 'uninstall_properties','q_left_slots')
-    orig_right_slots = getProperty(pp, 'uninstall_properties','q_right_slots')
-    # Remove 'uninstall_properties' from portal_properties
-    if 'uninstall_properties' in pp.objectIds() :
-        pp.manage_delObjects(ids=['uninstall_properties',])
-    # Uninstall skin
-    uninstallSkin(skinsTool, actual_skin_name, initial_skin)
-    # Unregister skin's CSS-es from portal_css. Only for Plone 2.1+
-    if portal_css and DOES_COSTOMIZE_CSS:
-        uninstallResource(portal_css, original_css_list, CSS_LIST, portal_css.registerStylesheet)
-    # Unregister skin's JS-s from portal_javascripts. Only for Plone 2.1+
-    if portal_js and DOES_COSTOMIZE_JS:
-        uninstallResource(portal_js, original_js_list, JS_LIST, portal_js.registerScript)
-    # Return site's column slots list unless Skin product installation
-    if orig_left_slots:
-        portal.left_slots = tuple(orig_left_slots)
-    if orig_right_slots:
-        portal.right_slots = tuple(orig_right_slots)
+def uninstall(self, reinstall=False):
+    """ Uninstall skin with GenericSetup uninstall profile
+    """
+    ps = getToolByName(self, 'portal_setup')
+    (ps.aq_base).__of__(self).runAllImportStepsFromProfile(GS_UNINSTALL_PROFILE)
+    
Index: qPloneSkinDump/trunk/skin_template/Extensions/__init__.py
===================================================================
--- qPloneSkinDump/trunk/skin_template/Extensions/__init__.py	(revision 72)
+++ qPloneSkinDump/trunk/skin_template/Extensions/__init__.py	(revision 74)
@@ -1,2 +1,1 @@
-# this file is here to make Install.py importable.
-# we need to make it non-zero size to make winzip cooperate
+#
Index: qPloneSkinDump/trunk/skin_template/Extensions/utils.py
===================================================================
--- qPloneSkinDump/trunk/skin_template/Extensions/utils.py	(revision 72)
+++ 	(revision )
@@ -1,416 +1,0 @@
-import os, sys, re, string
-from StringIO import StringIO
-from time import gmtime, strftime
-from zLOG import LOG, INFO
-from zExceptions import BadRequest
-from App.config import getConfiguration
-from Products.CMFCore.utils import getToolByName
-from Products.CMFCore.DirectoryView import addDirectoryViews
-from Products.%(SKIN_PRODUCT_NAME)s.config import *
-
-######################################################################
-##                      IMPORTING UTILS                             ##
-######################################################################
-osp = os.path
-ALLOWED_IMPORT_POLICY = ["only_new", "backup", "overwrite"]
-INTRO_TO_INSTANCE = "< Started copying object files from Product import directory to Instance one."
-SUMMARY_TO_INSTANCE = "> Finished copying."
-INTRO_TO_ROOT = "< Started import %%s file[s] with '%%s' policy."
-SUMMARY_TO_ROOT = "> Finished importing."
-INTRO_CLEAN = "< Started cleaning Instance import directory."
-SUMMARY_CLEAN = "> Finished cleaning."
-CREXP_INVALID_ID = re.compile('^The id \"(.*?)\" is invalid - it is already in use.$', re.DOTALL|re.IGNORECASE|re.MULTILINE)
-CSS_BASE_IDS_QPSD053 = ['id','expression','enabled','cookable','media','rel','title','rendering']   # supporting qPSD-0.5.3 version
-################    CHECK IMPORTING    ################
-def checkIfImport():
-    """ Return if perform importing, based on checking 
-        *zexp files in <SkinProduct>/import directory.
-    """
-    instance_ipath, product_ipath = getImportedPathes()
-    product_ilist = [i for i in os.listdir(product_ipath) \
-                     if osp.isfile(osp.join(product_ipath,i)) and i.endswith('.zexp')]
-    if product_ilist:
-        return 1
-    return 0
-
-################    IMPORTING TO PLONE'S IMPORT DIR   ################
-def getImportedPathes():
-    """ Return Plone instance and Skin product import pathes."""
-    # Based on instance path, construct import pathes 
-    cfg = getConfiguration()
-    instance_ipath = osp.join(cfg.instancehome, "import")
-    product_ipath = osp.join(cfg.instancehome, 'Products', PRODUCT_NAME, "import")
-    # Check presence of Product import directory
-    if not osp.isdir(product_ipath):        
-        raise BadRequest, "Skin Product's import directory '%%s' - does not exist or is'nt direcory" %% product_ipath
-    # Check presence of Instance import directory
-    if not osp.isdir(instance_ipath):
-        raise BadRequest, "Instance import directory '%%s' - does not exist or isn't direcory" %% instance_ipath
-    return [instance_ipath, product_ipath]
-
-def copyFile(src_dir, dst_dir, f_name):
-    """ Copy file from src_dir to dst_dir under original name."""
-    try:
-        src_file = open(osp.join(src_dir, f_name),"rb")
-        dst_file = open(osp.join(dst_dir, f_name),"wb")
-        dst_file.write(src_file.read())
-        dst_file.close()
-        src_file.close()
-    except Exception, e:
-        msg = "!!! In copying files from <%%s> dir to <%%s> dir exception occur. Details: %%s." %% (src_dir,dst_dir, str(e))
-        print >> import_out, msg
-        LOG('performImportToPortal',INFO,'copyFile', msg)
-
-def moveToTemp(same_instance_files, instance_ipath, temp_dir_path):
-    """ Move samenamed files from Instanse's dir to temp dir."""
-    os.mkdir(temp_dir_path) # Create temp back_[date] dir
-    try:
-        [copyFile(instance_ipath, temp_dir_path, f_name) for f_name in same_instance_files]
-        [os.remove(osp.join(instance_ipath, f_name)) for f_name in same_instance_files]
-    except Exception, e:
-        msg = "!!! Exception occur during moving files from Instance's dir to temp dir. Detaile:%%s." %% str(e)
-        print >> import_out, msg
-        LOG('performImportToPortal',INFO,'moveToTemp', msg)
-    
-def copyToInstanceImport():
-    """ Perform copying imported files from <SkinProduct>/import dir
-        to Plone's instance import dir.
-    """
-    print >> import_out, INTRO_TO_INSTANCE
-    instance_ipath, product_ipath = getImportedPathes()
-    # Compose temp dir back_[date] dir path in Instance import directory
-    temp_dir_id = "back_%%s" %% strftime("%%Y%%m%%d%%H%%M%%S", gmtime())
-    temp_dir_path = osp.join(instance_ipath, temp_dir_id)
-    # Get *.zexp files from Skin Product's import dir and Plone's instance import dir files
-    product_ilist = [i for i in os.listdir(product_ipath) \
-                     if osp.isfile(osp.join(product_ipath,i)) and i.endswith('.zexp')]
-    instance_ilist = [i for i in os.listdir(instance_ipath) \
-                      if osp.isfile(osp.join(instance_ipath,i)) and i.endswith('.zexp')]
-    # Check for presence samenamed files in Instance and Product import directories.
-    same_instance_files = [f_name for f_name in instance_ilist if f_name in product_ilist]
-    if same_instance_files:
-        moveToTemp(same_instance_files, instance_ipath, temp_dir_path)
-    # Copy all *zexp files from Product's import dir to Instance's import dir
-    [copyFile(product_ipath, instance_ipath, f_name) for f_name in product_ilist]
-    print >> import_out, SUMMARY_TO_INSTANCE
-    return [instance_ipath, product_ipath, temp_dir_path, product_ilist]
-
-################    IMPORTING TO PORTAL   ################
-def importObject(portal, file_name):
-    """ Work around old Zope bug in importing."""
-    try:
-        portal.manage_importObject(file_name)
-    except:
-        portal._p_jar = portal.Destination()._p_jar
-        portal.manage_importObject(file_name)
-
-def makeBackUp(portal, portal_objects, temp_dir_path, obj_id):
-    """ Perfom backup same named portal objects in temp folder."""
-    # Get id of temp folder-object
-    durty_path,temp_id = osp.split(temp_dir_path)
-    if not temp_id:
-        durty_path,temp_id = osp.split(durty_path)
-    # Get temp folder-object
-    if temp_id not in portal_objects:
-        portal.invokeFactory('Folder', id=temp_id)
-        print >> import_out, "! Created '%%s' backup directory with same-ids " \
-                             "objects from portal root." %% temp_id
-    temp_dir = getattr(portal, temp_id)
-    # Move object with same id to temp folder-object
-    get_transaction().commit(1)
-    obj = portal.manage_cutObjects(ids=[obj_id])
-    temp_dir.manage_pasteObjects(obj)
-    print >> import_out, "! '%%s' Object moved from portal root to '%%s' backup directory." %% (obj_id, temp_id)
-
-def performImport(portal, temp_dir_path, file_name):
-    """ Importing an object to portal."""
-    portal_objects = portal.objectIds()
-    try:
-        portal.manage_importObject(file_name)
-    except Exception, e:
-        msg = str(e)
-        is_invalid_id = CREXP_INVALID_ID.match(msg)
-        if is_invalid_id:
-            obj_id = is_invalid_id.group(1)
-            if IMPORT_POLICY == "only_new":
-                msg = "! Object with '%%s' id was not importing because it's already exist " \
-                      "in portal root." %% obj_id
-                print >> import_out, msg
-            elif IMPORT_POLICY == "backup":
-                makeBackUp(portal, portal_objects, temp_dir_path, obj_id)
-                importObject(portal, file_name)
-            elif IMPORT_POLICY == "overwrite":
-                portal.manage_delObjects(ids=[obj_id])
-                importObject(portal, file_name)
-        else:
-            # work around old Zope bug in importing
-            portal._p_jar = portal.Destination()._p_jar
-            portal.manage_importObject(file_name)
-
-def importToPortalRoot(portal, product_file_names, temp_dir_path):
-    """ Import all objects from *zexp files to portal root (based on IMPORT_POLICY)."""
-    if not IMPORT_POLICY in ALLOWED_IMPORT_POLICY:
-        raise Exception("%%s - wrong import policy in '%%s/config.py' file. Must be one of the %%s" \
-                        %% (IMPORT_POLICY, PRODUCT_NAME, ALLOWED_IMPORT_POLICY) )
-    print >> import_out, INTRO_TO_ROOT %% (product_file_names, IMPORT_POLICY)
-    for file_name in product_file_names:
-        try:
-            performImport(portal, temp_dir_path, file_name)
-        except Exception, error:
-            msg = '!!! Under "%%s" policy importing exception occur: %%s.' %% (IMPORT_POLICY, str(error))
-            print >> import_out, msg
-            LOG('performImportToPortal',INFO,'importToPortalRoot', msg)
-    print >> import_out, SUMMARY_TO_ROOT
-
-################    CLEANING PLONE'S IMPORT DIR   ################
-def cleanInstanceImport(instance_ipath, product_file_names, temp_dir_path):
-    """ Cleaning Plone's import dir."""
-    print >> import_out, INTRO_CLEAN
-    # Erase all copied *zexp files from Instance's import dir
-    for f_name in product_file_names:
-        f_path = osp.join(instance_ipath, f_name)
-        if osp.exists(f_path) and osp.isfile(f_path):
-            os.remove(f_path)
-        else:
-            msg = '! "%%s" file was not deleted from "%%s" import directory.' %%\
-                   (f_name, osp.join(instance_ipath))
-            print >> import_out, msg
-            LOG('performImportToPortal',INFO,'cleanInstanceImport', msg)
-    # Move all files from temp back_[date] dir to Instance's import dir
-    if osp.exists(temp_dir_path) and osp.isdir(temp_dir_path):
-        f_names = os.listdir(temp_dir_path)
-        try:
-            [copyFile(temp_dir_path, instance_ipath, f_name) for f_name in f_names]
-            [os.remove(osp.join(temp_dir_path, f_name)) for f_name in f_names]
-            # Erase temp back_[date] dir
-            os.rmdir(temp_dir_path)
-        except Exception, e:
-            msg = "!!! In moving files from temp dir to Instance's import dir exception occur."
-            print >> import_out, msg
-            LOG('performImportToPortal',INFO,'moveFromTempToImport', msg)
-    print >> import_out, SUMMARY_CLEAN
-
-################    MAIN    ################
-def performImportToPortal(portal):
-    """ Import objects from Skin Product to Portal root."""
-    globals()['import_out'] = StringIO()
-    instance_ipath, product_ipath, temp_dir_path, product_file_names = copyToInstanceImport()
-    if product_file_names:
-        importToPortalRoot(portal, product_file_names, temp_dir_path)
-        cleanInstanceImport(instance_ipath, product_file_names, temp_dir_path)
-    else:
-        print >> import_out, "!!! Failure importing: there is no file for importing to be found."
-    result = import_out
-    del globals()['import_out']
-    return result.getvalue()
-
-######################################################################
-##              INSTALLATION/UNINSTALLATION UTILS                   ##
-######################################################################
-CSS_REG_PROPS = ['id', 'expression', 'enabled', 'cookable', 'cacheable' \
-                ,'media', 'rel', 'title', 'rendering', 'compression']
-JS_REG_PROPS = ['id', 'expression', 'enabled', 'cookable', 'cacheable' \
-               ,'inline', 'compression']
-
-def installSkin(portal, pp_up, out):
-    # Checking for presense SKIN_NAME in portal_skins directory view or among Skin Names
-    skinsTool = getToolByName(portal, 'portal_skins')
-    # Get unique product_skin_name and remember it in case of differ from SKIN_NAME.
-    product_skin_name = SKIN_NAME
-    skin_names = skinsTool.getSkinSelections()
-    if product_skin_name in skin_names:
-        idx = 0
-        while product_skin_name in skin_names:
-            product_skin_name = SKIN_NAME + str(idx)
-            idx += 1
-        addProperty(pp_up, 'q_actual_skin_name', product_skin_name, 'string', out)
-    # Add directory views
-    layer_skin_name = string.lower(SKIN_NAME)
-    addDirectoryViews(skinsTool, 'skins', GLOBALS)
-    print >> out,  "- added '%%s' directory views to portal_skins." %% layer_skin_name
-    # Get Default skin and remember it for backup on uninstallig
-    default_skin = skinsTool.getDefaultSkin()
-    addProperty(pp_up, 'q_default_skin', default_skin, 'string', out)
-    # Building list of layers for NEW SKIN
-    base_path = skinsTool.getSkinPath(BASE_SKIN_NAME)
-    new_path = map( string.strip, string.split(base_path,',') )
-    if layer_skin_name in new_path :
-        print >> out, "- %%s layer already present in '%%s' skin." %% (layer_skin_name, BASE_SKIN_NAME)
-        # Remove layer_skin_name from current position.
-        del new_path[new_path.index(layer_skin_name)]
-    # Add layer_skin_name just after 'custom' position
-    try: 
-        new_path.insert(new_path.index('custom')+1, layer_skin_name)
-    except ValueError:
-        new_path.append(layer_skin_name)
-    new_path = string.join(new_path, ', ')
-    # Add NEW Skin and set it as dafault
-    skinsTool.addSkinSelection(product_skin_name, new_path, make_default=1)
-    print >> out, "Added %%s skin, bassed on %%s and set as default." %% (product_skin_name, BASE_SKIN_NAME)
-
-def uninstallSkin(skinsTool, actual_skin_name, initial_skin):
-    # Get 'portal_skins' object and list available skin names
-    # And remove SKIN_NAME from available skins, if it present
-    skin_names = skinsTool.getSkinSelections()
-    if actual_skin_name in skin_names :
-        skinsTool.manage_skinLayers(chosen=(actual_skin_name,), del_skin=1, REQUEST=None)
-        skin_names.remove(actual_skin_name)
-    # Remove product skin directory from skins tool 
-    # AND Remove skin-product layer from available skins
-    skin_layer = SKIN_NAME.lower()
-    if skin_layer in skinsTool.objectIds():
-        skinsTool.manage_delObjects(skin_layer)
-    for skin_name in skin_names:
-        path = skinsTool.getSkinPath(skin_name)
-        path = [i.strip() for i in  path.split(',')]
-        if skin_layer in path:
-            path.remove(skin_layer)
-            path = ','.join(path)
-            skinsTool.addSkinSelection(skin_name, path)
-    # If current default skin == actual_skin_name
-    # Set default skin in initial one (if initial skin still exist) 
-    # or in 1st from available skin names list.
-    current_default_skin = skinsTool.getDefaultSkin()
-    if current_default_skin == actual_skin_name:
-        if initial_skin in skin_names :
-            skinsTool.manage_properties(default_skin=initial_skin, REQUEST=None)
-        elif len(skin_names)>0 :
-            skinsTool.manage_properties(default_skin=skin_names[0], REQUEST=None)
-
-def addProperty(p_sheet, p_id, p_value, p_type, out):
-    if p_sheet.hasProperty(p_id):
-        p_sheet._delProperty(p_id)
-    p_sheet._setProperty(p_id, p_value, p_type)
-    print >> out, "... added %%s PropertySheet to %%s." %% (p_id, p_sheet.getId())
-
-def getResourceProperties(obj, prop_list, dflt=''):
-    """ Return list of 2 items list-[property name, property value]."""
-    properties=[]
-    for prop in prop_list:
-        accessor = getattr(obj, 'get%%s' %% prop.capitalize(), None)
-        if accessor:
-            properties.append([prop, accessor() or dflt])
-    return properties
-
-def registerResource(pp_up, portal_res, resRegisterFunction, out \
-                    ,RESOURCE_SKIN_LIST, SKIN_RES_REGDATA, UP_PROPERTY, RES_REG_PROPS):
-    """ Register resources in portal's registry, remember existant settings."""
-    # Get original registered resources
-    portal_res_srings = []
-    for r in portal_res.getResources():
-        portal_res_srings.append(";".join(['%%s::%%s'%%(r[0],str(r[1])) \
-                                for r in getResourceProperties(r, RES_REG_PROPS)]))
-    addProperty(pp_up, UP_PROPERTY, portal_res_srings, 'lines', out)
-    # Tune Resource registry according to new skin needs
-    unexistent = [] # list of default resources, 
-                    # which present in Skin-product, BUT absent in portal
-    portal_res_ids = portal_res.getResourceIds()
-    for res_dict in SKIN_RES_REGDATA:
-        if res_dict['id'] not in portal_res_ids:
-            # It's interesting - Resource Registry allow adding unexistent resource - use this
-            resRegisterFunction(**res_dict)
-            if res_dict['id'] not in RESOURCE_SKIN_LIST:
-                unexistent.append(res_dict['id'])
-        else:
-            pos = portal_res.getResourcePosition(res_dict['id'])
-            portal_res.unregisterResource(res_dict['id'])
-            resRegisterFunction(**res_dict)
-            portal_res.moveResource(res_dict['id'], pos)
-    if unexistent:
-        print >> out, "!!! - BAD: your Resource Regestry have'nt %%s resource(s), which may lead to some problems." %% unexistent
-
-def getVersion(res_list):
-    """Check version of skin product generator."""
-    return (res_list and not '::' in res_list[0] and '0.5') or '0.7'
-
-def uninstallResource(portal_res, original_res_list, RESOURCE_SKIN_LIST, resRegisterFunction):
-    # Prepare Resource Registry data for backup to original state
-    original_res_regestry = {}
-    genVersion = getVersion(original_res_list)
-    for rec in original_res_list:
-        resource = {}
-        if genVersion == '0.7':
-            [resource.update({prop.split('::')[0]:prop.split('::')[1]}) for prop in rec.split(";")]
-        elif genVersion == '0.5':
-            props = rec.split(";")
-            [resource.update({CSS_BASE_IDS_QPSD053[i]:props[i]}) for i in range(len(CSS_BASE_IDS_QPSD053))]
-        original_res_regestry[resource.pop('id')] = resource
-    # Work up actual Resource Registry
-    res_dict = portal_res.getResourcesDict()
-    for res_id in res_dict.keys():
-        # Remove from Resource Registry Skin product's resources
-        if res_id in RESOURCE_SKIN_LIST \
-           and res_id not in original_res_regestry.keys():
-            portal_res.unregisterResource(res_id)
-            continue
-        # Backup 'enabled' property Registry's resourses to it's original state
-        if original_res_regestry.has_key(res_id):
-            act_Enabled_state = res_dict[res_id].getEnabled()
-            orig_Enabled_state = original_res_regestry[res_id]['enabled']
-            if act_Enabled_state != orig_Enabled_state:
-                pos = portal_res.getResourcePosition(res_id)
-                resource = res_dict[res_id]
-                res = original_res_regestry[res_id]
-                portal_res.unregisterResource(res_id)
-                resRegisterFunction(res_id, **res)
-                portal_res.moveResource(res_id, pos)
-
-def customizeSlots(portal, pp_up, out):
-    # Get original Site's column lists
-    orig_left_slots = left_column = list(portal.left_slots)
-    orig_right_slots = right_column = list(portal.right_slots)
-    # Save original Site's LEFT and RIGHT slots
-    addProperty(pp_up, 'q_left_slots', orig_left_slots, 'lines', out)
-    addProperty(pp_up, 'q_right_slots', orig_right_slots, 'lines', out)
-    # blend-with-site - to portal's slots adding only new one from skin-porduct
-    # blend-with-skin - portal slots forming in the following manner: 
-    #                   first adding skin-porduct's slots, than new one from portal
-    # replace - to portal's slots forming only from the skin-porduct's slot list
-    if SLOT_FORMING == "blend_with_skin":
-        left_column, right_column = formSlotsColumn(LEFT_SLOTS, RIGHT_SLOTS, 
-                                                    orig_left_slots, orig_right_slots, MAIN_COLUMN)
-    elif SLOT_FORMING == "blend_with_site":
-        left_column, right_column = formSlotsColumn(orig_left_slots, orig_right_slots,
-                                                    LEFT_SLOTS, RIGHT_SLOTS, MAIN_COLUMN )
-    elif SLOT_FORMING == "replace":
-        left_column, right_column = formSlotsColumn(LEFT_SLOTS, RIGHT_SLOTS, [], [], MAIN_COLUMN)
-    # REPLACE SITE's column slots
-    portal.left_slots = tuple(left_column)
-    portal.right_slots = tuple(right_column)
-    print >> out, "Complited portal slots customization ..."
-
-# main_column ("left" / "right" / "both") mean which of the MAIN column is favour
-def formSlotsColumn(main_left, main_right, slave_left=[], slave_right=[], main_column="both"):
-    result_left = main_left
-    result_right = main_right
-    if main_column == "left":
-    # 1) APPEND to MAIN_LEFT list *new for main_left column* slots from slave_left list 
-    # 2) APPEND to MAIN_RIGHT list *new for both main columns* slots from slave_right
-    # 3) REMOVE slots from MAIN_RIGHT list, which are *doubled* in MAIN_LEFT
-        [result_left.append(slot) for slot in slave_left if slot not in result_left]
-        [result_right.append(slot) for slot in slave_right \
-                                   if slot not in result_right and slot not in result_left]
-        [result_right.remove(slot) for slot in result_left if slot in result_right]
-    elif main_column == "right":
-    # 1) APPEND to MAIN_LEFT list *new for main_right column* slots from slave_left list 
-    # 2) APPEND to MAIN_RIGHT list *new for both main columns* slots from slave_right
-    # 3) REMOVE slots from MAIN_LEFT list, which are *doubled* in MAIN_RIGHT
-        [result_right.append(slot) for slot in slave_right if slot not in result_right]
-        [result_left.append(slot) for slot in slave_left \
-                                  if slot not in result_left and slot not in result_right]
-        [result_left.remove(slot) for slot in result_right if slot in result_left]
-    elif main_column == "both":
-    # 1) APPEND to MAIN_LEFT list *new for both main columns* slots from slave_left list 
-    # 2) APPEND to MAIN_RIGHT list *new for both main columns* slots from slave_right
-        [result_left.append(slot) for slot in slave_left \
-                                  if slot not in result_left and slot not in result_right]
-        [result_right.append(slot) for slot in slave_right \
-                                   if slot not in result_right and slot not in result_left]
-    return [result_left, result_right]
-
-def getProperty(pp, ps, id, default=[]):
-    """ Get property from portal_properties/[property_sheet]"""
-    res = default
-    if ps in pp.objectIds() and pp[ps].hasProperty(id):
-        res = pp[ps].getProperty(id, default)
-    return res
Index: qPloneSkinDump/trunk/skin_template/HISTORY.txt
===================================================================
--- qPloneSkinDump/trunk/skin_template/HISTORY.txt	(revision 74)
+++ qPloneSkinDump/trunk/skin_template/HISTORY.txt	(revision 74)
@@ -0,0 +1,5 @@
+%(SKIN_PRODUCT_NAME)s Change Log
+
+  %(creation_date)s - 0.1 Release
+
+    - Initial version for plone 3;
Index: qPloneSkinDump/trunk/skin_template/VERSION.txt
===================================================================
--- qPloneSkinDump/trunk/skin_template/VERSION.txt	(revision 74)
+++ qPloneSkinDump/trunk/skin_template/VERSION.txt	(revision 74)
@@ -0,0 +1,1 @@
+0.1
Index: qPloneSkinDump/trunk/skin_template/__init__.py
===================================================================
--- qPloneSkinDump/trunk/skin_template/__init__.py	(revision 72)
+++ qPloneSkinDump/trunk/skin_template/__init__.py	(revision 74)
@@ -1,4 +1,1 @@
-from Products.CMFCore.DirectoryView import registerDirectory
-from config import GLOBALS
-
-registerDirectory('skins', GLOBALS)
+#
Index: qPloneSkinDump/trunk/skin_template/browser/__init__.py
===================================================================
--- qPloneSkinDump/trunk/skin_template/browser/__init__.py	(revision 74)
+++ qPloneSkinDump/trunk/skin_template/browser/__init__.py	(revision 74)
@@ -0,0 +1,1 @@
+#
Index: qPloneSkinDump/trunk/skin_template/browser/configure.zcml
===================================================================
--- qPloneSkinDump/trunk/skin_template/browser/configure.zcml	(revision 74)
+++ qPloneSkinDump/trunk/skin_template/browser/configure.zcml	(revision 74)
@@ -0,0 +1,14 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:browser="http://namespaces.zope.org/browser"
+    i18n_domain="custom_i18n_domain">
+
+    <interface
+        interface=".interfaces.ITheme%(skin_name_capital)s"
+        type="zope.publisher.interfaces.browser.IBrowserSkinType"
+        name="%(skin_name)s"
+        />
+
+    <include file="viewlets.zcml"/>
+
+</configure>
Index: qPloneSkinDump/trunk/skin_template/browser/interfaces.py
===================================================================
--- qPloneSkinDump/trunk/skin_template/browser/interfaces.py	(revision 74)
+++ qPloneSkinDump/trunk/skin_template/browser/interfaces.py	(revision 74)
@@ -0,0 +1,5 @@
+from plone.theme.interfaces import IDefaultPloneLayer
+
+class ITheme%(skin_name_capital)s(IDefaultPloneLayer):
+    """Marker interface that defines a Zope 3 skin layer.
+    """
Index: qPloneSkinDump/trunk/skin_template/browser/viewlets.zcml
===================================================================
--- qPloneSkinDump/trunk/skin_template/browser/viewlets.zcml	(revision 74)
+++ qPloneSkinDump/trunk/skin_template/browser/viewlets.zcml	(revision 74)
@@ -0,0 +1,8 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:browser="http://namespaces.zope.org/browser"
+    i18n_domain="custom_i18n_domain">
+
+    %(viewlets_zcml)s
+
+</configure>
Index: qPloneSkinDump/trunk/skin_template/config.py
===================================================================
--- qPloneSkinDump/trunk/skin_template/config.py	(revision 72)
+++ qPloneSkinDump/trunk/skin_template/config.py	(revision 74)
@@ -1,2 +1,3 @@
+import os
 ## PLONE AND SKIN PRODUCT SPECIFIC CONSTANTS
 GLOBALS = globals()
@@ -14,6 +15,6 @@
 ## ['some/portlet1','some/portlet2'] - will change appropriate (left or right)
 ##                                     slot to listed portlets
-LEFT_SLOTS = %(LEFT_SLOTS)s
-RIGHT_SLOTS = %(RIGHT_SLOTS)s
+#LEFT_SLOTS = %(LEFT_SLOTS)s
+#RIGHT_SLOTS = %(RIGHT_SLOTS)s
 
 ## Slot's list forming procedure.
@@ -24,5 +25,5 @@
 #SLOT_FORMING = "blend_with_site"
 #SLOT_FORMING = "replace"
-SLOT_FORMING = "%(SLOT_FORMING)s"
+#SLOT_FORMING = "%(SLOT_FORMING)s"
 
 ## Favour column for slots forming procedure. IMPORTANT only for 'Blend with...' 
@@ -37,5 +38,5 @@
 #MAIN_COLUMN = "right"
 #MAIN_COLUMN = "both"
-MAIN_COLUMN = "%(MAIN_COLUMN)s"
+#MAIN_COLUMN = "%(MAIN_COLUMN)s"
 
 
@@ -100,2 +101,17 @@
 from Products.CMFCore.utils import getToolByName
 FINAL_CUSTOMIZATION_FUNCTIONS = []
+
+# site portlets registry
+SLOT_STRUCTURE = %(slot_structure)s
+
+# portal_view_customization content
+CUSTOM_VIEWS = %(custom_views)s
+
+# absolute file system path to product
+from Globals import package_home
+PRODUCTS_PATH = os.sep.join(package_home(GLOBALS).split(os.sep)[:-1])
+
+## GenericSetup constants
+GS_INSTALL_PROFILE      = "profile-Products.%(product_name)s:default"
+GS_AFTERINSTALL_PROFILE = "profile-Products.%(product_name)s:afterinstall"
+GS_UNINSTALL_PROFILE    = "profile-Products.%(product_name)s:uninstall"
Index: qPloneSkinDump/trunk/skin_template/configure.zcml
===================================================================
--- qPloneSkinDump/trunk/skin_template/configure.zcml	(revision 74)
+++ qPloneSkinDump/trunk/skin_template/configure.zcml	(revision 74)
@@ -0,0 +1,12 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:cmf="http://namespaces.zope.org/cmf"
+    i18n_domain="%(product_name_lowercase)s">
+
+ <include file="profiles.zcml" />
+
+ <include file="skins.zcml" />
+
+ <include package=".browser" />
+
+</configure>
Index: qPloneSkinDump/trunk/skin_template/fixes.py
===================================================================
--- qPloneSkinDump/trunk/skin_template/fixes.py	(revision 74)
+++ qPloneSkinDump/trunk/skin_template/fixes.py	(revision 74)
@@ -0,0 +1,55 @@
+from Acquisition import aq_base
+from Products.CMFCore.utils import getToolByName
+from Products.ZCatalog.ProgressHandler import ZLogHandler
+from plone.app.linkintegrity.handlers import referencedRelationship as li_relation
+
+portal_catalog = None
+portal_repository = None
+uid_catalog = None
+reference_catalog = None
+
+def fix_archivest(ob):
+    ''' Fix #7334 bug of CMFEdition.
+        Fixed in CMFEdition v1.1.5+
+    '''
+    if portal_repository.isVersionable(ob):
+        portal_repository.save(obj=ob, comment="")
+
+def fix_catalog(ob):
+    ob.reindexObject()
+
+def fix_linkintegrity(ob):
+    """Fix losed references."""
+    uobject = aq_base(ob)
+    if reference_catalog.isReferenceable(uobject):
+        ob_li_refs = reference_catalog.getReferences(ob, relationship=li_relation)
+        if ob_li_refs:
+            annotations = ob._getReferenceAnnotations()
+            uniqueUIDs = uid_catalog.uniqueValuesFor('UID')
+            # delete references to non-existent objects
+            [annotations._delObject(ref.id) for ref in ob_li_refs \
+             if not ref.targetUID in uniqueUIDs]
+        
+def fix_all(ob):
+    """ Recursive function for perform registered
+        actions for all internal objects
+    """
+    [a(ob) for a in perobject_actions]
+
+    if getattr(ob, 'is_folderish', None):
+        [fix_all(o) for o in ob.objectValues()]
+
+perobject_actions = [fix_archivest, fix_catalog, fix_linkintegrity]
+
+def fix(context):
+    ''' Main fix function: fix defects of importing:
+        imported objects - absence in catalogs, some other issues'''
+    global portal_repository, portal_catalog
+    global uid_catalog, reference_catalog
+    portal_catalog = getToolByName(context,'portal_catalog')
+    portal_repository = getToolByName(context,'portal_repository')
+    uid_catalog = getToolByName(context,'uid_catalog')
+    reference_catalog = getToolByName(context,'reference_catalog')
+
+    fix_all(context)
+
Index: qPloneSkinDump/trunk/skin_template/profiles.zcml
===================================================================
--- qPloneSkinDump/trunk/skin_template/profiles.zcml	(revision 74)
+++ qPloneSkinDump/trunk/skin_template/profiles.zcml	(revision 74)
@@ -0,0 +1,30 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:genericsetup="http://namespaces.zope.org/genericsetup"
+    i18n_domain="%(product_name_lowercase)s">
+
+  <genericsetup:registerProfile
+      name="default"
+      title="%(product_name)s"
+      directory="profiles/default"
+      description="Extension profile for %(product_name)s."
+      provides="Products.GenericSetup.interfaces.EXTENSION"
+      />
+
+  <genericsetup:registerProfile
+      name="afterinstall"
+      title="%(product_name)s:afterinstall"
+      directory="profiles/afterinstall"
+      description="Extension profile for install zexps and other dependent objects of %(product_name)s."
+      provides="Products.GenericSetup.interfaces.EXTENSION"
+      />
+
+  <genericsetup:registerProfile
+      name="uninstall"
+      title="%(product_name)s:uninstall"
+      directory="profiles/uninstall"
+      description="Extension profile for UNINSTALL %(product_name)s."
+      provides="Products.GenericSetup.interfaces.EXTENSION"
+      />
+
+</configure>
Index: qPloneSkinDump/trunk/skin_template/profiles/afterinstall/import_steps.xml
===================================================================
--- qPloneSkinDump/trunk/skin_template/profiles/afterinstall/import_steps.xml	(revision 74)
+++ qPloneSkinDump/trunk/skin_template/profiles/afterinstall/import_steps.xml	(revision 74)
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<import-steps>
+ <import-step id="%(skin_name)s_zexps" version="%(version)s-1"
+              handler="Products.%(product_name)s.setuphandlers.importZexps"
+              title="Import zexp objects">
+   Import zexp objects
+ </import-step>
+ <import-step id="%(skin_name)s_customviews" version="%(version)s-2"
+              handler="Products.%(product_name)s.setuphandlers.importCustomViews"
+              title="Import customized views">
+  <dependency step="%(skin_name)s_zexps"/>
+   Import customized views to portal_view_customizations.
+ </import-step>
+ <import-step id="%(skin_name)s_portlets" version="%(version)s-3"
+              handler="Products.%(product_name)s.setuphandlers.importPortlets"
+              title="Customize %(skin_name)s portlets">
+  <dependency step="%(skin_name)s_zexps"/>
+  <dependency step="%(skin_name)s_customviews"/>
+   Customize %(skin_name)s left and right portlets.
+ </import-step>
+ <import-step id="%(skin_name)s_various" version="%(version)s-4"
+              handler="Products.%(product_name)s.setuphandlers.importVarious"
+              title="Perform various skin customizations">
+  <dependency step="%(skin_name)s_portlets"/>
+  <dependency step="%(skin_name)s_customviews"/>
+  <dependency step="%(skin_name)s_zexps"/>
+   Perform various skin product final customizations.
+ </import-step>
+</import-steps>
Index: qPloneSkinDump/trunk/skin_template/profiles/default/cssregistry.xml
===================================================================
--- qPloneSkinDump/trunk/skin_template/profiles/default/cssregistry.xml	(revision 74)
+++ qPloneSkinDump/trunk/skin_template/profiles/default/cssregistry.xml	(revision 74)
@@ -0,0 +1,1 @@
+%(stylesheets_xml)s
Index: qPloneSkinDump/trunk/skin_template/profiles/default/jsregistry.xml
===================================================================
--- qPloneSkinDump/trunk/skin_template/profiles/default/jsregistry.xml	(revision 74)
+++ qPloneSkinDump/trunk/skin_template/profiles/default/jsregistry.xml	(revision 74)
@@ -0,0 +1,1 @@
+%(javascripts_xml)s
Index: qPloneSkinDump/trunk/skin_template/profiles/default/propertiestool.xml
===================================================================
--- qPloneSkinDump/trunk/skin_template/profiles/default/propertiestool.xml	(revision 74)
+++ qPloneSkinDump/trunk/skin_template/profiles/default/propertiestool.xml	(revision 74)
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<object name="portal_properties" meta_type="Plone Properties Tool">
+ <object name="%(product_name_lowercase)s_properties" meta_type="Plone Property Sheet">
+  <property name="title">%(product_name)s properties</property>
+  <property name="portlets_before_install" type="string">[]</property>
+ </object>
+</object>
Index: qPloneSkinDump/trunk/skin_template/profiles/default/skins.xml
===================================================================
--- qPloneSkinDump/trunk/skin_template/profiles/default/skins.xml	(revision 74)
+++ qPloneSkinDump/trunk/skin_template/profiles/default/skins.xml	(revision 74)
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<object name="portal_skins" meta_type="Plone Skins Tool" allow_any="False"
+   cookie_persistence="False" default_skin="%(skin_name)s"
+   request_varname="plone_skin">
+%(directory_views_xml)s
+ <skin-path name="%(skin_name)s">
+%(skin_layers)s
+ </skin-path>
+</object>
Index: qPloneSkinDump/trunk/skin_template/profiles/uninstall/import_steps.xml
===================================================================
--- qPloneSkinDump/trunk/skin_template/profiles/uninstall/import_steps.xml	(revision 74)
+++ qPloneSkinDump/trunk/skin_template/profiles/uninstall/import_steps.xml	(revision 74)
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<import-steps>
+ <import-step id="%(skin_name)s_uninstallPortlets" version="20080312-1"
+              handler="Products.%(product_name)s.uninstallhandlers.uninstallPortlets"
+              title="Uninstall %(product_name)s portlets">
+   Uninstall custom %(product_name)s left and right portlets.
+ </import-step>
+ <import-step id="%(skin_name)s_uninstallProperties" version="20080312-2"
+              handler="Products.%(product_name)s.uninstallhandlers.uninstallProperties"
+              title="Remove %(product_name)s properties">
+  <dependency step="%(skin_name)s_uninstallPortlets"/>
+    Remove %(product_name)s properties.
+ </import-step>
+</import-steps>
Index: qPloneSkinDump/trunk/skin_template/profiles/uninstall/skins.xml
===================================================================
--- qPloneSkinDump/trunk/skin_template/profiles/uninstall/skins.xml	(revision 74)
+++ qPloneSkinDump/trunk/skin_template/profiles/uninstall/skins.xml	(revision 74)
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<object name="portal_skins" default_skin="Plone Default">
+ %(remove_directory_views_xml)s
+ <skin-path name="%(SKIN_NAME)s" remove="True" />
+</object>
Index: qPloneSkinDump/trunk/skin_template/setuphandlers.py
===================================================================
--- qPloneSkinDump/trunk/skin_template/setuphandlers.py	(revision 74)
+++ qPloneSkinDump/trunk/skin_template/setuphandlers.py	(revision 74)
@@ -0,0 +1,179 @@
+import sys
+from logging import getLogger
+
+from BTrees.OOBTree import OOBTree
+from persistent.list import PersistentList
+
+from zope.dottedname.resolve import resolve
+from zope.component import getUtility, getSiteManager, getMultiAdapter
+
+from plone.portlets.interfaces import IPortletAssignmentMapping, IPortletManager, IPlacelessPortletManager
+from plone.portlets.interfaces import IPortletContext, IPortletDataProvider
+from plone.portlets.interfaces import ILocalPortletAssignmentManager
+from plone.portlets.storage import PortletCategoryMapping, PortletAssignmentMapping
+from plone.app.portlets import portlets
+
+from plone.app.customerize.registration import *
+
+from Products.CMFCore.utils import getToolByName
+from Products.GenericSetup.utils import _getDottedName, _resolveDottedName
+
+from Products.%(product_name)s.config import *
+from Products.%(product_name)s.utils import *
+from Products.%(product_name)s.utilsPortlets import dumpPortlets
+
+logger = getLogger('%(product_name)s')
+
+def assignPortlet(mapping, info):
+    name = info['name']
+    try:
+        assignment = _resolveDottedName(info['class'])
+    except:
+        e,v,tr = sys.exc_info()
+        logger.info('Debug from setup portlets handler: %%s: %%s (%%s)' , info['class'], str(v), str(e))
+        return False
+    else:
+        portlet = assignment(**info['kwargs'])
+        if mapping.get(name, None) is not None:
+            del mapping[name]
+        mapping[name] = portlet
+        return portlet
+
+def setupSiteWidePortlets(site, data, managers):
+
+    for name, info in data:
+        manager = managers.get(name, None)
+        if manager is not None:
+            for category, keys in info.items():
+                catmapping = manager.get(category, None)
+                if catmapping is None:
+                    catmapping = manager[category] = PortletCategoryMapping()
+                for key, assignments in keys.items():
+                    mapping = catmapping.get(key, None)
+                    if mapping is None:
+                        mapping = catmapping[key] = PortletAssignmentMapping()
+                    for assignment in assignments.values():
+                        assignPortlet(mapping, assignment)
+
+def setupPortletsForContext(context, data, managers):
+
+    for name, info in data:
+        manager = managers.get(name, None)
+        if manager is not None:
+            # set portlet assignments
+            mapping = getMultiAdapter((context, manager), IPortletAssignmentMapping, context=context)
+
+            # purge mapping
+            mapping._data = OOBTree()
+            mapping._order = PersistentList()
+
+            if info['assignments']:
+                # set portlet assignments
+                for assignment in info['assignments']:
+                    assignPortlet(mapping, assignment)
+            if info['blacklists']:
+                # set blacklists
+                localassignmentmanager = getMultiAdapter((context, manager), ILocalPortletAssignmentManager, context=context)
+                for category, status in info['blacklists']:
+                    localassignmentmanager.setBlacklistStatus(category, status)
+
+
+def saveBeforeInstallPortlets(context):
+    # Save information about portlets before installation
+
+    beforeInstall = dumpPortlets(context=context, dump_policy='root', dump_portlets_selection=[] )
+
+    # update properties list
+    pp = getToolByName(context, 'portal_properties')
+    skin_props = pp._getOb('%(product_name_lowercase)s_properties')
+    skin_props._updateProperty('portlets_before_install', str(beforeInstall) )
+
+
+def importPortlets(context):
+
+    if context.readDataFile("%(afterinstall_profile_marker)s") is None:
+        return
+
+    site = context.getSite()
+
+    saveBeforeInstallPortlets(site)
+
+    components = getSiteManager(site)
+    ms = [r for r in components.registeredUtilities() if r.provided.isOrExtends(IPortletManager)]
+    context_managers = {}
+    for m in ms:
+        if not m.provided.isOrExtends(IPlacelessPortletManager):
+            context_managers[m.name] = getUtility(IPortletManager, name=m.name, context=site)
+
+    managers = {}
+    for m in ms:
+        managers[m.name] = getUtility(IPortletManager, name=m.name, context=site)
+
+    for path, info in SLOT_STRUCTURE:
+        if path == '__site-wide-portlets__':
+            setupSiteWidePortlets(site, info, managers)
+        else:
+            try:
+                obj = site.restrictedTraverse(path)
+            except:
+                e,v,tr = sys.exc_info()
+                logger.info('Debug from importPortlets handler: %%s: %%s (%%s)' , path, str(v), str(e))
+            else:
+                setupPortletsForContext(obj, info, context_managers)
+
+def importZexps(context):
+
+    if context.readDataFile("%(afterinstall_profile_marker)s") is None:
+        return
+
+    site = context.getSite()
+    if checkIfImport():
+        performImportToPortal(site)
+
+def importVarious(context):
+
+    if context.readDataFile("%(afterinstall_profile_marker)s") is None:
+        return
+
+    site = context.getSite()
+    out = StringIO()
+    if FINAL_CUSTOMIZATION_FUNCTIONS:
+        dummy = [func(site, out) for func in FINAL_CUSTOMIZATION_FUNCTIONS]
+
+def importCustomViews(context):
+
+    if context.readDataFile("%(afterinstall_profile_marker)s") is None:
+        return
+
+    site = context.getSite()
+
+    for view in CUSTOM_VIEWS:
+        for_name = view['for_name']
+        view_name = view['view_name']
+        type_name = view['type_name']
+        kwargs = view['kwargs']
+
+        reg = findTemplateViewRegistration(for_name, type_name, view_name)
+        viewzpt_id = str(generateIdFromRegistration(reg))
+
+        container = getUtility(IViewTemplateContainer)
+        if viewzpt_id in container.objectIds():
+            continue
+
+        attr, pt = findViewletTemplate(reg.factory)
+        if pt:
+            ptname = basename(pt.filename)
+        else:
+            ptname = None
+        viewzpt = TTWViewTemplate(
+            id = viewzpt_id,
+            text = kwargs['text'],
+            encoding = kwargs['encoding'],
+            content_type = kwargs['content_type'],
+            view = getViewClassFromRegistration(reg),
+            permission = getViewPermissionFromRegistration(reg),
+            name = ptname)
+        container.addTemplate(viewzpt_id, viewzpt)
+
+        sm = getSiteManager(site)
+        sm.registerAdapter(viewzpt, required = reg.required, provided = reg.provided, name = reg.name)
Index: qPloneSkinDump/trunk/skin_template/skins.zcml
===================================================================
--- qPloneSkinDump/trunk/skin_template/skins.zcml	(revision 74)
+++ qPloneSkinDump/trunk/skin_template/skins.zcml	(revision 74)
@@ -0,0 +1,8 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:cmf="http://namespaces.zope.org/cmf"
+    i18n_domain="%(product_name_lowercase)s">
+
+   <cmf:registerDirectory name="skins" directory="skins" recursive="True" />
+
+</configure>
Index: qPloneSkinDump/trunk/skin_template/uninstallhandlers.py
===================================================================
--- qPloneSkinDump/trunk/skin_template/uninstallhandlers.py	(revision 74)
+++ qPloneSkinDump/trunk/skin_template/uninstallhandlers.py	(revision 74)
@@ -0,0 +1,72 @@
+from zope.dottedname.resolve import resolve
+from zope.component import getUtility, getSiteManager, getMultiAdapter
+
+from plone.portlets.interfaces import IPortletAssignmentMapping, IPortletManager, IPlacelessPortletManager
+from plone.portlets.interfaces import IPortletContext, IPortletDataProvider
+from plone.portlets.interfaces import ILocalPortletAssignmentManager
+from plone.portlets.storage import PortletCategoryMapping, PortletAssignmentMapping
+from plone.app.portlets import portlets
+
+from plone.app.customerize.registration import *
+
+from Products.CMFCore.utils import getToolByName
+from Products.GenericSetup.utils import _getDottedName, _resolveDottedName
+
+from Products.%(product_name)s.config import *
+from Products.%(product_name)s.utils import *
+from Products.%(product_name)s.setuphandlers import setupSiteWidePortlets
+from Products.%(product_name)s.setuphandlers import setupPortletsForContext
+
+import sys
+from logging import getLogger
+logger = getLogger('%(product_name)s:unistall')
+
+_marker = []
+
+
+def uninstallPortlets(context):
+    if context.readDataFile('%(uninstall_profile_marker)s') is None:
+        return
+
+    site = context.getSite()
+
+    components = getSiteManager(site)
+    ms = [r for r in components.registeredUtilities() if r.provided.isOrExtends(IPortletManager)]
+    context_managers = {}
+    for m in ms:
+        if not m.provided.isOrExtends(IPlacelessPortletManager):
+            context_managers[m.name] = getUtility(IPortletManager, name=m.name, context=site)
+
+    managers = {}
+    for m in ms:
+        managers[m.name] = getUtility(IPortletManager, name=m.name, context=site)
+
+    # initiate list for collect blacklist properties
+    pp = getToolByName(site, 'portal_properties')
+    estate_props = getattr(pp, '%(product_name_lowercase)s_properties', None)
+    slots_structure_before_install = estate_props.getProperty('portlets_before_install',"[]")
+    slots_info = eval(slots_structure_before_install)
+
+    for path, info in slots_info:
+        if path == '__site-wide-portlets__':
+            setupSiteWidePortlets(site, info, managers)
+        else:
+            try:
+                obj = site.restrictedTraverse(path)
+            except:
+                e,v,tr = sys.exc_info()
+                logger.info('Debug from importPortlets handler: %%s: %%s (%%s)' , path, str(v), str(e))
+            else:
+                setupPortletsForContext(obj, info, context_managers)
+
+
+def uninstallProperties(context):
+    if context.readDataFile('%(uninstall_profile_marker)s') is None:
+        return
+
+    site = context.getSite()
+    portal_properties = getToolByName(site, 'portal_properties')
+    
+    if '%(product_name_lowercase)s_properties' in portal_properties.objectIds():
+           portal_properties.manage_delObjects(ids=['%(product_name_lowercase)s_properties',])
+
Index: qPloneSkinDump/trunk/skin_template/utils.py
===================================================================
--- qPloneSkinDump/trunk/skin_template/utils.py	(revision 74)
+++ qPloneSkinDump/trunk/skin_template/utils.py	(revision 74)
@@ -0,0 +1,472 @@
+import transaction
+import os, sys, re, string
+from sets import Set
+from StringIO import StringIO
+from time import gmtime, strftime
+from zLOG import LOG, INFO
+from zExceptions import BadRequest
+from App.config import getConfiguration
+from Products.CMFCore.utils import getToolByName
+from Products.CMFCore.DirectoryView import addDirectoryViews
+from Products.%(SKIN_PRODUCT_NAME)s.config import *
+from fixes import fix
+
+######################################################################
+##                      IMPORTING UTILS                             ##
+######################################################################
+osp = os.path
+ALLOWED_IMPORT_POLICY = ["only_new", "backup", "overwrite"]
+INTRO_TO_INSTANCE = "< Started copying object files from Product import directory to Instance one."
+SUMMARY_TO_INSTANCE = "> Finished copying."
+INTRO_TO_ROOT = "< Started import %%s file[s] with '%%s' policy."
+SUMMARY_TO_ROOT = "> Finished importing."
+INTRO_CLEAN = "< Started cleaning Instance import directory."
+SUMMARY_CLEAN = "> Finished cleaning."
+CREXP_INVALID_ID = re.compile('^The id \"(.*?)\" is invalid - it is already in use.$', re.DOTALL|re.IGNORECASE|re.MULTILINE)
+CSS_BASE_IDS_QPSD053 = ['id','expression','enabled','cookable','media','rel','title','rendering']   # supporting qPSD-0.5.3 version
+################    CHECK IMPORTING    ################
+def checkIfImport():
+    """ Return if perform importing, based on checking 
+        *zexp files in <SkinProduct>/import directory.
+    """
+    instance_ipath, product_ipath = getImportedPathes()
+    product_ilist = [i for i in os.listdir(product_ipath) \
+                     if osp.isfile(osp.join(product_ipath,i)) and i.endswith('.zexp')]
+    if product_ilist:
+        return 1
+    return 0
+
+################    IMPORTING TO PLONE'S IMPORT DIR   ################
+def getImportedPathes():
+    """ Return Plone instance and Skin product import pathes."""
+    # Based on instance path, construct import pathes 
+    cfg = getConfiguration()
+    instance_ipath = osp.join(cfg.instancehome, "import")
+    product_ipath = osp.join(PRODUCTS_PATH, PRODUCT_NAME, "import")
+    # Check presence of Product import directory
+    if not osp.isdir(product_ipath):        
+        raise BadRequest, "Skin Product's import directory '%%s' - does not exist or is'nt direcory" %% product_ipath
+    # Check presence of Instance import directory
+    if not osp.isdir(instance_ipath):
+        raise BadRequest, "Instance import directory '%%s' - does not exist or isn't direcory" %% instance_ipath
+    return [instance_ipath, product_ipath]
+
+def copyFile(src_dir, dst_dir, f_name):
+    """ Copy file from src_dir to dst_dir under original name."""
+    try:
+        src_file = open(osp.join(src_dir, f_name),"rb")
+        dst_file = open(osp.join(dst_dir, f_name),"wb")
+        dst_file.write(src_file.read())
+        dst_file.close()
+        src_file.close()
+    except Exception, e:
+        msg = "!!! In copying files from <%%s> dir to <%%s> dir exception occur. Details: %%s." %% (src_dir,dst_dir, str(e))
+        print >> import_out, msg
+        LOG('performImportToPortal',INFO,'copyFile', msg)
+
+def moveToTemp(same_instance_files, instance_ipath, temp_dir_path):
+    """ Move samenamed files from Instanse's dir to temp dir."""
+    os.mkdir(temp_dir_path) # Create temp back_[date] dir
+    try:
+        [copyFile(instance_ipath, temp_dir_path, f_name) for f_name in same_instance_files]
+        [os.remove(osp.join(instance_ipath, f_name)) for f_name in same_instance_files]
+    except Exception, e:
+        msg = "!!! Exception occur during moving files from Instance's dir to temp dir. Detaile:%%s." %% str(e)
+        print >> import_out, msg
+        LOG('performImportToPortal',INFO,'moveToTemp', msg)
+    
+def copyToInstanceImport():
+    """ Perform copying imported files from <SkinProduct>/import dir
+        to Plone's instance import dir.
+    """
+    print >> import_out, INTRO_TO_INSTANCE
+    instance_ipath, product_ipath = getImportedPathes()
+    # Compose temp dir back_[date] dir path in Instance import directory
+    temp_dir_id = "back_%%s" %% strftime("%%Y%%m%%d%%H%%M%%S", gmtime())
+    temp_dir_path = osp.join(instance_ipath, temp_dir_id)
+    # Get *.zexp files from Skin Product's import dir and Plone's instance import dir files
+    product_ilist = [i for i in os.listdir(product_ipath) \
+                     if osp.isfile(osp.join(product_ipath,i)) and i.endswith('.zexp')]
+    instance_ilist = [i for i in os.listdir(instance_ipath) \
+                      if osp.isfile(osp.join(instance_ipath,i)) and i.endswith('.zexp')]
+    # Check for presence samenamed files in Instance and Product import directories.
+    same_instance_files = [f_name for f_name in instance_ilist if f_name in product_ilist]
+    if same_instance_files:
+        moveToTemp(same_instance_files, instance_ipath, temp_dir_path)
+    # Copy all *zexp files from Product's import dir to Instance's import dir
+    [copyFile(product_ipath, instance_ipath, f_name) for f_name in product_ilist]
+    print >> import_out, SUMMARY_TO_INSTANCE
+    return [instance_ipath, product_ipath, temp_dir_path, product_ilist]
+
+################    IMPORTING TO PORTAL   ################
+def importObject(portal, file_name):
+    """ Work around old Zope bug in importing."""
+    try:
+        portal.manage_importObject(file_name)
+    except:
+        portal._p_jar = portal.Destination()._p_jar
+        portal.manage_importObject(file_name)
+
+def makeBackUp(portal, portal_objects, temp_dir_path, obj_id):
+    """ Perfom backup same named portal objects in temp folder."""
+    # Get id of temp folder-object
+    durty_path,temp_id = osp.split(temp_dir_path)
+    if not temp_id:
+        durty_path,temp_id = osp.split(durty_path)
+    # Get temp folder-object
+    if temp_id not in portal_objects:
+        portal.invokeFactory('Large Plone Folder', id=temp_id)
+        print >> import_out, "! Created '%%s' backup directory with same-ids " \
+                             "objects from portal root." %% temp_id
+    temp_dir = getattr(portal, temp_id)
+    # Move object with same id to temp folder-object
+    #get_transaction().commit(1)
+    transaction.savepoint()
+    obj = portal.manage_cutObjects(ids=[obj_id])
+    temp_dir.manage_pasteObjects(obj)
+    print >> import_out, "! '%%s' Object moved from portal root to '%%s' backup directory." %% (obj_id, temp_id)
+
+def performImport(portal, temp_dir_path, file_name):
+    """ Importing an object to portal."""
+    portal_objects = portal.objectIds()
+    try:
+        portal.manage_importObject(file_name)
+    except Exception, e:
+        msg = str(e)
+        is_invalid_id = CREXP_INVALID_ID.match(msg)
+        if is_invalid_id:
+            obj_id = is_invalid_id.group(1)
+            if IMPORT_POLICY == "only_new":
+                msg = "! Object with '%%s' id was not importing because it's already exist " \
+                      "in portal root." %% obj_id
+                print >> import_out, msg
+            elif IMPORT_POLICY == "backup":
+                makeBackUp(portal, portal_objects, temp_dir_path, obj_id)
+                importObject(portal, file_name)
+            elif IMPORT_POLICY == "overwrite":
+                portal.manage_delObjects(ids=[obj_id])
+                importObject(portal, file_name)
+        else:
+            # work around old Zope bug in importing
+            portal._p_jar = portal.Destination()._p_jar
+            portal.manage_importObject(file_name)
+
+def importToPortalRoot(portal, product_file_names, temp_dir_path):
+    """ Import all objects from *zexp files to portal root (based on IMPORT_POLICY)."""
+    if not IMPORT_POLICY in ALLOWED_IMPORT_POLICY:
+        raise Exception("%%s - wrong import policy in '%%s/config.py' file. Must be one of the %%s" \
+                        %% (IMPORT_POLICY, PRODUCT_NAME, ALLOWED_IMPORT_POLICY) )
+    print >> import_out, INTRO_TO_ROOT %% (product_file_names, IMPORT_POLICY)
+    for file_name in product_file_names:
+        try:
+            performImport(portal, temp_dir_path, file_name)
+        except Exception, error:
+            msg = '!!! Under "%%s" policy importing exception occur: %%s.' %% (IMPORT_POLICY, str(error))
+            print >> import_out, msg
+            LOG('performImportToPortal',INFO,'importToPortalRoot', msg)
+    print >> import_out, SUMMARY_TO_ROOT
+
+################    CLEANING PLONE'S IMPORT DIR   ################
+def cleanInstanceImport(instance_ipath, product_file_names, temp_dir_path):
+    """ Cleaning Plone's import dir."""
+    print >> import_out, INTRO_CLEAN
+    # Erase all copied *zexp files from Instance's import dir
+    for f_name in product_file_names:
+        f_path = osp.join(instance_ipath, f_name)
+        if osp.exists(f_path) and osp.isfile(f_path):
+            os.remove(f_path)
+        else:
+            msg = '! "%%s" file was not deleted from "%%s" import directory.' %%\
+                   (f_name, osp.join(instance_ipath))
+            print >> import_out, msg
+            LOG('performImportToPortal',INFO,'cleanInstanceImport', msg)
+    # Move all files from temp back_[date] dir to Instance's import dir
+    if osp.exists(temp_dir_path) and osp.isdir(temp_dir_path):
+        f_names = os.listdir(temp_dir_path)
+        try:
+            [copyFile(temp_dir_path, instance_ipath, f_name) for f_name in f_names]
+            [os.remove(osp.join(temp_dir_path, f_name)) for f_name in f_names]
+            # Erase temp back_[date] dir
+            os.rmdir(temp_dir_path)
+        except Exception, e:
+            msg = "!!! In moving files from temp dir to Instance's import dir exception occur."
+            print >> import_out, msg
+            LOG('performImportToPortal',INFO,'moveFromTempToImport', msg)
+    print >> import_out, SUMMARY_CLEAN
+
+def fixImportingIssues(portal, beforeimporting_objects):
+    ''' Fix defects of importing process: reindexing, other'''
+    afterimporting_objects = portal.objectItems()
+    diff_objects = list(Set(afterimporting_objects)-Set(beforeimporting_objects))
+    for id, ob in diff_objects:
+        if id.startswith('back_'):
+            continue
+        fix(ob)
+
+################    MAIN    ################
+def performImportToPortal(portal):
+    """ Import objects from Skin Product to Portal root."""
+    globals()['import_out'] = StringIO()
+    instance_ipath, product_ipath, temp_dir_path, product_file_names = copyToInstanceImport()
+    if product_file_names:
+        beforeimporting_objects = portal.objectItems()
+        importToPortalRoot(portal, product_file_names, temp_dir_path)
+        fixImportingIssues(portal, beforeimporting_objects)
+        cleanInstanceImport(instance_ipath, product_file_names, temp_dir_path)
+    else:
+        print >> import_out, "!!! Failure importing: there is no file for importing to be found."
+    result = import_out
+    del globals()['import_out']
+    return result.getvalue()
+
+######################################################################
+##              INSTALLATION/UNINSTALLATION UTILS                   ##
+######################################################################
+CSS_REG_PROPS = ['id', 'expression', 'enabled', 'cookable', 'cacheable' \
+                ,'media', 'rel', 'title', 'rendering', 'compression']
+JS_REG_PROPS = ['id', 'expression', 'enabled', 'cookable', 'cacheable' \
+               ,'inline', 'compression']
+
+def installSkin(portal, pp_up, out):
+    # Checking for presense SKIN_NAME in portal_skins directory view or among Skin Names
+    skinsTool = getToolByName(portal, 'portal_skins')
+    # Get unique product_skin_name and remember it in case of differ from SKIN_NAME.
+    product_skin_name = SKIN_NAME
+    skin_names = skinsTool.getSkinSelections()
+    if product_skin_name in skin_names:
+        idx = 0
+        while product_skin_name in skin_names:
+            product_skin_name = SKIN_NAME + str(idx)
+            idx += 1
+        addProperty(pp_up, 'q_actual_skin_name', product_skin_name, 'string', out)
+    # Add directory views
+    layer_skin_name = string.lower(SKIN_NAME)
+    addDirectoryViews(skinsTool, 'skins', GLOBALS)
+    print >> out,  "- added '%%s' directory views to portal_skins." %% layer_skin_name
+    # Get Default skin and remember it for backup on uninstallig
+    default_skin = skinsTool.getDefaultSkin()
+    addProperty(pp_up, 'q_default_skin', default_skin, 'string', out)
+    # Building list of layers for NEW SKIN
+    base_path = skinsTool.getSkinPath(BASE_SKIN_NAME)
+    new_path = map( string.strip, string.split(base_path,',') )
+    if layer_skin_name in new_path :
+        print >> out, "- %%s layer already present in '%%s' skin." %% (layer_skin_name, BASE_SKIN_NAME)
+        # Remove layer_skin_name from current position.
+        del new_path[new_path.index(layer_skin_name)]
+    # Add layer_skin_name just after 'custom' position
+    try: 
+        new_path.insert(new_path.index('custom')+1, layer_skin_name)
+    except ValueError:
+        new_path.append(layer_skin_name)
+    new_path = string.join(new_path, ', ')
+    # Add NEW Skin and set it as dafault
+    skinsTool.addSkinSelection(product_skin_name, new_path, make_default=1)
+    print >> out, "Added %%s skin, bassed on %%s and set as default." %% (product_skin_name, BASE_SKIN_NAME)
+
+def uninstallSkin(skinsTool, actual_skin_name, initial_skin):
+    # Get 'portal_skins' object and list available skin names
+    # And remove SKIN_NAME from available skins, if it present
+    skin_names = skinsTool.getSkinSelections()
+    if actual_skin_name in skin_names :
+        skinsTool.manage_skinLayers(chosen=(actual_skin_name,), del_skin=1, REQUEST=None)
+        skin_names.remove(actual_skin_name)
+    # Remove product skin directory from skins tool 
+    # AND Remove skin-product layer from available skins
+    skin_layer = SKIN_NAME.lower()
+    if skin_layer in skinsTool.objectIds():
+        skinsTool.manage_delObjects(skin_layer)
+    for skin_name in skin_names:
+        path = skinsTool.getSkinPath(skin_name)
+        path = [i.strip() for i in  path.split(',')]
+        if skin_layer in path:
+            path.remove(skin_layer)
+            path = ','.join(path)
+            skinsTool.addSkinSelection(skin_name, path)
+    # If current default skin == actual_skin_name
+    # Set default skin in initial one (if initial skin still exist) 
+    # or in 1st from available skin names list.
+    current_default_skin = skinsTool.getDefaultSkin()
+    if current_default_skin == actual_skin_name:
+        if initial_skin in skin_names :
+            skinsTool.manage_properties(default_skin=initial_skin, REQUEST=None)
+        elif len(skin_names)>0 :
+            skinsTool.manage_properties(default_skin=skin_names[0], REQUEST=None)
+
+def addProperty(p_sheet, p_id, p_value, p_type, out):
+    if p_sheet.hasProperty(p_id):
+        p_sheet._delProperty(p_id)
+    p_sheet._setProperty(p_id, p_value, p_type)
+    print >> out, "... added %%s PropertySheet to %%s." %% (p_id, p_sheet.getId())
+
+def getResourceProperties(obj, prop_list, dflt=''):
+    """ Return list of 2 items list-[property name, property value]."""
+    properties=[]
+    for prop in prop_list:
+        accessor = getattr(obj, 'get%%s' %% prop.capitalize(), None)
+        if accessor:
+            properties.append([prop, accessor() or dflt])
+    return properties
+
+def registerResource(pp_up, portal_res, resRegisterFunction, out \
+                    ,RESOURCE_SKIN_LIST, SKIN_RES_REGDATA, UP_PROPERTY, RES_REG_PROPS):
+    """ Register resources in portal's registry, remember existant settings."""
+    # Get original registered resources
+    portal_res_srings = []
+    for r in portal_res.getResources():
+        portal_res_srings.append(";".join(['%%s::%%s'%%(r[0],str(r[1])) \
+                                for r in getResourceProperties(r, RES_REG_PROPS)]))
+    addProperty(pp_up, UP_PROPERTY, portal_res_srings, 'lines', out)
+    # Tune Resource registry according to new skin needs
+    unexistent = [] # list of default resources, 
+                    # which present in Skin-product, BUT absent in portal
+    portal_res_ids = portal_res.getResourceIds()
+    for res_dict in SKIN_RES_REGDATA:
+        if res_dict['id'] not in portal_res_ids:
+            # It's interesting - Resource Registry allow adding unexistent resource - use this
+            resRegisterFunction(**res_dict)
+            if res_dict['id'] not in RESOURCE_SKIN_LIST:
+                unexistent.append(res_dict['id'])
+        else:
+            pos = portal_res.getResourcePosition(res_dict['id'])
+            portal_res.unregisterResource(res_dict['id'])
+            resRegisterFunction(**res_dict)
+            portal_res.moveResource(res_dict['id'], pos)
+    if unexistent:
+        print >> out, "!!! - BAD: your Resource Regestry have'nt %%s resource(s), which may lead to some problems." %% unexistent
+
+def getVersion(res_list):
+    """Check version of skin product generator."""
+    return (res_list and not '::' in res_list[0] and '0.5') or '0.7'
+
+def uninstallResource(portal_res, original_res_list, RESOURCE_SKIN_LIST, resRegisterFunction):
+    # Prepare Resource Registry data for backup to original state
+    original_res_regestry = {}
+    genVersion = getVersion(original_res_list)
+    for rec in original_res_list:
+        resource = {}
+        if genVersion == '0.7':
+            [resource.update({prop.split('::')[0]:prop.split('::')[1]}) for prop in rec.split(";")]
+        elif genVersion == '0.5':
+            props = rec.split(";")
+            [resource.update({CSS_BASE_IDS_QPSD053[i]:props[i]}) for i in range(len(CSS_BASE_IDS_QPSD053))]
+        original_res_regestry[resource.pop('id')] = resource
+    # Work up actual Resource Registry
+    res_dict = portal_res.getResourcesDict()
+    for res_id in res_dict.keys():
+        # Remove from Resource Registry Skin product's resources
+        if res_id in RESOURCE_SKIN_LIST \
+           and res_id not in original_res_regestry.keys():
+            portal_res.unregisterResource(res_id)
+            continue
+        # Backup 'enabled' property Registry's resourses to it's original state
+        if original_res_regestry.has_key(res_id):
+            act_Enabled_state = res_dict[res_id].getEnabled()
+            orig_Enabled_state = original_res_regestry[res_id]['enabled']
+            if act_Enabled_state != orig_Enabled_state:
+                pos = portal_res.getResourcePosition(res_id)
+                resource = res_dict[res_id]
+                res = original_res_regestry[res_id]
+                portal_res.unregisterResource(res_id)
+                resRegisterFunction(res_id, **res)
+                portal_res.moveResource(res_id, pos)
+
+def customizeSlots(portal, pp_up, out):
+    # Get original Site's column lists
+    orig_left_slots = left_column = list(portal.left_slots)
+    orig_right_slots = right_column = list(portal.right_slots)
+    # Save original Site's LEFT and RIGHT slots
+    addProperty(pp_up, 'q_left_slots', orig_left_slots, 'lines', out)
+    addProperty(pp_up, 'q_right_slots', orig_right_slots, 'lines', out)
+    # blend-with-site - to portal's slots adding only new one from skin-porduct
+    # blend-with-skin - portal slots forming in the following manner: 
+    #                   first adding skin-porduct's slots, than new one from portal
+    # replace - to portal's slots forming only from the skin-porduct's slot list
+    if SLOT_FORMING == "blend_with_skin":
+        left_column, right_column = formSlotsColumn(LEFT_SLOTS, RIGHT_SLOTS, 
+                                                    orig_left_slots, orig_right_slots, MAIN_COLUMN)
+    elif SLOT_FORMING == "blend_with_site":
+        left_column, right_column = formSlotsColumn(orig_left_slots, orig_right_slots,
+                                                    LEFT_SLOTS, RIGHT_SLOTS, MAIN_COLUMN )
+    elif SLOT_FORMING == "replace":
+        left_column, right_column = formSlotsColumn(LEFT_SLOTS, RIGHT_SLOTS, [], [], MAIN_COLUMN)
+    # REPLACE SITE's column slots
+    portal.left_slots = tuple(left_column)
+    portal.right_slots = tuple(right_column)
+    print >> out, "Complited portal slots customization ..."
+
+# main_column ("left" / "right" / "both") mean which of the MAIN column is favour
+def formSlotsColumn(main_left, main_right, slave_left=[], slave_right=[], main_column="both"):
+    result_left = main_left
+    result_right = main_right
+    if main_column == "left":
+    # 1) APPEND to MAIN_LEFT list *new for main_left column* slots from slave_left list 
+    # 2) APPEND to MAIN_RIGHT list *new for both main columns* slots from slave_right
+    # 3) REMOVE slots from MAIN_RIGHT list, which are *doubled* in MAIN_LEFT
+        [result_left.append(slot) for slot in slave_left if slot not in result_left]
+        [result_right.append(slot) for slot in slave_right \
+                                   if slot not in result_right and slot not in result_left]
+        [result_right.remove(slot) for slot in result_left if slot in result_right]
+    elif main_column == "right":
+    # 1) APPEND to MAIN_LEFT list *new for main_right column* slots from slave_left list 
+    # 2) APPEND to MAIN_RIGHT list *new for both main columns* slots from slave_right
+    # 3) REMOVE slots from MAIN_LEFT list, which are *doubled* in MAIN_RIGHT
+        [result_right.append(slot) for slot in slave_right if slot not in result_right]
+        [result_left.append(slot) for slot in slave_left \
+                                  if slot not in result_left and slot not in result_right]
+        [result_left.remove(slot) for slot in result_right if slot in result_left]
+    elif main_column == "both":
+    # 1) APPEND to MAIN_LEFT list *new for both main columns* slots from slave_left list 
+    # 2) APPEND to MAIN_RIGHT list *new for both main columns* slots from slave_right
+        [result_left.append(slot) for slot in slave_left \
+                                  if slot not in result_left and slot not in result_right]
+        [result_right.append(slot) for slot in slave_right \
+                                   if slot not in result_right and slot not in result_left]
+    return [result_left, result_right]
+
+def getProperty(pp, ps, id, default=[]):
+    """ Get property from portal_properties/[property_sheet]"""
+    res = default
+    if ps in pp.objectIds() and pp[ps].hasProperty(id):
+        res = pp[ps].getProperty(id, default)
+    return res
+
+
+###################################
+## OLD INSTALL
+
+def prepareInstallation(portal, pp, out):
+    #uninstallOtherSkinProducts(portal)
+    if not ('uninstall_properties' in pp.objectIds()) :
+        pp.addPropertySheet(id='uninstall_properties', title= 'uninstall_properties')
+        print >> out, "Created 'portal_properties.uninstall_properties' PropertySheet (UP) for backup purpose"
+    return pp.uninstall_properties
+CHECKED_MESSAGE = "The base installation checkings completed."
+
+def uninstallOtherSkinProducts(portal):
+    qi=getToolByName(portal, 'portal_quickinstaller', None)
+    if not qi:
+        raise Exception("Can't work without QuickInstaller tool.")
+    # Get installed products
+    installed_products = [getattr(qi, p_dict['id']) \
+                          for p_dict in qi.listInstalledProducts()
+                          if p_dict['id'] != PRODUCT_NAME]
+    seek_str = "%%s generated product" %% GENERATOR_PRODUCT
+    installed_skin_products = []
+    # Looking for installed skin-products
+    for p in installed_products:
+        transcript = p.getTranscriptAsText()
+        if transcript.find(seek_str) >= 0 :
+            installed_skin_products.append(p.getId())
+    # Uninstall found skin-products
+    if installed_skin_products:
+        qi.uninstallProducts(products=installed_skin_products)
+
+###################################
+## Prepare UNINSTALL
+
+def prepareUninstallSkin(portal, pp_up, out): # ??
+    # Checking for presense SKIN_NAME in portal_skins directory view or among Skin Names
+    skinsTool = getToolByName(portal, 'portal_skins')
+    # Get unique product_skin_name and remember it in case of differ from SKIN_NAME.
+    default_skin = skinsTool.getDefaultSkin()
+    addProperty(pp_up, 'q_default_skin', default_skin, 'string', out)
Index: qPloneSkinDump/trunk/skin_template/utilsPortlets.py
===================================================================
--- qPloneSkinDump/trunk/skin_template/utilsPortlets.py	(revision 74)
+++ qPloneSkinDump/trunk/skin_template/utilsPortlets.py	(revision 74)
@@ -0,0 +1,153 @@
+from zope.interface import providedBy
+from zope.schema import getFields
+from zope.component import getMultiAdapter, getUtility, getSiteManager
+
+from plone.portlets.interfaces import IPortletAssignmentMapping, IPortletManager, IPlacelessPortletManager
+from plone.portlets.interfaces import IPortletContext, IPortletDataProvider
+from plone.portlets.interfaces import ILocalPortletAssignmentManager
+
+from Products.CMFCore.utils import getToolByName
+from Products.GenericSetup.utils import _getDottedName, _resolveDottedName
+
+
+def extractInfoFromAssignment(name, assignment):
+    klass = assignment.__class__
+    a = {'name' : name, 'class' : '%s' % _getDottedName(klass)}
+    data = assignment.data
+    kwargs = {}
+    for i in list(providedBy(data)):
+        if i.isOrExtends(IPortletDataProvider):
+            for field_name, field in getFields(i).items():
+                kwargs[field_name] = field.get(assignment)
+    a['kwargs'] = kwargs
+    return a
+
+def extractSiteWidePortlets(context, managers):
+    """ Extract site-wide portlets 
+        Data structure:
+            '__site-wide-portlets__', [(<manager1_name>, <manager1_info>),
+                                       (<manager2_name>, <manager2_info>),
+                                       (<manager3_name>, <manager3_info>)])
+            <manager_info>:
+                {'category1' : <catmapping1>,
+                 'category2' : <catmapping2>}
+            <catmapping>:
+                {'key1' : <mapping1>,
+                 'key2' : <mapping2>}
+            <mapping>:
+                {'assignment_name1' : <assignment1>,
+                 'assignment_name2' : <assignment2>}
+            <assignment>:
+                {'name'   : 'Assignment',
+                 'class'  : 'dotted.path.to.assignment.class',
+                 'kwargs' : {'parameter1' : 'value1',
+                             'parameter2' : 'value2'}
+    """
+    info = []
+    for manager_name, manager in managers:
+        manager_info = {}
+        for category, catmapping in manager.items():
+            catmapping_info = {}
+            for key, mapping in catmapping.items():
+                mapping_info = {}
+                for name, assignment in mapping.items():
+                    mapping_info[name] = extractInfoFromAssignment(name, assignment)
+                catmapping_info[key] = mapping_info
+            manager_info[category] = catmapping_info
+        info.append((manager_name, manager_info))
+    return info
+
+def extractContextPortletsFromManager(context, manager):
+    """ Extract all contextual portlets from given object and portlet manager, and portlets blacklists
+        Data structure:
+        <manager_info> =
+            {'blacklists'  : [(GROUP_CATEGORY, True),
+                              (CONTENT_TYPE_CATEGORY, False),
+                              (CONTEXT_CATEGORY, None)],
+             'assignments' : [{'name'   : 'Assignment-2',
+                               'class'  : 'dotted.path.to.assignment.class',
+                               'kwargs' : {'parameter1' : 'value1',
+                                          'parameter2' : 'value2'}},
+                              {'name'   : 'Assignment',
+                               'class'  : 'dotted.path.to.assignment.class',
+                               'kwargs' : {'parameter1' : 'value1',
+                                            'parameter2' : 'value2'}]}
+    """
+
+    info = {}
+    info['assignments'] = assignments = []
+    info['blacklists'] = blacklists = []
+
+    # Extract contextual portlets
+    mapping = getMultiAdapter((context, manager), IPortletAssignmentMapping, context=context)
+    for name, assignment in mapping.items():
+        assignments.append(extractInfoFromAssignment(name, assignment))
+
+    # Extract blacklists for given object and manager
+    localassignmentmanager = getMultiAdapter((context, manager), ILocalPortletAssignmentManager)
+    blacklist = localassignmentmanager._getBlacklist()
+    if blacklist is not None:
+        for category, key in blacklist.items():
+            blacklists.append((category, key))
+
+    return info
+
+def extractPortletsFromContext(context, slot_structure, typesToShow, managers):
+    """ Extract portlets for given object assigned through all portlet managers.
+        Data structure:
+            ('unique/path/to/context', [(<manager1_name>, <manager1_info>),
+                                        (<manager2_name>, <manager2_info>),
+                                        (<manager3_name>, <manager3_info>)])
+    """
+
+
+    info = []
+    key = '/'.join(context.getPhysicalPath()[2:])
+
+    for name, manager in managers:
+        info.append((name, extractContextPortletsFromManager(context, manager)))
+
+    slot_structure.append((key, info))
+
+    return slot_structure
+
+def dumpAllPortlets(context, slot_structure, typesToShow, managers):
+    extractPortletsFromContext(context, slot_structure, typesToShow, managers)
+    if getattr(context.aq_base, 'isPrincipiaFolderish', 0):
+        for id, obj in context.contentItems():
+            if obj.portal_type in typesToShow:
+                dumpAllPortlets(obj, slot_structure, typesToShow, managers)
+
+    return slot_structure
+
+def dumpPortlets(context, dump_policy, dump_portlets_selection):
+    """ Extract portlets from given set of objects and site-wide portlets too.
+        Data structure:
+            SLOT_STRUCTURE =
+                [(), (), ()]
+    """
+
+    portal = getToolByName(context, 'portal_url').getPortalObject()
+    portal_state = getMultiAdapter((portal, context.REQUEST), name=u'plone_portal_state')
+    typesToShow = portal_state.friendly_types()
+
+    components = getSiteManager(context)
+    managers = [r for r in components.registeredUtilities() if r.provided.isOrExtends(IPortletManager)]
+    context_managers = [(m.name, getUtility(IPortletManager, name=m.name, context=context)) for m in managers
+                                                                               if not IPlacelessPortletManager.providedBy(m.component)]
+    managers = [(m.name, getUtility(IPortletManager, name=m.name, context=context)) for m in managers]
+
+    slot_structure = []
+    if dump_policy == 'root':
+        extractPortletsFromContext(portal, slot_structure, typesToShow, context_managers)
+    elif dump_policy == 'all':
+        dumpAllPortlets(portal, slot_structure, typesToShow, context_managers)
+    elif dump_policy == 'selection':
+        for ppath in dump_portlets_selection:
+            obj = portal.restrictedTraverse(ppath)
+            extractPortletsFromContext(obj, slot_structure, typesToShow, context_managers)
+
+    slot_structure.append(('__site-wide-portlets__', extractSiteWidePortlets(portal, managers)))
+
+    return slot_structure
+
Index: qPloneSkinDump/trunk/skins/qploneskindump/qploneskindump_config.cpt
===================================================================
--- qPloneSkinDump/trunk/skins/qploneskindump/qploneskindump_config.cpt	(revision 72)
+++ qPloneSkinDump/trunk/skins/qploneskindump/qploneskindump_config.cpt	(revision 74)
@@ -9,83 +9,133 @@
     <div metal:define-macro="main"
          tal:define="errors options/state/getErrors | nothing;">
-        <h1 class="QSDFirstHeading">
-            <img tal:replace="structure here/product_icon.gif" />
-            <span tal:replace="here/title_or_id">Title or id</span>
-        </h1>
-
-        <div metal:use-macro="here/document_actions/macros/document_actions">
-            Document actions (print, sendto etc)
+
+        <div metal:use-macro="here/global_statusmessage/macros/portal_message">
+            Portal status message
         </div>
+
+        <h1 class="documentFirstHeading"
+            i18n:translate="heading_addremove_products">Skin Dump</h1>
 
         <a href=""
            class="link-parent"
-           i18n:translate="label_up_to_product_page"
-           tal:define="parent_url python:here.navigationParent(here, template.getId())"
-           tal:condition="parent_url"
-           tal:attributes="href parent_url">
-            Up to Product page
+           tal:attributes="href string: $portal_url/plone_control_panel"
+           i18n:translate="label_up_to_plone_setup">
+            Up to Site Setup
         </a>
 
-        <h2 i18n:translate="heading_portalactions_lists">
-            qPloneSkinDump input FORM
-        </h2>
+        <p class="documentDescription"
+            i18n:translate="description_addremove_products">
+            This is a form for dumping your zmi skin to filesystem based product.
+        </p>
+
+        <p class="discreet" i18n:translate="description_product_location">
+            Navigate through all form tabs to set needed configuration for dump.
+        </p>
+
         <form name="edit_form"
               action="href"
               method="post"
+              class="enableFormTabbing"
               enctype="multipart/form-data"
               tal:attributes="action string:$here_url/$template_id">
-            <fieldset tal:define="error_zmiSN python:errors.get('ZMISkinName');
-                                  error_zmiBSN python:errors.get('ZMIBaseSkinName')">
-                <legend>
-                  <label style="font-size: 110%" i18n:translate="legend_ZMI"> ZMI:</label>
-                </legend>
-                <div class="ZMISkinName"
-                     tal:attributes="class python: test(error_zmiSN, 'ZMISkinName error', 'ZMISkinName');">
-                <!-- folder in ZMI .../portal_skins, from which will be copyed content -->
-                    <label class="ZMISkinName_title"
-                           i18n:translate="label_ZMISkinName">Source ZMI skin folder</label>
+
+            <fieldset id="fieldset-product"
+                      tal:define="error_fsSkinDir python:errors.get('FSSkinDirectory');
+                                  error_fsProdName python:errors.get('FSProductName');
+                                  error_fsDestinationDir python:errors.get('FSDestinationDirectory');">
+                <legend id="fieldsetlegend-product">
+                  <label style="font-size: 110%" i18n:translate="label_product">Product</label>
+                </legend>
+                <p />
+                <div class="FSProductName"
+                     tal:attributes="class python: test(error_fsProdName, 'FSProductName error', 'FSProductName');">
+                    <label class="FSProductName_title"
+                          i18n:translate="label_FSProductName">Product name</label>
                     <span class="fieldRequired"
                            title="Required"
                            i18n:translate="label_required"
-                           i18n:attributes="title title_required;">
-                                (Required)
-                    </span>
-                    <div i18n:translate="help_ZMISkinName"
-                         class="formHelp">
-                        Select folder from portal_skins, which content should by copyed to FS product.
-                    </div>
-                    <div tal:condition="error_zmiSN"
-                         tal:content="error_zmiSN" i18n:translate="">Validation Error</div>
-
-                    <select class="ZMISkinName_input" id="ZMISkinName" 
-                            size="1" name="ZMISkinName"
-                            tal:define="value request/ZMISkinName|string:custom;
-                                        p_skins_ids python:portal.portal_skins.objectIds(spec='Folder')"
-                            tal:attributes="value value;
-                                            tabindex tabindex/next;">
-                        <option selected=""
-                                value="#"
-                                tal:repeat="ps_folder p_skins_ids"
-                                tal:attributes="value nocall:ps_folder;
-                                                selected python:test(ps_folder==value, 'selected', None);"
-                                tal:content="ps_folder"/>
-                        
-                    </select>
-                </div>
-                <p/>
+                           i18n:attributes="title title_required;">(Required)</span>
+                    <div i18n:translate="help_FSProductName"
+                         class="formHelp">
+                        Name for dumped product. This name should be unique in Destination directory. The name must begin with alphabetical character, following with an alphanumeric combination, also underscore accepts, but not on boundaries.
+                    </div>
+                    <div tal:condition="error_fsProdName"
+                         tal:content="error_fsProdName" i18n:translate="">Validation Error</div>
+
+                    <input class="FSProductName_input"
+                           type="text"
+                           name="FSProductName"
+                           value="qPloneSkinTemplate"
+                           size="50"
+                           tal:attributes="value request/FSProductName|nothing" />
+                </div>
+                <p />
+                <div class="FSSkinDirectory"
+                     tal:attributes="class python: test(error_fsSkinDir, 'FSSkinDirectory error', 'FSSkinDirectory');">
+                    <label class="FSSkinDirectory_title"
+                          i18n:translate="label_FSSkinDirectory">Skin name</label>
+                    <span class="fieldRequired"
+                           title="Required"
+                           i18n:translate="label_required"
+                           i18n:attributes="title title_required;">(Required)</span>
+                    <div i18n:translate="help_FSSkinDirectory"
+                         class="formHelp">
+                         Skin name in dumped product. The name must begin with alphabetical character, following with an alphanumeric combination, also underscore accepts, but not on boundaries.
+                    </div>
+                    <div tal:condition="error_fsSkinDir"
+                         tal:content="error_fsSkinDir" i18n:translate="">Validation Error</div>
+
+                    <input class="FSSkinDirectory_input"
+                           type="text"
+                           name="FSSkinDirectory"
+                           value=""
+                           size="50"
+                           tal:attributes="value request/FSSkinDirectory|nothing" />
+                </div>
+                <p />
+                <div class="FSDestinationDirectory"
+                     tal:define="destinationDir python:modules['Products.qPloneSkinDump.qPloneSkinDump'].getProductsPath();"
+                     tal:attributes="class python: test(error_fsDestinationDir, 'FSDestinationDirectory error', 'FSDestinationDirectory');">
+                    <label class="FSDestinationDirectory_title"
+                          i18n:translate="label_FSDestinationDirectory">Destination directory</label>
+                    <span class="fieldRequired"
+                           title="Required"
+                           i18n:translate="label_required"
+                           i18n:attributes="title title_required;">(Required)</span>
+                    <div i18n:translate="help_FSDestinationDirectory"
+                         class="formHelp">
+                         Absolute path to directory, where SkinProduct will be created.
+                    </div>
+                    <div tal:condition="error_fsDestinationDir"
+                         tal:content="error_fsDestinationDir" i18n:translate="">Validation Error</div>
+
+                    <input class="FSDestinationDirectory_input"
+                           type="text"
+                           name="FSDestinationDirectory"
+                           value=""
+                           size="50"
+                           tal:attributes="value request/FSDestinationDirectory|destinationDir" />
+                </div>
+            </fieldset>
+
+            <fieldset id="fieldset-zmi"
+                      tal:define="error_zmiSN python:errors.get('ZMISkinName');
+                                  error_zmiBSN python:errors.get('ZMIBaseSkinName')">
+                <legend id="fieldsetlegend-zmi">
+                  <label style="font-size: 110%" i18n:translate="legend_ZMI">Skin</label>
+                </legend>
+                <p />
                 <div class="ZMIBaseSkinName"
                      tal:attributes="class python: test(error_zmiBSN, 'ZMIBaseSkinName error', 'ZMIBaseSkinName');">
                 <!-- base for building layers list -->
                     <label class="ZMIBaseSkinName_title"
-                           i18n:translate="label_ZMIBaseSkinName">ZMI base skin name</label>
+                           i18n:translate="label_ZMIBaseSkinName">Skin selection</label>
                     <span class="fieldRequired"
                            title="Required"
                            i18n:translate="label_required"
-                           i18n:attributes="title title_required;">
-                                (Required)
-                    </span>
+                           i18n:attributes="title title_required;">(Required)</span>
                     <div i18n:translate="help_ZMIBaseSkinName"
                          class="formHelp">
-                        Select Skin name, which layers list will be used for creating new skin.
+                        Select skin selection from portal_skins, which layers list will be used for creating new skin.
                     </div>
                     <div tal:condition="error_zmiBSN"
@@ -94,6 +144,5 @@
                     <select tal:define="value request/ZMIBaseSkinName|string:Plone Tableless;
                                         skin_names portal/portal_skins/getSkinSelections"
-                            tal:attributes="value value;
-                                            name string:ZMIBaseSkinName;
+                            tal:attributes="name string:ZMIBaseSkinName;
                                             id string:ZMIBaseSkinName;
                                             size string:1;
@@ -105,214 +154,153 @@
                                                 selected python:test(skin_name==value, 'selected', None);"
                                 tal:content="skin_name"/>
-                        
                     </select>
                 </div>
-                <p/>
+                <p />
+                <div class="ZMISkinName"
+                     tal:attributes="class python: test(error_zmiSN, 'ZMISkinName error', 'ZMISkinName');">
+                <!-- folder in ZMI .../portal_skins, from which will be copyed content -->
+                    <label class="ZMISkinName_title"
+                           i18n:translate="label_ZMISkinName">Skin folders</label>
+                    <span class="fieldRequired"
+                           title="Required"
+                           i18n:translate="label_required"
+                           i18n:attributes="title title_required;">(Required)</span>
+                    <div i18n:translate="help_ZMISkinName"
+                         class="formHelp">
+                        Select folders from portal_skins, which should be dumped to FS product's skins folder.
+                    </div>
+                    <div tal:condition="error_zmiSN"
+                         tal:content="error_zmiSN" i18n:translate="">Validation Error</div>
+
+                    <select class="ZMISkinName_input" id="ZMISkinName" 
+                            size="5" name="ZMISkinName" multiple="1"
+                            tal:define="value request/ZMISkinName|string:custom;
+                                        p_skins_ids python:portal.portal_skins.objectIds(spec='Folder')"
+                            tal:attributes="tabindex tabindex/next;">
+                        <option selected=""
+                                value="#"
+                                tal:repeat="ps_folder p_skins_ids"
+                                tal:attributes="value nocall:ps_folder;
+                                                selected python:test(ps_folder==value, 'selected', None);"
+                                tal:content="ps_folder"/>
+                    </select>
+                </div>
+                <p />
                 <div class="EraseFromSkin">
                 <!-- erase content of folder in ZMI .../portal_skins after copying -->
-                    <div i18n:translate="help_Erase"
-                         class="formHelp">
-                        Select for erase content of skin's source folder.
-                    </div>
-
                     <input class="EraseFromSkin_input"
                            type="checkbox"
                            name="EraseFromSkin"
+                           id="EraseFromSkin"
                            value="0"
                            tal:attributes="checked python:test(request.has_key('EraseFromSkin'), 'checked', nothing)"
                            />
-                    <label class="EraseFromSkin_title"
-                          i18n:translate="label_Erace">Erace </label>
-                </div>
-            </fieldset>
-
-            <fieldset tal:define="error_fsSkinDir python:errors.get('FSSkinDirectory');
-                                  error_fsProdName python:errors.get('FSProductName')">
-                <legend>
-                  <label style="font-size: 110%" i18n:translate="label_FS"> File system:</label>
-                </legend>
-                <div class="FSSkinDirectory"
-                     tal:attributes="class python: test(error_fsSkinDir, 'FSSkinDirectory error', 'FSSkinDirectory');">
-                    <label class="FSSkinDirectory_title"
-                          i18n:translate="label_FSSkinDirectory">Skin's name for new prodct</label>
-                    <span class="fieldRequired"
-                           title="Required"
-                           i18n:translate="label_required"
-                           i18n:attributes="title title_required;">
-                                (Required)
-                    </span>
-                    <div i18n:translate="help_FSSkinDirectory"
-                         class="formHelp">
-                         Input skin's name for new prodct. <br/>
-                         This name in lower case will be used as skin's folder name and as layer name too.<br/>
-                         The name must begin with alphabetical character, following with an alphanumeric combination, also underscore accepts, but not on boundaries.<br/>
-                    </div>
-                    <div tal:condition="error_fsSkinDir"
-                         tal:content="error_fsSkinDir" i18n:translate="">Validation Error</div>
-
-                    <input class="FSSkinDirectory_input"
-                           type="text"
-                           name="FSSkinDirectory"
-                           value=""
-                           size="50"
-                           tal:attributes="value request/FSSkinDirectory|nothing" />
-                </div>
-                <p/>
-                <div class="FSProductName"
-                     tal:attributes="class python: test(error_fsProdName, 'FSProductName error', 'FSProductName');">
-                    <label class="FSProductName_title"
-                          i18n:translate="label_FSProductName">Product name</label>
-                    <span class="fieldRequired"
-                           title="Required"
-                           i18n:translate="label_required"
-                           i18n:attributes="title title_required;">
-                                (Required)
-                    </span>
-                    <div i18n:translate="help_FSProductName"
-                         class="formHelp">
-                         Input name of new product.  <br/>
-                         This name can't be identical with other, presenting in your Products directory of Plone's instance. <br/>
-                         The name must begin with alphabetical character, following with an alphanumeric combination, also underscore accepts, but not on boundaries.
-                    </div>
-                    <div tal:condition="error_fsProdName"
-                         tal:content="error_fsProdName" i18n:translate="">Validation Error</div>
-
-                    <input class="FSProductName_input"
-                           type="text"
-                           name="FSProductName"
-                           value="qPloneSkinTemplate"
-                           size="50"
-                           tal:attributes="value request/FSProductName|nothing" />
-                </div>
-            </fieldset>
-
-            <fieldset>
-                <legend class="DoesCustomizeSlots">
+                    <label class="EraseFromSkin_title" for="EraseFromSkin"
+                          i18n:translate="label_Erase">Erase folders from portal_skins after dump</label>
+                </div>
+            </fieldset>
+
+            <fieldset id="fieldset-portlets">
+                <legend id="fieldsetlegend-portlets" class="DoesCustomizeSlots">
+                    <label style="font-size: 110%" i18n:translate="label_portlets">Portlets</label>
+                </legend>
+                <p />
+                <div class="customize-portlets">
                     <input class="noborder"
                            type="checkbox"
-                           name="DoesCustomizeSlots"
+                           name="dump_portlets"
                            id="DoesCustomizeSlots"
-                           value="DOCustomizeSlots"
-                           tal:attributes="checked python:test(request.has_key('DoesCustomizeSlots'),'checked', nothing)"/>
+                           value="0"
+                           tal:attributes="checked request/dump_portlets|nothing" />
                     <label for="DoesCustomizeSlots"
-                           style="font-size: 110%"
-                           i18n:translate="label_Slots">Customize portal slots in new product</label>
-                </legend>
-                <div class="formHelp"
-                     i18n:translate="help_DoesCustomizeSlots">
-                  Customization portal slots in New Skin Product.
-                </div>
-
+                           i18n:translate="label_dump_portlets">Dump Portlets</label>
+                </div>
                 <p/>
                 <div class="SlotsCustomizing">
                     <label class="SlotsCustomizing_title"
-                          i18n:translate="label_SlotsCustomizing">Portal slots</label>
+                          i18n:translate="label_dump_policy">Dump Policy</label>
 
                     <div i18n:translate="help_SlotsCustomizing"
                          class="formHelp">
-                         BE VERY ACCURACY!  
-                         Leave in the left and right slot lists only those portlets, which relate <br/>
-                         to your skin product and either bring with new product or is standard for Plone.
-                    </div>
-                    <div class="LeftSlotsCustomizing_title">
-                        <label class="LeftSlotsCustomizing_title"
-                              i18n:translate="label_LeftsSlotCustomizing">Left portal slots customizing</label>
-                        <textarea class="LeftSlotsCustomizing_lines"
-                               rows="6"
-                               cols="35"
-                               name="left_slots:lines"
-                               value=""
-                               tal:define="value python:'\n'.join(request.get('left_slots', portal.left_slots))"
-                               tal:attributes="value value"
-                               tal:content="value" ></textarea>
-                    </div>
-                    <p/>
-                    <div class="RightSlotsCustomizing_title">
-                        <label class="RightSlotsCustomizing_title"
-                              i18n:translate="label_RightSlotsCustomizing">Right portal slots customizing</label>
-                        <textarea class="RightSlotsCustomizing_lines"
-                               rows="6"
-                               cols="35"
-                               name="right_slots:lines"
-                               value=""
-                               tal:define="value python:'\n'.join(request.get('right_slots', portal.right_slots))"
-                               tal:attributes="value value" 
-                               tal:content="value"></textarea>
-                    </div>
-
-                </div>
-                <p/>
-                <div class="ColumnSlotsForming"
-                     tal:define="formers python:modules['Products.qPloneSkinDump.qPloneSkinDump'].getSlotsFormingList();
-                                 value request/slot_forming|formers/default"> 
-                    <label i18n:translate="label_ColumnSlotsForming">Slot's list forming</label>
-                    <div i18n:translate="help_ColumnSlotsForming"
-                         class="formHelp">
-                         Choose procedure of forming slots lists.<br/>
-                         Blend with skin - to SKIN PRODUCT's slots list added unknown slots from SITE.<br/>
-                         Blend with site - to SITE's slots list added unknown slots from SKIN PRODUCT.<br/>
-                         Replace - in left and right site's columns placed ONLY SKIN PRODUCT's slots.
-                    </div>
-                    <tal:loop tal:omit-tag=""
-                              tal:repeat="former formers/data">
-                        <div>
-                            <input type="radio"
-                                   name="slot_forming"
-                                   value="#"
-                                   tal:attributes="value python:former[0];
-                                                   checked python:test(former[0]==value,'checked', nothing)" />
-                            <label class="ColumnSlotsForming_title"
-                                   i18n:translate=""
-                                   tal:content="python:former[1]"></label>
-                        </div>
-                    </tal:loop>
-                </div>
-                <p/>
-                <div class="FavourColumn"
-                     tal:define="favour_columns python:modules['Products.qPloneSkinDump.qPloneSkinDump'].getMainColumnList();
-                                 value request/main_column|favour_columns/default">
-                    <label  i18n:translate="label_FavourColumn">Main column</label>
-                    <div i18n:translate="help_FavourColumn"
-                         class="formHelp">
-                         Choose favour column for slots forming procedure. IMPORTANT only for 'Blend with...' formers.<br/>
-                         Left/Right - if find same slots in left and right columns - than slots move accordingly to left/right column.<br/>
-                         Both - if find same slots in left and right columns - than slots positionings as in Master's slots lists 
-                         (from SKIN PRODUCT's slots for 'Blend with skin' procedure and SITE's slots for 'Blend with site').
-                    </div>
-                    <tal:loop tal:omit-tag=""
-                              tal:repeat="favour favour_columns/data">
-                        <div>
-                            <input type="radio"
-                                   name="main_column"
-                                   value="#"
-                                   tal:attributes="value python:favour[0];
-                                                   checked python:test(favour[0]==value,'checked', nothing)" />
-                            <label class="FavourColumn_title"
-                                   i18n:translate=""
-                                   tal:content="python:favour[1]"></label>
-                        </div>
-                    </tal:loop>
-                </div>
-
-            </fieldset>
-
-            <fieldset tal:define="exp_data python:modules['Products.qPloneSkinDump.qPloneSkinDump'].getExportingData(here);">
-                <legend class="DoesExportObjects">
+
+                    </div>
+
                     <input class="noborder"
+                           type="radio"
+                           name="dump_policy"
+                           value="root"
+                           id="root_dump_policy"
+                           onclick="javascript:document.getElementById('selection_widget').style.display='none';"
+                           tal:attributes="checked python:request.get('dump_policy', 'root') == 'root';" />
+                    <label for="root_dump_policy"
+                           i18n:translate="label_root_dump_policy">
+                        Dump portlets only for portal root
+                    </label>
+                    <br />
+
+                    <input class="noborder"
+                           type="radio"
+                           name="dump_policy"
+                           value="all"
+                           id="all_dump_policy"
+                           onclick="javascript:document.getElementById('selection_widget').style.display='none';"
+                           tal:attributes="checked python:request.get('dump_policy', 'root') == 'all';" />
+                    <label for="all_dump_policy"
+                           i18n:translate="label_all_dump_policy">
+                        Dump portlets for the whole site content
+                    </label>
+                    <br />
+
+                    <input class="noborder"
+                           type="radio"
+                           name="dump_policy"
+                           value="selection"
+                           id="selection_dump_policy"
+                           onclick="javascript:document.getElementById('selection_widget').style.display='';"
+                           tal:attributes="checked python:request.get('dump_policy', 'root') == 'selection';" />
+                    <label for="selection_dump_policy"
+                           i18n:translate="label_selection_dump_policy">
+                        Dump portlets only for selected content objects
+                    </label>
+                    <div id="selection_widget" style="display:none;"
+                         tal:define="friendly_types here/@@plone_portal_state/friendly_types;
+                                     options python:here.portal_catalog(portal_types=friendly_types)">
+                        <select name="dump_objects" multiple="1" size="7">
+                            <option value="root_path"
+                                    tal:content="string:[portal root]"
+                                    tal:attributes="value string:" />
+                            <tal:options repeat="option options">
+                            <option value="object_path"
+                                    tal:define="ppath python:'/'.join(option.getPath().split('/')[2:])"
+                                    tal:content="ppath"
+                                    tal:attributes="value ppath" />
+                            </tal:options>
+                        </select>
+                    </div>
+                </div>
+            </fieldset>
+
+            <fieldset id="fieldset-zexp"
+                      tal:define="exp_data python:modules['Products.qPloneSkinDump.qPloneSkinDump'].getExportingData(here);">
+                <legend id="fieldsetlegend-zexp" class="DoesExportObjects">
+                    <label style="font-size: 110%" i18n:translate="label_portlets">Objects Export</label>
+                </legend>
+                <p />
+                <div class="objects-export">
+                    <input class="noborder"
                            type="checkbox"
                            name="DoesExportObjects"
-                           id="DoesExportObjects" 
+                           id="DoesExportObjects"
                            value="DoesExportObjects"
                            tal:attributes="checked python:test(request.has_key('DoesExportObjects'), 'checked', nothing)" />
                     <label for="DoesExportObjects"
                            style="font-size: 110%"
-                           i18n:translate="label_DoesExportObjects">Exporting objects from portal root</label>
-                </legend>
-                <div class="formHelp"
-                     i18n:translate="help_DoesExportObjects">
-                  Selected below objects will be exported to New Skin Product. Then on installation generated Skin Product
-                  they will be imported to portal root, based on choosed policy.
-                </div>
-
+                           i18n:translate="label_DoesExportObjects">Dump Objects</label>
+                    <div class="formHelp"
+                         i18n:translate="help_DoesExportObjects">
+                      Selected below objects will be exported to New Skin Product. Then on installation generated Skin Product
+                      they will be imported to portal root, based on choosed policy.
+                    </div>
+                </div>
                 <p/>
                 <div class="ImportPolicy"
@@ -369,12 +357,14 @@
             </fieldset>
 
-            <fieldset tal:define="isFirst python:not request.get('dump_registries', None);
-                                  checked_css python:test(isFirst, 'checked', test(request.has_key('DumpCSSRegistry'), 'checked', nothing));
-                                  checked_js python:test(isFirst, 'checked', test(request.has_key('DumpJSRegistry'), 'checked', nothing));">
-                <legend class="DoesExportResources">
+            <fieldset id="fieldset-resources"
+                      tal:define="isFirst python:not request.get('dump_registries', None);
+                                  checked_css python:test(isFirst, 'checked', test(request.has_key('DumpCSSRegistry'), 'checked', None));
+                                  checked_js python:test(isFirst, 'checked', test(request.has_key('DumpJSRegistry'), 'checked', None));">
+                <legend id="fieldsetlegend-resources" class="DoesExportResources">
                     <label for="DoesExportResources"
                            style="font-size: 110%"
-                           i18n:translate="label_DoesExportResources">Exporting portal resources</label>
-                </legend>
+                           i18n:translate="label_DoesExportResources">Resources</label>
+                </legend>
+                <p />
                 <div class="formHelp"
                      i18n:translate="help_DoesExportResources">
@@ -391,8 +381,9 @@
                            type="checkbox"
                            name="DumpCSSRegistry"
+                           id="DumpCSSRegistry"
                            value="0"
                            tal:attributes="checked checked_css"
                            />
-                    <label class="DumpCSSRegistry_title"
+                    <label class="DumpCSSRegistry_title" for="DumpCSSRegistry"
                           i18n:translate="label_DumpCSSRegistry">Dump portal_css registry.</label>
                 </div>
@@ -403,11 +394,38 @@
                            type="checkbox"
                            name="DumpJSRegistry"
+                           id="DumpJSRegistry"
                            value="0"
                            tal:attributes="checked checked_js"
                            />
-                    <label class="DumpJSRegistry_title"
+                    <label class="DumpJSRegistry_title" for="DumpJSRegistry"
                           i18n:translate="label_DumpJSRegistry">Dump portal_javascripts registry.</label>
                 </div>
                 <p/>
+            </fieldset>
+
+            <!-- dump views -->
+            <fieldset id="fieldset-views"
+                      tal:define="error_zmiSN python:errors.get('ZMISkinName');
+                                  error_zmiBSN python:errors.get('ZMIBaseSkinName')">
+                <legend id="fieldsetlegend-views">
+                  <label style="font-size: 110%" i18n:translate="legend_viewlets">Views</label>
+                </legend>
+                <p />
+                <div class="dump-viewlets-field">
+                    <div i18n:translate="help_dumpviewlets"
+                         class="formHelp">
+                        Check this field for dumping all customized objects in portal_view_customization tool.
+                    </div>
+
+                    <input class="dumpviewlets-input"
+                           type="checkbox"
+                           name="dump_viewlets"
+                           id="dump_viewlets"
+                           value="1"
+                           tal:attributes="checked python:test(request.has_key('dump_viewlets'), 'checked', nothing)"
+                           />
+                    <label class="dumpviewlets-title" for="dump_viewlets"
+                          i18n:translate="label_dumpviewlets">Dump views, viewlets and portlets</label>
+                </div>
             </fieldset>
 
Index: qPloneSkinDump/trunk/skins/qploneskindump/qploneskindump_config_script.cpy
===================================================================
--- qPloneSkinDump/trunk/skins/qploneskindump/qploneskindump_config_script.cpy	(revision 72)
+++ qPloneSkinDump/trunk/skins/qploneskindump/qploneskindump_config_script.cpy	(revision 74)
@@ -12,11 +12,13 @@
 #from Products.CMFCore.utils import getToolByName
 from Products.qPloneSkinDump.qPloneSkinDump import createProduct
+from Products.CMFPlone import PloneMessageFactory as _
 
 REQUEST = context.REQUEST
 # ZMI data
-zmi_skin_name = REQUEST.get('ZMISkinName')
+zmi_skin_names = REQUEST.get('ZMISkinName')
 zmi_base_skin_name = REQUEST.get('ZMIBaseSkinName')
 
 # File system data
+fs_dest_directory = REQUEST.get("FSDestinationDirectory")
 fs_skin_directory = REQUEST.get('FSSkinDirectory')
 fs_product_name = REQUEST.get('FSProductName')
@@ -37,4 +39,9 @@
         right_slots = [i for i in right_slots if i]
 
+# Exporting portlets
+dump_portlets = REQUEST.get('dump_portlets', 0)
+dump_policy = REQUEST.get('dump_policy', 'root')
+dump_portlets_selection = REQUEST.get('dump_objects', [])
+
 # Exporting objects
 import_policy = exporting_objects = None
@@ -50,7 +57,10 @@
 dump_JS = REQUEST.get('DumpJSRegistry')
 
+dump_custom_views = REQUEST.get('dump_viewlets', None)
+
 # create Product
-result = createProduct(context, zmi_skin_name=zmi_skin_name,\
+result = createProduct(context, zmi_skin_names=zmi_skin_names,\
               zmi_base_skin_name=zmi_base_skin_name,\
+              fs_dest_directory=fs_dest_directory, \
               fs_skin_directory=fs_skin_directory,\
               fs_product_name=fs_product_name,\
@@ -65,9 +75,14 @@
               exporting_objects=exporting_objects, \
               dump_CSS=dump_CSS, \
-              dump_JS=dump_JS )
+              dump_JS=dump_JS, \
+              dump_portlets=dump_portlets, \
+              dump_policy=dump_policy, \
+              dump_portlets_selection=dump_portlets_selection, \
+              dump_custom_views=dump_custom_views )
 
-portal_status_message='"%s" Product successfully created.' % fs_product_name
+portal_status_message = u'"%s" Product successfully created.' % fs_product_name
 if result:
-    portal_status_message = portal_status_message + "Failed exporting objects: %s." % str(fail)
+    portal_status_message = portal_status_message + u"Failed exporting objects: %s." % str(result)
 
-return state.set(portal_status_message=portal_status_message)
+context.plone_utils.addPortalMessage(_(portal_status_message))
+return state
Index: qPloneSkinDump/trunk/skins/qploneskindump/validate_qploneskindump_form.vpy
===================================================================
--- qPloneSkinDump/trunk/skins/qploneskindump/validate_qploneskindump_form.vpy	(revision 72)
+++ qPloneSkinDump/trunk/skins/qploneskindump/validate_qploneskindump_form.vpy	(revision 74)
@@ -11,5 +11,7 @@
 
 from Products.CMFCore.utils import getToolByName
-from Products.qPloneSkinDump.qPloneSkinDump import isValidProductName, isValidDirName
+from Products.qPloneSkinDump.qPloneSkinDump import isValidProductName
+from Products.qPloneSkinDump.qPloneSkinDump import isValidDirName
+from Products.qPloneSkinDump.qPloneSkinDump import isValidDestinationDir
 errors = state.getErrors()
 
@@ -22,5 +24,5 @@
 
 # Check REQUIRED fields
-REQUIRED_FIELDS = ['ZMISkinName', 'ZMIBaseSkinName', 'FSProductName', 'FSSkinDirectory']
+REQUIRED_FIELDS = ['ZMISkinName', 'ZMIBaseSkinName', 'FSProductName', 'FSSkinDirectory', 'FSDestinationDirectory']
 theform = {}
 for f in REQUIRED_FIELDS:
@@ -30,6 +32,10 @@
     theform[f]=fdata
 
-if not( theform['FSProductName'] and isValidProductName(theform['FSProductName']) ):
-    update_errors(errors, {'FSProductName': u"Not valid Product name - read help attentively."})
+if not( theform["FSDestinationDirectory"] and isValidDestinationDir(theform["FSDestinationDirectory"]) ):
+    update_errors(errors, {"FSDestinationDirectory": u"Not valid Destination directory"})
+
+if not( theform['FSProductName'] and theform["FSDestinationDirectory"] \
+        and isValidProductName(theform['FSProductName'], theform["FSDestinationDirectory"]) ):
+    update_errors(errors, {'FSProductName': u"Not valid Product name or problem with destination directory - read help attentively."})
 
 if not( theform['FSSkinDirectory'] and isValidDirName(theform['FSSkinDirectory']) ):
Index: qPloneSkinDump/trunk/utils.py
===================================================================
--- qPloneSkinDump/trunk/utils.py	(revision 72)
+++ qPloneSkinDump/trunk/utils.py	(revision 74)
@@ -1,3 +1,4 @@
-import os, re, string, sets
+import os, re, string, sets, time
+from zope.app import zapi
 from App.config import getConfiguration
 from Products.CMFCore.utils import getToolByName
@@ -5,4 +6,18 @@
 from config import *
 from write_utils import writeProps, writeFileContent, writeObjectsMeta
+
+from zope.interface import providedBy
+from zope.schema import getFields
+from zope.component import getMultiAdapter, getUtility, getSiteManager
+from zope.publisher.interfaces.browser import IBrowserRequest
+from five.customerize.interfaces import IViewTemplateContainer, ITTWViewTemplate
+from plone.portlets.interfaces import IPortletAssignmentMapping, IPortletManager, IPlacelessPortletManager
+from plone.portlets.interfaces import IPortletContext, IPortletDataProvider
+from plone.portlets.interfaces import ILocalPortletAssignmentManager
+from plone.app.customerize.registration import generateIdFromRegistration, interfaceName
+
+from Products.GenericSetup.utils import _getDottedName, _resolveDottedName
+from Products.GenericSetup.interfaces import IBody
+from Products.GenericSetup.context import BaseContext
 
 CSS_PATTERN = re.compile("^.+\.css$")
@@ -26,16 +41,4 @@
     return products
 
-def getFSSkinPath(fs_product_name, fs_skin_directory, skin_obj, subdir):
-    """ Return file system skin path for subdir."""
-    skinpath = "%s/%s/skins/%s" % (PRODUCTS_PATH \
-                                  ,fs_product_name \
-                                  ,fs_skin_directory)
-    # If in skin's subfolder - get its path
-    skinp, subp = [obj.getPhysicalPath() for obj in [skin_obj, subdir]]
-    if len(subp) != len(skinp):
-        # adapt skinpath for creating directory
-        skinpath += '/' + '/'.join( subp[len(skinp):] )
-    return skinpath
-
 def get_id(obj):
     """ Get real object's id."""
@@ -48,22 +51,198 @@
     return meta_type in ['Image', 'File'] and obj.manage_FTPget() or obj.document_src()
 
-def dumpSkin(context, \
-             skin_name='custom', \
-             subdir=None, \
-             fs_skin_directory='custom', \
-             fs_product_name='QSkinTemplate', \
-             erase_from_skin=0):
-    """Dump custom information to file."""
-    # In case of recursable call go into subdir in skin folder.
-    skin_obj = getToolByName( context, 'portal_skins' )[skin_name]
-    subdir = subdir or skin_obj
-    skinpath = getFSSkinPath(fs_product_name, fs_skin_directory, skin_obj, subdir)
+def dumpPortalViewCustomization(context):
+    result = []
+
+    components = getSiteManager(context)
+    localregs = [reg for reg in components.registeredAdapters() if (len(reg.required) in (2, 4, 5) and
+                                                                     reg.required[1].isOrExtends(IBrowserRequest) and
+                                                                     ITTWViewTemplate.providedBy(reg.factory))]
+    container = getUtility(IViewTemplateContainer)
+#    import pdb;pdb.set_trace()
+    for lreg in localregs:
+#        ttw_id = generateIdFromRegistration(lreg)
+        ttw_id = lreg.factory.__name__
+                            
+        if ttw_id not in container.objectIds():
+            continue
+        ttw = getattr(container, ttw_id)
+        ttw_info = {'for_name'  : interfaceName(lreg.required[0]),
+                    'type_name' : interfaceName(lreg.required[-1]),
+                    'view_name' : lreg.name,
+                    'kwargs'    : {'text' : ttw._text,
+                                   'content_type' : ttw.content_type,
+                                   'encoding' : ttw.output_encoding,
+                                   }}
+        result.append(ttw_info)
+
+    return result
+
+def extractInfoFromAssignment(name, assignment):
+    klass = assignment.__class__
+    a = {'name' : name, 'class' : '%s' % _getDottedName(klass)}
+    data = assignment.data
+    kwargs = {}
+    for i in list(providedBy(data)):
+        if i.isOrExtends(IPortletDataProvider):
+            for field_name, field in getFields(i).items():
+                kwargs[field_name] = field.get(assignment)
+    a['kwargs'] = kwargs
+    return a
+
+def extractSiteWidePortlets(context, managers):
+    """ Extract site-wide portlets 
+        Data structure:
+            '__site-wide-portlets__', [(<manager1_name>, <manager1_info>),
+                                       (<manager2_name>, <manager2_info>),
+                                       (<manager3_name>, <manager3_info>)])
+            <manager_info>:
+                {'category1' : <catmapping1>,
+                 'category2' : <catmapping2>}
+            <catmapping>:
+                {'key1' : <mapping1>,
+                 'key2' : <mapping2>}
+            <mapping>:
+                {'assignment_name1' : <assignment1>,
+                 'assignment_name2' : <assignment2>}
+            <assignment>:
+                {'name'   : 'Assignment',
+                 'class'  : 'dotted.path.to.assignment.class',
+                 'kwargs' : {'parameter1' : 'value1',
+                             'parameter2' : 'value2'}
+    """
+    info = []
+    for manager_name, manager in managers:
+        manager_info = {}
+        for category, catmapping in manager.items():
+            catmapping_info = {}
+            for key, mapping in catmapping.items():
+                mapping_info = {}
+                for name, assignment in mapping.items():
+                    mapping_info[name] = extractInfoFromAssignment(name, assignment)
+                catmapping_info[key] = mapping_info
+            manager_info[category] = catmapping_info
+        info.append((manager_name, manager_info))
+    return info
+
+def extractContextPortletsFromManager(context, manager):
+    """ Extract all contextual portlets from given object and portlet manager, and portlets blacklists
+        Data structure:
+        <manager_info> =
+            {'blacklists'  : [(GROUP_CATEGORY, True),
+                              (CONTENT_TYPE_CATEGORY, False),
+                              (CONTEXT_CATEGORY, None)],
+             'assignments' : [{'name'   : 'Assignment-2',
+                               'class'  : 'dotted.path.to.assignment.class',
+                               'kwargs' : {'parameter1' : 'value1',
+                                          'parameter2' : 'value2'}},
+                              {'name'   : 'Assignment',
+                               'class'  : 'dotted.path.to.assignment.class',
+                               'kwargs' : {'parameter1' : 'value1',
+                                            'parameter2' : 'value2'}]}
+    """
+
+    info = {}
+    info['assignments'] = assignments = []
+    info['blacklists'] = blacklists = []
+
+    # Extract contextual portlets
+    mapping = getMultiAdapter((context, manager), IPortletAssignmentMapping, context=context)
+    for name, assignment in mapping.items():
+        assignments.append(extractInfoFromAssignment(name, assignment))
+
+    # Extract blacklists for given object and manager
+    localassignmentmanager = getMultiAdapter((context, manager), ILocalPortletAssignmentManager)
+    blacklist = localassignmentmanager._getBlacklist()
+    if blacklist is not None:
+        for category, key in blacklist.items():
+            blacklists.append((category, key))
+
+    return info
+
+def extractPortletsFromContext(context, slot_structure, typesToShow, managers):
+    """ Extract portlets for given object assigned through all portlet managers.
+        Data structure:
+            ('unique/path/to/context', [(<manager1_name>, <manager1_info>),
+                                        (<manager2_name>, <manager2_info>),
+                                        (<manager3_name>, <manager3_info>)])
+    """
+
+
+    info = []
+    key = '/'.join(context.getPhysicalPath()[2:])
+
+    for name, manager in managers:
+        info.append((name, extractContextPortletsFromManager(context, manager)))
+
+    slot_structure.append((key, info))
+
+    return slot_structure
+
+def dumpAllPortlets(context, slot_structure, typesToShow, managers):
+    extractPortletsFromContext(context, slot_structure, typesToShow, managers)
+    if getattr(context.aq_base, 'isPrincipiaFolderish', 0):
+        for id, obj in context.contentItems():
+            if obj.portal_type in typesToShow:
+                dumpAllPortlets(obj, slot_structure, typesToShow, managers)
+
+    return slot_structure
+
+def dumpPortlets(context, dump_policy, dump_portlets_selection):
+    """ Extract portlets from given set of objects and site-wide portlets too.
+        Data structure:
+            SLOT_STRUCTURE =
+                [(), (), ()]
+    """
+
+    portal = getToolByName(context, 'portal_url').getPortalObject()
+    portal_state = getMultiAdapter((portal, context.REQUEST), name=u'plone_portal_state')
+    typesToShow = portal_state.friendly_types()
+
+    components = getSiteManager(context)
+    managers = [r for r in components.registeredUtilities() if r.provided.isOrExtends(IPortletManager)]
+    context_managers = [(m.name, getUtility(IPortletManager, name=m.name, context=context)) for m in managers
+                                                                               if not IPlacelessPortletManager.providedBy(m.component)]
+    managers = [(m.name, getUtility(IPortletManager, name=m.name, context=context)) for m in managers]
+
+    slot_structure = []
+    if dump_policy == 'root':
+        extractPortletsFromContext(portal, slot_structure, typesToShow, context_managers)
+    elif dump_policy == 'all':
+        dumpAllPortlets(portal, slot_structure, typesToShow, context_managers)
+    elif dump_policy == 'selection':
+        for ppath in dump_portlets_selection:
+            obj = portal.restrictedTraverse(ppath)
+            extractPortletsFromContext(obj, slot_structure, typesToShow, context_managers)
+
+    slot_structure.append(('__site-wide-portlets__', extractSiteWidePortlets(portal, managers)))
+
+    return slot_structure
+
+def buildSkinLayers(context, zmi_base_skin_name):
+    pskins = getToolByName(context,'portal_skins')
+    layers = (pskins.getSkinPath(zmi_base_skin_name) or '').split(',')
+    return "\n".join(['   <layer name="%s"/>' % l for l in layers])
+
+def getFSSkinPath(folder, fs_dest_directory, fs_product_name):
+    """ Return file system skin path for subdir."""
+
+    folder_path = '/'.join(folder.getPhysicalPath()[list(folder.getPhysicalPath()).index('portal_skins')+1:])
+    skinpath = "%s/%s/skins/%s" % (fs_dest_directory, fs_product_name, folder_path)
+
+    # If in skin's subfolder - get its path
+    #skinp, subp = [obj.getPhysicalPath() for obj in [skin_obj, subdir]]
+    #if len(subp) != len(skinp):
+        ## adapt skinpath for creating directory
+        #skinpath += '/' + '/'.join( subp[len(skinp):] )
+    return skinpath
+
+def dumpFolder(folder, fs_dest_directory, fs_product_name):
+    skinpath = getFSSkinPath(folder, fs_dest_directory, fs_product_name)
     # Create directory in FS if not yet exist
-    if not os.path.exists( skinpath ):
-        os.makedirs( skinpath )
+    if not os.path.exists(skinpath):
+        os.makedirs(skinpath)
     # Loop of copying content from ZMIskin-folder to FSskin-folder 
-    deletelist = []
     obj_meta = {}
-    for o in subdir.objectValues():
+    for o in folder.objectValues():
         meta_type = o.meta_type
         id = get_id(o)
@@ -74,18 +253,12 @@
         if meta_type == 'Folder':
             # very plone specific
-            if id in ['stylesheet_properties', 'base_properties'] \
-               or id.startswith('base_properties'):
-                writeProps( o, skinpath, extension = '.props' )
+            if id in ['stylesheet_properties', 'base_properties'] or id.startswith('base_properties'):
+                writeProps(o, skinpath, extension = '.props')
             else:
-                dumpSkin( context, skin_name, subdir = o,\
-                          fs_skin_directory=fs_skin_directory,\
-                          fs_product_name=fs_product_name,\
-                          erase_from_skin = erase_from_skin )
-            deletelist.append( o.getId() )
+                dumpFolder(o, fs_product_name, fs_product_name)
         elif meta_type in _write_custom_meta_type_list:
             #writeProps( o, skinpath )      # write object's properties
             # extract content from object(depend on metatype) and write it to the file
-            writeFileContent( o, skinpath, getData(o, meta_type) )
-            deletelist.append( o.getId() )
+            writeFileContent(o, skinpath, getData(o, meta_type))
         else:
             print 'method ignoring ', meta_type
@@ -93,7 +266,16 @@
     if obj_meta :
         writeObjectsMeta(obj_meta, skinpath)
-    # delete objects from the skin, if request
-    if erase_from_skin:
-        subdir.manage_delObjects( ids = deletelist )
+
+def dumpSkin(context, skin_names=['custom',], fs_dest_directory=PRODUCTS_PATH,
+             fs_product_name='QSkinTemplate', erase_from_skin=0):
+    """Dump custom information to file."""
+    if type(skin_names) not in (type([]), type(())):
+        skin_names = [skin_names,]
+    for skin_name in list(skin_names):
+        folder = getToolByName(context, 'portal_skins')[skin_name]
+        dumpFolder(folder, fs_dest_directory, fs_product_name)
+        # delete objects from the skin, if request
+        if erase_from_skin:
+            folder.manage_delObjects(ids = folder.objectIds())
 
 def fillinFileTemplate(f_path_read, f_path_write=None, dict={}):
@@ -105,5 +287,8 @@
     f_tmpl.close()
     f_tmpl = open(f_path_write, 'w')
-    f_tmpl.write(tmpl % dict)
+    try:
+       f_tmpl.write(tmpl % dict)
+    except:
+        raise str(tmpl)
     f_tmpl.close()
 
@@ -163,29 +348,88 @@
             copyDir(src_path, dst_path, productName)
 
-def makeNewProduct(context, productName, productSkinName, \
-                   zmi_skin_name, zmi_base_skin_name, subdir,\
+def fsDirectoryViewsXML(folder_names, product_name, remove=False):
+    pattern = """ <object name="%(folder_name)s" meta_type="Filesystem Directory View"
+       directory="Products.%(product_name)s:skins/%(folder_name)s" %(remove)s/>\n"""
+    xml = ''
+    if type(folder_names) not in (type([]), type(())):
+        folder_names = [folder_names,]
+    for name in folder_names:
+       xml += pattern % {'product_name' : product_name, \
+                         'folder_name'  : name, \
+                         'remove'       : remove and 'remove="True"' or '', \
+                        }
+    return xml
+
+def makeNewProduct(context, destinationDir, productName, productSkinName, \
+                   zmi_skin_names, zmi_base_skin_name, subdir,\
                    doesCustomizeSlots, left_slots, right_slots, slot_forming, main_column, \
-                   doesExportObjects, import_policy, dump_CSS, dump_JS):
+                   doesExportObjects, import_policy, dump_CSS, dump_JS, \
+                   dump_portlets, dump_policy, dump_portlets_selection, dump_custom_views):
     """Create new skin-product's directory and 
-       copy skin-product template with little modification""" 
-    products_path = PRODUCTS_PATH
+       copy skin-product template with little modification"""
+    products_path = destinationDir
     productPath = ospJoin(products_path, productName)
-    if not ( productName in os.listdir(products_path) ):
+    if not (productName in os.listdir(products_path)):
         os.mkdir(productPath)
+    files_to_remove = []
+    files_to_add    = []
     # Form CSS and JS importing list and regestry data (looking in subdir too) for Plone 2.1.0+ 
-    subdir = subdir or getToolByName( context, 'portal_skins' )[zmi_skin_name]
+    stylesheets_xml = ''
+    javascripts_xml = ''
+    #subdir = subdir or getToolByName(context, 'portal_skins')[zmi_skin_name]
+    portal_setup = getToolByName(context, 'portal_setup')
     result_css_list = skin_css_regdata = result_js_list = skin_js_regdata = []
+    base_context = BaseContext(portal_setup, portal_setup.getEncoding())
     if dump_CSS:
-        result_css_list, skin_css_regdata = getResourceListRegdata(context, subdir,
-                                            CSS_PATTERN, 'portal_css', CSS_REG_PROPS)
+        res_reg = getToolByName(context, 'portal_css', None)
+        exporter = zapi.queryMultiAdapter((res_reg, base_context), IBody)
+        if exporter is not None:
+            stylesheets_xml = exporter.body
+        #result_css_list, skin_css_regdata = getResourceListRegdata(context, subdir,
+                                            #CSS_PATTERN, 'portal_css', CSS_REG_PROPS)
+    if stylesheets_xml == '':
+        files_to_remove.append(ospJoin('profiles', 'default', 'cssregistry.xml'))
     if dump_JS:
-        result_js_list, skin_js_regdata = getResourceListRegdata(context, subdir,
-                                            JS_PATTERN, 'portal_javascripts', JS_REG_PROPS)
+        res_reg = getToolByName(context, 'portal_javascripts', None)
+        exporter = zapi.queryMultiAdapter((res_reg, base_context), IBody)
+        if exporter is not None:
+            javascripts_xml = exporter.body
+        #result_js_list, skin_js_regdata = getResourceListRegdata(context, subdir,
+                                            #JS_PATTERN, 'portal_javascripts', JS_REG_PROPS)
+    if javascripts_xml == '':
+        files_to_remove.append(ospJoin('profiles', 'default', 'jsregistry.xml'))
+
+    slots = ()
+    if dump_portlets:
+        slots = dumpPortlets(context, dump_policy, dump_portlets_selection)
+
     # Get Slots customization information
     if not doesCustomizeSlots:
         left_slots = right_slots = None
         slot_forming = main_column = None
+
+    # Prepare XML strings for add to skins.xml
+    skin_layers = buildSkinLayers(context, zmi_base_skin_name)
+
+    # Prepare profiles
+    default_marker, afterinstall_marker, uninstall_marker = {}, {}, {}
+    profiles = ['default', 'afterinstall', 'uninstall']
+    profiles_path = ospJoin(products_path, productName, 'profiles')
+    for profile in profiles:
+        varname = "%s_marker" % profile
+        file_name = "%s_%s.txt" % (productName.lower(), profile)
+        locals()[varname].update({'fname' : file_name, \
+                                  'fpath' : ospJoin(profiles_path, profile, file_name), \
+                                  'fdata' : "# Marker file for %s profile of %s skin" % \
+                                            (profile, productName) })
+        files_to_add.append(locals()[varname])
+
+    # dump customized objects from portal_view_customization
+    custom_views = []
+    if dump_custom_views:
+        custom_views = dumpPortalViewCustomization(context)
+
     # Copy skin_template to SKIN_PRODUCT directory
-    templatePath = ospJoin(products_path, PROJECTNAME, TEMPLATE_PATH)
+    templatePath = ospJoin(PRODUCTS_PATH, PROJECTNAME, TEMPLATE_PATH)
     copyDir(templatePath, productPath, productName)
     # Form data dictionary and form Skin Product's files
@@ -205,9 +449,53 @@
                 ,"SLOT_FORMING" : slot_forming \
                 ,"MAIN_COLUMN" : main_column \
-                }
+                ,"product_name" : productName \
+                ,"skin_name" : productSkinName \
+                ,"skin_name_lowercase" : productSkinName.lower() \
+                ,"skin_name_capital" : '%s%s' % (productSkinName[0].upper(), productSkinName[1:]) \
+                ,"product_name_lowercase" : productName.lower() \
+                ,"viewlets_zcml" : '' \
+                ,"stylesheets_xml" : stylesheets_xml \
+                ,"javascripts_xml" : javascripts_xml \
+                ,"version" : time.strftime('%Y%m%d') \
+                ,"slot_structure" : str(slots) \
+                ,"skin_layers" : skin_layers \
+                ,"custom_views" : str(custom_views) \
+                ,"directory_views_xml" : fsDirectoryViewsXML(zmi_skin_names, productName) \
+                ,"remove_directory_views_xml" : fsDirectoryViewsXML(zmi_skin_names, productName, remove=True) \
+                ,"creation_date" : time.strftime('%d/%m/%Y') \
+                ,"install_profile_marker" : default_marker['fname'] \
+                ,"afterinstall_profile_marker" : afterinstall_marker['fname'] \
+                ,"uninstall_profile_marker" : uninstall_marker['fname'] \
+    }
     sp_updated_files = ['config.py' \
                        ,'README.txt' \
-                       ,ospJoin('Extensions', 'utils.py')\
-                       ,ospJoin('Extensions', 'Install.py')]
+                       ,'HISTORY.txt' \
+                       ,'setuphandlers.py' \
+                       ,'uninstallhandlers.py' \
+                       ,'profiles.zcml' \
+                       ,'utils.py' \
+                       ,'configure.zcml' \
+                       ,'skins.zcml' \
+                       ,ospJoin('Extensions', 'Install.py')\
+                       ,ospJoin('browser', 'interfaces.py')\
+                       ,ospJoin('browser', 'viewlets.zcml')\
+                       ,ospJoin('browser', 'configure.zcml')\
+                       ,ospJoin('profiles', 'default', 'skins.xml')\
+                       ,ospJoin('profiles', 'default', 'cssregistry.xml')\
+                       ,ospJoin('profiles', 'default', 'jsregistry.xml')\
+                       ,ospJoin('profiles', 'default', 'propertiestool.xml')\
+                       ,ospJoin('profiles', 'afterinstall', 'import_steps.xml')\
+                       ,ospJoin('profiles', 'uninstall', 'import_steps.xml')\
+                       ,ospJoin('profiles', 'uninstall', 'skins.xml')\
+                       ,ospJoin('browser', 'configure.zcml') \
+                       #,ospJoin('profiles', 'uninstall', 'cssregistry.xml')\
+                       #,ospJoin('profiles', 'uninstall', 'jsregistry.xml')\
+                       ]
     for fp in sp_updated_files:
         fillinFileTemplate(ospJoin(productPath, fp), dict=conf_dict)
+    for fp in files_to_remove:
+        os.remove(ospJoin(productPath,fp))
+    for data in files_to_add:
+        f = file(data['fpath'],'w')
+        f.write(data['fdata'])
+        f.close()
Index: qPloneSkinDump/trunk/version.txt
===================================================================
--- qPloneSkinDump/trunk/version.txt	(revision 72)
+++ qPloneSkinDump/trunk/version.txt	(revision 74)
@@ -1,1 +1,1 @@
-0.7.4
+0.8.4
