Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
黄成意
/
go_sku_server
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
3d349088
authored
Jul 16, 2025
by
杨树贤
Browse files
Options
_('Browse Files')
Download
Plain Diff
Merge branch 'ysx-寄售需求-20250710' into dev
parents
b2fe0668
9e8faaa4
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
194 additions
and
96 deletions
.cursorignore
controller/sku_controller.go
pkg/config/redis.go
pkg/gredis/redis.go
service/service_ly.go
service/service_tags.go
.cursorignore
0 → 100644
View file @
3d349088
/go.sum
/.idea/
gowatch.yml
*.exe
*.exe~
cmd.exe~
/cmd/logs/
/cmd/*.exe~
/cmd/logs
/bat/logs/
/conf/prod/*.ini
/go.mod
/logs
/mylogs
/doc/test
/vm.sh
/cmd/http
/doc/spuTest
/doc/test3
/.history
/.vscode
controller/sku_controller.go
View file @
3d349088
...
...
@@ -2,15 +2,16 @@ package controller
import
(
"encoding/json"
"github.com/gin-gonic/gin"
"github.com/gogf/gf/util/gconv"
"github.com/syyongx/php2go"
"go_sku_server/pkg/common"
"go_sku_server/pkg/gredis"
"go_sku_server/pkg/logger"
"go_sku_server/service"
"sync"
"time"
"github.com/gin-gonic/gin"
"github.com/gogf/gf/util/gconv"
"github.com/syyongx/php2go"
)
const
goodsSliceCount
=
10
//每多少个型号id开启一个协程
...
...
@@ -52,11 +53,16 @@ func CommonController(ctx *gin.Context) map[string]interface{} {
return
nil
}
ch
:=
make
(
chan
sync
.
Map
)
//管道
p
:=
0
//总共协程
zyGoodsId
:=
make
([]
string
,
0
)
lyGoodsId
:=
make
([]
string
,
0
)
var
wg
sync
.
WaitGroup
ch
:=
make
(
chan
sync
.
Map
,
50
)
//管道
zyGoodsId
:=
make
([]
string
,
0
,
goodsSliceCount
)
lyGoodsId
:=
make
([]
string
,
0
,
goodsSliceCount
)
for
_
,
goodsId
:=
range
goodsIdArr
{
//if len(goodsIdArr) > 100 {
// common.Output(ctx, 1001, "查询型号ID不得超过100个", "")
// return nil
//}
if
goodsId
==
""
{
continue
}
...
...
@@ -65,20 +71,32 @@ func CommonController(ctx *gin.Context) map[string]interface{} {
if
len
(
zyGoodsId
)
>=
goodsSliceCount
{
common
.
PrintDebugHtml
(
ctx
,
"zy增加协程1001:"
)
common
.
PrintDebugHtml
(
ctx
,
zyGoodsId
)
//wg.Add(1) //协程计数一
go
zyService
.
ZyGoodsDetail
(
ctx
,
zyGoodsId
,
ch
)
zyGoodsId
=
zyGoodsId
[
:
0
:
0
]
p
++
wg
.
Add
(
1
)
//协程计数一
idsToProcess
:=
make
([]
string
,
len
(
zyGoodsId
))
copy
(
idsToProcess
,
zyGoodsId
)
go
func
(
ctx_in
*
gin
.
Context
,
goodsIds_in
[]
string
,
chs_in
chan
sync
.
Map
)
{
defer
wg
.
Done
()
zyService
.
ZyGoodsDetail
(
ctx_in
,
goodsIds_in
,
chs_in
)
}(
ctx
,
idsToProcess
,
ch
)
zyGoodsId
=
zyGoodsId
[
:
0
]
}
}
else
{
//联营
lyGoodsId
=
append
(
lyGoodsId
,
goodsId
)
if
len
(
lyGoodsId
)
>=
goodsSliceCount
{
common
.
PrintDebugHtml
(
ctx
,
"ly增加协程1002:"
)
common
.
PrintDebugHtml
(
ctx
,
lyGoodsId
)
//wg.Add(1)
go
lyService
.
LyGoodsDetail
(
ctx
,
lyGoodsId
,
ch
)
lyGoodsId
=
lyGoodsId
[
:
0
:
0
]
p
++
wg
.
Add
(
1
)
idsToProcess
:=
make
([]
string
,
len
(
lyGoodsId
))
copy
(
idsToProcess
,
lyGoodsId
)
go
func
(
ctx_in
*
gin
.
Context
,
goodsIds_in
[]
string
,
chs_in
chan
sync
.
Map
)
{
defer
wg
.
Done
()
lyService
.
LyGoodsDetail
(
ctx_in
,
goodsIds_in
,
chs_in
)
}(
ctx
,
idsToProcess
,
ch
)
lyGoodsId
=
lyGoodsId
[
:
0
]
}
}
}
...
...
@@ -86,35 +104,55 @@ func CommonController(ctx *gin.Context) map[string]interface{} {
if
len
(
zyGoodsId
)
>
0
{
common
.
PrintDebugHtml
(
ctx
,
"zy增加协程1003:"
)
common
.
PrintDebugHtml
(
ctx
,
zyGoodsId
)
//wg.Add(1) //协程计数一
go
zyService
.
ZyGoodsDetail
(
ctx
,
zyGoodsId
,
ch
)
p
++
wg
.
Add
(
1
)
//协程计数一
idsToProcess
:=
make
([]
string
,
len
(
zyGoodsId
))
copy
(
idsToProcess
,
zyGoodsId
)
go
func
(
ctx_in
*
gin
.
Context
,
goodsIds_in
[]
string
,
chs_in
chan
sync
.
Map
)
{
defer
wg
.
Done
()
zyService
.
ZyGoodsDetail
(
ctx_in
,
goodsIds_in
,
chs_in
)
}(
ctx
,
zyGoodsId
,
ch
)
}
if
len
(
lyGoodsId
)
>
0
{
common
.
PrintDebugHtml
(
ctx
,
"ly增加协程1004:"
)
common
.
PrintDebugHtml
(
ctx
,
zyGoodsId
)
go
lyService
.
LyGoodsDetail
(
ctx
,
lyGoodsId
,
ch
)
p
++
common
.
PrintDebugHtml
(
ctx
,
lyGoodsId
)
wg
.
Add
(
1
)
idsToProcess
:=
make
([]
string
,
len
(
lyGoodsId
))
copy
(
idsToProcess
,
lyGoodsId
)
go
func
(
ctx_in
*
gin
.
Context
,
goodsIds_in
[]
string
,
chs_in
chan
sync
.
Map
)
{
defer
wg
.
Done
()
lyService
.
LyGoodsDetail
(
ctx_in
,
goodsIds_in
,
chs_in
)
}(
ctx
,
idsToProcess
,
ch
)
}
// 开启一个协程,等待所有任务完成,然后关闭channel
go
func
()
{
wg
.
Wait
()
close
(
ch
)
}()
//异步map最后转成map
temp
:=
make
(
map
[
string
]
interface
{})
for
i
:=
0
;
i
<
p
;
i
++
{
timeout
:=
time
.
After
(
time
.
Second
*
20
)
for
{
select
{
case
GoodsRes
:=
<-
ch
:
case
GoodsRes
,
ok
:=
<-
ch
:
if
!
ok
{
// channel被关闭,说明所有协程都已执行完毕
return
temp
}
GoodsRes
.
Range
(
func
(
k
,
v
interface
{})
bool
{
s
,
_
:=
k
.
(
string
)
temp
[
s
]
=
v
return
true
})
case
<-
time
.
After
(
time
.
Second
*
20
)
:
logger
.
Log
(
"协程超时"
,
"sku"
,
1
)
case
<-
timeout
:
logger
.
Log
(
"协程整体处理超时"
,
"sku"
,
1
)
return
temp
// 超时,返回已经收到的部分数据
}
}
return
temp
}
func
Synchronization
(
ctx
*
gin
.
Context
)
{
...
...
@@ -130,7 +168,7 @@ func Hbsdata(ctx *gin.Context) {
}
/*
测试redis
测试redis
*/
func
Testr
(
ctx
*
gin
.
Context
)
{
...
...
pkg/config/redis.go
View file @
3d349088
package
config
type
RedisDatabase
struct
{
Password
string
Host
string
Database
string
MaxIdle
int
MaxActive
int
Password
string
Host
string
Database
string
MaxIdle
int
MaxActive
int
IdleTimeout
int
MaxAIdleTimeoutctive
string
Prefix
string
Prefix
string
}
//多数据库配置
//
多数据库配置
func
BuildRedisConfigs
()
(
RedisDatabaseMap
map
[
string
]
RedisDatabase
)
{
redisReadMaxIdle
,
_
:=
Get
(
"default_redis_read.max_idle"
)
.
Int
()
redisReadMaxActive
,
_
:=
Get
(
"default_redis_read.max_active"
)
.
Int
()
redisWriteMaxIdle
,
_
:=
Get
(
"default_redis_write.max_idle"
)
.
Int
()
redisWriteMaxActive
,
_
:=
Get
(
"default_redis_write.max_active"
)
.
Int
()
redisSpuMaxIdle
,
_
:=
Get
(
"default_redis_spu.max_idle"
)
.
Int
()
redisSpuMaxActive
,
_
:=
Get
(
"default_redis_spu.max_active"
)
.
Int
()
redisReadMaxIdle
,
_
:=
Get
(
"default_redis_read.max_idle"
)
.
Int
()
redisReadMaxActive
,
_
:=
Get
(
"default_redis_read.max_active"
)
.
Int
()
redisWriteMaxIdle
,
_
:=
Get
(
"default_redis_write.max_idle"
)
.
Int
()
redisWriteMaxActive
,
_
:=
Get
(
"default_redis_write.max_active"
)
.
Int
()
redisSpuMaxIdle
,
_
:=
Get
(
"default_redis_spu.max_idle"
)
.
Int
()
redisSpuMaxActive
,
_
:=
Get
(
"default_redis_spu.max_active"
)
.
Int
()
redisIdleTimeout
,
_
:=
Get
(
"default_redis_read.idle_timeout"
)
.
Int
()
return
map
[
string
]
RedisDatabase
{
"search_r"
:
{
Host
:
Get
(
"default_redis_read.host"
)
.
String
(),
Password
:
Get
(
"default_redis_read.password"
)
.
String
(),
MaxIdle
:
redisReadMaxIdle
,
MaxActive
:
redisReadMaxActive
,
Host
:
Get
(
"default_redis_read.host"
)
.
String
(),
Password
:
Get
(
"default_redis_read.password"
)
.
String
(),
MaxIdle
:
redisReadMaxIdle
,
MaxActive
:
redisReadMaxActive
,
IdleTimeout
:
redisIdleTimeout
,
},
"default_r"
:
{
Host
:
Get
(
"default_redis_read.host"
)
.
String
(),
Password
:
Get
(
"default_redis_read.password"
)
.
String
(),
MaxIdle
:
redisReadMaxIdle
,
MaxActive
:
redisReadMaxActive
,
Host
:
Get
(
"default_redis_read.host"
)
.
String
(),
Password
:
Get
(
"default_redis_read.password"
)
.
String
(),
MaxIdle
:
redisReadMaxIdle
,
MaxActive
:
redisReadMaxActive
,
IdleTimeout
:
redisIdleTimeout
,
},
"search_w"
:
{
Host
:
Get
(
"default_redis_write.host"
)
.
String
(),
Password
:
Get
(
"default_redis_write.password"
)
.
String
(),
MaxIdle
:
redisWriteMaxIdle
,
MaxActive
:
redisWriteMaxActive
,
Host
:
Get
(
"default_redis_write.host"
)
.
String
(),
Password
:
Get
(
"default_redis_write.password"
)
.
String
(),
MaxIdle
:
redisWriteMaxIdle
,
MaxActive
:
redisWriteMaxActive
,
IdleTimeout
:
redisIdleTimeout
,
},
"spu"
:
{
Host
:
Get
(
"default_redis_spu.host"
)
.
String
(),
Password
:
Get
(
"default_redis_spu.password"
)
.
String
(),
MaxIdle
:
redisSpuMaxIdle
,
MaxActive
:
redisSpuMaxActive
,
Host
:
Get
(
"default_redis_spu.host"
)
.
String
(),
Password
:
Get
(
"default_redis_spu.password"
)
.
String
(),
MaxIdle
:
redisSpuMaxIdle
,
MaxActive
:
redisSpuMaxActive
,
IdleTimeout
:
redisIdleTimeout
,
},
}
}
pkg/gredis/redis.go
View file @
3d349088
...
...
@@ -2,9 +2,10 @@ package gredis
import
(
"fmt"
"github.com/gomodule/redigo/redis"
"go_sku_server/pkg/config"
"time"
"github.com/gomodule/redigo/redis"
)
type
ichuntRedis
struct
{
...
...
@@ -32,7 +33,7 @@ func Setup() (err error) {
return
nil
}
//格式化成字符串
//
格式化成字符串
func
String
(
a
interface
{},
err
error
)
(
string
,
error
)
{
return
redis
.
String
(
a
,
err
)
}
...
...
@@ -41,10 +42,15 @@ func getConn(writeHost, password string, maxIdle, maxActive int) (pool *redis.Po
//maxIdle, _ := config.Get("redis.max_idle").Int()
//maxActive, _ := config.Get("redis.max_active").Int()
pool
=
&
redis
.
Pool
{
MaxIdle
:
maxIdle
,
MaxActive
:
maxActive
,
MaxIdle
:
maxIdle
,
MaxActive
:
maxActive
,
IdleTimeout
:
240
*
time
.
Second
,
Dial
:
func
()
(
redis
.
Conn
,
error
)
{
c
,
err
:=
redis
.
Dial
(
"tcp"
,
writeHost
)
c
,
err
:=
redis
.
Dial
(
"tcp"
,
writeHost
,
redis
.
DialConnectTimeout
(
2
*
time
.
Second
),
redis
.
DialReadTimeout
(
2
*
time
.
Second
),
redis
.
DialWriteTimeout
(
2
*
time
.
Second
),
)
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -70,8 +76,9 @@ func getConn(writeHost, password string, maxIdle, maxActive int) (pool *redis.Po
@param hkey string 集合键值,如sku
@param targetIds string 查询的id 切片
eg:
redisConn := gredis.Conn("search_r")
skuArr := gredis.HgetPi(&redisConn,"Self_SelfGoods",[]string{"1001","10005"})
redisConn := gredis.Conn("search_r")
skuArr := gredis.HgetPi(&redisConn,"Self_SelfGoods",[]string{"1001","10005"})
*/
func
Hmget
(
redisCon
string
,
hkey
string
,
targetIds
[]
string
)
map
[
string
]
string
{
if
len
(
targetIds
)
==
0
{
...
...
@@ -86,7 +93,8 @@ func Hmget(redisCon string, hkey string, targetIds []string) map[string]string {
goods_id
:=
targetIds
[
0
]
info
,
err
:=
String
(
redisConn
.
Do
(
"HGET"
,
hkey
,
goods_id
))
if
err
!=
nil
&&
err
!=
redis
.
ErrNil
{
fmt
.
Print
(
"连接redis错误991:"
,
err
)
fmt
.
Printf
(
"redis HGET error for key %s, field %s: %v
\n
"
,
hkey
,
goods_id
,
err
)
return
nil
}
if
info
==
""
{
skuArr
[
goods_id
]
=
""
...
...
@@ -102,9 +110,14 @@ func Hmget(redisCon string, hkey string, targetIds []string) map[string]string {
}
res1
,
err1
:=
redisConn
.
Do
(
"hmget"
,
param
...
)
reply
,
_
:=
redis
.
Strings
(
res1
,
err1
)
if
err1
!=
nil
{
fmt
.
Println
(
err1
)
fmt
.
Printf
(
"redis HMGET error for key %s: %v
\n
"
,
hkey
,
err1
)
return
nil
}
reply
,
err
:=
redis
.
Strings
(
res1
,
err1
)
if
err
!=
nil
{
fmt
.
Printf
(
"redis Strings conversion error after HMGET for key %s: %v
\n
"
,
hkey
,
err
)
return
nil
}
for
k
,
goodsInfo
:=
range
reply
{
...
...
@@ -120,8 +133,9 @@ func Hmget(redisCon string, hkey string, targetIds []string) map[string]string {
@param hkey string 集合键值,如sku
@param targetIds string 查询的id 切片
eg:
redisConn := gredis.Conn("search_r")
skuArr := gredis.HgetPi(&redisConn,"Self_SelfGoods",[]string{"1001","10005"})
redisConn := gredis.Conn("search_r")
skuArr := gredis.HgetPi(&redisConn,"Self_SelfGoods",[]string{"1001","10005"})
*/
func
HgetPi
(
redisCon
string
,
hkey
string
,
targetIds
[]
string
)
map
[
string
]
string
{
redisConn
:=
Conn
(
redisCon
)
...
...
@@ -131,8 +145,9 @@ func HgetPi(redisCon string, hkey string, targetIds []string) map[string]string
if
len
(
targetIds
)
==
1
{
oneId
:=
targetIds
[
0
]
info
,
err
:=
String
(
redisConn
.
Do
(
"HGET"
,
hkey
,
oneId
))
if
err
!=
nil
{
fmt
.
Print
(
err
)
if
err
!=
nil
&&
err
!=
redis
.
ErrNil
{
fmt
.
Printf
(
"redis HGET error for key %s, field %s: %v
\n
"
,
hkey
,
oneId
,
err
)
return
nil
}
if
info
==
""
{
skuArr
[
oneId
]
=
""
...
...
@@ -148,7 +163,11 @@ func HgetPi(redisCon string, hkey string, targetIds []string) map[string]string
redisConn
.
Flush
()
for
_
,
goods_id
:=
range
targetIds
{
info
,
_
:=
redisConn
.
Receive
()
info
,
err
:=
redisConn
.
Receive
()
if
err
!=
nil
{
fmt
.
Printf
(
"redis Receive error for key %s: %v
\n
"
,
hkey
,
err
)
return
nil
}
if
info
==
nil
{
skuArr
[
goods_id
]
=
""
continue
...
...
@@ -164,8 +183,9 @@ func HgetPi(redisCon string, hkey string, targetIds []string) map[string]string
@param hkey string 集合键值,如sku
@param targetIds string 查询的id 切片
eg:
redisConn := gredis.Conn("search_r")
skuArr := gredis.HgetPi(&redisConn,"Self_SelfGoods",[]string{"1001","10005"})
redisConn := gredis.Conn("search_r")
skuArr := gredis.HgetPi(&redisConn,"Self_SelfGoods",[]string{"1001","10005"})
*/
func
HgetPi2
(
redisCon
string
,
hkey
string
,
targetIds
[]
string
)
map
[
string
]
string
{
redisConn
:=
Conn
(
redisCon
)
...
...
@@ -174,8 +194,9 @@ func HgetPi2(redisCon string, hkey string, targetIds []string) map[string]string
skuArr
:=
make
(
map
[
string
]
string
,
0
)
for
_
,
goods_id
:=
range
targetIds
{
info
,
err
:=
String
(
redisConn
.
Do
(
"HGET"
,
hkey
,
goods_id
))
if
err
!=
nil
{
fmt
.
Print
(
"连接redis错误991:"
,
err
)
if
err
!=
nil
&&
err
!=
redis
.
ErrNil
{
fmt
.
Printf
(
"redis HGET error in HgetPi2 for key %s, field %s: %v
\n
"
,
hkey
,
goods_id
,
err
)
return
nil
}
if
info
==
""
{
skuArr
[
goods_id
]
=
""
...
...
service/service_ly.go
View file @
3d349088
...
...
@@ -182,16 +182,13 @@ func (ls *LyService) LyGoodsDetail(ctx *gin.Context, goodsIds []string, ch chan
//case为0是为了兼容价格体系之前的价格
case
0
:
case
1
:
//如果是寄售的,也不走价格体系
if
sku
.
Source
!=
12
{
//这里猎芯和华云都是走同一套的价格体系了
//获取系数和价格
sku
=
ls
.
GetCoefficientAndPrice
(
sku
)
//获取自定义价格后的阶梯价
customPriceService
:=
CustomPrice
{}
sku
.
CustomPriceList
,
_
=
customPriceService
.
getCustomPriceList
(
sku
)
sku
=
priceService
.
GetActivityPrice
(
sku
)
}
//这里猎芯和寄售都是走同一套的价格体系了
//获取系数和价格
sku
=
ls
.
GetCoefficientAndPrice
(
sku
)
//获取自定义价格后的阶梯价
customPriceService
:=
CustomPrice
{}
sku
.
CustomPriceList
,
_
=
customPriceService
.
getCustomPriceList
(
sku
)
sku
=
priceService
.
GetActivityPrice
(
sku
)
case
3
:
//如果是寄售的,不走价格体系
if
sku
.
Source
==
12
{
...
...
@@ -240,6 +237,11 @@ func (ls *LyService) LyGoodsDetail(ctx *gin.Context, goodsIds []string, ch chan
sku
.
HkDeliveryTime
=
delivery
[
"hk_delivery"
]
}
//只要是寄售的,大陆交期都是0.5工作日
if
sku
.
Source
==
12
{
sku
.
CnDeliveryTime
=
"0.5工作日"
}
}
//处理是否可以购买
...
...
@@ -255,8 +257,8 @@ func (ls *LyService) LyGoodsDetail(ctx *gin.Context, goodsIds []string, ch chan
//判断是否可以购买
sku
.
IsBuy
=
ls
.
GetIsBuy
(
sku
)
if
sku
.
IsBuy
==
0
&&
sku
.
OrgId
!=
1
{
sku
.
AcType
=
0
;
if
sku
.
IsBuy
==
0
&&
sku
.
OrgId
!=
1
{
sku
.
AcType
=
0
}
sku
.
Stock
=
ls
.
GetStock
(
sku
)
...
...
service/service_tags.go
View file @
3d349088
package
service
import
(
"github.com/gomodule/redigo/redis"
"github.com/syyongx/php2go"
"github.com/tidwall/gjson"
"go_sku_server/model"
"go_sku_server/pkg/gredis"
"go_sku_server/pkg/vars"
"github.com/gomodule/redigo/redis"
"github.com/syyongx/php2go"
"github.com/tidwall/gjson"
)
//标签相关服务,包括goods_label
...
...
@@ -14,10 +15,10 @@ import (
type
TagsService
struct
{
}
//当天发货标签
//
当天发货标签
const
TagZiyingSku
=
4
//获取Spu的属性
//
获取Spu的属性
func
(
ts
*
TagsService
)
GetTags
(
skuId
string
,
selfSupplierType
int64
)
(
goodsTags
model
.
GoodsTag
)
{
redisCon
:=
gredis
.
Conn
(
"default_r"
)
defer
redisCon
.
Close
()
...
...
@@ -52,13 +53,13 @@ func (ts *TagsService) GetTags(skuId string, selfSupplierType int64) (goodsTags
goodsTags
.
GoodsLabelName
=
vars
.
GoodsTags
[
TagZiyingSku
]
}
}
goodsTags
.
GoodsTagNames
=
tagNames
goodsTags
.
GoodsTag
=
tags
return
goodsTags
}
//获取联营tags
// 获取联营tags
func
(
ts
*
TagsService
)
GetLyTags
(
sku
model
.
LySku
)
(
goodsTags
model
.
GoodsTag
)
{
skuId
:=
sku
.
GoodsId
redisCon
:=
gredis
.
Conn
(
"default_r"
)
...
...
@@ -83,13 +84,20 @@ func (ts *TagsService) GetLyTags(sku model.LySku) (goodsTags model.GoodsTag) {
for
_
,
cname
:=
range
customerTagArr
{
//如果是爱智的话,去掉可议价标签
if
sku
.
OrgId
==
3
&&
cname
==
"可议价"
{
if
sku
.
OrgId
==
3
&&
cname
==
"可议价"
{
continue
}
tagNames
=
append
(
tagNames
,
cname
)
}
}
}
if
sku
.
Source
==
12
{
if
!
php2go
.
InArray
(
"当天发货"
,
tagNames
)
{
tagNames
=
append
(
tagNames
,
"当天发货"
)
}
}
goodsTags
.
GoodsTagNames
=
tagNames
goodsTags
.
GoodsTag
=
tags
return
goodsTags
...
...
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