package com.slodon.b2b2c.model.promotion;

import com.alibaba.fastjson.JSON;
import com.slodon.b2b2c.core.constant.*;
import com.slodon.b2b2c.core.exception.MallException;
import com.slodon.b2b2c.core.response.PagerInfo;
import com.slodon.b2b2c.core.uid.CouponCode;
import com.slodon.b2b2c.core.util.AssertUtil;
import com.slodon.b2b2c.core.util.FileUrlUtil;
import com.slodon.b2b2c.core.util.StringUtil;
import com.slodon.b2b2c.core.util.TimeUtil;
import com.slodon.b2b2c.dao.read.promotion.CouponReadMapper;
import com.slodon.b2b2c.dao.read.promotion.DrawPrizeReadMapper;
import com.slodon.b2b2c.dao.read.promotion.DrawReadMapper;
import com.slodon.b2b2c.dao.read.promotion.DrawRecordReadMapper;
import com.slodon.b2b2c.dao.write.promotion.*;
import com.slodon.b2b2c.member.pojo.Member;
import com.slodon.b2b2c.promotion.dto.DrawDTO;
import com.slodon.b2b2c.promotion.example.DrawExample;
import com.slodon.b2b2c.promotion.example.DrawPrizeExample;
import com.slodon.b2b2c.promotion.example.DrawRecordExample;
import com.slodon.b2b2c.promotion.pojo.*;
import com.slodon.b2b2c.starter.mq.entity.MemberIntegralVO;
import com.slodon.b2b2c.starter.mq.entity.MessageSendProperty;
import com.slodon.b2b2c.starter.mq.entity.MessageSendVO;
import com.slodon.b2b2c.vo.promotion.DrawRecordVO;
import com.slodon.b2b2c.vo.promotion.DrawWinVO;
import com.slodon.b2b2c.vo.promotion.MemberDrawInfoVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static com.slodon.b2b2c.core.constant.StarterConfigConst.*;

/**
 * 抽奖活动表model
 */
@Component
@Slf4j
public class DrawModel {

    @Resource
    private DrawReadMapper drawReadMapper;
    @Resource
    private DrawWriteMapper drawWriteMapper;
    @Resource
    private DrawPrizeReadMapper drawPrizeReadMapper;
    @Resource
    private DrawPrizeWriteMapper drawPrizeWriteMapper;
    @Resource
    private DrawRecordReadMapper drawRecordReadMapper;
    @Resource
    private DrawRecordWriteMapper drawRecordWriteMapper;
    @Resource
    private CouponReadMapper couponReadMapper;
    @Resource
    private CouponWriteMapper couponWriteMapper;
    @Resource
    private CouponMemberWriteMapper couponMemberWriteMapper;
    @Resource
    private RabbitTemplate rabbitTemplate;
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 新增抽奖活动表
     *
     * @param draw
     * @return
     */
    public Integer saveDraw(Draw draw) {
        int count = drawWriteMapper.insert(draw);
        if (count == 0) {
            throw new MallException("添加抽奖活动表失败，请重试");
        }
        return draw.getDrawId();
    }

    /**
     * 根据drawId删除抽奖活动表
     *
     * @param drawId drawId
     * @return
     */
    public Integer deleteDraw(Integer drawId) {
        if (StringUtils.isEmpty(drawId)) {
            throw new MallException("请选择要删除的数据");
        }
        int count = drawWriteMapper.deleteByPrimaryKey(drawId);
        if (count == 0) {
            log.error("根据drawId：" + drawId + "删除抽奖活动表失败");
            throw new MallException("删除抽奖活动表失败,请重试");
        }
        return count;
    }

    /**
     * 根据drawId更新抽奖活动表
     *
     * @param draw
     * @return
     */
    public Integer updateDraw(Draw draw) {
        if (StringUtils.isEmpty(draw.getDrawId())) {
            throw new MallException("请选择要修改的数据");
        }
        int count = drawWriteMapper.updateByPrimaryKeySelective(draw);
        if (count == 0) {
            log.error("根据drawId：" + draw.getDrawId() + "更新抽奖活动表失败");
            throw new MallException("更新抽奖活动表失败,请重试");
        }
        return count;
    }

