Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
erp5
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
138
Merge Requests
138
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Jobs
Commits
Open sidebar
nexedi
erp5
Commits
c4e1dcf8
Commit
c4e1dcf8
authored
Oct 10, 2022
by
Kazuhiko Shiozaki
Committed by
Arnaud Fontaine
Jul 04, 2024
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
py2/py3: unicode() does not exist in Python 3.
parent
72ec7d78
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
51 additions
and
44 deletions
+51
-44
bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs/WebSite_getTranslationDataTextContent.py
...rp5_web_renderjs/WebSite_getTranslationDataTextContent.py
+4
-4
product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Base_getHistoricalComparisonDifferenceList.py
...s/erp5_core/Base_getHistoricalComparisonDifferenceList.py
+18
-16
product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/BusinessTemplate_getPythonSourceCodeMessageList.py
...5_core/BusinessTemplate_getPythonSourceCodeMessageList.py
+2
-2
product/ERP5Form/ListBox.py
product/ERP5Form/ListBox.py
+9
-9
product/ERP5Form/PDFTemplate.py
product/ERP5Form/PDFTemplate.py
+7
-8
product/ERP5OOo/FormPrintout.py
product/ERP5OOo/FormPrintout.py
+3
-1
product/ERP5Type/Accessor/TypeDefinition.py
product/ERP5Type/Accessor/TypeDefinition.py
+1
-1
product/ERP5Type/tests/testDynamicClassGeneration.py
product/ERP5Type/tests/testDynamicClassGeneration.py
+6
-2
product/PortalTransforms/transforms/safe_html.py
product/PortalTransforms/transforms/safe_html.py
+1
-1
No files found.
bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs/WebSite_getTranslationDataTextContent.py
View file @
c4e1dcf8
"""Returns the `text_content` that should be set on the translation data script for this RJS website.
"""Returns the `text_content` that should be set on the translation data script for this RJS website.
"""
"""
import
json
import
json
from
Products.ERP5Type.Utils
import
str2unicode
,
unicode2str
portal
=
context
.
getPortalObject
()
portal
=
context
.
getPortalObject
()
Base_translateString
=
context
.
Base_translateString
Base_translateString
=
context
.
Base_translateString
...
@@ -38,14 +39,13 @@ tmp = {}
...
@@ -38,14 +39,13 @@ tmp = {}
for
language
in
context
.
getAvailableLanguageSet
():
for
language
in
context
.
getAvailableLanguageSet
():
tmp
[
language
]
=
{}
tmp
[
language
]
=
{}
for
word
in
translatable_message_set
:
for
word
in
translatable_message_set
:
tmp
[
language
][
word
]
=
unicode
(
Base_translateString
(
word
,
lang
=
language
),
'utf-8'
)
tmp
[
language
][
word
]
=
str2unicode
(
Base_translateString
(
word
,
lang
=
language
))
# We pass unicode to this json.dump(ensure_ascii=False), so that it produce
# We pass unicode to this json.dump(ensure_ascii=False), so that it produce
# UTF-8 string and not escaped characters. At the end we return an UTF-8
# UTF-8 string and not escaped characters. At the end we return an UTF-8
# encoded string and not an unicode instance, because text_content property
# encoded string and not an unicode instance, because text_content property
# is usually UTF-8 encoded str (not unicode).
# is usually UTF-8 encoded str (not unicode).
return
(
u"""/**
return
unicode2str
(
u"""/**
* This translation data is generated automatically and updated with upgrader in post-upgarde.
* This translation data is generated automatically and updated with upgrader in post-upgarde.
* Do not edit manually, but use "Update Translation Data" action on web site to update from
* Do not edit manually, but use "Update Translation Data" action on web site to update from
* Localizer and from data-i18n tags on web pages.
* Localizer and from data-i18n tags on web pages.
...
@@ -64,4 +64,4 @@ return (u"""/**
...
@@ -64,4 +64,4 @@ return (u"""/**
sort_keys
=
True
,
sort_keys
=
True
,
indent
=
2
,
indent
=
2
,
ensure_ascii
=
False
,
ensure_ascii
=
False
,
separators
=
(
','
,
': '
)).
splitlines
())))
.
encode
(
'utf-8'
)
separators
=
(
','
,
': '
)).
splitlines
())))
product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Base_getHistoricalComparisonDifferenceList.py
View file @
c4e1dcf8
...
@@ -2,6 +2,7 @@ from Products.PythonScripts.standard import Object
...
@@ -2,6 +2,7 @@ from Products.PythonScripts.standard import Object
from
ZODB.POSException
import
ConflictError
from
ZODB.POSException
import
ConflictError
from
zExceptions
import
Unauthorized
from
zExceptions
import
Unauthorized
from
Products.ERP5Type.Document
import
newTempBase
from
Products.ERP5Type.Document
import
newTempBase
import
six
Base_translateString
=
context
.
Base_translateString
Base_translateString
=
context
.
Base_translateString
try
:
try
:
...
@@ -23,6 +24,20 @@ result = []
...
@@ -23,6 +24,20 @@ result = []
binary_data_explanation
=
Base_translateString
(
"Binary data can't be displayed"
)
binary_data_explanation
=
Base_translateString
(
"Binary data can't be displayed"
)
base_error_message
=
Base_translateString
(
'(value retrieval failed)'
)
base_error_message
=
Base_translateString
(
'(value retrieval failed)'
)
def
get_value_as_text
(
value
):
"""check if values are unicode convertible (binary are not)
"""
if
not
isinstance
(
value
,
six
.
text_type
):
try
:
if
isinstance
(
value
,
bytes
):
value
.
decode
(
'utf-8'
)
else
:
str
(
value
)
except
UnicodeDecodeError
:
value
=
binary_data_explanation
return
value
for
prop_dict
in
sorted
(
context
.
getPropertyMap
(),
key
=
lambda
prop
:
prop
[
'id'
]):
for
prop_dict
in
sorted
(
context
.
getPropertyMap
(),
key
=
lambda
prop
:
prop
[
'id'
]):
prop
=
prop_dict
[
'id'
]
prop
=
prop_dict
[
'id'
]
error
=
False
error
=
False
...
@@ -42,22 +57,9 @@ for prop_dict in sorted(context.getPropertyMap(), key=lambda prop: prop['id']):
...
@@ -42,22 +57,9 @@ for prop_dict in sorted(context.getPropertyMap(), key=lambda prop: prop['id']):
error
=
True
error
=
True
new_value
=
base_error_message
new_value
=
base_error_message
if
new_value
!=
old_value
or
error
:
if
new_value
!=
old_value
or
error
:
# check if values are unicode convertible (binary are not)
new_value
=
get_value_as_text
(
new_value
)
if
isinstance
(
new_value
,
(
str
,
unicode
)):
old_value
=
get_value_as_text
(
old_value
)
try
:
current_value
=
get_value_as_text
(
current_value
)
unicode
(
str
(
new_value
),
'utf-8'
)
except
UnicodeDecodeError
:
new_value
=
binary_data_explanation
if
isinstance
(
old_value
,
(
str
,
unicode
)):
try
:
unicode
(
str
(
old_value
),
'utf-8'
)
except
UnicodeDecodeError
:
old_value
=
binary_data_explanation
if
isinstance
(
current_value
,
(
str
,
unicode
)):
try
:
unicode
(
str
(
current_value
),
'utf-8'
)
except
UnicodeDecodeError
:
current_value
=
binary_data_explanation
x
=
{
'property_name'
:
prop
,
x
=
{
'property_name'
:
prop
,
'new_value'
:
new_value
,
'new_value'
:
new_value
,
'old_value'
:
old_value
,
'old_value'
:
old_value
,
...
...
product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/BusinessTemplate_getPythonSourceCodeMessageList.py
View file @
c4e1dcf8
...
@@ -53,7 +53,7 @@ def checkPythonScript(script_instance, script_path):
...
@@ -53,7 +53,7 @@ def checkPythonScript(script_instance, script_path):
'DateTime'
,
'whrandom'
,
'reorder'
,
'sets'
,
'test'
,
'math'
]
'DateTime'
,
'whrandom'
,
'reorder'
,
'sets'
,
'test'
,
'math'
]
code
=
script_instance
.
body
()
code
=
script_instance
.
body
()
if
six
.
PY2
:
if
six
.
PY2
:
code
=
unicod
e
(
code
,
'utf8'
)
code
=
six
.
text_typ
e
(
code
,
'utf8'
)
for
annotation
in
json
.
loads
(
portal
.
ERP5Site_checkPythonSourceCodeAsJSON
(
for
annotation
in
json
.
loads
(
portal
.
ERP5Site_checkPythonSourceCodeAsJSON
(
{
'bound_names'
:
extra_builtins
+
{
'bound_names'
:
extra_builtins
+
script_instance
.
getBindingAssignments
().
getAssignedNamesInOrder
(),
script_instance
.
getBindingAssignments
().
getAssignedNamesInOrder
(),
...
@@ -80,7 +80,7 @@ def checkComponent(component_instance):
...
@@ -80,7 +80,7 @@ def checkComponent(component_instance):
jio_key
=
component_relative_url
,),)
jio_key
=
component_relative_url
,),)
code
=
component_instance
.
getTextContent
()
code
=
component_instance
.
getTextContent
()
if
six
.
PY2
:
if
six
.
PY2
:
code
=
unicod
e
(
code
,
'utf8'
)
code
=
six
.
text_typ
e
(
code
,
'utf8'
)
for
annotation
in
json
.
loads
(
portal
.
ERP5Site_checkPythonSourceCodeAsJSON
(
for
annotation
in
json
.
loads
(
portal
.
ERP5Site_checkPythonSourceCodeAsJSON
(
{
'code'
:
code
}))[
'annotations'
]:
{
'code'
:
code
}))[
'annotations'
]:
annotation
[
'component_path'
]
=
component_relative_url
annotation
[
'component_path'
]
=
component_relative_url
...
...
product/ERP5Form/ListBox.py
View file @
c4e1dcf8
...
@@ -706,7 +706,7 @@ class ListBoxRenderer:
...
@@ -706,7 +706,7 @@ class ListBoxRenderer:
"""Return the title. Make sure that it is in unicode.
"""Return the title. Make sure that it is in unicode.
"""
"""
if
six
.
PY2
:
if
six
.
PY2
:
return
unicod
e
(
self
.
field
.
get_value
(
'title'
),
self
.
getEncoding
())
return
six
.
text_typ
e
(
self
.
field
.
get_value
(
'title'
),
self
.
getEncoding
())
else
:
else
:
return
self
.
field
.
get_value
(
'title'
)
return
self
.
field
.
get_value
(
'title'
)
...
@@ -898,7 +898,7 @@ class ListBoxRenderer:
...
@@ -898,7 +898,7 @@ class ListBoxRenderer:
"""
"""
columns
=
self
.
field
.
get_value
(
'columns'
)
columns
=
self
.
field
.
get_value
(
'columns'
)
if
six
.
PY2
:
if
six
.
PY2
:
return
[(
str
(
c
[
0
]),
unicod
e
(
c
[
1
],
self
.
getEncoding
()))
for
c
in
columns
]
return
[(
str
(
c
[
0
]),
six
.
text_typ
e
(
c
[
1
],
self
.
getEncoding
()))
for
c
in
columns
]
else
:
else
:
return
columns
return
columns
...
@@ -910,7 +910,7 @@ class ListBoxRenderer:
...
@@ -910,7 +910,7 @@ class ListBoxRenderer:
all_column_list
=
list
(
self
.
getColumnList
())
all_column_list
=
list
(
self
.
getColumnList
())
all_column_id_set
=
{
c
[
0
]
for
c
in
all_column_list
}
all_column_id_set
=
{
c
[
0
]
for
c
in
all_column_list
}
if
six
.
PY2
:
if
six
.
PY2
:
all_column_list
.
extend
((
str
(
c
[
0
]),
unicod
e
(
c
[
1
],
self
.
getEncoding
()))
all_column_list
.
extend
((
str
(
c
[
0
]),
six
.
text_typ
e
(
c
[
1
],
self
.
getEncoding
()))
for
c
in
self
.
field
.
get_value
(
'all_columns'
)
for
c
in
self
.
field
.
get_value
(
'all_columns'
)
if
c
[
0
]
not
in
all_column_id_set
)
if
c
[
0
]
not
in
all_column_id_set
)
else
:
else
:
...
@@ -932,7 +932,7 @@ class ListBoxRenderer:
...
@@ -932,7 +932,7 @@ class ListBoxRenderer:
stat_columns
=
self
.
field
.
get_value
(
'stat_columns'
)
stat_columns
=
self
.
field
.
get_value
(
'stat_columns'
)
if
stat_columns
:
if
stat_columns
:
if
six
.
PY2
:
if
six
.
PY2
:
stat_column_list
=
[(
str
(
c
[
0
]),
unicod
e
(
c
[
1
],
self
.
getEncoding
()))
for
c
in
stat_columns
]
stat_column_list
=
[(
str
(
c
[
0
]),
six
.
text_typ
e
(
c
[
1
],
self
.
getEncoding
()))
for
c
in
stat_columns
]
else
:
else
:
stat_column_list
=
stat_columns
stat_column_list
=
stat_columns
else
:
else
:
...
@@ -965,7 +965,7 @@ class ListBoxRenderer:
...
@@ -965,7 +965,7 @@ class ListBoxRenderer:
"""
"""
domain_root_list
=
self
.
field
.
get_value
(
'domain_root_list'
)
domain_root_list
=
self
.
field
.
get_value
(
'domain_root_list'
)
if
six
.
PY2
:
if
six
.
PY2
:
return
[(
str
(
c
[
0
]),
unicod
e
(
c
[
1
],
self
.
getEncoding
()))
for
c
in
domain_root_list
]
return
[(
str
(
c
[
0
]),
six
.
text_typ
e
(
c
[
1
],
self
.
getEncoding
()))
for
c
in
domain_root_list
]
else
:
else
:
return
domain_root_list
return
domain_root_list
...
@@ -975,7 +975,7 @@ class ListBoxRenderer:
...
@@ -975,7 +975,7 @@ class ListBoxRenderer:
"""
"""
report_root_list
=
self
.
field
.
get_value
(
'report_root_list'
)
report_root_list
=
self
.
field
.
get_value
(
'report_root_list'
)
if
six
.
PY2
:
if
six
.
PY2
:
return
[(
str
(
c
[
0
]),
unicod
e
(
c
[
1
],
self
.
getEncoding
()))
for
c
in
report_root_list
]
return
[(
str
(
c
[
0
]),
six
.
text_typ
e
(
c
[
1
],
self
.
getEncoding
()))
for
c
in
report_root_list
]
else
:
else
:
return
report_root_list
return
report_root_list
...
@@ -985,7 +985,7 @@ class ListBoxRenderer:
...
@@ -985,7 +985,7 @@ class ListBoxRenderer:
titles are in unicode"""
titles are in unicode"""
display_style_list
=
self
.
field
.
get_value
(
'display_style_list'
)
display_style_list
=
self
.
field
.
get_value
(
'display_style_list'
)
if
six
.
PY2
:
if
six
.
PY2
:
return
[(
str
(
c
[
0
]),
unicod
e
(
c
[
1
],
self
.
getEncoding
()))
for
c
in
\
return
[(
str
(
c
[
0
]),
six
.
text_typ
e
(
c
[
1
],
self
.
getEncoding
()))
for
c
in
\
display_style_list
]
display_style_list
]
else
:
else
:
return
display_style_list
return
display_style_list
...
@@ -1752,7 +1752,7 @@ class ListBoxRenderer:
...
@@ -1752,7 +1752,7 @@ class ListBoxRenderer:
if
not
isinstance
(
processed_value
,
six
.
text_type
):
if
not
isinstance
(
processed_value
,
six
.
text_type
):
if
six
.
PY2
:
if
six
.
PY2
:
processed_value
=
unicod
e
(
str
(
processed_value
),
self
.
getEncoding
(),
'replace'
)
processed_value
=
six
.
text_typ
e
(
str
(
processed_value
),
self
.
getEncoding
(),
'replace'
)
else
:
else
:
processed_value
=
str
(
processed_value
).
encode
(
processed_value
=
str
(
processed_value
).
encode
(
self
.
getEncoding
(),
'replace'
).
decode
()
self
.
getEncoding
(),
'replace'
).
decode
()
...
@@ -2382,7 +2382,7 @@ class ListBoxRendererLine:
...
@@ -2382,7 +2382,7 @@ class ListBoxRendererLine:
processed_value
=
u''
processed_value
=
u''
elif
not
isinstance
(
processed_value
,
six
.
text_type
):
elif
not
isinstance
(
processed_value
,
six
.
text_type
):
if
six
.
PY2
:
if
six
.
PY2
:
processed_value
=
unicod
e
(
str
(
processed_value
),
renderer
.
getEncoding
(),
'replace'
)
processed_value
=
six
.
text_typ
e
(
str
(
processed_value
),
renderer
.
getEncoding
(),
'replace'
)
else
:
else
:
processed_value
=
str
(
processed_value
).
encode
(
processed_value
=
str
(
processed_value
).
encode
(
renderer
.
getEncoding
(),
'replace'
).
decode
()
renderer
.
getEncoding
(),
'replace'
).
decode
()
...
...
product/ERP5Form/PDFTemplate.py
View file @
c4e1dcf8
...
@@ -44,6 +44,7 @@ from ZODB.POSException import ConflictError
...
@@ -44,6 +44,7 @@ from ZODB.POSException import ConflictError
from
Products.ERP5Type.Utils
import
UpperCase
from
Products.ERP5Type.Utils
import
UpperCase
from
zLOG
import
LOG
from
zLOG
import
LOG
import
six
try
:
try
:
from
zExceptions
import
ResourceLockedError
from
zExceptions
import
ResourceLockedError
...
@@ -304,18 +305,16 @@ if ReportTool:
...
@@ -304,18 +305,16 @@ if ReportTool:
#LOG('ReportTool_renderPDF', 0, 'encoding = %r' % encoding)
#LOG('ReportTool_renderPDF', 0, 'encoding = %r' % encoding)
rhandler
=
ERP5ResourceHandler
(
context
,
getattr
(
self
,
'resourcePath'
,
None
))
rhandler
=
ERP5ResourceHandler
(
context
,
getattr
(
self
,
'resourcePath'
,
None
))
# if zope gives us the xml in unicode
# we need to encode it before it can be parsed
template_xml
=
getattr
(
context
,
templatename
)(
*
args
,
**
kwargs
)
template_xml
=
getattr
(
context
,
templatename
)(
*
args
,
**
kwargs
)
if
type
(
template_xml
)
is
type
(
u''
):
if
not
isinstance
(
template_xml
,
six
.
text_type
):
template_xml
=
self
.
_encode
(
template_xml
,
encoding
)
template_xml
=
template_xml
.
decode
(
encoding
)
if
type
(
document_xml
)
is
type
(
u''
):
if
not
isinstance
(
document_xml
,
six
.
text_type
):
document_xml
=
self
.
_encode
(
document_xml
,
encoding
)
document_xml
=
document_xml
.
decode
(
encoding
)
#LOG('ReportTool_renderPDF', 0, 'template_xml = %r, document_xml = %r' % (template_xml, document_xml))
#LOG('ReportTool_renderPDF', 0, 'template_xml = %r, document_xml = %r' % (template_xml, document_xml))
# XXXXX Because reportlab does not support UTF-8, use Latin-1. What a mess.
# XXXXX Because reportlab does not support UTF-8, use Latin-1. What a mess.
template_xml
=
unicode
(
template_xml
,
encoding
)
.
encode
(
'iso-8859-1'
)
template_xml
=
template_xml
.
encode
(
'iso-8859-1'
)
document_xml
=
unicode
(
document_xml
,
encoding
).
encode
(
'iso-8859-1'
,
'replace'
)
document_xml
=
document_xml
.
encode
(
'iso-8859-1'
,
'replace'
)
encoding
=
'iso-8859-1'
encoding
=
'iso-8859-1'
# create the PDFTemplate from xml
# create the PDFTemplate from xml
...
...
product/ERP5OOo/FormPrintout.py
View file @
c4e1dcf8
...
@@ -894,7 +894,9 @@ class ODFStrategy(Implicit):
...
@@ -894,7 +894,9 @@ class ODFStrategy(Implicit):
if isinstance(field_value, six.text_type):
if isinstance(field_value, six.text_type):
value = field_value
value = field_value
elif field_value is not None:
elif field_value is not None:
value = unicode(str(field_value), 'utf-8')
value = str(field_value)
if six.PY2:
value = value.decode('utf-8')
return value
return value
class ODTStrategy(ODFStrategy):
class ODTStrategy(ODFStrategy):
...
...
product/ERP5Type/Accessor/TypeDefinition.py
View file @
c4e1dcf8
...
@@ -98,7 +98,7 @@ def asString(value):
...
@@ -98,7 +98,7 @@ def asString(value):
if
value
is
None
:
if
value
is
None
:
result
=
''
result
=
''
else
:
else
:
if
six
.
PY2
and
isinstance
(
value
,
unicod
e
):
if
six
.
PY2
and
isinstance
(
value
,
six
.
text_typ
e
):
result
=
value
.
encode
(
'utf-8'
)
result
=
value
.
encode
(
'utf-8'
)
elif
six
.
PY3
and
isinstance
(
value
,
bytes
):
elif
six
.
PY3
and
isinstance
(
value
,
bytes
):
result
=
value
.
decode
(
'utf-8'
)
result
=
value
.
decode
(
'utf-8'
)
...
...
product/ERP5Type/tests/testDynamicClassGeneration.py
View file @
c4e1dcf8
...
@@ -1389,10 +1389,14 @@ class TestZodbPropertySheet(ERP5TypeTestCase):
...
@@ -1389,10 +1389,14 @@ class TestZodbPropertySheet(ERP5TypeTestCase):
with
self
.
assertRaises
(
TypeError
):
with
self
.
assertRaises
(
TypeError
):
person
.
setSocialTitle
(
social_title_value
)
person
.
setSocialTitle
(
social_title_value
)
# Passing a unicode object to a not-Value setter should raise
with
self
.
assertRaises
(
TypeError
):
with
self
.
assertRaises
(
TypeError
):
organisation
=
self
.
portal
.
organisation_module
.
newContent
()
organisation
=
self
.
portal
.
organisation_module
.
newContent
()
person
.
setSubordination
(
unicode
(
organisation
.
getRelativeUrl
()))
if
six
.
PY2
:
# Passing a unicode object to a not-Value setter should raise
person
.
setSubordination
(
six
.
text_type
(
organisation
.
getRelativeUrl
()))
else
:
# Passing a bytes object to a not-Value setter should raise
person
.
setSubordination
(
organisation
.
getRelativeUrl
().
encode
())
from
Products.ERP5Type.Tool.ComponentTool
import
ComponentTool
from
Products.ERP5Type.Tool.ComponentTool
import
ComponentTool
...
...
product/PortalTransforms/transforms/safe_html.py
View file @
c4e1dcf8
...
@@ -535,7 +535,7 @@ class SafeHTML:
...
@@ -535,7 +535,7 @@ class SafeHTML:
# avoid breaking now.
# avoid breaking now.
# continue into the loop with repaired html
# continue into the loop with repaired html
else
:
else
:
if
isinstance
(
orig
,
unicod
e
):
if
isinstance
(
orig
,
six
.
text_typ
e
):
orig
=
orig
.
encode
(
'utf-8'
)
orig
=
orig
.
encode
(
'utf-8'
)
data
.
setData
(
orig
)
data
.
setData
(
orig
)
break
break
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment