|
@@ -16,6 +16,7 @@
|
|
|
*/
|
|
|
package org.springblade.manager.controller;
|
|
|
|
|
|
+import com.alibaba.fastjson.JSONArray;
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
import com.spire.xls.Workbook;
|
|
|
import com.spire.xls.Worksheet;
|
|
@@ -26,14 +27,26 @@ import javax.validation.Valid;
|
|
|
|
|
|
import lombok.SneakyThrows;
|
|
|
|
|
|
+import org.jsoup.Jsoup;
|
|
|
+import org.jsoup.nodes.Document;
|
|
|
+import org.jsoup.nodes.Element;
|
|
|
+import org.jsoup.select.Elements;
|
|
|
+import org.springblade.common.utils.SnowFlakeUtil;
|
|
|
+import org.springblade.core.log.exception.ServiceException;
|
|
|
import org.springblade.core.mp.support.Condition;
|
|
|
import org.springblade.core.mp.support.Query;
|
|
|
|
|
|
import org.springblade.core.oss.model.BladeFile;
|
|
|
import org.springblade.core.secure.BladeUser;
|
|
|
+import org.springblade.core.secure.utils.AuthUtil;
|
|
|
import org.springblade.core.tool.api.R;
|
|
|
+import org.springblade.core.tool.constant.BladeConstant;
|
|
|
import org.springblade.core.tool.utils.Func;
|
|
|
+import org.springblade.core.tool.utils.StringPool;
|
|
|
+import org.springblade.manager.entity.ExctabCell;
|
|
|
+import org.springblade.manager.entity.WbsTreePrivate;
|
|
|
import org.springblade.manager.service.IExctabCellService;
|
|
|
+import org.springblade.manager.service.IWbsTreePrivateService;
|
|
|
import org.springblade.manager.service.IWbsTreeService;
|
|
|
import org.springblade.manager.vo.*;
|
|
|
import org.springblade.manager.wrapper.ExcelTabWrapper;
|
|
@@ -47,7 +60,11 @@ import org.springframework.web.multipart.MultipartFile;
|
|
|
|
|
|
import java.io.*;
|
|
|
import java.util.ArrayList;
|
|
|
+import java.util.HashMap;
|
|
|
import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.regex.Matcher;
|
|
|
+import java.util.regex.Pattern;
|
|
|
|
|
|
/**
|
|
|
* 清表基础数据表 控制器
|
|
@@ -70,6 +87,8 @@ public class ExcelTabController extends BladeController {
|
|
|
|
|
|
private final IOSSClient iossClient;
|
|
|
|
|
|
+ // 私有项目wbs
|
|
|
+ private final IWbsTreePrivateService wbsTreePrivateService;
|
|
|
|
|
|
/**
|
|
|
* 详情
|
|
@@ -112,7 +131,25 @@ public class ExcelTabController extends BladeController {
|
|
|
@ApiOperationSupport(order = 4)
|
|
|
@ApiOperation(value = "新增", notes = "传入excelTab")
|
|
|
public R save(@Valid @RequestBody ExcelTab excelTab) {
|
|
|
- return R.status(excelTabService.save(excelTab));
|
|
|
+ if(Func.isEmpty(excelTab.getParentId())) {
|
|
|
+ excelTab.setTenantId(AuthUtil.getTenantId());
|
|
|
+ excelTab.setParentId(BladeConstant.TOP_PARENT_ID);
|
|
|
+ excelTab.setIsDeleted(BladeConstant.DB_NOT_DELETED);
|
|
|
+ excelTabService.save(excelTab);
|
|
|
+ excelTab.setAlias(excelTab.getId()+"");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (excelTab.getParentId() > 0) {
|
|
|
+ ExcelTab parent = excelTabService.getById(excelTab.getParentId());
|
|
|
+ if (Func.toLong(parent.getParentId()) == Func.toLong(excelTab.getId())) {
|
|
|
+ throw new ServiceException("父节点不可选择自身!");
|
|
|
+ }
|
|
|
+ excelTab.setTenantId(parent.getTenantId());
|
|
|
+ String ancestors = parent.getAlias() + StringPool.COMMA + excelTab.getParentId();
|
|
|
+ excelTab.setAlias(ancestors);
|
|
|
+ excelTab.setIsDeleted(BladeConstant.DB_NOT_DELETED);
|
|
|
+ }
|
|
|
+ return R.status(excelTabService.saveOrUpdate(excelTab));
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -132,6 +169,25 @@ public class ExcelTabController extends BladeController {
|
|
|
@ApiOperationSupport(order = 6)
|
|
|
@ApiOperation(value = "新增或修改", notes = "传入excelTab")
|
|
|
public R submit(@Valid @RequestBody ExcelTab excelTab) {
|
|
|
+ if(Func.isEmpty(excelTab.getParentId())) {
|
|
|
+ excelTab.setTenantId(AuthUtil.getTenantId());
|
|
|
+ excelTab.setParentId(BladeConstant.TOP_PARENT_ID);
|
|
|
+ excelTab.setIsDeleted(BladeConstant.DB_NOT_DELETED);
|
|
|
+ excelTab.setFileType(1); // 祖节点
|
|
|
+ excelTabService.save(excelTab);
|
|
|
+ excelTab.setAlias(excelTab.getId()+"");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (excelTab.getParentId() > 0) {
|
|
|
+ ExcelTab parent = excelTabService.getById(excelTab.getParentId());
|
|
|
+ if (Func.toLong(parent.getParentId()) == Func.toLong(excelTab.getId())) {
|
|
|
+ throw new ServiceException("父节点不可选择自身!");
|
|
|
+ }
|
|
|
+ excelTab.setTenantId(parent.getTenantId());
|
|
|
+ String ancestors = parent.getAlias() + StringPool.COMMA + excelTab.getParentId();
|
|
|
+ excelTab.setAlias(ancestors);
|
|
|
+ excelTab.setIsDeleted(BladeConstant.DB_NOT_DELETED);
|
|
|
+ }
|
|
|
return R.status(excelTabService.saveOrUpdate(excelTab));
|
|
|
}
|
|
|
|
|
@@ -153,8 +209,8 @@ public class ExcelTabController extends BladeController {
|
|
|
@GetMapping("/tab-lazytree")
|
|
|
@ApiOperationSupport(order = 8)
|
|
|
@ApiOperation(value = "清表清表树形结构", notes = "清表清表树形结构")
|
|
|
- public R<List<ExceTabTreVO>> tabLazyTree(Long modeId, BladeUser bladeUser) {
|
|
|
- List<ExceTabTreVO> tree = excelTabService.tabLazyTree( bladeUser.getTenantId(), modeId);
|
|
|
+ public R<List<ExceTabTreVO>> tabLazyTree(Long parentId,Long modeId, BladeUser bladeUser) {
|
|
|
+ List<ExceTabTreVO> tree = excelTabService.tabLazyTree( bladeUser.getTenantId(), modeId,parentId);
|
|
|
return R.data(tree);
|
|
|
}
|
|
|
|
|
@@ -178,27 +234,19 @@ public class ExcelTabController extends BladeController {
|
|
|
// 删除excel文件
|
|
|
R<BladeFile> bladeFile = iossClient.addFileInfo(file);
|
|
|
BladeFile bladeFile1 = bladeFile.getData();
|
|
|
-
|
|
|
- System.out.println(bladeFile1.getLink());
|
|
|
- String thmlUrl = "/Users/hongchuangyanfa/Desktop/ToHtml.html";
|
|
|
+ String filecode = SnowFlakeUtil.getId()+"";
|
|
|
+ String thmlUrl = "/Users/hongchuangyanfa/Desktop/"+filecode+".html";
|
|
|
// 解析excel
|
|
|
Workbook wb = new Workbook();
|
|
|
wb.loadFromMHtml(file.getInputStream());
|
|
|
- wb.loadFromMHtml(file.getInputStream());
|
|
|
-
|
|
|
//获取工作表
|
|
|
Worksheet sheet = wb.getWorksheets().get(0);
|
|
|
sheet.saveToHtml(thmlUrl);
|
|
|
-
|
|
|
detail.setExtension(bladeFile1.getOriginalName());
|
|
|
detail.setFileUrl(bladeFile1.getLink());
|
|
|
detail.setFileType(3); // 表示为清表信息 1 表示祖节点 2 表示为节点信息 3 表示清表
|
|
|
detail.setHtmlUrl(thmlUrl);
|
|
|
-
|
|
|
excelTabService.saveOrUpdate(detail);
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
/*
|
|
|
//解析数据
|
|
|
Thread.sleep(200);
|
|
@@ -304,11 +352,14 @@ public class ExcelTabController extends BladeController {
|
|
|
excelTab.setName(wbsExclTabParmVO.getNodeName());
|
|
|
excelTab.setTabType(wbsExclTabParmVO.getTabType());
|
|
|
}else{ // 新增
|
|
|
+ ExcelTab parent = excelTabService.getById(wbsExclTabParmVO.getParentId());
|
|
|
excelTab.setParentId(wbsExclTabParmVO.getParentId());
|
|
|
excelTab.setTabType(wbsExclTabParmVO.getTabType());
|
|
|
excelTab.setName(wbsExclTabParmVO.getNodeName());
|
|
|
- excelTab.setIsDeleted(0);
|
|
|
+ excelTab.setIsDeleted(BladeConstant.DB_NOT_DELETED);
|
|
|
excelTab.setFileType(2);
|
|
|
+ String ancestors = parent.getAlias() + StringPool.COMMA + excelTab.getParentId();
|
|
|
+ excelTab.setAlias(ancestors);
|
|
|
}
|
|
|
excelTabService.saveOrUpdate(excelTab);
|
|
|
return R.success("添加成功!");
|
|
@@ -342,6 +393,14 @@ public class ExcelTabController extends BladeController {
|
|
|
return val.substring(s, e);
|
|
|
}
|
|
|
|
|
|
+ public static String getStyle(String val) {
|
|
|
+ String start = "<<style type=\"text/css\">";
|
|
|
+ String end = "</style>";
|
|
|
+ int s = val.indexOf(start) + start.length();
|
|
|
+ int e = val.indexOf(end);
|
|
|
+ return val.substring(s, e);
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
/**
|
|
|
* 关联清表树
|
|
@@ -366,8 +425,274 @@ public class ExcelTabController extends BladeController {
|
|
|
@ApiImplicitParam(name = "tabId", value = "表Id", required = true)
|
|
|
})
|
|
|
public R<List<ExceTabTreVO>> saveLinkeTab(Long exceTabId,Long tabId, BladeUser bladeUser) {
|
|
|
-
|
|
|
+ // 查询私有项目信息
|
|
|
+ WbsTreePrivate wbsTree = new WbsTreePrivate();
|
|
|
+ wbsTree.setPKeyId(tabId);
|
|
|
+ WbsTreePrivate aPrivate = wbsTreePrivateService.getOne(Condition.getQueryWrapper(wbsTree));
|
|
|
+ aPrivate.setIsLinkTable(1); // 已关联
|
|
|
+ aPrivate.setExcelId(exceTabId);
|
|
|
+ wbsTreePrivateService.saveOrUpdate(aPrivate);
|
|
|
+ // 解析
|
|
|
return R.success("关联成功");
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ /*public static void main(String[] args) {
|
|
|
+ String thmlUrl = "/Users/hongchuangyanfa/Desktop/ToHtml.html";
|
|
|
+ String htmlString = readfile(thmlUrl);
|
|
|
+ String htmlBody= getBody(htmlString);
|
|
|
+ Map<String ,String > styleMap = new HashMap<>();
|
|
|
+
|
|
|
+ // 解析 style
|
|
|
+ Document doc = Jsoup.parse(htmlString);
|
|
|
+ Element style = doc.select("style").first();
|
|
|
+ Matcher cssMatcher = Pattern.compile("(\\w+)\\s*[{]([^}]+)[}]").matcher(style.html());
|
|
|
+ while (cssMatcher.find()) {
|
|
|
+ styleMap.put(cssMatcher.group(1),cssMatcher.group(2));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 解析 总行和总列
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ // 解析
|
|
|
+ Element table = doc.select("table").first();
|
|
|
+ Elements trs = table.select("tr");
|
|
|
+
|
|
|
+ // 获取总行列数
|
|
|
+ int maxCol = doc.select("Col").size();
|
|
|
+
|
|
|
+ System.out.println(trs.size());
|
|
|
+ System.out.println( maxCol );
|
|
|
+ List<Map<String,String>> textlist = new ArrayList();
|
|
|
+
|
|
|
+ // 计算 单元格的每个坐标
|
|
|
+*//* for(int i = 0 ;i < trs.size() ;i++) {
|
|
|
+ Element tr = trs.get(i);
|
|
|
+ Elements tds = tr.select("td");
|
|
|
+ int tdw =1;
|
|
|
+ for (int j = 0; j < tds.size(); j++) {
|
|
|
+ ExctabCell cell = new ExctabCell();
|
|
|
+ Element data = tds.get(j);
|
|
|
+ String textInfo = data.text();
|
|
|
+ int colspan = data.attr("COLSPAN").equals("") ? 1: Integer.parseInt(data.attr("COLSPAN"))-1;
|
|
|
+ int rowspan = data.attr("ROWSPAN").equals("") ? 1: Integer.parseInt(data.attr("ROWSPAN"))-1;
|
|
|
+
|
|
|
+ //if(!textInfo.equals("/") && !textInfo.isEmpty()){
|
|
|
+ *//**//*Map<String,String> textObject = new HashMap<>();
|
|
|
+ textObject.put("text",textInfo);
|
|
|
+ textObject.put("x1",tdw+"");
|
|
|
+ textObject.put("x2",tdw+colspan+"");
|
|
|
+ textObject.put("y1",i+"");
|
|
|
+ textObject.put("y2",(i+rowspan)+"");*//**//*
|
|
|
+ //textlist.add(textObject);
|
|
|
+ //}
|
|
|
+// System.out.print(textInfo +":x1:"+tdw +":x2:"+(tdw+colspan) + " ");
|
|
|
+ }
|
|
|
+ System.out.println();
|
|
|
+ }*//*
|
|
|
+
|
|
|
+ *//*for(Map<String,String> m:textlist){
|
|
|
+ System.out.println(m.get("text")+":"+m.get("x1")+":"+m.get("x2")+":"+m.get("y1")+":"+m.get("y1"));
|
|
|
+ }*//*
|
|
|
+
|
|
|
+ for(int i = 0 ;i < trs.size() ;i++){
|
|
|
+ Element tr = trs.get(i);
|
|
|
+ Elements tds = tr.select("td");
|
|
|
+ int tdw =0;
|
|
|
+ for( int j = 0 ; j < tds.size();j++ ){
|
|
|
+ ExctabCell cell = new ExctabCell();
|
|
|
+ Element data = tds.get(j);
|
|
|
+ boolean isadd = false ;
|
|
|
+ // 更改样式
|
|
|
+ String keyId = data.attr("class");
|
|
|
+ if(!keyId.isEmpty()){
|
|
|
+ data.removeAttr("class");
|
|
|
+ data.attr("style",styleMap.get(keyId));
|
|
|
+ }
|
|
|
+
|
|
|
+ int colspan = data.attr("COLSPAN").equals("") ? 1: Integer.parseInt(data.attr("COLSPAN"))-1;
|
|
|
+ int rowspan = data.attr("ROWSPAN").equals("") ? 1: Integer.parseInt(data.attr("ROWSPAN"))-1;
|
|
|
+
|
|
|
+ // 决定输入啥文本框
|
|
|
+ String textInfo = data.text();
|
|
|
+
|
|
|
+ //data
|
|
|
+
|
|
|
+ System.out.println(textInfo + ":" +data.attr("offsetTop"));
|
|
|
+ *//*if(textlist.size()>=1){
|
|
|
+ for(Map<String,String> m:textlist) {
|
|
|
+ int x1 = Integer.parseInt(m.get("x1"));
|
|
|
+ int x2 = Integer.parseInt(m.get("x2"));
|
|
|
+ int y1 = Integer.parseInt(m.get("y1"));
|
|
|
+ int y2 = Integer.parseInt(m.get("y2"));
|
|
|
+ System.out.println(m.get("text")+":"+m.get("x1")+":"+m.get("x2")+":"+m.get("y1")+":"+m.get("y2"));
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ Map<String,String> textObject = new HashMap<>();
|
|
|
+ textObject.put("text",textInfo);
|
|
|
+ textObject.put("x1",tdw+"");
|
|
|
+ textObject.put("x2",tdw+colspan+"");
|
|
|
+ textObject.put("y1",(i)+"");
|
|
|
+ textObject.put("y2",(i+rowspan)+"");
|
|
|
+ textlist.add(textObject);
|
|
|
+ }*//*
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ *//*if(textInfo.equals("/")|| textInfo.isEmpty()){
|
|
|
+ if(i== 0 && j==0 && maxCol==colspan ){ // 第一行为空
|
|
|
+ isadd = false;
|
|
|
+ }else{
|
|
|
+ // 得到 当前位置 获取值
|
|
|
+ for(Map<String,String> m:textlist){
|
|
|
+ int x1 = Integer.parseInt(m.get("x1"));
|
|
|
+ int x2 = Integer.parseInt(m.get("x2"));
|
|
|
+ int y1 = Integer.parseInt(m.get("y1"));
|
|
|
+ int y2 = Integer.parseInt(m.get("y2"));
|
|
|
+ String kekval = m.get("text");
|
|
|
+
|
|
|
+ //||(i>= y1 && (i+rowspan)<=y2 && x2 <tdw && !kekval.isEmpty())
|
|
|
+ //(tdw >= x1 && (tdw+colspan)<=x2 && y1<=i && !kekval.isEmpty())
|
|
|
+
|
|
|
+ if((i>= y1 && (i+rowspan)<=y2 && x2 < tdw && !kekval.isEmpty())){ // 向上取值
|
|
|
+ System.out.print(i+":"+j);
|
|
|
+ System.out.println(":"+m.get("text"));
|
|
|
+ isadd = true ;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ isadd = false;
|
|
|
+ }*//*
|
|
|
+
|
|
|
+ if(isadd){
|
|
|
+ data.empty().append("<el-input type='text' placeholder='请输入内容'> </el-input>");
|
|
|
+ }
|
|
|
+ tdw = tdw + colspan;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //System.out.println(table+"");
|
|
|
+ }
|
|
|
+
|
|
|
+*/
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 清表生成html
|
|
|
+ */
|
|
|
+ @GetMapping("/get-excel-html")
|
|
|
+ @ApiOperationSupport(order = 15)
|
|
|
+ @ApiOperation(value = "清表生成html", notes = "清表生成html")
|
|
|
+ public R getExcelHtml() {
|
|
|
+ String thmlUrl = "/Users/hongchuangyanfa/Desktop/ToHtml.html";
|
|
|
+ String htmlString = readfile(thmlUrl);
|
|
|
+ String htmlBody= getBody(htmlString);
|
|
|
+ Map<String ,String > styleMap = new HashMap<>();
|
|
|
+
|
|
|
+ // 解析 style
|
|
|
+ Document doc = Jsoup.parse(htmlString);
|
|
|
+ Element style = doc.select("style").first();
|
|
|
+ Matcher cssMatcher = Pattern.compile("(\\w+)\\s*[{]([^}]+)[}]").matcher(style.html());
|
|
|
+ while (cssMatcher.find()) {
|
|
|
+ styleMap.put(cssMatcher.group(1),cssMatcher.group(2));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 解析
|
|
|
+ Element table = doc.select("table").first();
|
|
|
+ Elements trs = table.select("tr");
|
|
|
+
|
|
|
+ // 获取总行列数
|
|
|
+ int maxCol = doc.select("Col").size();
|
|
|
+
|
|
|
+ List<Map<String,String>> textlist = new ArrayList();
|
|
|
+ // 计算 单元格的每个坐标
|
|
|
+ int trh = 0;
|
|
|
+ for(int i = 0 ;i < trs.size() ;i++) {
|
|
|
+ Element tr = trs.get(i);
|
|
|
+ Elements tds = tr.select("td");
|
|
|
+ int tdw =0;
|
|
|
+ for (int j = 0; j < tds.size(); j++) {
|
|
|
+ ExctabCell cell = new ExctabCell();
|
|
|
+ Element data = tds.get(j);
|
|
|
+ String textInfo = data.text();
|
|
|
+ if(!textInfo.equals("/") && !textInfo.isEmpty()){
|
|
|
+ int colspan = Integer.parseInt(data.attr("COLSPAN").equals("")?"0":data.attr("COLSPAN"));
|
|
|
+ int rowspan = Integer.parseInt(data.attr("ROWSPAN").equals("")?"0":data.attr("ROWSPAN"));
|
|
|
+
|
|
|
+ Map<String,String> textObject = new HashMap<>();
|
|
|
+ textObject.put("text",textInfo);
|
|
|
+ textObject.put("x1",tdw+"");
|
|
|
+ tdw = tdw + colspan;
|
|
|
+ textObject.put("x2",tdw+"");
|
|
|
+ textObject.put("y1",trh+"");
|
|
|
+ trh = trh + rowspan;
|
|
|
+ textObject.put("y2",trh+"");
|
|
|
+ textlist.add(textObject);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for(Map<String,String> m:textlist){
|
|
|
+ System.out.println(m.get("text")+":"+m.get("x1")+":"+m.get("x2")+":"+m.get("y1")+":"+m.get("y1"));
|
|
|
+ }
|
|
|
+
|
|
|
+ /*for(int i = 0 ;i < trs.size() ;i++){
|
|
|
+ Element tr = trs.get(i);
|
|
|
+ Elements tds = tr.select("td");
|
|
|
+
|
|
|
+
|
|
|
+ for( int j = 0 ; j < tds.size();j++ ){
|
|
|
+ ExctabCell cell = new ExctabCell();
|
|
|
+ Element data = tds.get(j);
|
|
|
+
|
|
|
+ boolean isadd = false ;
|
|
|
+
|
|
|
+ // 更改样式
|
|
|
+ String keyId = data.attr("class");
|
|
|
+ if(!keyId.isEmpty()){
|
|
|
+ data.removeAttr("class");
|
|
|
+ data.attr("style",styleMap.get(keyId));
|
|
|
+ }
|
|
|
+
|
|
|
+ int colspan = Integer.parseInt(data.attr("COLSPAN").equals("")?"0":data.attr("COLSPAN"));
|
|
|
+ int rowspan = Integer.parseInt(data.attr("ROWSPAN").equals("")?"0":data.attr("ROWSPAN"));
|
|
|
+ // 决定输入啥文本框
|
|
|
+ String textInfo = data.text();
|
|
|
+ if(textInfo.equals("/")|| textInfo.isEmpty()){
|
|
|
+ String trtopval = "";
|
|
|
+ String tdleftval = "";
|
|
|
+ if(i==0){ // tr 取值
|
|
|
+ trtopval = "";
|
|
|
+ }else{
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if(j==0){ // tr 取值
|
|
|
+ tdleftval = "";
|
|
|
+ }else{
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ }else{
|
|
|
+ isadd = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(isadd){
|
|
|
+ data.empty().append("<el-input type='text' placeholder=''> </el-input>");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }*/
|
|
|
+ return R.data(table+"");
|
|
|
+ }
|
|
|
}
|