Fix Unicode support on Windows, minor Windows tweaks #304

Merged
easyaspi314 merged 9 commits from unicode-windows-fixes into dev 2020-02-24 11:55:48 -06:00
easyaspi314 commented 2020-02-12 19:47:24 -06:00 (Migrated from github.com)
  • Unicode filenames should now work, with a method that works with and without Unicode mode on Windows.
    • Added a test in the Makefile.
  • Use unbuffered stderr output on Windows, fixes output not updating immediately on MinGW.
  • Fix some missing $(EXT)s in the Makefile, causing Clang to emit xxhsum instead of xxhsum.exe on Windows, as well as xxhsum's rule ignoring $(FLAGS).
- Unicode filenames should now work, with a method that works with and without Unicode mode on Windows. - Added a test in the Makefile. - Use unbuffered stderr output on Windows, fixes output not updating immediately on MinGW. - Fix some missing `$(EXT)`s in the Makefile, causing Clang to emit `xxhsum` instead of `xxhsum.exe` on Windows, as well as xxhsum's rule ignoring `$(FLAGS)`.
easyaspi314 commented 2020-02-12 19:49:45 -06:00 (Migrated from github.com)

This should fix #293.

This should fix #293.
Cyan4973 (Migrated from github.com) reviewed 2020-02-12 19:51:37 -06:00
@ -76,20 +76,22 @@ default: lib xxhsum_and_links
all: lib xxhsum xxhsum_inlinedXXH
xxhsum: xxhash.o xxhsum.o ## generate command line interface (CLI)
$(CC) $(FLAGS) $^ $(LDFLAGS) -o $@$(EXT)
Cyan4973 (Migrated from github.com) commented 2020-02-12 19:51:37 -06:00

minor : isn't this rule implied ?

minor : isn't this rule implied ?
Cyan4973 (Migrated from github.com) reviewed 2020-02-12 19:52:13 -06:00
Cyan4973 (Migrated from github.com) commented 2020-02-12 19:52:13 -06:00

nit : .PHONY

nit : `.PHONY`
easyaspi314 (Migrated from github.com) reviewed 2020-02-12 19:53:42 -06:00
@ -76,20 +76,22 @@ default: lib xxhsum_and_links
all: lib xxhsum xxhsum_inlinedXXH
xxhsum: xxhash.o xxhsum.o ## generate command line interface (CLI)
$(CC) $(FLAGS) $^ $(LDFLAGS) -o $@$(EXT)
easyaspi314 (Migrated from github.com) commented 2020-02-12 19:53:42 -06:00

Not the FLAGS/CFLAGS part. Make defines it as the following:

    $(CC) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS)
Not the FLAGS/CFLAGS part. Make defines it as the following: ```makefile $(CC) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS) ```
easyaspi314 (Migrated from github.com) reviewed 2020-02-12 19:53:57 -06:00
easyaspi314 (Migrated from github.com) commented 2020-02-12 19:53:56 -06:00

oof

oof
Cyan4973 (Migrated from github.com) reviewed 2020-02-12 19:56:08 -06:00
@ -285,11 +290,11 @@ test: all namespaceTest check test-xxhsum-c c90test test-tools
.PHONY: test-inline
Cyan4973 (Migrated from github.com) commented 2020-02-12 19:56:08 -06:00

How will the test itself behave on systems which do not support unicode (if they exist) ?

If there are risks, and this test should rather be reserved to a few "good enough" environments, such as Windows, and I assume Linux and OS-X, then it should rather belong to test-all category.
make test is reserved for tests which are supposed to be "reasonably" universal

How will the test itself behave on systems which do not support unicode (if they exist) ? If there are risks, and this test should rather be reserved to a few "good enough" environments, such as Windows, and I assume Linux and OS-X, then it should rather belong to `test-all` category. `make test` is reserved for tests which are supposed to be "reasonably" universal
easyaspi314 (Migrated from github.com) reviewed 2020-02-12 19:57:32 -06:00
@ -285,11 +290,11 @@ test: all namespaceTest check test-xxhsum-c c90test test-tools
.PHONY: test-inline
easyaspi314 (Migrated from github.com) commented 2020-02-12 19:57:32 -06:00

Fair point. I'll move it.

