Skip to content

Commit

Permalink
Windows|libcore: Adapting code for MSVC
Browse files Browse the repository at this point in the history
  • Loading branch information
skyjake committed Sep 1, 2019
1 parent af807c7 commit f6a41e4
Show file tree
Hide file tree
Showing 15 changed files with 129 additions and 74 deletions.
4 changes: 2 additions & 2 deletions doomsday/cmake/FindFoundation.cmake
Expand Up @@ -2,8 +2,8 @@ if (MSYS2_LIBS_DIR)
add_library (the_Foundation INTERFACE)
set (_tfDir ${MSYS2_LIBS_DIR}/${DE_ARCH}/the_Foundation)
target_link_libraries (the_Foundation INTERFACE
debug ${_tfDir}/lib/libFoundationd.lib
optimized ${_tfDir}/lib/libFoundation.lib
debug ${_tfDir}/lib/msys-Foundationd.lib
optimized ${_tfDir}/lib/msys-Foundation.lib
)
target_include_directories (the_Foundation INTERFACE
${_tfDir}/include
Expand Down
9 changes: 6 additions & 3 deletions doomsday/cmake/PlatformWindows.cmake
Expand Up @@ -48,6 +48,12 @@ if (MSVC)
append_unique (CMAKE_C_FLAGS "-w14505 -wd4100 -wd4748")
append_unique (CMAKE_CXX_FLAGS "-w14505 -wd4100 -wd4748")

# de::Error is derived from std::runtime_error (non-dll-interface class).
append_unique (CMAKE_CXX_FLAGS "-wd4251 -wd4275")

# Possible loss of data due to number conversion.
append_unique (CMAKE_CXX_FLAGS "-wd4244")

# Enable multi-processor compiling.
append_unique (CMAKE_C_FLAGS "-MP")
append_unique (CMAKE_CXX_FLAGS "-MP")
Expand All @@ -57,9 +63,6 @@ if (MSVC)
# type conversions.
append_unique (CMAKE_C_FLAGS "-wd4267")
append_unique (CMAKE_CXX_FLAGS "-wd4267")

# de::Error is derived from std::runtime_error (non-dll-interface class).
append_unique (CMAKE_CXX_FLAGS "-wd4275")
endif ()

# Locate Visual Studio.
Expand Down
79 changes: 56 additions & 23 deletions doomsday/libs/core/include/de/data/observers.h
Expand Up @@ -100,33 +100,66 @@

// Variadic conveniences:

#define DE_PIMPL_AUDIENCES_1(x) DE_PIMPL_AUDIENCE(x)
#define DE_PIMPL_AUDIENCES_2(x, ...) DE_PIMPL_AUDIENCE(x) DE_PIMPL_AUDIENCES_1(__VA_ARGS__)
#define DE_PIMPL_AUDIENCES_3(x, ...) DE_PIMPL_AUDIENCE(x) DE_PIMPL_AUDIENCES_2(__VA_ARGS__)
#define DE_PIMPL_AUDIENCES_4(x, ...) DE_PIMPL_AUDIENCE(x) DE_PIMPL_AUDIENCES_3(__VA_ARGS__)
#define DE_PIMPL_AUDIENCES_5(x, ...) DE_PIMPL_AUDIENCE(x) DE_PIMPL_AUDIENCES_4(__VA_ARGS__)
#define DE_PIMPL_AUDIENCES_6(x, ...) DE_PIMPL_AUDIENCE(x) DE_PIMPL_AUDIENCES_5(__VA_ARGS__)
#define DE_PIMPL_AUDIENCES_7(x, ...) DE_PIMPL_AUDIENCE(x) DE_PIMPL_AUDIENCES_6(__VA_ARGS__)
#define DE_PIMPL_AUDIENCES_8(x, ...) DE_PIMPL_AUDIENCE(x) DE_PIMPL_AUDIENCES_7(__VA_ARGS__)

#define DE_PIMPL_AUDIENCES_(N, ...) DE_CONCAT(DE_PIMPL_AUDIENCES_, N)(__VA_ARGS__)

#define DE_PIMPL_AUDIENCES(...) \
#if !defined (_MSC_VER)
# define DE_PIMPL_AUDIENCES_1(x) DE_PIMPL_AUDIENCE(x)
# define DE_PIMPL_AUDIENCES_2(x, ...) DE_PIMPL_AUDIENCE(x) DE_PIMPL_AUDIENCES_1(__VA_ARGS__)
# define DE_PIMPL_AUDIENCES_3(x, ...) DE_PIMPL_AUDIENCE(x) DE_PIMPL_AUDIENCES_2(__VA_ARGS__)
# define DE_PIMPL_AUDIENCES_4(x, ...) DE_PIMPL_AUDIENCE(x) DE_PIMPL_AUDIENCES_3(__VA_ARGS__)
# define DE_PIMPL_AUDIENCES_5(x, ...) DE_PIMPL_AUDIENCE(x) DE_PIMPL_AUDIENCES_4(__VA_ARGS__)
# define DE_PIMPL_AUDIENCES_6(x, ...) DE_PIMPL_AUDIENCE(x) DE_PIMPL_AUDIENCES_5(__VA_ARGS__)
# define DE_PIMPL_AUDIENCES_7(x, ...) DE_PIMPL_AUDIENCE(x) DE_PIMPL_AUDIENCES_6(__VA_ARGS__)
# define DE_PIMPL_AUDIENCES_8(x, ...) DE_PIMPL_AUDIENCE(x) DE_PIMPL_AUDIENCES_7(__VA_ARGS__)

# define DE_PIMPL_AUDIENCES_(N, ...) DE_CONCAT(DE_PIMPL_AUDIENCES_, N)(__VA_ARGS__)
# define DE_PIMPL_AUDIENCES(...) \
DE_PIMPL_AUDIENCES_(DE_NUM_ARG(__VA_ARGS__), __VA_ARGS__)

#define DE_AUDIENCE_METHODS_1(ClassName, x) DE_AUDIENCE_METHOD(ClassName, x)
#define DE_AUDIENCE_METHODS_2(ClassName, x, ...) DE_AUDIENCE_METHOD(ClassName, x) DE_AUDIENCE_METHODS_1(ClassName, __VA_ARGS__)
#define DE_AUDIENCE_METHODS_3(ClassName, x, ...) DE_AUDIENCE_METHOD(ClassName, x) DE_AUDIENCE_METHODS_2(ClassName, __VA_ARGS__)
#define DE_AUDIENCE_METHODS_4(ClassName, x, ...) DE_AUDIENCE_METHOD(ClassName, x) DE_AUDIENCE_METHODS_3(ClassName, __VA_ARGS__)
#define DE_AUDIENCE_METHODS_5(ClassName, x, ...) DE_AUDIENCE_METHOD(ClassName, x) DE_AUDIENCE_METHODS_4(ClassName, __VA_ARGS__)
#define DE_AUDIENCE_METHODS_6(ClassName, x, ...) DE_AUDIENCE_METHOD(ClassName, x) DE_AUDIENCE_METHODS_5(ClassName, __VA_ARGS__)
#define DE_AUDIENCE_METHODS_7(ClassName, x, ...) DE_AUDIENCE_METHOD(ClassName, x) DE_AUDIENCE_METHODS_6(ClassName, __VA_ARGS__)
#define DE_AUDIENCE_METHODS_8(ClassName, x, ...) DE_AUDIENCE_METHOD(ClassName, x) DE_AUDIENCE_METHODS_7(ClassName, __VA_ARGS__)

#define DE_AUDIENCE_METHODS_(N, ClassName, ...) DE_CONCAT(DE_AUDIENCE_METHODS_, N)(ClassName, __VA_ARGS__)
#define DE_AUDIENCE_METHODS(ClassName, ...) \
# define DE_AUDIENCE_METHODS_1(ClassName, x) DE_AUDIENCE_METHOD(ClassName, x)
# define DE_AUDIENCE_METHODS_2(ClassName, x, ...) DE_AUDIENCE_METHOD(ClassName, x) DE_AUDIENCE_METHODS_1(ClassName, __VA_ARGS__)
# define DE_AUDIENCE_METHODS_3(ClassName, x, ...) DE_AUDIENCE_METHOD(ClassName, x) DE_AUDIENCE_METHODS_2(ClassName, __VA_ARGS__)
# define DE_AUDIENCE_METHODS_4(ClassName, x, ...) DE_AUDIENCE_METHOD(ClassName, x) DE_AUDIENCE_METHODS_3(ClassName, __VA_ARGS__)
# define DE_AUDIENCE_METHODS_5(ClassName, x, ...) DE_AUDIENCE_METHOD(ClassName, x) DE_AUDIENCE_METHODS_4(ClassName, __VA_ARGS__)
# define DE_AUDIENCE_METHODS_6(ClassName, x, ...) DE_AUDIENCE_METHOD(ClassName, x) DE_AUDIENCE_METHODS_5(ClassName, __VA_ARGS__)
# define DE_AUDIENCE_METHODS_7(ClassName, x, ...) DE_AUDIENCE_METHOD(ClassName, x) DE_AUDIENCE_METHODS_6(ClassName, __VA_ARGS__)
# define DE_AUDIENCE_METHODS_8(ClassName, x, ...) DE_AUDIENCE_METHOD(ClassName, x) DE_AUDIENCE_METHODS_7(ClassName, __VA_ARGS__)

# define DE_AUDIENCE_METHODS_(N, ClassName, ...) DE_CONCAT(DE_AUDIENCE_METHODS_, N)(ClassName, __VA_ARGS__)
# define DE_AUDIENCE_METHODS(ClassName, ...) \
DE_AUDIENCE_METHODS_(DE_NUM_ARG(__VA_ARGS__), ClassName, __VA_ARGS__)

#else
// Slightly modified version for MSVC because __VA_ARGS__ gets expanded differently.
# define DE_PIMPL_AUDIENCES_X_(N, args) DE_GLUE(DE_CONCAT(DE_PIMPL_AUDIENCES_, N), args)
# define DE_PIMPL_AUDIENCES_1(x) DE_PIMPL_AUDIENCE(x)
# define DE_PIMPL_AUDIENCES_2(x, ...) DE_PIMPL_AUDIENCE(x) DE_PIMPL_AUDIENCES_1(__VA_ARGS__)
# define DE_PIMPL_AUDIENCES_3(x, ...) DE_PIMPL_AUDIENCE(x) DE_PIMPL_AUDIENCES_X_(2, (__VA_ARGS__))
# define DE_PIMPL_AUDIENCES_4(x, ...) DE_PIMPL_AUDIENCE(x) DE_PIMPL_AUDIENCES_X_(3, (__VA_ARGS__))
# define DE_PIMPL_AUDIENCES_5(x, ...) DE_PIMPL_AUDIENCE(x) DE_PIMPL_AUDIENCES_X_(4, (__VA_ARGS__))
# define DE_PIMPL_AUDIENCES_6(x, ...) DE_PIMPL_AUDIENCE(x) DE_PIMPL_AUDIENCES_X_(5, (__VA_ARGS__))
# define DE_PIMPL_AUDIENCES_7(x, ...) DE_PIMPL_AUDIENCE(x) DE_PIMPL_AUDIENCES_X_(6, (__VA_ARGS__))
# define DE_PIMPL_AUDIENCES_8(x, ...) DE_PIMPL_AUDIENCE(x) DE_PIMPL_AUDIENCES_X_(7, (__VA_ARGS__))

# define DE_PIMPL_AUDIENCES_N(N) DE_CONCAT(DE_PIMPL_AUDIENCES_, N)
# define DE_PIMPL_AUDIENCES_(N, args) DE_GLUE(DE_PIMPL_AUDIENCES_N(N), args)
# define DE_PIMPL_AUDIENCES(...) \
DE_PIMPL_AUDIENCES_(DE_NUM_ARG(__VA_ARGS__), (__VA_ARGS__))

# define DE_AUDIENCE_METHODS_X_(N, args) DE_GLUE(DE_CONCAT(DE_AUDIENCE_METHODS_, N), args)
# define DE_AUDIENCE_METHODS_1(ClassName, x) DE_AUDIENCE_METHOD(ClassName, x)
# define DE_AUDIENCE_METHODS_2(ClassName, x, ...) DE_AUDIENCE_METHOD(ClassName, x) DE_AUDIENCE_METHODS_1(ClassName, __VA_ARGS__)
# define DE_AUDIENCE_METHODS_3(ClassName, x, ...) DE_AUDIENCE_METHOD(ClassName, x) DE_AUDIENCE_METHODS_X_(2, (ClassName, __VA_ARGS__))
# define DE_AUDIENCE_METHODS_4(ClassName, x, ...) DE_AUDIENCE_METHOD(ClassName, x) DE_AUDIENCE_METHODS_X_(3, (ClassName, __VA_ARGS__))
# define DE_AUDIENCE_METHODS_5(ClassName, x, ...) DE_AUDIENCE_METHOD(ClassName, x) DE_AUDIENCE_METHODS_X_(4, (ClassName, __VA_ARGS__))
# define DE_AUDIENCE_METHODS_6(ClassName, x, ...) DE_AUDIENCE_METHOD(ClassName, x) DE_AUDIENCE_METHODS_X_(5, (ClassName, __VA_ARGS__))
# define DE_AUDIENCE_METHODS_7(ClassName, x, ...) DE_AUDIENCE_METHOD(ClassName, x) DE_AUDIENCE_METHODS_X_(6, (ClassName, __VA_ARGS__))
# define DE_AUDIENCE_METHODS_8(ClassName, x, ...) DE_AUDIENCE_METHOD(ClassName, x) DE_AUDIENCE_METHODS_X_(7, (ClassName, __VA_ARGS__))

# define DE_AUDIENCE_METHODS_N(N) DE_CONCAT(DE_AUDIENCE_METHODS_, N)
# define DE_AUDIENCE_METHODS_(N, args) DE_GLUE(DE_AUDIENCE_METHODS_N(N), args)
# define DE_AUDIENCE_METHODS(ClassName, ...) \
DE_AUDIENCE_METHODS_(DE_NUM_ARG(__VA_ARGS__), (ClassName, __VA_ARGS__))
#endif

/**
* Macro that can be used in class declarations to specify which audiences the class
* can belong to.
Expand Down
2 changes: 2 additions & 0 deletions doomsday/libs/core/include/de/data/string.h
Expand Up @@ -779,7 +779,9 @@ class DE_PUBLIC String : public IByteArray
static String asText(duint16 value) { return format("%u", value); }
static String asText(duint32 value) { return format("%u", value); }
static String asText(duint64 value) { return format("%llu", value); }
#if !defined (_WIN64) // size_t == uint64
static String asText(dsize value) { return format("%zu", value); }
#endif
static String asText(dfloat value) { return format("%f", double(value)); }
static String asText(dfloat value, int precision);
static String asText(ddouble value) { return format("%f", value); }
Expand Down
25 changes: 17 additions & 8 deletions doomsday/libs/core/include/de/libcore.h
Expand Up @@ -184,6 +184,9 @@
*/
#define DE_TYPE_NAME(t) (typeid(t).name())

#define DE_CONCAT(x, y) x##y
#define DE_GLUE(x, y) x y

/**
* @macro DE_UNUSED(...)
* Macro for marking parameters and variables as intentionally unused, so the compiler
Expand All @@ -192,15 +195,20 @@
#define DE_UNUSED_MANY(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, ...) \
((void)(_0), (void)(_1), (void)(_2), (void)(_3), (void)(_4), \
(void)(_5), (void)(_6), (void)(_7), (void)(_8), (void)(_9))
#define DE_UNUSED(...) DE_UNUSED_MANY(__VA_ARGS__, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)

// Macro trick for determining number of arguments (up to 8).
#define DE_NUM_ARG_RSEQ_N() 8, 7, 6, 5, 4, 3, 2, 1, 0
#define DE_NUM_ARG(...) DE_NUM_ARG_(__VA_ARGS__, DE_NUM_ARG_RSEQ_N())
#define DE_NUM_ARG_(...) DE_NUM_ARG_N(__VA_ARGS__)
#define DE_NUM_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N

#define DE_CONCAT(x, y) x##y
#if !defined (_MSC_VER)
# define DE_UNUSED(...) DE_UNUSED_MANY(__VA_ARGS__, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
// Macro trick for determining number of arguments (up to 8).
# define DE_NUM_ARG(...) DE_NUM_ARG_(__VA_ARGS__, DE_NUM_ARG_RSEQ_N())
# define DE_NUM_ARG_(...) DE_NUM_ARG_N(__VA_ARGS__)
#else // _MSC_VER
# define DE_UNUSED_MANY_(args) DE_UNUSED_MANY args
# define DE_UNUSED(...) DE_UNUSED_MANY_((__VA_ARGS__, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
# define DE_NUM_ARG_(args) DE_NUM_ARG_N args
# define DE_NUM_ARG(...) DE_NUM_ARG_((__VA_ARGS__, DE_NUM_ARG_RSEQ_N()))
#endif

#define DE_PLURAL_S(Count) ((Count) != 1? "s" : "")

Expand Down Expand Up @@ -817,9 +825,10 @@ typedef size_t dsize; // Likely unsigned long.
#if defined (_MSC_VER)
typedef long long dsigsize;
#else
typedef ssize_t dsigsize;
typedef ssize_t dsigsize;
#endif
typedef long dlong;
typedef long dlong;
typedef unsigned int uint;

class DE_PUBLIC Char
{
Expand Down
6 changes: 3 additions & 3 deletions doomsday/libs/core/src/c_wrapper.cpp
Expand Up @@ -266,7 +266,7 @@ int Info_FindValue(de_Info *info, char const *path, char *buffer, size_t bufSize
de::String value = static_cast<de::Info::KeyElement const *>(element)->value();
if (buffer)
{
strncpy(buffer, value, uint(bufSize));
strncpy(buffer, value, bufSize);
return true;
}
else
Expand All @@ -286,15 +286,15 @@ char *UnixInfo_GetConfigValue(char const *configFile, char const *key)
de::NativePath foundValue;
if (info.path(key, foundValue))
{
return strdup(foundValue);
return iDupStr(foundValue);
}
}
else if (!iCmpStr(configFile, "defaults"))
{
de::String foundValue;
if (info.defaults(key, foundValue))
{
return strdup(foundValue);
return iDupStr(foundValue);
}
}
return nullptr;
Expand Down
6 changes: 4 additions & 2 deletions doomsday/libs/core/src/core/app.cpp
Expand Up @@ -668,15 +668,17 @@ NativePath App::currentWorkPath()

NativePath App::tempPath()
{
NativePath sysTemp;
#if defined (WIN32)
{
DE_ASSERT_FAIL("tempPath not implemented");
sysTemp = NativePath::homePath() / "AppData\\Local\\Temp";
}
#else
{
return Stringf("/tmp/%s-%i", app().reverseDomainIdentifier().c_str(), pid_Process(nullptr));
sysTemp = "/tmp";
}
#endif
return sysTemp / Stringf("%s-%i", app().reverseDomainIdentifier().c_str(), pid_Process(nullptr));
}

NativePath App::cachePath()
Expand Down
4 changes: 2 additions & 2 deletions doomsday/libs/core/src/core/commandline.cpp
Expand Up @@ -36,7 +36,7 @@ namespace de {

static char *duplicateStringAsUtf8(String const &s)
{
return strdup(s);
return iDupStr(s);
}

DE_PIMPL(CommandLine)
Expand Down Expand Up @@ -229,7 +229,7 @@ CommandLine::ArgWithParams CommandLine::check(String const &arg, dint numParams)
found.params.append(*k);
}

found.pos = i - d->arguments.begin();
found.pos = dint(i - d->arguments.begin());
return found;
}

Expand Down
3 changes: 2 additions & 1 deletion doomsday/libs/core/src/core/timer.cpp
Expand Up @@ -23,6 +23,7 @@

#include <chrono>
#include <queue>
#include <atomic>

namespace sc = std::chrono;

Expand Down Expand Up @@ -135,7 +136,7 @@ struct TimerScheduler : public Thread, public Lockable
};

static LockableT<TimerScheduler *> scheduler;
static atomic_int timerCount; // Number of timers in existence.
static std::atomic_int timerCount; // Number of timers in existence.

} // namespace internal

Expand Down
3 changes: 2 additions & 1 deletion doomsday/libs/core/src/data/bytesubarray.cpp
Expand Up @@ -18,6 +18,7 @@
*/

#include "de/ByteSubArray"
#include "de/math.h"

namespace de {

Expand Down Expand Up @@ -51,7 +52,7 @@ void ByteSubArray::set(Offset at, Byte const *values, Size count)
throw NonModifiableError("ByteSubArray::set", "Array is non-modifiable.");
}
_mainArray->set(_at + at, values, count);
_size = std::max(_size, at + count);
_size = de::max(_size, at + count);
}

} // namespace de
2 changes: 1 addition & 1 deletion doomsday/libs/core/src/data/cstring.cpp
Expand Up @@ -61,7 +61,7 @@ dsize CString::indexOf(char ch, size_t from) const
dsize CString::indexOf(const char *cStr, size_t from) const
{
if (from >= size_t(_range.size())) return npos;
const char *pos = strnstr(_range.start + from, cStr, _range.size() - from);
const char *pos = iStrStrN(_range.start + from, cStr, _range.size() - from);
return pos ? (pos - _range.start) : npos;
}

