Quellcode durchsuchen

广开自定义试卷逻辑

xiatian vor 1 Jahr
Ursprung
Commit
2014548402

+ 55 - 0
src/main/java/cn/com/qmth/export/DetailDto2.java

@@ -0,0 +1,55 @@
+package cn.com.qmth.export;
+
+public class DetailDto2 {
+	private String pname;
+	private String tname;
+	public String getPname() {
+		return pname;
+	}
+	public void setPname(String pname) {
+		this.pname = pname;
+	}
+	public String getTname() {
+		return tname;
+	}
+	public void setTname(String tname) {
+		this.tname = tname;
+	}
+	public DetailDto2(String pname, String tname) {
+		super();
+		this.pname = pname;
+		this.tname = tname;
+	}
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result + ((pname == null) ? 0 : pname.hashCode());
+		result = prime * result + ((tname == null) ? 0 : tname.hashCode());
+		return result;
+	}
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		DetailDto2 other = (DetailDto2) obj;
+		if (pname == null) {
+			if (other.pname != null)
+				return false;
+		} else if (!pname.equals(other.pname))
+			return false;
+		if (tname == null) {
+			if (other.tname != null)
+				return false;
+		} else if (!tname.equals(other.tname))
+			return false;
+		return true;
+	}
+	
+	
+	
+}

+ 40 - 0
src/main/java/cn/com/qmth/export/ExportPaperByCourseCode2.java

@@ -0,0 +1,40 @@
+package cn.com.qmth.export;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+
+public class ExportPaperByCourseCode2 {
+	private static Logger logger = LogManager.getLogger(ExportPaperByCourseCode2.class);
+	//试卷后缀
+	private static String paperSuff = "(240318)";
+	//数据库名
+	private static String dbName="guangkai3";
+	private static AtomicInteger count=new AtomicInteger(0);
+	
+	public static void main(String[] args) {
+		logger.debug("导出开始");
+		Date start=new Date();
+		try {
+			MyProducer2 pro=new MyProducer2();
+			Map<String, Object> param=new HashMap<>();
+			param.put("paperSuff", paperSuff);
+			param.put("dbName", dbName);
+			pro.startDispose(MyConsumer2.class, 8, param);
+		} catch (Exception e) {
+			logger.error(e.getCause(), e);
+		}
+		Date end=new Date();
+		logger.debug("导出结束,耗时:"+((end.getTime()-start.getTime())/1000));
+	}
+
+
+	public static void  addDisposeCount() {
+		count.addAndGet(1);
+		logger.debug("处理了"+count);
+	}
+}

+ 36 - 0
src/main/java/cn/com/qmth/export/KdQuestion.java

@@ -3,7 +3,11 @@ package cn.com.qmth.export;
 import java.util.List;
 
 public class KdQuestion {
+	private String pname;
+	private String tname;
+	private String cname;
 	private String id;
+	private String pid;
 	private String typeId;
 	private String detailName;
 	private CusQuesStructType cusType;
@@ -130,4 +134,36 @@ public class KdQuestion {
 		this.typeId = typeId;
 	}
 
+	public String getPname() {
+		return pname;
+	}
+
+	public void setPname(String pname) {
+		this.pname = pname;
+	}
+
+	public String getTname() {
+		return tname;
+	}
+
+	public void setTname(String tname) {
+		this.tname = tname;
+	}
+
+	public String getCname() {
+		return cname;
+	}
+
+	public void setCname(String cname) {
+		this.cname = cname;
+	}
+
+	public String getPid() {
+		return pid;
+	}
+
+	public void setPid(String pid) {
+		this.pid = pid;
+	}
+
 }

+ 93 - 0
src/main/java/cn/com/qmth/export/MD5Util.java

@@ -0,0 +1,93 @@
+package cn.com.qmth.export;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Optional;
+import java.util.StringJoiner;
+
+import org.apache.commons.codec.digest.DigestUtils;
+
+/**
+ * @Description: MD5加密工具类
+ */
+public class MD5Util {
+	public static final String CHARSET_NAME = "UTF-8";
+
+    public static final Charset CHARSET = Charset.forName(CHARSET_NAME);
+    
+    public static final String MD5 = "MD5";
+
+    /**
+     * MD5加密
+     *
+     * @param text
+     * @return
+     * @throws Exception
+     */
+    public static String encoder(String text) throws NoSuchAlgorithmException {
+        text = Optional.of(text).get();
+        MessageDigest digest = MessageDigest.getInstance(MD5);
+        digest.update(text.getBytes(CHARSET));
+        byte s[] = digest.digest();
+        StringJoiner result = new StringJoiner("");
+        for (int i = 0; i < s.length; i++) {
+            result.add(Integer.toHexString((0x000000FF & s[i]) | 0xFFFFFF00).substring(6));
+        }
+        return result.toString();
+    }
+
+    /**
+     * MD5校验
+     *
+     * @param text
+     * @param md5
+     * @return
+     * @throws Exception
+     */
+    public static boolean verify(String text, String md5) throws NoSuchAlgorithmException {
+        text = Optional.of(text).get();
+        md5 = Optional.of(md5).get();
+        //根据传入的密钥进行验证
+        String md5Text = encoder(text);
+        if (md5Text.equalsIgnoreCase(md5)) {
+            return true;
+        }
+        return false;
+    }
+    
+	public static String md5Hex(File file) {
+		FileInputStream in = null;
+		try {
+			in = new FileInputStream(file);
+			return DigestUtils.md5Hex(in);
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		} finally {
+			if(in!=null)
+				try {
+					in.close();
+				} catch (IOException e) {
+				}
+		}
+	}
+	
+	public static String md5Hex(InputStream in) {
+		try {
+			return DigestUtils.md5Hex(in);
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		} finally {
+			if(in!=null)
+				try {
+					in.close();
+				} catch (IOException e) {
+				}
+		}
+	}
+}
+

+ 375 - 0
src/main/java/cn/com/qmth/export/MyConsumer2.java

@@ -0,0 +1,375 @@
+package cn.com.qmth.export;
+
+import java.io.File;
+import java.io.IOException;
+import java.security.NoSuchAlgorithmException;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import com.alibaba.fastjson.JSONObject;
+
+public class MyConsumer2 extends Consumer<PaperExportDto> {
+//	private static String[] sucStr = new String[] { "对", "正确", "√", "是", "True" };
+//	private static String[] errStr = new String[] { "错", "错误", "×", "不正确", "否", "False" };
+//	private static String paperSuff = "(231205)";
+	private int maxqc = 200;
+
+	private static String paperDir = "d:/guangkai/paper/";
+
+	private Pattern imgPat = Pattern.compile("<img[^<]+src=\"([^<\"]+)\"[^<]*>");
+
+	@Override
+	public void consume(PaperExportDto dto) {
+		Connection connect = null;
+		File sub = new File(paperDir + dto.getCourseCode() + "/");
+		sub.mkdir();
+		try {
+			Class.forName("com.mysql.cj.jdbc.Driver");
+
+			String url = "jdbc:mysql://localhost:3306/" + dto.getDbName() + "?serverTimezone=GMT%2B8";
+
+			String user = "root";
+
+			String password = "123456";
+			connect = DriverManager.getConnection(url, user, password);
+			exportPaper(connect, dto);
+			ExportPaperByCourseCode.addDisposeCount();
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		} finally {
+			if (connect != null) {
+				try {
+					connect.close();
+				} catch (SQLException e) {
+				}
+			}
+		}
+	}
+
+	private List<KdQuestion> of(List<QuestionVo> vos,List<QuestionVo> subvosList) {
+		List<KdQuestion> ret=new ArrayList<>();
+		Map<String,List<QuestionVo>> submap=new HashMap<>();
+		if(CollectionUtils.isNotEmpty(subvosList)) {
+			for(QuestionVo vo:subvosList) {
+				List<QuestionVo> tem=submap.get(vo.getPid());
+				if(tem==null) {
+					tem=new ArrayList<>();
+					submap.put(vo.getPid(), tem);
+				}
+				tem.add(vo);
+			}
+		}
+		for(QuestionVo vo:vos) {
+			KdQuestion q=of(vo);
+			ret.add(q);
+			if(QuesStructType.NESTED_ANSWER_QUESTION.equals(q.getQuesStructType())) {
+				List<QuestionVo> subvos=submap.get(q.getId());
+				q.setScore((double)subvos.size());
+				List<Double> subScores=new ArrayList<>();
+				List<KdQuestion> subQues=new ArrayList<>();
+				q.setSubScores(subScores);
+				q.setSubQuestions(subQues);
+				int num=0;
+				for(QuestionVo subvo:subvos) {
+					num++;
+					subScores.add(1.0);
+					KdQuestion subq=of(subvo);
+					subq.setId(null);
+					if(CusQuesStructType.cloze.equals(q.getCusType())&&StringUtils.isBlank(subq.getBody())) {
+						subq.setBody("___"+num+"___");
+					}
+					subQues.add(subq);
+				}
+				if(CusQuesStructType.cloze.equals(q.getCusType())) {
+					q.setBody(changeCloze(q.getBody()));
+				}
+			}
+		}
+		return ret;
+	}
+	
+	private String changeCloze(String text) {
+		StringBuffer buffer = new StringBuffer();
+        String regex = "<fillblank/>";
+
+        Pattern pattern = Pattern.compile(regex);
+        Matcher matcher = pattern.matcher(text);
+        // 使用find()方法查找匹配项
+        int num=0;
+        while (matcher.find()) {
+        	num++;
+        	matcher.appendReplacement(buffer, "___"+num+"___");
+        }
+        matcher.appendTail(buffer);
+        return buffer.toString();
+	}
+	
+	private KdQuestion of(QuestionVo vo) {
+		KdQuestion q=new KdQuestion();
+		q.setCusType(vo.getqType());
+		q.setQuesStructType(QuesStructType.getQuesStructTypeById(vo.getqType().getTypeId()));
+		if(QuesStructType.SINGLE_ANSWER_QUESTION.equals(q.getQuesStructType())) {
+			List<KdQuesOption> options=new ArrayList<>();
+			q.setOptions(options);
+			int num=0;
+			boolean cel=false;
+			for(String a:vo.getAnswer().getSubArea()) {
+				num++;
+				KdQuesOption o=new KdQuesOption();
+				options.add(o);
+				o.setNumber(num);
+				o.setBody(a);
+				o.setSelect(vo.getAnswer().getAnswer().contains(""+(num-1)));
+				if(o.getSelect()) {
+					cel=true;
+				}
+			}
+			if(!cel) {
+				throw new StatusException("没有答案");
+			}
+		}
+		if(!QuesStructType.NESTED_ANSWER_QUESTION.equals(q.getQuesStructType())) {
+			q.setAnswer(StringUtils.join(vo.getAnswer().getAnswer(),""));
+		}
+		q.setPid(vo.getPid());
+		q.setPname(vo.getPname());
+		q.setTname(vo.getTname());
+		q.setCname(vo.getCname());
+		q.setTypeId(vo.getTypeId());
+		q.setDetailName(vo.getTypeName());
+		q.setBody(vo.getBody());
+		if("101-204".equals(q.getTname())) {
+			q.setDifficulty(YunkaiDifficulty.JIAORONGYI);
+		}else if("301-404".equals(q.getTname())) {
+			q.setDifficulty(YunkaiDifficulty.ZHONGDENG);
+		}else if("501-504".equals(q.getTname())) {
+			q.setDifficulty(YunkaiDifficulty.JIAONAN);
+		}else {
+			if(StringUtils.isBlank(q.getPid())) {
+				throw new StatusException("错误");
+			}
+		}
+		q.setHaveAudio(false);
+		q.setId(vo.getQid());
+		q.setScore(1.0);
+		return q;
+	}
+
+	private List<QuestionVo> getQuestion(Connection connect, String courseCode) throws SQLException, IOException {
+		List<QuestionVo> qs = new ArrayList<>();
+		PreparedStatement preState = null;
+		ResultSet resultSet = null;
+		try {
+			String sql = " select p.name pname,t.name tname,c.name cname, "
+					+" q.TYPE_ID typeId,f.name typeName,f.ANSWER_TYPE qType "
+					+" ,q.ID qid,q.TITLE body,q.FATHER_ID pid  "
+					+" ,q.answer,q.SHOW_ORDER seq    "
+					+" from pe_question_bank t  "
+					+" INNER JOIN pe_question_bank p on p.id=t.parent_id "
+					+" INNER JOIN pe_question_bank c on c.parent_id=t.id "
+					+" INNER JOIN pe_questions q on c.id=q.BANK_ID "
+					+" INNER JOIN pe_question_type f on f.id=q.TYPE_ID "
+					+" where t.name in('101-204','301-404','501-504') and c.name in('难度:1','难度:2') "
+					+" order by p.name,t.name,c.name ";
+
+			preState = connect.prepareStatement(sql);
+
+			resultSet = preState.executeQuery();
+
+			while (resultSet.next()) {
+				QuestionVo q = new QuestionVo();
+				q.setPname(resultSet.getString("pname"));
+				q.setTname(resultSet.getString("tname"));
+				q.setCname(resultSet.getString("cname"));
+				q.setQid(resultSet.getString("qid"));
+				q.setTypeId(resultSet.getString("typeId"));
+				q.setTypeName(resultSet.getString("typeName"));
+				q.setPid(resultSet.getString("pid"));
+				q.setqType(CusQuesStructType.valueOf(resultSet.getString("qType")));
+				q.setBody(disposeImg(resultSet.getString("body"), courseCode));
+				q.setAnswer(JSONObject.parseObject(resultSet.getString("answer"), AnswerVo.class));
+				q.setSeq(resultSet.getInt("seq"));
+				qs.add(q);
+			}
+			return qs;
+		} finally {
+			if (resultSet != null) {
+				resultSet.close();
+			}
+			if (preState != null) {
+				preState.close();
+			}
+		}
+	}
+
+	private List<QuestionVo> getSubQuestion(Connection connect, String courseCode, List<String> pids)
+			throws SQLException, IOException {
+		List<QuestionVo> qs = new ArrayList<>();
+		PreparedStatement preState = null;
+		ResultSet resultSet = null;
+		try {
+			String sql = " select f.name typeName,f.ANSWER_TYPE qType " + " ,q.ID qid,q.TITLE body,q.FATHER_ID pid "
+					+ " ,q.answer,q.SHOW_ORDER seq  " + " from  pe_questions q  "
+					+ " INNER JOIN pe_question_type f on f.id=q.TYPE_ID " + " where q.FATHER_ID in ('"
+					+ StringUtils.join(pids, "','") + "') order by q.SHOW_ORDER";
+
+			preState = connect.prepareStatement(sql);
+
+			resultSet = preState.executeQuery();
+
+			while (resultSet.next()) {
+				QuestionVo q = new QuestionVo();
+				q.setQid(resultSet.getString("qid"));
+				q.setTypeName(resultSet.getString("typeName"));
+				q.setPid(resultSet.getString("pid"));
+				q.setqType(CusQuesStructType.valueOf(resultSet.getString("qType")));
+				q.setBody(disposeImg(resultSet.getString("body"), courseCode));
+				q.setAnswer(JSONObject.parseObject(resultSet.getString("answer"), AnswerVo.class));
+				q.setSeq(resultSet.getInt("seq"));
+				qs.add(q);
+			}
+			return qs;
+		} finally {
+			if (resultSet != null) {
+				resultSet.close();
+			}
+			if (preState != null) {
+				preState.close();
+			}
+		}
+	}
+
+	private String disposeImg(String str, String courseCode) {
+		if (StringUtils.isBlank(str)) {
+			return str;
+		}
+		Matcher matcher = imgPat.matcher(str);
+		Map<String, String> srcMap = new HashMap<>();
+		while (matcher.find()) {
+			String imgSrc = matcher.group(1).trim();
+			if (imgSrc.toLowerCase().trim().startsWith("http")) {
+				if (srcMap.get(imgSrc) == null) {
+					String suff = imgSrc.substring(imgSrc.lastIndexOf(".") + 1).toLowerCase();
+					File img = new File(paperDir + courseCode + "/" + UUID.randomUUID() + "." + suff);
+					FileUtil.saveUrlAs(imgSrc, img.getAbsolutePath());
+					String base64 = FileUtil.fileToBase64Src(img);
+					img.delete();
+					srcMap.put(imgSrc, base64);
+				}
+			}
+		}
+		for (String imgSrc : srcMap.keySet()) {
+			str = str.replaceAll(imgSrc, srcMap.get(imgSrc));
+		}
+		return str;
+	}
+
+
+	private void exportPaper(Connection connect, PaperExportDto dto) throws Exception {
+		List<QuestionVo> vos = getQuestion(connect, dto.getCourseCode());
+		if (CollectionUtils.isEmpty(vos)) {
+			return;
+		}
+		List<String> pids = vos.stream().filter(e -> e.getqType().getTypeId() == 6).map(QuestionVo::getQid)
+				.collect(Collectors.toList());
+		List<QuestionVo> subvos = getSubQuestion(connect, dto.getCourseCode(),pids);
+		List<KdQuestion> qs=of(vos,subvos);
+//		fillProp(connect, qs);
+//		fillAnswer(connect, qs, dto.getCourseCode());
+
+		Map<DetailDto2, List<KdQuestion>> qmap = new HashMap<>();
+		for (KdQuestion q : qs) {
+			DetailDto2 tem=new DetailDto2(q.getPname(),q.getTname());
+			List<KdQuestion> list = qmap.get(tem);
+			if (list == null) {
+				list = new ArrayList<>();
+				qmap.put(tem, list);
+			}
+			list.add(q);
+		}
+		for (DetailDto2 qt : qmap.keySet()) {
+			createPapers(qmap.get(qt), qt, dto);
+		}
+	}
+
+	private void createPapers(List<KdQuestion> qs, DetailDto2 qt, PaperExportDto dto) {
+		if (qs == null || qs.size() == 0) {
+			return;
+		}
+		if (qs.size() <= maxqc) {
+			createPaper(qs, qt, dto, 1);
+		} else {
+			int size = qs.size();
+			int len = maxqc;
+			int count = (size + len - 1) / len;
+
+			for (int i = 0; i < count; i++) {
+				List<KdQuestion> subList = qs.subList(i * len, ((i + 1) * len > size ? size : len * (i + 1)));
+				createPaper(subList, qt, dto, i + 1);
+			}
+		}
+
+	}
+
+	private void createPaper(List<KdQuestion> qs, DetailDto2 qt, PaperExportDto dto, int indx) {
+		if (qs.size() == 0) {
+			return;
+		}
+		double score=0.0;
+		int unit=0;
+		for(KdQuestion q:qs) {
+			if(CollectionUtils.isNotEmpty(q.getSubQuestions())) {
+				unit=unit+q.getSubQuestions().size();
+			}else {
+				unit++;
+			}
+			score=Calculator.add(score, q.getScore(),1);
+		}
+		String detailName = qt.getPname();
+		KdPaper paper = new KdPaper();
+		paper.setDetailCount(1);
+		paper.setUnitCount(unit);
+		paper.setTotalScore(score);
+		paper.setName(dto.getPaperSuff() + qt.getPname()+qt.getTname() + "_" + indx);
+		paper.setCourseCode(dto.getCourseCode());
+		List<KdDetail> des = new ArrayList<>();
+		KdDetail d = new KdDetail();
+		d.setName(detailName);
+		d.setNumber(1);
+		d.setQuestionCount(unit);
+		d.setTotalScore(score);
+		d.setQuestions(qs);
+		des.add(d);
+		paper.setDetails(des);
+		paper.setDetailCount(1);
+		paper.setUnitCount(qs.size());
+		try {
+			File paperdir = new File(paperDir + dto.getCourseCode() + "/" + MD5Util.encoder(qt.getPname()+qt.getTname())+ "/");
+			paperdir.mkdirs();
+			FileUtil.writeFile(paperdir.getAbsolutePath(), "/paper_" + indx + ".json", JSONObject.toJSONString(paper));
+		} catch (IOException e) {
+			throw new RuntimeException(e);
+		} catch (NoSuchAlgorithmException e) {
+			throw new RuntimeException(e);
+		}
+	}
+
+	@Override
+	public void initResult() {
+
+	}
+}

