Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
M
mycard
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
9
Issues
9
List
Boards
Labels
Service Desk
Milestones
Merge Requests
2
Merge Requests
2
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
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
MyCard
mycard
Commits
27727a69
Commit
27727a69
authored
Aug 27, 2021
by
神楽坂玲奈
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
candy libs
parent
f6b0a765
Pipeline
#5087
passed with stages
in 7 minutes and 31 seconds
Changes
5
Pipelines
1
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
1152 additions
and
22 deletions
+1152
-22
app/candy.component.ts
app/candy.component.ts
+42
-8
date.format.js
date.format.js
+126
-0
package-lock.json
package-lock.json
+968
-9
package.json
package.json
+8
-2
systemjs.config.js
systemjs.config.js
+8
-3
No files found.
app/candy.component.ts
View file @
27727a69
...
@@ -23,11 +23,24 @@ $.fn.init = new Proxy($.fn.init, {
...
@@ -23,11 +23,24 @@ $.fn.init = new Proxy($.fn.init, {
window
[
'
jQuery
'
]
=
$
;
window
[
'
jQuery
'
]
=
$
;
const
Mustache
=
require
(
'
mustache
'
);
window
[
'
Mustache
'
]
=
Mustache
;
import
{
Component
,
ElementRef
,
Input
,
OnChanges
,
OnInit
,
SimpleChanges
,
ViewEncapsulation
}
from
'
@angular/core
'
;
import
{
Component
,
ElementRef
,
Input
,
OnChanges
,
OnInit
,
SimpleChanges
,
ViewEncapsulation
}
from
'
@angular/core
'
;
import
{
LoginService
}
from
'
./login.service
'
;
import
{
LoginService
}
from
'
./login.service
'
;
import
{
SettingsService
}
from
'
./settings.sevices
'
;
import
{
SettingsService
}
from
'
./settings.sevices
'
;
import
{
App
}
from
'
./app
'
;
import
{
App
}
from
'
./app
'
;
import
'
node_modules/candy/libs.min.js
'
;
// candy libs
import
'
strophe.js
'
;
import
'
strophejs-plugin-disco
'
;
import
'
strophejs-plugin-roster
'
;
import
'
strophejs-plugin-muc
'
;
import
'
strophejs-plugin-caps
'
;
import
'
jquery-i18n
'
;
import
'
date.format.js
'
;
// candy
import
'
node_modules/candy/candy.min.js
'
;
import
'
node_modules/candy/candy.min.js
'
;
import
'
node_modules/candy-shop/notifyme/candy.js
'
;
import
'
node_modules/candy-shop/notifyme/candy.js
'
;
import
'
node_modules/candy-shop/namecomplete/candy.js
'
;
import
'
node_modules/candy-shop/namecomplete/candy.js
'
;
...
@@ -35,15 +48,34 @@ import 'node_modules/candy-shop/modify-role/candy.js';
...
@@ -35,15 +48,34 @@ import 'node_modules/candy-shop/modify-role/candy.js';
import
'
node_modules/candy-shop/me-does/candy.js
'
;
import
'
node_modules/candy-shop/me-does/candy.js
'
;
import
'
node_modules/candy-shop/notifications/candy.js
'
;
import
'
node_modules/candy-shop/notifications/candy.js
'
;
import
'
node_modules/candy-shop/refocus/candy.js
'
;
import
'
node_modules/candy-shop/refocus/candy.js
'
;
// @ts-ignore
// window.Base64 = {
// encode: (data: string) => Buffer.from(data).toString('base64'),
// decode: (data: string) => Buffer.from(data, 'base64').toString()
// };
import
*
as
crypto
from
'
crypto
'
;
delete
window
[
'
jQuery
'
];
delete
window
[
'
jQuery
'
];
// Candy fix
// Candy fix
declare
const
Candy
:
any
,
CandyShop
:
any
,
Base64
:
any
;
declare
const
Candy
:
any
,
CandyShop
:
any
;
window
[
'
MD5
'
]
=
{
hexdigest
(
s
:
string
)
{
return
crypto
.
createHash
(
'
sha256
'
).
update
(
s
).
digest
(
'
hex
'
);
}
};
Base64
.
encode
=
(
data
:
string
)
=>
Buffer
.
from
(
data
).
toString
(
'
base64
'
);
Mustache
.
to_html
=
function
(
template
,
view
,
partials
,
send
)
{
Base64
.
decode
=
(
data
:
string
)
=>
Buffer
.
from
(
data
,
'
base64
'
).
toString
();
const
result
=
Mustache
.
render
(
template
,
view
,
partials
);
if
(
typeof
send
===
'
function
'
)
{
send
(
result
);
}
else
{
return
result
;
}
};
Candy
.
Util
.
getPosLeftAccordingToWindowBounds
=
new
Proxy
(
Candy
.
Util
.
getPosLeftAccordingToWindowBounds
,
{
Candy
.
Util
.
getPosLeftAccordingToWindowBounds
=
new
Proxy
(
Candy
.
Util
.
getPosLeftAccordingToWindowBounds
,
{
apply
(
target
,
thisArg
,
argumentsList
)
{
apply
(
target
,
thisArg
,
argumentsList
)
{
...
@@ -63,9 +95,9 @@ Candy.View.Pane.Roster.joinAnimation = function () {
...
@@ -63,9 +95,9 @@ Candy.View.Pane.Roster.joinAnimation = function () {
};
};
// 性能优化:禁用用户排序
// 性能优化:禁用用户排序
declare
const
Mustache
:
any
;
Candy
.
View
.
Pane
.
Roster
.
_insertUser
=
function
(
roomJid
:
string
,
roomId
:
string
,
user
:
any
,
userId
:
string
,
currentUser
:
any
)
{
Candy
.
View
.
Pane
.
Roster
.
_insertUser
=
function
(
roomJid
:
string
,
roomId
:
string
,
user
:
any
,
userId
:
string
,
currentUser
:
any
)
{
let
contact
=
user
.
getContact
();
let
contact
=
user
.
getContact
();
// @ts-ignore
let
html
=
Mustache
.
to_html
(
Candy
.
View
.
Template
.
Roster
.
user
,
{
let
html
=
Mustache
.
to_html
(
Candy
.
View
.
Template
.
Roster
.
user
,
{
roomId
:
roomId
,
roomId
:
roomId
,
userId
:
userId
,
userId
:
userId
,
...
@@ -98,8 +130,8 @@ Candy.View.Pane.Chat.increaseUnreadMessages = function (roomJid: string) {
...
@@ -98,8 +130,8 @@ Candy.View.Pane.Chat.increaseUnreadMessages = function (roomJid: string) {
// 性能优化:将收到消息时的滚动放进requestIdleCallback
// 性能优化:将收到消息时的滚动放进requestIdleCallback
declare
const
requestIdleCallback
:
Function
;
declare
const
requestIdleCallback
:
Function
;
Candy
.
View
.
Pane
.
Message
.
// tslint:disable-next-line:max-line-length
show
=
function
(
roomJid
:
any
,
name
:
any
,
message
:
any
,
xhtmlMessage
:
any
,
timestamp
:
any
,
from
:
any
,
carbon
:
any
,
stanza
:
any
)
{
Candy
.
View
.
Pane
.
Message
.
show
=
function
(
roomJid
:
any
,
name
:
any
,
message
:
any
,
xhtmlMessage
:
any
,
timestamp
:
any
,
from
:
any
,
carbon
:
any
,
stanza
:
any
)
{
message
=
Candy
.
Util
.
Parser
.
all
(
message
.
substring
(
0
,
Candy
.
View
.
getOptions
().
crop
.
message
.
body
));
message
=
Candy
.
Util
.
Parser
.
all
(
message
.
substring
(
0
,
Candy
.
View
.
getOptions
().
crop
.
message
.
body
));
if
(
Candy
.
View
.
getOptions
().
enableXHTML
===
true
&&
xhtmlMessage
)
{
if
(
Candy
.
View
.
getOptions
().
enableXHTML
===
true
&&
xhtmlMessage
)
{
xhtmlMessage
=
Candy
.
Util
.
parseAndCropXhtml
(
xhtmlMessage
,
Candy
.
View
.
getOptions
().
crop
.
message
.
body
);
xhtmlMessage
=
Candy
.
Util
.
parseAndCropXhtml
(
xhtmlMessage
,
Candy
.
View
.
getOptions
().
crop
.
message
.
body
);
...
@@ -152,6 +184,7 @@ Candy.View.Pane.Message.
...
@@ -152,6 +184,7 @@ Candy.View.Pane.Message.
stanza
:
stanza
stanza
:
stanza
};
};
$
(
Candy
).
triggerHandler
(
'
candy:view.message.before-render
'
,
renderEvtData
);
$
(
Candy
).
triggerHandler
(
'
candy:view.message.before-render
'
,
renderEvtData
);
// @ts-ignore
let
html
=
Mustache
.
to_html
(
renderEvtData
.
template
,
renderEvtData
.
templateData
);
let
html
=
Mustache
.
to_html
(
renderEvtData
.
template
,
renderEvtData
.
templateData
);
Candy
.
View
.
Pane
.
Room
.
appendToMessagePane
(
roomJid
,
html
);
Candy
.
View
.
Pane
.
Room
.
appendToMessagePane
(
roomJid
,
html
);
let
elem
=
Candy
.
View
.
Pane
.
Room
.
getPane
(
roomJid
,
'
.message-pane
'
).
children
().
last
();
let
elem
=
Candy
.
View
.
Pane
.
Room
.
getPane
(
roomJid
,
'
.message-pane
'
).
children
().
last
();
...
@@ -340,6 +373,7 @@ export class CandyComponent implements OnInit, OnChanges {
...
@@ -340,6 +373,7 @@ export class CandyComponent implements OnInit, OnChanges {
$
(
'
#restore
'
).
hide
();
$
(
'
#restore
'
).
hide
();
$
(
'
#maximize
'
).
show
();
$
(
'
#maximize
'
).
show
();
}
}
restore
():
void
{
restore
():
void
{
$
(
'
#candy
'
).
attr
(
'
data-minormax
'
,
'
default
'
);
$
(
'
#candy
'
).
attr
(
'
data-minormax
'
,
'
default
'
);
document
.
getElementById
(
'
candy-wrapper
'
)
!
.
style
!
.
height
=
this
.
height_default_window
;
document
.
getElementById
(
'
candy-wrapper
'
)
!
.
style
!
.
height
=
this
.
height_default_window
;
...
@@ -357,7 +391,7 @@ export class CandyComponent implements OnInit, OnChanges {
...
@@ -357,7 +391,7 @@ export class CandyComponent implements OnInit, OnChanges {
maximize
():
void
{
maximize
():
void
{
$
(
'
#candy
'
).
attr
(
'
data-minormax
'
,
'
max
'
);
$
(
'
#candy
'
).
attr
(
'
data-minormax
'
,
'
max
'
);
document
.
getElementById
(
'
candy-wrapper
'
)
!
.
style
!
.
height
=
'
calc( 100% - 180px )
'
;
document
.
getElementById
(
'
candy-wrapper
'
)
!
.
style
!
.
height
=
'
calc( 100% - 180px )
'
;
$
(
'
#mobile-roster-icon
'
).
css
(
'
display
'
,
'
block
'
);
$
(
'
#mobile-roster-icon
'
).
css
(
'
display
'
,
'
block
'
);
$
(
'
#chat-toolbar
'
).
css
(
'
display
'
,
'
block
'
);
$
(
'
#chat-toolbar
'
).
css
(
'
display
'
,
'
block
'
);
$
(
'
#chat-rooms
'
).
css
(
'
display
'
,
'
block
'
);
$
(
'
#chat-rooms
'
).
css
(
'
display
'
,
'
block
'
);
...
...
date.format.js
0 → 100644
View file @
27727a69
/*
* Date Format 1.2.3
* (c) 2007-2009 Steven Levithan <stevenlevithan.com>
* MIT license
*
* Includes enhancements by Scott Trenda <scott.trenda.net>
* and Kris Kowal <cixar.com/~kris.kowal/>
*
* Accepts a date, a mask, or a date and a mask.
* Returns a formatted version of the given date.
* The date defaults to the current date/time.
* The mask defaults to dateFormat.masks.default.
*/
var
dateFormat
=
function
()
{
var
token
=
/d
{1,4}
|m
{1,4}
|yy
(?:
yy
)?
|
([
HhMsTt
])\1?
|
[
LloSZ
]
|"
[^
"
]
*"|'
[^
'
]
*'/g
,
timezone
=
/
\b(?:[
PMCEA
][
SDP
]
T|
(?:
Pacific|Mountain|Central|Eastern|Atlantic
)
(?:
Standard|Daylight|Prevailing
)
Time|
(?:
GMT|UTC
)(?:[
-+
]\d{4})?)\b
/g
,
timezoneClip
=
/
[^
-+
\d
A-Z
]
/g
,
pad
=
function
(
val
,
len
)
{
val
=
String
(
val
);
len
=
len
||
2
;
while
(
val
.
length
<
len
)
val
=
"
0
"
+
val
;
return
val
;
};
// Regexes and supporting functions are cached through closure
return
function
(
date
,
mask
,
utc
)
{
var
dF
=
dateFormat
;
// You can't provide utc if you skip other args (use the "UTC:" mask prefix)
if
(
arguments
.
length
==
1
&&
Object
.
prototype
.
toString
.
call
(
date
)
==
"
[object String]
"
&&
!
/
\d
/
.
test
(
date
))
{
mask
=
date
;
date
=
undefined
;
}
// Passing date through Date applies Date.parse, if necessary
date
=
date
?
new
Date
(
date
)
:
new
Date
;
if
(
isNaN
(
date
))
throw
SyntaxError
(
"
invalid date
"
);
mask
=
String
(
dF
.
masks
[
mask
]
||
mask
||
dF
.
masks
[
"
default
"
]);
// Allow setting the utc argument via the mask
if
(
mask
.
slice
(
0
,
4
)
==
"
UTC:
"
)
{
mask
=
mask
.
slice
(
4
);
utc
=
true
;
}
var
_
=
utc
?
"
getUTC
"
:
"
get
"
,
d
=
date
[
_
+
"
Date
"
](),
D
=
date
[
_
+
"
Day
"
](),
m
=
date
[
_
+
"
Month
"
](),
y
=
date
[
_
+
"
FullYear
"
](),
H
=
date
[
_
+
"
Hours
"
](),
M
=
date
[
_
+
"
Minutes
"
](),
s
=
date
[
_
+
"
Seconds
"
](),
L
=
date
[
_
+
"
Milliseconds
"
](),
o
=
utc
?
0
:
date
.
getTimezoneOffset
(),
flags
=
{
d
:
d
,
dd
:
pad
(
d
),
ddd
:
dF
.
i18n
.
dayNames
[
D
],
dddd
:
dF
.
i18n
.
dayNames
[
D
+
7
],
m
:
m
+
1
,
mm
:
pad
(
m
+
1
),
mmm
:
dF
.
i18n
.
monthNames
[
m
],
mmmm
:
dF
.
i18n
.
monthNames
[
m
+
12
],
yy
:
String
(
y
).
slice
(
2
),
yyyy
:
y
,
h
:
H
%
12
||
12
,
hh
:
pad
(
H
%
12
||
12
),
H
:
H
,
HH
:
pad
(
H
),
M
:
M
,
MM
:
pad
(
M
),
s
:
s
,
ss
:
pad
(
s
),
l
:
pad
(
L
,
3
),
L
:
pad
(
L
>
99
?
Math
.
round
(
L
/
10
)
:
L
),
t
:
H
<
12
?
"
a
"
:
"
p
"
,
tt
:
H
<
12
?
"
am
"
:
"
pm
"
,
T
:
H
<
12
?
"
A
"
:
"
P
"
,
TT
:
H
<
12
?
"
AM
"
:
"
PM
"
,
Z
:
utc
?
"
UTC
"
:
(
String
(
date
).
match
(
timezone
)
||
[
""
]).
pop
().
replace
(
timezoneClip
,
""
),
o
:
(
o
>
0
?
"
-
"
:
"
+
"
)
+
pad
(
Math
.
floor
(
Math
.
abs
(
o
)
/
60
)
*
100
+
Math
.
abs
(
o
)
%
60
,
4
),
S
:
[
"
th
"
,
"
st
"
,
"
nd
"
,
"
rd
"
][
d
%
10
>
3
?
0
:
(
d
%
100
-
d
%
10
!=
10
)
*
d
%
10
]
};
return
mask
.
replace
(
token
,
function
(
$0
)
{
return
$0
in
flags
?
flags
[
$0
]
:
$0
.
slice
(
1
,
$0
.
length
-
1
);
});
};
}();
// Some common format strings
dateFormat
.
masks
=
{
"
default
"
:
"
ddd mmm dd yyyy HH:MM:ss
"
,
shortDate
:
"
m/d/yy
"
,
mediumDate
:
"
mmm d, yyyy
"
,
longDate
:
"
mmmm d, yyyy
"
,
fullDate
:
"
dddd, mmmm d, yyyy
"
,
shortTime
:
"
h:MM TT
"
,
mediumTime
:
"
h:MM:ss TT
"
,
longTime
:
"
h:MM:ss TT Z
"
,
isoDate
:
"
yyyy-mm-dd
"
,
isoTime
:
"
HH:MM:ss
"
,
isoDateTime
:
"
yyyy-mm-dd'T'HH:MM:ss
"
,
isoUtcDateTime
:
"
UTC:yyyy-mm-dd'T'HH:MM:ss'Z'
"
};
// Internationalization strings
dateFormat
.
i18n
=
{
dayNames
:
[
"
Sun
"
,
"
Mon
"
,
"
Tue
"
,
"
Wed
"
,
"
Thu
"
,
"
Fri
"
,
"
Sat
"
,
"
Sunday
"
,
"
Monday
"
,
"
Tuesday
"
,
"
Wednesday
"
,
"
Thursday
"
,
"
Friday
"
,
"
Saturday
"
],
monthNames
:
[
"
Jan
"
,
"
Feb
"
,
"
Mar
"
,
"
Apr
"
,
"
May
"
,
"
Jun
"
,
"
Jul
"
,
"
Aug
"
,
"
Sep
"
,
"
Oct
"
,
"
Nov
"
,
"
Dec
"
,
"
January
"
,
"
February
"
,
"
March
"
,
"
April
"
,
"
May
"
,
"
June
"
,
"
July
"
,
"
August
"
,
"
September
"
,
"
October
"
,
"
November
"
,
"
December
"
]
};
// For convenience...
Date
.
prototype
.
format
=
function
(
mask
,
utc
)
{
return
dateFormat
(
this
,
mask
,
utc
);
};
package-lock.json
View file @
27727a69
This diff is collapsed.
Click to expand it.
package.json
View file @
27727a69
...
@@ -48,6 +48,8 @@
...
@@ -48,6 +48,8 @@
"
glob
"
:
"
7.1.2
"
,
"
glob
"
:
"
7.1.2
"
,
"
ini
"
:
"
1.3.4
"
,
"
ini
"
:
"
1.3.4
"
,
"
jquery
"
:
"
2.2.4
"
,
"
jquery
"
:
"
2.2.4
"
,
"
jquery-i18n
"
:
"
recurser/jquery-i18n
"
,
"
lodash
"
:
"
^4.17.21
"
,
"
marked
"
:
"
0.3.6
"
,
"
marked
"
:
"
0.3.6
"
,
"
mustache
"
:
"
^4.2.0
"
,
"
mustache
"
:
"
^4.2.0
"
,
"
raven-js
"
:
"
3.16.1
"
,
"
raven-js
"
:
"
3.16.1
"
,
...
@@ -55,14 +57,18 @@
...
@@ -55,14 +57,18 @@
"
reconnecting-websocket
"
:
"
3.0.7
"
,
"
reconnecting-websocket
"
:
"
3.0.7
"
,
"
reflect-metadata
"
:
"
0.1.10
"
,
"
reflect-metadata
"
:
"
0.1.10
"
,
"
rxjs
"
:
"
5.4.2
"
,
"
rxjs
"
:
"
5.4.2
"
,
"
strophe.js
"
:
"
^1.4.2
"
,
"
strophejs-plugin-caps
"
:
"
^1.1.3
"
,
"
strophejs-plugin-disco
"
:
"
^0.0.2
"
,
"
strophejs-plugin-muc
"
:
"
^1.1.0
"
,
"
strophejs-plugin-roster
"
:
"
^1.1.0
"
,
"
systemjs
"
:
"
0.20.15
"
,
"
systemjs
"
:
"
0.20.15
"
,
"
systemjs-plugin-text
"
:
"
0.0.11
"
,
"
systemjs-plugin-text
"
:
"
0.0.11
"
,
"
tether
"
:
"
latest
"
,
"
tether
"
:
"
latest
"
,
"
typeahead.js
"
:
"
0.11.1
"
,
"
typeahead.js
"
:
"
0.11.1
"
,
"
uuid
"
:
"
3.1.0
"
,
"
uuid
"
:
"
3.1.0
"
,
"
vue
"
:
"
2.3.4
"
,
"
vue
"
:
"
2.3.4
"
,
"
zone.js
"
:
"
0.8.12
"
,
"
zone.js
"
:
"
0.8.12
"
"
lodash
"
:
"
^4.17.21
"
},
},
"devDependencies"
:
{
"devDependencies"
:
{
"
@angular/compiler-cli
"
:
"
4.2.6
"
,
"
@angular/compiler-cli
"
:
"
4.2.6
"
,
...
...
systemjs.config.js
View file @
27727a69
...
@@ -70,7 +70,6 @@ System.config({
...
@@ -70,7 +70,6 @@ System.config({
// other node.js libraries
// other node.js libraries
"
electron
"
:
"
@node/electron
"
,
"
electron
"
:
"
@node/electron
"
,
"
ini
"
:
"
@node/ini
"
,
"
ini
"
:
"
@node/ini
"
,
"
mustache
"
:
"
@node/mustache
"
,
"
lodash
"
:
"
@node/lodash
"
,
"
lodash
"
:
"
@node/lodash
"
,
"
mkdirp
"
:
"
@node/mkdirp
"
,
"
mkdirp
"
:
"
@node/mkdirp
"
,
"
aria2
"
:
"
@node/aria2
"
,
"
aria2
"
:
"
@node/aria2
"
,
...
@@ -83,9 +82,15 @@ System.config({
...
@@ -83,9 +82,15 @@ System.config({
'
reconnecting-websocket
'
:
'
npm:reconnecting-websocket/dist/index.js
'
,
'
reconnecting-websocket
'
:
'
npm:reconnecting-websocket/dist/index.js
'
,
'
popper.js
'
:
'
npm:popper.js/dist/umd/popper.min.js
'
,
'
popper.js
'
:
'
npm:popper.js/dist/umd/popper.min.js
'
,
// 'typeahead.js': '@node/typeahead.js'
// 'typeahead.js': '@node/typeahead.js'
'
raven-js
'
:
'
npm:raven-js
'
,
'
raven-js
'
:
'
npm:raven-js
'
'
strophe.js
'
:
'
npm:strophe.js/dist/strophe.umd.js
'
,
'
strophejs-plugin-disco
'
:
'
npm:strophejs-plugin-disco/lib/strophe.disco.js
'
,
'
strophejs-plugin-roster
'
:
'
npm:strophejs-plugin-roster/lib/strophe.roster.js
'
,
'
strophejs-plugin-muc
'
:
'
npm:strophejs-plugin-muc/lib/strophe.muc.js
'
,
'
strophejs-plugin-caps
'
:
'
npm:strophejs-plugin-caps/lib/strophe.caps.js
'
,
'
jquery-i18n
'
:
'
npm:jquery-i18n/jquery.i18n.js
'
,
"
mustache
"
:
"
npm:mustache/mustache.js
"
},
},
// packages tells the System loader how to load when no filename and/or no extension
// packages tells the System loader how to load when no filename and/or no extension
packages
:
{
packages
:
{
...
...
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