Fair point. I'll move it.
easyaspi314 (Migrated from github.com) reviewed 2020-02-12 20:03:33 -06:00
@ -76,20 +76,22 @@ default: lib xxhsum_and_links
all: lib xxhsum xxhsum_inlinedXXH
xxhsum: xxhash.o xxhsum.o ## generate command line interface (CLI)
$(CC) $(FLAGS) $^ $(LDFLAGS) -o $@$(EXT)
easyaspi314 (Migrated from github.com) commented 2020-02-12 20:03:32 -06:00

So, for example, if you did this:

make CFLAGS="-m32 -O3"

GCC would fail at the link step due to expecting 64-bit object files

So, for example, if you did this: ``` make CFLAGS="-m32 -O3" ``` GCC would fail at the link step due to expecting 64-bit object files
easyaspi314 commented 2020-02-12 20:18:36 -06:00 (Migrated from github.com)

Hmmmm.... some interesting errors here...

Hmmmm.... some interesting errors here...
easyaspi314 commented 2020-02-12 20:34:16 -06:00 (Migrated from github.com)
Warning: corrupt .drectve at end of def file
xxhsum.o:xxhsum.c:(.text[fprintf]+0x38): undefined reference to `__stdio_common_vfprintf'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [Makefile:79: xxhsum] Error 1

Um.....

```c Warning: corrupt .drectve at end of def file xxhsum.o:xxhsum.c:(.text[fprintf]+0x38): undefined reference to `__stdio_common_vfprintf' clang: error: linker command failed with exit code 1 (use -v to see invocation) make: *** [Makefile:79: xxhsum] Error 1 ``` Um.....
easyaspi314 commented 2020-02-12 20:57:07 -06:00 (Migrated from github.com)

Got classic MinGW to work by changing _wfopen_s to _wfopen

s u c h   u n i c o d e

everything is fine

