From c73c59dc4f766f1b2e8130a439457e3915f20300 Mon Sep 17 00:00:00 2001 From: pangshenghao Date: Tue, 18 Jul 2023 13:40:04 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8F=E4=B8=B0=E4=BA=8C=E6=9C=9F=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- acs/nladmin-system/pom.xml | 6 + .../device/device_driver/DriverTypeEnum.java | 16 +- .../ItemProtocol.java | 2 +- .../standard_inspect_site/ItemProtocol.java | 2 +- .../HfKilnManipulatorDefination.java | 77 ++ .../HfKilnManipulatorDeviceDriver.java | 449 +++++++++++ .../hf_kiln_manipulator/ItemProtocol.java | 123 +++ .../hf_kiln_truss/HfKilnTrussDefination.java | 74 ++ .../HfKilnTrussDeviceDriver.java | 293 +++++++ .../hongfeng/hf_kiln_truss/ItemProtocol.java | 114 +++ .../hongfeng/hf_manipulator/ItemProtocol.java | 2 +- .../hf_rgv_two/HfRGVTwoDefination.java | 62 ++ .../hf_rgv_two/HfRGVTwoDeviceDriver.java | 717 ++++++++++++++++++ .../hongfeng/hf_rgv_two/ItemProtocol.java | 136 ++++ .../hongfeng/hf_station/ItemProtocol.java | 2 +- .../HfStationTwoDefination.java | 82 ++ .../HfStationTwoDeviceDriver.java | 704 +++++++++++++++++ .../hongfeng/hf_station_two/ItemProtocol.java | 212 ++++++ .../hongfeng/hf_two_rgv/ItemProtocol.java | 2 +- .../acs/ext/wms/service/AcsToWmsService.java | 22 + .../wms/service/impl/AcsToWmsServiceImpl.java | 75 ++ .../wms/service/impl/WmsToAcsServiceImpl.java | 15 +- .../org/nl/acs/opc/OpcServerServiceImpl.java | 193 +++++ .../src/main/java/org/nl/acs/opc/OpcUtl.java | 2 +- .../service/dto/ProduceshiftorderDto.java | 18 + .../impl/ProduceshiftorderServiceImpl.java | 138 ++++ .../org/nl/acs/order/service/wql/order.xls | Bin 163840 -> 143360 bytes .../main/resources/config/application-dev.yml | 6 +- .../src/main/resources/config/application.yml | 4 +- .../src/main/resources/logback-spring.xml | 32 +- .../src/views/acs/device/config.vue | 12 +- .../driver/hongfeng/hf_kiln_manipulator.vue | 522 +++++++++++++ .../device/driver/hongfeng/hf_kiln_truss.vue | 484 ++++++++++++ .../acs/device/driver/hongfeng/hf_rgv_two.vue | 641 ++++++++++++++++ .../acs/device/driver/hongfeng/hf_station.vue | 17 + .../device/driver/hongfeng/hf_station_two.vue | 484 ++++++++++++ acs/nladmin-ui/src/views/acs/order/index.vue | 6 + acs/nladmin-ui/src/views/login.vue | 10 +- acs/nladmin-ui/vue.config.js | 2 +- .../rest/VehicleDetailController.java | 67 ++ .../service/VehicleDetailService.java | 71 ++ .../basedata/service/dto/MaterialbaseDto.java | 18 + .../service/dto/VehicleDetailDto.java | 49 ++ .../service/impl/MaterialbaseServiceImpl.java | 6 +- .../impl/VehicleDetailServiceImpl.java | 129 ++++ .../nl/wms/basedata/wql/QMD_ME_MATERIAL.wql | 6 + .../wms/basedata/wql/QMD_PB_VEHICLE_GROUP.wql | 58 ++ .../wms/ext/acs/rest/AcsToWmsController.java | 18 + .../wms/ext/acs/service/AcsToWmsService.java | 14 + .../acs/service/impl/AcsToWmsServiceImpl.java | 128 ++++ .../pda/point/rest/pdaPointController.java | 40 + .../pda/point/service/PdaPointService.java | 14 + .../service/impl/PdaPointServiceImpl.java | 70 ++ .../nl/wms/pda/point/wql/PDA_OutStruct_01.wql | 81 ++ .../service/impl/WorkorderServiceImpl.java | 9 +- .../org/nl/wms/sch/manage/AutoCreateTask.java | 1 + .../sch/tasks/phaseTwo/PalletizingTask.java | 365 +++++++++ .../src/main/java/org/nl/wms/util/MapOf.java | 20 + .../src/main/java/org/nl/wms/wms.xls | Bin 272896 -> 239616 bytes .../main/resources/config/application-dev.yml | 4 +- .../src/main/resources/config/application.yml | 2 + .../src/main/resources/logback-spring.xml | 2 +- .../src/api/wms/basedata/vehicleDetail.js | 27 + .../src/views/wms/basedata/material/index.vue | 42 + 64 files changed, 6956 insertions(+), 43 deletions(-) create mode 100644 acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_kiln_manipulator/HfKilnManipulatorDefination.java create mode 100644 acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_kiln_manipulator/HfKilnManipulatorDeviceDriver.java create mode 100644 acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_kiln_manipulator/ItemProtocol.java create mode 100644 acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_kiln_truss/HfKilnTrussDefination.java create mode 100644 acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_kiln_truss/HfKilnTrussDeviceDriver.java create mode 100644 acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_kiln_truss/ItemProtocol.java create mode 100644 acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_rgv_two/HfRGVTwoDefination.java create mode 100644 acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_rgv_two/HfRGVTwoDeviceDriver.java create mode 100644 acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_rgv_two/ItemProtocol.java create mode 100644 acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_station_two/HfStationTwoDefination.java create mode 100644 acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_station_two/HfStationTwoDeviceDriver.java create mode 100644 acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_station_two/ItemProtocol.java create mode 100644 acs/nladmin-system/src/main/java/org/nl/acs/opc/OpcServerServiceImpl.java create mode 100644 acs/nladmin-ui/src/views/acs/device/driver/hongfeng/hf_kiln_manipulator.vue create mode 100644 acs/nladmin-ui/src/views/acs/device/driver/hongfeng/hf_kiln_truss.vue create mode 100644 acs/nladmin-ui/src/views/acs/device/driver/hongfeng/hf_rgv_two.vue create mode 100644 acs/nladmin-ui/src/views/acs/device/driver/hongfeng/hf_station_two.vue create mode 100644 lms/nladmin-system/src/main/java/org/nl/wms/basedata/rest/VehicleDetailController.java create mode 100644 lms/nladmin-system/src/main/java/org/nl/wms/basedata/service/VehicleDetailService.java create mode 100644 lms/nladmin-system/src/main/java/org/nl/wms/basedata/service/dto/VehicleDetailDto.java create mode 100644 lms/nladmin-system/src/main/java/org/nl/wms/basedata/service/impl/VehicleDetailServiceImpl.java create mode 100644 lms/nladmin-system/src/main/java/org/nl/wms/basedata/wql/QMD_PB_VEHICLE_GROUP.wql create mode 100644 lms/nladmin-system/src/main/java/org/nl/wms/pda/point/rest/pdaPointController.java create mode 100644 lms/nladmin-system/src/main/java/org/nl/wms/pda/point/service/PdaPointService.java create mode 100644 lms/nladmin-system/src/main/java/org/nl/wms/pda/point/service/impl/PdaPointServiceImpl.java create mode 100644 lms/nladmin-system/src/main/java/org/nl/wms/pda/point/wql/PDA_OutStruct_01.wql create mode 100644 lms/nladmin-system/src/main/java/org/nl/wms/sch/tasks/phaseTwo/PalletizingTask.java create mode 100644 lms/nladmin-system/src/main/java/org/nl/wms/util/MapOf.java create mode 100644 lms/nladmin-ui/src/api/wms/basedata/vehicleDetail.js diff --git a/acs/nladmin-system/pom.xml b/acs/nladmin-system/pom.xml index 207ff62..ff039e3 100644 --- a/acs/nladmin-system/pom.xml +++ b/acs/nladmin-system/pom.xml @@ -387,6 +387,12 @@ UserAgentUtils 1.21 + + + org.bouncycastle + bcprov-jdk15on + 1.50 + diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/device/device_driver/DriverTypeEnum.java b/acs/nladmin-system/src/main/java/org/nl/acs/device/device_driver/DriverTypeEnum.java index c90d7ad..0371161 100644 --- a/acs/nladmin-system/src/main/java/org/nl/acs/device/device_driver/DriverTypeEnum.java +++ b/acs/nladmin-system/src/main/java/org/nl/acs/device/device_driver/DriverTypeEnum.java @@ -37,7 +37,21 @@ public enum DriverTypeEnum { HF_STATION(14, "hf_station", "宏丰-工位(交互模板)", "conveyor"), - HF_TWO_RGV(15, "hf_two_rgv", "宏丰-双工位RGV", "rgv"); + HF_TWO_RGV(15, "hf_two_rgv", "宏丰-双工位RGV", "rgv"), + + HF_PACKAGE_PALLET_MANIPULATOR(16, "hf_package_pallet_manipulator", "宏丰-包装码垛机械手", "station"), + + HF_SPLIT_MANIPULATOR(17, "hf_split_manipulator", "宏丰-拆垛机械手", "station"), + + HF_STATION_TWO(18, "hf_station_two", "宏丰-工位二期", "conveyor"), + + HF_KILN_TRUSS(19, "hf_kiln_truss", "宏丰-入出窑桁架", "conveyor"), + + HF_KILN_MANIPULATOR(20, "hf_kiln_manipulator", "宏丰-码垛机械手", "conveyor"), + + HF_RGV_TWO(21, "hf_rgv_two", "宏丰-RGV二期", "rgv"); + + //驱动索引 diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/basedriver/standard_conveyor_control_with_plcscanner/ItemProtocol.java b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/basedriver/standard_conveyor_control_with_plcscanner/ItemProtocol.java index 8854280..6a4d8fc 100644 --- a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/basedriver/standard_conveyor_control_with_plcscanner/ItemProtocol.java +++ b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/basedriver/standard_conveyor_control_with_plcscanner/ItemProtocol.java @@ -101,7 +101,7 @@ public class ItemProtocol { public int getOpcIntegerValue(String protocol) { Integer value = this.driver.getIntegeregerValue(protocol); if (value == null) { - log.error(this.getDriver().getDeviceCode() + ":protocol " + protocol + " 信号同步异常!"); +// log.error(this.getDriver().getDeviceCode() + ":protocol " + protocol + " 信号同步异常!"); setIsonline(false); } else { setIsonline(true); diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/basedriver/standard_inspect_site/ItemProtocol.java b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/basedriver/standard_inspect_site/ItemProtocol.java index 7b189c7..5f95502 100644 --- a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/basedriver/standard_inspect_site/ItemProtocol.java +++ b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/basedriver/standard_inspect_site/ItemProtocol.java @@ -74,7 +74,7 @@ public class ItemProtocol { public int getOpcIntegerValue(String protocol) { Integer value = this.driver.getIntegeregerValue(protocol); if (value == null) { - log.error(this.getDriver().getDeviceCode() + ":protocol " + protocol + " 信号同步异常!"); +// log.error(this.getDriver().getDeviceCode() + ":protocol " + protocol + " 信号同步异常!"); setIsonline(false); } else { setIsonline(true); diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_kiln_manipulator/HfKilnManipulatorDefination.java b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_kiln_manipulator/HfKilnManipulatorDefination.java new file mode 100644 index 0000000..2e294af --- /dev/null +++ b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_kiln_manipulator/HfKilnManipulatorDefination.java @@ -0,0 +1,77 @@ +package org.nl.acs.device_driver.hongfeng.hf_kiln_manipulator; + +import org.nl.acs.device.device_driver.standard_inspect.ItemDto; +import org.nl.acs.device_driver.DeviceDriver; +import org.nl.acs.device_driver.defination.OpcDeviceDriverDefination; +import org.nl.acs.opc.Device; +import org.nl.acs.opc.DeviceType; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +/** + * 宏丰码垛机械手 + * + */ +@Service +public class HfKilnManipulatorDefination implements OpcDeviceDriverDefination { + @Override + public String getDriverCode() { + return "hf_kiln_manipulator"; + } + + @Override + public String getDriverName() { + return "宏丰-码垛机械手"; + } + + @Override + public String getDriverDescription() { + return "宏丰-码垛机械手"; + } + + @Override + public DeviceDriver getDriverInstance(Device device) { + return (new HfKilnManipulatorDeviceDriver()).setDevice(device).setDriverDefination(this); + + } + + @Override + public Class getDeviceDriverType() { + return HfKilnManipulatorDeviceDriver.class; + } + + @Override + public List getFitDeviceTypes() { + List types = new LinkedList(); + types.add(DeviceType.station); + return types; + } + + @Override + public List getReadableItemDtos() { + return getReadableItemDtos2(); + } + + public static List getReadableItemDtos2() { + ArrayList list = new ArrayList(); + list.add(new ItemDto(ItemProtocol.item_heartbeat, "心跳", "DB200.B0")); + list.add(new ItemDto(ItemProtocol.item_mode, "工作模式", "DB200.B1")); + list.add(new ItemDto(ItemProtocol.item_move, "光电信号", "DB200.B2")); + list.add(new ItemDto(ItemProtocol.item_action, "动作信号", "DB200.B3")); + list.add(new ItemDto(ItemProtocol.item_walk_y, "行走列", "DB200.D4")); + list.add(new ItemDto(ItemProtocol.item_error, "报警信号", "DB200.B5")); + list.add(new ItemDto(ItemProtocol.item_task, "任务号", "DB200.D6")); + list.add(new ItemDto(ItemProtocol.item_locate, "当前位置", "DB200.W10")); + list.add(new ItemDto(ItemProtocol.item_barcode, "条码", "DB200.W12")); + return list; + } + + @Override + public List getWriteableItemDtos() { + return ItemProtocol.getWriteableItemDtos(); + } + +} diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_kiln_manipulator/HfKilnManipulatorDeviceDriver.java b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_kiln_manipulator/HfKilnManipulatorDeviceDriver.java new file mode 100644 index 0000000..b0164b2 --- /dev/null +++ b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_kiln_manipulator/HfKilnManipulatorDeviceDriver.java @@ -0,0 +1,449 @@ +package org.nl.acs.device_driver.hongfeng.hf_kiln_manipulator; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSONObject; +import lombok.Data; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.nl.acs.device.device_driver.standard_inspect.ReadUtil; +import org.nl.acs.device.service.DeviceService; +import org.nl.acs.device_driver.DeviceDriver; +import org.nl.acs.device_driver.RouteableDeviceDriver; +import org.nl.acs.device_driver.driver.AbstractOpcDeviceDriver; +import org.nl.acs.device_driver.driver.ExecutableDeviceDriver; +import org.nl.acs.device_driver.hongfeng.hf_station.HfStationDeviceDriver; +import org.nl.acs.device_driver.hongfeng.hf_station_two.HfStationTwoDeviceDriver; +import org.nl.acs.ext.wms.service.AcsToWmsService; +import org.nl.acs.instruction.service.InstructionService; +import org.nl.acs.instruction.service.dto.Instruction; +import org.nl.acs.log.service.DeviceExecuteLogService; +import org.nl.acs.monitor.DeviceStageMonitor; +import org.nl.acs.opc.Device; +import org.nl.acs.opc.DeviceAppService; +import org.nl.acs.opc.DeviceAppServiceImpl; +import org.nl.acs.route.service.RouteLineService; +import org.nl.acs.task.service.TaskService; +import org.nl.acs.task.service.dto.TaskDto; +import org.nl.modules.common.exception.BadRequestException; +import org.nl.modules.wql.util.SpringContextHolder; +import org.openscada.opc.lib.da.Server; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 宏丰码垛机械手 + */ +@Slf4j +@Data +@RequiredArgsConstructor +public class HfKilnManipulatorDeviceDriver extends AbstractOpcDeviceDriver implements DeviceDriver, ExecutableDeviceDriver, RouteableDeviceDriver, DeviceStageMonitor { + protected ItemProtocol itemProtocol = new ItemProtocol(this); + + InstructionService instructionService = SpringContextHolder.getBean("instructionServiceImpl"); + + DeviceService deviceservice = SpringContextHolder.getBean("deviceServiceImpl"); + + RouteLineService routelineserver = SpringContextHolder.getBean("routeLineServiceImpl"); + + TaskService taskserver = SpringContextHolder.getBean("taskServiceImpl"); + + DeviceExecuteLogService logServer = SpringContextHolder.getBean("deviceExecuteLogServiceImpl"); + + AcsToWmsService acsToWmsService = SpringContextHolder.getBean("acsToWmsServiceImpl"); + + DeviceAppService appService = SpringContextHolder.getBean(DeviceAppServiceImpl.class); + + int mode = 0; + int error = 0; + int action = 0; + int last_action = 0; + int last_mode = 0; + int last_error = 0; + Boolean isonline = true; + int hasGoods = 0; + String message = null; + Boolean iserror = false; + + Integer heartbeat_tag; + private Date instruction_require_time = new Date(); + private Date instruction_finished_time = new Date(); + + private int instruction_require_time_out; + boolean requireSucess = false; + + private int instruction_finished_time_out; + + int branchProtocol = 0; + + float a = 0f; + float b = 0f; + + + //暂定 0就绪 1请求取货 2取货完成 3请求放货 4放货完成 5取货完成离开 6放货完成离开 7请求进入区域 8请求离开区域 + int flag; + + String device_code; + int move = 0; + int last_move = 0; + int walk_y = 0; + int last_walk_y = 0; + int task = 0; + int last_task = 0; + int locate = 0; + int last_locate = 0; + int barcode = 0; + int last_barcode = 0; + + @Override + public Device getDevice() { + return this.device; + } + + + @Override + public void execute() { + String message = null; + try { + device_code = this.getDeviceCode(); + mode = this.itemProtocol.getMode(); + move = this.itemProtocol.getMove(); + action = this.itemProtocol.getAction(); + error = this.itemProtocol.getError(); + walk_y = this.itemProtocol.getWalk_y(); + task = this.itemProtocol.getTask(); + locate = this.itemProtocol.getLocate(); + barcode = this.itemProtocol.getBarcode(); + + if (mode != last_mode) { + this.setRequireSucess(false); + logServer.deviceItemValue(this.device_code, "mode", String.valueOf(mode)); + logServer.deviceExecuteLog(this.device_code, "", "", "信号mode:" + last_mode + "->" + mode); + } + if (move != last_move) { + logServer.deviceItemValue(this.device_code, "move", String.valueOf(move)); + logServer.deviceExecuteLog(this.device_code, "", "", "move:" + last_move + "->" + move); + } + if (action != last_action) { + logServer.deviceItemValue(this.device_code, "action", String.valueOf(action)); + logServer.deviceExecuteLog(this.device_code, "", "", "action:" + last_action + "->" + action); + } + if (error != last_move) { + logServer.deviceItemValue(this.device_code, "error", String.valueOf(error)); + logServer.deviceExecuteLog(this.device_code, "", "", "error:" + last_error + "->" + error); + } + if (walk_y != last_walk_y) { + logServer.deviceItemValue(this.device_code, "walk_y", String.valueOf(walk_y)); + logServer.deviceExecuteLog(this.device_code, "", "", "walk_y:" + last_walk_y + "->" + walk_y); + } + if (task != last_task) { + logServer.deviceItemValue(this.device_code, "task", String.valueOf(task)); + logServer.deviceExecuteLog(this.device_code, "", "", "信号task:" + last_task + "->" + task); + } + if (locate != last_locate) { + logServer.deviceItemValue(this.device_code, "locate", String.valueOf(locate)); + logServer.deviceExecuteLog(this.device_code, "", "", "locate:" + last_locate + "->" + locate); + } + if (barcode != last_barcode) { + logServer.deviceItemValue(this.device_code, "barcode", String.valueOf(barcode)); + logServer.deviceExecuteLog(this.device_code, "", "", "信号barcode:" + last_barcode + "->" + barcode); + } + + //更改任务状态 + if (task > 0) { + //inst_message + Instruction inst1 = instructionService.findByCodeFromCache(String.valueOf(task)); + if (inst1 != null) { + if (StrUtil.equals(inst1.getInstruction_status(), "0")) { + inst1.setInstruction_status("1"); + instructionService.update(inst1); + } + } + } + + //申请取货 判断取货位是否有货 有货就下发允许取货命令 + if (mode == 3 && action == 1 && move == 0 && task > 0) { + Instruction inst2 = instructionService.findByCodeFromCache(String.valueOf(task)); + if (ObjectUtil.isNotEmpty(inst2)) { + String start_device_code = inst2.getStart_device_code(); + Device device = appService.findDeviceByCode(start_device_code); + HfStationDeviceDriver hfStationDeviceDriver; + if (device.getDeviceDriver() instanceof HfStationDeviceDriver) { + hfStationDeviceDriver = (HfStationDeviceDriver) device.getDeviceDriver(); + if (hfStationDeviceDriver.getMove() == 1) { + logServer.deviceInfo("反馈电气信号", this.getDevice_code(), "机械手取货时,开始反馈电气信号"); + this.writing("to_command", "2"); + } else { + logServer.deviceInfo("反馈电气信号", this.getDevice_code(), "机械手取货时,取货位不满足有货条件"); + } + } + } + } + + //行架机械手取货时校验条码 校验失败,取消任务 + if (mode == 4 && action == 1 && move == 0 && task > 0) { + logServer.deviceInfo("反馈电气信号", this.getDevice_code(), "机械手取货时条码校验失败,开始反馈电气信号"); + Instruction instructionDto = instructionService.findByCodeFromCache(String.valueOf(task)); + instructionService.cancel(instructionDto.getInstruction_id()); + taskserver.cancel(instructionDto.getTask_id()); + this.writing("to_onset", "0"); + this.writing("to_target", "0"); + this.writing("to_task", "0"); + this.writing("to_barcode", "0"); + this.writing("to_command", "99"); + } + + //申请放货 + if (mode == 3 && action == 3 && move == 1 && task > 0) { + Instruction instructionDto = instructionService.findByCodeFromCache(String.valueOf(task)); + String next_device_code = instructionDto.getNext_device_code(); + Device nextDevice = appService.findDeviceByCode(next_device_code); + HfStationTwoDeviceDriver hfStationDeviceDriver; + if (nextDevice.getDeviceDriver() instanceof HfStationTwoDeviceDriver) { + hfStationDeviceDriver = (HfStationTwoDeviceDriver) nextDevice.getDeviceDriver(); + int move = hfStationDeviceDriver.getMove(); + if (move == 0) { + logServer.deviceInfo("反馈电气信号", this.getDevice_code(), "机械手放货时,开始反馈电气信号"); + this.writing("to_command", "3"); + } else { + logServer.deviceInfo("反馈电气信号", this.getDevice_code(), "机械手放货时,放货位不满足无货条件"); + } + } + } + + //放货完成 + if (mode == 3 && action == 4 && move == 0 && task > 0) { + Instruction inst2 = instructionService.findByCodeFromCache(String.valueOf(task)); + if (inst2 != null) { + if (StrUtil.equals(inst2.getInstruction_status(), "1")) { + this.finish_instruction(inst2); + logServer.deviceInfo("反馈电气信号", this.getDevice_code(), "机械手任务完成,开始反馈电气信号"); + this.writing("to_onset", "0"); + this.writing("to_target", "0"); + this.writing("to_task", "0"); + this.writing("to_barcode", "0"); + this.writing("to_command", "0"); + } + } + } + + + + } catch (Exception e) { + log.error(e.getMessage()); + return; + } + + //急停 + if (this.isStop()) { + + //未在线无心跳 + } else if (!this.itemProtocol.getIsonline()) { + this.setIsonline(false); + this.setIserror(true); + message = "信号量同步异常"; + //未联机 + } else if (mode == 0) { + this.setIsonline(false); + this.setIserror(true); + message = "未联机"; + //有报警 + } else if (error != 0) { + this.setIsonline(false); + this.setIserror(true); + message = "有报警"; + //无报警 + } else { + this.setIsonline(true); + this.setIserror(false); + message = ""; + Instruction instruction = null; + List toInstructions; + //行架机械手申请任务 + if (mode == 2) { + if (move == 0 && task == 0 && !requireSucess) { + logServer.queryTask("机械手申请任务", this.getDevice_code(), "机械手开始申请任务!满足信号->mode == 2 && move == 0 && task == 0"); + applyTask(); + } else { + logServer.queryTask("机械手申请任务", this.getDevice_code(), "机械手不满足申请任务!此时:mode = " + mode + "move = " + move + "task = " + task + "requireSucess = " + requireSucess); + } + //条码比对失败,取消任务 + } + } + + last_mode = mode; + last_move = move; + last_action = action; + last_error = error; + last_walk_y = walk_y; + last_task = task; + last_locate = locate; + last_barcode = barcode; + } + + @Override + public JSONObject getDeviceStatusName() { + JSONObject jo = new JSONObject(); + return jo; + } + + @Override + public void setDeviceStatus(JSONObject data) { + + } + + public void writing(String param, String value) { + String to_param = this.getDevice().getOpc_server_code() + "." + this.getDevice().getOpc_plc_code() + "." + this.getDevice().getDevice_code() + + "." + param; + String opcservcerid = this.getDevice().getOpc_server_id(); + Server server = ReadUtil.getServer(opcservcerid); + Map itemMap = new HashMap(); + itemMap.put(to_param, value); + ReadUtil.write(itemMap, server); + logServer.writeLog("下发电气信号", this.getDevice_code(), "下发信号:" + to_param + "信号值:" + value); + } + + /** + * 申请任务 + * + * @param + */ + public synchronized boolean applyTask() { + Date date = new Date(); + if (date.getTime() - this.instruction_require_time.getTime() < (long) this.instruction_require_time_out) { + log.trace("触发时间因为小于{}毫秒,而被无视", this.instruction_require_time_out); + return false; + } else { + this.instruction_require_time = date; + //抓取工位 + List getDeviceCodeList = this.getExtraDeviceCodes("head_get_device_code"); + //放货工位 + List putDeviceCodeList = this.getExtraDeviceCodes("head_put_device_code"); + TaskDto task = null; + for (int i = 0; i < getDeviceCodeList.size(); i++) { + String startDeviceCode = getDeviceCodeList.get(i); + List taskDtos = taskserver.queryTaskByDeviceCodeAndStatus(startDeviceCode); + if (ObjectUtil.isNotEmpty(taskDtos)) { + TaskDto taskDto = taskDtos.get(0); + Instruction instruction = instructionService.findByTaskcode(taskDto.getTask_code()); + instruction.setInstruction_status("1"); + instruction.setUpdate_time(DateUtil.now()); + instructionService.update(instruction); + this.sendSignalType(instruction); + this.setRequireSucess(true); + logServer.deviceInfo("机械手申请任务", this.getDevice_code(), "机械手申请任务任务成功,任务为重新创建指令的任务,指令号:" + instruction.getInstruction_code()); + return true; + } else { + List taskDtoList = taskserver.queryTaskByDeviceCode(startDeviceCode); + if (ObjectUtil.isNotEmpty(taskDtoList)) { + task = taskDtoList.get(0); + } + if (ObjectUtil.isNotEmpty(task)) break; + } + } + if (!ObjectUtil.isEmpty(task)) { + String taskid = task.getTask_id(); + String taskcode = task.getTask_code(); + String vehiclecode = task.getVehicle_code(); + String priority = task.getPriority(); + String start_point_code = task.getStart_point_code(); + String start_device_code = task.getStart_device_code(); + String route_plan_code = task.getRoute_plan_code(); + String next_point_code = task.getNext_point_code(); + String next_device_code = task.getNext_device_code(); + + Instruction instdto = new Instruction(); + instdto.setInstruction_id(IdUtil.simpleUUID()); + instdto.setRoute_plan_code(route_plan_code); + instdto.setRemark(task.getRemark()); + instdto.setMaterial(task.getMaterial()); + instdto.setQuantity(task.getQuantity()); + instdto.setTask_id(taskid); + instdto.setTask_code(taskcode); + instdto.setVehicle_code(vehiclecode); + String now = DateUtil.now(); + instdto.setCreate_time(now); + instdto.setCreate_by("auto"); + instdto.setStart_device_code(start_device_code); + instdto.setNext_device_code(next_device_code); + instdto.setStart_point_code(start_point_code); + instdto.setNext_point_code(next_point_code); + instdto.setPriority(priority); + instdto.setInstruction_status("0"); + instdto.setExecute_device_code(start_point_code); + + try { + instructionService.create(instdto); + } catch (Exception e) { + e.printStackTrace(); + } + //创建指令后修改任务状态 + task.setTask_status("1"); + task.setUpdate_time(DateUtil.now()); + taskserver.update(task); + + this.sendSignalType(instdto); + this.setRequireSucess(true); + logServer.deviceInfo("机械手申请任务", this.getDevice_code(), "机械手申请任务成功,任务为就绪状态下的任务,指令号:" + instdto.getInstruction_code()); + } else { + this.writing("to_command", "99"); + logServer.deviceInfo("机械手申请任务", this.getDevice_code(), "机械手申请任务失败,未找到机械手取货位关联设备的起点任务!"); + } + return true; + } + } + + //将扩展表中的字符串数据转换成集合 + public List getExtraDeviceCodes(String extraName) { + String extraValue = (String) this.getDevice().getExtraValue().get(extraName); + if (StrUtil.isEmpty(extraValue)) { + return new ArrayList<>(); + } + String devicesString = extraValue.substring(1, extraValue.length() - 1); + List devicesList = new ArrayList<>(); + String[] devices = devicesString.split(","); + for (int i = 0; i < devices.length; i++) { + String s = devices[i].replace("\"", "").replace("\"", ""); + devicesList.add(s); + } + return devicesList; + } + + public synchronized void sendSignalType(Instruction dto) { + logServer.deviceInfo("机械手申请任务", this.getDevice_code(), "机械手申请任务指令创建成功,开始写入信号"); + String start_device_code = dto.getStart_device_code(); + String next_device_code = dto.getNext_device_code(); + Device startDevice = appService.findDeviceByCode(start_device_code); + Device nextDevice = appService.findDeviceByCode(next_device_code); + this.isSetAddress(startDevice); + this.isSetAddress(nextDevice); + String start_addr = startDevice.getExtraValue().get("address").toString(); + String next_addr = nextDevice.getExtraValue().get("address").toString(); + this.writing("to_onset", start_addr); + this.writing("to_target", next_addr); + this.writing("to_task", dto.getInstruction_code()); + this.writing("to_barcode", dto.getVehicle_code()); + this.writing("to_command", "1"); + logServer.deviceInfo("机械手申请任务", this.getDevice_code(), "机械手申请任务指令创建成功,信号写入成功"); + } + + //判断点位是否设置电气值 + public void isSetAddress(Device device) { + if (ObjectUtil.isEmpty(device.getExtraValue().get("address"))) { + logServer.deviceError("未设置电气调度号", this.getDevice_code(), "下发指令,设备: '" + device.getDevice_code() + "'未查询到电气调度号"); + throw new BadRequestException("设备:" + device.getDevice_code() + "未设置电气调度号!"); + } + } + + public synchronized boolean finish_instruction(Instruction inst) throws Exception { + instructionService.finish(inst); + return true; + } +} diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_kiln_manipulator/ItemProtocol.java b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_kiln_manipulator/ItemProtocol.java new file mode 100644 index 0000000..6bfcab9 --- /dev/null +++ b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_kiln_manipulator/ItemProtocol.java @@ -0,0 +1,123 @@ +package org.nl.acs.device_driver.hongfeng.hf_kiln_manipulator; + +import cn.hutool.core.util.StrUtil; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.nl.acs.device.device_driver.standard_inspect.ItemDto; + +import java.util.ArrayList; +import java.util.List; + +@Slf4j +@Data +public class ItemProtocol { + + public static String item_heartbeat = "heartbeat"; + public static String item_mode ="mode"; + public static String item_move ="move"; + public static String item_action ="action"; + public static String item_walk_y ="walk_y"; + public static String item_error ="error"; + public static String item_task ="task"; + public static String item_locate ="locate"; + public static String item_barcode ="barcode"; + public static String item_to_command ="to_command"; + public static String item_to_onset ="to_onset"; + public static String item_to_target ="to_target"; + public static String item_to_task ="to_task"; + public static String item_to_barcode ="to_barcode"; + + + private HfKilnManipulatorDeviceDriver driver; + + public ItemProtocol(HfKilnManipulatorDeviceDriver driver) { + this.driver = driver; + } + + public int getHeartbeat() { + return this.getOpcIntegerValue(item_heartbeat); + } + + public int getMode() { + return this.getOpcIntegerValue(item_mode); + } + + public int getMove() { + return this.getOpcIntegerValue(item_move); + } + + public int getAction() { + return this.getOpcIntegerValue(item_action); + } + + public int getError() { + return this.getOpcIntegerValue(item_error); + } + + public int getWalk_y() { + return this.getOpcIntegerValue(item_walk_y); + } + + public int getTask() { + return this.getOpcIntegerValue(item_task); + } + + public int getLocate() { + return this.getOpcIntegerValue(item_locate); + } + + public int getBarcode() { + return this.getOpcIntegerValue(item_barcode); + } + + Boolean isonline; + + public int getOpcIntegerValue(String protocol) { + Integer value = this.driver.getIntegeregerValue(protocol); + if (value == null) { +// log.error(this.getDriver().getDeviceCode() + ":protocol " + protocol + " 信号同步异常!"); + setIsonline(false); + } else { + setIsonline(true); + return value; + } + return 0; + + } + + public String getOpcStringValue(String protocol) { + String value = this.driver.getStringValue(protocol); + if (StrUtil.isEmpty(value)) { +// log.error("读取错误!"); + } else { + return value; + } + return "0"; + } + + public static List getReadableItemDtos() { + ArrayList list = new ArrayList(); + list.add(new ItemDto(item_heartbeat, "心跳", "DB200.B0")); + list.add(new ItemDto(item_mode, "工作模式", "DB200.B1")); + list.add(new ItemDto(item_move, "光电信号", "DB200.B2")); + list.add(new ItemDto(item_action, "动作信号", "DB200.B3")); + list.add(new ItemDto(item_walk_y, "行走列", "DB200.D4")); + list.add(new ItemDto(item_error, "报警信号", "DB200.B5")); + list.add(new ItemDto(item_task, "任务号", "DB200.D6")); + list.add(new ItemDto(item_locate, "当前位置", "DB200.W10")); + list.add(new ItemDto(item_barcode, "条码", "DB200.W12")); + return list; + } + + public static List getWriteableItemDtos() { + ArrayList list = new ArrayList(); + list.add(new ItemDto(item_to_command, "下发命令反馈", "DB201.W0", Boolean.valueOf(true))); + list.add(new ItemDto(item_to_onset, "下发起始站", "DB201.W2")); + list.add(new ItemDto(item_to_target, "下发目标站", "DB201.W4")); + list.add(new ItemDto(item_to_task, "下发任务号", "DB201.D6")); + list.add(new ItemDto(item_to_barcode, "条码", "DB201.W10")); + return list; + } + +} + diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_kiln_truss/HfKilnTrussDefination.java b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_kiln_truss/HfKilnTrussDefination.java new file mode 100644 index 0000000..b02ad56 --- /dev/null +++ b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_kiln_truss/HfKilnTrussDefination.java @@ -0,0 +1,74 @@ +package org.nl.acs.device_driver.hongfeng.hf_kiln_truss; + +import org.nl.acs.device.device_driver.standard_inspect.ItemDto; +import org.nl.acs.device_driver.DeviceDriver; +import org.nl.acs.device_driver.defination.OpcDeviceDriverDefination; +import org.nl.acs.opc.Device; +import org.nl.acs.opc.DeviceType; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +/** + * 宏丰入出窑桁架 + */ +@Service +public class HfKilnTrussDefination implements OpcDeviceDriverDefination { + @Override + public String getDriverCode() { + return "hf_kiln_truss"; + } + + @Override + public String getDriverName() { + return "宏丰-入出窑桁架"; + } + + @Override + public String getDriverDescription() { + return "宏丰-入出窑桁架"; + } + + @Override + public DeviceDriver getDriverInstance(Device device) { + return (new HfKilnTrussDeviceDriver()).setDevice(device).setDriverDefination(this); + } + + @Override + public Class getDeviceDriverType() { + return HfKilnTrussDeviceDriver.class; + } + + @Override + public List getFitDeviceTypes() { + List types = new LinkedList(); + types.add(DeviceType.station); + return types; + } + + @Override + public List getReadableItemDtos() { + return getReadableItemDtos2(); + } + + public static List getReadableItemDtos2() { + ArrayList list = new ArrayList(); + list.add(new ItemDto(ItemProtocol.item_heartbeat, "心跳", "DB200.B0")); + list.add(new ItemDto(ItemProtocol.item_mode, "工作模式", "DB200.B1")); + list.add(new ItemDto(ItemProtocol.item_move, "光电信号", "DB200.B2")); + list.add(new ItemDto(ItemProtocol.item_error, "报警信号", "DB200.B3")); + list.add(new ItemDto(ItemProtocol.item_task, "任务号", "DB200.D4")); + list.add(new ItemDto(ItemProtocol.item_barcode, "条码", "DB200.W8")); + list.add(new ItemDto(ItemProtocol.item_number,"数量","DB200.W10")); + list.add(new ItemDto(ItemProtocol.item_kiln_id,"窑号","DB200.W12")); + return list; + } + + @Override + public List getWriteableItemDtos() { + return ItemProtocol.getWriteableItemDtos(); + } + +} diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_kiln_truss/HfKilnTrussDeviceDriver.java b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_kiln_truss/HfKilnTrussDeviceDriver.java new file mode 100644 index 0000000..3577f62 --- /dev/null +++ b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_kiln_truss/HfKilnTrussDeviceDriver.java @@ -0,0 +1,293 @@ +package org.nl.acs.device_driver.hongfeng.hf_kiln_truss; + +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSONObject; +import lombok.Data; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.nl.acs.device.device_driver.standard_inspect.ReadUtil; +import org.nl.acs.device.service.DeviceService; +import org.nl.acs.device_driver.DeviceDriver; +import org.nl.acs.device_driver.RouteableDeviceDriver; +import org.nl.acs.device_driver.driver.AbstractOpcDeviceDriver; +import org.nl.acs.device_driver.driver.ExecutableDeviceDriver; +import org.nl.acs.ext.wms.service.AcsToWmsService; +import org.nl.acs.instruction.service.InstructionService; +import org.nl.acs.instruction.service.dto.Instruction; +import org.nl.acs.log.service.DeviceExecuteLogService; +import org.nl.acs.opc.Device; +import org.nl.acs.order.service.dto.ProduceshiftorderDto; +import org.nl.acs.route.service.RouteLineService; +import org.nl.acs.task.service.TaskService; +import org.nl.modules.wql.util.SpringContextHolder; +import org.openscada.opc.lib.da.Server; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.annotation.Resource; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.nl.modules.wql.util.SpringContextHolder.getBean; + +/** + * 宏丰入出窑桁架 + */ +@Slf4j +@Data +@RequiredArgsConstructor +public class HfKilnTrussDeviceDriver extends AbstractOpcDeviceDriver implements DeviceDriver, ExecutableDeviceDriver, RouteableDeviceDriver { + protected ItemProtocol itemProtocol = new ItemProtocol(this); + + InstructionService instructionService = SpringContextHolder.getBean("instructionServiceImpl"); + + DeviceService deviceservice = SpringContextHolder.getBean("deviceServiceImpl"); + + RouteLineService routelineserver = SpringContextHolder.getBean("routeLineServiceImpl"); + + TaskService taskserver = SpringContextHolder.getBean("taskServiceImpl"); + + DeviceExecuteLogService logServer = SpringContextHolder.getBean("deviceExecuteLogServiceImpl"); + + AcsToWmsService acsToWmsService=getBean("acsToWmsServiceImpl"); + + private Date instruction_require_time = new Date(); + + private int instruction_require_time_out = 3000; + + String device_code; + int mode = 0; + int error = 0; + int move = 0; + int last_mode = 0; + int last_error = 0; + int last_move = 0; + Boolean isonline = true; + int hasGoods = 0; + Boolean iserror = false; + + boolean requireSucess = false; + + private Date checkHeartbeattime = new Date(); + private Date last_checkHeartbeattime = new Date(); + + int branchProtocol = 0; + + //触摸屏手动触发任务 + private Boolean is_has_task = false; + + String message; + int task = 0; + int last_task = 0; + int barcode = 0; + int last_barcode = 0; + int number = 0; + int last_number = 0; + int kiln_id =0; + int last_kiln_id=0; + + //入窑标记 + Boolean inTrussSucess = false; + //出窑标记 + Boolean outTrussSucess = false; + + + @Override + public Device getDevice() { + return this.device; + } + + + @Override + public void execute() { + String message = null; + try { + device_code = this.getDeviceCode(); + mode = this.itemProtocol.getMode(); + move = this.itemProtocol.getMove(); + task = this.itemProtocol.getTask(); + barcode = this.itemProtocol.getBarcode(); + number = this.itemProtocol.getNumber(); + kiln_id =this.itemProtocol.getKilnId(); + + if (mode != last_mode) { + if (mode == 3) { + this.setInTrussSucess(false); + } + if (mode == 4) { + this.setOutTrussSucess(false); + } + } + + if (mode != last_mode) { + this.setRequireSucess(false); + logServer.deviceItemValue(this.device_code,"mode" ,String.valueOf(mode)); + logServer.deviceExecuteLog(this.device_code,"","","信号mode:" + last_mode + "->" + mode); + } + if (move != last_move) { + logServer.deviceItemValue(this.device_code,"move" ,String.valueOf(move)); + logServer.deviceExecuteLog(this.device_code,"","","move:" + last_move + "->" + move); + } + if (task != last_task) { + logServer.deviceItemValue(this.device_code,"task" ,String.valueOf(task)); + logServer.deviceExecuteLog(this.device_code,"","","信号task:" + last_task + "->" + task); + } + if (barcode != last_barcode) { + logServer.deviceItemValue(this.device_code,"barcode" ,String.valueOf(barcode)); + logServer.deviceExecuteLog(this.device_code,"","","信号barcode:" + last_barcode + "->" + barcode); + } + if (number != last_number) { + logServer.deviceItemValue(this.device_code,"number" ,String.valueOf(number)); + logServer.deviceExecuteLog(this.device_code,"","","信号number:" + last_number + "->" + number); + } + if (kiln_id != last_kiln_id) { + logServer.deviceItemValue(this.device_code,"kiln_id" ,String.valueOf(kiln_id)); + logServer.deviceExecuteLog(this.device_code,"","","信号kiln_id:" + last_kiln_id + "->" + kiln_id); + } + + } catch (Exception e) { + log.error(e.getMessage()); + return; + } + + //急停 + if (this.isStop()) { + + //未在线无心跳 + } else if (!this.itemProtocol.getIsonline()) { + this.setIsonline(false); + this.setIserror(true); + message = "信号量同步异常"; + //未联机 + } else if (mode == 0) { + this.setIsonline(false); + this.setIserror(true); + message = "未联机"; + //有报警 + } else if (error != 0) { + this.setIsonline(false); + this.setIserror(true); + message = "有报警"; + //无报警 + } else { + this.setIsonline(true); + this.setIserror(false); + message = ""; + Instruction instruction = null; + List toInstructions; + switch (mode) { + case 1: + log.debug("设备运转模式:等待工作"); + break; + case 2: + + break; + case 3: + //上报LMS,将对应托盘置为指定窑号中 + uploadKilnInJson(); + break; + case 4: + //上报LMS,将对应窑号中的所有托盘都设置为已出窑 + uploadKilnOutJson(); + break; + } + } + + last_mode = mode; + last_move = move; + last_task = task; + last_barcode = barcode; + last_number = number; + } + + public boolean exe_error() { + if (this.error == 0) { + return true; + } else { + log.debug("设备报警"); + return false; + } + } + + /** + * 组盘入窑 + * + * @param + */ + public synchronized boolean uploadKilnInJson() { + Date date = new Date(); + if (date.getTime() - this.instruction_require_time.getTime() < (long) this.instruction_require_time_out) { + log.trace("触发时间因为小于{}毫秒,而被无视", this.instruction_require_time_out); + return false; + } else { + if(barcode==0) { + return false; + } + logServer.deviceInfo("组盘入窑", this.getDevice_code(), "开始组盘入窑!"); + JSONObject json = new JSONObject(); + //任务号 + json.put("task",this.task); + //条码 + json.put("barcode",this.barcode); + //窑号 + json.put("kiln_id",this.kiln_id); + //0-入窑 + json.put("state",0); + JSONObject resp = acsToWmsService.updateKiln(json); + if (StrUtil.equals(resp.getString("status"), "200")) { + this.writing(3); + logServer.deviceInfo("acs组盘入窑", this.getDevice_code(), "组盘入窑成功!"); + }else{ + this.writing(99); + message = "窑道外冷却区存在存留托盘,无法出窑"; + } + this.setInTrussSucess(true); + return true; + } + } + + public synchronized boolean uploadKilnOutJson() { + Date date = new Date(); + if (date.getTime() - this.instruction_require_time.getTime() < (long) this.instruction_require_time_out) { + log.trace("触发时间因为小于{}毫秒,而被无视", this.instruction_require_time_out); + return false; + } else { +// if(barcode==0) { +// return false; +// } + logServer.deviceInfo("组盘出窑", this.getDevice_code(), "开始组盘出窑!"); + JSONObject json = new JSONObject(); +// //任务号 +// json.put("task",this.task); + //组盘数量 + json.put("number",this.number); + //窑号 + json.put("kiln_id",this.kiln_id); + //1-出窑 + json.put("state",1); + JSONObject resp = acsToWmsService.updateKiln(json); + if (StrUtil.equals(resp.getString("status"), "200")) { + this.writing(4); + logServer.deviceInfo("acs组盘出窑", this.getDevice_code(), "组盘出窑成功!"); + }else{ + this.writing(99); + logServer.deviceInfo("acs组盘出窑", this.getDevice_code(), "组盘出窑成功!"); + } + this.setOutTrussSucess(true); + return true; + } + } + + public void writing(int command) { + String to_command = this.getDevice().getOpc_server_code() + "." + this.getDevice().getOpc_plc_code() + "." + this.getDevice().getDevice_code() + + "." + org.nl.acs.device_driver.hongfeng.hf_station_two.ItemProtocol.item_to_command; + String opcservcerid = this.getDevice().getOpc_server_id(); + Server server = ReadUtil.getServer(opcservcerid); + Map itemMap = new HashMap(); + itemMap.put(to_command, command); + ReadUtil.write(itemMap, server); + logServer.writeLog("下发电气信号", this.getDevice_code(), "下发信号:" + to_command + "信号值:" + command); + } + +} diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_kiln_truss/ItemProtocol.java b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_kiln_truss/ItemProtocol.java new file mode 100644 index 0000000..08b2831 --- /dev/null +++ b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_kiln_truss/ItemProtocol.java @@ -0,0 +1,114 @@ +package org.nl.acs.device_driver.hongfeng.hf_kiln_truss; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.nl.acs.device.device_driver.standard_inspect.ItemDto; + +import java.util.ArrayList; +import java.util.List; + +@Slf4j +@Data +public class ItemProtocol { + public static String item_heartbeat = "heartbeat"; + public static String item_mode = "mode"; + public static String item_move = "move"; + public static String item_task = "task"; + public static String item_error = "error"; + public static String item_barcode = "barcode"; + public static String item_number = "number"; + public static String item_kiln_id= "kiln_id"; + + public static String item_to_command = "to_command"; + public static String item_to_target = "to_target"; + public static String item_to_task = "to_task"; + Boolean isonline; + + private HfKilnTrussDeviceDriver driver; + + public ItemProtocol(HfKilnTrussDeviceDriver driver) { + this.driver = driver; + } + + public int getHeartbeat() { + return this.getOpcIntegerValue(item_heartbeat); + } + + public int getMode() { + return this.getOpcIntegerValue(item_mode); + } + + public int getMove() { + return this.getOpcIntegerValue(item_move); + } + + public int getTask() { + return this.getOpcIntegerValue(item_task); + } + + public int getBarcode() { + return this.getOpcIntegerValue(item_barcode); + } + + public int getNumber() { + return this.getOpcIntegerValue(item_number); + } + + public int getKilnId() { + return this.getOpcIntegerValue(item_kiln_id); + } + + public int getTo_command() { + return this.getOpcIntegerValue(item_to_command); + } + + public int getTo_target() { + return this.getOpcIntegerValue(item_to_target); + } + + public int getTo_task() { + return this.getOpcIntegerValue(item_to_task); + } + + //是否有货 + public int hasGoods(int move) { + return move; + } + + + public int getOpcIntegerValue(String protocol) { + Integer value = this.driver.getIntegeregerValue(protocol); + if (value == null) { +// log.error(this.getDriver().getDeviceCode() + ":protocol " + protocol + " 信号同步异常!"); + setIsonline(false); + } else { + setIsonline(true); + return value; + } + return 0; + + } + + public static List getReadableItemDtos() { + ArrayList list = new ArrayList(); + list.add(new ItemDto(item_heartbeat, "心跳", "DB200.B0")); + list.add(new ItemDto(item_mode, "工作模式", "DB200.B1")); + list.add(new ItemDto(item_move, "光电信号", "DB200.B2")); + list.add(new ItemDto(item_error, "报警信号", "DB200.B3")); + list.add(new ItemDto(item_task, "任务号", "DB200.D4")); + list.add(new ItemDto(item_barcode, "条码", "DB200.W8")); + list.add(new ItemDto(item_number,"数量","DB200.W10")); + list.add(new ItemDto(item_kiln_id,"窑号","DB200.W12")); + return list; + } + + public static List getWriteableItemDtos() { + ArrayList list = new ArrayList(); + list.add(new ItemDto(item_to_command, "下发命令反馈", "DB201.W0", Boolean.valueOf(true))); + list.add(new ItemDto(item_to_target, "下发目标站", "DB201.W2")); + list.add(new ItemDto(item_to_task, "下发任务号", "DB201.D4")); + return list; + } + +} + diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_manipulator/ItemProtocol.java b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_manipulator/ItemProtocol.java index b3e856b..87a35ba 100644 --- a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_manipulator/ItemProtocol.java +++ b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_manipulator/ItemProtocol.java @@ -79,7 +79,7 @@ public class ItemProtocol { public int getOpcIntegerValue(String protocol) { Integer value = this.driver.getIntegeregerValue(protocol); if (value == null) { - log.error(this.getDriver().getDeviceCode() + ":protocol " + protocol + " 信号同步异常!"); +// log.error(this.getDriver().getDeviceCode() + ":protocol " + protocol + " 信号同步异常!"); setIsonline(false); } else { setIsonline(true); diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_rgv_two/HfRGVTwoDefination.java b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_rgv_two/HfRGVTwoDefination.java new file mode 100644 index 0000000..4843f62 --- /dev/null +++ b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_rgv_two/HfRGVTwoDefination.java @@ -0,0 +1,62 @@ +package org.nl.acs.device_driver.hongfeng.hf_rgv_two; + +import org.nl.acs.device.device_driver.standard_inspect.ItemDto; +import org.nl.acs.device_driver.DeviceDriver; +import org.nl.acs.device_driver.defination.OpcDeviceDriverDefination; +import org.nl.acs.opc.Device; +import org.nl.acs.opc.DeviceType; +import org.springframework.stereotype.Service; + +import java.util.LinkedList; +import java.util.List; + +/** + * 宏丰二期RGV + * + */ +@Service +public class HfRGVTwoDefination implements OpcDeviceDriverDefination { + @Override + public String getDriverCode() { + return "hf_rgv_two"; + } + + @Override + public String getDriverName() { + return "宏丰RGV二期"; + } + + @Override + public String getDriverDescription() { + return "宏丰RGV二期"; + } + + @Override + public DeviceDriver getDriverInstance(Device device) { + return (new HfRGVTwoDeviceDriver()).setDevice(device).setDriverDefination(this); + + } + + @Override + public Class getDeviceDriverType() { + return HfRGVTwoDeviceDriver.class; + } + + @Override + public List getFitDeviceTypes() { + List types = new LinkedList(); + types.add(DeviceType.station); + return types; + } + + @Override + public List getReadableItemDtos() { + return ItemProtocol.getReadableItemDtos(); + } + + @Override + public List getWriteableItemDtos() { + return ItemProtocol.getWriteableItemDtos(); + } + +} diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_rgv_two/HfRGVTwoDeviceDriver.java b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_rgv_two/HfRGVTwoDeviceDriver.java new file mode 100644 index 0000000..a7cea95 --- /dev/null +++ b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_rgv_two/HfRGVTwoDeviceDriver.java @@ -0,0 +1,717 @@ +package org.nl.acs.device_driver.hongfeng.hf_rgv_two; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSONObject; +import lombok.Data; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.nl.acs.device.device_driver.standard_inspect.ReadUtil; +import org.nl.acs.device.service.DeviceService; +import org.nl.acs.device_driver.DeviceDriver; +import org.nl.acs.device_driver.RouteableDeviceDriver; +import org.nl.acs.device_driver.driver.AbstractOpcDeviceDriver; +import org.nl.acs.device_driver.driver.ExecutableDeviceDriver; +import org.nl.acs.device_driver.hongfeng.hf_station.HfStationDeviceDriver; +import org.nl.acs.ext.wms.service.AcsToWmsService; +import org.nl.acs.instruction.service.InstructionService; +import org.nl.acs.instruction.service.dto.Instruction; +import org.nl.acs.log.service.DeviceExecuteLogService; +import org.nl.acs.monitor.DeviceStageMonitor; +import org.nl.acs.opc.Device; +import org.nl.acs.opc.DeviceAppService; +import org.nl.acs.opc.DeviceAppServiceImpl; +import org.nl.acs.route.service.RouteLineService; +import org.nl.acs.task.service.TaskService; +import org.nl.acs.task.service.dto.TaskDto; +import org.nl.modules.common.exception.BadRequestException; +import org.nl.modules.wql.util.SpringContextHolder; +import org.openscada.opc.lib.da.Server; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.nl.modules.wql.util.SpringContextHolder.*; + +/** + * 宏丰二期RGV + */ +@Slf4j +@Data +@RequiredArgsConstructor +public class HfRGVTwoDeviceDriver extends AbstractOpcDeviceDriver implements DeviceDriver, ExecutableDeviceDriver, RouteableDeviceDriver, DeviceStageMonitor { + protected ItemProtocol itemProtocol = new ItemProtocol(this); + + InstructionService instructionService = getBean("instructionServiceImpl"); + + DeviceService deviceservice = getBean("deviceServiceImpl"); + + RouteLineService routelineserver = getBean("routeLineServiceImpl"); + + TaskService taskserver = getBean("taskServiceImpl"); + + AcsToWmsService acsToWmsService = getBean("acsToWmsServiceImpl"); + + DeviceAppService deviceAppservice = getBean(DeviceAppServiceImpl.class); + + //当前指令1 + Instruction inst1 = null; + + DeviceExecuteLogService logServer = getBean("deviceExecuteLogServiceImpl"); + + //工作模式 + int mode = 0; + int last_mode = 0; + //设备状态 + int status = 0; + int last_status = 0; + //前后工位光电信号 + int move1 = 0; + int last_move1 = 0; + //前后工位动作信号 + int action1 = 0; + int last_action1 = 0; + //报警信号 + int error = 0; + int last_error = 0; + //行走列 + int walk_y = 0; + int last_walk_y = 0; + //前后工位任务号 + int task1 = 0; + int last_task1 = 0; + + + Boolean isonline = true; + //后工位申请任务请求标记 + Boolean requireBackSucess = false; + //前工位申请任务请求标记 + Boolean requireHeadSucess = false; + + int hasGoods = 0; + String message = null; + Boolean iserror = false; + + int branchProtocol = 0; + + //暂定 0就绪 1请求取货 2取货完成 3请求放货 4放货完成 5取货完成离开 6放货完成离开 7请求进入区域 8请求离开区域 + int flag; + + String device_code; + + + //后工位申请任务请求时间 + private Date instruction_require_time = new Date(); + //前工位申请任务请求时间 + private Date instruction_head_time = new Date(); + //请求超时时间 + private int instruction_require_time_out = 3000; + + @Override + public Device getDevice() { + return this.device; + } + + + @Override + public void execute() throws Exception { + String message = null; + try { + device_code = this.getDeviceCode(); + mode = this.itemProtocol.getMode(); + status = this.itemProtocol.getStatus(); + move1 = this.itemProtocol.getMove1(); + action1 = this.itemProtocol.getAction1(); + walk_y = this.itemProtocol.getWalk_y(); + error = this.itemProtocol.getError(); + task1 = this.itemProtocol.getTask1(); + + if (mode != last_mode) { + if (mode == 0) { + this.setRequireHeadSucess(false); + this.setRequireBackSucess(false); + } + logServer.deviceItemValue(this.device_code, "mode", String.valueOf(mode)); + logServer.deviceExecuteLog(this.device_code, "", "", "信号mode:" + last_mode + "->" + mode); + } + if (error != last_error) { + logServer.deviceItemValue(this.device_code, "error", String.valueOf(error)); + logServer.deviceExecuteLog(this.device_code, "", "", "信号error:" + last_error + "->" + error); + } + if (status != last_status) { + logServer.deviceItemValue(this.device_code, "status", String.valueOf(status)); + logServer.deviceExecuteLog(this.device_code, "", "", "信号status:" + last_status + "->" + status); + } + if (move1 != last_move1) { + if (move1 == 0) { + this.setRequireHeadSucess(false); + } + logServer.deviceItemValue(this.device_code, "move1", String.valueOf(move1)); + logServer.deviceExecuteLog(this.device_code, "", "", "信号move1:" + last_move1 + "->" + move1); + } + if (action1 != last_action1) { + logServer.deviceItemValue(this.device_code, "action1", String.valueOf(action1)); + logServer.deviceExecuteLog(this.device_code, "", "", "信号action1:" + last_action1 + "->" + action1); + } + if (walk_y != last_walk_y) { + logServer.deviceItemValue(this.device_code, "walk_y", String.valueOf(walk_y)); + logServer.deviceExecuteLog(this.device_code, "", "", "信号walk_y:" + last_walk_y + "->" + walk_y); + } + if (task1 != last_task1) { + logServer.deviceItemValue(this.device_code, "task1", String.valueOf(task1)); + logServer.deviceExecuteLog(this.device_code, "", "", "信号task1:" + last_task1 + "->" + task1); + } + + //前工位任务就绪->执行 + if (task1 > 0) { + Instruction inst1 = instructionService.findByCodeFromCache(String.valueOf(task1)); + if (inst1 != null) { + if (StrUtil.equals(inst1.getInstruction_status(), "0")) { + inst1.setInstruction_status("1"); + instructionService.update(inst1); + } + } + } + //前工位放货完成 任务完成 + if (mode == 3 && action1 == 4 && move1 == 0 && task1 > 0) { + //inst_message + Instruction inst1 = instructionService.findByCodeFromCache(String.valueOf(task1)); + if (inst1 != null) { + if (StrUtil.equals(inst1.getInstruction_status(), "1")) { + finish_instruction(inst1); +// JSONArray array = new JSONArray(); +// TaskDto taskDto = taskserver.findByCode(inst1.getTask_code()); +// if (ObjectUtil.isNotEmpty(taskDto)) { +// if (StrUtil.isNotEmpty(taskDto.getExt_task_id())) { +// JSONObject map = new JSONObject(); +// map.put("task_id", taskDto.getExt_task_id()); +// map.put("task_status", "2"); +// map.put("finished_type", "1"); +// array.add(map); +// acsToWmsService.feedbackTaskStatusToWms(array); +// } +// } + logServer.deviceInfo("反馈电气信号", this.getDevice_code(), "RGV前工位任务完成,开始反馈电气信号"); + this.writing("to_command1", "0"); + this.writing("to_onset1", "0"); + this.writing("to_target1", "0"); + this.writing("to_task1", "0"); + this.writing("to_command1", "0"); + this.writing("to_onset1", "0"); + this.writing("to_target1", "0"); + this.writing("to_task1", "0"); + this.setRequireHeadSucess(false); + } + } + } + + //前工位取货时判断取货位光电信号 + if (mode == 3 && action1 == 1 && move1 == 0 && task1 > 0 ) { + Instruction inst1 = instructionService.findByCodeFromCache(String.valueOf(task1)); + String start_device_code = inst1.getStart_device_code(); + Device startDevice = deviceAppservice.findDeviceByCode(start_device_code); + HfStationDeviceDriver hfStationDeviceDriver; + if (startDevice.getDeviceDriver() instanceof HfStationDeviceDriver) { + hfStationDeviceDriver = (HfStationDeviceDriver) startDevice.getDeviceDriver(); + int move = hfStationDeviceDriver.getMove(); + if (move != 0) { + logServer.deviceInfo("反馈电气信号", this.getDevice_code(), "RGV前工位取货时,开始反馈电气信号"); + this.writing("to_command1", "2"); + } else { + logServer.deviceError("反馈电气信号", this.getDevice_code(), "RGV前工位取货时,取货位光电信号不满足有货条件,反馈失败!"); + } + } + } + //前工位放货时判断放货位光电信号 + if (mode == 3 && action1 == 3 && move1 == 1 && task1 > 0) { + Instruction inst1 = instructionService.findByCodeFromCache(String.valueOf(task1)); + String next_device_code = inst1.getNext_device_code(); + Device nextDevice = deviceAppservice.findDeviceByCode(next_device_code); + HfStationDeviceDriver hfStationDeviceDriver; + if (nextDevice.getDeviceDriver() instanceof HfStationDeviceDriver) { + hfStationDeviceDriver = (HfStationDeviceDriver) nextDevice.getDeviceDriver(); + int move = hfStationDeviceDriver.getMove(); + if (move == 0) { + logServer.deviceInfo("反馈电气信号", this.getDevice_code(), "RGV前工位放货时,开始反馈电气信号"); + this.writing("to_command1", "3"); + } else { + logServer.deviceError("反馈电气信号", this.getDevice_code(), "RGV前工位放货时,放货位光电信号不满足无货条件,反馈失败!"); + } + } + } + + } catch (Exception var17) { + return; + } + + if (!this.itemProtocol.getIsonline()) { + this.setIsonline(false); + this.setIserror(true); + message = "信号量同步异常"; + //未联机 + } else if (mode == 0) { + this.setIsonline(false); + this.setIserror(true); + message = "未联机"; + //有报警 + } else if (error != 0) { + this.setIsonline(false); + this.setIserror(true); + message = "有报警"; + //无报警 + } else { + this.setIsonline(true); + this.setIserror(false); + message = ""; + Instruction instruction = null; + List toInstructions; + switch (mode) { + case 1: + log.debug("设备运转模式:等待工作"); + return; + case 2: + //前工位申请任务 + if (mode == 2 && move1 == 0 && !requireHeadSucess && !requireBackSucess && task1 == 0) { + logServer.queryTask("RGV申请前工位任务", this.getDevice_code(), "RGV开始申请前工位任务!满足信号->mode == 2 && move2 == 0 && action2 == 0 && task2 == 0 && move1 == 0"); + instruction_require(); + if (!requireHeadSucess) + logServer.queryTask("RGV申请前工位任务", this.getDevice_code(), "RGV不满足申请前工位任务!此时:mode = " + mode + "task2 = " + move1 + "requireHeadSucess = " + requireHeadSucess); + } + break; + case 3: + //前工位申请任务 + if (mode == 3 && move1 == 0 && !requireHeadSucess && task1 == 0) { + logServer.queryTask("RGV申请前工位任务", this.getDevice_code(), "RGV开始申请前工位任务!满足信号->mode == 3 && move2 == 1 && action2 == 1 && move1 == 0"); + instruction_require(); + if (!requireHeadSucess) + logServer.queryTask("RGV申请前工位任务", this.getDevice_code(), "RGV不满足申请前工位任务!此时:mode = " + mode + "move1 = " + move1 + "requireHeadSucess = " + requireHeadSucess); + } + } + + } + last_mode = mode; + last_error = error; + last_status = status; + last_move1 = move1; + last_action1 = action1; + last_walk_y = walk_y; + last_task1 = task1; +} + + + //申请前工位任务 + public synchronized boolean instruction_require() throws Exception { + Date date = new Date(); + if (date.getTime() - this.instruction_head_time.getTime() < (long) this.instruction_require_time_out) { + log.trace("触发时间因为小于{}毫秒,而被无视", this.instruction_head_time); + return false; + } else { + this.instruction_head_time = date; + //前工位取货关联设备 + List getDeviceCodeList = this.getExtraDeviceCodes("head_get_device_code"); + //前工位放货关联设备 + List putDeviceCodeList = this.getExtraDeviceCodes("head_put_device_code"); + //前工位重复关联设备 + List repeatDeviceCodeList = this.getExtraDeviceCodes("head_repeat_device_code"); + //前工位重复关联设备放货设备 + List repeatPutDeviceCodeList = this.getExtraDeviceCodes("head_repeat_put_device_code"); + TaskDto task = null; + for (int i = 0; i < getDeviceCodeList.size(); i++) { + String startDeviceCode = getDeviceCodeList.get(i); + List taskDtos = taskserver.queryTaskByDeviceCodeAndStatus(startDeviceCode); + if (ObjectUtil.isNotEmpty(taskDtos)) { + TaskDto taskDto = taskDtos.get(0); + if (repeatDeviceCodeList.contains(startDeviceCode)) { + String next_device_code = taskDto.getNext_device_code(); + if (!repeatPutDeviceCodeList.contains(next_device_code)) { + continue; + } + } + Instruction instruction = instructionService.findByTaskcode(taskDto.getTask_code()); + instruction.setInstruction_status("1"); + instruction.setUpdate_time(DateUtil.now()); + instructionService.update(instruction); + this.sendHeadSignalType(instruction); + requireHeadSucess = true; + logServer.deviceInfo("RGV申请前工位任务", this.getDevice_code(), "RGV申请前工位任务成功,任务为重新创建指令的任务,指令号:" + instruction.getInstruction_code()); + return true; + } else { + List taskDtoList = taskserver.queryTaskByDeviceCode(startDeviceCode); + if (ObjectUtil.isNotEmpty(taskDtoList)) { + task = taskDtoList.get(0); + String next_device_code = task.getNext_device_code(); + if (repeatDeviceCodeList.contains(startDeviceCode)) { + if (!repeatPutDeviceCodeList.contains(next_device_code)) { + task = null; + continue; + } else { + if (ObjectUtil.isNotEmpty(task)) break; + } + } + } + if (ObjectUtil.isNotEmpty(task)) break; + } + } + + if (!ObjectUtil.isEmpty(task)) { + String taskid = task.getTask_id(); + String taskcode = task.getTask_code(); + String vehiclecode = task.getVehicle_code(); + String priority = task.getPriority(); + String start_point_code = task.getStart_point_code(); + String start_device_code = task.getStart_device_code(); + String route_plan_code = task.getRoute_plan_code(); + String next_point_code = task.getNext_point_code(); + String next_device_code = task.getNext_device_code(); + + Instruction instdto = new Instruction(); + instdto.setInstruction_id(IdUtil.simpleUUID()); + instdto.setRoute_plan_code(route_plan_code); + instdto.setRemark(task.getRemark()); + instdto.setMaterial(task.getMaterial()); + instdto.setQuantity(task.getQuantity()); + instdto.setTask_id(taskid); + instdto.setTask_code(taskcode); + instdto.setVehicle_code(vehiclecode); + String now = DateUtil.now(); + instdto.setCreate_time(now); + instdto.setCreate_by("auto"); + instdto.setStart_device_code(start_device_code); + instdto.setNext_device_code(next_device_code); + instdto.setStart_point_code(start_point_code); + instdto.setNext_point_code(next_point_code); + instdto.setPriority(priority); + instdto.setInstruction_status("0"); + instdto.setExecute_device_code(start_point_code); + + try { + instructionService.create(instdto); + } catch (Exception e) { + e.printStackTrace(); + } + + //创建指令后修改任务状态 + task.setTask_status("1"); + task.setUpdate_time(DateUtil.now()); + taskserver.update(task); + this.sendHeadSignalType(instdto); + requireHeadSucess = true; + logServer.deviceInfo("RGV申请前工位任务", this.getDevice_code(), "RGV申请前工位任务成功,任务为就绪状态下的任务,指令号:" + instdto.getInstruction_code()); + } else { + logServer.deviceInfo("RGV申请前工位任务", this.getDevice_code(), "RGV申请前工位任务失败,未找到前工位取货位关联设备的起点任务!"); + } + } + return true; + } + + //申请后工位任务 + public synchronized boolean instruction_require2() throws Exception { + Date date = new Date(); + if (date.getTime() - this.instruction_require_time.getTime() < (long) this.instruction_require_time_out) { + log.trace("触发时间因为小于{}毫秒,而被无视", this.instruction_require_time); + return false; + } else { + this.instruction_require_time = date; + + //后工位取货关联设备 + List getDeviceCodeList = this.getExtraDeviceCodes("back_get_device_code"); + //后工位放货关联设备 + List putDeviceCodeList = this.getExtraDeviceCodes("back_put_device_code"); + //后工位重复关联设备 + List repeatDeviceCodeList = this.getExtraDeviceCodes("back_repeat_device_code"); + //后工位重复关联设备放货设备 + List repeatPutDeviceCodeList = this.getExtraDeviceCodes("back_repeat_put_device_code"); + + TaskDto task = null; + for (int i = 0; i < getDeviceCodeList.size(); i++) { + String startDeviceCode = getDeviceCodeList.get(i); + List taskDtos = taskserver.queryTaskByDeviceCodeAndStatus(startDeviceCode); + if (ObjectUtil.isNotEmpty(taskDtos)) { + TaskDto taskDto = taskDtos.get(0); + if (repeatDeviceCodeList.contains(startDeviceCode)) { + String next_device_code = taskDto.getNext_device_code(); + if (!repeatPutDeviceCodeList.contains(next_device_code)) { + continue; + } + } + Instruction instruction = instructionService.findByTaskcode(taskDto.getTask_code()); + instruction.setInstruction_status("1"); + instruction.setUpdate_time(DateUtil.now()); + instructionService.update(instruction); + this.sendBackSignalType(instruction); + requireBackSucess = true; + logServer.deviceInfo("RGV申请后工位任务", this.getDevice_code(), "RGV申请后工位任务成功,任务为重新创建指令的任务,指令号:" + instruction.getInstruction_code()); + return true; + } else { + List taskDtoList = taskserver.queryTaskByDeviceCode(startDeviceCode); + if (ObjectUtil.isNotEmpty(taskDtoList)) { + task = taskDtoList.get(0); + String next_device_code = task.getNext_device_code(); + if (repeatDeviceCodeList.contains(startDeviceCode)) { + if (!repeatPutDeviceCodeList.contains(next_device_code)) { + task = null; + continue; + } else { + if (ObjectUtil.isNotEmpty(task)) break; + } + } + } + if (ObjectUtil.isNotEmpty(task)) ; + } + } + + if (!ObjectUtil.isEmpty(task)) { + String taskid = task.getTask_id(); + String taskcode = task.getTask_code(); + String vehiclecode = task.getVehicle_code(); + String priority = task.getPriority(); + String start_point_code = task.getStart_point_code(); + String start_device_code = task.getStart_device_code(); + String route_plan_code = task.getRoute_plan_code(); + String next_point_code = task.getNext_point_code(); + String next_device_code = task.getNext_device_code(); + + Instruction instdto = new Instruction(); + instdto.setInstruction_id(IdUtil.simpleUUID()); + instdto.setRoute_plan_code(route_plan_code); + instdto.setRemark(task.getRemark()); + instdto.setMaterial(task.getMaterial()); + instdto.setQuantity(task.getQuantity()); + instdto.setTask_id(taskid); + instdto.setTask_code(taskcode); + instdto.setVehicle_code(vehiclecode); + String now = DateUtil.now(); + instdto.setCreate_time(now); + instdto.setCreate_by("auto"); + instdto.setStart_device_code(start_device_code); + instdto.setNext_device_code(next_device_code); + instdto.setStart_point_code(start_point_code); + instdto.setNext_point_code(next_point_code); + instdto.setPriority(priority); + instdto.setInstruction_status("0"); + instdto.setExecute_device_code(start_point_code); + + try { + instructionService.create(instdto); + } catch (Exception e) { + e.printStackTrace(); + } + + //创建指令后修改任务状态 + task.setTask_status("1"); + taskserver.update(task); + this.sendBackSignalType(instdto); + logServer.deviceInfo("RGV申请后工位任务", this.getDevice_code(), "RGV申请后工位任务成功,任务为就绪状态下的任务,指令号:" + instdto.getInstruction_code()); + } else { + logServer.deviceInfo("RGV申请后工位任务", this.getDevice_code(), "RGV申请后工位任务失败,未找到后工位取货位关联设备的起点任务!"); + } + } + return true; + } + + public synchronized void sendHeadSignalType(Instruction dto) { + logServer.deviceInfo("RGV申请前工位任务", this.getDevice_code(), "RGV前工位任务指令创建成功,开始写入信号"); + String start_device_code = dto.getStart_device_code(); + String next_device_code = dto.getNext_device_code(); + Device startDevice = deviceAppservice.findDeviceByCode(start_device_code); + Device nextDevice = deviceAppservice.findDeviceByCode(next_device_code); + this.isSetAddress(startDevice); + this.isSetAddress(nextDevice); + String start_addr = startDevice.getExtraValue().get("address").toString(); + String next_addr = nextDevice.getExtraValue().get("address").toString(); + this.writing("to_onset1", start_addr); + this.writing("to_target1", next_addr); + this.writing("to_task1", dto.getInstruction_code()); + this.writing("to_command1", "1"); + this.writing("to_onset1", start_addr); + this.writing("to_target1", next_addr); + this.writing("to_task1", dto.getInstruction_code()); + this.writing("to_command1", "1"); + logServer.deviceInfo("RGV申请前工位任务", this.getDevice_code(), "RGV前工位任务指令创建成功,信号写入成功"); + } + + public synchronized void sendBackSignalType(Instruction dto) { + logServer.deviceInfo("RGV申请后工位任务", this.getDevice_code(), "RGV后工位任务指令创建成功,开始写入信号"); + String start_device_code = dto.getStart_device_code(); + String next_device_code = dto.getNext_device_code(); + Device startDevice = deviceAppservice.findDeviceByCode(start_device_code); + Device nextDevice = deviceAppservice.findDeviceByCode(next_device_code); + this.isSetAddress(startDevice); + this.isSetAddress(nextDevice); + String start_addr = startDevice.getExtraValue().get("address").toString(); + String next_addr = nextDevice.getExtraValue().get("address").toString(); + this.writing("to_onset2", start_addr); + this.writing("to_target2", next_addr); + this.writing("to_task2", dto.getInstruction_code()); + this.writing("to_command2", "1"); + this.writing("to_onset2", start_addr); + this.writing("to_target2", next_addr); + this.writing("to_task2", dto.getInstruction_code()); + this.writing("to_command2", "1"); + logServer.deviceInfo("RGV申请后工位任务", this.getDevice_code(), "RGV后工位任务指令创建成功,信号写入成功"); + } + + //判断点位是否设置电气值 + public void isSetAddress(Device device) { + if (ObjectUtil.isEmpty(device.getExtraValue().get("address"))) { + logServer.deviceError("未设置电气调度号", this.getDevice_code(), "下发指令,设备: '" + device.getDevice_code() + "'未查询到电气调度号"); + throw new BadRequestException("设备:" + device.getDevice_code() + "未设置电气调度号!"); + } + } + + public boolean exe_error() { + if (this.error == 0) { + return true; + } else { + log.debug("设备报警"); + return false; + } + } + + public void writing(String param, String value) { + + String to_param = this.getDevice().getOpc_server_code() + "." + this.getDevice().getOpc_plc_code() + "." + this.getDevice().getDevice_code() + + "." + param; + String opcservcerid = this.getDevice().getOpc_server_id(); + Server server = ReadUtil.getServer(opcservcerid); + Map itemMap = new HashMap(); + itemMap.put(to_param, Integer.parseInt(value)); + + ReadUtil.write(itemMap, server); + logServer.writeLog("下发电气信号", this.getDevice_code(), "下发信号:" + to_param + "信号值:" + value); + } + + public boolean exe_business() { + return true; + } + + protected void executing(Instruction instruction) { + this.executing(1, instruction, ""); + } + + public void executing(int command, Instruction instruction, String appendMessage) { + + String opcservcerid = this.getDevice().getOpc_server_id(); + Server server = ReadUtil.getServer(opcservcerid); + Map itemMap = new HashMap(); + ReadUtil.write(itemMap, server); + + } + + + public synchronized boolean finish_instruction(Instruction inst) throws Exception { + instructionService.finish(inst); + return true; + } + + + public void executing(Server server, Map itemMap) { + ReadUtil.write(itemMap, server); + } + + public void writing1(int command) { + String to_command1 = this.getDevice().getOpc_server_code() + "." + this.getDevice().getOpc_plc_code() + "." + this.getDevice().getDevice_code() + + "." + ItemProtocol.item_to_command1; + + String opcservcerid = this.getDevice().getOpc_server_id(); + Server server = ReadUtil.getServer(opcservcerid); + Map itemMap = new HashMap(); + itemMap.put(to_command1, command); + ReadUtil.write(itemMap, server); + + } + + + //将扩展表中的字符串数组数据转换成集合 + public List getExtraDeviceCodes(String extraName) { + String extraValue = (String) this.getDevice().getExtraValue().get(extraName); + if (StrUtil.isEmpty(extraValue)) { + return new ArrayList<>(); + } + String devicesString = extraValue.substring(1, extraValue.length() - 1); + List devicesList = new ArrayList<>(); + String[] devices = devicesString.split(","); + for (int i = 0; i < devices.length; i++) { + String s = devices[i].replace("\"", "").replace("\"", ""); + devicesList.add(s); + } + return devicesList; + } + + @Override + public JSONObject getDeviceStatusName() { + JSONObject jo = new JSONObject(); + String move1 = ""; + String move2 = ""; + String action1 = ""; + String action2 = ""; + String walk_y = ""; + String mode = ""; + String status = ""; + + if (this.getMode() == 0) { + mode = "脱机"; + } else if (this.getMode() == 1) { + mode = "单机"; + } else if (this.getMode() == 2) { + mode = "待机"; + } else if (this.getMode() == 3) { + mode = "运行中"; + } + + if (this.getStatus() == 1) { + status = "待机"; + } else if (this.getStatus() == 2) { + status = "生产中"; + } else if (this.getStatus() == 3) { + status = "故障"; + } + + if (this.getMove1() == 0) { + move1 = "无货"; + } else if (this.getMove1() == 1) { + move1 = "有货"; + } + + if (this.getAction1() == 1) { + action1 = "取货中"; + } else if (this.getAction1() == 2) { + action1 = "取货完成"; + } else if (this.getAction1() == 3) { + action1 = "放货中"; + } else if (this.getAction1() == 4) { + action1 = "放货完成"; + } + + if (this.getWalk_y() == 0) { + walk_y = "原位"; + } else if (this.getWalk_y() == 2) { + walk_y = "非原位"; + } + + jo.put("device_name", this.getDevice().getDevice_name()); + jo.put("mode", mode); + jo.put("status", status); + jo.put("move1", move1); + jo.put("move2", move2); + jo.put("action1", action1); + jo.put("action2", action2); + jo.put("walk_y", walk_y); + jo.put("error", this.getError()); + jo.put("task1", this.getTask1()); + jo.put("isOnline", this.getIsonline()); + jo.put("isError", this.getIserror()); + jo.put("message", this.getMessage()); + return jo; + } + + @Override + public void setDeviceStatus(JSONObject data) { + + } +} diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_rgv_two/ItemProtocol.java b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_rgv_two/ItemProtocol.java new file mode 100644 index 0000000..4decf33 --- /dev/null +++ b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_rgv_two/ItemProtocol.java @@ -0,0 +1,136 @@ +package org.nl.acs.device_driver.hongfeng.hf_rgv_two; + +import cn.hutool.core.util.StrUtil; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.nl.acs.device.device_driver.standard_inspect.ItemDto; + +import java.util.ArrayList; +import java.util.List; + +@Slf4j +@Data +public class ItemProtocol { + + //心跳 + public static String item_heartbeat = "heartbeat"; + //工作模式 + public static String item_mode = "mode"; + //设备状态 + public static String item_status = "status"; + //前工位光电信号 + public static String item_move1 = "move1"; + //前工位动作信号 + public static String item_action1 = "action1"; + //行走列 + public static String item_walk_y = "walk_y"; + //报警信号 + public static String item_error = "error"; + //前工位任务号 + public static String item_task1 = "task1"; + + + //前工位下发命令 + public static String item_to_command1 = "to_command1"; + //前工位下发起始站 + public static String item_to_onset1 = "to_onset1"; + //前工位下发目标站 + public static String item_to_target1 = "to_target1"; + //前工位下发任务号 + public static String item_to_task1 = "to_task1"; + + + + private HfRGVTwoDeviceDriver driver; + + public ItemProtocol(HfRGVTwoDeviceDriver driver) { + this.driver = driver; + } + + public int getHeartbeat() { + return this.getOpcIntegerValue(item_heartbeat); + } + + public int getMode() { + return this.getOpcIntegerValue(item_mode); + } + + public int getStatus() { + return this.getOpcIntegerValue(item_status); + } + + public int getError() { + return this.getOpcIntegerValue(item_error); + } + + public int getMove1() { + return this.getOpcIntegerValue(item_move1); + } + + public int getAction1() { + return this.getOpcIntegerValue(item_action1); + } + + public int getWalk_y() { + return this.getOpcIntegerValue(item_walk_y); + } + + public int getTask1() { + return this.getOpcIntegerValue(item_task1); + } + + + //是否有货 + public int hasGoods(int move) { + return move; + } + + Boolean isonline; + + public int getOpcIntegerValue(String protocol) { + Integer value = this.driver.getIntegeregerValue(protocol); + if (value == null) { +// log.error(this.getDriver().getDeviceCode() + ":protocol " + protocol + " 信号同步异常!"); + setIsonline(false); + } else { + setIsonline(true); + return value; + } + return 0; + + } + + public String getOpcStringValue(String protocol) { + String value = this.driver.getStringValue(protocol); + if (StrUtil.isEmpty(value)) { + + } else { + return value; + } + return "0"; + } + + public static List getReadableItemDtos() { + ArrayList list = new ArrayList(); + list.add(new ItemDto(item_heartbeat, "心跳", "DB2.B0")); + list.add(new ItemDto(item_mode, "工作模式", "DB2.B1")); + list.add(new ItemDto(item_status, "设备状态", "DB2.B2")); + list.add(new ItemDto(item_move1, "前工位光电信号", "DB2.B3")); + list.add(new ItemDto(item_action1, "前工位动作信号", "DB2.B5")); + list.add(new ItemDto(item_walk_y, "行走列", "DB2.B7")); + list.add(new ItemDto(item_error, "报警信号", "DB2.B8")); + list.add(new ItemDto(item_task1, "前工位任务号", "DB2.D10")); + return list; + } + + public static List getWriteableItemDtos() { + ArrayList list = new ArrayList(); + list.add(new ItemDto(item_to_command1, "前工位下发命令", "DB3.W0")); + list.add(new ItemDto(item_to_onset1, "前工位下发起始站", "DB3.W2")); + list.add(new ItemDto(item_to_target1, "前工位下发目标站", "DB3.W4")); + list.add(new ItemDto(item_to_task1, "前工位下发任务号", "DB3.D6")); + return list; + } + +} + diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_station/ItemProtocol.java b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_station/ItemProtocol.java index 990f1eb..02a0924 100644 --- a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_station/ItemProtocol.java +++ b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_station/ItemProtocol.java @@ -125,7 +125,7 @@ public class ItemProtocol { public int getOpcIntegerValue(String protocol) { Integer value = this.driver.getIntegeregerValue(protocol); if (value == null) { - log.error(this.getDriver().getDeviceCode() + ":protocol " + protocol + " 信号同步异常!"); +// log.error(this.getDriver().getDeviceCode() + ":protocol " + protocol + " 信号同步异常!"); setIsonline(false); } else { setIsonline(true); diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_station_two/HfStationTwoDefination.java b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_station_two/HfStationTwoDefination.java new file mode 100644 index 0000000..925dbdb --- /dev/null +++ b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_station_two/HfStationTwoDefination.java @@ -0,0 +1,82 @@ +package org.nl.acs.device_driver.hongfeng.hf_station_two; + +import org.nl.acs.device.device_driver.standard_inspect.ItemDto; +import org.nl.acs.device_driver.DeviceDriver; +import org.nl.acs.device_driver.defination.OpcDeviceDriverDefination; +import org.nl.acs.opc.Device; +import org.nl.acs.opc.DeviceType; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +/** + * 宏丰-工位二期 + * + */ +@Service +public class HfStationTwoDefination implements OpcDeviceDriverDefination { + @Override + public String getDriverCode() { + return "hf_station_two"; + } + + @Override + public String getDriverName() { + return "宏丰-工位二期"; + } + + @Override + public String getDriverDescription() { + return "宏丰-工位二期"; + } + + @Override + public DeviceDriver getDriverInstance(Device device) { + return (new HfStationTwoDeviceDriver()).setDevice(device).setDriverDefination(this); + + } + + @Override + public Class getDeviceDriverType() { + return HfStationTwoDeviceDriver.class; + } + + @Override + public List getFitDeviceTypes() { + List types = new LinkedList(); + types.add(DeviceType.station); + return types; + } + + @Override + public List getReadableItemDtos() { + return getReadableItemDtos2(); + } + + public static List getReadableItemDtos2() { + List list = new ArrayList(); + list.add(new ItemDto(ItemProtocol.item_heartbeat, "心跳", "DB101.B0")); + list.add(new ItemDto(ItemProtocol.item_mode, "工作模式", "DB101.B1")); + list.add(new ItemDto(ItemProtocol.item_move, "光电信号", "DB101.B2")); + list.add(new ItemDto(ItemProtocol.item_action, "取放信号", "DB101.B3")); + list.add(new ItemDto(ItemProtocol.item_ioaction, "进出信号", "DB101.B4")); + list.add(new ItemDto(ItemProtocol.item_error, "报警信号", "DB101.B5")); + list.add(new ItemDto(ItemProtocol.item_task, "任务号", "DB101.D6")); + list.add(new ItemDto(ItemProtocol.item_status, "设备状态", "DB101.B10")); + list.add(new ItemDto(ItemProtocol.item_current_order_num, "当前工单数量", "DB101.D12")); + list.add(new ItemDto(ItemProtocol.item_order, "工单号", "DB200.STRING20.50")); + list.add(new ItemDto(ItemProtocol.item_barcode, "条码", "DB200.STRING72.50")); + list.add(new ItemDto(ItemProtocol.item_material_code, "物料号", "DB200.B72")); + list.add(new ItemDto(ItemProtocol.item_product_code,"产品编号","DB200.B124")); + list.add(new ItemDto(ItemProtocol.item_number,"托盘砖数量","DB200.B16")); + return list; + } + + @Override + public List getWriteableItemDtos() { + return ItemProtocol.getWriteableItemDtos(); + } + +} diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_station_two/HfStationTwoDeviceDriver.java b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_station_two/HfStationTwoDeviceDriver.java new file mode 100644 index 0000000..333176d --- /dev/null +++ b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_station_two/HfStationTwoDeviceDriver.java @@ -0,0 +1,704 @@ +package org.nl.acs.device_driver.hongfeng.hf_station_two; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSONObject; +import lombok.Data; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.nl.acs.device.device_driver.DriverTypeEnum; +import org.nl.acs.device.device_driver.standard_inspect.ReadUtil; +import org.nl.acs.device.service.DeviceService; +import org.nl.acs.device_driver.DeviceDriver; +import org.nl.acs.device_driver.RouteableDeviceDriver; +import org.nl.acs.device_driver.driver.AbstractOpcDeviceDriver; +import org.nl.acs.device_driver.driver.ExecutableDeviceDriver; +import org.nl.acs.device_driver.hongfeng.hf_kiln_manipulator.HfKilnManipulatorDeviceDriver; +import org.nl.acs.device_driver.hongfeng.hf_station.HfStationDeviceDriver; +import org.nl.acs.ext.wms.service.AcsToWmsService; +import org.nl.acs.instruction.service.InstructionService; +import org.nl.acs.instruction.service.dto.Instruction; +import org.nl.acs.log.service.DeviceExecuteLogService; +import org.nl.acs.monitor.DeviceStageMonitor; +import org.nl.acs.opc.Device; +import org.nl.acs.opc.DeviceAppService; +import org.nl.acs.order.service.ProduceshiftorderService; +import org.nl.acs.order.service.dto.ProduceshiftorderDto; +import org.nl.acs.route.service.RouteLineService; +import org.nl.acs.task.service.TaskService; +import org.nl.modules.wql.util.SpringContextHolder; +import org.openscada.opc.lib.da.Server; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.annotation.Resource; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import static org.nl.modules.wql.util.SpringContextHolder.getBean; + +/** + * 宏丰-工位(交互模板二期) + */ +@Slf4j +@Data +@RequiredArgsConstructor +public class HfStationTwoDeviceDriver extends AbstractOpcDeviceDriver implements DeviceDriver, ExecutableDeviceDriver, RouteableDeviceDriver, DeviceStageMonitor { + protected ItemProtocol itemProtocol = new ItemProtocol(this); + + InstructionService instructionService=getBean("instructionServiceImpl"); + + DeviceService deviceService=getBean("deviceServiceImpl"); + + RouteLineService routeLineServer=getBean("routeLineServiceImpl"); + + TaskService taskServer=getBean("taskServiceImpl"); + + DeviceExecuteLogService logServer=getBean("deviceExecuteLogServiceImpl"); + + AcsToWmsService acsToWmsService=getBean("acsToWmsServiceImpl"); + + ProduceshiftorderService produceshiftorderService=getBean("produceshiftorderServiceImpl"); + + DeviceAppService deviceAppService=getBean("deviceAppServiceImpl"); + + + String device_code; + + //心跳 + int heartbeat; + int last_heartbeat; + //工作模式 + int mode = 0; + int last_mode = 0; + //光电信号 + int move = 0; + int last_move = 0; + //取放信号 + int action = 0; + int last_action = 0; + //进出信号 + int io_action = 0; + int last_ioaction = 0; + //报警信号 + int error = 0; + int last_error = 0; + //任务号 + int task = 0; + int last_task = 0; + //设备状态 + int status = 0; + int last_status = 0; + //当前工单数量 + int current_order_num = 0; + int last_current_order_num = 0; + //工单号 + String order = "0"; + String last_order = "0"; + //产品编码 + String material_code = "0"; + String last_material_code = "0"; + //条码 + int barcode = 0; + int last_barcode = 0; + //重量 + int weight = 0; + int last_weight = 0; + + //托盘砖数量 + int number = 0; + int last_number =0; + + int product_code =0; + int last_product_code=0; + + + Boolean isonline = true; + int hasGoods = 0; + Boolean iserror = false; + + protected int instruction_num = 0; + protected int instruction_num_truth = 0; + Integer heartbeat_tag; + //人工排产确认请求时间 + private Date instruction_require_time = new Date(); + //工单完成请求时间 + private Date instruction_finished_time = new Date(); + //呼叫空盅请求时间 + private Date instruction_call_empty_time = new Date(); + //满盅入库请求时间 + private Date instruction_full_in_time = new Date(); + //叫料请求时间 + private Date instruction_call_material_time = new Date(); + //空料盅对接位有货时请求时间 + private Date instruction_empty_hasGoods_time = new Date(); + //条码改变请求标记 + private Date instruction_update_barcode_time = new Date(); + + + private int instruction_require_time_out = 3000; + //人工排产确认请求标记 + boolean requireSucess = false; + //工单完成请求标记 + boolean finishRequireSucess = false; + //呼叫空盅请求标记 + boolean callEmptyRequireSucess = false; + //满盅入库请求标记 + boolean fullInRequireSucess = false; + //叫料请求标记 + boolean callMaterialRequireSucess = false; + //空料盅对接位有货时请求标记 + boolean emptyHasGoodsRequireSucess = true; + //条码改变请求标记 + boolean updateBarcodeRequireSucess = true; + //光电变更 + boolean moveUpdateSuccess = true; + //托盘砖数量变更 + boolean numberUpdateSuccess = false; + + private int instruction_finished_time_out; + + + int branchProtocol = 0; + //当前指令 + Instruction inst = null; + //上次指令 + Instruction last_inst = null; + + //触摸屏手动触发任务 + private Boolean is_has_task = false; + + //暂定 0就绪 1请求取货 2取货完成 3请求放货 4放货完成 5取货完成离开 6放货完成离开 7请求进入区域 8请求离开区域 + int flag; + int last_flag; + + String message; + + int container_type = 0; + + + @Override + public Device getDevice() { + return this.device; + } + + + @Override + public void execute() { + String message = null; + try { + device_code = this.getDeviceCode(); + mode = this.itemProtocol.getMode(); + move = this.itemProtocol.getMove(); + action = this.itemProtocol.getAction(); + io_action = this.itemProtocol.getIoAction(); + error = this.itemProtocol.getError(); + task = this.itemProtocol.getTask(); + status = this.itemProtocol.getStatus(); + current_order_num = this.itemProtocol.getCurrent_order_num(); + barcode = this.itemProtocol.getBarcode(); + weight = this.itemProtocol.getWeight(); + material_code = this.itemProtocol.getMaterial_code(); + order = this.itemProtocol.getOrder(); + number =this.itemProtocol.getNumber(); + product_code=this.itemProtocol.getProduct_code(); + + if (mode != last_mode) { + if (mode == 3) { + this.setRequireSucess(false); + } + if (mode == 4) { + this.setFinishRequireSucess(false); + } + if (mode == 6) { + this.setCallEmptyRequireSucess(false); + } + if (mode == 7) { + this.setFullInRequireSucess(false); + } + if (mode == 8) { + this.setCallMaterialRequireSucess(false); + } + logServer.deviceItemValue(this.device_code, "mode", String.valueOf(mode)); + logServer.deviceExecuteLog(this.device_code, "", "", "信号mode:" + last_mode + "->" + mode); + } + if (move != last_move) { + Object apply_task = this.getDevice().getExtraValue().get("apply_task"); + if (ObjectUtil.isEmpty(apply_task)) { + apply_task = "false"; + } + if (apply_task.toString().equals("true") && move == 1) { + this.setEmptyHasGoodsRequireSucess(false); + } + this.setMoveUpdateSuccess(false); + logServer.deviceItemValue(this.device_code, "move", String.valueOf(move)); + logServer.deviceExecuteLog(this.device_code, "", "", "信号move:" + last_move + "->" + move); + } + if (action != last_action) { + logServer.deviceItemValue(this.device_code, "action", String.valueOf(action)); + logServer.deviceExecuteLog(this.device_code, "", "", "信号action:" + last_action + "->" + action); + } + if (io_action != last_ioaction) { + logServer.deviceItemValue(this.device_code, "io_action", String.valueOf(io_action)); + logServer.deviceExecuteLog(this.device_code, "", "", "信号io_action: " + last_ioaction + "->" + io_action); + } + if (error != last_error) { + logServer.deviceItemValue(this.device_code, "error", String.valueOf(error)); + logServer.deviceExecuteLog(this.device_code, "", "", "信号error:" + last_error + "->" + error); + } + if (task != last_task) { + logServer.deviceItemValue(this.device_code, "task", String.valueOf(task)); + logServer.deviceExecuteLog(this.device_code, "", "", "信号task:" + last_task + "->" + task); + } + if (status != last_status) { + logServer.deviceItemValue(this.device_code, "status", String.valueOf(status)); + logServer.deviceExecuteLog(this.device_code, "", "", "信号status: " + last_status + "->" + status); + } + if (current_order_num != last_current_order_num) { + logServer.deviceItemValue(this.device_code, "current_order_num", String.valueOf(current_order_num)); + logServer.deviceExecuteLog(this.device_code, "", "", "信号current_order_num: " + last_current_order_num + "->" + current_order_num); + } + if (weight != last_weight) { + logServer.deviceItemValue(this.device_code, "weight", String.valueOf(weight)); + logServer.deviceExecuteLog(this.device_code, "", "", "信号weight: " + last_weight + "->" + weight); + } + if (!order.equals(last_order)) { + logServer.deviceItemValue(this.device_code, "order", order); + logServer.deviceExecuteLog(this.device_code, "", "", "信号order:" + last_order + "->" + order); + } + if (barcode != last_barcode) { + this.setUpdateBarcodeRequireSucess(false); + logServer.deviceItemValue(this.device_code, "barcode", String.valueOf(barcode)); + logServer.deviceExecuteLog(this.device_code, "", "", "信号barcode:" + last_barcode + "->" + barcode); + } + if (!material_code.equals(last_material_code)) { + logServer.deviceItemValue(this.device_code, "material_code", material_code); + logServer.deviceExecuteLog(this.device_code, "", "", "信号material_code:" + last_material_code + "->" + material_code); + } + if (number != last_number) { + this.setNumberUpdateSuccess(true); + logServer.deviceItemValue(this.device_code, "number", String.valueOf(number)); + logServer.deviceExecuteLog(this.device_code, "", "", "信号number:" + last_number + "->" + number); + } + if (!Objects.equals(product_code, last_product_code)) { + logServer.deviceItemValue(this.device_code, "product_code", String.valueOf(product_code)); + logServer.deviceExecuteLog(this.device_code, "", "", "信号product_code:" + last_product_code + "->" + product_code); + } + + + } catch (Exception var17) { + return; + } + + //急停 + if (this.isStop()) { + //未在线无心跳 +// } else if (!this.itemProtocol.getIsonline()) { +// this.setIsonline(false); +// this.setIserror(true); +// message = "信号量同步异常"; +// //未联机 + } else if (mode == 0) { + this.setIsonline(false); + this.setIserror(true); + message = "未联机"; + //有报警 + } else if (error != 0) { + this.setIsonline(false); + this.setIserror(true); + message = "有报警"; + //无报警 + } else { + this.setIsonline(true); + this.setIserror(false); + message = ""; + Instruction instruction = null; + List toInstructions; + switch (mode) { + case 1: + log.debug("设备运转模式:等待工作"); + break; + case 3: + //人工排产确认 + if (!requireSucess && StrUtil.isNotEmpty(order)) { + enterOrder(); + } + break; + case 4: + //工单完成 + if (!finishRequireSucess && StrUtil.isNotEmpty(order)) { + finish(); + } + break; + case 6: + //满跺完成,请求呼叫 + if (!callEmptyRequireSucess && move != 0) { + //上报lms组盘完毕 + //反馈电气组盘成功 + uploadPalletizing(); + log.info("电气上报组盘完毕"); + } + case 7: + //满盅入库 + if (!fullInRequireSucess && move == 0) { + fullIn(); + + } + break; + default: + break; + } + + } + + last_mode = mode; + last_move = move; + last_action = action; + last_ioaction = io_action; + last_error = error; + last_task = task; + last_status = status; + last_current_order_num = current_order_num; + last_order = order; + last_barcode = barcode; + last_weight = weight; + last_material_code = material_code; + last_product_code = product_code; + } + + /** + * 出窑缓存区托盘 + * + * @param + */ + public synchronized boolean fullIn() { + Date date = new Date(); + if (date.getTime() - this.instruction_full_in_time.getTime() < (long) this.instruction_require_time_out) { + log.trace("触发时间因为小于{}毫秒,而被无视", this.instruction_full_in_time); + return false; + } else { + logServer.deviceInfo("acs申请任务", this.getDevice_code(), "开始申请满盅入库任务!"); + this.instruction_full_in_time = date; + JSONObject json = new JSONObject(); + json.put("device_code", device_code); + json.put("barcode", barcode); + json.put("weight", weight); + json.put("material_code",material_code); + json.put("create_mode", "2"); + json.put("is_auto_issue", "0"); + json.put("type", "5"); + JSONObject resp = acsToWmsService.apply(json); + if (StrUtil.equals(resp.getString("status"), "200")) { + this.writing(7); + this.setFullInRequireSucess(true); + logServer.deviceInfo("acs申请任务", this.getDevice_code(), "满盅入库任务申请成功!"); + }else{ + this.writing(99); + } + return true; + } + } + + /** + * 组盘信息上报 + * + * @param + */ + public synchronized boolean uploadPalletizing() { + Date date = new Date(); + if (date.getTime() - this.instruction_require_time.getTime() < (long) this.instruction_require_time_out) { + log.trace("触发时间因为小于{}毫秒,而被无视", this.instruction_require_time_out); + return false; + } else { + logServer.deviceInfo("组盘信息上报", this.getDevice_code(), "开始组盘信息上报!"); + ProduceshiftorderDto dto = produceshiftorderService.findByCode(order); + JSONObject json = new JSONObject(); + //设备号 + json.put("vehicle_code",this.barcode); + //工单号 + json.put("order_code",this.order); + //托盘砖数量 + json.put("number",this.number); + //产品编号 + json.put("product_code",this.product_code); + //物料号 + json.put("material_code",this.material_code); + JSONObject resp = acsToWmsService.uploadPalletizing(json); + if (StrUtil.equals(resp.getString("status"), "200")) { + this.writing(6); + this.setCallEmptyRequireSucess(true); + logServer.deviceInfo("acs组盘信息上报", this.getDevice_code(), "组盘信息上报成功!"); + }else{ + log.error("操作失败,{}",json); + this.writing(99); + } + return true; + } + + } + + + + + public boolean exe_error() { + if (this.error == 0) { + return true; + } else { + log.debug("设备报警"); + return false; + } + } + + public boolean exe_business() { + return true; + } + + public String autoGenericCode(String vehicle_code) { + return String.format("%0" + 4 + "d", Integer.parseInt(vehicle_code)); + } + + protected void executing(Instruction instruction) { + this.executing(1, instruction, ""); + } + + public void executing(int command, Instruction instruction, String appendMessage) { + String to_command = this.getDevice().getOpc_server_code() + "." + this.getDevice().getOpc_plc_code() + "." + this.getDevice().getDevice_code() + + "." + org.nl.acs.device_driver.hongfeng.hf_station.ItemProtocol.item_to_command; + String to_target = this.getDevice().getOpc_server_code() + "." + this.getDevice().getOpc_plc_code() + "." + this.getDevice().getDevice_code() + + "." + org.nl.acs.device_driver.hongfeng.hf_station.ItemProtocol.item_to_target; + String to_task = this.getDevice().getOpc_server_code() + "." + this.getDevice().getOpc_plc_code() + "." + this.getDevice().getDevice_code() + + "." + org.nl.acs.device_driver.hongfeng.hf_station.ItemProtocol.item_to_task; + if (appendMessage == null) { + appendMessage = ""; + } + if (instruction != null) { + instruction_num = Integer.parseInt(instruction.getInstruction_code()); + } + String opcservcerid = this.getDevice().getOpc_server_id(); + Server server = ReadUtil.getServer(opcservcerid); + Map itemMap = new HashMap(); + itemMap.put(to_command, 1); + itemMap.put(to_task, instruction_num); + ReadUtil.write(itemMap, server); + + } + + public void executing(Server server, Map itemMap) { + ReadUtil.write(itemMap, server); + } + + public void writing(int type, int command) { + String to_command = this.getDevice().getOpc_server_code() + "." + this.getDevice().getOpc_plc_code() + "." + this.getDevice().getDevice_code() + + "." + org.nl.acs.device_driver.hongfeng.hf_station.ItemProtocol.item_to_command; + String to_target = this.getDevice().getOpc_server_code() + "." + this.getDevice().getOpc_plc_code() + "." + this.getDevice().getDevice_code() + + "." + org.nl.acs.device_driver.hongfeng.hf_station.ItemProtocol.item_to_target; + String to_task = this.getDevice().getOpc_server_code() + "." + this.getDevice().getOpc_plc_code() + "." + this.getDevice().getDevice_code() + + "." + org.nl.acs.device_driver.hongfeng.hf_station.ItemProtocol.item_to_task; + String opcservcerid = this.getDevice().getOpc_server_id(); + Server server = ReadUtil.getServer(opcservcerid); + Map itemMap = new HashMap(); + if (type == 1) { + itemMap.put(to_command, command); + } else if (type == 2) { + itemMap.put(to_target, command); + + } else if (type == 3) { + itemMap.put(to_task, command); + } + ReadUtil.write(itemMap, server); + } + + public void writing(int command) { + String to_command = this.getDevice().getOpc_server_code() + "." + this.getDevice().getOpc_plc_code() + "." + this.getDevice().getDevice_code() + + "." + ItemProtocol.item_to_command; + String opcservcerid = this.getDevice().getOpc_server_id(); + Server server = ReadUtil.getServer(opcservcerid); + Map itemMap = new HashMap(); + itemMap.put(to_command, command); + ReadUtil.write(itemMap, server); + logServer.writeLog("下发电气信号", this.getDevice_code(), "下发信号:" + to_command + "信号值:" + command); + } + + public void writing(String param, String value) { + String to_param = this.getDevice().getOpc_server_code() + "." + this.getDevice().getOpc_plc_code() + "." + this.getDevice().getDevice_code() + + "." + param; + String opcservcerid = this.getDevice().getOpc_server_id(); + Server server = ReadUtil.getServer(opcservcerid); + Map itemMap = new HashMap(); + itemMap.put(to_param, value); + ReadUtil.write(itemMap, server); + logServer.writeLog("下发电气信号", this.getDevice_code(), "下发信号:" + to_param + "信号值:" + value); + } + + public synchronized boolean finish_instruction() throws Exception { + instructionService.finish(inst); + return true; + } + + public synchronized void OpenOrClose(String type) { + + //进入区域 +// if ("1".equals(type)) { +// writing(5); +// } else { +// //离开区域 +// writing(6); +// } + } + + + @Override + public String toString() { + return ""; + } + + @Override + public JSONObject getDeviceStatusName() { + JSONObject jo = new JSONObject(); + String mode = ""; + String action = ""; + String io_action = ""; + String move = ""; + String status = ""; + if (this.getMode() == 0) { + mode = "脱机"; + } else if (this.getMode() == 1) { + mode = "单机"; + } else if (this.getMode() == 2) { + mode = "待机"; + } else if (this.getMode() == 3) { + mode = "人工排产确认"; + } else if (this.getMode() == 4) { + mode = "工单完成"; + } else if (this.getMode() == 5) { + mode = "工单强制完成"; + } else if (this.getMode() == 6) { + mode = "呼叫空盅"; + } else if (this.getMode() == 7) { + mode = "满盅入库"; + } else if (this.getMode() == 8) { + mode = "叫料"; + } + + if (this.getStatus() == 1) { + status = "待机"; + } else if (this.getStatus() == 2) { + status = "生产中"; + } else { + status = "故障"; + } + + if (this.getAction() == 1) { + action = "允许取货"; + } else if (this.getAction() == 2) { + action = "允许放货"; + } else if (this.getAction() == 3) { + action = "允许取放"; + } + + if (this.getIo_action() == 1) { + io_action = "允许进入"; + } else if (this.getIo_action() == 2) { + io_action = "允许离开"; + } else if (this.getIo_action() == 3) { + io_action = "允许进出"; + } + + if (this.getMove() == 0) { + move = "无货"; + } else if (this.getMove() == 1) { + move = "有货"; + } else if (this.getMove() == 2) { + move = "有托盘有货"; + } + + jo.put("device_name", this.getDevice().getDevice_name()); + jo.put("mode", mode); + jo.put("move", move); + jo.put("action", action); + jo.put("io_action", io_action); + jo.put("hasGoods", this.getHasGoods()); + jo.put("isOnline", this.getIsonline()); + jo.put("error", this.getError()); + jo.put("status", status); + jo.put("message", this.getMessage()); + jo.put("task", this.getTask()); + return jo; + } + + @Override + public void setDeviceStatus(JSONObject data) { + + } + + /** + * 工单完成 + * + * @param + */ + public synchronized boolean finish() { + Date date = new Date(); + if (date.getTime() - this.instruction_finished_time.getTime() < (long) this.instruction_require_time_out) { + log.trace("触发时间因为小于{}毫秒,而被无视", this.instruction_finished_time); + return false; + } else { + logServer.deviceInfo("反馈工单状态", this.getDevice_code(), "开始反馈设备完成状态!"); + this.instruction_finished_time = date; + ProduceshiftorderDto dto = produceshiftorderService.findByCode(order); + JSONObject json = new JSONObject(); + json.put("device_code", device_code); + json.put("order_code", order); + json.put("ext_order_id", dto.getExt_order_id()); + json.put("qty", current_order_num); + json.put("type", "3"); + JSONObject resp = acsToWmsService.feedbackOrderStatus(json); + if (StrUtil.equals(resp.getString("status"), "200")) { + dto.setOrder_status("2"); + dto.setUpdate_time(DateUtil.now()); + produceshiftorderService.update(dto); + this.writing(4); + this.setFinishRequireSucess(true); + logServer.deviceInfo("反馈工单状态", this.getDevice_code(), "反馈设备完成状态成功!"); + } + return true; + } + } + + /** + * 人工排产确认 + * + * @param + */ + public synchronized boolean enterOrder() { + Date date = new Date(); + if (date.getTime() - this.instruction_require_time.getTime() < (long) this.instruction_require_time_out) { + log.trace("触发时间因为小于{}毫秒,而被无视", this.instruction_require_time_out); + return false; + } else { + logServer.deviceInfo("人工排产确认", this.getDevice_code(), "开始人工排产确认!"); + this.instruction_require_time = date; + ProduceshiftorderDto dto = produceshiftorderService.findByCode(order); + JSONObject json = new JSONObject(); + json.put("device_code", device_code); + json.put("material_code", dto.getMaterial_code()); + json.put("ext_order_id", dto.getExt_order_id()); + json.put("order_code", order); + JSONObject resp = acsToWmsService.orderConfirm(json); + if (StrUtil.equals(resp.getString("status"), "200")) { + dto.setOrder_status("1"); + dto.setUpdate_time(DateUtil.now()); + produceshiftorderService.update(dto); + this.setRequireSucess(true); + this.writing(8); + this.writing(8); + logServer.deviceInfo("人工排产确认", this.getDevice_code(), "人工排产确认成功!"); + } + return true; + } + } + + +} diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_station_two/ItemProtocol.java b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_station_two/ItemProtocol.java new file mode 100644 index 0000000..cef551c --- /dev/null +++ b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_station_two/ItemProtocol.java @@ -0,0 +1,212 @@ +package org.nl.acs.device_driver.hongfeng.hf_station_two; + +import lombok.extern.slf4j.Slf4j; + +import cn.hutool.core.util.StrUtil; +import lombok.Data; +import org.nl.acs.device.device_driver.standard_inspect.ItemDto; + + +import java.util.ArrayList; +import java.util.List; + +@Slf4j +@Data +public class ItemProtocol { + + //心跳 + public static String item_heartbeat = "heartbeat"; + //工作模式 + public static String item_mode = "mode"; + //光电信号 + public static String item_move = "move"; + //释放信号 + public static String item_action = "action"; + //进出信号 + public static String item_ioaction = "ioaction"; + //报警信号 + public static String item_error = "error"; + //任务号 + public static String item_task = "task"; + //设备状态 + public static String item_status = "status"; + //当前工单数量 + public static String item_current_order_num = "current_order_num"; + //工单号 + public static String item_order = "order"; + //物料号 + public static String item_material_code = "material_code"; + //条码 + public static String item_barcode = "barcode"; + //重量 + public static String item_weight = "weight"; + //产品编号 + public static String item_product_code="product_code"; + //托盘砖数量 + public static String item_number ="number"; + + + + //下发命令 + public static String item_to_command = "to_command"; + //下发目标站 + public static String item_to_target = "to_target"; + //下发任务号 + public static String item_to_task = "to_task"; + //故障代码 + public static String item_to_error = "to_error"; + //当前工单数量 + public static String item_to_order_num = "to_order_num"; + //物料号 + public static String item_to_material_code = "to_material_code"; + //产品编号 + public static String item_to_product_code = "to_product_code"; + //工单号 + public static String item_to_order = "to_order"; + //A长边 + public static String item_to_a = "to_a"; + //B短边 + public static String item_to_b = "to_b"; + //H梯形高 + public static String item_to_h = "to_h"; + //W厚度 + public static String item_to_w = "to_w"; + //托盘砖数量 + public static String item_to_number = "to_number"; + + + Boolean isonline; + + private HfStationTwoDeviceDriver driver; + + public ItemProtocol(HfStationTwoDeviceDriver driver) { + this.driver = driver; + } + + public int getHeartbeat() { + return this.getOpcIntegerValue(item_heartbeat); + } + + public int getMode() { + return this.getOpcIntegerValue(item_mode); + } + + public int getMove() { + return this.getOpcIntegerValue(item_move); + } + + public int getAction() { + return this.getOpcIntegerValue(item_action); + } + + public int getIoAction() { + return this.getOpcIntegerValue(item_ioaction); + } + + public int getError() { + return this.getOpcIntegerValue(item_error); + } + + public int getTask() { + return this.getOpcIntegerValue(item_task); + } + + public int getStatus() { + return this.getOpcIntegerValue(item_status); + } + + public int getNumber() { + return this.getOpcIntegerValue(item_number); + } + + public int getProduct_code() { + return this.getOpcIntegerValue(item_product_code); + } + + public int getCurrent_order_num() { + return this.getOpcIntegerValue(item_current_order_num); + } + + public String getOrder() { + return this.getOpcStringValue(item_order); + } + + public int getBarcode() { + return this.getOpcIntegerValue(item_barcode); + } + + public int getWeight() { + return this.getOpcIntegerValue(item_weight); + } + + public String getMaterial_code() { + return this.getOpcStringValue(item_material_code); + } + + //是否有货 + public int hasGoods(int move) { + return move; + } + + + public int getOpcIntegerValue(String protocol) { + Integer value = this.driver.getIntegeregerValue(protocol); + if (value == null) { +// log.error(this.getDriver().getDeviceCode() + ":protocol " + protocol + " 信号同步异常!"); + setIsonline(false); + } else { + setIsonline(true); + return value; + } + return 0; + } + + public String getOpcStringValue(String protocol) { + String value = this.driver.getStringValue(protocol); + if (StrUtil.isEmpty(value)) { + + } else { + return value; + } + return ""; + } + + public static List getReadableItemDtos() { + ArrayList list = new ArrayList(); + list.add(new ItemDto(item_heartbeat, "心跳", "DB101.B0")); + list.add(new ItemDto(item_mode, "工作模式", "DB101.B1")); + list.add(new ItemDto(item_move, "光电信号", "DB101.B2")); + list.add(new ItemDto(item_action, "取放信号", "DB101.B3")); + list.add(new ItemDto(item_ioaction, "进出信号", "DB101.B4")); + list.add(new ItemDto(item_error, "报警信号", "DB101.B5")); + list.add(new ItemDto(item_task, "任务号", "DB101.D6")); + list.add(new ItemDto(item_status, "设备状态", "DB101.B10")); + list.add(new ItemDto(item_current_order_num, "当前工单数量", "DB101.D12")); + list.add(new ItemDto(item_order, "工单号", "DB200.STRING20.50")); + list.add(new ItemDto(item_barcode, "条码", "DB200.STRING72.50")); + list.add(new ItemDto(item_material_code, "物料号", "DB200.B72")); + list.add(new ItemDto(item_product_code,"产品编号","DB200.B124")); + list.add(new ItemDto(item_number,"托盘砖数量","DB200.B16")); + return list; + } + + public static List getWriteableItemDtos() { + ArrayList list = new ArrayList(); + list.add(new ItemDto(item_to_command, "作业命令", "DB201.W0")); + list.add(new ItemDto(item_to_target, "目标站", "DB201.W2")); + list.add(new ItemDto(item_to_task, "任务号", "DB201.D4")); + list.add(new ItemDto(item_to_error, "故障代码", "DB201.B8")); + list.add(new ItemDto(item_to_order_num, "工单数量", "DB201.D10")); + list.add(new ItemDto(item_to_material_code, "下发物料号", "DB201.STRING14.50")); + list.add(new ItemDto(item_to_order, "工单号", "DB201.STRING66.50")); + list.add(new ItemDto(item_to_a, "A长边", "DB201.W118")); + list.add(new ItemDto(item_to_b, "B短边", "DB201.W120")); + list.add(new ItemDto(item_to_h, "H梯形高", "DB201.W122")); + list.add(new ItemDto(item_to_w, "W厚度", "DB201.W124")); + list.add(new ItemDto(item_to_number, "托盘砖数量", "DB201.W126")); + list.add(new ItemDto(item_to_product_code, "产品编号", "DB201.W128")); + return list; + } + +} + diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_two_rgv/ItemProtocol.java b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_two_rgv/ItemProtocol.java index b6d9651..ff48fe2 100644 --- a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_two_rgv/ItemProtocol.java +++ b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/hongfeng/hf_two_rgv/ItemProtocol.java @@ -115,7 +115,7 @@ public class ItemProtocol { public int getOpcIntegerValue(String protocol) { Integer value = this.driver.getIntegeregerValue(protocol); if (value == null) { - log.error(this.getDriver().getDeviceCode() + ":protocol " + protocol + " 信号同步异常!"); +// log.error(this.getDriver().getDeviceCode() + ":protocol " + protocol + " 信号同步异常!"); setIsonline(false); } else { setIsonline(true); diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/ext/wms/service/AcsToWmsService.java b/acs/nladmin-system/src/main/java/org/nl/acs/ext/wms/service/AcsToWmsService.java index 1169942..bbf48bc 100644 --- a/acs/nladmin-system/src/main/java/org/nl/acs/ext/wms/service/AcsToWmsService.java +++ b/acs/nladmin-system/src/main/java/org/nl/acs/ext/wms/service/AcsToWmsService.java @@ -47,4 +47,26 @@ public interface AcsToWmsService { * @return */ JSONObject updateBarcode(JSONObject param); + + /** + * 组盘信息上报 + * @param param + * @return + */ + JSONObject uploadPalletizing(JSONObject param); + + /** + * 更新托盘状态 + * @param param + * @return + */ + JSONObject updateKiln(JSONObject param); + + /** + * 查找出窑缓存区托盘 + * @param param + * @return + */ + JSONObject findVehicle(JSONObject param); + } diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/ext/wms/service/impl/AcsToWmsServiceImpl.java b/acs/nladmin-system/src/main/java/org/nl/acs/ext/wms/service/impl/AcsToWmsServiceImpl.java index 3eb4332..ae6ca7e 100644 --- a/acs/nladmin-system/src/main/java/org/nl/acs/ext/wms/service/impl/AcsToWmsServiceImpl.java +++ b/acs/nladmin-system/src/main/java/org/nl/acs/ext/wms/service/impl/AcsToWmsServiceImpl.java @@ -172,4 +172,79 @@ public class AcsToWmsServiceImpl implements AcsToWmsService { } } + @Override + public JSONObject uploadPalletizing(JSONObject param) { + String url = ""; + try { + String wmsUrl = paramService.findByCode(AcsConfig.WMSURL).getValue(); + AddressDto addressDto = addressService.findByCode("uploadPalletizing"); + String methods_url = addressDto.getMethods_url(); + url = wmsUrl + methods_url; + HttpResponse result = + HttpRequest + .post(url) + .body(JSON.toJSONString(param)) + .execute(); + JSONObject jsonObject = JSONObject.parseObject(result.body()); + logServer.acsToLms("组盘信息上报", url, String.valueOf(param), jsonObject.getString("status"), jsonObject.getString("message")); + return jsonObject; + } catch (Exception e) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("status", "400"); + jsonObject.put("message", e.getMessage()); + logServer.acsToLms("组盘信息上报", url, String.valueOf(param), jsonObject.getString("status"), jsonObject.getString("message")); + return jsonObject; + } + } + + @Override + public JSONObject updateKiln(JSONObject param) { + String url = ""; + try { + String wmsUrl = paramService.findByCode(AcsConfig.WMSURL).getValue(); + AddressDto addressDto = addressService.findByCode("updateKiln"); + String methods_url = addressDto.getMethods_url(); + url = wmsUrl + methods_url; + HttpResponse result = + HttpRequest + .post(url) + .body(JSON.toJSONString(param)) + .execute(); + JSONObject jsonObject = JSONObject.parseObject(result.body()); + logServer.acsToLms("更新托盘状态", url, String.valueOf(param), jsonObject.getString("status"), jsonObject.getString("message")); + return jsonObject; + } catch (Exception e) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("status", "400"); + jsonObject.put("message", e.getMessage()); + logServer.acsToLms("更新托盘状态", url, String.valueOf(param), jsonObject.getString("status"), jsonObject.getString("message")); + return jsonObject; + } + } + + @Override + public JSONObject findVehicle(JSONObject param) { + String url = ""; + try { + String wmsUrl = paramService.findByCode(AcsConfig.WMSURL).getValue(); + AddressDto addressDto = addressService.findByCode("findVehicle"); + String methods_url = addressDto.getMethods_url(); + url = wmsUrl + methods_url; + HttpResponse result = + HttpRequest + .post(url) + .body(JSON.toJSONString(param)) + .execute(); + JSONObject jsonObject = JSONObject.parseObject(result.body()); + logServer.acsToLms("查找出窑缓存区托盘", url, String.valueOf(param), jsonObject.getString("status"), jsonObject.getString("message")); + return jsonObject; + } catch (Exception e) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("status", "400"); + jsonObject.put("message", e.getMessage()); + logServer.acsToLms("查找出窑缓存区托盘", url, String.valueOf(param), jsonObject.getString("status"), jsonObject.getString("message")); + return jsonObject; + } + } + } diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/ext/wms/service/impl/WmsToAcsServiceImpl.java b/acs/nladmin-system/src/main/java/org/nl/acs/ext/wms/service/impl/WmsToAcsServiceImpl.java index 53eb802..ee87eb2 100644 --- a/acs/nladmin-system/src/main/java/org/nl/acs/ext/wms/service/impl/WmsToAcsServiceImpl.java +++ b/acs/nladmin-system/src/main/java/org/nl/acs/ext/wms/service/impl/WmsToAcsServiceImpl.java @@ -191,7 +191,14 @@ public class WmsToAcsServiceImpl implements WmsToAcsService { String order_code = order.getString("order_code"); String qty = order.getString("qty"); String material_code = order.getString("material_code"); + String material_name = order.getString("material_name"); String device_code = order.getString("device_code"); + String a=order.getString("a"); + String b=order.getString("b"); + String h=order.getString("h"); + String w=order.getString("w"); + String product_code=order.getString("product_code"); + String number=order.getString("number"); if (StrUtil.isEmpty(ext_order_id)) { throw new WDKException("工单外部标识不能为空"); } @@ -220,10 +227,16 @@ public class WmsToAcsServiceImpl implements WmsToAcsService { dto.setQty(new BigDecimal(qty)); dto.setExt_order_id(ext_order_id); dto.setMaterial_code(material_code); - dto.setMaterial_name(""); + dto.setMaterial_name(material_name); dto.setDevice_code(device_code); dto.setCreate_by("lms"); dto.setUpdate_by("lms"); + dto.setA(a); + dto.setB(b); + dto.setH(h); + dto.setW(w); + dto.setProduct_code(product_code); + dto.setNumber(number); produceshiftorderService.create(dto); } JSONObject resultJson = new JSONObject(); diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/opc/OpcServerServiceImpl.java b/acs/nladmin-system/src/main/java/org/nl/acs/opc/OpcServerServiceImpl.java new file mode 100644 index 0000000..7ad1c7e --- /dev/null +++ b/acs/nladmin-system/src/main/java/org/nl/acs/opc/OpcServerServiceImpl.java @@ -0,0 +1,193 @@ +package org.nl.acs.opc; + +import cn.hutool.core.util.StrUtil; +import org.jinterop.dcom.common.JIException; +import org.nl.acs.auto.initial.ApplicationAutoInitial; +import org.nl.acs.device_driver.driver.ItemValue; +import org.nl.modules.common.exception.BadRequestException; +import org.openscada.opc.lib.common.NotConnectedException; +import org.openscada.opc.lib.da.Group; +import org.openscada.opc.lib.da.Server; +import org.openscada.opc.lib.da.UnknownGroupException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.net.UnknownHostException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * @author ldjun + * @version 1.0 + * @date 2023年02月01日 11:27 + * @desc desc + */ +@Service +public class OpcServerServiceImpl implements OpcServerService, ApplicationAutoInitial { + + private static final Logger log = LoggerFactory.getLogger(OpcServerServiceImpl.class); + @Autowired + OpcServerManageService opcServerManageService; + Map opcServerManageDtos = new HashMap(); + Map servers = Collections.synchronizedMap(new HashMap()); + Map groups = Collections.synchronizedMap(new HashMap()); + + public OpcServerServiceImpl() {} + + @Override + public void autoInitial() throws Exception { + this.reload(); + if (OpcConfig.auto_start_opc) { + Thread t = + new Thread() { + public void run() { + Iterator var1 = OpcServerServiceImpl.this.opcServerManageDtos.values().iterator(); + + while (var1.hasNext()) { + OpcServerManageDto dto = (OpcServerManageDto) var1.next(); + + try { + OpcServerServiceImpl.this.getServer(dto.getOpc_code()); + OpcServerServiceImpl.log.info("加载opc server {}", dto.getOpc_code()); + } catch (Exception var4) { + OpcServerServiceImpl.log.warn("启动无法载入servers", var4); + } + } + } + }; + t.start(); + } + } + + public synchronized void reload() { + this.opcServerManageDtos = this.opcServerManageService.queryAllServerMap(); + this.opcServerManageDtos = Collections.synchronizedMap(this.opcServerManageDtos); + } + + public Group getServer(String code) { + synchronized(this.buildLock(code)) { + Group group = null; +// group = (Group)this.groups.get(code); +// if (group != null) { +// label68: { +// Group var10000; +// try { +// if (!group.isActive()) { +// break label68; +// } +// +// var10000 = group; +// } catch (JIException var14) { +// log.error(code, var14); +// break label68; +// } +// +// return var10000; +// } +// } + + Server server = (Server)this.servers.get(code); + boolean needcreate = false; + String groupName = code; + if (server == null) { + needcreate = true; + } else { + try { + group = server.findGroup(groupName); + } catch (UnknownHostException | JIException | UnknownGroupException | NotConnectedException | IllegalArgumentException var13) { + log.error(code, var13); + needcreate = true; + } + } + + if (needcreate) { + OpcServerManageDto dto = (OpcServerManageDto)this.opcServerManageDtos.get(code); + if (dto == null) { + throw new BadRequestException(code + "{} 不存在"); + } + + if (server == null) { + server = OpcServerUtl.getServerWithOutException(dto.getOpc_host(), StrUtil.trim(dto.getCls_id()), dto.getUser(), dto.getPassword(), StrUtil.trim(dto.getDomain())); + } + + try { + group = server.addGroup(groupName); + } catch (Exception var12) { + this.clearServer(code); + ThreadUtl.sleep(5000L); + log.warn("获取opc出错重新获取", code, var12); + server = OpcServerUtl.getServerWithOutException(dto.getOpc_host(), StrUtil.trim(dto.getCls_id()), dto.getUser(), dto.getPassword(), StrUtil.trim(dto.getDomain())); + + try { + group = server.addGroup(groupName); + } catch (Exception var11) { + var11.printStackTrace(); + } + } + + this.servers.put(code, server); + this.groups.put(code, group); + } + + return group; + } + } + + public void clearServer(String code) { + synchronized(this.buildLock(code)) { + try { + Server server = (Server)this.servers.get(code); + server.disconnect(); + } catch (Exception var5) { + } + + this.servers.remove(code); + this.groups.remove(code); + } + } + + public void writeInteger(String code, ItemValue... values) { + try { + Group group = this.getServer(code); + OpcUtl.writeValue(group, values); + } catch (Exception var4) { + this.clearServer(code); + log.warn("写入出错opc server {} 重新加载", code, var4); + ThreadUtl.sleep(5000L); + throw var4; + } + } + + private String buildLock(String key) { + if (StrUtil.isEmpty(key)) { + key = ""; + } + StringBuilder builder = new StringBuilder(); + builder.append("OpcServerService."); + builder.append(key); + String lock = builder.toString().intern(); + return lock; + } + + public void cleanGroups(String opcCode) { + Group group = (Group)this.groups.get(opcCode); + if (group != null) { + Server server = group.getServer(); + + try { + group.remove(); + } catch (JIException var5) { + var5.printStackTrace(); + } + + this.groups.remove(opcCode); + server.disconnect(); + this.servers.remove(opcCode); + } + + } +} diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/opc/OpcUtl.java b/acs/nladmin-system/src/main/java/org/nl/acs/opc/OpcUtl.java index d792a96..c38ba5a 100644 --- a/acs/nladmin-system/src/main/java/org/nl/acs/opc/OpcUtl.java +++ b/acs/nladmin-system/src/main/java/org/nl/acs/opc/OpcUtl.java @@ -230,7 +230,7 @@ public class OpcUtl { }finally{ System.out.println("successNum:"+successNum); System.out.println("errNum:"+errNum); - System.out.println(11); +// System.out.println(11); } } diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/order/service/dto/ProduceshiftorderDto.java b/acs/nladmin-system/src/main/java/org/nl/acs/order/service/dto/ProduceshiftorderDto.java index 946bab9..9bfabbc 100644 --- a/acs/nladmin-system/src/main/java/org/nl/acs/order/service/dto/ProduceshiftorderDto.java +++ b/acs/nladmin-system/src/main/java/org/nl/acs/order/service/dto/ProduceshiftorderDto.java @@ -69,4 +69,22 @@ public class ProduceshiftorderDto implements Serializable { //托盘总量 private String tray_num; + //A长边 + private String a; + + //B短边 + private String b; + + //H梯形高 + private String h; + + //W厚度 + private String w; + + //产品编号 + private String product_code; + + //托盘砖数量 + private String number; + } diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/order/service/impl/ProduceshiftorderServiceImpl.java b/acs/nladmin-system/src/main/java/org/nl/acs/order/service/impl/ProduceshiftorderServiceImpl.java index b369a75..1bdc939 100644 --- a/acs/nladmin-system/src/main/java/org/nl/acs/order/service/impl/ProduceshiftorderServiceImpl.java +++ b/acs/nladmin-system/src/main/java/org/nl/acs/order/service/impl/ProduceshiftorderServiceImpl.java @@ -7,7 +7,9 @@ import cn.hutool.core.util.StrUtil; import lombok.RequiredArgsConstructor; import org.nl.acs.auto.initial.ApplicationAutoInitial; import org.nl.acs.device.service.DeviceExtraService; +import org.nl.acs.device_driver.hongfeng.hf_kiln_manipulator.HfKilnManipulatorDeviceDriver; import org.nl.acs.device_driver.hongfeng.hf_station.HfStationDeviceDriver; +import org.nl.acs.device_driver.hongfeng.hf_station_two.HfStationTwoDeviceDriver; import org.nl.acs.device_driver.hongfeng.hf_two_rgv.HfTwoRGVDeviceDriver; import org.nl.acs.ext.wms.service.AcsToWmsService; import org.nl.acs.opc.Device; @@ -151,6 +153,58 @@ public class ProduceshiftorderServiceImpl implements ProduceshiftorderService, A hfStationDeviceDriver.writing("to_product_number", dto.getMaterial_code()); hfStationDeviceDriver.writing("to_command", "3"); hfStationDeviceDriver.writing("to_command", "3"); + //压力机下发工单同时下发到关联的码盘工位 + String device_code=hfStationDeviceDriver.getExtraValue().get("link_device_code").toString(); + Device linkDevice = deviceAppService.findDeviceByCode(device_code); + if (ObjectUtil.isNotEmpty(linkDevice)&&linkDevice.getDeviceDriver() instanceof HfStationTwoDeviceDriver) { + HfStationTwoDeviceDriver hfStationTwoDeviceDriver = (HfStationTwoDeviceDriver) linkDevice.getDeviceDriver(); + if (StrUtil.isNotBlank(hfStationTwoDeviceDriver.getOrder())) { + throw new BadRequestException("设备正在生产"); + } + hfStationTwoDeviceDriver.writing("to_order", dto.getOrder_code()); + hfStationTwoDeviceDriver.writing("to_order_num", String.valueOf(dto.getQty())); + hfStationTwoDeviceDriver.writing("to_a", dto.getA()); + hfStationTwoDeviceDriver.writing("to_b", dto.getB()); + hfStationTwoDeviceDriver.writing("to_h", dto.getH()); + hfStationTwoDeviceDriver.writing("to_w", dto.getW()); + hfStationTwoDeviceDriver.writing("to_number", dto.getNumber()); + hfStationTwoDeviceDriver.writing("to_product_code", dto.getProduct_code()); + hfStationTwoDeviceDriver.writing("to_order", dto.getOrder_code()); + hfStationTwoDeviceDriver.writing("to_order_num", String.valueOf(dto.getQty())); + hfStationTwoDeviceDriver.writing("to_a", dto.getA()); + hfStationTwoDeviceDriver.writing("to_b", dto.getB()); + hfStationTwoDeviceDriver.writing("to_h", dto.getH()); + hfStationTwoDeviceDriver.writing("to_w", dto.getW()); + hfStationTwoDeviceDriver.writing("to_number", dto.getNumber()); + hfStationTwoDeviceDriver.writing("to_product_code", dto.getProduct_code()); + hfStationTwoDeviceDriver.writing("to_command", "3"); + hfStationTwoDeviceDriver.writing("to_command", "3"); + } + }else if (device.getDeviceDriver() instanceof HfStationTwoDeviceDriver) { + HfStationTwoDeviceDriver hfStationTwoDeviceDriver = (HfStationTwoDeviceDriver) device.getDeviceDriver(); + if (StrUtil.isNotBlank(hfStationTwoDeviceDriver.getOrder())) { + throw new BadRequestException("设备正在生产"); + } + hfStationTwoDeviceDriver.writing("to_order", dto.getOrder_code()); + hfStationTwoDeviceDriver.writing("to_order_num", String.valueOf(dto.getQty())); + hfStationTwoDeviceDriver.writing("to_material_code", dto.getMaterial_code()); + hfStationTwoDeviceDriver.writing("to_a", dto.getA()); + hfStationTwoDeviceDriver.writing("to_b", dto.getB()); + hfStationTwoDeviceDriver.writing("to_h", dto.getH()); + hfStationTwoDeviceDriver.writing("to_w", dto.getW()); + hfStationTwoDeviceDriver.writing("to_number", dto.getNumber()); + hfStationTwoDeviceDriver.writing("to_product_code", dto.getProduct_code()); + hfStationTwoDeviceDriver.writing("to_order", dto.getOrder_code()); + hfStationTwoDeviceDriver.writing("to_order_num", String.valueOf(dto.getQty())); + hfStationTwoDeviceDriver.writing("to_material_code", dto.getMaterial_code()); + hfStationTwoDeviceDriver.writing("to_a", dto.getA()); + hfStationTwoDeviceDriver.writing("to_b", dto.getB()); + hfStationTwoDeviceDriver.writing("to_h", dto.getH()); + hfStationTwoDeviceDriver.writing("to_w", dto.getW()); + hfStationTwoDeviceDriver.writing("to_number", dto.getNumber()); + hfStationTwoDeviceDriver.writing("to_product_code", dto.getProduct_code()); + hfStationTwoDeviceDriver.writing("to_command", "3"); + hfStationTwoDeviceDriver.writing("to_command", "3"); } JSONObject json = (JSONObject) JSONObject.toJSON(dto); wo.insert(json); @@ -312,6 +366,90 @@ public class ProduceshiftorderServiceImpl implements ProduceshiftorderService, A hfStationDeviceDriver.writing("to_product_number", produceshiftorderDto.getMaterial_code()); hfStationDeviceDriver.writing("to_command", "3"); hfStationDeviceDriver.writing("to_command", "3"); + //压力机下发工单同时下发到关联的码盘工位 + String link_device_code=hfStationDeviceDriver.getExtraValue().get("link_device_code").toString(); + Device linkDevice = deviceAppService.findDeviceByCode(link_device_code); + if (linkDevice.getDeviceDriver() instanceof HfStationTwoDeviceDriver) { + HfStationTwoDeviceDriver hfStationTwoDeviceDriver = (HfStationTwoDeviceDriver) linkDevice.getDeviceDriver(); + if (StrUtil.isNotBlank(hfStationTwoDeviceDriver.getOrder())) { + throw new BadRequestException("设备正在生产"); + } + hfStationTwoDeviceDriver.writing("to_order", produceshiftorderDto.getOrder_code()); + hfStationTwoDeviceDriver.writing("to_order_num", String.valueOf(produceshiftorderDto.getQty())); + hfStationTwoDeviceDriver.writing("to_material_code", produceshiftorderDto.getMaterial_code()); + hfStationTwoDeviceDriver.writing("to_a", produceshiftorderDto.getA()); + hfStationTwoDeviceDriver.writing("to_b", produceshiftorderDto.getB()); + hfStationTwoDeviceDriver.writing("to_h", produceshiftorderDto.getH()); + hfStationTwoDeviceDriver.writing("to_w", produceshiftorderDto.getW()); + hfStationTwoDeviceDriver.writing("to_number", produceshiftorderDto.getNumber()); + hfStationTwoDeviceDriver.writing("to_product_code", produceshiftorderDto.getProduct_code()); + hfStationTwoDeviceDriver.writing("to_order", produceshiftorderDto.getOrder_code()); + hfStationTwoDeviceDriver.writing("to_order_num", String.valueOf(produceshiftorderDto.getQty())); + hfStationTwoDeviceDriver.writing("to_material_code", produceshiftorderDto.getMaterial_code()); + hfStationTwoDeviceDriver.writing("to_a", produceshiftorderDto.getA()); + hfStationTwoDeviceDriver.writing("to_b", produceshiftorderDto.getB()); + hfStationTwoDeviceDriver.writing("to_h", produceshiftorderDto.getH()); + hfStationTwoDeviceDriver.writing("to_w", produceshiftorderDto.getW()); + hfStationTwoDeviceDriver.writing("to_number", produceshiftorderDto.getNumber()); + hfStationTwoDeviceDriver.writing("to_product_code", produceshiftorderDto.getProduct_code()); + hfStationTwoDeviceDriver.writing("to_command", "3"); + hfStationTwoDeviceDriver.writing("to_command", "3"); + }else if (linkDevice.getDeviceDriver() instanceof HfStationTwoDeviceDriver) { + HfStationTwoDeviceDriver hfStationTwoDeviceDriver = (HfStationTwoDeviceDriver) linkDevice.getDeviceDriver(); + if (StrUtil.isNotBlank(hfStationTwoDeviceDriver.getOrder())) { + throw new BadRequestException("设备正在生产"); + } + hfStationTwoDeviceDriver.writing("to_order", produceshiftorderDto.getOrder_code()); + hfStationTwoDeviceDriver.writing("to_order_num", String.valueOf(produceshiftorderDto.getQty())); + hfStationTwoDeviceDriver.writing("to_material_code", produceshiftorderDto.getMaterial_code()); + hfStationTwoDeviceDriver.writing("to_a", produceshiftorderDto.getA()); + hfStationTwoDeviceDriver.writing("to_b", produceshiftorderDto.getB()); + hfStationTwoDeviceDriver.writing("to_h", produceshiftorderDto.getH()); + hfStationTwoDeviceDriver.writing("to_w", produceshiftorderDto.getW()); + hfStationTwoDeviceDriver.writing("to_number", produceshiftorderDto.getNumber()); + hfStationTwoDeviceDriver.writing("to_product_code", produceshiftorderDto.getProduct_code()); + hfStationTwoDeviceDriver.writing("to_order", produceshiftorderDto.getOrder_code()); + hfStationTwoDeviceDriver.writing("to_order_num", String.valueOf(produceshiftorderDto.getQty())); + hfStationTwoDeviceDriver.writing("to_material_code", produceshiftorderDto.getMaterial_code()); + hfStationTwoDeviceDriver.writing("to_a", produceshiftorderDto.getA()); + hfStationTwoDeviceDriver.writing("to_b", produceshiftorderDto.getB()); + hfStationTwoDeviceDriver.writing("to_h", produceshiftorderDto.getH()); + hfStationTwoDeviceDriver.writing("to_w", produceshiftorderDto.getW()); + hfStationTwoDeviceDriver.writing("to_number", produceshiftorderDto.getNumber()); + hfStationTwoDeviceDriver.writing("to_product_code", produceshiftorderDto.getProduct_code()); + hfStationTwoDeviceDriver.writing("to_command", "3"); + hfStationTwoDeviceDriver.writing("to_command", "3"); + } + } if (device.getDeviceDriver() instanceof HfStationTwoDeviceDriver) { + HfStationTwoDeviceDriver hfStationTwoDeviceDriver = (HfStationTwoDeviceDriver) device.getDeviceDriver(); + if (StrUtil.isNotBlank(hfStationTwoDeviceDriver.getOrder())) { + throw new BadRequestException("设备正在生产"); + } + hfStationTwoDeviceDriver.writing("to_order", produceshiftorderDto.getOrder_code()); + hfStationTwoDeviceDriver.writing("to_order_num", String.valueOf(produceshiftorderDto.getQty())); + hfStationTwoDeviceDriver.writing("to_material_code", produceshiftorderDto.getMaterial_code()); + hfStationTwoDeviceDriver.writing("to_a", produceshiftorderDto.getA()); + hfStationTwoDeviceDriver.writing("to_b", produceshiftorderDto.getB()); + hfStationTwoDeviceDriver.writing("to_h", produceshiftorderDto.getH()); + hfStationTwoDeviceDriver.writing("to_w", produceshiftorderDto.getW()); + hfStationTwoDeviceDriver.writing("to_number", produceshiftorderDto.getNumber()); + hfStationTwoDeviceDriver.writing("to_product_code", produceshiftorderDto.getProduct_code()); + hfStationTwoDeviceDriver.writing("to_order", produceshiftorderDto.getOrder_code()); + hfStationTwoDeviceDriver.writing("to_order_num", String.valueOf(produceshiftorderDto.getQty())); + hfStationTwoDeviceDriver.writing("to_material_code", produceshiftorderDto.getMaterial_code()); + hfStationTwoDeviceDriver.writing("to_a", produceshiftorderDto.getA()); + hfStationTwoDeviceDriver.writing("to_b", produceshiftorderDto.getB()); + hfStationTwoDeviceDriver.writing("to_h", produceshiftorderDto.getH()); + hfStationTwoDeviceDriver.writing("to_w", produceshiftorderDto.getW()); + hfStationTwoDeviceDriver.writing("to_number", produceshiftorderDto.getNumber()); + hfStationTwoDeviceDriver.writing("to_product_code", produceshiftorderDto.getProduct_code()); + hfStationTwoDeviceDriver.writing("to_command", "3"); + hfStationTwoDeviceDriver.writing("to_command", "3"); + }else if (device.getDeviceDriver() instanceof HfKilnManipulatorDeviceDriver) { + HfKilnManipulatorDeviceDriver hfKilnManipulatorDeviceDriver = (HfKilnManipulatorDeviceDriver) device.getDeviceDriver(); + + hfKilnManipulatorDeviceDriver.writing("to_command", "1"); + hfKilnManipulatorDeviceDriver.writing("to_command", "1"); } } } diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/order/service/wql/order.xls b/acs/nladmin-system/src/main/java/org/nl/acs/order/service/wql/order.xls index 23a5943ef9a2c47015ec648d970a7440b02d93c6..a502c841310f9a2179d0835d72028e91695218b0 100644 GIT binary patch literal 143360 zcmeEv2Ygh;_W#|@CfPs&2{rU3w9vvP1PDb)LJJC^Bs4(?frJ1Fi4Y((Ss+RjgeXNs z9nRCvZIaBZK z-NSE09pCm)!xM_->a7GRzgL7QAtrnfV4D_?R1`a4hTkhHDm3(50KXyt_1E=ZV1eJD z<7CuV5keM1Faqm56v2rQhENTmIzl)?1VRmjnh0SaR}oPu0oiAFcE?6W)kk%2vZQI zA><(BB1}cdLzs>*8({`QK0*P)OoT#&s}aa!7VgCeVKzmXgZs}2tk)9U=OZjYSctF) zVKKrr2ulz=2qVC$5V>6_`Apnri5y6{$g3Va2BO4eM;@1x--@zdd<#=b2;aL04b1Ja z<9%BYU=J$+S6|4?7bTSOs(x2f>^4n4?-!e&b;WBmN0E>=Eks399TF6vGnVx3U0e^>jbOc&%e zM~FfAqwSx3E~Wi5e=6kv(e}^$f3*E)K`!e%8(}iS6a=<^^3>Wt`vmp@{@OqLZ1w?c z|Lh~!2eAD!|2*6;ru`=;1iv@!_1B_y%u_zL)#)`_vAaY++X$lo`}<~dBC~&{na$zxyr<0r|X+BS8M|R7L2a;za{8(lt7LqNL^ng(aVi3x1;I zdX>{C_i-(s*WE}58v1B)?XLXZ%nR=m*Yy0I_E$oJl_w%z3w_pOQ$j)%ixJVjAeH z5A6_0&x$3!dP=+b;tzt4FMT^D8WvXZ=xriweKAZIptdI~E=;*5VahTa&=A11zNGfm zl5-MY?iZ>ptCn%*+J#;<;d#@bO^(nZ9rta&|>if~B zLjZb506gXP@gtY`E&=di0q|Y?=tDlv0Q6A-=xh7Ivo%@m*3{7+y-IDx7NeZ1h{61( z140X|S$ZlGGahRh1KZTmMG3)*$q)HB_*4!i2Ui8i*bR%d2EG~NAS;kGnby>ig5oy~ zoV9Yv8k1>Qpd~1_iEw^dvUY%sk`dn%>m75dciH_>#K1Z+BA3jYEa0Y&(O40-mBIpv zAwG}*rUha>A63*Na5-dg{psp0EHIrE+y^dgaM8*&6)W6$f90~W^DUh}ipoTFLffpX z*v6v^FxOIB)Y5pYxxMk@VeO`l?(ocp{<9c95-4*|cxNMPW=(1TQe~=?-5-)&m1VC? z1B20Vu|1(EKZ<1s8mzeXyNI^|{;?ubQGQU-O67PCzy9b0;mOq>{r_gX4V7kG(w^MP z5%xc?rAT~zM1_6Wk@9l16ZH}eP~g`^Mcq>Umg9-Q!O2_BsO8RbsUblnp|CQIf zuRaX~pVk`xx0Nh_Ad_}zW8f!YW~tjVR>SLZWxM01tGA!G51?lwZ#?qJOUm`tv$r?B zF1J|#e1`yd*-m}!Ci@3px%CAfU%aeGUp{dGe;w&fT@DK zq@NSEVP0v)V=qNH;y`VdL`8y&O9_#F9%|qv{}5U4p_l>+`bDZ-70*qvBM!*b^a+vr zNIXU{3qB0=C!}1JzoeJts%y}z<&u1ao?i66{3C=N$p47Lzg%y;nI5B+A3at3c*&)G zYi|xrw{GpjhE$>cwc=a-d7*uPk7nW;N!0z zW&Qf{k#<0;UM|T;;!!#sFa5!nUgD)4eEr|2U4%&flD?h6U-c`Aci~B%>d$I_sLM@K z@pjpcbUppxk2qqn+2Bnt{SftK!IO{hL%(>`yI(x&%P$^sOSJYV?W4=J;B~ov@xJ~h z>3#hK`|Qx)x4g9H5l34?Pt~5>s6XOx;fbNQo|3<>KTCRFeImfe#%Y75zeA2Y63=#L zi%M45AIkp9!1FnGeTAZz-jbZ@CvcW0l2Tcv%|}@be(ShqUrq>|AA` zWetU($H8$5KueY^;ckw&s`vr0+XOGTTvy&O8*~yI4 z>}1C2x>p?1`T6RJe$b?+P1h2KntbY>J6f_#v^AJk!nc`D>+2_0Tf0CjZ5^Z}bY{P# zU0Pjfao&CPLYuzmGH@5kD1+H2efhT1X?@FJZ5P}nGU~f>J7Nxc(X^PCf|m6gq*V0b z;SlZe)wdmzE>?&3UbGrd-hKIYtc2F;%WrQeJ9ne6GwZ3zHsdteW}GJ5jMLii-FM%u z+tGiUu(qjq=%cl%oLsK0v`fohxsN7*JdiJ0WpxIvCX2OiT$(HcL;teoPZasJ@>h6l zUS(xp<86Cu+v@^~i`BKOkfqu6#czH4bsQwn<@@T|%`1P!mz#B3%}+MxRFcc^wR@0`28qw20`J zuMSrr?P7HpTm{-;RiGVS1=35bJ>oW870ESk;`23{_Us%4CYp#45FtvRaws=uE0$Fe{VXKf=W7v{S*v zzt#N}$F~E@Lw=jzs`u@1r(L3~>6OT`4tg`HK$~9)t+j0w1S~@Ux1OnIu=-1Y4260I zt8WCzP*l|nSL+!rQl(jXh5#yAU2`@vRJo;DU9(u1YE{#}Yg+Tq(eqoizPS8ztC-*F zf+ff=n}$_?-)6+0a$RiSzo-hdiz}hEy7o1owd?ad^H`-ip0$8WDq(J=^;Cg&X(hDQ zN?r!qs`Ou0PhF1um+YyfRaC-Sh-)t~|8-T&Z>^ja$S=K5c&gXVnpM~9t0>Ew|AtG< zzp_gC*V-`;^C%TJI~yuDn`T8en^Iv{k|sRQ;wYqw^n_NdwKvB@DC}D&;FNVM#f9S{ zE~UrBpj9h!MvvRPan>>yev^8$Gr^mcqjg0M9F`88Ly8E)!v*~8WbK-q;Xc~f>p&Z( zXxh~FIG_#o2|OV}E3wO-Scwc@t=d4V%5q3iq4;I5O|gA*)y>Xm?_${+RoIkoIC&KI zsqYCAnncq+U8|%?EHtSshbE$d$0-Wk&=V}~jXYtvhv7HIu-obUS8npPTQ%5?DUwA5 zeu|7AHL+SUI{||)`rQG1fq>m zo_IgyiPXyzPrk?!g%j$!l4RUj@M&xCp=m8u7Zj!Q(M%bIqsU%-62YfA4&hhovDDF8 zb*@UQPSZOAN0#-fW5-}sv6ikP_b6G^=IBx?)rKBm)uuzG+Hm`lti$jddeOi9?5BUJ zEBcq8)&3<6KeY$xww1Rm^l>12J&-a*a;=G$4qw@ycWUa$jK0Hr<=yPG`bvHHijgj} zHOHy9O8e2Se#)7Eat7{4xpgYNCBdj=K18Iq)Wx?`v3d8^v}0=okx_iv9L+17mL6U6 zo|368hT3V}1MDhUjY- zkJUJKBS(9A$8;Z#w#MMd6iM0~PkSpha~D5mj;qwn+|8C|?(S`7w)VRCF^!Lz*?_EO zZsKERtt19Xc+m65x*1qkmP0f2WtD49U$eH`m`b(Q{H{5E z7Fem){#duDRBMfOUHmM`r@GitS*xp+PjzV>R$V38mjyd1D~q;1EVPcPxsp=3?fmt5 z?JBjM!8)~a+xcVNzEaz1tn1?S0Y0{4bFvn^qffz&Ce+VpLL7YAgqq{k5S3Q9zb4zM zQk6A%&GBjuuns)c^2gc@)|KUu{$Cd_Pw}w^`*5o@;(e@P^xJ9P)?mNg94}+3)EfTA ziO!W;LzCAW?|7-y8va-(R%#86bp&1=qt7#0sZn^3j6U;VO>^ea0KZ|brp+Wfi|VHf zXl{^B?c`L|JJBGD!YgTXwux%aDExj#M{@k5tSG#+#tX@LUIcz*s;k*uP-PfY-F1GM z-bmI<6kd9x^CP7cGRhm-MVaiZhd>{ZS3M0-HaOQtY%rxTVb~Qxj%tEpMf%BP0jOVm zT2`EwQ;^dsFbz+*N*aT*4scF|+-A(*P>;JETwn4;i{cCOLaf{yd?VNM{cZrY|z2k!xy)Br~KLn9{t$$ z?xXGBY5r}8k0(6Va{6T}2aZ1d*15JP`+wQKbv1j^Z#EXtP`g+CuP)n$(m&KlzGKNp z?RYBu_1K|>jl0x&rp0$n?tg5@`$OiwmH+mT^&fxL_3-u^_k4Iq)2AN(M}ux#zB_of z^~a5-uSrWQTei=2^(P+B;wwj)N_MwM76CZq_%idAFp0tf!G~0IUbpD(t zW;FeWr^7V`wqwtHaOI5iB|$ed7*ey|;SaX`c1`+IrGt|`yr=ZRphZt@IPlNdvg;CF zPh1%`bbb9fS8ZP9c;Skx4#oCzG+cK)bo>vtdnQJYO6)&W%exTbD+HG>;(@_T=dJ&FLeIl=NI1kWZ)ZXn*CPv>-q1#yYt(Q z9Scv?NN+Lk#C;F;`RTV;YaS_l?UUz&zM1uUkMWsT zp4k4`sg3iKhTJ**v+OTUo{jH)|H+SExaXh8{*kzR`sMef&7FMm`o~@>y0@s`h&#%+ zd=grknK$omBi`8cL}H!s-(R14uI(3DS5CXRd6W4^5+^>=xAvJ=@4r0x%-^Tp_VL1< z2ga^{_rp&Q4@@1EHLCfqCK@!M#s>JN)EhzkD^l=#~Ln(*C6!>6|hA#H)=;7k<}s z<3nMsx4)gd^xP|RQs3%x-^Y6oKJ&oGKjrQX9yf91_g`(^d348#^mjjxt3UbYZ#%v9 zVacX%q7JTl;i)eQ)?YL3?&TGW*7xrCw@%M=edE>m%;_K3{otDqe>i#lu^T=-aPs<~ zbI@C>uQ9;dk!qKK$_454!K0vF-KO9+=s$^Qj}BjJo&!A^GXwW_>@ROLT_^ z!WP$9_KoxYCqo7A6*`{dCQ6Tm-l};;_n+a_AhEyx80-zzaN^?b!_i*x%Uk_G;~>y zk5-L&qEqZw?<^gh_UMf{`F#%zKGl5xh}T|z<(W4f4^P-&ulvsFMI-Lt)z|&&;fxQktFktUN9g}re=ewH}ZOg7PGIr&(qxBD`Zv4P@#Qxqh?ueA& zc}G8c#nwpgo(*ua6x# z{?@S%4g9ox_qJV2XDleJIV^nJ%zFn-2nqjY%CA3tJ3r*cn2$f*_tR%1_sshC(e7vF z&FkIu)|9r-)VS@s?Yoz>z2l(`$9_8cWA6Ni&OLs^>Fej;_D<}clZmbd5b zPI+JL>He?x=Ra0*>x-{<{ObJ=R^L8-`kAj@u5<0SL08`uzdC;6n;#9Gu;>S+@lz4E zbjsL%*WCrlw=KEA$UbpaPX25$vKs^6-S6)B=i?ZsyV~T72qjG%DX(4g#`FX3@D<-) z`_%Fyi-*5?AiCAuPIs60?R4j2s~jawQV?>hLcAM1^HuUpoxH9KFf zc=&+((3YXkE_txSss4_c-PR4B_G$LEot-|(c&dD7&b@CpJ^bjtpWc;YyZ;GJEz6X| zpGhK)l>hBP&^3Zd+W4inPGnSb4XO5=yH4r3W%Hbcg>O9`c~k3;%ML&Ac2Mc3T_U>n zX*v9>uOoJKaK^2e^z^OMp19@qmupW>_(y!+y$zi`K3{+Jre_QGeYHAyM7{Lu-|snP zch<7ih26fcJN2e3Vu!SDIU+VLe&ehfZ7yHC`S1;yKY4Z~-MMDer!jYKPdWI+;k0ve z7H|FTHrt{XT0WH>x$qsO!G>X*DjxnVsp0igJ2k6!)$hYoX1{-JaO@o~9y;FQwtELV zUK#iJN%)$#Jpdy<{4K413I>X+_VwEy6(E$h8}bkB~FznmNVW@hS6SH1iW?|<^xKTF2% zI`_%exzTI?mHGL|33=B}S^UY)`+oT4v$jvX(=L8k(DF9-|6p4?;k{expZYA)-S+eC znV)az{!xRq`DgLltmta<*yFWXgI_T{Sk3&%};=)1W+UvYik{rgXUZu42^@>QLG zuQ@-gXV}J{3cnmW> zw@_;{WgaQ?cRi2r!iyJ17IKz$1k+!7V@^9;QXkuq%Q^C5Pc?e;>52 zxa!Qi3h#znWm=X&5#>f_7X+rti;v6k*bKX&utB&Ilq}HLcm$jx;RaX;mfHenv@s(r zCoX0LFXg@W-m757C+(}9W0ch?kz zzYfEzw&vn>T*W4e!N5($3*(Bh>D*OW1tBrouT8iZ@Ct~7oW0#affY1&g8rwR@TTR?iN01 z2CgV)=H!KoR*oia^DPqhNxH41`E=rHC{1o7F36Tw7PGkSL~_4jJ27_KsjEh2Y=W+v zOuA}%^1cdnHVU6-ZB7K#YNB2FQaS0s52wz2!0J>&&cw26@h-I~xKVp^enkIpTx)WF z7C)-V%gRr~Tkq(K#HHc2d|I4k<)z{O$enpKeuCL0@*|HxdRX~uaqC^ne<8e;E>QeJ zcx$>QSHo9!r|l|B|11+~KI;Lq?GsSjh83+=T&@&5g4+KuGWfk@bHPoQ zr5{MHQ#y6t?ae+(tW$QK!@exC|FEKE<2}pwZF~6nu%s1@T%Op-g5*b{%C2jXG_0TN zqvk1h<^1D@`@6>MeRoT@!l(cF&XvtW4(+kuo0qz)?A4t;+AV5xW#i!yA0OxvKC*h3 z-aEd!YueAZ9Bc7L_qnn|{G$8!n;-pd%GeECRxSIe>+I{!RlHs={qq6U-x#*; z&4i4%pWZa*(OQqa_~V_&9_Seoe(hx`&2C%s#?S}L+Pr_{yK(RC_{sfi>Muo`3l1+o zcGU|*Zuq$VsluimT8-(y{NskTHcx7D=eHjo`S|!}pPc&FHBUbG{2i?x?(xc%pPW5Y z{pa47hxJvepNWQ%mfBJ<7kb7PiN15cEg5hH`Z_1xP2ZsLZLnel0%~nEy7z3wCA#^! zfb%h26d`^Eh6%nDI~Va;xTgSHgjBwHlCNo=2K-F!*shxpJLi{0$FBK#baII@@kqvi zyuDMgkILw_g(1b*7iBNL7H`mf>zdN3h^EcL3wEcvlyeyk@r2M8k0-Hi5wK;xBFCjn z&T}adnJ(qb{D#;b*HOEtxRhImd!d@$h}Z1h=!M!g&ZQ*f3DkTX5%^{XvDHPE*C8^4+R{55#5>S*i}4_2i5Pp{mzQX8UP zx7j#SHLR!xZt{aS*STd0OXqGHHz@tvj8o~ar*~NR;iz`$voYG{;8TogYYX z$SdnH|I|uq-6MTwZo_gy;T1Oy=UblhhUb;_Lqiy>oXuegC7odlt)?3aE*TStjF5a- zo01P}yO(%{p<#S^bV2DmEM&b%ucObsFmd5V z`kazJxQyTRN6_DB(dy}?b7d`hQ?JUbmhR2t{M>aLh*_{;aGBW;@GM@`*Q#;v%&3t` z-+8R)m*E|z&ekV9zz~z<2tzVTH zG9s^xts^q~r*TV$#?CRQx`S%z{OlQ9M=V|wJ12JZ&Jnh(vpEszjQ=!l-2~cCJjIEf z6IMQdBS7+cET`r~91`f1+d2~%($LocrlDWUz~3C;put!kBN&E$54Rzh{{odxcz{H) z5}6kdB>T$;S|lR2y4Fz~yGGI5AKR!)@#!X9e8r`EGCG7w=v7yaX0?^hWuv81v7_0M zvN@j3S-5e=m=iN0pY04cHnK3qR)AOS&KC3XpGS9?%65h>m_76)^vhfdXy{PIHU%Af zf{qZG=UXzPM6q+~l(XfaXP%AMa>~B}$j2L1ZJL^~P`WLSy5ipzLMLw;#|+^WZk)|& z4M$*!Ix3xVgE1B$4_Qpc(7<72mN%1bU{c4M2~P>iR=;xSvax(;YF~W#)>eMVQq^ic zN=A!$X_W|uNH=sUo`6o98ffGNVvs6^xn0N_W`}Ch^09c0c3TJt27_Q6H4FcyTtniLQU0ri!z5Q~6QIsQZ> z2tn~smv5WqLNF2`3ZXVa9R$@N9Dw=aWlO1&Or?UYakx#du(LTKBi@{^35`d!^?-MD z$9FuwHF5AJ8c-{hCI&t}S5$yuzy#Q%EmX85B;a_OOlt0JRl}a~Fut^BN66+8Hmf## zsGF$N9Dg>a>j-)QwQFS9d=3_))1V_}2ZlbKk*6(I(Izit2U|L~XL{WFV0qY$MdM1j z2$n-heT&qVt=Stb3nWS!J7;xz)cDoubc)yJm(FGLtGDD_2AY;M8Yf5e{we>SFXDKKNAteIkkk6i;B7Wix#nju`m{&YS%s~-Yc9um;1 z)qOdz{XTz;w=*3y399b4Ff(|q}n-!eKZt*H} z)@pE@Y8(!%L}uY(!nf#v77e9yNdFQN^Yxtj=0@Qagtm-Z zIg~M*`@z}EmJuR1I3YdG+<2g<^vfmd6QDx}48zODHmtaI_+#VL+T;AkXly>E*1RiV zeaP{g$&G~O!f!gJo8?jehGYHNz**66!`XB$LTC%sdoQ35PfJQ4_HiFpk&z5@NH4zj zMok;lLOJl(S@6QyvU@Q)Gg`aB`fpdB7+T25>`b-&!l$!QIa3knw)C^^va>K6eQ{0^ zKD~y~z?@;K*=HjMDnX7el*Gxo?$w{MJ94B0{{O3%9(=}C~@RYxFcw7*~!*H$A;*`-IZD7NgK3%tnD1dn0HRGLIK#F-g~a#GD)g!_;7x zQyCA=OCq3VHKT=UiVnn(oq>&IG5x01xbUIJ`P3CVM^-x*31X5XC2C4(NmM9+Cow0Q zg>=Uiv*Co3A&^6YbaH+poznU5WdOMXE5r&4?Un$i16nEyZC*Wno3TGHW-v=hSl?&bSnc)?q$CY5O<>;DDx!i*(otszoTRHbUI_20VoB43}iF~9)Zyuy|4b2(e zaP0HfJeN_FW6sCDA(ny9iO9GA@QjIEVE?k@$jVb!%^MzGF;VQ$WlX$s*jKY&T|nCM znR2Irv#QPreGrBqq$8|CfCb5p(^D1X#0j8gEbJUgKB5XZ705@+$x$enzZb+Chis@z zIjz%>$p6xsPjS}rY&yW3C$E{Hf>fsVk}>1JRX*J+3bdQRU5(O>+yLR`7GrWBp;PA0 z5odEGzI1MKcGy&^7dyIR`VZ?<$6q;&F-i!pASJg*xWUDBeMGwC$GBMCXU5Kv7_*UC z$&{9uel{nsjHA+Z>B-sLy?4Y~OVBR;ad7RG*DbH+ zMEr9JABg6aMY`FoaN0Etv|OmpL7Wee`43{b$T<{vE?;LUQEqUdpUPS|GhdBL?d1P>iYd#-1)G1?pFJ$rDjRZ%UO98!_t4oT{y6RSND)i^a2NSh{n>s&SFo{Ml7U<%(<>gNSBx zc3`XUjhkSktHE$SdzWdmZq1=$a64Ivavs8NL=HPFvPwt$`=!(R7nP3Y@Jpv{p@8oB z>wD$l;X#I9y4hl{WHRMGy)twxm*|*XQIol%Vda=~Ltz??_<2IGM+}u*Vac(Xn~I`@ zOy%Mm944b;jC5_A34azf7JnGaPe*jVL-5TVRu{Z84;xiniuHi)XJZCn9dXn(|;?_Qa!`kebKT(aNR_JZE8#fYvi6`{>+y*f@IQ zCWtXld608Q`m>p=K(vn{m|tuC#ilB(fKOki{F*8M>bOG={xTTHg1#@p0SNp|fQO^x z-z7$R{as>pJ0Cd82mYOKZ-o;Ei|696J?HaHSm>lNv$4Z4H3b}nZw33BcocchcW(~K z9@b}~z_%0l_Tqb)z<5BTU9IeV1l_^56e-V&p9IuJe7T@572mBvohz=-`m`~@u{xL2 zeYoi*uhV_D;fKLt&nV-;Y@NHSt5&)DK-VKXfiXbj|(H#aQTmgMZTU2M`qHY5Y_ltwVX<@^K<1 z8tq82;7R9H$b)t80&+?oXhw*6eJ1lU$pRRZ`#D4y_uJ`kvv-oo;>L(@fy!oetFV< zfq2r6l4l#ilkJ~8+vtAL#xGCW`W59>@j0YuAK6}La}8tMWg2b&T7Z141A|_JWcy`Z z91`uf1N3|yqchul9qg0Xl{ZYELuf7R3s_GYheOcxuyO<+$&2-MNR%>8@FE|+RKd#U zJ$Udw4EZ0Ke7P}j{J0T%+iNL%MX!?#j=d0gt;Eq=%=Pta3OF~x3?isC02o(kjgQ@a zD`NLLPvIZJBhc-z8wv&)yNzHpbT;*1G)^|pV7N*Pac>0|V7!f}o?sN7#t4P-EJ!FS zio=5wog2F$C%SK%$%!tQU9D4@>a33dP`xn0;r~wu_2VBh*F-iOms9e@PXanexV89? zY3rnk+~mb>nvi5p*$?;w7m2PD;)<+D~^)~D~?`d z#nFANI1VOO9KFYiV~1tMvBRdHPF$=w`nnaz z3A`1@pF~@6{1Y@QjtdSmj*}2xPh)$T-_*;7yYUGT-5x9T8FV9(h7_d7c$Ilb-{5pB2CF zAqRSyl>_AjqbGU}pD@9Jd%PP!E%^n5-v<1}triPMjFu%odZ<5sAzu8rFTMfiRwRcI z!H+hlej(6rgJ^H$NALE>FVu@4pNMP_oji3975p}+Hey@w$APC+jS}*yzy|d2(#lRR z4s1F8ID~m|;4|qB7;q$qFfR`D9$yZ1K;s|J_U4bCZO$K_Ug-}{PxObUH~GWUWBlRi z@BZ*?i~jKR6n}X7j6XcR#~+>^;tx+>vEtvuqpOW@=i|1P_=!?99?hgG!|+KJpJ-qL zeZEpoa`WKK2jGg0gERCPF$>tJa7u9IImBx!jx({i<8PDB$o?M@(`8qxiF^w3uuYNv z2HbBBmv|fSk#K|MI6plMc)qXEqc~F7V=S@7V)F8g&4w0>cMrj<`ULS@wP!gOAWN51 zm%i9g;Re+tZ01ZsiRNG%sTjDK*g}_AI}Z{_vUlaW@~{v z_Gnh2eZ^4^aZiO9{dOmjMtY9}&k@qDY*kN~XqGy~`;WBgqICoPu${ zrlC0uhlOcVu!f?8L;^a9Akisu-AhLZsnV3GGn#3jDHFNLs|{|PGR!>P4r=fWVtR^j|;@IU|aqRA`ICk|`96Ks2?mu~ऍ+p077jI1~g)m9t_Un`D# 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
    j&KD3^KVUmXOiv;)L`|ByOfJZ$gQ%tR5 zx>`(|#dL?5y2SL9n0AS&W&|&XLOPV5lF0Cb^^{z|{~Y}yF7`e>>WG)8r!+JA;q{bi z`2FXrr~LE%BDo_yeErgX5xm`=-%{$KAKu3iM*bwjdkQ@su)+G&@Ok^MVIx>O+&{7- z2%p=luZZ{M4@E8VKSuwr)>rG+z@y%whkHFRHHoQNO!3|i#N)jnm^O*2Q%nztX{VT; zhjb{t1GY{8KUnVw2K>*_KZ5&F+&6W3dI#=jQ8K*V(GB}wKVQA$pYI=U;m%2 zcf_)KUcTM|?rmt-zgqA3zv?IXA-$we#`HTB+i&Ye>aFSTB>`P!-j(Vq$j7f-U-278 zU-{|$BxPEx*U!gKascjq;`ROK_(>K)`6!Qbd!O?|`pVDQPa+WW6?jUpU-12ZOk*KM zeFg8IMtz0i-|)fr|1l**xUi2{?Dm@S;#GEHqt~SrLZlS{lBi)pt&P-VRMo7AGw2Lj zts|wVR_2Jkox~+%WK2s>w~(lW)Re2DrdmkCjHs*96Q@RzRLj(~xWxE4k~%G8#vQjO z#t}A05<5L5K6YwChU^Yq>FkQC;-ZRB;hy~J zq7tDhqexRxYxB7q!#C=2zc?r)7j9Z&8#6?eRq9XPE2vqeOG#f{9b8pw6MX$+3v4S$ zbp>qCrP*o}<+p4ONL^KHuhOh2zwMs1wDJ`YhVlB`^g_JT$`ltH8%g6M;C|m)nossu zE>-BX8~j+1&UNWy{O9FE=$v2bW!G=f=Vzv;7i1B|Ci zBVMr$VN{7HhA|O?80*$)Q;87+7}sk^yBNP%-XXKdc<|!G``;3Lb=q8#1@EQPj8&Bo zCbi03NtfE}X{4;c0dZ|irNwrK5T`ar(o%=&4Ml{mLQ4s;WRy1TD(b!aZs*ttBMGbJfyusCYIJ_F8ryf#SD0zj-%85Fb7F5xzqOVe`1hqUg zNquX1jGH^ML)SPp?v3yciweT^ z*r_>Yj>??Q0&(*=oev(F*t5|) zIV^Odjlj1uBJ5Lxn+1|PZTQ&Gu%@To&~6Zx-;=S#yTzb1oFU(|7+Mt%8rHNJ991ob zvyb+)7+MU?1{?g`G0sL>45vetcN@-E(DLw2bj}TtclMZ1pV8RtXNYpgr@KEPuRcri zR~55hM}!4#Ele$g(+5j!CTF8gt1ePI3&}1^N@yw>9o_Xk5Pmwl+}wZ=A|qSE?Hh&Rkb`izl=Z(+}db}jO9~lmt{{I5eLy_ zV==sJn^%b3UTeh=xRvJSIJxm7Yd&48{Di!tj6VF}I9b(0>XnKwh4({@)(Kzxly^fY z+%q@C3YM`Q*RKy#SF2Bq->fxY)Y}ckt%i2N0D*2>g!vbBhP>2z!I&&JEScXTB={RL z9~2g85|S5cQWw6iIx1A(-wX|+MvOjNZ|vyQ@A*QfeN`P7ogZdjv-PnhD;^|iHN+Dr zR#9vBk7aRUi6;(izC~!5bYkCCiWK*_QdcTFJ<^6Tu51AmG>wHZr#BU8a_5QDP+9}CNG(lH0hJLkGaAM3>eP^dm`!-;w-g8b^N{kn; zhG?x{UEOfe{QT8A?ZUG1HtM}8fzC25R%6i4T#VYOS4FzC(S(KVq*q__Jv9`WnpM;H zcPi_*SVKRrQdTL;mGKcJN^^`-*?w+)vhsuU-P)(L$;!e*Yi^HG#whL1=iiC>z%NEw z_{6-eD-aW-thzPy_2a+r>-Mv}QLK!M@C#C8e^)nV)tG61L0&=0%1;;j1^rDGG&NbN z2}1If%e6tTB*ch+MJuOIR`$q)ssm#K=M(qziNaU$^GS(8=!yl;dQoBmp?4aKzsM~+ zKI(njGwSMx;*vM0Z*#a8)jT`JVV<|5h*XxQtg_pyDoNbm_L0KWit>`>rU(Lq%_8Iy z8(WL{^T}K>J{YN59mgVK%i<*Jy6a@p*IrDJTWC+Fi*lP#o#_u$J z>J^>uy06S$R8v1D*5Dr@pX;_&F144rb2i8X;m|hOJ<8Oo>NP$AjaRGB?)X!Hb{7j? zOje`70>MKtgdT{5;x0P~iA-6?^W^3uE9BY$p%f!=8mM;CYqR20m*RV;dW>+W(0~N= zrH;)-ORdBR?^^nP(NG&ItC!=oB^J5Dh_7?rBfrg(p*G?hocGA>#1rV&MU8l9(>2i$ zCZny|CFK>i(!%vy)kfiFysBrLeDqSqZKYIQFMoIITd^2W(|XnVfb!bL>g5hOzB*7J zFnX!VzQ(LDXd%LdJWP8=S6*AWs-hw^O@*N?W~<6030)QmQTZye+g7cJr0!?xeafjR z$9d8sD5>>+li`qRp{&d`ikeIijgfewi4)F6Z8n9ycH0aVba#4%LvXqy&Yhzg1AWTk zTHK>Dl{^0!SEeRcUqcOs2%7VK4Q=;*)_0=%aFQ_Qv-tOtXo$bb?H{M`Ipmibsxaqe zRp#5P!y?zwPZg2W(E1A1c3(qd=U%Uue>1_N->3+23Kp6zWR9XTxY>bt;xnFtxRwio z*9r9DvEPh|DixMZ5Y}n4g$Rh~Gq1eVw9&iW=LMfBi)n1I>4M-E+MT{p8_CQlry%__|2Ayo0NN$#!(|5A#IuhwNOk% zn@D-_uB7#ZU2J}k9teiZxD3scC#T<lrqp;(6)&auu*{)v1_5I_4uJhxhQVVuNzVp+IJ_m$k2`YGg!!vPqCk$9poUK5d{ z$Whowy{(_7NiwOCV^Xukp0^Vee=?UX8D!j+_yJEGA+XMp1|f zmMg{w<_Z26{oq!VuO`7|kyaM+@SVd|74|ziCPcUUUKlA?`+3_1s-i{es%Un@V{*0n zctX8=jOp0bEA`n`E*^@|X>DutpFa+Qww)UbAqZCz0YVV28+#}-d8|>LS6mcK;7&^j zHR$582K~HBeO{cU`OSz}`J{x!L7}Fq(LE)KWx8YJOm#qcjBKmCac|E?qj1xW)~Drf z%TAKE(&rZ^&nuawD^gvYa6IRDP9*&}VZ!oR>Q2Q4Wn_;s=8md~cl0P%z7_Xd+Mx5- zEgS2YKee&;P+6Lv@y*Z7JZj&JyQ#jk$X;Z4B8e{D0{UVnITK+yh%o51GAa;Ly9k;T=5xP<7 z_!ZpvqQ`)Gjy8zOKs*8U9AZR0;tfCAZH|{ApdKhDJfa@)gw!LRn0mw$63)L~0WtLi zIVkhhbJLBH!eg47$#h!p7|CPlHTcRK?k7Gxh~5E+qUX5EY|@R6s1I<6k&cR|^@gT9 zQCc5$Z!FyrOH;Oc$9?r)>>guLDcR?}DAyAhOPN9Fi{mN^rmy?8+tnu|(Q%kR&sI$%l&M32!Uq;deFvk=&Q@vLNaL8Q89N??KBA-oi z8QDu0hem}9dd@9{T+2=;ZgNY)APEXac9OQ{Baz;o0bM7 zDFsmEQfW-(RN@n(ig8dqu-?DNm8v>?k7XTJUKhE^uX@CUh}igf53~s+5o(N%@v=nMf#3(bw6CJF6w!p)Jr3hUZ6zsI}f!or(Lnp{r#!nS_Xe>tE zwHh0Ni<&75_m!8NN~%^AGrPejx`3?h@WRUoyD-*Q?g(wnaUZ%)_*^BPxFDW5UNcRH zR1tNGI>jxD^z3R3&qaLO)h&S)Uvy|GmB*;)@t6~`HRDEGRR(jD?+P`g3!o0%$gVr< zUmeguT!Ae@P+;7QNndOTnPf|KDVIF;$WvjF>I74CQ3P6xLgGOTs$IooAv=gc+x~EQx0@ngxgyEQ{<=~_#WOO)I8+>D^v`|9r~_W zaahrLFW3PDW3ppR?O+J1Z5JLa07GI6C;%2!fnZX>({?|msR zA~ba5n7=1golJ&!^KE)coQpqOUi+k?ZF%b}uPj#vx`LMVxS|`QAD9@bcPbo0W>9EQ zvR+tNqL8Pk_H@Q7=9Rx$YMQOC(@;Z=rnvY77v@%NlsTa~q|Fo;NslNVl1FvgS}Xw$ zO@nqmX`3Gv)jH$*3fo%+H_BGNR5!kEeByY&H_Jx(KSIu`F^W^mab?Sw4}G~Lq)oo> z@XBfG`@QQ_Z88>->FT`nkGt0;@}GQZ+F3xU8&kAfdZ zjIBgGFFH9exHYKwg!JA|r%0m8FyP@S>4^|tY2prH15xFt6BeixVknX90v<%kryxhr zfO-P~l*l~FBPcO92!>FK#Q>w=;L{am6Hf>wf?<*&m=HK^#Zbw5Wc9=w!XLvKB_2uX zJQxm&XsU?OM~0m%YP=D6yUB5#tRTtEBO*oKQ9v+mF&@x&vUo=gdG!7{W**^a^3Jsy z2s}fc!Qe$&3z<(JxDVqM5l>X{HPJCflV6y;!6J}#X)YenDmzN+bthHdW{$`y^zk+) zxaLqd3q^JENv-bPZC-DJ(i7f_k$id%KKN>@dh`0$t&jN9vkzwLbc(H1o*_Jlw@)hy z(lZ}qp_55U)#`XOBxc$>4oByhZYuxOhtg+-Il0N@PDeRuj7x2(cM{~hSxa`TL}P=A zw~s3w@^f+*q29Gt^*PmFDOD}&5R^)p--!wJ{zCm|G0-^JP~1O2^2^XaU@8aW&Bmm$ zq5{<0NSY84?PS*JHeV_PPD>N$OrOX?p9MaZr6=i_MxQfdmdy^Mhh=nv9(7swPEZOc zY6YhD(WY_@i1Y2Ek#RdJIp4l}QURrBCdY5{N%!)HH$uhOzWR#jW5#~Q;HSs_2e0OO6%#+*F%LHO(D~N zr<^{0yQxDJVJHpU8Qz|iY8!D*af~zwuCWVR62HjEo3TF89c{24Ib55z_) z#7~2-zUFAfe}1NM?^<%!5?7HHrub7K@w^_bFc}>$PojCY>eUrRC7U9uraz;pjxhet zG11T#;kFu$p9M`-pZ<16m|!I>ng=yBe*7j)PtP^qTr z#suy0e%-E3qK#wJ0I>1h*#^T{tFM+mNk>-OxSpC1WY zsg>CyjJxlTk)M@~un_C+)CJ}{Al%4mh&OWPj<4=SEu5aC>F(WG8SS#)%Bp2A<;dpB zVw%=D{r~8qOI&r@jshP?c&;D0Y3|`ddBt~@2?cVx+i$mD_^1ov+eY;$^zG_)^($Y=#4pK=t905BB79D)A&+mj<}I{UHkIl; zvP*~~=rRE5l|re2UI`~j^C^yZb>z476J6b4_da-^QLy;?>6Q9oga2F*U0?dvLMTJe zB|>T!$gW2wG0`>kmD=(__dRH zQAv+3jv{Z?->te{$e#onJHKOr4mm$@d$U4{)( z4U1$dWNX)gCeE)s1#xvf1(TV6XqSx>AwFOjBwuvRADrFZqva zDX7lk8={^U)ehPP8G1o-qVEott9=#8XqA=~Icj)#!3ln9vX$h%I*uJUrw~Y+u96y?Be~`-uRgWV z$z4flhEgT*#6#$4AIW03(WZ&vgc+z{pWdH+Q>0;rkO4AFor_^ zs5eqSNTTMA|svU*6q5f+`6cIqvf%ZEG|hLclXSmvUS_xCX^s%g{)C^@2rZn z*Zk?9{fk3R|H@Pj94bMv?`gk|aR-0V>RaDaOOYc*wod*$#8>BQz80p2pP4v)zb=}v z?DOzim(lg4BXrWQtjt=h>o9aq+ou>CLHAes?sw^^;4>yZ)h|8Ff15y!ZxTD_&H&u1a0)``jV89=5cvvC9eNH>aYjoz%m%e#WL7$PI zzWT+_F4}wryQyW`tKHKZP2X~Pus&QCkd?pBE4fB?NS04>b;m=i8Y1a6Grm?i;)waE z-x`&H5>NE%Tf@CdRF1SIA(ahsyhCsa!tEOI0(u7zPi?Hp zcY%-q8BsX7=l+v#$F9C4l5m14-tA? zw@2GJ^66r7dgR+9sj)+dINlOcB>0U88Mo<4$CGg1o+`Vzpk*DqKiw}m(5*VHI?0R` z8I3LCud}U%pu>;nG*>BNZ!J-zf1jPEf52}&l^-8*aD-l7mvb)}u}SN%x~M$*2Gbf=G>d5)NFphrCR#BGShe_6pfU-OjLgL!<`o3 z@xbB*W}kq2_;vc%y|1rW<5uak9&S(Xasan)-D#V*rnz;S^GVkqfZJEUZMPiwdn6gN zb*)ioU47i=kdNiDtE#=y%G>su#}oxq*me_{z3;h)g-3jw1@vGtBSkMUQk)N*MkB@N z(030j76^H^6-A1gKDT4dM3xBtj^zYsji@}FPpTzb>WIl%k%!2C_FEg$Z? z91n{XI5iUn73g7M`l8tayK9z`ke`zGkMQvRBF_68H4YuH)=2KabTDpgGBo&`xe7zZ z#6>lzmw`l>mfdjuyz(1MP3ol08S8$D5@8j&F6z;eDDr;&LqdTOOh)tt%QH7T4r^^i zQO$Cab5DAeD{b>cAt=?~c*tTACK2#!VoV`Jxp_@$8Cj5Uc>M1)hBxV?;(LzXK84N+ zoNe_>mzhHj7ApjFZo2r3F=VliyT~3OHH?y*{ng8t{ajTxN>vR;yIJFPM%tPGns~hf^H}Ygk5S{^SS~o z1#qcxOTh#lDmMy>f;Fyc8+bE~r$@SCgTeSAn;XJGPPixw2m5j4*%|(4P*8l50dj&c zCnm^=Q*+a4NAQIa(YwbcPZ^b>`%JezAxU{1@b_vHNDJco=FM?gG!`%C3JY{kNMF>2 z_bV3%T^n5$Feg2A@_4rfx#ub`)5+`z`G{=<42p8IaND9x&E>2U7|4YRB zmq`FE^`nzBb?!f3P=C;>a5t#^4aFHPQ#yj$r>QSq<)Wu=Ol~NWPv5Tnv`8LNT0_(K z1^Rn=jj4OY`*|O^4n;?mHu>(zwG>20*Ccl`6CDTXp6KiabLXPm_>j^~s^iV^!HMft zvis`F8uCV36^2lh8@FrH9O+zQ$nw96@s06~q?^_A7kuqKU)>WoW0lWEaD*OL9akl{ zB(}VGT=lSW<~aJS`i(j|-S_Xt6WUVkwTcAcVWEWd2r}xL#_!p+vWs@#lP&j6HS_Cr zT~Sl)V0i^iY1!EGTvuv*Px$y^`8H)f`9^vA`YwH{>`r6gwhr0W(QeC_d&6gzkE^Y2 zef0E%(-T0#RHb<(sH($Nk1+`o@e8sG%#dBpUPik6zTdWa(XxqDX@9mkGEO(;y9;u+ z9E8i{F{f44$#uTp)cGE}q1v13H@@(~VXw}%o{4%dbpYI?58gIa$KsC;UpVD^SZQ4j z;-%duer{g4dinSk*+b}EgDA}DNm-SZRcR^0b+PDN1K%1=T4i67h`zO_=H_lp5ekc~ zTWNaa;-pr~l>1)tpFFD|*qF3iTOnwQ1JlUvJ#%Sj>mIxbR<8rUbI$!tHXVPS`dv^} zzY`a}jfp2v^NN`-t!tItW@@-U=J7g(J)zzT-ZXTk9dGW5lOG@Xyf2ksxW7x*Go@9# zR8VQ|bA}o~K#iNw=S%B}-|5;3zO=O-r94lH;uXjy;DWt4AA}jDpZe)bO|ypxSeR z812BFMOg202Voo>-7a95pt4N`xkp?zzH&|hp6c=ya=VlH)im+9smj2229}8?-d;qC zD{SC30Y=R>-INa&)tLEJTV&*m4)Ly3O@)^t{I*gu0j(CoJZ@mMgepcchwbQNN9MkG zQP`*mvaccgjG;m_n(?a1m8-NBYTW$_i{y~B{w7)5L)W>1e(uw@!cY3o?nI*w}^uekae z$7|?@qyO>T%!Y9hq-4WONn6dcL*y=B2La6#Y?fd!T3q4l1Hfj1YfHFa!pS#hy{cbZ znXG7bSnJo#mN(_Q!1F~!p>=&1nh*yUnw1SjhYO=z@?{%k2Pb5AY!Wx!juxEb|E|n>G-1$!IlABgY_*{%D)BQ_YSpe}v)ntJ*)5(eweQ0T$Rj3>U=N+Y0ozz< z7X%bX&7;&iE`x*dGNttKXptn8i+N4-^VGJ`w=q`DoXm6Od@larua%-G0!b9iM3FTLB$1rl z&qNVOqD0tJ`#6%QCr-#Oka1B2l8B^>7x;hID~h-zl5tT4k|-WT5tx7FAdJ$2dxcR} zw?r6C9^cw4jItxXL1A>}P&vrt!{%`gSrlogvvlB1ug$-w9+*tYl%}y!8n@lJ#*P8zuJY@Q{7({%uPK2 zVy14{>6M+{)86yGEy7t^`ODHSRVcBj;&q>>)8E&u6hLmhWPJ$_a=mazoKPBz`!rn% z)m}?&KDf8`_EZx{t&7AT#8!(}-R%qXo4uC5aMML4t<}&@U)WjuyJ5q)6q%X)UNB5< zAJ@L_d+@QT&zRec$4g>1gwnrEPYVQ*<$rgP=2*bDv~HhQpTMfp!T~H0SnjCKjECzi z>NToH18tqgMb`Kd6+JUzlWG$zFSK>??!9Sbmo~uk@hI0k=Tt#GP4tGz=$F@vMov$} z?x5D7AdNf1NWu&~baK&6LArG#&B>4GP=xg?*MF+^Pdu$|-}d6R)9TO(FC9}y#LhS`=xV>=w-=v-Xzp3^uE&lw8;x)u`>t80kT2v>P zitiO_yWwiThm>{3-7jo=;gPKW*Og?r{-zm^J>B9}<~OY_`K75Z-J)unpqv)sKhA&8 z$6tKnb0KPX$M%k?-$fnoINlC63Zx=wAfW$LGG$$whwZ=d@NuOJGajtu2Ah zgw>(7Rr7NcX^Oa>_kHCfw*&eqIV%F=Y{B4`eIQG_R%bT+GH`jdH^G z!5Yhr8o6>oz{;<{9IMQoP%%lDRXGuUnzT+zsP!%QH-j`<1s@RYAi;BS2aG7FqlTS4!Y!~0z0FcuD*ph)I00c}M-J?r z{@kc(hQ=)@r1iycqEGOH4Jfjd8rj`xnQ(bp$7D)7)V9!LYJ5%S4Rvk4-0E=n@m;AG zKUZ~3d{-9Nq3cw}|5ibfm#m%W-JE69_yJhH5^!9r8uiooEHeIJ^H^Z5ihIxsBQP$5UeMG73wxlk!4pZ;_uWO5g zTkm`=X|Ie#MnxH_O*w(z-08>+yf=?tAN~|O8TUo?=-BkSYVWwLx;E`zMUTZhj=0Ap zE0dM6%1w=pjo&<}SV`K(O^qEJKcY_G)7AknlX~Iw*uuy29?$iTe`I8*?-@l;T}V$$S4*?}>y|r0(!FjUqjvbF#J>Z! zDcqlxVRvke%>z5JD6dLxA*uPyT3i*RUt4HRDD2!0w`Mt*e6F$WdD5$s6jqWOQAl^8 z(HP<#;yup0&9|;t-Zr)Q)^}%Kqnth~G{~47^1v$J`i53rfNwz{E%#YMtJmgR(UJIy z-TG|I_*-`DRp=E7E~CousM6qM*I2dTJys3c=H^Kckxz;%{MB%QRi4li+Y(#1>7~!x z8q^Qeh7{zu{0pY_oSXROgj}DmHy!rzmYs%ME?{E>1s}*g*DD{Pl6a4d1PIN{Rs#v> zK({9B^AtbSd#dEGrZ(@013B}RUN_B_xo>>Aval=U!i{nAI8y6W{XPCWb^DBZ*(}+A zkg)N^r0#(+9g|&Tj;!--zvam%(L;KVAJ8Na;+M3?JFa4xTK0~{b@R%K?1Vj0 z)vbYVnT*A8c@E~Svzac0o&2w`L@#}iu{zjb4r=!8HX0+ktM{p6avu?ry}q65MNM%d zV!U?$;psov0=}E#<>y7OU6!Hk{$srGvR6#biHGFTJ|zO({yr^t^UIss6P$jXJu7m1yHjNW#0O)_pRnAb7$s19aaNam?Y{ zgetxnIC@a22J}bSpMU{T0#`G!yCofEc-k(43R8bcB6X8uyfRdaby~%`qYzG=fD2Zx zS9u3ylTE;~d|}5Pj$b0fDzYnpVfo;}OUALlM`9@@rR)^WY7i0Z%%2U;`P4+HuOIc1 z!O#%EObf=e>O+8QA=7e*H$HCkOR?SUhYaf;zgkWH%8L3BWLO22OE-?K9qAnxI4b_@ zhrJUX_MZBnx1g=JZA`m%nV(nrCdDm9561Chf4Fh$5KWMcLH-#k@Wd$8z^l%~y^R|+ zwXTX(xj9u9=Xk`>Pvg~XB7-#EwV?6JgjH|-VxyLXkg@U8Q)*M3#L%wC$hd-?nYpJ?lGpO;@gvGH!wcueMc7@8s8cerugI_Ax_|Y zZfCM7!c;eV$02RjwG(CT$%Wb!ZR{_%#}`eGn{$0DY+4t3wSPKGd39THs#hy<&zNe} zojx6+&s6z5aM0nMUS=)Q$&1K;={U3de*aq!CWNY?~PAQI^8j%m{d)K}$lnvvYlfZKA*)iiY{d zK+##{5bp^zKO?I&zsL=e?@h**ptrPE-(tBlA@ab!otTYigjjRzr&Sh$TV_~3^^fTCIE0k-`_neG>_CP*sB=83K=IPe2;_9 zb+WB=vo@kEujP!=k-lN!Y*}+*WntUIHbUbWS#_&3xsv*?A2ac^lY<72%O&Rl&k z*hT#2$Xaq*Ry3~wpIYMS^)oLx(!Fa69`KI)zCtaNx2{<1#dj_|dYn;6nZ}iR+s&qy ziBC*i?G+njYz{W`ScBSPn-%x^#%gxwulGs`_)F3uuTD8#?6oH<*{jgeb1pa8YpU0K z`=+T^lH~FCw14-!>`gCY-Q!iV&Iu`knShV8qJml{+g7{S-FBwhq~wgAuViG(tyk}! zkSdEg{O+9p_sf^+pLqJ+Nqd5dY%ZTTx9MvuLB@FdnBB_V%IB0l?I&M6x%*_>uKi2q zZ8)pT8tu2AJbtqMr2b~qxJZSKzkQedQ0v9R<4*bcDt#}Utfk*xI0;7$e*eyH_eWm| z7f$AE-Pk3Ve}%tP2^BpTPUgCc$5bgg#$7o1mF&XFZ&nJM-iI6)PLek-oa|Dx8z)~l zdGfgnC!Zg2;bfZp1i5P;@m%T)?KRjlgkc_(#bN9+lo(d);le z(bw7J_p7hlI8reM`BH-ds76}&DNB(rk#YU_l5ERy#ki)~4h>mJmyxyWN`Nn|3zr9$ zJG9H>%3jUU*XG#m(8{MGhoX!_txE*HR zy(aU$V9L(v-TiAyo58k;cZ@R_E%T&HDB~#G?>OU9-rb;9=ZPw(qJ7^SLtdDX{ ziwHeps6|;~jEZtGjoS9sBSPd6h1WWPv;n(v?U^#aeWUBpgsewW6^`q+2gWLveBBWh zKW8sJ6d*)(z_~VS0a#R~u#xF&BfjZ;eSKhxeX3(ZO=`H$??QD?dZ+IwPW0`BWA$C= z)p~x~8P)4kKGl3e=bs%3ysD$QJ#lu?EAipc&g2fSp5*mqz^nW+oKvR0TCy$>H8MSJ z@wRRQ?xYj8SJjh4PohQ^NLM)@D{hZyic|SG}AUu>M0Yk`xeP>sU$!2#$ki-zeLj}xkl1&JCk}L#7%z}c&XMFT} z^;$uxkNU)ddbzi)L9ykwqNt6nwzoW6wYG?@x75~}`~A&1XLplqVxoTT?H^7u=ggV; z&2MIY^PAtiely#f-k!c^`b$xJ)_V8ca;od2_PB>s-d)?~WGaGQ-ZK}`rK2Zq zIsIZ$rvai!_iUdnDb|$iT~jxE8{2!Bt1R(LMYHbE2^R`CrO8)i6sy$59>)U@Ti#2~ zP1)#uVcU-0SZ}Olc5!Y@H=CN=@bg!u#)}69bhn{>RvQLmi!~?mJn>DKjkzQVq@}@_ z^FFMcO9E)ml$`S2yH6&w8yE|yJ)fF=@VWFNRu%y}OJ4 zGvmR36E5;57^Lx;EQWpsWp)xnKh0bk>pQWmxv@EsMg1XD=Mjp8`R^~O?dlg7Z=U)* zyIlKpV%$kqqowmHDYWYtwJ~K9!=58XTVCxN47MsWtM@;k6CK_A?&LGW+t)g(lH5s_ z`!O}F-!Gg~4;x{fPQCGCA@ixf2sFt0yP$sa`g4LbC#>pG@0;R{g(x%h3TO zF2O_(b8WBCDL8~@6YhywH(zL;IbTTeb|k#;tZo%FQ7-&@lO`&!ui!9tBl##RTh;BE z{uVo?jWd+2$;^Bm8dx0}*yH+i*7_QZvCh#Hu_Ul-z;VIZiv}N6)mwYt-tg|}=mT#Q z4-^j!PFwC*-!ps4FR#~Z%srP^QndR<)yg;LKjwS$xN4KXLDO42@Nzu?T7I)fEFS21 zwxu{N{E%s9{)|o2T~$2rI!h}aC=q(9i*&%P8T_lJc;NX{ zvto(|elJuXFCK_C53q$N=DGLdHw2{ta12(zMMeT6218|)o>p2}KGs%gDP`pG4JNCc zZyGt`(vf;hZv2z(c71~m1L(u*xJ8YcIp5W5YOqgg%sj!Dh}ETH^;*l zR8p1*dEGXM56kv%Z`WMmZk^HXi}wZ+l57w({f9}=WF|fmmGxrG<2z#Gb9dxy^F4XS z=w8#)pD0XuFJN*fy&AY{u5MEQTqC%_rm;PJBAMRkR3xUt?998w9FT_~TAFFvIyZrip^#Bkg<0Ex{ejsM7@zII&oFjW*-j-By8}&l$(OsereNcNXE5B6t7yYrjcT6(goV;kS zL-ex2T=5AZFlp9;mvCNKumptLZx#bj9e<+#1q_rP-q3sRgZ&r0ly_iS$>f((JU?D9 zwwh*Lt)sD0@W)a_U3O**7gMY2ea8>{KGicXTW84Z?Vq>j0$psv1)k(Lzjs2Vd(nII zx;c-h3faA>kNm2+Y0eK@QZx0b`u%4wskkV6*$vV8xvJ>_#s^12Kl*(>IJ$K1-Yt`E z)!821yu2v1Om*kt7j+favweo$!Yh?0V$Ir_10H6m=R>4bDaqnNHB@bP3lD3uyuN+u zt<8=9mBOMjmk9YnNo{%c{BCX9)C@=`{Z%+74Dm$LX(m(86s8O8>ovHdhN)pSu+gw| z?wgDt#K>RtYqR7Y)6ijY#wy(k0{W8t2o-%Dm%kH&Nk|F(-#_OfH&{Tdppzf@ua7jS=m-138#c0*eE}N z&ndw{E&O=?1c`bIl$0BWpE74`jvTX`0y$MfOu>=J4=FUUvZzf9oHGHO<)= z0rqT+a+yE}0MlpSDuK>chGk@z56d%ZRqCCkbeBL|bJR7WOKlt{B^J4gGPk(gZi~_2 zaOW4AErxt^skus5(EJqy0_@icMYe1w<6Qcps(HFF3P-es^> zj$teEWb)jCnNZIe?iwG58F}d?T1gzX68V8T3TV)ST(1V*pecdURl!<8 zqt*EG^Kjxjith(K>Oheyl*Nq_IKUTv#K#Ie-cr4Xmn14!>qgX18F{O6^98Y@mul6QYhyh9H_4ks3ibIYsoK7qt?iNu=7v z6+ECD)n-jt?NV(^wOa-WL1VU1TaQ#;sg<{ZJ~}y-@s?FUkEn361Ep~A{Myi#rE=Ni zx~A4`2kv}4sf80KlyS-$P*y9-Krygi2$;xag;p6j6n9LZoG!Si-L6Iql1nbmn_hfZ zpoZ)5MPbVTg{zO?azmEZ^EftMlO#85kUq&aDs=(EHlY<{MU6}g}8&HWFfC97fNCVO{li@oI8kOG}0#SAgM^SbHQ!lbR!qF8=_b# zr`bsF*m!9u_qZ1e zInPJ=oZtp>Q7<6LiBeu_EBuK6r7wv?h%=0cOWZ+aHOjI8OoWpqmxc zYeemmEP~$dV3ukq+~DBpyJS>UR67PyxH}CEZY@}ax)*9#E$Bu%@Yll8E*pln4lxX> z(c=sbJ}u9#GAM~Tn5hpAhUdc0(JqgG)-)uycEo#CMx~F8%E(czh=9s61eFn}K736o zczI-0R*s7L)^Hk9VGD<#vcl(2T@or!2vsTuB9fR>gpPqDydna^991Of!NI5Sn1^QbR|5g9cvp-(<{^I+dTDaPEeMOGq zPj4H_8{j;?S?IyqLZ_8Jwln%oFNk19i`*K~y{X>U8p!o9wYZ|xasHHtX~dPy?FQ?i z>tv_N7~Ly7t>#T|s>Mog{r>NJm`G8qPi4uj!l&ViBflkG9qVwC^G7dw&;xY)8#-Ej zcX`NN)!5iv@0+y2gTA4%hOPtab|&K^fT~ez*iv7kyP?^?Qv|HYRX0t)pXOn)JXm10 zZs_T4z-mv%J06x!CwJPE3(MLK(oJb+4gp-0RDqxgl=C+7hST{SJ;~UO8WzPUMfv1Y zM3J?Jy4sBM5G6qjU);I&bTB*ibI6XIHRA^%xAl*3$B4?sm3Pnfuz2Z<-(Ke4@GYVY z59W7P-t>Iv`$}A+@MDLEO%kO$ER`!PZTbtPoCZAVOk=Ybk>QkJHu^f`@9~O79PUlKDw=@XYJw%w=;4>Qh1SP0aVgHH{s@o#SRz0!${v&J_5;p$Q@ zI;6EfkP8<-Y-n$A@=Far15sjGMRT{GXZ?IN&j@Y9PrH?z{Cb8ni;;biFFPvt>s8$L zyAd2?mN;g`W)Dl2p=pcV*NQ6q_9G*}EfV;9{lrlca#x)Zu;-VLfVD}mS8k%(mS8J4 z1N8l@5ukPnw0R%#kc<|$?d`c|1f)rVECa`gth~9wXTN3yj8%d;|5uqms7XnB1E`a0 zK=DMSp>b`u2H!IyP!viij_8S*j`r-yY|9e+aP2#J9-@*6!VU(YPO5gu5QYq;=z8`~Q)eJkFiy_0*BJ?LR z2f$>atSElR32GGAz-~^$DqK1+-6OT3&X%+u^6_uJ zyp~#^bT!^H$b}%T^P4arF7qJ51?#HUJzr30MzA~&(3q$mzO@!P@5qDWdY z$70FlgX;rOP84aE_w;=3THk6|0~rNB=$2fqxJm*QPYqXZ7k7% zSYUm4eq+9&09KEeV#Vw-%=n#{vQFG+v3sOJv{YDPzVTpq1VF3Q66DbITQNbNm`TT! zD4glX6Pp^ZRR$cIeh*f_CT5Vnkb)>_u;VTNbAWwCPG;m3R}L8GE1foPWHV`$IDLOF zYrOc;cLe1f4hCWGZ1r|`Luo-iS`)U-C=G*$Y%m75AbFT|j4=BcVa74SEMtTjhJ;bq zR+JeU^J9m!+}GOa?7-QbO@7*0)x&Frud5q<69jpu*WZkzvnFFvrpazH8jaXA1%R`1 zVNqt8zRc)0>y2((xTQVUC8Y>0D|5L^4el}vB3XI4Ei?Gg?gsli6e> z>nufJV%)0oj&8a!)QsqdGY=31$?e$E6@)?gACHv zc{gs;_aR^56OSSsR15w)6XSyHF*E?D*=&+ESdDO5ZN@wuz$MNZ3M>0sBl_AS`Whqp zS|a)yhWm!I`KWGzmQ+~gh*e4{Lh2~~A#~w18+FZ(1*dq12y0qQnx~kCtUk(~)-X>J zS)8u+Fi*SUX$EsiDamzA_NFh3YR1mOjm}LKv(OE3vO-D6n}PZxZlQQYEk|q&#Gx2L!ie zjfBV2F1rL)JsjS$b#`UJNOz>*q}W;i@5)bD0&eKZ0=UZM-- zpFZ`lQN!U)purNxzC#E>oBshkoPij85pPfhMYBn)!duq}=T|Wz`ah-r8E^l05DB)) z{eQ<-NgQ!0{dBx1!;Uxop8)oVoW6i@5AEl6ViZJs*Aq3Va{2Kaq~lKi7l8H338}eG zLK(IQNbA8j(d04in)vwV9i%dc+7yhh6}(98NaB^*oVUOyfj9(GJBndbf^%YOYyA|! zBslPQARb@DgRy|)b1>**{|(d#$477pfFa(F100{WA>B183S5Xs69Gd!O6@FO;!$6# zag%}aIGq2{1~^>8aQ?UEHO-o@;10EyWEnnjIDFwRXPks2RoaUpcTxdQG)M}QB_?*h zre&rA8^TRYSOS|o95)Jm)H$-P6T?y&wZq}<3)sO*86G+6v!NkF})$jMwo2k;V8%S-2u>-I>Ga0*iRZSJc){{ff z1mG3K@drh;jv8k+1PjCd31c%iXzQvt2jfH!czD{jyr%H@8vqkZQ!S@S`XF44@%S$6 zIvRP*1oIR5yDh?3?i4nW@ktgUu3H0A5rFPm*}rbOmGAmB2A- z9bohyij(&jWK79VurH@_GhG1(Y}jYILKfqvKu1bheZ8*0x4MRL5h-9m&&8$iUe2 z8O~Rmhw#owSIyk7=yuPwSt-{qZ4I=Y*A_IQ#whxM~h-#RvM{Ox1M4s#@Q_>-o0m~94;n9cOFH@JFY z40?VJ;Sh&De7K<|bz;ZvKYd!YR{O*qF)TNG|2x#po`D4$VtC6K!~>at2M;uTC>&6C z4Y>hJZLJTMy3_k%shfTbmSiT$ep;{iH7xctAY)0NQqs~}1l^TJuCg$ijvFF{nYr@# zhj=X#4~BsToxg#LbcM-i&_YN{iSpp%dNUKtkL^p0e@-La&q(gTkT%OkuBaht^O4pf zX`znSO#2e){~5@4%HvYT)R={RPvtcin^bllSS3rl6_ zgjGx=nh`ANAd{ACKDfFav?6^lG89Hed6%HT)K19|eqxEwB)$lUKu-8cGm7X!8U)nF zXX8zIC5;D~-CcnV7ruyl`o8-g&c$3^YCx7F`$7;3A0bQnY-sTkE_o0TJs7-0~ zwun!)DNPz)*J5RuBmwDSQ_BqL_e%L8`9e5JFLo`kc7?$si03t93>X)0d!$Y6MGh{< zQ-yrWsE{PA`ijEc1=j8}7OlSfdYykUhM%9y6;Xi>HYjpEZkiBoR IFeU~57ybLz+5i9m literal 163840 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
      h_OKPqiPxw>Gv%DW^D4P>+!f;ma=%b zddZS3Gh=WfxXK64GK%VBu&NzsrOovw}#d3oEj;T3ZGR}EP1P@Pr)gDUND|&TNX@XQNja&bQ$WiR^`OLwxQTKfveii61?zCw(T5N@WjK{MLS8P^xW-@0&>c_v0gl*DWq=zISNcWJLzcxt?{xplW5FW=^ zj);(NUhSKx32YOyIaA8idGnr&+9wyW*f5+8EL_lkg1DKo74nwx!l-le0}E@%Pnl|T z^P7q2F`Q{>dU@BjWNc8O^sW<&o1}5-fUf`765jGRaadCHd^l-BK2oAP57OFuJNi~0 z^5JxPq&^*|G?)iAKIGe_Z$c7F{f`+(=3f{#p>I%Ol9*UZNV>nz583-BlXl5id4pUJ z%}!H5dq6KhJYWI9XiBvt$0m(Nt2@e(?KNKQ42<#4lFZ8+o$4iWY*IFEX^fFpSg2?g48Ho=Wir&%FUfL&V#ixG9@e3BN8w9QGG8j)5z87^(k2ySsu1x>i8V z^2pJn;5-pgEk#;AfiqW{Xnmv@K|0kEWfD)}dK#2MTXs~U0t1Nv3;5u z7Y5Peb#ggXO1b*z%F{nDF(ygD03-pEP@}QdE?4Odd@3;6 zN?4>Z3&BzY^iddqCud+-CaaRZcrXWqn*jQqvm~@;K(Cdm^oI|%Nyn^of>CLsq?~b% z6eEqNmzxNnn`ousC7Ru+k+)h{qcQX1$Z+I3Jba;qv?|9i^+(Z{f(khgX69AClC(;{ zTf_YdC@4Z#sA^?Q$#%e~Nh5_K`gji`>Lc|Yp~tJnr9{p$7-gyzT$QP{E_w!P_FeN% zMiynHCk(;Ss8_E>ojcpp(_3X`w#vydQmVPuvJ*M=A?=n2)< zrG&Ush#LCcbW0@b!Kjfv=QWDwj#kc;em8SNzXge*Bf0UWkmYo<_&djtizF- znUya(J%3$g36ObX^W6bECk84FQx7jD8$FS(W(LQTK-Nq%Qq@+6#&k_zoAMau4rF=g zxv7mz)>uc9TFCm?LZvhwl729P%a#=-A(`7W6(!H1C_8Xlxf$m_aE?k-l*zc=+<@~> zI8PX*D7!Gl^kllCTts`>dbFas z7N#ioWh=@uoS(w^GR~Xv^zn}}it==xqI_FcQI_T_%E@xL%buVpTgxlTh>4Ji=fC-r z@X)xTqGV52l2v@<)xve|^hENYARgaanwm~a(F+}(2;fpV@a>^OG zSHAr^WG5G?RK>FusG=lxlDGaz{V}G?8P<4WX2#1)_r-q@8QSGWw?AiJXw-f6<~UoO zZ)fdUwCCBWyFPxbcKN+0Hm@J>$Bmw!_V2jCUOuDY7fo-hX?;HX-5LQ~KUlSTefL*? z?%1IA_f_s4w)S+3-d}7S_|VMC7271Q4O#W;+dJNgXz^gdeGfg}Z|#(e<3{z|+;-8D z>>5j+|MXU@&%T)ax&?m~lsb^t_p6HEKeROV{N7H-FZgcTRBdqED;I9As(o(B>u;Hp`K|Hu4IX;tz>xR*->kIh@^DAYk(do%+kY;( zp!5fuEXd_;Y&hUL88{2ZZ8-%q` zX#8lDLW`rI#Mc>6K>V) zHpICRpfR8cAQBJ-hz4*oMl(PRpgEugAQsRP&g_^J#p>@hzIlr^a1n*^aCUS`U3_41_A~F1_Oow?gudaP@K8rY&akZ zFanSa7zs!Lqyij(G{7i8I$$*50RYoy;G78<3&;YD1B?ft0%1^v*(pFCARjORfC_`n z45PfVa`?)b2j_k|;X%Xc_iagKxl`6{TyIVBV7I{c@d%@|XI1;N%P}R(xc7`RzfBJvWLrI55 z*()`=xU=<|hkp3-*pQ5OPA%HJXlnD}`{Um$EIZ=2_Ls|iwtq(A3{fn;hW2vpvGtdB zLFeWu2(}PO*^Z2yCXM-j&f-H4d=MG*;MKYB&OS1&@24MBtdrkl?UGJSo|~qejhK-h zUggUw-+$SAkAI2nwmHvVz41cZ+po;Od3O0Fd-=y-^#9;or}q2O&*rz?Ib+t|xzDe! zV@sSk?qAPM`EqO0JAIBk*XBS}m9^crMXo3vGVhDt@AP}6W9pH;p`Ui|@@2D;wP&nf zIzH)mja6$ZooU|lv){`1JKkc%D~mVmE!^@!UaBg{-hSbnh6(Oj=ofHZu4yfX!HLx+BxkMEAc}GUiPk+3X>L z_V+6Bfjunf@Z&0^{PprA}KmEDm`>kly_n>!V+pJSt zW+94d|1hL?R@IoYJ8S(^?d7-Df6*)dvy7v?R-F2w`Qdd7H-GtT^>?>?U8%*IpFX}` z_f(Y!7I*75Z`Pak@#hN)x^Mh&?bOHP!pgpoG;`FHwEWe1-8$BaJKVN*)9Z(>7EYOd zedzYvk;#{r*zTKjveb8j9oSo_gcS zF%vuOu3gi1Y<;%x8?y($kdZQJ$iE^NTqw6@Y1xZ)ht?ka-b?dV?(wN%IW?!zt4ALg zvoCPn=z@N$l`mR95*U2nrXfpyjC%UX`Y!}@tn2@H#Q06N^r6G+Cfh+4D=sM%wuj{1`jJrO5 zY5p6>UXB?$b?)u&X6@e?zy7m~3!4W&>z`VqO3B}UJ9&S~nBDJHS+cuDg=-5B4t!(# z#WTSlpF3Xu+Fvhi-1@KiEuLO=zt4$8)w+YcjRkneVq&ZFg^nX3NK~ z8`5*)i>o($e=fCl#PIJ%c0F73@YB}zXPyn|_SgHHo~_q!%YvTcY&D;3a(MMM|Myl@ zYF+k|xit@z-P`AI&#kj>G!6PTYW)r~dZaJv(RItamdzKjYTEU)DF- z`TOt3v(`*JljyVf#cMTt&FlQe-msIG0xzcpo$nss_1wq?|B71odAY>VwZ}gkQz7K9 zH4j(&^~XwSCuV;idVJOm>+;eyu6^|D%v#s%tAm>NvZkpk?Mom z{oZ&&)6P3**BCeX#qC%7o_q6;A08O@XxByEeo>AzO*s40h2Zy}{Jq-#6V@^b4?MlA z^@Uc?eEZbrV-vqQeeBBAreDt5c<9kKt?#LSee|1;wd*7vfuO9d%J7~rI6XtIFqxriN&uu$*ebdBqO6)TWf{!j(n)vDK z=Sy#UZhQ^@7{8o|Iu~j-nt!(MrDmJ5$1UBJ7F>Ghw73Cn=8gB?IQ3NSA4~V&cW-IO z(D#RY8Z>3}n04c-_PJjBH@w&-uAg#f=a6Tykui z9CJ^JxBn`ame=U$TW@{7FnwK{R$p~rvGt(?-&X56{6+uSYh#`{)ZuWonJbQ;>GtZ7 z55jCsqmSjk(XRei&u+ZGP13{jQy1*1ePijdDM#+jJO6z6!185}Og=H<@TE_hzC7^k zu}@P^7koKsb$`e4*tx^bzT4ubeqry;9kt-m-s@`hcxmt6ez`|W-G5+3T0zIvTW1HZ zUUN2T@2>Cry|HptmvJ@9)ldH5_Wso7L)zU)d#TU{H1Z{YEo6>mq?+qLMGF?&-xb{vqG@96yH!5tUZ zF7I6~Z1%*dbGl~KzaI5w(u4IcH(gh{afhB=4mTN>w|-;hy06ZyzGv8P@9#hJLu}fR z1;1p!l<@k;sU=%HbN?qJzOH|6=Gft1EX=MjX!rAf)_I{{@cF{W>Q8Pzv*bgczji&& z_QoEcT2I#dv7ltRoDCg^^!#8)LHYNOmYP@o&D(QF+v>mhLGwbtmPZRS4-TnZcjMWi zFI*oz$2#|~Zo6kKX&cd_?yZCNfroB1?y>B`oSvNre7NGVa#K2&3as*7jHG zDHR)5c{b>k6-#dW{!yb`%`H!L`So9|zWJk1V%XF#4}WOSu)p|d#`&4KGhd%wD}D73 zPY2iS^~rZDCcJU-f!%4->SZ4N%CFApGK~)}dved|3eEDrSpC)ytB1bRGv!kG{EW;! z@i8$Iuctoz{^93iKdrcDRg=-5_Z~j=SEcH^!H+gcSoeHj-QO3~iTw4jZDwg9eiZTQ`^wNRY4zqkD;TJLle>U>H2DQsM4#%`;lem+?X}NmX-C{+o4PA zo|<=f<5Ax^-^2trZ(qCb4?hOK($LoU!Q>r}jo$v~lY7ggM1LKX{$gcYt8Z6~fBe17 zH-A_Z*ROp1LtnH`-85p>qO2A_mK(LSM?|l>wfjXhj#`yn>Ynb8tUmm3|Cm{q~2akuf%Zdbl$%4(42`F%_#H z+8GlX2S=`il`v}b7;WgxZ{%bgskk^DGvg%2Ek+(jCvfrDiJMuyHbuBZpB{b~F!6rC zPZ@^Xzg>c%C$M+=3EiL`5y}GK78r1k;%#J)>Ts8ov{yz>&S?4dipM(Mdh$edG7CgH z#XnTJzxRQFy?EN}5Bicm6)8sCi8R6akp+tK>Jmj6gFByK&~UQJ2e*kK;yMifc@u6^ z{(Rx5PkW8*(>_Vy>kE7X@qd=U6o^}Sa>fm|4{xesEi)1G9;QCzE&FUiJxBbn3+gm+ zTx@@j?mEKB<#PLay6b1e4SXza#`v=;%xzO~eAZq&hwNN!tE;Tm*@U|2k2X!U&;V!w zLZ4DjJIHAWn@^~~1VVd3YYD-ckWg_OYQ(Ydj5xL#MjUT(jW|wm7;$AxaI~F~j?*1R z9H&2wIE=(SaJ;WD(s8=Ph~xB$5y$BiBhGGut7(D@H{kxlgb(k9zXV`v4Yv$uJXi*&kW%u%$^nGjf075w#U0O(*}P%XNa=&tK%R5+=$f3M(+jm7sNjm_nm%Snlp=7{bakAFgg? z9Me>RK9hv4WXMPPTGh2Q;(QU}Px6s@rJs1?OMj7ks|mieE%mPk8%j>@yy#2bc+saM zuNs0ED=&G~@WRVp1TXrXmrcG}6^I!Esb!q>C`Y)ic4>H^DV9!8J6&H8R0*8dR?f{fhaOcCIDt z%$|m2#&=(ul|OA^W@qxEO(d^6f)^)v$g7SQUbL4tUbLI!#fLbP#MB~r-Q$H9Z8{l~ zmi$e1{-poYwl17@CF5x0Xbib*nzpUFV z4;PQg%5-H0elm{bG8H_G>5juQm!Ql3O6Q|hf#Z)}+s>ynW;IJ8bsV4#;0$0s#tHLT z^_<5!)aDSyw=PuUlw@7}e0(lomN*#2%!2kq5wVc?#Eb^^!?Y!{6@Z!Z#^PKYN8?WQ?7ziuD*KP!bR6gLb}6|8$Am9 z^G4}(#fXLTmA;+jGX(P?4<*QhjqI!yn9qLVf75V>nbd|k+BpD2ox2KKg_ndmi)gceuKmlNf`=4 zh?XTkdZ-yc-c7ssaihr~@hp=ZxORS!c&aHw^Gd$~}8J_jg49_}ghNt(K;aNA$@T{Lk{Bb;=UIlkP zW2ucN-WBoGx}(wuzmDQp5g2d3AC$|y^}luoTyfifjUK~V>a&W^<9)AvjO!4^dMyHH zybki3Z2u9^9X?74kxoGx)+y32!FgGb#9M$5g&RDA?fC-RGQ$#q zC+j*W7j|NG?61qVVJFkLLu0au< zqafH7X31;`a)q&a*g0t8Ad5467eUVsfnn|kx>#S*YlAALQ0913PRn);36X`o_ZT`xLW7Ra`sG$)@os2j(3q~A0*N9_dZ^W^oH{#gH8*yyl zjW{;$MjRVXsr`5hyU9kUU~uGWa-JdF{@=F^Dd9E={vfd`Lo z&?K<~XCrD+E;xS|;k~4x(_In^t+WB&Wpp0$_pM4p|4b1Jv6zA_Ns3|zPKK~O9XE$s z$QPk-XUK|BEoaCNq1w)nKSFg7n(iZK5mRw}tvz{i7SSOVcgc_s7DusW$&jyG$m$mI za|`)nffTzqO0eQg2}&HfV7HL6P&tgC4EbQNRnHmnbqiVDLVj)`N~n)?l)#!u2{s{t z+g0W(pQ$|Y0b-E zx`nK6AwRc}Ke+H20wu7OpoFqQLI5QEOF4otd9piA7fb16h!P^5ag^W+QGzQ(3G7!X zfo%>YR1^}}X)jQYs$AGrr;9~;lwgA&=tGnc?WCjxSBMgtB90Q+f>A+-R~#j{LX^+~l$5}lMG1Bxfput>7?4nF){oI*L7@!!x`nK6AwRbe zOS+{hp`nt#V<{KSV75WF9cAMyQ)JjuP&5hA6=mqJ;YpM+u=g zQ$j-_ArulGQa)7Eg}UW|&$L{5;L|LZ)}d&9^dU;4X_1F`XNY;|?F=yweVifY z!4+a2`XY`Jcw0sZQ9=Tr%nTNbX=(W~A`b~Fmol)@{bB$w02JPdP&D8Ut?gyD!|9xC8W2{A%K1(Am&HC+WEVT3b83CYe7C5&{2D8Ut?gcQV4 z0`Ffap}CMy5fT=O_k+`(6(M1aG6JzO>i?4va+@#B|i_(=&I>rq0ikWg7j7^O<6EF`2m zLzFPu8KMMN93{9yl<)v3nFo#>DWRp1z^8%^Bsh7YJHzl+c68PjZL)oLI=x|YD2>1N>=@LD7;?|5nzY5YKcm(z<} zX2YBL^7#4sUVxfD2=m}AA(inqt=Rk@O)GMEBoE4+gS)kE$NrnA6niOlJNIPuK>_u| zARz}GWVX^B|8s$n8_Mk%yml27y>J^DjT^m2!0?K%o#SD#`ucyRJa6w*Sb$GT2P%)3 zY-US^bwiZFKAZv>>_cmG5Vw{h!GGYNMdiUW%d`wG_*~q`y7PVU1HzRNCEf|TT&7Rh zGd5$qKFqJ0mm<5z>cvc0aVRcGhBL*of6)jc0P#BxrGWnpUGPKHr@M?#8|& zFuRe^t3U4^adX-Sq2i<10>u_6wm`83iY-uVfnp03TcFqi|J(wX%ivuZ1NwC1w8_NP zKYnqjyHAIz0oSh9?R?~!T`7;+z8e_Yt$)|ozFoEKLTYlyym^}=>esB*=48!h2VDz% zcKG`#A%|n$?%w@~JbnY+w0T+~997M>g!Aci+uF z{eK^t*<;(g-Cuom+fy%OTFb$h9jYKbkOQ(XVNrf4=dZy{p$%f4^@0(iO|z zyB@N?_l%M=W;}b)F|fgpufH^=>kIu~{QTY>A4R=;aL1J3wsR-Fdh`B`JvN?8%UsYY z*)Q<<=lk6A`0jldGP7SfwZ22)qR*clcIcaDroZsl!T2lJx92qZanbfaPVJwzvtH-U zod+B^_SAQ+vKt<{bg|`M9ZQ6TZCyO+M)J?UMVESQe$&05w5<0>?4HoFKbPLu?O@&T zTc`IIuDMukUiSz4PaV2;MVU9IKXY_v)=!fQ`z0(n(6Xzo>4{mdr2gc4^Q-qBO8seG zYJSe~Cm-37Hl$t6-=^1Dv$So`q=DxWlg^b{wR~R3`!DvHm-5c115d9mzqQO$n_DGT z-S*AQytn=p^U*i0w$|DFu+nc?@UuU*YZ-pa5taGi`+FB&JNfLp)i>v5L{6;nR;lHm zUpW8E@)G#~2TQ837I(*$#|DQwdZ_+t)#nE1+@Ff9peDkgE&Dq(UmnlAq zEl_NMVha>opx6S%7AUqru?31PP;7x>3lv+R*aF2CD7L_Vi3Qpy_<&CF@jq+^!Ic=_dHm!)W;*fr%10_Ct?<3aPf}9ONViQqBb61vQ68-| zQd#K?`6BeFGh{_*l{4gr&|}V!KSGZ?Ljedq;SAXjTI~!4BJ?Ce$04sO)Q-T$nfi); zIaQ>7IThaAbl1zNkVachwL{eIILK=Q;9<5~vjcRoz%#hvh;N+cB7Sj*)GA87)}z$* zR(cft+=>KTDTFJlepME?ppZ1s%Vy7*f3zx#ej$%qI4wVcH@2R|%CB?(Q!BG(Ldq<_ zY``4ATmY8{a$z7B0CL&i!vHSo<5E5@+2gyY=~Y~Y$K`fhWXGj-^lbVbeJmWNp?A@z z=t*{j=`}9_)&QOYJPmjT@GRgt!1I8$fOUZNfDM2b051aQe=h?z0$u^U3fKgA4X_!o z1@JmxD_|So4Zxd#w*YSgwgcV)ybIU?*a_GLcn|PC-~+&ifZYJryN>~XA)kA3{sh29 z##}yp0B{g+2yhs11i(e2p8>FhPAqK4GCHy828AbMTrvP6AP6N&W&H_-l z*d@+QeF`@6;cfeXOMuIOZvo!{z6bmO_z`dga20S3@Dt!?z%PJb0lxvR18x9*2iyeQ z0{j8^6Yv+{Hb5*sLz$GtbveL)@&#~MN9XZIl#qYaAFu^`OxJ#k&AjDZ?KRu;G`o9y zT?@J4!f5?wUH2EpA=`+**Gf8ldmW%W&nPF(7uUuG)=Xr?`I+GSO>or7nAT>33pBx% zFu|2H!3CM%f=zIxOmHD4xKI;Zmis0`9#r@%8)N8*`~^n6`|*xAwPtkcZU2CT8j{uUDMl#0$iJQe-|AT$VCGmf=|JW-{vHH+JGe-T<)1wXd!|734Yv+EBSFF?l94}kRRV?HA3_jJH!TmZWiND>cpB!9-)E<*H%j& z+-f^a^e^PWS2~OkJq>wKcRdf*Wb!C0cyL3lif`;1>J#}VFNSdaCh8qe!b!N**nr4EA zTLLM|y}Z~`k|svba8sWr4O>pqG#517mPdWu`LHD=O$$N8jdeeOCK>gcKUt=1SxFNs zXt*`*M-Ljdw4`Y%Xt=qJH14vhsx++x4Y#Lx(y%2apVoqg8_Yau*fNu*jiBKcF;9Ki zQj?~wpy4JjcN%WfYK01_ZPV(HJq4YeKW^Q+v){k7O^a=zUDdOl(9>?3-$ZIyL^0tXPtBDK60F>u)xFP1*{KbMT|Iw`!E1W!7Jso~{?_{XuzxbUw#T#6- z^5Qu`A5gEw=p5JV!sVf17?M85v-_ciwX+s0!$zzYYdn*?CP9n4)3h3W@%ip7a5wfH zfpJXn2A8|DZ!vYT1&S?DY=L466kDL!0>u_6wt#mF7&o}=?EXOz*qWzGGHz`>oQ|rYVEQH=5>i&u4OU57lIU>k9x%Spq3OYw*ef-+-cb@ot!}{m^%8d6P z*EIdQZ&uB>rzK_Vo7gpR!O!&%9gUjXtLifi_wK%4q0Ljb%kP-+?3J~n8eF(EyXA8O zUz+ye2c1VfVcB_Q_?{<@A!1HxkcXPrCofD_suXTjjG89XlL5)-pA9?XX>M4;}P)%GP^Q z-gq!@RkwX_4xjr+ozoTnivM%P=cj(Z{m_OwFEwoaNR!lKkG>rIWxp?$KK94%23xKS zZPTuI-Q#HkTU9QbwWjf&q}AWQ_R-N(<9_S#!d%C`y)X4{_c*lY5pk^bSE*wfdoS4H zm|_bQTcFqi#TF>GK(PgiEl_NMVha>opx6S%7AUqru?31P@Ly$t;tekUCyL{Lc7w|n z+q+`L48JzS6$RQS92w?<=d_CM3!Ig}_nq|Iu%b^dHmp>T8(_2zD_rfux7E59K!@ly zqHswPpQ{^jT*G6;`I_Lkq|->pWtkz$JhH&@3;9)UuF){kaoMC1$7PU49G5j3aa^Wo z#Bo`o5yxeSMjV$N8gX1^7$V*et|$eTH^k>MX)_}omk}CqTsCOLahaeV$Aya*z5!&Gl1tGN4845;-c99ZFA+!r2EZYp1im0bx%6JjmEQ*9W}y8F-uWwda6$87#fA`hb6dgNDqb&>igZAcUiC;#HXBo3ap-lPRAuhyz zNo$(D8{mdbm|WQ#?a@=HWqxc!pYibI)P zynO@(Da(?Jw_g|e;lk~$Vj~ZAu{mY(lgsZp{mSN5CR;?xl;0-e8p;>MHX_R8V(-rt ziz<_gy|)ONT@g@)e$j}1@(wJ;monKS9~T>|m>+&KX@}4y2r_qw z%~lfc=fwM?P2>hF`Yjjz@4(M9pX`w+Q-0%!3*mQ&EnBn|zoK+pY~CVoenm;j3>GrE zp-bX5nZd}XlqvC)Df#ewb3wulIBEPT1 z%?BryAl29T1*elrN!8cGpvyraGYqn-?2OHhC9ijG7jgB3C3JWg?{mmFUUgEhT{ta{=VthZ$25^onNy1;0y2Wa8u|=|Bq>*(wQFji9Y!3(+QGL* zXa^fX9zkKzK3Y7(`fG-@gLv(lXN`_$-d1Rb#@DBSyXOlF?JDgVoP8{Xh1?~`Lqy`A z4Dsy+iumMCHQWf)!FBzD8&17Qdl@)iH5Jns(=&Vmc;0BSJb1|eE?UaI1|Y3wOJ3{o z3~L8@@Sv6wCqr7i`&of?i4jQ@OL?^WL-CcrSW(!`5UPdGw4{nYO_KbB|F=J}pqmMw z$>Fqm;F|T4ZG#op%sp?VlmfOCQg4mkPJ~KNFW2Z}aZSxFmTtIOsXB>WY3$Q6E|Ltz zkp-F&xLRqY?G(kXH1m=1nVa)L#rQbj$w}jgGAQ$!(jhlDd-TY>T*YA@*fA+SITIIc z?coXOjyOkd)9~ODB`$ZgCg=F%Mox*0jNBC+85XOr8+5PeX3e&M@BYl?lUcT z>b)6RBa<^~T0Tq|mz-i*)-~Cdk>dzT?Ue0E4$Vy-nNhArpKOOc)sd2stoYxT8m7F| zKRYkDW0#5JY*{&uvQ_&#GRG+y$+?csj_lF?`98ImbsVg{HVH;JT|psUT$ty=-8-+cEu8jf4vgKN7oxRx0eV}9`1v;bHv#bta&5n2S+7! z${4MrjESfhTw*|u)sbzf5!E;$Ju7ZPaEUHsQ)gBP-cTaAMEM%gAvL0dYrsr*d05J$ zj?sBPg{hA+G0rsg7dSUk>mMC{;?Y-5Go}`<=K;3iS~gOo212CL+?3(FIYL29VQh-o z4U#7hi-iuztBE-Cy2wL{@6|Qp35zwvZ{s8f9s2TI%y+4S; z=W$&vzW(Y?`U7cBO0ihtsF9(4jU*23tEAKH>I!S^D>*Q|w71qmy671%V|nF%6ouC~ z$`sxx8LP=6jeI|dy!r?K*&IrC?*1pmST=3)*7WpG$5?1kR`!^YSy`cD*a9u+n4Dwr zSs+@V=*T{?Q7s!Op^?6}P623wO3Nl_+DxqpvK$W8nxG7;)&%9+v?eHZiPi)uui3OF zC<}zL3Cd8^CMe(6r?lDxjrK44BN#nbb-$N&VfchQDuHybbQ;E7GsV*XZ zNL-W6vn$5?)su)SmQqbp4k%Vp{*i7RQ@WwHVU;&))z2-T1Hh|C{x{4&K67 zJpMDdA6%^ueRQTR6cc93V0j(H>k;zW#%a`aUKa$~@LxDE=&gKaI8mkH^%6BLuQ#aI zd@Qm{UWf8UVTaXgGPi|N;ywjf@2llUOY8X>QR zta0i!Wi3&!d0Hi}MIN7)*Fx3?c`anUsp851uu9MC%jz{{i3va0jrj`Y7%E+O%{5@w#d3f9G180-tB#smWSmz*83O zunKrB?IuCPm56xduI_r5?)qch^u0!f1>Akb62rVo6q(s#r42_4?fXB)5&=_A!^;WNAj zPrmqWoQkiA>m@px4Z7<$ReI*-W9R+zHkg$2=RM()Y$M)9*zpMvIGDYOM>j$Mrde=3 z5AeTy{@l@Q`VI_QaI^sW5H$tjtggPQ77V)tNcfzkTc*%qLu~<&v6_oZl?cAPK#;FuOXhK9~ zR>R&-Rm2lJGzfFz-1yM_c-%Rk5uhfYj&6JolL?MH=d%ISaZ!^HlU8yx z@$Em2s7Y%3Hg7O#8rr1g|NG6%!#)eU9!=V&@7wjm&ez}mW}Z2J$ILu4qMY`YLNB_^ z9~4%sLWPa#V!koN4`StKB#kkNFO-||M_zjm3cFfmhq{pC$^0^(9Lm2d|1a|{mWdF` z>Doq=8`}Wc>@6ie%V%#{<%fQqANmbG>A3d+6|S6LIgg4gGAREp(`7ykQOC(2xjaE( zx2R0;gB(xhm-*yS{$2Thnb&u^PF3YUB;6L3`zxmFyT7!mBH#zPoO0RZ^2(w7yYl}s zuNZplCr|y}t*ZNq>H4nUHWeBVa(?7I$oY~(`FG|2WnMJ)<&P)7J5^|W$nj)enNJSo z-D|C3dz2r9Ht>XEXf0rqP zq7NYbc9{s_h1xR$I@LF$J-=D)W^eIsH{8#L)oN?;-EOv)*L=38y=8>`BGL&8+orOC zrzE!{hWJr59fKoj{i1ImeS?DeLhVdoLFzy4jJ3u;o^k8l&K|n&b`A>Lp)!Hzj;Ubv zi{viYZtbG2k$=l2v|BgC`)0ITpU?hnYx!o4Tib|nd*SxHQ`HY|f?&H`N_$p{K7jG= zxPg?QhL_I%@iX?s4Pa>H9Jm)f4mFr$WX@KdO4Pq1b1?#TfrL|7z@v$SpiY5Z3f!l_ zEU^*g#<=nL5Rr~uf!h?=jd(;{@Bqkw;6Y5VX-4D|JF;mcUCDDEY=gKst)om+UOO)t zL09r1#x}77kGzgvhy1W+jCI}wSWc%+q=WqJ3jR*cuR;DU1%I#LhuI6#r{M4B{4D*m z3VyaAF7kt$6Xg6vU;-jP6tJA1WTXQ>e&l|FBpZCmaSM69N2YA;YW~7wUF41o12#-Y#|pZc^Yjfl)qn zGK^=^$aT)+x;fn=^FT(ToH?OLXHbDnxbGZzSbGVK{5HgpHyrkMfwAnB0=EEe;@E() z9FB%SeglppE60Ht*QUVP0%Q6G3VNLaHwl~vJWj;Q{ZdfR_^duohxcD$&y&Eb02kl^ z8NgEvK^MntfXU+v>)C*f06dpNfG#xRDn3mmMxA_RP-5WU(7=<=i$1M^8i)uSA4HhKj+b6y`k#@>3Hh4*`Q_l!9mD^$t}53X%YzBcGG!i`4LZzo1ky#GtsFD{*3tZ0tSdARAsx0NDf*RX42rSr66s+6 z`$nguvjY7r=Lx_(n2-_d3#?npaRAnvo#Wtiz?BMm7soo}=|&9wlS1I;7%dI2viEbk zvd)=2Kg;O~S>bIHVKWSzk4HS$FcBEN>sE{7)QWVd6WH=Z3OEnnU&ZOH54Uj~fJ4qD z=vb~Uj&(R@y9LJjKg%)8{~%&-TSXlQBxYE7(;0vKB=`;TgEm+)$2uIMC5WLc*l+6u zt^wR9a5i8Yo;LwJ^B`yy7@y@97-hl$V(3?S5G3P6K#yQqS`mBq86@*If;5LQ=z9F2 zjmKsEt)0hJwjDv9PN2&=sEhLqrz7i^Zk~>Wb?at41~@qY%B8?(6`1YgcJlpp5$NYA zWd+c&I^r3fr&FN7l?v<>I0X3H1x7*EslZ(d+$}KX&CRfvjFK?!38X{)Anq3!2l-in zTL2FVjD63Eolcp5VMlc$9r^&K<5u8a1@2Se6C7*Va|IpS_pHEXz{!z3%_||W3yeH2 zfstoGVC>Hk6uux2i4bH9jDb_&#{s(pMj4(R1z*5_6$DO!G5tP)X91@85a7WeTVQ-v zoxu1km%tS834yl&9#rr&O$P#`a{~lj0>=P0VWk2c+tkJ?*h^MOD8~voT>>b}AJ(7k zA}-cpCC5x()N!n{0o^I+D!^_*PY2wqpqpj_0dxW8Ap-FTnR7XitenTdp2aa6`*ob3 z?YnK_bf(MNIDM2Z>*G93m-P#N%$p4>TjU`du`&I>Nt$8$nX5&I&Y&#dnET3J7mHAX+ zke_kzbN5Id$OG2TSx#5xUx)kyJbj%FFpY*UkjYrBc7ZA2R)LYVQ-S*gz5?ij0%P1{ z988c7g}^Q_>H??0SP$JC2jl_n6?E2)bAZrn2w?5VG1J{mh`r@M(-%%o$Eb1}A(Z

      zZWkE)k`09f@LUH$lfdbKPY4_Wm?prN_ZVTaH=ff+$zB`Mp$>x}$mUpu{jfyPv6FRi zthpL+w}Ng$rJ-y`$Q$M%0_lJa5Lh{8{!~22O!n3Z9!$Rpv7(P59)l##qfG|f&Upd= z%5}(eL?7qja#-+VnzkhPlI1XBZ~ICE6geH{UzZ4eCMP++a=b8`+{JmAP2S6KPzj`S zLeTNK@z_w!hG4A2WR6+Gw{gsThjzqDT>y23ab2A5$(ynrF9t(-nG7GDKC`!bc^;U( zJ;1R6tIRYXzJ$-1%`ubJC4!E5tK?XR{k%?KZ0jzLS^nLKmH8C%xpy?3@ehi07DF`H z4Uc)yVc*Uc7{@}Vz&Kvca;&F-O$*@*`U%F3M+|XMCO2`+xV_0G93OU)Th})^aZUsIeFv`gR#6nJ*F5?*GWQ4#dC#?dboa_=f0`Lir*;pPB z7}Fe7&?B&+#CWFy=K;xz80r~iOB1JSQJ=O7I(wGDg+M|-v@!|dB`&NE7`4ssqQR}D6Z1hNGipi*EgZyn+b$W^D{$G+6X`ITde$<V(0@Df=-Tg0A)GP^54tpo;)bq(T7a# z8_myj(+Q+Qom>UM0O#@aALtJ_er=dp@AN%9BA+Fk$CDpOa|T3fLOP@~4FVVEVRIvH zPG@r?{Twq{Js{{R;D4iP&2{ur;YZ!Gr0X<(SKM zf$>>`3VH-KCiFw(rvm2zwjzeM#%DDNTnN}DFv{>jfl-E+FXdU5E!e*&9Mfc+-F!*8FGOD`Ok!)0I{;qD>3lk7-=8L z19gu2tCQ2c`UZB&ZlntyH^)qd_X#@k7?v>}Cc{k}GkYT&v3DD>JQN6i1N>|k7ij)219V+2|A)>!B6#1!Q}>;78fs%lWkc zWqHeFdq3x4vfYpmKf*jV_LB&XnGCPvIJf}lO$vH1$4s{OA%-$i2u^UU11LX><$sXV zm3d&Yi(taawuW@De;SYu?T-Dhl4Aq*rFKEby6yK7cRbL~avm)PWI6nS{k$830*<+T zi`ZWsD)R$*Kz+d$tdw+b%*q~tmFKOen7&9xI;6v74(DO|!pZ4OU${7C`l3tFv5anx znZD>1I0Wc}9J8_*ir8~K<4foZ(`Y*5w;>&5JL-#U&ZBHE9oB#4NIJAj4bXczo#~Ne z6dpiFJ>nEN4sf@?*j{H53q2CQf?=jd>JWR^KNfdbJ`7_RzxYEFkIVFklgCx|C8kH( zfG+EicFu#zj7n41DK3$w33xggzgSyW;68zIyq{Iz0REqsBz#UDx#E7SLnnI5r=xF}DW z6u6yZb_PecpfeeQ*cpIgLmmr3!x-`~9{$tI`Gc{p`b9d(WWYi+8^&OjMR07wH0wAH zF9zJCp!adi>hJ`|0aJjdU*IbMlk4FRd+AAH$NNK@kodINB(Sqaa(@HkR#zj%9ao%*Jx3g5D=Ej^z`GmE#Ni)^~xFUC!u%@I5?Eaa>zhGrHHf zt_PBx(^-`;-v{!Bb#emf;v5_})E%FNqE{YwZ2TIK4*WPSsKCqEobqhMC8R3AhW&<0)lw&ron>c3U*U2#(zpVn}`0W%J z(?2Wtar_PnjP-0?17Bi(pq*pZzAld0`0WHN>+3G0gDrs{tWS9?cXNI%R-&8na2?&J zz-I+!jj73Ouft<44sbt@%f__{I}!A4 zOs9Zjwv1h(pgRS|pjF@(01pa`YgtQ4ix3$2CR8EA+CRW2Tqu1jfK6c<@=KTE@@Dbp*$3TvNdExV9o) zF|L(Z9^>&mF4Nb^jGvG3Yz4Lp%-ThPoeJElz-c3*%&Y2JZy|t3Y-W0bpoTlb_;wZ;C_x-yHiw#-g#hS+=_JQ!*LLl zaLmSatDs}qdpQopy!9#QgNT*m0@A@D4JQ?kq%+-J$LXVVcR?fL*I`syM`O~hoQ~Bq zOvgNsP4Fjlw-vDu-5t+)nC{LN7{`01B5tdov+;;nSr#Q0W4xX7voYQ!(!nu)f@7w; z&k8!GX}b}=gznDfnCWg8$83yua?Hkfm%up2`vk`HO*gT0*chh*qqr&Hn9cvVIc9C$ z%P||{eSqaLegf%!#`u5eqK_%+2m7KVorPMv9`4HAM=IF2ihQPldSsuG^lU%$Hb3+e z!}QNIR3dN#>r8l?;MiYZ_|5*0p6Pt!g9Arj8aQ_Fji+Az(a&CN0^T$5H-mKl`Gwyg z&!N-q{=Q%Q>=%d;J$vB!6YsqJ%r7w}Pk5&RUwOj(f2J7#gduJl!jM9^4}PYx=ZKEf)|aiWcJQ2`;ff!bPnkcY zd-7+yr2HYbzx-jkm_I!EQ+}=|e_FDkpaQEZk@bi9b^)D2U%A9nxb&?opS^0hHO?B{0zVF+EEg%Ki*7a^W-x)1u9g)CN`fo;uU zgpa+a-#qZ^1#dicXz#IuVw{wy`b?lpBns|;rDTmN z-Bt3wP_=|wQiSRcG{wBlU6!@D8f79SE68`Wl)F=q8@RtaGGvIF) z{2|>U!e|JS;BOB6#lT-I{KdiFT=>J67!%-cI{cwPo(F&P;co%_Erh?z;O`3fyBz)& z!CwmeVcJ)U5a9p$4~+9;&%JpBM|n@*{*SPi;drZq@wP@~B{eX1XOju!o!|ZJ_@PhU zK5*=1np@S-n8U`!+Xpy18^@f#9;5>6S0r80kBb^NgQ`iPYc?>HSzlY1S$k6rrUZkG zQj4GDQFh_zuo9jw&sX&&<_q~f`HCQ2uk**fa`x>bzubG^*Ka)E{ioMHJ9>!gZC;K> zD0c*mW+nhc`7j@itb9CQm@fbS8OY~2g4gXeI*OL(QY)7mb7(>|RtJ-(V}v|C_~u(D zWXob7$OQ{o#hw+y>=U#%Uj6f1zwYb9c>9P3e!q_W9!OAf&g<)Ak`sUB`L&Q6pslV0 zIWIw7ty0LzndC;$A5o+U>=3*l^mF(f`BZ-SD5QmDo5So7tow`QM@@ez{HS>^g&#Gc z%&)yb{-qK5*IWd@GXLs};8*5fcM<$@{;_@~5(uq&0~APZH~jx~@c%!7KE}7LQ4d^3 z@a9Ixd6gE9!sxgRM|Cx5uo&oVaaWgBZ*ma4a?-`pLEXI*vGM7puP=+ zUM7(=+ZL!{j8`e*$rd7yhsTVLj;Dfnw~2UoBJ~;I;TA7)ll;_>j9(9!WU5O0Tw=N9oaq@un8Jz)6k)VTe|yHmt#g?KwPc&sO;k5_r#i(QL- zSouY|Ci2Q(o_eM4@LPXE+yBjvUw9wm;jx_I%tB|m_AdldQ|(sr{j-S)Uw{hw9y@&>T_=Y4ml z29NVZdr3o96lGD=30VL8;8yz?q!V%(2=*nmW)w@gLPBnCmsY|&>lv7zG?1Tn?*E9l zBigObVfx#jAN0`URv-{XD_;dRiJqYwG zYp>nEJbL7dr$qhW^9R}QArSA_%g>&}Jn(opO?n2(#nVH5!0A>-Hwpe0&wN&+meAsK~AtZfE+~2tG0DH4Ax?={F163*i_-@e@-} zn6oUc@EW=_>l&-4+`K+sV5PEOO|kXsK|5TgV^NoJ70K#45m zFy!?)) z{p!lHdh0y6dO3PT8raTVBjZzw^(sF-#oFMgcC2ost1&Ou+0k@OeeDL?u(_eCd_x=r zOuIMGn<^cU=NeG+DJu#JvI?yh><8>e=CDH3S)wUixlC81d0AVpWb=56#g3*%>~4a$ zcypa2#Zqh;k#Wp-!svYGEJll!*IG(^G^NGaS$WDz$9NT^<3W33k&B88c~`Pz6lSFr zXVK!cbnrm29HTQBH@bKuDi_8yKF{X!d8`Zh?!OkRg)V}pDuxNq+e{XsQOfk~IdOD6lY%a#$4xQf4Bt&@^ZQtX7&+L#>t~ON?cO zB|4gd98l^YltL)iP!@#}>Qy0Bks`|D(J^Iti1uI}OXo0?ZL+;k0ro&|5T<{S$t`(a zhd&P_Hh$PsP;#q*&$oQXIVH>|riZ6=@c3ZI;wJ_*>BYrIJ0)3>AI$ebNSDi5H~1}D z(0{Le`26#-$AeNI^|)-6@+YCL@txBd0ji^-4*YFLedA`U zWm!>arlVnXeN|m!Rc#Fjd`nSAcGj{qL>1+=7_h->iD9+W%X)thp+L{b&t0)B&%%1g zON>rQG+mjURhY%Z7pRhv$w!AN`Z$*4$>H`xoqZL_D#^;A4Rxgzn86X59hKU7GD|78 zDbH;nQDl~t0(0vbYoqfKH=K{M3UH{r>&!J% z8@%kj;jCILX10D10el$GB=X_ui6||xmQmknV1}G}B?NZBuqNa6hw~V|+rdJfVd-!y z^%>O+atx#e;8lV-;$`76xXg$%U zzNH$@E$|pvI#0S-;uj#Nm<|XtNC*3c$KLi`I*;UI`VTyCd_I;gnksA4^F;o;27X@z zlEGvDV?D0~E$6cWqG?v%lAOG(l$@HH+RXIfhRn!LD=f+?PTADBCfP&G&&>r>hY?H5 zt7^dTfO2B`mHyI4-70^4TQC%?x12mbhEr)~T5+1U>CB#&M*NgVJZp7Xbv1=WNJo=n z^`=ILm7BNTh9TxV_B`oi*p*Z=S#%054bnr+_y zA9kT+Pao$1aBSmf-Ur{F-hdhs{Z@}{ro_mvoGZZoSf}RwvJyg1zvOlp&dU`59p__k zU2CVt#e8h+naY&VuTKuZeh>=M&U?P0V3_Vb-%vSB_nvRS1#?ViW5(+ zglFJvNQe*X<=y9w{hUC(qhJ0S8{1feI99=EhBm^~JoW2Oo^jjG(+XU!oliRaYvv!k z%XtvWiRDJyAH#j3{4c1!?s*2T&kQ6sHlMBHd-rWwt6)82UR1y*>pKZ(zU$Ff8eER* zApXxgdv;$q4YX!;STti|3;V(q*3_Ze+6zp+^sS%J<}uS>7-^Sy-Br zmkE|_kuZ+g|4Q@HmSs`dcQ064$}CfE=T9LZ_h}l4KW2LiRw||gu+}*r%rZs$t^=OW z$#Oo?pO-5R{dsifeUwga516^*A6|KvgCU=mTbxxW{CGu9!DC9x%%m1yZOg|s>SeHG z_y^~dXhwb>q?-o$p-^m3X+ntiY?H4vdAY#StrRWgyRUfX4=h3W`06Yp>)1QqbQTZe z;>Xizye2zXUid6M_i^JCxkJy^*E4v%h&f!IJjG5ly487(JQ~9Pd`bIc0?)!Hx}n~E z&6}{D9^z?~Jx`W&=eKV6s?Z)yhV*&9A(rC9CRACOFK#Xc#}C>eXJNakoKNL^3NNew z*$qBZf<8+PQQG{NF0T1v`7!-gNZ3siBwP4k3$$&p7dZg(qL~eueT+PM=!k zzIndfj!s=7a@yD*upc-feGHq1pEKHT$KOkafA=?PF`ro8ukN4narzpxCF+qtC^!4u za*G8$f2I9+VLug5GR1Uw-p)6Yxt~8$9&vkxKS$}eX0voJ-EYNHTzPwrmCGdx2X3Eb zv|dLE$N6V^@#CD?3YcWiS+*=IGY6;Jxdir=f~Wt$ql6PTvYejhfNVjJ&4*;>=}2U* z*Kea!;_U{SoqwR+pk#C;AGQg$ZxrEdkhP006Zaq#{X>)rC<fR5@MbL$5;V)n0n)V*Eq; zZ2XI`jy+HA*B-yO1nB7Z7C^XDgV!bEJh&%sR`9{m52P?Z?#u5@9;SQyy*QuF`Mv$# zN*ZXoXu-e4T`|gjjU!mLlfSC}I&WCcpuF)n^)_9Pf5V0UgWFQUrD^UC!jt$8|*2M(*HsK1?3RW?N|4M zobVj~evtg$4(9tp&+>Rd|B7|HZqQEH9+%?({Bzdrz^`7JQ=C2QyI3w_)s5TY-kuSR zGl+?OkgflKX6F45>`brp<(_e3C!DV^CZGW$Ze6{_(nt#*%y_&yse=od6)79m{c2=7nT7cU zV&xKC!mN^}P;`NjBa1_}9m`D>u} z@xyEr)TbBr$j~0{X3s^L3iF)!xy1duO)Ngo&q#mEzkejZt#xtUn8!oHTEg<@3P1LH z1W)rutDnL@EVX}ci?1X8z593D;5pw+Kk2LQOT>QA1xM5He*D$bWBw1Mhv}9;cm}Mi z3+;1^2R@8vW&CX4_eTfc#CMr(BonV(G|sIJabc@AN^doA2<%_H7c+ zzwmy_t6)FnSJ)y+hg%&c*(m8_ZHk^IzPrcEhV52K{B0*h;U+%*ES&%BpY-e*zU2Lr z%8{hRe*C}7h5rZPNWF*qCGoZm=Knzm?*YTCq3?C0PWZ)_zvmvNd;5DQhUwn^-hiNw z^!E(x{W250Kl|+4hfY8H_WqB&_hnM{yMMngS-hV%az7>B*y?Ltsglu0`+ZKJf2L_? z-+03-_<-=uKmRxUzBic8M;ZOE_y7Lm$AKjECq=oC9r2zf_SFCQasRCMH2>qrebfCo zyv6P7^y3B+W&8c_^W(Z$eBXW?w+7GeU0v+{!EAWWKf^CXdGpWk3!C6vum25xp|6!Q z+_9(hm(bpCjhFk`rM*|@D}8zG4E?@%NEg$$LU=L$A^|>(H#nE;l_K(D-!sQ?FHYat zH};~f25P9HysoUiu?k;SrRAGxWm!X|wW=bTHu|8KkNBa1CN08F1Rrjn!ahwu?>=DJ zu7Q~c{&p?)yKp$SarC2kI_I00!Ibz;%Qs*}5z7}L%4Zr;K0IrSrw8kpe)EN%8s~yt z>*wXtu>GlMW5K%Xi29LNM*Tl&W*lVh{_|7E20ipvpyNJKmk7H>*eAlXB7}~`_##9YFT!jQ+C|s| z;TbX(W{kYgV`^jc@vyxB>F>P#>=#e}6rbA(boP!A-%01SR{tCchLiq0$Ht7@v-cd7 z^I~?;;kg!UPoG!nDEWTPBp>(l--10DxSoC%{_qSjc{UE)!$Y@_x7hm{C#*94_kQ>} z-9p}G`(rv8{~v(&f8cKb(P5 zKU^LP80QX0pUdYau8!*Uv- zF68s+d~x&gv@`zx5%uDKrXA%w>|}xu%6qH_wcm32ekzW$LY4x|FnFJV1cR)0_=qHa zBGRS?M|~-*&6TdMt=_buMm`aV|F2YeFw%u`!!;9HywAZY2YmY|TlDiv1xt0l_bK0n zdZy%Es4u>+lvb_r-dNg*M+A>7ImW_r5AP9z*%fxM7QRhcR^8~R=Vv<6;itno7aTXj zEvNI>GWO2*So*vM{I8H%$Z5vMTgzK_py%=OFp_T%|`uL{%qy5FmMkIBc@>2iL*&iAT#`=I== zLi!le;ph0;O((Y}mUDO?GKJH8*dYzHYQqLcMHQSTD|*qWU2k%Hz8~0gUI*W&g?fdO zerN{@ng_q%W#8|yZ_b17ZOHq&xE>Pk*}{=Q(C0@y5j7iyUq)-j^SwQTPxd^G*Nef- zLnt=rp<`q)irX6l5W@MLprvsfVH8sltgVQjbZ?3&j!t!_V z_J)=5|Fi9lTpS&IMME~^FL(l@x54rES{mW9rBSX-0VN-|G9u(RSsKenoZyH&o;}EL z(sy+92&roUxlQ2n_uC`WdA-PWBjmq4|AloTZ%X`|qH!+Nn#o4WOoq^xol?N)qwSPRp#MA0i@4eQ^k^eq zoSo9f`2E`{b@2PYubuLbpBE_@FU$4w&x_#c_VPLkw`=^*am*l}sPLRZc?N8>J>@^H z_ZYT-x5MX0I-x%+=10VN`M$V?{A2w8Y-uU)UI7x%xscuQe`|gO*Fms;`XNNS z;{=3gci=k7PK^_!m2bOa5PtDxcbGtKbGo(EB0MWX zxEzYF*FfmY?ucjf(RK%(qx0`LKaveAVtj7u;_QwH#_!+m7=(SR|Gsv|KYo7X1iT%2 zG4mt;YP%zz<#TwR%C{eJS=zs2_Xf>zgO3G-AH~edbBJ;hf@suU-&u`|>xsbi`?>tW;5!)rq zlwiH!`~MimLx}bY-cyD43WX4F*Tnb#F(gD9I6%@G8|$meH#HImy*j-VZdw75Ld`20 z9Hf46ZT*G>bFkTHbf%XzsGRXPll1hYtoX~)7m(Qaq~yzD=UqnT#mA;COizm?327M% zvy$d7Ac={K7vFkwW&%me%u2{ej!h;D=Fg9vmzkJMV$+kel42JpLOPkr^O6^57&0<% z4X#*HU0dE#RxRCCR9CiIs-=s|sv8_ZcV^Vv;D#NzbZ=Z_fwSJhR%VDUGpB;QRb0O* zI6ceWR9D;JkV3-Zi-}`HT{W!FWttrIRX6S&ld-9R;$1~s?#j%pA{%J&H3eCvnIt{Y znh+l!L!F7yG_8Rak!MUbYlDqDLgAKH167Cd8nKanr7Ch{%Th8Kg48N>oNSgU^1Y~UAI2mS09J*qSn z-d=6O*YKo}U?Uu2o#hYqYHxk@bxz^E`DUnJ%WyxAm{!*h;(%WKag;V#crYkzw zNC`<>T-9p1XNk7r)xg%khT8RcK`(CCS2gQWXnck`Ln3hLt{IM(Hy?4g9G!{R=N{3e z(E#!Sts?q(T3p*rFS|^yll1DS6#Y#DRWUTaC9X%`1GmGb-X5^yvb!R(jJ?@pikY5; z7mBYMpO8DgC%9#vF5%UgX*#&Cr;(~{bC>F}*p0i*FKhDfqNA#p)xp!HEK)5^$7`&= ztafaje%o}-wI`?VzWn6$A=d*hProBDbw<>52Z3+x_UIWOnAuHoC(T3enYV8~WIkk; z*59>wO<;%lq}F_jbeMN(9x!k2Fgt69I?SiP-C^!9x0xOAbI+8m4){4rd#CwqHLaR? zA01kHZOm=9lcx-h##2Pw`N0$FGvvh|7i}ts+m491xwq7rQCU{A)?szEObIrY>0Rm` zt>vlDhl`(fLhM1eVWKuDSz+S!LpzS4P-{JasD+E=4zreb*s{B zYvCefxaNC(d2Q|bIKnSFj?0M0`>0fT^T#H{x%vIVT>+75CtQmJcOci;+BPMqE%qXM zi}nn8LmPMK=mS$!59&8+K9PPEX|Yc`^;rq&`IiX1}o7&(R=`%i;661dS7wHZu=^n|VddktZyMkIDw8DL^%MBR^v*8BUUwuE= zI43n_9!;vBL_ggvxnBLV4R37?Hol&k5<};`FRdk(b63pk3+emxigUInuLw4-tc8@i#&Jn=#sA{8e_JqH zs~%Su9v{A(^e>n$-S=tYa$=SS;$dpNEcwq#gj&i!DyTd@;a83y>Hk{yV8Ral7H5A+ z{g3B3ZOh08INdFMQ)45ktx5Rn0aBV#UA20>HJX4pVOQjW?8Lj>i-^DPTd&hRx2l_PXSdh08Vv?_DsjbpiPiUMKou z#KOz&t0~MZvYgDB9K5q2$uQBj0hCldVM;14yGmDKyZPm!7Q7ms zvqpL;CMk|x%0@uFu{*h)S!Rmz(b*a4oYqX7k4q1w-BayI3#zD?xhTVw1v=>5n8|Pu zV(}!K?um)+qf>I$+*wZ=4le;;BDjCa!l5NSr_s#(a?R#L*{2g$%}5OnxT7T@^obeY zDmY~;Ybynr69Gc!)I+he;V#ZcUh2+G+-vfA`%N6?5oqrf(+{bP&CQYcYK=BZ~Ll0C!`9LEmiELHRljMe% zH>izcqzb%>(@c%CURsoxu@+xEHQ^P98bfB)h7ju9S+>?rEby{r$Vb~7qEyXlJhvoG zt+C+yoOh|Wq%GE4@DG>DEmxxNFlr-8@4@cNy1IRXZw5Z{MxANH^eFJ$uv> z*J`#@P<^xd&E3C@#~U^6m)$<5s-dNBy;F_v4m6LMxK`J=*`_fY;p$BF4CATbs)m|P z)zwj%I=tIriLNS!&~-5s7Ju`)Hf@NZ{Xc33k!Hed|I064o##>N~3vF_5`YeqaBERLE{Oy*m6b0HiP_HVJf zi*C8BIOr!TDJ6e$spa$b>Gx^(Yb_JTKTNs|#d@in2&YJU?prCh6LzxsVcH!5r*WCv zX3x&LDN_@vb7z~60%xQy_fIrTm!z^jq1`SW3Lgm2Y^;7=%XY;&#eI%j1Jq~KbH?$_ zFGN1pasU-mGf7){U+|~u5E`mcYmSb=TNsIa4da#3`I>x9KRZYJ%fn zOWCukV%HkDH8I3;GVo|%oC(jy*HLHw*l>0!;s9QwFgHT2nHpXwg`Eq9V^Kbx1*b*Y z*`0@P9IdTxytQXq+@X+<$E)?BfsGQ?(K3B)96RDMwN8ILsaZYAdhCjgro37=zl+di z?`jEKJ_T-Vdw(+ALAa4fa0lVG$w#tNCtLJ|#BE1SH+X7QkSh>6kMh| zH|==-@%$M2UedJni}Zb(kF_yF+PSyZPQP_XyYZI^Kd0M+!-CgMb}paS(r~0QGt~0h zhc{1T(O+=8;mrdEkblI4SDTVXF_s9kNMI}x2bvvlMV(VzV+}6_#nAce8f&u2 zL7{hA&4DC*`iTXG>S%MYQAH)fO~E~yh(H~P0`hH(#U7p*E!}U?u3A&&FjmK=Cj~~K z8Si$0f8j{bW$6OK?wk*HDp?7`(rM;mxTQi;ZR7%`Vamp8XVe{9=l9{r7Zcv7=j?)O z8HjwNo>N?@M*`u;Mu+nt+^9$7EA@zcryh|n)dTIw?}Q6$*1)BDk{WJmsLRc=#7K`A zZXgS2vvWMZOmBOLdi%X3h~J{u4cF*7FSA*LCq_4q0rQdF7F#}l_-?wlE1F~Pj;EdR zH2u-Qgiqg!-)||aAO`|V3M^9U5V_Hr_P5b3#rOBPUnCTp3?%m79Ar(w&K&*F z$G^F4=%$v5Uu0ari_FqRq^q6eG>Mwrvvmhv9lp@9gEs5(u3G=CATyqNV`ta5Ikp}N zqR&SLJ03~a2G=*aZ*H)~k4dPxnbQ9@!HM((cqdy&!j2zlLuZaZW!r%&tXFDoeJZGQ z>z-c*?cEs_I6I#%4YhpnR>h}a%{lWbu9zNdzZ@i^s*!v*hOU4)S9 z!c1vu|2BB*!WnHdf?Ti5+q8kYvhU4$LmyMxtKVyVGI(gpsVPanpF;1X6=PDg5*TtB zbZ*T&5;Rvg*GWwvdjFPCq3a1bmUC2lbF>Abq&Q(oU z!SNSFz9P&3cZ4~T@tPSTUk}#2MB?{?rAq^NE7(cx{admEqo%1hCe9NwG#;g#; zG!>X%lDeSYR&^upQ0*tw0Ct^=;9W#Pj%piyYCqZzgnO;^F++5+>Sl{n_Tcg0Bf<6! zk}U!ZgfaOUv%olT^DDW#jQ2~@V^&I;aS+@tZP^u;u1519E8|6thn(J+{DhBh8c2 zCjH9f8asnpd&aJ;ETGi-18c|9j-@3_cTJ#a{V#`ZRc}>G=BfFh^6THDrTV#V*4_Pl zVRTf~_(^|DseLC^ldS17QQ}(l;rfQhG+pa=z3{?%ZMb{fx*>O5OWgg_qf9Q1Q_3C} zH7?a8tz4~9r|b6j#cP&Ty;fmeqTgzu=6XYU`P*EX+l{fdq`Js1YeEctS@WPew$IU# zHpXe#Zd^{fmdD2KS_mHTFN?2JZG3*~)U8vKr-r^(IU(#}a$1kqICUJ?c6{>SCu<_R z)CZ1koUgw(aI3CM#ja$!qA=^YDzdeIrE6_*#sJ>C)J%?F8>uttD7)xodG*z41a4OP zHcaG*%aw@yrjrwIw`Ma2!w1x9QmA$Y$nf;6WVl~xdZ)C5=!&ukyQvf|Q6hQ8{1&C4 z;(W;f<_+ASM3zy0g%XkPP>RPJMq%bHxHON*cPJ6OCmC)Nf>~Q}SF#C3Jqd*Sk71J% zze?#WOrU7usAjGyX2$zvE!Tl;w>qy@6{pzvl}ItS78AU<7hF%udn(bh|(WROAAt~T+S-el8~{z*+o$D z=B(-5h|UI6Z|~JO)$gm_ga$U)_3!KcLaA#UIrexY5k;8AOjF4|lXzIW!KoD9d<_ch1JcF8??MMv^SiwhUtp4=a2w!eII^^T}- zy8})}_CzLs5OKwoz19Eyp`m}@n$u|s)tNIie<+2E%J{vb8mq;5a273e)HPL?t-de1 zcEOJfbI8eKLZq?JF;|IWbPo$9~4h}X4cM(3`>vZ z&*y9fOGDDqbeUIg{qDfTBlm~IgYK|UM|}EpCweiU?Cdk&`RVknnmSF)J8Jrq@KE)a zv*>-H_l5rO+Oo^%j@uvjN~1A_wvajWt&qq`k#CIcm|wcOVD-6G;872qoIgFHh!7492pf(u7Z-TLWmXob`FX;%Le zIg1aeey*xhJ)f`2Rn2YP<_i10o33$hHTDz-IcLHVIoIbNEmc>4kv6SZO`iyTB6Q}2 zk7w?gFr+aZ(jU@4rN7^FQgu@GhAMS#SlAoKVH-z6^0F-oJvH>ncbt!GC-G?=(#-Fb z&Ac&u>tj07n<|ZOdiUx>+NZQB>xT?~G|bvoFl+I&L%QhHC7}xgUYzJi{)8;NEZ7)H zq~8*IFv{nSmx=TtRIAs9ZE1gmaXC+)DGpIb#-BZ-zrMd>e?|tANi{JQCmVTW3xBxWvVG<8>H4b8DtR{)NUN{ z^;Ytbb_v++;Jv~SCt#bgd5&fRm4bKLZflI%u0!YlF2m~D0_?CPEMdE8U7%j8ipkqv zfDY?Q{k)wi+a9ov2|YxX#io3FRV;a}`A*$6Qqe51*!dx==cV~oJAEHS`ue7qvSACIct9z(BO_?ga`Ky1CCn{{S*YfW5VebdZ<)jDV9n#grqci87958bXy z+|hnZdhmep4a=>PTas=zh!g0YTu)f)i`<|jKu46$9=i9P*W))CY_l!)8D{5fx^SpX zGcK6wmuH+MCh3nm_8b1%r=qJ2JyTN+so(zGnraw2HSMu+r*xAdkCBFeXlbl8x0H;P zz8iSoE%f&Is)i|b>s zokwo1y*jr%KY5HzpZNpR%!Fs}nT|$W%vtqSkr!5*+Pc8 z9xWPs<_#c*&ljC0>Pc1!C^zn|!GAVRy zaF>Ald<<1!*u7gy${1Wkk0l6x$1dvRvH{`?yMyK!2N@v?WF&* z4$0wqDo1PBdB0n?_7!cmsYqAZPy;xWA5L9w6A-;F|GS=F=W#2TP)J9rsF|Jg3=zjtS%t4s_QA+ zq_PM~*(~NqZ+`qj$omgT4~Mi#ID^TY6qCY9aov9sos^&>Up%B)Ar(3{lxgbM4`|pa z<73NOHL5KYHVI@u;eN{(Pw7DTn~T72dHLDL&qW!~Z|Ty5>_2k!?u|h>Ygsq@h{}YH z3zPgW#S9#N{r61vOA!;&{`<3Fx5>J3Dad{k2!E@){oMl>Gs9vBNzIf&HO{awd(p;~ zLFCsd`^U<%zl_WN7K1YwL~9J6z;rTcY&CBWvvCuKOiGB|u3rZlVSe8BYnD}AS7Fts z>|DI_F^(6nUtXg;G&gs&)j4;cQ zv@~fJfq6~5RLERq+niBJRwNyr`U`{kH9D*OuHKvH(52x^?4emITjb$#jf9h%ZvJKr zS)ftb*!(8#U5Cmdbj~y5Gp1R886I}k@NGRNR21(nh3QKo-^$|@hX+Wi0aO&GxmT@T z5~8sYt|;oQ{qy4EWuOm$b3{3bjRv&xDbfezoG$80jAWrr(lH{s(w@y#hcw+ zQJfs_j*kH6hwR)w6ZC|evio4)i#fe8>=Y`BGmAk_5H^Vkdg4TG7VU}ncx>DglT+tR zNDuxn_|c>k?bRUP>#U$HNXTn9B;?R|Je_Msc>lDlk^wwmxqRGJakXQXW@XHt+HXMV zxhcT>dIRMU~C@{tr$$Rp_PIe)8L}@|T8Me#~{twntz3>D|}#&)i-Xd*~oe zL?yld=I1X5y7i&Pm{jA;_o9u?l?QXy*aB_DZQM0}on=}`1EJ2y)oM@`9}+%8>F(dw zH}eTL;YC)J5iQpgJ=aB;L-x0k6GJZk))OdVZOPqPk$hXn*o+WK(dlR@fW zR2{X()H`Etp`bbjX7#5s)p3~akIP$;n~QqmT}toM9dApFNWNXCx@T+U_QLUYjX4VS z#?6LIr|>LPMW4NZRGo*vciiT!Dl?w)yh)s%+1UEe-A?c_AjFtwQh zNxHh3x<{CXiT)1R2X4r|wg3x#;+~&(1<=arRNMIDwwQ$AIbVFN?pK3ynLX*Gt}bn_Vu7%4h1FV7S7bK zpW2~%5NFrm8s@B&oSK^2%yjAMc${2=xiy-ysc}s*&aFM3TX09ZR9bG|O|xQFrR++Z zbI8R5rg`Slh7$L>_rhG-EufzEeHx@SbnM7*>t4~GjcK-^dJ2w?qX!?hWukh@9Ckrq zhlxCWW&j6-JmbhL%v@a5-!>l-Uid2E5tY_t}McM zhdEp(!ExFJ91}FQsic`7Em2FvwuK@BD{gF&fK&*7MpaF8T!oo%T0+$czD!F6-8C7OjuTp^YOc7_`4UdU z(f{|8%ePO7CaZTmpR(JwBvS1TapGrfIeGK?4aBc~omvHgL*?_v2Hl}LY zoc88zOVq7JZkYKZLTOzyfG))0l{W46vZJN3ZuPo5REMYK_1q^G-Cj2Dv>Yz9{^|k! zA=}*82@7JKwLN*kPPkDl0W=aQB+4|BttzAPMO$XlTd-(2>kq5)!XuX~MOEaS&O8{W zc;(-n-Ha{_dN92!x?!meRnh8DYmHIwPPM56XEMJsHOdYw{%$4gWiHCox6{-j{Q3UubC&$}kK@+LT zy-XE>CQ61iwfAC(e)_bcVii|KpovJ9IKlsmVO7L6k&3G#&_s!#iopG=0%epLF|3So z1{KO^_S9X&$|x`Tb5usBj#Pn8K5CodR1Kgu>VNdNVY_}XbI*|QbRLzd?o|Ci2rKR8;Ef2hW-GtDFmDkYVKds2k z=ms^jb=}F0eS!1e3fvOys;K#H#egn~r0Eia&*-y$W!NZz-g@5tJZ|KA`ql)gA|BUi z29oLm);fZ4ZSD1WR?u4KNEoQCj)1KI>qW$ka~9aGX(Hu7JR zdG?_xhqiqQb8Pxkwl2%@)pK`5(LXK73*{@A|7 z4{c4;Z`QS#>8|-)WldeJqo>B+r@Ie^7y3GdcV9n#z&OVG-URnD*E~r-U(AN7=qJ|* zCub=7iE+EejWhH|TgVLa5S?9i{kY(5<87%A2crrbT5tM5AC`Ple`wFMdrs=3raga5 zADuwYE%~A0t|of5={Ac_^R#NOIY~lq$6~@0027{q^Z#b;4f|PLNJaT?e^9=e$jAO= z!@EUWC2RTJQo|se?f0N|tL2HO_dNY@&T|7P=4-BB_{a}C0xCo2Z%uuE-t#x=x~6I8 zM}|!a+yCB2XM#SCeWK^lo_Sxy9`8Bcp?*lcGrc2$((jm_1=lC&o{6btq57W~?V678 zj_{j0!d*#CQ4O`r^EH{8grQ%BsK>WQsHJPj4;Rk8-8AQ~dsLRmH`S%Rrn>!x`VWTQ zICLm|fBLV$8!Lz%zj4Kwjh})$R#ULlWwO3$51`~r3mxi?ntb9)s%?3_Ao70_HslL! zIWfj&mLB~gg-Xv1&zQrM373FmrP#Pd*q#HBfN($+mw*OGbv1!Kg-OwbZyUm8Q5E5K zbSvlsjR^#ydY+pvl&Z(8jIbfae3X(j5Sx-_4P~1Xs0lZt7_OpO)w3FO&DtKAtPhw) zO&|@;BpcQr+i*f(eHo=%y%e4x4t|G49n{S$*s>?SPZ{NLL1=~Iwg}hTcf2h%*yo;uqoV;!E-qYWz zMk$Hk(WP4ya^sYRY&8tdXymJ5R?y(;$76a=arG-&7^^1ovqZ|ESuM^hedaPgKpSvWb?kbuZ?ts`6DgmQ^>aJ{m*VBpu&a z%k_Hb%f?x1o4rMiXQ4Gd{nI6y2K$0Nk}E1fA}QufrZaSoZ!Ndq%hbjI?82Z#dgZ!P zjp}N`RYqC8ovDny;M11ZIo4LyR2o-@m=~qo^w?f!r#`)5mouaJ7mw1-)6-Mveyuw2 zcPoz>9Yg$wenY8hOUeLx zhZ%SO&sF6SyKZ|a|gX6EB;XWU116XUbC)&(ZyZ0#~W zr5Q>KOd$P}QnjhtctQ?0yi*w;pPXF!y~6Jm1SUQ_zAxmIW@u~VP{%+=oBFekTO+dq zZl0ufhNLIH0lq05ptZQsxjViP{KT@tT6G%9C}Q5?|8MV0;G-(Cz3bk-SvqScBp4vT zr2`}olJuSq7}K3jhXjHF0=P^x-AOtU$VNJ08NhT{L#`1uHnqmH9t76x=i^Zw`F?kprI=zPET-uL@%a{AV-IE=%`3NtM@P(x5i7$g#JXig4pJn(*5G(1ZTP~SdjyrB_a+9a9}G~pN#|I#(?M1% zLt0wK-p|gKRz(Fl%gbkSt(sO%(}q_*ZC@F*(LHijp*L!lvFlvI+asojUD$9WER;Wm zBj~U&LIWShJ@0EDlaRQMXVF}XG*`n2=pnTx)_F?r@3t!WCaFDi+{=YC0+hE+<~xdC zttmM_va?vL&@y*h;CH%z1|3Lm<|pwVvC+dzS<}X$2giHaRQ}lSBIjqFBn_qc#Ke+2 zHwNn&i_F{|s;!zA#2*j#-oBvfM*Z%Tx~(xslM+j{Gd+^F&Xv?T`s7!m%}P~lVqKit z65A4SDKT-}rMi7VY11FzvXoyNlwy*0P?~br=TCj^ivDM^GEyl{nU@=K=}$WDRb^V? z2lp#d!^${u#|g2rLq5IffW9sASQoG881~fUrV+M)-)tH6NaWFvcfC7y!IaZZM~K!j z(!oM>WlaBG($;;vC@``x%!TY*t(6qMcaw;30Y{H54~G26{}~KOWH_5iI$Y8tn}~>< z;ZZgrd~BLBH}KZ*5Mjj|_?|k03Ra;C42`~#Z2-%Pz=}Q0FXc540SqgQ3@;^)1s#dC zoRv#fIEyhvNH%{i*!k3t3%cdHkJajx(bCjHVp`23!L^8Kd3;Acu8GWc-4jU+Yh9!} zxM)FD^GIS?vuf^GGt50WR2y@h?!x9!{pL`^rcf@V*|jET%DhNrv=%kN8%0N!1_tN%OLUcT;tJ)*MzW< zMQldFWfJe?wV^9V@=G#d{-MYpTJgq9?&jAH9l&@9b&+fp^zC7#s92MKcyj2<;J{}+ zdzRl5>v}l$(B`$VlS5asZt$3!Ezs2X-^QZ$f7!i!9Q|`X+U(0_*D-nsj&R(oFFZ z7+>4HZ_GYCd~57z;p`#C+Q9ib+Om?yB{fanc{n70N&??8z9b|&MDyqlopZc)>MdKb zXkDT_@X4fr>)T6h%B`#;-QWm6b!wz4FEDK5Ay24%uEQCwaI&w$WoGxU7msezj|%+d zxYL}IJrVpeINsI|T1~&XT^BH+bL+(?o#4{4PQ8ZRw9b`3HsgIXu-+?-7T@B%cYZZJ_HxsKDF+?v0LxDKJ>0sZOp_- zI?L}6|8?3#S3_-@OI)NJ7UEodG3(|TB?koK=rO~D(r`;e{R0=Vg&o`PRbL>XvHg)Xb+=Pwe#AL+fX44AuUtDu`EX zt-e($uUz=$xI`}7C=2zj+ml)o9#2@T)WjyX#HqU+vF(}`VSR)qcvsPCWp?yGG7l?{ zDa2cqyHm21C7!Nx)3cNY<@@`LK?_*c@O20N`2zp8GO=k(Eq`o8HfLebaaL7{j`6O= zUg>bVBzI<3Zr9&7 zE8w|+t^+4uI=Sm)`?D`rOuOq$c>a*c7ulAR2TrPPCy9$yx#aD4S@&=K%aQmGBO?ML zI#0UAuRBk|)Zq8WcXfRHH?H$!;kGsBIm=@dQp;6!b)KBwQ986%I2hk~@^5_S$%_lP z4JQzz^CWw_^W=HqK;rn$lP90+Jo&<)&XYNc57^p$%zvscgJ>**B}2LCJ2e&u{7wq{ zP|_kZAKU3(APiqGN~|lmhD3G7h?k0)0)+IT&_~R6ck6X5Zc^-|a)Kxu5JM$#&Q+sG z1jk8_N>Ql&B7JDcoS(af%yB913!1ZLu#ilAX{7+H!B*MI(#Mxrd>_8VKlH8;fA?fh zFk2wbW6M^QfiJBXqll^Wgv?U}bW4sAF3&Dch{8Y|N|ZR%3Ujad2gCfsodhoBk(Ut~ zSIx93Ml%ns1$#c3z>CW9@>;Mc+3DT$yePInF{SgwtJMnCn&x?d5#9hvM2l|z!*!Ud zOc0ZP5j^vNM@$iKRi${1<3{~P?WVCLF(t(-Nz|^R4{#HHBPdsJtR3viyE}Qtfi>R4 zBk~`x37$DSVl+aArW=#mmUU3sm9=^< zcvWO>Te9KxvK28Tk*R2jck6a=r*LjZZ8JOk1W9BuVq@DQC9DD`nPQ<`=1>?%U6#PD zTuF@utPL_5iDajmVrpXAh8+rQo9k>_f2O{(CS)7$T-%(K`1GEc!_@K4b7Se$(T??J z4`kM9!HUG)E#?TNKGJzx>F8#*{fK0;B%LanuuL#UAX&jxE9PDO8BFo=@eMqRVpTlt5v(9RUFg7)yV}c{}4$Q`KWDcYvVa)aj zH0Lq{YP)V+UTf>=NVe+9C)NmU`)f)(mW#Xgy9OVO(|r*+qb6DSh;^M0nE_Gk^r+Lr zND^yV6fJfRb~XH;d0;_bnOB?A?zD%BzZ3Yl>*pntES71VuRomv{aP<8n@w7Y2`wvg zMb6eN%~Beb=VKD@Q-g~@B!fiuMqTT^pw>bX$z+KvD@|Frd~?CvXh|XyJG_*k|;UTA4 zk&5=GMA52a;KHa_hBZe>TTaz&5VoeNXY6@g6s+#{P14M8!(3}&ggwHz1yjSaJ=}T4 zWfIoe=rw=g)X)8cBO&XboZ|S(^PD^7r7NfTGc zS-IU|4+hUm<0?m{aZ%3Nu$Oj=KZ7O8h=1M@5ICVF^$1oYB`GVBcRPl?$BwB&w3ge{ z>UUv*RU3yjuCGTeD1wZ2o~DQv&)O5#;a`pIdWtVIHGRqOVk*$s*Z zM_>2h%7BH*=O$-hj)`?ADFxAMn*iiA-tP}6DL0Km(+@cwoBGL}%x)hLg;>9zgg0oKiiJNgM z>qL;@1e@G3-o6JP5tIesU}(PuMhqhuqB5@`O)E=*ZncknOZWB-<}*28++X4n$vh@G z^jUk2rd)&oeMAwGUlA~7hbEv1>!dn$homA_WC!eGQ+y0&Tfp{l4oRUBHJzK_HiLZ_ zS3IyH;AVSOyxSG(^n^v2!Dzfkh|#FSpA1Ym5d8FNWoYv1am}u0&*|*9E%JtQ*L~{I z+auog+@B=IdXseQR`rS?tV)7p<>7@j^ja~rD*CJ#sz^uc;UE<;|MAHTir5;6)tMe2 z!_g$$JQ*v(q1thJXE*Sr?+lW)1cPwK@nLnMT?y$(g_mBh905x0UQ2ufgOM$C+@#qH zBC6JKwnI6>?ZlV7zdwB>hu9MHP9GEz9ih*i?U}>Pp|MYxQD6y>HqGy?7qboG!6}7< zQxEdolo7rS@>ypBvZ|Y#1FVUI=Ep2_E;_hgVokgV^B>A%ez7RhvwMk)v>yDk@?%Lf|GS63(s(#*in-X zVZ$(I^l%&237+RpJ>z`|g3=R>O%HGN4nH(u?@-I&Ls5=jFA%Eqqiz>TR$`)$PYGh8 zdcMS_ipyN5_Wmi_F+Ne$s++vy+lGtEu;Gr#cnPMb2jFYxz)AsCZzmga>e6ykgiiyqL;CkJz&9V#O*UPT1 zE{+2_ux^A}cqxGXbO5vTo8t4)u--14&$q``}_RmFgg7zry!@^lNw{E z`~~n9=?qB(mSh0aYv-R^qX>>!B|!aE4S6VoGM~6*h>#?B&|%b z!2I$k_KdujesNte_R`11&%#D}CherhM*6^o{OC>Djc%CYg;oAs$WiEiu=d>ay&jGU zz*8{IoGE+@cZ}!rlx%uTRA8P01iF5wLJ)9Pe*BzlEA}kZ&Vzkk0KN`8i&^-PKt3ds z4+%=<>$#ZVz-T2O{cV2Ry4$c+%}=?W4-p14F2mhWURx!&Zs3QwSpzGl(+#Sai-pIq zxophsOfkNAGNVS)X$<;5qmhCI!Nx-P2rimYBP~zRr7}%|Cc!qb_$E@~L+x2ygneoa zu4=umm{YiPsSQ=7355)n7uH5py~9c0I|A)!|hrn8x>kWFEBW<%p#?KKolEYq$0do}UKgE~`j zd=y>fs8qe|{87KbKO+D6$Y~al3@$9J<7HxBFJ5astHx&?uI-9p9Jq^o;e@UMFV*dN zHzaj_$XVW#@4b;KdO!RKw;*vhe+gs`^FzrH*Q{2^SlFRP=Jpfq4iK(nLW8F*jd&wznk~lXN#TSVCp%C&e_k#QW z=wLC_V*ZWswKWELQ~aDI4i@Rdrirc#o8k)|c(Nb5QAYpN>tJC%bnIXU?#0>taLqFA zEsIfnAMUgzK>aMCA8Lk-TGif>)40Mm2cY*g>7*=Wy*olLZTsPz||zEnc`%@a-*KP_^X+2jgM-Kg=Qb zp}P5l7LiZGk{e4v*yvSc=D!Q2;DmWj^tnJmUd+82ostvW^WdeF6DMW4Bb=yBGNqpQ zIXSWGwW|DIda8tf@z14wvz~%z>!iyVLdnc8MKVFmr{k-LAUXwlGuXfiz)HX>z-qu< zfHi=-0c!#G0M-H41MUUf2Oue{1^11BO@R9Wn*k31egSw8@DSi(z#{;{-{QMJj(aPh z4X_nJVcT)v;d4KU`%{3OfL{Wh20R0J7VsS4dB83}J770};uGwJdmrFMz)OIa0s8?I z_6qK=0)FLtK7hLya1d|^a2Rj|@H*hvfZqV#0Q?s4CVB&ZU8G21kzO=QtEBv7!^!EAI3$VggE*BfgQpUs3k zwH0hoV5IW1bW-<`u#JBnD)Hjpd{?{dee^sMi;1@Szr=K&W5ZYm&!gK<;uT0VlNT`d z^v9HaB7oo3rQ&hOnU6_n12=K_?l46Z7;afTP@^9j~p% zj9q8PYsBT1eo--SUB2f};PH;5ffB=WY%m}W?xDEH17!N}&l4H@HlHRVern=;vTguU zAlfAV9?J7$^}lm+N&5UQem{tXu_9Jm(ICRe(uwoViVJgDZobW~H5E_u6cwiC6ci+^ zQE@A$iCR;tMl9q@n-7Wwm8JF0_4P~GRK^WvK^`9GAJCaN?i*II2o6#jD*Tj(BxyI( zdjwA5(Bv45I=kJXO|fgtxtzu-;D|OMMWZue_HQ%fXtJ{nFsi}1XN5Nv6(4d36y;9S zX$lgvhv$mklDEgEu}Ms=&GNFG1^oOK)nS}%fkyM$@&rxxf&_1vhdpkbt3j5^wO(e8 zGeJpXFxb6o4IriL6oV-@Hw8zj<(gBn4W_&G83u2h!Dz=ZKP0NUi_IXF3{$bSu1;Ed zD=w%l19247q_o)XSqy>9oT~AZo#xG{uEphdm&ay$)trZ&PPK<`zy}&st5bQ$`e~to zd%5E_{Y+Pdy*#F}K~Xu=`(OpLzwZ52rR9L0E%QVinc~nHjN0_O^QXV6jZf9tUY+{z zz4sQ^*T&U06t8TtJUG*y+m79pvr5gLC~<2Pl$*6R4fVBEO0zFTwH8olvljGun2X8fI#{Iou^=`m>I_@_{*Z0=gLO`KHRvb9C2n%fZZkGm zDu?b==$==^&ps29w~cAHwO(p_dc-<4*UV2S4Lf_kS}lYmZ(~EY1<#sW>FzdM+c}xV ziHccm5tZIW>YMl_^I2&Jdf(jnZ0J`3x^Dt%qxEj@f$HezPtA`WwYOBvc&u8?5LHhp zaARHJvz?l^FNEv94A*@guA7EiS9oda7f1g-%yi<*aMS1ECj54Vp9ydHYyB7DN^zp~ zX6qVl++-Ggkn>E!gsyt*J}rxUQ_#IHq)nKghao&=;&USsR7tm3!WnZ-8=G!i9%-Dt zB$94Tk*sMnOJZXlUlOT$A*fGB`Jo3PiRFcBy0O^kS}J?gM2Aw zo(;VUo&mdIMX*|8YxAjm~MntNaGRs8Pcdn+;Sgx zw|3vtk+0VGWXEWeiiRz~UjjyfO61ijjSeFEn-fozHswdU0T{EgJEtrFurZ?`y4r+N2O|Qz4byh1%0dU5gqNL*vuqua(A3JG&X} zjbj>+C%Ns&cc2vQ7#+*d#xN2@{Y=2tz*Wdf**y4S9U4ys$gvc;(c4(kr=4EymJE7R zl`I+b&{B`<>ZnR5m7;e$LFERTDMxJ=Nt6W58}2yO4Ai8D6j3ZaQ8>{W#czPC6m^C| z4t1xu-UvUUzn*vAyDCZDZ(Ijj%7yF!r5xznhBs~m9m$f77Jgbhk&FZ5S%k>_!;18& zmInOE{yIs`51 zH=^zBQVCMZC%o=p5|FScwJp*Nm)i0k^UtJT{tBhBr+F67360O zHT5`AyA=0Y+$q@`21quYzjB`m1lz$kCHjbhjG7&y2KE zg4qKkn8pu;-PQHn2)TrdDcSj$HS}#aqm-a+fCMk}DWMVZ#*ms5S4&R`X==`K?eOS7 zN$>HY*6Dfr?{(2j|EVP)1;n+=JpDy$JALlM)y|}v~d)unW;Sc@lh3owObf1p;c!-kOQf?s&MVrgWS@xxGT1imNa|{C|e{RJZO4F09HAmim7b4 zOX$`H>;D98uu=-$#4i@Ck2W0CuLwg=7 zKS^gu+Z*qumXU(#%K-)Vyx8-63!Z;%b+A~0PSEy$NWlLcfm!doM`@82mCwk0IB)}N z*-yJ@{W%gzkm`bnd(PM*fs{*MCJ>B~YP zX@7I2IVwIzarGJdFp+CrhUe0hped@47^$G0*d<5Ntix}b~l=RI&-Id6LB6qn{H*zLm#r1cU#SnekZQ50z8JMgf&NMd|4NxX0mtm)hSRacmSP^I5!u zXQ_KEzL~K*EpQB=x0BxiS)X*rneY!3%-?QCM8jjZo=?V)2foDvZ|OaQ1U>#ZT8R$& z>j&j{qNLLthLvH`EjF*ER$sNS;O>h>cD$>nh?cKdMt|HuDK5oqcRhadm+L+$BK2h< zRTOate$V~mepQ&^qPX;qzdvq&n!W>t|Ni#5oUWGiqN`h;8`7&!T&cX&CsY8Lre|VC zP$W_155`5DA9YC;0$KWX#nfjF0Irv=Scm7MalXpqRT3^bo`>4r0^q^E``V{WxZ}Qr z{`f>t*8>!no}b`prnFt-Tb$WIWW*6N)D)gA#bsvNhb_T-P@}!lRBubqfKWywZ*DCSugQyo^|# zkjhBy9O^G43Qc9ay#B;I2`}vO`kNRVmF7>o=Y7*aP59xL+x$t#= zP+~IuFAkO&3cQkm#(s(lGe=lC(kiF4N-65Fl1VP9liI6GUFGGjauJ8`!z@%v{qGqs zEa;!j6@BK|XBOob-Y6PVHJb2{Y}y+yF149-R#QfCRYfRU;Y@~ue$yJ1GwjW$@C_^zO<3?J#?e{o-kvdFtS+8RQF8f(F^iiRdr`b-U zWHw~ztj1i}#lzl2BLhMw+cMQQy-k~wZZ~U<_6!2M6#?NPKg+9i)2CP(aIyjz7csEg z!b7^-M4P!(Z`SK_O!(@cjXEP(d2Wi?ZqO4e*Vr<&_`09bx_r`{Z2P3{Sm2x8Ze6Cl zH2^jlh@#QRKQ_OMyrfM6lO**Cj7|C^g94K7z>Uuox=^m(Tq9F6LG1pwg@<%^|Goh@ zCP*iP)}#f#DFfSWfi81~zPLVL(}2Di1N!O)^fg}Y+m~efJdsTkW9oi3Q!-NY75saW z_ywmU(M}r9dwhS$^#Hf+hfw|pgl|SEiA}s0q~v18kK=+FzAEPgyQsnzPMEHj@7My{km|j>Y0tfEIDz{?@7$w3m`F`!t($$_CV5?{EBfW zk+lv$V)@+w61z78NUUxH3<5k0AgbGmF^Kg2lt%fIMUtEF3vaYf&$rv`a7unE+i!2& z{|R3|p98;u%l)V!0GJ&}Z9;89V*bql%tAmaa$AsaOZ8X=pf*?qAQ3zOGgPvPq%p`P zS#e(5cx3(&*{CU&;TH+DzdI0qe z>LWz^9f00_gZ!{N*qPE;Lz~ht^`}cE^)GT!KcnmN`v?#l@nuYX*-K{*|4|~)qeu4b zdu!j}i_!y~fJg^HNe_F!IrPPm?RcOm{q8T{x_JCsDeC?m`<`H7NQ=rueU-xZ?>KpJ z_m@&pqzV2x(7&Gx5#3XlFyn{fSa7E@7vN6){AS##Om(AcQT2zRIlk�hU~`5s&WWdQkAGs{-ub?jg{ry@0r>IE%9Pr`|qrNen>v#CY~|R zS>v)05u}!3cew0NZS_{?D<8ddTy9T1cD$#n>ldHePNy;IusbnTo2p4Qr5kC=C8eDt zhiP?&3S9~&v6woQ=}J>F$_%9`I6hgW$35;c n#w|ji)Qdg}A_B;+tf(+c>T`*)%f~IIn%On#0pu+I_x=7CskUvc diff --git a/acs/nladmin-system/src/main/resources/config/application-dev.yml b/acs/nladmin-system/src/main/resources/config/application-dev.yml index fdc072b..a49f51d 100644 --- a/acs/nladmin-system/src/main/resources/config/application-dev.yml +++ b/acs/nladmin-system/src/main/resources/config/application-dev.yml @@ -6,11 +6,11 @@ spring: druid: db-type: com.alibaba.druid.pool.DruidDataSource driverClassName: net.sf.log4jdbc.sql.jdbcapi.DriverSpy - url: jdbc:log4jdbc:mysql://${DB_HOST:127.0.0.1}:${DB_PORT:3306}/${DB_NAME:hongfeng_acs}?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false&useOldAliasMetadataBehavior=true + url: jdbc:log4jdbc:mysql://${DB_HOST:127.0.0.1}:${DB_PORT:3306}/${DB_NAME:hf_acs}?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false&useOldAliasMetadataBehavior=true # url: jdbc:log4jdbc:mysql://${DB_HOST:47.111.78.178}:${DB_PORT:3306}/${DB_NAME:yongyu_acs2}?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false&useOldAliasMetadataBehavior=true username: ${DB_USER:root} #password: ${DB_PWD:P@ssw0rd} - password: ${DB_PWD:password} + password: ${DB_PWD:123456} # 初始连接数 initial-size: 5 # 最小连接数 @@ -128,7 +128,7 @@ file: avatarMaxSize: 5 logging: file: - path: C:\log\wms + path: C:\log\acs config: classpath:logback-spring.xml # Sa-Token配置 diff --git a/acs/nladmin-system/src/main/resources/config/application.yml b/acs/nladmin-system/src/main/resources/config/application.yml index a4d00ab..e56175e 100644 --- a/acs/nladmin-system/src/main/resources/config/application.yml +++ b/acs/nladmin-system/src/main/resources/config/application.yml @@ -2,7 +2,7 @@ spring: freemarker: check-template-location: false profiles: - active: prod + active: dev jackson: time-zone: GMT+8 data: @@ -44,7 +44,7 @@ rsa: private_key: MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEA0vfvyTdGJkdbHkB8mp0f3FE0GYP3AYPaJF7jUd1M0XxFSE2ceK3k2kw20YvQ09NJKk+OMjWQl9WitG9pB6tSCQIDAQABAkA2SimBrWC2/wvauBuYqjCFwLvYiRYqZKThUS3MZlebXJiLB+Ue/gUifAAKIg1avttUZsHBHrop4qfJCwAI0+YRAiEA+W3NK/RaXtnRqmoUUkb59zsZUBLpvZgQPfj1MhyHDz0CIQDYhsAhPJ3mgS64NbUZmGWuuNKp5coY2GIj/zYDMJp6vQIgUueLFXv/eZ1ekgz2Oi67MNCk5jeTF2BurZqNLR3MSmUCIFT3Q6uHMtsB9Eha4u7hS31tj1UWE+D+ADzp59MGnoftAiBeHT7gDMuqeJHPL4b+kC+gzV4FGTfhR9q3tTbklZkD2A== logging: file: - path: C:\log\wms + path: C:\log\acs config: classpath:logback-spring.xml # sa-token白名单配置 security: diff --git a/acs/nladmin-system/src/main/resources/logback-spring.xml b/acs/nladmin-system/src/main/resources/logback-spring.xml index 85e8ca0..4d97715 100644 --- a/acs/nladmin-system/src/main/resources/logback-spring.xml +++ b/acs/nladmin-system/src/main/resources/logback-spring.xml @@ -84,21 +84,21 @@ https://juejin.cn/post/6844903775631572999 - + - + - + - + - + @@ -130,7 +130,7 @@ https://juejin.cn/post/6844903775631572999 - + @@ -138,44 +138,44 @@ https://juejin.cn/post/6844903775631572999 - + - + - + - + - + - + - + - + - + - + diff --git a/acs/nladmin-ui/src/views/acs/device/config.vue b/acs/nladmin-ui/src/views/acs/device/config.vue index 7943258..4b379f7 100644 --- a/acs/nladmin-ui/src/views/acs/device/config.vue +++ b/acs/nladmin-ui/src/views/acs/device/config.vue @@ -90,6 +90,11 @@ import hf_two_rgv from '@/views/acs/device/driver/hongfeng/hf_two_rgv' import hf_station from '@/views/acs/device/driver/hongfeng/hf_station' import hf_manipulator from '@/views/acs/device/driver/hongfeng/hf_manipulator' +import hf_station_two from '@/views/acs/device/driver/hongfeng/hf_station_two' +import hf_kiln_truss from '@/views/acs/device/driver/hongfeng/hf_kiln_truss' +import hf_kiln_manipulator from '@/views/acs/device/driver/hongfeng/hf_kiln_manipulator' +import hf_rgv_two from '@/views/acs/device/driver/hongfeng/hf_rgv_two' + export default { name: 'DeviceConfig', components: { @@ -107,7 +112,12 @@ export default { empty_vehicle_stacking_position, hf_manipulator, hf_station, - hf_two_rgv + hf_two_rgv, + hf_station_two, + hf_kiln_truss, + hf_kiln_manipulator, + hf_rgv_two + }, dicts: ['device_type'], mixins: [crud], diff --git a/acs/nladmin-ui/src/views/acs/device/driver/hongfeng/hf_kiln_manipulator.vue b/acs/nladmin-ui/src/views/acs/device/driver/hongfeng/hf_kiln_manipulator.vue new file mode 100644 index 0000000..8222d4d --- /dev/null +++ b/acs/nladmin-ui/src/views/acs/device/driver/hongfeng/hf_kiln_manipulator.vue @@ -0,0 +1,522 @@ + + + + + diff --git a/acs/nladmin-ui/src/views/acs/device/driver/hongfeng/hf_kiln_truss.vue b/acs/nladmin-ui/src/views/acs/device/driver/hongfeng/hf_kiln_truss.vue new file mode 100644 index 0000000..ddfdf60 --- /dev/null +++ b/acs/nladmin-ui/src/views/acs/device/driver/hongfeng/hf_kiln_truss.vue @@ -0,0 +1,484 @@ + + + + + diff --git a/acs/nladmin-ui/src/views/acs/device/driver/hongfeng/hf_rgv_two.vue b/acs/nladmin-ui/src/views/acs/device/driver/hongfeng/hf_rgv_two.vue new file mode 100644 index 0000000..f0fbdbc --- /dev/null +++ b/acs/nladmin-ui/src/views/acs/device/driver/hongfeng/hf_rgv_two.vue @@ -0,0 +1,641 @@ + + + + + diff --git a/acs/nladmin-ui/src/views/acs/device/driver/hongfeng/hf_station.vue b/acs/nladmin-ui/src/views/acs/device/driver/hongfeng/hf_station.vue index 2975a8e..96a788a 100644 --- a/acs/nladmin-ui/src/views/acs/device/driver/hongfeng/hf_station.vue +++ b/acs/nladmin-ui/src/views/acs/device/driver/hongfeng/hf_station.vue @@ -113,6 +113,23 @@ + + + + + + + diff --git a/acs/nladmin-ui/src/views/acs/device/driver/hongfeng/hf_station_two.vue b/acs/nladmin-ui/src/views/acs/device/driver/hongfeng/hf_station_two.vue new file mode 100644 index 0000000..4a23ae3 --- /dev/null +++ b/acs/nladmin-ui/src/views/acs/device/driver/hongfeng/hf_station_two.vue @@ -0,0 +1,484 @@ + + + + + diff --git a/acs/nladmin-ui/src/views/acs/order/index.vue b/acs/nladmin-ui/src/views/acs/order/index.vue index 3f2c69f..4fffac3 100644 --- a/acs/nladmin-ui/src/views/acs/order/index.vue +++ b/acs/nladmin-ui/src/views/acs/order/index.vue @@ -97,6 +97,12 @@ + + + + + + diff --git a/acs/nladmin-ui/src/views/login.vue b/acs/nladmin-ui/src/views/login.vue index 74db7e2..58087e8 100644 --- a/acs/nladmin-ui/src/views/login.vue +++ b/acs/nladmin-ui/src/views/login.vue @@ -2,14 +2,14 @@