Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
ImportedProjects
SVG
Commits
5bd751c6
Commit
5bd751c6
authored
10 years ago
by
Tebjan Halm
Browse files
Options
Download
Plain Diff
Merge pull request #100 from vvvv/revert-97-BoundsPerformance
Revert "Performance Improvement"
parents
13132300
ae333749
Changes
27
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
Source/Basic Shapes/SvgCircle.cs
+3
-3
Source/Basic Shapes/SvgCircle.cs
Source/Basic Shapes/SvgEllipse.cs
+3
-3
Source/Basic Shapes/SvgEllipse.cs
Source/Basic Shapes/SvgImage.cs
+15
-15
Source/Basic Shapes/SvgImage.cs
Source/Basic Shapes/SvgLine.cs
+2
-2
Source/Basic Shapes/SvgLine.cs
Source/Basic Shapes/SvgPolygon.cs
+2
-2
Source/Basic Shapes/SvgPolygon.cs
Source/Basic Shapes/SvgRectangle.cs
+3
-3
Source/Basic Shapes/SvgRectangle.cs
Source/Basic Shapes/SvgVisualElement.cs
+18
-2
Source/Basic Shapes/SvgVisualElement.cs
Source/DataTypes/SvgUnit.cs
+3
-3
Source/DataTypes/SvgUnit.cs
Source/Document Structure/SvgFragment.cs
+37
-15
Source/Document Structure/SvgFragment.cs
Source/Document Structure/SvgGroup.cs
+21
-18
Source/Document Structure/SvgGroup.cs
Source/Document Structure/SvgSwitch.cs
+20
-17
Source/Document Structure/SvgSwitch.cs
Source/Document Structure/SvgSymbol.cs
+19
-16
Source/Document Structure/SvgSymbol.cs
Source/Document Structure/SvgUse.cs
+2
-3
Source/Document Structure/SvgUse.cs
Source/Extensibility/SvgForeignObject.cs
+20
-17
Source/Extensibility/SvgForeignObject.cs
Source/Painting/GenericBoundable.cs
+12
-2
Source/Painting/GenericBoundable.cs
Source/Painting/ISvgBoundable.cs
+14
-1
Source/Painting/ISvgBoundable.cs
Source/Painting/ImmutableBoundable.cs
+0
-19
Source/Painting/ImmutableBoundable.cs
Source/Painting/SvgGradientServer.cs
+1
-1
Source/Painting/SvgGradientServer.cs
Source/Painting/SvgLinearGradientServer.cs
+2
-2
Source/Painting/SvgLinearGradientServer.cs
Source/Painting/SvgMarker.cs
+8
-5
Source/Painting/SvgMarker.cs
with
205 additions
and
149 deletions
+205
-149
Source/Basic Shapes/SvgCircle.cs
+
3
-
3
View file @
5bd751c6
...
...
@@ -78,10 +78,10 @@ namespace Svg
/// <summary>
/// Gets the bounds of the circle.
/// </summary>
/// <
returns
>The rectangular bounds of the circle.</
returns
>
public
override
RectangleF
Calculate
Bounds
()
/// <
value
>The rectangular bounds of the circle.</
value
>
public
override
RectangleF
Bounds
{
return
this
.
Path
(
null
).
GetBounds
();
get
{
return
this
.
Path
(
null
).
GetBounds
();
}
}
/// <summary>
...
...
This diff is collapsed.
Click to expand it.
Source/Basic Shapes/SvgEllipse.cs
+
3
-
3
View file @
5bd751c6
...
...
@@ -92,10 +92,10 @@ namespace Svg
/// <summary>
/// Gets the bounds of the element.
/// </summary>
/// <
returns
>The bounds.</
returns
>
public
override
RectangleF
Calculate
Bounds
()
/// <
value
>The bounds.</
value
>
public
override
RectangleF
Bounds
{
return
this
.
Path
(
null
).
GetBounds
();
get
{
return
this
.
Path
(
null
).
GetBounds
();
}
}
/// <summary>
...
...
This diff is collapsed.
Click to expand it.
Source/Basic Shapes/SvgImage.cs
+
15
-
15
View file @
5bd751c6
...
...
@@ -76,21 +76,21 @@ namespace Svg
{
get
{
return
this
.
Attributes
.
GetAttribute
<
Uri
>(
"href"
);
}
set
{
this
.
Attributes
[
"href"
]
=
value
;
}
}
/// <summary>
/// Gets the bounds of the element.
/// </summary>
/// <
returns
>The bounds.</
returns>
public
override
RectangleF
Calculate
Bounds
()
{
return
new
RectangleF
(
this
.
Location
.
ToDeviceValue
(
null
,
this
),
new
SizeF
(
this
.
Width
.
ToDeviceValue
(
null
,
UnitRenderingType
.
Horizontal
,
this
),
this
.
Height
.
ToDeviceValue
(
null
,
UnitRenderingType
.
Vertical
,
this
)));
}
}
/// <summary>
/// Gets the bounds of the element.
/// </summary>
/// <
value
>The bounds.</
value>
public
override
RectangleF
Bounds
{
get
{
return
new
RectangleF
(
this
.
Location
.
ToDeviceValue
(
null
,
this
),
new
SizeF
(
this
.
Width
.
ToDeviceValue
(
null
,
UnitRenderingType
.
Horizontal
,
this
),
this
.
Height
.
ToDeviceValue
(
null
,
UnitRenderingType
.
Vertical
,
this
)));
}
}
/// <summary>
/// Gets the <see cref="GraphicsPath"/> for this element.
/// </summary>
...
...
This diff is collapsed.
Click to expand it.
Source/Basic Shapes/SvgLine.cs
+
2
-
2
View file @
5bd751c6
...
...
@@ -171,9 +171,9 @@ namespace Svg
return
result
;
}
public
override
RectangleF
Calculate
Bounds
()
public
override
System
.
Drawing
.
RectangleF
Bounds
{
return
this
.
Path
(
null
).
GetBounds
();
get
{
return
this
.
Path
(
null
).
GetBounds
();
}
}
public
override
SvgElement
DeepCopy
()
...
...
This diff is collapsed.
Click to expand it.
Source/Basic Shapes/SvgPolygon.cs
+
2
-
2
View file @
5bd751c6
...
...
@@ -130,9 +130,9 @@ namespace Svg
return
result
;
}
public
override
RectangleF
Calculate
Bounds
()
public
override
RectangleF
Bounds
{
return
this
.
Path
(
null
).
GetBounds
();
get
{
return
this
.
Path
(
null
).
GetBounds
();
}
}
...
...
This diff is collapsed.
Click to expand it.
Source/Basic Shapes/SvgRectangle.cs
+
3
-
3
View file @
5bd751c6
...
...
@@ -165,10 +165,10 @@ namespace Svg
/// <summary>
/// Gets the bounds of the element.
/// </summary>
/// <
returns
>The bounds.</
returns
>
public
override
RectangleF
Calculate
Bounds
()
/// <
value
>The bounds.</
value
>
public
override
RectangleF
Bounds
{
return
Path
(
null
).
GetBounds
();
get
{
return
Path
(
null
).
GetBounds
();
}
}
/// <summary>
...
...
This diff is collapsed.
Click to expand it.
Source/Basic Shapes/SvgVisualElement.cs
+
18
-
2
View file @
5bd751c6
...
...
@@ -19,11 +19,27 @@ namespace Svg
/// </summary>
public
abstract
GraphicsPath
Path
(
ISvgRenderer
renderer
);
PointF
ISvgBoundable
.
Location
{
get
{
return
Bounds
.
Location
;
}
}
SizeF
ISvgBoundable
.
Size
{
get
{
return
Bounds
.
Size
;
}
}
/// <summary>
/// Gets the bounds of the element.
/// </summary>
/// <
returns
>The bounds.</
returns
>
public
abstract
RectangleF
CalculateBounds
();
/// <
value
>The bounds.</
value
>
public
abstract
RectangleF
Bounds
{
get
;
}
/// <summary>
/// Gets the associated <see cref="SvgClipPath"/> if one has been specified.
...
...
This diff is collapsed.
Click to expand it.
Source/DataTypes/SvgUnit.cs
+
3
-
3
View file @
5bd751c6
...
...
@@ -149,7 +149,7 @@ namespace Svg
break
;
}
System
.
Drawing
.
SizeF
size
=
boundable
.
Calculate
Bounds
()
.
Size
;
System
.
Drawing
.
SizeF
size
=
boundable
.
Bounds
.
Size
;
switch
(
renderType
)
{
...
...
@@ -157,13 +157,13 @@ namespace Svg
_deviceValue
=
(
size
.
Width
/
100
)
*
value
;
break
;
case
UnitRenderingType
.
HorizontalOffset
:
_deviceValue
=
(
size
.
Width
/
100
)
*
value
+
boundable
.
CalculateBounds
().
Location
.
X
;
_deviceValue
=
(
size
.
Width
/
100
)
*
value
+
boundable
.
Location
.
X
;
break
;
case
UnitRenderingType
.
Vertical
:
_deviceValue
=
(
size
.
Height
/
100
)
*
value
;
break
;
case
UnitRenderingType
.
VerticalOffset
:
_deviceValue
=
(
size
.
Height
/
100
)
*
value
+
boundable
.
CalculateBounds
().
Location
.
Y
;
_deviceValue
=
(
size
.
Height
/
100
)
*
value
+
boundable
.
Location
.
Y
;
break
;
default
:
_deviceValue
=
(
float
)(
Math
.
Sqrt
(
Math
.
Pow
(
size
.
Width
,
2
)
+
Math
.
Pow
(
size
.
Height
,
2
))
/
Math
.
Sqrt
(
2
)
*
value
/
100.0
);
...
...
This diff is collapsed.
Click to expand it.
Source/Document Structure/SvgFragment.cs
+
37
-
15
View file @
5bd751c6
...
...
@@ -15,9 +15,28 @@ namespace Svg
/// </summary>
public
static
readonly
Uri
Namespace
=
new
Uri
(
"http://www.w3.org/2000/svg"
);
Rectangle
F
ISvgBoundable
.
CalculateBounds
()
Point
F
ISvgBoundable
.
Location
{
return
new
RectangleF
(
PointF
.
Empty
,
GetDimensions
());
get
{
return
PointF
.
Empty
;
}
}
SizeF
ISvgBoundable
.
Size
{
get
{
return
GetDimensions
();
}
}
RectangleF
ISvgBoundable
.
Bounds
{
get
{
return
new
RectangleF
(((
ISvgBoundable
)
this
).
Location
,
((
ISvgBoundable
)
this
).
Size
);
}
}
private
SvgUnit
_x
;
...
...
@@ -166,29 +185,32 @@ namespace Svg
break
;
}
}
/// <summary>
/// Gets the <see cref="GraphicsPath"/> for this element.
/// </summary>
/// <value></value>
public
GraphicsPath
Create
Path
()
public
GraphicsPath
Path
{
var
path
=
new
GraphicsPath
();
AddPaths
(
this
,
p
ath
);
get
{
var
path
=
new
GraphicsP
ath
(
);
return
path
;
AddPaths
(
this
,
path
);
return
path
;
}
}
/// <summary>
/// Gets the bounds of the svg element.
/// </summary>
/// <
returns
>The bounds.</
returns
>
public
RectangleF
Calculate
Bounds
()
{
using
(
var
path
=
CreatePath
())
/// <
value
>The bounds.</
value
>
public
RectangleF
Bounds
{
get
{
return
p
ath
.
GetBounds
();
return
this
.
P
ath
.
GetBounds
();
}
}
...
...
@@ -220,7 +242,7 @@ namespace Svg
}
else
{
bounds
=
this
.
Calculate
Bounds
()
;
//do just one call to the
expen
sive bounds
calculation method
bounds
=
this
.
Bounds
;
//do just one call to the
recur
sive bounds
property
}
}
...
...
This diff is collapsed.
Click to expand it.
Source/Document Structure/SvgGroup.cs
+
21
-
18
View file @
5bd751c6
...
...
@@ -21,32 +21,35 @@ namespace Svg
/// <summary>
/// Gets the bounds of the element.
/// </summary>
/// <
returns
>The bounds.</
returns
>
public
override
RectangleF
Calculate
Bounds
()
/// <
value
>The bounds.</
value
>
public
override
System
.
Drawing
.
RectangleF
Bounds
{
var
r
=
new
RectangleF
();
foreach
(
var
c
in
this
.
Children
)
{
if
(
c
is
SvgVisualElem
en
t
)
get
{
var
r
=
new
RectangleF
();
foreach
(
var
c
in
this
.
Childr
en
)
{
// First it should check if rectangle is empty or it will return the wrong Bounds.
// This is because when the Rectangle is Empty, the Union method adds as if the first values where X=0, Y=0
if
(
r
.
IsEmpty
)
if
(
c
is
SvgVisualElement
)
{
r
=
((
SvgVisualElement
)
c
).
CalculateBounds
();
}
else
{
var
childBounds
=
((
SvgVisualElement
)
c
).
CalculateBounds
();
if
(!
childBounds
.
IsEmpty
)
// First it should check if rectangle is empty or it will return the wrong Bounds.
// This is because when the Rectangle is Empty, the Union method adds as if the first values where X=0, Y=0
if
(
r
.
IsEmpty
)
{
r
=
((
SvgVisualElement
)
c
).
Bounds
;
}
else
{
r
=
RectangleF
.
Union
(
r
,
childBounds
);
var
childBounds
=
((
SvgVisualElement
)
c
).
Bounds
;
if
(!
childBounds
.
IsEmpty
)
{
r
=
RectangleF
.
Union
(
r
,
childBounds
);
}
}
}
}
return
r
;
}
return
r
;
}
protected
override
bool
Renderable
{
get
{
return
false
;
}
}
...
...
This diff is collapsed.
Click to expand it.
Source/Document Structure/SvgSwitch.cs
+
20
-
17
View file @
5bd751c6
...
...
@@ -25,32 +25,35 @@ namespace Svg
/// <summary>
/// Gets the bounds of the element.
/// </summary>
/// <
returns
>The bounds.</
returns
>
public
override
RectangleF
Calculate
Bounds
()
/// <
value
>The bounds.</
value
>
public
override
System
.
Drawing
.
RectangleF
Bounds
{
var
r
=
new
RectangleF
();
foreach
(
var
c
in
this
.
Children
)
get
{
if
(
c
is
SvgVisualElement
)
var
r
=
new
RectangleF
();
foreach
(
var
c
in
this
.
Children
)
{
// First it should check if rectangle is empty or it will return the wrong Bounds.
// This is because when the Rectangle is Empty, the Union method adds as if the first values where X=0, Y=0
if
(
r
.
IsEmpty
)
if
(
c
is
SvgVisualElement
)
{
r
=
((
SvgVisualElement
)
c
).
CalculateBounds
();
}
else
{
var
childBounds
=
((
SvgVisualElement
)
c
).
CalculateBounds
();
if
(!
childBounds
.
IsEmpty
)
// First it should check if rectangle is empty or it will return the wrong Bounds.
// This is because when the Rectangle is Empty, the Union method adds as if the first values where X=0, Y=0
if
(
r
.
IsEmpty
)
{
r
=
((
SvgVisualElement
)
c
).
Bounds
;
}
else
{
r
=
RectangleF
.
Union
(
r
,
childBounds
);
var
childBounds
=
((
SvgVisualElement
)
c
).
Bounds
;
if
(!
childBounds
.
IsEmpty
)
{
r
=
RectangleF
.
Union
(
r
,
childBounds
);
}
}
}
}
}
return
r
;
return
r
;
}
}
/// <summary>
...
...
This diff is collapsed.
Click to expand it.
Source/Document Structure/SvgSymbol.cs
+
19
-
16
View file @
5bd751c6
...
...
@@ -48,31 +48,34 @@ namespace Svg.Document_Structure
/// Gets the bounds of the element.
/// </summary>
/// <value>The bounds.</value>
public
override
System
.
Drawing
.
RectangleF
Calculate
Bounds
()
public
override
System
.
Drawing
.
RectangleF
Bounds
{
var
r
=
new
RectangleF
();
foreach
(
var
c
in
this
.
Children
)
get
{
if
(
c
is
SvgVisualElement
)
var
r
=
new
RectangleF
();
foreach
(
var
c
in
this
.
Children
)
{
// First it should check if rectangle is empty or it will return the wrong Bounds.
// This is because when the Rectangle is Empty, the Union method adds as if the first values where X=0, Y=0
if
(
r
.
IsEmpty
)
if
(
c
is
SvgVisualElement
)
{
r
=
((
SvgVisualElement
)
c
).
CalculateBounds
();
}
else
{
var
childBounds
=
((
SvgVisualElement
)
c
).
CalculateBounds
();
if
(!
childBounds
.
IsEmpty
)
// First it should check if rectangle is empty or it will return the wrong Bounds.
// This is because when the Rectangle is Empty, the Union method adds as if the first values where X=0, Y=0
if
(
r
.
IsEmpty
)
{
r
=
((
SvgVisualElement
)
c
).
Bounds
;
}
else
{
r
=
RectangleF
.
Union
(
r
,
childBounds
);
var
childBounds
=
((
SvgVisualElement
)
c
).
Bounds
;
if
(!
childBounds
.
IsEmpty
)
{
r
=
RectangleF
.
Union
(
r
,
childBounds
);
}
}
}
}
}
return
r
;
return
r
;
}
}
protected
override
bool
Renderable
{
get
{
return
false
;
}
}
...
...
This diff is collapsed.
Click to expand it.
Source/Document Structure/SvgUse.cs
+
2
-
3
View file @
5bd751c6
using
System
;
using
System.Collections.Generic
;
using
System.Drawing
;
using
System.Text
;
using
System.Web
;
using
System.Xml
;
...
...
@@ -62,9 +61,9 @@ namespace Svg
return
(
element
!=
null
)
?
element
.
Path
(
renderer
)
:
null
;
}
public
override
RectangleF
Calculate
Bounds
()
public
override
System
.
Drawing
.
RectangleF
Bounds
{
return
new
System
.
Drawing
.
RectangleF
();
get
{
return
new
System
.
Drawing
.
RectangleF
();
}
}
protected
override
bool
Renderable
{
get
{
return
false
;
}
}
...
...
This diff is collapsed.
Click to expand it.
Source/Extensibility/SvgForeignObject.cs
+
20
-
17
View file @
5bd751c6
...
...
@@ -25,32 +25,35 @@ namespace Svg
/// <summary>
/// Gets the bounds of the element.
/// </summary>
/// <
returns
>The bounds.</
returns
>
public
override
RectangleF
Calculate
Bounds
()
/// <
value
>The bounds.</
value
>
public
override
System
.
Drawing
.
RectangleF
Bounds
{
var
r
=
new
RectangleF
();
foreach
(
var
c
in
this
.
Children
)
get
{
if
(
c
is
SvgVisualElement
)
var
r
=
new
RectangleF
();
foreach
(
var
c
in
this
.
Children
)
{
// First it should check if rectangle is empty or it will return the wrong Bounds.
// This is because when the Rectangle is Empty, the Union method adds as if the first values where X=0, Y=0
if
(
r
.
IsEmpty
)
if
(
c
is
SvgVisualElement
)
{
r
=
((
SvgVisualElement
)
c
).
CalculateBounds
();
}
else
{
var
childBounds
=
((
SvgVisualElement
)
c
).
CalculateBounds
();
if
(!
childBounds
.
IsEmpty
)
// First it should check if rectangle is empty or it will return the wrong Bounds.
// This is because when the Rectangle is Empty, the Union method adds as if the first values where X=0, Y=0
if
(
r
.
IsEmpty
)
{
r
=
((
SvgVisualElement
)
c
).
Bounds
;
}
else
{
r
=
RectangleF
.
Union
(
r
,
childBounds
);
var
childBounds
=
((
SvgVisualElement
)
c
).
Bounds
;
if
(!
childBounds
.
IsEmpty
)
{
r
=
RectangleF
.
Union
(
r
,
childBounds
);
}
}
}
}
}
return
r
;
return
r
;
}
}
protected
override
bool
Renderable
{
get
{
return
false
;
}
}
...
...
This diff is collapsed.
Click to expand it.
Source/Painting/GenericBoundable.cs
+
12
-
2
View file @
5bd751c6
...
...
@@ -19,9 +19,19 @@ namespace Svg
_rect
=
new
RectangleF
(
x
,
y
,
width
,
height
);
}
public
RectangleF
CalculateBounds
()
public
System
.
Drawing
.
PointF
Location
{
return
_rect
;
get
{
return
_rect
.
Location
;
}
}
public
System
.
Drawing
.
SizeF
Size
{
get
{
return
_rect
.
Size
;
}
}
public
System
.
Drawing
.
RectangleF
Bounds
{
get
{
return
_rect
;
}
}
}
}
This diff is collapsed.
Click to expand it.
Source/Painting/ISvgBoundable.cs
+
14
-
1
View file @
5bd751c6
...
...
@@ -4,6 +4,19 @@ namespace Svg
{
public
interface
ISvgBoundable
{
RectangleF
CalculateBounds
();
PointF
Location
{
get
;
}
SizeF
Size
{
get
;
}
RectangleF
Bounds
{
get
;
}
}
}
\ No newline at end of file
This diff is collapsed.
Click to expand it.
Source/Painting/ImmutableBoundable.cs
deleted
100644 → 0
+
0
-
19
View file @
13132300
using
System.Drawing
;
namespace
Svg
{
internal
sealed
class
ImmutableBoundable
:
ISvgBoundable
{
private
readonly
RectangleF
bounds
;
public
ImmutableBoundable
(
ISvgBoundable
boundable
)
{
bounds
=
boundable
.
CalculateBounds
();
}
public
RectangleF
CalculateBounds
()
{
return
bounds
;
}
}
}
\ No newline at end of file
This diff is collapsed.
Click to expand it.
Source/Painting/SvgGradientServer.cs
+
1
-
1
View file @
5bd751c6
...
...
@@ -178,7 +178,7 @@ namespace Svg
for
(
int
i
=
0
;
i
<
colourBlends
;
i
++)
{
var
currentStop
=
this
.
Stops
[
radial
?
this
.
Stops
.
Count
-
1
-
actualStops
:
actualStops
];
var
boundWidth
=
renderer
.
GetBoundable
().
Calculate
Bounds
()
.
Width
;
var
boundWidth
=
renderer
.
GetBoundable
().
Bounds
.
Width
;
mergedOpacity
=
opacity
*
currentStop
.
GetOpacity
();
position
=
...
...
This diff is collapsed.
Click to expand it.
Source/Painting/SvgLinearGradientServer.cs
+
2
-
2
View file @
5bd751c6
...
...
@@ -191,7 +191,7 @@ namespace Svg
private
LinePoints
PointsToMove
(
ISvgBoundable
boundable
,
PointF
specifiedStart
,
PointF
specifiedEnd
)
{
var
bounds
=
boundable
.
Calculate
Bounds
()
;
var
bounds
=
boundable
.
Bounds
;
if
(
specifiedStart
.
X
==
specifiedEnd
.
X
)
{
return
(
bounds
.
Top
<
specifiedStart
.
Y
&&
specifiedStart
.
Y
<
bounds
.
Bottom
?
LinePoints
.
Start
:
LinePoints
.
None
)
|
...
...
@@ -227,7 +227,7 @@ namespace Svg
return
new
GradientPoints
(
specifiedStart
,
specifiedEnd
);
}
var
bounds
=
boundable
.
Calculate
Bounds
()
;
var
bounds
=
boundable
.
Bounds
;
var
effectiveStart
=
specifiedStart
;
var
effectiveEnd
=
specifiedEnd
;
var
intersectionPoints
=
CandidateIntersections
(
bounds
,
specifiedStart
,
specifiedEnd
);
...
...
This diff is collapsed.
Click to expand it.
Source/Painting/SvgMarker.cs
+
8
-
5
View file @
5bd751c6
...
...
@@ -95,12 +95,15 @@ namespace Svg
return
null
;
}
public
override
RectangleF
Calculate
Bounds
()
public
override
System
.
Drawing
.
RectangleF
Bounds
{
var
path
=
this
.
Path
(
null
);
if
(
path
!=
null
)
return
path
.
GetBounds
();
return
new
System
.
Drawing
.
RectangleF
();
get
{
var
path
=
this
.
Path
(
null
);
if
(
path
!=
null
)
return
path
.
GetBounds
();
return
new
System
.
Drawing
.
RectangleF
();
}
}
public
override
SvgElement
DeepCopy
()
...
...
This diff is collapsed.
Click to expand it.
Prev
1
2
Next
Write
Preview
Supports
Markdown
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
Menu
Projects
Groups
Snippets
Help