Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
T
traffic-signal-platform
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
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
signal
traffic-signal-platform
Commits
11a92de9
Commit
11a92de9
authored
Sep 19, 2023
by
hanbing
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[add] 新信号评价-运行评价-详细指标查询,转向级指标
parent
1726c58b
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
301 additions
and
1 deletion
+301
-1
MetricsTurnBO.java
...service/src/main/java/net/wanji/opt/bo/MetricsTurnBO.java
+32
-0
SceneEvaluateController.java
...ava/net/wanji/opt/controller/SceneEvaluateController.java
+15
-1
SceneEvaluateService.java
...main/java/net/wanji/opt/service/SceneEvaluateService.java
+4
-0
SceneEvaluateServiceImpl.java
.../net/wanji/opt/service/impl/SceneEvaluateServiceImpl.java
+193
-0
SceneEvaluateMetricsTurnVO.java
...ain/java/net/wanji/opt/vo/SceneEvaluateMetricsTurnVO.java
+47
-0
CrossTurnDataHistMapper.java
...net/wanji/databus/dao/mapper/CrossTurnDataHistMapper.java
+2
-0
CrossTurnDataHistMapper.xml
...bus/src/main/resources/mapper/CrossTurnDataHistMapper.xml
+8
-0
No files found.
signal-optimize-service/src/main/java/net/wanji/opt/bo/MetricsTurnBO.java
0 → 100644
View file @
11a92de9
package
net
.
wanji
.
opt
.
bo
;
import
com.fasterxml.jackson.annotation.JsonFormat
;
import
io.swagger.annotations.ApiModel
;
import
io.swagger.annotations.ApiModelProperty
;
import
lombok.Data
;
import
java.util.Date
;
/**
* @author Kent HAN
* @date 2023/6/9 13:52
*/
@Data
@ApiModel
(
value
=
"MetricsTurnBO"
,
description
=
"转向级指标查询输入参数"
)
public
class
MetricsTurnBO
{
@ApiModelProperty
(
value
=
"0正常 1失衡 2拥堵 3溢出"
)
private
Integer
status
;
@ApiModelProperty
(
value
=
"路口ID"
,
required
=
true
)
private
String
crossId
;
@ApiModelProperty
(
value
=
"进口方向:1北;2东北;3东;4东南;5南;6西南;7西;8西北"
,
required
=
true
)
private
Integer
dir
;
@ApiModelProperty
(
value
=
"时间 HH:mm"
,
required
=
true
)
private
String
hourMinute
;
@ApiModelProperty
(
value
=
"日期 yyyy-MM-dd"
)
@JsonFormat
(
shape
=
JsonFormat
.
Shape
.
STRING
,
pattern
=
"yyyy-MM-dd"
,
timezone
=
"GMT+8"
)
private
Date
day
;
}
signal-optimize-service/src/main/java/net/wanji/opt/controller/SceneEvaluateController.java
View file @
11a92de9
...
...
@@ -7,10 +7,12 @@ import io.swagger.annotations.ApiResponses;
import
net.wanji.common.framework.rest.JsonViewObject
;
import
net.wanji.databus.bo.CrossIdAndStartEndDateBO
;
import
net.wanji.opt.bo.AbnormalDetailBO
;
import
net.wanji.opt.bo.MetricsTurnBO
;
import
net.wanji.opt.bo.SceneMetricsDetailBO
;
import
net.wanji.opt.service.impl.SceneEvaluateServiceImpl
;
import
net.wanji.opt.vo.SceneEvaluateAbnormalDetailVO
;
import
net.wanji.opt.vo.SceneEvaluateAbnormalDistributeVO
;
import
net.wanji.opt.vo.SceneEvaluateMetricsTurnVO
;
import
net.wanji.opt.vo.SceneMetricsDetailVO
;
import
org.springframework.web.bind.annotation.PostMapping
;
import
org.springframework.web.bind.annotation.RequestBody
;
...
...
@@ -62,7 +64,7 @@ public class SceneEvaluateController {
return
JsonViewObject
.
newInstance
().
success
(
res
);
}
@ApiOperation
(
value
=
"
详细指标查询"
,
notes
=
"详细指标查询
"
,
response
=
JsonViewObject
.
class
,
@ApiOperation
(
value
=
"
曲线图"
,
notes
=
"曲线图
"
,
response
=
JsonViewObject
.
class
,
produces
=
MediaType
.
APPLICATION_JSON
,
consumes
=
MediaType
.
APPLICATION_JSON
)
@PostMapping
(
value
=
"/metricsDetail"
,
produces
=
MediaType
.
APPLICATION_JSON
,
consumes
=
MediaType
.
APPLICATION_JSON
)
...
...
@@ -74,4 +76,16 @@ public class SceneEvaluateController {
List
<
SceneMetricsDetailVO
>
res
=
sceneEvaluateService
.
metricsDetail
(
bo
);
return
JsonViewObject
.
newInstance
().
success
(
res
);
}
@ApiOperation
(
value
=
"转向级指标"
,
notes
=
"转向级指标"
,
response
=
JsonViewObject
.
class
,
produces
=
MediaType
.
APPLICATION_JSON
,
consumes
=
MediaType
.
APPLICATION_JSON
)
@PostMapping
(
value
=
"/metricsTurn"
,
produces
=
MediaType
.
APPLICATION_JSON
,
consumes
=
MediaType
.
APPLICATION_JSON
)
@ApiResponses
({
@ApiResponse
(
code
=
200
,
message
=
"OK"
,
response
=
SceneEvaluateMetricsTurnVO
.
class
),
})
public
JsonViewObject
metricsTurn
(
@RequestBody
MetricsTurnBO
bo
)
throws
ParseException
{
SceneEvaluateMetricsTurnVO
res
=
sceneEvaluateService
.
metricsTurn
(
bo
);
return
JsonViewObject
.
newInstance
().
success
(
res
);
}
}
\ No newline at end of file
signal-optimize-service/src/main/java/net/wanji/opt/service/SceneEvaluateService.java
View file @
11a92de9
...
...
@@ -2,9 +2,11 @@ package net.wanji.opt.service;
import
net.wanji.databus.bo.CrossIdAndStartEndDateBO
;
import
net.wanji.opt.bo.AbnormalDetailBO
;
import
net.wanji.opt.bo.MetricsTurnBO
;
import
net.wanji.opt.bo.SceneMetricsDetailBO
;
import
net.wanji.opt.vo.SceneEvaluateAbnormalDetailVO
;
import
net.wanji.opt.vo.SceneEvaluateAbnormalDistributeVO
;
import
net.wanji.opt.vo.SceneEvaluateMetricsTurnVO
;
import
net.wanji.opt.vo.SceneMetricsDetailVO
;
import
java.lang.reflect.InvocationTargetException
;
...
...
@@ -18,4 +20,6 @@ public interface SceneEvaluateService {
SceneEvaluateAbnormalDetailVO
abnormalDetail
(
AbnormalDetailBO
abnormalDetailBO
)
throws
ParseException
;
List
<
SceneMetricsDetailVO
>
metricsDetail
(
SceneMetricsDetailBO
bo
)
throws
InvocationTargetException
,
NoSuchMethodException
,
IllegalAccessException
;
SceneEvaluateMetricsTurnVO
metricsTurn
(
MetricsTurnBO
bo
)
throws
ParseException
;
}
signal-optimize-service/src/main/java/net/wanji/opt/service/impl/SceneEvaluateServiceImpl.java
View file @
11a92de9
...
...
@@ -15,8 +15,10 @@ import net.wanji.databus.dao.mapper.*;
import
net.wanji.databus.dto.MetricHistDTO
;
import
net.wanji.databus.po.CrossDataHistPO
;
import
net.wanji.databus.po.CrossDirDataHistPO
;
import
net.wanji.databus.po.CrossTurnDataHistPO
;
import
net.wanji.feign.service.ControlFeignClients
;
import
net.wanji.opt.bo.AbnormalDetailBO
;
import
net.wanji.opt.bo.MetricsTurnBO
;
import
net.wanji.opt.bo.SceneMetricsDetailBO
;
import
net.wanji.opt.service.SceneEvaluateService
;
import
net.wanji.opt.vo.*
;
...
...
@@ -297,6 +299,197 @@ public class SceneEvaluateServiceImpl implements SceneEvaluateService {
return
res
;
}
@Override
public
SceneEvaluateMetricsTurnVO
metricsTurn
(
MetricsTurnBO
bo
)
throws
ParseException
{
Integer
status
=
bo
.
getStatus
();
String
crossId
=
bo
.
getCrossId
();
Integer
dir
=
bo
.
getDir
();
Date
day
=
bo
.
getDay
();
String
hourMinute
=
bo
.
getHourMinute
();
// 构造开始时间结束时间
SimpleDateFormat
sdf
=
new
SimpleDateFormat
(
"yyyy-MM-dd"
);
SimpleDateFormat
dateTimeFormatter
=
new
SimpleDateFormat
(
"yyyy-MM-dd HH:mm:ss"
);
String
todayDateString
=
sdf
.
format
(
day
);
// Get today's date
String
startTimeString
=
todayDateString
+
" "
+
hourMinute
+
":00"
;
Date
startTime
=
dateTimeFormatter
.
parse
(
startTimeString
);
Calendar
cal
=
Calendar
.
getInstance
();
cal
.
setTime
(
startTime
);
cal
.
add
(
Calendar
.
MINUTE
,
4
);
cal
.
add
(
Calendar
.
SECOND
,
59
);
Date
endTime
=
cal
.
getTime
();
int
startTimeStamp
=
(
int
)
(
startTime
.
getTime
()
/
1000
);
int
endTimeStamp
=
(
int
)
(
endTime
.
getTime
()
/
1000
);
// 查询该时段内转向级别数据
List
<
CrossTurnDataHistPO
>
crossTurnDataHistPOList
=
crossTurnDataHistMapper
.
selectByCrossIdAndDir
(
crossId
,
dir
,
endTimeStamp
,
startTimeStamp
);
Map
<
String
,
List
<
CrossTurnDataHistPO
>>
groupedByTurn
=
crossTurnDataHistPOList
.
stream
()
.
collect
(
Collectors
.
groupingBy
(
CrossTurnDataHistPO:
:
getTurnType
));
SceneEvaluateMetricsTurnVO
res
=
new
SceneEvaluateMetricsTurnVO
();
// 获取延误
double
v
=
crossTurnDataHistPOList
.
stream
()
.
mapToInt
(
CrossTurnDataHistPO:
:
getDelayTime
)
.
average
()
.
orElse
(
0
);
Integer
delayTime
=
(
int
)
v
;
Integer
level
=
calcCongestionLevel
(
delayTime
);
res
.
setLevel
(
level
);
List
<
SceneEvaluateMetricsTurnVO
.
TurnListElement
>
elementList
=
new
ArrayList
<>();
for
(
Map
.
Entry
<
String
,
List
<
CrossTurnDataHistPO
>>
entry
:
groupedByTurn
.
entrySet
())
{
SceneEvaluateMetricsTurnVO
.
TurnListElement
element
=
buildTurnListElement
(
entry
,
status
);
elementList
.
add
(
element
);
}
res
.
setTurnList
(
elementList
);
return
res
;
}
private
SceneEvaluateMetricsTurnVO
.
TurnListElement
buildTurnListElement
(
Map
.
Entry
<
String
,
List
<
CrossTurnDataHistPO
>>
entry
,
Integer
status
)
{
SceneEvaluateMetricsTurnVO
.
TurnListElement
element
=
new
SceneEvaluateMetricsTurnVO
.
TurnListElement
();
String
turn
=
entry
.
getKey
();
element
.
setTurn
(
turn
);
List
<
CrossTurnDataHistPO
>
poList
=
entry
.
getValue
();
// 获取流量
OptionalDouble
optionalAverageFlow
=
poList
.
stream
()
.
filter
(
Objects:
:
nonNull
)
.
mapToInt
(
CrossTurnDataHistPO:
:
getFlow
)
.
average
();
int
averageFlow
=
0
;
if
(
optionalAverageFlow
.
isPresent
())
{
averageFlow
=
(
int
)
Math
.
round
(
optionalAverageFlow
.
getAsDouble
());
}
element
.
setFlow
(
averageFlow
);
// 动态指标
element
.
setMetricsMap
(
buildTurnMetricMap
(
poList
,
status
));
return
element
;
}
private
Map
<
String
,
Integer
>
buildTurnMetricMap
(
List
<
CrossTurnDataHistPO
>
poList
,
Integer
status
)
{
Map
<
String
,
Integer
>
res
=
new
HashMap
<>();
if
(
Objects
.
equals
(
status
,
CrossStatusEnum
.
CONGESTION
.
getCode
()))
{
buildTurnCongestionRes
(
res
,
poList
);
}
else
if
(
Objects
.
equals
(
status
,
CrossStatusEnum
.
UNBALANCE
.
getCode
()))
{
buildTurnUnbalanceRes
(
res
,
poList
);
}
else
if
(
Objects
.
equals
(
status
,
CrossStatusEnum
.
SPILLOVER
.
getCode
()))
{
buildTurnSpilloverRes
(
res
,
poList
);
}
return
res
;
}
private
void
buildTurnSpilloverRes
(
Map
<
String
,
Integer
>
res
,
List
<
CrossTurnDataHistPO
>
poList
)
{
// 最大排队长度
double
maxQueueLength
=
poList
.
stream
()
.
mapToDouble
(
CrossTurnDataHistPO:
:
getQueueLength
)
.
max
()
.
orElse
(
0.0
);
int
maxQueueLengthInt
=
(
int
)
(
Math
.
round
(
maxQueueLength
));
res
.
put
(
StrategyAndMetricsEnum
.
Metrics
.
MAX_QUEUE_LENGTH
.
getCode
(),
maxQueueLengthInt
);
// 平均延误
double
maxDelayTime
=
poList
.
stream
()
.
mapToInt
(
CrossTurnDataHistPO:
:
getDelayTime
)
.
average
()
.
orElse
(
0.0
);
int
maxDelayTimeInt
=
(
int
)
(
Math
.
round
(
maxDelayTime
));
res
.
put
(
StrategyAndMetricsEnum
.
Metrics
.
AVERAGE_DELAY
.
getCode
(),
maxDelayTimeInt
);
// 停车次数
double
maxStopTimes
=
poList
.
stream
()
.
mapToDouble
(
CrossTurnDataHistPO:
:
getStopTimes
)
.
average
()
.
orElse
(
0.0
);
int
maxStopTimesInt
=
(
int
)
(
Math
.
round
(
maxStopTimes
));
res
.
put
(
StrategyAndMetricsEnum
.
Metrics
.
STOP_TIMES
.
getCode
(),
maxStopTimesInt
);
// 溢流率
double
maxEffusionRate
=
poList
.
stream
()
.
mapToDouble
(
CrossTurnDataHistPO:
:
getEffusionRate
)
.
average
()
.
orElse
(
0.0
);
int
maxEffusionRateInt
=
(
int
)
(
Math
.
round
(
maxEffusionRate
*
100
));
res
.
put
(
StrategyAndMetricsEnum
.
Metrics
.
EFFUSION_RATE
.
getCode
(),
maxEffusionRateInt
);
}
private
void
buildTurnUnbalanceRes
(
Map
<
String
,
Integer
>
res
,
List
<
CrossTurnDataHistPO
>
poList
)
{
// 不停车通过率
double
maxNoStopRate
=
poList
.
stream
()
.
mapToDouble
(
CrossTurnDataHistPO:
:
getNoStopRate
)
.
average
()
.
orElse
(
0.0
);
int
maxNoStopRateInt
=
(
int
)
(
Math
.
round
(
maxNoStopRate
*
100
));
res
.
put
(
StrategyAndMetricsEnum
.
Metrics
.
NO_STOP_RATE
.
getCode
(),
maxNoStopRateInt
);
// N次停车通过率
double
maxOneStopRate
=
poList
.
stream
()
.
mapToDouble
(
CrossTurnDataHistPO:
:
getOneStopRate
)
.
average
()
.
orElse
(
0.0
);
int
maxOneStopRateInt
=
(
int
)
(
Math
.
round
(
maxOneStopRate
*
100
));
res
.
put
(
StrategyAndMetricsEnum
.
Metrics
.
STOP_RATE
.
getCode
(),
maxOneStopRateInt
);
// 空放次数-绿灯有效利用率小于80%
long
emptyDischarges
=
poList
.
stream
()
.
mapToDouble
(
CrossTurnDataHistPO:
:
getGreenLightEfficiency
)
.
filter
(
efficiency
->
efficiency
<
0.8
)
.
count
();
res
.
put
(
StrategyAndMetricsEnum
.
Metrics
.
EMPTY_DISCHARGES
.
getCode
(),
(
int
)
emptyDischarges
);
// 绿灯有效利用率
double
maxGreenLightEfficiency
=
poList
.
stream
()
.
mapToDouble
(
CrossTurnDataHistPO:
:
getGreenLightEfficiency
)
.
average
()
.
orElse
(
0.0
);
int
maxGreenLightEfficiencyInt
=
(
int
)
(
Math
.
round
(
maxGreenLightEfficiency
*
100
));
res
.
put
(
StrategyAndMetricsEnum
.
Metrics
.
GREEN_LIGHT_EFFICIENCY
.
getCode
(),
maxGreenLightEfficiencyInt
);
}
private
void
buildTurnCongestionRes
(
Map
<
String
,
Integer
>
res
,
List
<
CrossTurnDataHistPO
>
poList
)
{
// N次停车通过率
double
maxOneStopRate
=
poList
.
stream
()
.
mapToDouble
(
CrossTurnDataHistPO:
:
getOneStopRate
)
.
average
()
.
orElse
(
0.0
);
int
maxOneStopRateInt
=
(
int
)
(
Math
.
round
(
maxOneStopRate
*
100
));
res
.
put
(
StrategyAndMetricsEnum
.
Metrics
.
STOP_RATE
.
getCode
(),
maxOneStopRateInt
);
// 平均速度
double
maxSpeed
=
poList
.
stream
()
.
mapToDouble
(
CrossTurnDataHistPO:
:
getSpeed
)
.
average
()
.
orElse
(
0.0
);
int
maxSpeedInt
=
(
int
)
(
Math
.
round
(
maxSpeed
));
res
.
put
(
StrategyAndMetricsEnum
.
Metrics
.
AVERAGE_SPEED
.
getCode
(),
maxSpeedInt
);
// 平均延误
double
maxDelayTime
=
poList
.
stream
()
.
mapToInt
(
CrossTurnDataHistPO:
:
getDelayTime
)
.
average
()
.
orElse
(
0.0
);
int
maxDelayTimeInt
=
(
int
)
(
Math
.
round
(
maxDelayTime
));
res
.
put
(
StrategyAndMetricsEnum
.
Metrics
.
AVERAGE_DELAY
.
getCode
(),
maxDelayTimeInt
);
// 停车次数
double
maxStopTimes
=
poList
.
stream
()
.
mapToDouble
(
CrossTurnDataHistPO:
:
getStopTimes
)
.
average
()
.
orElse
(
0.0
);
int
maxStopTimesInt
=
(
int
)
(
Math
.
round
(
maxStopTimes
));
res
.
put
(
StrategyAndMetricsEnum
.
Metrics
.
STOP_TIMES
.
getCode
(),
maxStopTimesInt
);
// 最大排队长度
double
maxQueueLength
=
poList
.
stream
()
.
mapToDouble
(
CrossTurnDataHistPO:
:
getQueueLength
)
.
max
()
.
orElse
(
0.0
);
int
maxQueueLengthInt
=
(
int
)
(
Math
.
round
(
maxQueueLength
));
res
.
put
(
StrategyAndMetricsEnum
.
Metrics
.
MAX_QUEUE_LENGTH
.
getCode
(),
maxQueueLengthInt
);
// 溢流率
double
maxEffusionRate
=
poList
.
stream
()
.
mapToDouble
(
CrossTurnDataHistPO:
:
getEffusionRate
)
.
average
()
.
orElse
(
0.0
);
int
maxEffusionRateInt
=
(
int
)
(
Math
.
round
(
maxEffusionRate
*
100
));
res
.
put
(
StrategyAndMetricsEnum
.
Metrics
.
EFFUSION_RATE
.
getCode
(),
maxEffusionRateInt
);
}
private
List
<
SceneMetricsDetailVO
>
buildMetricsList
(
List
<
MetricHistDTO
>
metricHistDTOList
,
Integer
minutes
,
List
<
String
>
metricCodes
)
throws
NoSuchMethodException
,
InvocationTargetException
,
IllegalAccessException
{
List
<
SceneMetricsDetailVO
>
res
=
new
ArrayList
<>();
...
...
signal-optimize-service/src/main/java/net/wanji/opt/vo/SceneEvaluateMetricsTurnVO.java
0 → 100644
View file @
11a92de9
package
net
.
wanji
.
opt
.
vo
;
import
com.fasterxml.jackson.annotation.JsonAnyGetter
;
import
com.fasterxml.jackson.annotation.JsonIgnore
;
import
io.swagger.annotations.ApiModel
;
import
io.swagger.annotations.ApiModelProperty
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
java.util.Date
;
import
java.util.List
;
import
java.util.Map
;
/**
* @author Kent HAN
* @date 2023/2/9 8:38
*/
@Data
@NoArgsConstructor
@ApiModel
(
value
=
"SceneEvaluateMetricsTurnVO"
,
description
=
"转向级指标"
)
public
class
SceneEvaluateMetricsTurnVO
{
// todo 目前只有拥堵,后期扩展考虑增加字段
@ApiModelProperty
(
value
=
"等级"
,
notes
=
"0畅通 1轻度 2中度 3严重"
)
private
Integer
level
;
@ApiModelProperty
(
value
=
"转向指标"
)
private
List
<
TurnListElement
>
turnList
;
@NoArgsConstructor
@Data
public
static
class
TurnListElement
{
@ApiModelProperty
(
value
=
"转向:u掉头;l左转;s直行;r右转"
)
private
String
turn
;
@ApiModelProperty
(
value
=
"流量(单位:pcu/5min)"
)
private
Integer
flow
;
// 可变指标数据
@JsonIgnore
private
Map
<
String
,
Integer
>
metricsMap
;
@JsonAnyGetter
public
Map
<
String
,
Integer
>
any
()
{
return
metricsMap
;
}
}
}
wj-databus/src/main/java/net/wanji/databus/dao/mapper/CrossTurnDataHistMapper.java
View file @
11a92de9
...
...
@@ -26,4 +26,6 @@ public interface CrossTurnDataHistMapper extends BaseMapper<CrossTurnDataHistPO>
List
<
MetricHistDTO
>
selectMetricHistDTO
(
String
crossId
,
int
startStamp
,
int
endStamp
);
List
<
CrossTurnDataHistPOExt
>
selectByMetrics
(
String
crossId
,
int
dirInt
,
String
turnType
,
int
startTimeStamp
,
int
endTimeStamp
,
List
<
String
>
laneIds
);
List
<
CrossTurnDataHistPO
>
selectByCrossIdAndDir
(
String
crossId
,
Integer
dir
,
long
endTimeStamp
,
long
startTimeStamp
);
}
wj-databus/src/main/resources/mapper/CrossTurnDataHistMapper.xml
View file @
11a92de9
...
...
@@ -117,5 +117,13 @@
AND batch_time
<![CDATA[ >= ]]>
#{startTimeStamp}
</select>
<select
id=
"selectByCrossIdAndDir"
resultType=
"net.wanji.databus.po.CrossTurnDataHistPO"
>
select
<include
refid=
"Base_Column_List"
/>
from t_cross_turn_data_hist
where cross_id = #{crossId} and in_dir = #{dir}
and batch_time
<![CDATA[ <= ]]>
#{endTimeStamp}
and batch_time
<![CDATA[ >= ]]>
#{startTimeStamp}
</select>
</mapper>
\ No newline at end of file
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