Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
B
brandkbs2
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
shenjunjie
brandkbs2
Commits
b9117713
Commit
b9117713
authored
Jul 27, 2022
by
陈健智
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
热点库与危机库
parent
eed08ef5
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
347 additions
and
1 deletions
+347
-1
src/main/java/com/zhiwei/brandkbs2/common/RedisKeyPrefix.java
+6
-0
src/main/java/com/zhiwei/brandkbs2/controller/app/AppCrisisController.java
+106
-0
src/main/java/com/zhiwei/brandkbs2/controller/app/AppHotController.java
+168
-0
src/main/java/com/zhiwei/brandkbs2/service/MarkDataService.java
+26
-0
src/main/java/com/zhiwei/brandkbs2/service/impl/MarkDataServiceImpl.java
+28
-0
src/main/resources/application-local.properties
+12
-0
src/main/resources/application.properties
+1
-1
No files found.
src/main/java/com/zhiwei/brandkbs2/common/RedisKeyPrefix.java
View file @
b9117713
...
...
@@ -28,6 +28,12 @@ public class RedisKeyPrefix {
public
static
final
String
AGGREE_RESULT_CACHE
=
"BRANDKBS:AGGREE_CACHE:"
;
/**
* 热点相关缓存KEY
*/
public
static
final
String
HOT_RANKLIST
=
"brandkbs:hot:rankList:"
;
public
static
final
String
HOT_LIST
=
"brandkbs:hot:list:"
;
/**
* 项目简报报相关缓存KEY
*/
public
static
final
String
REPORT_PC
=
"BRANDKBS:REPORT:PC:"
;
...
...
src/main/java/com/zhiwei/brandkbs2/controller/app/AppCrisisController.java
0 → 100644
View file @
b9117713
package
com
.
zhiwei
.
brandkbs2
.
controller
.
app
;
import
com.alibaba.fastjson.JSON
;
import
com.alibaba.fastjson.JSONObject
;
import
com.zhiwei.brandkbs2.auth.Auth
;
import
com.zhiwei.brandkbs2.auth.UserThreadLocal
;
import
com.zhiwei.brandkbs2.controller.BaseController
;
import
com.zhiwei.brandkbs2.enmus.RoleEnum
;
import
com.zhiwei.brandkbs2.model.ResponseResult
;
import
io.swagger.annotations.Api
;
import
io.swagger.annotations.ApiOperation
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.client.RestTemplate
;
/**
* @ClassName AppCrisisController
* @Description 提供前台危机相关信息展示
* @author cjz
* @date 2022-07-19 10:20
*/
@RestController
@RequestMapping
(
"/app/crisis"
)
@Api
(
tags
=
"前台危机展示接口"
,
description
=
"提供前台危机相关信息展示"
)
@Auth
(
role
=
RoleEnum
.
CUSTOMER
)
public
class
AppCrisisController
extends
BaseController
{
@Value
(
"${crisis.search.url}"
)
private
String
crisisSearchUrl
;
@Value
(
"${crisis.searchTags.url}"
)
private
String
crisisTagsUrl
;
@Value
(
"${crisis.top3.url}"
)
private
String
crisisTop3Url
;
@Value
(
"${crisis.searchCriteria.url}"
)
private
String
crisisSearchCriteriaUrl
;
@Value
(
"${crisis.list.url}"
)
private
String
crisisListUrl
;
@Value
(
"${crisis.share.url}"
)
private
String
crisisEventShareUrl
;
@Autowired
private
RestTemplate
restTemplate
;
@ApiOperation
(
"危机库-查危机"
)
@GetMapping
(
"/crisisSearch"
)
public
ResponseResult
crisisSearch
(
@RequestParam
(
value
=
"page"
,
defaultValue
=
"1"
)
Integer
page
,
@RequestParam
(
value
=
"pageSize"
,
defaultValue
=
"3"
)
Integer
pageSize
,
@RequestParam
(
"keyword"
)
String
keyword
){
ResponseEntity
<
String
>
responseEntity
=
restTemplate
.
getForEntity
(
crisisSearchUrl
,
String
.
class
,
page
,
pageSize
,
keyword
);
Object
data
=
JSON
.
parseObject
(
responseEntity
.
getBody
()).
get
(
"data"
);
return
ResponseResult
.
success
(
data
);
}
@ApiOperation
(
"危机库-通过标签查危机"
)
@GetMapping
(
"/crisisTags"
)
public
ResponseResult
crisisTags
(
@RequestParam
(
value
=
"page"
,
defaultValue
=
"1"
)
Integer
page
,
@RequestParam
(
value
=
"pageSize"
,
defaultValue
=
"10"
)
Integer
pageSize
,
@RequestParam
(
value
=
"brand"
,
required
=
false
)
String
brand
,
@RequestParam
(
value
=
"category"
,
required
=
false
)
String
category
){
ResponseEntity
<
String
>
responseEntity
=
restTemplate
.
getForEntity
(
crisisTagsUrl
,
String
.
class
,
page
,
pageSize
,
brand
,
category
);
Object
data
=
JSON
.
parseObject
(
responseEntity
.
getBody
()).
get
(
"data"
);
return
ResponseResult
.
success
(
data
);
}
@ApiOperation
(
"危机库-近期热点危机"
)
@GetMapping
(
"/recentHotCrisis"
)
public
ResponseResult
recentHotCrisis
(){
ResponseEntity
<
String
>
responseEntity
=
restTemplate
.
getForEntity
(
crisisTop3Url
,
String
.
class
);
Object
data
=
JSON
.
parseObject
(
responseEntity
.
getBody
()).
get
(
"data"
);
return
ResponseResult
.
success
(
data
);
}
@ApiOperation
(
"危机库-危机搜索条件"
)
@GetMapping
(
"/crisisSearchCriteria"
)
public
ResponseResult
crisisSearchCriteria
(){
ResponseEntity
<
String
>
responseEntity
=
restTemplate
.
getForEntity
(
crisisSearchCriteriaUrl
,
String
.
class
);
Object
data
=
JSON
.
parseObject
(
responseEntity
.
getBody
()).
get
(
"data"
);
return
ResponseResult
.
success
(
data
);
}
@ApiOperation
(
"危机库-危机库列表"
)
@GetMapping
(
"/crisisList"
)
public
ResponseResult
crisisList
(
@RequestParam
(
value
=
"page"
,
defaultValue
=
"1"
)
Integer
page
,
@RequestParam
(
value
=
"pageSize"
,
defaultValue
=
"10"
)
Integer
pageSize
,
@RequestParam
(
value
=
"startTime"
,
required
=
false
)
String
startTime
,
@RequestParam
(
value
=
"endTime"
,
required
=
false
)
String
endTime
,
@RequestParam
(
value
=
"category"
,
defaultValue
=
"不限"
)
String
category
){
ResponseEntity
<
String
>
responseEntity
=
restTemplate
.
getForEntity
(
crisisListUrl
,
String
.
class
,
page
,
pageSize
,
startTime
,
endTime
,
category
);
Object
data
=
JSON
.
parseObject
(
responseEntity
.
getBody
()).
get
(
"data"
);
return
ResponseResult
.
success
(
data
);
}
@ApiOperation
(
"危机库-获取危机事件分享id"
)
@GetMapping
(
"/getCrisisEventShareId/{id}"
)
public
ResponseResult
getCrisisEventShareId
(
@PathVariable
int
id
){
ResponseEntity
<
String
>
responseEntity
=
restTemplate
.
getForEntity
(
crisisEventShareUrl
,
String
.
class
,
id
);
Object
data
=
JSON
.
parseObject
(
responseEntity
.
getBody
()).
get
(
"data"
);
return
ResponseResult
.
success
(
data
);
}
}
src/main/java/com/zhiwei/brandkbs2/controller/app/AppHotController.java
0 → 100644
View file @
b9117713
package
com
.
zhiwei
.
brandkbs2
.
controller
.
app
;
import
com.alibaba.fastjson.JSON
;
import
com.alibaba.fastjson.JSONObject
;
import
com.zhiwei.brandkbs2.auth.Auth
;
import
com.zhiwei.brandkbs2.auth.UserThreadLocal
;
import
com.zhiwei.brandkbs2.common.RedisKeyPrefix
;
import
com.zhiwei.brandkbs2.controller.BaseController
;
import
com.zhiwei.brandkbs2.enmus.EmotionEnum
;
import
com.zhiwei.brandkbs2.enmus.RoleEnum
;
import
com.zhiwei.brandkbs2.model.ResponseResult
;
import
com.zhiwei.brandkbs2.pojo.vo.ProjectVO
;
import
com.zhiwei.brandkbs2.service.MarkDataService
;
import
com.zhiwei.brandkbs2.service.ProjectService
;
import
com.zhiwei.brandkbs2.util.RedisUtil
;
import
io.swagger.annotations.Api
;
import
io.swagger.annotations.ApiOperation
;
import
org.apache.commons.lang3.time.DateUtils
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RequestParam
;
import
org.springframework.web.bind.annotation.RestController
;
import
org.springframework.web.client.RestTemplate
;
import
java.io.IOException
;
import
java.text.SimpleDateFormat
;
import
java.util.Date
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Objects
;
import
java.util.concurrent.TimeUnit
;
import
java.util.stream.Collectors
;
/**
* @ClassName AppCrisisController
* @Description 提供前台危机相关信息展示
* @author cjz
* @date 2022-07-19 16:17
*/
@RestController
@RequestMapping
(
"/app/hot"
)
@Api
(
tags
=
"前台热点展示接口"
,
description
=
"提供前台热点相关信息展示"
)
@Auth
(
role
=
RoleEnum
.
CUSTOMER
)
public
class
AppHotController
extends
BaseController
{
private
static
final
long
ONE_HOUR
=
1L
;
@Value
(
"${trends.longTimeInListSearchByInner.url}"
)
private
String
trendsListUrl
;
@Value
(
"${trends.findHotSearchESDataInTimeByInner.url}"
)
private
String
trendsSearchUrl
;
@Value
(
"${trends.longTimeInListSearch.url}"
)
private
String
longTimeInListSearchUrl
;
@Autowired
private
RestTemplate
restTemplate
;
@Autowired
private
RedisUtil
redisUtil
;
@Autowired
private
ProjectService
projectService
;
@Autowired
private
MarkDataService
markDataService
;
/**
* weibo 热搜
* weibo-topic 话题
* weibo-rise 预热
* zhihu 知乎
* toutiao 头条
* douyin 抖音
* bilibili-ranking B站
*/
@ApiOperation
(
"热点库"
)
@GetMapping
(
"/getHotList"
)
public
ResponseResult
getHotList
(
@RequestParam
(
value
=
"sortType"
,
defaultValue
=
"realTime"
)
String
sortType
,
@RequestParam
(
value
=
"type"
,
defaultValue
=
"weibo"
)
String
type
){
ResponseEntity
<
JSONObject
>
jsonObjectResponseEntity
=
restTemplate
.
getForEntity
(
trendsListUrl
,
JSONObject
.
class
,
sortType
,
type
);
Object
data
=
jsonObjectResponseEntity
.
getBody
().
get
(
"data"
);
String
redisKey
=
RedisKeyPrefix
.
HOT_LIST
+
type
;
String
result
=
redisUtil
.
get
(
redisKey
);
//当舆论场崩溃时从缓存里获取
if
(
Objects
.
nonNull
(
data
)){
if
(
Objects
.
isNull
(
result
))
{
redisUtil
.
setExpire
(
redisKey
,
JSON
.
toJSONString
(
data
),
ONE_HOUR
,
TimeUnit
.
HOURS
);
}
return
ResponseResult
.
success
(
data
);
}
else
{
if
(
Objects
.
nonNull
(
result
))
{
return
ResponseResult
.
success
(
result
);
}
return
ResponseResult
.
failure
(
"响应超时"
);
}
}
@ApiOperation
(
"热点库-查热点"
)
@GetMapping
(
"/searchHotList"
)
public
ResponseResult
searchHotList
(
@RequestParam
(
value
=
"pageSize"
,
defaultValue
=
"10"
)
Integer
limit
,
@RequestParam
(
value
=
"page"
,
defaultValue
=
"1"
)
Integer
page
,
@RequestParam
(
value
=
"type"
,
defaultValue
=
"weibo"
)
String
type
,
@RequestParam
(
value
=
"word"
)
String
word
){
ResponseEntity
<
JSONObject
>
jsonObjectResponseEntity
=
restTemplate
.
getForEntity
(
trendsSearchUrl
,
JSONObject
.
class
,
limit
,
page
,
type
,
word
);
JSONObject
body
=
jsonObjectResponseEntity
.
getBody
();
if
(
Objects
.
nonNull
(
body
)){
return
ResponseResult
.
success
(
body
);
}
else
{
return
ResponseResult
.
failure
(
"响应超时"
);
}
}
@ApiOperation
(
"热点库-热点榜单"
)
@GetMapping
(
"/hot"
)
public
ResponseResult
hot
(){
ResponseEntity
<
String
>
responseEntity
=
restTemplate
.
getForEntity
(
longTimeInListSearchUrl
,
String
.
class
,
"weibo"
);
JSONObject
jsonObject
=
JSON
.
parseObject
(
responseEntity
.
getBody
());
String
redisKey
=
RedisKeyPrefix
.
HOT_RANKLIST
;
String
result
=
redisUtil
.
get
(
redisKey
);
//当舆论场崩溃时从缓存里获取
if
(
jsonObject
.
getBoolean
(
"state"
)){
Object
data
=
jsonObject
.
get
(
"data"
);
if
(
Objects
.
isNull
(
result
))
{
redisUtil
.
setExpire
(
redisKey
,
JSON
.
toJSONString
(
data
),
ONE_HOUR
,
TimeUnit
.
HOURS
);
}
return
ResponseResult
.
success
(
data
);
}
else
{
if
(
Objects
.
nonNull
(
result
))
{
return
ResponseResult
.
success
(
result
);
}
return
ResponseResult
.
failure
(
"响应超时"
);
}
}
@ApiOperation
(
"热点库-最新资讯"
)
@GetMapping
(
"/latestNews"
)
public
ResponseResult
latestNews
(
@RequestParam
(
value
=
"pageSize"
,
defaultValue
=
"5"
)
Integer
size
)
throws
IOException
{
String
projectId
=
UserThreadLocal
.
getProjectId
();
String
linkedGroupId
=
projectService
.
getProjectVOById
(
projectId
).
getBrandLinkedGroupId
();
Date
endDate
=
new
Date
();
Date
startDate
=
DateUtils
.
addHours
(
endDate
,
-
24
);
List
<
Map
.
Entry
<
String
,
Integer
>>
markTopTitleList
=
markDataService
.
getMarkTopTitle
(
startDate
.
getTime
(),
endDate
.
getTime
(),
null
,
projectId
,
linkedGroupId
,
size
);
List
<
JSONObject
>
resultList
=
markTopTitleList
.
stream
().
map
(
map
->
{
JSONObject
article
=
null
;
try
{
article
=
markDataService
.
getFirstArticle
(
startDate
.
getTime
(),
endDate
.
getTime
(),
map
.
getKey
(),
projectId
,
linkedGroupId
);
}
catch
(
IOException
e
)
{
throw
new
RuntimeException
(
e
);
}
JSONObject
resultJsonObject
=
new
JSONObject
();
resultJsonObject
.
put
(
"title"
,
map
.
getKey
());
if
(
Objects
.
nonNull
(
article
))
{
resultJsonObject
.
put
(
"content"
,
article
.
get
(
"content"
));
resultJsonObject
.
put
(
"url"
,
article
.
get
(
"url"
));
resultJsonObject
.
put
(
"realSource"
,
article
.
get
(
"realSource"
));
}
resultJsonObject
.
put
(
"num"
,
map
.
getValue
());
return
resultJsonObject
;
}).
collect
(
Collectors
.
toList
());
return
ResponseResult
.
success
(
resultList
);
}
}
src/main/java/com/zhiwei/brandkbs2/service/MarkDataService.java
View file @
b9117713
package
com
.
zhiwei
.
brandkbs2
.
service
;
import
com.alibaba.fastjson.JSONObject
;
import
com.zhiwei.brandkbs2.pojo.EventData
;
import
com.zhiwei.brandkbs2.pojo.MarkFlowEntity
;
import
com.zhiwei.brandkbs2.pojo.dto.ExportAppYuqingDTO
;
import
com.zhiwei.brandkbs2.pojo.dto.MarkSearchDTO
;
import
com.zhiwei.brandkbs2.pojo.vo.PageVO
;
import
org.apache.commons.lang3.tuple.Pair
;
import
java.io.IOException
;
import
java.util.List
;
import
java.util.Map
;
/**
* @ClassName: MarkDataService
...
...
@@ -112,4 +115,27 @@ public interface MarkDataService {
*/
List
<
JSONObject
>
getMarkHighWord
(
Long
startTime
,
Long
endTime
);
/**
* 获取时间段某情感数据最多的标题
*
* @param startTime 开始时间
* @param endTime 结束时间
* @param emotion 情感倾向名称
* @param projectId 项目id
* @param linkedGroupId 关联组id
* @param size 分页大小
* @return 最热标题
*/
List
<
Map
.
Entry
<
String
,
Integer
>>
getMarkTopTitle
(
Long
startTime
,
Long
endTime
,
String
emotion
,
String
projectId
,
String
linkedGroupId
,
int
size
)
throws
IOException
;
/**
* 根据聚合标题和时间获取首发稿件
* @param startTime 开始时间
* @param endTime 结束时间
* @param aggTitle 聚合标题
* @param projectId 项目id
* @param linkedGroupId 关联组id
* @return 首发稿件
*/
JSONObject
getFirstArticle
(
Long
startTime
,
Long
endTime
,
String
aggTitle
,
String
projectId
,
String
linkedGroupId
)
throws
IOException
;
}
src/main/java/com/zhiwei/brandkbs2/service/impl/MarkDataServiceImpl.java
View file @
b9117713
...
...
@@ -104,6 +104,7 @@ public class MarkDataServiceImpl implements MarkDataService {
@Override
public
PageVO
<
MarkFlowEntity
>
getYuqingMarkList
(
MarkSearchDTO
markSearchDTO
)
{
try
{
//设置默认的时间、页码、排序方式等
defaultMarkSearch
(
markSearchDTO
);
// 搜索es数据
Pair
<
SearchHits
[],
Map
<
String
,
Long
>>
hitsAndCounts
=
searchMarkHitsAndCount
(
markSearchDTO
,
false
);
...
...
@@ -601,6 +602,7 @@ public class MarkDataServiceImpl implements MarkDataService {
helper
.
setSize
(
0
);
// TODO 本地调试不滚动查询
// List<SearchResponse> searchResponses = esClientDao.searchScrollResponse(helper);
//singletonList:只能存放一个元素,多一个或者少一个都会导致异常
List
<
SearchResponse
>
searchResponses
=
Collections
.
singletonList
(
esClientDao
.
searchResponse
(
helper
));
return
Pair
.
of
(
searchResponses
.
stream
().
map
(
SearchResponse:
:
getHits
).
toArray
(
SearchHits
[]::
new
),
null
);
}
...
...
@@ -799,6 +801,30 @@ public class MarkDataServiceImpl implements MarkDataService {
return
result
.
entrySet
().
stream
().
filter
(
data
->
!
"分享一篇文章"
.
equals
(
data
.
getKey
())).
sorted
(
Map
.
Entry
.
comparingByValue
(
Comparator
.
reverseOrder
())).
limit
(
size
).
collect
(
Collectors
.
toList
());
}
@Override
public
JSONObject
getFirstArticle
(
Long
startTime
,
Long
endTime
,
String
aggTitle
,
String
projectId
,
String
linkedGroupId
)
throws
IOException
{
// 索引
String
[]
indexes
=
esClientDao
.
getIndexes
();
// query
BoolQueryBuilder
query
=
projectLinkedGroupQuery
(
projectId
,
linkedGroupId
);
query
.
must
(
QueryBuilders
.
rangeQuery
(
"time"
).
gte
(
startTime
).
lt
(
endTime
))
.
must
(
QueryBuilders
.
termQuery
(
"agg_title.keyword"
,
aggTitle
));
// response
SearchResponse
searchResponse
=
esClientDao
.
searchResponse
(
indexes
,
null
,
query
,
null
,
null
,
null
,
0
,
0
,
null
);
//hits
SearchHits
hits
=
searchResponse
.
getHits
();
JSONObject
resultJSONObject
=
new
JSONObject
();
hits
.
forEach
(
hit
->
{
Map
<
String
,
Object
>
source
=
hit
.
getSourceAsMap
();
resultJSONObject
.
put
(
"time"
,
source
.
get
(
"time"
));
resultJSONObject
.
put
(
"content"
,
source
.
get
(
"content"
));
resultJSONObject
.
put
(
"url"
,
source
.
get
(
"url"
));
resultJSONObject
.
put
(
"realSource"
,
source
.
get
(
"real_source"
));
});
return
resultJSONObject
;
}
/**
* 获取每日稿件倾向稿件数量信息
*
...
...
@@ -1008,4 +1034,5 @@ public class MarkDataServiceImpl implements MarkDataService {
return
instance
;
}
}
\ No newline at end of file
src/main/resources/application-local.properties
View file @
b9117713
...
...
@@ -59,3 +59,14 @@ qbjc.project.url=https://yuqing.zhiweidata.com/qbjcbackPhoenix/interface/project
qbjc.event.url
=
https://yuqing.zhiweidata.com/qbjcbackPhoenix/interface/aplan/event
qbjc.event.tag.url
=
https://yuqing.zhiweidata.com/qbjcbackPhoenix/interface/tag/event?project={1}
qbjc.platform.url
=
https://yuqing.zhiweidata.com/qbjcbackPhoenix/interface/platform/resource
#\u5371\u673A\u5E93\u5916\u90E8\u63A5\u53E3
crisis.search.url
=
https://crisis.zhiweidata.com/app/brandkbs/crisisSearch?page={1}&size={2}&keyword={3}
crisis.searchTags.url
=
https://crisis.zhiweidata.com/app/brandkbs/searchCrisisByTags?page={1}&size={2}&brand={3}&category={4}
crisis.top3.url
=
https://crisis.zhiweidata.com/app/brandkbs/event/online-top3
crisis.searchCriteria.url
=
https://crisis.zhiweidata.com/app/brandkbs/condition
crisis.list.url
=
https://crisis.zhiweidata.com/app/brandkbs/crisisList?page={1}&size={2}&startTime={3}&endTime={4}&category={5}
crisis.share.url
=
https://crisis.zhiweidata.com/app/brandkbs/share/{1}
#\u70ED\u70B9\u5E93\u5916\u90E8\u63A5\u53E3
trends.longTimeInListSearchByInner.url
=
https://trends.zhiweidata.com/hotSearchTrend/inner/longTimeInListSearchByInner?sortType={1}&type={2}
trends.findHotSearchESDataInTimeByInner.url
=
https://hotsearch-manage.zhiweidata.com/hotsearch/hotSearch/findHotSearchESDataInTimeByInner?limit={1}&page={2}&type={3}&word={4}
trends.longTimeInListSearch.url
=
https://trends.zhiweidata.com/hotSearchTrend/search/longTimeInListSearch?type={1}&sortType=realTime
\ No newline at end of file
src/main/resources/application.properties
View file @
b9117713
spring.profiles.active
=
pro
spring.profiles.active
=
local
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