Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Z
ZODB
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Nicolas Wavrant
ZODB
Commits
cf01843c
Commit
cf01843c
authored
Jun 07, 2013
by
Tres Seaver
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Use protocol defined in _compat.
parent
4d046937
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
39 additions
and
32 deletions
+39
-32
src/ZODB/BaseStorage.py
src/ZODB/BaseStorage.py
+2
-2
src/ZODB/ConflictResolution.py
src/ZODB/ConflictResolution.py
+1
-2
src/ZODB/DB.py
src/ZODB/DB.py
+2
-2
src/ZODB/ExportImport.py
src/ZODB/ExportImport.py
+2
-2
src/ZODB/FileStorage/FileStorage.py
src/ZODB/FileStorage/FileStorage.py
+2
-2
src/ZODB/_compat.py
src/ZODB/_compat.py
+2
-0
src/ZODB/broken.py
src/ZODB/broken.py
+6
-2
src/ZODB/fsIndex.py
src/ZODB/fsIndex.py
+2
-1
src/ZODB/serialize.py
src/ZODB/serialize.py
+1
-4
src/ZODB/tests/PackableStorage.py
src/ZODB/tests/PackableStorage.py
+2
-2
src/ZODB/tests/StorageTestBase.py
src/ZODB/tests/StorageTestBase.py
+2
-2
src/ZODB/tests/testFileStorage.py
src/ZODB/tests/testFileStorage.py
+4
-4
src/ZODB/tests/testSerialize.py
src/ZODB/tests/testSerialize.py
+2
-2
src/ZODB/tests/testblob.py
src/ZODB/tests/testblob.py
+7
-4
src/ZODB/tests/testfsIndex.py
src/ZODB/tests/testfsIndex.py
+2
-1
No files found.
src/ZODB/BaseStorage.py
View file @
cf01843c
...
@@ -31,7 +31,7 @@ import ZODB.interfaces
...
@@ -31,7 +31,7 @@ import ZODB.interfaces
from
ZODB
import
POSException
from
ZODB
import
POSException
from
ZODB.utils
import
z64
,
oid_repr
,
byte_ord
,
byte_chr
from
ZODB.utils
import
z64
,
oid_repr
,
byte_ord
,
byte_chr
from
ZODB.UndoLogCompatible
import
UndoLogCompatible
from
ZODB.UndoLogCompatible
import
UndoLogCompatible
from
ZODB._compat
import
dumps
,
py2_hasattr
from
ZODB._compat
import
dumps
,
_protocol
,
py2_hasattr
log
=
logging
.
getLogger
(
"ZODB.BaseStorage"
)
log
=
logging
.
getLogger
(
"ZODB.BaseStorage"
)
...
@@ -235,7 +235,7 @@ class BaseStorage(UndoLogCompatible):
...
@@ -235,7 +235,7 @@ class BaseStorage(UndoLogCompatible):
desc
=
transaction
.
description
desc
=
transaction
.
description
ext
=
transaction
.
_extension
ext
=
transaction
.
_extension
if
ext
:
if
ext
:
ext
=
dumps
(
ext
,
1
)
ext
=
dumps
(
ext
,
_protocol
)
else
:
else
:
ext
=
""
ext
=
""
...
...
src/ZODB/ConflictResolution.py
View file @
cf01843c
...
@@ -19,8 +19,7 @@ import six
...
@@ -19,8 +19,7 @@ import six
import
zope.interface
import
zope.interface
from
ZODB.POSException
import
ConflictError
from
ZODB.POSException
import
ConflictError
from
ZODB.loglevels
import
BLATHER
from
ZODB.loglevels
import
BLATHER
from
ZODB.serialize
import
_protocol
from
ZODB._compat
import
BytesIO
,
Unpickler
,
Pickler
,
_protocol
from
ZODB._compat
import
BytesIO
,
Unpickler
,
Pickler
# Subtle: Python 2.x has pickle.PicklingError and cPickle.PicklingError,
# Subtle: Python 2.x has pickle.PicklingError and cPickle.PicklingError,
# and these are unrelated classes! So we shouldn't use pickle.PicklingError,
# and these are unrelated classes! So we shouldn't use pickle.PicklingError,
...
...
src/ZODB/DB.py
View file @
cf01843c
...
@@ -23,7 +23,7 @@ import warnings
...
@@ -23,7 +23,7 @@ import warnings
from
ZODB.broken
import
find_global
from
ZODB.broken
import
find_global
from
ZODB.utils
import
z64
from
ZODB.utils
import
z64
from
ZODB.Connection
import
Connection
from
ZODB.Connection
import
Connection
from
ZODB._compat
import
Pickler
,
BytesIO
from
ZODB._compat
import
Pickler
,
_protocol
,
BytesIO
import
ZODB.serialize
import
ZODB.serialize
import
transaction.weakset
import
transaction.weakset
...
@@ -448,7 +448,7 @@ class DB(object):
...
@@ -448,7 +448,7 @@ class DB(object):
# Manually create a pickle for the root to put in the storage.
# Manually create a pickle for the root to put in the storage.
# The pickle must be in the special ZODB format.
# The pickle must be in the special ZODB format.
file
=
BytesIO
()
file
=
BytesIO
()
p
=
Pickler
(
file
,
ZODB
.
serialize
.
_protocol
)
p
=
Pickler
(
file
,
_protocol
)
p
.
dump
((
root
.
__class__
,
None
))
p
.
dump
((
root
.
__class__
,
None
))
p
.
dump
(
root
.
__getstate__
())
p
.
dump
(
root
.
__getstate__
())
t
=
transaction
.
Transaction
()
t
=
transaction
.
Transaction
()
...
...
src/ZODB/ExportImport.py
View file @
cf01843c
...
@@ -23,9 +23,9 @@ import six
...
@@ -23,9 +23,9 @@ import six
from
ZODB.blob
import
Blob
from
ZODB.blob
import
Blob
from
ZODB.interfaces
import
IBlobStorage
from
ZODB.interfaces
import
IBlobStorage
from
ZODB.POSException
import
ExportError
from
ZODB.POSException
import
ExportError
from
ZODB.serialize
import
referencesf
,
_protocol
from
ZODB.serialize
import
referencesf
from
ZODB.utils
import
p64
,
u64
,
cp
,
mktemp
from
ZODB.utils
import
p64
,
u64
,
cp
,
mktemp
from
ZODB._compat
import
Pickler
,
Unpickler
,
BytesIO
from
ZODB._compat
import
Pickler
,
Unpickler
,
BytesIO
,
_protocol
logger
=
logging
.
getLogger
(
'ZODB.ExportImport'
)
logger
=
logging
.
getLogger
(
'ZODB.ExportImport'
)
...
...
src/ZODB/FileStorage/FileStorage.py
View file @
cf01843c
...
@@ -41,7 +41,7 @@ from ZODB.fsIndex import fsIndex
...
@@ -41,7 +41,7 @@ from ZODB.fsIndex import fsIndex
from
ZODB
import
BaseStorage
,
ConflictResolution
,
POSException
from
ZODB
import
BaseStorage
,
ConflictResolution
,
POSException
from
ZODB.POSException
import
UndoError
,
POSKeyError
,
MultipleUndoErrors
from
ZODB.POSException
import
UndoError
,
POSKeyError
,
MultipleUndoErrors
from
ZODB.utils
import
p64
,
u64
,
z64
,
as_bytes
,
as_text
from
ZODB.utils
import
p64
,
u64
,
z64
,
as_bytes
,
as_text
from
ZODB._compat
import
Pickler
,
loads
,
decodebytes
,
encodebytes
from
ZODB._compat
import
Pickler
,
loads
,
decodebytes
,
encodebytes
,
_protocol
# Not all platforms have fsync
# Not all platforms have fsync
...
@@ -369,7 +369,7 @@ class FileStorage(
...
@@ -369,7 +369,7 @@ class FileStorage(
if
not
self
.
_is_read_only
:
if
not
self
.
_is_read_only
:
# Save the converted index.
# Save the converted index.
f
=
open
(
index_name
,
'wb'
)
f
=
open
(
index_name
,
'wb'
)
p
=
Pickler
(
f
,
1
)
p
=
Pickler
(
f
,
_protocol
)
info
[
'index'
]
=
index
info
[
'index'
]
=
index
p
.
dump
(
info
)
p
.
dump
(
info
)
f
.
close
()
f
.
close
()
...
...
src/ZODB/_compat.py
View file @
cf01843c
...
@@ -17,6 +17,7 @@ try:
...
@@ -17,6 +17,7 @@ try:
from
cPickle
import
Pickler
,
Unpickler
,
dump
,
dumps
,
loads
from
cPickle
import
Pickler
,
Unpickler
,
dump
,
dumps
,
loads
IMPORT_MAPPING
=
{}
IMPORT_MAPPING
=
{}
NAME_MAPPING
=
{}
NAME_MAPPING
=
{}
_protocol
=
1
except
ImportError
:
except
ImportError
:
# Python 3.x: can't use stdlib's pickle because
# Python 3.x: can't use stdlib's pickle because
# http://bugs.python.org/issue6784
# http://bugs.python.org/issue6784
...
@@ -49,6 +50,7 @@ except ImportError:
...
@@ -49,6 +50,7 @@ except ImportError:
def
loads
(
s
):
def
loads
(
s
):
return
zodbpickle
.
pickle
.
loads
(
s
,
encoding
=
'ASCII'
,
errors
=
'bytes'
)
return
zodbpickle
.
pickle
.
loads
(
s
,
encoding
=
'ASCII'
,
errors
=
'bytes'
)
_protocol
=
3
# XXX: consistent spelling of inst_persistent_id/persistent_id?
# XXX: consistent spelling of inst_persistent_id/persistent_id?
...
...
src/ZODB/broken.py
View file @
cf01843c
...
@@ -20,7 +20,8 @@ import persistent
...
@@ -20,7 +20,8 @@ import persistent
import
zope.interface
import
zope.interface
import
ZODB.interfaces
import
ZODB.interfaces
from
ZODB._compat
import
loads
,
dumps
,
IMPORT_MAPPING
,
NAME_MAPPING
from
ZODB._compat
import
IMPORT_MAPPING
from
ZODB._compat
import
NAME_MAPPING
broken_cache
=
{}
broken_cache
=
{}
...
@@ -82,7 +83,10 @@ class Broken(object):
...
@@ -82,7 +83,10 @@ class Broken(object):
>>> r[2]
>>> r[2]
{'x': 1}
{'x': 1}
>>> a2 = loads(dumps(a, 1))
>>> from ZODB._compat import dumps
>>> from ZODB._compat import loads
>>> from ZODB._compat import _protocol
>>> a2 = loads(dumps(a, _protocol))
>>> a2
>>> a2
<broken not.there.Atall instance>
<broken not.there.Atall instance>
>>> a2.__Broken_newargs__
>>> a2.__Broken_newargs__
...
...
src/ZODB/fsIndex.py
View file @
cf01843c
...
@@ -47,6 +47,7 @@ import six
...
@@ -47,6 +47,7 @@ import six
from
ZODB._compat
import
INT_TYPES
from
ZODB._compat
import
INT_TYPES
from
ZODB._compat
import
Pickler
from
ZODB._compat
import
Pickler
from
ZODB._compat
import
Unpickler
from
ZODB._compat
import
Unpickler
from
ZODB._compat
import
_protocol
# convert between numbers and six-byte strings
# convert between numbers and six-byte strings
...
@@ -109,7 +110,7 @@ class fsIndex(object):
...
@@ -109,7 +110,7 @@ class fsIndex(object):
def
save
(
self
,
pos
,
fname
):
def
save
(
self
,
pos
,
fname
):
with
open
(
fname
,
'wb'
)
as
f
:
with
open
(
fname
,
'wb'
)
as
f
:
pickler
=
Pickler
(
f
,
1
)
pickler
=
Pickler
(
f
,
_protocol
)
pickler
.
fast
=
True
pickler
.
fast
=
True
pickler
.
dump
(
pos
)
pickler
.
dump
(
pos
)
for
k
,
v
in
six
.
iteritems
(
self
.
_data
):
for
k
,
v
in
six
.
iteritems
(
self
.
_data
):
...
...
src/ZODB/serialize.py
View file @
cf01843c
...
@@ -140,14 +140,11 @@ from persistent import Persistent
...
@@ -140,14 +140,11 @@ from persistent import Persistent
from
persistent.wref
import
WeakRefMarker
,
WeakRef
from
persistent.wref
import
WeakRefMarker
,
WeakRef
from
ZODB
import
broken
from
ZODB
import
broken
from
ZODB.POSException
import
InvalidObjectReference
from
ZODB.POSException
import
InvalidObjectReference
from
ZODB._compat
import
Pickler
,
Unpickler
,
BytesIO
from
ZODB._compat
import
Pickler
,
Unpickler
,
BytesIO
,
_protocol
_oidtypes
=
bytes
,
type
(
None
)
_oidtypes
=
bytes
,
type
(
None
)
# Py3: Python 3 uses protocol 3 by default, which is not loadable by Python
# 2. If we want this, we can add a condition here for Python 3.
_protocol
=
1
# Might to update or redo coptimizations to reflect weakrefs:
# Might to update or redo coptimizations to reflect weakrefs:
# from ZODB.coptimizations import new_persistent_id
# from ZODB.coptimizations import new_persistent_id
...
...
src/ZODB/tests/PackableStorage.py
View file @
cf01843c
...
@@ -22,11 +22,11 @@ from persistent import Persistent
...
@@ -22,11 +22,11 @@ from persistent import Persistent
from
persistent.mapping
import
PersistentMapping
from
persistent.mapping
import
PersistentMapping
from
ZODB
import
DB
from
ZODB
import
DB
from
ZODB.POSException
import
ConflictError
,
StorageError
from
ZODB.POSException
import
ConflictError
,
StorageError
from
ZODB.serialize
import
referencesf
,
_protocol
from
ZODB.serialize
import
referencesf
from
ZODB.tests.MinPO
import
MinPO
from
ZODB.tests.MinPO
import
MinPO
from
ZODB.tests.MTStorage
import
TestThread
from
ZODB.tests.MTStorage
import
TestThread
from
ZODB.tests.StorageTestBase
import
snooze
from
ZODB.tests.StorageTestBase
import
snooze
from
ZODB._compat
import
loads
,
Pickler
,
Unpickler
,
BytesIO
from
ZODB._compat
import
loads
,
Pickler
,
Unpickler
,
BytesIO
,
_protocol
import
transaction
import
transaction
import
ZODB.interfaces
import
ZODB.interfaces
import
ZODB.tests.util
import
ZODB.tests.util
...
...
src/ZODB/tests/StorageTestBase.py
View file @
cf01843c
...
@@ -25,7 +25,7 @@ import transaction
...
@@ -25,7 +25,7 @@ import transaction
from
ZODB.utils
import
u64
from
ZODB.utils
import
u64
from
ZODB.tests.MinPO
import
MinPO
from
ZODB.tests.MinPO
import
MinPO
from
ZODB._compat
import
Pickler
,
Unpickler
,
BytesIO
from
ZODB._compat
import
Pickler
,
Unpickler
,
BytesIO
,
_protocol
import
ZODB.tests.util
import
ZODB.tests.util
...
@@ -50,7 +50,7 @@ def _persistent_id(obj):
...
@@ -50,7 +50,7 @@ def _persistent_id(obj):
def
zodb_pickle
(
obj
):
def
zodb_pickle
(
obj
):
"""Create a pickle in the format expected by ZODB."""
"""Create a pickle in the format expected by ZODB."""
f
=
BytesIO
()
f
=
BytesIO
()
p
=
Pickler
(
f
,
1
)
p
=
Pickler
(
f
,
_protocol
)
if
sys
.
version_info
[
0
]
<
3
:
if
sys
.
version_info
[
0
]
<
3
:
p
.
inst_persistent_id
=
_persistent_id
p
.
inst_persistent_id
=
_persistent_id
else
:
else
:
...
...
src/ZODB/tests/testFileStorage.py
View file @
cf01843c
...
@@ -32,7 +32,7 @@ from ZODB.tests import HistoryStorage, IteratorStorage, Corruption
...
@@ -32,7 +32,7 @@ from ZODB.tests import HistoryStorage, IteratorStorage, Corruption
from
ZODB.tests
import
RevisionStorage
,
PersistentStorage
,
MTStorage
from
ZODB.tests
import
RevisionStorage
,
PersistentStorage
,
MTStorage
from
ZODB.tests
import
ReadOnlyStorage
,
RecoveryStorage
from
ZODB.tests
import
ReadOnlyStorage
,
RecoveryStorage
from
ZODB.tests.StorageTestBase
import
MinPO
,
zodb_pickle
from
ZODB.tests.StorageTestBase
import
MinPO
,
zodb_pickle
from
ZODB._compat
import
dump
,
dumps
from
ZODB._compat
import
dump
,
dumps
,
_protocol
class
FileStorageTests
(
class
FileStorageTests
(
...
@@ -92,7 +92,7 @@ class FileStorageTests(
...
@@ -92,7 +92,7 @@ class FileStorageTests(
data
[
'index'
]
=
newindex
data
[
'index'
]
=
newindex
with
open
(
'FileStorageTests.fs.index'
,
'wb'
)
as
fp
:
with
open
(
'FileStorageTests.fs.index'
,
'wb'
)
as
fp
:
dump
(
data
,
fp
,
1
)
dump
(
data
,
fp
,
_protocol
)
return
index
return
index
def
check_conversion_to_fsIndex
(
self
,
read_only
=
False
):
def
check_conversion_to_fsIndex
(
self
,
read_only
=
False
):
...
@@ -390,14 +390,14 @@ class AnalyzeDotPyTest(StorageTestBase.StorageTestBase):
...
@@ -390,14 +390,14 @@ class AnalyzeDotPyTest(StorageTestBase.StorageTestBase):
j
=
0
j
=
0
oid
,
revid
=
oids
[
j
]
oid
,
revid
=
oids
[
j
]
serial
=
self
.
_storage
.
store
(
serial
=
self
.
_storage
.
store
(
oid
,
revid
,
dumps
(
OOBTree
,
1
),
""
,
t
)
oid
,
revid
,
dumps
(
OOBTree
,
_protocol
),
""
,
t
)
oids
[
j
][
1
]
=
serial
oids
[
j
][
1
]
=
serial
# and it could be from a broken module
# and it could be from a broken module
j
=
1
j
=
1
oid
,
revid
=
oids
[
j
]
oid
,
revid
=
oids
[
j
]
serial
=
self
.
_storage
.
store
(
serial
=
self
.
_storage
.
store
(
oid
,
revid
,
dumps
(
Broken
,
1
),
""
,
t
)
oid
,
revid
,
dumps
(
Broken
,
_protocol
),
""
,
t
)
oids
[
j
][
1
]
=
serial
oids
[
j
][
1
]
=
serial
# but mostly it looks like this
# but mostly it looks like this
...
...
src/ZODB/tests/testSerialize.py
View file @
cf01843c
...
@@ -17,7 +17,7 @@ import unittest
...
@@ -17,7 +17,7 @@ import unittest
import
ZODB.tests.util
import
ZODB.tests.util
from
ZODB
import
serialize
from
ZODB
import
serialize
from
ZODB._compat
import
Pickler
,
BytesIO
from
ZODB._compat
import
Pickler
,
BytesIO
,
_protocol
class
ClassWithNewargs
(
int
):
class
ClassWithNewargs
(
int
):
...
@@ -33,7 +33,7 @@ class ClassWithoutNewargs(object):
...
@@ -33,7 +33,7 @@ class ClassWithoutNewargs(object):
def
make_pickle
(
ob
):
def
make_pickle
(
ob
):
sio
=
BytesIO
()
sio
=
BytesIO
()
p
=
Pickler
(
sio
,
1
)
p
=
Pickler
(
sio
,
_protocol
)
p
.
dump
(
ob
)
p
.
dump
(
ob
)
return
sio
.
getvalue
()
return
sio
.
getvalue
()
...
...
src/ZODB/tests/testblob.py
View file @
cf01843c
...
@@ -16,7 +16,7 @@ from ZODB.blob import BushyLayout
...
@@ -16,7 +16,7 @@ from ZODB.blob import BushyLayout
from
ZODB.DB
import
DB
from
ZODB.DB
import
DB
from
ZODB.FileStorage
import
FileStorage
from
ZODB.FileStorage
import
FileStorage
from
ZODB.tests.testConfig
import
ConfigTestBase
from
ZODB.tests.testConfig
import
ConfigTestBase
from
ZODB._compat
import
Pickler
,
Unpickler
from
ZODB._compat
import
Pickler
,
Unpickler
,
_protocol
import
os
import
os
if
os
.
environ
.
get
(
'USE_ZOPE_TESTING_DOCTEST'
):
if
os
.
environ
.
get
(
'USE_ZOPE_TESTING_DOCTEST'
):
...
@@ -125,7 +125,7 @@ class BlobCloneTests(ZODB.tests.util.TestCase):
...
@@ -125,7 +125,7 @@ class BlobCloneTests(ZODB.tests.util.TestCase):
transaction
.
commit
()
transaction
.
commit
()
stream
=
BytesIO
()
stream
=
BytesIO
()
p
=
Pickler
(
stream
,
1
)
p
=
Pickler
(
stream
,
_protocol
)
p
.
dump
(
root
[
'blob'
])
p
.
dump
(
root
[
'blob'
])
u
=
Unpickler
(
stream
)
u
=
Unpickler
(
stream
)
stream
.
seek
(
0
)
stream
.
seek
(
0
)
...
@@ -742,7 +742,8 @@ def storage_reusable_suite(prefix, factory,
...
@@ -742,7 +742,8 @@ def storage_reusable_suite(prefix, factory,
suite
=
unittest
.
TestSuite
()
suite
=
unittest
.
TestSuite
()
suite
.
addTest
(
doctest
.
DocFileSuite
(
suite
.
addTest
(
doctest
.
DocFileSuite
(
"blob_connection.txt"
,
"blob_importexport.txt"
,
"blob_connection.txt"
,
"blob_importexport.txt"
,
"blob_transaction.txt"
,
"blob_transaction.txt"
,
setUp
=
setup
,
tearDown
=
zope
.
testing
.
setupstack
.
tearDown
,
setUp
=
setup
,
tearDown
=
zope
.
testing
.
setupstack
.
tearDown
,
checker
=
zope
.
testing
.
renormalizing
.
RENormalizing
([
checker
=
zope
.
testing
.
renormalizing
.
RENormalizing
([
...
@@ -805,7 +806,9 @@ def test_suite():
...
@@ -805,7 +806,9 @@ def test_suite():
suite.addTest(unittest.makeSuite(BlobCloneTests))
suite.addTest(unittest.makeSuite(BlobCloneTests))
suite.addTest(unittest.makeSuite(BushyLayoutTests))
suite.addTest(unittest.makeSuite(BushyLayoutTests))
suite.addTest(doctest.DocFileSuite(
suite.addTest(doctest.DocFileSuite(
"blob_basic.txt", "blob_consume.txt", "blob_tempdir.txt",
"blob_basic.txt",
"blob_consume.txt",
"blob_tempdir.txt",
"blobstorage_packing.txt",
"blobstorage_packing.txt",
setUp=setUp,
setUp=setUp,
tearDown=zope.testing.setupstack.tearDown,
tearDown=zope.testing.setupstack.tearDown,
...
...
src/ZODB/tests/testfsIndex.py
View file @
cf01843c
...
@@ -221,8 +221,9 @@ Note that we pass a file position, which gets saved with the index data.
...
@@ -221,8 +221,9 @@ Note that we pass a file position, which gets saved with the index data.
If we save the data in the old format, we can still read it:
If we save the data in the old format, we can still read it:
>>> from ZODB._compat import dump
>>> from ZODB._compat import dump
>>> from ZODB._compat import _protocol
>>> with open('old', 'wb') as fp:
>>> with open('old', 'wb') as fp:
... dump(dict(pos=42, index=index), fp,
1
)
... dump(dict(pos=42, index=index), fp,
_protocol
)
>>> info = fsIndex.load('old')
>>> info = fsIndex.load('old')
>>> info['pos']
>>> info['pos']
42
42
...
...
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