发送邮件配置邮件模板

This commit is contained in:
limqhz
2022-05-15 21:38:11 +08:00
parent e51efb81f4
commit cce09bf997
18 changed files with 333 additions and 29 deletions

View File

@@ -0,0 +1,14 @@
package com.quinn.common;
public enum EmailType {
/**
* 论坛
*/
REGISTER,
/**
* 资源
*/
SUCCESS
}

View File

@@ -35,4 +35,6 @@ public interface QuinnConstant {
String DEFAULT_ATTR_BASE64 = "/images/avatar/a1.png"; String DEFAULT_ATTR_BASE64 = "/images/avatar/a1.png";
String DEFAULT_ATTR = "/images/avatar/a#.png"; String DEFAULT_ATTR = "/images/avatar/a#.png";
String EMAIL_REPLACE = "#!!#";
} }

View File

@@ -28,7 +28,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
// 访问权限 // 访问权限
http.authorizeRequests() http.authorizeRequests()
.antMatchers("/","/index","/favicon.ico").permitAll() .antMatchers("/","/index","/favicon.ico").permitAll()
.antMatchers("/register","/login","/toLogin","/checkLogin").permitAll() .antMatchers("/register","/login","/toLogin","/checkLogin","/checkRegister").permitAll()
.antMatchers("/source","/source/view/*").permitAll() .antMatchers("/source","/source/view/*").permitAll()
.antMatchers("/blog","/blog/read/*").permitAll() .antMatchers("/blog","/blog/read/*").permitAll()
.antMatchers("/search/**").permitAll() .antMatchers("/search/**").permitAll()

View File

@@ -79,20 +79,27 @@ public class LoginController {
// 表单密码重复判断 // 表单密码重复判断
if (!registerForm.getPassword().equals(registerForm.getRepassword())){ if (!registerForm.getPassword().equals(registerForm.getRepassword())){
toResult(writer,"两次输入密码不一致!"); toResult(writer,"两次输入密码不一致!");
return;
} }
// 用户名已存在 // 用户名已存在
User hasUser = userService.getOne(new QueryWrapper<User>().eq("username", registerForm.getUsername())); User hasUser = userService.getOne(new QueryWrapper<User>().eq("username", registerForm.getUsername()));
if (hasUser!=null){ if (hasUser!=null){
toResult(writer,"用户名太热门了,请更换用户名"); toResult(writer,"用户名太热门了,请更换用户名");
return;
} }
// 验证邀请码 // 验证邀请码
Invite invite = inviteService.getOne(new QueryWrapper<Invite>().eq("code", registerForm.getCode())); Invite invite = inviteService.getOne(new QueryWrapper<Invite>()
.eq("code", registerForm.getCode())
.eq("status",'0'));
if (invite==null){ if (invite==null){
toResult(writer,"注册码不存在!"); toResult(writer,"注册码不存在!");
return;
} }
if (!invite.getApplyEmail().equals(registerForm.getEmail())){ if (!invite.getApplyEmail().equals(registerForm.getEmail())){
toResult(writer,"请使用申请注册码邮箱注册用户!"); toResult(writer,"请使用申请注册码邮箱注册用户!");
return;
} }
toResult(writer,"ok");
} }
// 注册业务 // 注册业务

View File

