Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
mariadb
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
mariadb
Commits
366ee3c7
Commit
366ee3c7
authored
Jan 30, 2011
by
Vladislav Vaintroub
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Move common functionality (analyze service configuration) into winservice library
parent
e353bc80
Changes
8
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
70 additions
and
176 deletions
+70
-176
sql/CMakeLists.txt
sql/CMakeLists.txt
+4
-1
sql/Makefile.am
sql/Makefile.am
+1
-0
sql/mysql_upgrade_service.cc
sql/mysql_upgrade_service.cc
+23
-49
win/packaging/CMakeLists.txt
win/packaging/CMakeLists.txt
+1
-0
win/packaging/ca/CMakeLists.txt
win/packaging/ca/CMakeLists.txt
+2
-1
win/packaging/ca/CustomAction.cpp
win/packaging/ca/CustomAction.cpp
+3
-45
win/upgrade_wizard/CMakeLists.txt
win/upgrade_wizard/CMakeLists.txt
+4
-2
win/upgrade_wizard/upgradeDlg.cpp
win/upgrade_wizard/upgradeDlg.cpp
+32
-78
No files found.
sql/CMakeLists.txt
View file @
366ee3c7
...
...
@@ -186,10 +186,13 @@ ADD_CUSTOM_COMMAND(
COMPONENT Server
)
TARGET_LINK_LIBRARIES
(
mysql_install_db mysys strings dbug
)
ADD_LIBRARY
(
winservice STATIC winservice.c
)
MYSQL_ADD_EXECUTABLE
(
mysql_upgrade_service
mysql_upgrade_service.cc
COMPONENT Server
)
TARGET_LINK_LIBRARIES
(
mysql_upgrade_service mysys strings dbug
)
TARGET_LINK_LIBRARIES
(
mysql_upgrade_service mysys strings dbug winservice
)
# mysql_install_db should be in the same directory as mysqld
# to work correctly
...
...
sql/Makefile.am
View file @
366ee3c7
...
...
@@ -153,6 +153,7 @@ BUILT_SOURCES = $(BUILT_MAINT_SRC) lex_hash.h link_sources
EXTRA_DIST
=
udf_example.c udf_example.def
$(BUILT_MAINT_SRC)
\
nt_servc.cc nt_servc.h mysql_install_db.cc mysql_upgrade_service.cc
\
message.mc message.h message.rc MSG00001.bin
\
winservice.c winservice.h
CMakeLists.txt
CLEANFILES
=
lex_hash.h sql_yacc.output link_sources
...
...
sql/mysql_upgrade_service.cc
View file @
366ee3c7
...
...
@@ -26,6 +26,7 @@
#include <my_sys.h>
#include <m_string.h>
#include <mysql_version.h>
#include <winservice.h>
#include <stdlib.h>
#include <stdio.h>
...
...
@@ -38,8 +39,8 @@ static char mysqld_path[MAX_PATH];
static
char
mysqladmin_path
[
MAX_PATH
];
static
char
mysqlupgrade_path
[
MAX_PATH
];
static
char
defaults_file_param
[
FN_REFLEN
];
static
char
logfile_path
[
FN_REFLEN
];
static
char
defaults_file_param
[
MAX_PATH
+
16
];
/*--defaults-file=<path> */
static
char
logfile_path
[
MAX_PATH
];
static
char
*
opt_service
;
static
SC_HANDLE
service
;
static
SC_HANDLE
scm
;
...
...
@@ -301,7 +302,7 @@ end:
/*
Shutdown mysql server. Not using mysqladmin, since
our --skip-grant-tables do not work anymore after mysql_upgrade
that does "flush privileges". Instead, the shutdown
handle
is set.
that does "flush privileges". Instead, the shutdown
event
is set.
*/
void
initiate_mysqld_shutdown
()
{
...
...
@@ -327,8 +328,7 @@ void initiate_mysqld_shutdown()
*/
static
void
change_service_config
()
{
wchar_t
old_mysqld_path
[
MAX_PATH
];
wchar_t
*
file_part
;
char
defaults_file
[
MAX_PATH
];
char
default_character_set
[
64
];
...
...
@@ -346,59 +346,32 @@ static void change_service_config()
if
(
!
QueryServiceConfigW
(
service
,
config
,
size
,
&
needed
))
die
(
"QueryServiceConfig failed with %d
\n
"
,
GetLastError
());
int
numargs
;
LPWSTR
*
args
=
CommandLineToArgvW
(
config
->
lpBinaryPathName
,
&
numargs
);
char
commandline
[
3
*
FN_REFLEN
+
32
];
/* Run some checks to ensure we're really upgrading mysql service */
if
(
numargs
!=
3
)
{
die
(
"Expected 3 parameters in service configuration binPath,"
"got %d parameters instead
\n
. binPath: %S"
,
numargs
,
config
->
lpBinaryPathName
);
}
if
(
wcsncmp
(
args
[
1
],
L"--defaults-file="
,
16
)
!=
0
)
{
die
(
"Unexpected service configuration, second parameter must start with "
"--defaults-file. binPath= %S"
,
config
->
lpBinaryPathName
);
}
GetFullPathNameW
(
args
[
0
],
MAX_PATH
,
old_mysqld_path
,
&
file_part
);
if
(
wcsicmp
(
file_part
,
L"mysqld.exe"
)
!=
0
&&
wcsicmp
(
file_part
,
L"mysqld"
)
!=
0
)
mysqld_service_properties
props
;
if
(
get_mysql_service_properties
(
config
->
lpBinaryPathName
,
&
props
))
{
die
(
"The service executable is not mysqld. binPath: %S"
,
config
->
lpBinaryPathName
);
die
(
"Not a valid MySQL service"
);
}
if
(
wcsicmp
(
file_part
,
L"mysqld"
)
==
0
)
wcscat_s
(
old_mysqld_path
,
L".exe"
);
int
old_mysqld_major
,
old_mysqld_minor
;
get_file_version
(
old_mysqld_path
,
&
old_mysqld_major
,
&
old_mysqld_minor
);
int
my_major
=
MYSQL_VERSION_ID
/
10000
;
int
my_minor
=
(
MYSQL_VERSION_ID
-
10000
*
my_major
)
/
100
;
if
(
my_major
<
old_mysqld
_major
||
(
my_major
==
old_mysqld_major
&&
my_minor
<
old_mysqld_minor
))
if
(
my_major
<
props
.
version
_major
||
(
my_major
==
props
.
version_minor
&&
my_minor
<
props
.
version_patch
))
{
die
(
"Can not downgrade, the service is currently running as version %d.%d"
", my version is %d.%d"
,
old_mysqld_major
,
old_mysqld_minor
,
my_maj
or
,
my_minor
);
", my version is %d.%d"
,
props
.
version_major
,
props
.
version_min
or
,
my_m
ajor
,
my_m
inor
);
}
wcstombs
(
defaults_file
,
args
[
1
]
+
16
,
MAX_PATH
);
/*
Remove basedir from defaults file, otherwise the service wont come up in
the new version, and will complain about mismatched message file.
*/
WritePrivateProfileString
(
"mysqld"
,
"basedir"
,
NULL
,
defaults_
file
);
WritePrivateProfileString
(
"mysqld"
,
"basedir"
,
NULL
,
props
.
ini
file
);
#ifdef _WIN64
/* Currently, pbxt is non-functional on x64 */
WritePrivateProfileString
(
"mysqld"
,
"loose-skip-pbxt"
,
"1"
,
defaults_
file
);
WritePrivateProfileString
(
"mysqld"
,
"loose-skip-pbxt"
,
"1"
,
props
.
ini
file
);
#endif
/*
Replace default-character-set with character-set-server, to avoid
...
...
@@ -406,7 +379,7 @@ static void change_service_config()
message.
*/
default_character_set
[
0
]
=
0
;
GetPrivateProfileString
A
(
"mysqld"
,
"default-character-set"
,
NULL
,
GetPrivateProfileString
(
"mysqld"
,
"default-character-set"
,
NULL
,
default_character_set
,
sizeof
(
default_character_set
),
defaults_file
);
if
(
default_character_set
[
0
])
{
...
...
@@ -416,15 +389,16 @@ static void change_service_config()
default_character_set
,
defaults_file
);
}
sprintf_s
(
commandline
,
"
\"
%s
\"
\"
%S
\"
\"
%S
\"
"
,
mysqld_path
,
args
[
1
],
args
[
2
]);
sprintf
(
defaults_file_param
,
"--defaults-file=%s"
,
props
.
inifile
);
char
commandline
[
3
*
MAX_PATH
+
19
];
sprintf_s
(
commandline
,
"
\"
%s
\"
\"
%s
\"
\"
%s
\"
"
,
mysqld_path
,
defaults_file_param
,
opt_service
);
if
(
!
ChangeServiceConfig
(
service
,
SERVICE_NO_CHANGE
,
SERVICE_NO_CHANGE
,
SERVICE_NO_CHANGE
,
commandline
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
))
{
die
(
"ChangeServiceConfigW failed with %d"
,
GetLastError
());
}
sprintf_s
(
defaults_file_param
,
"%S"
,
args
[
1
]);
LocalFree
(
args
);
}
...
...
@@ -483,13 +457,13 @@ int main(int argc, char **argv)
for communication, for security reasons.
*/
char
socket_param
[
FN_REFLEN
];
sprintf_s
(
socket_param
,
"--s
hared_memory_base_name
=mysql_upgrade_service_%d"
,
sprintf_s
(
socket_param
,
"--s
ocket
=mysql_upgrade_service_%d"
,
GetCurrentProcessId
());
log
(
"Phase 3/8: Starting mysqld for upgrade"
);
mysqld_process
=
(
HANDLE
)
run_tool
(
P_NOWAIT
,
mysqld_path
,
defaults_file_param
,
"--skip-networking"
,
"--skip-grant-tables"
,
"--enable-
shared-memory
"
,
socket_param
,
NULL
);
"--enable-
named-pipe
"
,
socket_param
,
NULL
);
if
(
mysqld_process
==
INVALID_HANDLE_VALUE
)
{
...
...
@@ -503,7 +477,7 @@ int main(int argc, char **argv)
if
(
WaitForSingleObject
(
mysqld_process
,
0
)
!=
WAIT_TIMEOUT
)
die
(
"mysqld.exe did not start"
);
if
(
run_tool
(
P_WAIT
,
mysqladmin_path
,
"--protocol=
memory
"
,
if
(
run_tool
(
P_WAIT
,
mysqladmin_path
,
"--protocol=
pipe
"
,
socket_param
,
"ping"
,
NULL
)
==
0
)
{
break
;
...
...
@@ -516,7 +490,7 @@ int main(int argc, char **argv)
log
(
"Phase 5/8: Running mysql_upgrade"
);
int
upgrade_err
=
(
int
)
run_tool
(
P_WAIT
,
mysqlupgrade_path
,
"--protocol=
memory
"
,
"--force"
,
socket_param
,
"--protocol=
pipe
"
,
"--force"
,
socket_param
,
NULL
);
log
(
"Phase 6/8: Initiating server shutdown"
);
...
...
win/packaging/CMakeLists.txt
View file @
366ee3c7
...
...
@@ -23,6 +23,7 @@ FIND_PATH(WIX_DIR heat.exe
$ENV{ProgramFiles}/wix/bin
"$ENV{ProgramFiles}/Windows Installer XML v3/bin"
"$ENV{ProgramFiles}/Windows Installer XML v3.5/bin"
"$ENV{ProgramFiles}/Windows Installer XML v3.6/bin"
)
SET
(
CPACK_WIX_PACKAGE_BASE_NAME
"MariaDB"
)
...
...
win/packaging/ca/CMakeLists.txt
View file @
366ee3c7
...
...
@@ -18,6 +18,7 @@ LINK_DIRECTORIES(${WIX_DIR}/../SDK/lib)
SET
(
WIXCA_SOURCES CustomAction.cpp CustomAction.def
)
INCLUDE_DIRECTORIES
(
${
CMAKE_SOURCE_DIR
}
/sql
)
IF
(
CMAKE_SIZEOF_VOID_P EQUAL 8
)
SET
(
WIX_ARCH_SUFFIX
"_x64"
)
...
...
@@ -47,4 +48,4 @@ FIND_LIBRARY(WIX_DUTIL_LIBRARY
ADD_VERSION_INFO
(
wixca SHARED WIXCA_SOURCES
)
ADD_LIBRARY
(
wixca SHARED EXCLUDE_FROM_ALL
${
WIXCA_SOURCES
}
)
TARGET_LINK_LIBRARIES
(
wixca
${
WIX_WCAUTIL_LIBRARY
}
${
WIX_DUTIL_LIBRARY
}
msi version
)
msi version
winservice
)
win/packaging/ca/CustomAction.cpp
View file @
366ee3c7
...
...
@@ -27,6 +27,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <strsafe.h>
#include <assert.h>
#include <winservice.h>
UINT
ExecRemoveDataDirectory
(
wchar_t
*
dir
)
{
...
...
@@ -547,49 +548,6 @@ LExit:
return
WcaFinalize
(
er
);
}
/*
Extract major and minor version from
mysqld.exe, using commandline in service definition
*/
static
void
GetMySQLVersion
(
wchar_t
*
cmdline
,
wchar_t
*
programBuf
,
bool
*
isMySQL
,
int
*
major
,
int
*
minor
)
{
*
major
=
0
;
*
minor
=
0
;
*
isMySQL
=
false
;
int
argc
;
wchar_t
**
wargv
=
CommandLineToArgvW
(
cmdline
,
&
argc
);
if
(
argc
!=
3
)
return
;
wchar_t
path
[
MAX_PATH
];
wchar_t
*
filepart
;
wcscpy_s
(
programBuf
,
MAX_PATH
,
wargv
[
0
]);
if
(
!
wcsstr
(
programBuf
,
L".exe"
))
wcscat_s
(
programBuf
,
MAX_PATH
,
L".exe"
);
GetFullPathNameW
(
programBuf
,
MAX_PATH
,
path
,
&
filepart
);
if
(
wcsicmp
(
filepart
,
L"mysqld.exe"
)
==
0
)
{
*
isMySQL
=
true
;
DWORD
handle
;
DWORD
size
=
GetFileVersionInfoSizeW
(
path
,
&
handle
);
BYTE
*
versionInfo
=
new
BYTE
[
size
];
if
(
GetFileVersionInfo
(
path
,
handle
,
size
,
versionInfo
))
{
UINT
len
=
0
;
VS_FIXEDFILEINFO
*
vsfi
=
NULL
;
VerQueryValueW
(
versionInfo
,
L"
\\
"
,
(
void
**
)
&
vsfi
,
&
len
);
*
major
=
HIWORD
(
vsfi
->
dwFileVersionMS
);
*
minor
=
LOWORD
(
vsfi
->
dwFileVersionMS
);
}
delete
[]
versionInfo
;
}
}
/*
Enables/disables optional "Launch upgrade wizard" checkbox at the end of installation
...
...
@@ -603,7 +561,7 @@ extern "C" UINT __stdcall CheckServiceUpgrades(MSIHANDLE hInstall)
wchar_t
*
service
=
0
;
wchar_t
*
dir
=
0
;
wchar_t
installerVersion
[
MAX_VERSION_PROPERTY_SIZE
];
wchar_t
installDir
[
MAX_PATH
];
char
installDir
[
MAX_PATH
];
DWORD
size
=
MAX_VERSION_PROPERTY_SIZE
;
int
installerMajorVersion
,
installerMinorVersion
,
installerPatchVersion
;
bool
upgradableServiceFound
=
false
;
...
...
@@ -623,7 +581,7 @@ extern "C" UINT __stdcall CheckServiceUpgrades(MSIHANDLE hInstall)
}
size
=
MAX_PATH
;
if
(
MsiGetProperty
W
(
hInstall
,
L
"INSTALLDIR"
,
installDir
,
&
size
)
if
(
MsiGetProperty
A
(
hInstall
,
"INSTALLDIR"
,
installDir
,
&
size
)
!=
ERROR_SUCCESS
)
{
hr
=
HRESULT_FROM_WIN32
(
GetLastError
());
...
...
win/upgrade_wizard/CMakeLists.txt
View file @
366ee3c7
...
...
@@ -18,9 +18,11 @@ SET(CMAKE_MFC_FLAG 1)
# Enable exception handling (avoids warnings)
SET
(
CMAKE_CXX_FLAGS
"
${
CMAKE_CXX_FLAGS
}
/EHsc"
)
MYSQL_ADD_EXECUTABLE
(
upgrade_wizard upgrade.cpp upgradeDlg.cpp upgrade.rc
INCLUDE_DIRECTORIES
(
${
CMAKE_SOURCE_DIR
}
/sql
)
MYSQL_ADD_EXECUTABLE
(
upgrade_wizard
upgrade.cpp upgradeDlg.cpp upgrade.rc
COMPONENT Server
)
TARGET_LINK_LIBRARIES
(
upgrade_wizard winservice
)
# upgrade_wizard is Windows executable, set WIN32_EXECUTABLE so it does not
# create a console.
SET_TARGET_PROPERTIES
(
upgrade_wizard PROPERTIES WIN32_EXECUTABLE 1
)
...
...
win/upgrade_wizard/upgradeDlg.cpp
View file @
366ee3c7
...
...
@@ -14,6 +14,8 @@
#include <string>
#include <vector>
#include <winservice.h>
using
namespace
std
;
#ifdef _DEBUG
...
...
@@ -75,7 +77,7 @@ vector<ServiceProperties> services;
<unknown> , of executable does not have any version
info embedded (like MySQL 5.1 for example)
*/
string
GetExeVersion
(
const
string
&
filename
,
int
*
major
,
int
*
minor
,
int
*
patch
)
void
GetExeVersion
(
const
string
&
filename
,
int
*
major
,
int
*
minor
,
int
*
patch
)
{
DWORD
handle
;
*
major
=
*
minor
=
*
patch
=
0
;
...
...
@@ -85,20 +87,17 @@ string GetExeVersion(const string& filename, int *major, int *minor, int *patch)
if
(
!
GetFileVersionInfo
(
filename
.
c_str
(),
handle
,
size
,
versionInfo
))
{
delete
[]
versionInfo
;
return
"<unknown>"
;
return
;
}
// we have version information
UINT
len
=
0
;
VS_FIXEDFILEINFO
*
vsfi
=
NULL
;
VerQueryValue
(
versionInfo
,
"
\\
"
,
(
void
**
)
&
vsfi
,
&
len
);
char
arr
[
64
];
*
major
=
(
int
)
HIWORD
(
vsfi
->
dwFileVersionMS
);
*
minor
=
(
int
)
LOWORD
(
vsfi
->
dwFileVersionMS
);
*
patch
=
(
int
)
HIWORD
(
vsfi
->
dwFileVersionLS
);
sprintf_s
(
arr
,
"%d.%d.%d"
,
*
major
,
*
minor
,
*
patch
);
delete
[]
versionInfo
;
return
string
(
arr
);
}
...
...
@@ -122,19 +121,6 @@ void CUpgradeDlg::SelectService(int index)
}
/* Remove quotes from string */
static
char
*
RemoveQuotes
(
char
*
s
)
{
if
(
s
[
0
]
==
'"'
)
{
s
++
;
char
*
p
=
strchr
(
s
,
'"'
);
if
(
p
)
*
p
=
0
;
}
return
s
;
}
/*
Iterate over services, lookup for mysqld.exe ones.
...
...
@@ -157,8 +143,7 @@ void CUpgradeDlg::PopulateServicesList()
static
BYTE
buf
[
64
*
1024
];
static
BYTE
configBuffer
[
8
*
1024
];
char
datadirBuf
[
MAX_PATH
];
char
datadirNormalized
[
MAX_PATH
];
DWORD
bufsize
=
sizeof
(
buf
);
DWORD
bufneed
;
DWORD
num_services
;
...
...
@@ -184,71 +169,40 @@ void CUpgradeDlg::PopulateServicesList()
CloseServiceHandle
(
service
);
if
(
ok
)
{
int
argc
;
wchar_t
**
wargv
=
CommandLineToArgvW
(
config
->
lpBinaryPathName
,
&
argc
);
mysqld_service_properties
service_props
;
// We expect path\to\mysqld --defaults-file=<path> <servicename>
if
(
argc
==
3
)
{
if
(
get_mysql_service_properties
(
config
->
lpBinaryPathName
,
&
service_props
))
continue
;
// Convert wide strings to ANSI
char
*
argv
[
3
];
for
(
int
k
=
0
;
k
<
3
;
k
++
)
{
size_t
nbytes
=
2
*
wcslen
(
wargv
[
k
])
+
1
;
argv
[
k
]
=
new
char
[
nbytes
];
wcstombs
(
argv
[
k
],
wargv
[
k
],
nbytes
);
}
/* Check if service uses mysqld in installation directory */
if
(
_strnicmp
(
service_props
.
mysqld_exe
,
m_InstallDir
.
c_str
(),
m_InstallDir
.
size
())
==
0
)
continue
;
size_t
len
=
strlen
(
argv
[
0
]);
char
path
[
MAX_PATH
]
=
{
0
};
char
*
filepart
;
GetFullPathName
(
argv
[
0
],
MAX_PATH
,
path
,
&
filepart
);
if
(
_stricmp
(
filepart
,
"mysqld.exe"
)
==
0
||
_stricmp
(
filepart
,
"mysqld"
)
==
0
)
if
(
m_MajorVersion
>
service_props
.
version_major
||
(
m_MajorVersion
==
service_props
.
version_major
&&
m_MinorVersion
>=
service_props
.
version_minor
))
{
if
(
_strnicmp
(
argv
[
1
],
"--defaults-file="
,
16
)
==
0
)
{
/* Remove quotes around defaults-file */
char
*
inifile
=
argv
[
1
]
+
16
;
inifile
=
RemoveQuotes
(
inifile
);
char
*
datadir
=
datadirBuf
;
GetPrivateProfileString
(
"mysqld"
,
"datadir"
,
NULL
,
datadirBuf
,
MAX_PATH
,
inifile
);
/* Remove quotes from datadir */
datadir
=
RemoveQuotes
(
datadir
);
GetFullPathName
(
datadir
,
MAX_PATH
,
datadirNormalized
,
NULL
);
ServiceProperties
props
;
props
.
myini
=
inifile
;
props
.
myini
=
service_props
.
inifile
;
props
.
datadir
=
service_props
.
datadir
;
props
.
servicename
=
info
[
i
].
lpServiceName
;
string
exefilename
(
argv
[
0
]);
if
(
!
strstr
(
argv
[
0
],
".exe"
))
exefilename
+=
".exe"
;
int
major
,
minor
,
patch
;
props
.
version
=
GetExeVersion
(
exefilename
,
&
major
,
&
minor
,
&
patch
);
if
(
m_MajorVersion
>
major
||
(
m_MajorVersion
==
major
&&
m_MinorVersion
>=
minor
))
{
if
(
_strnicmp
(
exefilename
.
c_str
(),
m_InstallDir
.
c_str
(),
m_InstallDir
.
size
())
!=
0
)
if
(
service_props
.
version_major
)
{
props
.
datadir
=
datadirNormalized
;
char
ver
[
64
];
sprintf
(
ver
,
"%d.%d.%d"
,
service_props
.
version_major
,
service_props
.
version_minor
,
service_props
.
version_patch
);
props
.
version
=
ver
;
}
else
props
.
version
=
"<unknown>"
;
index
=
m_Services
.
AddString
(
info
[
i
].
lpServiceName
);
services
.
resize
(
index
+
1
);
services
[
index
]
=
props
;
}
}
}
}
for
(
int
k
=
0
;
k
<
3
;
k
++
)
delete
[]
argv
[
k
];
}
LocalFree
((
HLOCAL
)
wargv
);
}
if
(
index
!=
-
1
)
{
m_Services
.
SetCurSel
(
0
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment