From dfaff98bbdfd59adf9cbc89e5a0a922a9ad5381f Mon Sep 17 00:00:00 2001 From: "Stormeye.Wu" Date: Thu, 18 Oct 2018 10:26:21 +0800 Subject: [PATCH] =?UTF-8?q?[=E6=A0=87=E7=AD=BE=E7=9F=AD=E4=BF=A1][?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D]:=E6=A0=87=E7=AD=BE=E7=9F=AD=E4=BF=A1code=20?= =?UTF-8?q?=E9=87=8D=E6=95=B4=EF=BC=8C=E5=8F=91=E9=80=81=E5=89=8D=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E7=96=B2=E5=8A=B3=E5=BA=A6=E6=A3=80=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iformall/schedule/MsgSendingSchedule.java | 53 +++------- .../service/impl/WxMallApplyServiceImpl.java | 41 +------- .../service/impl/WxMsgModelServiceImpl.java | 42 +------- .../service/impl/WxMsgServiceImpl.java | 53 ++++------ .../WxMsgValidationcodeModelServiceImpl.java | 42 +------- .../impl/WxMsgValidationcodeServiceImpl.java | 43 +-------- .../java/com/iformall/utils/WiwideUtil.java | 96 +++++++++++++++++++ 7 files changed, 137 insertions(+), 233 deletions(-) create mode 100644 mallinkService/src/main/java/com/iformall/utils/WiwideUtil.java diff --git a/mallinkAdmin/src/main/java/com/iformall/schedule/MsgSendingSchedule.java b/mallinkAdmin/src/main/java/com/iformall/schedule/MsgSendingSchedule.java index 4ddf08bb6..c561be095 100644 --- a/mallinkAdmin/src/main/java/com/iformall/schedule/MsgSendingSchedule.java +++ b/mallinkAdmin/src/main/java/com/iformall/schedule/MsgSendingSchedule.java @@ -1,13 +1,12 @@ package com.iformall.schedule; import com.alibaba.fastjson.JSONObject; -import com.iformall.common.ErrorCode; -import com.iformall.common.ResultData; -import com.iformall.domain.po.WxCUser; import com.iformall.domain.po.WxMsg; import com.iformall.domain.po.WxMsgConfig; +import com.iformall.exception.MallinkException; import com.iformall.mapper.WxMsgConfigMapper; import com.iformall.mapper.WxMsgMapper; +import com.iformall.service.PushLimitService; import com.iformall.utils.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -28,6 +27,9 @@ public class MsgSendingSchedule { @Autowired private WxMsgConfigMapper wxMsgConfigMapper; + @Autowired + private PushLimitService pushLimitService; + @Scheduled(cron = "0 1 * * * ?") // 每小时第一分钟执行 public void sendmsgschedule() { @@ -41,7 +43,15 @@ public class MsgSendingSchedule { List list = wxMsgMapper.findList(wxMsg); for(WxMsg msg:list){ - sendmsg(msg); + boolean checkTime = false; + try { + checkTime = pushLimitService.checkSendTime(wxMsg.getTenantId()); + } catch (MallinkException e) { + logger.error(e.getMessage()); + } + if (checkTime) { + sendmsg(msg); + } } logger.info("sendmsg定时任务结束"); @@ -77,40 +87,7 @@ public class MsgSendingSchedule { String signature = wxMsg.getSignature(); String msg = wxMsg.getMsg(); String notifyUrl = wxMsgConfig.getNotifyurl(); - TreeMap message = new TreeMap<>(); - message.put("bid", bid); - message.put("phone", phone); - message.put("signature", signature); - message.put("msg", msg); - message.put("notify_url", notifyUrl); - - StringBuilder sb = new StringBuilder(); - Set> entries = message.entrySet(); - for (Map.Entry entry : entries) { - sb.append(entry.getKey()).append("=").append(entry.getValue()); - } - sb.append("&secret=").append(secret); - String sign = HMACSHA256.sha256_HMAC(sb.toString(), secret); - message.put("sign", sign.toUpperCase()); - - String str32 = HMACSHA256.STR2; - String iv = HMACSHA256.IV; - - Map params = new HashMap<>(); - params.put("iv", iv); - params.put("bid", bid); - - try { - String data = AesUtil.AESEncode(str32, JSONObject.toJSONString(message), iv); - String sc = RsaUtil.RSAEncode(str32.getBytes(), publickey); - params.put("data", data); - params.put("sc", sc); - } catch (Exception e) { - e.printStackTrace(); - } - - String requestUrl = "https://webapp.wiwide.com/apisms/send"; - String result = HttpUtil.doPost(requestUrl, params); + String result = WiwideUtil.sendMsg(secret, bid, publickey, phone, signature, msg, notifyUrl); JSONObject jsonObjectResult = JSONObject.parseObject(result); String ret = jsonObjectResult.get("ret").toString(); diff --git a/mallinkService/src/main/java/com/iformall/service/impl/WxMallApplyServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/WxMallApplyServiceImpl.java index 146b9fb30..f148de060 100644 --- a/mallinkService/src/main/java/com/iformall/service/impl/WxMallApplyServiceImpl.java +++ b/mallinkService/src/main/java/com/iformall/service/impl/WxMallApplyServiceImpl.java @@ -16,10 +16,7 @@ import com.iformall.mapper.WxMsgConfigMapper; import com.iformall.mapper.WxMsgValidationcodeMapper; import com.iformall.mapper.WxMsgValidationcodeModelMapper; import com.iformall.service.WxMallApplyService; -import com.iformall.utils.AesUtil; -import com.iformall.utils.HMACSHA256; -import com.iformall.utils.HttpUtil; -import com.iformall.utils.RsaUtil; +import com.iformall.utils.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -121,41 +118,7 @@ public class WxMallApplyServiceImpl implements WxMallApplyService { wxMsgValidationcode.setMsg(msg); String notifyUrl = wxMsgConfig.getNotifyurl(); - TreeMap message = new TreeMap<>(); - message.put("bid", bid); - message.put("phone", phone); - message.put("signature", signature); - message.put("msg", msg); - message.put("notify_url", notifyUrl); - message.put("verifysms","1"); - - StringBuilder sb = new StringBuilder(); - Set> entries = message.entrySet(); - for (Map.Entry entry : entries) { - sb.append(entry.getKey()).append("=").append(entry.getValue()); - } - sb.append("&secret=").append(secret); - String sign = HMACSHA256.sha256_HMAC(sb.toString(), secret); - message.put("sign", sign.toUpperCase()); - - String str32 = HMACSHA256.STR2; - String iv = HMACSHA256.IV; - - Map params = new HashMap<>(); - params.put("iv", iv); - params.put("bid", bid); - - try { - String data = AesUtil.AESEncode(str32, JSONObject.toJSONString(message), iv); - String sc = RsaUtil.RSAEncode(str32.getBytes(), publickey); - params.put("data", data); - params.put("sc", sc); - } catch (Exception e) { - throw new RuntimeException("发送失败"); - } - - String requestUrl = "https://webapp.wiwide.com/apisms/send"; - String result = HttpUtil.doPost(requestUrl, params); + String result = WiwideUtil.sendMsg(secret, bid, publickey, phone, signature, msg, notifyUrl); JSONObject jsonObjectResult = JSONObject.parseObject(result); String ret = jsonObjectResult.get("ret").toString(); diff --git a/mallinkService/src/main/java/com/iformall/service/impl/WxMsgModelServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/WxMsgModelServiceImpl.java index 0a8c36e22..4fb6e1997 100644 --- a/mallinkService/src/main/java/com/iformall/service/impl/WxMsgModelServiceImpl.java +++ b/mallinkService/src/main/java/com/iformall/service/impl/WxMsgModelServiceImpl.java @@ -10,14 +10,10 @@ import com.iformall.common.ResultData; import com.iformall.domain.po.WxMsgConfig; import com.iformall.domain.po.WxMsgModel; import com.iformall.enums.EnumMsgModelStatus; -import com.iformall.exception.MallinkException; import com.iformall.mapper.WxMsgConfigMapper; import com.iformall.mapper.WxMsgModelMapper; import com.iformall.service.WxMsgModelService; -import com.iformall.utils.AesUtil; -import com.iformall.utils.HMACSHA256; -import com.iformall.utils.HttpUtil; -import com.iformall.utils.RsaUtil; +import com.iformall.utils.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -73,40 +69,8 @@ public class WxMsgModelServiceImpl implements WxMsgModelService { } } - //请求api数据排序 - TreeMap message = new TreeMap<>(); - message.put("bid", bid); - message.put("signature", signature); - message.put("content", content); - message.put("notify_url", wxMsgConfig.getModelnotifyurl()); - - StringBuilder sb = new StringBuilder(); - Set> entries = message.entrySet(); - for (Map.Entry entry : entries) { - sb.append(entry.getKey()).append("=").append(entry.getValue()); - } - sb.append("&secret=").append(secret); - String sign = HMACSHA256.sha256_HMAC(sb.toString(), secret); - message.put("sign", sign.toUpperCase()); - - String str32 = HMACSHA256.STR2; - String iv = HMACSHA256.IV; - - Map params = new HashMap<>(); - params.put("iv", iv); - params.put("bid", bid); - try { - String data = AesUtil.AESEncode(str32, JSONObject.toJSONString(message), iv); - String sc = RsaUtil.RSAEncode(str32.getBytes(), wxMsgConfig.getPublickey()); - params.put("data", data); - params.put("sc", sc); - } catch (Exception e) { - logger.info("短信AES/RSA解密失败"); - throw new MallinkException(ErrorCode.TEMPLATE_SEND_FAILED); - } - - String requestUrl = "https://webapp.wiwide.com/apisms/addtemplate"; - String result = HttpUtil.doPost(requestUrl, params); + String result = WiwideUtil.addTemplate(secret, bid, wxMsgConfig.getPublickey(), signature, + content, wxMsgConfig.getModelnotifyurl()); JSONObject jsonObjectResult = JSONObject.parseObject(result); String ret = jsonObjectResult.get("ret").toString(); if (ret.equals(EnumMsgModelStatus.SUCCESS.getCode().toString())) { diff --git a/mallinkService/src/main/java/com/iformall/service/impl/WxMsgServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/WxMsgServiceImpl.java index dd1f10636..a5435ac8b 100644 --- a/mallinkService/src/main/java/com/iformall/service/impl/WxMsgServiceImpl.java +++ b/mallinkService/src/main/java/com/iformall/service/impl/WxMsgServiceImpl.java @@ -20,6 +20,7 @@ import com.iformall.mapper.WxCUserBasicInfoMapper; import com.iformall.mapper.WxMsgCallbackMapper; import com.iformall.mapper.WxMsgConfigMapper; import com.iformall.mapper.WxMsgMapper; +import com.iformall.service.PushLimitService; import com.iformall.service.WxCUserTagsService; import com.iformall.service.WxMsgService; import com.iformall.utils.*; @@ -49,6 +50,9 @@ public class WxMsgServiceImpl implements WxMsgService { @Autowired WxMsgCallbackMapper wxMsgCallbackMapper; + @Autowired + PushLimitService pushLimitService; + @Override public PageInfo listAsPage(WxMsg record, Integer pageIndex, Integer pageSize) { PageHelper.startPage(pageIndex, pageSize); @@ -132,6 +136,12 @@ public class WxMsgServiceImpl implements WxMsgService { //是否立即发送 if (wxMsg.getIsright().equals(EnumMsgSend.MSG_SEND_IMMEDIATELY.getCode())) { wxMsg.setStatus(EnumMsgStatus.MSG_STATUS_SENDED.getCode()); + try { + pushLimitService.checkSendTime(wxMsg.getTenantId()); + } catch (MallinkException e) { + logger.error(e.getMessage()); + return new ResultData(e.getErrorCode(),e.getMessage()); + } return sendmsg(wxMsg); } else { wxMsg.setStatus(EnumMsgStatus.MSG_STATUS_NOT_SEND.getCode()); @@ -181,6 +191,12 @@ public class WxMsgServiceImpl implements WxMsgService { //是否立即发送 if (wxMsg.getIsright().equals(EnumMsgSend.MSG_SEND_IMMEDIATELY.getCode())) { wxMsg.setStatus(EnumMsgStatus.MSG_STATUS_SENDED.getCode()); + try { + pushLimitService.checkSendTime(wxMsg.getTenantId()); + } catch (MallinkException e) { + logger.error(e.getMessage()); + return new ResultData(e.getErrorCode(),e.getMessage()); + } return sendmsg(wxMsg); } else { //定时 @@ -245,41 +261,7 @@ public class WxMsgServiceImpl implements WxMsgService { String signature = wxMsg.getSignature(); String msg = wxMsg.getMsg(); String notifyUrl = wxMsgConfig.getNotifyurl(); - TreeMap message = new TreeMap<>(); - message.put("bid", bid); - message.put("phone", phone); - message.put("signature", signature); - message.put("msg", msg); - message.put("notify_url", notifyUrl); - - StringBuilder sb = new StringBuilder(); - Set> entries = message.entrySet(); - for (Map.Entry entry : entries) { - sb.append(entry.getKey()).append("=").append(entry.getValue()); - } - sb.append("&secret=").append(secret); - String sign = HMACSHA256.sha256_HMAC(sb.toString(), secret); - message.put("sign", sign.toUpperCase()); - - String str32 = HMACSHA256.STR2; - String iv = HMACSHA256.IV; - - Map params = new HashMap<>(); - params.put("iv", iv); - params.put("bid", bid); - - try { - String data = AesUtil.AESEncode(str32, JSONObject.toJSONString(message), iv); - String sc = RsaUtil.RSAEncode(str32.getBytes(), publickey); - params.put("data", data); - params.put("sc", sc); - } catch (Exception e) { - logger.info("短信AES/RSA解密失败"); - throw new MallinkException(ErrorCode.MSG_SEND_ERROR); - } - - String requestUrl = "https://webapp.wiwide.com/apisms/send"; - String result = HttpUtil.doPost(requestUrl, params); + String result = WiwideUtil.sendMsg(secret, bid, publickey, phone, signature, msg, notifyUrl); JSONObject jsonObjectResult = JSONObject.parseObject(result); String ret = jsonObjectResult.get("ret").toString(); String batchNo = jsonObjectResult.get("data").toString(); @@ -311,7 +293,6 @@ public class WxMsgServiceImpl implements WxMsgService { } - public void addMsgCallback(WxMsg wxmsg, String batchNo){ logger.info("营销短信发送时主动添加回调记录开始..."); String phones = wxmsg.getPhones(); diff --git a/mallinkService/src/main/java/com/iformall/service/impl/WxMsgValidationcodeModelServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/WxMsgValidationcodeModelServiceImpl.java index b20c466ac..1670523d2 100644 --- a/mallinkService/src/main/java/com/iformall/service/impl/WxMsgValidationcodeModelServiceImpl.java +++ b/mallinkService/src/main/java/com/iformall/service/impl/WxMsgValidationcodeModelServiceImpl.java @@ -10,14 +10,10 @@ import com.iformall.common.ResultData; import com.iformall.domain.po.WxMsgConfig; import com.iformall.domain.po.WxMsgValidationcodeModel; import com.iformall.enums.EnumMsgModelStatus; -import com.iformall.exception.MallinkException; import com.iformall.mapper.WxMsgConfigMapper; import com.iformall.mapper.WxMsgValidationcodeModelMapper; import com.iformall.service.WxMsgValidationcodeModelService; -import com.iformall.utils.AesUtil; -import com.iformall.utils.HMACSHA256; -import com.iformall.utils.HttpUtil; -import com.iformall.utils.RsaUtil; +import com.iformall.utils.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -75,42 +71,8 @@ public class WxMsgValidationcodeModelServiceImpl implements WxMsgValidationcodeM } } + String result = WiwideUtil.addTemplate(secret, bid, wxMsgConfig.getPublickey(), signature, content, wxMsgConfig.getModelnotifyurl()); - //请求api数据排序 - TreeMap message = new TreeMap<>(); - message.put("bid", bid); - message.put("signature", signature); - message.put("content", content); - message.put("notify_url",wxMsgConfig.getModelnotifyurl()); - message.put("verifysms","1"); - - StringBuilder sb = new StringBuilder(); - Set> entries = message.entrySet(); - for (Map.Entry entry : entries) { - sb.append(entry.getKey()).append("=").append(entry.getValue()); - } - sb.append("&secret=").append(secret); - String sign = HMACSHA256.sha256_HMAC(sb.toString(), secret); - message.put("sign", sign.toUpperCase()); - - String str32 = HMACSHA256.STR2; - String iv = HMACSHA256.IV; - - Map params = new HashMap<>(); - params.put("iv", iv); - params.put("bid", bid); - try { - String data = AesUtil.AESEncode(str32, JSONObject.toJSONString(message), iv); - String sc = RsaUtil.RSAEncode(str32.getBytes(), wxMsgConfig.getPublickey()); - params.put("data", data); - params.put("sc", sc); - } catch (Exception e) { - logger.info("短信AES/RSA解密失败"); - throw new MallinkException(ErrorCode.TEMPLATE_SEND_FAILED); - } - - String requestUrl = "https://webapp.wiwide.com/apisms/addtemplate"; - String result = HttpUtil.doPost(requestUrl, params); JSONObject jsonObjectResult = JSONObject.parseObject(result); String ret = jsonObjectResult.get("ret").toString(); if (ret.equals(EnumMsgModelStatus.SUCCESS.getCode().toString())) { diff --git a/mallinkService/src/main/java/com/iformall/service/impl/WxMsgValidationcodeServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/WxMsgValidationcodeServiceImpl.java index e9365f8bc..f955127c8 100644 --- a/mallinkService/src/main/java/com/iformall/service/impl/WxMsgValidationcodeServiceImpl.java +++ b/mallinkService/src/main/java/com/iformall/service/impl/WxMsgValidationcodeServiceImpl.java @@ -9,13 +9,9 @@ import com.iformall.common.Result; import com.iformall.common.ResultData; import com.iformall.domain.po.*; import com.iformall.enums.EnumMsgSendStatus; -import com.iformall.exception.MallinkException; import com.iformall.mapper.*; import com.iformall.service.WxMsgValidationcodeService; -import com.iformall.utils.AesUtil; -import com.iformall.utils.HMACSHA256; -import com.iformall.utils.HttpUtil; -import com.iformall.utils.RsaUtil; +import com.iformall.utils.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -124,42 +120,7 @@ public class WxMsgValidationcodeServiceImpl implements WxMsgValidationcodeServic wxMsgValidationcode.setMsg(msg); String notifyUrl = wxMsgConfig.getNotifyurl(); - TreeMap message = new TreeMap<>(); - message.put("bid", bid); - message.put("phone", phone); - message.put("signature", signature); - message.put("msg", msg); - message.put("notify_url", notifyUrl); - message.put("verifysms","1"); - - StringBuilder sb = new StringBuilder(); - Set> entries = message.entrySet(); - for (Map.Entry entry : entries) { - sb.append(entry.getKey()).append("=").append(entry.getValue()); - } - sb.append("&secret=").append(secret); - String sign = HMACSHA256.sha256_HMAC(sb.toString(), secret); - message.put("sign", sign.toUpperCase()); - - String str32 = HMACSHA256.STR2; - String iv = HMACSHA256.IV; - - Map params = new HashMap<>(); - params.put("iv", iv); - params.put("bid", bid); - - try { - String data = AesUtil.AESEncode(str32, JSONObject.toJSONString(message), iv); - String sc = RsaUtil.RSAEncode(str32.getBytes(), publickey); - params.put("data", data); - params.put("sc", sc); - } catch (Exception e) { - logger.info("短信AES/RSA解密失败"); - throw new MallinkException(ErrorCode.MSG_SEND_ERROR); - } - - String requestUrl = "https://webapp.wiwide.com/apisms/send"; - String result = HttpUtil.doPost(requestUrl, params); + String result = WiwideUtil.sendMsg(secret, bid, publickey, phone, signature, msg, notifyUrl); JSONObject jsonObjectResult = JSONObject.parseObject(result); String ret = jsonObjectResult.get("ret").toString(); String batchNo = jsonObjectResult.get("data").toString(); diff --git a/mallinkService/src/main/java/com/iformall/utils/WiwideUtil.java b/mallinkService/src/main/java/com/iformall/utils/WiwideUtil.java new file mode 100644 index 000000000..98f7dc001 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/utils/WiwideUtil.java @@ -0,0 +1,96 @@ +package com.iformall.utils; + +import com.alibaba.fastjson.JSONObject; +import com.iformall.common.ErrorCode; +import com.iformall.exception.MallinkException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +public class WiwideUtil { + private static final Logger logger = LoggerFactory.getLogger(ETCPUtil.class); + + private static final String addTemplateUrl = "https://webapp.wiwide.com/apisms/addtemplate"; + private static final String smsSendUrl = "https://webapp.wiwide.com/apisms/send"; + + public static String addTemplate(String secret, String bid, String publickey, String signature, String content, String notifyUrl) { + //请求api数据排序 + TreeMap message = new TreeMap<>(); + message.put("bid", bid); + message.put("signature", signature); + message.put("content", content); + message.put("notify_url",notifyUrl); + message.put("verifysms","1"); + + StringBuilder sb = new StringBuilder(); + Set> entries = message.entrySet(); + for (Map.Entry entry : entries) { + sb.append(entry.getKey()).append("=").append(entry.getValue()); + } + sb.append("&secret=").append(secret); + String sign = HMACSHA256.sha256_HMAC(sb.toString(), secret); + message.put("sign", sign.toUpperCase()); + + String str32 = HMACSHA256.STR2; + String iv = HMACSHA256.IV; + + Map params = new HashMap<>(); + params.put("iv", iv); + params.put("bid", bid); + try { + String data = AesUtil.AESEncode(str32, JSONObject.toJSONString(message), iv); + String sc = RsaUtil.RSAEncode(str32.getBytes(), publickey); + params.put("data", data); + params.put("sc", sc); + } catch (Exception e) { + logger.info("短信AES/RSA解密失败"); + throw new MallinkException(ErrorCode.TEMPLATE_SEND_FAILED); + } + + String requestUrl = addTemplateUrl; + return HttpUtil.doPost(requestUrl, params); + } + + public static String sendMsg(String secret, String bid, String publickey, + String phone, String signature, String msg, String notifyUrl) { + TreeMap message = new TreeMap<>(); + message.put("bid", bid); + message.put("phone", phone); + message.put("signature", signature); + message.put("msg", msg); + message.put("notify_url", notifyUrl); + + StringBuilder sb = new StringBuilder(); + Set> entries = message.entrySet(); + for (Map.Entry entry : entries) { + sb.append(entry.getKey()).append("=").append(entry.getValue()); + } + sb.append("&secret=").append(secret); + String sign = HMACSHA256.sha256_HMAC(sb.toString(), secret); + message.put("sign", sign.toUpperCase()); + + String str32 = HMACSHA256.STR2; + String iv = HMACSHA256.IV; + + Map params = new HashMap<>(); + params.put("iv", iv); + params.put("bid", bid); + + try { + String data = AesUtil.AESEncode(str32, JSONObject.toJSONString(message), iv); + String sc = RsaUtil.RSAEncode(str32.getBytes(), publickey); + params.put("data", data); + params.put("sc", sc); + } catch (Exception e) { + logger.info("短信AES/RSA解密失败"); + throw new MallinkException(ErrorCode.MSG_SEND_ERROR); + } + + String requestUrl = smsSendUrl; + return HttpUtil.doPost(requestUrl, params); + } +}