@@ -3,6 +3,7 @@ package com.quinn.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.quinn.common.EmailType;
import com.quinn.dto.req.SearchPage; import com.quinn.dto.req.SearchPage;
import com.quinn.dto.req.SendCode; import com.quinn.dto.req.SendCode;
import com.quinn.dto.res.AboutDTO; import com.quinn.dto.res.AboutDTO;
@@ -10,23 +11,15 @@ import com.quinn.dto.res.ResponseDTO;
import com.quinn.intergration.SendBMail; import com.quinn.intergration.SendBMail;
import com.quinn.pojo.About; import com.quinn.pojo.About;
import com.quinn.pojo.Invite; import com.quinn.pojo.Invite;
import com.quinn.pojo.UserInfo;
import com.quinn.service.AboutService; import com.quinn.service.AboutService;
import com.quinn.service.InviteService; import com.quinn.service.InviteService;
import com.quinn.service.UserInfoService;
import com.quinn.service.UserService;
import com.quinn.utils.QuinnUtils; import com.quinn.utils.QuinnUtils;
import com.quinn.vo.MyPageParam; import com.quinn.vo.MyPageParam;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -44,9 +37,9 @@ public class WxController extends BaseModelController {
@Resource @Resource
AboutService aboutService; AboutService aboutService;
@Resource @Resource
UserInfoService userInfoService;
@Resource
InviteService inviteService; InviteService inviteService;
@Resource
SendBMail sendBMail;
@PostMapping("about/us") @PostMapping("about/us")
public ResponseDTO userIndexBlog(SearchPage searchPage){ public ResponseDTO userIndexBlog(SearchPage searchPage){
@@ -83,9 +76,9 @@ public class WxController extends BaseModelController {
invite.setCode(code); invite.setCode(code);
invite.setGmtCreate(QuinnUtils.getTime()); invite.setGmtCreate(QuinnUtils.getTime());
inviteService.save(invite); inviteService.save(invite);
boolean sendFlag = SendBMail.INSTANCE.sendRegisterMail(code, sendCode.getEmail()); boolean sendFlag = sendBMail.sendOneParamMail(EmailType.REGISTER,code, sendCode.getEmail());
if (!sendFlag){ if (!sendFlag){
return ResponseDTO.ok().setData("发送识别,请确认邮箱是否正确!"); return ResponseDTO.ok().setData("发送失败,请确认邮箱是否正确!");
} }
return ResponseDTO.ok().setData("success"); return ResponseDTO.ok().setData("success");
} }

View File

@@ -51,7 +51,7 @@ public class CodeGenerator {
// 5、策略配置 // 5、策略配置
StrategyConfig strategy = new StrategyConfig(); StrategyConfig strategy = new StrategyConfig();
strategy.setInclude("qn_star");//设置要映射的表名 strategy.setInclude("qn_email");//设置要映射的表名
strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略 strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略
strategy.setTablePrefix("qn_");//设置表前缀不生成 strategy.setTablePrefix("qn_");//设置表前缀不生成

View File

@@ -1,7 +1,16 @@
package com.quinn.intergration; package com.quinn.intergration;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.quinn.common.EmailType;
import com.quinn.common.QuinnConstant;
import com.quinn.pojo.Email;
import com.quinn.service.EmailService;
import com.quinn.utils.SpringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.mail.Authenticator; import javax.mail.Authenticator;
import javax.mail.Message; import javax.mail.Message;
import javax.mail.PasswordAuthentication; import javax.mail.PasswordAuthentication;
@@ -9,15 +18,16 @@ import javax.mail.Session;
import javax.mail.Transport; import javax.mail.Transport;
import javax.mail.internet.InternetAddress; import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMessage;
import java.util.Map;
import java.util.Properties; import java.util.Properties;
/** /**
* 使用@multiavatar生成头像 * 使用@multiavatar生成头像
* https://api.multiavatar.com/ * https://api.multiavatar.com/
*/ */
public enum SendBMail { @Component
public class SendBMail {
INSTANCE;
private static final Logger log = LoggerFactory.getLogger(SendBMail.class); private static final Logger log = LoggerFactory.getLogger(SendBMail.class);
final String username = "quinn.admin@88.com"; final String username = "quinn.admin@88.com";
final String password = "Y3YYd4hcY2fFB9VY"; final String password = "Y3YYd4hcY2fFB9VY";
@@ -27,14 +37,18 @@ public enum SendBMail {
boolean isAuth = true; boolean isAuth = true;
String from = "quinn.admin@88.com"; String from = "quinn.admin@88.com";
public boolean sendRegisterMail(String registerCode,String email){ @Resource
return sendMail("QUINN注册码", EmailService emailService;
"您好,您的注册码是【" + registerCode + "",email);
public boolean sendOneParamMail(EmailType emailType, String param, String email){
// 可以设计枚举,使用同一个发送邮件的公共方法
Email register = emailService.getOne(new QueryWrapper<Email>().eq("type",emailType.name()));
String content = register.getContent().replace(QuinnConstant.EMAIL_REPLACE, param);
return sendMail(register.getTitle(), content,email);
} }
public boolean sendWelcome(String username,String email){ public boolean sendParamsMail(EmailType emailType, String email, Map<String,String> map){
return sendMail("QUINN-注册成功", return true;
username + "您好,欢迎使用!",email);
} }
private boolean sendMail(String subject,String content,String toEmail){ private boolean sendMail(String subject,String content,String toEmail){
@@ -60,6 +74,7 @@ public enum SendBMail {
log.error("发送邮件失败",e); log.error("发送邮件失败",e);
return false; return false;
} }
log.info("发送邮件成功"+toEmail);
return true; return true;
} }

View File

@@ -0,0 +1,16 @@
package com.quinn.mapper;
import com.quinn.pojo.Email;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @author limqsh
* @since 2022-05-15
*/
public interface EmailMapper extends BaseMapper<Email> {
}

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.quinn.mapper.EmailMapper">
</mapper>

View File

@@ -0,0 +1,48 @@
package com.quinn.pojo;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType;
import java.util.Date;
import com.baomidou.mybatisplus.annotation.TableId;
import java.io.Serializable;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* <p>
*
* </p>
*
* @author limqsh
* @since 2022-05-15
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("qn_email")
@ApiModel(value="Email对象", description="")
public class Email implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "唯一id")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@ApiModelProperty(value = "类型")
private String type;
@ApiModelProperty(value = "标题")
private String title;
@ApiModelProperty(value = "内容")
private String content;
@ApiModelProperty(value = "时间")
private Date gmtCreate;
}

View File

@@ -0,0 +1,16 @@
package com.quinn.service;
import com.quinn.pojo.Email;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 服务类
* </p>
*
* @author limqsh
* @since 2022-05-15
*/
public interface EmailService extends IService<Email> {
}

View File

@@ -0,0 +1,20 @@
package com.quinn.service.impl;
import com.quinn.pojo.Email;
import com.quinn.mapper.EmailMapper;
import com.quinn.service.EmailService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
* <p>
* 服务实现类
* </p>
*
* @author limqsh
* @since 2022-05-15
*/
@Service
public class EmailServiceImpl extends ServiceImpl<EmailMapper, Email> implements EmailService {
}

View File

@@ -1,6 +1,8 @@
package com.quinn.task; package com.quinn.task;
import com.quinn.common.EmailType;
import com.quinn.intergration.SendBMail; import com.quinn.intergration.SendBMail;
import com.quinn.utils.SpringUtils;
import lombok.Data; import lombok.Data;
@Data @Data
@@ -17,6 +19,7 @@ public class SendAsyncEmail implements Runnable{
@Override @Override
public void run() { public void run() {
SendBMail.INSTANCE.sendWelcome(username,email); SendBMail sendBMail = SpringUtils.getBean(SendBMail.class);
sendBMail.sendOneParamMail(EmailType.SUCCESS,username,email);
} }
} }

View File

@@ -0,0 +1,34 @@
package com.quinn.utils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class SpringUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext;
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
public static<T> T getBean(Class<T> tClass) {
return getApplicationContext().getBean(tClass);
}
public static<T> T getBean(String name,Class<T> tClass) {
return getApplicationContext().getBean(name,tClass);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (SpringUtils.applicationContext == null){
SpringUtils.applicationContext = applicationContext;
}
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
}

View File

@@ -17,6 +17,7 @@
background: url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAIAAAAmkwkpAAAAHklEQVQImWNkYGBgYGD4//8/A5wF5SBYyAr+//8PAPOCFO0Q2zq7AAAAAElFTkSuQmCC) repeat;text-shadow: 5px -5px black, 4px -4px white;font-weight: bold;-webkit-text-fill-color: transparent;-webkit-background-clip: text background: url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAIAAAAmkwkpAAAAHklEQVQImWNkYGBgYGD4//8/A5wF5SBYyAr+//8PAPOCFO0Q2zq7AAAAAElFTkSuQmCC) repeat;text-shadow: 5px -5px black, 4px -4px white;font-weight: bold;-webkit-text-fill-color: transparent;-webkit-background-clip: text
} }
.invertedContent p{ .invertedContent p{
text-align: center;
background: url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAIAAAAmkwkpAAAAHklEQVQImWNkYGBgYGD4//8/A5wF5SBYyAr+//8PAPOCFO0Q2zq7AAAAAElFTkSuQmCC) repeat;text-shadow: 2px -2px black, 1px -1px white;font-weight: bold;-webkit-text-fill-color: transparent;-webkit-background-clip: text background: url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAIAAAAmkwkpAAAAHklEQVQImWNkYGBgYGD4//8/A5wF5SBYyAr+//8PAPOCFO0Q2zq7AAAAAElFTkSuQmCC) repeat;text-shadow: 2px -2px black, 1px -1px white;font-weight: bold;-webkit-text-fill-color: transparent;-webkit-background-clip: text
} }
#fastLink{ #fastLink{
@@ -30,7 +31,20 @@
<div class="container "> <div class="container ">
<div class="jumbotron jumbotron-fluid mt-5"> <div class="jumbotron jumbotron-fluid mt-5">
<div class="container"> <div class="container">
<h1 class="display-3 inverted">Quinn</h1> <h2 style="margin: 0;padding: 0;text-align: center;color: #3A3A3A;font-size: 30px;">
<span style="width: 20px;height: 20px;background: #00C6FF;display: inline-block;position: relative;left: 10px;top: 5px;">
</span>
<i style="width: 20px;height: 20px;z-index: 2;background: #FFB900;display: inline-block;position: relative;left: -30px;top: 10px;">
</i>
<strong style="position: relative;">QUINN</strong>
<b style="width: 20px;height: 20px;background: #00C6FF;display: inline-block;position: relative;left: 40px;top: 5px;">
</b>
<em style="width: 20px;height: 20px;background: #FFB900;display: inline-block;position: relative;left: 0px;top: 10px;">
</em>
</h2>
<p style="margin: 0;padding: 0;text-align: center;color: #969696; font-size: 14px;">
私人博客平台
</p>
<br/> <br/>
<div class="lead invertedContent"> <div class="lead invertedContent">
<p>欢迎访问</p> <p>欢迎访问</p>
@@ -41,7 +55,8 @@
<p>戳下方了解详情↓↓↓</p> <p>戳下方了解详情↓↓↓</p>
</div> </div>
<div id="fastLink" class="row"> <div id="fastLink" class="row">
<div class="col-md-1"> <div class="col-md-4"></div>
<div class="ml-2 col-md-1">
<a th:href="@{/blog/read/1}" class="text-dark font-weight-bold text-decoration-none"> <a th:href="@{/blog/read/1}" class="text-dark font-weight-bold text-decoration-none">
<p class= "badge badge-pill badge-dark">注册说明 <p class= "badge badge-pill badge-dark">注册说明
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-postcard-fill" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-postcard-fill" viewBox="0 0 16 16">
@@ -71,6 +86,7 @@
</p> </p>
</a> </a>
</div> </div>
<div class="col-md-4"></div>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -0,0 +1,108 @@
<body>
<style type="text/css">
.qmbox body {
margin: 0 auto;
padding: 0;
font-family: Microsoft Yahei, Tahoma, Arial;
color: #333333;
background-color: #fff;
font-size: 12px;
}
.qmbox a {
color: text-decoration: none
}
</style>
<style>
.qmbox .body {
color: #5E5E5E;
}
.qmbox * {
font-family: '微软雅黑';
}
.qmbox a {
cursor: pointer;
outline: none;
text-decoration: none;
}
.qmbox li {
list-style-type: none;
}
.qmbox table tr th {
font-weight: 100;
}
.qmbox table tr th li p {
font-size: 18px;
}
</style>
<table width="800" border="0" align="center" cellpadding="0" cellspacing="0" height="48"
style="font-family:'Microsoft YaHei';">
<tbody>
<tr>
<div style="width:800px;margin:0 auto;text-align:left;">
<table width="944px" style="margin: 0 auto">
<tbody>
<tr style="width: 100%;height: 100px;">
<td style="width: 994px;height: 100px;margin: 0 auto;padding-top: 10px;">
<h2
style="margin: 0;padding: 0;text-align: center;color: #3A3A3A;font-size: 30px;">
<span
style="width: 20px;height: 20px;background: #00C6FF;display: inline-block;position: relative;left: 10px;top: 5px;">
</span>
<i
style="width: 20px;height: 20px;z-index: 2;background: #FFB900;display: inline-block;position: relative;left: -30px;top: 10px;">
</i>
<strong style="position: relative;">QUINN</strong>
<b
style="width: 20px;height: 20px;background: #00C6FF;display: inline-block;position: relative;left: 40px;top: 5px;">
</b>
<em
style="width: 20px;height: 20px;background: #FFB900;display: inline-block;position: relative;left: 0px;top: 10px;">
</em>
</h2>
<p
style="margin: 0;padding: 0;text-align: center;color: #969696; font-size: 14px;">
私人博客平台
</p>
</td>
</tr>
<tr style="min-height: 234px;width: 100%;margin-bottom: 20px;">
<td
style="min-height: 182px;width: 852px;margin: 0 auto;padding: 26px 46px;border: 1px #ECECEC solid;position: relative;">
<span
style="width: 8px;height: 35px;display: table-cell;background: #00C6FF;position: absolute;left: 31px;"></span>
<h3
style="display: table-cell;margin: 0;padding: 0;font-size: 22px;line-height: 35px;">
注册成功
</h3>
<p style="margin: 0;padding: 0;font-size: 20px;margin-top: 20px;">
尊敬的#!!#,您好!您已经注册成功,欢迎使用您的专属个人博客平台。
</p>
<a style="cursor: pointer;outline: none;text-decoration: none;width: 134px;height: 40px;margin-top: 36px;line-height: 40px;text-align:center;display: inline-block;background: #00C6FF;color: #fff;font-weight: 450;"
href="https://www.qnforever.top"
target="_blank" rel="noopener">
访问
</a>
</td>
</tr>
<tr height="36px;">
<td></td>
</tr>
</tbody>
</table>
</div>
</tr>
<tr>
<div style="height: 400px;width:800px;margin:0 auto;background: url(https://www.qnforever.top/images/menu/register.png) no-repeat;background-size: 100% 100%;"></div>
</tr>
<tr>
<p style="margin: 0 auto;text-align: center;">感谢! © Quinn</p>
</tr>
</tbody>
</table>
</body>

