Commit 3e9384df authored by 朱江伟's avatar 朱江伟

光伏功率预测-调整预测准确率

parent e40d862b
package pps.core.base.constant;
public class MapeConstant {
public static final String MAPE_ADJ_ROLE_DIC_ALIAS = "MAPE_ADJ_ROLE";
}
package pps.core.base.entity;
import java.io.Serializable;
import java.util.Date;
import com.baomidou.mybatisplus.annotation.IdType;
import java.math.BigDecimal;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import xstartup.annotation.XText;
@TableName("base_photovoltaic_plant_mape_adj")
public class BasePhotovoltaicPlantMapeAdjEnt implements Serializable {
@TableId(type = IdType.AUTO)
private Integer id;
@XText("base_photovoltaic_plant.id")
@TableField
private String plantId;
@XText("预测类型(1 中期光伏功率预测 2 短期光伏功率预测 3 超短期光伏功率预测 4 15天光伏功率预测 5 1天光伏功率预测)")
@TableField
private Integer mapeType;
@XText("预测准确率附加值")
@TableField
private BigDecimal mapePlusVal;
@XText("创建人ID")
@TableField
private String createById;
@XText("创建人名称")
@TableField
private String createByName;
@XText("创建时间")
@TableField
private Date createTime;
@XText("修改人ID")
@TableField
private String modifyById;
@XText("修改人名称")
@TableField
private String modifyByName;
@XText("修改时间")
@TableField
private Date modifyTime;
public Integer getId() {
return this.id;
}
public void setId(Integer value) {
this.id = value;
}
public String getPlantId() {
return this.plantId;
}
public void setPlantId(String value) {
this.plantId = value;
}
public Integer getMapeType() {
return this.mapeType;
}
public void setMapeType(Integer value) {
this.mapeType = value;
}
public BigDecimal getMapePlusVal() {
return this.mapePlusVal;
}
public void setMapePlusVal(BigDecimal value) {
this.mapePlusVal = value;
}
public String getCreateById() {
return this.createById;
}
public void setCreateById(String value) {
this.createById = value;
}
public String getCreateByName() {
return this.createByName;
}
public void setCreateByName(String value) {
this.createByName = value;
}
public Date getCreateTime() {
return this.createTime;
}
public void setCreateTime(Date value) {
this.createTime = value;
}
public String getModifyById() {
return this.modifyById;
}
public void setModifyById(String value) {
this.modifyById = value;
}
public String getModifyByName() {
return this.modifyByName;
}
public void setModifyByName(String value) {
this.modifyByName = value;
}
public Date getModifyTime() {
return this.modifyTime;
}
public void setModifyTime(Date value) {
this.modifyTime = value;
}
}
package pps.core.base.entity;
import java.io.Serializable;
import java.util.Date;
import java.math.BigDecimal;
import com.baomidou.mybatisplus.annotation.TableField;
import xstartup.annotation.XText;
public class BasePhotovoltaicPlantMapeAdjView implements Serializable {
@TableField
private Integer id;
@XText("base_photovoltaic_plant.id")
@TableField
private String plantId;
@XText("预测类型(1 中期光伏功率预测 2 短期光伏功率预测 3 超短期光伏功率预测 4 15天光伏功率预测 5 1天光伏功率预测)")
@TableField
private Integer mapeType;
@XText("预测准确率附加值")
@TableField
private BigDecimal mapePlusVal;
@XText("创建人ID")
@TableField
private String createById;
@XText("创建人名称")
@TableField
private String createByName;
@XText("创建时间")
@TableField
private Date createTime;
@XText("修改人ID")
@TableField
private String modifyById;
@XText("修改人名称")
@TableField
private String modifyByName;
@XText("修改时间")
@TableField
private Date modifyTime;
public Integer getId() {
return this.id;
}
public void setId(Integer value) {
this.id = value;
}
public String getPlantId() {
return this.plantId;
}
public void setPlantId(String value) {
this.plantId = value;
}
public Integer getMapeType() {
return this.mapeType;
}
public void setMapeType(Integer value) {
this.mapeType = value;
}
public BigDecimal getMapePlusVal() {
return this.mapePlusVal;
}
public void setMapePlusVal(BigDecimal value) {
this.mapePlusVal = value;
}
public String getCreateById() {
return this.createById;
}
public void setCreateById(String value) {
this.createById = value;
}
public String getCreateByName() {
return this.createByName;
}
public void setCreateByName(String value) {
this.createByName = value;
}
public Date getCreateTime() {
return this.createTime;
}
public void setCreateTime(Date value) {
this.createTime = value;
}
public String getModifyById() {
return this.modifyById;
}
public void setModifyById(String value) {
this.modifyById = value;
}
public String getModifyByName() {
return this.modifyByName;
}
public void setModifyByName(String value) {
this.modifyByName = value;
}
public Date getModifyTime() {
return this.modifyTime;
}
public void setModifyTime(Date value) {
this.modifyTime = value;
}
}
package pps.core.base.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springframework.stereotype.Repository;
import pps.core.base.entity.BasePhotovoltaicPlantMapeAdjEnt;
@Repository(value="pps.core.base.mapper.BasePhotovoltaicPlantMapeAdjMapper")
public interface BasePhotovoltaicPlantMapeAdjMapper extends BaseMapper<BasePhotovoltaicPlantMapeAdjEnt> {
}
package pps.core.base.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springframework.stereotype.Repository;
import pps.core.base.entity.BasePhotovoltaicPlantMapeAdjView;
import java.util.List;
@Repository(value="pps.core.base.mapper.BasePhotovoltaicPlantMapeAdjViewMapper")
public interface BasePhotovoltaicPlantMapeAdjViewMapper {
BasePhotovoltaicPlantMapeAdjView selectOne(BasePhotovoltaicPlantMapeAdjView record);
List<BasePhotovoltaicPlantMapeAdjView> selectList(BasePhotovoltaicPlantMapeAdjView record);
}
package pps.core.base.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import pps.core.base.entity.BasePhotovoltaicPlantEnt;
import pps.core.base.entity.BasePhotovoltaicPlantMapeAdjEnt;
import pps.core.base.entity.BasePhotovoltaicPlantMapeAdjView;
import pps.core.base.mapper.BasePhotovoltaicPlantMapeAdjMapper;
import pps.core.base.mapper.BasePhotovoltaicPlantMapeAdjViewMapper;
import pps.core.base.mapper.BasePhotovoltaicPlantMapper;
import pps.core.base.service.data.base_photovoltaic_plant_mape_adj.CreateBasePhotovoltaicPlantMapeAdjInput;
import pps.core.base.service.data.base_photovoltaic_plant_mape_adj.GetBasePhotovoltaicPlantMapeAdjInput;
import pps.core.base.service.data.base_photovoltaic_plant_mape_adj.GetBasePhotovoltaicPlantMapeAdjOutput;
import pps.core.common.entity.BaseModel;
import pps.core.common.session.PpsUserSession;
import xstartup.annotation.XService;
import xstartup.annotation.XText;
import xstartup.base.XContext;
import xstartup.base.util.XCopyUtils;
import xstartup.data.XServiceResult;
import xstartup.data.XSingleResult;
import xstartup.error.XError;
import xstartup.feature.api.annotation.XApiGet;
import xstartup.feature.api.annotation.XApiPost;
import java.math.BigDecimal;
import java.util.Date;
@XText("光伏功率预测准确率调整相关操作")
@XService
public class BasePhotovoltaicPlantMapeAdjService {
@XText("保存数据")
@XApiPost
public XServiceResult saveData(XContext context, CreateBasePhotovoltaicPlantMapeAdjInput input){
BasePhotovoltaicPlantMapeAdjMapper mapper = context.getBean(BasePhotovoltaicPlantMapeAdjMapper.class);
BasePhotovoltaicPlantMapeAdjEnt ent = XCopyUtils.copyNewObject(input, BasePhotovoltaicPlantMapeAdjEnt.class);
if(ent.getMapePlusVal()==null) ent.setMapePlusVal(BigDecimal.ZERO);
PpsUserSession session = context.getSession(PpsUserSession.class);
Date date = new Date();
if(input.getId() == null){
ent.setCreateById(session.getId());
ent.setCreateByName(session.getUserName());
ent.setCreateTime(date);
mapper.insert(ent);
}else{
ent.setModifyById(session.getId());
ent.setModifyByName(session.getUserName());
ent.setModifyTime(date);
mapper.updateById(ent);
}
return XServiceResult.OK;
}
@XText("获取调整数据")
@XApiPost
public XSingleResult<GetBasePhotovoltaicPlantMapeAdjOutput> getData(XContext context, GetBasePhotovoltaicPlantMapeAdjInput input){
GetBasePhotovoltaicPlantMapeAdjOutput output = new GetBasePhotovoltaicPlantMapeAdjOutput();
//获取电站信息
BasePhotovoltaicPlantMapper basePhotovoltaicPlantMapper = context.getBean(BasePhotovoltaicPlantMapper.class);
BasePhotovoltaicPlantEnt basePhotovoltaicPlantEnt = basePhotovoltaicPlantMapper.selectOne(new LambdaQueryWrapper<BasePhotovoltaicPlantEnt>()
.eq(BaseModel::getId, input.getPlantId()));
if(basePhotovoltaicPlantEnt == null) return XSingleResult.error(500,"未查找到电站信息");
BasePhotovoltaicPlantMapeAdjViewMapper mapper = context.getBean(BasePhotovoltaicPlantMapeAdjViewMapper.class);
BasePhotovoltaicPlantMapeAdjView record = new BasePhotovoltaicPlantMapeAdjView();
XCopyUtils.copyObject(input, record);
BasePhotovoltaicPlantMapeAdjView view = mapper.selectOne(record);
if(view == null) {
output.setPlantName(basePhotovoltaicPlantEnt.getStationName());
output.setMapePlusVal(BigDecimal.ZERO);
return XSingleResult.error(context, XError.NotFound);
}
XCopyUtils.copyObject(view, output);
output.setPlantName(basePhotovoltaicPlantEnt.getStationName());
return XSingleResult.success(output);
}
@XText("重置调整数据")
@XApiPost
public XServiceResult resetData(XContext context, GetBasePhotovoltaicPlantMapeAdjInput input){
BasePhotovoltaicPlantMapeAdjMapper mapper = context.getBean(BasePhotovoltaicPlantMapeAdjMapper.class);
PpsUserSession session = context.getSession(PpsUserSession.class);
BasePhotovoltaicPlantMapeAdjEnt ent = new BasePhotovoltaicPlantMapeAdjEnt();
ent.setMapePlusVal(BigDecimal.ZERO);
ent.setModifyById(session.getId());
ent.setModifyByName(session.getUserName());
ent.setModifyTime(new Date());
UpdateWrapper<BasePhotovoltaicPlantMapeAdjEnt> ur = new UpdateWrapper<>();
ur.lambda().eq(BasePhotovoltaicPlantMapeAdjEnt::getPlantId,input.getPlantId()).eq(BasePhotovoltaicPlantMapeAdjEnt::getMapeType,input.getMapeType());
mapper.update(ent,ur);
return XServiceResult.OK;
}
}
......@@ -9,12 +9,21 @@ import pps.cloud.prediction.service.PlantTrainPowerTaskCloudService;
import pps.cloud.prediction.service.data.plant_train_power_task.GetPlantTrainPowerTaskCloudInput;
import pps.cloud.prediction.service.data.plant_train_power_task.GetPlantTrainPowerTaskCloudOutput;
import pps.cloud.system.service.SystemAreaService;
import pps.cloud.system.service.SystemDictionaryService;
import pps.cloud.system.service.SystemUserRoleRelService;
import pps.cloud.system.service.data.CreateSysDictionaryInput;
import pps.cloud.system.service.data.GetSysUserRoleRelInput;
import pps.cloud.system.service.data.GetSysUserRoleRelOutput;
import pps.cloud.system.service.data.QuerySysDictionaryViewOutput;
import pps.cloud.system.service.data.sys_area.GetSysAreaInput;
import pps.cloud.system.service.data.sys_area.GetSysAreaOutput;
import pps.core.base.constant.MapeConstant;
import pps.core.base.entity.BasePhotovoltaicPlantEnt;
import pps.core.base.entity.BasePhotovoltaicPlantMapeAdjView;
import pps.core.base.entity.BasePowerLineEnt;
import pps.core.base.entity.BasePowerLinePlantEnt;
import pps.core.base.enums.BusinessError;
import pps.core.base.mapper.BasePhotovoltaicPlantMapeAdjViewMapper;
import pps.core.base.mapper.BasePhotovoltaicPlantMapper;
import pps.core.base.mapper.BasePowerLinePlantMapper;
import pps.core.base.service.data.base_photovoltaic_plant.*;
......@@ -24,6 +33,7 @@ import pps.core.common.constant.UserConstant;
import pps.core.common.entity.BaseModel;
import pps.core.common.session.PpsUserSession;
import pps.core.common.utils.BaseUtils;
import pps.core.common.utils.TraceHelper;
import pps.core.system.constant.SysOrganizationCode;
import pps.core.system.entity.SysOrganizationView;
import pps.core.system.mapper.SysOrganizationViewMapper;
......@@ -48,6 +58,7 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
/**
......@@ -196,10 +207,34 @@ public class BasePhotovoltaicPlantService {
if (result.isSuccess() && result.getResult() != null && XStringUtils.isNotEmpty(result.getResult().getMetricsScore())) {
Map<String, Object> map = XJsonUtils.toMap(result.getResult().getMetricsScore());
if (map.containsKey("MAPE") && XStringUtils.isNotEmpty(map.get("MAPE").toString())) {
output.setMape(new BigDecimal(map.get("MAPE").toString()).setScale(2, BigDecimal.ROUND_UP).toPlainString() + "%");
BigDecimal relMape = new BigDecimal(map.get("MAPE").toString());
BigDecimal mape = null;
//获取调整的准确率附加值
BasePhotovoltaicPlantMapeAdjViewMapper mapeAdjMapper = context.getBean(BasePhotovoltaicPlantMapeAdjViewMapper.class);
BasePhotovoltaicPlantMapeAdjView record = new BasePhotovoltaicPlantMapeAdjView();
record.setPlantId(input.getId());
record.setMapeType(input.getMapeType());
BasePhotovoltaicPlantMapeAdjView view = mapeAdjMapper.selectOne(record);
if(view != null && view.getMapePlusVal() !=null) {
mape = relMape.add(view.getMapePlusVal());
if(mape.compareTo(BigDecimal.valueOf(100))>0) mape = BigDecimal.valueOf(100);
}else{
mape = relMape;
}
//output.setRelMape(relMape.setScale(2, BigDecimal.ROUND_UP).toPlainString() + "%");
output.setMape(mape.setScale(2, BigDecimal.ROUND_UP).toPlainString() + "%");
}
}
}
return XSingleResult.success(output);
}
@XText("获取调整光伏功率预测准确率按钮")
@XApiGet
public XSingleResult<MapeAjdPowerOutput> getAjdButton(XContext context) {
MapeAjdPowerOutput output = new MapeAjdPowerOutput();
output.setShowAdjButton(this.checkUserMapeAdjPower(context));
return XSingleResult.success(output);
}
......@@ -338,4 +373,49 @@ public class BasePhotovoltaicPlantService {
);
return count > 0;
}
/**
* 校验当前用户是否有调整光伏预测准确率的权限
* @param context
* @return
*/
private boolean checkUserMapeAdjPower(XContext context){
boolean result = false;
try {
//获取字典配置的角色
SystemDictionaryService dictionaryService = context.getBean(SystemDictionaryService.class);
CreateSysDictionaryInput createSysDictionaryInput = new CreateSysDictionaryInput();
createSysDictionaryInput.setAlias(MapeConstant.MAPE_ADJ_ROLE_DIC_ALIAS);
XListResult<QuerySysDictionaryViewOutput> dicResult = dictionaryService.querySysDictionarysByAlias(context, createSysDictionaryInput);
if(!dicResult.isSuccess()){
context.getLogger().error("=======get dic error: alias="+MapeConstant.MAPE_ADJ_ROLE_DIC_ALIAS+" errorMsg:"+XJsonUtils.toJson(dicResult.getError()));
return result;
}
List<QuerySysDictionaryViewOutput> roleDicList = dicResult.getResult();
if(roleDicList.isEmpty()) return result;
List<String> roleIds = roleDicList.stream().map(QuerySysDictionaryViewOutput::getDicKey).collect(Collectors.toList());
//获取当前用户角色
SystemUserRoleRelService roleRelService = context.getBean(SystemUserRoleRelService.class);
GetSysUserRoleRelInput getSysUserRoleRelInput = new GetSysUserRoleRelInput();
getSysUserRoleRelInput.setUserId(context.getSession(PpsUserSession.class).getId());
XListResult<GetSysUserRoleRelOutput> roleResult = roleRelService.getSysRoleByUserId(context, getSysUserRoleRelInput);
if(!roleResult.isSuccess()){
context.getLogger().error("=======get user role error:"+XJsonUtils.toJson(roleResult.getError()));
return result;
}
for(GetSysUserRoleRelOutput item:roleResult.getResult()){
if (roleIds.contains(item.getRoleId())){
result = true;
break;
}
}
}catch (Exception e){
e.printStackTrace();
TraceHelper.appendTraceLog(context,e.toString());
}
return result;
}
}
......@@ -11,4 +11,8 @@ public class GetBasePhotovoltaicPlantInput {
@XText("(15天,10天)传1(3天,1天)传2(4小时)传3,不传无返回")
private String type;
@XText("预测类型(1 中期光伏功率预测 2 短期光伏功率预测 3 超短期光伏功率预测 4 15天光伏功率预测 5 1天光伏功率预测)")
private Integer mapeType;
}
\ No newline at end of file
package pps.core.base.service.data.base_photovoltaic_plant;
import lombok.Data;
import xstartup.annotation.XText;
@Data
public class MapeAjdPowerOutput {
@XText("是否显示参数调整按钮")
private Boolean showAdjButton;
}
package pps.core.base.service.data.base_photovoltaic_plant_mape_adj;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import xstartup.annotation.XText;
import java.util.Date;
import java.math.BigDecimal;
public class CreateBasePhotovoltaicPlantMapeAdjInput {
private Integer id;
@XText("光伏电站id")
@NotBlank
private String plantId;
@XText("预测类型(1 中期光伏功率预测 2 短期光伏功率预测 3 超短期光伏功率预测 4 15天光伏功率预测 5 1天光伏功率预测)")
@NotNull
private Integer mapeType;
@XText("预测准确率附加值")
private BigDecimal mapePlusVal;
public Integer getId() {
return this.id;
}
public void setId(Integer value) {
this.id = value;
}
public String getPlantId() {
return this.plantId;
}
public void setPlantId(String value) {
this.plantId = value;
}
public Integer getMapeType() {
return this.mapeType;
}
public void setMapeType(Integer value) {
this.mapeType = value;
}
public BigDecimal getMapePlusVal() {
return this.mapePlusVal;
}
public void setMapePlusVal(BigDecimal value) {
this.mapePlusVal = value;
}
}
package pps.core.base.service.data.base_photovoltaic_plant_mape_adj;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import xstartup.annotation.XText;
public class GetBasePhotovoltaicPlantMapeAdjInput {
@XText("光伏电站id")
@NotBlank
private String plantId;
@XText("预测类型(1 中期光伏功率预测 2 短期光伏功率预测 3 超短期光伏功率预测 4 15天光伏功率预测 5 1天光伏功率预测)")
@NotNull
private Integer mapeType;
public String getPlantId() {
return plantId;
}
public void setPlantId(String plantId) {
this.plantId = plantId;
}
public Integer getMapeType() {
return mapeType;
}
public void setMapeType(Integer mapeType) {
this.mapeType = mapeType;
}
}
package pps.core.base.service.data.base_photovoltaic_plant_mape_adj;
import xstartup.annotation.XText;
import java.util.Date;
import java.math.BigDecimal;
public class GetBasePhotovoltaicPlantMapeAdjOutput {
private Integer id;
@XText("光伏电站id")
private String plantId;
@XText("光伏电站名称")
private String plantName;
@XText("预测类型(1 中期光伏功率预测 2 短期光伏功率预测 3 超短期光伏功率预测 4 15天光伏功率预测 5 1天光伏功率预测)")
private Integer mapeType;
@XText("预测准确率附加值")
private BigDecimal mapePlusVal;
@XText("创建人ID")
private String createById;
@XText("创建人名称")
private String createByName;
@XText("创建时间")
private Date createTime;
@XText("修改人ID")
private String modifyById;
@XText("修改人名称")
private String modifyByName;
@XText("修改时间")
private Date modifyTime;
public Integer getId() {
return this.id;
}
public void setId(Integer value) {
this.id = value;
}
public String getPlantId() {
return this.plantId;
}
public void setPlantId(String value) {
this.plantId = value;
}
public String getPlantName() {
return plantName;
}
public void setPlantName(String plantName) {
this.plantName = plantName;
}
public Integer getMapeType() {
return this.mapeType;
}
public void setMapeType(Integer value) {
this.mapeType = value;
}
public BigDecimal getMapePlusVal() {
return this.mapePlusVal;
}
public void setMapePlusVal(BigDecimal value) {
this.mapePlusVal = value;
}
public String getCreateById() {
return this.createById;
}
public void setCreateById(String value) {
this.createById = value;
}
public String getCreateByName() {
return this.createByName;
}
public void setCreateByName(String value) {
this.createByName = value;
}
public Date getCreateTime() {
return this.createTime;
}
public void setCreateTime(Date value) {
this.createTime = value;
}
public String getModifyById() {
return this.modifyById;
}
public void setModifyById(String value) {
this.modifyById = value;
}
public String getModifyByName() {
return this.modifyByName;
}
public void setModifyByName(String value) {
this.modifyByName = value;
}
public Date getModifyTime() {
return this.modifyTime;
}
public void setModifyTime(Date value) {
this.modifyTime = value;
}
}
<?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="pps.core.base.mapper.BasePhotovoltaicPlantMapeAdjViewMapper">
<resultMap id="BaseResultMap" type="pps.core.base.entity.BasePhotovoltaicPlantMapeAdjView">
<id column="id" property="id" jdbcType="INTEGER" />
<result column="plant_id" property="plantId" jdbcType="VARCHAR" />
<result column="mape_type" property="mapeType" jdbcType="INTEGER" />
<result column="mape_plus_val" property="mapePlusVal" jdbcType="DECIMAL" />
<result column="create_by_id" property="createById" jdbcType="VARCHAR" />
<result column="create_by_name" property="createByName" jdbcType="VARCHAR" />
<result column="create_time" property="createTime" jdbcType="TIMESTAMP" />
<result column="modify_by_id" property="modifyById" jdbcType="VARCHAR" />
<result column="modify_by_name" property="modifyByName" jdbcType="VARCHAR" />
<result column="modify_time" property="modifyTime" jdbcType="TIMESTAMP" />
</resultMap>
<sql id="Base_Column_List">
id,
plant_id,
mape_type,
mape_plus_val,
create_by_id,
create_by_name,
create_time,
modify_by_id,
modify_by_name,
modify_time
</sql>
<select id="selectOne" parameterType="pps.core.base.entity.BasePhotovoltaicPlantMapeAdjView" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from base_photovoltaic_plant_mape_adj
<where>
<if test="plantId != null and plantId != ''">
and plant_id = #{plantId}
</if>
<if test="mapeType != null">
and mape_type = #{mapeType}
</if>
<if test="id != null">
and id = #{id}
</if>
</where>
order by create_time desc
limit 1
</select>
<select id="selectList" parameterType="pps.core.base.entity.BasePhotovoltaicPlantMapeAdjView" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from base_photovoltaic_plant_mape_adj
where
id=#{id}
</select>
</mapper>
\ No newline at end of file
Markdown is supported
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