Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
gaoqiong
MIGraphX
Commits
93c89587
Commit
93c89587
authored
Dec 13, 2023
by
Paul
Browse files
Split onnx tests
parent
d2532d0e
Changes
490
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
447 additions
and
0 deletions
+447
-0
test/onnx/parse/reversesequence_batch_test.cpp
test/onnx/parse/reversesequence_batch_test.cpp
+48
-0
test/onnx/parse/reversesequence_rank_err_test.cpp
test/onnx/parse/reversesequence_rank_err_test.cpp
+10
-0
test/onnx/parse/reversesequence_same_axis_err_test.cpp
test/onnx/parse/reversesequence_same_axis_err_test.cpp
+10
-0
test/onnx/parse/reversesequence_sequence_lens_shape_err_test.cpp
...nx/parse/reversesequence_sequence_lens_shape_err_test.cpp
+11
-0
test/onnx/parse/reversesequence_time_axis_err_test.cpp
test/onnx/parse/reversesequence_time_axis_err_test.cpp
+10
-0
test/onnx/parse/reversesequence_time_test.cpp
test/onnx/parse/reversesequence_time_test.cpp
+56
-0
test/onnx/parse/roialign_default_test.cpp
test/onnx/parse/roialign_default_test.cpp
+31
-0
test/onnx/parse/roialign_test.cpp
test/onnx/parse/roialign_test.cpp
+34
-0
test/onnx/parse/round_test.cpp
test/onnx/parse/round_test.cpp
+16
-0
test/onnx/parse/scatter_add_test.cpp
test/onnx/parse/scatter_add_test.cpp
+14
-0
test/onnx/parse/scatter_mul_test.cpp
test/onnx/parse/scatter_mul_test.cpp
+14
-0
test/onnx/parse/scatter_none_test.cpp
test/onnx/parse/scatter_none_test.cpp
+14
-0
test/onnx/parse/scatternd_dyn_test.cpp
test/onnx/parse/scatternd_dyn_test.cpp
+28
-0
test/onnx/parse/scatternd_invalid_reduction_test.cpp
test/onnx/parse/scatternd_invalid_reduction_test.cpp
+10
-0
test/onnx/parse/selu_test.cpp
test/onnx/parse/selu_test.cpp
+38
-0
test/onnx/parse/shape_dyn_test0.cpp
test/onnx/parse/shape_dyn_test0.cpp
+22
-0
test/onnx/parse/shape_dyn_test1.cpp
test/onnx/parse/shape_dyn_test1.cpp
+23
-0
test/onnx/parse/shape_dyn_test2.cpp
test/onnx/parse/shape_dyn_test2.cpp
+23
-0
test/onnx/parse/shape_dyn_test3.cpp
test/onnx/parse/shape_dyn_test3.cpp
+23
-0
test/onnx/parse/shape_end_less_start_error.cpp
test/onnx/parse/shape_end_less_start_error.cpp
+12
-0
No files found.
test/onnx/parse/reversesequence_batch_test.cpp
0 → 100644
View file @
93c89587
#include <onnx_test.hpp>
TEST_CASE
(
reversesequence_batch_test
)
{
migraphx
::
program
p
;
auto
*
mm
=
p
.
get_main_module
();
int
batch_axis
=
0
;
int
time_axis
=
1
;
migraphx
::
shape
sx
{
migraphx
::
shape
::
float_type
,
{
4
,
4
}};
auto
input
=
mm
->
add_parameter
(
"x"
,
sx
);
std
::
vector
<
int64_t
>
sequence_lens
=
{
1
,
2
,
3
,
4
};
mm
->
add_literal
({{
migraphx
::
shape
::
int64_type
,
{
4
}},
sequence_lens
});
int
batch_size
=
sx
.
lens
()[
batch_axis
];
int
time_size
=
sx
.
lens
()[
time_axis
];
auto
add_slice
=
[
&
mm
,
&
input
,
batch_axis
,
time_axis
](
int
b_start
,
int
b_end
,
int
t_start
,
int
t_end
)
{
return
mm
->
add_instruction
(
migraphx
::
make_op
(
"slice"
,
{{
"axes"
,
{
batch_axis
,
time_axis
}},
{
"starts"
,
{
b_start
,
t_start
}},
{
"ends"
,
{
b_end
,
t_end
}}}),
input
);
};
auto
ret
=
add_slice
(
0
,
1
,
0
,
time_size
);
for
(
int
b
=
1
;
b
<
batch_size
;
++
b
)
{
auto
s0
=
add_slice
(
b
,
b
+
1
,
0
,
sequence_lens
[
b
]);
s0
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"reverse"
,
{{
"axes"
,
{
time_axis
}}}),
s0
);
if
(
sequence_lens
[
b
]
<
time_size
)
{
auto
s1
=
add_slice
(
b
,
b
+
1
,
sequence_lens
[
b
],
time_size
);
s0
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"concat"
,
{{
"axis"
,
time_axis
}}),
s0
,
s1
);
}
ret
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"concat"
,
{{
"axis"
,
batch_axis
}}),
ret
,
s0
);
}
mm
->
add_return
({
ret
});
auto
prog
=
migraphx
::
parse_onnx
(
"reversesequence_batch_test.onnx"
);
EXPECT
(
p
==
prog
);
}
test/onnx/parse/reversesequence_rank_err_test.cpp
0 → 100644
View file @
93c89587
#include <onnx_test.hpp>
TEST_CASE
(
reversesequence_rank_err_test
)
{
EXPECT
(
test
::
throws
([
&
]
{
migraphx
::
parse_onnx
(
"reversesequence_rank_err_test.onnx"
);
}));
}
test/onnx/parse/reversesequence_same_axis_err_test.cpp
0 → 100644
View file @
93c89587
#include <onnx_test.hpp>
TEST_CASE
(
reversesequence_same_axis_err_test
)
{
EXPECT
(
test
::
throws
([
&
]
{
migraphx
::
parse_onnx
(
"reversesequence_same_axis_err_test.onnx"
);
}));
}
test/onnx/parse/reversesequence_sequence_lens_shape_err_test.cpp
0 → 100644
View file @
93c89587
#include <onnx_test.hpp>
TEST_CASE
(
reversesequence_sequence_lens_shape_err_test
)
{
EXPECT
(
test
::
throws
(
[
&
]
{
migraphx
::
parse_onnx
(
"reversesequence_sequence_lens_shape_err_test.onnx"
);
}));
}
test/onnx/parse/reversesequence_time_axis_err_test.cpp
0 → 100644
View file @
93c89587
#include <onnx_test.hpp>
TEST_CASE
(
reversesequence_time_axis_err_test
)
{
EXPECT
(
test
::
throws
([
&
]
{
migraphx
::
parse_onnx
(
"reversesequence_time_axis_err_test.onnx"
);
}));
}
test/onnx/parse/reversesequence_time_test.cpp
0 → 100644
View file @
93c89587
#include <onnx_test.hpp>
TEST_CASE
(
reversesequence_time_test
)
{
migraphx
::
program
p
;
auto
*
mm
=
p
.
get_main_module
();
int
batch_axis
=
1
;
int
time_axis
=
0
;
migraphx
::
shape
sx
{
migraphx
::
shape
::
float_type
,
{
4
,
4
}};
auto
input
=
mm
->
add_parameter
(
"x"
,
sx
);
int
batch_size
=
sx
.
lens
()[
batch_axis
];
int
time_size
=
sx
.
lens
()[
time_axis
];
std
::
vector
<
int64_t
>
sequence_lens
=
{
4
,
3
,
2
,
1
};
auto
add_slice
=
[
&
mm
,
&
input
,
batch_axis
,
time_axis
](
int
b_start
,
int
b_end
,
int
t_start
,
int
t_end
)
{
return
mm
->
add_instruction
(
migraphx
::
make_op
(
"slice"
,
{{
"axes"
,
{
batch_axis
,
time_axis
}},
{
"starts"
,
{
b_start
,
t_start
}},
{
"ends"
,
{
b_end
,
t_end
}}}),
input
);
};
migraphx
::
instruction_ref
ret
;
for
(
int
b
=
0
;
b
<
batch_size
-
1
;
++
b
)
{
auto
s0
=
add_slice
(
b
,
b
+
1
,
0
,
sequence_lens
[
b
]);
s0
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"reverse"
,
{{
"axes"
,
{
time_axis
}}}),
s0
);
if
(
sequence_lens
[
b
]
<
time_size
)
{
auto
s1
=
add_slice
(
b
,
b
+
1
,
sequence_lens
[
b
],
time_size
);
s0
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"concat"
,
{{
"axis"
,
time_axis
}}),
s0
,
s1
);
}
if
(
b
==
0
)
{
ret
=
s0
;
}
else
{
ret
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"concat"
,
{{
"axis"
,
batch_axis
}}),
ret
,
s0
);
}
}
auto
s0
=
add_slice
(
batch_size
-
1
,
batch_size
,
0
,
time_size
);
ret
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"concat"
,
{{
"axis"
,
batch_axis
}}),
ret
,
s0
);
mm
->
add_return
({
ret
});
auto
prog
=
migraphx
::
parse_onnx
(
"reversesequence_time_test.onnx"
);
EXPECT
(
p
==
prog
);
}
test/onnx/parse/roialign_default_test.cpp
0 → 100644
View file @
93c89587
#include <onnx_test.hpp>
TEST_CASE
(
roialign_default_test
)
{
migraphx
::
shape
sx
{
migraphx
::
shape
::
float_type
,
{
10
,
4
,
7
,
8
}};
migraphx
::
shape
srois
{
migraphx
::
shape
::
float_type
,
{
8
,
4
}};
migraphx
::
shape
sbi
{
migraphx
::
shape
::
int64_type
,
{
8
}};
migraphx
::
program
p
;
auto
*
mm
=
p
.
get_main_module
();
auto
x
=
mm
->
add_parameter
(
"x"
,
sx
);
auto
rois
=
mm
->
add_parameter
(
"rois"
,
srois
);
auto
bi
=
mm
->
add_parameter
(
"batch_ind"
,
sbi
);
// Due to the onnx model using opset 12, the coordinate_transformation_mode should be set to
// output_half_pixel
auto
r
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"roialign"
,
{{
"coordinate_transformation_mode"
,
"output_half_pixel"
}}),
x
,
rois
,
bi
);
mm
->
add_return
({
r
});
auto
prog
=
migraphx
::
parse_onnx
(
"roialign_default_test.onnx"
);
EXPECT
(
p
==
prog
);
}
test/onnx/parse/roialign_test.cpp
0 → 100644
View file @
93c89587
#include <onnx_test.hpp>
TEST_CASE
(
roialign_test
)
{
migraphx
::
shape
sx
{
migraphx
::
shape
::
float_type
,
{
10
,
5
,
4
,
7
}};
migraphx
::
shape
srois
{
migraphx
::
shape
::
float_type
,
{
8
,
4
}};
migraphx
::
shape
sbi
{
migraphx
::
shape
::
int64_type
,
{
8
}};
migraphx
::
program
p
;
auto
*
mm
=
p
.
get_main_module
();
auto
x
=
mm
->
add_parameter
(
"x"
,
sx
);
auto
rois
=
mm
->
add_parameter
(
"rois"
,
srois
);
auto
bi
=
mm
->
add_parameter
(
"batch_ind"
,
sbi
);
auto
r
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"roialign"
,
{{
"coordinate_transformation_mode"
,
"output_half_pixel"
},
{
"spatial_scale"
,
2.0
f
},
{
"output_height"
,
5
},
{
"output_width"
,
5
},
{
"sampling_ratio"
,
3
}}),
x
,
rois
,
bi
);
mm
->
add_return
({
r
});
auto
prog
=
migraphx
::
parse_onnx
(
"roialign_test.onnx"
);
EXPECT
(
p
==
prog
);
}
test/onnx/parse/round_test.cpp
0 → 100644
View file @
93c89587
#include <onnx_test.hpp>
TEST_CASE
(
round_test
)
{
migraphx
::
program
p
;
auto
*
mm
=
p
.
get_main_module
();
auto
input
=
mm
->
add_parameter
(
"x"
,
migraphx
::
shape
{
migraphx
::
shape
::
double_type
,
{
10
,
5
}});
mm
->
add_instruction
(
migraphx
::
make_op
(
"nearbyint"
),
input
);
auto
prog
=
optimize_onnx
(
"round_test.onnx"
);
EXPECT
(
p
==
prog
);
}
test/onnx/parse/scatter_add_test.cpp
0 → 100644
View file @
93c89587
#include <onnx_test.hpp>
#include <onnx_test_utils.hpp>
TEST_CASE
(
scatter_add_test
)
{
migraphx
::
program
p
=
create_scatter_program
(
"scatter_add"
,
-
2
);
auto
prog
=
migraphx
::
parse_onnx
(
"scatter_add_test.onnx"
);
EXPECT
(
p
==
prog
);
}
test/onnx/parse/scatter_mul_test.cpp
0 → 100644
View file @
93c89587
#include <onnx_test.hpp>
#include <onnx_test_utils.hpp>
TEST_CASE
(
scatter_mul_test
)
{
migraphx
::
program
p
=
create_scatter_program
(
"scatter_mul"
,
-
2
);
auto
prog
=
migraphx
::
parse_onnx
(
"scatter_mul_test.onnx"
);
EXPECT
(
p
==
prog
);
}
test/onnx/parse/scatter_none_test.cpp
0 → 100644
View file @
93c89587
#include <onnx_test.hpp>
#include <onnx_test_utils.hpp>
TEST_CASE
(
scatter_none_test
)
{
migraphx
::
program
p
=
create_scatter_program
(
"scatter_none"
,
-
2
);
auto
prog
=
migraphx
::
parse_onnx
(
"scatter_none_test.onnx"
);
EXPECT
(
p
==
prog
);
}
test/onnx/parse/scatternd_dyn_test.cpp
0 → 100644
View file @
93c89587
#include <onnx_test.hpp>
TEST_CASE
(
scatternd_dyn_test
)
{
// dynamic input.
migraphx
::
program
p
;
auto
*
mm
=
p
.
get_main_module
();
// parameters with dynamic dimensions
auto
l0
=
mm
->
add_parameter
(
"data"
,
migraphx
::
shape
{
migraphx
::
shape
::
float_type
,
{{
1
,
3
,
{
2
}},
{
2
,
2
},
{
2
,
2
}}});
auto
l1
=
mm
->
add_parameter
(
"indices"
,
migraphx
::
shape
{
migraphx
::
shape
::
int64_type
,
{{
2
,
1
,
{
2
}},
{
1
,
1
},
{
2
,
2
}}});
auto
l2
=
mm
->
add_parameter
(
"updates"
,
migraphx
::
shape
{
migraphx
::
shape
::
float_type
,
{{
2
,
1
,
{
2
}},
{
1
,
1
},
{
2
,
2
}}});
auto
r
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"scatternd_none"
),
l0
,
l1
,
l2
);
mm
->
add_return
({
r
});
migraphx
::
onnx_options
options
;
options
.
map_dyn_input_dims
[
"data"
]
=
{{
1
,
3
,
{
2
}},
{
2
,
2
},
{
2
,
2
}};
options
.
map_dyn_input_dims
[
"indices"
]
=
{{
2
,
1
,
{
2
}},
{
1
,
1
},
{
2
,
2
}};
options
.
map_dyn_input_dims
[
"updates"
]
=
{{
2
,
1
,
{
2
}},
{
1
,
1
},
{
2
,
2
}};
auto
prog
=
migraphx
::
parse_onnx
(
"scatternd_dyn_test.onnx"
,
options
);
EXPECT
(
p
==
prog
);
}
test/onnx/parse/scatternd_invalid_reduction_test.cpp
0 → 100644
View file @
93c89587
#include <onnx_test.hpp>
TEST_CASE
(
scatternd_invalid_reduction_test
)
{
EXPECT
(
test
::
throws
([
&
]
{
migraphx
::
parse_onnx
(
"scatternd_invalid_reduction_test.onnx"
);
}));
}
test/onnx/parse/selu_test.cpp
0 → 100644
View file @
93c89587
#include <onnx_test.hpp>
TEST_CASE
(
selu_test
)
{
migraphx
::
program
p
;
auto
*
mm
=
p
.
get_main_module
();
std
::
vector
<
std
::
size_t
>
lens
=
{
2
,
3
};
migraphx
::
shape
s
{
migraphx
::
shape
::
double_type
,
lens
};
auto
x
=
mm
->
add_parameter
(
"x"
,
s
);
migraphx
::
shape
ls
{
migraphx
::
shape
::
double_type
,
{
1
}};
auto
la
=
mm
->
add_literal
({
ls
,
{
0.3
}});
auto
lg
=
mm
->
add_literal
({
ls
,
{
0.25
}});
auto
mbla
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"multibroadcast"
,
{{
"out_lens"
,
lens
}}),
la
);
auto
mblg
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"multibroadcast"
,
{{
"out_lens"
,
lens
}}),
lg
);
auto
sign_x
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"sign"
),
x
);
auto
exp_x
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"exp"
),
x
);
auto
mlax
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"mul"
),
mbla
,
exp_x
);
auto
smlax
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"sub"
),
mlax
,
mbla
);
auto
item1
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"add"
),
smlax
,
x
);
auto
item2
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"sub"
),
smlax
,
x
);
auto
sitem2
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"mul"
),
sign_x
,
item2
);
auto
item12
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"sub"
),
item1
,
sitem2
);
auto
r
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"mul"
),
item12
,
mblg
);
mm
->
add_return
({
r
});
auto
prog
=
migraphx
::
parse_onnx
(
"selu_test.onnx"
);
EXPECT
(
p
==
prog
);
}
test/onnx/parse/shape_dyn_test0.cpp
0 → 100644
View file @
93c89587
#include <onnx_test.hpp>
TEST_CASE
(
shape_dyn_test0
)
{
migraphx
::
program
p
;
auto
*
mm
=
p
.
get_main_module
();
migraphx
::
shape
s
{
migraphx
::
shape
::
float_type
,
{{
1
,
4
,
{
1
,
4
}},
{
4
,
4
},
{
2
,
4
},
{
2
,
4
}}};
auto
p0
=
mm
->
add_parameter
(
"x"
,
s
);
migraphx
::
shape
s_shape
{
migraphx
::
shape
::
int64_type
,
{
4
}};
auto
ret
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"dimensions_of"
,
{{
"end"
,
4
}}),
p0
);
mm
->
add_return
({
ret
});
migraphx
::
onnx_options
options
;
options
.
map_dyn_input_dims
[
"x"
]
=
{{
1
,
4
,
{
1
,
4
}},
{
4
,
4
},
{
2
,
4
},
{
2
,
4
}};
auto
prog
=
parse_onnx
(
"shape_dyn_test0.onnx"
,
options
);
EXPECT
(
p
==
prog
);
}
test/onnx/parse/shape_dyn_test1.cpp
0 → 100644
View file @
93c89587
#include <onnx_test.hpp>
TEST_CASE
(
shape_dyn_test1
)
{
migraphx
::
program
p
;
auto
*
mm
=
p
.
get_main_module
();
migraphx
::
shape
s
{
migraphx
::
shape
::
float_type
,
{{
1
,
4
,
{
1
,
4
}},
{
4
,
4
},
{
2
,
4
},
{
2
,
4
}}};
auto
p0
=
mm
->
add_parameter
(
"x"
,
s
);
migraphx
::
shape
s_shape
{
migraphx
::
shape
::
int64_type
,
{
4
}};
auto
ret
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"dimensions_of"
,
{{
"start"
,
2
},
{
"end"
,
4
}}),
p0
);
mm
->
add_return
({
ret
});
migraphx
::
onnx_options
options
;
options
.
map_dyn_input_dims
[
"x"
]
=
{{
1
,
4
,
{
1
,
4
}},
{
4
,
4
},
{
2
,
4
},
{
2
,
4
}};
auto
prog
=
parse_onnx
(
"shape_dyn_test1.onnx"
,
options
);
EXPECT
(
p
==
prog
);
}
test/onnx/parse/shape_dyn_test2.cpp
0 → 100644
View file @
93c89587
#include <onnx_test.hpp>
TEST_CASE
(
shape_dyn_test2
)
{
migraphx
::
program
p
;
auto
*
mm
=
p
.
get_main_module
();
migraphx
::
shape
s
{
migraphx
::
shape
::
float_type
,
{{
1
,
4
,
{
1
,
4
}},
{
4
,
4
},
{
2
,
4
},
{
2
,
4
}}};
auto
p0
=
mm
->
add_parameter
(
"x"
,
s
);
migraphx
::
shape
s_shape
{
migraphx
::
shape
::
int64_type
,
{
4
}};
auto
ret
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"dimensions_of"
,
{{
"start"
,
2
},
{
"end"
,
4
}}),
p0
);
mm
->
add_return
({
ret
});
migraphx
::
onnx_options
options
;
options
.
map_dyn_input_dims
[
"x"
]
=
{{
1
,
4
,
{
1
,
4
}},
{
4
,
4
},
{
2
,
4
},
{
2
,
4
}};
auto
prog
=
parse_onnx
(
"shape_dyn_test2.onnx"
,
options
);
EXPECT
(
p
==
prog
);
}
test/onnx/parse/shape_dyn_test3.cpp
0 → 100644
View file @
93c89587
#include <onnx_test.hpp>
TEST_CASE
(
shape_dyn_test3
)
{
migraphx
::
program
p
;
auto
*
mm
=
p
.
get_main_module
();
migraphx
::
shape
s
{
migraphx
::
shape
::
float_type
,
{{
1
,
4
,
{
1
,
4
}},
{
4
,
4
},
{
2
,
4
},
{
2
,
4
}}};
auto
p0
=
mm
->
add_parameter
(
"x"
,
s
);
migraphx
::
shape
s_shape
{
migraphx
::
shape
::
int64_type
,
{
4
}};
auto
ret
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"dimensions_of"
,
{{
"start"
,
1
},
{
"end"
,
2
}}),
p0
);
mm
->
add_return
({
ret
});
migraphx
::
onnx_options
options
;
options
.
map_dyn_input_dims
[
"x"
]
=
{{
1
,
4
,
{
1
,
4
}},
{
4
,
4
},
{
2
,
4
},
{
2
,
4
}};
auto
prog
=
parse_onnx
(
"shape_dyn_test3.onnx"
,
options
);
EXPECT
(
p
==
prog
);
}
test/onnx/parse/shape_end_less_start_error.cpp
0 → 100644
View file @
93c89587
#include <onnx_test.hpp>
TEST_CASE
(
shape_end_less_start_error
)
{
migraphx
::
onnx_options
options
;
options
.
map_dyn_input_dims
[
"x"
]
=
{{
1
,
4
,
{
1
,
4
}},
{
4
,
4
},
{
2
,
4
},
{
2
,
4
}};
EXPECT
(
test
::
throws
([
&
]
{
migraphx
::
parse_onnx
(
"shape_end_less_start_error.onnx"
,
options
);
}));
}
Prev
1
…
16
17
18
19
20
21
22
23
24
25
Next
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