Commit edea2263 authored by unknown's avatar unknown

added options to give nodeid and mgmd host directly as switches (without using the connectstring)


ndb/src/mgmapi/LocalConfig.cpp:
  added options to give nodeid and mgmd host directly as switches (without using the connectstring)
  reset nodeid on init
  allow only nodeid to be specified in the connectstring
  allow mgmd-host in connectstring
ndb/src/mgmapi/mgmapi.cpp:
  just some extra debug printouts
parent c7afc80b
...@@ -25,10 +25,15 @@ ...@@ -25,10 +25,15 @@
#include <ndb_opt_defaults.h> #include <ndb_opt_defaults.h>
#define NDB_STD_OPTS_VARS \ #define NDB_STD_OPTS_VARS \
const char *opt_connect_str= 0;\
my_bool opt_ndb_optimized_node_selection my_bool opt_ndb_optimized_node_selection
int opt_ndb_nodeid;
my_bool opt_ndb_shm; my_bool opt_ndb_shm;
const char *opt_ndb_connectstring= 0;
const char *opt_connect_str= 0;
const char *opt_ndb_mgmd_host= 0;
char opt_ndb_constrbuf[1024];
unsigned opt_ndb_constrbuf_len;
#define OPT_NDB_CONNECTSTRING 'c' #define OPT_NDB_CONNECTSTRING 'c'
...@@ -43,8 +48,17 @@ my_bool opt_ndb_shm; ...@@ -43,8 +48,17 @@ my_bool opt_ndb_shm;
"Set connect string for connecting to ndb_mgmd. " \ "Set connect string for connecting to ndb_mgmd. " \
"Syntax: \"[nodeid=<id>;][host=]<hostname>[:<port>]\". " \ "Syntax: \"[nodeid=<id>;][host=]<hostname>[:<port>]\". " \
"Overides specifying entries in NDB_CONNECTSTRING and Ndb.cfg", \ "Overides specifying entries in NDB_CONNECTSTRING and Ndb.cfg", \
(gptr*) &opt_connect_str, (gptr*) &opt_connect_str, 0, \ (gptr*) &opt_ndb_connectstring, (gptr*) &opt_ndb_connectstring, \
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },\
{ "ndb-mgmd-host", OPT_NDB_MGMD_HOST, \
"Set host and port for connecting to ndb_mgmd. " \
"Syntax: <hostname>[:<port>].", \
(gptr*) &opt_ndb_mgmd_host, (gptr*) &opt_ndb_mgmd_host, 0, \
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },\ GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },\
{ "ndb-nodeid", OPT_NDB_NODEID, \
"Set node id for this node.", \
(gptr*) &opt_ndb_nodeid, (gptr*) &opt_ndb_nodeid, 0, \
GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },\
{ "ndb-shm", OPT_NDB_SHM,\ { "ndb-shm", OPT_NDB_SHM,\
"Allow optimizing using shared memory connections when available",\ "Allow optimizing using shared memory connections when available",\
(gptr*) &opt_ndb_shm, (gptr*) &opt_ndb_shm, 0,\ (gptr*) &opt_ndb_shm, (gptr*) &opt_ndb_shm, 0,\
...@@ -55,8 +69,8 @@ my_bool opt_ndb_shm; ...@@ -55,8 +69,8 @@ my_bool opt_ndb_shm;
(gptr*) &opt_ndb_optimized_node_selection, 0,\ (gptr*) &opt_ndb_optimized_node_selection, 0,\
GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},\ GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},\
{ "connect-string", OPT_NDB_CONNECTSTRING, "same as --ndb-connectstring",\ { "connect-string", OPT_NDB_CONNECTSTRING, "same as --ndb-connectstring",\
(gptr*) &opt_connect_str, (gptr*) &opt_connect_str, 0,\ (gptr*) &opt_ndb_connectstring, (gptr*) &opt_ndb_connectstring, \
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 } 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }
#ifndef DBUG_OFF #ifndef DBUG_OFF
#define NDB_STD_OPTS(prog_name) \ #define NDB_STD_OPTS(prog_name) \
...@@ -79,6 +93,8 @@ enum ndb_std_options { ...@@ -79,6 +93,8 @@ enum ndb_std_options {
OPT_NDB_SHM= 256, OPT_NDB_SHM= 256,
OPT_NDB_SHM_SIGNUM, OPT_NDB_SHM_SIGNUM,
OPT_NDB_OPTIMIZED_NODE_SELECTION, OPT_NDB_OPTIMIZED_NODE_SELECTION,
OPT_NDB_MGMD_HOST,
OPT_NDB_NODEID,
NDB_STD_OPTIONS_LAST /* should always be last in this enum */ NDB_STD_OPTIONS_LAST /* should always be last in this enum */
}; };
...@@ -110,6 +126,29 @@ ndb_std_get_one_option(int optid, ...@@ -110,6 +126,29 @@ ndb_std_get_one_option(int optid,
#endif #endif
} }
break; break;
case OPT_NDB_MGMD_HOST:
case OPT_NDB_NODEID:
{
const char *tmp="";
if (optid == OPT_NDB_NODEID)
tmp= "nodeid=";
int len= my_snprintf(opt_ndb_constrbuf+opt_ndb_constrbuf_len,
sizeof(opt_ndb_constrbuf)-opt_ndb_constrbuf_len,
"%s%s%s",opt_ndb_constrbuf_len > 0 ? ",":"",
tmp, argument);
opt_ndb_constrbuf_len+= len;
}
/* fall through to add the connectstring to the end
* and set opt_ndbcluster_connectstring
*/
case OPT_NDB_CONNECTSTRING:
if (opt_ndb_connectstring && opt_ndb_connectstring[0])
my_snprintf(opt_ndb_constrbuf+opt_ndb_constrbuf_len,
sizeof(opt_ndb_constrbuf)-opt_ndb_constrbuf_len,
"%s%s", opt_ndb_constrbuf_len > 0 ? ",":"",
opt_ndb_connectstring);
opt_connect_str= opt_ndb_constrbuf;
break;
} }
return 0; return 0;
} }
......
...@@ -27,7 +27,9 @@ LocalConfig::LocalConfig(){ ...@@ -27,7 +27,9 @@ LocalConfig::LocalConfig(){
bool bool
LocalConfig::init(const char *connectString, LocalConfig::init(const char *connectString,
const char *fileName) { const char *fileName)
{
DBUG_ENTER("LocalConfig::init");
/** /**
* Escalation: * Escalation:
* 1. Check connectString * 1. Check connectString
...@@ -38,21 +40,25 @@ LocalConfig::init(const char *connectString, ...@@ -38,21 +40,25 @@ LocalConfig::init(const char *connectString,
* 6. Check defaultConnectString * 6. Check defaultConnectString
*/ */
_ownNodeId= 0;
//1. Check connectString //1. Check connectString
if(connectString != 0 && connectString[0] != 0){ if(connectString != 0 && connectString[0] != 0){
if(readConnectString(connectString, "connect string")){ if(readConnectString(connectString, "connect string")){
return true; if (ids.size())
} DBUG_RETURN(true);
return false; // only nodeid given, continue to find hosts
} else
DBUG_RETURN(false);
} }
//2. Check given filename //2. Check given filename
if (fileName && strlen(fileName) > 0) { if (fileName && strlen(fileName) > 0) {
bool fopenError; bool fopenError;
if(readFile(fileName, fopenError)){ if(readFile(fileName, fopenError)){
return true; DBUG_RETURN(true);
} }
return false; DBUG_RETURN(false);
} }
//3. Check environment variable //3. Check environment variable
...@@ -60,9 +66,9 @@ LocalConfig::init(const char *connectString, ...@@ -60,9 +66,9 @@ LocalConfig::init(const char *connectString,
if(NdbEnv_GetEnv("NDB_CONNECTSTRING", buf, sizeof(buf)) && if(NdbEnv_GetEnv("NDB_CONNECTSTRING", buf, sizeof(buf)) &&
strlen(buf) != 0){ strlen(buf) != 0){
if(readConnectString(buf, "NDB_CONNECTSTRING")){ if(readConnectString(buf, "NDB_CONNECTSTRING")){
return true; DBUG_RETURN(true);
} }
return false; DBUG_RETURN(false);
} }
//4. Check Ndb.cfg in NDB_HOME //4. Check Ndb.cfg in NDB_HOME
...@@ -71,9 +77,9 @@ LocalConfig::init(const char *connectString, ...@@ -71,9 +77,9 @@ LocalConfig::init(const char *connectString,
char *buf= NdbConfig_NdbCfgName(1 /*true*/); char *buf= NdbConfig_NdbCfgName(1 /*true*/);
NdbAutoPtr<char> tmp_aptr(buf); NdbAutoPtr<char> tmp_aptr(buf);
if(readFile(buf, fopenError)) if(readFile(buf, fopenError))
return true; DBUG_RETURN(true);
if (!fopenError) if (!fopenError)
return false; DBUG_RETURN(false);
} }
//5. Check Ndb.cfg in cwd //5. Check Ndb.cfg in cwd
...@@ -82,9 +88,9 @@ LocalConfig::init(const char *connectString, ...@@ -82,9 +88,9 @@ LocalConfig::init(const char *connectString,
char *buf= NdbConfig_NdbCfgName(0 /*false*/); char *buf= NdbConfig_NdbCfgName(0 /*false*/);
NdbAutoPtr<char> tmp_aptr(buf); NdbAutoPtr<char> tmp_aptr(buf);
if(readFile(buf, fopenError)) if(readFile(buf, fopenError))
return true; DBUG_RETURN(true);
if (!fopenError) if (!fopenError)
return false; DBUG_RETURN(false);
} }
//7. Check //7. Check
...@@ -92,12 +98,12 @@ LocalConfig::init(const char *connectString, ...@@ -92,12 +98,12 @@ LocalConfig::init(const char *connectString,
char buf[256]; char buf[256];
BaseString::snprintf(buf, sizeof(buf), "host=localhost:%s", NDB_PORT); BaseString::snprintf(buf, sizeof(buf), "host=localhost:%s", NDB_PORT);
if(readConnectString(buf, "default connect string")) if(readConnectString(buf, "default connect string"))
return true; DBUG_RETURN(true);
} }
setError(0, ""); setError(0, "");
return false; DBUG_RETURN(false);
} }
LocalConfig::~LocalConfig(){ LocalConfig::~LocalConfig(){
...@@ -142,6 +148,7 @@ const char *nodeIdTokens[] = { ...@@ -142,6 +148,7 @@ const char *nodeIdTokens[] = {
const char *hostNameTokens[] = { const char *hostNameTokens[] = {
"host://%[^:]:%i", "host://%[^:]:%i",
"host=%[^:]:%i", "host=%[^:]:%i",
"mgmd-host=%[^:]:%i",
"%[^:^=^ ]:%i", "%[^:^=^ ]:%i",
"%s %i", "%s %i",
0 0
...@@ -207,30 +214,22 @@ LocalConfig::parseString(const char * connectString, BaseString &err){ ...@@ -207,30 +214,22 @@ LocalConfig::parseString(const char * connectString, BaseString &err){
char * copy = strdup(connectString); char * copy = strdup(connectString);
NdbAutoPtr<char> tmp_aptr(copy); NdbAutoPtr<char> tmp_aptr(copy);
bool b_nodeId = false;
bool found_other = false;
for (char *tok = strtok_r(copy,";,",&for_strtok); tok != 0; for (char *tok = strtok_r(copy,";,",&for_strtok); tok != 0;
tok = strtok_r(NULL, ";,", &for_strtok)) { tok = strtok_r(NULL, ";,", &for_strtok)) {
if (tok[0] == '#') continue; if (tok[0] == '#') continue;
if (!b_nodeId) // only one nodeid definition allowed if (!_ownNodeId) // only one nodeid definition allowed
if (b_nodeId = parseNodeId(tok)) if (parseNodeId(tok))
continue; continue;
if (found_other = parseHostName(tok)) if (parseHostName(tok))
continue; continue;
if (found_other = parseFileName(tok)) if (parseFileName(tok))
continue; continue;
err.assfmt("Unexpected entry: \"%s\"", tok); err.assfmt("Unexpected entry: \"%s\"", tok);
return false; return false;
} }
if (!found_other) {
err.appfmt("Missing host/file name extry in \"%s\"", connectString);
return false;
}
return true; return true;
} }
......
...@@ -169,17 +169,18 @@ extern "C" ...@@ -169,17 +169,18 @@ extern "C"
int int
ndb_mgm_set_connectstring(NdbMgmHandle handle, const char * mgmsrv) ndb_mgm_set_connectstring(NdbMgmHandle handle, const char * mgmsrv)
{ {
DBUG_ENTER("ndb_mgm_set_connectstring");
new (&(handle->cfg)) LocalConfig; new (&(handle->cfg)) LocalConfig;
if (!handle->cfg.init(mgmsrv, 0) || if (!handle->cfg.init(mgmsrv, 0) ||
handle->cfg.ids.size() == 0) handle->cfg.ids.size() == 0)
{ {
new (&(handle->cfg)) LocalConfig; new (&(handle->cfg)) LocalConfig;
handle->cfg.init(0, 0); /* reset the LocalCongig */ handle->cfg.init(0, 0); /* reset the LocalConfig */
SET_ERROR(handle, NDB_MGM_ILLEGAL_CONNECT_STRING, ""); SET_ERROR(handle, NDB_MGM_ILLEGAL_CONNECT_STRING, "");
return -1; DBUG_RETURN(-1);
} }
handle->cfg_i= -1; handle->cfg_i= -1;
return 0; DBUG_RETURN(0);
} }
/** /**
...@@ -356,6 +357,7 @@ ndb_mgm_connect(NdbMgmHandle handle, int no_retries, ...@@ -356,6 +357,7 @@ ndb_mgm_connect(NdbMgmHandle handle, int no_retries,
SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_connect"); SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_connect");
CHECK_HANDLE(handle, -1); CHECK_HANDLE(handle, -1);
DBUG_ENTER("ndb_mgm_connect");
#ifdef MGMAPI_LOG #ifdef MGMAPI_LOG
/** /**
* Open the log file * Open the log file
...@@ -385,6 +387,13 @@ ndb_mgm_connect(NdbMgmHandle handle, int no_retries, ...@@ -385,6 +387,13 @@ ndb_mgm_connect(NdbMgmHandle handle, int no_retries,
} }
if (sockfd != NDB_INVALID_SOCKET) if (sockfd != NDB_INVALID_SOCKET)
break; break;
#ifndef DBUG_OFF
{
char buf[1024];
DBUG_PRINT("info",("Unable to connect with connect string: %s",
cfg.makeConnectString(buf,sizeof(buf))));
}
#endif
if (verbose > 0) { if (verbose > 0) {
char buf[1024]; char buf[1024];
ndbout_c("Unable to connect with connect string: %s", ndbout_c("Unable to connect with connect string: %s",
...@@ -398,7 +407,7 @@ ndb_mgm_connect(NdbMgmHandle handle, int no_retries, ...@@ -398,7 +407,7 @@ ndb_mgm_connect(NdbMgmHandle handle, int no_retries,
cfg.makeConnectString(buf,sizeof(buf))); cfg.makeConnectString(buf,sizeof(buf)));
if (verbose == -2) if (verbose == -2)
ndbout << ", failed." << endl; ndbout << ", failed." << endl;
return -1; DBUG_RETURN(-1);
} }
if (verbose == -1) { if (verbose == -1) {
ndbout << "Retrying every " << retry_delay_in_seconds << " seconds"; ndbout << "Retrying every " << retry_delay_in_seconds << " seconds";
...@@ -426,7 +435,7 @@ ndb_mgm_connect(NdbMgmHandle handle, int no_retries, ...@@ -426,7 +435,7 @@ ndb_mgm_connect(NdbMgmHandle handle, int no_retries,
handle->socket = sockfd; handle->socket = sockfd;
handle->connected = 1; handle->connected = 1;
return 0; DBUG_RETURN(0);
} }
/** /**
......
...@@ -291,8 +291,13 @@ my_bool opt_log_slave_updates= 0; ...@@ -291,8 +291,13 @@ my_bool opt_log_slave_updates= 0;
my_bool opt_console= 0, opt_bdb, opt_innodb, opt_isam, opt_ndbcluster; my_bool opt_console= 0, opt_bdb, opt_innodb, opt_isam, opt_ndbcluster;
#ifdef HAVE_NDBCLUSTER_DB #ifdef HAVE_NDBCLUSTER_DB
const char *opt_ndbcluster_connectstring= 0; const char *opt_ndbcluster_connectstring= 0;
const char *opt_ndb_connectstring= 0;
char opt_ndb_constrbuf[1024];
unsigned opt_ndb_constrbuf_len;
my_bool opt_ndb_shm, opt_ndb_optimized_node_selection; my_bool opt_ndb_shm, opt_ndb_optimized_node_selection;
ulong opt_ndb_cache_check_time= 0; ulong opt_ndb_cache_check_time;
const char *opt_ndb_mgmd_host;
ulong opt_ndb_nodeid;
#endif #endif
my_bool opt_readonly, use_temp_pool, relay_log_purge; my_bool opt_readonly, use_temp_pool, relay_log_purge;
my_bool opt_sync_bdb_logs, opt_sync_frm; my_bool opt_sync_bdb_logs, opt_sync_frm;
...@@ -4173,6 +4178,7 @@ enum options_mysqld ...@@ -4173,6 +4178,7 @@ enum options_mysqld
OPT_NDBCLUSTER, OPT_NDB_CONNECTSTRING, OPT_NDB_USE_EXACT_COUNT, OPT_NDBCLUSTER, OPT_NDB_CONNECTSTRING, OPT_NDB_USE_EXACT_COUNT,
OPT_NDB_FORCE_SEND, OPT_NDB_AUTOINCREMENT_PREFETCH_SZ, OPT_NDB_FORCE_SEND, OPT_NDB_AUTOINCREMENT_PREFETCH_SZ,
OPT_NDB_SHM, OPT_NDB_OPTIMIZED_NODE_SELECTION, OPT_NDB_CACHE_CHECK_TIME, OPT_NDB_SHM, OPT_NDB_OPTIMIZED_NODE_SELECTION, OPT_NDB_CACHE_CHECK_TIME,
OPT_NDB_MGMD_HOST, OPT_NDB_NODEID,
OPT_SKIP_SAFEMALLOC, OPT_SKIP_SAFEMALLOC,
OPT_TEMP_POOL, OPT_TX_ISOLATION, OPT_COMPLETION_TYPE, OPT_TEMP_POOL, OPT_TX_ISOLATION, OPT_COMPLETION_TYPE,
OPT_SKIP_STACK_TRACE, OPT_SKIP_SYMLINKS, OPT_SKIP_STACK_TRACE, OPT_SKIP_SYMLINKS,
...@@ -4664,9 +4670,19 @@ Disable with --skip-ndbcluster (will save memory).", ...@@ -4664,9 +4670,19 @@ Disable with --skip-ndbcluster (will save memory).",
#ifdef HAVE_NDBCLUSTER_DB #ifdef HAVE_NDBCLUSTER_DB
{"ndb-connectstring", OPT_NDB_CONNECTSTRING, {"ndb-connectstring", OPT_NDB_CONNECTSTRING,
"Connect string for ndbcluster.", "Connect string for ndbcluster.",
(gptr*) &opt_ndbcluster_connectstring, (gptr*) &opt_ndb_connectstring,
(gptr*) &opt_ndbcluster_connectstring, (gptr*) &opt_ndb_connectstring,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"ndb-mgmd-host", OPT_NDB_MGMD_HOST,
"Set host and port for ndb_mgmd. Syntax: hostname[:port]",
(gptr*) &opt_ndb_mgmd_host,
(gptr*) &opt_ndb_mgmd_host,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"ndb-nodeid", OPT_NDB_NODEID,
"Nodeid for this mysqlserver in the cluster.",
(gptr*) &opt_ndb_nodeid,
(gptr*) &opt_ndb_nodeid,
0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"ndb-autoincrement-prefetch-sz", OPT_NDB_AUTOINCREMENT_PREFETCH_SZ, {"ndb-autoincrement-prefetch-sz", OPT_NDB_AUTOINCREMENT_PREFETCH_SZ,
"Specify number of autoincrement values that are prefetched.", "Specify number of autoincrement values that are prefetched.",
(gptr*) &global_system_variables.ndb_autoincrement_prefetch_sz, (gptr*) &global_system_variables.ndb_autoincrement_prefetch_sz,
...@@ -4705,9 +4721,10 @@ Disable with --skip-ndbcluster (will save memory).", ...@@ -4705,9 +4721,10 @@ Disable with --skip-ndbcluster (will save memory).",
(gptr*) &opt_ndb_optimized_node_selection, (gptr*) &opt_ndb_optimized_node_selection,
0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0}, 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
{ "ndb_cache_check_time", OPT_NDB_CACHE_CHECK_TIME, { "ndb_cache_check_time", OPT_NDB_CACHE_CHECK_TIME,
"A dedicated thread is created to update cached commit count value at the given interval.", "A dedicated thread is created to update cached commit count value"
(gptr*) &opt_ndb_cache_check_time, (gptr*) &opt_ndb_cache_check_time, 0, GET_ULONG, REQUIRED_ARG, " at the given interval.",
0, 0, LONG_TIMEOUT, 0, 1, 0}, (gptr*) &opt_ndb_cache_check_time, (gptr*) &opt_ndb_cache_check_time,
0, GET_ULONG, REQUIRED_ARG, 0, 0, LONG_TIMEOUT, 0, 1, 0},
#endif #endif
{"new", 'n', "Use very new possible 'unsafe' functions.", {"new", 'n', "Use very new possible 'unsafe' functions.",
(gptr*) &global_system_variables.new_mode, (gptr*) &global_system_variables.new_mode,
...@@ -6504,6 +6521,31 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), ...@@ -6504,6 +6521,31 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
have_ndbcluster= SHOW_OPTION_DISABLED; have_ndbcluster= SHOW_OPTION_DISABLED;
#endif #endif
break; break;
#ifdef HAVE_NDBCLUSTER_DB
case OPT_NDB_MGMD_HOST:
case OPT_NDB_NODEID:
{
const char *tmp="";
if (optid == OPT_NDB_NODEID)
tmp= "nodeid=";
int len= my_snprintf(opt_ndb_constrbuf+opt_ndb_constrbuf_len,
sizeof(opt_ndb_constrbuf)-opt_ndb_constrbuf_len,
"%s%s%s",opt_ndb_constrbuf_len > 0 ? ",":"",
tmp, argument);
opt_ndb_constrbuf_len+= len;
}
/* fall through to add the connectstring to the end
* and set opt_ndbcluster_connectstring
*/
case OPT_NDB_CONNECTSTRING:
if (opt_ndb_connectstring && opt_ndb_connectstring[0])
my_snprintf(opt_ndb_constrbuf+opt_ndb_constrbuf_len,
sizeof(opt_ndb_constrbuf)-opt_ndb_constrbuf_len,
"%s%s", opt_ndb_constrbuf_len > 0 ? ",":"",
opt_ndb_connectstring);
opt_ndbcluster_connectstring= opt_ndb_constrbuf;
break;
#endif
case OPT_INNODB: case OPT_INNODB:
#ifdef HAVE_INNOBASE_DB #ifdef HAVE_INNOBASE_DB
if (opt_innodb) if (opt_innodb)
......
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