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
OpenDAS
nni
Commits
b1dfafff
Unverified
Commit
b1dfafff
authored
Apr 18, 2019
by
SparkSnail
Committed by
GitHub
Apr 18, 2019
Browse files
Merge pull request #161 from Microsoft/master
merge master
parents
aec49771
cbad7acb
Changes
37
Show whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
72 additions
and
33 deletions
+72
-33
src/webui/src/components/trial-detail/Intermeidate.tsx
src/webui/src/components/trial-detail/Intermeidate.tsx
+2
-2
src/webui/src/components/trial-detail/Para.tsx
src/webui/src/components/trial-detail/Para.tsx
+1
-1
src/webui/src/components/trial-detail/TableList.tsx
src/webui/src/components/trial-detail/TableList.tsx
+12
-12
src/webui/src/index.tsx
src/webui/src/index.tsx
+0
-2
src/webui/src/static/const.ts
src/webui/src/static/const.ts
+3
-3
src/webui/src/static/function.ts
src/webui/src/static/function.ts
+2
-1
src/webui/src/static/style/accuracy.css
src/webui/src/static/style/accuracy.css
+1
-1
src/webui/src/static/style/openRow.scss
src/webui/src/static/style/openRow.scss
+26
-2
src/webui/src/static/style/progress.scss
src/webui/src/static/style/progress.scss
+2
-2
src/webui/src/static/style/table.scss
src/webui/src/static/style/table.scss
+6
-7
src/webui/src/static/style/tableStatus.css
src/webui/src/static/style/tableStatus.css
+1
-0
test/pipelines-it-kubeflow.yml
test/pipelines-it-kubeflow.yml
+1
-0
test/pipelines-it-local.yml
test/pipelines-it-local.yml
+1
-0
test/pipelines-it-pai.yml
test/pipelines-it-pai.yml
+1
-0
test/pipelines-it-remote.yml
test/pipelines-it-remote.yml
+1
-0
test/tuner_test.py
test/tuner_test.py
+4
-0
test/tuner_test/batchtuner_search_space.json
test/tuner_test/batchtuner_search_space.json
+8
-0
No files found.
src/webui/src/components/trial-detail/Intermeidate.tsx
View file @
b1dfafff
...
@@ -109,7 +109,7 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
...
@@ -109,7 +109,7 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
obj
=
temp
.
hyperPara
;
obj
=
temp
.
hyperPara
;
}
}
return
'
<div class="tooldetailAccuracy">
'
+
return
'
<div class="tooldetailAccuracy">
'
+
'
<div>Trial I
d
:
'
+
trialId
+
'
</div>
'
+
'
<div>Trial I
D
:
'
+
trialId
+
'
</div>
'
+
'
<div>Intermediate:
'
+
data
.
data
+
'
</div>
'
+
'
<div>Intermediate:
'
+
data
.
data
+
'
</div>
'
+
'
<div>Parameters:
'
+
'
<div>Parameters:
'
+
'
<pre>
'
+
JSON
.
stringify
(
obj
,
null
,
4
)
+
'
</pre>
'
+
'
<pre>
'
+
JSON
.
stringify
(
obj
,
null
,
4
)
+
'
</pre>
'
+
...
@@ -252,7 +252,7 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
...
@@ -252,7 +252,7 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
/>
/>
</
Col
>
</
Col
>
<
Col
className
=
"range"
span
=
{
10
}
>
<
Col
className
=
"range"
span
=
{
10
}
>
<
span
>
Intermediate
R
esult
</
span
>
<
span
>
Intermediate
r
esult
</
span
>
<
input
<
input
placeholder
=
"number"
placeholder
=
"number"
ref
=
{
input
=>
this
.
minValInput
=
input
}
ref
=
{
input
=>
this
.
minValInput
=
input
}
...
...
src/webui/src/components/trial-detail/Para.tsx
View file @
b1dfafff
...
@@ -401,7 +401,7 @@ class Para extends React.Component<ParaProps, ParaState> {
...
@@ -401,7 +401,7 @@ class Para extends React.Component<ParaProps, ParaState> {
<
Col
span
=
{
6
}
/>
<
Col
span
=
{
6
}
/>
<
Col
span
=
{
18
}
>
<
Col
span
=
{
18
}
>
<
Row
className
=
"meline"
>
<
Row
className
=
"meline"
>
<
span
>
t
op
</
span
>
<
span
>
T
op
</
span
>
<
Select
<
Select
style
=
{
{
width
:
'
20%
'
,
marginRight
:
10
}
}
style
=
{
{
width
:
'
20%
'
,
marginRight
:
10
}
}
placeholder
=
"100%"
placeholder
=
"100%"
...
...
src/webui/src/components/trial-detail/TableList.tsx
View file @
b1dfafff
...
@@ -17,7 +17,7 @@ require('../../static/style/logPath.scss');
...
@@ -17,7 +17,7 @@ require('../../static/style/logPath.scss');
require
(
'
../../static/style/search.scss
'
);
require
(
'
../../static/style/search.scss
'
);
require
(
'
../../static/style/table.scss
'
);
require
(
'
../../static/style/table.scss
'
);
require
(
'
../../static/style/button.scss
'
);
require
(
'
../../static/style/button.scss
'
);
require
(
'
../../static/style/
tableList
.scss
'
);
require
(
'
../../static/style/
openRow
.scss
'
);
const
echarts
=
require
(
'
echarts/lib/echarts
'
);
const
echarts
=
require
(
'
echarts/lib/echarts
'
);
require
(
'
echarts/lib/chart/line
'
);
require
(
'
echarts/lib/chart/line
'
);
require
(
'
echarts/lib/component/tooltip
'
);
require
(
'
echarts/lib/component/tooltip
'
);
...
@@ -132,12 +132,12 @@ class TableList extends React.Component<TableListProps, TableListState> {
...
@@ -132,12 +132,12 @@ class TableList extends React.Component<TableListProps, TableListState> {
Object
.
keys
(
checkedValues
).
map
(
m
=>
{
Object
.
keys
(
checkedValues
).
map
(
m
=>
{
switch
(
checkedValues
[
m
])
{
switch
(
checkedValues
[
m
])
{
case
'
Trial No.
'
:
case
'
Trial No.
'
:
case
'
I
d
'
:
case
'
I
D
'
:
case
'
Duration
'
:
case
'
Duration
'
:
case
'
Status
'
:
case
'
Status
'
:
case
'
Operation
'
:
case
'
Operation
'
:
case
'
Default
'
:
case
'
Default
'
:
case
'
Intermediate
R
esult
'
:
case
'
Intermediate
r
esult
'
:
break
;
break
;
default
:
default
:
finalKeys
.
push
(
checkedValues
[
m
]);
finalKeys
.
push
(
checkedValues
[
m
]);
...
@@ -238,13 +238,13 @@ class TableList extends React.Component<TableListProps, TableListState> {
...
@@ -238,13 +238,13 @@ class TableList extends React.Component<TableListProps, TableListState> {
(
a
.
sequenceId
as
number
)
-
(
b
.
sequenceId
as
number
)
(
a
.
sequenceId
as
number
)
-
(
b
.
sequenceId
as
number
)
});
});
break
;
break
;
case
'
I
d
'
:
case
'
I
D
'
:
showColumn
.
push
({
showColumn
.
push
({
title
:
'
I
d
'
,
title
:
'
I
D
'
,
dataIndex
:
'
id
'
,
dataIndex
:
'
id
'
,
key
:
'
id
'
,
key
:
'
id
'
,
width
:
60
,
width
:
60
,
className
:
'
tableHead
idt
itle
'
,
className
:
'
tableHead
leftT
itle
'
,
// the sort of string
// the sort of string
sorter
:
(
a
:
TableObj
,
b
:
TableObj
):
number
=>
a
.
id
.
localeCompare
(
b
.
id
),
sorter
:
(
a
:
TableObj
,
b
:
TableObj
):
number
=>
a
.
id
.
localeCompare
(
b
.
id
),
render
:
(
text
:
string
,
record
:
TableObj
)
=>
{
render
:
(
text
:
string
,
record
:
TableObj
)
=>
{
...
@@ -298,10 +298,11 @@ class TableList extends React.Component<TableListProps, TableListState> {
...
@@ -298,10 +298,11 @@ class TableList extends React.Component<TableListProps, TableListState> {
break
;
break
;
case
'
Default
'
:
case
'
Default
'
:
showColumn
.
push
({
showColumn
.
push
({
title
:
'
Default Metric
'
,
title
:
'
Default metric
'
,
className
:
'
leftTitle
'
,
dataIndex
:
'
acc
'
,
dataIndex
:
'
acc
'
,
key
:
'
acc
'
,
key
:
'
acc
'
,
width
:
1
6
0
,
width
:
1
2
0
,
sorter
:
(
a
:
TableObj
,
b
:
TableObj
)
=>
{
sorter
:
(
a
:
TableObj
,
b
:
TableObj
)
=>
{
const
aa
=
a
.
description
.
intermediate
;
const
aa
=
a
.
description
.
intermediate
;
const
bb
=
b
.
description
.
intermediate
;
const
bb
=
b
.
description
.
intermediate
;
...
@@ -359,9 +360,9 @@ class TableList extends React.Component<TableListProps, TableListState> {
...
@@ -359,9 +360,9 @@ class TableList extends React.Component<TableListProps, TableListState> {
});
});
break
;
break
;
case
'
Intermediate
R
esult
'
:
case
'
Intermediate
r
esult
'
:
showColumn
.
push
({
showColumn
.
push
({
title
:
'
Intermediate
R
esult
'
,
title
:
'
Intermediate
r
esult
'
,
dataIndex
:
'
intermediate
'
,
dataIndex
:
'
intermediate
'
,
key
:
'
intermediate
'
,
key
:
'
intermediate
'
,
width
:
'
16%
'
,
width
:
'
16%
'
,
...
@@ -413,7 +414,7 @@ class TableList extends React.Component<TableListProps, TableListState> {
...
@@ -413,7 +414,7 @@ class TableList extends React.Component<TableListProps, TableListState> {
/>
/>
{
/* Intermediate Result Modal */
}
{
/* Intermediate Result Modal */
}
<
Modal
<
Modal
title
=
"Intermediate
R
esult"
title
=
"Intermediate
r
esult"
visible
=
{
modalVisible
}
visible
=
{
modalVisible
}
onCancel
=
{
this
.
hideIntermediateModal
}
onCancel
=
{
this
.
hideIntermediateModal
}
footer
=
{
null
}
footer
=
{
null
}
...
@@ -446,7 +447,6 @@ class TableList extends React.Component<TableListProps, TableListState> {
...
@@ -446,7 +447,6 @@ class TableList extends React.Component<TableListProps, TableListState> {
className
=
"titleColumn"
className
=
"titleColumn"
/>
/>
</
Modal
>
</
Modal
>
</
Row
>
</
Row
>
);
);
}
}
...
...
src/webui/src/index.tsx
View file @
b1dfafff
...
@@ -4,7 +4,6 @@ import * as ReactDOM from 'react-dom';
...
@@ -4,7 +4,6 @@ import * as ReactDOM from 'react-dom';
import
App
from
'
./App
'
;
import
App
from
'
./App
'
;
import
{
Router
,
Route
,
browserHistory
,
IndexRedirect
}
from
'
react-router
'
;
import
{
Router
,
Route
,
browserHistory
,
IndexRedirect
}
from
'
react-router
'
;
import
registerServiceWorker
from
'
./registerServiceWorker
'
;
import
registerServiceWorker
from
'
./registerServiceWorker
'
;
import
Control
from
'
./components/Control
'
;
import
Overview
from
'
./components/Overview
'
;
import
Overview
from
'
./components/Overview
'
;
import
TrialsDetail
from
'
./components/TrialsDetail
'
;
import
TrialsDetail
from
'
./components/TrialsDetail
'
;
import
'
./index.css
'
;
import
'
./index.css
'
;
...
@@ -15,7 +14,6 @@ ReactDOM.render(
...
@@ -15,7 +14,6 @@ ReactDOM.render(
<
IndexRedirect
to
=
"/oview"
/>
<
IndexRedirect
to
=
"/oview"
/>
<
Route
path
=
"/oview"
component
=
{
Overview
}
/>
<
Route
path
=
"/oview"
component
=
{
Overview
}
/>
<
Route
path
=
"/detail"
component
=
{
TrialsDetail
}
/>
<
Route
path
=
"/detail"
component
=
{
TrialsDetail
}
/>
<
Route
path
=
"/control"
component
=
{
Control
}
/>
</
Route
>
</
Route
>
</
Router
>,
</
Router
>,
document
.
getElementById
(
'
root
'
)
as
HTMLElement
document
.
getElementById
(
'
root
'
)
as
HTMLElement
...
...
src/webui/src/static/const.ts
View file @
b1dfafff
...
@@ -25,7 +25,7 @@ const COLUMN_INDEX = [
...
@@ -25,7 +25,7 @@ const COLUMN_INDEX = [
index
:
1
index
:
1
},
},
{
{
name
:
'
I
d
'
,
name
:
'
I
D
'
,
index
:
2
index
:
2
},
},
{
{
...
@@ -45,11 +45,11 @@ const COLUMN_INDEX = [
...
@@ -45,11 +45,11 @@ const COLUMN_INDEX = [
index
:
10000
index
:
10000
},
},
{
{
name
:
'
Intermediate
R
esult
'
,
name
:
'
Intermediate
r
esult
'
,
index
:
10001
index
:
10001
}
}
];
];
const
COLUMN
=
[
'
Trial No.
'
,
'
I
d
'
,
'
Duration
'
,
'
Status
'
,
'
Default
'
,
'
Operation
'
,
'
Intermediate
R
esult
'
];
const
COLUMN
=
[
'
Trial No.
'
,
'
I
D
'
,
'
Duration
'
,
'
Status
'
,
'
Default
'
,
'
Operation
'
,
'
Intermediate
r
esult
'
];
export
{
export
{
MANAGER_IP
,
DOWNLOAD_IP
,
trialJobStatus
,
MANAGER_IP
,
DOWNLOAD_IP
,
trialJobStatus
,
CONTROLTYPE
,
MONACO
,
COLUMN
,
COLUMN_INDEX
CONTROLTYPE
,
MONACO
,
COLUMN
,
COLUMN_INDEX
...
...
src/webui/src/static/function.ts
View file @
b1dfafff
...
@@ -90,7 +90,7 @@ const intermediateGraphOption = (intermediateArr: number[], id: string) => {
...
@@ -90,7 +90,7 @@ const intermediateGraphOption = (intermediateArr: number[], id: string) => {
data
:
sequence
data
:
sequence
},
},
yAxis
:
{
yAxis
:
{
name
:
'
Default
M
etric
'
,
name
:
'
Default
m
etric
'
,
type
:
'
value
'
,
type
:
'
value
'
,
data
:
intermediateArr
data
:
intermediateArr
},
},
...
@@ -112,6 +112,7 @@ const killJob = (key: number, id: string, status: string, updateList: Function)
...
@@ -112,6 +112,7 @@ const killJob = (key: number, id: string, status: string, updateList: Function)
})
})
.
then
(
res
=>
{
.
then
(
res
=>
{
if
(
res
.
status
===
200
)
{
if
(
res
.
status
===
200
)
{
message
.
destroy
();
message
.
success
(
'
Cancel the job successfully
'
);
message
.
success
(
'
Cancel the job successfully
'
);
// render the table
// render the table
updateList
();
updateList
();
...
...
src/webui/src/static/style/accuracy.css
View file @
b1dfafff
src/webui/src/static/style/
tableList
.scss
→
src/webui/src/static/style/
openRow
.scss
View file @
b1dfafff
/* website theme color */
$color
:
#0071bc
;
$color
:
#0071bc
;
/* bg light grey */
$bgColor
:
#f2f2f2
;
.openRowContent
{
.openRowContent
{
.ant-tabs-vertical.ant-tabs-left
.ant-tabs-bar
.ant-tabs-tab
{
.ant-tabs-vertical.ant-tabs-left
.ant-tabs-bar
.ant-tabs-tab
{
text-align
:
left
!
important
;
text-align
:
left
!
important
;
...
@@ -12,6 +14,7 @@ $color: #0071bc;
...
@@ -12,6 +14,7 @@ $color: #0071bc;
}
}
.openRowContent
{
.openRowContent
{
margin-top
:
15px
;
margin-top
:
15px
;
background-color
:
$bgColor
;
.card
{
.card
{
.ant-tabs-vertical
.ant-tabs-bar
.ant-tabs-tab
{
.ant-tabs-vertical
.ant-tabs-bar
.ant-tabs-tab
{
margin
:
0
;
margin
:
0
;
...
@@ -25,7 +28,7 @@ $color: #0071bc;
...
@@ -25,7 +28,7 @@ $color: #0071bc;
}
}
.ant-tabs-tabpane
{
.ant-tabs-tabpane
{
background
:
#f2f2f2
;
background
:
#f2f2f2
;
padding
:
1
0px
20px
;
padding
:
1
2px
12px
12px
0
;
}
}
}
}
}
}
...
@@ -44,3 +47,24 @@ $color: #0071bc;
...
@@ -44,3 +47,24 @@ $color: #0071bc;
height
:
100%
;
height
:
100%
;
}
}
}
}
#description
{
.bgHyper
{
background-color
:
#fff
;
margin-bottom
:
12px
;
}
.copy
{
Button
{
background-color
:
#ccc
;
color
:
#191919
;
border
:
none
;
outline
:
none
;
}
Button
:hover
{
background-color
:
#ccc
;
color
:
#191919
;
border
:
none
;
outline
:
none
;
}
}
}
src/webui/src/static/style/progress.scss
View file @
b1dfafff
...
@@ -53,7 +53,7 @@
...
@@ -53,7 +53,7 @@
}
}
div
{
div
{
font-size
:
16px
;
font-size
:
16px
;
color
:
#
333
;
color
:
#
0573bc
;
}
}
}
}
...
@@ -73,7 +73,7 @@
...
@@ -73,7 +73,7 @@
*/
*/
.inputBox
{
.inputBox
{
height
:
26px
;
height
:
26px
;
margin-top
:
-3
px
;
margin-top
:
5
px
;
.concurrencyInput
{
.concurrencyInput
{
width
:
25%
;
width
:
25%
;
height
:
26px
;
height
:
26px
;
...
...
src/webui/src/static/style/table.scss
View file @
b1dfafff
/* react-json-tree background */
/* react-json-view background */
#description
ul
,
#allList
ul
{
#description
ul
,
#allList
ul
{
background
:
none
!
important
;
background
:
none
!
important
;
}
}
...
@@ -10,10 +9,10 @@
...
@@ -10,10 +9,10 @@
#succeTable
.commonTableStyle
{
#succeTable
.commonTableStyle
{
overflow-y
:
scroll
;
overflow-y
:
scroll
;
}
}
}
}
#succeTable
,
#tableList
{
#succeTable
,
#tableList
{
.commonTableStyle
.
idt
itle
div
{
.commonTableStyle
.
leftT
itle
div
{
text-align
:
left
;
text-align
:
left
;
}
}
.durationsty
{
.durationsty
{
...
@@ -52,7 +51,6 @@
...
@@ -52,7 +51,6 @@
}
}
tr
:hover
{
tr
:hover
{
/* cancel antd table default hover style */
/* cancel antd table default hover style */
td
{
td
{
background-color
:
transparent
;
background-color
:
transparent
;
...
@@ -85,7 +83,8 @@
...
@@ -85,7 +83,8 @@
}
}
}
}
pre
.hyperpar
{
/* let openrow content left*/
.hyperpar
{
text-align
:
left
;
text-align
:
left
;
line-height
:
18px
;
line-height
:
18px
;
font-size
:
14px
;
font-size
:
14px
;
...
...
src/webui/src/static/style/tableStatus.css
View file @
b1dfafff
/* all table status font-color */
.RUNNING
,
.USER_CANCELED
{
.RUNNING
,
.USER_CANCELED
{
color
:
#0071BC
;
color
:
#0071BC
;
}
}
...
...
test/pipelines-it-kubeflow.yml
View file @
b1dfafff
...
@@ -46,6 +46,7 @@ jobs:
...
@@ -46,6 +46,7 @@ jobs:
python3 -m pip install tensorflow==1.12.0 --user
python3 -m pip install tensorflow==1.12.0 --user
sudo apt-get install swig -y
sudo apt-get install swig -y
PATH=$HOME/.local/bin:$PATH nnictl package install --name=SMAC
PATH=$HOME/.local/bin:$PATH nnictl package install --name=SMAC
PATH=$HOME/.local/bin:$PATH nnictl package install --name=BOHB
displayName
:
'
Install
dependencies
for
integration
tests
in
Kubeflow
mode'
displayName
:
'
Install
dependencies
for
integration
tests
in
Kubeflow
mode'
-
script
:
|
-
script
:
|
...
...
test/pipelines-it-local.yml
View file @
b1dfafff
...
@@ -15,6 +15,7 @@ jobs:
...
@@ -15,6 +15,7 @@ jobs:
python3 -m pip install tensorflow-gpu==1.12.0 --user
python3 -m pip install tensorflow-gpu==1.12.0 --user
sudo apt-get install swig -y
sudo apt-get install swig -y
PATH=$HOME/.local/bin:$PATH nnictl package install --name=SMAC
PATH=$HOME/.local/bin:$PATH nnictl package install --name=SMAC
PATH=$HOME/.local/bin:$PATH nnictl package install --name=BOHB
displayName
:
'
Install
dependencies
for
integration
tests'
displayName
:
'
Install
dependencies
for
integration
tests'
-
script
:
|
-
script
:
|
cd test
cd test
...
...
test/pipelines-it-pai.yml
View file @
b1dfafff
...
@@ -46,6 +46,7 @@ jobs:
...
@@ -46,6 +46,7 @@ jobs:
python3 -m pip install tensorflow-gpu==1.12.0 --user
python3 -m pip install tensorflow-gpu==1.12.0 --user
sudo apt-get install swig -y
sudo apt-get install swig -y
PATH=$HOME/.local/bin:$PATH nnictl package install --name=SMAC
PATH=$HOME/.local/bin:$PATH nnictl package install --name=SMAC
PATH=$HOME/.local/bin:$PATH nnictl package install --name=BOHB
displayName
:
'
Install
dependencies
for
integration
tests
in
PAI
mode'
displayName
:
'
Install
dependencies
for
integration
tests
in
PAI
mode'
-
script
:
|
-
script
:
|
...
...
test/pipelines-it-remote.yml
View file @
b1dfafff
...
@@ -16,6 +16,7 @@ jobs:
...
@@ -16,6 +16,7 @@ jobs:
-
script
:
|
-
script
:
|
sudo apt-get install swig -y
sudo apt-get install swig -y
PATH=$HOME/.local/bin:$PATH nnictl package install --name=SMAC
PATH=$HOME/.local/bin:$PATH nnictl package install --name=SMAC
PATH=$HOME/.local/bin:$PATH nnictl package install --name=BOHB
displayName
:
'
Install
dependencies
for
integration
tests
in
remote
mode'
displayName
:
'
Install
dependencies
for
integration
tests
in
remote
mode'
-
task
:
CopyFilesOverSSH@0
-
task
:
CopyFilesOverSSH@0
inputs
:
inputs
:
...
...
test/tuner_test.py
View file @
b1dfafff
...
@@ -49,6 +49,10 @@ def switch(dispatch_type, dispatch_name):
...
@@ -49,6 +49,10 @@ def switch(dispatch_type, dispatch_name):
'optimize_mode'
:
'maximize'
'optimize_mode'
:
'maximize'
}
}
}
}
if
dispatch_name
==
'BatchTuner'
:
experiment_config
[
'searchSpacePath'
]
=
'batchtuner_search_space.json'
else
:
experiment_config
[
'searchSpacePath'
]
=
'search_space.json'
dump_yml_content
(
config_path
,
experiment_config
)
dump_yml_content
(
config_path
,
experiment_config
)
def
test_builtin_dispatcher
(
dispatch_type
,
dispatch_name
):
def
test_builtin_dispatcher
(
dispatch_type
,
dispatch_name
):
...
...
test/tuner_test/batchtuner_search_space.json
0 → 100644
View file @
b1dfafff
{
"combine_params"
:
{
"_type"
:
"choice"
,
"_value"
:
[{
"x"
:
1
},
{
"x"
:
100
}]
}
}
Prev
1
2
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