Expand Down
14 changes: 7 additions & 7 deletions doomsday/libs/core/src/data/numbervalue.cpp
Expand Up @@ -32,31 +32,31 @@ const NumberValue NumberValue::bTrue(true);
const NumberValue NumberValue::bFalse(false);

NumberValue::NumberValue(Number initialValue, SemanticHints semantic)
: _value(initialValue), _semantic(semantic)
: _value(Number(initialValue)), _semantic(semantic)
{}

NumberValue::NumberValue(dint64 initialInteger)
: _value(initialInteger), _semantic(Int)
: _value(Number(initialInteger)), _semantic(Int)
{}

NumberValue::NumberValue(duint64 initialUnsignedInteger)
: _value(initialUnsignedInteger), _semantic(UInt)
: _value(Number(initialUnsignedInteger)), _semantic(UInt)
{}

NumberValue::NumberValue(dint32 initialInteger, SemanticHints semantic)
: _value(initialInteger), _semantic(semantic)
: _value(Number(initialInteger)), _semantic(semantic)
{}

NumberValue::NumberValue(duint32 initialUnsignedInteger, SemanticHints semantic)
: _value(initialUnsignedInteger), _semantic(semantic)
: _value(Number(initialUnsignedInteger)), _semantic(semantic)
{}

NumberValue::NumberValue(unsigned long initialUnsignedInteger, SemanticHints semantic)
: _value(initialUnsignedInteger), _semantic(semantic)
: _value(Number(initialUnsignedInteger)), _semantic(semantic)
{}

