mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
[ci-skip] update feature table and be good at stuff
This commit is contained in:
parent
ec7673f469
commit
391152382c
|
@ -58,9 +58,9 @@ The Feature Matrix™
|
|||
|
||||
The below feature table checks for the presence of something. It, however, does not actually account for any kind of laborious syntax.
|
||||
|
||||
✔ full support: works as you'd expecte (operator[] on tables, etc...)
|
||||
✔ full support: works as you'd expect (operator[] on tables, etc...)
|
||||
|
||||
~ partial support / wonky support: this means its either supported through some other fashion (not with the desired syntax, serious caveats, etc.). Sometimes means dropping down t use the plain C API.
|
||||
~ partial support / wonky support: this means its either supported through some other fashion (not with the desired syntax, serious caveats, etc.). Sometimes means dropping down to use the plain C API (at which point, what was the point of the abstraction?).
|
||||
|
||||
✗ no support: feature doesn't work or, if it's there, it REALLY sucks to use
|
||||
|
||||
|
@ -89,10 +89,10 @@ Explanations for a few categories are below (rest are self-explanatory).
|
|||
* coroutines: allowing a function to be called multiple times, resuming the execution of a Lua coroutine each time
|
||||
|
||||
+---------------------------+-------------+------------+----------+---------+----------+-----------+-----------+----------------+----------+----------+-----------+-----------------+--------+
|
||||
| | plain C | luawrapper | lua-intf | luabind | Selene | Sol2 | oolua | lua-api-pp | kaguya | SLB | SWIG | luacppinterface | luwra |
|
||||
| | plain C | luawrapper | lua-intf | luabind | Selene | Sol2 | oolua | lua-api-pp | kaguya | SLB3 | SWIG | luacppinterface | luwra |
|
||||
| | | | | | | | | | | | | | |
|
||||
+===========================+=============+============+==========+=========+==========+===========+===========+================+==========+==========+===========+=================+========+
|
||||
| optional | ~ | ✗ | ✔ | ✗ | ✗ | ✔ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |
|
||||
| optional | ~ | ✗ | ✔ | ✗ | ✗ | ✔ | ✗ | ✗ | ✔ | ✗ | ✗ | ✗ | ✗ |
|
||||
+---------------------------+-------------+------------+----------+---------+----------+-----------+-----------+----------------+----------+----------+-----------+-----------------+--------+
|
||||
| tables | ~ | ~ | ~ | ✔ | ✔ | ✔ | ~ | ✔ | ✔ | ✗ | ✗ | ~ | ✔ |
|
||||
+---------------------------+-------------+------------+----------+---------+----------+-----------+-----------+----------------+----------+----------+-----------+-----------------+--------+
|
||||
|
@ -110,7 +110,7 @@ Explanations for a few categories are below (rest are self-explanatory).
|
|||
+---------------------------+-------------+------------+----------+---------+----------+-----------+-----------+----------------+----------+----------+-----------+-----------------+--------+
|
||||
| lua callables from C(++) | ~ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ~ |
|
||||
+---------------------------+-------------+------------+----------+---------+----------+-----------+-----------+----------------+----------+----------+-----------+-----------------+--------+
|
||||
| function binding | ~ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ~ |
|
||||
| function binding | ~ | ✔ | ✔ | ✔ | ✔ | ✔ | ~ | ~ | ✔ | ~ | ~ | ~ | ✔ |
|
||||
+---------------------------+-------------+------------+----------+---------+----------+-----------+-----------+----------------+----------+----------+-----------+-----------------+--------+
|
||||
| protected call | ~ | ✗ | ~ | ~ | ~ | ✔ | ~ | ✔ | ~ | ~ | ~ | ~ | ~ |
|
||||
+---------------------------+-------------+------------+----------+---------+----------+-----------+-----------+----------------+----------+----------+-----------+-----------------+--------+
|
||||
|
@ -120,7 +120,7 @@ Explanations for a few categories are below (rest are self-explanatory).
|
|||
+---------------------------+-------------+------------+----------+---------+----------+-----------+-----------+----------------+----------+----------+-----------+-----------------+--------+
|
||||
| inheritance | ~ | ✔ | ✔ | ✔ | ✔ | ✔ | ~ | ~ | ✔ | ~ | ✔ | ~ | ✗ |
|
||||
+---------------------------+-------------+------------+----------+---------+----------+-----------+-----------+----------------+----------+----------+-----------+-----------------+--------+
|
||||
| overloading | ~ | ✗ | ✗ | ✗ | ✗ | ✔ | ✗ | ✗ | ✔ | ✔ | ✔ | ✗ | ✗ |
|
||||
| overloading | ~ | ✗ | ✔ | ✗ | ✗ | ✔ | ✗ | ✗ | ✔ | ✔ | ✔ | ✗ | ✗ |
|
||||
+---------------------------+-------------+------------+----------+---------+----------+-----------+-----------+----------------+----------+----------+-----------+-----------------+--------+
|
||||
| Lua thread | ~ | ✗ | ~ | ✗ | ✗ | ✔ | ✔ | ✗ | ✔ | ✗ | ✗ | ✔ | ✗ |
|
||||
+---------------------------+-------------+------------+----------+---------+----------+-----------+-----------+----------------+----------+----------+-----------+-----------------+--------+
|
||||
|
@ -153,18 +153,17 @@ Plain C -
|
|||
|
||||
kaguya -
|
||||
|
||||
* Probably the closest in implementation details and interface to Sol itself
|
||||
* member variables are automatically turned into ``obj:x( value )`` to set and ``obj:x()`` to get
|
||||
* Has optional support
|
||||
* Inspired coroutine support for Sol
|
||||
* Library author (satoren) is a nice guy!
|
||||
* C++11/14, or boostified (which makes it C++03 compatible)
|
||||
* Class registration is a bit verbose, but not as offensive as OOLua or lua-intf or others
|
||||
* Deserves lots of love!
|
||||
|
||||
Sol -
|
||||
|
||||
* Only library with Optional support, hoorah!
|
||||
* Prrreeettty fast (still working on being the ABSOLUTE FASTEST)!
|
||||
* One of the few libraries with optional support!
|
||||
* Basically the fastest in almomst all respects: http://sol2.readthedocs.io/en/latest/benchmarks.html
|
||||
* Overloading support can get messy with inheritance, see :doc:`here<api/overload>`
|
||||
* C++14/"C++1y" (-std=c++14, -std=c++1y, =std=c++1z) flags are used (available since GCC 4.9 and Clang 3.5)
|
||||
* Active issues, active individuals
|
||||
|
@ -173,6 +172,7 @@ Sol -
|
|||
lua-intf -
|
||||
|
||||
* Can be both header-only or compiled
|
||||
* Has optional support
|
||||
* C++11
|
||||
* Macro-based registration (strange pseudo-language)
|
||||
* Fairly fast in most regards
|
||||
|
@ -185,30 +185,28 @@ Selene -
|
|||
* member variables are automatically turned into ``obj:set_x( value )`` to set and ``obj:x()`` to get
|
||||
* Registering classes/"modules" using C++ code is extremely verbose, similar to lua-intf's style
|
||||
* Eats crap when it comes to performance, most of the time (see :doc:`benchmarks<benchmarks>`)
|
||||
* Lots of users, but the Repository is kinda stagnant...
|
||||
* Lots of users (blogpost etc. made it popular), but the Repository is kinda stagnant...
|
||||
|
||||
luawrapper -
|
||||
|
||||
* Takes the approach of writing and reading tables using ``readVariable`` and ``writeVariable`` functions
|
||||
* C++11
|
||||
* No macros!
|
||||
* C++11, no macros!
|
||||
* The interface can be clunky (no table-like data structures: most things go though ``readVariable`` / ``writeVariable``)
|
||||
* Internal Compiler errors in Visual Studio 2015 - submitted a PR to fix it, hopefully it'll get picked up
|
||||
|
||||
SWIG (3.0) -
|
||||
|
||||
* Very comprehensive for binding concepts of C++ (classes, variables, etc.) to lua
|
||||
* Very comprehensive for binding concepts of C++ (classes, variables, etc.) to Lua
|
||||
* Helps with literally nothing else (tables, threads, stack abstractions, etc.)
|
||||
* Not really a good, full-featured Library...
|
||||
* Requires preprocessing step (but it's not a... TERRIBLY complicated preprocessing step); some boilerplate in writing additional classes that you've already declared
|
||||
|
||||
luacppinterface -
|
||||
|
||||
* The branch that fixes VC++ warnings
|
||||
* The branch that fixes VC++ warnings and introduces some new work has type checker issues, so use the stable branch only
|
||||
* No member variable support
|
||||
* Actually has tables (but no operator[])
|
||||
* Does not support arbitrary keys
|
||||
* Pretty decent
|
||||
|
||||
luabind -
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ get going:
|
|||
tutorial/tutorial-top
|
||||
features
|
||||
api/api-top
|
||||
mentions
|
||||
benchmarks
|
||||
safety
|
||||
exceptions
|
||||
|
|
22
docs/source/mentions.rst
Normal file
22
docs/source/mentions.rst
Normal file
|
@ -0,0 +1,22 @@
|
|||
mentions
|
||||
========
|
||||
so does anyone cool use this thing...?
|
||||
--------------------------------------
|
||||
|
||||
Okay, so the features don't convince you, the documentation doesn't convince you, you want to see what *other* people think about Sol? Well, aside from the well-wishes that come through in the issue tracker, here's a few things floating around about sol2 that I occasionally get pinged about:
|
||||
|
||||
|
||||
* (Reddit) Posts on reddit about it
|
||||
- https://www.reddit.com/r/cpp/comments/4a8gy7/sol2_lua_c_binding_framework/
|
||||
- https://www.reddit.com/r/cpp/comments/4x82hd/plain_c_versus_lua_libraries_benchmarking_speed/
|
||||
* (CppNow) sol2 was mentioned in a comparison to other scripting languages by ChaiScript developer, Jason Turner (@lefticus), at a conference!
|
||||
- https://github.com/lefticus/presentations/blob/master/HowAndWhyToAddScripting.md
|
||||
* (CppCast) Showed up in CppCast with Elias Daler
|
||||
- https://eliasdaler.github.io/cppcast#read-more
|
||||
- http://cppcast.com/2016/07/elias-daler/
|
||||
* (Twitter) Retweets by ThePhD from others!:
|
||||
- https://twitter.com/thephantomderp/status/755214464950034432
|
||||
- https://twitter.com/thephantomderp/status/762043162835709952
|
||||
- https://twitter.com/thephantomderp/status/755214464950034432
|
||||
|
||||
And, of course, I use it. Isn't that enough?
|
|
@ -20,8 +20,8 @@
|
|||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
// This file was generated with a script.
|
||||
// Generated 2016-08-11 15:38:20.268226 UTC
|
||||
// This header was generated with sol v2.11.1 (revision ff8ac8a)
|
||||
// Generated 2016-08-12 04:49:38.051104 UTC
|
||||
// This header was generated with sol v2.11.2 (revision dcff206)
|
||||
// https://github.com/ThePhD/sol2
|
||||
|
||||
#ifndef SOL_SINGLE_INCLUDE_HPP
|
||||
|
|
|
@ -187,8 +187,6 @@ namespace sol {
|
|||
}
|
||||
};
|
||||
|
||||
#if 0
|
||||
|
||||
template<>
|
||||
struct getter<std::wstring> {
|
||||
static std::wstring get(lua_State* L, int index, record& tracking) {
|
||||
|
@ -197,6 +195,8 @@ namespace sol {
|
|||
}
|
||||
};
|
||||
|
||||
#if 0
|
||||
|
||||
template<>
|
||||
struct getter<std::u16string> {
|
||||
static std::u16string get(lua_State* L, int index, record& tracking) {
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "raii.hpp"
|
||||
#include "optional.hpp"
|
||||
#include <memory>
|
||||
#include <codecvt>
|
||||
|
||||
namespace sol {
|
||||
namespace stack {
|
||||
|
@ -342,11 +343,15 @@ namespace sol {
|
|||
lua_pushlstring(L, str, len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int push(lua_State* L, const char* str) {
|
||||
return push_sized(L, str, std::char_traits<char>::length(str));
|
||||
}
|
||||
|
||||
static int push(lua_State* L, const char* strb, const char* stre) {
|
||||
return push_sized(L, strb, stre - strb);
|
||||
}
|
||||
|
||||
static int push(lua_State* L, const char* str, std::size_t len) {
|
||||
return push_sized(L, str, len);
|
||||
}
|
||||
|
@ -395,27 +400,42 @@ namespace sol {
|
|||
}
|
||||
};
|
||||
|
||||
#if 0
|
||||
|
||||
template<>
|
||||
struct pusher<const wchar_t*> {
|
||||
static int push(lua_State* L, const wchar_t* wstr) {
|
||||
return push(L, wstr, wstr + std::char_traits<wchar_t>::length(wstr));
|
||||
return push(L, wstr, std::char_traits<wchar_t>::length(wstr));
|
||||
}
|
||||
static int push(lua_State* L, const wchar_t* wstrb, const wchar_t* wstre) {
|
||||
std::string str{};
|
||||
return stack::push(L, str);
|
||||
|
||||
static int push(lua_State* L, const wchar_t* wstr, std::size_t sz) {
|
||||
return push(L, wstr, wstr + sz);
|
||||
}
|
||||
|
||||
static int push(lua_State* L, const wchar_t* strb, const wchar_t* stre) {
|
||||
std::wstring_convert<std::codecvt_utf8<wchar_t>> utf8_conv;
|
||||
std::string u8str = utf8_conv.to_bytes(strb, stre);
|
||||
return stack::push(L, u8str);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct pusher<const char16_t*> {
|
||||
static int push(lua_State* L, const char16_t* u16str) {
|
||||
return push(L, u16str, u16str + std::char_traits<char16_t>::length(u16str));
|
||||
return push(L, u16str, std::char_traits<char16_t>::length(u16str));
|
||||
}
|
||||
static int push(lua_State* L, const char16_t* u16strb, const char16_t* u16stre) {
|
||||
std::string str{};
|
||||
return stack::push(L, str);
|
||||
|
||||
static int push(lua_State* L, const char16_t* u16str, std::size_t sz) {
|
||||
return push(L, u16str, u16str + sz);
|
||||
}
|
||||
|
||||
static int push(lua_State* L, const char16_t* strb, const char16_t* stre) {
|
||||
#ifdef _MSC_VER
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<int16_t>, int16_t> convert;
|
||||
std::string u8str = convert.to_bytes(reinterpret_cast<const int16_t*>(strb), reinterpret_cast<const int16_t*>(stre));
|
||||
#else
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
|
||||
std::string u8str = convert.to_bytes(strb, stre);
|
||||
#endif // VC++ is a shit
|
||||
return stack::push(L, u8str);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -424,30 +444,53 @@ namespace sol {
|
|||
static int push(lua_State* L, const char32_t* u32str) {
|
||||
return push(L, u32str, u32str + std::char_traits<char32_t>::length(u32str));
|
||||
}
|
||||
static int push(lua_State* L, const char32_t* u32strb, const char32_t* u32stre) {
|
||||
std::string str{};
|
||||
return stack::push(L, str);
|
||||
|
||||
static int push(lua_State* L, const char32_t* u32str, std::size_t sz) {
|
||||
return push(L, u32str, u32str + sz);
|
||||
}
|
||||
|
||||
static int push(lua_State* L, const char32_t* strb, const char32_t* stre) {
|
||||
#ifdef _MSC_VER
|
||||
std::wstring_convert<std::codecvt_utf8<int32_t>, int32_t> convert;
|
||||
std::string u8str = convert.to_bytes(reinterpret_cast<const int32_t*>(strb), reinterpret_cast<const int32_t*>(stre));
|
||||
#else
|
||||
std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> convert;
|
||||
std::string u8str = convert.to_bytes(strb, stre);
|
||||
#endif // VC++ is a shit
|
||||
return stack::push(L, u8str);
|
||||
}
|
||||
};
|
||||
|
||||
template<size_t N>
|
||||
struct pusher<wchar_t[N]> {
|
||||
static int push(lua_State* L, const wchar_t(&str)[N]) {
|
||||
return stack::push<const wchar_t*>(L, str, str + N - 1);
|
||||
return push(L, str, N - 1);
|
||||
}
|
||||
|
||||
static int push(lua_State* L, const wchar_t(&str)[N], std::size_t sz) {
|
||||
return stack::push<const wchar_t*>(L, str, str + sz);
|
||||
}
|
||||
};
|
||||
|
||||
template<size_t N>
|
||||
struct pusher<char16_t[N]> {
|
||||
static int push(lua_State* L, const char16_t(&str)[N]) {
|
||||
return stack::push<const char16_t*>(L, str, str + N - 1);
|
||||
return push(L, str, N - 1);
|
||||
}
|
||||
|
||||
static int push(lua_State* L, const char16_t(&str)[N], std::size_t sz) {
|
||||
return stack::push<const char16_t*>(L, str, str + sz);
|
||||
}
|
||||
};
|
||||
|
||||
template<size_t N>
|
||||
struct pusher<char32_t[N]> {
|
||||
static int push(lua_State* L, const char32_t(&str)[N]) {
|
||||
return stack::push<const char32_t*>(L, str, str + N - 1);
|
||||
return push(L, str, N - 1);
|
||||
}
|
||||
|
||||
static int push(lua_State* L, const char32_t(&str)[N], std::size_t sz) {
|
||||
return stack::push<const char32_t*>(L, str, str + sz);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -455,7 +498,7 @@ namespace sol {
|
|||
struct pusher<wchar_t> {
|
||||
static int push(lua_State* L, wchar_t c) {
|
||||
const wchar_t str[2] = { c, '\0' };
|
||||
return stack::push(L, str);
|
||||
return stack::push(L, str, 1);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -463,7 +506,7 @@ namespace sol {
|
|||
struct pusher<char16_t> {
|
||||
static int push(lua_State* L, char16_t c) {
|
||||
const char16_t str[2] = { c, '\0' };
|
||||
return stack::push(L, str);
|
||||
return stack::push(L, str, 1);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -471,33 +514,43 @@ namespace sol {
|
|||
struct pusher<char32_t> {
|
||||
static int push(lua_State* L, char32_t c) {
|
||||
const char32_t str[2] = { c, '\0' };
|
||||
return stack::push(L, str);
|
||||
return stack::push(L, str, 1);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct pusher<std::wstring> {
|
||||
static int push(lua_State* L, const std::wstring& wstr) {
|
||||
return stack::push(L, wstr.data(), wstr.data() + wstr.size());
|
||||
return push(L, wstr.data(), wstr.size());
|
||||
}
|
||||
|
||||
static int push(lua_State* L, const std::wstring& wstr, std::size_t sz) {
|
||||
return stack::push(L, wstr.data(), wstr.data() + sz);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct pusher<std::u16string> {
|
||||
static int push(lua_State* L, const std::u16string& u16str) {
|
||||
return stack::push(L, u16str.data(), u16str.data() + u16str.size());
|
||||
return push(L, u16str, u16str.size());
|
||||
}
|
||||
|
||||
static int push(lua_State* L, const std::u16string& u16str, std::size_t sz) {
|
||||
return stack::push(L, u16str.data(), u16str.data() + sz);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct pusher<std::u32string> {
|
||||
static int push(lua_State* L, const std::u32string& u32str) {
|
||||
return stack::push(L, u32str.data(), u32str.data() + u32str.size());
|
||||
return push(L, u32str, u32str.size());
|
||||
}
|
||||
|
||||
static int push(lua_State* L, const std::u32string& u32str, std::size_t sz) {
|
||||
return stack::push(L, u32str.data(), u32str.data() + sz);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // Bad conversions
|
||||
|
||||
template<typename... Args>
|
||||
struct pusher<std::tuple<Args...>> {
|
||||
template <std::size_t... I, typename T>
|
||||
|
|
|
@ -25,7 +25,6 @@ TEST_CASE("stack/strings", "test that strings can be roundtripped") {
|
|||
static const wchar_t widestr[] = L"Fuck these shitty compilers";
|
||||
static const char32_t utf32str2[] = U"🕴";
|
||||
|
||||
#if 0
|
||||
lua["utf8"] = utf8str;
|
||||
lua["utf16"] = utf16str;
|
||||
lua["utf32"] = utf32str;
|
||||
|
@ -36,11 +35,22 @@ TEST_CASE("stack/strings", "test that strings can be roundtripped") {
|
|||
std::string utf32_to_utf8 = lua["utf32"];
|
||||
std::string wide_to_utf8 = lua["wide"];
|
||||
|
||||
REQUIRE(utf8_to_utf8 == utf8str);
|
||||
REQUIRE(utf16_to_utf8 == utf8str);
|
||||
REQUIRE(utf32_to_utf8 == utf8str);
|
||||
REQUIRE(wide_to_utf8 == utf8str);
|
||||
|
||||
std::wstring utf8_to_wide = lua["utf8"];
|
||||
std::wstring utf16_to_wide = lua["utf16"];
|
||||
std::wstring utf32_to_wide = lua["utf32"];
|
||||
std::wstring wide_to_wide = lua["wide"];
|
||||
|
||||
REQUIRE(utf8_to_wide == widestr);
|
||||
REQUIRE(utf16_to_wide == widestr);
|
||||
REQUIRE(utf32_to_wide == widestr);
|
||||
REQUIRE(wide_to_wide == widestr);
|
||||
|
||||
#if 0
|
||||
std::u16string utf8_to_utf16 = lua["utf8"];
|
||||
std::u16string utf16_to_utf16 = lua["utf16"];
|
||||
std::u16string utf32_to_utf16 = lua["utf32"];
|
||||
|
@ -51,26 +61,11 @@ TEST_CASE("stack/strings", "test that strings can be roundtripped") {
|
|||
std::u32string utf32_to_utf32 = lua["utf32"];
|
||||
std::u32string wide_to_utf32 = lua["wide"];
|
||||
|
||||
REQUIRE(utf8_to_utf8 == utf8str);
|
||||
REQUIRE(utf16_to_utf8 == utf8str);
|
||||
REQUIRE(utf32_to_utf8 == utf8str);
|
||||
REQUIRE(wide_to_utf8 == utf8str);
|
||||
|
||||
REQUIRE(utf8_to_utf16 == utf16str);
|
||||
REQUIRE(utf16_to_utf16 == utf16str);
|
||||
REQUIRE(utf32_to_utf16 == utf16str);
|
||||
REQUIRE(wide_to_utf16 == utf16str);
|
||||
|
||||
REQUIRE(utf8_to_utf32 == utf32str);
|
||||
REQUIRE(utf16_to_utf32 == utf32str);
|
||||
REQUIRE(utf32_to_utf32 == utf32str);
|
||||
REQUIRE(wide_to_utf32 == utf32str);
|
||||
|
||||
REQUIRE(utf8_to_wide == widestr);
|
||||
REQUIRE(utf16_to_wide == widestr);
|
||||
REQUIRE(utf32_to_wide == widestr);
|
||||
REQUIRE(wide_to_wide == widestr);
|
||||
|
||||
char32_t utf8_to_char32 = lua["utf8"];
|
||||
char32_t utf16_to_char32 = lua["utf16"];
|
||||
char32_t utf32_to_char32 = lua["utf32"];
|
||||
|
|
Loading…
Reference in New Issue
Block a user