Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
H
HYH.APSJ
Project
Project
Details
Activity
Releases
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
佟礼
HYH.APSJ
Commits
01233646
Commit
01233646
authored
Dec 22, 2025
by
Tong Li
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin/tl'
parents
ed06e909
fc28f637
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
231 additions
and
71 deletions
+231
-71
OrderMaterial.java
src/main/java/com/aps/entity/Algorithm/OrderMaterial.java
+13
-0
OrderMaterialRequirement.java
...va/com/aps/entity/Algorithm/OrderMaterialRequirement.java
+2
-0
ErpPurchaseOrder.java
src/main/java/com/aps/entity/ErpPurchaseOrder.java
+1
-1
PurchaseReceipt.java
src/main/java/com/aps/entity/PurchaseReceipt.java
+1
-1
SjzPfWhStock.java
src/main/java/com/aps/entity/SjzPfWhStock.java
+1
-1
MaterialRequirementService.java
...com/aps/service/Algorithm/MaterialRequirementService.java
+130
-38
ScheduleOperationService.java
...a/com/aps/service/Algorithm/ScheduleOperationService.java
+5
-1
PlanResultService.java
src/main/java/com/aps/service/plan/PlanResultService.java
+73
-24
PlanResultServiceTest.java
src/test/java/com/aps/demo/PlanResultServiceTest.java
+5
-5
No files found.
src/main/java/com/aps/entity/Algorithm/OrderMaterial.java
0 → 100644
View file @
01233646
package
com
.
aps
.
entity
.
Algorithm
;
import
lombok.Data
;
/**
* 作者:佟礼
* 时间:2025-12-22
*/
@Data
public
class
OrderMaterial
{
private
OrderMaterialRequirement
materialRequirement
;
private
double
UseStcok
;
}
src/main/java/com/aps/entity/Algorithm/OrderMaterialRequirement.java
View file @
01233646
...
...
@@ -84,4 +84,6 @@ public class OrderMaterialRequirement {
* 检验周期
*/
private
Long
CkeckLeadTime
;
private
List
<
OrderMaterialRequirement
>
replaceMaterial
=
new
ArrayList
<>();
}
src/main/java/com/aps/entity/ErpPurchaseOrder.java
View file @
01233646
...
...
@@ -22,7 +22,7 @@ private String materialName;
private
Long
warehouseId
;
private
String
warehouseCode
;
private
String
warehouseName
;
private
BigDecimal
purchaseQty
;
private
double
purchaseQty
;
private
Long
unitId
;
private
String
unitName
;
private
Long
purchaseCycle
;
...
...
src/main/java/com/aps/entity/PurchaseReceipt.java
View file @
01233646
...
...
@@ -19,7 +19,7 @@ private String wlbm;
private
String
wlbb
;
private
String
zjlDw
;
private
BigDecimal
zjlSl
;
private
BigDecimal
fjl1Sl
;
private
double
fjl1Sl
;
private
String
scpc
;
private
LocalDateTime
scrq
;
private
LocalDateTime
yxqz
;
...
...
src/main/java/com/aps/entity/SjzPfWhStock.java
View file @
01233646
...
...
@@ -19,7 +19,7 @@ private String wlbm;
private
String
wlbb
;
private
String
zjlDw
;
private
BigDecimal
zjlSl
;
private
BigDecimal
fjl1Sl
;
private
double
fjl1Sl
;
private
String
scpc
;
private
LocalDateTime
scrq
;
private
LocalDateTime
yxqz
;
...
...
src/main/java/com/aps/service/Algorithm/MaterialRequirementService.java
View file @
01233646
...
...
@@ -4,6 +4,7 @@ import com.aps.common.util.SnowFlackIdWorker;
import
com.aps.entity.*
;
import
com.aps.entity.Algorithm.BOMBuildResult
;
import
com.aps.entity.Algorithm.IDAndChildID.GroupResult
;
import
com.aps.entity.Algorithm.OrderMaterial
;
import
com.aps.entity.Algorithm.OrderMaterialRequirement
;
import
com.aps.entity.basic.*
;
import
com.aps.mapper.RoutingHeaderMapper
;
...
...
@@ -385,15 +386,10 @@ public class MaterialRequirementService {
if
(
MaterialRequirements
!=
null
&&
MaterialRequirements
.
size
()>
0
)
{
for
(
Routingsupporting
component
:
MaterialRequirements
)
{
OrderMaterialRequirement
orderMaterial
=
new
OrderMaterialRequirement
();
materialRequirements
.
add
(
orderMaterial
);
orderMaterial
.
setOrderId
(
orderId
);
orderMaterial
.
setOperationId
(
operation
.
getId
());
orderMaterial
.
setChildorderId
(
StringUtils
.
isBlank
(
childorderId
)
?
orderId
:
childorderId
);
double
allneeded
=
parentQuantity
*
component
.
getMainQty
().
doubleValue
();
orderMaterial
.
setRequiredQuantity
(
allneeded
);
double
needed
=
allneeded
;
// 查找物料(流式处理替代First)
...
...
@@ -402,52 +398,76 @@ public class MaterialRequirementService {
.
findFirst
()
.
orElse
(
null
);
if
(
material
==
null
)
{
continue
;
return
null
;
}
orderMaterial
.
setMaterialType
(
material
.
getMaterialType
());
orderMaterial
.
setMaterialTypeName
(
material
.
getMaterialTypeName
());
orderMaterial
.
setMaterialId
(
material
.
getId
());
orderMaterial
.
setCkeckLeadTime
(
material
.
getCkeckLeadTime
());
OrderMaterialRequirement
orderMaterial
=
MaterialStock
(
material
,
""
,
orderId
,
childorderId
,
operation
,
allneeded
,
needed
);
double
useStock
=
0
;
if
(
orderMaterial
!=
null
)
{
useStock
=
orderMaterial
.
getUseStock
();
materialRequirements
.
add
(
orderMaterial
);
orderMaterial
.
setLevel
(
level
);
}
// 扣减现有库存
double
availableNow
=
material
.
getCurrentStock
();
double
useStock
=
Math
.
min
(
needed
,
availableNow
);
material
.
setCurrentStock
(
material
.
getCurrentStock
()
-
useStock
);
orderMaterial
.
setUseStock
(
useStock
);
needed
-=
useStock
;
if
(
needed
<=
0
)
{
orderMaterial
.
setYpQty
(
allneeded
-
needed
);
orderMaterial
.
setQjQty
(
needed
);
continue
;
}
List
<
RoutingSupportingReplace
>
routingsupportingreplaces2
=
routingsupportingreplaces
.
stream
().
filter
(
t
->
t
.
getStrsupid
().
equals
(
component
.
getStrId
())&&
t
.
getMaterialid
()!=
component
.
getMaterialId
()).
collect
(
Collectors
.
toList
());
if
(
routingsupportingreplaces2
!=
null
&&
routingsupportingreplaces2
.
size
()
>
1
)
{
for
(
RoutingSupportingReplace
rsr:
routingsupportingreplaces2
)
{
OrderMaterialRequirement
orderMaterial1
=
MaterialStock
(
null
,
rsr
.
getMaterialid
(),
orderId
,
childorderId
,
operation
,
allneeded
,
needed
);
if
(
orderMaterial1
!=
null
)
{
useStock
=
orderMaterial1
.
getUseStock
();
needed
-=
useStock
;
orderMaterial
.
setUseStock
(
orderMaterial
.
getUseStock
()+
useStock
);
orderMaterial
.
getReplaceMaterial
().
add
(
orderMaterial1
);
if
(
needed
<=
0
)
{
break
;
}
}
}
}
if
(
needed
<=
0
)
{
orderMaterial
.
setYpQty
(
allneeded
-
needed
);
orderMaterial
.
setQjQty
(
needed
);
continue
;
}
MaterialInTransit
(
material
,
""
,
orderMaterial
,
needed
);
// 处理在途物料
double
accumulated
=
0
;
LocalDateTime
earliestTime
=
null
;
double
useTransit
=
0
;
needed
-=
orderMaterial
.
getUseTransit
();
// 按到货时间排序在途物料
List
<
MaterialSupply
>
sortedInTransit
=
material
.
getInTransit
().
stream
()
.
filter
(
t
->
t
.
getQuantity
()
>
0
)
.
sorted
(
Comparator
.
comparing
(
MaterialSupply:
:
getArrivalTime
))
.
collect
(
Collectors
.
toList
());
if
(
routingsupportingreplaces2
!=
null
&&
routingsupportingreplaces2
.
size
()
>
1
)
{
for
(
RoutingSupportingReplace
rsr:
routingsupportingreplaces2
)
{
for
(
MaterialSupply
supply
:
sortedInTransit
)
{
double
useq
=
Math
.
min
(
needed
,
supply
.
getQuantity
());
useTransit
+=
useq
;
needed
-=
useq
;
supply
.
setQuantity
(
supply
.
getQuantity
()
-
useq
);
OrderMaterialRequirement
orderMaterial1
=
orderMaterial
.
getReplaceMaterial
().
stream
()
.
filter
(
t
->
t
.
getMaterialId
().
equals
(
rsr
.
getMaterialid
()))
.
findFirst
()
.
orElse
(
null
);
if
(
needed
<=
0
)
{
earliestTime
=
supply
.
getArrivalTime
();
break
;
}
}
MaterialInTransit
(
null
,
rsr
.
getMaterialid
(),
orderMaterial1
,
needed
);
orderMaterial
.
setUseTransit
(
useTransit
);
orderMaterial
.
setArrivalTime
(
earliestTime
);
orderMaterial
.
setLevel
(
level
);
needed
-=
orderMaterial1
.
getUseTransit
();
LocalDateTime
earliestTime
=
orderMaterial
.
getArrivalTime
().
compareTo
(
orderMaterial1
.
getArrivalTime
())>
0
?
orderMaterial
.
getArrivalTime
():
orderMaterial1
.
getArrivalTime
();
orderMaterial
.
setArrivalTime
(
earliestTime
);
orderMaterial
.
setUseTransit
(
orderMaterial
.
getUseTransit
()+
orderMaterial1
.
getUseTransit
());
if
(
needed
<=
0
)
{
break
;
}
}
}
if
(
needed
<=
0
)
{
orderMaterial
.
setYpQty
(
allneeded
-
needed
);
orderMaterial
.
setQjQty
(
needed
);
continue
;
}
if
(
needed
>
0
)
{
orderMaterial
.
setYpQty
(
allneeded
-
needed
);
orderMaterial
.
setQjQty
(
needed
);
...
...
@@ -561,4 +581,76 @@ public class MaterialRequirementService {
return
new
BOMBuildResult
(
materialRequirements
,
_childorders
,
_newEntrys
,
_newMachines
);
}
private
OrderMaterialRequirement
MaterialStock
(
Material
material
,
String
materialId
,
String
orderId
,
String
childorderId
,
Entry
operation
,
double
allneeded
,
double
needed
)
{
OrderMaterialRequirement
orderMaterial
=
new
OrderMaterialRequirement
();
orderMaterial
.
setOrderId
(
orderId
);
orderMaterial
.
setOperationId
(
operation
.
getId
());
orderMaterial
.
setChildorderId
(
StringUtils
.
isBlank
(
childorderId
)
?
orderId
:
childorderId
);
orderMaterial
.
setRequiredQuantity
(
allneeded
);
if
(
material
==
null
)
{
material
=
_materials
.
stream
()
.
filter
(
m
->
m
.
getId
().
equals
(
materialId
))
.
findFirst
()
.
orElse
(
null
);
if
(
material
==
null
)
{
return
null
;
}
}
double
availableNow
=
material
.
getCurrentStock
();
orderMaterial
.
setMaterialType
(
material
.
getMaterialType
());
orderMaterial
.
setMaterialTypeName
(
material
.
getMaterialTypeName
());
orderMaterial
.
setMaterialId
(
material
.
getId
());
orderMaterial
.
setCkeckLeadTime
(
material
.
getCkeckLeadTime
());
// 扣减现有库存
double
useStock
=
Math
.
min
(
needed
,
availableNow
);
material
.
setCurrentStock
(
material
.
getCurrentStock
()
-
useStock
);
orderMaterial
.
setUseStock
(
useStock
);
return
orderMaterial
;
}
private
void
MaterialInTransit
(
Material
material
,
String
materialId
,
OrderMaterialRequirement
orderMaterial
,
double
needed
){
// 处理在途物料
double
accumulated
=
0
;
LocalDateTime
earliestTime
=
LocalDateTime
.
of
(
2000
,
1
,
1
,
0
,
0
,
0
);
double
useTransit
=
0
;
if
(
material
==
null
)
{
material
=
_materials
.
stream
()
.
filter
(
m
->
m
.
getId
().
equals
(
materialId
))
.
findFirst
()
.
orElse
(
null
);
if
(
material
==
null
)
{
return
;
}
}
// 按到货时间排序在途物料
List
<
MaterialSupply
>
sortedInTransit
=
material
.
getInTransit
().
stream
()
.
filter
(
t
->
t
.
getQuantity
()
>
0
)
.
sorted
(
Comparator
.
comparing
(
MaterialSupply:
:
getArrivalTime
))
.
collect
(
Collectors
.
toList
());
for
(
MaterialSupply
supply
:
sortedInTransit
)
{
double
useq
=
Math
.
min
(
needed
,
supply
.
getQuantity
());
useTransit
+=
useq
;
needed
-=
useq
;
supply
.
setQuantity
(
supply
.
getQuantity
()
-
useq
);
earliestTime
=
earliestTime
.
compareTo
(
supply
.
getArrivalTime
())>
0
?
earliestTime:
supply
.
getArrivalTime
();
if
(
needed
<=
0
)
{
break
;
}
}
orderMaterial
.
setUseTransit
(
useTransit
);
orderMaterial
.
setArrivalTime
(
earliestTime
);
}
}
src/main/java/com/aps/service/Algorithm/ScheduleOperationService.java
View file @
01233646
...
...
@@ -114,7 +114,11 @@ Integer newMachineId1=newMachineId.intValue();
.
findFirst
()
.
orElse
(
null
);
if
(
FirstMachineResult
!=
null
)
{
opTimeMap
.
put
(
FirstMachineResult
.
getOperationId
(),
newStartTime
);
if
(
opTimeMap
.
get
(
FirstMachineResult
.
getOperationId
())<
newStartTime
)
{
opTimeMap
.
put
(
FirstMachineResult
.
getOperationId
(),
newStartTime
);
}
}
// 生成新的工序顺序
...
...
src/main/java/com/aps/service/plan/PlanResultService.java
View file @
01233646
package
com
.
aps
.
service
.
plan
;
import
com.aps.common.util.DateGroupUtil
;
import
com.aps.common.util.FileHelper
;
import
com.aps.common.util.JsonFileReader
;
import
com.aps.common.util.ProductionDeepCopyUtil
;
import
com.aps.common.util.*
;
import
com.aps.controller.gantt.FileUploadController
;
import
com.aps.entity.*
;
import
com.aps.entity.Algorithm.*
;
...
...
@@ -13,8 +10,7 @@ import com.aps.entity.basic.ScheduleChromosome;
import
com.aps.entity.Schedule.GenVO
;
import
com.aps.entity.Schedule.MachineVO
;
import
com.aps.entity.basic.*
;
import
com.aps.mapper.ConfigMapper
;
import
com.aps.mapper.MaterialInfoMapper
;
import
com.aps.mapper.*
;
import
com.aps.service.*
;
import
com.aps.service.Algorithm.*
;
import
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper
;
...
...
@@ -89,23 +85,23 @@ public class PlanResultService {
@Autowired
private
OrderSortService
orderSortService
;
@Autowired
private
MaterialInfoService
materialInfoService
;
@Autowired
private
MaterialInfoMapper
materialInfoMapper
;
@Autowired
private
Stock
Service
stockService
;
private
Stock
Mapper
stockMapper
;
@Autowired
private
SjzPfWhStock
Service
sjzPfWhStockService
;
private
SjzPfWhStock
Mapper
sjzPfWhStockMapper
;
@Autowired
private
PurchaseReceipt
Service
purchaseReceiptService
;
private
PurchaseReceipt
Mapper
purchaseReceiptMapper
;
@Autowired
private
ErpPurchaseOrder
Service
erpPurchaseOrderService
;
private
ErpPurchaseOrder
Mapper
erpPurchaseOrderMapper
;
@Autowired
private
MaterialRequirementService
materialRequirementService
;
...
...
@@ -300,7 +296,7 @@ order.setDueDate(LocalDateTime.of(2025, 12, 1,0,0,0));
public
Chromosome
execute2
(
String
SceneId
)
{
try
{
SceneId
=
"6AF8001449FC4D20A3C9992EC24CBF05"
;
ScheduleParams
param
=
new
ScheduleParams
();
param
.
setBaseTime
(
LocalDateTime
.
of
(
2025
,
11
,
1
,
0
,
0
,
0
));
...
...
@@ -326,7 +322,7 @@ order.setDueDate(LocalDateTime.of(2025, 12, 1,0,0,0));
// 3. 构建订单-工序数据
List
<
Order
>
orders
=
InitOrder
(
ProdLaunchOrders
);
List
<
Material
>
Materials
=
null
;
//
InitMaterial();
List
<
Material
>
Materials
=
InitMaterial
();
Map
<
Integer
,
Object
>
list
=
InitEntrys
(
SceneId
,
ProdEquipments
,
orders
);
List
<
Entry
>
entrys
=(
List
<
Entry
>)
list
.
get
(
1
);
...
...
@@ -932,26 +928,32 @@ private GlobalParam InitGlobalParam()
MaterialInfoWrapper
.
eq
(
MaterialInfo:
:
getIsdeleted
,
0
);
List
<
MaterialInfo
>
materiallist
=
materialInfoMapper
.
selectList
(
MaterialInfoWrapper
);
List
<
MaterialInfo
>
materiallist
=
materialInfoMapper
.
selectList
(
MaterialInfoWrapper
);
System
.
out
.
println
(
"开始初始化物料数据"
);
LambdaQueryWrapper
<
Stock
>
StockWrapper
=
new
LambdaQueryWrapper
<>();
StockWrapper
.
eq
(
Stock:
:
getIsdeleted
,
0
);
// List<ProdEquipSpecialCal> ProdEquipSpecialCals= _prodEquipSpecialCalService.list(ProdEquipSpecialCal
Wrapper);
List
<
Stock
>
Stocklist
=
stockMapper
.
selectList
(
Stock
Wrapper
);
LambdaQueryWrapper
<
ErpPurchaseOrder
>
ErpPurchaseOrderWrapper
=
new
LambdaQueryWrapper
<>();
ErpPurchaseOrderWrapper
.
eq
(
ErpPurchaseOrder:
:
getIsdeleted
,
0
);
//原材料采购订单
List
<
ErpPurchaseOrder
>
ErpPurchaseOrderlist
=
erpPurchaseOrderMapper
.
selectList
(
ErpPurchaseOrderWrapper
);
LambdaQueryWrapper
<
PurchaseReceipt
>
PurchaseReceiptWrapper
=
new
LambdaQueryWrapper
<>();
PurchaseReceiptWrapper
.
eq
(
PurchaseReceipt:
:
getIsdeleted
,
0
);
//原材料待验
List
<
PurchaseReceipt
>
PurchaseReceiptlist
=
purchaseReceiptMapper
.
selectList
(
PurchaseReceiptWrapper
);
L
ist
<
Stock
>
Stocklist
=
stockService
.
lambdaQuery
()
.
eq
(
Stock:
:
getIsdeleted
,
0
)
.
gt
(
Stock:
:
getTotal
,
0
)
.
list
(
);
L
ambdaQueryWrapper
<
SjzPfWhStock
>
SjzPfWhStockWrapper
=
new
LambdaQueryWrapper
<>();
SjzPfWhStockWrapper
.
eq
(
SjzPfWhStock:
:
getIsdeleted
,
0
);
List
<
SjzPfWhStock
>
SjzPfWhStocklists
=
sjzPfWhStockMapper
.
selectList
(
SjzPfWhStockWrapper
);
materiallist
.
forEach
(
m
->
{
Material
material
=
new
Material
();
...
...
@@ -965,6 +967,53 @@ private GlobalParam InitGlobalParam()
.
mapToDouble
(
Stock:
:
getTotal
)
.
sum
();
material
.
setCurrentStock
(
stock
);
List
<
MaterialSupply
>
materialSupplys
=
new
ArrayList
<>();
if
(
m
.
getMaterialTypeName
().
equals
(
"MP"
))
{
List
<
PurchaseReceipt
>
PurchaseReceipts
=
PurchaseReceiptlist
.
stream
()
.
filter
(
t
->
t
.
getMaterialid
()==
m
.
getId
())
.
collect
(
Collectors
.
toList
());
if
(
PurchaseReceipts
!=
null
)
{
for
(
PurchaseReceipt
mm:
PurchaseReceipts
)
{
//原材料待验
MaterialSupply
ms
=
new
MaterialSupply
();
LocalDateTime
dt
=
mm
.
getExp5
()
==
null
?
ParamValidator
.
parseDateTime
(
mm
.
getExp1
(),
""
)
:
mm
.
getExp5
();
ms
.
setQuantity
(
mm
.
getFjl1Sl
());
ms
.
setArrivalTime
(
dt
);
materialSupplys
.
add
(
ms
);
}
}
List
<
ErpPurchaseOrder
>
ErpPurchaseOrders
=
ErpPurchaseOrderlist
.
stream
()
.
filter
(
t
->
t
.
getMaterialId
()==
m
.
getId
())
.
collect
(
Collectors
.
toList
());
if
(
ErpPurchaseOrders
!=
null
)
{
for
(
ErpPurchaseOrder
mm:
ErpPurchaseOrders
)
{
//原材料采购,可用时间要加上检验时间
MaterialSupply
ms
=
new
MaterialSupply
();
LocalDateTime
dt
=
mm
.
getArrivalDate
().
plusDays
(
m
.
getInspectDuration
());
ms
.
setQuantity
(
mm
.
getPurchaseQty
());
ms
.
setArrivalTime
(
dt
);
materialSupplys
.
add
(
ms
);
}
}
}
else
{
List
<
SjzPfWhStock
>
SjzPfWhStocks
=
SjzPfWhStocklists
.
stream
()
.
filter
(
t
->
t
.
getMaterialid
()==
m
.
getId
())
.
collect
(
Collectors
.
toList
());
if
(
SjzPfWhStocks
!=
null
)
{
for
(
SjzPfWhStock
mm:
SjzPfWhStocks
)
{
//原材料采购,可用时间要加上检验时间
MaterialSupply
ms
=
new
MaterialSupply
();
LocalDateTime
dt
=
ParamValidator
.
parseDateTime
(
mm
.
getExp1
(),
""
);
ms
.
setQuantity
(
mm
.
getFjl1Sl
());
ms
.
setArrivalTime
(
dt
);
materialSupplys
.
add
(
ms
);
}
}
}
material
.
setInTransit
(
materialSupplys
);
materials
.
add
(
material
);
});
CommonCache
.
put
(
"material"
,
materials
);
...
...
src/test/java/com/aps/demo/PlanResultServiceTest.java
View file @
01233646
...
...
@@ -26,12 +26,12 @@ public class PlanResultServiceTest {
@Test
public
void
testExecute
()
{
// planResultService.execute2("
");
planResultService
.
execute2
(
"B571EF6682DB463AB2977B1055A74112
"
);
LocalDateTime
t
=
LocalDateTime
.
of
(
2025
,
11
,
15
,
6
,
51
,
11
);
List
<
Integer
>
opids
=
new
ArrayList
<>();
opids
.
add
(
1
);
planResultService
.
Move
(
"B571EF6682DB463AB2977B1055A74112"
,
opids
,
t
,
3403L
);
//
LocalDateTime t= LocalDateTime.of(2025, 11, 15, 6, 51, 11);
//
List<Integer> opids=new ArrayList<>();
//
opids.add(1);
//
planResultService.Move("B571EF6682DB463AB2977B1055A74112",opids,t,3403L);
// planResultService.Move("B571EF6682DB463AB2977B1055A74112",2,t,3243L);
}
...
...
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