|
@@ -1,5 +1,6 @@
|
|
|
package cn.iocoder.yudao.module.pms.util;
|
|
package cn.iocoder.yudao.module.pms.util;
|
|
|
|
|
|
|
|
|
|
+import com.google.common.collect.ImmutableList;
|
|
|
import org.apache.poi.util.Units;
|
|
import org.apache.poi.util.Units;
|
|
|
import org.apache.poi.xwpf.usermodel.*;
|
|
import org.apache.poi.xwpf.usermodel.*;
|
|
|
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
|
|
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
|
|
@@ -12,21 +13,20 @@ import java.util.List;
|
|
|
|
|
|
|
|
public class SafetyObservationCardGenerator {
|
|
public class SafetyObservationCardGenerator {
|
|
|
|
|
|
|
|
- public static void main(String[] args) {
|
|
|
|
|
|
|
+ // 核心入口:支持传入需要打勾的子项列表
|
|
|
|
|
+ public static void generateCard(List<String> checkedItems) {
|
|
|
try (XWPFDocument document = new XWPFDocument();
|
|
try (XWPFDocument document = new XWPFDocument();
|
|
|
FileOutputStream out = new FileOutputStream("行为安全观察与沟通卡-数智化.docx")) {
|
|
FileOutputStream out = new FileOutputStream("行为安全观察与沟通卡-数智化.docx")) {
|
|
|
|
|
|
|
|
- // 1. 标题:替换为KERUI科瑞石油技术图片(核心修改)
|
|
|
|
|
|
|
+ // 1. 标题:替换为KERUI科瑞石油技术图片
|
|
|
XWPFParagraph logoPara = document.createParagraph();
|
|
XWPFParagraph logoPara = document.createParagraph();
|
|
|
logoPara.setAlignment(ParagraphAlignment.CENTER); // 图片居中
|
|
logoPara.setAlignment(ParagraphAlignment.CENTER); // 图片居中
|
|
|
XWPFRun logoRun = logoPara.createRun();
|
|
XWPFRun logoRun = logoPara.createRun();
|
|
|
|
|
|
|
|
// 读取本地图片并插入(替换为你的图片实际路径)
|
|
// 读取本地图片并插入(替换为你的图片实际路径)
|
|
|
String imagePath = "pic/keruishiyoujishu.png";
|
|
String imagePath = "pic/keruishiyoujishu.png";
|
|
|
-// 获取resources下图片的输入流(无需关心物理路径)
|
|
|
|
|
InputStream imageStream = new ClassPathResource(imagePath).getInputStream();
|
|
InputStream imageStream = new ClassPathResource(imagePath).getInputStream();
|
|
|
|
|
|
|
|
-// 然后将imageStream传入插入图片的方法(替代原有的FileInputStream)
|
|
|
|
|
XWPFRun run = logoPara.createRun();
|
|
XWPFRun run = logoPara.createRun();
|
|
|
run.addPicture(imageStream, XWPFDocument.PICTURE_TYPE_PNG, "keruishiyoujishu.png",
|
|
run.addPicture(imageStream, XWPFDocument.PICTURE_TYPE_PNG, "keruishiyoujishu.png",
|
|
|
Units.toEMU(250), Units.toEMU(30)); // 宽高按需调整
|
|
Units.toEMU(250), Units.toEMU(30)); // 宽高按需调整
|
|
@@ -48,11 +48,10 @@ public class SafetyObservationCardGenerator {
|
|
|
XWPFTableCell titleCell = titleRow.getCell(0);
|
|
XWPFTableCell titleCell = titleRow.getCell(0);
|
|
|
setTitleStyle(titleCell, "行为安全观察与沟通卡", true, ParagraphAlignment.CENTER, "FFFFFF");
|
|
setTitleStyle(titleCell, "行为安全观察与沟通卡", true, ParagraphAlignment.CENTER, "FFFFFF");
|
|
|
|
|
|
|
|
- // 黄色提示栏 - 核心修改:单独设置提示文字样式
|
|
|
|
|
|
|
+ // 黄色提示栏
|
|
|
XWPFTableRow tipRow = table.createRow();
|
|
XWPFTableRow tipRow = table.createRow();
|
|
|
mergeCellsHorizontally(tipRow, 0, 2);
|
|
mergeCellsHorizontally(tipRow, 0, 2);
|
|
|
XWPFTableCell tipCell = tipRow.getCell(0);
|
|
XWPFTableCell tipCell = tipRow.getCell(0);
|
|
|
- // 调用自定义的提示文字样式方法
|
|
|
|
|
setTipTextStyle(tipCell, "若有任何不安全,请在小项前面□内打√。大项完全安全,请在大项后面□内打√。", true, ParagraphAlignment.LEFT, "FFFF00");
|
|
setTipTextStyle(tipCell, "若有任何不安全,请在小项前面□内打√。大项完全安全,请在大项后面□内打√。", true, ParagraphAlignment.LEFT, "FFFF00");
|
|
|
|
|
|
|
|
// 行3:个人防护 | 规范操作 | 观察描述
|
|
// 行3:个人防护 | 规范操作 | 观察描述
|
|
@@ -72,7 +71,13 @@ public class SafetyObservationCardGenerator {
|
|
|
"□ 躯干\n" +
|
|
"□ 躯干\n" +
|
|
|
"□ 腿部和脚\n" +
|
|
"□ 腿部和脚\n" +
|
|
|
"□ 其他 _______________";
|
|
"□ 其他 _______________";
|
|
|
|
|
+ // 处理个人防护子项勾选
|
|
|
|
|
+ ppeText = checkItemsInText(ppeText, checkedItems);
|
|
|
|
|
+
|
|
|
String opText = "员工是否严格执行操作规程?\n□ 不按规定的方法操作\n□ 不采取安全措施进行操作\n□ 其他 _______________";
|
|
String opText = "员工是否严格执行操作规程?\n□ 不按规定的方法操作\n□ 不采取安全措施进行操作\n□ 其他 _______________";
|
|
|
|
|
+ // 处理规范操作子项勾选
|
|
|
|
|
+ opText = checkItemsInText(opText, checkedItems);
|
|
|
|
|
+
|
|
|
setCellStyle(row4.getCell(0), ppeText, false, ParagraphAlignment.LEFT, "FFFFFF");
|
|
setCellStyle(row4.getCell(0), ppeText, false, ParagraphAlignment.LEFT, "FFFFFF");
|
|
|
setCellStyle(row4.getCell(1), opText, false, ParagraphAlignment.LEFT, "FFFFFF");
|
|
setCellStyle(row4.getCell(1), opText, false, ParagraphAlignment.LEFT, "FFFFFF");
|
|
|
setCellStyle(row4.getCell(2), "", false, ParagraphAlignment.LEFT, "E6EBF5");
|
|
setCellStyle(row4.getCell(2), "", false, ParagraphAlignment.LEFT, "E6EBF5");
|
|
@@ -85,7 +90,13 @@ public class SafetyObservationCardGenerator {
|
|
|
|
|
|
|
|
XWPFTableRow row10 = table.createRow();
|
|
XWPFTableRow row10 = table.createRow();
|
|
|
String cmdText1 = "是否违章指挥?\n□ 指挥信号不正确/不清楚\n□ 多人指挥,信号不统一\n□ 非特殊情况下越权指挥\n□ 明知危险仍强令冒险作业\n□ 特殊作业前没有进行作业申请/风险分析\n□ 其他 _______________";
|
|
String cmdText1 = "是否违章指挥?\n□ 指挥信号不正确/不清楚\n□ 多人指挥,信号不统一\n□ 非特殊情况下越权指挥\n□ 明知危险仍强令冒险作业\n□ 特殊作业前没有进行作业申请/风险分析\n□ 其他 _______________";
|
|
|
|
|
+ // 处理规范指挥子项勾选
|
|
|
|
|
+ cmdText1 = checkItemsInText(cmdText1, checkedItems);
|
|
|
|
|
+
|
|
|
String posText1 = "人员站位是否安全?\n□ 碰撞到物体\n□ 被物体夹住/手扶握物体部位不正确\n□ 跌倒/坠落/陷入物体之中\n□ 被物体砸到\n□ 接触极高/极低温度/电流/电击\n□ 吸入/吸收/吞食有害物质\n□ 姿势不良/用力过度\n□ 其他 _______________";
|
|
String posText1 = "人员站位是否安全?\n□ 碰撞到物体\n□ 被物体夹住/手扶握物体部位不正确\n□ 跌倒/坠落/陷入物体之中\n□ 被物体砸到\n□ 接触极高/极低温度/电流/电击\n□ 吸入/吸收/吞食有害物质\n□ 姿势不良/用力过度\n□ 其他 _______________";
|
|
|
|
|
+ // 处理人员位置子项勾选
|
|
|
|
|
+ posText1 = checkItemsInText(posText1, checkedItems);
|
|
|
|
|
+
|
|
|
String safeText1 = "·观察到的安全行为或安全状态\n·鼓励安全行为或安全状态所采取的行动";
|
|
String safeText1 = "·观察到的安全行为或安全状态\n·鼓励安全行为或安全状态所采取的行动";
|
|
|
setCellStyle(row10.getCell(0), cmdText1, false, ParagraphAlignment.LEFT, "FFFFFF");
|
|
setCellStyle(row10.getCell(0), cmdText1, false, ParagraphAlignment.LEFT, "FFFFFF");
|
|
|
setCellStyle(row10.getCell(1), posText1, false, ParagraphAlignment.LEFT, "FFFFFF");
|
|
setCellStyle(row10.getCell(1), posText1, false, ParagraphAlignment.LEFT, "FFFFFF");
|
|
@@ -93,7 +104,6 @@ public class SafetyObservationCardGenerator {
|
|
|
|
|
|
|
|
// 行6:规范指挥明细 | 人员位置明细 | 安全行为描述(后续垂直合并)
|
|
// 行6:规范指挥明细 | 人员位置明细 | 安全行为描述(后续垂直合并)
|
|
|
XWPFTableRow row6 = table.createRow();
|
|
XWPFTableRow row6 = table.createRow();
|
|
|
- // ========== 核心修改1:设置row6行高(增高,示例:800缇 ≈ 40磅) ==========
|
|
|
|
|
setRowHeight(row6, 1900);
|
|
setRowHeight(row6, 1900);
|
|
|
String cmdText = "";
|
|
String cmdText = "";
|
|
|
String posText = "";
|
|
String posText = "";
|
|
@@ -104,7 +114,6 @@ public class SafetyObservationCardGenerator {
|
|
|
|
|
|
|
|
// 行7:规范指挥明细 | 人员位置明细 | 安全行为描述(后续垂直合并)
|
|
// 行7:规范指挥明细 | 人员位置明细 | 安全行为描述(后续垂直合并)
|
|
|
XWPFTableRow row7 = table.createRow();
|
|
XWPFTableRow row7 = table.createRow();
|
|
|
- // ========== 核心修改2:设置row7行高(降低,示例:200缇 ≈ 10磅) ==========
|
|
|
|
|
setRowHeight(row7, 500);
|
|
setRowHeight(row7, 500);
|
|
|
String cmdText2 = "";
|
|
String cmdText2 = "";
|
|
|
String posText2 = "";
|
|
String posText2 = "";
|
|
@@ -121,9 +130,14 @@ public class SafetyObservationCardGenerator {
|
|
|
|
|
|
|
|
// 行8:作业场所明细 | 空 | 不安全行为描述(后续垂直合并)
|
|
// 行8:作业场所明细 | 空 | 不安全行为描述(后续垂直合并)
|
|
|
XWPFTableRow row8 = table.createRow();
|
|
XWPFTableRow row8 = table.createRow();
|
|
|
-// mergeCellsHorizontally(row8, 0, 1);
|
|
|
|
|
String houseText = "□ 作业场所杂乱\n□ 作业空间狭小\n□ 堵塞安全通道\n□ 地面滑(水/雨/雪/油污等)\n□ 物体/工具放置位置不当 \n□ 危险场所没有标志/标志不清\n□ 照明光线不良";
|
|
String houseText = "□ 作业场所杂乱\n□ 作业空间狭小\n□ 堵塞安全通道\n□ 地面滑(水/雨/雪/油污等)\n□ 物体/工具放置位置不当 \n□ 危险场所没有标志/标志不清\n□ 照明光线不良";
|
|
|
|
|
+ // 处理作业场所子项勾选
|
|
|
|
|
+ houseText = checkItemsInText(houseText, checkedItems);
|
|
|
|
|
+
|
|
|
String secondText = "□ 带电装置带电部分裸露\n□ 设备无防护/防护装置不当\n□ 未工完料净场地清/垃圾未分类存放\n□ 通风不良/氧气含量未达标\n□ 其他 _______________";
|
|
String secondText = "□ 带电装置带电部分裸露\n□ 设备无防护/防护装置不当\n□ 未工完料净场地清/垃圾未分类存放\n□ 通风不良/氧气含量未达标\n□ 其他 _______________";
|
|
|
|
|
+ // 处理作业场所子项勾选
|
|
|
|
|
+ secondText = checkItemsInText(secondText, checkedItems);
|
|
|
|
|
+
|
|
|
String unsafeText = "";
|
|
String unsafeText = "";
|
|
|
setCellStyle(row8.getCell(0), houseText, false, ParagraphAlignment.LEFT, "FFFFFF");
|
|
setCellStyle(row8.getCell(0), houseText, false, ParagraphAlignment.LEFT, "FFFFFF");
|
|
|
setCellStyle(row8.getCell(1), secondText, false, ParagraphAlignment.LEFT, "FFFFFF");
|
|
setCellStyle(row8.getCell(1), secondText, false, ParagraphAlignment.LEFT, "FFFFFF");
|
|
@@ -133,10 +147,11 @@ public class SafetyObservationCardGenerator {
|
|
|
XWPFTableRow footerRow = table.createRow();
|
|
XWPFTableRow footerRow = table.createRow();
|
|
|
mergeCellsHorizontally(footerRow, 0, 2);
|
|
mergeCellsHorizontally(footerRow, 0, 2);
|
|
|
String footerText = "观察区域: ____________ 实施观察人员: ____________ 被观察岗位:____________ \n被观察人员:□员工 □承包商 □供应商 日期: __________ 时间:___点___分到___点___分";
|
|
String footerText = "观察区域: ____________ 实施观察人员: ____________ 被观察岗位:____________ \n被观察人员:□员工 □承包商 □供应商 日期: __________ 时间:___点___分到___点___分";
|
|
|
|
|
+ // 处理底部人员类型勾选(可选)
|
|
|
|
|
+ footerText = checkItemsInText(footerText, checkedItems);
|
|
|
setCellStyle(footerRow.getCell(0), footerText, true, ParagraphAlignment.LEFT, "FFFFFF");
|
|
setCellStyle(footerRow.getCell(0), footerText, true, ParagraphAlignment.LEFT, "FFFFFF");
|
|
|
|
|
|
|
|
- // 核心修复:垂直合并第三列的单元格(行3到行8的第三列)
|
|
|
|
|
- // 行索引说明:table.getRow(2) = 行3(标题行是0,提示行是1),table.getRow(7) = 行8
|
|
|
|
|
|
|
+ // 垂直合并第三列的单元格
|
|
|
mergeCellsVertically(table, 2, 4, 2);
|
|
mergeCellsVertically(table, 2, 4, 2);
|
|
|
mergeCellsVertically(table, 5,7,0);
|
|
mergeCellsVertically(table, 5,7,0);
|
|
|
mergeCellsVertically(table, 5,7,1);
|
|
mergeCellsVertically(table, 5,7,1);
|
|
@@ -149,13 +164,41 @@ public class SafetyObservationCardGenerator {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // ========== 新增:设置行高的工具方法(适配POI 5.2.5) ==========
|
|
|
|
|
|
|
+ // 核心工具方法:处理文本中的勾选框,匹配到checkedItems的子项则替换□为☑
|
|
|
|
|
+ private static String checkItemsInText(String originalText, List<String> checkedItems) {
|
|
|
|
|
+ if (checkedItems == null || checkedItems.isEmpty()) {
|
|
|
|
|
+ return originalText;
|
|
|
|
|
+ }
|
|
|
|
|
+ String processedText = originalText;
|
|
|
|
|
+ for (String item : checkedItems) {
|
|
|
|
|
+ // 匹配 "□ 子项内容" 格式,替换为 "☑ 子项内容"
|
|
|
|
|
+ String target = "□ " + item;
|
|
|
|
|
+ String replacement = "☑ " + item;
|
|
|
|
|
+ processedText = processedText.replace(target, replacement);
|
|
|
|
|
+ }
|
|
|
|
|
+ return processedText;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 测试入口
|
|
|
|
|
+ public static void main(String[] args) {
|
|
|
|
|
+ // 示例:需要打勾的子项列表
|
|
|
|
|
+ List<String> checkedItems = ImmutableList.of(
|
|
|
|
|
+ "头部", // 个人防护子项
|
|
|
|
|
+ "不按规定的方法操作", // 规范操作子项
|
|
|
|
|
+ "指挥信号不正确/不清楚", // 规范指挥子项
|
|
|
|
|
+ "碰撞到物体", // 人员位置子项
|
|
|
|
|
+ "作业场所杂乱" // 作业场所子项
|
|
|
|
|
+ );
|
|
|
|
|
+ generateCard(checkedItems);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 设置行高的工具方法(适配POI 5.2.5)
|
|
|
private static void setRowHeight(XWPFTableRow row, int heightInTwips) {
|
|
private static void setRowHeight(XWPFTableRow row, int heightInTwips) {
|
|
|
CTRow ctTr = row.getCtRow();
|
|
CTRow ctTr = row.getCtRow();
|
|
|
CTTrPr trPr = ctTr.getTrPr() == null ? ctTr.addNewTrPr() : ctTr.getTrPr();
|
|
CTTrPr trPr = ctTr.getTrPr() == null ? ctTr.addNewTrPr() : ctTr.getTrPr();
|
|
|
CTHeight trHeight = trPr.addNewTrHeight();
|
|
CTHeight trHeight = trPr.addNewTrHeight();
|
|
|
trHeight.setVal(BigInteger.valueOf(heightInTwips));
|
|
trHeight.setVal(BigInteger.valueOf(heightInTwips));
|
|
|
- trHeight.setHRule(STHeightRule.EXACT); // 强制使用固定行高(不自动适应内容)
|
|
|
|
|
|
|
+ trHeight.setHRule(STHeightRule.EXACT); // 强制使用固定行高
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 标题样式设置
|
|
// 标题样式设置
|
|
@@ -174,7 +217,7 @@ public class SafetyObservationCardGenerator {
|
|
|
setCellBorder(cell);
|
|
setCellBorder(cell);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 新增:提示文字专属样式设置(增加左缩进+行间距)
|
|
|
|
|
|
|
+ // 提示文字专属样式设置(增加左缩进+行间距)
|
|
|
private static void setTipTextStyle(XWPFTableCell cell, String text, boolean bold, ParagraphAlignment align, String bgColor) {
|
|
private static void setTipTextStyle(XWPFTableCell cell, String text, boolean bold, ParagraphAlignment align, String bgColor) {
|
|
|
clearCellContent(cell);
|
|
clearCellContent(cell);
|
|
|
|
|
|
|
@@ -187,16 +230,15 @@ public class SafetyObservationCardGenerator {
|
|
|
paragraph.setAlignment(align);
|
|
paragraph.setAlignment(align);
|
|
|
paragraph.setSpacingAfter(100); // 段后间距(缇,1磅=20缇)
|
|
paragraph.setSpacingAfter(100); // 段后间距(缇,1磅=20缇)
|
|
|
paragraph.setSpacingBefore(100); // 段前间距
|
|
paragraph.setSpacingBefore(100); // 段前间距
|
|
|
- // 设置左缩进(示例:2字符缩进,1字符≈1440缇)
|
|
|
|
|
- paragraph.setIndentationFirstLine(288);
|
|
|
|
|
|
|
+ paragraph.setIndentationFirstLine(288); // 左缩进2字符
|
|
|
|
|
|
|
|
XWPFRun run = paragraph.createRun();
|
|
XWPFRun run = paragraph.createRun();
|
|
|
run.setText(text.trim());
|
|
run.setText(text.trim());
|
|
|
- run.setFontSize(9); // 设置字体大小为9号
|
|
|
|
|
- run.setFontFamily("宋体"); // 设置字体为宋体
|
|
|
|
|
- run.setBold(true); // 加粗
|
|
|
|
|
- run.setColor("003366"); // 设置字体颜色为深蓝色
|
|
|
|
|
- run.setTextPosition(10); // 行内文字垂直间距
|
|
|
|
|
|
|
+ run.setFontSize(9);
|
|
|
|
|
+ run.setFontFamily("宋体");
|
|
|
|
|
+ run.setBold(true);
|
|
|
|
|
+ run.setColor("003366");
|
|
|
|
|
+ run.setTextPosition(10);
|
|
|
|
|
|
|
|
cell.setColor(bgColor);
|
|
cell.setColor(bgColor);
|
|
|
setCellBorder(cell);
|
|
setCellBorder(cell);
|
|
@@ -221,11 +263,9 @@ public class SafetyObservationCardGenerator {
|
|
|
paragraph.setSpacingBefore(0);
|
|
paragraph.setSpacingBefore(0);
|
|
|
|
|
|
|
|
// 关键:给包含□的行增加左缩进(2字符),普通行按需调整
|
|
// 关键:给包含□的行增加左缩进(2字符),普通行按需调整
|
|
|
- if (line.startsWith("□")) {
|
|
|
|
|
- // 1字符≈1440缇,2字符=2880缇,可根据需要调整
|
|
|
|
|
|
|
+ if (line.startsWith("□")||line.startsWith("☑")) {
|
|
|
paragraph.setIndentationFirstLine(288);
|
|
paragraph.setIndentationFirstLine(288);
|
|
|
} else {
|
|
} else {
|
|
|
- // 非选择框行,缩进1字符
|
|
|
|
|
paragraph.setIndentationFirstLine(144);
|
|
paragraph.setIndentationFirstLine(144);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -234,7 +274,6 @@ public class SafetyObservationCardGenerator {
|
|
|
run.setFontSize(9);
|
|
run.setFontSize(9);
|
|
|
run.setFontFamily("宋体");
|
|
run.setFontFamily("宋体");
|
|
|
run.setBold(bold);
|
|
run.setBold(bold);
|
|
|
- // 行内文字垂直间距(上下间距)
|
|
|
|
|
run.setTextPosition(12);
|
|
run.setTextPosition(12);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -295,14 +334,13 @@ public class SafetyObservationCardGenerator {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 新增:垂直合并单元格
|
|
|
|
|
|
|
+ // 垂直合并单元格
|
|
|
private static void mergeCellsVertically(XWPFTable table, int fromRow, int toRow, int col) {
|
|
private static void mergeCellsVertically(XWPFTable table, int fromRow, int toRow, int col) {
|
|
|
for (int rowIndex = fromRow; rowIndex <= toRow; rowIndex++) {
|
|
for (int rowIndex = fromRow; rowIndex <= toRow; rowIndex++) {
|
|
|
XWPFTableCell cell = table.getRow(rowIndex).getCell(col);
|
|
XWPFTableCell cell = table.getRow(rowIndex).getCell(col);
|
|
|
CTTcPr tcPr = cell.getCTTc().getTcPr() != null ? cell.getCTTc().getTcPr() : cell.getCTTc().addNewTcPr();
|
|
CTTcPr tcPr = cell.getCTTc().getTcPr() != null ? cell.getCTTc().getTcPr() : cell.getCTTc().addNewTcPr();
|
|
|
STMerge.Enum mergeVal = (rowIndex == fromRow) ? STMerge.RESTART : STMerge.CONTINUE;
|
|
STMerge.Enum mergeVal = (rowIndex == fromRow) ? STMerge.RESTART : STMerge.CONTINUE;
|
|
|
tcPr.addNewVMerge().setVal(mergeVal);
|
|
tcPr.addNewVMerge().setVal(mergeVal);
|
|
|
- // 确保合并后边框正常
|
|
|
|
|
setCellBorder(cell);
|
|
setCellBorder(cell);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|