Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
asn1c
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
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
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Libraries
asn1c
Commits
d357f3d5
Commit
d357f3d5
authored
7 years ago
by
Lev Walkin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix ioc value encoding
parent
83d8b2f2
Changes
11
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
513 additions
and
50 deletions
+513
-50
libasn1compiler/asn1c_ioc.c
libasn1compiler/asn1c_ioc.c
+4
-4
libasn1fix/asn1fix_cws.c
libasn1fix/asn1fix_cws.c
+41
-31
tests/tests-asn1c-compiler/125-bitstring-constraint-OK.asn1.-X
.../tests-asn1c-compiler/125-bitstring-constraint-OK.asn1.-X
+1
-1
tests/tests-asn1c-compiler/139-component-relation-OK.asn1.-P
tests/tests-asn1c-compiler/139-component-relation-OK.asn1.-P
+4
-4
tests/tests-asn1c-compiler/140-component-relation-OK.asn1
tests/tests-asn1c-compiler/140-component-relation-OK.asn1
+1
-1
tests/tests-asn1c-compiler/140-component-relation-OK.asn1.-EFprint-class-matrix
...iler/140-component-relation-OK.asn1.-EFprint-class-matrix
+1
-1
tests/tests-asn1c-compiler/140-component-relation-OK.asn1.-P
tests/tests-asn1c-compiler/140-component-relation-OK.asn1.-P
+4
-4
tests/tests-asn1c-compiler/141-component-relation-OK.asn1
tests/tests-asn1c-compiler/141-component-relation-OK.asn1
+38
-0
tests/tests-asn1c-compiler/141-component-relation-OK.asn1.-EFprint-class-matrix
...iler/141-component-relation-OK.asn1.-EFprint-class-matrix
+40
-0
tests/tests-asn1c-compiler/141-component-relation-OK.asn1.-P
tests/tests-asn1c-compiler/141-component-relation-OK.asn1.-P
+375
-0
tests/tests-asn1c-compiler/98-attribute-class-OK.asn1.-P
tests/tests-asn1c-compiler/98-attribute-class-OK.asn1.-P
+4
-4
No files found.
libasn1compiler/asn1c_ioc.c
View file @
d357f3d5
...
...
@@ -132,8 +132,8 @@ emit_ioc_value(arg_t *arg, struct asn1p_ioc_cell_s *cell) {
return
-
1
;
}
}
OUT
(
"static const %s asn_VAL_%
s_%d = "
,
prim_type
,
MKID
(
cell
->
value
)
,
cell
->
value
->
_type_unique_index
);
OUT
(
"static const %s asn_VAL_%
d_%s = "
,
prim_type
,
cell
->
value
->
_type_unique_index
,
MKID
(
cell
->
value
)
);
asn1p_expr_t
*
expr_value
=
cell
->
value
;
while
(
expr_value
->
value
->
type
==
ATV_REFERENCED
)
{
...
...
@@ -198,8 +198,8 @@ emit_ioc_cell(arg_t *arg, struct asn1p_ioc_cell_s *cell) {
GEN_INCLUDE
(
asn1c_type_name
(
arg
,
cell
->
value
,
TNF_INCLUDE
));
OUT
(
"aioc__value, "
);
OUT
(
"&asn_DEF_%s, "
,
asn1c_type_name
(
arg
,
cell
->
value
,
TNF_SAFE
));
OUT
(
"&asn_VAL_%
s_%d"
,
MKID
(
cell
->
value
)
,
cell
->
value
->
_type_unique_index
);
OUT
(
"&asn_VAL_%
d_%s"
,
cell
->
value
->
_type_unique_index
,
MKID
(
cell
->
value
)
);
}
else
if
(
cell
->
value
->
meta_type
==
AMT_TYPEREF
)
{
GEN_INCLUDE
(
asn1c_type_name
(
arg
,
cell
->
value
,
TNF_INCLUDE
));
...
...
This diff is collapsed.
Click to expand it.
libasn1fix/asn1fix_cws.c
View file @
d357f3d5
...
...
@@ -4,8 +4,8 @@
static
int
_asn1f_parse_class_object_data
(
arg_t
*
,
asn1p_expr_t
*
eclass
,
struct
asn1p_ioc_row_s
*
row
,
asn1p_wsyntx_t
*
syntax
,
const
uint8_t
*
buf
,
const
uint8_t
*
bend
,
int
optional_mode
,
const
uint8_t
**
newpos
);
static
int
_asn1f_assign_cell_value
(
arg_t
*
arg
,
struct
asn1p_ioc_cell_s
*
cell
,
const
uint8_t
*
buf
,
const
uint8_t
*
bend
);
int
optional_mode
,
const
uint8_t
**
newpos
,
int
counter
);
static
int
_asn1f_assign_cell_value
(
arg_t
*
arg
,
struct
asn1p_ioc_cell_s
*
cell
,
const
uint8_t
*
buf
,
const
uint8_t
*
bend
,
int
counter
);
static
asn1p_wsyntx_chunk_t
*
asn1f_next_literal_chunk
(
asn1p_wsyntx_t
*
syntax
,
asn1p_wsyntx_chunk_t
*
chunk
,
const
uint8_t
*
buf
);
int
...
...
@@ -43,7 +43,7 @@ asn1f_check_class_object(arg_t *arg) {
expr
->
value
->
value
.
string
.
buf
+
1
,
expr
->
value
->
value
.
string
.
buf
+
expr
->
value
->
value
.
string
.
size
-
1
,
0
,
0
);
0
,
0
,
0
);
asn1p_ioc_row_delete
(
row
);
...
...
@@ -74,6 +74,7 @@ struct parse_object_key {
arg_t
*
arg
;
asn1p_expr_t
*
expr
;
/* InformationObjectSet */
asn1p_expr_t
*
eclass
;
/* CLASS */
int
sequence
;
/* Sequence counter */
};
/*
...
...
@@ -120,11 +121,13 @@ _asn1f_parse_object_cb(const uint8_t *buf, size_t size, void *keyp) {
asn1p_ioc_row_t
*
row
;
int
ret
;
key
->
sequence
++
;
row
=
asn1p_ioc_row_new
(
eclass
);
assert
(
row
);
ret
=
_asn1f_parse_class_object_data
(
arg
,
eclass
,
row
,
eclass
->
with_syntax
,
buf
,
buf
+
size
,
0
,
0
);
buf
,
buf
+
size
,
0
,
0
,
key
->
sequence
);
if
(
ret
)
{
LOG
((
int
)(
ret
<
0
),
"Cannot parse %s of CLASS %s found at line %d"
,
...
...
@@ -143,7 +146,7 @@ _asn1f_parse_object_cb(const uint8_t *buf, size_t size, void *keyp) {
row
=
asn1p_ioc_row_new
(
eclass
);
assert
(
row
);
ret
=
_asn1f_parse_class_object_data
(
arg
,
eclass
,
row
,
eclass
->
with_syntax
,
buf
,
buf
+
size
,
0
,
0
);
buf
,
buf
+
size
,
0
,
0
,
key
->
sequence
);
assert
(
ret
==
0
);
if
(
_asn1f_add_unique_row
(
arg
,
expr
,
row
)
!=
0
)
...
...
@@ -261,6 +264,7 @@ asn1f_parse_class_object(arg_t *arg) {
.
arg
=
arg
,
.
expr
=
expr
,
.
eclass
=
eclass
,
.
sequence
=
0
};
switch
(
source
)
{
...
...
@@ -288,7 +292,7 @@ static int
_asn1f_parse_class_object_data
(
arg_t
*
arg
,
asn1p_expr_t
*
eclass
,
struct
asn1p_ioc_row_s
*
row
,
asn1p_wsyntx_t
*
syntax
,
const
uint8_t
*
buf
,
const
uint8_t
*
bend
,
int
optional_mode
,
const
uint8_t
**
newpos
)
{
int
optional_mode
,
const
uint8_t
**
newpos
,
int
counter
)
{
struct
asn1p_wsyntx_chunk_s
*
chunk
;
int
ret
;
...
...
@@ -342,7 +346,7 @@ _asn1f_parse_class_object_data(arg_t *arg, asn1p_expr_t *eclass,
DEBUG
(
"Reference %s satisfied by %s (%d)"
,
chunk
->
content
.
token
,
buf
,
p
-
buf
);
ret
=
_asn1f_assign_cell_value
(
arg
,
cell
,
buf
,
p
);
ret
=
_asn1f_assign_cell_value
(
arg
,
cell
,
buf
,
p
,
counter
);
if
(
ret
)
return
ret
;
buf
=
p
;
if
(
newpos
)
*
newpos
=
buf
;
...
...
@@ -351,7 +355,7 @@ _asn1f_parse_class_object_data(arg_t *arg, asn1p_expr_t *eclass,
const
uint8_t
*
np
=
0
;
SKIPSPACES
;
ret
=
_asn1f_parse_class_object_data
(
arg
,
eclass
,
row
,
chunk
->
content
.
syntax
,
buf
,
bend
,
1
,
&
np
);
chunk
->
content
.
syntax
,
buf
,
bend
,
1
,
&
np
,
counter
);
if
(
newpos
)
*
newpos
=
np
;
if
(
ret
&&
np
!=
buf
)
return
ret
;
...
...
@@ -368,9 +372,9 @@ _asn1f_parse_class_object_data(arg_t *arg, asn1p_expr_t *eclass,
static
int
_asn1f_assign_cell_value
(
arg_t
*
arg
,
struct
asn1p_ioc_cell_s
*
cell
,
const
uint8_t
*
buf
,
const
uint8_t
*
bend
)
{
const
uint8_t
*
buf
,
const
uint8_t
*
bend
,
int
counter
)
{
asn1p_expr_t
*
expr
=
(
asn1p_expr_t
*
)
NULL
;
char
*
p
;
char
*
mivr
;
/* Most Immediate Value Representation */
int
new_ref
=
1
;
asn1p_t
*
asn
;
asn1p_module_t
*
mod
;
...
...
@@ -385,19 +389,19 @@ _asn1f_assign_cell_value(arg_t *arg, struct asn1p_ioc_cell_s *cell,
return
-
1
;
}
p
=
malloc
(
bend
-
buf
+
1
);
assert
(
p
);
memcpy
(
p
,
buf
,
bend
-
buf
);
p
[
bend
-
buf
]
=
'\0'
;
mivr
=
malloc
(
bend
-
buf
+
1
);
assert
(
mivr
);
memcpy
(
mivr
,
buf
,
bend
-
buf
);
mivr
[
bend
-
buf
]
=
'\0'
;
/* remove trailing space */
for
(
i
=
bend
-
buf
-
1
;
(
i
>
0
)
&&
isspace
(
p
[
i
]);
i
--
)
p
[
i
]
=
'\0'
;
for
(
i
=
bend
-
buf
-
1
;
(
i
>
0
)
&&
isspace
(
mivr
[
i
]);
i
--
)
mivr
[
i
]
=
'\0'
;
/* This value 100 should be larger than following formatting string */
psize
=
bend
-
buf
+
100
;
pp
=
malloc
(
psize
);
if
(
pp
==
NULL
)
{
free
(
p
);
free
(
mivr
);
return
-
1
;
}
...
...
@@ -406,7 +410,7 @@ _asn1f_assign_cell_value(arg_t *arg, struct asn1p_ioc_cell_s *cell,
"M DEFINITIONS ::=
\n
BEGIN
\n
"
"V ::= %s
\n
"
"END
\n
"
,
p
mivr
);
}
else
if
(
cell
->
field
->
expr_type
==
A1TC_CLASSFIELD_FTVFS
)
{
type_expr
=
TQ_FIRST
(
&
(
cell
->
field
->
members
));
...
...
@@ -417,11 +421,11 @@ _asn1f_assign_cell_value(arg_t *arg, struct asn1p_ioc_cell_s *cell,
type_expr
->
reference
?
type_expr
->
reference
->
components
[
0
].
name
:
_asn1p_expr_type2string
(
type_expr
->
expr_type
),
p
mivr
);
}
else
{
WARNING
(
"asn1c only be able to parse TypeFieldSpec and FixedTypeValueFieldSpec. Failed when parsing %s at line %d
\n
"
,
p
,
arg
->
expr
->
_lineno
);
free
(
p
);
WARNING
(
"asn1c only be able to parse TypeFieldSpec and FixedTypeValueFieldSpec. Failed when parsing %s at line %d
\n
"
,
mivr
,
arg
->
expr
->
_lineno
);
free
(
mivr
);
free
(
pp
);
return
-
1
;
}
...
...
@@ -435,10 +439,10 @@ _asn1f_assign_cell_value(arg_t *arg, struct asn1p_ioc_cell_s *cell,
if
(
asn
==
NULL
)
{
FATAL
(
"Cannot parse Setting token %s "
"at line %d"
,
p
,
mivr
,
arg
->
expr
->
_lineno
);
free
(
p
);
free
(
mivr
);
return
-
1
;
}
else
{
mod
=
TQ_FIRST
(
&
(
asn
->
modules
));
...
...
@@ -446,13 +450,19 @@ _asn1f_assign_cell_value(arg_t *arg, struct asn1p_ioc_cell_s *cell,
expr
=
TQ_REMOVE
(
&
(
mod
->
members
),
next
);
assert
(
expr
);
free
(
expr
->
Identifier
);
expr
->
parent_expr
=
NULL
;
asn1p_expr_set_source
(
expr
,
arg
->
expr
->
module
,
arg
->
expr
->
_lineno
);
if
(
expr
->
reference
)
{
expr
->
_type_unique_index
=
counter
;
DEBUG
(
"Parsed identifier %s, mivr [%s], reference [%s] value [%s]"
,
expr
->
Identifier
,
mivr
,
asn1p_ref_string
(
expr
->
reference
),
asn1f_printable_value
(
expr
->
value
));
free
(
expr
->
Identifier
);
if
(
expr
->
value
)
{
expr
->
Identifier
=
strdup
(
asn1f_printable_value
(
expr
->
value
));
}
else
if
(
expr
->
reference
)
{
expr
->
Identifier
=
strdup
(
expr
->
reference
->
components
[
expr
->
reference
->
comp_count
-
1
].
name
);
}
else
{
expr
->
Identifier
=
p
;
expr
->
Identifier
=
mivr
;
}
asn1p_delete
(
asn
);
}
...
...
@@ -467,21 +477,21 @@ _asn1f_assign_cell_value(arg_t *arg, struct asn1p_ioc_cell_s *cell,
expr
->
reference
=
0
;
asn1p_expr_free
(
expr
);
FATAL
(
"Cannot find %s referenced by %s at line %d"
,
p
,
arg
->
expr
->
Identifier
,
mivr
,
arg
->
expr
->
Identifier
,
arg
->
expr
->
_lineno
);
free
(
p
);
/* freeing must happen *after* p was used in FATAL() */
free
(
mivr
);
return
-
1
;
}
}
DEBUG
(
"Field %s assignment of %s got %s"
,
cell
->
field
->
Identifier
,
p
,
expr
->
Identifier
);
cell
->
field
->
Identifier
,
mivr
,
expr
->
Identifier
);
cell
->
value
=
expr
;
cell
->
new_ref
=
new_ref
;
if
(
expr
->
Identifier
!=
p
)
{
free
(
p
);
if
(
expr
->
Identifier
!=
mivr
)
{
free
(
mivr
);
}
return
0
;
...
...
This diff is collapsed.
Click to expand it.
tests/tests-asn1c-compiler/125-bitstring-constraint-OK.asn1.-X
View file @
d357f3d5
...
...
@@ -3,6 +3,6 @@
<!-- ASN.1 module
ModuleBitStringConstraint { iso org(3) dod(6) internet(1) private(4)
enterprise(1) spelio(9363) software(1) asn1c(5) test(1) 125 }
found in ../
tests
/125-bitstring-constraint-OK.asn1 -->
found in ../
../tests/tests-asn1c-compiler
/125-bitstring-constraint-OK.asn1 -->
<!ELEMENT T (flag1?, flag2?, flag3?)>
This diff is collapsed.
Click to expand it.
tests/tests-asn1c-compiler/139-component-relation-OK.asn1.-P
View file @
d357f3d5
...
...
@@ -28,12 +28,12 @@ extern asn_TYPE_descriptor_t asn_DEF_Frame;
/*** <<< IOC-TABLES [Frame] >>> ***/
static const long asn_VAL_
basicMessage_0
= 1;
static const long asn_VAL_2_
0
= 2;
static const long asn_VAL_
1_basicMessage
= 1;
static const long asn_VAL_2_
2
= 2;
static const asn_ioc_cell_t asn_IOS_FrameTypes_1_rows[] = {
{ "&id", aioc__value, &asn_DEF_NativeInteger, &asn_VAL_
basicMessage_0
},
{ "&id", aioc__value, &asn_DEF_NativeInteger, &asn_VAL_
1_basicMessage
},
{ "&Type", aioc__type, &asn_DEF_PrimitiveMessage },
{ "&id", aioc__value, &asn_DEF_NativeInteger, &asn_VAL_2_
0
},
{ "&id", aioc__value, &asn_DEF_NativeInteger, &asn_VAL_2_
2
},
{ "&Type", aioc__type, &asn_DEF_ComplexMessage }
};
static asn_ioc_set_t asn_IOS_FrameTypes_1[] = {
...
...
This diff is collapsed.
Click to expand it.
tests/tests-asn1c-compiler/140-component-relation-OK.asn1
View file @
d357f3d5
...
...
@@ -13,7 +13,7 @@ BEGIN
Frame ::= SEQUENCE {
ident FRAME-STRUCTURE.&id({FrameTypes}),
value FRAME-STRUCTURE.&Type({FrameTypes}{@
.
ident}),
value FRAME-STRUCTURE.&Type({FrameTypes}{@ident}),
...
}
...
...
This diff is collapsed.
Click to expand it.
tests/tests-asn1c-compiler/140-component-relation-OK.asn1.-EFprint-class-matrix
View file @
d357f3d5
...
...
@@ -5,7 +5,7 @@ BEGIN
Frame ::= SEQUENCE {
ident FRAME-STRUCTURE.&id ({FrameTypes}),
value FRAME-STRUCTURE.&Type ({FrameTypes}{@
.
ident}),
value FRAME-STRUCTURE.&Type ({FrameTypes}{@ident}),
...
}
...
...
This diff is collapsed.
Click to expand it.
tests/tests-asn1c-compiler/140-component-relation-OK.asn1.-P
View file @
d357f3d5
...
...
@@ -28,12 +28,12 @@ extern asn_TYPE_descriptor_t asn_DEF_Frame;
/*** <<< IOC-TABLES [Frame] >>> ***/
static const long asn_VAL_
basicMessage_0
= 1;
static const long asn_VAL_2_
0
= 2;
static const long asn_VAL_
1_basicMessage
= 1;
static const long asn_VAL_2_
2
= 2;
static const asn_ioc_cell_t asn_IOS_FrameTypes_1_rows[] = {
{ "&id", aioc__value, &asn_DEF_NativeInteger, &asn_VAL_
basicMessage_0
},
{ "&id", aioc__value, &asn_DEF_NativeInteger, &asn_VAL_
1_basicMessage
},
{ "&Type", aioc__type, &asn_DEF_PrimitiveMessage },
{ "&id", aioc__value, &asn_DEF_NativeInteger, &asn_VAL_2_
0
},
{ "&id", aioc__value, &asn_DEF_NativeInteger, &asn_VAL_2_
2
},
{ "&Type", aioc__type, &asn_DEF_ComplexMessage }
};
static asn_ioc_set_t asn_IOS_FrameTypes_1[] = {
...
...
This diff is collapsed.
Click to expand it.
tests/tests-asn1c-compiler/141-component-relation-OK.asn1
0 → 100755
View file @
d357f3d5
-- OK: Everything is fine
-- iso.org.dod.internet.private.enterprise (1.3.6.1.4.1)
-- .spelio.software.asn1c.test (9363.1.5.1)
-- .141
ModuleComponentRelationConstraint
{ iso org(3) dod(6) internet (1) private(4) enterprise(1)
spelio(9363) software(1) asn1c(5) test(1) 141 }
DEFINITIONS ::=
BEGIN
Frame ::= SEQUENCE {
ident FRAME-STRUCTURE.&id({FrameTypes}),
value FRAME-STRUCTURE.&Type({FrameTypes}{@.ident}),
...
}
FRAME-STRUCTURE ::= CLASS {
&id ConstrainedInteger UNIQUE,
&Type
} WITH SYNTAX {&Type IDENTIFIED BY &id}
ConstrainedInteger ::= INTEGER (0..32767)
FrameTypes FRAME-STRUCTURE ::= {
{ PrimitiveMessage IDENTIFIED BY primMessage } |
{ ComplexMessage IDENTIFIED BY cplxMessage }
, ... }
PrimitiveMessage ::= SEQUENCE {}
ComplexMessage ::= SEQUENCE {}
primMessage INTEGER ::= 1
cplxMessage INTEGER ::= 2
END
This diff is collapsed.
Click to expand it.
tests/tests-asn1c-compiler/141-component-relation-OK.asn1.-EFprint-class-matrix
0 → 100644
View file @
d357f3d5
ModuleComponentRelationConstraint { iso org(3) dod(6) internet(1) private(4)
enterprise(1) spelio(9363) software(1) asn1c(5) test(1) 141 }
DEFINITIONS ::=
BEGIN
Frame ::= SEQUENCE {
ident FRAME-STRUCTURE.&id ({FrameTypes}),
value FRAME-STRUCTURE.&Type ({FrameTypes}{@.ident}),
...
}
FRAME-STRUCTURE ::= CLASS {
&id ConstrainedInteger UNIQUE,
&Type ANY
} WITH SYNTAX {&Type IDENTIFIED BY &id}
-- Information Object Set has 2 entries:
-- [ &id][ &Type]
-- [1] primMessage PrimitiveMessage
-- [2] cplxMessage ComplexMessage
ConstrainedInteger ::= INTEGER (0..32767)
FrameTypes FRAME-STRUCTURE ::= {{ PrimitiveMessage IDENTIFIED BY primMessage } | { ComplexMessage IDENTIFIED BY cplxMessage },...}
-- Information Object Set has 2 entries:
-- [ &id][ &Type]
-- [1] primMessage PrimitiveMessage
-- [2] cplxMessage ComplexMessage
PrimitiveMessage ::= SEQUENCE { }
ComplexMessage ::= SEQUENCE { }
primMessage INTEGER ::= 1
cplxMessage INTEGER ::= 2
END
This diff is collapsed.
Click to expand it.
tests/tests-asn1c-compiler/141-component-relation-OK.asn1.-P
0 → 100644
View file @
d357f3d5
This diff is collapsed.
Click to expand it.
tests/tests-asn1c-compiler/98-attribute-class-OK.asn1.-P
View file @
d357f3d5
...
...
@@ -22,11 +22,11 @@ extern asn_TYPE_descriptor_t asn_DEF_Attribute;
/*** <<< IOC-TABLES [Attribute] >>> ***/
static const RELATIVE_OID_t asn_VAL_
raf_0
= { "not supported", 0 };
static const RELATIVE_OID_t asn_VAL_
rcf_0
= { "not supported", 0 };
static const RELATIVE_OID_t asn_VAL_
1_raf
= { "not supported", 0 };
static const RELATIVE_OID_t asn_VAL_
2_rcf
= { "not supported", 0 };
static const asn_ioc_cell_t asn_IOS_Attributes_1_rows[] = {
{ "&id", aioc__value, &asn_DEF_RELATIVE_OID, &asn_VAL_
raf_0
},
{ "&id", aioc__value, &asn_DEF_RELATIVE_OID, &asn_VAL_
rcf_0
}
{ "&id", aioc__value, &asn_DEF_RELATIVE_OID, &asn_VAL_
1_raf
},
{ "&id", aioc__value, &asn_DEF_RELATIVE_OID, &asn_VAL_
2_rcf
}
};
static asn_ioc_set_t asn_IOS_Attributes_1[] = {
2, 1, asn_IOS_Attributes_1_rows
...
...
This diff is collapsed.
Click to expand it.
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