Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
ed40dd35
Commit
ed40dd35
authored
Apr 29, 2016
by
Viktor Lidholt
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Initial set of tests for flutter sprites (#3643)
* Initial set of tests for flutter sprites
parent
01a27ca4
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
513 additions
and
1 deletion
+513
-1
sprite_box.dart
packages/flutter_sprites/lib/src/sprite_box.dart
+13
-1
action_test.dart
packages/flutter_sprites/test/action_test.dart
+213
-0
constraint_test.dart
packages/flutter_sprites/test/constraint_test.dart
+82
-0
node_test.dart
packages/flutter_sprites/test/node_test.dart
+205
-0
No files found.
packages/flutter_sprites/lib/src/sprite_box.dart
View file @
ed40dd35
...
...
@@ -63,6 +63,12 @@ class SpriteBox extends RenderBox {
_scheduleTick
();
}
@override
void
detach
()
{
super
.
detach
();
_unscheduleTick
();
}
// Member variables
// Root node for drawing
...
...
@@ -366,8 +372,14 @@ class SpriteBox extends RenderBox {
// Updates
int
_frameCallbackId
;
void
_scheduleTick
()
{
SchedulerBinding
.
instance
.
scheduleFrameCallback
(
_tick
);
_frameCallbackId
=
SchedulerBinding
.
instance
.
scheduleFrameCallback
(
_tick
);
}
void
_unscheduleTick
()
{
SchedulerBinding
.
instance
.
cancelFrameCallbackWithId
(
_frameCallbackId
);
}
void
_tick
(
Duration
timeStamp
)
{
...
...
packages/flutter_sprites/test/action_test.dart
0 → 100644
View file @
ed40dd35
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:ui'
;
import
'package:flutter_sprites/flutter_sprites.dart'
;
import
'package:test/test.dart'
;
const
double
epsilon
=
0.01
;
void
main
(
)
{
test
(
"Actions - ActionTween"
,
()
{
// Tween doubles.
double
doubleValue
;
ActionTween
tween
=
new
ActionTween
((
double
a
)
=>
doubleValue
=
a
,
0.0
,
10.0
,
60.0
);
tween
.
update
(
0.0
);
expect
(
doubleValue
,
closeTo
(
0.0
,
epsilon
));
tween
.
update
(
0.1
);
expect
(
doubleValue
,
closeTo
(
1.0
,
epsilon
));
tween
.
update
(
0.5
);
expect
(
doubleValue
,
closeTo
(
5.0
,
epsilon
));
tween
.
update
(
1.0
);
expect
(
doubleValue
,
closeTo
(
10.0
,
epsilon
));
tween
.
update
(
1.5
);
expect
(
doubleValue
,
closeTo
(
15.0
,
epsilon
));
tween
.
update
(-
0.5
);
expect
(
doubleValue
,
closeTo
(-
5.0
,
epsilon
));
// Tween Points.
Point
pointValue
;
tween
=
new
ActionTween
((
Point
a
)
=>
pointValue
=
a
,
Point
.
origin
,
new
Point
(
10.0
,
20.0
),
60.0
);
tween
.
update
(
0.0
);
expect
(
pointValue
.
x
,
closeTo
(
0.0
,
epsilon
));
expect
(
pointValue
.
y
,
closeTo
(
0.0
,
epsilon
));
tween
.
update
(
0.1
);
expect
(
pointValue
.
x
,
closeTo
(
1.0
,
epsilon
));
expect
(
pointValue
.
y
,
closeTo
(
2.0
,
epsilon
));
tween
.
update
(
0.5
);
expect
(
pointValue
.
x
,
closeTo
(
5.0
,
epsilon
));
expect
(
pointValue
.
y
,
closeTo
(
10.0
,
epsilon
));
tween
.
update
(
1.0
);
expect
(
pointValue
.
x
,
closeTo
(
10.0
,
epsilon
));
expect
(
pointValue
.
y
,
closeTo
(
20.0
,
epsilon
));
tween
.
update
(
1.5
);
expect
(
pointValue
.
x
,
closeTo
(
15.0
,
epsilon
));
expect
(
pointValue
.
y
,
closeTo
(
30.0
,
epsilon
));
tween
.
update
(-
0.5
);
expect
(
pointValue
.
x
,
closeTo
(-
5.0
,
epsilon
));
expect
(
pointValue
.
y
,
closeTo
(-
10.0
,
epsilon
));
// Tween Colors.
Color
colorValue
;
tween
=
new
ActionTween
((
Color
a
)
=>
colorValue
=
a
,
const
Color
(
0xff000000
),
const
Color
(
0xffffffff
),
60.0
);
tween
.
update
(
0.0
);
expect
(
colorValue
,
equals
(
const
Color
(
0xff000000
)));
tween
.
update
(
0.5
);
expect
(
colorValue
,
equals
(
const
Color
(
0xff7f7f7f
)));
tween
.
update
(
1.0
);
expect
(
colorValue
,
equals
(
const
Color
(
0xffffffff
)));
tween
.
update
(-
0.5
);
expect
(
colorValue
,
equals
(
const
Color
(
0xff000000
)));
tween
.
update
(
1.5
);
expect
(
colorValue
,
equals
(
const
Color
(
0xffffffff
)));
// Tween Size.
Size
sizeValue
;
tween
=
new
ActionTween
((
Size
a
)
=>
sizeValue
=
a
,
Size
.
zero
,
const
Size
(
200.0
,
100.0
),
60.0
);
tween
.
update
(
0.0
);
expect
(
sizeValue
,
equals
(
Size
.
zero
));
tween
.
update
(
1.0
);
expect
(
sizeValue
,
equals
(
const
Size
(
200.0
,
100.0
)));
tween
.
update
(
0.5
);
expect
(
sizeValue
.
width
,
closeTo
(
100.0
,
epsilon
));
expect
(
sizeValue
.
height
,
closeTo
(
50.0
,
epsilon
));
// Tween Rect.
Rect
rectValue
;
tween
=
new
ActionTween
(
(
Rect
a
)
=>
rectValue
=
a
,
new
Rect
.
fromLTWH
(
0.0
,
0.0
,
100.0
,
100.0
),
new
Rect
.
fromLTWH
(
100.0
,
100.0
,
200.0
,
200.0
),
60.0
);
tween
.
update
(
0.0
);
expect
(
rectValue
,
equals
(
new
Rect
.
fromLTWH
(
0.0
,
0.0
,
100.0
,
100.0
)));
tween
.
update
(
1.0
);
expect
(
rectValue
,
equals
(
new
Rect
.
fromLTWH
(
100.0
,
100.0
,
200.0
,
200.0
)));
tween
.
update
(
0.5
);
expect
(
rectValue
.
left
,
closeTo
(
50.0
,
epsilon
));
expect
(
rectValue
.
top
,
closeTo
(
50.0
,
epsilon
));
expect
(
rectValue
.
width
,
closeTo
(
150.0
,
epsilon
));
expect
(
rectValue
.
height
,
closeTo
(
150.0
,
epsilon
));
});
test
(
"Actions - ActionRepeat"
,
()
{
double
doubleValue
;
ActionTween
tween
=
new
ActionTween
((
double
a
)
=>
doubleValue
=
a
,
0.0
,
1.0
,
60.0
);
ActionRepeat
repeat2x
=
new
ActionRepeat
(
tween
,
2
);
expect
(
repeat2x
.
duration
,
closeTo
(
120.0
,
epsilon
));
repeat2x
.
update
(
0.0
);
expect
(
doubleValue
,
closeTo
(
0.0
,
epsilon
));
repeat2x
.
update
(
0.25
);
expect
(
doubleValue
,
closeTo
(
0.5
,
epsilon
));
repeat2x
.
update
(
0.75
);
expect
(
doubleValue
,
closeTo
(
0.5
,
epsilon
));
repeat2x
.
update
(
1.0
);
expect
(
doubleValue
,
closeTo
(
1.0
,
epsilon
));
ActionRepeat
repeat4x
=
new
ActionRepeat
(
tween
,
4
);
expect
(
repeat4x
.
duration
,
closeTo
(
240.0
,
epsilon
));
repeat4x
.
update
(
0.0
);
expect
(
doubleValue
,
closeTo
(
0.0
,
epsilon
));
repeat4x
.
update
(
0.125
);
expect
(
doubleValue
,
closeTo
(
0.5
,
epsilon
));
repeat4x
.
update
(
0.875
);
expect
(
doubleValue
,
closeTo
(
0.5
,
epsilon
));
repeat4x
.
update
(
1.0
);
expect
(
doubleValue
,
closeTo
(
1.0
,
epsilon
));
});
test
(
"Actions - ActionGroup"
,
()
{
double
value0
;
double
value1
;
ActionTween
tween0
=
new
ActionTween
((
double
a
)
=>
value0
=
a
,
0.0
,
1.0
,
10.0
);
ActionTween
tween1
=
new
ActionTween
((
double
a
)
=>
value1
=
a
,
0.0
,
1.0
,
20.0
);
ActionGroup
group
=
new
ActionGroup
([
tween0
,
tween1
]);
expect
(
group
.
duration
,
closeTo
(
20.0
,
epsilon
));
group
.
update
(
0.0
);
expect
(
value0
,
closeTo
(
0.0
,
epsilon
));
expect
(
value1
,
closeTo
(
0.0
,
epsilon
));
group
.
update
(
0.5
);
expect
(
value0
,
closeTo
(
1.0
,
epsilon
));
expect
(
value1
,
closeTo
(
0.5
,
epsilon
));
group
.
update
(
1.0
);
expect
(
value0
,
closeTo
(
1.0
,
epsilon
));
expect
(
value1
,
closeTo
(
1.0
,
epsilon
));
});
test
(
"Actions - ActionSequence"
,
()
{
double
doubleValue
;
ActionTween
tween0
=
new
ActionTween
((
double
a
)
=>
doubleValue
=
a
,
0.0
,
1.0
,
4.0
);
ActionTween
tween1
=
new
ActionTween
((
double
a
)
=>
doubleValue
=
a
,
1.0
,
0.0
,
12.0
);
ActionSequence
sequence
=
new
ActionSequence
([
tween0
,
tween1
]);
expect
(
sequence
.
duration
,
closeTo
(
16.0
,
epsilon
));
sequence
.
update
(
0.0
);
expect
(
doubleValue
,
closeTo
(
0.0
,
epsilon
));
sequence
.
update
(
0.125
);
expect
(
doubleValue
,
closeTo
(
0.5
,
epsilon
));
sequence
.
update
(
0.25
);
expect
(
doubleValue
,
closeTo
(
1.0
,
epsilon
));
sequence
.
update
(
1.0
);
expect
(
doubleValue
,
closeTo
(
0.0
,
epsilon
));
});
test
(
"Actions - stepping"
,
()
{
double
doubleValue
;
ActionTween
tween
=
new
ActionTween
((
double
a
)
=>
doubleValue
=
a
,
0.0
,
1.0
,
60.0
);
tween
.
step
(
0.0
);
expect
(
doubleValue
,
closeTo
(
0.0
,
epsilon
));
tween
.
step
(
30.0
);
expect
(
doubleValue
,
closeTo
(
0.5
,
epsilon
));
tween
.
step
(
30.0
);
expect
(
doubleValue
,
closeTo
(
1.0
,
epsilon
));
});
}
packages/flutter_sprites/test/constraint_test.dart
0 → 100644
View file @
ed40dd35
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:ui'
;
import
'package:flutter_sprites/flutter_sprites.dart'
;
import
'package:test/test.dart'
;
const
double
epsilon
=
0.01
;
void
main
(
)
{
test
(
"Constraints - ConstraintPositionToNode"
,
()
{
Node
parent
=
new
Node
();
Node
node0
=
new
Node
();
Node
node1
=
new
Node
();
parent
.
addChild
(
node0
);
parent
.
addChild
(
node1
);
node1
.
constraints
=
[(
new
ConstraintPositionToNode
(
node0
))];
node0
.
position
=
const
Point
(
100.0
,
50.0
);
node1
.
applyConstraints
(
0.1
);
expect
(
node1
.
position
.
x
,
closeTo
(
100.0
,
epsilon
));
expect
(
node1
.
position
.
y
,
closeTo
(
50.0
,
epsilon
));
});
test
(
"Constraints - ConstraintRotationToNode"
,
()
{
Node
parent
=
new
Node
();
Node
node0
=
new
Node
();
Node
node1
=
new
Node
()..
position
=
const
Point
(
0.0
,
100.0
);
parent
.
addChild
(
node0
);
parent
.
addChild
(
node1
);
node1
.
constraints
=
[(
new
ConstraintRotationToNode
(
node0
))];
node1
.
applyConstraints
(
0.1
);
expect
(
node1
.
rotation
,
closeTo
(-
90.0
,
epsilon
));
});
test
(
"Constraints - ConstraintRotationToNodeRotation"
,
()
{
Node
parent
=
new
Node
();
Node
node0
=
new
Node
();
Node
node1
=
new
Node
();
parent
.
addChild
(
node0
);
parent
.
addChild
(
node1
);
node1
.
constraints
=
[(
new
ConstraintRotationToNodeRotation
(
node0
,
baseRotation:
10.0
))];
node0
.
rotation
=
90.0
;
node1
.
applyConstraints
(
0.1
);
expect
(
node1
.
rotation
,
closeTo
(
100.0
,
epsilon
));
});
test
(
"Constraints - ConstraintRotationToMovement"
,
()
{
Node
parent
=
new
Node
();
Node
node0
=
new
Node
();
parent
.
addChild
(
node0
);
Constraint
constraint
=
new
ConstraintRotationToMovement
();
node0
.
constraints
=
[
constraint
];
node0
.
position
=
const
Point
(
0.0
,
0.0
);
constraint
.
preUpdate
(
node0
,
0.1
);
node0
.
position
=
const
Point
(
0.0
,
100.0
);
node0
.
applyConstraints
(
0.1
);
expect
(
node0
.
rotation
,
closeTo
(
90.0
,
epsilon
));
});
}
packages/flutter_sprites/test/node_test.dart
0 → 100644
View file @
ed40dd35
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:ui'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter_sprites/flutter_sprites.dart'
;
import
'package:test/test.dart'
;
void
main
(
)
{
test
(
"Node - adding and removing children"
,
()
{
// Create root node.
NodeWithSize
rootNode
=
new
NodeWithSize
(
const
Size
(
1024.0
,
1024.0
));
expect
(
rootNode
.
spriteBox
,
isNull
);
expect
(
rootNode
.
children
.
length
,
equals
(
0
));
// Create children.
Node
child0
=
new
Node
();
Node
child1
=
new
Node
();
expect
(
child0
.
parent
,
isNull
);
expect
(
child1
.
parent
,
isNull
);
expect
(
child0
.
spriteBox
,
isNull
);
expect
(
child1
.
spriteBox
,
isNull
);
// Create sprite box.
SpriteBox
spriteBox
=
new
SpriteBox
(
rootNode
);
expect
(
rootNode
.
spriteBox
,
equals
(
spriteBox
));
// Add children.
rootNode
.
addChild
(
child0
);
rootNode
.
addChild
(
child1
);
expect
(
child0
,
isIn
(
rootNode
.
children
));
expect
(
child1
,
isIn
(
rootNode
.
children
));
expect
(
rootNode
.
children
.
length
,
equals
(
2
));
expect
(
child0
.
parent
,
equals
(
rootNode
));
expect
(
child1
.
parent
,
equals
(
rootNode
));
expect
(
child0
.
spriteBox
,
equals
(
spriteBox
));
expect
(
child1
.
spriteBox
,
equals
(
spriteBox
));
// Remove one of the children.
rootNode
.
removeChild
(
child0
);
expect
(
child1
,
isIn
(
rootNode
.
children
));
expect
(
child1
.
parent
,
equals
(
rootNode
));
expect
(
rootNode
.
children
.
length
,
equals
(
1
));
expect
(
child0
.
parent
,
isNull
);
expect
(
child0
.
spriteBox
,
isNull
);
// Add a child back in.
rootNode
.
addChild
(
child0
);
expect
(
child0
,
isIn
(
rootNode
.
children
));
expect
(
child1
,
isIn
(
rootNode
.
children
));
expect
(
rootNode
.
children
.
length
,
equals
(
2
));
expect
(
child0
.
parent
,
equals
(
rootNode
));
expect
(
child1
.
parent
,
equals
(
rootNode
));
expect
(
child0
.
spriteBox
,
equals
(
spriteBox
));
expect
(
child1
.
spriteBox
,
equals
(
spriteBox
));
// Remove all children.
rootNode
.
removeAllChildren
();
expect
(
rootNode
.
children
.
length
,
equals
(
0
));
expect
(
child0
.
parent
,
isNull
);
expect
(
child1
.
parent
,
isNull
);
expect
(
child0
.
spriteBox
,
isNull
);
expect
(
child1
.
spriteBox
,
isNull
);
});
testWidgets
(
"Node - transformations"
,
(
WidgetTester
tester
)
{
const
double
epsilon
=
0.01
;
NodeWithSize
rootNode
=
new
NodeWithSize
(
const
Size
(
1024.0
,
1024.0
));
tester
.
pumpWidget
(
new
SpriteWidget
(
rootNode
));
// Translations and transformations adding up correctly.
Node
child0
=
new
Node
();
child0
.
position
=
const
Point
(
100.0
,
0.0
);
rootNode
.
addChild
(
child0
);
Node
child1
=
new
Node
();
child1
.
position
=
const
Point
(
200.0
,
0.0
);
child0
.
addChild
(
child1
);
Point
rootPoint
=
rootNode
.
convertPointFromNode
(
Point
.
origin
,
child1
);
expect
(
rootPoint
.
x
,
closeTo
(
300.0
,
epsilon
));
expect
(
rootPoint
.
y
,
closeTo
(
0.0
,
epsilon
));
// Rotations.
Node
rotatedChild
=
new
Node
();
rotatedChild
.
rotation
=
90.0
;
rootNode
.
addChild
(
rotatedChild
);
rootPoint
=
rootNode
.
convertPointFromNode
(
const
Point
(
1.0
,
0.0
),
rotatedChild
);
expect
(
rootPoint
.
x
,
closeTo
(
0.0
,
epsilon
));
expect
(
rootPoint
.
y
,
closeTo
(
1.0
,
epsilon
));
// Scale.
Node
scaledChild
=
new
Node
();
scaledChild
.
scale
=
2.0
;
rootNode
.
addChild
(
scaledChild
);
rootPoint
=
rootNode
.
convertPointFromNode
(
const
Point
(
1.0
,
1.0
),
scaledChild
);
expect
(
rootPoint
.
x
,
closeTo
(
2.0
,
epsilon
));
expect
(
rootPoint
.
y
,
closeTo
(
2.0
,
epsilon
));
// Scale x-axis only.
Node
scaledXChild
=
new
Node
();
scaledXChild
.
scaleX
=
2.0
;
rootNode
.
addChild
(
scaledXChild
);
rootPoint
=
rootNode
.
convertPointFromNode
(
const
Point
(
1.0
,
1.0
),
scaledXChild
);
expect
(
rootPoint
.
x
,
closeTo
(
2.0
,
epsilon
));
expect
(
rootPoint
.
y
,
closeTo
(
1.0
,
epsilon
));
// Scale y-axis only.
Node
scaledYChild
=
new
Node
();
scaledYChild
.
scaleY
=
2.0
;
rootNode
.
addChild
(
scaledYChild
);
rootPoint
=
rootNode
.
convertPointFromNode
(
const
Point
(
1.0
,
1.0
),
scaledYChild
);
expect
(
rootPoint
.
x
,
closeTo
(
1.0
,
epsilon
));
expect
(
rootPoint
.
y
,
closeTo
(
2.0
,
epsilon
));
// Skew x-axis.
Node
skewedXChild
=
new
Node
();
skewedXChild
.
skewX
=
45.0
;
rootNode
.
addChild
(
skewedXChild
);
rootPoint
=
rootNode
.
convertPointFromNode
(
const
Point
(
1.0
,
1.0
),
skewedXChild
);
expect
(
rootPoint
.
x
,
closeTo
(
1.0
,
epsilon
));
expect
(
rootPoint
.
y
,
closeTo
(
2.0
,
epsilon
));
// Skew y-axis.
Node
skewedYChild
=
new
Node
();
skewedYChild
.
skewY
=
45.0
;
rootNode
.
addChild
(
skewedYChild
);
rootPoint
=
rootNode
.
convertPointFromNode
(
const
Point
(
1.0
,
1.0
),
skewedYChild
);
expect
(
rootPoint
.
x
,
closeTo
(
2.0
,
epsilon
));
expect
(
rootPoint
.
y
,
closeTo
(
1.0
,
epsilon
));
});
test
(
"Node - zOrder"
,
()
{
// Ensure zOrder takes president over order added.
{
Node
rootNode
=
new
Node
();
Node
node0
=
new
Node
();
Node
node1
=
new
Node
();
Node
node2
=
new
Node
()..
zPosition
=
1.0
;
Node
node3
=
new
Node
()..
zPosition
=
1.0
;
rootNode
.
addChild
(
node0
);
rootNode
.
addChild
(
node2
);
rootNode
.
addChild
(
node1
);
rootNode
.
addChild
(
node3
);
expect
(
rootNode
.
children
[
0
],
equals
(
node0
));
expect
(
rootNode
.
children
[
1
],
equals
(
node1
));
expect
(
rootNode
.
children
[
2
],
equals
(
node2
));
expect
(
rootNode
.
children
[
3
],
equals
(
node3
));
}
// Test negative zOrder.
{
Node
rootNode
=
new
Node
();
Node
node0
=
new
Node
()..
zPosition
=
-
1.0
;;
Node
node1
=
new
Node
();
Node
node2
=
new
Node
()..
zPosition
=
1.0
;
rootNode
.
addChild
(
node2
);
rootNode
.
addChild
(
node1
);
rootNode
.
addChild
(
node0
);
expect
(
rootNode
.
children
[
0
],
equals
(
node0
));
expect
(
rootNode
.
children
[
1
],
equals
(
node1
));
expect
(
rootNode
.
children
[
2
],
equals
(
node2
));
}
});
test
(
"Node - isPointInside"
,
()
{
Node
node
=
new
Node
();
expect
(
node
.
isPointInside
(
Point
.
origin
),
equals
(
false
));
NodeWithSize
nodeWithSize
=
new
NodeWithSize
(
const
Size
(
10.0
,
10.0
));
nodeWithSize
.
pivot
=
Point
.
origin
;
expect
(
nodeWithSize
.
isPointInside
(
const
Point
(
1.0
,
1.0
)),
isTrue
);
expect
(
nodeWithSize
.
isPointInside
(
const
Point
(
9.0
,
9.0
)),
isTrue
);
expect
(
nodeWithSize
.
isPointInside
(
const
Point
(
11.0
,
1.0
)),
isFalse
);
expect
(
nodeWithSize
.
isPointInside
(
const
Point
(-
1.0
,
-
1.0
)),
isFalse
);
nodeWithSize
.
pivot
=
const
Point
(
0.5
,
0.5
);
expect
(
nodeWithSize
.
isPointInside
(
const
Point
(
1.0
,
1.0
)),
isTrue
);
expect
(
nodeWithSize
.
isPointInside
(
const
Point
(
9.0
,
9.0
)),
isFalse
);
expect
(
nodeWithSize
.
isPointInside
(
const
Point
(
11.0
,
1.0
)),
isFalse
);
expect
(
nodeWithSize
.
isPointInside
(
const
Point
(-
1.0
,
-
1.0
)),
isTrue
);
});
}
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