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
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
MariaDB
Commits
c6257d20
Commit
c6257d20
authored
May 03, 2005
by
unknown
Browse files
Options
Browse Files
Download
Plain Diff
Merge jlindstrom@bk-internal.mysql.com:/home/bk/mysql-4.1
into hundin.mysql.fi:/home/jan/mysql-4.1
parents
391c8423
9f5a4955
Changes
13
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
208 additions
and
30 deletions
+208
-30
extra/my_print_defaults.c
extra/my_print_defaults.c
+12
-1
libmysqld/emb_qcache.cc
libmysqld/emb_qcache.cc
+18
-18
libmysqld/emb_qcache.h
libmysqld/emb_qcache.h
+24
-3
mysql-test/mysql-test-run.sh
mysql-test/mysql-test-run.sh
+6
-0
mysql-test/r/lowercase_table.result
mysql-test/r/lowercase_table.result
+3
-0
mysql-test/r/query_cache.result
mysql-test/r/query_cache.result
+27
-0
mysql-test/t/lowercase_table.test
mysql-test/t/lowercase_table.test
+8
-0
mysql-test/t/query_cache.test
mysql-test/t/query_cache.test
+45
-0
mysys/default.c
mysys/default.c
+6
-5
sql/sql_cache.cc
sql/sql_cache.cc
+5
-0
sql/sql_parse.cc
sql/sql_parse.cc
+1
-1
sql/sql_table.cc
sql/sql_table.cc
+2
-0
tests/mysql_client_test.c
tests/mysql_client_test.c
+51
-2
No files found.
extra/my_print_defaults.c
View file @
c6257d20
...
...
@@ -27,12 +27,20 @@
const
char
*
config_file
=
"my"
;
/* Default config file */
uint
verbose
=
0
,
opt_defaults_file_used
=
0
;
const
char
*
default_dbug_option
=
"d:t:o,/tmp/my_print_defaults.trace"
;
static
struct
my_option
my_long_options
[]
=
{
{
"config-file"
,
'c'
,
"The config file to be used."
,
(
gptr
*
)
&
config_file
,
(
gptr
*
)
&
config_file
,
0
,
GET_STR
,
REQUIRED_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
#ifdef DBUG_OFF
{
"debug"
,
'#'
,
"This is a non-debug version. Catch this and exit"
,
0
,
0
,
0
,
GET_DISABLED
,
OPT_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
#else
{
"debug"
,
'#'
,
"Output debug log"
,
(
gptr
*
)
&
default_dbug_option
,
(
gptr
*
)
&
default_dbug_option
,
0
,
GET_STR
,
OPT_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
#endif
{
"defaults-file"
,
'c'
,
"Synonym for --config-file."
,
(
gptr
*
)
&
config_file
,
(
gptr
*
)
&
config_file
,
0
,
GET_STR
,
REQUIRED_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
...
...
@@ -95,6 +103,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
case
'V'
:
usage
(
1
);
exit
(
0
);
case
'#'
:
DBUG_PUSH
(
argument
?
argument
:
default_dbug_option
);
break
;
}
return
0
;
}
...
...
@@ -118,7 +129,7 @@ static int get_options(int *argc,char ***argv)
int
main
(
int
argc
,
char
**
argv
)
{
int
count
,
error
;
char
**
load_default_groups
,
*
tmp_arguments
[
2
],
char
**
load_default_groups
,
*
tmp_arguments
[
3
],
**
argument
,
**
arguments
;
char
*
defaults
,
*
extra_defaults
;
MY_INIT
(
argv
[
0
]);
...
...
libmysqld/emb_qcache.cc
View file @
c6257d20
...
...
@@ -22,7 +22,7 @@
void
Querycache_stream
::
store_char
(
char
c
)
{
if
(
data_end
==
cur_data
)
use_next_block
();
use_next_block
(
TRUE
);
*
(
cur_data
++
)
=
c
;
#ifndef DBUG_OFF
stored_size
++
;
...
...
@@ -42,13 +42,13 @@ void Querycache_stream::store_short(ushort s)
}
if
(
data_end
==
cur_data
)
{
use_next_block
();
use_next_block
(
TRUE
);
int2store
(
cur_data
,
s
);
cur_data
+=
2
;
return
;
}
*
cur_data
=
((
byte
*
)(
&
s
))[
0
];
use_next_block
();
use_next_block
(
TRUE
);
*
(
cur_data
++
)
=
((
byte
*
)(
&
s
))[
1
];
}
...
...
@@ -66,7 +66,7 @@ void Querycache_stream::store_int(uint i)
}
if
(
!
rest_len
)
{
use_next_block
();
use_next_block
(
TRUE
);
int4store
(
cur_data
,
i
);
cur_data
+=
4
;
return
;
...
...
@@ -74,7 +74,7 @@ void Querycache_stream::store_int(uint i)
char
buf
[
4
];
int4store
(
buf
,
i
);
memcpy
(
cur_data
,
buf
,
rest_len
);
use_next_block
();
use_next_block
(
TRUE
);
memcpy
(
cur_data
,
buf
+
rest_len
,
4
-
rest_len
);
cur_data
+=
4
-
rest_len
;
}
...
...
@@ -93,13 +93,13 @@ void Querycache_stream::store_ll(ulonglong ll)
}
if
(
!
rest_len
)
{
use_next_block
();
use_next_block
(
TRUE
);
int8store
(
cur_data
,
ll
);
cur_data
+=
8
;
return
;
}
memcpy
(
cur_data
,
&
ll
,
rest_len
);
use_next_block
();
use_next_block
(
TRUE
);
memcpy
(
cur_data
,
((
byte
*
)
&
ll
)
+
rest_len
,
8
-
rest_len
);
cur_data
+=
8
-
rest_len
;
}
...
...
@@ -112,14 +112,14 @@ void Querycache_stream::store_str_only(const char *str, uint str_len)
do
{
size_t
rest_len
=
data_end
-
cur_data
;
if
(
rest_len
>
str_len
)
if
(
rest_len
>
=
str_len
)
{
memcpy
(
cur_data
,
str
,
str_len
);
cur_data
+=
str_len
;
return
;
}
memcpy
(
cur_data
,
str
,
rest_len
);
use_next_block
();
use_next_block
(
TRUE
);
str_len
-=
rest_len
;
str
+=
rest_len
;
}
while
(
str_len
);
...
...
@@ -145,7 +145,7 @@ void Querycache_stream::store_safe_str(const char *str, uint str_len)
char
Querycache_stream
::
load_char
()
{
if
(
cur_data
==
data_end
)
use_next_block
();
use_next_block
(
FALSE
);
return
*
(
cur_data
++
);
}
...
...
@@ -160,13 +160,13 @@ ushort Querycache_stream::load_short()
}
if
(
data_end
==
cur_data
)
{
use_next_block
();
use_next_block
(
FALSE
);
result
=
uint2korr
(
cur_data
);
cur_data
+=
2
;
return
result
;
}
((
byte
*
)
&
result
)[
0
]
=
*
cur_data
;
use_next_block
();
use_next_block
(
FALSE
);
((
byte
*
)
&
result
)[
1
]
=
*
(
cur_data
++
);
return
result
;
}
...
...
@@ -183,14 +183,14 @@ uint Querycache_stream::load_int()
}
if
(
!
rest_len
)
{
use_next_block
();
use_next_block
(
FALSE
);
result
=
uint4korr
(
cur_data
);
cur_data
+=
4
;
return
result
;
}
char
buf
[
4
];
memcpy
(
buf
,
cur_data
,
rest_len
);
use_next_block
();
use_next_block
(
FALSE
);
memcpy
(
buf
+
rest_len
,
cur_data
,
4
-
rest_len
);
cur_data
+=
4
-
rest_len
;
result
=
uint4korr
(
buf
);
...
...
@@ -209,13 +209,13 @@ ulonglong Querycache_stream::load_ll()
}
if
(
!
rest_len
)
{
use_next_block
();
use_next_block
(
FALSE
);
result
=
uint8korr
(
cur_data
);
cur_data
+=
8
;
return
result
;
}
memcpy
(
&
result
,
cur_data
,
rest_len
);
use_next_block
();
use_next_block
(
FALSE
);
memcpy
(((
byte
*
)
&
result
)
+
rest_len
,
cur_data
,
8
-
rest_len
);
cur_data
+=
8
-
rest_len
;
return
result
;
...
...
@@ -226,7 +226,7 @@ void Querycache_stream::load_str_only(char *buffer, uint str_len)
do
{
size_t
rest_len
=
data_end
-
cur_data
;
if
(
rest_len
>
str_len
)
if
(
rest_len
>
=
str_len
)
{
memcpy
(
buffer
,
cur_data
,
str_len
);
cur_data
+=
str_len
;
...
...
@@ -234,7 +234,7 @@ void Querycache_stream::load_str_only(char *buffer, uint str_len)
break
;
}
memcpy
(
buffer
,
cur_data
,
rest_len
);
use_next_block
();
use_next_block
(
FALSE
);
str_len
-=
rest_len
;
buffer
+=
rest_len
;
}
while
(
str_len
);
...
...
libmysqld/emb_qcache.h
View file @
c6257d20
...
...
@@ -22,18 +22,39 @@ class Querycache_stream
uint
headers_len
;
public:
#ifndef DBUG_OFF
Query_cache_block
*
first_block
;
uint
stored_size
;
#endif
Querycache_stream
(
Query_cache_block
*
ini_block
,
uint
ini_headers_len
)
:
block
(
ini_block
),
headers_len
(
ini_headers_len
)
{
use_next_block
();
cur_data
=
((
byte
*
)
block
)
+
headers_len
;
data_end
=
cur_data
+
(
block
->
used
-
headers_len
);
#ifndef DBUG_OFF
first_block
=
ini_block
;
stored_size
=
0
;
#endif
}
void
use_next_block
()
void
use_next_block
(
bool
writing
)
{
/*
This shouldn't be called if there is only one block, or to loop
around to the first block again. That means we're trying to write
more data than we allocated space for.
*/
DBUG_ASSERT
(
block
->
next
!=
block
);
DBUG_ASSERT
(
block
->
next
!=
first_block
);
block
=
block
->
next
;
/*
While writing, update the type of each block as we write to it.
While reading, make sure that the block is of the expected type.
*/
if
(
writing
)
block
->
type
=
Query_cache_block
::
RES_CONT
;
else
DBUG_ASSERT
(
block
->
type
==
Query_cache_block
::
RES_CONT
);
cur_data
=
((
byte
*
)
block
)
+
headers_len
;
data_end
=
cur_data
+
(
block
->
used
-
headers_len
);
}
...
...
mysql-test/mysql-test-run.sh
View file @
c6257d20
...
...
@@ -685,6 +685,12 @@ then
fi
MYSQL_CLIENT_TEST
=
"
$MYSQL_CLIENT_TEST
--no-defaults --testcase --user=root --socket=
$MASTER_MYSOCK
--port=
$MYSQL_TCP_PORT
--silent
$EXTRA_MYSQL_CLIENT_TEST_OPT
"
# Need to pass additional arguments to MYSQL_CLIENT_TEST for embedded server
# -A marks each argument for passing to the function which initializes the
# embedded library
if
[
"x
$USE_EMBEDDED_SERVER
"
=
"x1"
]
;
then
MYSQL_CLIENT_TEST
=
"
$MYSQL_CLIENT_TEST
-A --language=
$LANGUAGE
-A --datadir=
$SLAVE_MYDDIR
-A --character-sets-dir=
$CHARSETSDIR
"
fi
MYSQL_DUMP
=
"
$MYSQL_DUMP
--no-defaults -uroot --socket=
$MASTER_MYSOCK
--password=
$DBPASSWD
$EXTRA_MYSQLDUMP_OPT
"
MYSQL_BINLOG
=
"
$MYSQL_BINLOG
--no-defaults --local-load=
$MYSQL_TMP_DIR
$EXTRA_MYSQLBINLOG_OPT
"
MYSQL_FIX_SYSTEM_TABLES
=
"
$MYSQL_FIX_SYSTEM_TABLES
--no-defaults --host=localhost --port=
$MASTER_MYPORT
--socket=
$MASTER_MYSOCK
--user=root --password=
$DBPASSWD
--basedir=
$BASEDIR
--bindir=
$CLIENT_BINDIR
--verbose"
...
...
mysql-test/r/lowercase_table.result
View file @
c6257d20
...
...
@@ -78,5 +78,8 @@ ERROR 42000: Not unique table/alias: 'C'
select C.a, c.a from t1 c, t2 C;
ERROR 42000: Not unique table/alias: 'C'
drop table t1, t2;
create table t1 (a int);
create table t2 like T1;
drop table t1, t2;
show tables;
Tables_in_test
mysql-test/r/query_cache.result
View file @
c6257d20
This diff is collapsed.
Click to expand it.
mysql-test/t/lowercase_table.test
View file @
c6257d20
...
...
@@ -73,4 +73,12 @@ select * from t1 c, t2 C;
select
C
.
a
,
c
.
a
from
t1
c
,
t2
C
;
drop
table
t1
,
t2
;
#
# Bug #9761: CREATE TABLE ... LIKE ... not handled correctly when
# lower_case_table_names is set
create
table
t1
(
a
int
);
create
table
t2
like
T1
;
drop
table
t1
,
t2
;
show
tables
;
mysql-test/t/query_cache.test
View file @
c6257d20
...
...
@@ -685,4 +685,49 @@ repair table t1;
show
status
like
'qcache_queries_in_cache'
;
drop
table
t1
;
# Bug #9549: Make sure cached queries that span more than one cache block
# are handled properly in the embedded server.
# We just want a small query cache, so we can fragment it easily
set
GLOBAL
query_cache_size
=
64
*
1024
;
# This actually gives us a usable cache size of about 48K
# Each table is about 14K
create
table
t1
(
a
text
);
insert
into
t1
values
(
repeat
(
'abcdefghijklmnopqrstuvwxyz'
,
550
));
create
table
t2
(
a
text
);
insert
into
t2
values
(
repeat
(
'ijklmnopqrstuvwxyzabcdefgh'
,
550
));
# Load a query from each table into the query cache
--
disable_result_log
select
a
from
t1
;
# Q1
select
a
from
t2
;
# Q2
--
enable_result_log
show
status
like
'Qcache_%_blocks'
;
# Now the cache looks like (14K for Q1)(14K for Q2)(20K free)
# Flush Q1 from the cache by adding an out-of-order chunk to t1
insert
into
t1
select
reverse
(
a
)
from
t1
;
show
status
like
'Qcache_%_blocks'
;
# Now the cache looks like (14K free)(14K for Q2)(20K free)
# Load our new data into the query cache
--
disable_result_log
select
a
from
t1
;
# Q3
--
enable_result_log
show
status
like
'Qcache_%_blocks'
;
# Now the cache should be like (14K for Q3)(14K for Q2)(14K for Q3)(6K free)
# Note that Q3 is split across two chunks!
# Load Q3 from the cache, and actually pay attention to the results
select
a
from
t1
;
flush
query
cache
;
drop
table
t1
,
t2
;
set
GLOBAL
query_cache_size
=
0
;
mysys/default.c
View file @
c6257d20
...
...
@@ -144,7 +144,7 @@ int load_defaults(const char *conf_file, const char **groups,
int
*
argc
,
char
***
argv
)
{
DYNAMIC_ARRAY
args
;
const
char
**
dirs
,
*
forced_default_file
;
const
char
**
dirs
,
*
forced_default_file
,
*
forced_extra_defaults
;
TYPELIB
group
;
my_bool
found_print_defaults
=
0
;
uint
args_used
=
0
;
...
...
@@ -174,13 +174,14 @@ int load_defaults(const char *conf_file, const char **groups,
}
get_defaults_files
(
*
argc
,
*
argv
,
(
char
**
)
&
forced_default_file
,
&
defaults_extra_file
);
(
char
**
)
&
forced_default_file
,
(
char
**
)
&
forced_extra_defaults
);
if
(
forced_default_file
)
forced_default_file
=
strchr
(
forced_default_file
,
'='
)
+
1
;
if
(
defaults_extra_file
)
defaults_extra_file
=
strchr
(
defaults_extra_file
,
'='
)
+
1
;
if
(
forced_extra_defaults
)
defaults_extra_file
=
strchr
(
forced_extra_defaults
,
'='
)
+
1
;
args_used
+=
(
forced_default_file
?
1
:
0
)
+
(
defaults_extra_file
?
1
:
0
);
args_used
+=
(
forced_default_file
?
1
:
0
)
+
(
forced_extra_defaults
?
1
:
0
);
group
.
count
=
0
;
group
.
name
=
"defaults"
;
...
...
sql/sql_cache.cc
View file @
c6257d20
...
...
@@ -1933,6 +1933,11 @@ my_bool Query_cache::write_result_data(Query_cache_block **result_block,
type
=
Query_cache_block
::
RES_CONT
;
}
while
(
block
!=
*
result_block
);
#else
/*
Set type of first block, emb_store_querycache_result() will handle
the others.
*/
(
*
result_block
)
->
type
=
type
;
Querycache_stream
qs
(
*
result_block
,
headers_len
);
emb_store_querycache_result
(
&
qs
,
(
THD
*
)
data
);
#endif
/*!EMBEDDED_LIBRARY*/
...
...
sql/sql_parse.cc
View file @
c6257d20
...
...
@@ -449,7 +449,7 @@ static int check_for_max_user_connections(THD *thd, USER_CONN *uc)
uc
->
user_resources
.
connections
<=
uc
->
conn_per_hour
)
{
net_printf
(
thd
,
ER_USER_LIMIT_REACHED
,
uc
->
user
,
"max_connections"
,
"max_connections
_per_hour
"
,
(
long
)
uc
->
user_resources
.
connections
);
error
=
1
;
goto
end
;
...
...
sql/sql_table.cc
View file @
c6257d20
...
...
@@ -2281,6 +2281,8 @@ int mysql_create_like_table(THD* thd, TABLE_LIST* table,
reg_ext
,
NullS
);
/* Resolve symlinks (for windows) */
fn_format
(
src_path
,
src_path
,
""
,
""
,
MYF
(
MY_UNPACK_FILENAME
));
if
(
lower_case_table_names
)
my_casedn_str
(
files_charset_info
,
src_path
);
if
(
access
(
src_path
,
F_OK
))
{
my_error
(
ER_BAD_TABLE_ERROR
,
MYF
(
0
),
src_table
);
...
...
tests/mysql_client_test.c
View file @
c6257d20
...
...
@@ -30,6 +30,7 @@
#define VER "2.1"
#define MAX_TEST_QUERY_LENGTH 300
/* MAX QUERY BUFFER LENGTH */
#define MAX_SERVER_ARGS 64
/* set default options */
static
int
opt_testcase
=
0
;
...
...
@@ -48,6 +49,18 @@ static unsigned int test_count= 0;
static
unsigned
int
opt_count
=
0
;
static
unsigned
int
iter_count
=
0
;
static
const
char
*
opt_basedir
=
"./"
;
static
int
embedded_server_arg_count
=
0
;
static
char
*
embedded_server_args
[
MAX_SERVER_ARGS
];
static
const
char
*
embedded_server_groups
[]
=
{
"server"
,
"embedded"
,
"mysql_client_test_SERVER"
,
NullS
};
static
time_t
start_time
,
end_time
;
static
double
total_time
;
...
...
@@ -93,6 +106,8 @@ static void client_disconnect();
#define DIE_UNLESS(expr) \
((void) ((expr) ? 0 : (die(__FILE__, __LINE__, #expr), 0)))
#define DIE(expr) \
die(__FILE__, __LINE__, #expr)
void
die
(
const
char
*
file
,
int
line
,
const
char
*
expr
)
{
...
...
@@ -11617,7 +11632,7 @@ static void test_bug7990()
static
void
test_bug8378
()
{
#if
def HAVE_CHARSET_gbk
#if
defined(HAVE_CHARSET_gbk) && !defined(EMBEDDED_LIBRARY)
MYSQL
*
lmysql
;
char
out
[
9
];
/* strlen(TEST_BUG8378)*2+1 */
int
len
;
...
...
@@ -11664,6 +11679,8 @@ static char **defaults_argv;
static
struct
my_option
client_test_long_options
[]
=
{
{
"basedir"
,
'b'
,
"Basedir for tests."
,
(
gptr
*
)
&
opt_basedir
,
(
gptr
*
)
&
opt_basedir
,
0
,
GET_STR
,
REQUIRED_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"count"
,
't'
,
"Number of times test to be executed"
,
(
char
**
)
&
opt_count
,
(
char
**
)
&
opt_count
,
0
,
GET_UINT
,
REQUIRED_ARG
,
1
,
0
,
0
,
0
,
0
,
0
},
{
"database"
,
'D'
,
"Database to use"
,
(
char
**
)
&
opt_db
,
(
char
**
)
&
opt_db
,
...
...
@@ -11679,6 +11696,8 @@ static struct my_option client_test_long_options[] =
0
,
0
,
0
,
GET_STR
,
OPT_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"port"
,
'P'
,
"Port number to use for connection"
,
(
char
**
)
&
opt_port
,
(
char
**
)
&
opt_port
,
0
,
GET_UINT
,
REQUIRED_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"server-arg"
,
'A'
,
"Send embedded server this as a parameter."
,
0
,
0
,
0
,
GET_STR
,
REQUIRED_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"show-tests"
,
'T'
,
"Show all tests' names"
,
0
,
0
,
0
,
GET_NO_ARG
,
NO_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"silent"
,
's'
,
"Be more silent"
,
0
,
0
,
0
,
GET_NO_ARG
,
NO_ARG
,
0
,
0
,
0
,
0
,
0
,
...
...
@@ -11899,6 +11918,25 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
else
opt_silent
++
;
break
;
case
'A'
:
/*
When the embedded server is being tested, the test suite needs to be
able to pass command-line arguments to the embedded server so it can
locate the language files and data directory. The test suite
(mysql-test-run) never uses config files, just command-line options.
*/
if
(
!
embedded_server_arg_count
)
{
embedded_server_arg_count
=
1
;
embedded_server_args
[
0
]
=
(
char
*
)
""
;
}
if
(
embedded_server_arg_count
==
MAX_SERVER_ARGS
-
1
||
!
(
embedded_server_args
[
embedded_server_arg_count
++
]
=
my_strdup
(
argument
,
MYF
(
MY_FAE
))))
{
DIE
(
"Can't use server argument"
);
}
break
;
case
'T'
:
{
struct
my_tests_st
*
fptr
;
...
...
@@ -11967,6 +12005,11 @@ int main(int argc, char **argv)
defaults_argv
=
argv
;
get_options
(
&
argc
,
&
argv
);
if
(
mysql_server_init
(
embedded_server_arg_count
,
embedded_server_args
,
(
char
**
)
embedded_server_groups
))
DIE
(
"Can't initialize MySQL server"
);
client_connect
();
/* connect to server */
total_time
=
0
;
...
...
@@ -12019,6 +12062,12 @@ int main(int argc, char **argv)
client_disconnect
();
/* disconnect from server */
free_defaults
(
defaults_argv
);
print_test_output
();
while
(
embedded_server_arg_count
>
1
)
my_free
(
embedded_server_args
[
--
embedded_server_arg_count
],
MYF
(
0
));
mysql_server_end
();
my_end
(
0
);
exit
(
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