[Test-3557][API] full cover DataAnalysisServiceImpl (#3605)

* generate equals and hashCode method

* make up for the state of oblivion

* simplify countQueueState method

* delete try catch, because this never throw exception

* full cover DataAnalysisServiceImpl

* improve test coverage

* adjust code style

* simplify countCommandState method

* reduce duplication

* simplify countTaskDtos method

* Update DataAnalysisServiceImpl.java

Co-authored-by: dailidong <dailidong66@gmail.com>
This commit is contained in:
孙继峰 2020-10-26 21:29:37 +08:00 committed by GitHub
parent e9479e4a03
commit afd0e6ab65
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 237 additions and 202 deletions

View File

@ -57,4 +57,32 @@ public class CommandStateCount {
public void setCommandState(CommandType commandState) {
this.commandState = commandState;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
CommandStateCount that = (CommandStateCount) o;
if (errorCount != that.errorCount) {
return false;
}
if (normalCount != that.normalCount) {
return false;
}
return commandState == that.commandState;
}
@Override
public int hashCode() {
int result = errorCount;
result = 31 * result + normalCount;
result = 31 * result + (commandState != null ? commandState.hashCode() : 0);
return result;
}
}

View File

@ -19,8 +19,10 @@ package org.apache.dolphinscheduler.api.dto;
import org.apache.dolphinscheduler.common.enums.ExecutionStatus;
import org.apache.dolphinscheduler.dao.entity.ExecuteStatusCount;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* task count dto
@ -43,77 +45,16 @@ public class TaskCountDto {
}
private void countTaskDtos(List<ExecuteStatusCount> taskInstanceStateCounts) {
int submittedSuccess = 0;
int runningExecution = 0;
int delayExecution = 0;
int readyPause = 0;
int pause = 0;
int readyStop = 0;
int stop = 0;
int failure = 0;
int success = 0;
int needFaultTolerance = 0;
int kill = 0;
int waittingThread = 0;
Map<ExecutionStatus, Integer> statusCountMap = taskInstanceStateCounts.stream()
.collect(Collectors.toMap(ExecuteStatusCount::getExecutionStatus, ExecuteStatusCount::getCount, Integer::sum));
for (ExecuteStatusCount taskInstanceStateCount : taskInstanceStateCounts) {
ExecutionStatus status = taskInstanceStateCount.getExecutionStatus();
totalCount += taskInstanceStateCount.getCount();
switch (status) {
case SUBMITTED_SUCCESS:
submittedSuccess += taskInstanceStateCount.getCount();
break;
case RUNNING_EXECUTION:
runningExecution += taskInstanceStateCount.getCount();
break;
case DELAY_EXECUTION:
delayExecution += taskInstanceStateCount.getCount();
break;
case READY_PAUSE:
readyPause += taskInstanceStateCount.getCount();
break;
case PAUSE:
pause += taskInstanceStateCount.getCount();
break;
case READY_STOP:
readyStop += taskInstanceStateCount.getCount();
break;
case STOP:
stop += taskInstanceStateCount.getCount();
break;
case FAILURE:
failure += taskInstanceStateCount.getCount();
break;
case SUCCESS:
success += taskInstanceStateCount.getCount();
break;
case NEED_FAULT_TOLERANCE:
needFaultTolerance += taskInstanceStateCount.getCount();
break;
case KILL:
kill += taskInstanceStateCount.getCount();
break;
case WAITTING_THREAD:
waittingThread += taskInstanceStateCount.getCount();
break;
taskCountDtos = Arrays.stream(ExecutionStatus.values())
.map(status -> new TaskStateCount(status, statusCountMap.getOrDefault(status, 0)))
.collect(Collectors.toList());
default:
break;
}
}
this.taskCountDtos = new ArrayList<>();
this.taskCountDtos.add(new TaskStateCount(ExecutionStatus.SUBMITTED_SUCCESS, submittedSuccess));
this.taskCountDtos.add(new TaskStateCount(ExecutionStatus.RUNNING_EXECUTION, runningExecution));
this.taskCountDtos.add(new TaskStateCount(ExecutionStatus.DELAY_EXECUTION, delayExecution));
this.taskCountDtos.add(new TaskStateCount(ExecutionStatus.READY_PAUSE, readyPause));
this.taskCountDtos.add(new TaskStateCount(ExecutionStatus.PAUSE, pause));
this.taskCountDtos.add(new TaskStateCount(ExecutionStatus.READY_STOP, readyStop));
this.taskCountDtos.add(new TaskStateCount(ExecutionStatus.STOP, stop));
this.taskCountDtos.add(new TaskStateCount(ExecutionStatus.FAILURE, failure));
this.taskCountDtos.add(new TaskStateCount(ExecutionStatus.SUCCESS, success));
this.taskCountDtos.add(new TaskStateCount(ExecutionStatus.NEED_FAULT_TOLERANCE, needFaultTolerance));
this.taskCountDtos.add(new TaskStateCount(ExecutionStatus.KILL, kill));
this.taskCountDtos.add(new TaskStateCount(ExecutionStatus.WAITTING_THREAD, waittingThread));
totalCount = taskCountDtos.stream()
.mapToInt(TaskStateCount::getCount)
.sum();
}
public List<TaskStateCount> getTaskCountDtos() {

View File

@ -47,4 +47,28 @@ public class TaskStateCount {
public void setTaskStateType(ExecutionStatus taskStateType) {
this.taskStateType = taskStateType;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
TaskStateCount that = (TaskStateCount) o;
if (count != that.count) {
return false;
}
return taskStateType == that.taskStateType;
}
@Override
public int hashCode() {
int result = count;
result = 31 * result + (taskStateType != null ? taskStateType.hashCode() : 0);
return result;
}
}

View File

@ -16,7 +16,6 @@
*/
package org.apache.dolphinscheduler.api.service.impl;
import org.apache.dolphinscheduler.api.dto.CommandStateCount;
import org.apache.dolphinscheduler.api.dto.DefineUserDto;
import org.apache.dolphinscheduler.api.dto.TaskCountDto;
@ -45,14 +44,14 @@ import org.apache.dolphinscheduler.service.process.ProcessService;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@ -62,8 +61,6 @@ import org.springframework.stereotype.Service;
@Service
public class DataAnalysisServiceImpl extends BaseService implements DataAnalysisService {
private static final Logger logger = LoggerFactory.getLogger(DataAnalysisServiceImpl.class);
@Autowired
private ProjectMapper projectMapper;
@ -88,10 +85,6 @@ public class DataAnalysisServiceImpl extends BaseService implements DataAnalysis
@Autowired
private ProcessService processService;
private static final String COMMAND_STATE = "commandState";
private static final String ERROR_COMMAND_STATE = "errorCommandState";
/**
* statistical task instance status data
*
@ -137,16 +130,17 @@ public class DataAnalysisServiceImpl extends BaseService implements DataAnalysis
return result;
}
Date start;
Date end;
try {
Date start = null;
Date end = null;
if (StringUtils.isNotEmpty(startDate) && StringUtils.isNotEmpty(endDate)) {
start = DateUtils.getScheduleDate(startDate);
end = DateUtils.getScheduleDate(endDate);
} catch (Exception e) {
logger.error(e.getMessage(), e);
putErrorRequestParamsMsg(result);
return result;
if (Objects.isNull(start) || Objects.isNull(end)) {
putErrorRequestParamsMsg(result);
return result;
}
}
Integer[] projectIdArray = getProjectIdsArrays(loginUser, projectId);
List<ExecuteStatusCount> processInstanceStateCounts =
instanceStateCounter.apply(start, end, projectIdArray);
@ -204,79 +198,39 @@ public class DataAnalysisServiceImpl extends BaseService implements DataAnalysis
* statistics based on task status execution, failure, completion, wait, total
*/
Date start = null;
if (StringUtils.isNotEmpty(startDate)) {
start = DateUtils.getScheduleDate(startDate);
if (Objects.isNull(start)) {
putErrorRequestParamsMsg(result);
return result;
}
}
Date end = null;
if (startDate != null && endDate != null) {
try {
start = DateUtils.getScheduleDate(startDate);
end = DateUtils.getScheduleDate(endDate);
} catch (Exception e) {
logger.error(e.getMessage(), e);
if (StringUtils.isNotEmpty(endDate)) {
end = DateUtils.getScheduleDate(endDate);
if (Objects.isNull(end)) {
putErrorRequestParamsMsg(result);
return result;
}
}
Integer[] projectIdArray = getProjectIdsArrays(loginUser, projectId);
// count command state
List<CommandCount> commandStateCounts =
commandMapper.countCommandState(
loginUser.getId(),
start,
end,
projectIdArray);
// count normal command state
Map<CommandType, Integer> normalCountCommandCounts = commandMapper.countCommandState(loginUser.getId(), start, end, projectIdArray)
.stream()
.collect(Collectors.toMap(CommandCount::getCommandType, CommandCount::getCount));
// count error command state
List<CommandCount> errorCommandStateCounts =
errorCommandMapper.countCommandState(
start, end, projectIdArray);
Map<CommandType, Integer> errorCommandCounts = errorCommandMapper.countCommandState(start, end, projectIdArray)
.stream()
.collect(Collectors.toMap(CommandCount::getCommandType, CommandCount::getCount));
// enumMap
Map<CommandType, Map<String, Integer>> dataMap = new EnumMap<>(CommandType.class);
Map<String, Integer> commonCommand = new HashMap<>();
commonCommand.put(COMMAND_STATE, 0);
commonCommand.put(ERROR_COMMAND_STATE, 0);
// init data map
/**
* START_PROCESS, START_CURRENT_TASK_PROCESS, RECOVER_TOLERANCE_FAULT_PROCESS, RECOVER_SUSPENDED_PROCESS,
START_FAILURE_TASK_PROCESS,COMPLEMENT_DATA,SCHEDULER, REPEAT_RUNNING,PAUSE,STOP,RECOVER_WAITTING_THREAD;
*/
dataMap.put(CommandType.START_PROCESS, commonCommand);
dataMap.put(CommandType.START_CURRENT_TASK_PROCESS, commonCommand);
dataMap.put(CommandType.RECOVER_TOLERANCE_FAULT_PROCESS, commonCommand);
dataMap.put(CommandType.RECOVER_SUSPENDED_PROCESS, commonCommand);
dataMap.put(CommandType.START_FAILURE_TASK_PROCESS, commonCommand);
dataMap.put(CommandType.COMPLEMENT_DATA, commonCommand);
dataMap.put(CommandType.SCHEDULER, commonCommand);
dataMap.put(CommandType.REPEAT_RUNNING, commonCommand);
dataMap.put(CommandType.PAUSE, commonCommand);
dataMap.put(CommandType.STOP, commonCommand);
dataMap.put(CommandType.RECOVER_WAITTING_THREAD, commonCommand);
// put command state
for (CommandCount executeStatusCount : commandStateCounts) {
Map<String, Integer> commandStateCountsMap = new HashMap<>(dataMap.get(executeStatusCount.getCommandType()));
commandStateCountsMap.put(COMMAND_STATE, executeStatusCount.getCount());
dataMap.put(executeStatusCount.getCommandType(), commandStateCountsMap);
}
// put error command state
for (CommandCount errorExecutionStatus : errorCommandStateCounts) {
Map<String, Integer> errorCommandStateCountsMap = new HashMap<>(dataMap.get(errorExecutionStatus.getCommandType()));
errorCommandStateCountsMap.put(ERROR_COMMAND_STATE, errorExecutionStatus.getCount());
dataMap.put(errorExecutionStatus.getCommandType(), errorCommandStateCountsMap);
}
List<CommandStateCount> list = new ArrayList<>();
for (Map.Entry<CommandType, Map<String, Integer>> next : dataMap.entrySet()) {
CommandStateCount commandStateCount = new CommandStateCount(next.getValue().get(ERROR_COMMAND_STATE),
next.getValue().get(COMMAND_STATE), next.getKey());
list.add(commandStateCount);
}
List<CommandStateCount> list = Arrays.stream(CommandType.values())
.map(commandType -> new CommandStateCount(
errorCommandCounts.getOrDefault(commandType, 0),
normalCountCommandCounts.getOrDefault(commandType, 0),
commandType)
).collect(Collectors.toList());
result.put(Constants.DATA_LIST, list);
putMsg(result, Status.SUCCESS);
@ -311,59 +265,10 @@ public class DataAnalysisServiceImpl extends BaseService implements DataAnalysis
return result;
}
// TODO tasksQueueList and tasksKillList is never updated.
List<String> tasksQueueList = new ArrayList<>();
List<String> tasksKillList = new ArrayList<>();
//TODO need to add detail data info
Map<String, Integer> dataMap = new HashMap<>();
if (loginUser.getUserType() == UserType.ADMIN_USER) {
dataMap.put("taskQueue", tasksQueueList.size());
dataMap.put("taskKill", tasksKillList.size());
result.put(Constants.DATA_LIST, dataMap);
putMsg(result, Status.SUCCESS);
return result;
}
int[] tasksQueueIds = new int[tasksQueueList.size()];
int[] tasksKillIds = new int[tasksKillList.size()];
int i = 0;
for (String taskQueueStr : tasksQueueList) {
if (StringUtils.isNotEmpty(taskQueueStr)) {
String[] splits = taskQueueStr.split("_");
if (splits.length >= 4) {
tasksQueueIds[i++] = Integer.parseInt(splits[3]);
}
}
}
i = 0;
for (String taskKillStr : tasksKillList) {
if (StringUtils.isNotEmpty(taskKillStr)) {
String[] splits = taskKillStr.split("-");
if (splits.length == 2) {
tasksKillIds[i++] = Integer.parseInt(splits[1]);
}
}
}
Integer taskQueueCount = 0;
Integer taskKillCount = 0;
Integer[] projectIds = getProjectIdsArrays(loginUser, projectId);
if (tasksQueueIds.length != 0) {
taskQueueCount = taskInstanceMapper.countTask(
projectIds,
tasksQueueIds);
}
if (tasksKillIds.length != 0) {
taskKillCount = taskInstanceMapper.countTask(projectIds, tasksKillIds);
}
dataMap.put("taskQueue", taskQueueCount);
dataMap.put("taskKill", taskKillCount);
dataMap.put("taskQueue", 0);
dataMap.put("taskKill", 0);
result.put(Constants.DATA_LIST, dataMap);
putMsg(result, Status.SUCCESS);
return result;

View File

@ -16,12 +16,19 @@
*/
package org.apache.dolphinscheduler.api.service;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import org.apache.dolphinscheduler.api.dto.CommandStateCount;
import org.apache.dolphinscheduler.api.dto.TaskStateCount;
import org.apache.dolphinscheduler.api.enums.Status;
import org.apache.dolphinscheduler.api.service.impl.DataAnalysisServiceImpl;
import org.apache.dolphinscheduler.api.service.impl.ProjectServiceImpl;
import org.apache.dolphinscheduler.common.Constants;
import org.apache.dolphinscheduler.common.enums.CommandType;
import org.apache.dolphinscheduler.common.enums.ExecutionStatus;
import org.apache.dolphinscheduler.common.enums.UserType;
import org.apache.dolphinscheduler.common.utils.DateUtils;
import org.apache.dolphinscheduler.dao.entity.CommandCount;
import org.apache.dolphinscheduler.dao.entity.ExecuteStatusCount;
@ -36,6 +43,7 @@ import org.apache.dolphinscheduler.dao.mapper.TaskInstanceMapper;
import org.apache.dolphinscheduler.service.process.ProcessService;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -123,6 +131,74 @@ public class DataAnalysisServiceTest {
result = dataAnalysisService.countTaskStateByProject(user, 1, startDate, endDate);
Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS));
// when date in illegal format then return error message
String startDate2 = "illegalDateString";
String endDate2 = "illegalDateString";
result = dataAnalysisService.countTaskStateByProject(user, 0, startDate2, endDate2);
Assert.assertEquals(Status.REQUEST_PARAMS_NOT_VALID_ERROR, result.get(Constants.STATUS));
// when one of date in illegal format then return error message
String startDate3 = "2020-08-28 14:13:40";
String endDate3 = "illegalDateString";
result = dataAnalysisService.countTaskStateByProject(user, 0, startDate3, endDate3);
Assert.assertEquals(Status.REQUEST_PARAMS_NOT_VALID_ERROR, result.get(Constants.STATUS));
// when one of date in illegal format then return error message
String startDate4 = "illegalDateString";
String endDate4 = "2020-08-28 14:13:40";
result = dataAnalysisService.countTaskStateByProject(user, 0, startDate4, endDate4);
Assert.assertEquals(Status.REQUEST_PARAMS_NOT_VALID_ERROR, result.get(Constants.STATUS));
// when counting general user's task status then return user's task status count
user.setUserType(UserType.GENERAL_USER);
Mockito.when(processService.getProjectIdListHavePerm(anyInt()))
.thenReturn(Collections.singletonList(123));
ExecuteStatusCount executeStatusCount = new ExecuteStatusCount();
executeStatusCount.setExecutionStatus(ExecutionStatus.RUNNING_EXECUTION);
executeStatusCount.setCount(10);
Mockito.when(taskInstanceMapper.countTaskInstanceStateByUser(any(), any(), any()))
.thenReturn(Collections.singletonList(executeStatusCount));
result = dataAnalysisService.countTaskStateByProject(user, 0, startDate, null);
assertThat(result.get(Constants.DATA_LIST)).extracting("taskCountDtos").first().asList()
.hasSameSizeAs(ExecutionStatus.values());
assertThat(result.get(Constants.DATA_LIST)).extracting("totalCount").first().isEqualTo(10);
TaskStateCount taskStateCount = new TaskStateCount(ExecutionStatus.RUNNING_EXECUTION, 10);
assertThat(result.get(Constants.DATA_LIST)).extracting("taskCountDtos").first().asList().containsOnlyOnce(taskStateCount);
// when general user doesn't have any task then return all count are 0
user.setUserType(UserType.GENERAL_USER);
Mockito.when(processService.getProjectIdListHavePerm(anyInt()))
.thenReturn(new ArrayList<>());
Mockito.when(taskInstanceMapper.countTaskInstanceStateByUser(any(), any(), any()))
.thenReturn(Collections.emptyList());
result = dataAnalysisService.countTaskStateByProject(user, 0, null, null);
assertThat(result.get(Constants.DATA_LIST)).extracting("totalCount").first().isEqualTo(0);
assertThat(result.get(Constants.DATA_LIST)).extracting("taskCountDtos").first().asList()
.hasSameSizeAs(ExecutionStatus.values());
assertThat(result.get(Constants.DATA_LIST)).extracting("taskCountDtos").first().asList()
.extracting("count").allMatch(count -> count.equals(0));
// when general user doesn't have any task then return all count are 0
user.setUserType(UserType.GENERAL_USER);
Mockito.when(processService.getProjectIdListHavePerm(anyInt()))
.thenReturn(new ArrayList<>());
Mockito.when(taskInstanceMapper.countTaskInstanceStateByUser(any(), any(), any()))
.thenReturn(Collections.emptyList());
result = dataAnalysisService.countTaskStateByProject(user, 0, null, null);
assertThat(result.get(Constants.DATA_LIST)).extracting("totalCount").first().isEqualTo(0);
assertThat(result.get(Constants.DATA_LIST)).extracting("taskCountDtos").first().asList()
.hasSameSizeAs(ExecutionStatus.values());
assertThat(result.get(Constants.DATA_LIST)).extracting("taskCountDtos").first().asList()
.extracting("count").allMatch(count -> count.equals(0));
// when instanceStateCounter return null, then return nothing
user.setUserType(UserType.GENERAL_USER);
Mockito.when(processService.getProjectIdListHavePerm(anyInt()))
.thenReturn(new ArrayList<>());
Mockito.when(taskInstanceMapper.countTaskInstanceStateByUser(any(), any(), any()))
.thenReturn(null);
result = dataAnalysisService.countTaskStateByProject(user, 0, null, null);
assertThat(result).isEmpty();
}
@Test
@ -169,6 +245,67 @@ public class DataAnalysisServiceTest {
result = dataAnalysisService.countCommandState(user, 1, startDate, endDate);
Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS));
// when project check fail then return nothing
Map<String, Object> result1 = dataAnalysisService.countCommandState(user, 2, null, null);
Assert.assertTrue(result1.isEmpty());
// when all date in illegal format then return error message
String startDate2 = "illegalDateString";
String endDate2 = "illegalDateString";
Map<String, Object> result2 = dataAnalysisService.countCommandState(user, 0, startDate2, endDate2);
Assert.assertEquals(Status.REQUEST_PARAMS_NOT_VALID_ERROR, result2.get(Constants.STATUS));
// when one of date in illegal format then return error message
String startDate3 = "2020-08-22 09:23:10";
String endDate3 = "illegalDateString";
Map<String, Object> result3 = dataAnalysisService.countCommandState(user, 0, startDate3, endDate3);
Assert.assertEquals(Status.REQUEST_PARAMS_NOT_VALID_ERROR, result3.get(Constants.STATUS));
// when one of date in illegal format then return error message
String startDate4 = "illegalDateString";
String endDate4 = "2020-08-22 09:23:10";
Map<String, Object> result4 = dataAnalysisService.countCommandState(user, 0, startDate4, endDate4);
Assert.assertEquals(Status.REQUEST_PARAMS_NOT_VALID_ERROR, result4.get(Constants.STATUS));
// when no command found then return all count are 0
Mockito.when(commandMapper.countCommandState(anyInt(), any(), any(), any())).thenReturn(Collections.emptyList());
Mockito.when(errorCommandMapper.countCommandState(any(), any(), any())).thenReturn(Collections.emptyList());
Map<String, Object> result5 = dataAnalysisService.countCommandState(user, 0, startDate, null);
assertThat(result5).containsEntry(Constants.STATUS, Status.SUCCESS);
assertThat(result5.get(Constants.DATA_LIST)).asList().extracting("errorCount").allMatch(count -> count.equals(0));
assertThat(result5.get(Constants.DATA_LIST)).asList().extracting("normalCount").allMatch(count -> count.equals(0));
// when command found then return combination result
CommandCount normalCommandCount = new CommandCount();
normalCommandCount.setCommandType(CommandType.START_PROCESS);
normalCommandCount.setCount(10);
CommandCount errorCommandCount = new CommandCount();
errorCommandCount.setCommandType(CommandType.START_PROCESS);
errorCommandCount.setCount(5);
Mockito.when(commandMapper.countCommandState(anyInt(), any(), any(), any())).thenReturn(Collections.singletonList(normalCommandCount));
Mockito.when(errorCommandMapper.countCommandState(any(), any(), any())).thenReturn(Collections.singletonList(errorCommandCount));
Map<String, Object> result6 = dataAnalysisService.countCommandState(user, 0, null, null);
assertThat(result6).containsEntry(Constants.STATUS, Status.SUCCESS);
CommandStateCount commandStateCount = new CommandStateCount();
commandStateCount.setCommandState(CommandType.START_PROCESS);
commandStateCount.setNormalCount(10);
commandStateCount.setErrorCount(5);
assertThat(result6.get(Constants.DATA_LIST)).asList().containsOnlyOnce(commandStateCount);
}
@Test
public void testCountQueueState() {
// when project check fail then return nothing
Map<String, Object> result1 = dataAnalysisService.countQueueState(user, 2);
Assert.assertTrue(result1.isEmpty());
// when project check success when return all count are 0
Map<String, Object> result2 = dataAnalysisService.countQueueState(user, 1);
assertThat(result2.get(Constants.DATA_LIST)).extracting("taskQueue", "taskKill")
.isNotEmpty()
.allMatch(count -> count.equals(0));
}
/**