Commit 5dca3a75 authored by zhh's avatar zhh
Browse files

demo前端模版添加

parent 109a95d3
...@@ -12,7 +12,9 @@ MyBatisGenerator | 代码生成 ...@@ -12,7 +12,9 @@ MyBatisGenerator | 代码生成
PageHelper | MyBatis物理分页插件 PageHelper | MyBatis物理分页插件
Thymeleaf | 模板引擎 Thymeleaf | 模板引擎
Swagger-UI | 文档生产工具 Swagger-UI | 文档生产工具
Fluent-validator | 验证框架 Hibernator-Validator | 验证框架
Vue | 前端框架
AdminLte | 前端模版
####框架搭建 ####框架搭建
功能 | 完成 功能 | 完成
...@@ -20,11 +22,20 @@ Fluent-validator | 验证框架 ...@@ -20,11 +22,20 @@ Fluent-validator | 验证框架
集成MyBatis | ✔ 集成MyBatis | ✔
集成MyBatisGenerator | ✔ 集成MyBatisGenerator | ✔
集成SpringSecurity | ✔ 集成SpringSecurity | ✔
集成Swagger-UI | 集成Swagger-UI |
集成Hibernator-Validator | ✔ 集成Hibernator-Validator | ✔
对通用返回结果进行封装 | ✔ 对通用返回结果进行封装 | ✔
crud操作demo | ✔ crud操作demo | ✔
添加分页查询功能 | ✔ 添加分页查询功能 | ✔
集成日志功能 | ✔ 集成日志功能 | ✔
集成监控功能 | ✔ 集成监控功能 | ✔
包结构调整 | ✔ 包结构调整 | ✔
\ No newline at end of file SpringSecurity登录改为Restful形式 |
####功能完善
后台登录功能
商品管理
促销管理
内容管理
用户管理
订单管理
\ No newline at end of file
...@@ -29,7 +29,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { ...@@ -29,7 +29,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception { protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()//配置权限 http.authorizeRequests()//配置权限
// .antMatchers("/").access("hasRole('TEST')")//该路径需要TEST角色 // .antMatchers("/").access("hasRole('TEST')")//该路径需要TEST角色
// .antMatchers("/brand/list").authenticated()//该路径需要登录认证 .antMatchers("/").authenticated()//该路径需要登录认证
// .antMatchers("/brand/list").hasAuthority("TEST")//该路径需要TEST权限 // .antMatchers("/brand/list").hasAuthority("TEST")//该路径需要TEST权限
.antMatchers("/**").permitAll() .antMatchers("/**").permitAll()
.and()//启用基于http的认证 .and()//启用基于http的认证
...@@ -48,6 +48,9 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { ...@@ -48,6 +48,9 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
// .key("rememberMeKey") // .key("rememberMeKey")
.and()//关闭跨域伪造 .and()//关闭跨域伪造
.csrf() .csrf()
.disable()
.headers()//去除X-Frame-Options
.frameOptions()
.disable(); .disable();
} }
......
...@@ -6,10 +6,17 @@ spring.datasource.password=root ...@@ -6,10 +6,17 @@ spring.datasource.password=root
mybatis.mapper-locations=classpath:mapper/*.xml,classpath*:com/**/mapper/*.xml mybatis.mapper-locations=classpath:mapper/*.xml,classpath*:com/**/mapper/*.xml
#日志配置DEBUG,INFO,WARN,ERROR #日志配置DEBUG,INFO,WARN,ERROR
logging.level.root=warn logging.level.root=info
#单独配置日志级别 #单独配置日志级别
logging.level.com.macro.mall=debug logging.level.com.macro.mall=debug
#配置日志生成路径 #配置日志生成路径
#logging.path=/var/logs #logging.path=/var/logs
#配置日志文件名称 #配置日志文件名称
#logging.file=demo_log.log #logging.file=demo_log.log
\ No newline at end of file #thymeleaf start
spring.thymeleaf.mode=HTML5
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.content-type=text/html
#开发时关闭缓存,不然没法看到实时页面
spring.thymeleaf.cache=false
#thymeleaf end
\ No newline at end of file
...@@ -9,11 +9,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter ...@@ -9,11 +9,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
@SpringBootApplication @SpringBootApplication
@MapperScan("com.macro.mall.mapper") @MapperScan("com.macro.mall.mapper")
public class MallDemoApplication extends WebMvcConfigurerAdapter{ public class MallDemoApplication{
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
}
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(MallDemoApplication.class, args); SpringApplication.run(MallDemoApplication.class, args);
} }
......
...@@ -31,7 +31,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { ...@@ -31,7 +31,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception { protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()//配置权限 http.authorizeRequests()//配置权限
// .antMatchers("/").access("hasRole('TEST')")//该路径需要TEST角色 // .antMatchers("/").access("hasRole('TEST')")//该路径需要TEST角色
// .antMatchers("/brand/list").authenticated()//该路径需要登录认证 .antMatchers("/").authenticated()//该路径需要登录认证
// .antMatchers("/brand/list").hasAuthority("TEST")//该路径需要TEST权限 // .antMatchers("/brand/list").hasAuthority("TEST")//该路径需要TEST权限
.antMatchers("/**").permitAll() .antMatchers("/**").permitAll()
.and()//启用基于http的认证 .and()//启用基于http的认证
...@@ -50,6 +50,9 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { ...@@ -50,6 +50,9 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
// .key("rememberMeKey") // .key("rememberMeKey")
.and()//关闭跨域伪造 .and()//关闭跨域伪造
.csrf() .csrf()
.disable()
.headers()//去除X-Frame-Options
.frameOptions()
.disable(); .disable();
} }
......
...@@ -25,20 +25,6 @@ public class DemoController { ...@@ -25,20 +25,6 @@ public class DemoController {
private static final Logger LOGGER = LoggerFactory.getLogger(DemoController.class); private static final Logger LOGGER = LoggerFactory.getLogger(DemoController.class);
@ApiOperation(value = "此处为首页")
@RequestMapping(value = "/", method = RequestMethod.GET)
@ResponseBody
public String hello() {
return "This is home!";
}
@ApiOperation(value = "获取品牌列表界面(网页显示)")
@RequestMapping(value = "/list", method = RequestMethod.GET)
public String getBrandListPage(Model model) {
model.addAttribute("brandList", demoService.listAllBrand());
return "demo";
}
@ApiOperation(value = "获取全部品牌列表") @ApiOperation(value = "获取全部品牌列表")
@RequestMapping(value = "/brand/listAll", method = RequestMethod.GET) @RequestMapping(value = "/brand/listAll", method = RequestMethod.GET)
@ResponseBody @ResponseBody
......
package com.macro.mall.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* 页面跳转控制器
*/
@Controller
public class PageController {
@RequestMapping(value = "/", method = RequestMethod.GET)
public String index() {
return "index";
}
@RequestMapping(value = "/crud", method = RequestMethod.GET)
public String crud() {
return "crud";
}
@RequestMapping(value = "/login", method = RequestMethod.GET)
public String login() {
return "login";
}
}
...@@ -10,7 +10,7 @@ public class FlagValidatorClass implements ConstraintValidator<FlagValidator,Int ...@@ -10,7 +10,7 @@ public class FlagValidatorClass implements ConstraintValidator<FlagValidator,Int
private String[] values; private String[] values;
@Override @Override
public void initialize(FlagValidator flagValidator) { public void initialize(FlagValidator flagValidator) {
this.values = flagValidator.values(); this.values = flagValidator.value();
} }
@Override @Override
......
...@@ -13,4 +13,12 @@ logging.level.com.macro.mall=debug ...@@ -13,4 +13,12 @@ logging.level.com.macro.mall=debug
#配置日志生成路径 #配置日志生成路径
#logging.path=/var/logs #logging.path=/var/logs
#配置日志文件名称 #配置日志文件名称
#logging.file=demo_log.log #logging.file=demo_log.log
\ No newline at end of file
#thymeleaf start
spring.thymeleaf.mode=HTML5
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.content-type=text/html
#开发时关闭缓存,不然没法看到实时页面
spring.thymeleaf.cache=false
#thymeleaf end
\ No newline at end of file
body, html {height: 100%; position: relative; font-family: 'Microsoft yahei'; font-size: 13px; font-weight: 400; overflow-y: hidden;}
img {vertical-align: middle;}
a, a:hover, a:active, a:focus {text-decoration: none; -webkit-user-drag: none;}
/** 头部 **/
#header {width: 100%; height: 70px; padding: 0 20px; position: fixed; z-index: 11; left: 0; top: 0; box-shadow: 0 1px 4px rgba(0,0,0,.3);}
#menu {position: relative; list-style: none; padding: 17px 0; margin-bottom: 0; height: 70px;}
#menu>li {float: left;}
/* 头部左侧侧边栏操作按钮 */
.line-trigger{margin-left:-5px;cursor:pointer;position:relative;display:none!important}
.line-trigger:before{content:"";position:absolute;top:50%;left:50%;width:45px;height:45px;border-radius:50%;background:rgba(255,255,255,.22);-webkit-transition:all;-o-transition:all;transition:all;-webkit-transition-duration:.3s;transition-duration:.3s;transform:scale(0);z-index:0;margin-top:-22px;margin-left:-22px}
.line-trigger.toggled:before{-webkit-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}
.line-wrap{width:18px;height:12px;-webkit-transition:all;transition:all;-webkit-transition-duration:.3s;transition-duration:.3s;margin:12px 20px}
.toggled .line-wrap{-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}
.line-wrap .line{width:18px;height:2px;-webkit-transition:all;transition:all;-webkit-transition-duration:.3s;transition-duration:.3s;background-color:#fff}
.toggled .line-wrap .line.top{width:12px;transform:translateX(8px) translateY(1px) rotate(45deg);-webkit-transform:translateX(8px) translateY(1px) rotate(45deg)}
.line-wrap .line.center{margin:3px 0}
.toggled .line-wrap .line.bottom{width:12px;transform:translateX(8px) translateY(-1px) rotate(-45deg);-webkit-transform:translateX(8px) translateY(-1px) rotate(-45deg)}
/* 头部左侧logo */
#logo a {margin-left: 10px!important;}
#logo a img{vertical-align: top;}
#system_title{color: #fff; height:33px; line-height: 33px; font-size: 16px;}
/* 头部右侧工具按钮 */
.pull-right {float: right!important;}
.hi-menu {list-style: none; padding:0;}
.hi-menu>li {display: inline-block; margin: 0 1px; vertical-align: top; min-width: 50px;}
.hi-menu>li>a {color: #fff; display: block; text-align: center; z-index: 1; position: relative; -webkit-transition: background-color; -o-transition: background-color; transition: background-color; -webkit-transition-duration: 250ms; transition-duration: 250ms; border-radius: 2px;}
.hi-menu>li>a>.him-icon {font-size: 24px; line-height: 36px;}
.dropdown {position: relative;}
.dropdown-menu{box-shadow: 0 2px 10px rgba(0,0,0,.2);border: none;}
.dropdown-menu .divider{height:1px;margin:8px 0;overflow:hidden;background-color:rgba(0,0,0,.08)}
.dropdown-menu>li>a{display:block;clear:both;font-weight:400;color:#333;padding:10px 20px;font-size:13px;-webkit-transition:background-color;-o-transition:background-color;transition:background-color;-webkit-transition-duration:.3s;transition-duration:.3s}
.dropdown li>a>.zmdi{line-height:100%;vertical-align:top;font-size:16px;width:28px}
#header .skin-switch{padding:10px 0 2px;text-align:center;font-size:13px;}
#search-form{margin: 6px 15px;}
#keywords{min-width:150px}
/** 正文 **/
#main {height: 100%; padding-top: 70px; padding-bottom: 0;}
/* 侧边栏响应式 */
@media (max-width: 1279px) {
#sidebar {-webkit-transform:translate3d(-288px,0,0); transform: translate3d(-288px,0,0); box-shadow: 0 0 20px rgba(14,18,21,.38) }
#sidebar.toggled {-webkit-transform: translate3d(0,0,0); transform: translate3d(0,0,0);}
#header .line-trigger {display: inline-block!important;}
}
@media (max-width: 767px) {
#header{padding: 0 8px;}
}
/** 侧边栏 **/
#sidebar {position: fixed; width: 268px; background: #fff; height: calc(100% - 70px); top: 70px; transition: all; -webkit-transition-duration: .3s; transition-duration: .3s; z-index: 10; overflow-y: auto; box-shadow: 1px 0 4px rgba(0,0,0,.3);}
/* 侧边栏个人信息 */
.s-profile>a{display:block;height:129px;margin-bottom:5px;width:100%;background-size:100%;text-decoration:none}
.s-profile>a .sp-pic{padding:12px}
.s-profile>a .sp-pic>img{width:47px;height:47px;border-radius:50%;border:3px solid rgba(0,0,0,.14);box-sizing:content-box}
.s-profile>a .sp-info{background:rgba(0,0,0,.37);padding:7px 14px;color:#fff;margin-top:20px;position:relative}
.s-profile>a .sp-info>i{font-size:19px;line-height:100%;position:absolute;right:15px;top:7px;-webkit-transition:all;-o-transition:all;transition:all;-webkit-transition-duration:.3s;transition-duration:.3s}
.s-profile.toggled .sp-info>i{-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}
.s-profile .main-menu{display:none;margin:0}
.zmdi{display:inline-block;font:normal normal normal 14px/1 Material-Design-Iconic-Font;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}
.zmdi-caret-down:before{content:'\f2f2'}
/* 侧边栏菜单 */
.main-menu{list-style:none;padding-left:0;margin:20px 0 0}
.main-menu a{-webkit-transition:color;-o-transition:color;transition:color;-webkit-transition-duration:.3s;transition-duration:.3s}
.main-menu>li>a{padding:14px 20px 14px 65px;display:block;font-weight:500;position:relative;color:#4C4C4C}
.main-menu>li>a>i{position:absolute;left:25px;font-size:18px;top:2px;width:25px;text-align:center;padding:13px 0}
.sub-menu ul{list-style:none;display:none;padding:0}
.sub-menu ul>li:first-child>a{padding-top:14px}
.sub-menu ul>li:last-child>a{padding-bottom:16px}
.sub-menu ul>li>a{padding:8px 20px 8px 65px;font-weight:500;display:block;color:#989898}
.sub-menu.toggled>ul{display:block}
.sub-menu>a:after,.sub-menu>a:before{position:absolute;top:50%;margin-top:-11px;font-family:Material-Design-Iconic-Font;font-size:17px;right:15px;-webkit-transition:all;-o-transition:all;transition:all;-webkit-transition-duration:250ms;transition-duration:250ms}
.sub-menu>a:before{content:"\f278";-webkit-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}
.sub-menu.toggled>a:before{content:"\f278";-webkit-transform:scale(0);-ms-transform:scale(0);-o-transform:scale(0);transform:scale(0)}
.sub-menu>a:after,.sub-menu>a:before{position:absolute;top:50%;margin-top:-11px;font-family:Material-Design-Iconic-Font;font-size:17px;right:15px;-webkit-transition:all;-o-transition:all;transition:all;-webkit-transition-duration:250ms;transition-duration:250ms}
.sub-menu>a:after{content:"\f273";transform:scale(0)}
.sub-menu.toggled>a:after{content:"\f273";-webkit-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}
.main-menu a:hover{color:#262626}
.upms-version{margin-top: 10px; height: 46px; line-height: 46px; font-size: 12px; color: #777; text-align: center; border-top: 1px solid #eee;}
/* 内容区响应式 */
@media (min-width: 768px) {
#content {padding-left: 0;}
}
@media (min-width: 992px) {
#content {padding-left: 0;}
}
@media (min-width: 1280px) {
#content {padding-left: 268px;}
}
#content {height: 100%; padding-right: 0; transition: all;}
/* 内容区 */
.container, .container-fluid{height:100%;padding:0;}
@media (min-width: 1280px) {
#content:not(.content-alt) {padding-left: 268px;padding-right: 0}
}
@media (min-width: 768px) and (max-width:1279px) {
#content {padding-left: 0;padding-right: 0}
}
@media (min-width: 992px) {
.container {width:100%}
}
@media (min-width: 1200px) {
.container {width:100%}
}
#content {height: 100%;}
/* 选项卡 */
.content_tab{width:100%;height:48px;overflow:hidden;}
.content_tab>ul{padding:0;font-size:0;display:block;white-space:nowrap;-webkit-overflow-scrolling:touch;overflow-x:scroll;}
.scroll>ul{margin:0 40px;}
.scroll>.tab_left,.scroll>.tab_right{display:block;}
.tab_left,.tab_right{width:40px;height:48px;line-height:48px;color:#fff;text-align:center;display:none;}
.tab_left{float:left;margin-right:-40px;}
.tab_right{float:right;margin-left:-40px;}
.tab_left>a,.tab_right>a{display:block;width:100%;color:rgba(255, 255, 255, 0.5);font-size:22px;}
.tab_left>.active,.tab_right>.active{color:#fff;}
.content_tab{position:relative;}
.content_tab>ul>li{display:inline-block; height: 48px; line-height: 48px; margin:0; font-size:14px;}
.content_tab>ul>li>a{display:block; height: 48px; line-height: 48px;color:rgba(255, 255, 255, 0.9);padding:0 28px;transition:background-color .35s cubic-bezier(.35,0,.25,1);border-bottom:none;position: relative;}
.content_tab>ul>li>a:active{background:rgba(255, 255, 255, 0.1);}
.content_tab>ul>.cur>a{/*border-bottom:3px solid #FFEB3B;*/color:#fff;}
.content_tab>ul>li>a:after{content:"";position:absolute;bottom:0;left:50%;right:50%;width:0;border-bottom:3px solid #FFEB3B;transition:all linear .2s}
.content_tab>ul>.cur>a:after{left:0;bottom:1px;width:100%;opacity:1;transition:all linear .2s}
.content_main{height:calc(100% - 48px);-webkit-overflow-scrolling:touch;}
.content_main>.cur{display:block;}
.iframe{height:100%;display:none;}
#iframe_home{padding: 15px 30px; font-size: 13px;overflow:auto;}
#iframe_home p{margin-bottom: 5px; line-height: 2em;}
/* 底部 */
#footer {display:none;}
/* 滚动条 */
.mCSB_scrollTools{width:5px}
.mCSB_scrollTools .mCSB_dragger_bar{border-radius:0!important}
.mCSB_scrollTools.mCSB_scrollTools_horizontal,.mCSB_scrollTools.mCSB_scrollTools_vertical{margin:0!important}
.mCSB_scrollTools.mCSB_scrollTools_horizontal{height:10px}
body, html {height: 100%; position: relative; font-family: 'Microsoft yahei'; font-size: 13px; font-weight: 400;}
img {vertical-align: middle;}
a, a:hover, a:active, a:focus {text-decoration: none; -webkit-user-drag: none; outline: none; color: #000;}
a i{font-size: 13px;}
#main{padding: 10px 20px;}
/* 数据表格 */
body{font-size: 12px;}
.table i{font-size: 12px; color: #000;}
.bootstrap-table .table>thead>tr>th{border-bottom: none;}
.bootstrap-table .table:not(.table-condensed), .bootstrap-table .table:not(.table-condensed)>tbody>tr>td, .bootstrap-table .table:not(.table-condensed)>tbody>tr>th, .bootstrap-table .table:not(.table-condensed)>tfoot>tr>td, .bootstrap-table .table:not(.table-condensed)>tfoot>tr>th, .bootstrap-table .table:not(.table-condensed)>thead>tr>td{padding: 12px 8px;}
/* 分页 */
.pagination>.active>a, .pagination>.active>span, .pagination>.active>a:hover, .pagination>.active>span:hover, .pagination>.active>a:focus, .pagination>.active>span:focus{background: #f5f5f5; color: #000; border-color: #7d7d7d;}
.pagination>li>a, .pagination>li>span{color: #000;}.dropdown-menu>.active>a, .dropdown-menu>.active>a:hover, .dropdown-menu>.active>a:focus{background-color: #999;}
/* bootstrap */
.jconfirm .jconfirm-box .jconfirm-buttons button{-webkit-border-radius: 0; border-radius: 0;}
.btn:active{-webkit-box-shadow: none; box-shadow: none;}
/* input */
body .jconfirm{z-index: 999;}
.jconfirm-content form{margin-top: 10px;}
.crudDialog{padding: 0 0 2px;}
.dialog-buttons a{font-weight: bold;}
.form-group{margin-bottom: 20px;}
.form-group label{position: absolute; line-height: 2; font-size: 16px; font-weight: normal; transition: all .2s; pointer-events: none; color: #999;}
.form-group .active{transform: translateY(-65%); font-size: 12px; color: #337ab7;}
.form-group .form-control{font-size: 14px; box-shadow: none; padding-left: 0; padding-right: 0; border-radius: 0; border: none; border-bottom: 2px solid #eee; outline: none; transition: all .5s;}
.form-group .form-control:focus{box-shadow: none; border-color: #337ab7;}
\ No newline at end of file
body, html {height: 100%; font-family: 'Microsoft yahei'; font-size: 13px; font-weight: 400;}
img {vertical-align: middle;}
a, a:hover, a:active, a:focus {text-decoration: none; -webkit-user-drag: none;}
a i{font-size: 13px;}
body{background:#ECECEC;}
body:before{height:50%;width:100%;position:absolute;top:0;left:0;background:#29a176;content:"";z-index:0}
#login-window{position:relative;top:50%;left:50%;width:300px;height:200px;margin-left:-150px;margin-top:-100px;padding:35px 55px 35px 25px;z-index:10;background:#fff;box-shadow:0 1px 11px rgba(0,0,0,.27);border-radius:2px;}
.m-b-20{margin-bottom:20px !important;}
#login-bt{position:absolute;width:50px;height:50px;border-radius:50%;line-height:36px!important;top:50%;margin-top:-25px;right:-25px;background:#FF4F0F;}
#login-bt i{font-size:23px;color:#fff;}
.input-group-addon{border:none;background:none;font-size:16px;}
.form-control{position:relative;font-size:13px;border:1px solid #e0e0e0;border-left:0;border-right:0;border-top:0;padding:0;background:#fff;height:35px;line-height:35px;transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;box-shadow:none;}
.form-control:active, .form-control:focus{box-shadow:none;}
.fg-line{position:relative;vertical-align:top;display:inline-block;width:100%;}
.fg-line:after{position:absolute;z-index:3;bottom:0;left:0;height:2px;width:0;content:"";-webkit-transition:all;-o-transition:all;transition:all;-webkit-transition-duration:.3s;transition-duration:.3s;background:#29a176;}
.fg-line.fg-toggled:after{width:100%}
input[type=checkbox].checkbix:checked+label>span:before{box-sizing: content-box;}
\ No newline at end of file
This diff is collapsed.
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment