Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
I
integrated-scheduling-v3
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
1
Merge Requests
1
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
张晓彤
integrated-scheduling-v3
Commits
e85b1be3
Commit
e85b1be3
authored
Jun 14, 2022
by
张晓彤
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
1.dispatcher redis 写入 2.dispatchInfo 读取group name 3.tables 增加部分表字段
parent
66ff835d
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
231 additions
and
61 deletions
+231
-61
algorithm.py
alg/algorithm.py
+1
-1
dispatcher.py
core/dispatcher.py
+165
-51
group.py
core/group.py
+5
-2
schedule.py
core/schedule.py
+1
-0
dispatchInfo.py
data/dispatchInfo.py
+22
-0
truck.py
equipment/truck.py
+0
-2
realtime_dispatch.py
realtime_dispatch.py
+1
-2
static_data_process.py
static_data_process.py
+2
-2
tables.py
tables.py
+34
-1
No files found.
alg/algorithm.py
View file @
e85b1be3
...
...
@@ -186,7 +186,7 @@ class ExpectedTime(AlgorithmBase):
# 车辆驶往各目的地时间
truck_reach_time
=
60
*
self
.
group
.
park_to_excavator_distance
[
0
,
:]
/
1000
/
\
self
.
truckempty_speed
[
truck_id
]
+
truck_avl_time
self
.
truck
.
empty_speed
[
truck_id
]
+
truck_avl_time
# 计算车辆得到服务时间
truck_service_time
=
np
.
maximum
(
truck_reach_time
,
excavator_val_time
)
...
...
core/dispatcher.py
View file @
e85b1be3
...
...
@@ -10,7 +10,7 @@ from data.dispatchInfo import DispatchInfo
from
core.group
import
Group
from
alg.algorithm
import
ExpectedTime
from
settings
import
get_logger
,
session_mysql
,
redis5
from
tables
import
Dispatch
from
tables
import
Dispatch
,
DispatchMatch
,
DispatchEquipment
,
DispatchGroup
from
para_config
import
DeviceMap
,
get_value
,
global_period_para_update
from
equipment
import
TruckInfo
,
ExcavatorInfo
,
DumpInfo
from
core.schedule
import
PreSchedule
...
...
@@ -69,6 +69,8 @@ class Dispatcher:
"""
for
group
in
self
.
group_list
:
truck_dispatch_plan_dict
=
group
.
group_dispatch
(
ExpectedTime
)
print
(
"truck_dispatch_plan_dict"
)
print
(
truck_dispatch_plan_dict
)
self
.
submission
.
group_dispatch_to_redis
(
group
,
truck_dispatch_plan_dict
)
...
...
@@ -95,7 +97,8 @@ class DispatchSubmission:
"""
try
:
try
:
group_id
=
self
.
group
.
dispatch_truck_group
[
truck_id
]
# group_id = self.group.dispatch_truck_group[truck_id]
group_id
=
DispatchInfo
.
truck_group_dict
[
truck_id
]
record
=
{
"truckId"
:
truck_id
}
task
=
self
.
truck
.
get_truck_current_task
()[
truck_id
]
...
...
@@ -105,65 +108,139 @@ class DispatchSubmission:
if
task
in
[
0
,
1
,
2
]:
# 卡车空载或在装载区出场前, 可变更卸载目的地
try
:
# item = (
# session_mysql.query(DispatchMatch)
# .filter_by(dump_id=dispatch_seq[1],
# exactor_id=dispatch_seq[0],
# truck_id=truck_id,
# group_id=group_id,
# isauto=1, isdeleted=0, ).first())
# item = (
# session_mysql.query(DispatchMatch)
# .filter_by(exactor_id=dispatch_seq[0],
# dump_id=dispatch_seq[1],
# truck_id=truck_id,
# group_id=group_id,
# isauto=1, isdeleted=0, ).first())
item
=
(
session_mysql
.
query
(
Dispatch
)
.
filter_by
(
dump_id
=
DeviceMap
.
dump_index_to_uuid_dict
[
dispatch_seq
[
1
]],
exactor_id
=
DeviceMap
.
excavator_index_to_uuid_dict
[
dispatch_seq
[
0
]],
truck_id
=
truck_id
,
group_id
=
group_id
,
isauto
=
1
,
isdeleted
=
0
,
)
.
first
())
session_mysql
.
query
(
DispatchEquipment
.
id
,
DispatchMatch
.
load_area_id
,
DispatchMatch
.
unload_area_id
,
DispatchMatch
.
dump_id
,
DispatchEquipment
.
isdeleted
)
.
join
(
DispatchEquipment
,
DispatchMatch
.
match_code
==
DispatchEquipment
.
match_code
)
.
filter
(
DispatchMatch
.
exactor_id
==
dispatch_seq
[
0
],
DispatchMatch
.
dump_id
==
dispatch_seq
[
1
],
DispatchEquipment
.
equipment_id
==
truck_id
,
DispatchMatch
.
id
==
group_id
)
.
first
())
if
item
is
None
:
raise
Exception
(
"调度计划表与实时监控不匹配"
)
except
Exception
as
es
:
self
.
logger
.
error
(
es
)
# item = (
# session_mysql.query(DispatchMatch)
# .filter_by(truck_id=truck_id,
# # group_id=group_id,
# isauto=1, isdeleted=0, ).first())
item
=
(
session_mysql
.
query
(
Dispatch
)
.
filter_by
(
truck_id
=
truck_id
,
# group_id=group_id,
isauto
=
1
,
isdeleted
=
0
,
)
.
first
())
session_mysql
.
query
(
DispatchEquipment
.
id
,
DispatchMatch
.
load_area_id
,
DispatchMatch
.
unload_area_id
,
DispatchMatch
.
dump_id
,
DispatchEquipment
.
isdeleted
)
.
join
(
DispatchEquipment
,
DispatchMatch
.
match_code
==
DispatchEquipment
.
match_code
)
.
filter
(
DispatchEquipment
.
equipment_id
==
truck_id
,
DispatchMatch
.
id
==
group_id
)
.
first
())
try
:
record
[
"exactorId"
]
=
item
.
exactor_id
# record["exactorId"] = item.exactor_id
# record["dumpId"] = item.dump_id
# record["loadAreaId"] = item.load_area_id
# record["unloadAreaId"] = item.unload_area_id
# record["dispatchId"] = item.id
# record["isdeleted"] = False
# record["creator"] = item.creator
# record["createtime"] = item.createtime.strftime(
# "%b %d, %Y %I:%M:%S %p")
record
[
"id"
]
=
item
.
id
record
[
"exactorId"
]
=
dispatch_seq
[
0
]
record
[
"dumpId"
]
=
item
.
dump_id
record
[
"loadAreaId"
]
=
item
.
load_area_id
record
[
"unloadAreaId"
]
=
item
.
unload_area_id
record
[
"
dispatchId"
]
=
item
.
id
record
[
"
groupId"
]
=
group_
id
record
[
"isdeleted"
]
=
False
record
[
"
creator"
]
=
item
.
creator
record
[
"
createtime"
]
=
item
.
createtime
.
strftime
(
"
%
b
%
d,
%
Y
%
I:
%
M:
%
S
%
p"
)
record
[
"
isTemp"
]
=
False
record
[
"
haulFlag"
]
=
-
1
record
[
"groupName"
]
=
DispatchInfo
.
group_name
[
group_id
]
redis5
.
set
(
truck_id
,
str
(
json
.
dumps
(
record
)))
except
Exception
as
es
:
self
.
logger
.
error
(
"调度结果写入异常-矿卡空载"
)
elif
task
in
[
3
,
4
,
5
]:
# 卡车重载或在卸载区出场前, 可变更装载目的地
try
:
# item = (
# session_mysql.query(DispatchSetting)
# .filter_by(exactor_id=dispatch_seq[0],
# dump_id=dispatch_seq[1],
# truck_id=truck_id,
# group_id=group_id,
# isauto=1, isdeleted=0, ).first())
# item = (
# session_mysql.query(DispatchMatch)
# .filter_by(exactor_id=dispatch_seq[0],
# dump_id=dispatch_seq[1],
# truck_id=truck_id,
# group_id=group_id,
# isauto=1, isdeleted=0, ).first())
item
=
(
session_mysql
.
query
(
Dispatch
)
.
filter_by
(
exactor_id
=
DeviceMap
.
excavator_index_to_uuid_dict
[
dispatch_seq
[
1
]],
dump_id
=
DeviceMap
.
dump_index_to_uuid_dict
[
dispatch_seq
[
0
]],
truck_id
=
truck_id
,
group_id
=
group_id
,
isauto
=
1
,
isdeleted
=
0
,
)
.
first
())
session_mysql
.
query
(
DispatchEquipment
.
id
,
DispatchMatch
.
load_area_id
,
DispatchMatch
.
unload_area_id
,
DispatchMatch
.
dump_id
,
DispatchEquipment
.
isdeleted
)
.
join
(
DispatchEquipment
,
DispatchMatch
.
match_code
==
DispatchEquipment
.
match_code
)
.
filter
(
DispatchMatch
.
exactor_id
==
dispatch_seq
[
0
],
DispatchMatch
.
dump_id
==
dispatch_seq
[
1
],
DispatchEquipment
.
equipment_id
==
truck_id
,
DispatchMatch
.
id
==
group_id
)
.
first
())
if
item
is
None
:
raise
Exception
(
"调度计划表与实时监控不匹配"
)
except
Exception
as
es
:
self
.
logger
.
error
(
es
)
# item = (
# session_mysql.query(DispatchMatch)
# .filter_by(truck_id=truck_id,
# # group_id=group_id,
# isauto=1, isdeleted=0, ).first())
item
=
(
session_mysql
.
query
(
Dispatch
)
.
filter_by
(
truck_id
=
truck_id
,
# group_id=group_id,
isauto
=
1
,
isdeleted
=
0
,
)
.
first
())
session_mysql
.
query
(
DispatchEquipment
.
id
,
DispatchMatch
.
load_area_id
,
DispatchMatch
.
unload_area_id
,
DispatchMatch
.
dump_id
,
DispatchEquipment
.
isdeleted
)
.
join
(
DispatchEquipment
,
DispatchMatch
.
match_code
==
DispatchEquipment
.
match_code
)
.
filter
(
DispatchEquipment
.
equipment_id
==
truck_id
,
DispatchMatch
.
id
==
group_id
)
.
first
())
try
:
record
[
"exactorId"
]
=
self
.
excavator
.
excavator_index_to_uuid_dict
[
dispatch_seq
[
1
]]
# record["exactorId"] = self.excavator.excavator_index_to_uuid_dict[dispatch_seq[1]]
# record["dumpId"] = item.dump_id
# record["loadAreaId"] = item.load_area_id
# record["unloadAreaId"] = item.unload_area_id
# record["dispatchId"] = item.id
# record["isdeleted"] = False
# record["creator"] = item.creator
# record["createtime"] = item.createtime.strftime(
# "%b %d, %Y %I:%M:%S %p")
record
[
"id"
]
=
item
.
id
record
[
"exactorId"
]
=
dispatch_seq
[
0
]
record
[
"dumpId"
]
=
item
.
dump_id
record
[
"loadAreaId"
]
=
item
.
load_area_id
record
[
"unloadAreaId"
]
=
item
.
unload_area_id
record
[
"
dispatchId"
]
=
item
.
id
record
[
"
groupId"
]
=
group_
id
record
[
"isdeleted"
]
=
False
record
[
"
creator"
]
=
item
.
creator
record
[
"
createtime"
]
=
item
.
createtime
.
strftime
(
"
%
b
%
d,
%
Y
%
I:
%
M:
%
S
%
p"
)
record
[
"
isTemp"
]
=
False
record
[
"
haulFlag"
]
=
-
1
record
[
"groupName"
]
=
DispatchInfo
.
group_name
[
group_id
]
redis5
.
set
(
truck_id
,
str
(
json
.
dumps
(
record
)))
except
Exception
as
es
:
...
...
@@ -171,40 +248,77 @@ class DispatchSubmission:
elif
task
==
-
2
:
try
:
try
:
# item = (
# session_mysql.query(Dispatch)
# .filter_by(exactor_id=dispatch_seq[0],
# truck_id=truck_id,
# group_id=group_id,
# isauto=1, isdeleted=0).first())
# load_ability = session_mysql.query(EquipmentSpec.mining_abililty). \
# join(Equipment, Equipment.equipment_spec == EquipmentSpec.id). \
# filter(Equipment.id == self.excavator_index_to_uuid_dict[excavator_index]).first()
self
.
logger
.
info
(
f
'写入矿卡 {truck_id} 调度信息'
)
self
.
logger
.
info
(
f
'挖机 {dispatch_seq[0]}'
)
self
.
logger
.
info
(
f
'分组 {group_id}'
)
item
=
(
session_mysql
.
query
(
Dispatch
)
.
filter_by
(
exactor_id
=
DeviceMap
.
excavator_index_to_uuid_dict
[
dispatch_seq
[
1
]],
truck_id
=
truck_id
,
group_id
=
group_id
,
isauto
=
1
,
isdeleted
=
0
)
.
first
())
session_mysql
.
query
(
DispatchEquipment
.
id
,
DispatchMatch
.
load_area_id
,
DispatchMatch
.
unload_area_id
,
DispatchMatch
.
dump_id
,
DispatchEquipment
.
isdeleted
)
.
join
(
DispatchEquipment
,
DispatchMatch
.
match_code
==
DispatchEquipment
.
match_code
)
.
filter
(
DispatchMatch
.
exactor_id
==
dispatch_seq
[
0
],
DispatchEquipment
.
equipment_id
==
truck_id
,
# DispatchMatch.group_code==group_id
)
.
first
())
if
item
is
None
:
raise
Exception
(
"调度计划表与实时监控不匹配"
)
self
.
logger
.
info
(
dispatch_seq
)
self
.
logger
.
info
(
dispatch_seq
[
1
])
self
.
logger
.
info
(
DeviceMap
.
excavator_index_to_uuid_dict
[
dispatch_seq
[
1
]])
# self.logger.info(dispatch_seq[1])
# self.logger.info(DeviceMap.excavator_index_to_uuid_dict[dispatch_seq[1]])
self
.
logger
.
info
(
"item"
)
print
(
item
.
id
,
item
.
truck_id
,
item
.
exactor_id
,
item
.
dump_id
)
# print
("item")
#
print(item.id, item.truck_id, item.exactor_id, item.dump_id)
except
Exception
as
es
:
self
.
logger
.
error
(
es
)
# item = (
# session_mysql.query(DispatchMatch)
# .filter_by(truck_id=truck_id,
# # group_id=group_id,
# isauto=1, isdeleted=0).first())
item
=
(
session_mysql
.
query
(
Dispatch
)
.
filter_by
(
truck_id
=
truck_id
,
# group_id=group_id,
isauto
=
1
,
isdeleted
=
0
)
.
first
())
session_mysql
.
query
(
DispatchEquipment
.
id
,
DispatchMatch
.
load_area_id
,
DispatchMatch
.
unload_area_id
,
DispatchMatch
.
dump_id
,
DispatchEquipment
.
isdeleted
)
.
join
(
DispatchEquipment
,
DispatchMatch
.
match_code
==
DispatchEquipment
.
match_code
)
.
filter
(
DispatchEquipment
.
equipment_id
==
truck_id
,
DispatchMatch
.
id
==
group_id
)
.
first
())
try
:
record
[
"exactorId"
]
=
item
.
exactor_id
# record["exactorId"] = item.exactor_id
# record["dumpId"] = item.dump_id
# record["loadAreaId"] = item.load_area_id
# record["unloadAreaId"] = item.unload_area_id
# record["dispatchId"] = item.id
# record["isdeleted"] = False
# record["creator"] = item.creator
# record["createtime"] = item.createtime.strftime(
# "%b %d, %Y %I:%M:%S %p")
record
[
"id"
]
=
item
.
id
record
[
"exactorId"
]
=
dispatch_seq
[
0
]
record
[
"dumpId"
]
=
item
.
dump_id
record
[
"loadAreaId"
]
=
item
.
load_area_id
record
[
"unloadAreaId"
]
=
item
.
unload_area_id
record
[
"
dispatchId"
]
=
item
.
id
record
[
"
groupId"
]
=
group_
id
record
[
"isdeleted"
]
=
False
record
[
"creator"
]
=
item
.
creator
record
[
"createtime"
]
=
item
.
createtime
.
strftime
(
"
%
b
%
d,
%
Y
%
I:
%
M:
%
S
%
p"
)
record
[
"isTemp"
]
=
False
record
[
"haulFlag"
]
=
-
1
record
[
"groupName"
]
=
DispatchInfo
.
group_name
[
group_id
]
self
.
logger
.
info
(
f
'redis 注入 {record}'
)
# record["createtime"] = datetime.now().strftime(
# "%b %d, %Y %I:%M:%S %p")
redis5
.
set
(
truck_id
,
str
(
json
.
dumps
(
record
)))
...
...
core/group.py
View file @
e85b1be3
...
...
@@ -142,14 +142,17 @@ class Group:
# min_index = next_excavator_list.index(min(next_excavator_list))
min_index
=
np
.
argmin
(
next_excavator_list
)
next_excavator_id
=
self
.
excavator_uuid_index_dict
.
inverse
[
min_index
]
next_dump_id
=
truck_trip
[
-
1
]
if
truck_task
==
-
2
:
next_dump_id
=
"Park"
else
:
next_dump_id
=
self
.
dump_uuid_index_dict
.
inverse
[
truck_trip
[
-
1
]]
truck_dispatch
[
i
]
=
[
next_excavator_id
,
next_dump_id
]
if
truck_task
in
[
0
,
1
]:
next_dump_list
=
s
.
solve
(
i
)
min_index
=
next_dump_list
.
index
(
min
(
next_dump_list
))
next_dump_id
=
self
.
dump_uuid_index_dict
.
inverse
[
min_index
]
next_excavator_id
=
truck_trip
[
-
1
]
next_excavator_id
=
self
.
excavator_uuid_index_dict
.
inverse
[
truck_trip
[
-
1
]
]
truck_dispatch
[
i
]
=
[
next_excavator_id
,
next_dump_id
]
# return dispatch plan
...
...
core/schedule.py
View file @
e85b1be3
...
...
@@ -269,6 +269,7 @@ class PreSchedule:
return
self
.
update_excavator_avl_time
(
excavator_avl_ls
)
\
[
self
.
excavator
.
excavator_uuid_to_index_dict
[
excavator_id
]]
else
:
tmp
=
self
.
update_excavator_avl_time
(
excavator_avl_ls
)
return
self
.
update_excavator_avl_time
(
excavator_avl_ls
)
def
get_truck_avl_time
(
self
,
truck_id
=
None
):
...
...
data/dispatchInfo.py
View file @
e85b1be3
...
...
@@ -8,6 +8,7 @@ import numpy as np
from
settings
import
*
import
pandas
as
pd
from
tables
import
DispatchMatch
,
DispatchEquipment
logger
=
get_logger
(
"mqc.dispatchInfo"
)
...
...
@@ -39,6 +40,9 @@ class DispatchInfo:
load_distance
=
{}
unload_distance
=
{}
# group_name <-> group_id
group_name
=
{}
@classmethod
def
renew_set
(
cls
):
"""
...
...
@@ -209,6 +213,24 @@ class DispatchInfo:
# logger.error("派车模式数据更新异常")
# logger.error(es)
@classmethod
def
update_group_name
(
cls
):
"""
@date:2022/6/13 20:30
@author:zxtc
@desc:处理 group name
"""
# update group_id->mode_code
logger
=
get_logger
(
"zxt.update_group_name"
)
cls
.
group_name
=
{}
try
:
for
item
in
session_mysql
.
query
(
DispatchGroup
)
.
all
():
name
=
item
.
group_name
cls
.
group_name
[
item
.
id
]
=
name
except
Exception
as
es
:
logger
.
error
(
"group_id->name更新异常"
)
logger
.
error
(
es
)
# @classmethod
# def dispatch_group_init(cls):
# """
...
...
equipment/truck.py
View file @
e85b1be3
...
...
@@ -586,10 +586,8 @@ class TruckInfo(WalkManage):
try
:
dump_material_id
=
session_postgre
.
query
(
DumpArea
)
.
filter_by
(
Id
=
unload_area_id
)
.
first
()
.
Materials
except
Exception
as
es
:
self
.
logger
.
error
(
es
)
session_postgre
.
rollback
()
session_mysql
.
rollback
()
self
.
truck_material_bind
[
truck_id
]
=
dump_material_id
if
truck_id
in
self
.
truck_excavator_bind
:
...
...
realtime_dispatch.py
View file @
e85b1be3
...
...
@@ -56,8 +56,7 @@ def process(dispatcher):
DispatchInfo
.
update_group_mode
()
DispatchInfo
.
update_group_name
()
# logger.info
# group_set = set()
...
...
static_data_process.py
View file @
e85b1be3
...
...
@@ -338,7 +338,7 @@ def update_autodisp_excavator():
dynamic_excavator_list
=
[]
try
:
for
item
in
(
session_mysql
.
query
(
Dispatch
)
.
filter_by
(
isdeleted
=
0
,
isauto
=
1
)
.
all
()
session_mysql
.
query
(
Dispatch
Match
)
.
filter_by
(
)
.
all
()
):
dynamic_excavator_list
.
append
(
item
.
exactor_id
)
if
len
(
dynamic_excavator_list
)
<
1
:
...
...
@@ -356,7 +356,7 @@ def update_autodisp_dump():
dynamic_dump_list
=
[]
try
:
for
item
in
(
session_mysql
.
query
(
Dispatch
)
.
filter_by
(
isdeleted
=
0
,
isauto
=
1
)
.
all
()
session_mysql
.
query
(
Dispatch
Match
)
.
filter_by
(
)
.
all
()
):
dynamic_dump_list
.
append
(
item
.
dump_id
)
if
len
(
dynamic_dump_list
)
<
1
:
...
...
tables.py
View file @
e85b1be3
...
...
@@ -344,6 +344,37 @@ class Dispatch(Base):
self
.
deletor
=
deletor
self
.
deletetime
=
deletetime
# class DispatchSetting(Base):
# __tablename__ = 'sys_dispatch_setting_v'
#
# group_name = Column(VARCHAR(36))
# group_id = Column(VARCHAR(36))
# group_code = Column(VARCHAR(36))
# group_type = Column(Integer)
# load_area_id = Column(VARCHAR(36))
# exactor_id = Column(VARCHAR(36))
# unload_area_id = Column(VARCHAR(36))
# dump_id = Column(VARCHAR(36))
# isauto = Column(BOOLEAN)
# truck_id = Column(VARCHAR(36))
# team_id = Column(VARCHAR(36))
# isdeleted = Column(BOOLEAN)
# proportion_id = Column(VARCHAR(36))
#
# def __init__(self, group_name, group_id, group_code, group_type, load_area_id, exactor_id, unload_area_id, dump_id, isauto, truck_id, remark, proportion_id):
# self.group_name = group_name
# self.group_id = group_id
# self.group_code = group_code
# self.group_type = group_type
# self.load_area_id = load_area_id
# self.exactor_id = exactor_id
# self.unload_area_id = unload_area_id
# self.dump_id = dump_id
# self.isauto = isauto
# self.truck_id = truck_id
# self.proportion_id = proportion_id
# self.remark = remark
class
WalkTimePark
(
Base
):
__tablename__
=
'park_load_distance'
...
...
@@ -544,13 +575,15 @@ class DispatchGroup(Base):
group_code
=
Column
(
VARCHAR
(
36
))
mode_id
=
Column
(
VARCHAR
(
36
))
mode_code
=
Column
(
Integer
)
group_name
=
Column
(
VARCHAR
(
36
))
def
__init__
(
self
,
id
,
group_type
,
group_code
,
mode_id
,
mode_code
):
def
__init__
(
self
,
id
,
group_type
,
group_code
,
mode_id
,
mode_code
,
group_name
):
self
.
id
=
id
self
.
group_type
=
group_type
self
.
group_code
=
group_code
self
.
mode_id
=
mode_id
self
.
mode_code
=
mode_code
self
.
group_name
=
group_name
class
DispatchMatch
(
Base
):
...
...
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