Commit 69a94059 by shiwenbo

提交场站和购砂单位通用查询接口

parent 2085e656
package com.xyst.dinas.biz.web;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.json.JSONArray;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.beecode.amino.common.Convert;
import com.beecode.amino.core.Amino;
import com.beecode.bap.biztrait.billbasic.changeInfo.SubDatasChangeInfo;
import com.beecode.bap.biztrait.billbasic.web.BapBiztraitInputModel;
import com.beecode.bap.biztrait.billbasic.web.BiztraitOutputModel;
import com.beecode.bap.biztrait.billbasic.web.BiztraitOutputModel.OutputStatus;
import com.beecode.bap.biztrait.exception.ValidateErrorException;
import com.beecode.bap.biztrait.exception.ValidateWarnException;
import com.beecode.bcp.authz.Privilege;
import com.beecode.bcp.authz.service.PrivilegeService;
import com.beecode.bcp.biz.BiztraitMethod;
import com.beecode.bcp.biz.Biztype;
import com.beecode.bcp.biz.BusinessException;
import com.beecode.bcp.query.scene.ScenePrecidate;
import com.beecode.bcp.type.KObject;
import com.beecode.bcp.type.json.JSONObjectUtils;
import com.beecode.inz.query.define.QueryDefinition;
import com.beecode.inz.query.entity.PaginationResult;
import com.beecode.inz.query.exception.QueryException;
import com.beecode.inz.query.param.QueryPagination;
import com.beecode.inz.query.pojo.OrderObj;
import com.beecode.inz.query.pojo.QueryConditionObj;
import com.beecode.inz.query.pojo.QueryParamObj;
import com.beecode.inz.query.pojo.QueryResultObj;
import com.beecode.inz.query.service.QueryService;
import com.beecode.nlib.utils.StringUtils;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
@RestController
public class SandQueryController {
@Autowired
private QueryService queryService;
@Autowired
private PrivilegeService privilegeService;
private static final Logger logger = LoggerFactory.getLogger(SandQueryController.class);
private static final ObjectMapper OBJECTMAPPER = new ObjectMapper();
/**
* 查询分页
*
* @return
* @throws JsonProcessingException
*/
@RequestMapping(value = "/sand/user/query/functionQuery", method = RequestMethod.POST)
public String functionQuery(@RequestBody QueryParamObj queryParamObj) throws JsonProcessingException {
return this.doQuery(queryParamObj, true);
}
private String doQuery(QueryParamObj queryParamObj,boolean judgeFunctionAuth) throws JsonProcessingException {
QueryResultObj info = new QueryResultObj();
boolean check = checkQueryParam(queryParamObj.getConditions());
if(!check){
logger.error("查询参数不合法!");
info.setTotalCount(0);
info.setRowDatas(new JSONArray().toString());
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(info);
}
QueryDefinition queryDefinition = Amino.getApplicationMetadataContext().getBean(queryParamObj.getQueryDefinitionMetaName(), QueryDefinition.class);
if(judgeFunctionAuth){
Privilege privilege = queryDefinition.getPrivilege();
if(null != privilege){
if(!privilegeService.canAccess(privilege.getId(), null)){
logger.error("无权限进行元数据标识为"+queryDefinition.getName()+"的查询");
info.setTotalCount(0);
info.setRowDatas(new JSONArray().toString());
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(info);
}
}
}
if(queryParamObj.isUsePaging() && queryParamObj.getOrders().size() >= 1){//使用分页并且使用了排序,mysql数据库的分页和排序一起使用的时候有些特殊。
OrderObj idOrder = new OrderObj();
idOrder.setAsc(true);
idOrder.setName("id");
queryParamObj.getOrders().add(idOrder);
}
QueryPagination queryPagination = new QueryPagination();
queryPagination.setConditions(queryParamObj.getConditions());
queryPagination.setOrders(queryParamObj.getOrders());
queryPagination.setPageIndex(queryParamObj.getPageIndex());
queryPagination.setPageSize(queryParamObj.getPageSize());
queryPagination.setQueryFields(queryParamObj.getQueryFields());
queryPagination.setSumFields(queryParamObj.getSumFields());
queryPagination.setUsePaging(queryParamObj.isUsePaging());
try {
UUID sceneId = null;
if (StringUtils.isNotEmptyWithTrim(queryParamObj.getSceneId()) && queryParamObj.isUseScene()) {
sceneId = UUID.fromString(queryParamObj.getSceneId());
}
queryPagination.setSceneId(sceneId);
PaginationResult paginationResult = queryService.queryPaginationResult(queryDefinition, queryPagination);
info.setTotalCount(paginationResult.getCount());
JSONArray rowDatas = new JSONArray();
paginationResult.getRowDatas().forEach((row) -> {
rowDatas.put(row.toJson());
});
info.setRowDatas(rowDatas.toString());
if(null != paginationResult.getSumDatas()){
info.setSumDatas(paginationResult.getSumDatas().toJson().toString());
}
} catch (QueryException e) {
logger.warn(e.getMessage());
info.setTotalCount(0);
info.setRowDatas(new JSONArray().toString());
}
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(info);
}
/**
* 查询分页
*
* @return
* @throws JsonProcessingException
*/
@RequestMapping(value = "/sand/user/query/pagination", method = RequestMethod.POST)
public String queryPagination(@RequestBody QueryParamObj queryParamObj) throws JsonProcessingException {
return this.doQuery(queryParamObj, false);
}
private boolean checkQueryParam(ArrayList<QueryConditionObj> conditions ){
if(null == conditions || conditions.size() == 0){
return true;
}
for(QueryConditionObj obj : conditions){
if(ScenePrecidate.findPrecidateByValue(obj.getRelation()) == ScenePrecidate.IN || ScenePrecidate.findPrecidateByValue(obj.getRelation()) == ScenePrecidate.NOT_IN ){
if(obj.getValues().isEmpty()){
return false;
}
}
}
return true;
}
@RequestMapping(value = "/sand/user/query/queryInfo", method = RequestMethod.POST)
public String getQueryInfo(@RequestBody QueryParamObj queryParamObj) throws JsonProcessingException {
QueryResultObj queryInfo = new QueryResultObj();
QueryDefinition queryDefinition = Amino.getApplicationMetadataContext().getBean(queryParamObj.getQueryDefinitionMetaName(), QueryDefinition.class);
queryInfo.setFieldDefinitions(queryDefinition.getFieldsDefinition().getFields());
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(queryInfo);
}
private String serialize(Object methodReturnValue) {
if(null == methodReturnValue){
return null;
}
String result;
if (methodReturnValue instanceof String) {
result = (String) methodReturnValue;
} else if (methodReturnValue instanceof UUID) {
result = ((UUID) methodReturnValue).toString();
} else if (methodReturnValue instanceof Boolean) {
result = methodReturnValue.toString();
} else if(methodReturnValue instanceof KObject){
// result = new BizObjectSerializer(methodReturnValue).serialize().toString();
result = JSONObjectUtils.toJson(methodReturnValue,false,false).toString();
} else if(methodReturnValue instanceof List){
result = JSONObjectUtils.toJson(methodReturnValue,false,false).toString();
} else {
result = methodReturnValue.toString();
}
return result;
}
private Object deSerialize(Biztype bizType,Class<?> targetType, String stringValue)
throws IOException, JsonParseException, JsonMappingException {
Object value = null;
if(null != stringValue && !"".equals(stringValue)){
if (targetType == String.class) {
value = stringValue;
} else if (targetType == UUID.class) {
value = Convert.toUUID(stringValue);
} else if (targetType == Integer.class) {
value = Integer.valueOf(stringValue);
} else if (targetType == Long.class) {
value = Long.valueOf(stringValue);
} else if (targetType == KObject.class) {
//value = JSONObjectUtils.toObject(stringValue);
JsonNode json = JSONObjectUtils.getMapper().readTree(stringValue);
//KObject类型参数就需要带_type标记
KObject bizData = (KObject) JSONObjectUtils.toObject(json);
// BiztraitUtil.bizDataReplaceRelateObjects(bizType.getType(), bizData);
value = bizData;
}else if (targetType == SubDatasChangeInfo.class) {
SubDatasChangeInfo changeInfo = new SubDatasChangeInfo();
changeInfo.fromJson(stringValue);
value = changeInfo;
}else if (targetType == Object.class) {
value = stringValue;
} else {
value = OBJECTMAPPER.readValue(stringValue,
targetType);
}
}
return value;
}
/**
* url为/biz/simple/{defineName}/{methodName}
* post请求
* Content-Type:'application/json'
* 参数格式为{runtimeId:'',methodParameters:[]}
*/
@ResponseBody
@RequestMapping(value = "/sand/user/biz/simple/{defineName}/{methodName}", method = RequestMethod.POST,consumes="application/json")
@CrossOrigin
public BiztraitOutputModel simpleInvoke(@PathVariable("defineName") String defineName,@PathVariable("methodName") String methodName,@RequestBody BapBiztraitInputModel bcpBizInputModel) {
BiztraitOutputModel bom = new BiztraitOutputModel();
Biztype bizType = Amino.getApplicationMetadataContext().getBean(defineName, Biztype.class);
try {
if (bizType != null) {
String authorityItem = bizType.getAuthorityItemByMethodName(methodName);
if(authorityItem != null && !"".equals(authorityItem)){
Privilege privilege = Amino.getApplicationMetadataContext().getBean(authorityItem, Privilege.class);
if(null != privilege){
if(!privilegeService.canAccess(privilege.getId(), null)){
String message = "无权限进行业务类型为["+defineName+"],方法名为[" + methodName + "]的调用!";
throw new AccessDeniedException(message);
}
}
}
BiztraitMethod biztraitMethod = bizType.getBiztraitMethod(methodName);
Object[] paras = new Object[biztraitMethod.getParameterTypes().length];
List<String> parameterValues = bcpBizInputModel.getMethodParameters();
if (null != parameterValues && !parameterValues.isEmpty()) {
try {
for (int i = 0; i < paras.length; i++) {
if(i < parameterValues.size()){
paras[i] = deSerialize(bizType,biztraitMethod.getParameterTypes()[i], parameterValues.get(i));
}
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("参数解析异常:" + e.getMessage(), e);
}
}
Object methodReturnValue = bizType.invoke(methodName, paras);
bom.setStatus(OutputStatus.success); //执行成功,正常返回结果
bom.setResult(serialize(methodReturnValue));
} else {
throw new RuntimeException("没有合适的业务类型处理该请求!");
}
} catch (ValidateErrorException e) { //校验错误异常
bom.setStatus(OutputStatus.validateErrorException);
bom.setResult(e.getMessage());
} catch (ValidateWarnException e) { //校验提示异常
bom.setStatus(OutputStatus.validateAlertException);
bom.setResult(e.getMessage());
} catch (BusinessException e) { //业务异常,前端弹出提示
bom.setStatus(OutputStatus.businessException);
bom.setResult(e.getMessage());
} catch(AccessDeniedException e){
throw e;
} catch (Exception e) { //程序异常,前端提示后刷新页面,进行进行后续操作。
e.printStackTrace();
bom.setStatus(OutputStatus.programException);
bom.setResult(e.getMessage());
}finally{
}
return bom;
}
}
package com.xyst.dinas.biz.web;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.json.JSONArray;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.beecode.amino.common.Convert;
import com.beecode.amino.core.Amino;
import com.beecode.bap.biztrait.billbasic.changeInfo.SubDatasChangeInfo;
import com.beecode.bap.biztrait.billbasic.web.BapBiztraitInputModel;
import com.beecode.bap.biztrait.billbasic.web.BiztraitOutputModel;
import com.beecode.bap.biztrait.billbasic.web.BiztraitOutputModel.OutputStatus;
import com.beecode.bap.biztrait.exception.ValidateErrorException;
import com.beecode.bap.biztrait.exception.ValidateWarnException;
import com.beecode.bcp.authz.Privilege;
import com.beecode.bcp.authz.service.PrivilegeService;
import com.beecode.bcp.biz.BiztraitMethod;
import com.beecode.bcp.biz.Biztype;
import com.beecode.bcp.biz.BusinessException;
import com.beecode.bcp.query.scene.ScenePrecidate;
import com.beecode.bcp.type.KObject;
import com.beecode.bcp.type.json.JSONObjectUtils;
import com.beecode.inz.query.define.QueryDefinition;
import com.beecode.inz.query.entity.PaginationResult;
import com.beecode.inz.query.exception.QueryException;
import com.beecode.inz.query.param.QueryPagination;
import com.beecode.inz.query.pojo.OrderObj;
import com.beecode.inz.query.pojo.QueryConditionObj;
import com.beecode.inz.query.pojo.QueryParamObj;
import com.beecode.inz.query.pojo.QueryResultObj;
import com.beecode.inz.query.service.QueryService;
import com.beecode.nlib.utils.StringUtils;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
@RestController
public class WarehouseQueryController {
@Autowired
private QueryService queryService;
@Autowired
private PrivilegeService privilegeService;
private static final Logger logger = LoggerFactory.getLogger(WarehouseQueryController.class);
private static final ObjectMapper OBJECTMAPPER = new ObjectMapper();
/**
* 查询分页
*
* @return
* @throws JsonProcessingException
*/
@RequestMapping(value = "/warehouse/api/query/functionQuery", method = RequestMethod.POST)
public String functionQuery(@RequestBody QueryParamObj queryParamObj) throws JsonProcessingException {
return this.doQuery(queryParamObj, true);
}
private String doQuery(QueryParamObj queryParamObj,boolean judgeFunctionAuth) throws JsonProcessingException {
QueryResultObj info = new QueryResultObj();
boolean check = checkQueryParam(queryParamObj.getConditions());
if(!check){
logger.error("查询参数不合法!");
info.setTotalCount(0);
info.setRowDatas(new JSONArray().toString());
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(info);
}
QueryDefinition queryDefinition = Amino.getApplicationMetadataContext().getBean(queryParamObj.getQueryDefinitionMetaName(), QueryDefinition.class);
if(judgeFunctionAuth){
Privilege privilege = queryDefinition.getPrivilege();
if(null != privilege){
if(!privilegeService.canAccess(privilege.getId(), null)){
logger.error("无权限进行元数据标识为"+queryDefinition.getName()+"的查询");
info.setTotalCount(0);
info.setRowDatas(new JSONArray().toString());
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(info);
}
}
}
if(queryParamObj.isUsePaging() && queryParamObj.getOrders().size() >= 1){//使用分页并且使用了排序,mysql数据库的分页和排序一起使用的时候有些特殊。
OrderObj idOrder = new OrderObj();
idOrder.setAsc(true);
idOrder.setName("id");
queryParamObj.getOrders().add(idOrder);
}
QueryPagination queryPagination = new QueryPagination();
queryPagination.setConditions(queryParamObj.getConditions());
queryPagination.setOrders(queryParamObj.getOrders());
queryPagination.setPageIndex(queryParamObj.getPageIndex());
queryPagination.setPageSize(queryParamObj.getPageSize());
queryPagination.setQueryFields(queryParamObj.getQueryFields());
queryPagination.setSumFields(queryParamObj.getSumFields());
queryPagination.setUsePaging(queryParamObj.isUsePaging());
try {
UUID sceneId = null;
if (StringUtils.isNotEmptyWithTrim(queryParamObj.getSceneId()) && queryParamObj.isUseScene()) {
sceneId = UUID.fromString(queryParamObj.getSceneId());
}
queryPagination.setSceneId(sceneId);
PaginationResult paginationResult = queryService.queryPaginationResult(queryDefinition, queryPagination);
info.setTotalCount(paginationResult.getCount());
JSONArray rowDatas = new JSONArray();
paginationResult.getRowDatas().forEach((row) -> {
rowDatas.put(row.toJson());
});
info.setRowDatas(rowDatas.toString());
if(null != paginationResult.getSumDatas()){
info.setSumDatas(paginationResult.getSumDatas().toJson().toString());
}
} catch (QueryException e) {
logger.warn(e.getMessage());
info.setTotalCount(0);
info.setRowDatas(new JSONArray().toString());
}
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(info);
}
/**
* 查询分页
*
* @return
* @throws JsonProcessingException
*/
@RequestMapping(value = "/warehouse/api/query/pagination", method = RequestMethod.POST)
public String queryPagination(@RequestBody QueryParamObj queryParamObj) throws JsonProcessingException {
return this.doQuery(queryParamObj, false);
}
private boolean checkQueryParam(ArrayList<QueryConditionObj> conditions ){
if(null == conditions || conditions.size() == 0){
return true;
}
for(QueryConditionObj obj : conditions){
if(ScenePrecidate.findPrecidateByValue(obj.getRelation()) == ScenePrecidate.IN || ScenePrecidate.findPrecidateByValue(obj.getRelation()) == ScenePrecidate.NOT_IN ){
if(obj.getValues().isEmpty()){
return false;
}
}
}
return true;
}
@RequestMapping(value = "/warehouse/api/query/queryInfo", method = RequestMethod.POST)
public String getQueryInfo(@RequestBody QueryParamObj queryParamObj) throws JsonProcessingException {
QueryResultObj queryInfo = new QueryResultObj();
QueryDefinition queryDefinition = Amino.getApplicationMetadataContext().getBean(queryParamObj.getQueryDefinitionMetaName(), QueryDefinition.class);
queryInfo.setFieldDefinitions(queryDefinition.getFieldsDefinition().getFields());
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(queryInfo);
}
private String serialize(Object methodReturnValue) {
if(null == methodReturnValue){
return null;
}
String result;
if (methodReturnValue instanceof String) {
result = (String) methodReturnValue;
} else if (methodReturnValue instanceof UUID) {
result = ((UUID) methodReturnValue).toString();
} else if (methodReturnValue instanceof Boolean) {
result = methodReturnValue.toString();
} else if(methodReturnValue instanceof KObject){
// result = new BizObjectSerializer(methodReturnValue).serialize().toString();
result = JSONObjectUtils.toJson(methodReturnValue,false,false).toString();
} else if(methodReturnValue instanceof List){
result = JSONObjectUtils.toJson(methodReturnValue,false,false).toString();
} else {
result = methodReturnValue.toString();
}
return result;
}
private Object deSerialize(Biztype bizType,Class<?> targetType, String stringValue)
throws IOException, JsonParseException, JsonMappingException {
Object value = null;
if(null != stringValue && !"".equals(stringValue)){
if (targetType == String.class) {
value = stringValue;
} else if (targetType == UUID.class) {
value = Convert.toUUID(stringValue);
} else if (targetType == Integer.class) {
value = Integer.valueOf(stringValue);
} else if (targetType == Long.class) {
value = Long.valueOf(stringValue);
} else if (targetType == KObject.class) {
//value = JSONObjectUtils.toObject(stringValue);
JsonNode json = JSONObjectUtils.getMapper().readTree(stringValue);
//KObject类型参数就需要带_type标记
KObject bizData = (KObject) JSONObjectUtils.toObject(json);
// BiztraitUtil.bizDataReplaceRelateObjects(bizType.getType(), bizData);
value = bizData;
}else if (targetType == SubDatasChangeInfo.class) {
SubDatasChangeInfo changeInfo = new SubDatasChangeInfo();
changeInfo.fromJson(stringValue);
value = changeInfo;
}else if (targetType == Object.class) {
value = stringValue;
} else {
value = OBJECTMAPPER.readValue(stringValue,
targetType);
}
}
return value;
}
/**
* url为/biz/simple/{defineName}/{methodName}
* post请求
* Content-Type:'application/json'
* 参数格式为{runtimeId:'',methodParameters:[]}
*/
@ResponseBody
@RequestMapping(value = "/warehouse/api/biz/simple/{defineName}/{methodName}", method = RequestMethod.POST,consumes="application/json")
@CrossOrigin
public BiztraitOutputModel simpleInvoke(@PathVariable("defineName") String defineName,@PathVariable("methodName") String methodName,@RequestBody BapBiztraitInputModel bcpBizInputModel) {
BiztraitOutputModel bom = new BiztraitOutputModel();
Biztype bizType = Amino.getApplicationMetadataContext().getBean(defineName, Biztype.class);
try {
if (bizType != null) {
String authorityItem = bizType.getAuthorityItemByMethodName(methodName);
if(authorityItem != null && !"".equals(authorityItem)){
Privilege privilege = Amino.getApplicationMetadataContext().getBean(authorityItem, Privilege.class);
if(null != privilege){
if(!privilegeService.canAccess(privilege.getId(), null)){
String message = "无权限进行业务类型为["+defineName+"],方法名为[" + methodName + "]的调用!";
throw new AccessDeniedException(message);
}
}
}
BiztraitMethod biztraitMethod = bizType.getBiztraitMethod(methodName);
Object[] paras = new Object[biztraitMethod.getParameterTypes().length];
List<String> parameterValues = bcpBizInputModel.getMethodParameters();
if (null != parameterValues && !parameterValues.isEmpty()) {
try {
for (int i = 0; i < paras.length; i++) {
if(i < parameterValues.size()){
paras[i] = deSerialize(bizType,biztraitMethod.getParameterTypes()[i], parameterValues.get(i));
}
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("参数解析异常:" + e.getMessage(), e);
}
}
Object methodReturnValue = bizType.invoke(methodName, paras);
bom.setStatus(OutputStatus.success); //执行成功,正常返回结果
bom.setResult(serialize(methodReturnValue));
} else {
throw new RuntimeException("没有合适的业务类型处理该请求!");
}
} catch (ValidateErrorException e) { //校验错误异常
bom.setStatus(OutputStatus.validateErrorException);
bom.setResult(e.getMessage());
} catch (ValidateWarnException e) { //校验提示异常
bom.setStatus(OutputStatus.validateAlertException);
bom.setResult(e.getMessage());
} catch (BusinessException e) { //业务异常,前端弹出提示
bom.setStatus(OutputStatus.businessException);
bom.setResult(e.getMessage());
} catch(AccessDeniedException e){
throw e;
} catch (Exception e) { //程序异常,前端提示后刷新页面,进行进行后续操作。
e.printStackTrace();
bom.setStatus(OutputStatus.programException);
bom.setResult(e.getMessage());
}finally{
}
return bom;
}
}
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