    /**
     * 根据drawId获取抽奖活动表详情
     *
     * @param drawId drawId
     * @return
     */
    public Draw getDrawByDrawId(Integer drawId) {
        return drawReadMapper.getByPrimaryKey(drawId);
    }

    /**
     * 根据条件获取抽奖活动表列表
     *
     * @param example 查询条件信息
     * @param pager   分页信息
     * @return
     */
    public List<Draw> getDrawList(DrawExample example, PagerInfo pager) {
        List<Draw> drawList;
        if (pager != null) {
            pager.setRowsCount(drawReadMapper.countByExample(example));
            drawList = drawReadMapper.listPageByExample(example, pager.getStart(), pager.getPageSize());
        } else {
            drawList = drawReadMapper.listByExample(example);
        }
        return drawList;
    }

    /**
     * 新增抽奖活动表,抽奖奖品表
     *
     * @param drawDTO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Integer saveDraw(DrawDTO drawDTO, Integer adminId) {
        //1.添加抽奖活动表
        Draw draw = new Draw();
        BeanUtils.copyProperties(drawDTO, draw);
        draw.setCreateAdminId(adminId);
        draw.setCreateTime(new Date());

        //定义综合中奖率
        Integer totalRate = 0;
        List<DrawDTO.DrawPrizeInfo> drawPrizeInfoList = drawDTO.getDrawPrizeInfoList();
        for (DrawDTO.DrawPrizeInfo drawPrizeInfo : drawPrizeInfoList) {
            totalRate += drawPrizeInfo.getRate();
        }
        draw.setTotalRate(totalRate);
        Integer drawId = this.saveDraw(draw);

        //2.添加抽奖奖品表
        for (DrawDTO.DrawPrizeInfo drawPrizeInfo : drawPrizeInfoList) {
            DrawPrize drawPrize = new DrawPrize();
            BeanUtils.copyProperties(drawPrizeInfo, drawPrize);
            drawPrize.setDrawId(drawId);
            if (!StringUtil.isNullOrZero(drawPrizeInfo.getCouponId())) {
                Coupon coupon = couponReadMapper.getByPrimaryKey(drawPrizeInfo.getCouponId());
                AssertUtil.notNull(coupon, "查询的优惠券信息为空");
                if (coupon.getCouponType() == CouponConst.COUPON_TYPE_1) {
                    String publishValue = coupon.getPublishValue().stripTrailingZeros().toPlainString();
                    drawPrize.setCouponName(publishValue + "元券");
                } else if (coupon.getCouponType() == CouponConst.COUPON_TYPE_2) {
                    String publishValue = coupon.getPublishValue().divide(new BigDecimal(10)).stripTrailingZeros().toPlainString();
                    drawPrize.setCouponName(publishValue + "折券");
                } else if (coupon.getCouponType() == CouponConst.COUPON_TYPE_3) {
                    String randomMin = coupon.getRandomMin().stripTrailingZeros().toPlainString();
                    String randomMax = coupon.getRandomMax().stripTrailingZeros().toPlainString();
                    drawPrize.setCouponName(randomMin + "~" + randomMax + "元随机券");
                }
                drawPrize.setCouponContent(coupon.getCouponContent());
            }
            int count = drawPrizeWriteMapper.insert(drawPrize);
            AssertUtil.notNullOrZero(count, "添加抽奖奖品表失败,请重试");
        }
        return drawId;
    }

    /**
     * 编辑抽奖活动表,抽奖奖品表
     *
     * @param drawDTO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Integer updateDraw(DrawDTO drawDTO) {
        //1.编辑抽奖活动表
        Draw draw = new Draw();
        BeanUtils.copyProperties(drawDTO, draw);

        //定义综合中奖率
        Integer totalRate = 0;
        //2.删除抽奖奖品表
        DrawPrizeExample example = new DrawPrizeExample();
        example.setDrawId(drawDTO.getDrawId());
        drawPrizeWriteMapper.deleteByExample(example);

        //3.添加抽奖奖品表
        List<DrawDTO.DrawPrizeInfo> drawPrizeInfoList = drawDTO.getDrawPrizeInfoList();
        for (DrawDTO.DrawPrizeInfo drawPrizeInfo : drawPrizeInfoList) {
            DrawPrize drawPrize = new DrawPrize();
            BeanUtils.copyProperties(drawPrizeInfo, drawPrize);
            drawPrize.setDrawId(drawDTO.getDrawId());
            if (!StringUtil.isNullOrZero(drawPrizeInfo.getCouponId())) {
                Coupon coupon = couponReadMapper.getByPrimaryKey(drawPrizeInfo.getCouponId());
                AssertUtil.notNull(coupon, "查询的优惠券信息为空");
                if (coupon.getCouponType() == CouponConst.COUPON_TYPE_1) {
                    String publishValue = coupon.getPublishValue().stripTrailingZeros().toPlainString();
                    drawPrize.setCouponName(publishValue + "元券");
                } else if (coupon.getCouponType() == CouponConst.COUPON_TYPE_2) {
                    String publishValue = coupon.getPublishValue().divide(new BigDecimal(10)).stripTrailingZeros().toPlainString();
                    drawPrize.setCouponName(publishValue + "折券");
                } else if (coupon.getCouponType() == CouponConst.COUPON_TYPE_3) {
                    String randomMin = coupon.getRandomMin().stripTrailingZeros().toPlainString();
                    String randomMax = coupon.getRandomMax().stripTrailingZeros().toPlainString();
                    drawPrize.setCouponName(randomMin + "~" + randomMax + "元随机券");
                }
                drawPrize.setCouponContent(coupon.getCouponContent());
            }
            drawPrizeWriteMapper.insert(drawPrize);

            totalRate += drawPrize.getRate();
        }
        draw.setTotalRate(totalRate);
        draw.setUpdateTime(new Date());
        return this.updateDraw(draw);
    }

    /**
     * 根据drawId删除抽奖活动表,抽奖奖品表
     *
     * @param drawId drawId
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Integer deleteDrawWithDrawPrize(Integer drawId) {
        //1.删除抽奖活动表
        int count = drawWriteMapper.deleteByPrimaryKey(drawId);
        if (count == 0) {
            log.error("根据drawId：" + drawId + "删除抽奖活动表失败");
            throw new MallException("删除抽奖活动表失败,请重试");
        }

        //2.删除抽奖奖品表
        DrawPrizeExample example = new DrawPrizeExample();
        example.setDrawId(drawId);
        count = drawPrizeWriteMapper.deleteByExample(example);
        AssertUtil.notNullOrZero(count, "删除抽奖奖品表失败,请重试");
        return count;
    }

    /**
     * 新增抽奖记录表
     *
     * @param draw     抽奖对象
     * @param memberDb 会员信息
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public MemberDrawInfoVO doDraw(Draw draw, Member memberDb) {
        MemberDrawInfoVO vo = new MemberDrawInfoVO();
        //key-奖品id，value-奖品对象
        Map<Integer, DrawPrize> map = new HashMap<>();
        //剩余概率为未中奖概率
        if (draw.getTotalRate() < 100) {
            DrawPrize prize = new DrawPrize();
            prize.setPrizeId(0);
            prize.setRate(100 - draw.getTotalRate());
            map.put(prize.getPrizeId(), prize);
        }
        //查询奖品信息
        DrawPrizeExample example = new DrawPrizeExample();
        example.setDrawId(draw.getDrawId());
        List<DrawPrize> list = drawPrizeReadMapper.listByExample(example);
        list.forEach(drawPrize -> {
            map.put(drawPrize.getPrizeId(), drawPrize);
        });
        //返回奖品id
        Integer prizeId = getRandomPrize(map);

        //记录积分消耗日志
        if (!StringUtil.isNullOrZero(draw.getIntegralUse())) {
            //记录抽奖消耗积分记录
            MemberIntegralVO memberIntegralVO = new MemberIntegralVO(memberDb.getMemberId(), memberDb.getMemberName(), draw.getIntegralUse(),
                    MemberIntegralLogConst.TYPE_14, "抽奖使用" + draw.getIntegralUse() + "积分", null, 0, "");
            rabbitTemplate.convertAndSend(MQ_EXCHANGE_NAME, MQ_QUEUE_NAME_MEMBER_INTEGRAL, memberIntegralVO);
            //查询会员信息
            memberDb.setMemberIntegral(memberDb.getMemberIntegral() - draw.getIntegralUse());
            //发送积分变动消息通知
            this.sendMsgIntegralChange(memberDb, "抽奖使用" + draw.getIntegralUse() + "积分");
        }

        //保存抽奖记录
        DrawRecord drawRecord = new DrawRecord();
        drawRecord.setDrawId(draw.getDrawId());
        if (prizeId != 0) {
            DrawPrize drawPrize = map.get(prizeId);

            //查询抽奖记录
            DrawRecordExample recordExample = new DrawRecordExample();
            recordExample.setDrawId(draw.getDrawId());
            recordExample.setPrizeId(prizeId);
            int recordCount = drawRecordReadMapper.countByExample(recordExample);
            //判断是否还有奖品
            if (recordCount >= drawPrize.getPrizeNum()) {
                drawRecord.setPrizeId(0);
                drawRecord.setPrizeName("未中奖");
                drawRecord.setIsPrize(DrawConst.IS_PRIZE_0);
                drawRecord.setDescription("未中奖");

                vo.setPrizeId(prizeId);
                vo.setPrizeName("未中奖");
                vo.setLosePrizeImage(FileUrlUtil.getFileUrl(draw.getLosePrizeImage(), null));
                vo.setIsPrize(DrawConst.IS_PRIZE_0);
                vo.setDescription("未中奖");
            } else {
                drawRecord.setPrizeId(prizeId);
                drawRecord.setPrizeName(drawPrize.getPrizeName());
                drawRecord.setIsPrize(DrawConst.IS_PRIZE_1);
                drawRecord.setPrizeType(drawPrize.getPrizeType());

                vo.setPrizeId(prizeId);
                vo.setPrizeName(drawPrize.getPrizeName());
                vo.setPrizeImage(FileUrlUtil.getFileUrl(drawPrize.getPrizeImage(), null));
                vo.setIsPrize(DrawConst.IS_PRIZE_1);
                vo.setPrizeType(drawPrize.getPrizeType());
                if (drawPrize.getPrizeType() == DrawConst.PRIZE_TYPE_1) {
                    drawRecord.setDescription(drawPrize.getIntegralNum() + "积分");
                    vo.setDescription(drawPrize.getIntegralNum() + "积分");

                    //记录抽奖积分日志
                    if (!StringUtil.isNullOrZero(drawPrize.getIntegralNum())) {
                        //记录抽奖消耗积分记录
                        MemberIntegralVO memberIntegralVO = new MemberIntegralVO(memberDb.getMemberId(), memberDb.getMemberName(), drawPrize.getIntegralNum(),
                                MemberIntegralLogConst.TYPE_5, "抽奖抽中" + drawPrize.getIntegralNum() + "积分", null, 0, "");
                        rabbitTemplate.convertAndSend(MQ_EXCHANGE_NAME, MQ_QUEUE_NAME_MEMBER_INTEGRAL, memberIntegralVO);
                        //查询会员信息
                        memberDb.setMemberIntegral(memberDb.getMemberIntegral() - draw.getIntegralUse());
                        //发送积分变动消息通知
                        this.sendMsgIntegralChange(memberDb, "抽奖抽中" + drawPrize.getIntegralNum() + "积分");
                    }
                } else {
                    Coupon coupon = couponReadMapper.getByPrimaryKey(drawPrize.getCouponId());
                    //判断是否还有优惠券
                    if (coupon == null || coupon.getReceivedNum() >= coupon.getPublishNum()) {
                        drawRecord.setPrizeId(0);
                        drawRecord.setPrizeName("未中奖");
                        drawRecord.setIsPrize(DrawConst.IS_PRIZE_0);
                        drawRecord.setDescription("未中奖");

                        vo.setPrizeId(prizeId);
                        vo.setPrizeName("未中奖");
                        vo.setLosePrizeImage(FileUrlUtil.getFileUrl(draw.getLosePrizeImage(), null));
                        vo.setIsPrize(DrawConst.IS_PRIZE_0);
                        vo.setDescription("未中奖");
                    } else {
                        vo.setCouponType(coupon.getCouponType());
                        vo.setPublishValue(coupon.getPublishValue());
                        vo.setRandomMin(coupon.getRandomMin());
                        vo.setRandomMax(coupon.getRandomMax());

                        //奖励优惠券记录
                        CouponMember couponMember = new CouponMember();
                        couponMember.setMemberId(memberDb.getMemberId());
                        couponMember.setMemberName(memberDb.getMemberName());
                        couponMember.setCouponId(coupon.getCouponId());
                        couponMember.setCouponCode(CouponCode.getKey());
                        couponMember.setReceiveTime(new Date());
                        couponMember.setUseState(CouponConst.USE_STATE_1);
                        couponMember.setStoreId(coupon.getStoreId());
                        if (coupon.getEffectiveTimeType() == CouponConst.EFFECTIVE_TIME_TYPE_2) {
                            couponMember.setEffectiveStart(new Date());
                            couponMember.setEffectiveEnd(TimeUtil.getDateApartDay(coupon.getCycle()));

                            vo.setEffectiveStart(new Date());
                            vo.setEffectiveEnd(TimeUtil.getDateApartDay(coupon.getCycle()));
                        } else {
                            couponMember.setEffectiveStart(coupon.getEffectiveStart());
                            couponMember.setEffectiveEnd(coupon.getEffectiveEnd());

                            vo.setEffectiveStart(coupon.getEffectiveStart());
                            vo.setEffectiveEnd(coupon.getEffectiveEnd());
                        }
                        couponMember.setUseType(coupon.getUseType());

                        Object key = null;
                        if (coupon.getCouponType() == CouponConst.COUPON_TYPE_1) {
                            String publishValue = coupon.getPublishValue().stripTrailingZeros().toPlainString();
                            drawRecord.setDescription(publishValue + "元优惠券");
                            vo.setDescription(publishValue + "元优惠券");
                        } else if (coupon.getCouponType() == CouponConst.COUPON_TYPE_2) {
                            String publishValue = coupon.getPublishValue().divide(new BigDecimal(10)).stripTrailingZeros().toPlainString();
                            drawRecord.setDescription(publishValue + "折优惠券");
                            vo.setDescription(publishValue + "折优惠券");
                        } else if (coupon.getCouponType() == CouponConst.COUPON_TYPE_3) {
                            Map<Object, Object> couponMap = stringRedisTemplate.opsForHash().entries(RedisConst.COUPON_PREFIX + coupon.getCouponId());
                            BigDecimal amount = BigDecimal.ZERO;
                            for (Map.Entry<Object, Object> entry : couponMap.entrySet()) {
                                key = entry.getKey();
                                amount = new BigDecimal((String) entry.getValue());
                                break;
                            }
                            String publishValue = amount.stripTrailingZeros().toPlainString();
                            drawRecord.setDescription(publishValue + "元优惠券");
                            vo.setDescription(publishValue + "元优惠券");
                            couponMember.setRandomAmount(amount);
                        }
                        int count = couponMemberWriteMapper.insert(couponMember);
                        AssertUtil.notNullOrZero(count, "奖励优惠券失败");

                        //更新优惠券领取数量
                        Coupon updateCoupon = new Coupon();
                        updateCoupon.setCouponId(coupon.getCouponId());
                        updateCoupon.setReceivedNum(coupon.getReceivedNum() + 1);
                        count = couponWriteMapper.updateByPrimaryKeySelective(updateCoupon);
                        AssertUtil.isTrue(count == 0, "更新优惠券领取数量信息失败，请重试！");

                        //最后删除获取的数据
                        if (coupon.getCouponType() == CouponConst.COUPON_TYPE_3 && key != null) {
                            stringRedisTemplate.opsForHash().delete(RedisConst.COUPON_PREFIX + couponMember.getCouponId(), key);
                        }
                    }
                }
            }
        } else {
            drawRecord.setPrizeId(0);
            drawRecord.setPrizeName("未中奖");
            drawRecord.setIsPrize(DrawConst.IS_PRIZE_0);
            drawRecord.setDescription("未中奖");

            vo.setPrizeId(prizeId);
            vo.setPrizeName("未中奖");
            vo.setLosePrizeImage(FileUrlUtil.getFileUrl(draw.getLosePrizeImage(), null));
            vo.setIsPrize(DrawConst.IS_PRIZE_0);
            vo.setDescription("未中奖");
        }
        drawRecord.setMemberId(memberDb.getMemberId());
        drawRecord.setMemberName(memberDb.getMemberName());
        drawRecord.setRecordTime(new Date());
        drawRecord.setUseIntegral(draw.getIntegralUse());
        int count = drawRecordWriteMapper.insert(drawRecord);
        if (count == 0) {
            throw new MallException("添加抽奖记录表失败，请重试");
        }
        //如果中奖存入redis
        if (drawRecord.getIsPrize() == DrawConst.IS_PRIZE_1) {
            this.cacheData(drawRecord, draw.getEndTime());
        }
        return vo;
    }

    /**
     * 中奖信息存入redis
     *
     * @param drawRecord 中奖信息
     * @param endTime    结束时间
     */
    public void cacheData(DrawRecord drawRecord, Date endTime) {
        DrawWinVO vo = new DrawWinVO();
        vo.setWinId(UUID.randomUUID().toString());
        vo.setPrizeId(drawRecord.getPrizeId());
        vo.setPrizeName(drawRecord.getPrizeName());
        vo.setMemberId(drawRecord.getMemberId());
        vo.setMemberName(drawRecord.getMemberName());
        vo.setMemberNameHide(DrawRecordVO.dealMemberNameHide(drawRecord.getMemberName()));
        vo.setPrizeType(drawRecord.getPrizeType());
        vo.setIsVirtualData(DrawConst.IS_VIRTUAL_DATA_1);
        stringRedisTemplate.opsForZSet().add(RedisConst.DRAW_PREFIX + drawRecord.getDrawId(), JSON.toJSONString(vo), System.currentTimeMillis());
        //设置过期时间
        long remainedTime = endTime.getTime() - System.currentTimeMillis();
        stringRedisTemplate.expire(RedisConst.DRAW_PREFIX + drawRecord.getDrawId(), remainedTime, TimeUnit.MILLISECONDS);
    }

