Kaydet (Commit) 2b31e751 authored tarafından Noel Grandin's avatar Noel Grandin Kaydeden (comit) Luboš Luňák

Create OUString and OString number(*) methods.

API CHANGE: Adds new methods (several overloads)
   OString::number()
   OUString::number()
and marks all of the existing fromValue() methods as deprecated.

The purpose of this change is to clean up call sites
by hiding the necessary casts.

The casts are necessary because of overload resolution rules which are
somewhat vague about which methods to choose when using integer types.

See mailing list discussion here:
  http://nabble.documentfoundation.org/replacing-OUString-valueOf-static-cast-lt-sal-Int32-gt-td4027989.html
  Subject: "replacing OUString::valueOf(static_cast<sal_Int32>) ??"

Change-Id: Id3d150a6525eb0334e41e2ec6640bb06cd790b43
Reviewed-on: https://gerrit.libreoffice.org/1625Reviewed-by: 's avatarLuboš Luňák <l.lunak@suse.cz>
Tested-by: 's avatarLuboš Luňák <l.lunak@suse.cz>
üst 6f6ed9c7
...@@ -38,6 +38,7 @@ $(eval $(call gb_CppunitTest_add_exception_objects,sal_rtl_strings,\ ...@@ -38,6 +38,7 @@ $(eval $(call gb_CppunitTest_add_exception_objects,sal_rtl_strings,\
sal/qa/rtl/strings/test_oustring_noadditional \ sal/qa/rtl/strings/test_oustring_noadditional \
sal/qa/rtl/strings/test_oustring_startswith \ sal/qa/rtl/strings/test_oustring_startswith \
sal/qa/rtl/strings/test_oustring_stringliterals \ sal/qa/rtl/strings/test_oustring_stringliterals \
sal/qa/rtl/strings/test_strings_valuex \
)) ))
$(eval $(call gb_CppunitTest_use_libraries,sal_rtl_strings,\ $(eval $(call gb_CppunitTest_use_libraries,sal_rtl_strings,\
......
...@@ -1399,8 +1399,9 @@ public: ...@@ -1399,8 +1399,9 @@ public:
@param b a sal_Bool. @param b a sal_Bool.
@return a string with the string representation of the argument. @return a string with the string representation of the argument.
@deprecated there is no replacement, just code your own
*/ */
static OString valueOf( sal_Bool b ) SAL_THROW(()) SAL_DEPRECATED_INTERNAL("just code your own") static OString valueOf( sal_Bool b ) SAL_THROW(())
{ {
sal_Char aBuf[RTL_STR_MAX_VALUEOFBOOLEAN]; sal_Char aBuf[RTL_STR_MAX_VALUEOFBOOLEAN];
rtl_String* pNewData = 0; rtl_String* pNewData = 0;
...@@ -1413,8 +1414,9 @@ public: ...@@ -1413,8 +1414,9 @@ public:
@param c a character. @param c a character.
@return a string with the string representation of the argument. @return a string with the string representation of the argument.
@deprecated just use the "+" or "+=" operator
*/ */
static OString valueOf( sal_Char c ) SAL_THROW(()) SAL_DEPRECATED_INTERNAL("use the + or += operator") static OString valueOf( sal_Char c ) SAL_THROW(())
{ {
return OString( &c, 1 ); return OString( &c, 1 );
} }
...@@ -1427,8 +1429,9 @@ public: ...@@ -1427,8 +1429,9 @@ public:
@param i a int32. @param i a int32.
@param radix the radix (between 2 and 36) @param radix the radix (between 2 and 36)
@return a string with the string representation of the argument. @return a string with the string representation of the argument.
@deprecated use number(sal_Int64,sal_Int16)
*/ */
static OString valueOf( sal_Int32 i, sal_Int16 radix = 10 ) SAL_THROW(()) SAL_DEPRECATED_INTERNAL("use number") static OString valueOf( sal_Int32 i, sal_Int16 radix = 10 ) SAL_THROW(())
{ {
sal_Char aBuf[RTL_STR_MAX_VALUEOFINT32]; sal_Char aBuf[RTL_STR_MAX_VALUEOFINT32];
rtl_String* pNewData = 0; rtl_String* pNewData = 0;
...@@ -1436,16 +1439,68 @@ public: ...@@ -1436,16 +1439,68 @@ public:
return OString( pNewData, (DO_NOT_ACQUIRE*)0 ); return OString( pNewData, (DO_NOT_ACQUIRE*)0 );
} }
/**
Returns the string representation of the int argument.
This function can't be used for language specific conversion.
@param i a int32.
@param radix the radix (between 2 and 36)
@return a string with the string representation of the argument.
*/
static OString number( int i, sal_Int16 radix = 10 )
{
sal_Char aBuf[RTL_STR_MAX_VALUEOFINT32];
rtl_String* pNewData = 0;
rtl_string_newFromStr_WithLength( &pNewData, aBuf, rtl_str_valueOfInt32( aBuf, i, radix ) );
return OString( pNewData, (DO_NOT_ACQUIRE*)0 );
}
/**
Returns the string representation of the int argument.
This function can't be used for language specific conversion.
@param i a int32.
@param radix the radix (between 2 and 36)
@return a string with the string representation of the argument.
*/
static OString number( unsigned int i, sal_Int16 radix = 10 )
{
sal_Char aBuf[RTL_STR_MAX_VALUEOFINT64];
rtl_String* pNewData = 0;
rtl_string_newFromStr_WithLength( &pNewData, aBuf, rtl_str_valueOfInt64( aBuf, i, radix ) );
return OString( pNewData, (DO_NOT_ACQUIRE*)0 );
}
/**
Returns the string representation of the long argument.
This function can't be used for language specific conversion.
@param ll a int64.
@param radix the radix (between 2 and 36)
@return a string with the string representation of the argument.
@deprecated use number(sal_Int64,sal_Int16)
*/
SAL_DEPRECATED_INTERNAL("use number") static OString valueOf( sal_Int64 ll, sal_Int16 radix = 10 ) SAL_THROW(())
{
return number( ll, radix );
}
/** /**
Returns the string representation of the long argument. Returns the string representation of the long argument.
This is here because when choosing which conversion for overloaded
functions is better, the standard treats all integer conversions the same.
This function can't be used for language specific conversion. This function can't be used for language specific conversion.
@param ll a int64. @param ll a int64.
@param radix the radix (between 2 and 36) @param radix the radix (between 2 and 36)
@return a string with the string representation of the argument. @return a string with the string representation of the argument.
@since LibreOffice 4.1
*/ */
static OString valueOf( sal_Int64 ll, sal_Int16 radix = 10 ) SAL_THROW(()) static OString number( long ll, sal_Int16 radix = 10 )
{ {
sal_Char aBuf[RTL_STR_MAX_VALUEOFINT64]; sal_Char aBuf[RTL_STR_MAX_VALUEOFINT64];
rtl_String* pNewData = 0; rtl_String* pNewData = 0;
...@@ -1453,6 +1508,61 @@ public: ...@@ -1453,6 +1508,61 @@ public:
return OString( pNewData, (DO_NOT_ACQUIRE*)0 ); return OString( pNewData, (DO_NOT_ACQUIRE*)0 );
} }
/**
Returns the string representation of the long argument.
This is here because when choosing which conversion for overloaded
functions is better, the standard treats all integer conversions the same.
This function can't be used for language specific conversion.
@param ll a int64.
@param radix the radix (between 2 and 36)
@return a string with the string representation of the argument.
@since LibreOffice 4.1
*/
static OString number( unsigned long ll, sal_Int16 radix = 10 )
{
sal_Char aBuf[RTL_STR_MAX_VALUEOFINT64];
rtl_String* pNewData = 0;
rtl_string_newFromStr_WithLength( &pNewData, aBuf, rtl_str_valueOfInt64( aBuf, ll, radix ) );
return OString( pNewData, (DO_NOT_ACQUIRE*)0 );
}
/// @overload
/// @since LibreOffice 4.1
static OString number( long long ll, sal_Int16 radix = 10 )
{
sal_Char aBuf[RTL_STR_MAX_VALUEOFINT64];
rtl_String* pNewData = 0;
rtl_string_newFromStr_WithLength( &pNewData, aBuf, rtl_str_valueOfInt64( aBuf, ll, radix ) );
return OString( pNewData, (DO_NOT_ACQUIRE*)0 );
}
/// @overload
/// @since LibreOffice 4.1
static OString number( unsigned long long ll, sal_Int16 radix = 10 )
{
assert( ll <= SAL_MAX_INT64 ); // valueOfInt64 may not be able to handle the highest bit
sal_Char aBuf[RTL_STR_MAX_VALUEOFINT64];
rtl_String* pNewData = 0;
rtl_string_newFromStr_WithLength( &pNewData, aBuf, rtl_str_valueOfInt64( aBuf, ll, radix ) );
return OString( pNewData, (DO_NOT_ACQUIRE*)0 );
}
/**
Returns the string representation of the float argument.
This function can't be used for language specific conversion.
@param f a float.
@return a string with the string representation of the argument.
@deprecated use number(float)
*/
SAL_DEPRECATED_INTERNAL("use number") static OString valueOf( float f ) SAL_THROW(())
{
return number(f);
}
/** /**
Returns the string representation of the float argument. Returns the string representation of the float argument.
...@@ -1460,8 +1570,9 @@ public: ...@@ -1460,8 +1570,9 @@ public:
@param f a float. @param f a float.
@return a string with the string representation of the argument. @return a string with the string representation of the argument.
@since LibreOffice 4.1
*/ */
static OString valueOf( float f ) SAL_THROW(()) static OString number( float f )
{ {
sal_Char aBuf[RTL_STR_MAX_VALUEOFFLOAT]; sal_Char aBuf[RTL_STR_MAX_VALUEOFFLOAT];
rtl_String* pNewData = 0; rtl_String* pNewData = 0;
...@@ -1476,8 +1587,23 @@ public: ...@@ -1476,8 +1587,23 @@ public:
@param d a double. @param d a double.
@return a string with the string representation of the argument. @return a string with the string representation of the argument.
@deprecated use number(double)
*/
SAL_DEPRECATED_INTERNAL("use number") static OString valueOf( double d ) SAL_THROW(())
{
return number(d);
}
/**
Returns the string representation of the double argument.
This function can't be used for language specific conversion.
@param d a double.
@return a string with the string representation of the argument.
@since LibreOffice 4.1
*/ */
static OString valueOf( double d ) SAL_THROW(()) static OString number( double d )
{ {
sal_Char aBuf[RTL_STR_MAX_VALUEOFDOUBLE]; sal_Char aBuf[RTL_STR_MAX_VALUEOFDOUBLE];
rtl_String* pNewData = 0; rtl_String* pNewData = 0;
......
...@@ -2033,8 +2033,9 @@ public: ...@@ -2033,8 +2033,9 @@ public:
@param b a sal_Bool. @param b a sal_Bool.
@return a string with the string representation of the argument. @return a string with the string representation of the argument.
@deprecated there is no replacement, just code your own
*/ */
static OUString valueOf( sal_Bool b ) SAL_THROW(()) SAL_DEPRECATED_INTERNAL("just code your own") static OUString valueOf( sal_Bool b ) SAL_THROW(())
{ {
sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFBOOLEAN]; sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFBOOLEAN];
rtl_uString* pNewData = 0; rtl_uString* pNewData = 0;
...@@ -2047,8 +2048,9 @@ public: ...@@ -2047,8 +2048,9 @@ public:
@param c a character. @param c a character.
@return a string with the string representation of the argument. @return a string with the string representation of the argument.
@deprecated just use the '+' or '+'; operator
*/ */
static OUString valueOf( sal_Unicode c ) SAL_THROW(()) SAL_DEPRECATED_INTERNAL("just use the '+' or '+'; operator") static OUString valueOf( sal_Unicode c ) SAL_THROW(())
{ {
return OUString( &c, 1 ); return OUString( &c, 1 );
} }
...@@ -2061,8 +2063,9 @@ public: ...@@ -2061,8 +2063,9 @@ public:
@param i a int32. @param i a int32.
@param radix the radix (between 2 and 36) @param radix the radix (between 2 and 36)
@return a string with the string representation of the argument. @return a string with the string representation of the argument.
@deprecated use number(sal_Int64,sal_Int16)
*/ */
static OUString valueOf( sal_Int32 i, sal_Int16 radix = 10 ) SAL_THROW(()) SAL_DEPRECATED_INTERNAL("use number") static OUString valueOf( sal_Int32 i, sal_Int16 radix = 10 ) SAL_THROW(())
{ {
sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFINT32]; sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFINT32];
rtl_uString* pNewData = 0; rtl_uString* pNewData = 0;
...@@ -2070,6 +2073,40 @@ public: ...@@ -2070,6 +2073,40 @@ public:
return OUString( pNewData, (DO_NOT_ACQUIRE*)0 ); return OUString( pNewData, (DO_NOT_ACQUIRE*)0 );
} }
/**
Returns the string representation of the int argument.
This function can't be used for language specific conversion.
@param i a int32.
@param radix the radix (between 2 and 36)
@return a string with the string representation of the argument.
*/
static OUString number( int i, sal_Int16 radix = 10 )
{
sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFINT32];
rtl_uString* pNewData = 0;
rtl_uString_newFromStr_WithLength( &pNewData, aBuf, rtl_ustr_valueOfInt32( aBuf, i, radix ) );
return OUString( pNewData, (DO_NOT_ACQUIRE*)0 );
}
/**
Returns the string representation of the int argument.
This function can't be used for language specific conversion.
@param i a int32.
@param radix the radix (between 2 and 36)
@return a string with the string representation of the argument.
*/
static OUString number( unsigned int i, sal_Int16 radix = 10 )
{
sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFINT64];
rtl_uString* pNewData = 0;
rtl_uString_newFromStr_WithLength( &pNewData, aBuf, rtl_ustr_valueOfInt64( aBuf, i, radix ) );
return OUString( pNewData, (DO_NOT_ACQUIRE*)0 );
}
/** /**
Returns the string representation of the long argument. Returns the string representation of the long argument.
...@@ -2078,8 +2115,26 @@ public: ...@@ -2078,8 +2115,26 @@ public:
@param ll a int64. @param ll a int64.
@param radix the radix (between 2 and 36) @param radix the radix (between 2 and 36)
@return a string with the string representation of the argument. @return a string with the string representation of the argument.
@deprecated use number(sal_Int64,sal_Int16)
*/ */
static OUString valueOf( sal_Int64 ll, sal_Int16 radix = 10 ) SAL_THROW(()) SAL_DEPRECATED_INTERNAL("use number") static OUString valueOf( sal_Int64 ll, sal_Int16 radix = 10 ) SAL_THROW(())
{
return number( ll, radix );
}
/**
Returns the string representation of the long argument.
This is here because when choosing which conversion for overloaded
functions is better, the standard treats all integer conversions the same.
This function can't be used for language specific conversion.
@param ll a int64.
@param radix the radix (between 2 and 36)
@return a string with the string representation of the argument.
@since LibreOffice 4.1
*/
static OUString number( long ll, sal_Int16 radix = 10)
{ {
sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFINT64]; sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFINT64];
rtl_uString* pNewData = 0; rtl_uString* pNewData = 0;
...@@ -2087,6 +2142,61 @@ public: ...@@ -2087,6 +2142,61 @@ public:
return OUString( pNewData, (DO_NOT_ACQUIRE*)0 ); return OUString( pNewData, (DO_NOT_ACQUIRE*)0 );
} }
/**
Returns the string representation of the long argument.
This is here because when choosing which conversion for overloaded
functions is better, the standard treats all integer conversions the same.
This function can't be used for language specific conversion.
@param ll a int64.
@param radix the radix (between 2 and 36)
@return a string with the string representation of the argument.
@since LibreOffice 4.1
*/
static OUString number( unsigned long ll, sal_Int16 radix = 10 )
{
sal_Unicode aBuf[RTL_STR_MAX_VALUEOFINT64];
rtl_uString* pNewData = 0;
rtl_uString_newFromStr_WithLength( &pNewData, aBuf, rtl_ustr_valueOfInt64( aBuf, ll, radix ) );
return OUString( pNewData, (DO_NOT_ACQUIRE*)0 );
}
/// @overload
/// @since LibreOffice 4.1
static OUString number( long long ll, sal_Int16 radix = 10 )
{
sal_Unicode aBuf[RTL_STR_MAX_VALUEOFINT64];
rtl_uString* pNewData = 0;
rtl_uString_newFromStr_WithLength( &pNewData, aBuf, rtl_ustr_valueOfInt64( aBuf, ll, radix ) );
return OUString( pNewData, (DO_NOT_ACQUIRE*)0 );
}
/// @overload
/// @since LibreOffice 4.1
static OUString number( unsigned long long ll, sal_Int16 radix = 10 )
{
assert( ll <= SAL_MAX_INT64 ); // valueOfInt64 may not be able to handle the highest bit
sal_Unicode aBuf[RTL_STR_MAX_VALUEOFINT64];
rtl_uString* pNewData = 0;
rtl_uString_newFromStr_WithLength( &pNewData, aBuf, rtl_ustr_valueOfInt64( aBuf, ll, radix ) );
return OUString( pNewData, (DO_NOT_ACQUIRE*)0 );
}
/**
Returns the string representation of the float argument.
This function can't be used for language specific conversion.
@param f a float.
@return a string with the string representation of the argument.
@deprecated use number(float)
*/
SAL_DEPRECATED_INTERNAL("use number") static OUString valueOf( float f ) SAL_THROW(())
{
return number(f);
}
/** /**
Returns the string representation of the float argument. Returns the string representation of the float argument.
...@@ -2094,8 +2204,9 @@ public: ...@@ -2094,8 +2204,9 @@ public:
@param f a float. @param f a float.
@return a string with the string representation of the argument. @return a string with the string representation of the argument.
@since LibreOffice 4.1
*/ */
static OUString valueOf( float f ) SAL_THROW(()) static OUString number( float f )
{ {
sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFFLOAT]; sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFFLOAT];
rtl_uString* pNewData = 0; rtl_uString* pNewData = 0;
...@@ -2110,8 +2221,23 @@ public: ...@@ -2110,8 +2221,23 @@ public:
@param d a double. @param d a double.
@return a string with the string representation of the argument. @return a string with the string representation of the argument.
@deprecated use number(double)
*/
SAL_DEPRECATED_INTERNAL("use number") static OUString valueOf( double d ) SAL_THROW(())
{
return number(d);
}
/**
Returns the string representation of the double argument.
This function can't be used for language specific conversion.
@param d a double.
@return a string with the string representation of the argument.
@since LibreOffice 4.1
*/ */
static OUString valueOf( double d ) SAL_THROW(()) static OUString number( double d )
{ {
sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFDOUBLE]; sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFDOUBLE];
rtl_uString* pNewData = 0; rtl_uString* pNewData = 0;
......
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <sal/types.h>
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>
#include "rtl/ustring.hxx"
#include <iostream>
namespace test { namespace strings {
class valueX : public CppUnit::TestFixture {
public:
void testOUInt();
void testOInt();
void testOUFloat();
void testOFloat();
void testOUDouble();
void testODouble();
CPPUNIT_TEST_SUITE(valueX);
CPPUNIT_TEST(testOUInt);
CPPUNIT_TEST(testOInt);
CPPUNIT_TEST(testOUFloat);
CPPUNIT_TEST(testOFloat);
CPPUNIT_TEST(testOUDouble);
CPPUNIT_TEST(testODouble);
CPPUNIT_TEST_SUITE_END();
};
} }
CPPUNIT_TEST_SUITE_REGISTRATION(test::strings::valueX);
template< typename T >
void testInt() {
CPPUNIT_ASSERT_EQUAL( T( "30039062" ), T::number( 30039062 ));
// test the overloading resolution
CPPUNIT_ASSERT_EQUAL( T( "30" ), T::number( static_cast< signed char >( 30 )));
CPPUNIT_ASSERT_EQUAL( T( "30" ), T::number( static_cast< unsigned char >( 30 )));
CPPUNIT_ASSERT_EQUAL( T( "30039" ), T::number( static_cast< short >( 30039 )));
CPPUNIT_ASSERT_EQUAL( T( "30039" ), T::number( static_cast< unsigned short >( 30039 )));
CPPUNIT_ASSERT_EQUAL( T( "30039062" ), T::number( static_cast< int >( 30039062 )));
CPPUNIT_ASSERT_EQUAL( T( "30039062" ), T::number( static_cast< unsigned int >( 30039062 )));
CPPUNIT_ASSERT_EQUAL( T( "30039062" ), T::number( static_cast< long >( 30039062 )));
CPPUNIT_ASSERT_EQUAL( T( "30039062" ), T::number( static_cast< unsigned long >( 30039062 )));
CPPUNIT_ASSERT_EQUAL( T( "30039062" ), T::number( static_cast< long long >( 30039062 )));
// The highest bit set in unsigned long long may not actually work.
CPPUNIT_ASSERT_EQUAL( T( "30039062" ), T::number( static_cast< unsigned long long >( 30039062 )));
CPPUNIT_ASSERT_EQUAL( T( "30" ), T::number( static_cast< sal_Int8 >( 30 )));
CPPUNIT_ASSERT_EQUAL( T( "30" ), T::number( static_cast< sal_uInt8 >( 30 )));
CPPUNIT_ASSERT_EQUAL( T( "30039" ), T::number( static_cast< sal_Int16 >( 30039 )));
CPPUNIT_ASSERT_EQUAL( T( "30039" ), T::number( static_cast< sal_uInt16 >( 30039 )));
CPPUNIT_ASSERT_EQUAL( T( "30039062" ), T::number( static_cast< sal_Int32 >( 30039062 )));
CPPUNIT_ASSERT_EQUAL( T( "30039062" ), T::number( static_cast< sal_uInt32 >( 30039062 )));
CPPUNIT_ASSERT_EQUAL( T( "30039062" ), T::number( static_cast< sal_Int64 >( 30039062 )));
CPPUNIT_ASSERT_EQUAL( T( "30039062" ), T::number( static_cast< sal_uInt64 >( 30039062 )));
// The implementation internally uses sal_Int64 etc. types, so check ranges.
assert( sizeof( int ) <= sizeof( sal_Int32 ));
assert( sizeof( long ) <= sizeof( sal_Int64 ));
assert( sizeof( long long ) <= sizeof( sal_Int64 ));
assert( sizeof( unsigned int ) < sizeof( sal_Int64 ));
assert( sizeof( unsigned long ) < sizeof( sal_Int64 ));
}
void test::strings::valueX::testOUInt() {
testInt<rtl::OUString>();
}
void test::strings::valueX::testOInt() {
testInt<rtl::OString>();
}
template< typename T >
void testFloat() {
T val1 = T::valueOf( 30039062.0f );
T val2 = T::number( 30039062.0f );
CPPUNIT_ASSERT_EQUAL( val1, val2 );
CPPUNIT_ASSERT_EQUAL( T( "39062.2" ), T::number( 39062.2f ));
}
void test::strings::valueX::testOUFloat() {
testFloat<rtl::OUString>();
}
void test::strings::valueX::testOFloat() {
testFloat<rtl::OString>();
}
template< typename T >
void testDouble() {
T val1 = T::valueOf( 30039062.0 );
T val2 = T::number( 30039062.0 );
CPPUNIT_ASSERT_EQUAL( val1, val2 );
CPPUNIT_ASSERT_EQUAL( T( "30039062.2" ), T::number( 30039062.2 ));
}
void test::strings::valueX::testOUDouble() {
testDouble<rtl::OUString>();
}
void test::strings::valueX::testODouble() {
testDouble<rtl::OString>();
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment