Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
mpd
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Иван Мажукин
mpd
Commits
1a75abff
Commit
1a75abff
authored
Aug 07, 2012
by
Max Kellermann
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Database{Plugin,Visitor}: pass references
parent
c6a0f5d3
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
95 additions
and
91 deletions
+95
-91
DatabasePlaylist.cxx
src/DatabasePlaylist.cxx
+13
-6
DatabasePlugin.hxx
src/DatabasePlugin.hxx
+3
-3
DatabasePrint.cxx
src/DatabasePrint.cxx
+43
-46
DatabaseQueue.cxx
src/DatabaseQueue.cxx
+9
-10
DatabaseVisitor.hxx
src/DatabaseVisitor.hxx
+4
-3
Directory.cxx
src/Directory.cxx
+3
-3
Stats.cxx
src/Stats.cxx
+4
-4
SimpleDatabasePlugin.cxx
src/db/SimpleDatabasePlugin.cxx
+7
-7
SimpleDatabasePlugin.hxx
src/db/SimpleDatabasePlugin.hxx
+1
-1
DumpDatabase.cxx
test/DumpDatabase.cxx
+8
-8
No files found.
src/DatabasePlaylist.cxx
View file @
1a75abff
...
...
@@ -31,6 +31,13 @@ extern "C" {
#include <functional>
static
bool
AddSong
(
const
char
*
playlist_path_utf8
,
song
&
song
,
GError
**
error_r
)
{
return
spl_append_song
(
playlist_path_utf8
,
&
song
,
error_r
);
}
bool
addAllInToStoredPlaylist
(
const
char
*
uri_utf8
,
const
char
*
playlist_path_utf8
,
GError
**
error_r
)
...
...
@@ -39,17 +46,17 @@ addAllInToStoredPlaylist(const char *uri_utf8, const char *playlist_path_utf8,
db_selection_init
(
&
selection
,
uri_utf8
,
true
);
using
namespace
std
::
placeholders
;
const
auto
f
=
std
::
bind
(
spl_append_s
ong
,
playlist_path_utf8
,
_1
,
_2
);
return
GetDatabase
()
->
Visit
(
&
selection
,
f
,
error_r
);
const
auto
f
=
std
::
bind
(
AddS
ong
,
playlist_path_utf8
,
_1
,
_2
);
return
GetDatabase
()
->
Visit
(
selection
,
f
,
error_r
);
}
static
bool
SearchAddSong
(
const
char
*
playlist_path_utf8
,
const
struct
locate_item_list
*
criteria
,
s
truct
song
*
song
,
GError
**
error_r
)
s
ong
&
song
,
GError
**
error_r
)
{
return
!
locate_song_search
(
song
,
criteria
)
||
spl_append_song
(
playlist_path_utf8
,
song
,
error_r
);
return
!
locate_song_search
(
&
song
,
criteria
)
||
spl_append_song
(
playlist_path_utf8
,
&
song
,
error_r
);
}
bool
...
...
@@ -66,7 +73,7 @@ search_add_to_playlist(const char *uri, const char *playlist_path_utf8,
using
namespace
std
::
placeholders
;
const
auto
f
=
std
::
bind
(
SearchAddSong
,
playlist_path_utf8
,
new_list
,
_1
,
_2
);
bool
success
=
GetDatabase
()
->
Visit
(
&
selection
,
f
,
error_r
);
bool
success
=
GetDatabase
()
->
Visit
(
selection
,
f
,
error_r
);
locate_item_list_free
(
new_list
);
...
...
src/DatabasePlugin.hxx
View file @
1a75abff
...
...
@@ -64,13 +64,13 @@ public:
/**
* Visit the selected entities.
*/
virtual
bool
Visit
(
const
struct
db_selection
*
selection
,
virtual
bool
Visit
(
const
db_selection
&
selection
,
VisitDirectory
visit_directory
,
VisitSong
visit_song
,
VisitPlaylist
visit_playlist
,
GError
**
error_r
)
const
=
0
;
bool
Visit
(
const
struct
db_selection
*
selection
,
bool
Visit
(
const
db_selection
&
selection
,
VisitDirectory
visit_directory
,
VisitSong
visit_song
,
GError
**
error_r
)
const
{
...
...
@@ -78,7 +78,7 @@ public:
VisitPlaylist
(),
error_r
);
}
bool
Visit
(
const
struct
db_selection
*
selection
,
VisitSong
visit_song
,
bool
Visit
(
const
db_selection
&
selection
,
VisitSong
visit_song
,
GError
**
error_r
)
const
{
return
Visit
(
selection
,
VisitDirectory
(),
visit_song
,
error_r
);
}
...
...
src/DatabasePrint.cxx
View file @
1a75abff
...
...
@@ -40,79 +40,76 @@ extern "C" {
#include <set>
static
bool
PrintDirectory
(
struct
client
*
client
,
const
struct
directory
*
directory
)
PrintDirectory
(
struct
client
*
client
,
const
directory
&
directory
)
{
if
(
!
directory_is_root
(
directory
))
client_printf
(
client
,
"directory: %s
\n
"
,
directory_get_path
(
directory
));
if
(
!
directory_is_root
(
&
directory
))
client_printf
(
client
,
"directory: %s
\n
"
,
directory_get_path
(
&
directory
));
return
true
;
}
static
void
print_playlist_in_directory
(
struct
client
*
client
,
const
struct
directory
*
directory
,
const
directory
&
directory
,
const
char
*
name_utf8
)
{
if
(
directory_is_root
(
directory
))
if
(
directory_is_root
(
&
directory
))
client_printf
(
client
,
"playlist: %s
\n
"
,
name_utf8
);
else
client_printf
(
client
,
"playlist: %s/%s
\n
"
,
directory_get_path
(
directory
),
name_utf8
);
directory_get_path
(
&
directory
),
name_utf8
);
}
static
bool
PrintSongBrief
(
struct
client
*
client
,
s
truct
song
*
song
)
PrintSongBrief
(
struct
client
*
client
,
s
ong
&
song
)
{
assert
(
song
!=
NULL
);
assert
(
song
->
parent
!=
NULL
);
assert
(
song
.
parent
!=
NULL
);
song_print_uri
(
client
,
song
);
song_print_uri
(
client
,
&
song
);
if
(
song
->
tag
!=
NULL
&&
song
->
tag
->
has_playlist
)
if
(
song
.
tag
!=
NULL
&&
song
.
tag
->
has_playlist
)
/* this song file has an embedded CUE sheet */
print_playlist_in_directory
(
client
,
song
->
parent
,
song
->
uri
);
print_playlist_in_directory
(
client
,
*
song
.
parent
,
song
.
uri
);
return
true
;
}
static
bool
PrintSongFull
(
struct
client
*
client
,
s
truct
song
*
song
)
PrintSongFull
(
struct
client
*
client
,
s
ong
&
song
)
{
assert
(
song
!=
NULL
);
assert
(
song
->
parent
!=
NULL
);
assert
(
song
.
parent
!=
NULL
);
song_print_info
(
client
,
song
);
song_print_info
(
client
,
&
song
);
if
(
song
->
tag
!=
NULL
&&
song
->
tag
->
has_playlist
)
if
(
song
.
tag
!=
NULL
&&
song
.
tag
->
has_playlist
)
/* this song file has an embedded CUE sheet */
print_playlist_in_directory
(
client
,
song
->
parent
,
song
->
uri
);
print_playlist_in_directory
(
client
,
*
song
.
parent
,
song
.
uri
);
return
true
;
}
static
bool
PrintPlaylistBrief
(
struct
client
*
client
,
const
struct
playlist_metadata
*
playlist
,
const
struct
directory
*
directory
)
const
playlist_metadata
&
playlist
,
const
directory
&
directory
)
{
print_playlist_in_directory
(
client
,
directory
,
playlist
->
name
);
print_playlist_in_directory
(
client
,
directory
,
playlist
.
name
);
return
true
;
}
static
bool
PrintPlaylistFull
(
struct
client
*
client
,
const
struct
playlist_metadata
*
playlist
,
const
struct
directory
*
directory
)
const
playlist_metadata
&
playlist
,
const
directory
&
directory
)
{
print_playlist_in_directory
(
client
,
directory
,
playlist
->
name
);
print_playlist_in_directory
(
client
,
directory
,
playlist
.
name
);
#ifndef G_OS_WIN32
struct
tm
tm
;
#endif
char
timestamp
[
32
];
time_t
t
=
playlist
->
mtime
;
time_t
t
=
playlist
.
mtime
;
strftime
(
timestamp
,
sizeof
(
timestamp
),
#ifdef G_OS_WIN32
"%Y-%m-%dT%H:%M:%SZ"
,
...
...
@@ -138,15 +135,15 @@ db_selection_print(struct client *client, const struct db_selection *selection,
const
auto
p
=
std
::
bind
(
full
?
PrintPlaylistFull
:
PrintPlaylistBrief
,
client
,
_1
,
_2
);
return
GetDatabase
()
->
Visit
(
selection
,
d
,
s
,
p
,
error_r
);
return
GetDatabase
()
->
Visit
(
*
selection
,
d
,
s
,
p
,
error_r
);
}
static
bool
SearchPrintSong
(
struct
client
*
client
,
const
struct
locate_item_list
*
criteria
,
s
truct
song
*
song
)
s
ong
&
song
)
{
if
(
locate_song_search
(
song
,
criteria
))
song_print_info
(
client
,
song
);
if
(
locate_song_search
(
&
song
,
criteria
))
song_print_info
(
client
,
&
song
);
return
true
;
}
...
...
@@ -164,7 +161,7 @@ searchForSongsIn(struct client *client, const char *uri,
using
namespace
std
::
placeholders
;
const
auto
f
=
std
::
bind
(
SearchPrintSong
,
client
,
new_list
,
_1
);
bool
success
=
GetDatabase
()
->
Visit
(
&
selection
,
f
,
error_r
);
bool
success
=
GetDatabase
()
->
Visit
(
selection
,
f
,
error_r
);
locate_item_list_free
(
new_list
);
...
...
@@ -173,10 +170,10 @@ searchForSongsIn(struct client *client, const char *uri,
static
bool
MatchPrintSong
(
struct
client
*
client
,
const
struct
locate_item_list
*
criteria
,
s
truct
song
*
song
)
s
ong
&
song
)
{
if
(
locate_song_match
(
song
,
criteria
))
song_print_info
(
client
,
song
);
if
(
locate_song_match
(
&
song
,
criteria
))
song_print_info
(
client
,
&
song
);
return
true
;
}
...
...
@@ -191,7 +188,7 @@ findSongsIn(struct client *client, const char *uri,
using
namespace
std
::
placeholders
;
const
auto
f
=
std
::
bind
(
MatchPrintSong
,
client
,
criteria
,
_1
);
return
GetDatabase
()
->
Visit
(
&
selection
,
f
,
error_r
);
return
GetDatabase
()
->
Visit
(
selection
,
f
,
error_r
);
}
struct
SearchStats
{
...
...
@@ -207,11 +204,11 @@ static void printSearchStats(struct client *client, SearchStats *stats)
static
bool
stats_visitor_song
(
SearchStats
&
stats
,
const
struct
locate_item_list
*
criteria
,
s
truct
song
*
song
)
s
ong
&
song
)
{
if
(
locate_song_match
(
song
,
criteria
))
{
if
(
locate_song_match
(
&
song
,
criteria
))
{
stats
.
numberOfSongs
++
;
stats
.
playTime
+=
song_get_duration
(
song
);
stats
.
playTime
+=
song_get_duration
(
&
song
);
}
return
true
;
...
...
@@ -232,7 +229,7 @@ searchStatsForSongsIn(struct client *client, const char *name,
using
namespace
std
::
placeholders
;
const
auto
f
=
std
::
bind
(
stats_visitor_song
,
std
::
ref
(
stats
),
criteria
,
_1
);
if
(
!
GetDatabase
()
->
Visit
(
&
selection
,
f
,
error_r
))
if
(
!
GetDatabase
()
->
Visit
(
selection
,
f
,
error_r
))
return
false
;
printSearchStats
(
client
,
&
stats
);
...
...
@@ -267,13 +264,13 @@ typedef std::set<const char *, StringLess> StringSet;
static
void
visitTag
(
struct
client
*
client
,
StringSet
&
set
,
s
truct
song
*
song
,
enum
tag_type
tagType
)
s
ong
&
song
,
enum
tag_type
tagType
)
{
struct
tag
*
tag
=
song
->
tag
;
struct
tag
*
tag
=
song
.
tag
;
bool
found
=
false
;
if
(
tagType
==
LOCATE_TAG_FILE_TYPE
)
{
song_print_uri
(
client
,
song
);
song_print_uri
(
client
,
&
song
);
return
;
}
...
...
@@ -295,9 +292,9 @@ static bool
unique_tags_visitor_song
(
struct
client
*
client
,
enum
tag_type
tag_type
,
const
struct
locate_item_list
*
criteria
,
StringSet
&
set
,
s
truct
song
*
song
)
StringSet
&
set
,
s
ong
&
song
)
{
if
(
locate_song_match
(
song
,
criteria
))
if
(
locate_song_match
(
&
song
,
criteria
))
visitTag
(
client
,
set
,
song
,
tag_type
);
return
true
;
...
...
@@ -317,7 +314,7 @@ listAllUniqueTags(struct client *client, int type,
const
auto
f
=
std
::
bind
(
unique_tags_visitor_song
,
client
,
(
enum
tag_type
)
type
,
criteria
,
std
::
ref
(
set
),
_1
);
if
(
!
GetDatabase
()
->
Visit
(
&
selection
,
f
,
error_r
))
if
(
!
GetDatabase
()
->
Visit
(
selection
,
f
,
error_r
))
return
false
;
if
(
type
>=
0
&&
type
<=
TAG_NUM_OF_ITEM_TYPES
)
...
...
src/DatabaseQueue.cxx
View file @
1a75abff
...
...
@@ -32,11 +32,10 @@ extern "C" {
#include <functional>
static
bool
AddToQueue
(
struct
player_control
*
pc
,
struct
song
*
song
,
GError
**
error_r
)
AddToQueue
(
struct
player_control
*
pc
,
song
&
song
,
GError
**
error_r
)
{
enum
playlist_result
result
=
playlist_append_song
(
&
g_playlist
,
pc
,
song
,
NULL
);
playlist_append_song
(
&
g_playlist
,
pc
,
&
song
,
NULL
);
if
(
result
!=
PLAYLIST_RESULT_SUCCESS
)
{
g_set_error
(
error_r
,
playlist_quark
(),
result
,
"Playlist error"
);
...
...
@@ -54,15 +53,15 @@ addAllIn(struct player_control *pc, const char *uri, GError **error_r)
using
namespace
std
::
placeholders
;
const
auto
f
=
std
::
bind
(
AddToQueue
,
pc
,
_1
,
_2
);
return
GetDatabase
()
->
Visit
(
&
selection
,
f
,
error_r
);
return
GetDatabase
()
->
Visit
(
selection
,
f
,
error_r
);
}
static
bool
MatchAddSong
(
struct
player_control
*
pc
,
const
struct
locate_item_list
*
criteria
,
s
truct
song
*
song
,
GError
**
error_r
)
s
ong
&
song
,
GError
**
error_r
)
{
return
!
locate_song_match
(
song
,
criteria
)
||
return
!
locate_song_match
(
&
song
,
criteria
)
||
AddToQueue
(
pc
,
song
,
error_r
);
}
...
...
@@ -75,15 +74,15 @@ findAddIn(struct player_control *pc, const char *uri,
using
namespace
std
::
placeholders
;
const
auto
f
=
std
::
bind
(
MatchAddSong
,
pc
,
criteria
,
_1
,
_2
);
return
GetDatabase
()
->
Visit
(
&
selection
,
f
,
error_r
);
return
GetDatabase
()
->
Visit
(
selection
,
f
,
error_r
);
}
static
bool
SearchAddSong
(
struct
player_control
*
pc
,
const
struct
locate_item_list
*
criteria
,
s
truct
song
*
song
,
GError
**
error_r
)
s
ong
&
song
,
GError
**
error_r
)
{
return
!
locate_song_search
(
song
,
criteria
)
||
return
!
locate_song_search
(
&
song
,
criteria
)
||
AddToQueue
(
pc
,
song
,
error_r
);
}
...
...
@@ -100,7 +99,7 @@ search_add_songs(struct player_control *pc, const char *uri,
using
namespace
std
::
placeholders
;
const
auto
f
=
std
::
bind
(
SearchAddSong
,
pc
,
new_list
,
_1
,
_2
);
bool
success
=
GetDatabase
()
->
Visit
(
&
selection
,
f
,
error_r
);
bool
success
=
GetDatabase
()
->
Visit
(
selection
,
f
,
error_r
);
locate_item_list_free
(
new_list
);
...
...
src/DatabaseVisitor.hxx
View file @
1a75abff
...
...
@@ -28,8 +28,9 @@ struct directory;
struct
song
;
struct
playlist_metadata
;
typedef
std
::
function
<
bool
(
const
struct
directory
*
,
GError
**
)
>
VisitDirectory
;
typedef
std
::
function
<
bool
(
struct
song
*
,
GError
**
)
>
VisitSong
;
typedef
std
::
function
<
bool
(
const
struct
playlist_metadata
*
,
const
struct
directory
*
,
GError
**
)
>
VisitPlaylist
;
typedef
std
::
function
<
bool
(
const
directory
&
,
GError
**
)
>
VisitDirectory
;
typedef
std
::
function
<
bool
(
struct
song
&
,
GError
**
)
>
VisitSong
;
typedef
std
::
function
<
bool
(
const
playlist_metadata
&
,
const
directory
&
,
GError
**
)
>
VisitPlaylist
;
#endif
src/Directory.cxx
View file @
1a75abff
...
...
@@ -291,21 +291,21 @@ directory::Walk(bool recursive,
if
(
visit_song
)
{
struct
song
*
song
;
directory_for_each_song
(
song
,
this
)
if
(
!
visit_song
(
song
,
error_r
))
if
(
!
visit_song
(
*
song
,
error_r
))
return
false
;
}
if
(
visit_playlist
)
{
struct
playlist_metadata
*
i
;
directory_for_each_playlist
(
i
,
this
)
if
(
!
visit_playlist
(
i
,
this
,
error_r
))
if
(
!
visit_playlist
(
*
i
,
*
this
,
error_r
))
return
false
;
}
struct
directory
*
child
;
directory_for_each_child
(
child
,
this
)
{
if
(
visit_directory
&&
!
visit_directory
(
child
,
error_r
))
!
visit_directory
(
*
child
,
error_r
))
return
false
;
if
(
recursive
&&
...
...
src/Stats.cxx
View file @
1a75abff
...
...
@@ -83,12 +83,12 @@ visit_tag(StringSet &artists, StringSet &albums, const struct tag *tag)
}
static
bool
collect_stats_song
(
StringSet
&
artists
,
StringSet
&
albums
,
s
truct
song
*
song
)
collect_stats_song
(
StringSet
&
artists
,
StringSet
&
albums
,
s
ong
&
song
)
{
++
stats
.
song_count
;
if
(
song
->
tag
!=
NULL
)
visit_tag
(
artists
,
albums
,
song
->
tag
);
if
(
song
.
tag
!=
NULL
)
visit_tag
(
artists
,
albums
,
song
.
tag
);
return
true
;
}
...
...
@@ -106,7 +106,7 @@ void stats_update(void)
using
namespace
std
::
placeholders
;
const
auto
f
=
std
::
bind
(
collect_stats_song
,
std
::
ref
(
artists
),
std
::
ref
(
albums
),
_1
);
GetDatabase
()
->
Visit
(
&
selection
,
f
,
NULL
);
GetDatabase
()
->
Visit
(
selection
,
f
,
NULL
);
stats
.
artist_count
=
artists
.
size
();
stats
.
album_count
=
albums
.
size
();
...
...
src/db/SimpleDatabasePlugin.cxx
View file @
1a75abff
...
...
@@ -237,30 +237,30 @@ SimpleDatabase::LookupDirectory(const char *uri) const
}
bool
SimpleDatabase
::
Visit
(
const
struct
db_selection
*
selection
,
SimpleDatabase
::
Visit
(
const
db_selection
&
selection
,
VisitDirectory
visit_directory
,
VisitSong
visit_song
,
VisitPlaylist
visit_playlist
,
GError
**
error_r
)
const
{
const
struct
directory
*
directory
=
LookupDirectory
(
selection
->
uri
);
const
struct
directory
*
directory
=
LookupDirectory
(
selection
.
uri
);
if
(
directory
==
NULL
)
{
struct
song
*
song
;
if
(
visit_song
&&
(
song
=
GetSong
(
selection
->
uri
,
NULL
))
!=
NULL
)
return
visit_song
(
song
,
error_r
);
(
song
=
GetSong
(
selection
.
uri
,
NULL
))
!=
NULL
)
return
visit_song
(
*
song
,
error_r
);
g_set_error
(
error_r
,
db_quark
(),
DB_NOT_FOUND
,
"No such directory"
);
return
false
;
}
if
(
selection
->
recursive
&&
visit_directory
&&
!
visit_directory
(
directory
,
error_r
))
if
(
selection
.
recursive
&&
visit_directory
&&
!
visit_directory
(
*
directory
,
error_r
))
return
false
;
db_lock
();
bool
ret
=
directory
->
Walk
(
selection
->
recursive
,
bool
ret
=
directory
->
Walk
(
selection
.
recursive
,
visit_directory
,
visit_song
,
visit_playlist
,
error_r
);
db_unlock
();
...
...
src/db/SimpleDatabasePlugin.hxx
View file @
1a75abff
...
...
@@ -60,7 +60,7 @@ public:
virtual
void
Close
()
override
;
virtual
struct
song
*
GetSong
(
const
char
*
uri_utf8
,
GError
**
error_r
)
const
override
;
virtual
bool
Visit
(
const
struct
db_selection
*
selection
,
virtual
bool
Visit
(
const
db_selection
&
selection
,
VisitDirectory
visit_directory
,
VisitSong
visit_song
,
VisitPlaylist
visit_playlist
,
...
...
test/DumpDatabase.cxx
View file @
1a75abff
...
...
@@ -48,24 +48,24 @@ my_log_func(const gchar *log_domain, G_GNUC_UNUSED GLogLevelFlags log_level,
}
static
bool
DumpDirectory
(
const
struct
directory
*
directory
,
GError
**
)
DumpDirectory
(
const
directory
&
directory
,
GError
**
)
{
cout
<<
"D "
<<
directory
->
path
<<
endl
;
cout
<<
"D "
<<
directory
.
path
<<
endl
;
return
true
;
}
static
bool
DumpSong
(
s
truct
song
*
song
,
GError
**
)
DumpSong
(
s
ong
&
song
,
GError
**
)
{
cout
<<
"S "
<<
song
->
parent
->
path
<<
"/"
<<
song
->
uri
<<
endl
;
cout
<<
"S "
<<
song
.
parent
->
path
<<
"/"
<<
song
.
uri
<<
endl
;
return
true
;
}
static
bool
DumpPlaylist
(
const
struct
playlist_metadata
*
playlist
,
const
struct
directory
*
directory
,
GError
**
)
DumpPlaylist
(
const
playlist_metadata
&
playlist
,
const
directory
&
directory
,
GError
**
)
{
cout
<<
"P "
<<
directory
->
path
<<
"/"
<<
playlist
->
name
<<
endl
;
cout
<<
"P "
<<
directory
.
path
<<
"/"
<<
playlist
.
name
<<
endl
;
return
true
;
}
...
...
@@ -133,7 +133,7 @@ main(int argc, char **argv)
db_selection
selection
;
db_selection_init
(
&
selection
,
""
,
true
);
if
(
!
db
->
Visit
(
&
selection
,
DumpDirectory
,
DumpSong
,
DumpPlaylist
,
if
(
!
db
->
Visit
(
selection
,
DumpDirectory
,
DumpSong
,
DumpPlaylist
,
&
error
))
{
db
->
Close
();
delete
db
;
...
...
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