Commit 3eb86e03 by mushishixian

Merge branch 'ysx-quote-20200628' into dev

parents ec5c62f8 e85062c1
......@@ -41,6 +41,6 @@ database = liexin_config
[brand]
#是否开启排除品牌
is_not_ti = 1
ti_ly_brand_ids = 23,45069,7754,17484,43215,13421,5220,7636,44534,43556,44543,9429,758,9470,10430,10653,10707,11227,11276,11819,12608,12965,12997,13327,13675,13680,13752
IS_NOT_TI = 1
TI_LY_BRAND_IDS = 23,45069,7754,17484,43215,13421,5220,7636,44534,43556,44543,9429,758,9470,10430,10653,10707,11227,11276,11819,12608,12965,12997,13327,13675,13680,13752
ti_zy_brand_id = 23
\ No newline at end of file
......@@ -3,10 +3,19 @@
2 ="verical"
3 ="tme"
#相似物料供应商
[alike_supplier]
1 = "ti"
[common]
'MOUSER_API'='http://footstone.liexin.net/webapi/handle_mouser'
[brand]
is_not_ti = 0
ti_ly_brand_ids=23,45069,7754,17484,43215,13421,5220,7636,44534,43556,44543,9429,758,9470,10430,10653,10707,11227,11276,11819,12608,12965,12997,13327,13675,13680,13752
ti_zy_brand_ids=23
\ No newline at end of file
IS_NOT_TI = 0
TI_LY_BRAND_IDS=23,45069,7754,17484,43215,13421,5220,7636,44534,43556,44543,9429,758,9470,10430,10653,10707,11227,11276,11819,12608,12965,12997,13327,13675,13680,13752
TI_ZY_BRAND_IDS=23
[supplier]
# 供应商redis的首key
SUPPLIER_REDIS_PRE = SUPPLIER_REDIS_INFO_
......@@ -8,24 +8,42 @@ import (
"search_server/service"
)
//搜索快手搜搜
//check_button=2&pf=1&keyword=123213&supplier_id=7&offset=2&follow_hit=1&p=1&_=1593582814402
func QuoteIndex(c *gin.Context) {
var request requests.QuoteIndexRequest
var (
request requests.QuoteIndexRequest
)
//绑定参数到结构体
if err := c.ShouldBind(&request); err != nil {
fmt.Println(err)
}
if request.Keyword == "" || request.SupplierId == "" {
c.JSON(200, common.GetResponse(1, "缺少参数", []string{}))
//检查参数,有错误就返回错误
errCode, errMsg := requests.CheckQuoteRequest(request)
if errCode != 0 {
c.JSON(200, common.Response{
ErrCode: errCode,
ErrMsg: errMsg,
Data: []string{},
})
return
}
supplierName := "temp"
if supplierName == "" {
c.JSON(200, common.GetResponse(1, "供应商id有误", []string{}))
return
if request.FollowHit != 0 && request.FollowHit != 1 {
service.GetGoodsBySupplier(request)
} else {
}
service.GetGoodsInfoBySupplier(request)
flag := 1
if true {
flag = 0
}
//构建返回
c.JSON(200, common.Response{
ErrCode: flag,
ErrMsg: "",
Data: nil,
})
}
......@@ -7,20 +7,20 @@ import (
//获取需要排除的品牌id
//branType = 1 : 联营 2 : 自营
func GetExcludeBrandIds(brandType int) (excludeBrandIds []int) {
isNoTi := config.Get("brand.is_not_ti").String()
isNoTi := config.Get("brand.IS_NOT_TI").String()
//如果关闭,直接返回空数据
if isNoTi == "1" {
return
}
//返回联营的brand_id切片
if brandType == 1 {
tiLyBrandIds := config.Get("brand.ti_ly_brand_ids").Ints(",")
tiLyBrandIds := config.Get("brand.TI_LY_BRAND_IDS").Ints(",")
excludeBrandIds = tiLyBrandIds
//获取的是字符串
return
}
//返回自营的ti的brand_id切片
tiZyBrandId := config.Get("brand.ti_zy_brand_ids").Ints(",")
tiZyBrandId := config.Get("brand.TI_ZY_BRAND_IDS").Ints(",")
excludeBrandIds = tiZyBrandId
return
......
package model
type ApiGoods struct {
PickType int `json:"pick_type"`
BarCode string `json:"bar_code"`
GoodsId string `json:"goods_id"`
GoodsName string `json:"goods_name"`
GoodsType int `json:"goods_type"`
SupplierId int `json:"supplier_id"`
Moq int `json:"moq"`
Mpq int `json:"mpq"`
Stock int `json:"stock"`
HkDeliveryTime string `json:"hk_delivery_time"`
CnDeliveryTime string `json:"cn_delivery_time"`
LadderPrice []LadderPrice `json:"ladder_price"`
BrandName string `json:"brand_name"`
SupplierName string `json:"supplier_name"`
BrandId int `json:"brand_id"`
ClassId1 int `json:"class_id1"`
ClassId2 int `json:"class_id2"`
Encoded string `json:"encoded"`
Packing string `json:"packing"`
GoodsUnit string `json:"goods_unit"`
GoodsImages string `json:"goods_images"`
GoodsBrief string `json:"goods_brief"`
IsBuy int `json:"is_buy"`
Mpl int `json:"mpl"`
Status int `json:"status"`
Pdf string `json:"pdf"`
Encap string `json:"encap"`
AcType int `json:"ac_type"`
OtherAttrs OtherAttrs `json:"other_attrs"`
UpdateTime int `json:"update_time"`
SkuName string `json:"sku_name"`
Attrs Attrs `json:"attrs"`
Cost string `json:"cost"`
NewCost string `json:"new_cost"`
SupplierStock int `json:"supplier_stock"`
SelfSupplierType int `json:"self_supplier_type"`
GoodsUnitName string `json:"goods_unit_name"`
PackingName string `json:"packing_name"`
MpgUnitName string `json:"mpg_unit_name"`
ScmBrandName string `json:"scm_brand_name"`
AllowCoupon int `json:"allow_coupon"`
ClassId1Name string `json:"class_id1_name"`
CLassId2Name string `json:"c_lass_id2_name"`
SpuId string `json:"spu_id,omitempty"`
BatchSn string `json:"batch_sn,omitempty"`
Canal string `json:"canal,omitempty"`
CpTime int `json:"cp_time,omitempty"`
Coefficient Coefficient `json:"coefficient,omitempty"`
OriginalPrice []OriginalPrice `json:"original_price,omitempty"`
SuppExtendFee SuppExtendFee `json:"supp_extend_fee,omitempty"`
ClassId3 int `json:"class_id3,omitempty"`
SpuName string `json:"spu_name,omitempty"`
ImagesL string `json:"images_l,omitempty"`
SpuBrief string `json:"spu_brief,omitempty"`
SpuDetail string `json:"spu_detail,omitempty"`
ClassName3 string `json:"class_name3,omitempty"`
ErpTax bool `json:"erp_tax,omitempty"`
ScmBrand ScmBrand `json:"scm_brand,omitempty"`
PickType int `json:"pick_type,omitempty"`
BarCode string `json:"barcode,omitempty"`
GoodsId string `json:"goods_id"`
GoodsName string `json:"goods_name"`
GoodsSn string `json:"goods_sn"`
GoodsType int `json:"goods_type"`
SupplierId int `json:"supplier_id"`
Moq int `json:"moq"`
Mpq int `json:"mpq"`
Stock int `json:"stock"`
HkDeliveryTime string `json:"hk_delivery_time"`
CnDeliveryTime string `json:"cn_delivery_time"`
LadderPrice []LadderPrice `json:"ladder_price"`
BrandName string `json:"brand_name"`
SupplierName string `json:"supplier_name"`
BrandId int `json:"brand_id"`
ClassId1 int `json:"class_id1"`
ClassId2 int `json:"class_id2"`
Encoded string `json:"encoded"`
Packing string `json:"packing,omitempty"`
GoodsUnit string `json:"goods_unit,goods_unit"`
GoodsImages string `json:"goods_images"`
GoodsBrief string `json:"goods_brief,omitempty"`
IsBuy int `json:"is_buy"`
Mpl int `json:"mpl"`
Status int `json:"status"`
Pdf string `json:"pdf"`
Encap string `json:"encap"`
AcType int `json:"ac_type"`
OtherAttrs OtherAttrs `json:"other_attrs"`
UpdateTime int `json:"update_time"`
SkuName string `json:"sku_name,omitempty"`
Attrs Attrs `json:"attrs"`
Cost string `json:"cost,omitempty"`
NewCost string `json:"new_cost,omitempty"`
SupplierStock int `json:"supplier_stock,omitempty"`
SelfSupplierType int `json:"self_supplier_type,omitempty"`
GoodsUnitName string `json:"goods_unit_name,omitempty"`
PackingName string `json:"packing_name,omitempty"`
MpgUnitName string `json:"mpg_unit_name,omitempty"`
ScmBrandName string `json:"scm_brand_name,omitempty"`
AllowCoupon int `json:"allow_coupon"`
ClassId1Name string `json:"class_id1_name"`
CLassId2Name string `json:"c_lass_id2_name"`
SpuId string `json:"spu_id,omitempty"`
BatchSn string `json:"batch_sn,omitempty"`
Canal string `json:"canal,omitempty"`
CpTime int `json:"cp_time"`
Coefficient Coefficient `json:"coefficient,omitempty"`
OriginalPrice []OriginalPrice `json:"original_price,omitempty"`
SuppExtendFee SuppExtendFee `json:"supp_extend_fee,omitempty"`
ClassId3 int `json:"class_id3,omitempty"`
SpuName string `json:"spu_name,omitempty"`
ImagesL string `json:"images_l,omitempty"`
SpuBrief string `json:"spu_brief"`
SpuDetail string `json:"spu_detail,omitempty"`
ClassName3 string `json:"class_name3,omitempty"`
ErpTax bool `json:"erp_tax"`
ScmBrand ScmBrand `json:"scm_brand,omitempty"`
//额外增加的字段
GoodsNameTemp string `json:"goods_name_temp,omitempty"`
Multiple int `json:"multiple,omitempty"`
SearchSampleApplication string `json:"search_sample_application"`
SearchContactExperts string `json:"search_contact_experts"`
}
type Attr struct {
AttrName string
AttrValue string
AttrName string `json:"attr_name,omitempty"`
AttrValue string `json:"attr_value,omitempty"`
}
type Attrs map[string]Attr
type OtherAttrs struct {
GrossWeight string `json:"gross_weight"`
GrossWeight string `json:"gross_weight,omitempty"`
}
type LadderPrice struct {
Purchases int `json:"purchases"`
Purchases int `json:"purchases"`
PriceUs float64 `json:"price_us"`
PriceCn float64 `json:"price_cn"`
PriceAc float64 `json:"price_ac"`
......@@ -99,14 +104,14 @@ type SuppExtendFee struct {
Max int `json:"max"`
Price float64 `json:"price"`
} `json:"cn,omitempty"`
Hk struct{
Hk struct {
Max int `json:"max"`
Price float64 `json:"price"`
} `json:"hk,omitempty"`
}
type ScmBrand struct {
ErpBrandName string `json:"erp_brand_name"`
ErpBrandId string `json:"erp_brand_id"`
ScmBrandId string `json:"scm_brand_id"`
ErpBrandName string `json:"erp_brand_name,omitempty"`
ErpBrandId string `json:"erp_brand_id,omitempty"`
ScmBrandId string `json:"scm_brand_id,omitempty"`
}
package model
import (
"github.com/gomodule/redigo/redis"
"search_server/pkg/config"
"search_server/pkg/gredis"
)
type QuoteSupplier struct {
HkDelivery string `json:"hk_delivery"`
CnDelivery string `json:"cn_delivery"`
PriceJson string `json:"price_json"`
AdText string `json:"ad_text"`
SupplierLogo string `json:"supplier_logo"`
AdUrl string `json:"ad_url"`
Sort int `json:"sort"`
}
func getSupplier(supplierId string) {
redisCon := gredis.Conn("default_r")
defer redisCon.Close()
supplierInfoStr, _ := redis.String(redisCon.Do("HGET", config.Get("supplier.SUPPLIER_REDIS_PRE")))
if supplierInfoStr != "" {
//序列化出来使用
} else {
//如果redis找不到,就要去数据库里面取了
}
}
......@@ -4,6 +4,7 @@ import (
"crypto/md5"
"encoding/hex"
"github.com/syyongx/php2go"
"regexp"
"strconv"
)
......@@ -58,6 +59,12 @@ func ToString(a interface{}) string {
return "change to String error"
}
//替换字符串,不区分大小写
func CaseInsensitiveReplace(subject string, search string, replace string) string {
searchRegex := regexp.MustCompile("(?i)" + search)
return searchRegex.ReplaceAllString(subject, replace)
}
/**
* 获取联营活动价
*/
......
package requests
import (
"github.com/syyongx/php2go"
"search_server/pkg/config"
)
type QuoteIndexRequest struct {
Keyword string `form:"key_word"`
Keyword string `form:"keyword"`
CheckButton int `form:"check_button"`
SupplierId string `form:"supplier_id"`
Offset int `form:"offset"`
......@@ -9,7 +14,7 @@ type QuoteIndexRequest struct {
Stock int `form:"stock"`
GoodsNameEq string `form:"goods_name/eq"`
IsExact int `form:"is_exact"`
BrandId string `form:"brand_id"`
BrandId string `form:"brand_id"`
AvailRank int `form:"avail_rank"`
SingleRank int `form:"single_rank"`
StockRank int `form:"stock_rank"`
......@@ -18,3 +23,23 @@ type QuoteIndexRequest struct {
P int `form:"p"`
Topic int `form:"topic"`
}
func CheckQuoteRequest(r QuoteIndexRequest) (errCode int, errMsg string) {
//解码参数
var err error
if r.Keyword != "" {
r.Keyword, err = php2go.URLDecode(r.Keyword)
if err != nil {
return 1, "参数解码失败"
}
}
//判断参数
if r.Keyword == "" || r.SupplierId == "" {
return 1, "缺少参数"
}
//判断供应商
if config.Get("supplier_all."+r.SupplierId).String() == "" {
return 1, "供应商id有误"
}
return
}
......@@ -17,8 +17,10 @@ func InitRouter() *gin.Engine {
r.POST("/search/bom/recommend", controller.Recommend)
r.POST("search/ZiYing/zyh", controller.Zyh)
//快手平台相关
//r.GET("/search/quote", controller.QuoteIndex)
r.GET("/search/quote", controller.QuoteIndex)
r.POST("/search/quote", controller.QuoteIndex)
return r
}
......@@ -48,7 +48,7 @@ func SearchAttr(attrOrigin, encap string) (goodsName string, err error) {
numberR, _ := regexp.Compile(common.PureNumberRegular)
pureNumber := numberR.FindString(encap)
//再去找对应属性
redisConn := gredis.Conn("default_redis_read")
redisConn := gredis.Conn("search_r")
defer redisConn.Close()
attrName, _ := redis.String(redisConn.Do("HGET", "sku_map2", pureNumber))
if attrName != "" {
......@@ -203,7 +203,7 @@ func getAttrValueByAttr(attr string) (attrValue string) {
}
} else {
//再去找没有单位的对应属性
redisConn := gredis.Conn("default_redis_read")
redisConn := gredis.Conn("search_r")
defer redisConn.Close()
attrName, _ := redis.String(redisConn.Do("HGET", "sku_map2", pureNumber))
if attrName != "" {
......
......@@ -101,8 +101,7 @@ func Recommend(req *common.RecommendRequest) (rsp *common.BomResponse) {
goodsIdList = append(goodsIdList, goodsId)
}
goodsIdListStr = strings.Join(goodsIdList, ",")
goodsService := GoodsService{}
goodsList, err := goodsService.GetGoodsInfoByApi(goodsIdListStr)
goodsList, err := GetGoodsInfoByApi(goodsIdListStr)
response.Data = goodsList
response.Flag = req.Flag
return &response
......
......@@ -4,6 +4,7 @@ import (
"fmt"
"github.com/gomodule/redigo/redis"
"github.com/imroc/req"
"github.com/syyongx/php2go"
"github.com/tidwall/gjson"
"github.com/uniplaces/carbon"
"gopkg.in/olivere/elastic.v5"
......@@ -17,11 +18,8 @@ import (
"strings"
)
type GoodsService struct {
}
//获取商品信息,需要传入userId用于判断是否登陆
func (gs *GoodsService) GetGoodsInfo(goodsIdsStr string, userId int) (goodsListMap map[string]*model.ApiGoods, err error) {
func GetGoodsInfo(goodsIdsStr string, userId int) (goodsListMap map[string]*model.ApiGoods, err error) {
isNewCustomer, isMember := CheckIsNewCustomer(userId)
params := req.Param{
"goods_id": goodsIdsStr,
......@@ -33,7 +31,7 @@ func (gs *GoodsService) GetGoodsInfo(goodsIdsStr string, userId int) (goodsListM
}
//获取商品信息
func (gs *GoodsService) GetGoodsInfoByApi(goodsIdsStr string) (goodsList []*model.ApiGoods, err error) {
func GetGoodsInfoByApi(goodsIdsStr string) (goodsList []*model.ApiGoods, err error) {
params := req.Param{
"goods_id": goodsIdsStr,
}
......@@ -43,6 +41,48 @@ func (gs *GoodsService) GetGoodsInfoByApi(goodsIdsStr string) (goodsList []*mode
}
//处理商品信息数据
func DullGoodsInfo(keyword string, goodsListMap map[string]*model.ApiGoods) map[string]*model.ApiGoods {
//获取redis链接
redisCon := gredis.Conn("default_r")
defer redisCon.Close()
for key, goods := range goodsListMap {
fmt.Println(key)
fmt.Println(goods)
if goods.Mpq == 0 {
goods.Mpq = 1
}
if goods.GoodsName == "" {
goods.GoodsName = goods.SpuName
}
//goods_name_temp
if keyword != "" {
replaceString := "<b class='f-red'>" + strings.ToUpper(keyword) + "</b>"
goods.GoodsNameTemp = common.CaseInsensitiveReplace(goods.GoodsName, keyword, replaceString)
} else {
goods.GoodsNameTemp = goods.GoodsName
}
if goods.Mpq > goods.Moq {
goods.Multiple = goods.Moq
} else {
goods.Multiple = goods.Mpq
}
//te广告按钮
teSwitch, _ := redis.Int(redisCon.Do("GET", "TeSwitch"))
if goods.BrandId == 161 && goods.GoodsId != "1152755238555810539" && teSwitch == 2 {
goods.SearchSampleApplication = "https://www.te.com.cn/chn-zh/solutions/sg-sample-request-form.html?te_bu=Cor&te_type=other&te_campaign=ich_chn_cor-ich-chn-part-selectmktg-fy19-srp-sample_sma-431_10&elqCampaignId=32896"
goods.SearchContactExperts = "https://www.te.com.cn/chn-zh/solutions/connectivity.html?te_bu=Cor&te_type=other&te_campaign=ich_chn_cor-ich-chn-part-selectmktg-fy19-srp-contact_sma-431_11&elqCampaignId=32897"
}
//供应商信息,读取redis,来源于基石配置
}
return nil
}
//isMap:是否以字典形式返回值,默认是数组
func CurlGoodsInfo(goodsIdsStr string, params req.Param) (goodsList []*model.ApiGoods, goodsListMap map[string]*model.ApiGoods, err error) {
//req.Debug = true
......@@ -66,6 +106,7 @@ func CurlGoodsInfo(goodsIdsStr string, params req.Param) (goodsList []*model.Api
goods.BarCode = data.Get("bar_code").String()
goods.GoodsId = data.Get("goods_id").String()
goods.GoodsName = data.Get("goods_name").String()
goods.GoodsSn = data.Get("goods_sn").String()
goods.GoodsType = int(data.Get("goods_type").Int())
goods.SupplierId = int(data.Get("supplier_id").Int())
goods.Mpq = int(data.Get("mpq").Int())
......@@ -133,13 +174,12 @@ func CurlGoodsInfo(goodsIdsStr string, params req.Param) (goodsList []*model.Api
//Attrs
attrMap := make(map[string]model.Attr, 0)
for key, attr := range data.Get("attrs").Array() {
for key, attr := range data.Get("attrs").Map() {
attr := model.Attr{
AttrName: attr.Get("attr_name").String(),
AttrValue: attr.Get("attr_value").String(),
}
attrMap[common.ToString(key)] = attr
attrMap[key] = attr
}
goods.Attrs = attrMap
......@@ -185,6 +225,7 @@ func CurlGoodsInfo(goodsIdsStr string, params req.Param) (goodsList []*model.Api
return
}
//判断是否是新客价
func CheckIsNewCustomer(userId int) (isNewCustomer, isMember bool) {
//判断新客价
if userId != 0 {
......@@ -210,22 +251,44 @@ func CheckIsNewCustomer(userId int) (isNewCustomer, isMember bool) {
}
//根据供应商获取商品信息
func GetGoodsInfoBySupplier(req requests.QuoteIndexRequest) error {
supplierIndex := config.Get("es.search_supplier").String()
func GetGoodsBySupplier(r requests.QuoteIndexRequest) (err error) {
//索引字典
supplierIndex := getSupplierIndex(r.SupplierId)
//获取查询条件
queryString, err := getSupplierQuery(req)
queryString, err := getSupplierQuery(r)
queryString = ""
res, err := es.CurlES(supplierIndex, queryString)
if err != nil {
return err
}
fmt.Println(res)
goodsIds := GetGoodsIdsByEs(res)
//if err != nil {
// return err
//}
goodsIdsStr := strings.Join(goodsIds, ",")
goodsList, err := GetGoodsInfo(goodsIdsStr, 0)
fmt.Println(goodsList)
return nil
}
func getSupplierIndex(supplierId string) string {
return "temp"
func getSupplierIndex(supplierId string) (supplierIndex string) {
supplierIndexMap := config.Cfg.Section("supplier_all").KeysHash()
if index, exist := supplierIndexMap[supplierId]; exist {
return index
}
if strings.Contains(supplierId, ",") {
supplierIdSlice := strings.Split(supplierId, ",")
for _, supplierId := range supplierIdSlice {
if index, exist := supplierIndexMap[supplierId]; exist {
if supplierIndex == "" {
supplierIndex = index
} else {
supplierIndex = supplierIndex + "," + index
}
}
}
}
return
}
//获取根据供应商搜索
func getSupplierQuery(req requests.QuoteIndexRequest) (string, error) {
req.SupplierId = strings.TrimSpace(req.SupplierId)
source := elastic.NewSearchSource()
......@@ -243,6 +306,7 @@ func getSupplierQuery(req requests.QuoteIndexRequest) (string, error) {
query.Must(elastic.NewRangeQuery("update_time").Gte(oneMonthTimeStamp))
keyword := strings.ToUpper(req.Keyword)
//判断关键词是否为空
if req.Keyword != "" {
r1, _ := regexp.Compile(`/[\x{4e00}-\x{9fff}]+/u`)
......@@ -251,7 +315,6 @@ func getSupplierQuery(req requests.QuoteIndexRequest) (string, error) {
r2, _ := regexp.Compile(`/[^A-Za-z0-9]+/`)
req.Keyword = r2.ReplaceAllString(removeCnKeyword, "")
//
if req.IsExact == 1 {
query.Must(elastic.NewTermQuery("auto_goods_name.raw", keyword))
} else {
......@@ -266,8 +329,10 @@ func getSupplierQuery(req requests.QuoteIndexRequest) (string, error) {
}
//判断是否存在类似物料搜索
//todo:类似索引获取
if true {
supplierIndexName := getSupplierIndex(req.SupplierId)
//获取相似物料供应商列表
alikeSuppliers := config.Cfg.Section("alike_supplier").KeyStrings()
if php2go.InArray(supplierIndexName, alikeSuppliers) && keyword != "" {
query.Should(elastic.NewTermQuery("goods_name_alike", keyword))
}
......@@ -276,7 +341,7 @@ func getSupplierQuery(req requests.QuoteIndexRequest) (string, error) {
//判断库存
if req.Stock > 0 {
query.Must(elastic.NewRangeQuery("stick").Gte(req.Stock))
query.Must(elastic.NewRangeQuery("stock").Gte(req.Stock))
}
//判断是否要根据品牌id搜索
......@@ -383,8 +448,18 @@ func getSupplierQuery(req requests.QuoteIndexRequest) (string, error) {
for _, brandId := range excludeBrandId {
query.MustNot(elastic.NewTermQuery("brand_id", brandId))
}
source.Query(query)
searchRequest := elastic.NewSearchRequest().Source(source)
return searchRequest.Body()
}
//根据es的结果获取goods_id列表
func GetGoodsIdsByEs(res string) (goodsIds []string) {
//直接用gjson去获取goods_id列表
gjArray := gjson.Get(res, "hits.hits.#._id").Array()
for _, item := range gjArray {
goodsIds = append(goodsIds, item.String())
}
return
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment