|
@@ -1,51 +1,127 @@
|
|
|
package com.github.zuihou.business.util;
|
|
|
|
|
|
-import org.apache.commons.lang3.StringUtils;
|
|
|
-import org.slf4j.Logger;
|
|
|
-import org.slf4j.LoggerFactory;
|
|
|
+import com.github.zuihou.business.util.qRcode.Image2Zpl;
|
|
|
+import com.github.zuihou.business.util.qRcode.ImageProducerUtil;
|
|
|
+import com.github.zuihou.business.util.qRcode.TwoDimensionCode;
|
|
|
+import lombok.Data;
|
|
|
|
|
|
import javax.print.*;
|
|
|
import javax.print.attribute.standard.PrinterName;
|
|
|
+import java.awt.image.BufferedImage;
|
|
|
import java.io.File;
|
|
|
import java.io.FileInputStream;
|
|
|
import java.io.IOException;
|
|
|
import java.io.UnsupportedEncodingException;
|
|
|
|
|
|
|
|
|
+@Data
|
|
|
public class ZplPrinter {
|
|
|
- private static Logger log = LoggerFactory.getLogger(ZplPrinter.class);
|
|
|
- private String printerURI = null; //打印机完整路径
|
|
|
- private PrintService printService = null; //打印机服务
|
|
|
- private byte[] font;
|
|
|
- private String darkness = "~SD22"; //设置色带颜色的深度 0~30
|
|
|
- private String width = "^PW1200"; //打印宽度 0~1500
|
|
|
- private String begin = "^XA" + darkness + width; //标签格式以^XA开始
|
|
|
- private String end = "^XZ";
|
|
|
- private String content = ""; //打印内容
|
|
|
- private String message = ""; //打印的结果信息
|
|
|
+ private String printerURI = null;// 打印机完整路径
|
|
|
+ private PrintService printService = null;// 打印机服务
|
|
|
+ private byte[] dotFont;
|
|
|
+ private String begin = "^XA"; // 标签格式以^XA开始
|
|
|
+ private String end = "^XZ"; // 标签格式以^XZ结束
|
|
|
+ private String content = "";
|
|
|
+
|
|
|
+ public static void main(String[] args) {
|
|
|
+
|
|
|
+ ZplPrinter p = new ZplPrinter("\\\\192.168.11.247\\ZDesigner ZT210-200dpi ZPL");
|
|
|
+ String zpl2 = p.getZpl();
|
|
|
+
|
|
|
+ printBarcode(p,"K&DD_202221390963&TASK_20222139490279&kT_DH001&KT001&000002");
|
|
|
+ boolean result2 = p.print(zpl2);
|
|
|
+ System.out.println("result2=======" + result2);
|
|
|
+
|
|
|
+
|
|
|
+ // printBarcode();
|
|
|
+ // printQRCOde();
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ public static boolean printBarcode(ZplPrinter p,String uniqueCode){
|
|
|
+ String zpl2 = "";
|
|
|
+ try {
|
|
|
+ //String uniqueCode = "K&DD_202221390963&TASK_20222139490279&kT_DH001&KT001&000002";
|
|
|
+ BufferedImage labelImg = ImageProducerUtil.createImage(uniqueCode);
|
|
|
+ zpl2 = Image2Zpl.image2Zpl2(labelImg);
|
|
|
+ System.out.println("zpl2======="+zpl2);
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ return p.print(zpl2);
|
|
|
+ }
|
|
|
+ public static void printBarcode() {
|
|
|
+ String electronicCode = "123457FFFFEEEB";
|
|
|
+
|
|
|
+ ZplPrinter zplPrinter = new ZplPrinter("\\\\192.168.11.247\\ZDesigner ZT210-200dpi ZPL");
|
|
|
+ String productName = "product.getName";
|
|
|
+ productName = productName.replace(",", ",");
|
|
|
+ productName = productName.replace("(", "(");
|
|
|
+ productName = productName.replace(")", ")");
|
|
|
+ productName = productName.replace("×", "*");
|
|
|
+ productName = "product.getName";
|
|
|
+ if (productName.length() < 25) {
|
|
|
+ zplPrinter.setText(productName, 15, 10, 25, 25, 15, 1, 1, 24);
|
|
|
+ } else if (productName.length() > 25) {
|
|
|
+ if (productName.length() > 50) {
|
|
|
+ productName = productName.substring(0, 50) + "...";
|
|
|
+ }
|
|
|
+ zplPrinter.setText(productName.substring(0, 25), 15, 10, 25, 25, 15, 1, 1, 24);
|
|
|
+ zplPrinter.setText(productName.substring(25, productName.length()), 15, 40, 25, 25, 15, 1, 1, 24);
|
|
|
+ }
|
|
|
+ String bar0Zpl = "^FO25,80^BY3,3.0,150^BCN,,Y,N,N^FD${data}^FS";//条码样式模板
|
|
|
+ zplPrinter.setBarcode(electronicCode, bar0Zpl);
|
|
|
+ System.out.println(zplPrinter.getZpl());
|
|
|
+ zplPrinter.print(zplPrinter.getZpl());
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void printQRCOde() {
|
|
|
+ // 打印二维码
|
|
|
+ String stockCode = "123457FFFFEEEB";
|
|
|
+
|
|
|
+ ZplPrinter codeZplPrinter = new ZplPrinter("\\\\192.168.11.247\\ZDesigner ZT210-200dpi ZPL");
|
|
|
+ TwoDimensionCode handler = new TwoDimensionCode();
|
|
|
+ BufferedImage bufferedImage = handler.encoderQRCode(stockCode, "png", 9);
|
|
|
+ String codeBegin = Image2Zpl.image2Zpl(bufferedImage);
|
|
|
+
|
|
|
+ codeZplPrinter.setBegin(codeZplPrinter.getBegin() + codeBegin);
|
|
|
+ codeZplPrinter.setContent(codeZplPrinter.getContent() + "^FO50,70^XG" + Image2Zpl.imgLength + ",1,1^FS\n");
|
|
|
+
|
|
|
+ codeZplPrinter.setChar(stockCode, 250, 135, 22, 22);
|
|
|
+
|
|
|
+// content += "^PQ2";//打印2张
|
|
|
+ codeZplPrinter.print(codeZplPrinter.getZpl());
|
|
|
+
|
|
|
+ codeZplPrinter.print(codeZplPrinter.getZpl());
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
|
|
|
/**
|
|
|
* 构造方法
|
|
|
+ *
|
|
|
+ * @param printerURI 打印机路径
|
|
|
*/
|
|
|
public ZplPrinter(String printerURI) {
|
|
|
this.printerURI = printerURI;
|
|
|
- //加载字体
|
|
|
+ // 加载点阵字库 汉字需要
|
|
|
String relativelyPath = System.getProperty("user.dir");
|
|
|
File file = new File(relativelyPath + "//ts24.lib");
|
|
|
if (file.exists()) {
|
|
|
FileInputStream fis;
|
|
|
try {
|
|
|
fis = new FileInputStream(file);
|
|
|
- font = new byte[fis.available()];
|
|
|
- fis.read(font);
|
|
|
+ dotFont = new byte[fis.available()];
|
|
|
+ fis.read(dotFont);
|
|
|
fis.close();
|
|
|
- } catch (Exception e) {
|
|
|
- log.info(e.getMessage());
|
|
|
+ } catch (IOException e) {
|
|
|
+ e.printStackTrace();
|
|
|
}
|
|
|
} else {
|
|
|
- log.info("D://lib//ts24.lib 文件不存在");
|
|
|
+ System.out.println("d://ts24.lib文件不存在");
|
|
|
}
|
|
|
- //初始化打印机
|
|
|
+ // 初始化打印机
|
|
|
PrintService[] services = PrintServiceLookup.lookupPrintServices(null, null);
|
|
|
if (services != null && services.length > 0) {
|
|
|
for (PrintService service : services) {
|
|
@@ -56,27 +132,28 @@ public class ZplPrinter {
|
|
|
}
|
|
|
}
|
|
|
if (printService == null) {
|
|
|
- log.info("没有找到打印机:[" + printerURI + "]");
|
|
|
+ System.out.println("没有找到打印机:[" + printerURI + "]");
|
|
|
+ // 循环出所有的打印机
|
|
|
if (services != null && services.length > 0) {
|
|
|
- log.info("可用的打印机列表:");
|
|
|
+ System.out.println("可用的打印机列表:");
|
|
|
for (PrintService service : services) {
|
|
|
- log.info("[" + service.getName() + "]");
|
|
|
+ System.out.println("[" + service.getName() + "]");
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
|
- log.info("找到打印机:[" + printerURI + "]");
|
|
|
- log.info("打印机名称:[" + printService.getAttribute(PrinterName.class).getValue() + "]");
|
|
|
+ System.out.println("找到打印机:[" + printerURI + "]");
|
|
|
+ System.out.println("打印机名称:[" + printService.getAttribute(PrinterName.class).getValue() + "]");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 设置条形码
|
|
|
*
|
|
|
- * @param barCode 条码字符
|
|
|
+ * @param barcode 条码字符
|
|
|
* @param zpl 条码样式模板
|
|
|
*/
|
|
|
- public void setBarCode(String barCode, String zpl) {
|
|
|
- content += zpl.replace("${data}", barCode);
|
|
|
+ public void setBarcode(String barcode, String zpl) {
|
|
|
+ content += zpl.replace("${data}", barcode);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -95,38 +172,31 @@ public class ZplPrinter {
|
|
|
public void setText(String str, int x, int y, int eh, int ew, int es, int mx, int my, int ms) {
|
|
|
byte[] ch = str2bytes(str);
|
|
|
for (int off = 0; off < ch.length; ) {
|
|
|
- if (((int) ch[off] & 0x00ff) >= 0xA0) {//中文字符
|
|
|
- try {
|
|
|
- int qcode = ch[off] & 0xff;
|
|
|
- int wcode = ch[off + 1] & 0xff;
|
|
|
- content += String.format("^FO%d,%d^XG0000%01X%01X,%d,%d^FS\n", x, y, qcode, wcode, mx, my);
|
|
|
- begin += String.format("~DG0000%02X%02X,00072,003,\n", qcode, wcode);
|
|
|
- qcode = (qcode + 128 - 32) & 0x00ff;
|
|
|
- wcode = (wcode + 128 - 32) & 0x00ff;
|
|
|
- int offset = ((int) qcode - 16) * 94 * 72 + ((int) wcode - 1) * 72;
|
|
|
- for (int j = 0; j < 72; j += 3) {
|
|
|
- qcode = (int) font[j + offset] & 0x00ff;
|
|
|
- wcode = (int) font[j + offset + 1] & 0x00ff;
|
|
|
- int qcode1 = (int) font[j + offset + 2] & 0x00ff;
|
|
|
- begin += String.format("%02X%02X%02X\n", qcode, wcode, qcode1);
|
|
|
- }
|
|
|
- x = x + ms * mx;
|
|
|
- off = off + 2;
|
|
|
- } catch (Exception e) {
|
|
|
- e.printStackTrace();
|
|
|
- //替换成X号
|
|
|
- setChar("X", x, y, eh, ew);
|
|
|
- x = x + es;//注意间距更改为英文字符间距
|
|
|
- off = off + 2;
|
|
|
+ if (((int) ch[off] & 0x00ff) >= 0xA0) {//ASCII码值"0xa0"表示汉字的开始
|
|
|
+ int qcode = ch[off] & 0xff;
|
|
|
+ int wcode = ch[off + 1] & 0xff;
|
|
|
+ content += String.format("^FO%d,%d^XG0000%01X%01X,%d,%d^FS\n", x, y, qcode, wcode, mx, my);
|
|
|
+ begin += String.format("~DG0000%02X%02X,00072,003,\n", qcode, wcode);
|
|
|
+ qcode = (qcode + 128 - 32) & 0x00ff;//区码:或qcode = (qcode - 128 - 32) & 0x00ff;(一般这样用)可达到减去0xA0的效果
|
|
|
+ wcode = (wcode + 128 - 32) & 0x00ff;//位码:或wcode = (wcode - 128 - 32) & 0x00ff;(一般这样用)可达到减去0xA0的效果
|
|
|
+ int offset = ((int) qcode - 16) * 94 * 72 + ((int) wcode - 1) * 72;//偏移量是指字模首字节距离文件头的相对位置
|
|
|
+ for (int j = 0; j < 72; j += 3) {
|
|
|
+ qcode = (int) dotFont[j + offset] & 0x00ff;
|
|
|
+ wcode = (int) dotFont[j + offset + 1] & 0x00ff;
|
|
|
+ int qcode1 = (int) dotFont[j + offset + 2] & 0x00ff;
|
|
|
+ begin += String.format("%02X%02X%02X\n", qcode, wcode, qcode1);//X --- 以十六进制显示,不足两位则补零
|
|
|
}
|
|
|
- } else if (((int) ch[off] & 0x00FF) < 0xA0) {//英文字符
|
|
|
+ x = x + ms * mx;
|
|
|
+ off = off + 2;//中文包含两个字节
|
|
|
+ } else if (((int) ch[off] & 0x00FF) < 0xA0) {
|
|
|
setChar(String.format("%c", ch[off]), x, y, eh, ew);
|
|
|
x = x + es;
|
|
|
- off++;
|
|
|
+ off++;//英文包含一个字节
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+
|
|
|
/**
|
|
|
* 英文字符串(包含数字)
|
|
|
*
|
|
@@ -140,17 +210,54 @@ public class ZplPrinter {
|
|
|
content += "^FO" + x + "," + y + "^A0," + h + "," + w + "^FD" + str + "^FS";
|
|
|
}
|
|
|
|
|
|
+
|
|
|
/**
|
|
|
- * 重置ZPL指令,多张标签同时打印时需要调用
|
|
|
+ * BQ 二维码 ^BQa,b,c,d,e
|
|
|
+ *
|
|
|
+ * @param data
|
|
|
+ * @param x x坐标
|
|
|
+ * @param y y坐标
|
|
|
+ * @param b 模型 默认值:2(增强) 推荐 其他值:1
|
|
|
+ * @param c 放大倍数 默认值:1在150 dpi打印机 2在200 dpi打印机 3在300 dpi打印机 其他值:4至10
|
|
|
+ * @param d 校验等级,H Q M L L级:约可纠错7%的数据码字 M级:约可纠错15%的数据码字 Q级:约可纠错25%的数据码字
|
|
|
+ * H级:约可纠错30%的数据码字
|
|
|
*/
|
|
|
- public void resetZpl() {
|
|
|
- begin = "^XA" + darkness + width;
|
|
|
- end = "^XZ";
|
|
|
- content = "";
|
|
|
+ public void setCodeByBQ(String data, int x, int y, int b, int c, String d) {
|
|
|
+ content += "^FT" + x + "," + y + "^BQ," + b + "," + c + "," + d + "^FDQA," + data + "^FS";
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 打印方框
|
|
|
+ * ^FO10,10\n^GB50,760,3,B^FS
|
|
|
+ *
|
|
|
+ * @param x x坐标
|
|
|
+ * @param y y坐标
|
|
|
+ * @param w 方框宽度
|
|
|
+ * @param h 方框高度
|
|
|
+ * @param t 线宽
|
|
|
+ */
|
|
|
+ public void setBox(int x, int y, int w, int h, int t) {
|
|
|
+ content += "^FO" + x + "," + y + "^GB" + w + "," + h + "," + t + "^FS";
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 英文字符(包含数字)顺时针旋转90度
|
|
|
+ *
|
|
|
+ * @param str 英文字符串
|
|
|
+ * @param x x坐标
|
|
|
+ * @param y y坐标
|
|
|
+ * @param h 高度
|
|
|
+ * @param w 宽度
|
|
|
+ */
|
|
|
+ public void setCharR(String str, int x, int y, int h, int w) {
|
|
|
+ content += "^FO" + x + "," + y + "^A0R," + h + "," + w + "^FD" + str + "^FS";
|
|
|
}
|
|
|
|
|
|
+
|
|
|
/**
|
|
|
- * 获取完整的ZPL指令
|
|
|
+ * 获取完整的ZPL
|
|
|
*
|
|
|
* @return
|
|
|
*/
|
|
@@ -159,22 +266,12 @@ public class ZplPrinter {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 字符串转换为byte[]
|
|
|
- *
|
|
|
- * @param s
|
|
|
- * @return
|
|
|
+ * 重置ZPL指令,当需要打印多张纸的时候需要调用。
|
|
|
*/
|
|
|
- private byte[] str2bytes(String s) {
|
|
|
- if (null == s || "".equals(s)) {
|
|
|
- return null;
|
|
|
- }
|
|
|
- byte[] abytes = null;
|
|
|
- try {
|
|
|
- abytes = s.getBytes("gb2312");
|
|
|
- } catch (UnsupportedEncodingException ex) {
|
|
|
- ex.printStackTrace();
|
|
|
- }
|
|
|
- return abytes;
|
|
|
+ public void resetZpl() {
|
|
|
+ begin = "^XA";
|
|
|
+ end = "^XZ";
|
|
|
+ content = "";
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -184,7 +281,7 @@ public class ZplPrinter {
|
|
|
*/
|
|
|
public boolean print(String zpl) {
|
|
|
if (printService == null) {
|
|
|
- log.info("打印出错:没有找到打印机[" + printerURI + "]");
|
|
|
+ System.out.println("打印出错:没有找到打印机:[" + printerURI + "]");
|
|
|
return false;
|
|
|
}
|
|
|
DocPrintJob job = printService.createPrintJob();
|
|
@@ -193,83 +290,32 @@ public class ZplPrinter {
|
|
|
Doc doc = new SimpleDoc(by, flavor, null);
|
|
|
try {
|
|
|
job.print(doc, null);
|
|
|
- log.info("已打印");
|
|
|
+ System.out.println("已打印");
|
|
|
return true;
|
|
|
} catch (PrintException e) {
|
|
|
- log.info("打印出错:" + e.getMessage());
|
|
|
e.printStackTrace();
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- public static boolean printBarcode(ZplPrinter printer, String uniqueCode) {
|
|
|
- if (StringUtils.isNotEmpty(uniqueCode)) {
|
|
|
- String[] uniqueCodeArray = uniqueCode.split("&");
|
|
|
- if (uniqueCodeArray.length > 4) {
|
|
|
- printer.setChar("Order: " + uniqueCodeArray[0] + uniqueCodeArray[1], 40, 20, 30, 30);
|
|
|
- printer.setChar("Task: " + uniqueCodeArray[2], 40, 70, 30, 30);
|
|
|
- printer.setChar("SN0: " + uniqueCodeArray[3], 40, 120, 30, 30);
|
|
|
- printer.setChar("SN: " + uniqueCodeArray[4], 40, 170, 30, 30);
|
|
|
- printer.setText("生产日期: 2022-11-29", 40, 220, 30, 30, 20, 1, 1, 22);
|
|
|
- // printer.setText("生产日期:", 40, 220, 56, 56, 30, 2, 2, 24);
|
|
|
- // printer.setChar("2019", 120, 230, 40, 40);
|
|
|
- //条码
|
|
|
- // String data = "9Y203CCNW9A019396";//条码内容
|
|
|
- // String dataZpl = "^FO260,250^BY2,11.0,10,40^BCC,80,N^FD${data}^FS";//条码样式模板
|
|
|
- // printer.setBarcode(data, dataZpl);
|
|
|
- //二维码
|
|
|
- String ewm = "9Y203CCNW9A019396";//条码内容
|
|
|
- String ewmZpl = "^FO430,50^BQ,2,6^CI26^FH^FDQA^FD${data}^FS";//条码样式模板
|
|
|
- printer.setBarCode(ewm, ewmZpl);
|
|
|
- printer.resetZpl();
|
|
|
- printer.setText("批号:", 20, 550, 56, 56, 30, 2, 2, 24);
|
|
|
- printer.setChar("78787878788", 200, 560, 40, 40);
|
|
|
- //下边的条码
|
|
|
- String bar2 = "00000999990018822969";//20位
|
|
|
- String bar2Paper = "^FO260,250^BY2,3.0,66^BCN,,Y,N,N^FD${data}^FS";//条码样式模板
|
|
|
- printer.setBarCode(bar2, bar2Paper);
|
|
|
- String zpl = printer.getZpl();
|
|
|
- return printer.print(zpl);
|
|
|
- }
|
|
|
+ /**
|
|
|
+ * 字符串转byte[]
|
|
|
+ *
|
|
|
+ * @param s
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private static byte[] str2bytes(String s) {
|
|
|
+ if (null == s || "".equals(s)) {
|
|
|
+ return null;
|
|
|
}
|
|
|
- return false;
|
|
|
-
|
|
|
+ byte[] abytes = null;
|
|
|
+ try {
|
|
|
+ abytes = s.getBytes("gb2312");
|
|
|
+ } catch (UnsupportedEncodingException ex) {
|
|
|
+ ex.printStackTrace();
|
|
|
+ }
|
|
|
+ return abytes;
|
|
|
}
|
|
|
|
|
|
- public static void main(String[] args) {
|
|
|
-// ZplPrinter printer = new ZplPrinter("\\\\192.168.11.247\\ZDesigner ZT210-200dpi ZPL");
|
|
|
-// printBarcode(printer, "K&DD_202221390963&TASK_20222139490279&kT_DH001&KT001&000002");
|
|
|
- ZplPrinter printer = new ZplPrinter("\\\\192.168.11.247\\ZDesigner ZT210-200dpi ZPL");
|
|
|
- /**
|
|
|
- * 文本
|
|
|
- */
|
|
|
- printer.setChar("SN: 9Y203CCNW9A19396", 40, 20, 30, 30);
|
|
|
- printer.setChar("MAC: 74EE2AEB1A52", 40, 70, 30, 30);
|
|
|
- printer.setChar("DID: 9FCNY21EZJ460B190916", 40, 120, 30, 30);
|
|
|
- printer.setChar("CMIIT: 2016DP9142", 40, 170, 30, 30);
|
|
|
-// printer.setText("生产日期:2019", 40, 220 ,30, 30, 20, 1 , 1, 22);
|
|
|
-// printer.setText("生产日期:", 40, 220, 56, 56, 30, 2, 2, 24);
|
|
|
-// printer.setChar("2019", 120, 230, 40, 40);
|
|
|
- //条码
|
|
|
-// String data = "9Y203CCNW9A019396";//条码内容
|
|
|
-// String dataZpl = "^FO260,250^BY2,11.0,10,40^BCC,80,N^FD${data}^FS";//条码样式模板
|
|
|
-// printer.setBarcode(data, dataZpl);
|
|
|
- //二维码
|
|
|
- String ewm = "9Y203CCNW9A019396";//条码内容
|
|
|
- String ewmZpl = "^FO430,50^BQ,2,6^CI26^FH^FDQA^FD${data}^FS";//条码样式模板
|
|
|
- printer.setBarCode(ewm, ewmZpl);
|
|
|
- printer.resetZpl();
|
|
|
- printer.setText("批号:", 20, 550, 56, 56, 30, 2, 2, 24);
|
|
|
- printer.setChar("78787878788", 200, 560, 40, 40);
|
|
|
-// printer.setText("批号:", 20, 220, 56, 56, 30, 1, 1, 24);
|
|
|
-// printer.setChar("78787878788", 120, 230, 40, 40);
|
|
|
- //下边的条码
|
|
|
- String bar2 = "00000999990018822969";//20位
|
|
|
- String bar2Paper = "^FO260,250^BY2,3.0,66^BCN,,Y,N,N^FD${data}^FS";//条码样式模板
|
|
|
- printer.setBarCode(bar2, bar2Paper);
|
|
|
- String zpl = printer.getZpl();
|
|
|
-// System.out.println(zpl);
|
|
|
- printer.print(zpl);
|
|
|
- }
|
|
|
-}
|
|
|
|
|
|
+}
|