(It is actually an encoding issue on the terminal's side, it defaults to OEM encoding instead of UTF-8. The hash value is correct).

Got classic MinGW to work by changing `_wfopen_s` to `_wfopen` <img width="518" alt="s u c h u n i c o d e" src="https://user-images.githubusercontent.com/6258309/74397093-ea2cb400-4de1-11ea-858f-42c11ec88b36.png"/> `everything is fine` (It is actually an encoding issue on the terminal's side, it defaults to OEM encoding instead of UTF-8. The hash value is correct).
easyaspi314 commented 2020-02-12 22:15:52 -06:00 (Migrated from github.com)

Classic MinGW doesn't even like Unicode text at all:

$ /c/Windows/System32/chcp.com 65001
Active code page: 65001

$ cat Makefile
....
# Make sure that Unicode works.
# https://github.com/Cyan4973/xxHash/issues/293
# Japanese: echo "This filename is Unicode." > "Unicode.txt"
.PHONY: test-unicode
test-unicode: xxhsum check
        # Test Unicode filenames.
        cat: write error: Permission denied

However, there is no way to tell the old MinGW from the new MinGW-w32 AFAIK, and the exe works in the correct console mode.

Will investigate more tomorrow.

Classic MinGW doesn't even like Unicode text at all: ``` $ /c/Windows/System32/chcp.com 65001 Active code page: 65001 $ cat Makefile .... # Make sure that Unicode works. # https://github.com/Cyan4973/xxHash/issues/293 # Japanese: echo "This filename is Unicode." > "Unicode.txt" .PHONY: test-unicode test-unicode: xxhsum check # Test Unicode filenames. cat: write error: Permission denied ``` However, there is no way to tell the old MinGW from the new MinGW-w32 AFAIK, and the exe works in the correct console mode. Will investigate more tomorrow.
easyaspi314 commented 2020-02-13 12:25:27 -06:00 (Migrated from github.com)

Maybe we should move the Unicode to a separate file. Or generate it on the fly, like so:

#include <stdio.h>

/* "Unicode.txt" in Japanese */
#define FILENAME "\u30e6\u306b\u30b3\u30fc\u30c9.txt"
#define WSTR(x) L##x
int main(void)
{
    FILE *f, *script;
#ifdef _WIN32
    if (!(f = _wfopen(WSTR(FILENAME), L"wb"))) return 1;
    if (!(script = fopen("unicode_test.bat", "w"))) {
        fclose(f);
        return 1;
    }
    fprintf(script, "@ECHO OFF\n");
    fprintf(script, "\"..\\xxhsum.exe\" \"%s\"\n", FILENAME);
    fprintf(script, "SET /A EXITCODE=%%ERRORLEVEL%%\n");
    fprintf(script, "RM \"%s\"\n", FILENAME);
    fprintf(script, "EXIT /B %%EXITCODE%%\n");
#else
    if (!(f = fopen(FILENAME, "wb"))) return 1;
    if (!(script = fopen("unicode_test.sh", "w"))) {
        fclose(f);
        return 1;
    }
    fprintf(script, "#!/bin/sh\n");
    fprintf(script, "\"../xxhsum\" \"%s\"\n", FILENAME);
    fprintf(script, "EXITCODE=\"$?\"\n");
    fprintf(script, "rm -f \"%s\"\n", FILENAME);
    fprintf(script, "exit $EXITCODE\n");
#endif
    fprintf(f, "test\n");

    fclose(f);
    fclose(script);
}

Just theory-crafting here, it is untested.

Maybe we should move the Unicode to a separate file. Or generate it on the fly, like so: ```c #include <stdio.h> /* "Unicode.txt" in Japanese */ #define FILENAME "\u30e6\u306b\u30b3\u30fc\u30c9.txt" #define WSTR(x) L##x int main(void) { FILE *f, *script; #ifdef _WIN32 if (!(f = _wfopen(WSTR(FILENAME), L"wb"))) return 1; if (!(script = fopen("unicode_test.bat", "w"))) { fclose(f); return 1; } fprintf(script, "@ECHO OFF\n"); fprintf(script, "\"..\\xxhsum.exe\" \"%s\"\n", FILENAME); fprintf(script, "SET /A EXITCODE=%%ERRORLEVEL%%\n"); fprintf(script, "RM \"%s\"\n", FILENAME); fprintf(script, "EXIT /B %%EXITCODE%%\n"); #else if (!(f = fopen(FILENAME, "wb"))) return 1; if (!(script = fopen("unicode_test.sh", "w"))) { fclose(f); return 1; } fprintf(script, "#!/bin/sh\n"); fprintf(script, "\"../xxhsum\" \"%s\"\n", FILENAME); fprintf(script, "EXITCODE=\"$?\"\n"); fprintf(script, "rm -f \"%s\"\n", FILENAME); fprintf(script, "exit $EXITCODE\n"); #endif fprintf(f, "test\n"); fclose(f); fclose(script); } ``` Just theory-crafting here, it is untested.
Cyan4973 commented 2020-02-13 14:33:22 -06:00 (Migrated from github.com)

We could probably get the same effect without a need for a separate file, just with some #ifdef macro magic.

We could probably get the same effect without a need for a separate file, just with some `#ifdef` macro magic.
easyaspi314 commented 2020-02-13 15:18:44 -06:00 (Migrated from github.com)

The main problem is that some programs and terminals flip out when they encounter Unicode text.

This seems to work well:

/*
 * Generates a Unicode test while keeping the source tree and terminal
 * output entirely ASCII.
 *
 * Certain terminals don't properly handle UTF-8 (i.e. rxvt and command prompt
 * in the default codepage), and that can cause issues.
 *
 * We use this C file to generate a file with a Unicode filename, a
 * file with a checksum of said file, and both a Windows batch script
 * and a Unix shell script to test the file.
 */

#define _CRT_SECURE_NO_WARNINGS /* Silence warnings on MSVC */
#include <stdio.h>

/* Use a Japanese filename, something that can't be encoded in ANSI.
 * yuniko-do.unicode (literally Unicode.unicode) */

/* Use raw hex values to ensure that the output is well-formed UTF-8. It is also C90 compliant. */
static const char FILENAME[] = {
    (char)0xe3, (char)0x83, (char)0xa6,  /* U+30e6: Katakana letter yu */
    (char)0xe3, (char)0x83, (char)0x8b,  /* U+30cb: Katakana letter ni */
    (char)0xe3, (char)0x82, (char)0xb3,  /* U+30b3: Katakana letter ko */
    (char)0xe3, (char)0x83, (char)0xbc,  /* U+30fc: Katakana-Hiragana prolonged sound mark (dash) */
    (char)0xe3, (char)0x83, (char)0x89,  /* U+30c9: Katakana letter do */
    '.','u','n','i','c','o','d','e','\0' /* ".unicode" (so we can glob in make clean and .gitignore) */
};

#ifdef _WIN32
/* The same text as above, but encoded in Windows UTF-16 for _wfopen. */
static const wchar_t WFILENAME[] = { 0x30e6, 0x30cb, 0x30b3, 0x30fc, 0x30c9, L'.', L'u', L'n', L'i', L'c', L'o', L'd', L'e', L'\0' };
#endif

int main(void)
{
    FILE *f, *script, *checksum;

    /* Create our Unicode file. Use _wfopen on Windows as fopen doesn't support Unicode filenames. */
#ifdef _WIN32
    if (!(f = _wfopen(WFILENAME, L"wb")))
        return 1;
#else
    if (!(f = fopen(FILENAME, "wb")))
        return 1;
#endif
    fprintf(f, "test\n");
    fclose(f);

    /* XXH64 checksum file with the precalculated checksum for said file. */
    if (!(checksum = fopen("unicode_test.xxh64", "wb")))
        return 1;
    fprintf(checksum, "2d7f1808da1fa63c  %s\n", FILENAME);
    fclose(checksum);


    /* Create two scripts for both Windows and Unix. */

    /* Generate a Windows batch script. Always insert CRLF manually. */
    if (!(script = fopen("unicode_test.bat", "wb")))
        return 1;

    /* Hide the commands */
    fprintf(script, "@ECHO OFF >NUL\r\n");

    /* Change to codepage 65001 for UTF-8. */
    fprintf(script, "chcp 65001 >NUL 2>&1\r\n");

    /* First test a Unicode filename */
    fprintf(script, "xxhsum.exe \"%s\" >NUL 2>&1\r\n", FILENAME);
    fprintf(script, "SET /A EXITCODE=%%ERRORLEVEL%%\r\n");

    /* If we can support Unicode filenames, test the -c option. */
    fprintf(script, "IF %%EXITCODE%% EQU 0 (\r\n");
    fprintf(script, "    xxhsum.exe -c -q unicode_test.xxh64 >NUL 2>&1\r\n");
    fprintf(script, "    SET /A EXITCODE=%%ERRORLEVEL%%\r\n");
    fprintf(script, ")\r\n");

    /* Delete the Unicode file and the checksum */
    fprintf(script, "DEL /F \"%s\" >NUL 2>&1\r\n", FILENAME);
    fprintf(script, "DEL /F unicode_test.xxh64 >NUL 2>&1\r\n");

    /* Print "Unicode test failed!" to stderr if there was an error. */
    fprintf(script, "IF %%EXITCODE%% NEQ 0 (\r\n");
    fprintf(script, "    ECHO Unicode test failed! >&2\r\n");
    fprintf(script, ")\r\n");

    /* Exit with the error code */
    fprintf(script, "EXIT /B %%EXITCODE%%\r\n");
    fclose(script);

    /* Generate a Unix shell script */
    if (!(script = fopen("unicode_test.sh", "wb")))
        return 1;

    fprintf(script, "#!/bin/sh\n");
    /*
     * Some versions of MSYS, MinGW and Cygwin do not support UTF-8, and the ones that
     * don't may error with something like this:
     *
     *    Error: Could not open '<mojibake>.unicode': No such file or directory.
     *
     * which is an internal error that happens when it tries to convert MinGW/Cygwin
     * paths to Windows paths.
     *
     * In that case, we bail to cmd.exe and the batch script, which supports UTF-8
     * on Windows 7 and later.
     */
    fprintf(script, "case $(uname) in\n");
    fprintf(script, "    *MINGW*|*CYGWIN*|*MSYS*|*WINDOWS*|*NT*)\n");
    fprintf(script, "        exec cmd.exe //c unicode_test.bat\n");
    fprintf(script, "        ;;\n");
    fprintf(script, "esac\n");

    /* First test a Unicode filename */
    fprintf(script, "./xxhsum \"%s\" 2>&1 >/dev/null\n", FILENAME);
    fprintf(script, "EXITCODE=\"$?\"\n");

    /* If we can support Unicode filenames, test the -c option. */
    fprintf(script, "if [ $EXITCODE -eq 0 ]; then\n");
    fprintf(script, "    ./xxhsum -c -q unicode_test.xxh64 2>&1 >/dev/null\n");
    fprintf(script, "    EXITCODE=\"$?\"\n");
    fprintf(script, "fi\n");

    /* Delete the Unicode file and the checksum file. */
    fprintf(script, "rm -f \"%s\" 2>&1 >/dev/null\n", FILENAME);
    fprintf(script, "rm -f unicode_test.xxh64 2>&1 >/dev/null\n");

    /* Print "Unicode test failed!" to stderr if there was an error. */
    fprintf(script, "if [ $EXITCODE -ne 0 ]; then\n");
    fprintf(script, "    echo \"Unicode test failed!\" >&2\n");
    fprintf(script, "fi\n");

    /* Exit with the error code */
    fprintf(script, "exit $EXITCODE\n");

    fclose(script);

    return 0;
}
The main problem is that some programs and terminals flip out when they encounter Unicode text. This seems to work well: ```c /* * Generates a Unicode test while keeping the source tree and terminal * output entirely ASCII. * * Certain terminals don't properly handle UTF-8 (i.e. rxvt and command prompt * in the default codepage), and that can cause issues. * * We use this C file to generate a file with a Unicode filename, a * file with a checksum of said file, and both a Windows batch script * and a Unix shell script to test the file. */ #define _CRT_SECURE_NO_WARNINGS /* Silence warnings on MSVC */ #include <stdio.h> /* Use a Japanese filename, something that can't be encoded in ANSI. * yuniko-do.unicode (literally Unicode.unicode) */ /* Use raw hex values to ensure that the output is well-formed UTF-8. It is also C90 compliant. */ static const char FILENAME[] = { (char)0xe3, (char)0x83, (char)0xa6, /* U+30e6: Katakana letter yu */ (char)0xe3, (char)0x83, (char)0x8b, /* U+30cb: Katakana letter ni */ (char)0xe3, (char)0x82, (char)0xb3, /* U+30b3: Katakana letter ko */ (char)0xe3, (char)0x83, (char)0xbc, /* U+30fc: Katakana-Hiragana prolonged sound mark (dash) */ (char)0xe3, (char)0x83, (char)0x89, /* U+30c9: Katakana letter do */ '.','u','n','i','c','o','d','e','\0' /* ".unicode" (so we can glob in make clean and .gitignore) */ }; #ifdef _WIN32 /* The same text as above, but encoded in Windows UTF-16 for _wfopen. */ static const wchar_t WFILENAME[] = { 0x30e6, 0x30cb, 0x30b3, 0x30fc, 0x30c9, L'.', L'u', L'n', L'i', L'c', L'o', L'd', L'e', L'\0' }; #endif int main(void) { FILE *f, *script, *checksum; /* Create our Unicode file. Use _wfopen on Windows as fopen doesn't support Unicode filenames. */ #ifdef _WIN32 if (!(f = _wfopen(WFILENAME, L"wb"))) return 1; #else if (!(f = fopen(FILENAME, "wb"))) return 1; #endif fprintf(f, "test\n"); fclose(f); /* XXH64 checksum file with the precalculated checksum for said file. */ if (!(checksum = fopen("unicode_test.xxh64", "wb"))) return 1; fprintf(checksum, "2d7f1808da1fa63c %s\n", FILENAME); fclose(checksum); /* Create two scripts for both Windows and Unix. */ /* Generate a Windows batch script. Always insert CRLF manually. */ if (!(script = fopen("unicode_test.bat", "wb"))) return 1; /* Hide the commands */ fprintf(script, "@ECHO OFF >NUL\r\n"); /* Change to codepage 65001 for UTF-8. */ fprintf(script, "chcp 65001 >NUL 2>&1\r\n"); /* First test a Unicode filename */ fprintf(script, "xxhsum.exe \"%s\" >NUL 2>&1\r\n", FILENAME); fprintf(script, "SET /A EXITCODE=%%ERRORLEVEL%%\r\n"); /* If we can support Unicode filenames, test the -c option. */ fprintf(script, "IF %%EXITCODE%% EQU 0 (\r\n"); fprintf(script, " xxhsum.exe -c -q unicode_test.xxh64 >NUL 2>&1\r\n"); fprintf(script, " SET /A EXITCODE=%%ERRORLEVEL%%\r\n"); fprintf(script, ")\r\n"); /* Delete the Unicode file and the checksum */ fprintf(script, "DEL /F \"%s\" >NUL 2>&1\r\n", FILENAME); fprintf(script, "DEL /F unicode_test.xxh64 >NUL 2>&1\r\n"); /* Print "Unicode test failed!" to stderr if there was an error. */ fprintf(script, "IF %%EXITCODE%% NEQ 0 (\r\n"); fprintf(script, " ECHO Unicode test failed! >&2\r\n"); fprintf(script, ")\r\n"); /* Exit with the error code */ fprintf(script, "EXIT /B %%EXITCODE%%\r\n"); fclose(script); /* Generate a Unix shell script */ if (!(script = fopen("unicode_test.sh", "wb"))) return 1; fprintf(script, "#!/bin/sh\n"); /* * Some versions of MSYS, MinGW and Cygwin do not support UTF-8, and the ones that * don't may error with something like this: * * Error: Could not open '<mojibake>.unicode': No such file or directory. * * which is an internal error that happens when it tries to convert MinGW/Cygwin * paths to Windows paths. * * In that case, we bail to cmd.exe and the batch script, which supports UTF-8 * on Windows 7 and later. */ fprintf(script, "case $(uname) in\n"); fprintf(script, " *MINGW*|*CYGWIN*|*MSYS*|*WINDOWS*|*NT*)\n"); fprintf(script, " exec cmd.exe //c unicode_test.bat\n"); fprintf(script, " ;;\n"); fprintf(script, "esac\n"); /* First test a Unicode filename */ fprintf(script, "./xxhsum \"%s\" 2>&1 >/dev/null\n", FILENAME); fprintf(script, "EXITCODE=\"$?\"\n"); /* If we can support Unicode filenames, test the -c option. */ fprintf(script, "if [ $EXITCODE -eq 0 ]; then\n"); fprintf(script, " ./xxhsum -c -q unicode_test.xxh64 2>&1 >/dev/null\n"); fprintf(script, " EXITCODE=\"$?\"\n"); fprintf(script, "fi\n"); /* Delete the Unicode file and the checksum file. */ fprintf(script, "rm -f \"%s\" 2>&1 >/dev/null\n", FILENAME); fprintf(script, "rm -f unicode_test.xxh64 2>&1 >/dev/null\n"); /* Print "Unicode test failed!" to stderr if there was an error. */ fprintf(script, "if [ $EXITCODE -ne 0 ]; then\n"); fprintf(script, " echo \"Unicode test failed!\" >&2\n"); fprintf(script, "fi\n"); /* Exit with the error code */ fprintf(script, "exit $EXITCODE\n"); fclose(script); return 0; } ```
easyaspi314 commented 2020-02-14 18:08:35 -06:00 (Migrated from github.com)

Actually this is too complex. I'm going to just check $LANG for UTF-8 and skip the test if it isn't found.

That way you can see the output.

Actually this is too complex. I'm going to just check `$LANG` for `UTF-8` and skip the test if it isn't found. That way you can see the output.
easyaspi314 commented 2020-02-14 18:46:45 -06:00 (Migrated from github.com)

Oh, I get it why Clang is failing. It has to do with the new Makefile rules.

The MOREFLAGS=--target=x86_64-w64-mingw32 flag was being applied to the .exe but not to the object files, and Clang was trying to link MSVC object files as MinGW object files.

Oh, I get it why Clang is failing. It has to do with the new Makefile rules. The `MOREFLAGS=--target=x86_64-w64-mingw32` flag was being applied to the .exe but not to the object files, and Clang was trying to link MSVC object files as MinGW object files.
easyaspi314 commented 2020-02-18 20:33:28 -06:00 (Migrated from github.com)

@Cyan4973 thoughts? I believe it is ready to merge.

@Cyan4973 thoughts? I believe it is ready to merge.
Cyan4973 (Migrated from github.com) approved these changes 2020-02-24 11:55:15 -06:00
Cyan4973 commented 2020-02-24 11:55:43 -06:00 (Migrated from github.com)

Great work @easyaspi314 !

Great work @easyaspi314 !
Sign in to join this conversation.
No description provided.