|
|
@ -2,11 +2,14 @@ package com.docus.demo.service;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import cn.hutool.core.collection.CollUtil;
|
|
|
|
import cn.hutool.core.collection.CollUtil;
|
|
|
|
|
|
|
|
import cn.hutool.core.date.DateUtil;
|
|
|
|
import cn.hutool.core.util.ObjectUtil;
|
|
|
|
import cn.hutool.core.util.ObjectUtil;
|
|
|
|
import cn.hutool.core.util.StrUtil;
|
|
|
|
import cn.hutool.core.util.StrUtil;
|
|
|
|
|
|
|
|
import com.docus.demo.dto.BasicChooseDto;
|
|
|
|
import com.docus.demo.dto.BasicCorrectDto;
|
|
|
|
import com.docus.demo.dto.BasicCorrectDto;
|
|
|
|
import com.docus.demo.dto.SyncBasicDataDto;
|
|
|
|
import com.docus.demo.dto.SyncBasicDataDto;
|
|
|
|
import com.docus.demo.entity.CommonResult;
|
|
|
|
import com.docus.demo.entity.CommonResult;
|
|
|
|
|
|
|
|
import com.docus.demo.entity.ScanAssort;
|
|
|
|
import com.docus.demo.entity.Tbasic;
|
|
|
|
import com.docus.demo.entity.Tbasic;
|
|
|
|
import com.docus.demo.entity.TbasicSub;
|
|
|
|
import com.docus.demo.entity.TbasicSub;
|
|
|
|
import com.docus.demo.entity.sqlserver.CardInfo;
|
|
|
|
import com.docus.demo.entity.sqlserver.CardInfo;
|
|
|
@ -158,10 +161,278 @@ public class SyncBasicDataImpl implements ISyncBasicDataService {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public void choose() {
|
|
|
|
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
List<String> inpatientNos = basicMapper.getInpatientNos();
|
|
|
|
|
|
|
|
log.info("本次筛选病案号数量为:{}", inpatientNos.size());
|
|
|
|
|
|
|
|
for (String inpatientNo : inpatientNos) {
|
|
|
|
|
|
|
|
choose(inpatientNo);
|
|
|
|
|
|
|
|
count++;
|
|
|
|
|
|
|
|
log.info("已经筛选病案号:{} 个", count);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
log.info("本次筛选完成!");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 根据 病案号、姓名、出院日期、住院次数 判断是同一个人,进行数据筛选。
|
|
|
|
|
|
|
|
* 有盘号/箱号 优先级 +10
|
|
|
|
|
|
|
|
* 如果有现场扫描文件数据 优先级 +4。
|
|
|
|
|
|
|
|
* 如果有联众文件数据 优先级 +3。
|
|
|
|
|
|
|
|
* 文件数量更多的,判断现场和联众 现场多优先级 +2 ,联众多优先级 +1。
|
|
|
|
|
|
|
|
* 根据最后优先级选择最高的,如果有相同选择,随机挑选一条。
|
|
|
|
|
|
|
|
* 文件数据合并到选择的患者(选择的患者没有的文件来源随机挑选一个患者)。
|
|
|
|
|
|
|
|
* 未被选择的删除基础信息。
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
private void choose(String inpatientNo) {
|
|
|
|
|
|
|
|
List<Tbasic> basicList = basicMapper.getTbasicByInpatientNo(inpatientNo);
|
|
|
|
|
|
|
|
if (basicList.size() == 1) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Map<String, List<Tbasic>> group = new HashMap<>();
|
|
|
|
|
|
|
|
for (Tbasic tbasic : basicList) {
|
|
|
|
|
|
|
|
String groupKey = tbasic.getInpatientNo() + "_" + tbasic.getName() + "_" + DateUtil.formatDate(tbasic.getDisDate()) + "_" + tbasic.getAdmissTimes();
|
|
|
|
|
|
|
|
List<Tbasic> groupOrDefault = group.getOrDefault(groupKey, new ArrayList<>());
|
|
|
|
|
|
|
|
groupOrDefault.add(tbasic);
|
|
|
|
|
|
|
|
group.put(groupKey, groupOrDefault);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Set<Map.Entry<String, List<Tbasic>>> entries = group.entrySet();
|
|
|
|
|
|
|
|
for (Map.Entry<String, List<Tbasic>> entry : entries) {
|
|
|
|
|
|
|
|
List<Tbasic> value = entry.getValue();
|
|
|
|
|
|
|
|
if (value.size() <= 1) {
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
groupChoose(value);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 根据重复数据已经分组进行处理
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
private void groupChoose(List<Tbasic> basicList) {
|
|
|
|
|
|
|
|
if (basicList.size() <= 1) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
List<BasicChooseDto> chooseDtoList = new ArrayList<>();
|
|
|
|
|
|
|
|
for (Tbasic basic : basicList) {
|
|
|
|
|
|
|
|
BasicChooseDto chooseDto = new BasicChooseDto();
|
|
|
|
|
|
|
|
chooseDto.setPatientId(basic.getPatientId());
|
|
|
|
|
|
|
|
chooseDto.setName(basic.getName());
|
|
|
|
|
|
|
|
chooseDto.setInpatientNo(basic.getInpatientNo());
|
|
|
|
|
|
|
|
chooseDto.setAdmissTimes(basic.getAdmissTimes());
|
|
|
|
|
|
|
|
chooseDto.setDisDate(DateUtil.formatDate(basic.getDisDate()));
|
|
|
|
|
|
|
|
if (StrUtil.isBlank(basic.getPh())) {
|
|
|
|
|
|
|
|
chooseDto.setPriority(0);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
chooseDto.setPriority(10);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
chooseDtoList.add(chooseDto);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (judgeAndProcess(chooseDtoList)) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Map<String, Map<String, List<ScanAssort>>> groupByPatientGroupBySource = new HashMap<>(10);
|
|
|
|
|
|
|
|
for (BasicChooseDto basicChooseDto : chooseDtoList) {
|
|
|
|
|
|
|
|
List<ScanAssort> assorts = scanAssortMapper.getListByPid(basicChooseDto.getPatientId());
|
|
|
|
|
|
|
|
assorts = assorts.stream().filter(f -> {
|
|
|
|
|
|
|
|
if (f.getSource() == null) {
|
|
|
|
|
|
|
|
f.setSource("unknow");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Integer del = 1;
|
|
|
|
|
|
|
|
return ObjectUtil.notEqual(del, f.getIsDel());
|
|
|
|
|
|
|
|
}).collect(Collectors.toList());
|
|
|
|
|
|
|
|
if (CollUtil.isEmpty(assorts)) {
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Map<String, List<ScanAssort>> groupBySource = assorts.stream().collect(Collectors.groupingBy(ScanAssort::getSource));
|
|
|
|
|
|
|
|
if (groupBySource.containsKey("-1")) {
|
|
|
|
|
|
|
|
basicChooseDto.setPriority(basicChooseDto.getPriority() + 4);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (groupBySource.containsKey("lianzhong")) {
|
|
|
|
|
|
|
|
basicChooseDto.setPriority(basicChooseDto.getPriority() + 3);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
groupByPatientGroupBySource.put(basicChooseDto.getPatientId(), groupBySource);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (judgeAndProcess(chooseDtoList)) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int siteMaxSize = 0;
|
|
|
|
|
|
|
|
int lianzhongMaxSize = 0;
|
|
|
|
|
|
|
|
HashMap<Integer, List<BasicChooseDto>> siteFileCountMap = new HashMap<>();
|
|
|
|
|
|
|
|
HashMap<Integer, List<BasicChooseDto>> lianzhongFileCountMap = new HashMap<>();
|
|
|
|
|
|
|
|
for (BasicChooseDto chooseDto : chooseDtoList) {
|
|
|
|
|
|
|
|
Map<String, List<ScanAssort>> groupBySource = groupByPatientGroupBySource.getOrDefault(chooseDto.getPatientId(), new HashMap<>());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
List<ScanAssort> siteScan = groupBySource.getOrDefault("-1", new ArrayList<>());
|
|
|
|
|
|
|
|
int siteSize = siteScan.size();
|
|
|
|
|
|
|
|
List<ScanAssort> lianzhong = groupBySource.getOrDefault("lianzhong", new ArrayList<>());
|
|
|
|
|
|
|
|
int lianzhongSize = lianzhong.size();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
List<BasicChooseDto> siteGroup = siteFileCountMap.getOrDefault(siteSize, new ArrayList<>());
|
|
|
|
|
|
|
|
siteGroup.add(chooseDto);
|
|
|
|
|
|
|
|
List<BasicChooseDto> lianzhongGroup = lianzhongFileCountMap.getOrDefault(lianzhongSize, new ArrayList<>());
|
|
|
|
|
|
|
|
lianzhongGroup.add(chooseDto);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
siteFileCountMap.put(siteSize, siteGroup);
|
|
|
|
|
|
|
|
lianzhongFileCountMap.put(lianzhongSize, lianzhongGroup);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
siteMaxSize = Math.max(siteMaxSize, siteSize);
|
|
|
|
|
|
|
|
lianzhongMaxSize = Math.max(lianzhongMaxSize, lianzhongSize);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
List<BasicChooseDto> siteCountChoose = siteFileCountMap.get(siteMaxSize);
|
|
|
|
|
|
|
|
List<BasicChooseDto> lianzhongCountChoose = lianzhongFileCountMap.get(lianzhongMaxSize);
|
|
|
|
|
|
|
|
for (BasicChooseDto dto : siteCountChoose) {
|
|
|
|
|
|
|
|
dto.setPriority(dto.getPriority() + 2);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
for (BasicChooseDto dto : lianzhongCountChoose) {
|
|
|
|
|
|
|
|
dto.setPriority(dto.getPriority() + 1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// 最后无需再判定,直接取最大优先权中的一条
|
|
|
|
|
|
|
|
processSelection(chooseDtoList, electedOneData(chooseDtoList));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 判定选择并且处理
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @return 如果已经选择且处理 返回true
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
private boolean judgeAndProcess(List<BasicChooseDto> chooseDtoList) {
|
|
|
|
|
|
|
|
if (elected(chooseDtoList) && electedOne(chooseDtoList)) {
|
|
|
|
|
|
|
|
processSelection(chooseDtoList, electedOneData(chooseDtoList));
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 处理选择后的逻辑,
|
|
|
|
|
|
|
|
* 文件数据合并到选择的患者(选择的患者没有的文件来源随机挑选一个患者)。
|
|
|
|
|
|
|
|
* 未被选择的删除基础信息。
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @param chooseDtoList 选择的集合
|
|
|
|
|
|
|
|
* @param finalElected 最终的选择数据
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
private void processSelection(List<BasicChooseDto> chooseDtoList, BasicChooseDto finalElected) {
|
|
|
|
|
|
|
|
String selectPatientId = finalElected.getPatientId();
|
|
|
|
|
|
|
|
List<String> allPatientIds = chooseDtoList.stream().map(BasicChooseDto::getPatientId).collect(Collectors.toList());
|
|
|
|
|
|
|
|
List<ScanAssort> allScanAssorts = scanAssortMapper.getListByPids(allPatientIds);
|
|
|
|
|
|
|
|
allScanAssorts = allScanAssorts.stream().filter(f -> {
|
|
|
|
|
|
|
|
if (f.getSource() == null) {
|
|
|
|
|
|
|
|
f.setSource("unknow");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Integer del = 1;
|
|
|
|
|
|
|
|
return ObjectUtil.notEqual(del, f.getIsDel());
|
|
|
|
|
|
|
|
}).collect(Collectors.toList());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (CollUtil.isEmpty(allScanAssorts)) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Set<String> allSources = allScanAssorts.stream().map(ScanAssort::getSource).collect(Collectors.toSet());
|
|
|
|
|
|
|
|
Set<String> selectPatientSources = allScanAssorts.stream()
|
|
|
|
|
|
|
|
.filter(e -> ObjectUtil.equals(selectPatientId, e.getPatientId()))
|
|
|
|
|
|
|
|
.map(ScanAssort::getSource)
|
|
|
|
|
|
|
|
.collect(Collectors.toSet());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (String source : allSources) {
|
|
|
|
|
|
|
|
if (selectPatientSources.contains(source)) {
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
transferScanAssortBySource(allScanAssorts, selectPatientId, source);
|
|
|
|
|
|
|
|
selectPatientSources.add(source);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
List<String> notSelectedPids = allPatientIds.stream().filter(e -> !e.equals(selectPatientId)).collect(Collectors.toList());
|
|
|
|
|
|
|
|
basicMapper.delTbasic(notSelectedPids);
|
|
|
|
|
|
|
|
for (String notSelectedPid : notSelectedPids) {
|
|
|
|
|
|
|
|
basicMapper.delTbasicSub(notSelectedPid);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 文件数据合并到选择的患者(选择的患者没有的文件来源随机挑选一个患者)。
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @param allScanAssorts 所有的文件数据
|
|
|
|
|
|
|
|
* @param selectPatientId 选择的患者主键
|
|
|
|
|
|
|
|
* @param source 来源
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
private void transferScanAssortBySource(List<ScanAssort> allScanAssorts, String selectPatientId, String source) {
|
|
|
|
|
|
|
|
// 选择该来源的其他患者中这个来源数量最多的
|
|
|
|
|
|
|
|
Map<String, List<ScanAssort>> groupByPatient = allScanAssorts.stream()
|
|
|
|
|
|
|
|
.filter(e -> !ObjectUtil.equals(selectPatientId, e.getPatientId()) && ObjectUtil.equals(source, e.getSource()))
|
|
|
|
|
|
|
|
.collect(Collectors.groupingBy(ScanAssort::getPatientId));
|
|
|
|
|
|
|
|
int maxSize = 0;
|
|
|
|
|
|
|
|
String maxSizePatient = null;
|
|
|
|
|
|
|
|
Set<Map.Entry<String, List<ScanAssort>>> entries = groupByPatient.entrySet();
|
|
|
|
|
|
|
|
for (Map.Entry<String, List<ScanAssort>> entry : entries) {
|
|
|
|
|
|
|
|
List<ScanAssort> assorts = entry.getValue();
|
|
|
|
|
|
|
|
int size = assorts.size();
|
|
|
|
|
|
|
|
if (size > maxSize) {
|
|
|
|
|
|
|
|
maxSize = size;
|
|
|
|
|
|
|
|
maxSizePatient = assorts.get(0).getPatientId();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
List<ScanAssort> updateScanAssort = groupByPatient.get(maxSizePatient);
|
|
|
|
|
|
|
|
List<Long> updateScanAssortIds = updateScanAssort.stream()
|
|
|
|
|
|
|
|
.map(ScanAssort::getId)
|
|
|
|
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
|
|
|
|
scanAssortMapper.updatePatientIdById(updateScanAssortIds, selectPatientId);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 是否已经有选举,判定集合中是否已经有优先级大于0的数据
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
private boolean elected(List<BasicChooseDto> chooseDtoList) {
|
|
|
|
|
|
|
|
for (BasicChooseDto dto : chooseDtoList) {
|
|
|
|
|
|
|
|
if (dto.getPriority() > 0) {
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 只存在一条选举,判定集合中优先级最大的只有一条
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
private boolean electedOne(List<BasicChooseDto> chooseDtoList) {
|
|
|
|
|
|
|
|
List<BasicChooseDto> list = electedMaxPriorityData(chooseDtoList);
|
|
|
|
|
|
|
|
return list.size() == 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 从最大选举权的数据选择一条
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
private BasicChooseDto electedOneData(List<BasicChooseDto> chooseDtoList) {
|
|
|
|
|
|
|
|
List<BasicChooseDto> list = electedMaxPriorityData(chooseDtoList);
|
|
|
|
|
|
|
|
return list.get(0);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 取得最大选举权的集合
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
private List<BasicChooseDto> electedMaxPriorityData(List<BasicChooseDto> chooseDtoList) {
|
|
|
|
|
|
|
|
Map<Integer, List<BasicChooseDto>> groupByPriority = chooseDtoList.stream()
|
|
|
|
|
|
|
|
.collect(Collectors.groupingBy(BasicChooseDto::getPriority));
|
|
|
|
|
|
|
|
int maxPriority = 0;
|
|
|
|
|
|
|
|
for (BasicChooseDto chooseDto : chooseDtoList) {
|
|
|
|
|
|
|
|
int priority = chooseDto.getPriority();
|
|
|
|
|
|
|
|
maxPriority = Math.max(priority, maxPriority);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return groupByPriority.get(maxPriority);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static void main(String[] args) {
|
|
|
|
public static void main(String[] args) {
|
|
|
|
LocalDate startDate = LocalDate.parse("2024-05-06");
|
|
|
|
LocalDate startDate = LocalDate.parse("2024-05-06");
|
|
|
|
System.out.println(startDate);
|
|
|
|
System.out.println(startDate);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private List<TbasicSub> getTbasicSubList(List<Tbasic> tbasicList) {
|
|
|
|
private List<TbasicSub> getTbasicSubList(List<Tbasic> tbasicList) {
|
|
|
|
return tbasicList.stream().map(m -> {
|
|
|
|
return tbasicList.stream().map(m -> {
|
|
|
|
TbasicSub tbasicSub = new TbasicSub();
|
|
|
|
TbasicSub tbasicSub = new TbasicSub();
|
|
|
@ -307,7 +578,6 @@ public class SyncBasicDataImpl implements ISyncBasicDataService {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private List<Tbasic> getInsertTbasic(List<Tbasic> oldBasicList, List<CardInfo> cardInfoList) {
|
|
|
|
private List<Tbasic> getInsertTbasic(List<Tbasic> oldBasicList, List<CardInfo> cardInfoList) {
|
|
|
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
|
|
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
|
|
|
List<CardInfo> cardInfos = cardInfoList.stream().filter(f -> {
|
|
|
|
List<CardInfo> cardInfos = cardInfoList.stream().filter(f -> {
|
|
|
|