Commit a54a5444 authored by Łukasz Nowak's avatar Łukasz Nowak

Create Software Release on the fly while requesting.

parent 36760a77
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Category Membership Arity Constraint" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_identity_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>_range_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>constraint_base_category</string> </key>
<value>
<tuple>
<string>aggregate</string>
</tuple>
</value>
</item>
<item>
<key> <string>constraint_portal_type</string> </key>
<value> <string>python: (\'Software Product\',)</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>aggregate_category_membership_arity_constraint</string> </value>
</item>
<item>
<key> <string>int_index</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>max_arity</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>membership_criterion_category</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>message_arity_not_in_range</string> </key>
<value> <string>One Software Product must be defined</string> </value>
</item>
<item>
<key> <string>message_arity_too_small</string> </key>
<value> <string>One Software Product must be defined</string> </value>
</item>
<item>
<key> <string>message_arity_with_portal_type_not_in_range</string> </key>
<value> <string>One Software Product must be defined</string> </value>
</item>
<item>
<key> <string>message_arity_with_portal_type_too_small</string> </key>
<value> <string>One Software Product must be defined</string> </value>
</item>
<item>
<key> <string>min_arity</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Category Membership Arity Constraint</string> </value>
</item>
<item>
<key> <string>string_index</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>test_method_id</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>test_tales_expression</string> </key>
<value> <string>python: object.getValidationState() not in (\'draft\' , \'cancelled\')</string> </value>
</item>
<item>
<key> <string>use_acquisition</string> </key>
<value> <int>0</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Category Membership State Constraint" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_identity_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>_range_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>base_category</string> </key>
<value> <string>aggregate</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>aggregate_state_constraint</string> </value>
</item>
<item>
<key> <string>int_index</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>membership_criterion_category</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>membership_portal_type_list</string> </key>
<value> <string>python: (\'Software Product\',)</string> </value>
</item>
<item>
<key> <string>message_different_state</string> </key>
<value> <string>Software Product must be validated</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Category Membership State Constraint</string> </value>
</item>
<item>
<key> <string>string_index</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>test_method_id</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>test_tales_expression</string> </key>
<value> <string>python: object.getValidationState() not in (\'draft\', \'cancelled\')</string> </value>
</item>
<item>
<key> <string>workflow_state_list</string> </key>
<value> <string>python: (\'published\', \'validated\')</string> </value>
</item>
<item>
<key> <string>workflow_variable</string> </key>
<value> <string>validation_state</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Category Membership Arity Constraint" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_identity_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>_range_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>constraint_base_category</string> </key>
<value>
<tuple>
<string>contributor</string>
</tuple>
</value>
</item>
<item>
<key> <string>constraint_portal_type</string> </key>
<value> <string>python: (\'Person\',)</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>There must be one and one only Contributor</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>contributor_category_membership_arity_constraint</string> </value>
</item>
<item>
<key> <string>max_arity</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>message_arity_not_in_range</string> </key>
<value> <string>One Contributor must be defined</string> </value>
</item>
<item>
<key> <string>message_arity_too_small</string> </key>
<value> <string>One Contributor must be defined</string> </value>
</item>
<item>
<key> <string>message_arity_with_portal_type_not_in_range</string> </key>
<value> <string>One Contributor must be defined</string> </value>
</item>
<item>
<key> <string>message_arity_with_portal_type_too_small</string> </key>
<value> <string>One Contributor must be defined</string> </value>
</item>
<item>
<key> <string>min_arity</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Category Membership Arity Constraint</string> </value>
</item>
<item>
<key> <string>use_acquisition</string> </key>
<value> <int>0</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
465 466
\ No newline at end of file \ No newline at end of file
...@@ -2,113 +2,92 @@ ...@@ -2,113 +2,92 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="Category Membership State Constraint" module="erp5.portal_type"/> <global name="Alarm" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
<item> <item>
<key> <string>_identity_criterion</string> </key> <key> <string>active_sense_method_id</string> </key>
<value> <value> <string>Alarm_orderPlannedSaleOrder</string> </value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>_range_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item> </item>
<item> <item>
<key> <string>base_category</string> </key> <key> <string>description</string> </key>
<value> <string>contributor</string> </value> <value> <string>Orders planned Sale Orders.</string> </value>
</item> </item>
<item> <item>
<key> <string>description</string> </key> <key> <string>enabled</string> </key>
<value> <value> <int>1</int> </value>
<none/>
</value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>contributor_state_constraint</string> </value> <value> <string>order_planned_sale_order</string> </value>
</item> </item>
<item> <item>
<key> <string>int_index</string> </key> <key> <string>periodicity_hour</string> </key>
<value> <value>
<none/> <tuple/>
</value> </value>
</item> </item>
<item> <item>
<key> <string>membership_criterion_category</string> </key> <key> <string>periodicity_minute</string> </key>
<value> <value>
<tuple/> <tuple/>
</value> </value>
</item> </item>
<item> <item>
<key> <string>membership_portal_type_list</string> </key> <key> <string>periodicity_minute_frequency</string> </key>
<value> <string>python: (\'Person\',)</string> </value> <value> <int>1</int> </value>
</item> </item>
<item> <item>
<key> <string>message_different_state</string> </key> <key> <string>periodicity_month</string> </key>
<value> <string>Contributor must be validated</string> </value> <value>
<tuple/>
</value>
</item> </item>
<item> <item>
<key> <string>portal_type</string> </key> <key> <string>periodicity_month_day</string> </key>
<value> <string>Category Membership State Constraint</string> </value> <value>
<tuple/>
</value>
</item> </item>
<item> <item>
<key> <string>string_index</string> </key> <key> <string>periodicity_start_date</string> </key>
<value> <value>
<object>
<klass>
<global name="DateTime" module="DateTime.DateTime"/>
</klass>
<tuple>
<none/> <none/>
</tuple>
<state>
<tuple>
<float>1288051200.0</float>
<string>GMT</string>
</tuple>
</state>
</object>
</value> </value>
</item> </item>
<item> <item>
<key> <string>test_method_id</string> </key> <key> <string>periodicity_week</string> </key>
<value> <value>
<tuple/> <tuple/>
</value> </value>
</item> </item>
<item> <item>
<key> <string>test_tales_expression</string> </key> <key> <string>portal_type</string> </key>
<value> <string>python: context.getValidationState() != \'cancelled\'</string> </value> <value> <string>Alarm</string> </value>
</item>
<item>
<key> <string>workflow_state_list</string> </key>
<value> <string>python: \'validated\'</string> </value>
</item>
<item>
<key> <string>workflow_variable</string> </key>
<value> <string>validation_state</string> </value>
</item> </item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item> <item>
<key> <string>data</string> </key> <key> <string>sense_method_id</string> </key>
<value> <value>
<dictionary/> <none/>
</value> </value>
</item> </item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item> <item>
<key> <string>data</string> </key> <key> <string>title</string> </key>
<value> <value> <string>Order planned Sale Orders</string> </value>
<dictionary/>
</value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>portal = context.getPortalObject()\n
setup_service = portal.portal_preferences.getPreferredInstanceSetupResource()\n
\n
portal.portal_catalog.searchAndActivate(\n
portal_type=\'Sale Order Line\',\n
default_resource_uid=portal.restrictedTraverse(setup_service).getUid(),\n
simulation_state="planned",\n
method_id=\'SaleOrderLine_tryToAssociateSoftwareRelease\',\n
packet_size=1, # Separate calls to many transactions\n
activate_kw={\'tag\': tag}\n
)\n
\n
context.activate(after_tag=tag).getId()\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>tag, fixit, params</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Alarm_orderPlannedSaleOrder</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ExternalMethod" module="Products.ExternalMethod.ExternalMethod"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_function</string> </key>
<value> <string>getSha512Hexdiest</string> </value>
</item>
<item>
<key> <string>_module</string> </key>
<value> <string>VifibUtil</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Base_getSha512Hexdiest</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -95,6 +95,9 @@ def assignComputerPartition(order):\n ...@@ -95,6 +95,9 @@ def assignComputerPartition(order):\n
\n \n
sale_order = context.getParentValue()\n sale_order = context.getParentValue()\n
if sale_order.getSimulationState() == \'ordered\':\n if sale_order.getSimulationState() == \'ordered\':\n
if not context.SaleOrderLine_tryToAssociateSoftwareRelease():\n
# support changing software release for not instantiated orders\n
markHistory(sale_order, \'Software Release not associated.\')\n
try:\n try:\n
software_instance, computer_partition = assignComputerPartition(sale_order)\n software_instance, computer_partition = assignComputerPartition(sale_order)\n
except ValueError:\n except ValueError:\n
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>from DateTime import DateTime\n
from Products.DCWorkflow.DCWorkflow import ValidationFailed\n
from zExceptions import Unauthorized\n
\n
def markHistory(document, comment):\n
document.portal_workflow.doActionFor(document, action=\'edit_action\', comment=comment)\n
\n
def getSoftwareRelease(software_release_url):\n
# try to find, if needed create and publish\n
portal = context.getPortalObject()\n
software_release_document = portal.portal_catalog.getResultValue(portal_type=\'Software Release\',\n
url_string=software_release_url)\n
if software_release_document is None:\n
digest = context.Base_getSha512Hexdiest(software_release_url)\n
tag = \'%s_inProgress\' % digest\n
if portal.portal_activities.countMessageWithTag(tag) == 0:\n
# can create new one\n
software_release_document = portal.software_release_module.newContent(\n
portal_type=\'Software Release\',\n
reference=digest,\n
version=digest,\n
url_string=software_release_url,\n
language=\'en\'\n
)\n
software_release_document.publish()\n
return software_release_document\n
\n
state = context.getSimulationState()\n
portal = context.getPortalObject()\n
order = context.getParentValue()\n
if state in [\'planned\', \'ordered\']:\n
instance = context.getAggregateValue(portal_type=[\'Software Instance\', \'Slave Instance\'])\n
instance_software_release_url = instance.getRootSoftwareReleaseUrl()\n
line_software_release_document = context.getAggregateValue(portal_type=\'Software Release\')\n
line_software_release_url = \'\'\n
if line_software_release_document is not None:\n
line_software_release_url = line_software_release_document.getUrlString()\n
\n
software_release_document = getSoftwareRelease(instance_software_release_url)\n
\n
if line_software_release_url == \'\' or \\\n
line_software_release_url != instance_software_release_url:\n
if software_release_document is not None:\n
# update\n
aggregate_value_list = [q for q in context.getAggregateValueList() if q.getPortalType() != \'Software Release\']\n
aggregate_value_list.append(software_release_document)\n
context.setAggregateValueList(aggregate_value_list)\n
if context.getSimulationState() == \'planned\':\n
context.getParentValue().order(comment=\'Associated Software Release with %r\' % software_release_document.getUrlString())\n
else:\n
markHistory(context.getParentValue(), comment=\'Updated Software Release with %r\' % software_release_document.getUrlString())\n
return True\n
else:\n
return False\n
else:\n
# nothing to do, all asserted\n
return True\n
\n
return False\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>SaleOrderLine_tryToAssociateSoftwareRelease</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
803 804
\ No newline at end of file \ No newline at end of file
...@@ -3,6 +3,7 @@ portal_alarms/confirm_planned_sale_invoice_transaction ...@@ -3,6 +3,7 @@ portal_alarms/confirm_planned_sale_invoice_transaction
portal_alarms/deliver_subscription_sale_packing_list portal_alarms/deliver_subscription_sale_packing_list
portal_alarms/free_computer_partition portal_alarms/free_computer_partition
portal_alarms/garbage_collect_destroyed_root_tree portal_alarms/garbage_collect_destroyed_root_tree
portal_alarms/order_planned_sale_order
portal_alarms/stop_confirmed_sale_invoice_transaction portal_alarms/stop_confirmed_sale_invoice_transaction
portal_alarms/vifib_bang_selenium_tester_instance portal_alarms/vifib_bang_selenium_tester_instance
portal_alarms/vifib_cancel_destroy_partition portal_alarms/vifib_cancel_destroy_partition
......
...@@ -73,11 +73,6 @@ hosting_service_relative_url = portal.portal_preferences.getPreferredInstanceHos ...@@ -73,11 +73,6 @@ hosting_service_relative_url = portal.portal_preferences.getPreferredInstanceHos
hosting_service = portal.restrictedTraverse(hosting_service_relative_url)\n hosting_service = portal.restrictedTraverse(hosting_service_relative_url)\n
cleanup_service_relative_url = portal.portal_preferences.getPreferredInstanceCleanupResource()\n cleanup_service_relative_url = portal.portal_preferences.getPreferredInstanceCleanupResource()\n
cleanup_service = portal.restrictedTraverse(cleanup_service_relative_url)\n cleanup_service = portal.restrictedTraverse(cleanup_service_relative_url)\n
# Get software release\n
software_release_document = portal.portal_catalog.getResultValue(\n
portal_type=\'Software Release\',\n
url_string=instance.getRootSoftwareReleaseUrl())\n
assert software_release_document is not None\n
\n \n
sale_order_portal_type = "Sale Order"\n sale_order_portal_type = "Sale Order"\n
sale_order_line_portal_type = "Sale Order Line"\n sale_order_line_portal_type = "Sale Order Line"\n
...@@ -106,12 +101,9 @@ if (partition is None):\n ...@@ -106,12 +101,9 @@ if (partition is None):\n
quantity_unit="unit/piece",\n quantity_unit="unit/piece",\n
quantity=1,\n quantity=1,\n
price=setup_service.getSaleSupplyLineBasePrice(),\n price=setup_service.getSaleSupplyLineBasePrice(),\n
aggregate_value_list=[instance,\n aggregate_value_list=[instance, hosting_subscription],\n
hosting_subscription,\n
software_release_document\n
],\n
)\n )\n
sale_order.order()\n sale_order.plan()\n
instance.edit(causality_value=sale_order)\n instance.edit(causality_value=sale_order)\n
\n \n
else:\n else:\n
...@@ -119,16 +111,6 @@ if (partition is None):\n ...@@ -119,16 +111,6 @@ if (partition is None):\n
if state == destroyed:\n if state == destroyed:\n
# Can destroy the instance before allocation\n # Can destroy the instance before allocation\n
delivery.cancel()\n delivery.cancel()\n
else:\n
# Update the software release if it has been changed before allocation\n
sale_order_line = delivery.contentValues(portal_type=sale_order_line_portal_type)[0]\n
if sale_order_line.getAggregateValue(portal_type=\'Software Release\').getUrlString() != instance.getRootSoftwareReleaseUrl():\n
software_release = portal.portal_catalog.getResultValue(portal_type=\'Software Release\',\n
url_string=instance.getRootSoftwareReleaseUrl())\n
aggregate_list = [software_release.getRelativeUrl(), \n
instance.getRelativeUrl(),\n
hosting_subscription.getRelativeUrl()]\n
sale_order_line.edit(aggregate_list=aggregate_list)\n
else:\n else:\n
assert delivery is not None\n assert delivery is not None\n
\n \n
......
27 28
\ No newline at end of file \ No newline at end of file
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