|
|
@@ -0,0 +1,365 @@
|
|
|
+package com.uas.eis.serviceImpl;
|
|
|
+
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
+import com.uas.eis.core.support.TokenHandler;
|
|
|
+import com.uas.eis.dao.BaseDao;
|
|
|
+import com.uas.eis.dao.SqlMap;
|
|
|
+import com.uas.eis.dao.SqlRowList;
|
|
|
+import com.uas.eis.entity.ErrorMessage;
|
|
|
+import com.uas.eis.entity.ErrorMsg;
|
|
|
+import com.uas.eis.entity.StepWork.StationReq;
|
|
|
+import com.uas.eis.entity.StepWork.TestReq;
|
|
|
+import com.uas.eis.exception.ApiStepWorkException;
|
|
|
+import com.uas.eis.exception.SystemException;
|
|
|
+import com.uas.eis.sdk.entity.ApiResult;
|
|
|
+import com.uas.eis.sdk.entity.StepWorkApiResult;
|
|
|
+import com.uas.eis.sdk.resp.StepWorkApiResponse;
|
|
|
+import com.uas.eis.service.StepWorkService;
|
|
|
+import com.uas.eis.utils.*;
|
|
|
+import org.aspectj.weaver.ast.Test;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+
|
|
|
+import java.util.*;
|
|
|
+
|
|
|
+@Service
|
|
|
+public class StepWorkServiceImpl implements StepWorkService {
|
|
|
+ @Autowired
|
|
|
+ private BaseDao baseDao;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String login(String username, String password) {
|
|
|
+ SqlRowList rs = baseDao.queryForRowSet("select AE_SECRET from APIEMPLOYEE where AE_KEY=?",username);
|
|
|
+ if(rs.next()){
|
|
|
+ System.out.println("secret:"+MD5Util.encrypt32Up(rs.getString("ae_secret")));
|
|
|
+ if(!password.equals(MD5Util.encrypt32Up(rs.getString("ae_secret")))){
|
|
|
+ throw new ApiStepWorkException(new StepWorkApiResult(ErrorMessage.ACCESSSECRET_ERROR));
|
|
|
+ }else{
|
|
|
+ return TokenHandler.createToken(username,rs.getString("ae_secret"));
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ throw new ApiStepWorkException(new StepWorkApiResult(ErrorMessage.ACCESSKEY_ERROR));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 保存测试信息并且过站
|
|
|
+ * @param data
|
|
|
+ * @return
|
|
|
+ * {
|
|
|
+ * "workOrderNo":"WO20220826000002SHD", //工单号 必填
|
|
|
+ * "stationCode":"GW--001", //工位编码 必填
|
|
|
+ * "routeCode":"22b443b4fa379a546330f4e984cc6ed1", //工序编号 必填
|
|
|
+ * "sequenceNumber":"[P]2022083426046[B]",//产品SN 必填
|
|
|
+ * "eventResult":"PASS", 测试结果:PASS(合格),FAIL(不合格) 必填
|
|
|
+ * failureCode MES不良配置里维护的信息 * 注:PASS可以不用传, 如果是FAIL不良代码就必传 非必填
|
|
|
+ * extendSequenceNumber 测试合格后会把三方条码和组合体SN组合,后续扫描其中任意条码都可以识别。多个条码中间用逗分隔 非必填
|
|
|
+ * machineTestData 设备测试数据 非必填 Json可以传产品多次测试记录。results的键值需要和titles的键值对应Titles中的键值不能重复
|
|
|
+ * isInputSn 是否属于投入产品 非必填 Boolean (true:根据投入SN过站并生成产品数据,false[默认]:从工单中查找是否有过站SN)
|
|
|
+ * }
|
|
|
+ *
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public StepWorkApiResult<Map<String,Object>> test(String data) {
|
|
|
+ insertLogger(data,"test");
|
|
|
+ return testmain(data);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * * {
|
|
|
+ * * "workOrderNo":"WO20220826000002SHD", //工单号
|
|
|
+ * * "stationCode":"GW--001", //工位编码
|
|
|
+ * * "routeCode":"22b443b4fa379a546330f4e984cc6ed1", //工序编号
|
|
|
+ * * "sequenceNumber":"[P]2022083426046[B]" //产品SN
|
|
|
+ * * }
|
|
|
+ * @param data
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public StepWorkApiResult<Map<String,Object>> station(String data) {
|
|
|
+ insertLogger(data,"station");
|
|
|
+ return stationmain(data);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 工单绑定,工序检测
|
|
|
+ *
|
|
|
+ */
|
|
|
+ private Map<String,Object> checkStep(String macode,String sourcecode,String sncode,String usercode ){
|
|
|
+ List<String> list = new ArrayList<String>();
|
|
|
+ /**
|
|
|
+ * v_i_macode in varchar2 ,
|
|
|
+ * v_i_sourcecode in varchar2,
|
|
|
+ * v_i_sncode in varchar2,
|
|
|
+ * v_i_usercode in varchar2,
|
|
|
+ * v_o_macode out varchar2,
|
|
|
+ * v_o_msid out int,
|
|
|
+ * v_o_errmsg out varchar2
|
|
|
+ */
|
|
|
+ list = baseDao.callProcedureWithOut("CS_CHECKSTEPSNANDMACODE", new Object[]{
|
|
|
+ macode, sourcecode,sncode,usercode
|
|
|
+ }, new Integer[]{1, 2, 3, 4}, new Integer[]{5, 6, 7});
|
|
|
+ Map<String,Object> map = new HashMap<>();
|
|
|
+ String msg = list.get(2);
|
|
|
+ if(StringUtil.hasText(msg)){
|
|
|
+ map.put("success",false);
|
|
|
+ map.put("msg",msg);
|
|
|
+ }else{
|
|
|
+ map.put("success",true);
|
|
|
+ map.put("macode",list.get(0));
|
|
|
+ }
|
|
|
+ return map;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean stepPassed(String iMakeCode, String iSourceCode, String iSN, String iUserCode, String iResult) {
|
|
|
+ String msg = baseDao.callProcedure("CS_SETSTEPRESULT",
|
|
|
+ String.valueOf(iMakeCode),
|
|
|
+ String.valueOf(iSourceCode),
|
|
|
+ String.valueOf(iSN),
|
|
|
+ String.valueOf(iUserCode),
|
|
|
+ String.valueOf(iResult));
|
|
|
+ if(StringUtil.hasText(msg)){
|
|
|
+ throw new ApiStepWorkException(new StepWorkApiResult(false,400,msg));
|
|
|
+ }else{
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 保存测试数据并且过站
|
|
|
+ * @param macode
|
|
|
+ * @param sccode
|
|
|
+ * @param sncode
|
|
|
+ * @param isok
|
|
|
+ * @param failureCode
|
|
|
+ * @param machineTestData
|
|
|
+ * "machineTestData":{
|
|
|
+ * "machineCode":"JT001",
|
|
|
+ * "titles":{
|
|
|
+ * "芯片型号":"100",
|
|
|
+ * "开机电流":"200",
|
|
|
+ *"线损补偿":"300",
|
|
|
+ * "输出功率":"400",
|
|
|
+ * "测试时长":"500",
|
|
|
+ * "测试结果":"600"},
|
|
|
+ * "results":[{
|
|
|
+ * "芯片型号":"XXC5121",
|
|
|
+ * "开机电流":"9.438",
|
|
|
+ * "线损补偿":"11.00",
|
|
|
+ * "输出功率":"11.683",
|
|
|
+ * "测试时长":"31.37",
|
|
|
+ * "测试结果":"成功"
|
|
|
+ * }]}
|
|
|
+ */
|
|
|
+ private void saveTestDataAndPassed(String macode, String stepcode,String sccode, String sncode, String isok, String failureCode, Object isinput,Object machineTestData) {
|
|
|
+ //保存测试数据
|
|
|
+ Object machinecode = "";
|
|
|
+ List<Map<Object,Object>> sqldata = new ArrayList<>();
|
|
|
+ int mainid = baseDao.getSeqId("STEPTESTMAIN_SEQ");
|
|
|
+ if(StringUtil.hasText(machineTestData)){
|
|
|
+ Map<Object, Object> map = null;
|
|
|
+ if (machineTestData instanceof Map) {
|
|
|
+ map = (Map<Object, Object>) machineTestData;
|
|
|
+ }else{
|
|
|
+ map = BaseUtil.parseFormStoreToMap(machineTestData.toString());
|
|
|
+ }
|
|
|
+ if(!map.isEmpty()) {
|
|
|
+ int detno=1;
|
|
|
+ machinecode = map.containsKey("machineCode")?map.get("machineCode"):"";
|
|
|
+ Object titles = map.get("titles");
|
|
|
+ Object results = map.get("results");
|
|
|
+ if(StringUtil.hasText(titles) && StringUtil.hasText(results)){
|
|
|
+ // SD_SN,SD_MAKECODE,SD_MACHINECODE,SD_INDATE,
|
|
|
+ Map<Object,Object> baseData = new HashMap<>() ;
|
|
|
+ baseData.put("SD_SN",sncode);
|
|
|
+ baseData.put("SD_MAKECODE",macode);
|
|
|
+ baseData.put("SD_MACHINECODE",machinecode);
|
|
|
+ baseData.put("SD_INDATE",DateUtil.parseDateToString(new Date(), Constant.YMD_HMS));
|
|
|
+ Map<String,Object> titledata = null;
|
|
|
+ if (machineTestData instanceof Map) {
|
|
|
+ titledata = (Map<String, Object>) titles;
|
|
|
+ }else{
|
|
|
+ titledata = FlexJsonUtil.fromJson(titles.toString());
|
|
|
+ }
|
|
|
+ List<Map<String,Object>> resultdata = null;
|
|
|
+ if (results instanceof List) {
|
|
|
+ resultdata = (List<Map<String,Object>>) results;
|
|
|
+ }else{
|
|
|
+ resultdata = FlexJsonUtil.fromJsonArray(results.toString(),HashMap.class);
|
|
|
+ }
|
|
|
+ for(Map<String,Object> m : resultdata){
|
|
|
+ Iterator<Map.Entry<String, Object>> iterator = titledata.entrySet().iterator();
|
|
|
+ baseData.put("SD_DETNO", detno);
|
|
|
+ detno++;
|
|
|
+ while (iterator.hasNext()) {
|
|
|
+ Map.Entry<String, Object> entry = iterator.next();
|
|
|
+ String key = entry.getKey();
|
|
|
+ Object value = entry.getValue();
|
|
|
+ Map<Object,Object> sqlm = new HashMap<>();
|
|
|
+ sqlm.putAll(baseData);
|
|
|
+ sqlm.put("SD_CLASS", key);
|
|
|
+ sqlm.put("SD_LENGTH", value);
|
|
|
+ sqlm.put("SD_SMID",mainid);
|
|
|
+ Object v = m.get(key);
|
|
|
+ sqlm.put("SD_ACTVALUE",v);
|
|
|
+ sqlm.put("SD_ID",null);
|
|
|
+ sqldata.add(sqlm);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //测试项和测试结果不一致
|
|
|
+ /**
|
|
|
+ * insert into STEPTESTMAIN(SM_ID,SM_SN,SM_MAKECODE,SM_STEPCODE,SM_SCCODE,SM_RESULT,SM_BADCODE,SM_ISINPUT,SM_INDATE)
|
|
|
+ * insert into STEPTESTDETAIL(SD_ID,SD_SMID,SD_SN,SD_MAKECODE,SD_MACHINECODE,SD_INDATE,SD_CLASS,SD_StandardVALUE,SD_ACTVALUE)
|
|
|
+ */
|
|
|
+ //插入数据
|
|
|
+ baseDao.execute("insert into STEPTESTMAIN(SM_ID,SM_SN,SM_MAKECODE,SM_STEPCODE,SM_SCCODE,SM_RESULT,SM_BADCODE,SM_ISINPUT,SM_INDATE)" +
|
|
|
+ "select ?,?,?,?,?,?,?,?,sysdate from dual ",mainid,sncode,macode,stepcode,sccode,isok,failureCode,isinput);
|
|
|
+ if(sqldata.size()>0){
|
|
|
+ baseDao.execute(SqlUtil.getInsertSqlbyList(sqldata,"STEPTESTDETAIL","SD_ID"));
|
|
|
+ }
|
|
|
+
|
|
|
+ Object msstepcode = baseDao.getFieldDataByCondition("Makeserial", "ms_stepcode", "ms_sncode='" + sncode + "' and ms_makecode='" + macode + "'");
|
|
|
+ Object BgCode = baseDao.getFieldDataByCondition("step", "nvl(st_badgroupcode,' ')", "st_code='" + stepcode + "'");
|
|
|
+ Map<Object, Object> rmap = new HashMap<>();
|
|
|
+ if("FAIL".equals(isok)){
|
|
|
+ //将历史的不良记录更新状态
|
|
|
+ baseDao.execute("update makebad set mb_status=-1 where mb_sncode=? and mb_makecode=? and mb_stepcode=? and mb_status=0",sncode,macode);
|
|
|
+ baseDao.execute("insert into makebad(mb_id,mb_makecode,mb_mscode,mb_sncode,mb_inman,mb_indate,mb_stepcode,mb_sourcecode,mb_badcode,mb_badtable,mb_bgcode,mb_soncode,mb_status)" +
|
|
|
+ " select makebad_seq.nextval,ma_code,ms_code,ms_sncode,'EIS对接',sysdate,?,?,?,'',?,sp_soncode,0 from make left join makeserial on ms_makecode=ma_code left join " +
|
|
|
+ " stepproduct on sp_mothercode=ma_prodcode and sp_stepcode=ms_nextstepcode where ms_sncode=? and ms_makecode=?",stepcode,sccode,failureCode,BgCode,sncode,macode);
|
|
|
+ //将不良的序列号的状态码设为3
|
|
|
+ //baseDao.execute("update "+Master+".makeserial set ms_status='3' where ms_sncode='" + iSN + "' and ms_makecode='" + iMakeCode + "'");
|
|
|
+ }else if("PASS".equals(isok) && StringUtil.hasText(failureCode)){ //强制良品也有不良代码的
|
|
|
+ baseDao.execute("insert into makebad(mb_id,mb_makecode,mb_mscode,mb_sncode,mb_inman,mb_indate,mb_stepcode,mb_sourcecode,mb_badcode,mb_badtable,mb_bgcode,mb_soncode,mb_status)" +
|
|
|
+ " select makebad_seq.nextval,ma_code,ms_code,ms_sncode,'EIS对接',sysdate,?,?,?,'',?,sp_soncode,-1 from make left join makeserial on ms_makecode=ma_code left join " +
|
|
|
+ " stepproduct on sp_mothercode=ma_prodcode and sp_stepcode=ms_nextstepcode where ms_sncode=? and ms_makecode=?",stepcode,sccode,failureCode,BgCode,sncode,macode);
|
|
|
+ }
|
|
|
+ //不良采集为良品是更新
|
|
|
+ if (msstepcode!=null && msstepcode.toString().equals(stepcode) && isok == "PASS") {
|
|
|
+ Object[] ob = baseDao.getFieldsDataByCondition("makeserial", "ms_status,ms_craftcode,ms_prodcode", "ms_sncode='" + sncode + "' and ms_makecode='" + macode + "'");
|
|
|
+ if (ob!=null){
|
|
|
+ String ms_status =ob[0].toString();
|
|
|
+ String ms_craftcode= ob[1].toString();
|
|
|
+ String ms_prodcode = ob[2].toString();
|
|
|
+ if (ms_status == "3") {
|
|
|
+ String nextstepcode =baseDao.getFieldDataByCondition("craft left join craftdetail on cr_id=cd_crid ", "cd_nextstepcode", "cr_code='" + ms_craftcode + "' and cr_prodcode='" + ms_prodcode + "' and cd_stepcode='" + stepcode + "'").toString();
|
|
|
+ baseDao.updateByCondition("makeserial", "ms_status=1,ms_nextstepcode='" + nextstepcode + "'", "ms_sncode='" + sncode + "' and ms_makecode='" + macode + "'");
|
|
|
+ baseDao.updateByCondition("makebad", "mb_status=-1", "mb_sncode='" + sncode + "' and mb_makecode='" + macode + "'");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ stepPassed(macode,sccode,sncode,null,"PASS".equals(isok)?"OK":"NG");
|
|
|
+ }
|
|
|
+
|
|
|
+ //记录日志
|
|
|
+ private void insertLogger(String data,String type){
|
|
|
+ baseDao.execute("insert into EISDATA(ed_id,ed_data,ed_indate,ED_TYPE)" +
|
|
|
+ "values(EISDATA_seq.nextval,?,sysdate,?)", data,type);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Transactional
|
|
|
+ public StepWorkApiResult<Map<String,Object>> testmain(String data){
|
|
|
+ Map<Object,Object> map = BaseUtil.parseFormStoreToMap(data);
|
|
|
+ String macode = " ";
|
|
|
+ if(StringUtil.hasText(map.get("workOrderNo"))){//工单号可填写可不填
|
|
|
+ macode = map.get("workOrderNo").toString();
|
|
|
+ }
|
|
|
+ Object sccode = map.get("stationCode");
|
|
|
+ if(!StringUtil.hasText(sccode)){
|
|
|
+ return StepWorkApiResponse.failRsp(400,"工位编码(stationCode)不能为空!");
|
|
|
+ }
|
|
|
+ Object stepcode = map.get("routeCode");
|
|
|
+ if(!StringUtil.hasText(stepcode)){
|
|
|
+ return StepWorkApiResponse.failRsp(400,"工序编号(routeCode)不能为空!");
|
|
|
+ }
|
|
|
+ Object sncode = map.get("sequenceNumber");
|
|
|
+ if(!StringUtil.hasText(sncode)){
|
|
|
+ return StepWorkApiResponse.failRsp(400,"产品SN(sequenceNumber)不能为空!");
|
|
|
+ }
|
|
|
+ //测试结果
|
|
|
+ Object isok = map.get("eventResult"); //测试结果:PASS(合格),FAIL(不合格) 必填 ,测试强制合格有的时候也会有不良代码
|
|
|
+ Object failureCode =map.get("failureCode");
|
|
|
+ if(!StringUtil.hasText(isok)){
|
|
|
+ return StepWorkApiResponse.failRsp(400,"测试结果(eventResult)不能为空!");
|
|
|
+ }else{
|
|
|
+ if(!"PASS".equals(isok) && !"FAIL".equals(isok)){
|
|
|
+ return StepWorkApiResponse.failRsp(400,"测试结果值【"+isok+"】,只能是PASS或者FAIL!");
|
|
|
+ }
|
|
|
+ if("FAIL".equals(isok) && !StringUtil.hasText(failureCode)){
|
|
|
+ return StepWorkApiResponse.failRsp(400,"测试结果为不合格,不良代码(failureCode)值必填!");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(StringUtil.hasText("failureCode")) {
|
|
|
+ String bccode = baseDao.getJdbcTemplate().queryForObject("select max(bc_code) from badcode where bc_code=?", String.class, failureCode);//oErrMessage = "不良代码"+BadCode[i]+"不存在";
|
|
|
+ if (null == bccode) {
|
|
|
+ throw new ApiStepWorkException(new StepWorkApiResult(false, 400, "测试不良代码:" + failureCode + "在MES系统不存在!"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //工序校验
|
|
|
+ Map<String,Object> remap = checkStep(macode,sccode.toString(),sncode.toString(),null);
|
|
|
+ if(Boolean.valueOf(remap.get("success").toString())){
|
|
|
+ //工序保存测试数据并且过站
|
|
|
+ saveTestDataAndPassed(remap.get("macode").toString(),stepcode.toString(),sccode.toString(),sncode.toString(),
|
|
|
+ isok.toString(),failureCode.toString(),map.get("isinput"),map.get("machineTestData"));
|
|
|
+ return StepWorkApiResponse.successRsp(200,"【"+sncode+"】产品序列号过站成功!");
|
|
|
+ }else{
|
|
|
+ return StepWorkApiResponse.failRsp(400,remap.get("msg").toString());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Transactional
|
|
|
+ public StepWorkApiResult<Map<String,Object>> stationmain(String data) {
|
|
|
+ Map<Object, Object> map = BaseUtil.parseFormStoreToMap(data);
|
|
|
+ String macode = " ";
|
|
|
+ if (StringUtil.hasText(map.get("workOrderNo"))) {//工单号可填写可不填
|
|
|
+ macode = map.get("workOrderNo").toString();
|
|
|
+ }
|
|
|
+ Object sccode = map.get("stationCode");
|
|
|
+ if (!StringUtil.hasText(sccode)) {
|
|
|
+ return StepWorkApiResponse.failRsp(400, "工位编码(stationCode)不能为空!");
|
|
|
+ }
|
|
|
+ Object stepcode = map.get("routeCode");
|
|
|
+ if (!StringUtil.hasText(stepcode)) {
|
|
|
+ return StepWorkApiResponse.failRsp(400, "工序编号(routeCode)不能为空!");
|
|
|
+ }
|
|
|
+ Object sncode = map.get("sequenceNumber");
|
|
|
+ if (!StringUtil.hasText(sncode)) {
|
|
|
+ return StepWorkApiResponse.failRsp(400, "产品SN(sequenceNumber)不能为空!");
|
|
|
+ }
|
|
|
+ Map<String, Object> remap = checkStep(macode, sccode.toString(), sncode.toString(), null);
|
|
|
+ if (Boolean.valueOf(remap.get("success").toString())) {
|
|
|
+ stepPassed(remap.get("macode").toString(), sccode.toString(), sncode.toString(), null, "OK");
|
|
|
+ return StepWorkApiResponse.successRsp(200, "【" + sncode + "】产品序列号过站成功!");
|
|
|
+ } else {
|
|
|
+ return StepWorkApiResponse.failRsp(400, remap.get("msg").toString());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* SqlRowList rs=baseDao.queryForRowSet("select nvl(st_ifinput,0)st_ifinput,nvl(st_ifoqc,0)st_ifoqc,nvl(st_ifweigh,0)st_ifweigh from "+Master+".source left join "+Master+".step on sc_stepcode=st_code where sc_code='"+iResCode+"'");
|
|
|
+ if(rs.next()){
|
|
|
+ String st_ifinput=rs.getString("st_ifinput");
|
|
|
+ String st_ifoqc=rs.getString("st_ifinput");
|
|
|
+ String st_ifweigh=rs.getString("st_ifweigh");
|
|
|
+ if(st_ifinput.equals("-1")){
|
|
|
+ oErrMessage = "上料工序必须在客户端进行过站";
|
|
|
+ rmap.put("oErrMessage",oErrMessage);
|
|
|
+ return rmap;
|
|
|
+ }
|
|
|
+ if(st_ifoqc.equals("-1")){
|
|
|
+ oErrMessage = "OQC必须在客户端进行过站";
|
|
|
+ rmap.put("oErrMessage",oErrMessage);
|
|
|
+ return rmap;
|
|
|
+ }
|
|
|
+ if(st_ifweigh.equals("-1")){
|
|
|
+ oErrMessage = "称重工序必须在客户端进行过站";
|
|
|
+ rmap.put("oErrMessage",oErrMessage);
|
|
|
+ return rmap;
|
|
|
+ }
|
|
|
+ }*/
|
|
|
+
|
|
|
+}
|