Commit 4c07bada zshaohui

新的计算逻辑提交

1 个父辈 b56dec73
package com.neotel.webbox.capacitynew;
import com.neotel.webbox.capacity.bean.ReelItem;
import com.neotel.webbox.capacitynew.bean.BoxData;
import com.neotel.webbox.capacitynew.bean.BoxResult;
import com.neotel.webbox.capacitynew.bean.ReelData;
import com.neotel.webbox.capacitynew.bean.RequestItem;
import com.neotel.webbox.capacitynew.data.BaseDataCacheNew;
import com.neotel.webbox.capacitynew.method.AssignMethod;
import com.neotel.webbox.capacitynew.bean.ResultBean;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.*;
@Slf4j
@RestController
@RequestMapping("/box")
public class BoxRestControllerNew {
/**
* 获取料仓基本数据
*
* @return
*/
@RequestMapping("/baseData")
public ResultBean baseData() {
Map<String, Object> map = new HashMap<>();
List<BoxData> boxDataList = new ArrayList<>(BaseDataCacheNew.getBoxDataList());
boxDataList.sort(Comparator.comparing(BoxData::getBoxName));
map.put("boxDataList", boxDataList);
Collection<ReelData> reelNameList = BaseDataCacheNew.getReelDataList();
Map<Integer, List<Integer>> reelSizeMap = new HashMap<>();
for (ReelData reelData : reelNameList) {
int reelSize = reelData.getReelSize();
List<Integer> reelHeightList = reelSizeMap.get(reelSize);
if (reelHeightList == null) {
reelHeightList = new ArrayList<>();
}
int reelHeight = reelData.getReelHeight();
reelHeightList.add(reelHeight);
reelHeightList.sort(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;
}
});
reelSizeMap.put(reelSize, reelHeightList);
}
map.put("reelSizeMap", reelSizeMap);
return ResultBean.newOkResult(map);
}
@RequestMapping("/capacity")
public ResultBean capacityCalculation(@RequestBody Map<String, String> paramMap) {
try {
//获取到料仓数据
String boxName = paramMap.get("boxName");
log.info("收到计算料仓数量请求:" + boxName);
BoxData boxData = BaseDataCacheNew.getBoxData(boxName);
if (boxData == null) {
String msg = "未找到" + boxName + "对应的料仓";
log.warn(msg);
return ResultBean.newErrorResult(101, msg);
}
//获取到料盘数据
List<RequestItem> requestList = new ArrayList<>();
for (Map.Entry<String, String> item : paramMap.entrySet()) {
if (item.getKey().equals("boxName")) {
continue;
}
ReelData reelData = BaseDataCacheNew.getReelData(item.getKey());
if (reelData == null) {
String msg = "未找到" + boxName + "对应的料盘" + item.getKey();
log.warn(msg);
return ResultBean.newErrorResult(102, msg);
}
log.info("料盘需求" + item.getKey() + ":" + item.getValue());
int num = Integer.valueOf(item.getValue());
requestList.add(new RequestItem(num, reelData));
}
if (requestList.isEmpty()) {
String msg = "Params Error";
log.warn(msg);
return ResultBean.newErrorResult(102, msg);
}
BoxResult boxResult = AssignMethod.averageCapacityToBox(boxData, requestList);
log.info("方案一共需要" + boxResult.getBoxList().size() + "个料仓");
for (ReelItem reelItem : boxResult.getReelItemList()) {
log.info(reelItem.getSizeStr() + " 料盘需求:" + reelItem.getNeedNum() + " 容量:" + reelItem.getCapacity());
}
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("boxCount", boxResult.getBoxList().size());
List<Map<String, Object>> capacityItems = new ArrayList<>();
for (ReelItem reelItem : boxResult.getReelItemList()) {
Map<String, Object> dataMap = new HashMap<>();
int needNum = reelItem.getNeedNum();
int capacity = reelItem.getCapacity();
int w = reelItem.getW();
int h = reelItem.getH();
dataMap.put("w", w);
dataMap.put("h", h);
dataMap.put("capacity", capacity);
dataMap.put("needNum", needNum);
capacityItems.add(dataMap);
}
resultMap.put("boxName", boxName);
resultMap.put("capacityItems", capacityItems);
return ResultBean.newOkResult(resultMap);
} catch (Exception e) {
log.error("计算料仓数量时发生异常", e);
return ResultBean.newErrorResult(500, "Error");
}
}
}
package com.neotel.webbox.capacitynew.bean;
import com.neotel.webbox.capacity.bean.ReelItem;
import com.neotel.webbox.capacitynew.box.Box;
import lombok.Getter;
import lombok.Setter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@Getter
@Setter
public class BoxResult {
private List<Box> boxList;
private List<RequestItem> requestList = new ArrayList<>();
public List<ReelItem> getReelItemList() {
List<ReelItem> reelItemList = initRequestNum(requestList);
if (boxList != null) {
for (Box box : boxList) {
for (ReelItem boxReelItem : box.getCapacity().values()) {
reelItemList = addBoxCapacityToResult(reelItemList, boxReelItem);
}
}
}
return reelItemList;
}
private List<ReelItem> addBoxCapacityToResult(List<ReelItem> reelItemList, ReelItem boxReelItem) {
for (ReelItem totalReelItem : reelItemList) {
if (totalReelItem.getSizeStr().equals(boxReelItem.getSizeStr())) {
totalReelItem.addCapacity(boxReelItem.getCapacity());
return reelItemList;
}
}
//未找到,新添加一个
reelItemList.add(boxReelItem);
return reelItemList;
}
private List<ReelItem> initRequestNum(Collection<RequestItem> requestList) {
List<ReelItem> reelItemList = new ArrayList<>();
for (RequestItem reelRequestItem : requestList) {
ReelItem reelItem = new ReelItem();
reelItem.setW(reelRequestItem.getReelData().getReelSize());
reelItem.setH(reelRequestItem.getReelData().getReelHeight());
reelItem.setNeedNum(reelRequestItem.getNum());
reelItemList.add(reelItem);
}
return reelItemList;
}
}
package com.neotel.webbox.capacitynew.bean;
import lombok.Getter;
import lombok.Setter;
/**
* 标题特殊列包含的内容
*/
@Getter
@Setter
public class BoxSpecialColumnContent {
/**
* 子所在位置
*/
private Integer index;
/**
* 子标题
*/
private String title;
/**
* 对应行内容
*/
private String value;
/**
* 对应高度
*/
private Integer height;
}
package com.neotel.webbox.capacitynew.bean;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
/**
* 料仓标题
*/
public class BoxTitle {
/**
* 标题名称
*/
private String titleName;
/**
* 标题合并单元格列坐标集合
*/
private List<Integer> mergeColumnIndexList;
}
package com.neotel.webbox.capacitynew.bean;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Getter;
import lombok.Setter;
import java.util.Map;
@Getter
@Setter
public class ReelData {
/**
* 料盘尺寸
*/
@ExcelProperty("料盘尺寸")
private int reelSize;
/**
* 料盘高度
*/
@ExcelProperty("料盘厚度")
private int reelHeight;
/**
* 压紧张开高度
*/
@ExcelProperty("压紧张开高度")
private int pressHeight;
/**
* 料盘占用空间高度
*/
@ExcelProperty("料格占用高度")
private int reelSlotHeight;
/**
* 最小模组单元
*/
@ExcelIgnore
private int minUnit = 3;
/**
* 料仓特殊列,需要的数值信息,例如:入口碗:757
*/
@ExcelIgnore
private Map<String,Integer> boxSpecialColumn;
/**
* 是否是7寸盘
*/
public boolean is7Reel(){
return reelSize == 7;
}
public String getReelSizeStr(){
return reelSize + " x " + reelHeight;
}
public boolean isValid() {
return reelSize >= 7
&& reelHeight >= 8
&& pressHeight >= 10
&& reelSlotHeight >= 10;
}
}
package com.neotel.webbox.capacitynew.bean;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class RequestItem {
public RequestItem(int num, ReelData reelData) {
this.num = num;
this.reelData = reelData;
}
/**
* 需求数量
*/
private int num;
/**
* 料盘数量
*/
private ReelData reelData;
/**
* 需要纯料仓的数量
*/
private int pureBoxCount;
/**
* 放完纯料仓后剩余数量
*/
private int remainNum;
/**
* 剩余物料需要的总高度
*/
public int getRemainNeedHeight(){
int reelCount = remainNum;
if(reelData.is7Reel()){
//7寸盘,每行放2个
reelCount = reelCount /2;
if(remainNum % 2 != 0){
reelCount = reelCount + 1;
}
}
return reelCount * reelData.getReelSlotHeight();
}
public String getReelSizeStr(){
return reelData.getReelSizeStr();
}
}
package com.neotel.webbox.capacitynew.bean;
public class ResultBean {
private int code;
private String msg;
private Object data;
public static ResultBean newOkResult(Object data){
ResultBean resultBean = new ResultBean();
resultBean.setMsg("OK");
resultBean.setData(data);
return resultBean;
}
public static ResultBean newErrorResult(int code, String msg){
ResultBean resultBean = new ResultBean();
resultBean.setCode(code);
resultBean.setMsg(msg);
resultBean.setData("");
return resultBean;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
package com.neotel.webbox.capacitynew.box;
import com.neotel.webbox.capacity.bean.ReelItem;
import com.neotel.webbox.capacitynew.bean.BoxData;
import com.neotel.webbox.capacitynew.bean.BoxSpecialColumnContent;
import com.neotel.webbox.capacitynew.bean.RequestItem;
import lombok.Getter;
import lombok.Setter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Getter
@Setter
public class Box {
/**
* 标准列数量
*/
private int columnCount;
/**
* 标准列
*/
private Column column;
/**
* 特殊列
*/
private Map<String, Column> specialColumnMap;
/**
* 特殊列上部
*/
private Map<String, Column> specialColumnUpMap;
public static Box newBox(BoxData boxData, List<RequestItem> requestList, int maxPressHeight) {
int validColumnHeight = boxData.getColumnValidHeight(maxPressHeight);
Box box = new Box();
//每台机器可用的高度是一样的,只取第一条即可
Map<String, Column> specialColumnMap = getSpecialColumnMap(boxData, requestList.get(0));
box.setSpecialColumnMap(specialColumnMap);
Map<String, Column> specialColumnUpMap = getSpecialColumnUpMap(boxData, requestList, maxPressHeight);
box.setSpecialColumnUpMap(specialColumnUpMap);
Column column = new Column(validColumnHeight);
box.setColumn(column);
return box;
}
private static Map<String, Column> getSpecialColumnUpMap(BoxData boxData, List<RequestItem> requestList, int maxPressHeight) {
Map<String, Column> specialColumnUpMap = new HashMap<>();
Map<String, List<BoxSpecialColumnContent>> boxSpecialColumnMap = boxData.getBoxSpecialColumnMap();
//开始对特殊列进行遍历,取特殊列最上方最小的
if (boxSpecialColumnMap != null && boxSpecialColumnMap.size() > 0) {
for (Map.Entry<String, List<BoxSpecialColumnContent>> entry : boxSpecialColumnMap.entrySet()) {
int boxSpecialColumnUpHeight = boxData.getBoxHeight();
for (RequestItem requestItem : requestList) {
boxSpecialColumnMap = boxData.boxFillSpecialColumnHeight(boxSpecialColumnMap, requestItem.getReelData());
List<BoxSpecialColumnContent> boxSpecialColumnContentList = entry.getValue();
int boxSpecialColumnHeightTotal = boxSpecialColumnContentList.stream().mapToInt(BoxSpecialColumnContent::getHeight).sum();
int boxSpecialColumnUpValidHeight = boxData.getBoxSpecialColumnUpHeightTotal(boxSpecialColumnHeightTotal, maxPressHeight);
if (boxSpecialColumnUpHeight > boxSpecialColumnUpValidHeight) {
boxSpecialColumnUpHeight = boxSpecialColumnUpValidHeight;
}
}
if (boxSpecialColumnUpHeight != 0) {
specialColumnUpMap.put(entry.getKey(), new Column(boxSpecialColumnUpHeight));
}
}
}
return specialColumnUpMap;
}
public static Map<String, Column> getSpecialColumnMap(BoxData boxData, RequestItem requestItem) {
Map<String, Column> specialColumnMap = new HashMap<>();
Map<String, List<BoxSpecialColumnContent>> boxSpecialColumnMap = boxData.getBoxSpecialColumnMap();
if (boxSpecialColumnMap != null && boxSpecialColumnMap.size() >0) {
boxSpecialColumnMap = boxData.boxFillSpecialColumnHeight(boxSpecialColumnMap, requestItem.getReelData());
for (Map.Entry<String, List<BoxSpecialColumnContent>> entry : boxSpecialColumnMap.entrySet()) {
int boxSpecialColumnValidHeight = boxData.getBoxSingleSpecialColumnHeight(entry.getValue());
specialColumnMap.put(entry.getKey(), new Column(boxSpecialColumnValidHeight));
}
}
return specialColumnMap;
}
/**
* 获取料仓的容量明细
*/
public Map<String, ReelItem> getCapacity() {
Map<String, ReelItem> capacityMap = new HashMap<>();
for (int i = 0; i < getColumnCount(); i++) {
capacityMap = addToMap(capacityMap, column.getColumnCapacity());
}
for (Map.Entry<String, Column> entry : specialColumnMap.entrySet()) {
capacityMap = addToMap(capacityMap, entry.getValue().getColumnCapacity());
}
for (Map.Entry<String, Column> entry : specialColumnUpMap.entrySet()) {
capacityMap = addToMap(capacityMap, entry.getValue().getColumnCapacity());
}
return capacityMap;
}
private Map<String, ReelItem> addToMap(Map<String, ReelItem> capacityMap, Map<String, ReelItem> columnMap) {
for (Map.Entry<String, ReelItem> entry : columnMap.entrySet()) {
String sizeStr = entry.getKey();
ReelItem capacityItem = capacityMap.get(sizeStr);
if (capacityItem == null) {
capacityItem = new ReelItem();
capacityItem.setW(entry.getValue().getW());
capacityItem.setH(entry.getValue().getH());
}
int capacity = capacityItem.getCapacity() + entry.getValue().getCapacity();
capacityItem.setCapacity(capacity);
capacityMap.put(sizeStr, capacityItem);
}
return capacityMap;
}
}
package com.neotel.webbox.capacitynew.box;
import com.neotel.webbox.capacity.bean.ReelItem;
import com.neotel.webbox.capacitynew.bean.ReelData;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.compress.utils.Lists;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Getter
@Setter
public class Column {
public Column(int validHeight) {
this.validHeight = validHeight; //可用高度
this.remainHeight = validHeight; //需要高度
}
private int validHeight;
private int remainHeight;
private List<SlotUnit> slotUnitList = Lists.newArrayList();
public SlotUnit getSlotUnit(ReelData reelData){
for (SlotUnit slotUnit : slotUnitList) {
if(slotUnit.getReelData().equals(reelData)){
return slotUnit;
}
}
return null;
}
public SlotUnit mergeSlotUnit(SlotUnit newSlotUnit){
if(newSlotUnit == null){
return null;
}
SlotUnit existSlotUnit = getSlotUnit(newSlotUnit.getReelData());
if(existSlotUnit != null){
int mergeCount = newSlotUnit.getReelCount() + existSlotUnit.getReelCount();
newSlotUnit.setReelCount(mergeCount);
remainHeight = remainHeight + existSlotUnit.getSlotHeight();
slotUnitList.remove(existSlotUnit);
}
return addSlotUnit(newSlotUnit);
}
/**
* 将模组加入列中, 返回加入结果,如果没放入返回null
*/
public SlotUnit addSlotUnit(SlotUnit slotUnit){
if(slotUnit == null){
return null;
}
int slotHeight = slotUnit.getSlotHeight();
if(slotHeight > remainHeight){
return null;
}
remainHeight = remainHeight - slotHeight;
slotUnitList.add(slotUnit);
return slotUnit;
}
public Map<String, ReelItem> getColumnCapacity(){
Map<String,ReelItem> capacityMap = new HashMap<>();
for (SlotUnit slotUnit : getSlotUnitList()) {
String reelSizeStr = slotUnit.getReelData().getReelSizeStr();
ReelItem capacityItem = capacityMap.get(reelSizeStr);
if(capacityItem == null){
capacityItem = new ReelItem();
capacityItem.setW(slotUnit.getReelData().getReelSize());
capacityItem.setH(slotUnit.getReelData().getReelHeight());
}
int columnCapacity = slotUnit.getReelCount();
int capacity = capacityItem.getCapacity() + columnCapacity;
capacityItem.setCapacity(capacity);
capacityMap.put(reelSizeStr,capacityItem);
}
return capacityMap;
}
}
package com.neotel.webbox.capacitynew.box;
import com.neotel.webbox.capacitynew.bean.ReelData;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class SlotUnit {
public SlotUnit(ReelData reelData, int reelCount) {
this.reelData = reelData;
this.reelCount = reelCount;
}
private ReelData reelData; //料盘数据
private int reelCount; //料盘数量
public int getSlotHeight(){
int count = reelCount;
if(reelData.is7Reel()){
//7寸盘,一行摆2个
count = reelCount / 2;
if(count < reelData.getMinUnit()){
//小于最小单元,需要进行补充
count = reelData.getMinUnit();
reelCount = count * 2;
}else{
if(reelCount % 2 != 0){
count = count + 1;
reelCount = reelCount + 1;
}
}
}
int reelSlotHeight = reelData.getReelSlotHeight();
return count * reelSlotHeight;
}
}
package com.neotel.webbox.capacitynew.method;
import com.neotel.webbox.capacitynew.bean.*;
import com.neotel.webbox.capacitynew.box.Box;
import com.neotel.webbox.capacitynew.box.Column;
import com.neotel.webbox.capacitynew.box.SlotUnit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class BasicMethod {
protected static SlotUnit getValidSlotUnit(int requestReelCount, ReelData reelData, int validHeight) {
if (requestReelCount <= 0) {
return null;
}
//剩余空间可放多少层料格
int slotCount = validHeight / reelData.getReelSlotHeight();
if (slotCount < reelData.getMinUnit()) {
//可放料格层数不到一个模组
return null;
}
int validReelCount = slotCount;
if (reelData.is7Reel()) {
validReelCount = validReelCount * 2;
}
if (validReelCount >= requestReelCount) {
//可以全部放下
return new SlotUnit(reelData, requestReelCount);
}
//只可以放下部分
return new SlotUnit(reelData, validReelCount);
}
protected static int fillToColumn(Column column, int remainCount, ReelData reelData) {
if (remainCount > 0 || remainCount == -1) {
//剩余空间可放多少层料格
int slotCount = column.getRemainHeight() / reelData.getReelSlotHeight();
if (remainCount != -1 && slotCount > remainCount) {
slotCount = remainCount;
}
SlotUnit existSlotUnit = column.getSlotUnit(reelData);
int existCount = 0;
if (existSlotUnit == null) {
//不存在同尺寸料格,需要判断最小模组
if (slotCount < reelData.getMinUnit()) {
//可放料格层数不到一个模组,尝试扩展已存在的料盘
return 0;
}
} else {
existCount = existSlotUnit.getReelCount();
}
int reelCount = slotCount;
if (reelData.is7Reel()) {
reelCount = reelCount * 2;
}
SlotUnit newSlotUnit = new SlotUnit(reelData, reelCount);
SlotUnit mergeSlotUnit = column.mergeSlotUnit(newSlotUnit);
if (mergeSlotUnit != null) {
int addCount = mergeSlotUnit.getReelCount() - existCount;
return addCount;
}
}
return 0;
}
protected static Column getPureColumn(int validHeight, BoxData boxData, ReelData reelData, int pureCapacity) {
Column column = new Column(validHeight);
column.setRemainHeight(0);
List<SlotUnit> slotUnitList = new ArrayList<>();
SlotUnit unit = new SlotUnit(reelData, pureCapacity);
slotUnitList.add(unit);
column.setSlotUnitList(slotUnitList);
return column;
}
protected static BoxResult getBoxResult(List<RequestItem> requestList, BoxData boxData, List<Box> mixBoxList) {
List<Box> boxes = new ArrayList<>();
for (RequestItem requestItem : requestList) {
ReelData reelData = requestItem.getReelData();
int pressHeight = reelData.getPressHeight();
for (int i = 0; i < requestItem.getPureBoxCount(); i++) {
Box box = new Box();
box.setColumnCount(boxData.getColumnCount());
int standColumnValidHeight = boxData.getColumnValidHeight(pressHeight); //标准列可用高度
int pureColumnCapacity = boxData.getColumnPureSizeCapacity(standColumnValidHeight,reelData.getReelSize(),reelData.getReelSlotHeight()); //可放入数量
Column standColumn = getPureColumn(standColumnValidHeight, boxData, reelData, pureColumnCapacity);
box.setColumn(standColumn);
//获取特殊列与特殊列上部的值
Map<String, Column> specialColumnMap = new HashMap<>();
Map<String, Column> specialColumnUpMap = new HashMap<>();
Map<String, List<BoxSpecialColumnContent>> boxSpecialColumnMap = boxData.getBoxSpecialColumnMap();
if (boxSpecialColumnMap != null && boxSpecialColumnMap.size() > 0) {
boxSpecialColumnMap = boxData.boxFillSpecialColumnHeight(boxSpecialColumnMap, reelData);
for (Map.Entry<String, List<BoxSpecialColumnContent>> entry : boxSpecialColumnMap.entrySet()) {
String boxSpecialColumnTitle = entry.getKey();
//特殊列
List<BoxSpecialColumnContent> boxSpecialColumnContentList = entry.getValue();
int boxSpecialColumnValidHeight = boxData.getBoxSingleSpecialColumnHeight(boxSpecialColumnContentList);
int boxSingleSpecialColumnCapacity = boxData.getColumnPureSizeCapacity(boxSpecialColumnValidHeight, reelData.getReelSize(),reelData.getReelSlotHeight());
Column specialColumn = getPureColumn(boxSpecialColumnValidHeight, boxData, reelData, boxSingleSpecialColumnCapacity);
specialColumnMap.put(boxSpecialColumnTitle, specialColumn);
//特殊列上部
int boxSingleSpecialColumnUpValidHeight = boxData.getBoxSingleSpecialColumnUpValidHeight(boxSpecialColumnContentList, reelData.getPressHeight());
int boxSingleSpecialColumnUpCapacity = boxData.getColumnPureSizeCapacity(boxSingleSpecialColumnUpValidHeight, reelData.getReelSize(), reelData.getReelSlotHeight());
Column specialColumnUp = getPureColumn(boxSingleSpecialColumnUpValidHeight, boxData, reelData, boxSingleSpecialColumnUpCapacity);
specialColumnUpMap.put(boxSpecialColumnTitle, specialColumnUp);
}
}
box.setSpecialColumnMap(specialColumnMap);
box.setSpecialColumnUpMap(specialColumnUpMap);
boxes.add(box);
}
}
for (Box box : mixBoxList) {
boxes.add(box);
}
BoxResult boxResult = new BoxResult();
boxResult.setBoxList(boxes);
boxResult.setRequestList(requestList);
return boxResult;
}
}
package com.neotel.webbox.util;
import java.math.BigDecimal;
import java.util.regex.Pattern;
public class NumberUtil {
/**
* 判断是否为整数,使用异常方式
* @param str
* @return
*/
public static boolean isInteger(String str) {
try{
int i = (int) Double.parseDouble(str);
return true;
}catch (Exception e){
return false;
}
}
}
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!