rev:刻字上料

Signed-off-by: jiaoliming <dawnjiao@foxmail.com>
This commit is contained in:
jiaoliming
2023-09-01 10:01:55 +08:00
parent 1f07dab81f
commit b20069eaa4
2 changed files with 135 additions and 75 deletions

View File

@@ -40,6 +40,8 @@ import org.nl.acs.task.service.TaskService;
import org.nl.acs.task.service.dto.TaskDto; import org.nl.acs.task.service.dto.TaskDto;
import org.nl.acs.task.service.impl.TaskServiceImpl; import org.nl.acs.task.service.impl.TaskServiceImpl;
import org.nl.modules.common.utils.RedisUtils; import org.nl.modules.common.utils.RedisUtils;
import org.nl.modules.lucene.service.LuceneExecuteLogService;
import org.nl.modules.lucene.service.dto.LuceneLogDto;
import org.nl.modules.system.service.ParamService; import org.nl.modules.system.service.ParamService;
import org.nl.modules.wql.util.SpringContextHolder; import org.nl.modules.wql.util.SpringContextHolder;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -75,6 +77,8 @@ public class HailiangEngravingInDeviceDriver extends AbstractOpcDeviceDriver imp
TaskService taskserver = SpringContextHolder.getBean(TaskService.class); TaskService taskserver = SpringContextHolder.getBean(TaskService.class);
@Autowired @Autowired
ParamService paramService = SpringContextHolder.getBean(ParamService.class); ParamService paramService = SpringContextHolder.getBean(ParamService.class);
@Autowired
LuceneExecuteLogService lucene = SpringContextHolder.getBean(LuceneExecuteLogService.class);
//线体状态 //线体状态
int status = 0; int status = 0;
//线体开机状态 //线体开机状态
@@ -123,6 +127,8 @@ public class HailiangEngravingInDeviceDriver extends AbstractOpcDeviceDriver imp
int device_running_time = 0; int device_running_time = 0;
//待机时间S) //待机时间S)
int await_time = 0; int await_time = 0;
//拉闸信号
int to_agv_put_finish = 0;
//线体状态 //线体状态
int last_status = 0; int last_status = 0;
@@ -247,11 +253,14 @@ public class HailiangEngravingInDeviceDriver extends AbstractOpcDeviceDriver imp
device_running_time = this.itemProtocol.getItem_device_running_time();//设备运转时间S) device_running_time = this.itemProtocol.getItem_device_running_time();//设备运转时间S)
await_time = this.itemProtocol.getItem_await_time(); //待机时间S) await_time = this.itemProtocol.getItem_await_time(); //待机时间S)
to_agv_put_finish = this.itemProtocol.getItem_to_agv_put_finish();
isonline = this.itemProtocol.getIsonline(); isonline = this.itemProtocol.getIsonline();
if (mode != last_mode) { if (mode != last_mode) {
feedDeviceStatusFlag = false; feedDeviceStatusFlag = false;
logServer.deviceExecuteLog(this.device_code, "", "", "信号mode" + last_mode + "->" + mode); logServer.deviceExecuteLog(this.device_code, "", "", "信号mode" + last_mode + "->" + mode);
lucene.deviceExecuteLog(new LuceneLogDto(this.device_code, ItemProtocol.item_mode, mode, last_mode));
} }
if (gd_move != last_gd_move) { if (gd_move != last_gd_move) {
logServer.deviceExecuteLog(this.device_code, "", "", "信号move" + last_gd_move + "->" + gd_move); logServer.deviceExecuteLog(this.device_code, "", "", "信号move" + last_gd_move + "->" + gd_move);
@@ -263,7 +272,7 @@ public class HailiangEngravingInDeviceDriver extends AbstractOpcDeviceDriver imp
logServer.deviceExecuteLog(this.device_code, "", "", "信号is_open" + last_is_open + "->" + is_open); logServer.deviceExecuteLog(this.device_code, "", "", "信号is_open" + last_is_open + "->" + is_open);
} }
if (is_running != last_is_running) { if (is_running != last_is_running) {
logServer.deviceExecuteLog(this.device_code, "", "", "信号is_running" + last_is_running + "->" + is_running); logServer.deviceExecuteLog(this.device_code, "", "", "信号is_running【是否允】" + last_is_running + "->" + is_running);
} }
if (empty_req != last_empty_req) { if (empty_req != last_empty_req) {
if (empty_req == 1) { if (empty_req == 1) {
@@ -324,7 +333,7 @@ public class HailiangEngravingInDeviceDriver extends AbstractOpcDeviceDriver imp
logServer.deviceExecuteLog(this.device_code, "", "", "信号engraving_weight" + last_engraving_weight + "->" + engraving_weight); logServer.deviceExecuteLog(this.device_code, "", "", "信号engraving_weight" + last_engraving_weight + "->" + engraving_weight);
} }
if (engraving_storage_now_weight != last_engraving_storage_now_weight) { if (engraving_storage_now_weight != last_engraving_storage_now_weight) {
logServer.deviceExecuteLog(this.device_code, "", "", "信号engraving_storage_now_weight" + last_engraving_storage_now_weight + "->" + engraving_storage_now_weight); // logServer.deviceExecuteLog(this.device_code, "", "", "信号engraving_storage_now_weight" + last_engraving_storage_now_weight + "->" + engraving_storage_now_weight);
} }
if (engraving_all_weight != last_engraving_all_weight) { if (engraving_all_weight != last_engraving_all_weight) {
logServer.deviceExecuteLog(this.device_code, "", "", "信号engraving_all_weight" + last_engraving_all_weight + "->" + engraving_all_weight); logServer.deviceExecuteLog(this.device_code, "", "", "信号engraving_all_weight" + last_engraving_all_weight + "->" + engraving_all_weight);
@@ -335,9 +344,9 @@ public class HailiangEngravingInDeviceDriver extends AbstractOpcDeviceDriver imp
if (fl_full_weight != last_fl_full_weight) { if (fl_full_weight != last_fl_full_weight) {
logServer.deviceExecuteLog(this.device_code, "", "", "信号fl_full_weight" + last_fl_full_weight + "->" + fl_full_weight); logServer.deviceExecuteLog(this.device_code, "", "", "信号fl_full_weight" + last_fl_full_weight + "->" + fl_full_weight);
} }
if (barcode != last_barcode) { // if (barcode != last_barcode) {
logServer.deviceExecuteLog(this.device_code, "", "", "信号barcode" + last_barcode + "->" + barcode); // logServer.deviceExecuteLog(this.device_code, "", "", "信号barcode" + last_barcode + "->" + barcode);
} // }
if (open_ready_time != last_open_ready_time) { if (open_ready_time != last_open_ready_time) {
logServer.deviceExecuteLog(this.device_code, "", "", "信号open_ready_time" + last_open_ready_time + "->" + open_ready_time); logServer.deviceExecuteLog(this.device_code, "", "", "信号open_ready_time" + last_open_ready_time + "->" + open_ready_time);
} }
@@ -399,26 +408,54 @@ public class HailiangEngravingInDeviceDriver extends AbstractOpcDeviceDriver imp
feedDeviceStatusFlag = true; feedDeviceStatusFlag = true;
} }
// // 修改工单状态为生产中 // 修改工单状态为生产中
// if (mode == 1 && order > 0) { if (mode == 1 && task_finish == 0 && task > 0 ) {
// ProduceshiftorderDto pdto = produceshiftorderService.findByCodeFromCache(String.valueOf(order)); ProduceshiftorderDto pdto = produceshiftorderService.findByCodeFromCache(String.valueOf(task));
// if (pdto != null) { if (pdto != null) {
// if (pdto.getOrder_status().equals(WorkerOrderEnum.READY.getCode())) { if (pdto.getOrder_status().equals(WorkerOrderEnum.READY.getCode())) {
// pdto.setOrder_status(WorkerOrderEnum.PRODUCTING.getCode()); pdto.setOrder_status(WorkerOrderEnum.PRODUCTING.getCode());
// produceshiftorderService.update(pdto); produceshiftorderService.update(pdto);
// } // TODO 反馈mes
// } JSONObject reqParam = new JSONObject();
// } reqParam.put("task_code", task);
reqParam.put("status", StatusEnum.TASK_RUNNING.getCode());
HttpResponse httpResponse = acsToWmsService.washTask(reqParam);
if (ObjectUtil.isNotEmpty(httpResponse) && httpResponse.getStatus() == 200) {
this.message = "反馈刻字输送线任务执行中成功";
}
}
}
}
//修改工单状态为自动完成 //修改工单状态为自动完成
// if (mode == 1 && order_finish != last_order_finish && order_finish == 1 && order > 0) { if (mode == 1 && task_finish == 1) {
// ProduceshiftorderDto pdto = produceshiftorderService.findByCodeFromCache(String.valueOf(order)); logServer.deviceExecuteLog(this.device_code, "", "", "task_finish"+task_finish+"电气完成任务后信号last_task" + last_task + "last_task任务号不为空则查询工单更新状态自动完成");
// if (pdto != null) { logServer.deviceExecuteLog(this.device_code, "", "", "this.device_code"+this.device_code+ "device_code不为空则查询工单更新状态自动完成");
// if (pdto.getOrder_status().equals(WorkerOrderEnum.PRODUCTING.getCode())) { // ProduceshiftorderDto pdto = produceshiftorderService.findByCodeFromCache(String.valueOf(last_task));
// produceshiftorderService.finished(pdto); ProduceshiftorderDto pdto = produceshiftorderService.findOrderByDeviceCode(this.device_code);
// } if (pdto != null) {
// } if (pdto.getOrder_status().equals(WorkerOrderEnum.PRODUCTING.getCode())) {
// } //修改工单状态为完成
pdto.setOrder_status(WorkerOrderEnum.COMPLETE.getCode());
produceshiftorderService.update(pdto);
// TODO 反馈mes
JSONObject reqParam = new JSONObject();
reqParam.put("task_code", pdto.getOrder_code());
reqParam.put("status", StatusEnum.TASK_FINISH.getCode());
HttpResponse httpResponse = acsToWmsService.washTask(reqParam);
if (ObjectUtil.isNotEmpty(httpResponse) && httpResponse.getStatus() == 200) {
this.message = "反馈刻字输送线任务完成成功";
}
this.writing("to_confirm_finished", "1");
this.writing("to_agv_put_finish", "0");
this.writing("to_del_task","1");
}
}
// this.writing("to_task","0");
}
} catch (Exception var17) { } catch (Exception var17) {
var17.printStackTrace(); var17.printStackTrace();
logServer.deviceExecuteLog(this.device_code, "", "", "读取信号值时出现异常:" + var17 + ",inst == null :" + ObjectUtil.isEmpty(inst)); logServer.deviceExecuteLog(this.device_code, "", "", "读取信号值时出现异常:" + var17 + ",inst == null :" + ObjectUtil.isEmpty(inst));
@@ -461,7 +498,8 @@ public class HailiangEngravingInDeviceDriver extends AbstractOpcDeviceDriver imp
// } // }
// } // }
//无货、联机、空箱请求申请AGV搬运任务 //有框、联机、空箱请求申请AGV搬运任务
if (StrUtil.equals(paramService.findByCode(AcsConfig.KZPLAN).getValue(), "1")) {
if (gd_move == 1 && mode == 1 && empty_req == 1 && !requireSucess) { if (gd_move == 1 && mode == 1 && empty_req == 1 && !requireSucess) {
// boolean flag_wash = washTaskRun(task); // boolean flag_wash = washTaskRun(task);
// if (flag_wash) { // if (flag_wash) {
@@ -487,6 +525,7 @@ public class HailiangEngravingInDeviceDriver extends AbstractOpcDeviceDriver imp
this.noApplyTaskMessage = this.replace(notApplyTaskMessage); this.noApplyTaskMessage = this.replace(notApplyTaskMessage);
} }
} }
}
//到达取货点 //到达取货点
if (agvphase == 0x03) { if (agvphase == 0x03) {
@@ -540,6 +579,7 @@ public class HailiangEngravingInDeviceDriver extends AbstractOpcDeviceDriver imp
if (agvphase == 0x07) { if (agvphase == 0x07) {
logServer.deviceExecuteLog(this.device_code, "", inst.getInstruction_code(), "刻字上料PS20上报到达放货点:" + ",inst == null :" + ObjectUtil.isEmpty(inst)); logServer.deviceExecuteLog(this.device_code, "", inst.getInstruction_code(), "刻字上料PS20上报到达放货点:" + ",inst == null :" + ObjectUtil.isEmpty(inst));
// if (ObjectUtil.isNotEmpty(inst) && gd_move == 0) { // if (ObjectUtil.isNotEmpty(inst) && gd_move == 0) {
this.writing("to_peel","1");
if (ObjectUtil.isNotEmpty(inst)) { if (ObjectUtil.isNotEmpty(inst)) {
inst.setExecute_status(InstActionEnum.EXECUTE_TO_PUT_FALL_SEND_FULL.getCode()); inst.setExecute_status(InstActionEnum.EXECUTE_TO_PUT_FALL_SEND_FULL.getCode());
instructionService.update(inst); instructionService.update(inst);
@@ -563,49 +603,41 @@ public class HailiangEngravingInDeviceDriver extends AbstractOpcDeviceDriver imp
//放货完成 //放货完成
if (agvphase == 0x09) { if (agvphase == 0x09) {
// if (ObjectUtil.isNotEmpty(inst) && mode == 1 && allow_put == 1) { logServer.deviceExecuteLog(device_code, "", "","PS20上报放货完成信号="+agvphase);
logServer.deviceExecuteLog(device_code, "", "","信号to_agv_put_finish="+to_agv_put_finish);
if (mode == 1) {
logServer.deviceExecuteLog(device_code, "", "","信号to_agv_put_finish="+to_agv_put_finish);
if (StrUtil.equals(paramService.findByCode(AcsConfig.KZPLAN).getValue(), "1")) {
if(to_agv_put_finish == 0){
try {
logServer.deviceExecuteLog(device_code, "", "","拉闸前实时重量="+engraving_storage_now_weight);
logServer.deviceExecuteLog(device_code, "", "","agv放货完成检测到料框光电信号to_agv_put_finish=0延迟2秒开始下发拉闸信号");
Thread.sleep(2000L);
this.writing("to_agv_put_finish", "1");
logServer.deviceExecuteLog(device_code, "", "","下发拉闸信号完成");
Thread.sleep(10000L);
logServer.deviceExecuteLog(device_code, "", "","拉闸后等5秒让车走");
is_test = ObjectUtil.isNotEmpty(inst) && mode == 1 && gd_move == 1 && engraving_storage_now_weight <10000;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// if (ObjectUtil.isNotEmpty(inst) && mode == 1) {//正式方案需要联机 }else {
//一体机临时方案不判断联机 is_test = ObjectUtil.isNotEmpty(inst) && mode == 1 && gd_move == 1;
}
if (StrUtil.equals(paramService.findByCode(AcsConfig.ISTEST).getValue(), "1")) {
is_test = ObjectUtil.isNotEmpty(inst);
}else { }else {
is_test = ObjectUtil.isNotEmpty(inst) && mode == 1; is_test = ObjectUtil.isNotEmpty(inst) && mode == 0;
} }
if (is_test) { if (is_test) {
//放框完成
writing("to_agv_put_finish", "1");
//判断电气上报的【剩余实时重量】>10kg ,保障电气拉开气闸门下料
logServer.deviceExecuteLog(device_code, "", "任务号"+inst.getTask_code(), "下发开闸门开始----");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
int i = 0;
while (this.engraving_storage_now_weight < 10000 && i<5){
writing("to_agv_put_finish", "1");
i++;
logServer.deviceExecuteLog(device_code, "", "任务号"+inst.getTask_code(), "重量小于10KG循环下发拉闸门");
}
logServer.deviceExecuteLog(device_code, "", "任务号"+inst.getTask_code(), "关闭闸门----反馈称重");
inst.setExecute_status(InstActionEnum.EXECUTE_PUT_FALL_SEND_FULL_FINISH.getCode()); inst.setExecute_status(InstActionEnum.EXECUTE_PUT_FALL_SEND_FULL_FINISH.getCode());
instructionService.update(inst); instructionService.update(inst);
byte[] data = agvService.sendAgvOneModeInst(agvphase, index, 0); byte[] data = agvService.sendAgvOneModeInst(agvphase, index, 0);
OneNDCSocketConnectionAutoRun.write(data); OneNDCSocketConnectionAutoRun.write(data);
//agv任务完成反馈mes
if (inst != null) {
TaskDto taskDto = taskserver.findByCodeFromCache(inst.getTask_code());
logServer.deviceExecuteLog(device_code, "", "任务号"+inst.getTask_code(), "任务="+taskDto.getTask_code());
if (taskDto != null) {
taskDto.setExt_param(new HashMap<>());
taskDto.getExt_param().put("take_finish", "1");
taskDto.getExt_param().put("weight", String.valueOf(engraving_storage_now_weight));
taskserver.update(taskDto);
}
}
this.set(0, 0, null); this.set(0, 0, null);
logServer.deviceExecuteLog(device_code, "", "","PS20车可以走了");
noFeedAgvMessage = null; noFeedAgvMessage = null;
message = this.messageInfo(agvphase); message = this.messageInfo(agvphase);
logServer.deviceExecuteLog(device_code, "", "", this.messageInfo(agvphase)); logServer.deviceExecuteLog(device_code, "", "", this.messageInfo(agvphase));
@@ -620,12 +652,12 @@ public class HailiangEngravingInDeviceDriver extends AbstractOpcDeviceDriver imp
this.noFeedAgvMessage = this.replace(notFeedAgvMessage); this.noFeedAgvMessage = this.replace(notFeedAgvMessage);
} }
} }
if (mode == 1 && task_finish == 1 ) { // if (mode == 1 && task_finish == 1 ) {
boolean flag = washTask(task); // boolean flag = washTask(task);
if (flag) { // if (flag) {
this.message = "反馈刻字上料完成成功"; // this.message = "反馈刻字上料完成成功";
} // }
} // }
// } // }
@@ -668,7 +700,7 @@ public class HailiangEngravingInDeviceDriver extends AbstractOpcDeviceDriver imp
if (redisUtils.hasKey("apply:" + this.device_code)) { if (redisUtils.hasKey("apply:" + this.device_code)) {
return false; return false;
} else { } else {
redisUtils.setExpire(this.device_code, null, ApplyTaskTime.APPLY_TIME, TimeUnit.SECONDS); redisUtils.setExpire(this.device_code, null, ApplyTaskTime.APPLY_TIME_TEN, TimeUnit.SECONDS);
// ProduceshiftorderDto produceshiftorderDto = produceshiftorderService.findByCodeFromCache(String.valueOf(order)); // ProduceshiftorderDto produceshiftorderDto = produceshiftorderService.findByCodeFromCache(String.valueOf(order));
TaskDto taskDto = taskService.findByNextCode(device_code); TaskDto taskDto = taskService.findByNextCode(device_code);
if (taskDto == null) { if (taskDto == null) {
@@ -802,15 +834,34 @@ public class HailiangEngravingInDeviceDriver extends AbstractOpcDeviceDriver imp
*/ */
@Override @Override
public void issuedOrderInfo(ProduceshiftorderDto dto) { public void issuedOrderInfo(ProduceshiftorderDto dto) {
// if (!this.getItemProtocol().getIsonline()) {
// throw new BadRequestException("设备未开机,工单下发失败!");
// }
Map<String, Object> map = new LinkedHashMap<>(); Map<String, Object> map = new LinkedHashMap<>();
map.put("to_clear", "1"); try {
map.put("to_order", dto.getOrder_code()); this.writing("to_del_task","1");
map.put("to_one_box_num", String.valueOf(dto.getOne_qty())); this.writing("to_confirm_finished", "1");
map.put("to_order_prod_num", String.valueOf(dto.getQty())); this.writing("to_agv_put_finish", "0");
this.writing(map); Thread.sleep(1000L);
String[] sort = dto.getMaterial_name().split(",");
for (int i=0;i< sort.length;i++){
map.put("to_sort"+(i+1),sort[i]);
}
String[] devices = dto.getIn_devices().split(",");
for (int i=0;i< devices.length;i++){
String[] device_i = devices[i].split("_");
map.put("to_devices"+(i+1),device_i[device_i.length-1]);
}
String[] weight = dto.getMaterial_spec().split(",");
for (int i=0;i< weight.length;i++){
map.put("to_weight"+(i+1),weight[i]);
}
map.put("to_all_weight", dto.getQty().toString());
this.writing(map);
Thread.sleep(1000L);
this.writing("to_task",dto.getOrder_code());
} catch (InterruptedException e) {
e.printStackTrace();
}
} }
/** /**
@@ -827,6 +878,7 @@ public class HailiangEngravingInDeviceDriver extends AbstractOpcDeviceDriver imp
} }
//map.put("to_order", "0"); //map.put("to_order", "0");
map.put("to_clear", "1"); map.put("to_clear", "1");
map.put("to_del_task","1");
this.writing(map); this.writing(map);
} }

View File

@@ -64,6 +64,8 @@ public class ItemProtocol {
public static String item_to_dis_barcode = "to_dis_barcode"; public static String item_to_dis_barcode = "to_dis_barcode";
//秤去皮 //秤去皮
public static String item_to_peel = "to_peel"; public static String item_to_peel = "to_peel";
//删除任务
public static String item_to_del_task = "to_del_task";
//任务号 //任务号
public static String item_to_task = "to_task"; public static String item_to_task = "to_task";
//刻字上料重量 //刻字上料重量
@@ -226,8 +228,8 @@ public class ItemProtocol {
return this.getOpcIntegerValue(item_device_running_time); return this.getOpcIntegerValue(item_device_running_time);
} }
public int getItem_await_time() { public int getItem_to_agv_put_finish() {
return this.getOpcIntegerValue(item_await_time); return this.getOpcIntegerValue(item_to_agv_put_finish);
} }
public int getItem_engraving_weight() { public int getItem_engraving_weight() {
@@ -264,6 +266,9 @@ public class ItemProtocol {
return this.getOpcFloatValue(item_current_weight); return this.getOpcFloatValue(item_current_weight);
} }
public int getItem_await_time() {
return this.getOpcIntegerValue(item_await_time);
}
//是否有货 //是否有货
public int hasGoods(int move) { public int hasGoods(int move) {
return move; return move;
@@ -340,6 +345,7 @@ public class ItemProtocol {
list.add(new ItemDto(item_to_agv_take_finish, "AGV取货完成", "DB2.W26")); list.add(new ItemDto(item_to_agv_take_finish, "AGV取货完成", "DB2.W26"));
list.add(new ItemDto(item_to_dis_barcode, "是否禁用条码", "DB2.W28")); list.add(new ItemDto(item_to_dis_barcode, "是否禁用条码", "DB2.W28"));
list.add(new ItemDto(item_to_peel, "秤去皮", "DB2.W30")); list.add(new ItemDto(item_to_peel, "秤去皮", "DB2.W30"));
list.add(new ItemDto(item_to_del_task, "删除任务", "DB2.W32"));
list.add(new ItemDto(item_to_task, "任务号", "DB2.D92")); list.add(new ItemDto(item_to_task, "任务号", "DB2.D92"));
list.add(new ItemDto(item_to_in_weight, "刻字上料重量", "DB2.D96")); list.add(new ItemDto(item_to_in_weight, "刻字上料重量", "DB2.D96"));
list.add(new ItemDto(item_to_fl_full_weight, "回流满框重量标准值", "DB2.D100")); list.add(new ItemDto(item_to_fl_full_weight, "回流满框重量标准值", "DB2.D100"));
@@ -348,6 +354,8 @@ public class ItemProtocol {
list.add(new ItemDto(item_to_sort_array, "排序数组", "DB200.W0[15]")); list.add(new ItemDto(item_to_sort_array, "排序数组", "DB200.W0[15]"));
list.add(new ItemDto(item_to_devices_array, "站点数组", "DB200.W30[15]")); list.add(new ItemDto(item_to_devices_array, "站点数组", "DB200.W30[15]"));
list.add(new ItemDto(item_to_weight_array, "重量数组", "DB200.REAL60[15]")); list.add(new ItemDto(item_to_weight_array, "重量数组", "DB200.REAL60[15]"));
list.add(new ItemDto(item_to_sort1, "排序1", "DB200.W0")); list.add(new ItemDto(item_to_sort1, "排序1", "DB200.W0"));
list.add(new ItemDto(item_to_sort2, "排序2", "DB200.W2")); list.add(new ItemDto(item_to_sort2, "排序2", "DB200.W2"));
list.add(new ItemDto(item_to_sort3, "排序3", "DB200.W4")); list.add(new ItemDto(item_to_sort3, "排序3", "DB200.W4"));