    /**
     * 生成随机奖励
     *
     * @param map
     * @return 奖品id
     */
    public Integer getRandomPrize(Map<Integer, DrawPrize> map) {
        Set<Integer> keySet = map.keySet();
        List<Integer> weights = new ArrayList<>();
        for (Iterator<Integer> it = keySet.iterator(); it.hasNext(); ) {
            Integer weightStr = it.next();
            int weight = map.get(weightStr).getRate();
            for (int i = 0; i < weight; i++) {
                weights.add(weightStr);
            }
        }
        int idx = new Random().nextInt(weights.size());
        return weights.get(idx);
    }

    /**
     * 发送积分变动消息通知
     *
     * @param member 会员信息
     */
    public void sendMsgIntegralChange(Member member, String description) {
        //日期格式转换
        String now = TimeUtil.getDateTimeString(new Date());
        //消息通知
        //微信消息通知
        List<MessageSendProperty> messageSendPropertyList = new ArrayList<>();
        messageSendPropertyList.add(new MessageSendProperty("first", "您的账户发生了积分变动。"));
        messageSendPropertyList.add(new MessageSendProperty("keyword1", now));
        messageSendPropertyList.add(new MessageSendProperty("keyword2", description));
        messageSendPropertyList.add(new MessageSendProperty("keyword3", member.getMemberIntegral().toString()));
        String msgLinkInfo = "{\"type\":\"integral_change\"}";
        String[] templateParam = {now, description, member.getMemberIntegral().toString()};
        MessageSendVO messageSendVO = new MessageSendVO(messageSendPropertyList, member.getMemberId(),
                MemberTplConst.INTEGRAL_CHANGE_REMINDER, msgLinkInfo, templateParam);
        //发送到mq
        rabbitTemplate.convertAndSend(MQ_EXCHANGE_NAME, MQ_QUEUE_NAME_MEMBER_MSG, messageSendVO);
    }

}