Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
converse.js
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
nexedi
converse.js
Commits
f564a1ed
Commit
f564a1ed
authored
Feb 14, 2020
by
JC Brand
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Show reason and actor for ban/kick events
parent
39d14000
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
137 additions
and
58 deletions
+137
-58
package-lock.json
package-lock.json
+81
-8
sass/_core.scss
sass/_core.scss
+3
-0
spec/muc.js
spec/muc.js
+19
-15
src/converse-muc-views.js
src/converse-muc-views.js
+0
-3
src/headless/converse-muc.js
src/headless/converse-muc.js
+29
-26
src/templates/info.html
src/templates/info.html
+2
-1
tests/mock.js
tests/mock.js
+3
-5
No files found.
package-lock.json
View file @
f564a1ed
...
...
@@ -9988,6 +9988,11 @@
"dev"
:
true
,
"optional"
:
true
},
"filesize"
:
{
"version"
:
"4.2.1"
,
"resolved"
:
"https://registry.npmjs.org/filesize/-/filesize-4.2.1.tgz"
,
"integrity"
:
"sha512-bP82Hi8VRZX/TUBKfE24iiUGsB/sfm2WUrwTQyAzQrhO3V9IhcBBNBXMyzLY5orACxRyYJ3d2HeRVX+eFv4lmA=="
},
"fill-range"
:
{
"version"
:
"4.0.0"
,
"resolved"
:
"https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz"
,
...
...
@@ -10299,7 +10304,6 @@
"version"
:
"8.1.0"
,
"resolved"
:
"https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz"
,
"integrity"
:
"sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="
,
"dev"
:
true
,
"requires"
:
{
"graceful-fs"
:
"^4.2.0"
,
"jsonfile"
:
"^4.0.0"
,
...
...
@@ -10309,8 +10313,7 @@
"graceful-fs"
:
{
"version"
:
"4.2.3"
,
"resolved"
:
"https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz"
,
"integrity"
:
"sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ=="
,
"dev"
:
true
"integrity"
:
"sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ=="
}
}
},
...
...
@@ -11535,8 +11538,7 @@
"graceful-fs"
:
{
"version"
:
"4.1.11"
,
"resolved"
:
"https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz"
,
"integrity"
:
"sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg="
,
"dev"
:
true
"integrity"
:
"sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg="
},
"handle-thing"
:
{
"version"
:
"2.0.0"
,
...
...
@@ -12004,6 +12006,11 @@
"minimatch"
:
"^3.0.4"
}
},
"immediate"
:
{
"version"
:
"3.0.6"
,
"resolved"
:
"https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz"
,
"integrity"
:
"sha1-nbHb0Pr43m++D13V5Wu2BigN5ps="
},
"import-cwd"
:
{
"version"
:
"2.1.0"
,
"resolved"
:
"https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz"
,
...
...
@@ -12567,6 +12574,11 @@
"integrity"
:
"sha1-5kAN8ea1bhMLYcS80JPap/boyhU="
,
"dev"
:
true
},
"jed"
:
{
"version"
:
"1.1.1"
,
"resolved"
:
"https://registry.npmjs.org/jed/-/jed-1.1.1.tgz"
,
"integrity"
:
"sha1-elSbvZ/+FYWwzQoZHiAwVb7ldLQ="
},
"jest-worker"
:
{
"version"
:
"25.1.0"
,
"resolved"
:
"https://registry.npmjs.org/jest-worker/-/jest-worker-25.1.0.tgz"
,
...
...
@@ -12726,7 +12738,6 @@
"version"
:
"4.0.0"
,
"resolved"
:
"https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz"
,
"integrity"
:
"sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss="
,
"dev"
:
true
,
"requires"
:
{
"graceful-fs"
:
"^4.1.6"
}
...
...
@@ -12963,6 +12974,14 @@
"type-check"
:
"~0.3.2"
}
},
"lie"
:
{
"version"
:
"3.1.1"
,
"resolved"
:
"https://registry.npmjs.org/lie/-/lie-3.1.1.tgz"
,
"integrity"
:
"sha1-mkNrLMd0bKWd56QfpGmz77dr2H4="
,
"requires"
:
{
"immediate"
:
"~3.0.5"
}
},
"linkify-it"
:
{
"version"
:
"2.2.0"
,
"resolved"
:
"https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz"
,
...
...
@@ -13025,6 +13044,14 @@
"json5"
:
"^0.5.0"
}
},
"localforage"
:
{
"version"
:
"1.7.3"
,
"resolved"
:
"https://registry.npmjs.org/localforage/-/localforage-1.7.3.tgz"
,
"integrity"
:
"sha512-1TulyYfc4udS7ECSBT2vwJksWbkwwTX8BzeUIiq8Y07Riy7bDAAnxDaPU/tWyOVmQAcWJIEIFP9lPfBGqVoPgQ=="
,
"requires"
:
{
"lie"
:
"3.1.1"
}
},
"locate-path"
:
{
"version"
:
"3.0.0"
,
"resolved"
:
"https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz"
,
...
...
@@ -19160,6 +19187,14 @@
}
}
},
"pluggable.js"
:
{
"version"
:
"2.0.1"
,
"resolved"
:
"https://registry.npmjs.org/pluggable.js/-/pluggable.js-2.0.1.tgz"
,
"integrity"
:
"sha512-SBt6v6Tbp20Jf8hU0cpcc/+HBHGMY8/Q+yA6Ih0tBQE8tfdZ6U4PRG0iNvUUjLx/hVyOP53n0UfGBymlfaaXCg=="
,
"requires"
:
{
"lodash"
:
"^4.17.11"
}
},
"po-loader"
:
{
"version"
:
"0.5.0"
,
"resolved"
:
"https://registry.npmjs.org/po-loader/-/po-loader-0.5.0.tgz"
,
...
...
@@ -21068,6 +21103,13 @@
"integrity"
:
"sha512-Mf37VjirD7RqCVeYgI8jb5K0DymIho/jNJqDgIkMs4cgKbEkvsow8Q6hpvF7Zmys9iEif0oW41hgbeWVZwABJw=="
,
"dev"
:
true
},
"skeletor.js"
:
{
"version"
:
"github:skeletorjs/skeletor#dea2d5791ee894493e30b92662c953efec0e58f6"
,
"from"
:
"github:skeletorjs/skeletor#dea2d5791ee894493e30b92662c953efec0e58f6"
,
"requires"
:
{
"lodash"
:
"^4.17.14"
}
},
"slash"
:
{
"version"
:
"2.0.0"
,
"resolved"
:
"https://registry.npmjs.org/slash/-/slash-2.0.0.tgz"
,
...
...
@@ -21742,6 +21784,11 @@
"through"
:
"^2.3.4"
}
},
"strophe.js"
:
{
"version"
:
"1.3.4"
,
"resolved"
:
"https://registry.npmjs.org/strophe.js/-/strophe.js-1.3.4.tgz"
,
"integrity"
:
"sha512-jSLDG8jolhAwGOSgiJ7DTMSYK3wVoEJHKtpVRyEacQZ6CWA6z2WRPJpcFMjsIweq5aP9/XIvKUQqHBu/ZhvESA=="
},
"style-loader"
:
{
"version"
:
"0.23.1"
,
"resolved"
:
"https://registry.npmjs.org/style-loader/-/style-loader-0.23.1.tgz"
,
...
...
@@ -22195,6 +22242,33 @@
"integrity"
:
"sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
,
"dev"
:
true
},
"twemoji"
:
{
"version"
:
"12.1.5"
,
"resolved"
:
"https://registry.npmjs.org/twemoji/-/twemoji-12.1.5.tgz"
,
"integrity"
:
"sha512-B0PBVy5xomwb1M/WZxf/IqPZfnoIYy1skXnlHjMwLwTNfZ9ljh8VgWQktAPcJXu8080WoEh6YwQGPVhDVqvrVQ=="
,
"requires"
:
{
"fs-extra"
:
"^8.0.1"
,
"jsonfile"
:
"^5.0.0"
,
"twemoji-parser"
:
"12.1.3"
,
"universalify"
:
"^0.1.2"
},
"dependencies"
:
{
"jsonfile"
:
{
"version"
:
"5.0.0"
,
"resolved"
:
"https://registry.npmjs.org/jsonfile/-/jsonfile-5.0.0.tgz"
,
"integrity"
:
"sha512-NQRZ5CRo74MhMMC3/3r5g2k4fjodJ/wh8MxjFbCViWKFjxrnudWSY5vomh+23ZaXzAS7J3fBZIR2dV6WbmfM0w=="
,
"requires"
:
{
"graceful-fs"
:
"^4.1.6"
,
"universalify"
:
"^0.1.2"
}
}
}
},
"twemoji-parser"
:
{
"version"
:
"12.1.3"
,
"resolved"
:
"https://registry.npmjs.org/twemoji-parser/-/twemoji-parser-12.1.3.tgz"
,
"integrity"
:
"sha512-ND4LZXF4X92/PFrzSgGkq6KPPg8swy/U0yRw1k/+izWRVmq1HYi3khPwV3XIB6FRudgVICAaBhJfW8e8G3HC7Q=="
},
"type-check"
:
{
"version"
:
"0.3.2"
,
"resolved"
:
"https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz"
,
...
...
@@ -22415,8 +22489,7 @@
"universalify"
:
{
"version"
:
"0.1.2"
,
"resolved"
:
"https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz"
,
"integrity"
:
"sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
,
"dev"
:
true
"integrity"
:
"sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
},
"unpipe"
:
{
"version"
:
"1.0.0"
,
...
...
sass/_core.scss
View file @
f564a1ed
...
...
@@ -333,6 +333,9 @@ body.converse-fullscreen {
q
{
quotes
:
"“"
"”"
"‘"
"’"
;
&
.reason
{
display
:
block
;
}
}
q
:before
{
content
:
open-quote
;
...
...
spec/muc.js
View file @
f564a1ed
...
...
@@ -3512,20 +3512,23 @@
`</iq>`
);
presence
=
$pres
({
'
from
'
:
'
lounge@montague.lit/annoyingGuy
'
,
'
id
'
:
'
27C55F89-1C6A-459A-9EB5-77690145D628
'
,
'
to
'
:
'
romeo@montague.lit/desktop
'
})
.
c
(
'
x
'
,
{
'
xmlns
'
:
'
http://jabber.org/protocol/muc#user
'
})
.
c
(
'
item
'
,
{
'
jid
'
:
'
annoyingguy@montague.lit
'
,
'
affiliation
'
:
'
outcast
'
,
'
role
'
:
'
participant
'
});
'
from
'
:
'
lounge@montague.lit/annoyingGuy
'
,
'
id
'
:
'
27C55F89-1C6A-459A-9EB5-77690145D628
'
,
'
to
'
:
'
romeo@montague.lit/desktop
'
}).
c
(
'
x
'
,
{
'
xmlns
'
:
'
http://jabber.org/protocol/muc#user
'
})
.
c
(
'
item
'
,
{
'
jid
'
:
'
annoyingguy@montague.lit
'
,
'
affiliation
'
:
'
outcast
'
,
'
role
'
:
'
participant
'
}).
c
(
'
actor
'
,
{
'
nick
'
:
'
romeo
'
}).
up
()
.
c
(
'
reason
'
).
t
(
"
You're annoying
"
).
up
().
up
()
.
c
(
'
status
'
,
{
'
code
'
:
'
301
'
});
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
presence
));
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-info
'
)[
3
].
textContent
.
trim
()).
toBe
(
"
annoyingGuy has been banned from this groupchat
"
);
await
u
.
waitUntil
(()
=>
view
.
el
.
querySelectorAll
(
'
.chat-info
'
).
length
===
4
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-info__message
'
)[
2
].
textContent
.
trim
()).
toBe
(
"
annoyingGuy has been banned by romeo
"
);
expect
(
view
.
el
.
querySelector
(
'
.chat-info:last-child q
'
).
textContent
.
trim
()).
toBe
(
"
You're annoying
"
);
presence
=
$pres
({
'
from
'
:
'
lounge@montague.lit/joe2
'
,
'
id
'
:
'
27C55F89-1C6A-459A-9EB5-77690145D624
'
,
...
...
@@ -3628,13 +3631,14 @@
.
c
(
'
item
'
,
{
'
affiliation
'
:
'
none
'
,
'
role
'
:
'
none
'
}).
up
()
}).
c
(
'
actor
'
,
{
'
nick
'
:
'
romeo
'
}).
up
()
.
c
(
'
reason
'
).
t
(
"
You're annoying
"
).
up
().
up
()
.
c
(
'
status
'
,
{
'
code
'
:
'
307
'
});
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
presence
));
await
u
.
waitUntil
(()
=>
view
.
el
.
querySelectorAll
(
'
.chat-info
'
).
length
===
4
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-info
'
)[
3
].
textContent
.
trim
()).
toBe
(
"
annoying guy has been kicked out
"
);
expect
(
view
.
el
.
querySelector
All
(
'
.chat-info
'
).
length
).
toBe
(
4
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-info
__message
'
)[
2
].
textContent
.
trim
()).
toBe
(
"
annoying guy has been kicked out by romeo
"
);
expect
(
view
.
el
.
querySelector
(
'
.chat-info:last-child q
'
).
textContent
.
trim
()).
toBe
(
"
You're annoying
"
);
done
();
}));
...
...
src/converse-muc-views.js
View file @
f564a1ed
...
...
@@ -1064,13 +1064,10 @@ converse.plugins.add('converse-muc-views', {
}
else
if
(
previous_affiliation
===
'
outcast
'
)
{
this
.
showChatEvent
(
__
(
"
%1$s is no longer banned from this groupchat
"
,
occupant
.
get
(
'
nick
'
)))
}
if
(
current_affiliation
===
'
none
'
&&
previous_affiliation
===
'
member
'
)
{
this
.
showChatEvent
(
__
(
"
%1$s is no longer a member of this groupchat
"
,
occupant
.
get
(
'
nick
'
)))
}
if
(
current_affiliation
===
'
member
'
)
{
this
.
showChatEvent
(
__
(
"
%1$s is now a member of this groupchat
"
,
occupant
.
get
(
'
nick
'
)))
}
else
if
(
current_affiliation
===
'
outcast
'
)
{
this
.
showChatEvent
(
__
(
"
%1$s has been banned from this groupchat
"
,
occupant
.
get
(
'
nick
'
)))
}
else
if
(
current_affiliation
===
'
admin
'
||
current_affiliation
==
'
owner
'
)
{
// For example: AppleJack is now an (admin|owner) of this groupchat
this
.
showChatEvent
(
__
(
'
%1$s is now an %2$s of this groupchat
'
,
occupant
.
get
(
'
nick
'
),
current_affiliation
))
...
...
src/headless/converse-muc.js
View file @
f564a1ed
...
...
@@ -180,14 +180,7 @@ converse.plugins.add('converse-muc', {
332
:
__
(
"
You have been removed from this groupchat because the service hosting it is being shut down
"
)
},
action_info_messages
:
{
// XXX: Note the triple underscore function and not double underscore.
301
:
___
(
"
%1$s has been banned
"
),
303
:
___
(
"
%1$s's nickname has changed
"
),
307
:
___
(
"
%1$s has been kicked out
"
),
321
:
___
(
"
%1$s has been removed because of an affiliation change
"
),
322
:
___
(
"
%1$s has been removed for not being a member
"
)
}
action_info_codes
:
[
'
301
'
,
'
303
'
,
'
307
'
,
'
321
'
,
'
322
'
]
}
...
...
@@ -1815,6 +1808,21 @@ converse.plugins.add('converse-muc', {
},
getActionInfoMessage
(
code
,
nick
,
actor
)
{
if
(
code
===
'
301
'
)
{
return
actor
?
__
(
"
%1$s has been banned by %2$s
"
,
nick
,
actor
)
:
__
(
"
%1$s has been banned
"
,
nick
);
}
else
if
(
code
===
'
303
'
)
{
return
___
(
"
%1$s's nickname has changed
"
);
}
else
if
(
code
===
'
307
'
)
{
return
actor
?
__
(
"
%1$s has been kicked out by %2$s
"
,
nick
,
actor
)
:
__
(
"
%1$s has been kicked out
"
,
nick
);
}
else
if
(
code
===
'
321
'
)
{
return
__
(
"
%1$s has been removed because of an affiliation change
"
);
}
else
if
(
code
===
'
322
'
)
{
return
___
(
"
%1$s has been removed for not being a member
"
);
}
},
/**
* Create info messages based on a received presence stanza
* @private
...
...
@@ -1829,24 +1837,19 @@ converse.plugins.add('converse-muc', {
}
const
codes
=
sizzle
(
'
status
'
,
x
).
map
(
s
=>
s
.
getAttribute
(
'
code
'
));
codes
.
forEach
(
code
=>
{
let
message
;
const
data
=
{
'
type
'
:
'
info
'
};
if
(
code
===
'
110
'
||
(
code
===
'
100
'
&&
!
is_self
))
{
return
;
}
else
if
(
code
in
_converse
.
muc
.
info_messages
)
{
message
=
_converse
.
muc
.
info_messages
[
code
];
}
else
if
(
!
is_self
&&
(
code
in
_converse
.
muc
.
action_info_messages
))
{
data
.
message
=
_converse
.
muc
.
info_messages
[
code
];
}
else
if
(
!
is_self
&&
_converse
.
muc
.
action_info_codes
.
includes
(
code
))
{
const
nick
=
Strophe
.
getResourceFromJid
(
stanza
.
getAttribute
(
'
from
'
));
message
=
__
(
_converse
.
muc
.
action_info_messages
[
code
],
nick
);
const
item
=
x
.
querySelector
(
'
item
'
);
const
reason
=
item
?
get
(
item
.
querySelector
(
'
reason
'
),
'
textContent
'
)
:
undefined
;
const
actor
=
item
?
invoke
(
item
.
querySelector
(
'
actor
'
),
'
getAttribute
'
,
'
nick
'
)
:
undefined
;
if
(
actor
)
{
message
+=
'
\n
'
+
__
(
'
This action was done by %1$s.
'
,
actor
);
}
if
(
reason
)
{
message
+=
'
\n
'
+
__
(
'
The reason given is: "%1$s".
'
,
reason
);
}
data
.
actor
=
item
?
invoke
(
item
.
querySelector
(
'
actor
'
),
'
getAttribute
'
,
'
nick
'
)
:
undefined
;
data
.
reason
=
item
?
get
(
item
.
querySelector
(
'
reason
'
),
'
textContent
'
)
:
undefined
;
data
.
message
=
this
.
getActionInfoMessage
(
code
,
nick
,
data
.
actor
);
}
else
if
(
is_self
&&
(
code
in
_converse
.
muc
.
new_nickname_messages
))
{
let
nick
;
if
(
is_self
&&
code
===
"
210
"
)
{
...
...
@@ -1855,18 +1858,18 @@ converse.plugins.add('converse-muc', {
nick
=
stanza
.
querySelector
(
'
x item
'
).
getAttribute
(
'
nick
'
);
}
this
.
save
(
'
nick
'
,
nick
);
message
=
__
(
_converse
.
muc
.
new_nickname_messages
[
code
],
nick
);
data
.
message
=
__
(
_converse
.
muc
.
new_nickname_messages
[
code
],
nick
);
}
if
(
message
)
{
if
(
code
===
"
201
"
&&
this
.
messages
.
findWhere
(
{
'
type
'
:
'
info
'
,
message
}
))
{
if
(
data
.
message
)
{
if
(
code
===
"
201
"
&&
this
.
messages
.
findWhere
(
data
))
{
return
;
}
else
if
(
code
in
_converse
.
muc
.
info_messages
&&
this
.
messages
.
length
&&
this
.
messages
.
pop
().
get
(
'
message
'
)
===
message
)
{
this
.
messages
.
pop
().
get
(
'
message
'
)
===
data
.
message
)
{
// XXX: very naive duplication checking
return
;
}
this
.
messages
.
create
(
{
'
type
'
:
'
info
'
,
message
}
);
this
.
messages
.
create
(
data
);
}
});
},
...
...
src/templates/info.html
View file @
f564a1ed
...
...
@@ -4,7 +4,8 @@
]}
{{o.message}}
{[ } else { ]}
{{{o.message}}}
<div
class=
"chat-info__message"
>
{{{o.message}}}
</div>
{[ if (o.reason) { ]}
<q
class=
"reason"
>
{{{o.reason}}}
</q>
{[ } ]}
{[ } ]}
{[ if (o.retry) { ]}
<a
class=
"retry"
>
Retry
</a>
...
...
tests/mock.js
View file @
f564a1ed
...
...
@@ -315,10 +315,9 @@
}
return
async
done
=>
{
let
_converse
;
const
_converse
=
await
initConverse
(
settings
);
async
function
_done
()
{
if
(
_converse
&&
_converse
.
api
.
connection
.
connected
())
{
if
(
_converse
.
api
.
connection
.
connected
())
{
await
_converse
.
api
.
user
.
logout
();
}
const
el
=
document
.
querySelector
(
'
#conversejs
'
);
...
...
@@ -328,9 +327,8 @@
document
.
title
=
"
Converse Tests
"
;
done
();
}
await
Promise
.
all
((
promise_names
||
[]).
map
(
_converse
.
api
.
waitUntil
));
try
{
_converse
=
await
initConverse
(
settings
);
await
Promise
.
all
((
promise_names
||
[]).
map
(
_converse
.
api
.
waitUntil
));
await
func
(
_done
,
_converse
);
}
catch
(
e
)
{
console
.
error
(
e
);
...
...
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