Commit 16a02477 authored by hewei's avatar hewei

SelectSelectivePlugin插件重构

parent baf72992
......@@ -129,7 +129,7 @@ public class BatchInsertPlugin extends BasePlugin {
XmlElementGeneratorTools.useGeneratedKeys(batchInsertEle, introspectedTable);
batchInsertEle.addElement(new TextElement("insert into " + introspectedTable.getFullyQualifiedTableNameAtRuntime()));
for (Element element : XmlElementGeneratorTools.generateKeys(ListUtilities.removeIdentityAndGeneratedAlwaysColumns(introspectedTable.getAllColumns()))) {
for (Element element : XmlElementGeneratorTools.generateKeys(ListUtilities.removeIdentityAndGeneratedAlwaysColumns(introspectedTable.getAllColumns()), true)) {
batchInsertEle.addElement(element);
}
......
......@@ -132,9 +132,13 @@ public class SelectOneByExamplePlugin extends BasePlugin {
// 只查询一条
selectOneElement.addElement(new TextElement("limit 1"));
// hook
if (PluginTools.getHook(ISelectOneByExamplePluginHook.class).sqlMapSelectOneByExampleWithoutBLOBsElementGenerated(document, selectOneElement, introspectedTable)) {
// 添加到根节点
FormatTools.addElementWithBestPosition(document.getRootElement(), selectOneElement);
logger.debug("itfsw(查询单条数据插件):" + introspectedTable.getMyBatis3XmlMapperFileName() + "增加selectOneByExample方法。");
}
// ------------------------------------ selectOneByExampleWithBLOBs ----------------------------------
// !!! 注意这里的行为不以有没有生成Model 的 WithBLOBs类为基准
......@@ -179,10 +183,13 @@ public class SelectOneByExamplePlugin extends BasePlugin {
// 只查询一条
selectOneWithBLOBsElement.addElement(new TextElement("limit 1"));
// hook
if (PluginTools.getHook(ISelectOneByExamplePluginHook.class).sqlMapSelectOneByExampleWithBLOBsElementGenerated(document, selectOneWithBLOBsElement, introspectedTable)) {
// 添加到根节点
FormatTools.addElementWithBestPosition(document.getRootElement(), selectOneWithBLOBsElement);
logger.debug("itfsw(查询单条数据插件):" + introspectedTable.getMyBatis3XmlMapperFileName() + "增加selectOneByExampleWithBLOBs方法。");
}
}
return true;
......
......@@ -20,14 +20,12 @@ import com.itfsw.mybatis.generator.plugins.utils.*;
import com.itfsw.mybatis.generator.plugins.utils.hook.ISelectOneByExamplePluginHook;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.api.dom.xml.Attribute;
import org.mybatis.generator.api.dom.xml.Document;
import org.mybatis.generator.api.dom.xml.TextElement;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.api.dom.java.Interface;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.java.Parameter;
import org.mybatis.generator.api.dom.xml.*;
import org.mybatis.generator.codegen.mybatis3.MyBatis3FormattingUtilities;
import org.mybatis.generator.codegen.mybatis3.xmlmapper.elements.ResultMapWithBLOBsElementGenerator;
import org.mybatis.generator.codegen.mybatis3.xmlmapper.elements.ResultMapWithoutBLOBsElementGenerator;
import java.util.List;
......@@ -120,28 +118,21 @@ public class SelectSelectivePlugin extends BasePlugin implements ISelectOneByExa
return super.clientSelectByPrimaryKeyMethodGenerated(method, interfaze, introspectedTable);
}
// ============================================== sqlMap 生成 ===================================================
@Override
public boolean clientSelectOneByExampleWithBLOBsMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) {
FormatTools.addMethodWithBestPosition(interfaze, this.replaceMethodWithSelective(
method,
METHOD_SELECT_ONE_BY_EXAMPLE_SELECTIVE,
"@Param(\"example\")",
introspectedTable
));
return true;
public boolean sqlMapSelectByExampleWithoutBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
return super.sqlMapSelectByExampleWithoutBLOBsElementGenerated(element, introspectedTable);
}
@Override
public boolean clientSelectOneByExampleWithoutBLOBsMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) {
if (!introspectedTable.hasBLOBColumns()) {
FormatTools.addMethodWithBestPosition(interfaze, this.replaceMethodWithSelective(
method,
METHOD_SELECT_ONE_BY_EXAMPLE_SELECTIVE,
"@Param(\"example\")",
introspectedTable
));
public boolean sqlMapSelectByExampleWithBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
return super.sqlMapSelectByExampleWithBLOBsElementGenerated(element, introspectedTable);
}
return true;
@Override
public boolean sqlMapSelectByPrimaryKeyElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
return super.sqlMapSelectByPrimaryKeyElementGenerated(element, introspectedTable);
}
/**
......@@ -166,78 +157,127 @@ public class SelectSelectivePlugin extends BasePlugin implements ISelectOneByExa
resultMapEle.addAttribute(new Attribute("type", returnType));
commentGenerator.addComment(resultMapEle);
if (introspectedTable.getRules().generateResultMapWithBLOBs()) {
addResultMapElementsWithBLOBs(resultMapEle, introspectedTable);
} else if (introspectedTable.getRules().generateBaseResultMap()) {
addResultMapElementsWithoutBLOBs(resultMapEle, introspectedTable);
for (IntrospectedColumn introspectedColumn : introspectedTable.getPrimaryKeyColumns()) {
resultMapEle.addElement(XmlElementGeneratorTools.generateResultMapResultElement("id", introspectedColumn));
}
document.getRootElement().getElements().add(0, resultMapEle);
for (IntrospectedColumn introspectedColumn : introspectedTable.getNonPrimaryKeyColumns()) {
resultMapEle.addElement(XmlElementGeneratorTools.generateResultMapResultElement("result", introspectedColumn));
}
// 生成返回字段节点
XmlElement columnsEle = new XmlElement("foreach");
columnsEle.addAttribute(new Attribute("collection", "selective"));
columnsEle.addAttribute(new Attribute("item", "column"));
columnsEle.addAttribute(new Attribute("separator", ","));
columnsEle.addElement(new TextElement("${column.value}"));
document.getRootElement().getElements().add(0, resultMapEle);
}
// 1. selectByExampleSelective 方法
XmlElement selectByExampleSelectiveEle = new XmlElement("select");
commentGenerator.addComment(selectByExampleSelectiveEle);
FormatTools.addElementWithBestPosition(document.getRootElement(), this.generateSelectSelectiveElement(METHOD_SELECT_BY_EXAMPLE_SELECTIVE, introspectedTable, false, true));
selectByExampleSelectiveEle.addAttribute(new Attribute("id", METHOD_SELECT_BY_EXAMPLE_SELECTIVE));
// issues#16
if (introspectedTable.isConstructorBased()) {
selectByExampleSelectiveEle.addAttribute(new Attribute("resultMap", ID_FOR_PROPERTY_BASED_RESULT_MAP));
} else {
selectByExampleSelectiveEle.addAttribute(new Attribute("resultMap", introspectedTable.getBaseResultMapId()));
// 2. selectByPrimaryKeySelective
FormatTools.addElementWithBestPosition(document.getRootElement(), this.generateSelectSelectiveElement(METHOD_SELECT_BY_PRIMARY_KEY_SELECTIVE, introspectedTable, false, false));
return true;
}
selectByExampleSelectiveEle.addAttribute(new Attribute("parameterType", "map"));
selectByExampleSelectiveEle.addElement(new TextElement("select"));
if (stringHasValue(introspectedTable.getSelectByExampleQueryId())) {
selectByExampleSelectiveEle.addElement(new TextElement("'" + introspectedTable.getSelectByExampleQueryId() + "' as QUERYID,"));
// ===================================== ISelectOneByExamplePluginHook =========================================
@Override
public boolean clientSelectOneByExampleWithBLOBsMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) {
FormatTools.addMethodWithBestPosition(interfaze, this.replaceMethodWithSelective(
method,
METHOD_SELECT_ONE_BY_EXAMPLE_SELECTIVE,
"@Param(\"example\")",
introspectedTable
));
return true;
}
// issues#20
XmlElement ifDistinctElement = new XmlElement("if");
ifDistinctElement.addAttribute(new Attribute("test", "example.distinct"));
ifDistinctElement.addElement(new TextElement("distinct"));
selectByExampleSelectiveEle.addElement(ifDistinctElement);
@Override
public boolean clientSelectOneByExampleWithoutBLOBsMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) {
if (!introspectedTable.hasBLOBColumns()) {
FormatTools.addMethodWithBestPosition(interfaze, this.replaceMethodWithSelective(
method,
METHOD_SELECT_ONE_BY_EXAMPLE_SELECTIVE,
"@Param(\"example\")",
introspectedTable
));
}
return true;
}
selectByExampleSelectiveEle.addElement(columnsEle);
selectByExampleSelectiveEle.addElement(new TextElement("from " + introspectedTable.getAliasedFullyQualifiedTableNameAtRuntime()));
@Override
public boolean sqlMapSelectOneByExampleWithoutBLOBsElementGenerated(Document document, XmlElement element, IntrospectedTable introspectedTable) {
if (!introspectedTable.hasBLOBColumns()) {
FormatTools.addElementWithBestPosition(document.getRootElement(), this.generateSelectOneByExampleSelectiveElement(introspectedTable));
}
return true;
}
selectByExampleSelectiveEle.addElement(XmlElementGeneratorTools.getUpdateByExampleIncludeElement(introspectedTable));
@Override
public boolean sqlMapSelectOneByExampleWithBLOBsElementGenerated(Document document, XmlElement element, IntrospectedTable introspectedTable) {
FormatTools.addElementWithBestPosition(document.getRootElement(), this.generateSelectOneByExampleSelectiveElement(introspectedTable));
return true;
}
XmlElement ifElement = new XmlElement("if");
ifElement.addAttribute(new Attribute("test", "example.orderByClause != null"));
ifElement.addElement(new TextElement("order by ${example.orderByClause}"));
selectByExampleSelectiveEle.addElement(ifElement);
// =========================================== 一些私有方法 =====================================================
FormatTools.addElementWithBestPosition(document.getRootElement(), selectByExampleSelectiveEle);
/**
* 生成selectOneByExampleSelective
* @param introspectedTable
* @return
*/
private XmlElement generateSelectOneByExampleSelectiveElement(IntrospectedTable introspectedTable) {
return this.generateSelectSelectiveElement(METHOD_SELECT_ONE_BY_EXAMPLE_SELECTIVE, introspectedTable, true, true);
}
// 2. selectByPrimaryKeySelective
XmlElement selectByPrimaryKeySelectiveEle = new XmlElement("select");
commentGenerator.addComment(selectByPrimaryKeySelectiveEle);
/**
* 生成selectOneByExampleSelective
* @param introspectedTable
* @return
*/
private XmlElement generateSelectSelectiveElement(String id, IntrospectedTable introspectedTable, boolean selectOne, boolean byExample) {
XmlElement selectSelectiveEle = new XmlElement("select");
commentGenerator.addComment(selectSelectiveEle);
selectByPrimaryKeySelectiveEle.addAttribute(new Attribute("id", METHOD_SELECT_BY_PRIMARY_KEY_SELECTIVE));
selectSelectiveEle.addAttribute(new Attribute("id", id));
// issues#16
if (introspectedTable.isConstructorBased()) {
selectByPrimaryKeySelectiveEle.addAttribute(new Attribute("resultMap", ID_FOR_PROPERTY_BASED_RESULT_MAP));
selectSelectiveEle.addAttribute(new Attribute("resultMap", ID_FOR_PROPERTY_BASED_RESULT_MAP));
} else if (introspectedTable.hasBLOBColumns()) {
selectSelectiveEle.addAttribute(new Attribute("resultMap", introspectedTable.getResultMapWithBLOBsId()));
} else {
selectByPrimaryKeySelectiveEle.addAttribute(new Attribute("resultMap", introspectedTable.getBaseResultMapId()));
selectSelectiveEle.addAttribute(new Attribute("resultMap", introspectedTable.getBaseResultMapId()));
}
selectByPrimaryKeySelectiveEle.addAttribute(new Attribute("parameterType", "map"));
selectSelectiveEle.addAttribute(new Attribute("parameterType", "map"));
selectByPrimaryKeySelectiveEle.addElement(new TextElement("select"));
if (byExample) {
selectSelectiveEle.addElement(new TextElement("select"));
if (stringHasValue(introspectedTable.getSelectByExampleQueryId())) {
selectByPrimaryKeySelectiveEle.addElement(new TextElement("'" + introspectedTable.getSelectByExampleQueryId() + "' as QUERYID,"));
selectSelectiveEle.addElement(new TextElement("'" + introspectedTable.getSelectByExampleQueryId() + "' as QUERYID,"));
}
if (!selectOne) {
// issues#20
XmlElement ifDistinctElement = new XmlElement("if");
ifDistinctElement.addAttribute(new Attribute("test", "example.distinct"));
ifDistinctElement.addElement(new TextElement("distinct"));
selectSelectiveEle.addElement(ifDistinctElement);
}
} else {
selectSelectiveEle.addElement(new TextElement("select"));
if (stringHasValue(introspectedTable.getSelectByPrimaryKeyQueryId())) {
selectSelectiveEle.addElement(new TextElement("'" + introspectedTable.getSelectByPrimaryKeyQueryId() + "' as QUERYID,"));
}
}
selectByPrimaryKeySelectiveEle.addElement(columnsEle);
selectByPrimaryKeySelectiveEle.addElement(new TextElement("from " + introspectedTable.getAliasedFullyQualifiedTableNameAtRuntime()));
selectSelectiveEle.addElement(this.generateSelectiveElement(introspectedTable));
selectSelectiveEle.addElement(new TextElement("from " + introspectedTable.getAliasedFullyQualifiedTableNameAtRuntime()));
if (byExample) {
selectSelectiveEle.addElement(XmlElementGeneratorTools.getUpdateByExampleIncludeElement(introspectedTable));
XmlElement ifElement1 = new XmlElement("if");
ifElement1.addAttribute(new Attribute("test", "example.orderByClause != null"));
ifElement1.addElement(new TextElement("order by ${example.orderByClause}"));
selectSelectiveEle.addElement(ifElement1);
} else {
boolean and = false;
StringBuffer sb = new StringBuffer();
for (IntrospectedColumn introspectedColumn : introspectedTable.getPrimaryKeyColumns()) {
......@@ -252,51 +292,47 @@ public class SelectSelectivePlugin extends BasePlugin implements ISelectOneByExa
sb.append(MyBatis3FormattingUtilities.getAliasedEscapedColumnName(introspectedColumn));
sb.append(" = ");
sb.append(MyBatis3FormattingUtilities.getParameterClause(introspectedColumn, introspectedTable.getRules().generatePrimaryKeyClass() ? "record." : null));
selectByPrimaryKeySelectiveEle.addElement(new TextElement(sb.toString()));
selectSelectiveEle.addElement(new TextElement(sb.toString()));
}
FormatTools.addElementWithBestPosition(document.getRootElement(), selectByPrimaryKeySelectiveEle);
// 3. selectOneByExampleSelective
if (PluginTools.getPluginConfiguration(context, SelectOneByExamplePlugin.class) != null) {
XmlElement selectOneByExampleSelectiveEle = new XmlElement("select");
commentGenerator.addComment(selectOneByExampleSelectiveEle);
selectOneByExampleSelectiveEle.addAttribute(new Attribute("id", METHOD_SELECT_ONE_BY_EXAMPLE_SELECTIVE));
// issues#16
if (introspectedTable.isConstructorBased()) {
selectOneByExampleSelectiveEle.addAttribute(new Attribute("resultMap", ID_FOR_PROPERTY_BASED_RESULT_MAP));
} else {
selectOneByExampleSelectiveEle.addAttribute(new Attribute("resultMap", introspectedTable.getBaseResultMapId()));
}
selectOneByExampleSelectiveEle.addAttribute(new Attribute("parameterType", "map"));
selectOneByExampleSelectiveEle.addElement(new TextElement("select"));
if (stringHasValue(introspectedTable.getSelectByExampleQueryId())) {
selectOneByExampleSelectiveEle.addElement(new TextElement("'" + introspectedTable.getSelectByExampleQueryId() + "' as QUERYID,"));
if (selectOne) {
// 只查询一条
selectSelectiveEle.addElement(new TextElement("limit 1"));
}
selectOneByExampleSelectiveEle.addElement(columnsEle);
selectOneByExampleSelectiveEle.addElement(new TextElement("from " + introspectedTable.getAliasedFullyQualifiedTableNameAtRuntime()));
selectOneByExampleSelectiveEle.addElement(XmlElementGeneratorTools.getUpdateByExampleIncludeElement(introspectedTable));
return selectSelectiveEle;
}
XmlElement ifElement1 = new XmlElement("if");
ifElement1.addAttribute(new Attribute("test", "example.orderByClause != null"));
ifElement1.addElement(new TextElement("order by ${example.orderByClause}"));
selectOneByExampleSelectiveEle.addElement(ifElement1);
/**
* 生成Selective xml节点
* @param introspectedTable
* @return
*/
private XmlElement generateSelectiveElement(IntrospectedTable introspectedTable) {
XmlElement chooseEle = new XmlElement("choose");
// 只查询一条
selectOneByExampleSelectiveEle.addElement(new TextElement("limit 1"));
XmlElement whenEle = new XmlElement("when");
whenEle.addAttribute(new Attribute("test", "selective != null and selective.length > 0"));
chooseEle.addElement(whenEle);
// 添加到根节点
FormatTools.addElementWithBestPosition(document.getRootElement(), selectOneByExampleSelectiveEle);
// 生成返回字段节点
XmlElement keysEle = new XmlElement("foreach");
whenEle.addElement(keysEle);
keysEle.addAttribute(new Attribute("collection", "selective"));
keysEle.addAttribute(new Attribute("item", "column"));
keysEle.addAttribute(new Attribute("separator", ","));
keysEle.addElement(new TextElement("${column.value}"));
XmlElement otherwiseEle = new XmlElement("otherwise");
chooseEle.addElement(otherwiseEle);
for (Element element : XmlElementGeneratorTools.generateKeys(introspectedTable.getAllColumns())) {
otherwiseEle.addElement(element);
}
return true;
return chooseEle;
}
// =========================================== 一些私有方法 =====================================================
/**
* 替换方法成withSelective
* @param method
......@@ -328,31 +364,4 @@ public class SelectSelectivePlugin extends BasePlugin implements ISelectOneByExa
private FullyQualifiedJavaType getModelColumnFullyQualifiedJavaType(IntrospectedTable introspectedTable) {
return new FullyQualifiedJavaType(introspectedTable.getRules().calculateAllFieldsClass().getShortName() + "." + ModelColumnPlugin.ENUM_NAME);
}
/**
* @param answer
* @param introspectedTable
* @see ResultMapWithoutBLOBsElementGenerator#addResultMapElements(XmlElement)
*/
private void addResultMapElementsWithoutBLOBs(XmlElement answer, IntrospectedTable introspectedTable) {
for (IntrospectedColumn introspectedColumn : introspectedTable.getPrimaryKeyColumns()) {
answer.addElement(XmlElementGeneratorTools.generateResultMapResultElement("id", introspectedColumn));
}
List<IntrospectedColumn> columns = introspectedTable.getBaseColumns();
for (IntrospectedColumn introspectedColumn : columns) {
answer.addElement(XmlElementGeneratorTools.generateResultMapResultElement("result", introspectedColumn));
}
}
/**
* @param answer
* @param introspectedTable
* @see ResultMapWithBLOBsElementGenerator#addResultMapElements(XmlElement)
*/
private void addResultMapElementsWithBLOBs(XmlElement answer, IntrospectedTable introspectedTable) {
for (IntrospectedColumn introspectedColumn : introspectedTable.getBLOBColumns()) {
answer.addElement(XmlElementGeneratorTools.generateResultMapResultElement("result", introspectedColumn));
}
}
}
......@@ -134,28 +134,17 @@ public class XmlElementGeneratorTools {
* @return
*/
public static List<Element> generateKeys(List<IntrospectedColumn> columns) {
return generateKeys(columns, null);
return generateKeys(columns, false);
}
/**
* 生成keys Ele
* @param columns
* @param prefix
* @return
*/
public static List<Element> generateKeys(List<IntrospectedColumn> columns, String prefix) {
return generateKeys(columns, prefix, true);
}
/**
* 生成keys Ele
* @param columns
* @param prefix
* @param bracket
* @return
*/
public static List<Element> generateKeys(List<IntrospectedColumn> columns, String prefix, boolean bracket) {
return generateCommColumns(columns, prefix, bracket, 1);
public static List<Element> generateKeys(List<IntrospectedColumn> columns, boolean bracket) {
return generateCommColumns(columns, null, bracket, 1);
}
/**
......
......@@ -25,6 +25,7 @@ import org.mybatis.generator.api.dom.java.InnerClass;
import org.mybatis.generator.api.dom.java.Interface;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.java.TopLevelClass;
import org.mybatis.generator.api.dom.xml.Document;
import org.mybatis.generator.api.dom.xml.Element;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.config.Context;
......@@ -210,7 +211,6 @@ public class HookAggregator implements IUpsertPluginHook, IModelBuilderPluginHoo
// ============================================= ISelectOneByExamplePluginHook ==============================================
@Override
public boolean clientSelectOneByExampleWithBLOBsMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) {
for (ISelectOneByExamplePluginHook plugin : this.getPlugins(ISelectOneByExamplePluginHook.class)) {
......@@ -230,4 +230,24 @@ public class HookAggregator implements IUpsertPluginHook, IModelBuilderPluginHoo
}
return true;
}
@Override
public boolean sqlMapSelectOneByExampleWithoutBLOBsElementGenerated(Document document, XmlElement element, IntrospectedTable introspectedTable) {
for (ISelectOneByExamplePluginHook plugin : this.getPlugins(ISelectOneByExamplePluginHook.class)) {
if (!plugin.sqlMapSelectOneByExampleWithoutBLOBsElementGenerated(document, element, introspectedTable)) {
return false;
}
}
return true;
}
@Override
public boolean sqlMapSelectOneByExampleWithBLOBsElementGenerated(Document document, XmlElement element, IntrospectedTable introspectedTable) {
for (ISelectOneByExamplePluginHook plugin : this.getPlugins(ISelectOneByExamplePluginHook.class)) {
if (!plugin.sqlMapSelectOneByExampleWithBLOBsElementGenerated(document, element, introspectedTable)) {
return false;
}
}
return true;
}
}
......@@ -19,6 +19,8 @@ package com.itfsw.mybatis.generator.plugins.utils.hook;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.dom.java.Interface;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.xml.Document;
import org.mybatis.generator.api.dom.xml.XmlElement;
/**
* ---------------------------------------------------------------------------
......@@ -48,4 +50,21 @@ public interface ISelectOneByExamplePluginHook {
*/
boolean clientSelectOneByExampleWithoutBLOBsMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable);
/**
* selectOneByExample 方法sqlMap实现
* @param document
* @param element
* @param introspectedTable
* @return
*/
boolean sqlMapSelectOneByExampleWithoutBLOBsElementGenerated(Document document, XmlElement element, IntrospectedTable introspectedTable);
/**
* selectOneByExampleWithBLOBs 方法sqlMap实现
* @param document
* @param element
* @param introspectedTable
* @return
*/
boolean sqlMapSelectOneByExampleWithBLOBsElementGenerated(Document document, XmlElement element, IntrospectedTable introspectedTable);
}
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