Skip to content

Commit 3415717

Browse files
authored
Merge pull request #1942 from stan-dev/fix/sfinae-operators
Replace ... with * = nullptr for requires
2 parents a9a2ceb + 0e880b3 commit 3415717

34 files changed

+76
-73
lines changed

stan/math/fwd/core/operator_division.hpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ inline fvar<T> operator/(const fvar<T>& x1, const fvar<T>& x2) {
3131
* @param x2 second argument
3232
* @return first argument divided by second argument
3333
*/
34-
template <typename T, typename U, require_arithmetic_t<U>...>
34+
template <typename T, typename U, require_arithmetic_t<U>* = nullptr>
3535
inline fvar<T> operator/(const fvar<T>& x1, U x2) {
3636
return fvar<T>(x1.val_ / x2, x1.d_ / x2);
3737
}
@@ -44,7 +44,7 @@ inline fvar<T> operator/(const fvar<T>& x1, U x2) {
4444
* @param x2 second argument
4545
* @return first argument divided by second argument
4646
*/
47-
template <typename T, typename U, require_arithmetic_t<U>...>
47+
template <typename T, typename U, require_arithmetic_t<U>* = nullptr>
4848
inline fvar<T> operator/(U x1, const fvar<T>& x2) {
4949
return fvar<T>(x1 / x2.val_, -x1 * x2.d_ / (x2.val_ * x2.val_));
5050
}
@@ -54,7 +54,7 @@ inline std::complex<fvar<T>> operator/(const std::complex<fvar<T>>& x1,
5454
const std::complex<fvar<T>>& x2) {
5555
return internal::complex_divide(x1, x2);
5656
}
57-
template <typename T, typename U, require_arithmetic_t<U>...>
57+
template <typename T, typename U, require_arithmetic_t<U>* = nullptr>
5858
inline std::complex<fvar<T>> operator/(const std::complex<fvar<T>>& x1,
5959
const std::complex<U>& x2) {
6060
return internal::complex_divide(x1, x2);
@@ -64,17 +64,17 @@ inline std::complex<fvar<T>> operator/(const std::complex<fvar<T>>& x1,
6464
const fvar<T>& x2) {
6565
return internal::complex_divide(x1, x2);
6666
}
67-
template <typename T, typename U, require_arithmetic_t<U>...>
67+
template <typename T, typename U, require_arithmetic_t<U>* = nullptr>
6868
inline std::complex<fvar<T>> operator/(const std::complex<fvar<T>>& x1, U x2) {
6969
return internal::complex_divide(x1, x2);
7070
}
7171

72-
template <typename T, typename U, require_arithmetic_t<U>...>
72+
template <typename T, typename U, require_arithmetic_t<U>* = nullptr>
7373
inline std::complex<fvar<T>> operator/(const std::complex<U>& x1,
7474
const std::complex<fvar<T>>& x2) {
7575
return internal::complex_divide(x1, x2);
7676
}
77-
template <typename T, typename U, require_arithmetic_t<U>...>
77+
template <typename T, typename U, require_arithmetic_t<U>* = nullptr>
7878
inline std::complex<fvar<T>> operator/(const std::complex<U>& x1,
7979
const fvar<T>& x2) {
8080
return internal::complex_divide(x1, x2);
@@ -92,7 +92,7 @@ inline std::complex<fvar<T>> operator/(const fvar<T>& x1,
9292
return internal::complex_divide(x1, x2);
9393
}
9494

95-
template <typename T, typename U, require_arithmetic_t<U>...>
95+
template <typename T, typename U, require_arithmetic_t<U>* = nullptr>
9696
inline std::complex<fvar<T>> operator/(U x1, const std::complex<fvar<T>>& x2) {
9797
return internal::complex_divide(x1, x2);
9898
}

stan/math/fwd/fun/is_nan.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ namespace math {
1818
* @param x Value to test.
1919
* @return <code>1</code> if the value is NaN and <code>0</code> otherwise.
2020
*/
21-
template <typename T, require_fvar_t<T>...>
21+
template <typename T, require_fvar_t<T>* = nullptr>
2222
inline bool is_nan(T&& x) {
2323
return is_nan(std::forward<decltype(x.val())>(x.val()));
2424
}

stan/math/fwd/fun/log_mix.hpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ inline fvar<T> log_mix(const fvar<T>& theta, const fvar<T>& lambda1,
114114
}
115115
}
116116

117-
template <typename T, typename P, require_all_arithmetic_t<P>...>
117+
template <typename T, typename P, require_all_arithmetic_t<P>* = nullptr>
118118
inline fvar<T> log_mix(const fvar<T>& theta, const fvar<T>& lambda1,
119119
P lambda2) {
120120
if (lambda1.val_ > lambda2) {
@@ -132,7 +132,7 @@ inline fvar<T> log_mix(const fvar<T>& theta, const fvar<T>& lambda1,
132132
}
133133
}
134134

135-
template <typename T, typename P, require_all_arithmetic_t<P>...>
135+
template <typename T, typename P, require_all_arithmetic_t<P>* = nullptr>
136136
inline fvar<T> log_mix(const fvar<T>& theta, P lambda1,
137137
const fvar<T>& lambda2) {
138138
if (lambda1 > lambda2.val_) {
@@ -150,7 +150,7 @@ inline fvar<T> log_mix(const fvar<T>& theta, P lambda1,
150150
}
151151
}
152152

153-
template <typename T, typename P, require_all_arithmetic_t<P>...>
153+
template <typename T, typename P, require_all_arithmetic_t<P>* = nullptr>
154154
inline fvar<T> log_mix(P theta, const fvar<T>& lambda1,
155155
const fvar<T>& lambda2) {
156156
if (lambda1.val_ > lambda2.val_) {
@@ -169,7 +169,7 @@ inline fvar<T> log_mix(P theta, const fvar<T>& lambda1,
169169
}
170170

171171
template <typename T, typename P1, typename P2,
172-
require_all_arithmetic_t<P1, P2>...>
172+
require_all_arithmetic_t<P1, P2>* = nullptr>
173173
inline fvar<T> log_mix(const fvar<T>& theta, P1 lambda1, P2 lambda2) {
174174
if (lambda1 > lambda2) {
175175
fvar<T> partial_deriv_array[1];
@@ -185,7 +185,7 @@ inline fvar<T> log_mix(const fvar<T>& theta, P1 lambda1, P2 lambda2) {
185185
}
186186

187187
template <typename T, typename P1, typename P2,
188-
require_all_arithmetic_t<P1, P2>...>
188+
require_all_arithmetic_t<P1, P2>* = nullptr>
189189
inline fvar<T> log_mix(P1 theta, const fvar<T>& lambda1, P2 lambda2) {
190190
if (lambda1.val_ > lambda2) {
191191
fvar<T> partial_deriv_array[1];
@@ -201,7 +201,7 @@ inline fvar<T> log_mix(P1 theta, const fvar<T>& lambda1, P2 lambda2) {
201201
}
202202

203203
template <typename T, typename P1, typename P2,
204-
require_all_arithmetic_t<P1, P2>...>
204+
require_all_arithmetic_t<P1, P2>* = nullptr>
205205
inline fvar<T> log_mix(P1 theta, P2 lambda1, const fvar<T>& lambda2) {
206206
if (lambda1 > lambda2.val_) {
207207
fvar<T> partial_deriv_array[1];

stan/math/fwd/fun/log_sum_exp.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ inline fvar<T> log_sum_exp(const fvar<T>& x1, double x2) {
5050
* @param[in] x Matrix of specified values.
5151
* @return The log of the sum of the exponentiated vector values.
5252
*/
53-
template <typename T, require_container_st<is_fvar, T>...>
53+
template <typename T, require_container_st<is_fvar, T>* = nullptr>
5454
inline auto log_sum_exp(const T& x) {
5555
return apply_vector_unary<T>::reduce(x, [&](const auto& v) {
5656
using T_fvar_inner = typename value_type_t<decltype(v)>::Scalar;

stan/math/opencl/copy.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ namespace math {
4141
* @return matrix_cl with a copy of the data in the source matrix
4242
*/
4343
template <typename Mat, typename Mat_scalar = scalar_type_t<Mat>,
44-
require_eigen_vt<std::is_arithmetic, Mat>...>
44+
require_eigen_vt<std::is_arithmetic, Mat>* = nullptr>
4545
inline matrix_cl<Mat_scalar> to_matrix_cl(Mat&& src) {
4646
return matrix_cl<Mat_scalar>(std::forward<Mat>(src));
4747
}
@@ -60,7 +60,7 @@ inline matrix_cl<Mat_scalar> to_matrix_cl(Mat&& src) {
6060
* @return matrix_cl with a copy of the data in the source matrix
6161
*/
6262
template <typename Vec, typename Vec_scalar = scalar_type_t<Vec>,
63-
require_std_vector_vt<std::is_arithmetic, Vec>...>
63+
require_std_vector_vt<std::is_arithmetic, Vec>* = nullptr>
6464
inline matrix_cl<Vec_scalar> to_matrix_cl(Vec&& src) {
6565
return matrix_cl<Vec_scalar>(std::forward<Vec>(src));
6666
}
@@ -158,7 +158,7 @@ inline std::vector<T> packed_copy(const matrix_cl<T>& src) {
158158
*/
159159
template <matrix_cl_view matrix_view, typename Vec,
160160
typename Vec_scalar = scalar_type_t<Vec>,
161-
require_vector_vt<std::is_arithmetic, Vec>...>
161+
require_vector_vt<std::is_arithmetic, Vec>* = nullptr>
162162
inline matrix_cl<Vec_scalar> packed_copy(Vec&& src, int rows) {
163163
const int packed_size = rows * (rows + 1) / 2;
164164
check_size_match("copy (packed std::vector -> OpenCL)", "src.size()",

stan/math/opencl/kernel_cl.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ inline void assign_event(const cl::Event& e,
112112
helper.set(e, m);
113113
}
114114

115-
template <typename T, require_same_t<T, cl::Event>...>
115+
template <typename T, require_same_t<T, cl::Event>* = nullptr>
116116
inline void assign_events(const T&) {}
117117

118118
/** \ingroup kernel_executor_opencl

stan/math/opencl/matrix_cl.hpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -233,8 +233,8 @@ class matrix_cl<T, require_arithmetic_t<T>> {
233233
* @throw <code>std::system_error</code> if the memory on the device could not
234234
* be allocated
235235
*/
236-
template <typename Vec, require_std_vector_vt<is_eigen, Vec>...,
237-
require_st_same<Vec, T>...>
236+
template <typename Vec, require_std_vector_vt<is_eigen, Vec>* = nullptr,
237+
require_st_same<Vec, T>* = nullptr>
238238
explicit matrix_cl(Vec&& A) try : rows_(A.empty() ? 0 : A[0].size()),
239239
cols_(A.size()) {
240240
if (this->size() == 0) {
@@ -305,7 +305,8 @@ class matrix_cl<T, require_arithmetic_t<T>> {
305305
* @throw <code>std::system_error</code> if the memory on the device could not
306306
* be allocated
307307
*/
308-
template <typename Mat, require_eigen_t<Mat>..., require_vt_same<Mat, T>...>
308+
template <typename Mat, require_eigen_t<Mat>* = nullptr,
309+
require_vt_same<Mat, T>* = nullptr>
309310
explicit matrix_cl(Mat&& A,
310311
matrix_cl_view partial_view = matrix_cl_view::Entire)
311312
: rows_(A.rows()), cols_(A.cols()), view_(partial_view) {
@@ -360,8 +361,8 @@ class matrix_cl<T, require_arithmetic_t<T>> {
360361
* @throw <code>std::system_error</code> if the memory on the device could not
361362
* be allocated
362363
*/
363-
template <typename Vec, require_std_vector_t<Vec>...,
364-
require_vt_same<Vec, T>...>
364+
template <typename Vec, require_std_vector_t<Vec>* = nullptr,
365+
require_vt_same<Vec, T>* = nullptr>
365366
explicit matrix_cl(Vec&& A,
366367
matrix_cl_view partial_view = matrix_cl_view::Entire)
367368
: matrix_cl(std::forward<Vec>(A), A.size(), 1) {}
@@ -384,8 +385,8 @@ class matrix_cl<T, require_arithmetic_t<T>> {
384385
* @throw <code>std::system_error</code> if the memory on the device could not
385386
* be allocated
386387
*/
387-
template <typename Vec, require_std_vector_t<Vec>...,
388-
require_vt_same<Vec, T>...>
388+
template <typename Vec, require_std_vector_t<Vec>* = nullptr,
389+
require_vt_same<Vec, T>* = nullptr>
389390
explicit matrix_cl(Vec&& A, const int& R, const int& C,
390391
matrix_cl_view partial_view = matrix_cl_view::Entire)
391392
: rows_(R), cols_(C), view_(partial_view) {
@@ -409,7 +410,7 @@ class matrix_cl<T, require_arithmetic_t<T>> {
409410
* @throw <code>std::system_error</code> if the memory on the device could not
410411
* be allocated
411412
*/
412-
template <typename U, require_same_t<T, U>...>
413+
template <typename U, require_same_t<T, U>* = nullptr>
413414
explicit matrix_cl(const U* A, const int& R, const int& C,
414415
matrix_cl_view partial_view = matrix_cl_view::Entire)
415416
: rows_(R), cols_(C), view_(partial_view) {

stan/math/opencl/rev/copy.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ namespace math {
2626
* @param src source Eigen matrix
2727
* @return matrix_cl with a copy of the data in the source matrix
2828
*/
29-
template <typename T, int R, int C, require_var_t<T>...>
29+
template <typename T, int R, int C, require_var_t<T>* = nullptr>
3030
inline matrix_cl<T> to_matrix_cl(const Eigen::Matrix<T, R, C>& src) try {
3131
matrix_cl<T> dst(src.rows(), src.cols());
3232
if (src.size() == 0) {
@@ -50,7 +50,7 @@ inline matrix_cl<T> to_matrix_cl(const Eigen::Matrix<T, R, C>& src) try {
5050
* @return Eigen matrix with a copy of the adjoints in the source matrix
5151
*/
5252
template <int R = Eigen::Dynamic, int C = Eigen::Dynamic, typename T,
53-
require_var_t<T>...>
53+
require_var_t<T>* = nullptr>
5454
inline Eigen::Matrix<double, R, C> from_matrix_cl(const matrix_cl<T>& src) try {
5555
Eigen::Matrix<double, R, C> dst(src.rows(), src.cols());
5656
if (src.size() == 0) {
@@ -130,7 +130,7 @@ inline matrix_cl<var> packed_copy(vari** src, int rows) try {
130130
* @throw <code>std::invalid_argument</code> if the
131131
* matrices do not have matching dimensions
132132
*/
133-
template <typename T, require_var_t<T>...>
133+
template <typename T, require_var_t<T>* = nullptr>
134134
inline matrix_cl<T> copy_cl(const matrix_cl<T>& src) {
135135
matrix_cl<T> dst(src.rows(), src.cols(), src.view());
136136
if (src.size() == 0) {

stan/math/opencl/rev/matrix_cl.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ class matrix_cl<T, require_var_t<T>> {
107107
* @param A an object derived from `Eigen::EigenBase`
108108
* @param partial_view `matrix_cl_view` for declaring special type.
109109
*/
110-
template <typename Mat, require_eigen_st<is_var, Mat>...>
110+
template <typename Mat, require_eigen_st<is_var, Mat>* = nullptr>
111111
explicit matrix_cl(Mat&& A,
112112
matrix_cl_view partial_view = matrix_cl_view::Entire)
113113
: rows_(A.rows()),

stan/math/prim/fun/isfinite.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace math {
1717
* @param[in] v argument
1818
* @return true if argument is finite
1919
*/
20-
template <typename ADType, require_autodiff_t<ADType>...>
20+
template <typename ADType, require_autodiff_t<ADType>* = nullptr>
2121
inline bool isfinite(ADType&& v) {
2222
using std::isfinite;
2323
return isfinite(v.val());

stan/math/prim/fun/isnormal.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace math {
1717
* @param[in] v argument
1818
* @return true if argument is normal
1919
*/
20-
template <typename ADType, require_autodiff_t<ADType>...>
20+
template <typename ADType, require_autodiff_t<ADType>* = nullptr>
2121
inline bool isnormal(ADType&& v) {
2222
using std::isnormal;
2323
return isnormal(v.val());

stan/math/prim/fun/log_softmax.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ namespace math {
4040
* Note: The return must be evaluated otherwise the Ref object falls out
4141
* of scope
4242
*/
43-
template <typename Container, require_arithmetic_t<scalar_type_t<Container>>...>
43+
template <typename Container,
44+
require_arithmetic_t<scalar_type_t<Container>>* = nullptr>
4445
inline auto log_softmax(const Container& x) {
4546
return apply_vector_unary<Container>::apply(x, [](const auto& v) {
4647
const Eigen::Ref<const plain_type_t<decltype(v)>>& v_ref = v;

stan/math/prim/fun/log_sum_exp.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ inline return_type_t<T1, T2> log_sum_exp(const T2& a, const T1& b) {
7676
* @param[in] x matrix of specified values
7777
* @return The log of the sum of the exponentiated vector values.
7878
*/
79-
template <typename T, require_container_st<std::is_arithmetic, T>...>
79+
template <typename T, require_container_st<std::is_arithmetic, T>* = nullptr>
8080
inline auto log_sum_exp(const T& x) {
8181
return apply_vector_unary<T>::reduce(x, [&](const auto& v) {
8282
if (v.size() == 0) {

stan/math/prim/fun/signbit.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace math {
1717
* @param[in] v argument
1818
* @return `true` if the argument is negative
1919
*/
20-
template <typename ADType, require_autodiff_t<ADType>...>
20+
template <typename ADType, require_autodiff_t<ADType>* = nullptr>
2121
inline bool signbit(ADType&& v) {
2222
using std::signbit;
2323
return signbit(v.val());

stan/math/prim/meta/apply_vector_unary.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,13 @@ struct apply_vector_unary<T, require_eigen_t<T>> {
4646
* @return Eigen object with result of applying functor to input
4747
*/
4848
template <typename F, typename T2 = T,
49-
require_t<is_eigen_matrix_base<plain_type_t<T2>>>...>
49+
require_t<is_eigen_matrix_base<plain_type_t<T2>>>* = nullptr>
5050
static inline auto apply(const T& x, const F& f) {
5151
return f(x).matrix().eval();
5252
}
5353

5454
template <typename F, typename T2 = T,
55-
require_t<is_eigen_array<plain_type_t<T2>>>...>
55+
require_t<is_eigen_array<plain_type_t<T2>>>* = nullptr>
5656
static inline auto apply(const T& x, const F& f) {
5757
return f(x).array().eval();
5858
}

stan/math/rev/core/matrix_vari.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class op_matrix_vari : public vari {
1717
vari** vis_;
1818

1919
public:
20-
template <typename T, require_eigen_vt<is_var, T>...>
20+
template <typename T, require_eigen_vt<is_var, T>* = nullptr>
2121
op_matrix_vari(double f, const T& vs) : vari(f), size_(vs.size()) {
2222
vis_ = ChainableStack::instance_->memalloc_.alloc_array<vari*>(size_);
2323
Eigen::Map<Eigen::Matrix<vari*, -1, -1>>(vis_, vs.rows(), vs.cols())

stan/math/rev/core/operator_addition.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ inline var operator+(var a, var b) {
9494
* @param b Second scalar operand.
9595
* @return Result of adding variable and scalar.
9696
*/
97-
template <typename Arith, require_arithmetic_t<Arith>...>
97+
template <typename Arith, require_arithmetic_t<Arith>* = nullptr>
9898
inline var operator+(var a, Arith b) {
9999
if (b == 0.0) {
100100
return a;
@@ -114,7 +114,7 @@ inline var operator+(var a, Arith b) {
114114
* @param b Second variable operand.
115115
* @return Result of adding variable and scalar.
116116
*/
117-
template <typename Arith, require_arithmetic_t<Arith>...>
117+
template <typename Arith, require_arithmetic_t<Arith>* = nullptr>
118118
inline var operator+(Arith a, var b) {
119119
if (a == 0.0) {
120120
return b;

stan/math/rev/core/operator_divide_equal.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ inline var& var::operator/=(var b) {
1212
return *this;
1313
}
1414

15-
template <typename Arith, require_arithmetic_t<Arith>...>
15+
template <typename Arith, require_arithmetic_t<Arith>*>
1616
inline var& var::operator/=(Arith b) {
1717
if (b == 1.0) {
1818
return *this;

stan/math/rev/core/operator_division.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ inline var operator/(var dividend, var divisor) {
115115
* @param divisor Scalar operand.
116116
* @return Variable result of dividing the variable by the scalar.
117117
*/
118-
template <typename Arith, require_arithmetic_t<Arith>...>
118+
template <typename Arith, require_arithmetic_t<Arith>* = nullptr>
119119
inline var operator/(var dividend, Arith divisor) {
120120
if (divisor == 1.0) {
121121
return dividend;
@@ -135,7 +135,7 @@ inline var operator/(var dividend, Arith divisor) {
135135
* @param divisor Variable operand.
136136
* @return Quotient of the dividend and divisor.
137137
*/
138-
template <typename Arith, require_arithmetic_t<Arith>...>
138+
template <typename Arith, require_arithmetic_t<Arith>* = nullptr>
139139
inline var operator/(Arith dividend, var divisor) {
140140
return {new internal::divide_dv_vari(dividend, divisor.vi_)};
141141
}

stan/math/rev/core/operator_equal.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ inline bool operator==(var a, var b) { return a.val() == b.val(); }
3636
* @return True if the first variable's value is the same as the
3737
* second value.
3838
*/
39-
template <typename Arith, require_arithmetic_t<Arith>...>
39+
template <typename Arith, require_arithmetic_t<Arith>* = nullptr>
4040
inline bool operator==(var a, Arith b) {
4141
return a.val() == b;
4242
}
@@ -50,7 +50,7 @@ inline bool operator==(var a, Arith b) {
5050
* @param b Second variable.
5151
* @return True if the variable's value is equal to the scalar.
5252
*/
53-
template <typename Arith, require_arithmetic_t<Arith>...>
53+
template <typename Arith, require_arithmetic_t<Arith>* = nullptr>
5454
inline bool operator==(Arith a, var b) {
5555
return a == b.val();
5656
}

0 commit comments

Comments
 (0)