|
@@ -29,6 +29,7 @@ import org.jfree.data.xy.XYSeries;
|
|
|
import org.slf4j.Logger;
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
|
|
|
import javax.annotation.Resource;
|
|
|
import javax.swing.*;
|
|
@@ -40,6 +41,7 @@ import java.time.Instant;
|
|
|
import java.time.LocalDateTime;
|
|
|
import java.time.ZoneId;
|
|
|
import java.time.format.DateTimeFormatter;
|
|
|
+import java.time.temporal.ChronoUnit;
|
|
|
import java.util.*;
|
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
|
import java.util.concurrent.atomic.AtomicReference;
|
|
@@ -48,7 +50,7 @@ import java.util.stream.Collectors;
|
|
|
import java.util.stream.IntStream;
|
|
|
|
|
|
//@Service
|
|
|
-//@Service
|
|
|
+@Service
|
|
|
public class JavaFunctionJobHandler extends IJobHandler {
|
|
|
private static final Logger logger = LoggerFactory.getLogger(JavaFunctionJobHandler.class);
|
|
|
|
|
@@ -1010,6 +1012,49 @@ public class JavaFunctionJobHandler extends IJobHandler {
|
|
|
//stationInfoDayService.saveOrUpdateBatch(byDate);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 将PointData列表转换为5分钟间隔的平均值列表
|
|
|
+ *
|
|
|
+ * @param sjglRaw 原始数据列表
|
|
|
+ * @return 5分钟间隔的平均值列表
|
|
|
+ */
|
|
|
+ public static List<Double> convertTo5MinAverages(List<PointData> sjglRaw) {
|
|
|
+ if (sjglRaw == null || sjglRaw.isEmpty()) {
|
|
|
+ return new ArrayList<>();
|
|
|
+ }
|
|
|
+ // 1. 按5分钟间隔分组
|
|
|
+ Map<Long, List<PointData>> groupedData = sjglRaw.stream()
|
|
|
+ .collect(Collectors.groupingBy(
|
|
|
+ point -> {
|
|
|
+ // 将时间戳转换为LocalDateTime
|
|
|
+ LocalDateTime dateTime = LocalDateTime.ofInstant(
|
|
|
+ Instant.ofEpochMilli(point.getTs()),
|
|
|
+ ZoneId.systemDefault()
|
|
|
+ );
|
|
|
+ int i = dateTime.getMinute() / 15 * 15;
|
|
|
+ // 截断到5分钟
|
|
|
+ LocalDateTime truncated = dateTime.truncatedTo(ChronoUnit.HOURS)
|
|
|
+ .plusMinutes(i);
|
|
|
+ // 转换回时间戳
|
|
|
+ return truncated.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
|
|
|
+ }
|
|
|
+ ));
|
|
|
+
|
|
|
+ // 2. 计算每个5分钟间隔的平均值
|
|
|
+ List<Double> result = groupedData.entrySet().stream()
|
|
|
+ .sorted(Map.Entry.comparingByKey()) // 按时间排序
|
|
|
+ .map(entry -> {
|
|
|
+ List<PointData> pointsInInterval = entry.getValue();
|
|
|
+ double sum = pointsInInterval.stream()
|
|
|
+ .mapToDouble(PointData::getValue)
|
|
|
+ .sum();
|
|
|
+ return sum / pointsInInterval.size(); // 计算平均值
|
|
|
+ })
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
public void calcStationSwGwCyRdl(Date date) {
|
|
|
//date当天零点
|
|
|
DateTime time = DateUtil.beginOfDay(date);
|
|
@@ -4540,58 +4585,19 @@ public class JavaFunctionJobHandler extends IJobHandler {
|
|
|
turbineInfoDayService.saveOrUpdateBatch(byDate.values());
|
|
|
}
|
|
|
|
|
|
+ public void calcStationSwdl(DateTime begin, DateTime end) {
|
|
|
|
|
|
- /**
|
|
|
- * 计算状态时间和次数
|
|
|
- *
|
|
|
- * @param datas
|
|
|
- * @return
|
|
|
- */
|
|
|
- public Map<String, Map<Double, Long>> calcStateDurationFrequency(List<PointData> datas) {
|
|
|
- Map<Double, Long> durations = new HashMap<>();
|
|
|
- Map<Double, Long> frequency = new HashMap<>();
|
|
|
- Map<String, Map<Double, Long>> dlmm = new HashMap<>();
|
|
|
- dlmm.put("duration", durations);
|
|
|
- dlmm.put("frequency", frequency);
|
|
|
- if (CollUtil.isEmpty(datas)) return dlmm;
|
|
|
-
|
|
|
- double prevState = datas.get(0).getValue(); // 初始状态
|
|
|
- long prevTs = datas.get(0).getTs(); // 初始时间戳
|
|
|
-
|
|
|
- PointData current;
|
|
|
- double currentState;
|
|
|
- long currentTs;
|
|
|
- for (int i = 1; i < datas.size(); i++) {
|
|
|
- current = datas.get(i);
|
|
|
- currentState = current.getValue();
|
|
|
- currentTs = current.getTs();
|
|
|
+ List<PointInfo> swdlEt = getEntity("Z-ZXYG-CX", "meter");
|
|
|
+ Map<String, PointInfo> swdlMap = getRawDataByEntity(swdlEt, goldenUri(), begin, end, PointInfo::getStationId);
|
|
|
|
|
|
- if (currentState != prevState) {
|
|
|
- // 当状态变化时,计算前一个状态的持续时间并更新map
|
|
|
- long tsc = currentTs - prevTs;
|
|
|
- //if (prevState == 3 || prevState == 4) {
|
|
|
- // System.out.println(DateUtil.formatDateTime(new Date(prevTs)));
|
|
|
- // System.out.print(",");
|
|
|
- // System.out.println(tsc / 1000);
|
|
|
- //}
|
|
|
- //如果是故障
|
|
|
- if (prevState == 4) {
|
|
|
- //只有10分钟才算时间次数
|
|
|
- if (tsc > 10 * 60 * 1000) {
|
|
|
- frequency.put(prevState, frequency.getOrDefault(prevState, 0L) + 1);
|
|
|
- durations.put(prevState, durations.getOrDefault(prevState, 0L) + tsc);
|
|
|
- }
|
|
|
- }else {
|
|
|
- frequency.put(prevState, frequency.getOrDefault(prevState, 0L) + 1);
|
|
|
- durations.put(prevState, durations.getOrDefault(prevState, 0L) + tsc);
|
|
|
- }
|
|
|
- prevState = currentState;
|
|
|
- prevTs = currentTs;
|
|
|
- }
|
|
|
+ List<StationInfoMin> byDate = getStationinfoByMin(begin, swdlEt);
|
|
|
+ for (StationInfoMin info : byDate) {
|
|
|
+ PointInfo swdlPi = swdlMap.get(info.getStationId());
|
|
|
+ double swdl = calcHaDl(swdlPi);
|
|
|
+ if (swdl < 0 || swdl > 6000000) swdl = 0;
|
|
|
+ info.setSwdl(swdl);
|
|
|
}
|
|
|
- // 计算列表中最后一个状态的持续时间(如果列表没有以状态变化结束)
|
|
|
- durations.put(prevState, durations.getOrDefault(prevState, 0L) + (datas.get(datas.size() - 1).getTs() - prevTs));
|
|
|
- return dlmm;
|
|
|
+ stationInfoMinService.saveOrUpdateBatch(byDate);
|
|
|
}
|
|
|
|
|
|
public Long calcMatchDuration(List<PointData> datas, Function<PointData, Boolean> func) {
|
|
@@ -6562,6 +6568,59 @@ public class JavaFunctionJobHandler extends IJobHandler {
|
|
|
stationInfoMinService.saveOrUpdateBatch(byDate);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 计算状态时间和次数
|
|
|
+ *
|
|
|
+ * @param datas
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public Map<String, Map<Double, Long>> calcStateDurationFrequency(List<PointData> datas) {
|
|
|
+ Map<Double, Long> durations = new HashMap<>();
|
|
|
+ Map<Double, Long> frequency = new HashMap<>();
|
|
|
+ Map<String, Map<Double, Long>> dlmm = new HashMap<>();
|
|
|
+ dlmm.put("duration", durations);
|
|
|
+ dlmm.put("frequency", frequency);
|
|
|
+ if (CollUtil.isEmpty(datas)) return dlmm;
|
|
|
+
|
|
|
+ double prevState = datas.get(0).getValue(); // 初始状态
|
|
|
+ long prevTs = datas.get(0).getTs(); // 初始时间戳
|
|
|
+
|
|
|
+ PointData current;
|
|
|
+ double currentState;
|
|
|
+ long currentTs;
|
|
|
+ for (int i = 1; i < datas.size(); i++) {
|
|
|
+ current = datas.get(i);
|
|
|
+ currentState = current.getValue();
|
|
|
+ currentTs = current.getTs();
|
|
|
+
|
|
|
+ if (currentState != prevState) {
|
|
|
+ // 当状态变化时,计算前一个状态的持续时间并更新map
|
|
|
+ long tsc = currentTs - prevTs;
|
|
|
+ //if (prevState == 3 || prevState == 4) {
|
|
|
+ // System.out.println(DateUtil.formatDateTime(new Date(prevTs)));
|
|
|
+ // System.out.print(",");
|
|
|
+ // System.out.println(tsc / 1000);
|
|
|
+ //}
|
|
|
+ //如果是故障
|
|
|
+ if (prevState == 4) {
|
|
|
+ //只有10分钟才算时间次数
|
|
|
+ if (tsc > 10 * 60 * 1000) {
|
|
|
+ frequency.put(prevState, frequency.getOrDefault(prevState, 0L) + 1);
|
|
|
+ durations.put(prevState, durations.getOrDefault(prevState, 0L) + tsc);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ frequency.put(prevState, frequency.getOrDefault(prevState, 0L) + 1);
|
|
|
+ durations.put(prevState, durations.getOrDefault(prevState, 0L) + tsc);
|
|
|
+ }
|
|
|
+ prevState = currentState;
|
|
|
+ prevTs = currentTs;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 计算列表中最后一个状态的持续时间(如果列表没有以状态变化结束)
|
|
|
+ durations.put(prevState, durations.getOrDefault(prevState, 0L) + (datas.get(datas.size() - 1).getTs() - prevTs));
|
|
|
+ return dlmm;
|
|
|
+ }
|
|
|
+
|
|
|
public void calcStationYcglSwdl(Date time) {
|
|
|
DateTime beginOfDay = DateUtil.beginOfDay(time);
|
|
|
//时间调为整15分钟
|
|
@@ -6596,8 +6655,7 @@ public class JavaFunctionJobHandler extends IJobHandler {
|
|
|
PointInfo cxInfo = cxData.get(day.getStationId());
|
|
|
double pjgl = 0, dqycgl = 0, cdqycgl = 0, llcdqycgl = 0;
|
|
|
if (cxInfo != null) {
|
|
|
- pjgl = cxInfo.getPointDatas().stream().mapToDouble
|
|
|
- (PointData::getValue).average().orElse(0) * cxInfo.getCoef();
|
|
|
+ pjgl = cxInfo.getPointDatas().stream().mapToDouble(PointData::getValue).average().orElse(0) * cxInfo.getCoef();
|
|
|
}
|
|
|
day.setPjgl(pjgl);
|
|
|
if (!dqData.isEmpty()) {
|
|
@@ -6645,6 +6703,83 @@ public class JavaFunctionJobHandler extends IJobHandler {
|
|
|
stationInfoMinService.saveOrUpdateBatch(byDate);
|
|
|
}
|
|
|
|
|
|
+ public void calcStationYcgl_ha(DateTime time) {
|
|
|
+ DateTime beginOfDay = DateUtil.beginOfDay(time);
|
|
|
+ //实际功率
|
|
|
+ List<PointData> sjglRaw = adapter.getHistoryRaw(goldenUri(), "区域集控.惠安风场.统计计算.总有功功率", beginOfDay.getTime(), time.getTime());
|
|
|
+ List<Double> sjglData = convertTo5MinAverages(sjglRaw);
|
|
|
+ //短期
|
|
|
+ List<String> dqKeys = new ArrayList<>();
|
|
|
+ String dqKey = "区域集控.惠安风场.WpdToDip.短期1.短期";
|
|
|
+ for (int i = 1; i < 97; i++) {
|
|
|
+ dqKeys.add(dqKey + i);
|
|
|
+ }
|
|
|
+ Map<String, PointData> dqSection = adapter.getHistorySection(goldenUri(), String.join(",", dqKeys), DateUtil.offsetHour(beginOfDay, -12).getTime());
|
|
|
+ List<Double> dqData = new ArrayList<>();
|
|
|
+ for (String key : dqKeys) {
|
|
|
+ dqData.add(dqSection.get(key).getValue());
|
|
|
+ }
|
|
|
+ double dqzql = dqzql(sjglData, dqData);
|
|
|
+ //超短期
|
|
|
+ List<PointData> cdqSnap = adapter.getHistorySnap(goldenUri(), "区域集控.惠安风场.WpdToDip.超短期.超短期15", beginOfDay.getTime(), time.getTime(), 15 * 60);
|
|
|
+ List<Double> cdqData = cdqSnap.stream().map(PointData::getValue).collect(Collectors.toList());
|
|
|
+ double cdqzql = cdqzql(sjglData, cdqData);
|
|
|
+ //超短期
|
|
|
+ List<PointData> llcdqSnap = adapter.getHistorySnap(goldenUri(), "区域集控.惠安风场.WpdToDip.理论超短期.理论超短期15", beginOfDay.getTime(), time.getTime(), 15 * 60);
|
|
|
+ List<Double> llcdqData = llcdqSnap.stream().map(PointData::getValue).collect(Collectors.toList());
|
|
|
+ double llcdqzql = cdqzql(sjglData, llcdqData);
|
|
|
+
|
|
|
+ if (dqzql > 100 || dqzql < 0) dqzql = 87.6;
|
|
|
+ if (cdqzql > 100 || cdqzql < 0) cdqzql = 86.5;
|
|
|
+ if (llcdqzql > 100 || llcdqzql < 0) llcdqzql = 85.7;
|
|
|
+ time = DateUtil.beginOfMinute(time);
|
|
|
+ int i = time.minute() / 15 * 15;
|
|
|
+ time.setMinutes(i);
|
|
|
+ List<PointInfo> entityCx = getEntity("AGC001", "booster");
|
|
|
+ List<StationInfoMin> byDate = getStationinfoByMin(time, entityCx);
|
|
|
+ StationInfoMin min = byDate.get(0);
|
|
|
+ min.setDqycglZql(dqzql);
|
|
|
+ min.setCdqycglZql(cdqzql);
|
|
|
+ min.setLlcdqycglZql(llcdqzql);
|
|
|
+ stationInfoMinService.saveOrUpdate(min);
|
|
|
+ }
|
|
|
+
|
|
|
+ public double dqzql(List<Double> sjarry, List<Double> ycarry) {
|
|
|
+ double zql = 0;
|
|
|
+ double sjsum = 0;
|
|
|
+ double ycsum = 0;
|
|
|
+ //double sum = 0;
|
|
|
+ if (CollUtil.isEmpty(ycarry)) return zql;
|
|
|
+ int min = Math.min(sjarry.size(), ycarry.size());
|
|
|
+ for (int i = 0; i < min; i++) {
|
|
|
+ sjsum += sjarry.get(i);
|
|
|
+ ycsum += ycarry.get(i);
|
|
|
+ //sum += Math.abs(((sjarry[i] - ycarry[i]) / ycarry[i])) * 100;
|
|
|
+ }
|
|
|
+ zql = (1 - (Math.abs((sjsum - ycsum) / ycsum))) * 100;
|
|
|
+ return zql;
|
|
|
+ }
|
|
|
+
|
|
|
+ public double cdqzql(List<Double> sjarry, List<Double> ycarry) {
|
|
|
+ double zql = 0;
|
|
|
+ if (CollUtil.isEmpty(ycarry)) return zql;
|
|
|
+ double fm = 0;
|
|
|
+
|
|
|
+ int min = Math.min(sjarry.size(), ycarry.size());
|
|
|
+ for (int j = 0; j < min; j++) {
|
|
|
+ fm += Math.abs(sjarry.get(j) - ycarry.get(j));
|
|
|
+ }
|
|
|
+ for (int i = 0; i < min; i++) {
|
|
|
+ double pr = sjarry.get(i);
|
|
|
+ double pn = ycarry.get(i);
|
|
|
+
|
|
|
+ zql += Math.abs(pr / (pr + pn) - 0.5) * (Math.abs(pr - pn) / fm);
|
|
|
+ }
|
|
|
+
|
|
|
+ double cdqzql = (1 - 2 * zql) * 100;
|
|
|
+ return cdqzql;
|
|
|
+ }
|
|
|
+
|
|
|
public void calcStationSjglAgcPjfsHjwdDlMin(Date begin, Date end, String stId) {
|
|
|
//AGC
|
|
|
List<PointInfo> entityAgc = getEntity("AGC002", "booster");
|
|
@@ -8164,6 +8299,8 @@ public class JavaFunctionJobHandler extends IJobHandler {
|
|
|
lineCalcHz2(lidsBqQc, fillMapBq16, LineInfoDay::getProjectId, lid -> Double.valueOf(lid.getRfdl()), eijMap, begin);
|
|
|
|
|
|
lineCalcHz(tidsBqCz, fillMapBq01, TurbineInfoDay::getStationId, tid -> tid.getRfdl() / 1000, eijMap, begin);
|
|
|
+ List<PointData> sjfdl = adapter.getHistoryRaw(goldenUri(), "区域集控.惠安风场.二期.全场日总发电量", begin.getTime(), end.getTime());
|
|
|
+ eijMap.get("区域集控.惠安风场.全场本期实际发电量").setStopCode(sjfdl.get(sjfdl.size() - 1).getValue());
|
|
|
lineCalcHz(sidBq, fillMapBq02, StationInfoDay::getStationId, sid -> sid.getSwdl() / 1000d, eijMap, begin);
|
|
|
lineCalcHz(sidBq, fillMapBq03, StationInfoDay::getStationId, sid -> sid.getGwdl() / 1000d, eijMap, begin);
|
|
|
lineCalcHz(sidBq, fillMapBq04, StationInfoDay::getStationId, sid -> sid.getCydl() / 100d, eijMap, begin);
|
|
@@ -8181,7 +8318,7 @@ public class JavaFunctionJobHandler extends IJobHandler {
|
|
|
lineCalcHz(tidsBqCz, fillMapBq15, TurbineInfoDay::getStationId, tid -> (tid.getXdss() + tid.getSlss() + tid.getJhjxss() + tid.getGzss()) / 1000, eijMap, begin);
|
|
|
lineCalcHz(tidsBqCz, fillMapBq16, TurbineInfoDay::getStationId, tid -> tid.getXdss() / 1000, eijMap, begin);
|
|
|
lineCalcHz2(lidsBqCz, fillMapBq16, LineInfoDay::getStationId, lid -> Double.valueOf(lid.getRfdl()), eijMap, begin);
|
|
|
- proEconEquipmentInfoJsService.saveOrUpdateBatch(eijMap.values());
|
|
|
+ //proEconEquipmentInfoJsService.saveOrUpdateBatch(eijMap.values());
|
|
|
}
|
|
|
|
|
|
//计算惠安报表汇总实时
|
|
@@ -8470,6 +8607,8 @@ public class JavaFunctionJobHandler extends IJobHandler {
|
|
|
lineCalcHz2(lidsNQc, fillMapN16, LineInfoDay::getProjectId, lid -> Double.valueOf(lid.getRfdl()), eijMap, yesterday);
|
|
|
//场站月
|
|
|
lineCalcHz(tidsYCz, fillMapY01, TurbineInfoDay::getStationId, tid -> tid.getRfdl() / 1000, eijMap, yesterday);
|
|
|
+ List<PointData> sjfdly = adapter.getHistoryRaw(goldenUri(), "区域集控.惠安风场.二期.全场月总发电量", begin.getTime() - 3 * 60 * 1000, begin.getTime() + 1);
|
|
|
+ eijMap.get("区域集控.惠安风场.二期月累实际发电量").setStopCode(sjfdly.stream().mapToDouble(PointData::getValue).max().orElse(0));
|
|
|
lineCalcHz(sidY, fillMapY02, StationInfoDay::getStationId, sid -> sid.getSwdl() / 1000d, eijMap, yesterday);
|
|
|
lineCalcHz(sidY, fillMapY03, StationInfoDay::getStationId, sid -> sid.getGwdl() / 1000d, eijMap, yesterday);
|
|
|
lineCalcHz(sidY, fillMapY04, StationInfoDay::getStationId, sid -> sid.getCydl() / 100d, eijMap, yesterday);
|
|
@@ -8487,6 +8626,8 @@ public class JavaFunctionJobHandler extends IJobHandler {
|
|
|
lineCalcHz2(lidsYCz, fillMapY16, LineInfoDay::getStationId, lid -> Double.valueOf(lid.getRfdl()), eijMap, yesterday);
|
|
|
//场站年
|
|
|
lineCalcHz(tidsNCz, fillMapN01, TurbineInfoDay::getStationId, tid -> tid.getRfdl() / 1000, eijMap, yesterday);
|
|
|
+ List<PointData> sjfdln = adapter.getHistoryRaw(goldenUri(), "区域集控.惠安风场.二期.全场年总发电量", begin.getTime() - 3 * 60 * 1000, begin.getTime() + 1);
|
|
|
+ eijMap.get("区域集控.惠安风场.二期年累实际发电量").setStopCode(sjfdln.stream().mapToDouble(PointData::getValue).max().orElse(0));
|
|
|
lineCalcHz(sidN, fillMapN02, StationInfoDay::getStationId, sid -> sid.getSwdl() / 1000d, eijMap, yesterday);
|
|
|
lineCalcHz(sidN, fillMapN03, StationInfoDay::getStationId, sid -> sid.getGwdl() / 1000d, eijMap, yesterday);
|
|
|
lineCalcHz(sidN, fillMapN04, StationInfoDay::getStationId, sid -> sid.getCydl() / 100d, eijMap, yesterday);
|
|
@@ -9001,4 +9142,22 @@ public class JavaFunctionJobHandler extends IJobHandler {
|
|
|
});
|
|
|
turbineInfoDayService.saveOrUpdateBatch(byDate);
|
|
|
}
|
|
|
+
|
|
|
+ public void calcStationZhcydl(DateTime begin, DateTime end) {
|
|
|
+ //指标保存表
|
|
|
+ QueryWrapper<ProEconEquipmentInfoJs> eijWrapper = new QueryWrapper<>();
|
|
|
+ String codes = "区域集控.惠安风场.一期本期实际发电量,区域集控.惠安风场.二期本期实际发电量,区域集控.惠安风场.全场本期上网电量,区域集控.惠安风场.全场本期购网电量";
|
|
|
+ eijWrapper.eq("record_date", begin).in("meter_name", codes.split(","));
|
|
|
+ List<ProEconEquipmentInfoJs> eijs = proEconEquipmentInfoJsService.list(eijWrapper);
|
|
|
+ Map<String, ProEconEquipmentInfoJs> eijMap = eijs.stream().collect(Collectors.toMap(ProEconEquipmentInfoJs::getMeterName, Function.identity(), (k1, k2) -> k1));
|
|
|
+ //风机日月发电量
|
|
|
+ List<StationInfoDay> byDate = getStationinfoByDate(begin);
|
|
|
+ for (StationInfoDay day : byDate) {
|
|
|
+ day.setZhcydl((int) ((eijMap.get("区域集控.惠安风场.一期本期实际发电量").getStopCode()
|
|
|
+ + eijMap.get("区域集控.惠安风场.二期本期实际发电量").getStopCode()
|
|
|
+ + eijMap.get("区域集控.惠安风场.全场本期购网电量").getStopCode()
|
|
|
+ - eijMap.get("区域集控.惠安风场.全场本期上网电量").getStopCode()) * 1000));
|
|
|
+ }
|
|
|
+ stationInfoDayService.saveOrUpdateBatch(byDate);
|
|
|
+ }
|
|
|
}
|