|
@@ -4,12 +4,19 @@ package org.springblade.manager.service.impl;
|
|
|
import cn.hutool.core.util.HashUtil;
|
|
|
import cn.hutool.log.StaticLog;
|
|
|
import com.alibaba.fastjson.JSON;
|
|
|
+import com.alibaba.fastjson.JSONArray;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
import com.jfireel.expression.Expression;
|
|
|
import com.mixsmart.utils.*;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
+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.mp.base.BaseServiceImpl;
|
|
|
+import org.springblade.core.tool.api.R;
|
|
|
import org.springblade.core.tool.utils.*;
|
|
|
import org.springblade.manager.bean.TableInfo;
|
|
|
import org.springblade.manager.dto.*;
|
|
@@ -24,6 +31,10 @@ import org.springblade.manager.vo.AppWbsTreeContractVO;
|
|
|
import org.springblade.manager.vo.CurrentNode;
|
|
|
import org.springframework.jdbc.core.JdbcTemplate;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import java.io.File;
|
|
|
+import java.io.FileInputStream;
|
|
|
+import java.io.FileNotFoundException;
|
|
|
import java.util.*;
|
|
|
import java.util.concurrent.atomic.AtomicReference;
|
|
|
import java.util.regex.Matcher;
|
|
@@ -51,6 +62,8 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
|
|
|
private final IWbsTreeService wbsTreeService;
|
|
|
private final JdbcTemplate jdbcTemplate;
|
|
|
private final IFormulaOptionService formulaOptionService;
|
|
|
+ private final ITextdictInfoService textdictInfoService;
|
|
|
+
|
|
|
/** private final Container env;*/
|
|
|
private TableElementConverter tec;
|
|
|
private Map<String,Object> constantMap;
|
|
@@ -109,7 +122,9 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
|
|
|
/*合同段信息*/
|
|
|
this.constantMap.put(CTI,info);
|
|
|
/*项目信息*/
|
|
|
- this.constantMap.put(PJI,this.projectInfoService.getById(info.getPId()));
|
|
|
+ ProjectInfo pji=this.projectInfoService.getById(info.getPId());
|
|
|
+ tec.setProjectId(pji.getId());
|
|
|
+ this.constantMap.put(PJI,pji);
|
|
|
/*wbs节点链*/
|
|
|
List<WbsTreeContract> nodes = wpService.chain(contractId,id,primaryKeyId,null);
|
|
|
if(Func.isEmpty(nodes)){
|
|
@@ -427,6 +442,14 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
|
|
|
continue;
|
|
|
}
|
|
|
String tmp =fd.getFormula().getFormula();
|
|
|
+ /*G8G10指令脱壳*/
|
|
|
+ if(tmp.contains("G8@")||tmp.contains("G10@")){
|
|
|
+ Matcher mg= RegexUtils.matcher("FC.shell\\d{3}\\([^(FC.)]+,(G\\d+@\\w+)\\)",tmp);
|
|
|
+ while (mg.find()){
|
|
|
+ String[] ka= mg.group(1).split("@");
|
|
|
+ tmp=tmp.replace(mg.group(),ka[0]+"['"+ka[1]+"']");
|
|
|
+ }
|
|
|
+ }
|
|
|
/*假如是直接取数,则补充上非空过滤*/
|
|
|
if(tmp.matches("^E\\[m__[0-9]{14}_[0-9]{19}:key_[0-9]{0,3}]$")){
|
|
|
tmp="FC.removeEmpty("+tmp+")";
|
|
@@ -545,6 +568,72 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
|
|
|
fd.setUpdate(1);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+/*###############################附表的处理##################################*/
|
|
|
+ if(false) {
|
|
|
+ try {
|
|
|
+ /*检验单附表处理*/
|
|
|
+ List<FormData> inspectionList = new ArrayList<>();
|
|
|
+ this.tec.getTableAll().stream().filter(e -> e.getNodeName().contains("检验单") || e.getNodeName().contains("评定表")).forEach(e -> {
|
|
|
+ /*获取所有挂在表里的元素映射关系*/
|
|
|
+ this.tec.getKeyMappers().stream().filter(p -> p.getPkId().equals(e.getPKeyId())).forEach(k -> {
|
|
|
+ /*元素长度筛选超页的元素*/
|
|
|
+ List<FormData> target = this.formDataMap.values().stream().filter(f -> f.getCode().equals(k.getCode()) && f.getAddPages() > 0).collect(Collectors.toList());
|
|
|
+ if (Func.isNotEmpty(target)) {
|
|
|
+ inspectionList.addAll(target);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ if (Func.isNotEmpty(inspectionList)) {
|
|
|
+ /*检查是否存在附表,不存在则加载*/
|
|
|
+ List<AppWbsTreeContractVO> subTabList = this.tec.getTableAll().stream().filter(e -> e.getNodeName().contains("附表")).collect(Collectors.toList());
|
|
|
+ if (subTabList.size() == 0) {
|
|
|
+ WbsTreePrivate sub = wbsTreePrivateService.getOne(Wrappers.<WbsTreePrivate>lambdaQuery().eq(WbsTreePrivate::getNodeName, "质量检验表(附表)").eq(WbsTreePrivate::getProjectId, tec.getProjectId()));
|
|
|
+ if (sub == null) {
|
|
|
+ this.tec.getLog().append("该项目没有挂有附表信息");
|
|
|
+ } else {
|
|
|
+ this.wbsTreePrivateService.addWbsTreeContractInfo(this.tec.getCurrentNode().getPkId().toString(), sub.getPKeyId().toString(), tec.getContractId());
|
|
|
+ AppWbsTreeContractVO one = this.tec.getTableAll().get(0);
|
|
|
+ WbsTreeContract wtc = this.wbsTreeContractService.getOne(Wrappers.<WbsTreeContract>lambdaQuery().eq(WbsTreeContract::getParentId, one.getParentId()).eq(WbsTreeContract::getWbsId, one.getWbsId()).eq(WbsTreeContract::getNodeName, "质量检验表(附表)"));
|
|
|
+ if (wtc != null) {
|
|
|
+ AppWbsTreeContractVO obj = BeanUtil.copy(wtc, AppWbsTreeContractVO.class);
|
|
|
+ this.tec.getTableAll().add(obj);
|
|
|
+ subTabList.add(obj);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ AppWbsTreeContractVO first = subTabList.get(0);
|
|
|
+ if (tec.getTableInfoList().stream().noneMatch(e -> StringUtils.isEquals(e.getPkeyId(), first.getPKeyId()))) {
|
|
|
+ /*找不到附表表单数据,则从数据库加载*/
|
|
|
+ JSONArray dataArray = new JSONArray();
|
|
|
+ for (WbsTreeContract data : subTabList) {
|
|
|
+ R bussDataInfo = this.getBussDataInfo(data.getPKeyId(), 1);
|
|
|
+ Object data1 = bussDataInfo.getData();
|
|
|
+ dataArray.add(data1);
|
|
|
+ }
|
|
|
+ List<TableInfo> subTableInfo = FormulaUtils.getTableInfoList(dataArray);
|
|
|
+ tec.getTableInfoList().addAll(subTableInfo);
|
|
|
+ tec.getCoordinateMap().put(subTabList.get(0).getInitTableName(), CustomFunction.getElementCell(first.getHtmlUrl()));
|
|
|
+ List<Map<String, Object>> elementMaps = this.jdbcTemplate.queryForList("select b.e_name name , CONCAT(a.tab_en_name,':',b.e_key) code from m_table_info a join m_wbs_form_element b on a.id = b.f_id where a.tab_en_name='" + first.getInitTableName() + "' and b.is_deleted=0 ");
|
|
|
+ if (Func.isNotEmpty(elementMaps)) {
|
|
|
+ elementMaps.forEach(e -> {
|
|
|
+ String name = StringUtils.handleNull(e.get("name"));
|
|
|
+ String code = StringUtils.handleNull(e.get("code"));
|
|
|
+
|
|
|
+ tec.getFormDataMap().put(code, createFormDataFast(name, code, null));
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /*检验单或者评定表存在超页数据*/
|
|
|
+ Map<String, List<ElementData>> overMap = new HashMap<>();
|
|
|
+ inspectionList.forEach(f -> {
|
|
|
+
|
|
|
+ });
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
return this;
|
|
|
}
|
|
|
|
|
@@ -602,6 +691,17 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
|
|
|
}
|
|
|
//enlarge(fd,pageAdd);
|
|
|
}
|
|
|
+ /*复制只有一个单元格的元素*/
|
|
|
+ this.formDataMap.values().stream().filter(e->StringUtils.isEquals(e.getTableName(),fd.getTableName())&&fd.getCoordsList().size()==1).forEach(t->{
|
|
|
+ ElementData data=t.getValues().get(t.getValues().size()-1);
|
|
|
+ int start =data.getIndex();
|
|
|
+ for(int i=0;i<pageAdd;i++){
|
|
|
+ ElementData ed =new ElementData();
|
|
|
+ BeanUtil.copy(data,ed);
|
|
|
+ ed.setIndex(++start);
|
|
|
+ t.getValues().add(ed);
|
|
|
+ }
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
|
|
@@ -624,25 +724,6 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- try {
|
|
|
- /*检验单附表处理*/
|
|
|
- List<FormData> inspectionList= new ArrayList<>();
|
|
|
- this.tec.getTableAll().stream().filter(e->e.getNodeName().contains("检验单")).forEach(e->{
|
|
|
- this.tec.getKeyMappers().stream().filter(p->p.getPkId().equals(e.getPKeyId())).forEach(k->{
|
|
|
- this.formDataMap.values().stream().filter(f->f.getCode().equals(k.getCode())&&f.getAddPages()>0).forEach(inspectionList::add);
|
|
|
- });
|
|
|
- });
|
|
|
- if(Func.isNotEmpty(inspectionList)){
|
|
|
- Map<String,List<ElementData>> overMap=new HashMap<>();
|
|
|
- inspectionList.forEach(f->{
|
|
|
-
|
|
|
- });
|
|
|
- }
|
|
|
- }catch (Exception e){
|
|
|
- e.printStackTrace();
|
|
|
- }
|
|
|
-
|
|
|
/*检查超页情况*/
|
|
|
this.formDataMap.values().stream().filter(e->e.getUpdate()==1&&e.getAddPages()>0).sorted(Comparator.comparing(FormData::getAddPages).reversed())
|
|
|
.collect(Collectors.groupingBy(FormData::getTableName,LinkedHashMap::new,Collectors.toList())).values()
|
|
@@ -1039,7 +1120,222 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
|
|
|
return new HashMap<>();
|
|
|
}
|
|
|
|
|
|
+ public R getBussDataInfo(Long pkeyId,int type) {
|
|
|
+
|
|
|
+ Map<String, Object> reData = new HashMap<>();
|
|
|
+
|
|
|
+ WbsTreeContract wbsTreeContract = wbsTreeContractService.getBaseMapper().selectOne(Wrappers.<WbsTreeContract>query().lambda()
|
|
|
+ .eq(WbsTreeContract::getPKeyId, pkeyId));
|
|
|
+ if (wbsTreeContract == null) {
|
|
|
+ return R.data(reData);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (wbsTreeContract.getHtmlUrl() == null) {
|
|
|
+ return R.data(reData);
|
|
|
+ }
|
|
|
+
|
|
|
+ //表单是否存储在
|
|
|
+ String tabName = wbsTreeContract.getInitTableName();
|
|
|
+ String isExitSql = " select * from information_schema.TABLES where TABLE_NAME='" + tabName + "'";
|
|
|
+ List<Map<String, Object>> tabList = jdbcTemplate.queryForList(isExitSql);
|
|
|
+ if (tabList == null || tabList.size() <= 0) {
|
|
|
+ return R.fail("无实体表对应");
|
|
|
+ }
|
|
|
+
|
|
|
+ String querySql = "select * from " + wbsTreeContract.getInitTableName() + " where p_key_id=" + pkeyId;
|
|
|
+ List<Map<String, Object>> dataIn = jdbcTemplate.queryForList(querySql);
|
|
|
+
|
|
|
+ // 匹配关联
|
|
|
+ try {
|
|
|
+ File file1 = ResourceUtil.getFile(wbsTreeContract.getHtmlUrl());
|
|
|
+ String htmlString = IoUtil.readToString(new FileInputStream(file1));
|
|
|
+ Document doc = Jsoup.parse(htmlString);
|
|
|
+
|
|
|
+ // 解析
|
|
|
+ // 模糊匹配
|
|
|
+ Elements dwtitle = doc.select("el-input[placeholder~=.*承包单位]");
|
|
|
+ Elements sgtitle = doc.select("el-input[placeholder~=^施工单位]");
|
|
|
+ Elements sgtitle1 = doc.select("el-input[placeholder=安装单位]");
|
|
|
+ sgtitle.addAll(sgtitle1);
|
|
|
+
|
|
|
+ Elements htdtitle = doc.select("el-input[placeholder~=.*合同段.*]");
|
|
|
+ Elements htdtitle1 = doc.select("el-input[placeholder~=合同名称.*]");
|
|
|
+ htdtitle.addAll(htdtitle1);
|
|
|
+
|
|
|
+ Elements jltitle = doc.select("el-input[placeholder~=监理单位.*]");
|
|
|
+
|
|
|
+ Elements bhtitle = doc.select("el-input[placeholder~=^编号]");
|
|
|
+ Elements bhtitle1 = doc.select("el-input[placeholder~=合同编号.*]");
|
|
|
+ bhtitle.addAll(bhtitle1);
|
|
|
+
|
|
|
+
|
|
|
+ Elements xmtitle = doc.select("el-input[placeholder~=^项目名称]");
|
|
|
+
|
|
|
+
|
|
|
+ // Elements title = doc.select("el-input[placeholder~=^编号]");
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 承包单位 承包单位、施工单位:引用施工单位名称 ,
|
|
|
+ * 监理单位:引用监理单位名称
|
|
|
+ * 合同段、所属建设项目(合同段):引用合同段编号
|
|
|
+ *
|
|
|
+ * 施工单位:施工单位 和 安装单位
|
|
|
+ *
|
|
|
+ */
|
|
|
+ ContractInfo contractInfo = contractInfoService.getById(wbsTreeContract.getContractId());
|
|
|
+ // 施工单位名称
|
|
|
+ if (dwtitle.size() >= 1) {
|
|
|
+ int y = Integer.parseInt(dwtitle.attr("trindex"));
|
|
|
+ if (y <= 10) {
|
|
|
+ reData.put(dwtitle.attr("keyName"), contractInfo.getConstructionUnitName());
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ if (sgtitle.size() >= 1) {
|
|
|
+ int y = Integer.parseInt(sgtitle.attr("trindex"));
|
|
|
+ if (y <= 10) {
|
|
|
+ reData.put(sgtitle.attr("keyName"), contractInfo.getConstructionUnitName());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 合同段名称
|
|
|
+ if (htdtitle.size() >= 1) {
|
|
|
+ for (Element element : htdtitle) {
|
|
|
+ int trindex = Integer.parseInt(element.attr("trindex"));
|
|
|
+ if (trindex <= 8) {
|
|
|
+ reData.put(element.attr("keyName"), contractInfo.getContractNumber());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 监理单位名称
|
|
|
+ if (jltitle.size() >= 1) {
|
|
|
+
|
|
|
+ for (Element element : jltitle) {
|
|
|
+ int trindex = Integer.parseInt(element.attr("trindex"));
|
|
|
+ if (trindex <= 10) {
|
|
|
+ reData.put(element.attr("keyName"), contractInfo.getSupervisionUnitName());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //获取父节点划分编号
|
|
|
+ WbsTreeContract node = wbsTreeContractService.getBaseMapper().selectOne(Wrappers.<WbsTreeContract>query().lambda()
|
|
|
+ .eq(WbsTreeContract::getId, wbsTreeContract.getParentId())
|
|
|
+ .eq(WbsTreeContract::getContractId, wbsTreeContract.getContractId()));
|
|
|
+ // 编号
|
|
|
+ if (bhtitle.size() >= 1 && contractInfo.getIsReferenceNumber() == 1) {
|
|
|
+ for (Element element : bhtitle) {
|
|
|
+ int trindex = Integer.parseInt(element.attr("trindex"));
|
|
|
+ if (trindex <= 10) {
|
|
|
+ reData.put(element.attr("keyName"), node.getPartitionCode() == null ? "" : node.getPartitionCode());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 项目名称
|
|
|
+ if (xmtitle.size() >= 1) {
|
|
|
+ for (Element element : xmtitle) {
|
|
|
+ int trindex = Integer.parseInt(element.attr("trindex"));
|
|
|
+ if (trindex <= 6) {
|
|
|
+ ProjectInfo projectInfo = projectInfoService.getById(wbsTreeContract.getProjectId());
|
|
|
+ reData.put(element.attr("keyName"), projectInfo.getProjectName());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (FileNotFoundException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (dataIn != null && dataIn.size() >= 1) {
|
|
|
+ Map<String, Object> mysqlData = dataIn.get(0);
|
|
|
+ for (String key : mysqlData.keySet()) {
|
|
|
+ String tabVal = mysqlData.get(key) + "";
|
|
|
+ // 时间段处理
|
|
|
+ if (org.apache.commons.lang.StringUtils.isNotEmpty(tabVal) && tabVal.indexOf("null") < 0) {
|
|
|
+ if (tabVal.indexOf("T") >= 0 && tabVal.indexOf(".000Z]") >= 0) {
|
|
|
+ String[] tabData = tabVal.split("_\\^_");
|
|
|
+
|
|
|
+ if (reData.containsKey("pickerKey")) {
|
|
|
+ String pickerKey = reData.get("pickerKey") + "," + key + "__" + tabData[1];
|
|
|
+ reData.put("pickerKey", pickerKey);
|
|
|
+ } else {
|
|
|
+ reData.put("pickerKey", key + "__" + tabData[1]);
|
|
|
+ }
|
|
|
|
|
|
+ String sql = tabData[0];
|
|
|
+ sql = sql.replaceAll("\\[", "['");
|
|
|
+ sql = sql.replaceAll("]", "']");
|
|
|
+ sql = sql.replaceAll("000Z,", "000Z',");
|
|
|
+ sql = sql.replaceAll(", 20", ", '20");
|
|
|
+ // sql = sql.replaceAll("'", "");
|
|
|
+ if (org.apache.commons.lang.StringUtils.isNotEmpty(tabData[0])) {
|
|
|
+ reData.put(key + "__" + tabData[1], sql);
|
|
|
+ }
|
|
|
+ } else if (tabVal.indexOf("T") >= 0 && tabVal.indexOf(".000Z") >= 0) { //时间
|
|
|
+ // 时间和字符串合作
|
|
|
+ if (tabVal.indexOf("☆") >= 0) {
|
|
|
+ String[] mysql = tabVal.split("☆");
|
|
|
+ for (String data : mysql) {
|
|
|
+ String[] tabData = data.split("_\\^_");
|
|
|
+ if (org.apache.commons.lang.StringUtils.isNotEmpty(tabData[0])) {
|
|
|
+ reData.put(key + "__" + tabData[1], tabData[0]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ String[] tabData = tabVal.split("_\\^_");
|
|
|
+ if (org.apache.commons.lang.StringUtils.isNotEmpty(tabData[0])) {
|
|
|
+ reData.put(key + "__" + tabData[1], tabData[0]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if (tabVal.indexOf("☆") >= 0) {
|
|
|
+ String[] mysql = tabVal.split("☆");
|
|
|
+ for (String data : mysql) {
|
|
|
+ String[] tabData = data.split("_\\^_");
|
|
|
+ if (org.apache.commons.lang.StringUtils.isNotEmpty(tabData[0])) {
|
|
|
+ reData.put(key + "__" + tabData[1], tabData[0]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if (tabVal.indexOf("_^_") >= 0) {
|
|
|
+ String[] tabData = tabVal.split("_\\^_");
|
|
|
+ if (org.apache.commons.lang.StringUtils.isNotEmpty(tabData[0])) {
|
|
|
+ reData.put(key + "__" + tabData[1], tabData[0]);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ reData.put(key, tabVal);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取默认值
|
|
|
+ QueryWrapper<TextdictInfo> queryWrapper = new QueryWrapper<>();
|
|
|
+ queryWrapper.eq("type", 4);
|
|
|
+ queryWrapper.eq("tab_id", wbsTreeContract.getIsTypePrivatePid());
|
|
|
+ final List<TextdictInfo> textdictInfos = textdictInfoService.getBaseMapper().selectList(queryWrapper);
|
|
|
+ if (!textdictInfos.isEmpty()) {
|
|
|
+ for (TextdictInfo textdictInfo : textdictInfos) {
|
|
|
+ if (reData.containsKey(textdictInfo.getColKey())) {
|
|
|
+ String keyVal = reData.get(textdictInfo.getColKey()) + "";
|
|
|
+ } else {
|
|
|
+ reData.put(textdictInfo.getColKey() + "", textdictInfo.getSigRoleName());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 移除Id 和 p_key_id
|
|
|
+ if(type==0){
|
|
|
+ reData.remove("id");
|
|
|
+ reData.remove("p_key_id");
|
|
|
+ reData.remove("classify");
|
|
|
+ reData.remove("contractId");
|
|
|
+ reData.remove("pkeyId");
|
|
|
+ reData.remove("projectId");
|
|
|
+ }
|
|
|
+ if(type==1){
|
|
|
+ reData.put("pkeyId",reData.get("p_key_id"));
|
|
|
+ }
|
|
|
+ reData.put("tabGroupId", wbsTreeContract.getTabGroupId());
|
|
|
+ return R.data(reData);
|
|
|
+ }
|
|
|
|
|
|
}
|
|
|
|