Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
G
go-cqhttp
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
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
nanahira
go-cqhttp
Commits
aaa73ef5
Commit
aaa73ef5
authored
Oct 11, 2020
by
wdvxdr1123
Committed by
GitHub
Oct 11, 2020
Browse files
Options
Browse Files
Download
Plain Diff
Merge
Dev
parents
2a5f7849
a72a688a
Changes
7
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
165 additions
and
32 deletions
+165
-32
coolq/bot.go
coolq/bot.go
+43
-0
coolq/cqcode.go
coolq/cqcode.go
+34
-4
coolq/event.go
coolq/event.go
+14
-0
docs/cqhttp.md
docs/cqhttp.md
+17
-0
go.mod
go.mod
+2
-2
go.sum
go.sum
+4
-24
server/apiAdmin.go
server/apiAdmin.go
+51
-2
No files found.
coolq/bot.go
View file @
aaa73ef5
...
@@ -66,6 +66,7 @@ func NewQQBot(cli *client.QQClient, conf *global.JsonConfig) *CQBot {
...
@@ -66,6 +66,7 @@ func NewQQBot(cli *client.QQClient, conf *global.JsonConfig) *CQBot {
bot
.
Client
.
OnGroupMemberJoined
(
bot
.
memberJoinEvent
)
bot
.
Client
.
OnGroupMemberJoined
(
bot
.
memberJoinEvent
)
bot
.
Client
.
OnGroupMemberLeaved
(
bot
.
memberLeaveEvent
)
bot
.
Client
.
OnGroupMemberLeaved
(
bot
.
memberLeaveEvent
)
bot
.
Client
.
OnGroupMemberPermissionChanged
(
bot
.
memberPermissionChangedEvent
)
bot
.
Client
.
OnGroupMemberPermissionChanged
(
bot
.
memberPermissionChangedEvent
)
bot
.
Client
.
OnGroupMemberCardUpdated
(
bot
.
memberCardUpdatedEvent
)
bot
.
Client
.
OnNewFriendRequest
(
bot
.
friendRequestEvent
)
bot
.
Client
.
OnNewFriendRequest
(
bot
.
friendRequestEvent
)
bot
.
Client
.
OnNewFriendAdded
(
bot
.
friendAddedEvent
)
bot
.
Client
.
OnNewFriendAdded
(
bot
.
friendAddedEvent
)
bot
.
Client
.
OnGroupInvited
(
bot
.
groupInvitedEvent
)
bot
.
Client
.
OnGroupInvited
(
bot
.
groupInvitedEvent
)
...
@@ -151,6 +152,48 @@ func (bot *CQBot) SendGroupMessage(groupId int64, m *message.SendingMessage) int
...
@@ -151,6 +152,48 @@ func (bot *CQBot) SendGroupMessage(groupId int64, m *message.SendingMessage) int
bot
.
Client
.
SendGroupGift
(
uint64
(
groupId
),
uint64
(
i
.
Target
),
i
.
GiftId
)
bot
.
Client
.
SendGroupGift
(
uint64
(
groupId
),
uint64
(
i
.
Target
),
i
.
GiftId
)
return
0
return
0
}
}
if
i
,
ok
:=
elem
.
(
*
QQMusicElement
);
ok
{
var
msgStyle
uint32
=
4
if
i
.
MusicUrl
==
""
{
msgStyle
=
0
// fix vip song
}
ret
,
err
:=
bot
.
Client
.
SendGroupRichMessage
(
groupId
,
100497308
,
1
,
msgStyle
,
client
.
RichClientInfo
{
Platform
:
1
,
SdkVersion
:
"0.0.0"
,
PackageName
:
"com.tencent.qqmusic"
,
Signature
:
"cbd27cd7c861227d013a25b2d10f0799"
,
},
&
message
.
RichMessage
{
Title
:
i
.
Title
,
Summary
:
i
.
Summary
,
Url
:
i
.
Url
,
PictureUrl
:
i
.
PictureUrl
,
MusicUrl
:
i
.
MusicUrl
,
})
if
err
!=
nil
{
log
.
Warnf
(
"警告: 群 %v 富文本消息发送失败: %v"
,
groupId
,
err
)
return
-
1
}
return
bot
.
InsertGroupMessage
(
ret
)
}
if
i
,
ok
:=
elem
.
(
*
CloudMusicElement
);
ok
{
ret
,
err
:=
bot
.
Client
.
SendGroupRichMessage
(
groupId
,
100495085
,
1
,
4
,
client
.
RichClientInfo
{
Platform
:
1
,
SdkVersion
:
"0.0.0"
,
PackageName
:
"com.netease.cloudmusic"
,
Signature
:
"da6b069da1e2982db3e386233f68d76d"
,
},
&
message
.
RichMessage
{
Title
:
i
.
Title
,
Summary
:
i
.
Summary
,
Url
:
i
.
Url
,
PictureUrl
:
i
.
PictureUrl
,
MusicUrl
:
i
.
MusicUrl
,
})
if
err
!=
nil
{
log
.
Warnf
(
"警告: 群 %v 富文本消息发送失败: %v"
,
groupId
,
err
)
return
-
1
}
return
bot
.
InsertGroupMessage
(
ret
)
}
newElem
=
append
(
newElem
,
elem
)
newElem
=
append
(
newElem
,
elem
)
}
}
m
.
Elements
=
newElem
m
.
Elements
=
newElem
...
...
coolq/cqcode.go
View file @
aaa73ef5
...
@@ -35,10 +35,30 @@ type GiftElement struct {
...
@@ -35,10 +35,30 @@ type GiftElement struct {
GiftId
message
.
GroupGift
GiftId
message
.
GroupGift
}
}
type
MusicElement
struct
{
Title
string
Summary
string
Url
string
PictureUrl
string
MusicUrl
string
}
type
QQMusicElement
struct
{
MusicElement
}
type
CloudMusicElement
struct
{
MusicElement
}
func
(
e
*
GiftElement
)
Type
()
message
.
ElementType
{
func
(
e
*
GiftElement
)
Type
()
message
.
ElementType
{
return
message
.
At
return
message
.
At
}
}
func
(
e
*
MusicElement
)
Type
()
message
.
ElementType
{
return
message
.
Service
}
var
GiftId
=
[]
message
.
GroupGift
{
var
GiftId
=
[]
message
.
GroupGift
{
message
.
SweetWink
,
message
.
SweetWink
,
message
.
HappyCola
,
message
.
HappyCola
,
...
@@ -429,8 +449,13 @@ func (bot *CQBot) ToElement(t string, d map[string]string, group bool) (message.
...
@@ -429,8 +449,13 @@ func (bot *CQBot) ToElement(t string, d map[string]string, group bool) (message.
if
d
[
"content"
]
!=
""
{
if
d
[
"content"
]
!=
""
{
content
=
d
[
"content"
]
content
=
d
[
"content"
]
}
}
json
:=
fmt
.
Sprintf
(
"{
\"
app
\"
:
\"
com.tencent.structmsg
\"
,
\"
desc
\"
:
\"
音乐
\"
,
\"
meta
\"
: {
\"
music
\"
: {
\"
desc
\"
:
\"
%s
\"
,
\"
jumpUrl
\"
:
\"
%s
\"
,
\"
musicUrl
\"
:
\"
%s
\"
,
\"
preview
\"
:
\"
%s
\"
,
\"
tag
\"
:
\"
QQ音乐
\"
,
\"
title
\"
:
\"
%s
\"
}},
\"
prompt
\"
:
\"
[分享]%s
\"
,
\"
ver
\"
:
\"
0.0.0.1
\"
,
\"
view
\"
:
\"
music
\"
}"
,
content
,
jumpUrl
,
purl
,
preview
,
name
,
name
)
return
&
QQMusicElement
{
MusicElement
:
MusicElement
{
return
message
.
NewLightApp
(
json
),
nil
Title
:
name
,
Summary
:
content
,
Url
:
jumpUrl
,
PictureUrl
:
preview
,
MusicUrl
:
purl
,
}},
nil
}
}
if
d
[
"type"
]
==
"163"
{
if
d
[
"type"
]
==
"163"
{
info
,
err
:=
global
.
NeteaseMusicSongInfo
(
d
[
"id"
])
info
,
err
:=
global
.
NeteaseMusicSongInfo
(
d
[
"id"
])
...
@@ -448,8 +473,13 @@ func (bot *CQBot) ToElement(t string, d map[string]string, group bool) (message.
...
@@ -448,8 +473,13 @@ func (bot *CQBot) ToElement(t string, d map[string]string, group bool) (message.
if
info
.
Get
(
"artists.0"
)
.
Exists
()
{
if
info
.
Get
(
"artists.0"
)
.
Exists
()
{
artistName
=
info
.
Get
(
"artists.0.name"
)
.
Str
artistName
=
info
.
Get
(
"artists.0.name"
)
.
Str
}
}
json
:=
fmt
.
Sprintf
(
"{
\"
app
\"
:
\"
com.tencent.structmsg
\"
,
\"
desc
\"
:
\"
音乐
\"
,
\"
view
\"
:
\"
music
\"
,
\"
prompt
\"
:
\"
[分享]%s
\"
,
\"
ver
\"
:
\"
0.0.0.1
\"
,
\"
meta
\"
:{
\"
music
\"
: {
\"
desc
\"
:
\"
%s
\"
,
\"
jumpUrl
\"
:
\"
%s
\"
,
\"
musicUrl
\"
:
\"
%s
\"
,
\"
preview
\"
:
\"
%s
\"
,
\"
tag
\"
:
\"
网易云音乐
\"
,
\"
title
\"
:
\"
%s
\"
}}}"
,
name
,
artistName
,
jumpUrl
,
musicUrl
,
picUrl
,
name
)
return
&
CloudMusicElement
{
MusicElement
{
return
message
.
NewLightApp
(
json
),
nil
Title
:
name
,
Summary
:
artistName
,
Url
:
jumpUrl
,
PictureUrl
:
picUrl
,
MusicUrl
:
musicUrl
,
}},
nil
}
}
if
d
[
"type"
]
==
"custom"
{
if
d
[
"type"
]
==
"custom"
{
xml
:=
fmt
.
Sprintf
(
`<?xml version='1.0' encoding='UTF-8' standalone='yes' ?><msg serviceID="2" templateID="1" action="web" brief="[分享] %s" sourceMsgId="0" url="%s" flag="0" adverSign="0" multiMsgFlag="0"><item layout="2"><audio cover="%s" src="%s"/><title>%s</title><summary>%s</summary></item><source name="音乐" icon="https://i.gtimg.cn/open/app_icon/01/07/98/56/1101079856_100_m.png" url="http://web.p.qq.com/qqmpmobile/aio/app.html?id=1101079856" action="app" a_actionData="com.tencent.qqmusic" i_actionData="tencent1101079856://" appid="1101079856" /></msg>`
,
xml
:=
fmt
.
Sprintf
(
`<?xml version='1.0' encoding='UTF-8' standalone='yes' ?><msg serviceID="2" templateID="1" action="web" brief="[分享] %s" sourceMsgId="0" url="%s" flag="0" adverSign="0" multiMsgFlag="0"><item layout="2"><audio cover="%s" src="%s"/><title>%s</title><summary>%s</summary></item><source name="音乐" icon="https://i.gtimg.cn/open/app_icon/01/07/98/56/1101079856_100_m.png" url="http://web.p.qq.com/qqmpmobile/aio/app.html?id=1101079856" action="app" a_actionData="com.tencent.qqmusic" i_actionData="tencent1101079856://" appid="1101079856" /></msg>`
,
...
...
coolq/event.go
View file @
aaa73ef5
...
@@ -310,6 +310,20 @@ func (bot *CQBot) memberPermissionChangedEvent(c *client.QQClient, e *client.Mem
...
@@ -310,6 +310,20 @@ func (bot *CQBot) memberPermissionChangedEvent(c *client.QQClient, e *client.Mem
})
})
}
}
func
(
bot
*
CQBot
)
memberCardUpdatedEvent
(
c
*
client
.
QQClient
,
e
*
client
.
MemberCardUpdatedEvent
)
{
log
.
Infof
(
"群 %v 的 %v 更新了名片 %v -> %v"
,
formatGroupName
(
e
.
Group
),
formatMemberName
(
e
.
Member
),
e
.
OldCard
,
e
.
Member
.
CardName
)
bot
.
dispatchEventMessage
(
MSG
{
"post_type"
:
"notice"
,
"notice_type"
:
"group_card"
,
"group_id"
:
e
.
Group
.
Code
,
"user_id"
:
e
.
Member
.
Uin
,
"card_new"
:
e
.
Member
.
CardName
,
"card_old"
:
e
.
OldCard
,
"time"
:
time
.
Now
()
.
Unix
(),
"self_id"
:
c
.
Uin
,
})
}
func
(
bot
*
CQBot
)
memberJoinEvent
(
c
*
client
.
QQClient
,
e
*
client
.
MemberJoinGroupEvent
)
{
func
(
bot
*
CQBot
)
memberJoinEvent
(
c
*
client
.
QQClient
,
e
*
client
.
MemberJoinGroupEvent
)
{
log
.
Infof
(
"新成员 %v 进入了群 %v."
,
formatMemberName
(
e
.
Member
),
formatGroupName
(
e
.
Group
))
log
.
Infof
(
"新成员 %v 进入了群 %v."
,
formatMemberName
(
e
.
Member
),
formatGroupName
(
e
.
Group
))
bot
.
dispatchEventMessage
(
bot
.
groupIncrease
(
e
.
Group
.
Code
,
0
,
e
.
Member
.
Uin
))
bot
.
dispatchEventMessage
(
bot
.
groupIncrease
(
e
.
Group
.
Code
,
0
,
e
.
Member
.
Uin
))
...
...
docs/cqhttp.md
View file @
aaa73ef5
...
@@ -520,3 +520,20 @@ Type: `tts`
...
@@ -520,3 +520,20 @@ Type: `tts`
|
`sub_type`
| string |
`honor`
| 提示类型 |
|
`sub_type`
| string |
`honor`
| 提示类型 |
|
`user_id`
| int64 | | 成员id |
|
`user_id`
| int64 | | 成员id |
|
`honor_type`
| string |
`talkative:龙王`
`performer:群聊之火`
`emotion:快乐源泉`
| 荣誉类型 |
|
`honor_type`
| string |
`talkative:龙王`
`performer:群聊之火`
`emotion:快乐源泉`
| 荣誉类型 |
#### 群成员名片更新
> 注意: 此事件不保证时效性,仅在收到消息时校验卡片
**上报数据**
| 字段 | 类型 | 可能的值 | 说明 |
| ------------- | ------ | -------------- | -------------- |
|
`post_type`
| string |
`notice`
| 上报类型 |
|
`notice_type`
| string |
`group_card`
| 消息类型 |
|
`group_id`
| int64 | | 群号 |
|
`user_id`
| int64 | | 成员id |
|
`card_new`
| int64 | | 新名片 |
|
`card_old`
| int64 | | 旧名片 |
> PS: 当名片为空时 `card_xx` 字段为空字符串, 并不是昵称
\ No newline at end of file
go.mod
View file @
aaa73ef5
...
@@ -3,7 +3,7 @@ module github.com/Mrs4s/go-cqhttp
...
@@ -3,7 +3,7 @@ module github.com/Mrs4s/go-cqhttp
go 1.14
go 1.14
require (
require (
github.com/Mrs4s/MiraiGo v0.0.0-2020100
5155759-f9b3c399e5e0
github.com/Mrs4s/MiraiGo v0.0.0-2020100
8134448-b53aaceaa1b4
github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 // indirect
github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 // indirect
github.com/gin-gonic/gin v1.6.3
github.com/gin-gonic/gin v1.6.3
github.com/go-playground/validator/v10 v10.4.0 // indirect
github.com/go-playground/validator/v10 v10.4.0 // indirect
...
@@ -23,7 +23,7 @@ require (
...
@@ -23,7 +23,7 @@ require (
github.com/tebeka/strftime v0.1.5 // indirect
github.com/tebeka/strftime v0.1.5 // indirect
github.com/tidwall/gjson v1.6.1
github.com/tidwall/gjson v1.6.1
github.com/ugorji/go v1.1.10 // indirect
github.com/ugorji/go v1.1.10 // indirect
github.com/wdvxdr1123/go-silk v0.0.0-2020100
6020916-0398076200ea
github.com/wdvxdr1123/go-silk v0.0.0-2020100
7123416-b982fd3d91d6
github.com/xujiajun/nutsdb v0.5.0
github.com/xujiajun/nutsdb v0.5.0
github.com/yinghau76/go-ascii-art v0.0.0-20190517192627-e7f465a30189
github.com/yinghau76/go-ascii-art v0.0.0-20190517192627-e7f465a30189
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 // indirect
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 // indirect
...
...
go.sum
View file @
aaa73ef5
This diff is collapsed.
Click to expand it.
server/apiAdmin.go
View file @
aaa73ef5
...
@@ -98,12 +98,24 @@ func (s *webServer) Dologin() {
...
@@ -98,12 +98,24 @@ func (s *webServer) Dologin() {
s
.
Console
=
bufio
.
NewReader
(
os
.
Stdin
)
s
.
Console
=
bufio
.
NewReader
(
os
.
Stdin
)
conf
:=
GetConf
()
conf
:=
GetConf
()
cli
:=
s
.
Cli
cli
:=
s
.
Cli
cli
.
AllowSlider
=
true
rsp
,
err
:=
cli
.
Login
()
rsp
,
err
:=
cli
.
Login
()
for
{
for
{
global
.
Check
(
err
)
global
.
Check
(
err
)
var
text
string
var
text
string
if
!
rsp
.
Success
{
if
!
rsp
.
Success
{
switch
rsp
.
Error
{
switch
rsp
.
Error
{
case
client
.
SliderNeededError
:
if
client
.
SystemDeviceInfo
.
Protocol
==
client
.
AndroidPhone
{
log
.
Warnf
(
"警告: Android Phone 强制要求暂不支持的滑条验证码, 请开启设备锁或切换到Watch协议验证通过后再使用."
)
log
.
Infof
(
"按 Enter 继续...."
)
_
,
_
=
s
.
Console
.
ReadString
(
'\n'
)
os
.
Exit
(
0
)
}
cli
.
AllowSlider
=
false
cli
.
Disconnect
()
rsp
,
err
=
cli
.
Login
()
continue
case
client
.
NeedCaptcha
:
case
client
.
NeedCaptcha
:
_
=
ioutil
.
WriteFile
(
"captcha.jpg"
,
rsp
.
CaptchaImage
,
0644
)
_
=
ioutil
.
WriteFile
(
"captcha.jpg"
,
rsp
.
CaptchaImage
,
0644
)
img
,
_
,
_
:=
image
.
Decode
(
bytes
.
NewReader
(
rsp
.
CaptchaImage
))
img
,
_
,
_
:=
image
.
Decode
(
bytes
.
NewReader
(
rsp
.
CaptchaImage
))
...
@@ -118,20 +130,57 @@ func (s *webServer) Dologin() {
...
@@ -118,20 +130,57 @@ func (s *webServer) Dologin() {
rsp
,
err
=
cli
.
SubmitCaptcha
(
strings
.
ReplaceAll
(
text
,
"
\n
"
,
""
),
rsp
.
CaptchaSign
)
rsp
,
err
=
cli
.
SubmitCaptcha
(
strings
.
ReplaceAll
(
text
,
"
\n
"
,
""
),
rsp
.
CaptchaSign
)
global
.
DelFile
(
"captcha.jpg"
)
global
.
DelFile
(
"captcha.jpg"
)
continue
continue
case
client
.
SMSNeededError
:
log
.
Warnf
(
"账号已开启设备锁, 按下 Enter 向手机 %v 发送短信验证码."
,
rsp
.
SMSPhone
)
_
,
_
=
s
.
Console
.
ReadString
(
'\n'
)
if
!
cli
.
RequestSMS
()
{
log
.
Warnf
(
"发送验证码失败,可能是请求过于频繁."
)
time
.
Sleep
(
time
.
Second
*
5
)
os
.
Exit
(
0
)
}
log
.
Warn
(
"请输入短信验证码: (Enter 提交)"
)
text
,
_
=
s
.
Console
.
ReadString
(
'\n'
)
rsp
,
err
=
cli
.
SubmitSMS
(
strings
.
ReplaceAll
(
strings
.
ReplaceAll
(
text
,
"
\n
"
,
""
),
"
\r
"
,
""
))
continue
case
client
.
SMSOrVerifyNeededError
:
log
.
Warnf
(
"账号已开启设备锁,请选择验证方式:"
)
log
.
Warnf
(
"1. 向手机 %v 发送短信验证码"
,
rsp
.
SMSPhone
)
log
.
Warnf
(
"2. 使用手机QQ扫码验证."
)
log
.
Warn
(
"请输入(1 - 2): "
)
text
,
_
=
s
.
Console
.
ReadString
(
'\n'
)
if
strings
.
Contains
(
text
,
"1"
)
{
if
!
cli
.
RequestSMS
()
{
log
.
Warnf
(
"发送验证码失败,可能是请求过于频繁."
)
time
.
Sleep
(
time
.
Second
*
5
)
os
.
Exit
(
0
)
}
log
.
Warn
(
"请输入短信验证码: (Enter 提交)"
)
text
,
_
=
s
.
Console
.
ReadString
(
'\n'
)
rsp
,
err
=
cli
.
SubmitSMS
(
strings
.
ReplaceAll
(
strings
.
ReplaceAll
(
text
,
"
\n
"
,
""
),
"
\r
"
,
""
))
continue
}
log
.
Warnf
(
"请前往 -> %v <- 验证并重启Bot."
,
rsp
.
VerifyUrl
)
log
.
Infof
(
"按 Enter 继续...."
)
_
,
_
=
s
.
Console
.
ReadString
(
'\n'
)
os
.
Exit
(
0
)
return
case
client
.
UnsafeDeviceError
:
case
client
.
UnsafeDeviceError
:
log
.
Warnf
(
"账号已开启设备锁,请前往 -> %v <- 验证并重启Bot."
,
rsp
.
VerifyUrl
)
log
.
Warnf
(
"账号已开启设备锁,请前往 -> %v <- 验证并重启Bot."
,
rsp
.
VerifyUrl
)
if
conf
.
WebUi
.
WebInput
{
if
conf
.
WebUi
.
WebInput
{
log
.
Infof
(
" (http://%s:%d/admin/do_web_write 确认后继续)...."
,
conf
.
WebUi
.
Host
,
conf
.
WebUi
.
WebUiPort
)
log
.
Infof
(
" (http://%s:%d/admin/do_web_write 确认后继续)...."
,
conf
.
WebUi
.
Host
,
conf
.
WebUi
.
WebUiPort
)
text
=
<-
WebInput
text
=
<-
WebInput
}
else
{
}
else
{
log
.
Infof
(
"
按 Enter 继续...."
)
log
.
Infof
(
"按 Enter 继续...."
)
_
,
_
=
s
.
Console
.
ReadString
(
'\n'
)
_
,
_
=
s
.
Console
.
ReadString
(
'\n'
)
}
}
log
.
Info
(
text
)
log
.
Info
(
text
)
os
.
Exit
(
0
)
os
.
Exit
(
0
)
return
return
case
client
.
OtherLoginError
,
client
.
UnknownLoginError
:
case
client
.
OtherLoginError
,
client
.
UnknownLoginError
:
log
.
Fatalf
(
"登录失败: %v"
,
rsp
.
ErrorMessage
)
log
.
Warnf
(
"登录失败: %v"
,
rsp
.
ErrorMessage
)
log
.
Infof
(
"按 Enter 继续...."
)
_
,
_
=
s
.
Console
.
ReadString
(
'\n'
)
os
.
Exit
(
0
)
return
return
}
}
}
}
...
...
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