Commit 5bb0e1da authored by Christopher Dykes's avatar Christopher Dykes Committed by Facebook Github Bot

Modernize use of std::make_unique

Summary: Via the clang-tidy check modernize-make-unique.

Reviewed By: yfeldblum

Differential Revision: D6107790

fbshipit-source-id: 1cf186feae511cbd91f44893059737a85778b6cf
parent a9ade34f
......@@ -24,6 +24,7 @@
#include <iostream>
#include <limits>
#include <map>
#include <memory>
#include <utility>
#include <vector>
......@@ -451,7 +452,7 @@ void runBenchmarks() {
std::unique_ptr<boost::regex> bmRegex;
if (!FLAGS_bm_regex.empty()) {
bmRegex.reset(new boost::regex(FLAGS_bm_regex));
bmRegex = std::make_unique<boost::regex>(FLAGS_bm_regex);
}
// PLEASE KEEP QUIET. MEASUREMENTS IN PROGRESS.
......
......@@ -255,7 +255,7 @@ class NodeRecycler<NodeType, NodeAlloc, typename std::enable_if<
void add(NodeType* node) {
std::lock_guard<MicroSpinLock> g(lock_);
if (nodes_.get() == nullptr) {
nodes_.reset(new std::vector<NodeType*>(1, node));
nodes_ = std::make_unique<std::vector<NodeType*>>(1, node);
} else {
nodes_->push_back(node);
}
......
......@@ -18,6 +18,8 @@
#include <folly/executors/ManualExecutor.h>
#include <folly/portability/GTest.h>
#include <memory>
using namespace folly;
TEST(AsyncFunc, manual_executor) {
......@@ -45,7 +47,7 @@ TEST(AsyncFunc, void_lambda) {
}
TEST(AsyncFunc, moveonly_lambda) {
auto lambda = [] { return std::unique_ptr<int>(new int(42)); };
auto lambda = [] { return std::make_unique<int>(42); };
auto future = async(lambda);
EXPECT_EQ(42, *future.get());
}
......@@ -14,6 +14,7 @@
* limitations under the License.
*/
#include <memory>
#include <thread>
#include <folly/executors/CPUThreadPoolExecutor.h>
......@@ -445,8 +446,7 @@ TEST(ThreadPoolExecutorTest, RequestContext) {
RequestContextScopeGuard rctx; // create new request context for this scope
EXPECT_EQ(nullptr, RequestContext::get()->getContextData("test"));
RequestContext::get()->setContextData(
"test", std::unique_ptr<TestData>(new TestData(42)));
RequestContext::get()->setContextData("test", std::make_unique<TestData>(42));
auto data = RequestContext::get()->getContextData("test");
EXPECT_EQ(42, dynamic_cast<TestData*>(data)->data_);
......
......@@ -17,6 +17,8 @@
#include <folly/futures/Future.h>
#include <folly/portability/GTest.h>
#include <memory>
using namespace folly;
class TestData : public RequestData {
......@@ -34,9 +36,7 @@ TEST(Context, basic) {
EXPECT_EQ(nullptr, RequestContext::get()->getContextData("test"));
// Set some test data
RequestContext::get()->setContextData(
"test",
std::unique_ptr<TestData>(new TestData(10)));
RequestContext::get()->setContextData("test", std::make_unique<TestData>(10));
// Start a future
Promise<Unit> p;
......
......@@ -561,7 +561,7 @@ TEST(Future, thenBindTry) {
}
TEST(Future, value) {
auto f = makeFuture(std::unique_ptr<int>(new int(42)));
auto f = makeFuture(std::make_unique<int>(42));
auto up = std::move(f.value());
EXPECT_EQ(42, *up);
......
......@@ -17,6 +17,8 @@
#include <folly/futures/Future.h>
#include <folly/portability/GTest.h>
#include <memory>
using namespace folly;
using std::unique_ptr;
using std::string;
......@@ -75,7 +77,7 @@ TEST(Promise, setValue) {
Promise<unique_ptr<int>> mov;
auto fmov = mov.getFuture();
mov.setValue(unique_ptr<int>(new int(42)));
mov.setValue(std::make_unique<int>(42));
unique_ptr<int> ptr = std::move(fmov.value());
EXPECT_EQ(42, *ptr);
......
......@@ -72,7 +72,7 @@ TEST(SemiFuture, special) {
}
TEST(SemiFuture, value) {
auto f = makeSemiFuture(std::unique_ptr<int>(new int(42)));
auto f = makeSemiFuture(std::make_unique<int>(42));
auto up = std::move(f.value());
EXPECT_EQ(42, *up);
......@@ -159,8 +159,8 @@ TEST(SemiFuture, MakeSemiFutureFromFutureWithUnit) {
}
TEST(SemiFuture, MakeSemiFutureFromFutureWithValue) {
auto f = SemiFuture<std::unique_ptr<int>>{
makeFuture(std::unique_ptr<int>(new int(42)))};
auto f =
SemiFuture<std::unique_ptr<int>>{makeFuture(std::make_unique<int>(42))};
auto up = std::move(f.value());
EXPECT_EQ(42, *up);
}
......
......@@ -17,6 +17,7 @@
#include <glog/logging.h>
#include <iosfwd>
#include <memory>
#include <random>
#include <set>
#include <vector>
......@@ -604,13 +605,13 @@ TEST(Gen, DistinctBy) { // 0 1 4 9 6 5 6 9 4 1 0
TEST(Gen, DistinctMove) { // 0 1 4 9 6 5 6 9 4 1 0
auto expected = vector<int>{0, 1, 2, 3, 4, 5};
auto actual =
seq(0, 100)
| mapped([](int i) { return std::unique_ptr<int>(new int(i)); })
auto actual = seq(0, 100) |
mapped([](int i) { return std::make_unique<int>(i); })
// see comment below about selector parameters for Distinct
| distinctBy([](const std::unique_ptr<int>& pi) { return *pi * *pi % 10; })
| mapped([](std::unique_ptr<int> pi) { return *pi; })
| as<vector>();
| distinctBy([](const std::unique_ptr<int>& pi) {
return *pi * *pi % 10;
}) |
mapped([](std::unique_ptr<int> pi) { return *pi; }) | as<vector>();
// NOTE(tjackson): the following line intentionally doesn't work:
// | distinctBy([](std::unique_ptr<int> pi) { return *pi * *pi % 10; })
......@@ -917,11 +918,10 @@ TEST(Gen, CustomType) {
}
TEST(Gen, NoNeedlessCopies) {
auto gen = seq(1, 5)
| map([](int x) { return unique_ptr<int>(new int(x)); })
| map([](unique_ptr<int> p) { return p; })
| map([](unique_ptr<int>&& p) { return std::move(p); })
| map([](const unique_ptr<int>& p) { return *p; });
auto gen = seq(1, 5) | map([](int x) { return std::make_unique<int>(x); }) |
map([](unique_ptr<int> p) { return p; }) |
map([](unique_ptr<int>&& p) { return std::move(p); }) |
map([](const unique_ptr<int>& p) { return *p; });
EXPECT_EQ(15, gen | sum);
EXPECT_EQ(6, gen | take(3) | sum);
}
......@@ -1236,18 +1236,16 @@ TEST(Gen, Batch) {
TEST(Gen, BatchMove) {
auto expected = vector<vector<int>>{ {0, 1}, {2, 3}, {4} };
auto actual =
seq(0, 4)
| mapped([](int i) { return std::unique_ptr<int>(new int(i)); })
| batch(2)
| mapped([](std::vector<std::unique_ptr<int>>& pVector) {
std::vector<int> iVector;
for (const auto& p : pVector) {
iVector.push_back(*p);
};
return iVector;
})
| as<vector>();
auto actual = seq(0, 4) |
mapped([](int i) { return std::make_unique<int>(i); }) | batch(2) |
mapped([](std::vector<std::unique_ptr<int>>& pVector) {
std::vector<int> iVector;
for (const auto& p : pVector) {
iVector.push_back(*p);
};
return iVector;
}) |
as<vector>();
EXPECT_EQ(expected, actual);
}
......@@ -1256,22 +1254,22 @@ TEST(Gen, Window) {
for (size_t windowSize = 1; windowSize <= 20; ++windowSize) {
// no early stop
auto actual = seq(0, 10) |
mapped([](int i) { return std::unique_ptr<int>(new int(i)); }) |
window(4) | dereference | as<std::vector>();
mapped([](int i) { return std::make_unique<int>(i); }) | window(4) |
dereference | as<std::vector>();
EXPECT_EQ(expected, actual) << windowSize;
}
for (size_t windowSize = 1; windowSize <= 20; ++windowSize) {
// pre-window take
auto actual = seq(0) |
mapped([](int i) { return std::unique_ptr<int>(new int(i)); }) |
take(11) | window(4) | dereference | as<std::vector>();
mapped([](int i) { return std::make_unique<int>(i); }) | take(11) |
window(4) | dereference | as<std::vector>();
EXPECT_EQ(expected, actual) << windowSize;
}
for (size_t windowSize = 1; windowSize <= 20; ++windowSize) {
// post-window take
auto actual = seq(0) |
mapped([](int i) { return std::unique_ptr<int>(new int(i)); }) |
window(4) | take(11) | dereference | as<std::vector>();
mapped([](int i) { return std::make_unique<int>(i); }) | window(4) |
take(11) | dereference | as<std::vector>();
EXPECT_EQ(expected, actual) << windowSize;
}
}
......
......@@ -16,6 +16,7 @@
#include <array>
#include <iostream>
#include <memory>
#include <vector>
#include <glog/logging.h>
......@@ -52,7 +53,7 @@ static auto isPrime = [](int n) {
struct {
template <class T>
std::unique_ptr<T> operator()(T t) const {
return std::unique_ptr<T>(new T(std::move(t)));
return std::make_unique<T>(std::move(t));
}
} makeUnique;
......
......@@ -24,6 +24,7 @@
#include <fcntl.h>
#include <sys/types.h>
#include <chrono>
#include <memory>
#include <folly/Bits.h>
#include <folly/Format.h>
......@@ -1716,7 +1717,7 @@ int AsyncSSLSocket::sslVerifyCallback(
void AsyncSSLSocket::enableClientHelloParsing() {
parseClientHello_ = true;
clientHelloInfo_.reset(new ssl::ClientHelloInfo());
clientHelloInfo_ = std::make_unique<ssl::ClientHelloInfo>();
}
void AsyncSSLSocket::resetClientHelloParsing(SSL *ssl) {
......
......@@ -22,6 +22,7 @@
#include <fcntl.h>
#include <memory>
#include <mutex>
#include <thread>
......@@ -626,12 +627,12 @@ bool EventBase::runLoopCallbacks() {
void EventBase::initNotificationQueue() {
// Infinite size queue
queue_.reset(new NotificationQueue<Func>());
queue_ = std::make_unique<NotificationQueue<Func>>();
// We allocate fnRunner_ separately, rather than declaring it directly
// as a member of EventBase solely so that we don't need to include
// NotificationQueue.h from EventBase.h
fnRunner_.reset(new FunctionRunner());
fnRunner_ = std::make_unique<FunctionRunner>();
// Mark this as an internal event, so event_base_loop() will return if
// there are no other events besides this one installed.
......
......@@ -38,6 +38,7 @@
#include <condition_variable>
#include <iostream>
#include <list>
#include <memory>
namespace folly {
......@@ -824,13 +825,13 @@ class BlockingWriteClient :
bufLen_(2500),
iovCount_(2000) {
// Fill buf_
buf_.reset(new uint8_t[bufLen_]);
buf_ = std::make_unique<uint8_t[]>(bufLen_);
for (uint32_t n = 0; n < sizeof(buf_); ++n) {
buf_[n] = n % 0xff;
}
// Initialize iov_
iov_.reset(new struct iovec[iovCount_]);
iov_ = std::make_unique<struct iovec[]>(iovCount_);
for (uint32_t n = 0; n < iovCount_; ++n) {
iov_[n].iov_base = buf_.get() + n;
if (n & 0x1) {
......@@ -885,7 +886,7 @@ class BlockingWriteServer :
: socket_(std::move(socket)),
bufSize_(2500 * 2000),
bytesRead_(0) {
buf_.reset(new uint8_t[bufSize_]);
buf_ = std::make_unique<uint8_t[]>(bufSize_);
socket_->sslAccept(this, std::chrono::milliseconds(100));
}
......
......@@ -1610,7 +1610,7 @@ TEST(EventBaseTest, IdleTime) {
ASSERT_EQ(6, tos0.getTimeouts());
ASSERT_GE(6100, eventBase.getAvgLoopTime() - 1200);
ASSERT_LE(6100, eventBase.getAvgLoopTime() + 1200);
tos.reset(new IdleTimeTimeoutSeries(&eventBase, timeouts));
tos = std::make_unique<IdleTimeTimeoutSeries>(&eventBase, timeouts);
});
// Kick things off with an "immedite" timeout
......
......@@ -19,6 +19,8 @@
#include <folly/portability/Sockets.h>
#include <folly/ssl/SSLSession.h>
#include <memory>
using namespace std;
using namespace testing;
using folly::ssl::SSLSession;
......@@ -97,7 +99,7 @@ TEST_F(SSLSessionTest, BasicTest) {
eventBase.loop();
ASSERT_TRUE(client.handshakeSuccess_);
sess.reset(new SSLSession(clientPtr->getSSLSession()));
sess = std::make_unique<SSLSession>(clientPtr->getSSLSession());
ASSERT_NE(sess.get(), nullptr);
}
......
......@@ -16,6 +16,7 @@
#include <folly/ssl/detail/OpenSSLThreading.h>
#include <memory>
#include <mutex>
#include <folly/Portability.h>
......@@ -152,7 +153,7 @@ static void dyn_destroy(struct CRYPTO_dynlock_value* lock, const char*, int) {
void installThreadingLocks() {
// static locking
locks().reset(new SSLLock[size_t(CRYPTO_num_locks())]);
locks() = std::make_unique<SSLLock[]>(size_t(CRYPTO_num_locks()));
for (auto it : lockTypes()) {
locks()[size_t(it.first)].lockType = it.second;
}
......
......@@ -16,6 +16,7 @@
#include <cstddef>
#include <map>
#include <memory>
#include <stdexcept>
#include <folly/AtomicHashArray.h>
......@@ -154,7 +155,7 @@ void testNoncopyableMap() {
auto arr = MyArr::create(250);
for (int i = 0; i < 100; i++) {
arr->insert(make_pair(i,std::unique_ptr<ValueT>(new ValueT(i))));
arr->insert(make_pair(i, std::make_unique<ValueT>(i)));
}
for (int i = 100; i < 150; i++) {
arr->emplace(i,new ValueT(i));
......
......@@ -76,10 +76,10 @@ TEST(Ahm, BasicNoncopyable) {
EXPECT_TRUE(myMap.begin() == myMap.end());
for (int i = 0; i < 50; ++i) {
myMap.insert(make_pair(i, std::unique_ptr<int>(new int(i))));
myMap.insert(make_pair(i, std::make_unique<int>(i)));
}
for (int i = 50; i < 100; ++i) {
myMap.insert(i, std::unique_ptr<int>(new int (i)));
myMap.insert(i, std::make_unique<int>(i));
}
for (int i = 100; i < 150; ++i) {
myMap.emplace(i, new int (i));
......@@ -482,7 +482,7 @@ TEST(Ahm, collision_test) {
" Byte entries replicated in " << FLAGS_numThreads <<
" threads with " << FLAGS_maxLoadFactor * 100.0 << "% max load factor.";
globalAHM.reset(new AHMapT(int(numInserts * sizeFactor), config));
globalAHM = std::make_unique<AHMapT>(int(numInserts * sizeFactor), config);
size_t sizeInit = globalAHM->capacity();
VLOG(1) << " Initial capacity: " << sizeInit;
......@@ -571,7 +571,7 @@ TEST(Ahm, race_insert_iterate_thread_test) {
VLOG(1) << "Testing iteration and insertion with " << kInsertThreads
<< " threads inserting and " << kIterateThreads << " threads iterating.";
globalAHM.reset(new AHMapT(raceFinalSizeEstimate / 9, config));
globalAHM = std::make_unique<AHMapT>(raceFinalSizeEstimate / 9, config);
vector<pthread_t> threadIds;
for (int j = 0; j < kInsertThreads + kIterateThreads; j++) {
......@@ -649,7 +649,7 @@ TEST(Ahm, thread_erase_insert_race) {
VLOG(1) << "Testing insertion and erase with " << kInsertThreads
<< " thread inserting and " << kEraseThreads << " threads erasing.";
globalAHM.reset(new AHMapT(kTestEraseInsertions / 4, config));
globalAHM = std::make_unique<AHMapT>(kTestEraseInsertions / 4, config);
vector<pthread_t> threadIds;
for (int64_t j = 0; j < kInsertThreads + kEraseThreads; j++) {
......@@ -820,7 +820,7 @@ void loadGlobalAhm() {
std::cout << "loading global AHM with " << FLAGS_numThreads
<< " threads...\n";
uint64_t start = nowInUsec();
globalAHM.reset(new AHMapT(maxBMElements, config));
globalAHM = std::make_unique<AHMapT>(maxBMElements, config);
numOpsPerThread = FLAGS_numBMElements / FLAGS_numThreads;
runThreads(insertThread);
uint64_t elapsed = nowInUsec() - start;
......@@ -833,7 +833,7 @@ void loadGlobalQPAhm() {
std::cout << "loading global QPAHM with " << FLAGS_numThreads
<< " threads...\n";
uint64_t start = nowInUsec();
globalQPAHM.reset(new QPAHMapT(maxBMElements, qpConfig));
globalQPAHM = std::make_unique<QPAHMapT>(maxBMElements, qpConfig);
numOpsPerThread = FLAGS_numBMElements / FLAGS_numThreads;
runThreads(qpInsertThread);
uint64_t elapsed = nowInUsec() - start;
......@@ -1020,7 +1020,7 @@ BENCHMARK(st_baseline_modulus_and_random, iters) {
BENCHMARK(mt_ahm_insert, iters) {
BENCHMARK_SUSPEND {
globalAHM.reset(new AHMapT(int(iters * LF), config));
globalAHM = std::make_unique<AHMapT>(int(iters * LF), config);
numOpsPerThread = iters / FLAGS_numThreads;
}
runThreads(insertThread);
......@@ -1028,7 +1028,7 @@ BENCHMARK(mt_ahm_insert, iters) {
BENCHMARK(mt_qpahm_insert, iters) {
BENCHMARK_SUSPEND {
globalQPAHM.reset(new QPAHMapT(int(iters * LF), qpConfig));
globalQPAHM = std::make_unique<QPAHMapT>(int(iters * LF), qpConfig);
numOpsPerThread = iters / FLAGS_numThreads;
}
runThreads(qpInsertThread);
......
......@@ -16,6 +16,7 @@
#include <folly/AtomicUnorderedMap.h>
#include <memory>
#include <thread>
#include <unordered_map>
......@@ -207,7 +208,7 @@ BENCHMARK(lookup_int_int_hit, iters) {
size_t capacity = 100000;
BENCHMARK_SUSPEND {
ptr.reset(new AtomicUnorderedInsertMap<int,size_t>(capacity));
ptr = std::make_unique<AtomicUnorderedInsertMap<int, size_t>>(capacity);
for (size_t i = 0; i < capacity; ++i) {
auto k = 3 * ((5641 * i) % capacity);
ptr->emplace(k, k + 1);
......@@ -249,7 +250,7 @@ void contendedRW(size_t itersPerThread,
std::vector<std::thread> threads;
BENCHMARK_SUSPEND {
ptr.reset(new Map(capacity));
ptr = std::make_unique<Map>(capacity);
while (threads.size() < numThreads) {
threads.emplace_back([&](){
while (!go) {
......
......@@ -286,7 +286,7 @@ TEST(ConcurrentSkipList, TestMovableData) {
static const int N = 10;
for (int i = 0; i < N; ++i) {
accessor.insert(std::unique_ptr<int>(new int(i)));
accessor.insert(std::make_unique<int>(i));
}
for (int i = 0; i < N; ++i) {
......
......@@ -230,10 +230,10 @@ TEST(Expected, Unique) {
ex = makeUnexpected(-1);
// empty->moved
ex = unique_ptr<int>(new int(6));
ex = std::make_unique<int>(6);
EXPECT_EQ(6, **ex);
// full->moved
ex = unique_ptr<int>(new int(7));
ex = std::make_unique<int>(7);
EXPECT_EQ(7, **ex);
// move it out by move construct
......
......@@ -191,7 +191,7 @@ TEST(fbvector, unique_ptr) {
v[0] = std::move(p);
EXPECT_FALSE(v[0].get());
v[0].reset(new int(32));
v[0] = std::make_unique<int>(32);
std::unique_ptr<int> somePtr;
v.insert(v.begin(), std::move(somePtr));
EXPECT_EQ(*v[1], 32);
......
......@@ -28,7 +28,7 @@ TEST(makeMoveWrapper, Empty) {
}
TEST(makeMoveWrapper, NonEmpty) {
auto u = std::unique_ptr<int>(new int(5));
auto u = std::make_unique<int>(5);
EXPECT_EQ(*u, 5);
auto p = makeMoveWrapper(std::move(u));
EXPECT_TRUE(!u);
......
......@@ -223,10 +223,10 @@ TEST(Optional, Unique) {
opt.clear();
// empty->moved
opt = unique_ptr<int>(new int(6));
opt = std::make_unique<int>(6);
EXPECT_EQ(6, **opt);
// full->moved
opt = unique_ptr<int>(new int(7));
opt = std::make_unique<int>(7);
EXPECT_EQ(7, **opt);
// move it out by move construct
......
......@@ -18,6 +18,7 @@
#include <atomic>
#include <condition_variable>
#include <memory>
#include <thread>
#include <glog/logging.h>
......@@ -86,7 +87,8 @@ TEST_F(ThreadCachedIntTest, MultithreadedSlow) {
// iteration, threads[1] performs 2 iterations, threads[2] performs
// 3 iterations, and so on.
for (uint32_t i = 0; i < kNumThreads; ++i) {
threads[i].reset(new std::thread(Runner, &g_counter_for_mt_slow, i + 1));
threads[i] =
std::make_unique<std::thread>(Runner, &g_counter_for_mt_slow, i + 1);
}
// Variable to grab current counter value.
int32_t counter_value;
......@@ -141,7 +143,8 @@ TEST_F(ThreadCachedIntTest, MultithreadedFast) {
// iteration, threads[1] performs 2 iterations, threads[2] performs
// 3 iterations, and so on.
for (uint32_t i = 0; i < kNumThreads; ++i) {
threads[i].reset(new std::thread(Runner, &g_counter_for_mt_fast, i + 1));
threads[i] =
std::make_unique<std::thread>(Runner, &g_counter_for_mt_fast, i + 1);
}
// Let the threads run to completion.
{
......
......@@ -29,6 +29,7 @@
#include <climits>
#include <condition_variable>
#include <map>
#include <memory>
#include <mutex>
#include <set>
#include <thread>
......@@ -269,7 +270,7 @@ TEST(ThreadLocal, InterleavedDestructors) {
{
std::lock_guard<std::mutex> g(lock);
thIterPrev = thIter;
w.reset(new ThreadLocal<Widget>());
w = std::make_unique<ThreadLocal<Widget>>();
++wVersion;
}
while (true) {
......
......@@ -176,7 +176,7 @@ struct TestBasicGuarantee {
std::unique_ptr<folly::small_vector<Thrower,3> > workingVec;
for (int counter = 1; !done; ++counter) {
throwCounter = 1000;
workingVec.reset(new folly::small_vector<Thrower,3>(vec));
workingVec = std::make_unique<folly::small_vector<Thrower, 3>>(vec);
throwCounter = counter;
EXPECT_EQ(Thrower::alive, prepopulate * 2);
try {
......
......@@ -330,8 +330,8 @@ TEST(SortedVectorTest, EmptyTest) {
TEST(SortedVectorTest, MoveTest) {
sorted_vector_set<std::unique_ptr<int>> s;
s.insert(std::unique_ptr<int>(new int(5)));
s.insert(s.end(), std::unique_ptr<int>(new int(10)));
s.insert(std::make_unique<int>(5));
s.insert(s.end(), std::make_unique<int>(10));
EXPECT_EQ(s.size(), 2);
for (const auto& p : s) {
......@@ -339,8 +339,8 @@ TEST(SortedVectorTest, MoveTest) {
}
sorted_vector_map<int, std::unique_ptr<int>> m;
m.insert(std::make_pair(5, std::unique_ptr<int>(new int(5))));
m.insert(m.end(), std::make_pair(10, std::unique_ptr<int>(new int(10))));
m.insert(std::make_pair(5, std::make_unique<int>(5)));
m.insert(m.end(), std::make_pair(10, std::make_unique<int>(10)));
EXPECT_EQ(*m[5], 5);
EXPECT_EQ(*m[10], 10);
......
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