NumberValue::NumberValue(bool initialBoolean)
: _value(initialBoolean? True : False), _semantic(Boolean)
: _value(initialBoolean ? True : False), _semantic(Boolean)
{}

void NumberValue::setSemanticHints(SemanticHints hints)
Expand Down
4 changes: 4 additions & 0 deletions doomsday/libs/core/src/data/ziparchive.cpp
Expand Up @@ -38,6 +38,10 @@
#include <cstring>
#include <zlib.h>

#ifdef max
# undef max
#endif

namespace de {
namespace internal {

Expand Down
8 changes: 4 additions & 4 deletions doomsday/libs/core/src/legacy/findfile_windows.cpp
Expand Up @@ -26,8 +26,8 @@
#include <string>
#include <de/String>

#include "de/memory.h"
#include "de/findfile.h"
#include "de/legacy/memory.h"
#include "de/legacy/findfile.h"

typedef struct winfinddata_s {
struct _wfinddata_t data;
Expand All @@ -40,7 +40,7 @@ static void setdata(FindData *dta)
dta->date = fd->data.time_write;
dta->time = fd->data.time_write;
dta->size = fd->data.size;
Str_Set(&dta->name, QString::fromWCharArray(fd->data.name).toUtf8());
Str_Set(&dta->name, de::String(fd->data.name));
Str_ReplaceAll(&dta->name, '\\', '/');
dta->attrib = 0;
if (fd->data.attrib & _A_SUBDIR)
Expand All @@ -63,7 +63,7 @@ int FindFile_FindFirst(FindData *dta, char const *filenameUtf8)
Str_InitStd(&dta->name);

// Begin the search.
fd->handle = _wfindfirst(de::String(filenameUtf8).toStdWString().c_str(), &fd->data);
fd->handle = _wfindfirst(de::String(filenameUtf8).toWideString().c_str(), &fd->data);

setdata(dta);
return (fd->handle == (long) (-1));
Expand Down

0 comments on commit f6a41e4

Please sign in to comment.