import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.common.primitives.Bytes;
import com.huifu.adapay.core.exception.BaseAdaPayException;
import com.huifu.adapay.model.Refund;
import com.jsowell.JsowellApplication;
import com.jsowell.adapay.service.AdapayMemberService;
import com.jsowell.common.constant.CacheConstants;
import com.jsowell.common.constant.Constants;
import com.jsowell.common.core.domain.entity.SysDictData;
import com.jsowell.common.core.domain.ykc.LoginRequestData;
import com.jsowell.common.core.domain.ykc.TransactionRecordsData;
import com.jsowell.common.core.redis.RedisCache;
import com.jsowell.common.enums.ykc.OrderStatusEnum;
import com.jsowell.common.enums.ykc.StartModeEnum;
import com.jsowell.common.exception.BusinessException;
import com.jsowell.common.util.*;
import com.jsowell.common.util.http.HttpUtils;
import com.jsowell.common.util.id.SnUtils;
import com.jsowell.common.util.id.SnowflakeIdWorker;
import com.jsowell.common.util.ip.AddressUtils;
import com.jsowell.pile.domain.ykcCommond.IssueQRCodeCommand;
import com.jsowell.pile.domain.ykcCommond.ProofreadTimeCommand;
import com.jsowell.netty.handler.HeartbeatRequestHandler;
import com.jsowell.netty.service.yunkuaichong.YKCBusinessService;
import com.jsowell.pile.service.YKCPushCommandService;
import com.jsowell.pile.domain.*;
import com.jsowell.pile.dto.*;
import com.jsowell.pile.mapper.MemberBasicInfoMapper;
import com.jsowell.pile.mapper.PileBillingTemplateMapper;
import com.jsowell.pile.service.*;
import com.jsowell.pile.vo.web.BillingTemplateVO;
import com.jsowell.pile.vo.web.OrderListVO;
import com.jsowell.pile.vo.web.PileDetailVO;
import com.jsowell.service.MemberService;
import com.jsowell.service.OrderService;
import com.jsowell.service.PileRemoteService;
import com.jsowell.service.PileService;
import com.jsowell.thirdparty.amap.service.AMapService;
import com.jsowell.thirdparty.lianlian.dto.CommonParamsDTO;
import com.jsowell.thirdparty.lianlian.service.LianLianService;
import com.jsowell.thirdparty.lianlian.util.Cryptos;
import com.jsowell.thirdparty.lianlian.util.Encodes;
import com.jsowell.thirdparty.lianlian.util.GBSignUtils;
import com.jsowell.wxpay.common.WeChatPayParameter;
import com.jsowell.wxpay.dto.AppletTemplateMessageSendDTO;
import com.jsowell.wxpay.dto.WeChatRefundDTO;
import com.jsowell.wxpay.response.WechatPayRefundRequest;
import com.jsowell.wxpay.service.WxAppletRemoteService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.compress.utils.Lists;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.StopWatch;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

@ActiveProfiles("dev")
@SpringBootTest(classes = JsowellApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@RunWith(SpringRunner.class)
public class SpringBootTestController {

	private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

	@Autowired
	private SnUtils snUtils;

	@Autowired
	private PileService pileService;

	@Autowired
	private YKCPushCommandService ykcPushCommandService;

	@Autowired
	private IPileMsgRecordService pileMsgRecordService;

	@Autowired
	private IPileStationInfoService pileStationInfoService;

	@Autowired
	private YKCPushCommandService ykcPushBusinessService;

	@Autowired
	private HeartbeatRequestHandler heartbeatRequestHandler;

	@Autowired
	private YKCBusinessService ykcBusinessService;

	@Autowired
	private PileBillingTemplateMapper pileBillingTemplateMapper;

	@Autowired
	private PileRemoteService pileRemoteService;

	@Autowired
	private MemberService memberService;

	@Autowired
	private OrderService orderService;

	@Autowired
	private IPileBillingTemplateService pileBillingTemplateService;

	@Autowired
	private MemberBasicInfoMapper memberBasicInfoMapper;

	@Autowired
	private SimCardService simCardService;

	@Autowired
	private IPileBasicInfoService pileBasicInfoService;

	@Autowired
	private WechatPayService wechatPayService;

	@Autowired
	private IOrderBasicInfoService orderBasicInfoService;

	@Autowired
	private WxpayCallbackRecordService wxpayCallbackRecordService;

	@Autowired
	private WxAppletRemoteService wxAppletRemoteService;

	@Autowired
	private RedisCache redisCache;

	@Autowired
	private IPileAuthCardService pileAuthCardService;

	@Autowired
	private LianLianService lianLianService;

	@Autowired
	private IMemberTransactionRecordService memberTransactionRecordService;

	@Autowired
	private IMemberPlateNumberRelationService memberPlateNumberRelationService;

	static final String MAC_KEY = "53TtFpc4gdVZbF3x";

	static final String ALGORITHM_MAC = "HmacMD5";

	@Autowired
	private AdapayCallbackRecordService adapayCallbackRecordService;

	@Autowired
	private IAdapayRefundRecordService adapayRefundRecordService;

	@Autowired
	private AdapayMemberService adapayMemberService;

	@Autowired
	private AMapService aMapService;

	@Test
	public void testQueryAdapayMemberInfo() {
		String adapayMemberId = "AM25703321";
		String settleAccountId = "0489089447022976";
		try {
			// adapayMemberService.queryAdapayMemberInfo(adapayMemberId);

			adapayMemberService.queryAdapaySettleAccount(adapayMemberId, settleAccountId);
		} catch (BaseAdaPayException e) {
			throw new RuntimeException(e);
		}
	}

	@Test
	public void testSaveAdapayCallbackRecord() throws JsonProcessingException {
		String data = "{\n" +
				"    \"object\": \"refund\",\n" +
				"    \"status\": \"succeeded\",\n" +
				"    \"prod_mode\": \"true\",\n" +
				"    \"id\": \"0022120230531111946980509821471137853440\",\n" +
				"    \"refund_order_no\": \"823725974557265920\",\n" +
				"    \"payment_id\": \"002212023053110524210509814658135928832\",\n" +
				"    \"payment_order_no\": \"C27262970851\",\n" +
				"    \"refund_amt\": \"7.82\",\n" +
				"    \"fee_amt\": \"0.04\",\n" +
				"    \"channel_no\": \"2023053121R064uj\",\n" +
				"    \"created_time\": \"1685503187000\",\n" +
				"    \"succeed_time\": \"1685503199000\",\n" +
				"    \"app_id\": \"app_d0c80cb1-ffc8-48cb-a030-fe9bec823aaa\",\n" +
				"    \"reason\": \"\",\n" +
				"    \"notify_url\": \"https://api.jsowellcloud.com/uniapp/pay/adapayRefundCallback\"\n" +
				"}";

		JSONObject jsonObject = JSON.parseObject(data);
		ObjectMapper mapper = new ObjectMapper();
		mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
		mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
		AdapayRefundRecord adapayRefundRecord = mapper.readValue(jsonObject.toJSONString(), AdapayRefundRecord.class);
		adapayRefundRecord.setRefundId(jsonObject.getString("id"));
		// 保存到数据库
		adapayRefundRecordService.insertAdapayRefundRecord(adapayRefundRecord);
	}

	@Test
	public void testQueryCallback() {
		AdapayCallbackRecord aaaa = adapayCallbackRecordService.selectByOrderCode("aaaa");
		System.out.println(aaaa);
	}

	@Test
	public void testAdapayRefund() {
		// 创建汇付退款对象 在完成初始化设置情况下，调用方法，获取 Refund对象
		try {
			String id = "002212023052710075810508353847861903360";
			String refundAmount = "0.01";
			Map<String, Object> refundParams = Maps.newHashMap();
			refundParams.put("refund_amt", AdapayUtil.formatAmount(refundAmount));
			refundParams.put("refund_order_no", SnowflakeIdWorker.getSnowflakeId());
			refundParams.put("notify_url", "https://api.jsowellcloud.com/uniapp/pay/adapayRefundCallback");
			Map<String, Object> response = Refund.create(id, refundParams);
			System.out.println(JSON.toJSONString(response));
			// if (response != null && !response.isEmpty()) {
			// 	JSONObject jsonObject = JSONObject.parseObject(response.get("expend").toString());
			// 	JSONObject pay_info = jsonObject.getJSONObject("pay_info");
			// 	Map<String, Object> resultMap = JSONObject.parseObject(pay_info.toJSONString(), new TypeReference<Map<String, Object>>() {});
			// }
		} catch (Exception e) {
			System.out.println(e);
		}
	}

	@Test
	public void testSaveCallback() throws JsonProcessingException {
		String data = "{\"app_id\":\"app_d0c80cb1-ffc8-48cb-a030-fe9bec823aaa\",\"created_time\":\"20230530132956\",\"description\":\"{\\\"orderCode\\\":\\\"C29505932783\\\",\\\"type\\\":\\\"order\\\"}\",\"end_time\":\"20230530133027\",\"expend\":{\"bank_type\":\"OTHERS\",\"open_id\":\"o8jhot6PJF93EPhNISsXi28dKdS8\",\"sub_open_id\":\"o4REX5MprZfTaLnVNxfdOY-wnwGI\"},\"fee_amt\":\"0.11\",\"id\":\"002212023053013295610509491838664794112\",\"order_no\":\"C29505932783\",\"out_trans_id\":\"4200001855202305308670391485\",\"party_order_id\":\"02212305304859640306711\",\"pay_amt\":\"20.00\",\"pay_channel\":\"wx_lite\",\"real_amt\":\"20.00\",\"share_eq\":\"Y\",\"status\":\"succeeded\",\"wx_user_id\":\"\"}";
		JSONObject jsonObject = JSON.parseObject(data);
		ObjectMapper mapper = new ObjectMapper();
		mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
		AdapayCallbackRecord adapayCallbackRecord = mapper.readValue(jsonObject.toJSONString(), AdapayCallbackRecord.class);
		adapayCallbackRecord.setExpend(jsonObject.getString("expend"));
		adapayCallbackRecord.setPaymentId(jsonObject.getString("id"));
		adapayCallbackRecordService.saveAdapayCallbackRecord(adapayCallbackRecord);

	}

	@Test
	public void testAMap() throws Exception {
		String pileConnectorCode = "8800000000012601";
		String s = aMapService.pushChargingDeviceDynamics(pileConnectorCode);
		System.out.println(s);
	}

	@Test
	public void testVinCode() {
		String msg = "880000000000210203000000000000000000000000000000000000000000000000004C5257594743454B584D43303437313434";
		// 获取消息体
		byte[] msgBody = BytesUtil.str2Bcd(msg);

		int startIndex = 0;
		int length = 7;

		// 桩编码
		byte[] pileSnByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String pileSn = BytesUtil.binary(pileSnByteArr, 16);

		// 保存时间
		// saveLastTime(pileSn);

		// 枪号
		startIndex += length;
		length = 1;
		byte[] connectorNumByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String connectorCode = BytesUtil.bcd2Str(connectorNumByteArr);

		// 启动方式
		// 0x01 表示通过刷卡启动充电
		// 0x02 表求通过帐号启动充电 （暂不支持）
		// 0x03 表示vin码启动充电
		startIndex += length;
		byte[] startModeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String startMode = BytesUtil.bcd2Str(startModeByteArr);

		// 是否需要密码  0x00 不需要 0x01 需要
		startIndex += length;
		byte[] needPasswordFlagByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String needPasswordFlag = BytesUtil.bcd2Str(needPasswordFlagByteArr);

		// 物理卡号  不足 8 位补 0
		startIndex += length;
		length = 8;
		byte[] cardNumByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String physicsCard = BytesUtil.binary(cardNumByteArr, 16);

		// 输入密码  对用户输入的密码进行16 位MD5 加密，采用小写上传
		startIndex += length;
		length = 16;
		byte[] inputPasswordByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);

		// VIN码
		startIndex += length;
		length = 17;
		byte[] vinCodeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String vinCode = BytesUtil.ascii2Str(vinCodeByteArr);
		System.out.println("桩号:" + pileSn +"申请充电VIN码:"  + vinCode);

		/**
		 * 刷卡启动充电
		 */
		String logicCard = "";
		byte[] authenticationFlagByteArr = Constants.zeroByteArray; // 鉴权成功标识
		byte[] accountBalanceByteArr = Constants.zeroByteArray; // 账户余额
		String transactionCode = "";

		try {
			/**
			 * VIN码启动充电
			 */
			if (StringUtils.equals("03", startMode)) {
				// 通过vin码查询数据库绑定用户信息
				MemberPlateNumberRelation plateInfo = memberPlateNumberRelationService.getMemberPlateInfoByVinCode(vinCode);
				if (plateInfo == null) {
					throw new BusinessException("", "未查到绑定用户信息");
				}
				if (!StringUtils.equals("1", plateInfo.getVinStatus())) {
					// 1- 正常使用
					throw new BusinessException("", "vin状态不正确");
				}
				// vin码生成订单 vin启动充电
				GenerateOrderDTO dto = new GenerateOrderDTO();
				dto.setMemberPlateNumberRelation(plateInfo);
				dto.setPileSn(pileSn);
				dto.setConnectorCode(connectorCode);
				dto.setStartMode(StartModeEnum.VIN_CODE.getValue());
				Map<String, Object> map = orderBasicInfoService.generateOrderByCard(dto);
				if (map != null) {
					transactionCode = (String) map.get("transactionCode");
					accountBalanceByteArr = YKCUtils.getPriceByte(String.valueOf(map.get("accountBalance")), 2);
					// 鉴权成功标识  0x00 失败 0x01 成功
					authenticationFlagByteArr = Constants.oneByteArray;
				}else {
					throw new BusinessException("", "生成vin订单失败");
				}
			}
		}catch (BusinessException e){
			e.printStackTrace();
			System.out.println("1");
			// log.error("VIN码启动充电鉴权 error:{}, {}", e.getCode(), e.getMessage());
		}catch (Exception e) {
			e.printStackTrace();
			System.out.println("2");
			transactionCode = "00000000000000000000000000000000";
			accountBalanceByteArr = BytesUtil.checkLengthAndBehindAppendZero(accountBalanceByteArr, 8);
			authenticationFlagByteArr = Constants.zeroByteArray;
			// log.error("VIN码启动充电鉴权 error", e);
		}
		byte[] serialNumByteArr = BytesUtil.str2Bcd(transactionCode);

		byte[] defeatReasonByteArr = Constants.zeroByteArray;

		// 不足位数的值补零
		// cardNumByteArr = BytesUtil.checkLengthAndBehindAppendZero(cardNumByteArr, 16);
		// serialNumByteArr = BytesUtil.checkLengthAndBehindAppendZero(serialNumByteArr, 32);
		// pileSnByteArr = BytesUtil.checkLengthAndBehindAppendZero(pileSnByteArr, 14);
		// accountBalanceByteArr = BytesUtil.checkLengthAndBehindAppendZero(accountBalanceByteArr, 8);

		// 拼装消息体
		byte[] msgBodyByteArr = Bytes.concat(serialNumByteArr, pileSnByteArr, connectorNumByteArr, cardNumByteArr, accountBalanceByteArr,
				authenticationFlagByteArr, defeatReasonByteArr);

		String s = BytesUtil.bin2HexStr(msgBodyByteArr);
		System.out.println(s);
	}

	@Test
	public void testGenerateLianlianToken() throws UnsupportedEncodingException {
		String OperatorID = "425010765";
		String OperatorSecret = "123123123123aaaa"; // 1234567890abcdef

		//请求dataX
		Map<String, String> data = new HashMap<>();
		data.put("OperatorID", OperatorID);
		data.put("OperatorSecret", OperatorSecret);
		String dataJson = JSONUtil.toJsonStr(data);

		//加密
		byte[] encryptText = Cryptos.aesEncrypt(dataJson.getBytes(StandardCharsets.UTF_8),
				OperatorSecret.getBytes(), OperatorSecret.getBytes());
		String strData = Encodes.encodeBase64(encryptText);

		Map<String, String> request = new LinkedHashMap<>();
		request.put("OperatorID", OperatorID);
		request.put("Data", strData);
		request.put("TimeStamp", System.currentTimeMillis() + "");
		request.put("Seq", "0001");

		//生成签名
		String sig = GBSignUtils.sign(request, OperatorSecret);
		request.put("Sig", sig);
		String tokenRequest = JSONUtil.toJsonStr(request);

		CommonParamsDTO dto = JSONObject.parseObject(tokenRequest, CommonParamsDTO.class);

		lianLianService.generateToken(dto);
	}

	@Test
	public void testupdateElecAmount() {
		orderBasicInfoService.updateElecAmount();
	}

	@Test
	public void testSelectSomeStatusCardInfo() {
		PileAuthCard pileAuthCard = pileAuthCardService.selectCardInfoByLogicCard("1111111111111111");
		System.out.println(pileAuthCard);
	}

	@Test
	public void testLianLian() throws UnsupportedEncodingException {
		// 获取令牌
		// LianLianGetTokenDTO dto = new LianLianGetTokenDTO();
		// dto.setOperatorId("MA1JLFUU8");
		// dto.setOperatorSecret("Nh62XxlIR5OjAzFj");
		// String token = lianLianService.getToken("", "MA1JLFUU8", "fGwLsxW1HdzLw7jp");
		// System.out.println("token:" + token);

		String operatorId = "425010765";
		String operatorSecret = "3DSBTWHVIC6KVCKI";
		// 请求data
		// Map<String, String> data = new HashMap<>();
		// data.put("OperatorID", operatorId);
		// data.put("OperatorSecret", operatorSecret);
		// String dataJson = JSONUtil.toJsonStr(data);

		JSONObject json = new JSONObject();
		// json.put("StationIDs", com.google.common.collect.Lists.newArrayList("1", "2"));
		json.put("LastQueryTime", "2023-05-29 10:00:00");
		json.put("PageNo", 1);
		json.put("PageSize", 10);

		String dataJson = JSONObject.toJSONString(json);
		// 加密
		byte[] encryptText = Cryptos.aesEncrypt(dataJson.getBytes(StandardCharsets.UTF_8),
				operatorSecret.getBytes(), operatorSecret.getBytes());
		String strData = Encodes.encodeBase64(encryptText);
		String timeStamp = DateUtils.parseDateToStr(DateUtils.YYYYMMDDHHMMSS, new Date());
		Map<String, String> request = new LinkedHashMap<>();
		request.put("OperatorID", operatorId);
		request.put("Data", strData);
		request.put("TimeStamp", timeStamp);
		request.put("Seq", "0001");

		// 生成签名
		String sig = GBSignUtils.sign(request, operatorSecret);
		request.put("Sig", sig);
		JSONObject jsonObject = new JSONObject(request);
		System.out.println(jsonObject);
		// CommonParamsDTO dto = new CommonParamsDTO();
		// dto.setOperatorID(operatorId);
		// dto.setData(strData);
		// dto.setTimeStamp(timeStamp);
		// dto.setSeq("0001");
		// dto.setSig(sig);
		// Map<String, String> map = lianLianService.generateToken(dto);
		QueryStationInfoDTO dto = new QueryStationInfoDTO();
		dto.setOperatorId(operatorId);
		Map<String, String> map = lianLianService.query_stations_info(dto);
		// String data1 = map.get("Data");
		// 解密data
		// String data1 = "JudlP17tnYuQc2zwOzmjJAb9hgghIymefG5v3ZzSOlPDh5+bJHIedsYzKMD56tHlmlg6Cb7vG+o6KjMSSpn1fyqBH3UVaEFF7uEc+lOuEc9c1vUzq20vBQ7N3EpDKqVBKjZbOezMsKYaCX7Br8XTsCYT8VCQui/np3cn+phi3VC+0s1coNxBX7xoEDZ7iuPjPoSWL7g3J0uOw2SoGaIdBQG3eTxaZJ5L+vBmuDF0pEXgazTMnuKml1mx1QHkig2F7h/ILT0VEKVXWMmmogYgiBk5ItO0DyzRl+ASb184gOhYGo82GJmWRiXrAXmceCiSNvTGg6aL26imIGKkJNfOx9/9mTqjGvy6kzxvWJ29PBU=";
		// byte[] plainText = Cryptos.aesDecrypt(Encodes.decodeBase64(data1),
		// 		operatorSecret.getBytes(), operatorSecret.getBytes());
		// String dataStr = new String(plainText, "UTF-8");
		// Map<String, String> resultMap = (Map<String, String>) JSON.parse(dataStr);
		//
		// String token = resultMap.get("AccessToken");
		//
		// System.out.println("解密后token：" + token);

		// LianLianPushStationInfoDTO dto1 = LianLianPushStationInfoDTO.builder()
		// 		.OperatorID("MA1JLFUU8")
		// 		.DataSecret("HVicnbRZbhPdIdpF")
		// 		.DataSecretIV("JNvcjSOn1vhrE11M")
		// 		.SigSecret("53TtFpc4gdVZbF3x")
		// 		// .token(token)
		// 		.stationId(2L)
		//
		// 		.build();
		// lianLianService.pushStationInfo(dto1);

		// 推送订单状态
		// lianLianService.pushConnectorStatus("8800000000000101", "1");

		// 推送订单信息
		// lianLianService.pushOrderInfo("C27680791529");

		// 推送启动充电结果
		// lianLianService.pushStartChargeResult("C27680791529");

		// 推送充电状态
		// lianLianService.pushChargeStatus("C27680791529");

		// 推送停止充电结果
		// lianLianService.pushStopChargeResult("C27680791529");

		// 推送充电订单信息
		// lianLianService.pushChargeOrderInfo("C27680791529");

		// 推送订单结算信息
		// lianLianService.pushOrderSettlementInfo("C27680791529");

		// 查询订单结算信息
		// lianLianService.queryOrderSettlementInfo("C27680791529");

		// 推送订单对账结果信息
		// lianLianService.pushOrderReconciliationInfo("C27680791529");

		// 测试生成、解密令牌
		// long ttlMillis = 60 * 60 * 24 * 1000;
		// String token = JWTUtils.createToken(operatorId, operatorSecret, ttlMillis);
		// System.out.println(JWTUtils.checkThirdPartyToken(token));

		JSONObject jsonObject1 = new JSONObject(map);
		jsonObject1.put("OperatorID", "425010765");
		jsonObject1.put("Data", "Ntu99RpveEOm2VUNq6RpD7OuOPXRbNxMOPmaBl67nkLk0nD/VmhipdSpq/Qfswhe1o55YMT+3Z7e6xe3fiJA3cZcvetxOEUF6sjvKLRq2rU=");
		jsonObject1.put("TimeStamp", "20230530090132");
		jsonObject1.put("Seq", "0001");
		jsonObject1.put("Sig", "1568D2D35B245A0205B33D0EF92E7981");

		String jsonString = JSONObject.toJSONString(jsonObject1);

		String result = HttpUtils.sendPostContentType("http://localhost:8080/LianLian/v1/query_stations_info", jsonString, "application/json");
		JSONObject object = JSONObject.parseObject(result);
		String data1 = (String) object.get("data");
		// 解密data
		byte[] plainText = Cryptos.aesDecrypt(Encodes.decodeBase64(data1),
				operatorSecret.getBytes(), operatorSecret.getBytes());
		String dataStr = new String(plainText, "UTF-8");
		Map<String, String> resultMap = (Map<String, String>) JSON.parse(dataStr);
	}


	@Test
	public void testRefundForBalance() {
		BigDecimal refundAmount = new BigDecimal("2");
		// 退款金额 元转分 123
		int refundTotalCents = refundAmount.multiply(new BigDecimal(100)).intValue();

		// 查询用户充值余额订单 过滤掉已经退款的充值订单 refundableOrder
		List<RefundableWxPayOrderData> recordList = Lists.newArrayList();
		// recordList.add(RefundableWxPayOrderData.builder().outTradeNo("1").transactionId("1").payerAmount(new BigDecimal("1000")).refundableAmount(new BigDecimal("0")).build());
		// recordList.add(RefundableWxPayOrderData.builder().outTradeNo("2").transactionId("2").payerAmount(new BigDecimal("1000")).refundableAmount(new BigDecimal("0")).build());
		recordList.add(RefundableWxPayOrderData.builder().outTradeNo("3").transactionId("3").payerAmount(new BigDecimal("500")).refundableAmount(new BigDecimal("300")).build());

		// 也许需要多笔支付订单才够退款
		List<WechatPayRefundRequest> requestList = com.google.common.collect.Lists.newArrayList();
		WechatPayRefundRequest request;
		for (RefundableWxPayOrderData record : recordList) {
			int refundableTotal = record.getRefundableAmount().intValue(); // 该笔支付订单的可退金额，单位分
			int payerTotal = record.getPayerAmount().intValue(); // 该笔支付订单的支付金额，单位分
			// 用户申请退款金额-可退金额
			refundTotalCents = refundTotalCents - refundableTotal; // 123 - 100
			request = new WechatPayRefundRequest();
			request.setTransaction_id(record.getTransactionId()); // 微信支付单号
			request.setOut_trade_no(record.getOutTradeNo()); // 商户订单号
			request.setOut_refund_no(SnowflakeIdWorker.getSnowflakeId()); // 商户退款单号
			request.setNotify_url(WeChatPayParameter.refundNotifyUrl); // 回调接口
			request.setReason("用户余额退款");
			request.setFunds_account("AVAILABLE");
			if (refundTotalCents > 0) {
				// 如果大于0说明，这笔单退完也不够
				WechatPayRefundRequest.Amount amount = new WechatPayRefundRequest.Amount();
				amount.setRefund(refundableTotal); // 退款金额
				amount.setTotal(payerTotal); // 原订单金额
				request.setAmount(amount);
				requestList.add(request);
			} else {
				// 如果小于0，这笔单退一部分
				// 生成退款单号
				WechatPayRefundRequest.Amount amount = new WechatPayRefundRequest.Amount();
				// 部分退
				int i = refundableTotal + refundTotalCents;
				amount.setRefund(i); // 退款金额
				amount.setTotal(payerTotal); // 原订单金额
				request.setAmount(amount);
				requestList.add(request);
				break;
			}
		}

		System.out.println(requestList);
	}

	@Test
	public void testCloseStartFailedOrder() {
		String startTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, DateUtils.addDays(new Date(), -2));
		String endTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, new Date());
		orderBasicInfoService.closeStartFailedOrder(startTime, endTime);
	}

	@Test
	public void testRedisSaveRealTimeData() {
		String pileSn = "88000000000001";
		String connectorCode = "01";
		String orderCode = "88000000000001012211161342359448";

		String pileConnectorCode = pileSn + connectorCode;
		String redisKey = CacheConstants.PILE_REAL_TIME_MONITOR_DATA + pileConnectorCode + "_" + orderCode;

		// for (int i = 0; i < 10; i++) {
		// 	try {
		// 		Thread.sleep(10000);
		// 	} catch (InterruptedException e) {
		// 		e.printStackTrace();
		// 	}
		// 	Date now = new Date();
		// 	redisCache.hset(redisKey, DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:00", now), i + ":" + DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", now));
		// }

		orderBasicInfoService.getChargingRealTimeData(orderCode);
	}

	@Test
	public void testuniformMessageSend() {
		AppletTemplateMessageSendDTO appletTemplateMessageSendDTO = new AppletTemplateMessageSendDTO();
		// String openId = wxAppletRemoteService.getOpenIdByCode("0537u2100jTXsP1Y0Y300j426t47u210");
		// System.out.println("openId:" + openId);

		appletTemplateMessageSendDTO.setTouser("o4REX5MprZfTaLnVNxfdOY-wnwGI"); // openid

		String templateId = "UyBPbADlZfsCj89rh_xvfZGlxTW5J5KURpZtt9CNFrY";
		appletTemplateMessageSendDTO.setTemplate_id(templateId);
		// appletTemplateMessageSendDTO.setPage("跳转的页面");
		Map<String, Object> map = new HashMap<>();
		map.put("amount17", ImmutableMap.of("value", "￥100")); // 结束时间
		map.put("time3", ImmutableMap.of("value", "2022-12-30")); // 结束时间
		map.put("thing7", ImmutableMap.of("value", "thing7")); // 结束原因

		// map.put("thing5", ImmutableMap.of("value", "thing5")); // 结束原因
		// map.put("time2", ImmutableMap.of("value", "time2")); // 结束原因
		appletTemplateMessageSendDTO.setData(map);

		wxAppletRemoteService.uniformMessageSend(appletTemplateMessageSendDTO);
	}

	@Test
	public void testWeChatRefund() {
		WeChatRefundDTO dto = new WeChatRefundDTO();
		dto.setRefundType("2");
		dto.setMemberId("82100864");
		dto.setRefundAmount(new BigDecimal("1.23"));
		orderBasicInfoService.weChatRefund(dto);
	}

	@Test
	public void testSelectBalanceRechargeRecord() {
		List<WxpayCallbackRecord> list = wxpayCallbackRecordService.queryBalanceRechargeRecordOfTheLatestYear("82100864");
		System.out.println(list);
	}

	@Test
	public void testSelectOrderBasicInfoList() {
		QueryOrderDTO orderBasicInfo = new QueryOrderDTO();
		orderBasicInfo.setPileSn("88000000000001");
		orderBasicInfo.setOrderStatus(OrderStatusEnum.IN_THE_CHARGING.getValue());
		List<OrderListVO> orderListVOS = orderBasicInfoService.selectOrderBasicInfoList(orderBasicInfo);
		System.out.println(orderListVOS);
		for (OrderListVO orderListVO : orderListVOS) {
			if (StringUtils.equals(orderListVO.getOrderStatus(), OrderStatusEnum.IN_THE_CHARGING.getValue())) {
				// 修改数据库订单状态
				OrderBasicInfo info = OrderBasicInfo.builder()
						.id(Long.parseLong(orderListVO.getId()))
						.orderStatus(OrderStatusEnum.ABNORMAL.getValue())
						.build();
				orderBasicInfoService.updateOrderBasicInfo(info);
			}
		}
	}

	@Test
	public void testWechatRefund() throws JsonProcessingException {
		WechatPayRefundRequest request = new WechatPayRefundRequest();
		request.setTransaction_id("4200001656202212302746036536"); // 微信支付单号
		request.setOut_trade_no("768677222373363712"); // 商户订单号
		// 生成退款单号
		request.setOut_refund_no(SnowflakeIdWorker.getSnowflakeId()); // 商户退款单号
		request.setNotify_url(WeChatPayParameter.refundNotifyUrl); // 回调接口
		WechatPayRefundRequest.Amount amount = new WechatPayRefundRequest.Amount();
		amount.setRefund(10 * 100); // 退款金额
		amount.setTotal(10 * 100); // 原订单金额
		request.setAmount(amount);
		request.setReason("结算退款");
		request.setFunds_account("AVAILABLE");

		wechatPayService.ApplyForWechatPayRefundV3(request);

		// 退款方法

	}

	@Test
	public void testUpdatePileSimInfo() {
		String pileSn = "88000000000001";
		String iccid = "898604940121C1385725";
		pileBasicInfoService.updatePileSimInfo(pileSn, iccid);
	}

	@Test
	public void testPay() {
		String code = "081zIoGa11GamE0iVVIa1aaJ4G0zIoGE";
		String openId = memberService.getOpenIdByCode(code);
		Map<String, Object> pay = null;
		try {
			WeixinPayDTO dto = new WeixinPayDTO();
			dto.setOpenId(openId);
			dto.setAmount("0.01");
			pay = orderService.weixinPayV3(dto);
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println(JSONObject.toJSONString(pay));
	}

	@Test
	public void testMemberRegisterAndLogin() {
		// String phone = "18512341234";
		// String merchantId = "18512341234";
		// String token = memberService.memberRegisterAndLogin(phone, merchantId);
		// System.out.println(token);
		// String memberId = JWTUtils.getMemberId(token);
		// System.out.println(memberId);
	}

	@Test
	public void testMemberBasicInfoMapper() {
		// String memberId = "21772870";
		// BigDecimal principalBalance = new BigDecimal("-10");
		// BigDecimal giftBalance = new BigDecimal("-110");
		// Integer version = 2;
		// int i = memberBasicInfoMapper.updateMemberBalance(memberId, principalBalance, giftBalance, version);
		// if (i == 1) {
		// 	System.out.println("更新余额成功");
		// } else {
		// 	System.out.println("更新余额失败");
		// }
	}

	@Test
	public void testGenerateBillingTemplateMsgBody() {
		String pileSn = "88000000000001";
		// 根据桩号查询计费模板
		BillingTemplateVO billingTemplateVO = pileBillingTemplateService.selectBillingTemplateDetailByPileSn(pileSn);

		byte[] messageBody = pileBillingTemplateService.generateBillingTemplateMsgBody(pileSn, billingTemplateVO);
		System.out.println(BytesUtil.binary(messageBody, 16));
	}

	@Test
	public void testAnalysisPileParameter() {
		BasicPileDTO dto = new BasicPileDTO();
		// 3个都不传的情况
		try {
			System.out.println("3个都不传的情况");
			dto.setPileSn("");
			dto.setConnectorCode("");
			dto.setPileConnectorCode("");
			orderService.analysisPileParameter(dto);
			System.out.println("数据正确");
		} catch (BusinessException e) {
			System.out.println(e.getMessage());
		}
		System.out.println();

		// 只传sn的情况
		try {
			System.out.println("只传sn的情况");
			dto.setConnectorCode("");
			dto.setPileConnectorCode("");
			dto.setPileSn("88000000000001");
			orderService.analysisPileParameter(dto);
			System.out.println("数据正确");
		} catch (BusinessException e) {
			System.out.println(e.getMessage());
		}
		System.out.println();

		//
		try {
			System.out.println("只穿枪口号的情况");
			dto.setConnectorCode("01");
			dto.setPileConnectorCode("");
			dto.setPileSn("");
			orderService.analysisPileParameter(dto);
			System.out.println("数据正确");
		} catch (BusinessException e) {
			System.out.println(e.getMessage());
		}
		System.out.println();

		// 只传充电桩枪口编号的情况
		try {
			System.out.println("只传充电桩枪口编号的情况");
			dto.setPileConnectorCode("8800000000000101");
			dto.setConnectorCode("");
			dto.setPileSn("");
			orderService.analysisPileParameter(dto);
			System.out.println("数据正确");
		} catch (BusinessException e) {
			System.out.println(e.getMessage());
		}

		try {
			System.out.println();
			System.out.println("传充电桩枪sn+枪口号的情况");
			dto.setPileConnectorCode("");
			dto.setConnectorCode("01");
			dto.setPileSn("88000000000001");
			orderService.analysisPileParameter(dto);
			System.out.println("数据正确");
		} catch (BusinessException e) {
			System.out.println(e.getMessage());
		}
	}

	@Test
	public void testImportBillingTemplate() {
		ImportBillingTemplateDTO dto = new ImportBillingTemplateDTO();
		dto.setBillingTemplateId("1");
		// 查询公共计费模板是否存在
		PileBillingTemplate pileBillingTemplate = pileBillingTemplateMapper.selectPileBillingTemplateById(Long.valueOf(dto.getBillingTemplateId()));
		if (pileBillingTemplate == null) {

		}
		List<PileBillingDetail> billingDetailList = pileBillingTemplate.getPileBillingDetailList();
	}

	@Test
	public void testProcess() {
		// 62   68
		String msgString = "680da300000388000000000001010020d06840a40000130000000000000000000000000000000088000000000001010202000000000000000000000000000000000000000000000000000000000000000000001516";
		byte[] msg = BytesUtil.str2Bcd(msgString);
		boolean b = YKCUtils.checkMsg(msg);
		// ykcBusinessService.process(msg, null);
	}

	@Test
	public void testHeartbeat() {
		// heartbeatRequestHandler.updateStatus("88000000000001", "01", "0");

		// heartbeatRequestHandler.updateStatus("88000000000001", "02", "0");
	}

	@Test
	public void testPush() {
		byte[] msg = new byte[]{};
		String pileSn = "88000000000001";
		// ykcPushBusinessService.push(msg, pileSn, YKCFrameTypeCode.READ_REAL_TIME_MONITOR_DATA_CODE);
	}

	@Test
	public void TestMapUtils() {
		String address = "淀山湖镇黄浦江南路278号";
		String areaCode = "320000,320500,320583";
		Map<String, String> longitudeAndLatitude = AddressUtils.getLongitudeAndLatitude(areaCode, address);
		System.out.println(longitudeAndLatitude);
	}

	@Test
	public void testCreatePile() {
		BatchCreatePileDTO dto = BatchCreatePileDTO.builder()
				.merchantId("1")
				.stationId("1")
				.softwareProtocol("1")
				// .connectorNum(1)
				// .num(10)
				// .productionDate(new Date())
				.build();
		pileService.batchCreatePile(dto);
	}

	@Test
	public void testGetIncre() {
		StopWatch stopWatch = new StopWatch();

		// 生成100个
		stopWatch.start("生成100个sn号");
		List<String> list2 = snUtils.generateSN(1);
		stopWatch.stop();
		System.out.println(list2);

		System.out.println(stopWatch.getLastTaskTimeMillis());
	}

	@Test
	public void testDict() {
		// String dictValue = DictUtils.getDictValue("query_pile_info", "url");
		// String station_type = DictUtils.getDictLabel("station_type", "1");
		// System.out.println(station_type);
		// System.out.println("123");

		List<SysDictData> adapay_station = DictUtils.getDictCache("adapay_station");
		List<String> stationIdList = com.google.common.collect.Lists.newArrayList();
		if (CollectionUtils.isNotEmpty(adapay_station)) {
			for (SysDictData sysDictData : adapay_station) {
				stationIdList.add(sysDictData.getDictValue());
			}
		}
		System.out.println(stationIdList);
	}

	@Test
	public void testSelectByMerchantId() {
		List<PileStationInfo> list = pileStationInfoService.selectStationListByMerchantId(Long.valueOf(Constants.ONE));
		System.out.println(list);
	}

	@Test
	public void testStr2Bcd() {
		String logicCardNum = "00000000";
		byte[] logicCardNumByteArr = BytesUtil.str2Bcd(logicCardNum);
		System.out.println(Arrays.toString(logicCardNumByteArr));
	}

	@Test
	public void testBigDecimalMultiply() {
		BigDecimal a = new BigDecimal("216.5");
		BigDecimal b = new BigDecimal("11.5");

		BigDecimal result = a.multiply(b).setScale(2, BigDecimal.ROUND_HALF_UP);
		System.out.println(result);
	}

	@Test
	public void testRemoteUpdate() {
		ArrayList<String> list = new ArrayList<>();
		list.add("88000000000001");
		pileRemoteService.updateFirmware(list);
	}

	@Test
	public void testGetUserPhoneNum() {
		String code = "0e5394cfa4eb41c6181ed257f2368a86dfe4ebdac0a4fac85df63657637e6cc3";
		wxAppletRemoteService.getMobileNumberByCode(code);
	}

	@Test
	public void testDistance() {
		QueryStationDTO dto = new QueryStationDTO();
		dto.setStationLat("123.2222");
		dto.setStationLng("55.6232");

		// pileStationInfoService.uniAppQueryStationInfos(dto);
	}

	/**
	 * 生成英文字母随机数  RandomStringUtils.randomAlphabetic(10);
	 * 生成数字随机数 RandomStringUtils.randomNumeric(10);
	 * 字母+数字结合  RandomStringUtils.randomAlphanumeric(10);
	 */
	@Test
	public void Test() throws ParseException {
		/*String s = RandomStringUtils.randomAlphanumeric(32);
		System.out.println(s); // PuLe4Tyyg1jSFNPhF5d2Ts9ejRn6E8KQ
		String str = "JS160829";
		System.out.println(Md5Utils.hash(str).toUpperCase(Locale.ROOT));
*/

		Date startTimeDate = sdf.parse("2022-11-26 10:44:11");
		Date endTimeDate = sdf.parse("2022-11-27 12:45:11");

		System.out.println(DateUtils.getDatePoor(endTimeDate, startTimeDate)); // 1天2小时1分钟




		/*String stra = "sp_mchid=1632405339&sub_mchid=1632405339&out_trade_no=1217752501201407033233368318&sp_appid=wxbb3e0d474569481d&sub_appid=wxbb3e0d474569481d" +
				"bbac689f4654b209de4d6944808ec80b";
		System.out.println(Md5Utils.hash(stra).toUpperCase(Locale.ROOT));*/
	}

	@Test
	public void testSimCard() throws ParseException {
		ArrayList<String> list = Lists.newArrayList();
		Collections.addAll(list, "898607B9102090253556", "898607B9102090253560");
		// String s = list.toString().replaceAll("(?:\\[|null|\\]| +)", "");
		// System.out.println(s);
		// List<SimCardVO> simCardVOList = simCardService.selectSimCardInfoByIccId(list);
		// System.out.println(simCardVOList.toString());

		// simCardService.XunZhongSimRenewal(list, 12);
		// System.out.println(s);

		// SimCardVO simCardVO = simCardService.searchByLoop("898607B9102090253556");
		//
		// System.out.println(simCardVO.toString());

		simCardService.WuLianSimRenew(list, 1);


	}

	@Test
	public void testRefund() {
		OrderBasicInfo orderInfo = orderBasicInfoService.getOrderInfoByOrderCode("88000000000001012212171045412218");
		orderInfo.setReason("充电异常中止，急停开入");

		TransactionRecordsData data = TransactionRecordsData.builder()
				.transactionCode("88000000000001012212171045412218")
				.consumptionAmount(String.valueOf(0.00))
				.stopReasonMsg(orderInfo.getReason())
				.totalElectricity("0")
				.sharpUsedElectricity("0")
				.peakUsedElectricity("0")
				.flatUsedElectricity("0")
				.valleyUsedElectricity("0")
				.build();

		orderBasicInfoService.settleOrder(data, orderInfo);
	}


	@Test
	public void testLoginHandler() {
		String msg = "8800000000001001010f63362d333000000000898604b319227036282200";
		byte[] msgBody = BytesUtil.str2Bcd(msg);

		int startIndex = 0;
		int length = 7;

		// 桩编码
		byte[] pileSnByte = BytesUtil.copyBytes(msgBody, startIndex, length);
		String pileSn = BytesUtil.binary(pileSnByte, 16);
		// log.info("桩号：{}", pileSn);


		// 桩类型  0 表示直流桩， 1 表示交流桩
		startIndex += length;
		length = 1;
		byte[] pileTypeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String pileType = BytesUtil.bcd2Str(pileTypeByteArr);

		// 充电枪数量
		startIndex += length;
		byte[] connectorNumByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String connectorNum = BytesUtil.bcd2Str(connectorNumByteArr);

		// 通信协议版本  版本号乘 10，v1.0 表示 0x0A
		startIndex += length;
		byte[] communicationVersionByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		// int i = Integer.parseInt(BytesUtil.bcd2Str(communicationVersionByteArr)); // 0F --> 15
		BigDecimal bigDecimal = new BigDecimal(BytesUtil.bcd2Str(communicationVersionByteArr));
		BigDecimal communicationVersionTemp = bigDecimal.divide(new BigDecimal(10));
		String communicationVersion = "v" + communicationVersionTemp;

		// 程序版本
		startIndex += length;
		length = 8;
		byte[] programVersionByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String programVersion = BytesUtil.bcd2Str(programVersionByteArr);

		// 网络连接类型  0x00 SIM 卡  0x01 LAN   0x02 WAN  0x03 其他
		startIndex += length;
		length = 1;
		byte[] internetConnectionTypeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String internetConnection = BytesUtil.bcd2Str(internetConnectionTypeByteArr);

		// sim卡
		startIndex += length;
		length = 10;
		byte[] simCardNumByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String iccid = BytesUtil.bin2HexStr(simCardNumByteArr);

		// 运营商  0x00 移动  0x02 电信  0x03 联通  0x04 其他
		startIndex += length;
		length = 1;
		byte[] businessTypeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String business = BytesUtil.bcd2Str(businessTypeByteArr);

		LoginRequestData loginRequestData = LoginRequestData.builder()
				.pileSn(pileSn)
				.pileType(pileType)
				.connectorNum(connectorNum)
				.communicationVersion(communicationVersion)
				.programVersion(programVersion)
				.internetConnection(internetConnection)
				.iccid(iccid)
				.business(business)
				.build();

		// 结果（默认 0x01:登录失败）
		byte[] flag = Constants.oneByteArray;

		// 通过桩编码SN查询数据库，如果有数据，则登录成功，否则登录失败
		QueryPileDTO dto = new QueryPileDTO();
		dto.setPileSn(pileSn);
		List<PileDetailVO> list = pileBasicInfoService.queryPileInfos(dto);
		if (CollectionUtils.isNotEmpty(list)) {
			flag = Constants.zeroByteArray;
			// 登录成功，保存桩号和channel的关系

			// PileChannelEntity.put(pileSn, channel);
			// 更改桩和该桩下的枪口状态分别为 在线、空闲
			// pileBasicInfoService.updatePileStatus(pileSn, PileStatusEnum.ON_LINE.getValue());
			// pileConnectorInfoService.updateConnectorStatusByPileSn(pileSn, PileConnectorDataBaseStatusEnum.FREE.getValue());

			// 对时
			ProofreadTimeCommand command = ProofreadTimeCommand.builder().pileSn(pileSn).build();
			ykcPushCommandService.pushProofreadTimeCommand(command);

			// 公共方法修改状态
			pileBasicInfoService.updateStatus(BytesUtil.bcd2Str(new byte[]{0x01}), pileSn, null, null, null);


			// 下发二维码
			IssueQRCodeCommand issueQRCodeCommand = IssueQRCodeCommand.builder().pileSn(pileSn).build();
			ykcPushCommandService.pushIssueQRCodeCommand(issueQRCodeCommand);

		}


		// 充电桩使用的sim卡，把信息存库
		if (StringUtils.equals("00", internetConnection)) {
			try {
				pileBasicInfoService.updatePileSimInfo(pileSn, iccid);
			} catch (Exception e) {
				// log.error("更新充电桩sim卡信息失败", e);
				System.out.println(e.getMessage());
			}
		}

		// 保存报文
		String jsonMsg = JSONObject.toJSONString(loginRequestData);
		// pileMsgRecordService.save(pileSn, pileSn, type, jsonMsg, ykcDataProtocol.getHEXString());

		// // 消息体
		// byte[] messageBody = Bytes.concat(pileSnByte, flag);
		// return getResult(ykcDataProtocol, messageBody);
	}

	@Test
	public void testGetMemberToken(){
		String memberId = JWTUtils.getMemberId("eyJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2NzY1MTY5MzgsImV4cCI6MTY3OTEwODkzOH0.4MwhZIOpnCfQloR7zEm2hwPOh2yyI2qxbBbTcv_SnZ4");
		System.out.println(memberId);
	}

}
