Commit 8c16125d authored by Scott Cyphers's avatar Scott Cyphers

Merge branch 'master' into cyphers/view

parents 0064cfd0 8d57ce68
...@@ -44,3 +44,10 @@ SpacesInSquareBrackets: false ...@@ -44,3 +44,10 @@ SpacesInSquareBrackets: false
SortIncludes: false SortIncludes: false
ReflowComments: true ReflowComments: true
IncludeCategories:
- Regex: '^".*'
Priority: 3
- Regex: '^<.*'
Priority: 2
SortIncludes: true
...@@ -27,7 +27,10 @@ const ngraph::ElementType element_type_uint64_t = ngraph::ElementType(64, false, ...@@ -27,7 +27,10 @@ const ngraph::ElementType element_type_uint64_t = ngraph::ElementType(64, false,
std::map<std::string, ngraph::ElementType> ngraph::ElementType::m_element_list; std::map<std::string, ngraph::ElementType> ngraph::ElementType::m_element_list;
ngraph::ElementType::ElementType(size_t bitwidth, bool is_float, bool is_signed, const std::string& cname) ngraph::ElementType::ElementType(size_t bitwidth,
bool is_float,
bool is_signed,
const std::string& cname)
: m_bitwidth{bitwidth} : m_bitwidth{bitwidth}
, m_is_float{is_float} , m_is_float{is_float}
, m_is_signed{is_signed} , m_is_signed{is_signed}
......
...@@ -18,8 +18,8 @@ ...@@ -18,8 +18,8 @@
#pragma once #pragma once
#include <string>
#include <map> #include <map>
#include <string>
namespace ngraph namespace ngraph
{ {
......
...@@ -14,12 +14,12 @@ ...@@ -14,12 +14,12 @@
*/ */
#include <chrono> #include <chrono>
#include <condition_variable>
#include <ctime>
#include <iomanip> #include <iomanip>
#include <iostream> #include <iostream>
#include <ctime>
#include <thread>
#include <mutex> #include <mutex>
#include <condition_variable> #include <thread>
#include "log.hpp" #include "log.hpp"
......
...@@ -15,9 +15,9 @@ ...@@ -15,9 +15,9 @@
#pragma once #pragma once
#include <deque>
#include <sstream> #include <sstream>
#include <stdexcept> #include <stdexcept>
#include <deque>
namespace nervana namespace nervana
{ {
......
...@@ -14,40 +14,39 @@ ...@@ -14,40 +14,39 @@
#pragma once #pragma once
#include <string>
#include <map> #include <map>
#include <string>
namespace ngraph namespace ngraph
{ {
//================================================================================================
//================================================================================================ // NameableValue
// NameableValue // An Axis labels a dimension of a tensor. The op-graph uses
// An Axis labels a dimension of a tensor. The op-graph uses // the identity of Axis objects to pair and specify dimensions in
// the identity of Axis objects to pair and specify dimensions in // symbolic expressions. This system has several advantages over
// symbolic expressions. This system has several advantages over // using the length and position of the axis as in other frameworks:
// using the length and position of the axis as in other frameworks: //
// // 1) Convenience. The dimensions of tensors, which may be nested
// 1) Convenience. The dimensions of tensors, which may be nested // deep in a computation graph, can be specified without having to
// deep in a computation graph, can be specified without having to // calculate their lengths.
// calculate their lengths. //
// // 2) Safety. Axis labels are analogous to types in general-purpose
// 2) Safety. Axis labels are analogous to types in general-purpose // programming languages, allowing objects to interact only when
// programming languages, allowing objects to interact only when // they are permitted to do so in advance. In symbolic computation,
// they are permitted to do so in advance. In symbolic computation, // this prevents interference between axes that happen to have the
// this prevents interference between axes that happen to have the // same lengths but are logically distinct, e.g. if the number of
// same lengths but are logically distinct, e.g. if the number of // training examples and the number of input features are both 50.
// training examples and the number of input features are both 50. //
// // TODO: Please add to the list...
// TODO: Please add to the list... //
// // Arguments:
// Arguments: // length: The length of the axis.
// length: The length of the axis. // batch: Whether the axis is a batch axis.
// batch: Whether the axis is a batch axis. // recurrent: Whether the axis is a recurrent axis.
// recurrent: Whether the axis is a recurrent axis. //================================================================================================
//================================================================================================ class NameableValue
class NameableValue {
{ public:
public:
//!----------------------------------------------------------------------------------- //!-----------------------------------------------------------------------------------
//! NameableValue //! NameableValue
//! An object that can be named. //! An object that can be named.
...@@ -103,7 +102,6 @@ public: ...@@ -103,7 +102,6 @@ public:
std::string m_graph_label; std::string m_graph_label;
std::string m_short_name; std::string m_short_name;
std::string m_doc_string; std::string m_doc_string;
}; };
} // end namespace ngraph } // end namespace ngraph
#include <iostream>
#include <algorithm> #include <algorithm>
#include <iostream>
#include "strides.hpp" #include "strides.hpp"
#include "util.hpp" #include "util.hpp"
......
#pragma once #pragma once
#include <cstdio> #include <cstdio>
#include <vector>
#include <initializer_list> #include <initializer_list>
#include <vector>
#include "element_type.hpp" #include "element_type.hpp"
#include "tree.hpp" #include "tree.hpp"
...@@ -27,7 +27,6 @@ public: ...@@ -27,7 +27,6 @@ public:
ElementType et = element_type_float); ElementType et = element_type_float);
const ElementType& get_type() const { return m_element_type; } const ElementType& get_type() const { return m_element_type; }
tensor_stride full_strides() const; tensor_stride full_strides() const;
tensor_stride strides() const; tensor_stride strides() const;
tensor_size sizes() const; tensor_size sizes() const;
...@@ -53,7 +52,6 @@ class ngraph::tensor_stride ...@@ -53,7 +52,6 @@ class ngraph::tensor_stride
public: public:
tensor_stride(); tensor_stride();
const ElementType& get_type() const { return m_element_type; } const ElementType& get_type() const { return m_element_type; }
tensor_stride full_strides() const; tensor_stride full_strides() const;
tensor_stride strides() const; tensor_stride strides() const;
......
...@@ -12,10 +12,10 @@ ...@@ -12,10 +12,10 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#include <cassert>
#include <cmath>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <cmath>
#include <cassert>
#include "axes.hpp" #include "axes.hpp"
#include "util.hpp" #include "util.hpp"
......
This diff is collapsed.
...@@ -12,10 +12,10 @@ ...@@ -12,10 +12,10 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#include <cmath>
#include <exception>
#include <memory> #include <memory>
#include <sstream> #include <sstream>
#include <exception>
#include <cmath>
#include "exop.hpp" #include "exop.hpp"
#include "op_graph.hpp" #include "op_graph.hpp"
......
This diff is collapsed.
This diff is collapsed.
...@@ -14,24 +14,21 @@ ...@@ -14,24 +14,21 @@
#pragma once #pragma once
#include "mock.hpp"
#include "exop.hpp" #include "exop.hpp"
#include "mock.hpp"
namespace ngraph namespace ngraph
{ {
//================================================================================================
//================================================================================================ // CpuTransformer
// CpuTransformer //================================================================================================
//================================================================================================ class CpuTransformer : public Transformer
class CpuTransformer : public Transformer {
{ public:
public:
virtual ~CpuTransformer() {} virtual ~CpuTransformer() {}
ExecutionState& execution_state() override { return m_execution_state; } ExecutionState& execution_state() override { return m_execution_state; }
private:
private:
ExecutionState m_execution_state; ExecutionState m_execution_state;
}; };
} // end namespace ngraph } // end namespace ngraph
...@@ -14,8 +14,8 @@ ...@@ -14,8 +14,8 @@
#pragma once #pragma once
#include <vector>
#include <memory> #include <memory>
#include <vector>
#include "element_type.hpp" #include "element_type.hpp"
#include "strides.hpp" #include "strides.hpp"
......
...@@ -14,8 +14,8 @@ ...@@ -14,8 +14,8 @@
#include <sstream> #include <sstream>
#include "op_graph.hpp"
#include "axes.hpp" #include "axes.hpp"
#include "op_graph.hpp"
#include "util.hpp" #include "util.hpp"
using namespace ngraph; using namespace ngraph;
...@@ -2794,7 +2794,9 @@ ElementWiseOp::ElementWiseOp() ...@@ -2794,7 +2794,9 @@ ElementWiseOp::ElementWiseOp()
{ {
} }
void ElementWiseOp::ElementWiseOp_init(std::vector<op_ptr>, Axes) {} void ElementWiseOp::ElementWiseOp_init(std::vector<op_ptr>, Axes)
{
}
//================================================================================================ //================================================================================================
// UnaryElementWiseOp // UnaryElementWiseOp
......
This diff is collapsed.
#pragma once #pragma once
#include <algorithm>
#include <functional> #include <functional>
#include <vector>
#include <initializer_list> #include <initializer_list>
#include <iostream> #include <iostream>
#include <algorithm> #include <vector>
#include "util.hpp" #include "util.hpp"
...@@ -51,7 +51,6 @@ public: ...@@ -51,7 +51,6 @@ public:
bool is_list() const { return m_is_list; } bool is_list() const { return m_is_list; }
T get_value() const { return m_value; } T get_value() const { return m_value; }
const std::vector<tree>& get_list() const { return m_list; } const std::vector<tree>& get_list() const { return m_list; }
static void traverse_tree(tree& s, std::function<void(T*)> func) static void traverse_tree(tree& s, std::function<void(T*)> func)
{ {
if (s.is_list()) if (s.is_list())
......
...@@ -12,8 +12,8 @@ ...@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#include <map>
#include <iomanip> #include <iomanip>
#include <map>
#include "util.hpp" #include "util.hpp"
......
...@@ -14,23 +14,22 @@ ...@@ -14,23 +14,22 @@
#pragma once #pragma once
#include <string>
#include <sstream>
#include <vector>
#include <chrono>
#include <algorithm> #include <algorithm>
#include <map> #include <chrono>
#include <iostream> #include <iostream>
#include <map>
#include <sstream>
#include <string>
#include <vector>
namespace ngraph namespace ngraph
{ {
class stopwatch;
extern std::map<std::string, stopwatch*> stopwatch_statistics;
class stopwatch; template <typename T>
extern std::map<std::string, stopwatch*> stopwatch_statistics; std::string join(const T& v, const std::string& sep)
{
template <typename T>
std::string join(const T& v, const std::string& sep)
{
std::ostringstream ss; std::ostringstream ss;
for (const auto& x : v) for (const auto& x : v)
{ {
...@@ -41,11 +40,11 @@ std::string join(const T& v, const std::string& sep) ...@@ -41,11 +40,11 @@ std::string join(const T& v, const std::string& sep)
ss << x; ss << x;
} }
return ss.str(); return ss.str();
} }
template <typename U, typename T> template <typename U, typename T>
bool contains(const U& container, const T& obj) bool contains(const U& container, const T& obj)
{ {
bool rc = false; bool rc = false;
for (auto o : container) for (auto o : container)
{ {
...@@ -56,11 +55,11 @@ bool contains(const U& container, const T& obj) ...@@ -56,11 +55,11 @@ bool contains(const U& container, const T& obj)
} }
} }
return rc; return rc;
} }
template <typename U, typename T> template <typename U, typename T>
bool contains_key(const U& container, const T& obj) bool contains_key(const U& container, const T& obj)
{ {
bool rc = false; bool rc = false;
for (auto o : container) for (auto o : container)
{ {
...@@ -71,28 +70,28 @@ bool contains_key(const U& container, const T& obj) ...@@ -71,28 +70,28 @@ bool contains_key(const U& container, const T& obj)
} }
} }
return rc; return rc;
} }
template <typename U, typename T> template <typename U, typename T>
void remove_from(U& container, const T& obj) void remove_from(U& container, const T& obj)
{ {
auto it = container.find(obj); auto it = container.find(obj);
if (it != container.end()) if (it != container.end())
{ {
container.erase(it); container.erase(it);
} }
} }
size_t hash_combine(const std::vector<size_t>& list); size_t hash_combine(const std::vector<size_t>& list);
void dump(std::ostream& out, const void*, size_t); void dump(std::ostream& out, const void*, size_t);
std::string to_lower(const std::string& s); std::string to_lower(const std::string& s);
std::string trim(const std::string& s); std::string trim(const std::string& s);
std::vector<std::string> split(const std::string& s, char delimiter, bool trim = false); std::vector<std::string> split(const std::string& s, char delimiter, bool trim = false);
class stopwatch class stopwatch
{ {
public: public:
stopwatch() {} stopwatch() {}
stopwatch(const std::string& name) stopwatch(const std::string& name)
: m_name{name} : m_name{name}
...@@ -149,21 +148,21 @@ public: ...@@ -149,21 +148,21 @@ public:
size_t get_total_milliseconds() const { return get_total_nanoseconds() / 1e6; } size_t get_total_milliseconds() const { return get_total_nanoseconds() / 1e6; }
size_t get_total_microseconds() const { return get_total_nanoseconds() / 1e3; } size_t get_total_microseconds() const { return get_total_nanoseconds() / 1e3; }
size_t get_total_nanoseconds() const { return m_total_time.count(); } size_t get_total_nanoseconds() const { return m_total_time.count(); }
private:
private:
std::chrono::high_resolution_clock m_clock; std::chrono::high_resolution_clock m_clock;
std::chrono::time_point<std::chrono::high_resolution_clock> m_start_time; std::chrono::time_point<std::chrono::high_resolution_clock> m_start_time;
bool m_active = false; bool m_active = false;
std::chrono::nanoseconds m_total_time = std::chrono::high_resolution_clock::duration::zero(); std::chrono::nanoseconds m_total_time =
std::chrono::high_resolution_clock::duration::zero();
std::chrono::nanoseconds m_last_time; std::chrono::nanoseconds m_last_time;
size_t m_total_count = 0; size_t m_total_count = 0;
std::string m_name; std::string m_name;
}; };
template <class InputIt, class BinaryOp> template <class InputIt, class BinaryOp>
typename std::iterator_traits<InputIt>::value_type typename std::iterator_traits<InputIt>::value_type
reduce(InputIt first, InputIt last, BinaryOp op) reduce(InputIt first, InputIt last, BinaryOp op)
{ {
typename std::iterator_traits<InputIt>::value_type result; typename std::iterator_traits<InputIt>::value_type result;
if (first == last) if (first == last)
...@@ -180,18 +179,18 @@ typename std::iterator_traits<InputIt>::value_type ...@@ -180,18 +179,18 @@ typename std::iterator_traits<InputIt>::value_type
} }
} }
return result; return result;
} }
template <typename T> template <typename T>
T plus(const T& a, const T& b) T plus(const T& a, const T& b)
{ {
return a + b; return a + b;
} }
template <typename T> template <typename T>
T mul(const T& a, const T& b) T mul(const T& a, const T& b)
{ {
return a * b; return a * b;
} }
} // end namespace ngraph } // end namespace ngraph
...@@ -15,10 +15,10 @@ ...@@ -15,10 +15,10 @@
#pragma once #pragma once
#include <array> #include <array>
#include <random> #include <cstring>
#include <iomanip> #include <iomanip>
#include <iostream> #include <iostream>
#include <cstring> #include <random>
static std::mt19937_64 random_generator; static std::mt19937_64 random_generator;
...@@ -74,7 +74,6 @@ public: ...@@ -74,7 +74,6 @@ public:
} }
bool operator!=(const uuid_type& other) const { return !(*this == other); } bool operator!=(const uuid_type& other) const { return !(*this == other); }
friend std::ostream& operator<<(std::ostream& out, const uuid_type& id) friend std::ostream& operator<<(std::ostream& out, const uuid_type& id)
{ {
out << id.to_string(); out << id.to_string();
......
...@@ -12,10 +12,10 @@ ...@@ -12,10 +12,10 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#include <vector>
#include <string>
#include <sstream> #include <sstream>
#include <string>
#include <unordered_map> #include <unordered_map>
#include <vector>
#include "gtest/gtest.h" #include "gtest/gtest.h"
...@@ -310,7 +310,7 @@ TEST(axes, index) ...@@ -310,7 +310,7 @@ TEST(axes, index)
EXPECT_EQ(7, b[1].length()); EXPECT_EQ(7, b[1].length());
} }
TEST(axes, as_nested_list) TEST(axes, DISABLED_as_nested_list)
{ {
Axis C = make_axis(5); Axis C = make_axis(5);
Axis H = make_axis(3); Axis H = make_axis(3);
...@@ -325,7 +325,7 @@ TEST(axes, as_nested_list) ...@@ -325,7 +325,7 @@ TEST(axes, as_nested_list)
FAIL(); FAIL();
} }
TEST(axes, flatten) TEST(axes, DISABLED_flatten)
{ {
Axis C = make_axis(5); Axis C = make_axis(5);
Axis H = make_axis(3); Axis H = make_axis(3);
...@@ -336,7 +336,7 @@ TEST(axes, flatten) ...@@ -336,7 +336,7 @@ TEST(axes, flatten)
EXPECT_TRUE(c.is_flattened()); EXPECT_TRUE(c.is_flattened());
} }
TEST(axes, as_flattened_list) TEST(axes, DISABLED_as_flattened_list)
{ {
FAIL(); FAIL();
} }
...@@ -364,7 +364,7 @@ TEST(axes, hash_axes) ...@@ -364,7 +364,7 @@ TEST(axes, hash_axes)
m2[axes] = 1; m2[axes] = 1;
} }
TEST(axes, reaxe_0d_to_1d) TEST(axes, DISABLED_reaxe_0d_to_1d)
{ {
TensorDescription td{}; TensorDescription td{};
ngraph::ndarray x = random(td); ngraph::ndarray x = random(td);
...@@ -382,7 +382,7 @@ TEST(axes, reaxe_0d_to_1d) ...@@ -382,7 +382,7 @@ TEST(axes, reaxe_0d_to_1d)
FAIL(); FAIL();
} }
TEST(axes, reaxe_0d_to_2d) TEST(axes, DISABLED_reaxe_0d_to_2d)
{ {
// td = TensorDescription(axes=()) // td = TensorDescription(axes=())
// x = random(td) // x = random(td)
...@@ -407,7 +407,7 @@ TEST(axes, reaxe_0d_to_2d) ...@@ -407,7 +407,7 @@ TEST(axes, reaxe_0d_to_2d)
// I started refactoring into smaller pieces as seen in tests above, but // I started refactoring into smaller pieces as seen in tests above, but
// stopped ... // stopped ...
//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------
TEST(axes, simple_tensors) TEST(axes, DISABLED_simple_tensors)
{ {
// # A simple vector // # A simple vector
// td1 = TensorDescription(axes=[ax_A]) // td1 = TensorDescription(axes=[ax_A])
...@@ -582,7 +582,7 @@ TEST(axes, axes_map) ...@@ -582,7 +582,7 @@ TEST(axes, axes_map)
// assert axes_after == axes_map.map_axes(axes_before) // assert axes_after == axes_map.map_axes(axes_before)
} }
TEST(axes, axes_map_immutable) TEST(axes, DISABLED_axes_map_immutable)
{ {
FAIL(); FAIL();
// axes_map = AxesMap({}) // axes_map = AxesMap({})
...@@ -591,7 +591,7 @@ TEST(axes, axes_map_immutable) ...@@ -591,7 +591,7 @@ TEST(axes, axes_map_immutable)
// axes_map["x"] = "y" // axes_map["x"] = "y"
} }
TEST(axes, axes_map_init_from_axes) TEST(axes, DISABLED_axes_map_init_from_axes)
{ {
FAIL(); FAIL();
// axes_map = AxesMap({ng.make_axis(1, name="aaa"): ng.make_axis(1, name="zzz")}) // axes_map = AxesMap({ng.make_axis(1, name="aaa"): ng.make_axis(1, name="zzz")})
......
...@@ -12,9 +12,9 @@ ...@@ -12,9 +12,9 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#include <vector>
#include <string>
#include <sstream> #include <sstream>
#include <string>
#include <vector>
#include "gtest/gtest.h" #include "gtest/gtest.h"
......
...@@ -12,9 +12,9 @@ ...@@ -12,9 +12,9 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#include <vector>
#include <string>
#include <sstream> #include <sstream>
#include <string>
#include <vector>
#include "gtest/gtest.h" #include "gtest/gtest.h"
......
...@@ -12,8 +12,8 @@ ...@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#include <iostream>
#include <chrono> #include <chrono>
#include <iostream>
#include "gtest/gtest.h" #include "gtest/gtest.h"
......
...@@ -12,9 +12,9 @@ ...@@ -12,9 +12,9 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#include <vector>
#include <string>
#include <sstream> #include <sstream>
#include <string>
#include <vector>
#include "gtest/gtest.h" #include "gtest/gtest.h"
...@@ -22,4 +22,6 @@ ...@@ -22,4 +22,6 @@
using namespace ngraph; using namespace ngraph;
TEST(names, name) {} TEST(names, name)
{
}
...@@ -12,9 +12,9 @@ ...@@ -12,9 +12,9 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#include <vector>
#include <string>
#include <sstream> #include <sstream>
#include <string>
#include <vector>
#include "gtest/gtest.h" #include "gtest/gtest.h"
......
...@@ -12,10 +12,10 @@ ...@@ -12,10 +12,10 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#include <vector>
#include <string>
#include <sstream> #include <sstream>
#include <string>
#include <unordered_map> #include <unordered_map>
#include <vector>
#include "gtest/gtest.h" #include "gtest/gtest.h"
......
...@@ -12,10 +12,10 @@ ...@@ -12,10 +12,10 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#include <vector>
#include <string>
#include <sstream>
#include <memory> #include <memory>
#include <sstream>
#include <string>
#include <vector>
#include "gtest/gtest.h" #include "gtest/gtest.h"
......
...@@ -12,9 +12,9 @@ ...@@ -12,9 +12,9 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#include <vector>
#include <string>
#include <sstream> #include <sstream>
#include <string>
#include <vector>
#include "gtest/gtest.h" #include "gtest/gtest.h"
...@@ -134,7 +134,9 @@ TEST(util, contains) ...@@ -134,7 +134,9 @@ TEST(util, contains)
EXPECT_FALSE(contains(v1, 8)); EXPECT_FALSE(contains(v1, 8));
} }
TEST(util, remove_from) {} TEST(util, remove_from)
{
}
TEST(util, reduce) TEST(util, reduce)
{ {
......
...@@ -12,9 +12,9 @@ ...@@ -12,9 +12,9 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#include <vector>
#include <string>
#include <sstream> #include <sstream>
#include <string>
#include <vector>
#include "gtest/gtest.h" #include "gtest/gtest.h"
......
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