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
yangql
googletest
Commits
fab35920
Commit
fab35920
authored
Oct 08, 2018
by
misterg
Committed by
Gennadiy Civil
Oct 08, 2018
Browse files
Remove non-variadic pre C++11 AllOf
PiperOrigin-RevId: 216183352
parent
40f82ce5
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
38 additions
and
286 deletions
+38
-286
googlemock/include/gmock/gmock-generated-matchers.h
googlemock/include/gmock/gmock-generated-matchers.h
+0
-170
googlemock/include/gmock/gmock-generated-matchers.h.pump
googlemock/include/gmock/gmock-generated-matchers.h.pump
+0
-50
googlemock/include/gmock/gmock-matchers.h
googlemock/include/gmock/gmock-matchers.h
+1
-8
googlemock/test/gmock-matchers_test.cc
googlemock/test/gmock-matchers_test.cc
+37
-58
No files found.
googlemock/include/gmock/gmock-generated-matchers.h
View file @
fab35920
...
...
@@ -297,94 +297,6 @@ class ArgsMatcher {
GTEST_DISALLOW_ASSIGN_
(
ArgsMatcher
);
};
// A set of metafunctions for computing the result type of AllOf.
// AllOf(m1, ..., mN) returns
// AllOfResultN<decltype(m1), ..., decltype(mN)>::type.
// Although AllOf isn't defined for one argument, AllOfResult1 is defined
// to simplify the implementation.
template
<
typename
M1
>
struct
AllOfResult1
{
typedef
M1
type
;
};
template
<
typename
M1
,
typename
M2
>
struct
AllOfResult2
{
typedef
BothOfMatcher
<
typename
AllOfResult1
<
M1
>::
type
,
typename
AllOfResult1
<
M2
>::
type
>
type
;
};
template
<
typename
M1
,
typename
M2
,
typename
M3
>
struct
AllOfResult3
{
typedef
BothOfMatcher
<
typename
AllOfResult1
<
M1
>::
type
,
typename
AllOfResult2
<
M2
,
M3
>::
type
>
type
;
};
template
<
typename
M1
,
typename
M2
,
typename
M3
,
typename
M4
>
struct
AllOfResult4
{
typedef
BothOfMatcher
<
typename
AllOfResult2
<
M1
,
M2
>::
type
,
typename
AllOfResult2
<
M3
,
M4
>::
type
>
type
;
};
template
<
typename
M1
,
typename
M2
,
typename
M3
,
typename
M4
,
typename
M5
>
struct
AllOfResult5
{
typedef
BothOfMatcher
<
typename
AllOfResult2
<
M1
,
M2
>::
type
,
typename
AllOfResult3
<
M3
,
M4
,
M5
>::
type
>
type
;
};
template
<
typename
M1
,
typename
M2
,
typename
M3
,
typename
M4
,
typename
M5
,
typename
M6
>
struct
AllOfResult6
{
typedef
BothOfMatcher
<
typename
AllOfResult3
<
M1
,
M2
,
M3
>::
type
,
typename
AllOfResult3
<
M4
,
M5
,
M6
>::
type
>
type
;
};
template
<
typename
M1
,
typename
M2
,
typename
M3
,
typename
M4
,
typename
M5
,
typename
M6
,
typename
M7
>
struct
AllOfResult7
{
typedef
BothOfMatcher
<
typename
AllOfResult3
<
M1
,
M2
,
M3
>::
type
,
typename
AllOfResult4
<
M4
,
M5
,
M6
,
M7
>::
type
>
type
;
};
template
<
typename
M1
,
typename
M2
,
typename
M3
,
typename
M4
,
typename
M5
,
typename
M6
,
typename
M7
,
typename
M8
>
struct
AllOfResult8
{
typedef
BothOfMatcher
<
typename
AllOfResult4
<
M1
,
M2
,
M3
,
M4
>::
type
,
typename
AllOfResult4
<
M5
,
M6
,
M7
,
M8
>::
type
>
type
;
};
template
<
typename
M1
,
typename
M2
,
typename
M3
,
typename
M4
,
typename
M5
,
typename
M6
,
typename
M7
,
typename
M8
,
typename
M9
>
struct
AllOfResult9
{
typedef
BothOfMatcher
<
typename
AllOfResult4
<
M1
,
M2
,
M3
,
M4
>::
type
,
typename
AllOfResult5
<
M5
,
M6
,
M7
,
M8
,
M9
>::
type
>
type
;
};
template
<
typename
M1
,
typename
M2
,
typename
M3
,
typename
M4
,
typename
M5
,
typename
M6
,
typename
M7
,
typename
M8
,
typename
M9
,
typename
M10
>
struct
AllOfResult10
{
typedef
BothOfMatcher
<
typename
AllOfResult5
<
M1
,
M2
,
M3
,
M4
,
M5
>::
type
,
typename
AllOfResult5
<
M6
,
M7
,
M8
,
M9
,
M10
>::
type
>
type
;
};
// A set of metafunctions for computing the result type of AnyOf.
// AnyOf(m1, ..., mN) returns
// AnyOfResultN<decltype(m1), ..., decltype(mN)>::type.
...
...
@@ -553,88 +465,6 @@ Args(const InnerMatcher& matcher) {
k9
,
k10
>
(
matcher
);
}
// AllOf(m1, m2, ..., mk) matches any value that matches all of the given
// sub-matchers. AllOf is called fully qualified to prevent ADL from firing.
template
<
typename
M1
,
typename
M2
>
inline
typename
internal
::
AllOfResult2
<
M1
,
M2
>::
type
AllOf
(
M1
m1
,
M2
m2
)
{
return
typename
internal
::
AllOfResult2
<
M1
,
M2
>::
type
(
m1
,
m2
);
}
template
<
typename
M1
,
typename
M2
,
typename
M3
>
inline
typename
internal
::
AllOfResult3
<
M1
,
M2
,
M3
>::
type
AllOf
(
M1
m1
,
M2
m2
,
M3
m3
)
{
return
typename
internal
::
AllOfResult3
<
M1
,
M2
,
M3
>::
type
(
m1
,
::
testing
::
AllOf
(
m2
,
m3
));
}
template
<
typename
M1
,
typename
M2
,
typename
M3
,
typename
M4
>
inline
typename
internal
::
AllOfResult4
<
M1
,
M2
,
M3
,
M4
>::
type
AllOf
(
M1
m1
,
M2
m2
,
M3
m3
,
M4
m4
)
{
return
typename
internal
::
AllOfResult4
<
M1
,
M2
,
M3
,
M4
>::
type
(
::
testing
::
AllOf
(
m1
,
m2
),
::
testing
::
AllOf
(
m3
,
m4
));
}
template
<
typename
M1
,
typename
M2
,
typename
M3
,
typename
M4
,
typename
M5
>
inline
typename
internal
::
AllOfResult5
<
M1
,
M2
,
M3
,
M4
,
M5
>::
type
AllOf
(
M1
m1
,
M2
m2
,
M3
m3
,
M4
m4
,
M5
m5
)
{
return
typename
internal
::
AllOfResult5
<
M1
,
M2
,
M3
,
M4
,
M5
>::
type
(
::
testing
::
AllOf
(
m1
,
m2
),
::
testing
::
AllOf
(
m3
,
m4
,
m5
));
}
template
<
typename
M1
,
typename
M2
,
typename
M3
,
typename
M4
,
typename
M5
,
typename
M6
>
inline
typename
internal
::
AllOfResult6
<
M1
,
M2
,
M3
,
M4
,
M5
,
M6
>::
type
AllOf
(
M1
m1
,
M2
m2
,
M3
m3
,
M4
m4
,
M5
m5
,
M6
m6
)
{
return
typename
internal
::
AllOfResult6
<
M1
,
M2
,
M3
,
M4
,
M5
,
M6
>::
type
(
::
testing
::
AllOf
(
m1
,
m2
,
m3
),
::
testing
::
AllOf
(
m4
,
m5
,
m6
));
}
template
<
typename
M1
,
typename
M2
,
typename
M3
,
typename
M4
,
typename
M5
,
typename
M6
,
typename
M7
>
inline
typename
internal
::
AllOfResult7
<
M1
,
M2
,
M3
,
M4
,
M5
,
M6
,
M7
>::
type
AllOf
(
M1
m1
,
M2
m2
,
M3
m3
,
M4
m4
,
M5
m5
,
M6
m6
,
M7
m7
)
{
return
typename
internal
::
AllOfResult7
<
M1
,
M2
,
M3
,
M4
,
M5
,
M6
,
M7
>::
type
(
::
testing
::
AllOf
(
m1
,
m2
,
m3
),
::
testing
::
AllOf
(
m4
,
m5
,
m6
,
m7
));
}
template
<
typename
M1
,
typename
M2
,
typename
M3
,
typename
M4
,
typename
M5
,
typename
M6
,
typename
M7
,
typename
M8
>
inline
typename
internal
::
AllOfResult8
<
M1
,
M2
,
M3
,
M4
,
M5
,
M6
,
M7
,
M8
>::
type
AllOf
(
M1
m1
,
M2
m2
,
M3
m3
,
M4
m4
,
M5
m5
,
M6
m6
,
M7
m7
,
M8
m8
)
{
return
typename
internal
::
AllOfResult8
<
M1
,
M2
,
M3
,
M4
,
M5
,
M6
,
M7
,
M8
>::
type
(
::
testing
::
AllOf
(
m1
,
m2
,
m3
,
m4
),
::
testing
::
AllOf
(
m5
,
m6
,
m7
,
m8
));
}
template
<
typename
M1
,
typename
M2
,
typename
M3
,
typename
M4
,
typename
M5
,
typename
M6
,
typename
M7
,
typename
M8
,
typename
M9
>
inline
typename
internal
::
AllOfResult9
<
M1
,
M2
,
M3
,
M4
,
M5
,
M6
,
M7
,
M8
,
M9
>::
type
AllOf
(
M1
m1
,
M2
m2
,
M3
m3
,
M4
m4
,
M5
m5
,
M6
m6
,
M7
m7
,
M8
m8
,
M9
m9
)
{
return
typename
internal
::
AllOfResult9
<
M1
,
M2
,
M3
,
M4
,
M5
,
M6
,
M7
,
M8
,
M9
>::
type
(
::
testing
::
AllOf
(
m1
,
m2
,
m3
,
m4
),
::
testing
::
AllOf
(
m5
,
m6
,
m7
,
m8
,
m9
));
}
template
<
typename
M1
,
typename
M2
,
typename
M3
,
typename
M4
,
typename
M5
,
typename
M6
,
typename
M7
,
typename
M8
,
typename
M9
,
typename
M10
>
inline
typename
internal
::
AllOfResult10
<
M1
,
M2
,
M3
,
M4
,
M5
,
M6
,
M7
,
M8
,
M9
,
M10
>::
type
AllOf
(
M1
m1
,
M2
m2
,
M3
m3
,
M4
m4
,
M5
m5
,
M6
m6
,
M7
m7
,
M8
m8
,
M9
m9
,
M10
m10
)
{
return
typename
internal
::
AllOfResult10
<
M1
,
M2
,
M3
,
M4
,
M5
,
M6
,
M7
,
M8
,
M9
,
M10
>::
type
(
::
testing
::
AllOf
(
m1
,
m2
,
m3
,
m4
,
m5
),
::
testing
::
AllOf
(
m6
,
m7
,
m8
,
m9
,
m10
));
}
// AnyOf(m1, m2, ..., mk) matches any value that matches any of the given
// sub-matchers. AnyOf is called fully qualified to prevent ADL from firing.
...
...
googlemock/include/gmock/gmock-generated-matchers.h.pump
View file @
fab35920
...
...
@@ -187,36 +187,6 @@ class ArgsMatcher {
GTEST_DISALLOW_ASSIGN_
(
ArgsMatcher
);
};
// A set of metafunctions for computing the result type of AllOf.
// AllOf(m1, ..., mN) returns
// AllOfResultN<decltype(m1), ..., decltype(mN)>::type.
// Although AllOf isn't defined for one argument, AllOfResult1 is defined
// to simplify the implementation.
template
<
typename
M1
>
struct
AllOfResult1
{
typedef
M1
type
;
};
$
range
i
1.
.
n
$
range
i
2.
.
n
$
for
i
[[
$
range
j
2.
.
i
$
var
m
=
i
/
2
$
range
k
1.
.
m
$
range
t
m
+
1.
.
i
template
<
typename
M1
$
for
j
[[,
typename
M
$
j
]]>
struct
AllOfResult
$
i
{
typedef
BothOfMatcher
<
typename
AllOfResult
$
m
<
$
for
k
,
[[
M
$
k
]]
>::
type
,
typename
AllOfResult
$
(
i
-
m
)
<
$
for
t
,
[[
M
$
t
]]
>::
type
>
type
;
};
]]
// A set of metafunctions for computing the result type of AnyOf.
// AnyOf(m1, ..., mN) returns
// AnyOfResultN<decltype(m1), ..., decltype(mN)>::type.
...
...
@@ -263,26 +233,6 @@ Args(const InnerMatcher& matcher) {
}
]]
// AllOf(m1, m2, ..., mk) matches any value that matches all of the given
// sub-matchers. AllOf is called fully qualified to prevent ADL from firing.
$
range
i
2.
.
n
$
for
i
[[
$
range
j
1.
.
i
$
var
m
=
i
/
2
$
range
k
1.
.
m
$
range
t
m
+
1.
.
i
template
<
$
for
j
,
[[
typename
M
$
j
]]>
inline
typename
internal
::
AllOfResult
$
i
<
$
for
j
,
[[
M
$
j
]]
>::
type
AllOf
(
$
for
j
,
[[
M
$
j
m
$
j
]])
{
return
typename
internal
::
AllOfResult
$
i
<
$
for
j
,
[[
M
$
j
]]
>::
type
(
$
if
m
==
1
[[
m1
]]
$
else
[[
::
testing
::
AllOf
(
$
for
k
,
[[
m
$
k
]])]],
$
if
m
+
1
==
i
[[
m
$
i
]]
$
else
[[
::
testing
::
AllOf
(
$
for
t
,
[[
m
$
t
]])]]);
}
]]
// AnyOf(m1, m2, ..., mk) matches any value that matches any of the given
...
...
googlemock/include/gmock/gmock-matchers.h
View file @
fab35920
...
...
@@ -1772,7 +1772,6 @@ class AllOfMatcherImpl
GTEST_DISALLOW_ASSIGN_
(
AllOfMatcherImpl
);
};
#if GTEST_LANG_CXX11
// VariadicMatcher is used for the variadic implementation of
// AllOf(m_1, m_2, ...) and AnyOf(m_1, m_2, ...).
// CombiningMatcher<T> is used to recursively combine the provided matchers
...
...
@@ -1816,8 +1815,6 @@ class VariadicMatcher {
template
<
typename
...
Args
>
using
AllOfMatcher
=
VariadicMatcher
<
AllOfMatcherImpl
,
Args
...
>
;
#endif // GTEST_LANG_CXX11
// Used for implementing the AllOf(m_1, ..., m_n) matcher, which
// matches a value that matches all of the matchers m_1, ..., and m_n.
template
<
typename
Matcher1
,
typename
Matcher2
>
...
...
@@ -5185,9 +5182,7 @@ UnorderedElementsAre(const Args&... matchers) {
make_tuple
(
matchers
...));
}
#if GTEST_LANG_CXX11
// Define variadic matcher versions. They are overloaded in
// gmock-generated-matchers.h for the cases supported by pre C++11 compilers.
// Define variadic matcher versions.
template
<
typename
...
Args
>
internal
::
AllOfMatcher
<
typename
std
::
decay
<
const
Args
&>::
type
...
>
AllOf
(
const
Args
&
...
matchers
)
{
...
...
@@ -5202,8 +5197,6 @@ internal::AnyOfMatcher<typename std::decay<const Args&>::type...> AnyOf(
matchers
...);
}
#endif // GTEST_LANG_CXX11
// AllArgs(m) is a synonym of m. This is useful in
//
// EXPECT_CALL(foo, Bar(_, _)).With(AllArgs(Eq()));
...
...
googlemock/test/gmock-matchers_test.cc
View file @
fab35920
...
...
@@ -2555,27 +2555,6 @@ TEST(AllOfTest, MatchesWhenAllMatch) {
Ne
(
9
),
Ne
(
10
)));
}
#if GTEST_LANG_CXX11
// Tests the variadic version of the AllOfMatcher.
TEST
(
AllOfTest
,
VariadicMatchesWhenAllMatch
)
{
// Make sure AllOf is defined in the right namespace and does not depend on
// ADL.
::
testing
::
AllOf
(
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
,
9
,
10
,
11
);
Matcher
<
int
>
m
=
AllOf
(
Ne
(
1
),
Ne
(
2
),
Ne
(
3
),
Ne
(
4
),
Ne
(
5
),
Ne
(
6
),
Ne
(
7
),
Ne
(
8
),
Ne
(
9
),
Ne
(
10
),
Ne
(
11
));
EXPECT_THAT
(
Describe
(
m
),
EndsWith
(
"and (isn't equal to 11)"
));
AllOfMatches
(
11
,
m
);
AllOfMatches
(
50
,
AllOf
(
Ne
(
1
),
Ne
(
2
),
Ne
(
3
),
Ne
(
4
),
Ne
(
5
),
Ne
(
6
),
Ne
(
7
),
Ne
(
8
),
Ne
(
9
),
Ne
(
10
),
Ne
(
11
),
Ne
(
12
),
Ne
(
13
),
Ne
(
14
),
Ne
(
15
),
Ne
(
16
),
Ne
(
17
),
Ne
(
18
),
Ne
(
19
),
Ne
(
20
),
Ne
(
21
),
Ne
(
22
),
Ne
(
23
),
Ne
(
24
),
Ne
(
25
),
Ne
(
26
),
Ne
(
27
),
Ne
(
28
),
Ne
(
29
),
Ne
(
30
),
Ne
(
31
),
Ne
(
32
),
Ne
(
33
),
Ne
(
34
),
Ne
(
35
),
Ne
(
36
),
Ne
(
37
),
Ne
(
38
),
Ne
(
39
),
Ne
(
40
),
Ne
(
41
),
Ne
(
42
),
Ne
(
43
),
Ne
(
44
),
Ne
(
45
),
Ne
(
46
),
Ne
(
47
),
Ne
(
48
),
Ne
(
49
),
Ne
(
50
)));
}
#endif // GTEST_LANG_CXX11
// Tests that AllOf(m1, ..., mn) describes itself properly.
TEST
(
AllOfTest
,
CanDescribeSelf
)
{
...
...
@@ -2584,59 +2563,59 @@ TEST(AllOfTest, CanDescribeSelf) {
EXPECT_EQ
(
"(is <= 2) and (is >= 1)"
,
Describe
(
m
));
m
=
AllOf
(
Gt
(
0
),
Ne
(
1
),
Ne
(
2
));
EXPECT_EQ
(
"(is > 0) and "
"((isn't equal to 1) and "
"(isn't equal to 2))"
,
Describe
(
m
));
std
::
string
expected_descr1
=
"(is > 0) and (isn't equal to 1) and (isn't equal to 2)"
;
EXPECT_EQ
(
expected_descr1
,
Describe
(
m
));
m
=
AllOf
(
Gt
(
0
),
Ne
(
1
),
Ne
(
2
),
Ne
(
3
));
EXPECT_EQ
(
"((is > 0) and "
"(isn't equal to 1)) and "
"((isn't equal to 2) and "
"(isn't equal to 3))"
,
Describe
(
m
));
std
::
string
expected_descr2
=
"(is > 0) and (isn't equal to 1) and (isn't equal to 2) and (isn't equal "
"to 3)"
;
EXPECT_EQ
(
expected_descr2
,
Describe
(
m
));
m
=
AllOf
(
Ge
(
0
),
Lt
(
10
),
Ne
(
3
),
Ne
(
5
),
Ne
(
7
));
EXPECT_EQ
(
"((is >= 0) and "
"(is < 10)) and "
"((isn't equal to 3) and "
"((isn't equal to 5) and "
"(isn't equal to 7)))"
,
Describe
(
m
));
std
::
string
expected_descr3
=
"(is >= 0) and (is < 10) and (isn't equal to 3) and (isn't equal to 5) "
"and (isn't equal to 7)"
;
EXPECT_EQ
(
expected_descr3
,
Describe
(
m
));
}
// Tests that AllOf(m1, ..., mn) describes its negation properly.
TEST
(
AllOfTest
,
CanDescribeNegation
)
{
Matcher
<
int
>
m
;
m
=
AllOf
(
Le
(
2
),
Ge
(
1
));
EXPECT_EQ
(
"(isn't <= 2) or "
"(isn't >= 1)"
,
DescribeNegation
(
m
));
std
::
string
expected_descr4
=
"(isn't <= 2) or (isn't >= 1)"
;
EXPECT_EQ
(
expected_descr4
,
DescribeNegation
(
m
));
m
=
AllOf
(
Gt
(
0
),
Ne
(
1
),
Ne
(
2
));
EXPECT_EQ
(
"(isn't > 0) or "
"((is equal to 1) or "
"(is equal to 2))"
,
DescribeNegation
(
m
));
std
::
string
expected_descr5
=
"(isn't > 0) or (is equal to 1) or (is equal to 2)"
;
EXPECT_EQ
(
expected_descr5
,
DescribeNegation
(
m
));
m
=
AllOf
(
Gt
(
0
),
Ne
(
1
),
Ne
(
2
),
Ne
(
3
));
EXPECT_EQ
(
"((isn't > 0) or "
"(is equal to 1)) or "
"((is equal to 2) or "
"(is equal to 3))"
,
DescribeNegation
(
m
));
std
::
string
expected_descr6
=
"(isn't > 0) or (is equal to 1) or (is equal to 2) or (is equal to 3)"
;
EXPECT_EQ
(
expected_descr6
,
DescribeNegation
(
m
));
m
=
AllOf
(
Ge
(
0
),
Lt
(
10
),
Ne
(
3
),
Ne
(
5
),
Ne
(
7
));
EXPECT_EQ
(
"((isn't >= 0) or "
"(isn't < 10)) or "
"((is equal to 3) or "
"((is equal to 5) or "
"(is equal to 7)))"
,
DescribeNegation
(
m
));
std
::
string
expected_desr7
=
"(isn't >= 0) or (isn't < 10) or (is equal to 3) or (is equal to 5) or "
"(is equal to 7)"
;
EXPECT_EQ
(
expected_desr7
,
DescribeNegation
(
m
));
m
=
AllOf
(
Ne
(
1
),
Ne
(
2
),
Ne
(
3
),
Ne
(
4
),
Ne
(
5
),
Ne
(
6
),
Ne
(
7
),
Ne
(
8
),
Ne
(
9
),
Ne
(
10
),
Ne
(
11
));
AllOf
(
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
,
9
,
10
,
11
);
EXPECT_THAT
(
Describe
(
m
),
EndsWith
(
"and (isn't equal to 11)"
));
AllOfMatches
(
11
,
m
);
AllOfMatches
(
50
,
AllOf
(
Ne
(
1
),
Ne
(
2
),
Ne
(
3
),
Ne
(
4
),
Ne
(
5
),
Ne
(
6
),
Ne
(
7
),
Ne
(
8
),
Ne
(
9
),
Ne
(
10
),
Ne
(
11
),
Ne
(
12
),
Ne
(
13
),
Ne
(
14
),
Ne
(
15
),
Ne
(
16
),
Ne
(
17
),
Ne
(
18
),
Ne
(
19
),
Ne
(
20
),
Ne
(
21
),
Ne
(
22
),
Ne
(
23
),
Ne
(
24
),
Ne
(
25
),
Ne
(
26
),
Ne
(
27
),
Ne
(
28
),
Ne
(
29
),
Ne
(
30
),
Ne
(
31
),
Ne
(
32
),
Ne
(
33
),
Ne
(
34
),
Ne
(
35
),
Ne
(
36
),
Ne
(
37
),
Ne
(
38
),
Ne
(
39
),
Ne
(
40
),
Ne
(
41
),
Ne
(
42
),
Ne
(
43
),
Ne
(
44
),
Ne
(
45
),
Ne
(
46
),
Ne
(
47
),
Ne
(
48
),
Ne
(
49
),
Ne
(
50
)));
}
// Tests that monomorphic matchers are safely cast by the AllOf matcher.
...
...
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