View File

@@ -38,7 +38,7 @@
<label for="code">注册码</label> <label for="code">注册码</label>
<input id="code" type="text" name="code" class="form-control" placeholder="注册码" required> <input id="code" type="text" name="code" class="form-control" placeholder="注册码" required>
</div> </div>
<button class="btn btn-dark btn-block" type="button" onclick="javascript:registerSubmit();">注 册</button> <button class="btn btn-dark btn-block" type="button" onclick="registerSubmit();">注 册</button>
<p class="mt-1 clearfix"> <p class="mt-1 clearfix">
<a style="color: white" th:href="@{/toLogin}" class="float-right text-decoration-none">已有账号?去登录</a> <a style="color: white" th:href="@{/toLogin}" class="float-right text-decoration-none">已有账号?去登录</a>
</p> </p>
@@ -85,12 +85,14 @@
layer.open({ content: '注册码格式不正确', skin: 'msg', time: 2 }); layer.open({ content: '注册码格式不正确', skin: 'msg', time: 2 });
return; return;
} }
console.log(123);
$.ajax({ $.ajax({
url: "/checkRegister", url: "/checkRegister",
async: false, async: false,
type: "post", type: "post",
data: {"username":username,"password":password,"repassword":repassword,"email":email,"code":code}, data: {"username":username,"password":password,"repassword":repassword,"email":email,"code":code},
success: function (data) { success: function (data) {
console.log(data);
if(data == 'ok'){ if(data == 'ok'){
this.disabled = true; this.disabled = true;
$('#registerForm').submit(); $('#registerForm').submit();

View File

@@ -1,7 +1,9 @@
package com.quinn.test; package com.quinn.test;
import com.quinn.QuinnApplication; import com.quinn.QuinnApplication;
import com.quinn.common.EmailType;
import com.quinn.common.QuinnConstant; import com.quinn.common.QuinnConstant;
import com.quinn.intergration.SendBMail;
import com.quinn.pojo.Source; import com.quinn.pojo.Source;
import com.quinn.service.SourceService; import com.quinn.service.SourceService;
import com.quinn.utils.RedisUtils; import com.quinn.utils.RedisUtils;
@@ -25,14 +27,17 @@ public class RedisTest {
@Resource @Resource
RedisUtils redisUtils; RedisUtils redisUtils;
@Resource
SendBMail sendBMail;
@Test @Test
public void updateViewTask(){ public void updateViewTask(){
} }
@Test @Test
public void setTestKey(){ public void sendEmail(){
sendBMail.sendOneParamMail(EmailType.SUCCESS,"1234","540344226@qq.com");
} }
} }