+ 70 - 0
src/main/java/cn/com/qmth/export/MyProducer2.java

@@ -0,0 +1,70 @@
+package cn.com.qmth.export;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.LinkedHashSet;
+import java.util.Map;
+
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+import org.apache.poi.xssf.usermodel.XSSFRow;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+
+public class MyProducer2 extends Producer {
+	private static Logger logger = LogManager.getLogger(MyProducer2.class);
+	private static String dir = "d:/guangkai/";
+	private static String paperDir = "d:/guangkai/paper/";
+
+	@Override
+	protected void produce(Map<String, Object> param) throws Exception {
+		logger.info("***************************任务生产开始");
+		String paperSuff = (String)param.get("paperSuff");
+		String dbName = (String)param.get("dbName");
+		File excelFolder = new File(paperDir);
+		if (excelFolder.exists()) {
+			FileUtil.clearDirectory(paperDir);
+		} else {
+			excelFolder.mkdirs();
+		}
+		LinkedHashSet<String> cs = readSubject();
+		if (CollectionUtils.isEmpty(cs)) {
+			logger.debug("无数据导出");
+			return;
+		} else {
+			logger.debug(cs.size() + "个课程");
+		}
+		for (String c : cs) {
+			offer(new PaperExportDto(c, paperSuff,dbName));
+		}
+		logger.info("***************************任务生产结束");
+	}
+	
+	
+	private static LinkedHashSet<String> readSubject() {
+		LinkedHashSet<String> list = new LinkedHashSet<>();
+		XSSFWorkbook wb = null;
+		try {
+			wb = new XSSFWorkbook(dir + "subject_info.xlsx");
+			XSSFSheet sheet = wb.getSheetAt(0);
+			int rows = sheet.getLastRowNum();
+			for (int i = 1; i <= rows; i++) {
+				XSSFRow row = sheet.getRow(i);
+				String yunkaiCode = row.getCell(1).getStringCellValue().trim();
+				list.add(yunkaiCode);
+			}
+		} catch (IOException e) {
+			throw new RuntimeException(e);
+		} finally {
+			if (wb != null) {
+				try {
+					wb.close();
+				} catch (IOException e) {
+				}
+			}
+		}
+		return list;
+	}
+}

+ 27 - 0
src/main/java/cn/com/qmth/export/QuestionVo.java

@@ -1,6 +1,9 @@
 package cn.com.qmth.export;
 
 public class QuestionVo {
+	private String pname;
+	private String tname;
+	private String cname;
 	private String typeId;
 	private String typeName;
 	private CusQuesStructType qType;
@@ -74,4 +77,28 @@ public class QuestionVo {
 		this.typeId = typeId;
 	}
 
+	public String getPname() {
+		return pname;
+	}
+
+	public void setPname(String pname) {
+		this.pname = pname;
+	}
+
+	public String getTname() {
+		return tname;
+	}
+
+	public void setTname(String tname) {
+		this.tname = tname;
+	}
+
+	public String getCname() {
+		return cname;
+	}
+
+	public void setCname(String cname) {
+		this.cname = cname;
+	}
+
 }