Commit 1f6ce553 authored by Aurel's avatar Aurel

do not failed at uninstall if cannot resolve path, add test for this, remove trailling spaces

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@12640 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 480946d9
...@@ -628,7 +628,7 @@ class ObjectTemplateItem(BaseTemplateItem): ...@@ -628,7 +628,7 @@ class ObjectTemplateItem(BaseTemplateItem):
container_ids = container.objectIds() container_ids = container.objectIds()
subobjects_dict = {} subobjects_dict = {}
# Object already exists # Object already exists
if object_id in container_ids: if object_id in container_ids:
old_obj = container._getOb(object_id) old_obj = container._getOb(object_id)
if hasattr(aq_base(old_obj), 'groups'): if hasattr(aq_base(old_obj), 'groups'):
# we must keep original order groups # we must keep original order groups
...@@ -706,7 +706,7 @@ class ObjectTemplateItem(BaseTemplateItem): ...@@ -706,7 +706,7 @@ class ObjectTemplateItem(BaseTemplateItem):
# we remove object not added in forms # we remove object not added in forms
# we put old objects we have kept # we put old objects we have kept
for path in groups.keys(): for path in groups.keys():
new_groups_dict = groups[path] new_groups_dict = groups[path]
if not old_groups.has_key(path): if not old_groups.has_key(path):
# installation of a new form # installation of a new form
obj = portal.unrestrictedTraverse(path) obj = portal.unrestrictedTraverse(path)
...@@ -716,13 +716,13 @@ class ObjectTemplateItem(BaseTemplateItem): ...@@ -716,13 +716,13 @@ class ObjectTemplateItem(BaseTemplateItem):
old_groups_dict = old_groups[path] old_groups_dict = old_groups[path]
obj = portal.unrestrictedTraverse(path) obj = portal.unrestrictedTraverse(path)
# first check that all widgets are in new order # first check that all widgets are in new order
# excetp the one that had to be removed # excetp the one that had to be removed
widget_id_list = obj.objectIds() widget_id_list = obj.objectIds()
for widget_id in widget_id_list: for widget_id in widget_id_list:
widget_path = path+'/'+widget_id widget_path = path+'/'+widget_id
if update_dict.has_key(widget_path) and update_dict[widget_path] in ('remove', 'save_and_remove'): if update_dict.has_key(widget_path) and update_dict[widget_path] in ('remove', 'save_and_remove'):
continue continue
widget_in_form = 0 widget_in_form = 0
for group_id in new_groups_dict.keys(): for group_id in new_groups_dict.keys():
group_values = new_groups_dict[group_id] group_values = new_groups_dict[group_id]
if widget_id in group_values: if widget_id in group_values:
...@@ -827,7 +827,11 @@ class PathTemplateItem(ObjectTemplateItem): ...@@ -827,7 +827,11 @@ class PathTemplateItem(ObjectTemplateItem):
object_keys.reverse() object_keys.reverse()
p = context.getPortalObject() p = context.getPortalObject()
for path in object_keys: for path in object_keys:
path_list = self._resolvePath(p, [], path.split('/')) try:
path_list = self._resolvePath(p, [], path.split('/'))
except AttributeError:
# path seems to not exist anymore
continue
path_list.sort() path_list.sort()
path_list.reverse() path_list.reverse()
for relative_url in path_list: for relative_url in path_list:
...@@ -2209,7 +2213,7 @@ class PortalTypeRolesTemplateItem(BaseTemplateItem): ...@@ -2209,7 +2213,7 @@ class PortalTypeRolesTemplateItem(BaseTemplateItem):
setattr(obj, '_roles', []) setattr(obj, '_roles', [])
except (NotFound, KeyError): except (NotFound, KeyError):
pass pass
class SitePropertyTemplateItem(BaseTemplateItem): class SitePropertyTemplateItem(BaseTemplateItem):
def build(self, context, **kw): def build(self, context, **kw):
...@@ -4124,7 +4128,7 @@ Business Template is a set of definitions, such as skins, portal types and categ ...@@ -4124,7 +4128,7 @@ Business Template is a set of definitions, such as skins, portal types and categ
if update_catalog: if update_catalog:
site.ERP5Site_reindexAll() site.ERP5Site_reindexAll()
# Update translation table, in case we added new portal types or # Update translation table, in case we added new portal types or
# workflow states. # workflow states.
site.ERP5Site_updateTranslationTable() site.ERP5Site_updateTranslationTable()
...@@ -4518,7 +4522,7 @@ Business Template is a set of definitions, such as skins, portal types and categ ...@@ -4518,7 +4522,7 @@ Business Template is a set of definitions, such as skins, portal types and categ
if item is not None: if item is not None:
items_list.extend(item.getKeys()) items_list.extend(item.getKeys())
return items_list return items_list
#By christophe Dumez <christophe@nexedi.com> #By christophe Dumez <christophe@nexedi.com>
def checkDependencies(self): def checkDependencies(self):
""" """
...@@ -4540,7 +4544,7 @@ Business Template is a set of definitions, such as skins, portal types and categ ...@@ -4540,7 +4544,7 @@ Business Template is a set of definitions, such as skins, portal types and categ
installed_bt = self.portal_templates.getInstalledBusinessTemplate(dependency) installed_bt = self.portal_templates.getInstalledBusinessTemplate(dependency)
if (not self.portal_templates.IsOneProviderInstalled(dependency)) \ if (not self.portal_templates.IsOneProviderInstalled(dependency)) \
and ((installed_bt is None) \ and ((installed_bt is None) \
or (version_restriction not in (None, '') and or (version_restriction not in (None, '') and
(not self.portal_templates.compareVersionStrings(installed_bt.getVersion(), version_restriction)))): (not self.portal_templates.compareVersionStrings(installed_bt.getVersion(), version_restriction)))):
missing_dep_list.append((dependency, version_restriction or '')) missing_dep_list.append((dependency, version_restriction or ''))
if len(missing_dep_list) != 0: if len(missing_dep_list) != 0:
...@@ -4887,7 +4891,7 @@ Business Template is a set of definitions, such as skins, portal types and categ ...@@ -4887,7 +4891,7 @@ Business Template is a set of definitions, such as skins, portal types and categ
# Block acquisition on all _item_name_list properties by setting # Block acquisition on all _item_name_list properties by setting
# a default class value to None # a default class value to None
for key in BusinessTemplate._item_name_list: for key in BusinessTemplate._item_name_list:
setattr(BusinessTemplate, key, None) setattr(BusinessTemplate, key, None)
# Transaction Manager used for update of business template workflow # Transaction Manager used for update of business template workflow
# XXX update seems to works without it # XXX update seems to works without it
......
...@@ -108,7 +108,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor): ...@@ -108,7 +108,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor):
pw.manage_changeWorkflows('', props=props) pw.manage_changeWorkflows('', props=props)
get_transaction().commit() get_transaction().commit()
self._ignore_log_errors() self._ignore_log_errors()
def login(self): def login(self):
uf = self.getPortal().acl_users uf = self.getPortal().acl_users
uf._doAddUser('seb', '', ['Manager'], []) uf._doAddUser('seb', '', ['Manager'], [])
...@@ -168,7 +168,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor): ...@@ -168,7 +168,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor):
""" """
bt = sequence.get('export_bt') bt = sequence.get('export_bt')
sequence.edit(current_bt=bt) sequence.edit(current_bt=bt)
def stepUseDependencyBusinessTemplate(self, sequence=None, def stepUseDependencyBusinessTemplate(self, sequence=None,
sequence_list=None, **kw): sequence_list=None, **kw):
""" """
...@@ -323,7 +323,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor): ...@@ -323,7 +323,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor):
bt.edit(template_portal_type_id_list=ptype_ids) bt.edit(template_portal_type_id_list=ptype_ids)
self.stepFillPortalTypesFields(sequence=sequence, sequence_list=sequence_list, **kw) self.stepFillPortalTypesFields(sequence=sequence, sequence_list=sequence_list, **kw)
def stepAddDuplicatedPortalTypeToBusinessTemplate(self, sequence=None, def stepAddDuplicatedPortalTypeToBusinessTemplate(self, sequence=None,
sequence_list=None, **kw): sequence_list=None, **kw):
""" """
Add duplicated portal type to business template Add duplicated portal type to business template
...@@ -376,7 +376,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor): ...@@ -376,7 +376,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor):
object_type = pt._getOb(object_id, None) object_type = pt._getOb(object_id, None)
self.failUnless(object_type is None) self.failUnless(object_type is None)
def stepCheckDuplicatedPortalTypeRemoved(self, sequence=None, def stepCheckDuplicatedPortalTypeRemoved(self, sequence=None,
sequence_list=None, **kw): sequence_list=None, **kw):
""" """
Check non presence of portal type Check non presence of portal type
...@@ -552,7 +552,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor): ...@@ -552,7 +552,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor):
subskin_id = sequence.get('skin_subfolder_id') subskin_id = sequence.get('skin_subfolder_id')
skin_subfolder = skin_folder._getOb(subskin_id, None) skin_subfolder = skin_folder._getOb(subskin_id, None)
self.failUnless(skin_subfolder is not None) self.failUnless(skin_subfolder is not None)
def stepCreateNewObjectInSkinSubFolder(self, sequence=None, sequence_list=None, **kw): def stepCreateNewObjectInSkinSubFolder(self, sequence=None, sequence_list=None, **kw):
""" """
Create a new object in skin subfolder Create a new object in skin subfolder
...@@ -568,7 +568,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor): ...@@ -568,7 +568,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor):
zsql_method = skin_subfolder._getOb(method_id, None) zsql_method = skin_subfolder._getOb(method_id, None)
self.failUnless(zsql_method is not None) self.failUnless(zsql_method is not None)
sequence.edit(zsql_method_id = method_id) sequence.edit(zsql_method_id = method_id)
def stepRemoveSkinFolder(self, sequence=None, sequence_list=None, **kw): def stepRemoveSkinFolder(self, sequence=None, sequence_list=None, **kw):
""" """
Remove Skin folder Remove Skin folder
...@@ -612,7 +612,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor): ...@@ -612,7 +612,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor):
wf_ids.append(sequence.get('skin_folder_id', '')) wf_ids.append(sequence.get('skin_folder_id', ''))
self.assertEqual(len(wf_ids), 1) self.assertEqual(len(wf_ids), 1)
bt.edit(template_skin_id_list=wf_ids) bt.edit(template_skin_id_list=wf_ids)
def stepAddPathToBusinessTemplate(self, sequence=None, sequence_list=None, **kw): def stepAddPathToBusinessTemplate(self, sequence=None, sequence_list=None, **kw):
""" """
Add a path to business template Add a path to business template
...@@ -1264,7 +1264,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor): ...@@ -1264,7 +1264,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor):
# table related configuration # table related configuration
self.failUnless('translation' in catalog.sql_search_tables) self.failUnless('translation' in catalog.sql_search_tables)
# column related configuration # column related configuration
self.failUnless('catalog.reference' self.failUnless('catalog.reference'
in catalog.sql_search_result_keys) in catalog.sql_search_result_keys)
def stepRemoveCatalogLocalConfiguration(self, sequence, **kw): def stepRemoveCatalogLocalConfiguration(self, sequence, **kw):
...@@ -1647,7 +1647,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor): ...@@ -1647,7 +1647,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor):
f = file(ps_path, 'r') f = file(ps_path, 'r')
data = f.read() data = f.read()
self.assertEqual(data, ps_data) self.assertEqual(data, ps_data)
def stepCheckPropertySheetRemoved(self, sequence=None, sequencer_list=None, **kw): def stepCheckPropertySheetRemoved(self, sequence=None, sequencer_list=None, **kw):
""" """
Check presence of Property Sheet Check presence of Property Sheet
...@@ -1736,7 +1736,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor): ...@@ -1736,7 +1736,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor):
f = file(ct_path, 'r') f = file(ct_path, 'r')
data = f.read() data = f.read()
self.assertEqual(data, ct_data) self.assertEqual(data, ct_data)
def stepCheckConstraintRemoved(self, sequence=None, sequencer_list=None, **kw): def stepCheckConstraintRemoved(self, sequence=None, sequencer_list=None, **kw):
""" """
Check presence of Constraint Check presence of Constraint
...@@ -1807,7 +1807,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor): ...@@ -1807,7 +1807,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor):
import_bt = sequence.get('import_bt') import_bt = sequence.get('import_bt')
import_bt.install(force=1) import_bt.install(force=1)
def stepInstallDuplicatedBusinessTemplate(self, sequence=None, def stepInstallDuplicatedBusinessTemplate(self, sequence=None,
sequence_list=None, **kw): sequence_list=None, **kw):
""" """
Install importzed business template Install importzed business template
...@@ -1841,7 +1841,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor): ...@@ -1841,7 +1841,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor):
description='bt for unit_test') description='bt for unit_test')
sequence.edit(export_bt=template) sequence.edit(export_bt=template)
def stepCreateDuplicatedBusinessTemplate(self, sequence=None, def stepCreateDuplicatedBusinessTemplate(self, sequence=None,
sequence_list=None, **kw): sequence_list=None, **kw):
""" """
Create a new Business Template which will duplicate Create a new Business Template which will duplicate
...@@ -1865,7 +1865,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor): ...@@ -1865,7 +1865,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor):
template = sequence.get('current_bt') template = sequence.get('current_bt')
self.assertRaises(AttributeError, self.assertRaises(AttributeError,
template.build) template.build)
def stepBuildBusinessTemplate(self, sequence=None, sequence_list=None, **kw): def stepBuildBusinessTemplate(self, sequence=None, sequence_list=None, **kw):
""" """
Build Business Template Build Business Template
...@@ -1947,7 +1947,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor): ...@@ -1947,7 +1947,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor):
bt = sequence.get('current_bt') bt = sequence.get('current_bt')
bt.uninstall() bt.uninstall()
def stepUninstallPreviousBusinessTemplate(self, sequence=None, def stepUninstallPreviousBusinessTemplate(self, sequence=None,
sequence_list=None, **kw): sequence_list=None, **kw):
""" """
Uninstall current Business Template Uninstall current Business Template
...@@ -2000,7 +2000,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor): ...@@ -2000,7 +2000,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor):
'portal_categories/%s' % base_category_id) 'portal_categories/%s' % base_category_id)
self.failUnless(base_category_obj is not None) self.failUnless(base_category_obj is not None)
self.assertEquals(len(base_category_obj.objectIds()), 0) self.assertEquals(len(base_category_obj.objectIds()), 0)
def stepCheckInitialRevision(self, sequence=None, sequence_list=None, **kw): def stepCheckInitialRevision(self, sequence=None, sequence_list=None, **kw):
""" Check if revision of a new bt is an empty string """ Check if revision of a new bt is an empty string
""" """
...@@ -2012,13 +2012,13 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor): ...@@ -2012,13 +2012,13 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor):
""" """
bt = sequence.get('current_bt') bt = sequence.get('current_bt')
self.assertEqual(bt.getRevision(), '1') self.assertEqual(bt.getRevision(), '1')
def stepCheckSecondRevision(self, sequence=None, sequence_list=None, **kw): def stepCheckSecondRevision(self, sequence=None, sequence_list=None, **kw):
""" Check if revision of the bt is 2 """ Check if revision of the bt is 2
""" """
bt = sequence.get('current_bt') bt = sequence.get('current_bt')
self.assertEqual(bt.getRevision(), '2') self.assertEqual(bt.getRevision(), '2')
def stepCheckNoMissingDependencies(self, sequence=None, sequence_list=None, **kw): def stepCheckNoMissingDependencies(self, sequence=None, sequence_list=None, **kw):
""" Check if bt has no missing dependency """ Check if bt has no missing dependency
""" """
...@@ -2029,7 +2029,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor): ...@@ -2029,7 +2029,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor):
except: except:
missing_dep = True missing_dep = True
self.failUnless(not missing_dep) self.failUnless(not missing_dep)
def stepCheckMissingDependencies(self, sequence=None, sequence_list=None, **kw): def stepCheckMissingDependencies(self, sequence=None, sequence_list=None, **kw):
""" Check if bt has missing dependency """ Check if bt has missing dependency
""" """
...@@ -2040,13 +2040,13 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor): ...@@ -2040,13 +2040,13 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor):
except: except:
missing_dep = True missing_dep = True
self.failUnless(missing_dep) self.failUnless(missing_dep)
def stepAddDependency(self, sequence=None, sequence_list=None, **kw): def stepAddDependency(self, sequence=None, sequence_list=None, **kw):
""" Add a dependency to the business template """ Add a dependency to the business template
""" """
bt = sequence.get('current_bt') bt = sequence.get('current_bt')
bt.setDependencyList(['dependency_bt',]) bt.setDependencyList(['dependency_bt',])
def stepCreateDependencyBusinessTemplate(self, sequence=None, sequence_list=None, **kw): def stepCreateDependencyBusinessTemplate(self, sequence=None, sequence_list=None, **kw):
""" """
Create a new Business Template Create a new Business Template
...@@ -2059,7 +2059,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor): ...@@ -2059,7 +2059,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor):
version='1.0', version='1.0',
description='bt for unit_test') description='bt for unit_test')
sequence.edit(dependency_bt=template) sequence.edit(dependency_bt=template)
# tests # tests
def test_Title(self): def test_Title(self):
"""Tests the Title of the Template Tool.""" """Tests the Title of the Template Tool."""
...@@ -2515,6 +2515,53 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor): ...@@ -2515,6 +2515,53 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor):
sequence_list.addSequenceString(sequence_string) sequence_list.addSequenceString(sequence_string)
sequence_list.play(self, quiet=quiet) sequence_list.play(self, quiet=quiet)
def test_101_BusinessTemplateUninstallWithPathAndJoker1Removed(self, quiet=quiet, run=1): #run_all_test):
if not run: return
if not quiet:
message = 'Test Business Template Uninstall With Path And Joker * Removed'
ZopeTestCase._print('\n%s ' % message)
LOG('Testing... ', 0, message)
sequence_list = SequenceList()
# path with subobjects
sequence_string = '\
CreateBaseCategory \
CreateCategories \
CreateNewBusinessTemplate \
UseExportBusinessTemplate \
CheckModifiedBuildingState \
CheckNotInstalledInstallationState \
AddCategoriesAsPathToBusinessTemplate \
BuildBusinessTemplate \
CheckBuiltBuildingState \
CheckNotInstalledInstallationState \
CheckObjectPropertiesInBusinessTemplate \
SaveBusinessTemplate \
CheckBuiltBuildingState \
CheckNotInstalledInstallationState \
RemoveCategories \
RemoveBusinessTemplate \
RemoveAllTrashBins \
ImportBusinessTemplate \
UseImportBusinessTemplate \
CheckBuiltBuildingState \
CheckNotInstalledInstallationState \
InstallBusinessTemplate \
Tic \
CheckInstalledInstallationState \
CheckBuiltBuildingState \
CheckNoTrashBin \
CheckSkinsLayers \
CheckCategoriesExists \
RemoveCategories \
UninstallBusinessTemplate \
CheckBuiltBuildingState \
CheckNotInstalledInstallationState \
CheckCategoriesRemoved \
RemoveBaseCategory \
'
sequence_list.addSequenceString(sequence_string)
sequence_list.play(self, quiet=quiet)
def test_11_BusinessTemplateWithPathAndJoker2(self, quiet=quiet, run=run_all_test): def test_11_BusinessTemplateWithPathAndJoker2(self, quiet=quiet, run=run_all_test):
if not run: return if not run: return
if not quiet: if not quiet:
...@@ -3477,7 +3524,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor): ...@@ -3477,7 +3524,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor):
' '
sequence_list.addSequenceString(sequence_string) sequence_list.addSequenceString(sequence_string)
sequence_list.play(self, quiet=quiet) sequence_list.play(self, quiet=quiet)
def test_24_CheckMissingDependency(self, quiet=quiet, run=run_all_test): def test_24_CheckMissingDependency(self, quiet=quiet, run=run_all_test):
if not run: return if not run: return
if not quiet: if not quiet:
...@@ -3496,7 +3543,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor): ...@@ -3496,7 +3543,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor):
' '
sequence_list.addSequenceString(sequence_string) sequence_list.addSequenceString(sequence_string)
sequence_list.play(self, quiet=quiet) sequence_list.play(self, quiet=quiet)
def test_25_CheckNoMissingDependency(self, quiet=quiet, run=run_all_test): def test_25_CheckNoMissingDependency(self, quiet=quiet, run=run_all_test):
if not run: return if not run: return
if not quiet: if not quiet:
...@@ -3730,7 +3777,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor): ...@@ -3730,7 +3777,7 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor):
sequence_list.addSequenceString(sequence_string) sequence_list.addSequenceString(sequence_string)
sequence_list.play(self, quiet=quiet) sequence_list.play(self, quiet=quiet)
def test_32_BusinessTemplateWithDuplicatedPortalTypes(self, quiet=quiet, def test_32_BusinessTemplateWithDuplicatedPortalTypes(self, quiet=quiet,
run=run_all_test): run=run_all_test):
if not run: return if not run: return
if not quiet: if not quiet:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment