| | |
| | | using WIDESEAWCS_Model.Models; |
| | | using WIDESEAWCS_Model.Models.System; |
| | | using WIDESEAWCS_QuartzJob; |
| | | using WIDESEAWCS_QuartzJob.DTO; |
| | | using WIDESEAWCS_QuartzJob.Models; |
| | | using WIDESEAWCS_QuartzJob.Service; |
| | | using WIDESEAWCS_TaskInfoRepository; |
| | |
| | | //忥ç»ä¸æ¸¸åé¦ä»»å¡å®æ |
| | | Dt_roadwayinfo roadwayinfo = _Dt_roadwayinfoService.GetRoadwayinfo(task.Roadway); |
| | | CommandResult command = taskreturn(int.Parse(task.WMStaskid), Result, roadwayinfo.WarehouseInvType, ""); |
| | | if (command.status != "success") |
| | | { |
| | | WriteLog.Write_Log("è°å䏿¸¸è¿å失败", "宿å åæºä»»å¡å¤±è´¥", $"æ¡ç :ã{task.PalletCode}ã,ä»»å¡å·ï¼ã{task.TaskNum}ã"); |
| | | return content.Error($"è°å䏿¸¸è¿å失败ï¼å®æå åæºä»»å¡å¤±è´¥ï¼æ¡ç ï¼{task.PalletCode},ä»»å¡å·ï¼{task.TaskNum}"); |
| | | } |
| | | if (command.status != "success")return content.Error($"è°å䏿¸¸è¿å失败ï¼å®æå åæºä»»å¡å¤±è´¥ï¼æ¡ç ï¼{task.PalletCode},ä»»å¡å·ï¼{task.TaskNum}"); |
| | | } |
| | | task.ModifyDate = DateTime.Now; |
| | | BaseDal.DeleteData(task); |
| | |
| | | { |
| | | Dt_roadwayinfo roadwayinfo = _Dt_roadwayinfoService.GetRoadwayinfo(task.Roadway); |
| | | CommandResult command = taskreturn(int.Parse(task.WMStaskid), Result, roadwayinfo.WarehouseInvType, ""); |
| | | if (command.status != "success") |
| | | { |
| | | WriteLog.Write_Log("è°å䏿¸¸è¿å失败", "宿å åæºä»»å¡å¤±è´¥", $"æ¡ç :ã{task.PalletCode}ã,ä»»å¡å·ï¼ã{task.TaskNum}ã"); |
| | | return content.Error($"è°å䏿¸¸è¿å失败ï¼å®æå åæºä»»å¡å¤±è´¥ï¼æ¡ç ï¼{task.PalletCode},ä»»å¡å·ï¼{task.TaskNum}"); |
| | | } |
| | | if (command.status != "success") return content.Error($"è°å䏿¸¸è¿å失败ï¼å®æå åæºä»»å¡å¤±è´¥ï¼æ¡ç ï¼{task.PalletCode},ä»»å¡å·ï¼{task.TaskNum}"); |
| | | } |
| | | task.ModifyDate = DateTime.Now; |
| | | task.Modifier = "System"; |
| | |
| | | task.TaskState = (int)TaskinventoryStatusEnum.inventoryFinish; |
| | | BaseDal.UpdateData(task); |
| | | string Result = WMSTaskStatusEnum.insuccess.GetDescription(); |
| | | |
| | | if (task.Creater.Equals("WMS")) |
| | | { |
| | | Dt_roadwayinfo roadwayinfo = _Dt_roadwayinfoService.GetRoadwayinfo(task.Roadway); |
| | | CommandResult command = taskreturn(int.Parse(task.WMStaskid), Result, roadwayinfo.WarehouseInvType, ""); |
| | | if (command.status != "success") |
| | | { |
| | | WriteLog.Write_Log("è°å䏿¸¸è¿å失败", "宿å åæºä»»å¡å¤±è´¥", $"æ¡ç :ã{task.PalletCode}ã,ä»»å¡å·ï¼ã{task.TaskNum}ã"); |
| | | return content.Error($"è°å䏿¸¸è¿å失败ï¼å®æå åæºä»»å¡å¤±è´¥ï¼æ¡ç ï¼{task.PalletCode},ä»»å¡å·ï¼{task.TaskNum}"); |
| | | } |
| | | if (command.status != "success")return content.Error($"è°å䏿¸¸è¿å失败ï¼å®æå åæºä»»å¡å¤±è´¥ï¼æ¡ç ï¼{task.PalletCode},ä»»å¡å·ï¼{task.TaskNum}"); |
| | | } |
| | | task.ModifyDate = DateTime.Now; |
| | | task.Modifier = "System"; |
| | | BaseDal.DeleteData(task); |
| | | _task_HtyService.AddTaskHty(task); |
| | | _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, $"å
¥åºå®æ"); |
| | | _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, $"çç¹å®æ"); |
| | | } |
| | | else |
| | | { |
| | |
| | | /// <returns>è¿åä»»å¡å®ä½å¯¹è±¡ï¼å¯è½ä¸ºnull</returns> |
| | | public List<Dt_Task> QueryStackerCraneTask(string deviceNo, string currentAddress = "") |
| | | { |
| | | return BaseDal.QueryData(x => x.Roadway == deviceNo && (x.TaskState == (int)TaskInStatusEnum.InNew || x.TaskState == (int)TaskOutStatusEnum.OutNew), TaskOrderBy); |
| | | return BaseDal.QueryData(x => x.Roadway == deviceNo && (x.TaskState == (int)TaskInStatusEnum.InNew || x.TaskState == (int)TaskOutStatusEnum.OutNew || x.TaskState == (int)TaskinventoryStatusEnum.inventoryNew), TaskOrderBy); |
| | | } |
| | | |
| | | public Dt_Task CutStackerCraneTask(string deviceNo) |
| | | { |
| | | Dt_Task dt_Task = BaseDal.QueryFirst(x => x.Roadway == deviceNo && (x.TaskState == (int)TaskOutStatusEnum.SC_OutExecuting || x.TaskState == (int)TaskInStatusEnum.SC_InExecuting)); |
| | | Dt_Task dt_Task = BaseDal.QueryFirst(x => x.Roadway == deviceNo && (x.TaskState == (int)TaskOutStatusEnum.SC_OutExecuting || x.TaskState == (int)TaskInStatusEnum.SC_InExecuting || x.TaskState == (int)TaskinventoryStatusEnum.SC_inventoryExecuting)); |
| | | return dt_Task; |
| | | } |
| | | /// <summary> |
| | |
| | | try |
| | | { |
| | | Dt_Task task = BaseDal.QueryFirst(x => x.TaskNum == taskNum); |
| | | if (task != null) |
| | | if (task == null) return WebResponseContent.Instance.Error($"æªæ¾å°è¯¥ä»»å¡ä¿¡æ¯,ä»»å¡å·:ã{taskNum}ã"); |
| | | string Result = task.TaskType == 200 || task.TaskType == 300 ? WMSTaskStatusEnum.inerror.GetDescription(): WMSTaskStatusEnum.outerror.GetDescription(); |
| | | if (task.Creater.Equals("WMS")) |
| | | { |
| | | //䏿¥å
¥åºä»»å¡å¼å¸¸ |
| | | if (task.TaskType == (int)TaskTypeEnum.Inbound) |
| | | { |
| | | string Result = WMSTaskStatusEnum.inerror.GetDescription(); |
| | | if (task.Creater.Equals("WMS")) |
| | | { |
| | | Dt_roadwayinfo roadwayinfo = _Dt_roadwayinfoService.GetRoadwayinfo(task.Roadway); |
| | | CommandResult command = taskreturn(int.Parse(task.WMStaskid), Result, roadwayinfo.WarehouseInvType, ""); |
| | | if (command.status != "success") return content.Error($"è°å䏿¸¸è¿å失败ï¼ä»»å¡åæ¶å¤±è´¥ï¼æ¡ç ï¼{task.PalletCode},ä»»å¡å·ï¼{task.TaskNum}"); |
| | | } |
| | | BaseDal.DeleteData(task); |
| | | task.ModifyDate = DateTime.Now; |
| | | task.Modifier = App.User?.UserName; |
| | | task.Remark = "人工æå¨åæ¶"; |
| | | BaseDal.DeleteData(task); |
| | | _task_HtyService.AddTaskHty(task); |
| | | content.Status = true; |
| | | } |
| | | else |
| | | { |
| | | return WebResponseContent.Instance.Error($"åæ¶å¤±è´¥,åªè½åæ¶å
¥åºä»»å¡"); |
| | | } |
| | | Dt_roadwayinfo roadwayinfo = _Dt_roadwayinfoService.GetRoadwayinfo(task.Roadway); |
| | | CommandResult command = taskreturn(int.Parse(task.WMStaskid), Result, roadwayinfo.WarehouseInvType, ""); |
| | | if (command.status != "success") return content.Error($"è°å䏿¸¸è¿å失败ï¼ä»»å¡åæ¶å¤±è´¥ï¼æ¡ç ï¼{task.PalletCode},ä»»å¡å·ï¼{task.TaskNum}"); |
| | | } |
| | | else |
| | | { |
| | | return WebResponseContent.Instance.Error($"åæ¶å¤±è´¥,该任å¡ã{taskNum}ãä¸åå¨"); |
| | | } |
| | | BaseDal.DeleteData(task); |
| | | task.ModifyDate = DateTime.Now; |
| | | task.Modifier = App.User?.UserName; |
| | | task.Remark = "人工æå¨åæ¶"; |
| | | BaseDal.DeleteData(task); |
| | | _task_HtyService.AddTaskHty(task); |
| | | content.Status = true; |
| | | return content; |
| | | } |
| | | catch (Exception e) |
| | |
| | | CommandResult command = taskreturn(int.Parse(task.WMStaskid), Result, roadwayinfo.WarehouseInvType, ""); |
| | | if (command.status != "success") return content.Error($"è°å䏿¸¸è¿å失败ï¼å®æå åæºä»»å¡å¤±è´¥ï¼æ¡ç ï¼{task.PalletCode},ä»»å¡å·ï¼{task.TaskNum}"); |
| | | } |
| | | task.ModifyDate = DateTime.Now; |
| | | task.ModifyDate = DateTime.Now; |
| | | task.Modifier = App.User?.UserName; |
| | | task.Remark = "人工æå¨å®æ"; |
| | | BaseDal.DeleteData(task); |
| | |
| | | CommandResult command = taskreturn(int.Parse(task.WMStaskid), Result, roadwayinfo.WarehouseInvType, ""); |
| | | if (command.status != "success") return content.Error($"è°å䏿¸¸è¿å失败ï¼å®æå åæºä»»å¡å¤±è´¥ï¼æ¡ç ï¼{task.PalletCode},ä»»å¡å·ï¼{task.TaskNum}"); |
| | | } |
| | | task.ModifyDate = DateTime.Now; |
| | | |
| | | task.ModifyDate = DateTime.Now; |
| | | task.Modifier = App.User?.UserName; |
| | | task.Remark = "人工æå¨å®æ"; |
| | | BaseDal.DeleteData(task); |
| | |
| | | _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, $"æå¨å
¥åºå®æ"); |
| | | } |
| | | else if (task.TaskType == (int)TaskTypeEnum.Inventorybound) |
| | | {; |
| | | { |
| | | string Result = WMSTaskStatusEnum.insuccess.GetDescription(); |
| | | if (task.Creater.Equals("WMS")) |
| | | { |
| | | Dt_roadwayinfo roadwayinfo = _Dt_roadwayinfoService.GetRoadwayinfo(task.Roadway); |
| | | CommandResult command = taskreturn(int.Parse(task.WMStaskid), Result, roadwayinfo.WarehouseInvType, ""); |
| | | if (command.status != "success") return content.Error($"è°å䏿¸¸è¿å失败ï¼å®æå åæºä»»å¡å¤±è´¥ï¼æ¡ç ï¼{task.PalletCode},ä»»å¡å·ï¼{task.TaskNum}"); |
| | | |
| | | } |
| | | task.ModifyDate = DateTime.Now; |
| | | task.Modifier = App.User?.UserName; |
| | | task.Remark = "人工æå¨å®æ"; |
| | | BaseDal.DeleteData(task); |
| | | _task_HtyService.AddTaskHty(task); |
| | | _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, $"æå¨å
¥åºå®æ"); |
| | | _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, $"æå¨çç¹å®æ"); |
| | | } |
| | | else |
| | | { |
| | |
| | | } |
| | | |
| | | // 夿å°åæ¯å¦å±äºå½å设å¤åº |
| | | if (transfer.SourceAddress.Contains(device.DeviceCode) && transfer.TargetAddress.Contains(device.DeviceCode)) |
| | | if ((transfer.TaskType == 300 || transfer.SourceAddress.Contains(device.DeviceCode) ) && transfer.TargetAddress.Contains(device.DeviceCode)) |
| | | { |
| | | |
| | | // å
¥åº |
| | | if (transfer.TaskType == 200) |
| | | { |
| | |
| | | { |
| | | content.Error($"æå¨å建任å¡å¤±è´¥,åå :{device.DeviceCode}åºä¸åå¨è¿ä¸ªåºå£ï¼{transfer.SourceAddress}"); |
| | | WriteLog.Write_Log("æå¨ä»»å¡å建失败", "å建失败", $"æçç¼å·ï¼{transfer.PalletCode}ï¼ä»»å¡ç±»åï¼{transfer.TaskType},èµ·å§å°åï¼{transfer.SourceAddress}ï¼ç®æ å°åï¼{transfer.TargetAddress}"); |
| | | |
| | | } |
| | | else |
| | | { |
| | |
| | | _unitOfWorkManage.BeginTran(); |
| | | BaseDal.AddData(transfer); |
| | | _unitOfWorkManage.CommitTran(); |
| | | content.OK("æå¨ä»»å¡å建æåï¼"); |
| | | WriteLog.Write_Log("æå¨ä»»å¡å建æå", "å建æå", $"æçç¼å·ï¼{transfer.PalletCode}ï¼ä»»å¡ç±»åï¼{transfer.TaskType},èµ·å§å°åï¼{transfer.SourceAddress}ï¼ç®æ å°åï¼{transfer.TargetAddress}"); |
| | | content.OK("æå¨å
¥åºä»»å¡å建æåï¼"); |
| | | WriteLog.Write_Log("æå¨ä»»å¡å建æå", "å建æå", $"ï¼ä»»å¡ç±»åï¼ãå
¥åºãï¼ä»»å¡å·ï¼ã{transfer.TaskNum}ãæçç¼å·ï¼ã{transfer.PalletCode}ã,èµ·å§å°åï¼ã{transfer.SourceAddress}ãï¼ç®æ å°åï¼ã{transfer.TargetAddress}ã"); |
| | | } |
| | | return content; |
| | | |
| | |
| | | _unitOfWorkManage.BeginTran(); |
| | | BaseDal.AddData(transfer); |
| | | _unitOfWorkManage.CommitTran(); |
| | | content.OK("æå¨ä»»å¡å建æåï¼"); |
| | | WriteLog.Write_Log("æå¨ä»»å¡å建æå", "å建æå", $"æçç¼å·ï¼{transfer.PalletCode}ï¼ä»»å¡ç±»åï¼{transfer.TaskType},èµ·å§å°åï¼{transfer.SourceAddress}ï¼ç®æ å°åï¼{transfer.TargetAddress}"); |
| | | content.OK("æå¨åºåºä»»å¡å建æåï¼"); |
| | | WriteLog.Write_Log("æå¨ä»»å¡å建æå", "å建æå", $"ä»»å¡ç±»åï¼ãåºåºã,ä»»å¡å·ï¼ã{transfer.TaskNum}ãæçç¼å·ï¼ã{transfer.PalletCode}ãï¼,èµ·å§å°åï¼ã{transfer.SourceAddress}ãï¼ç®æ å°åï¼ã{transfer.TargetAddress}ã"); |
| | | } |
| | | return content; |
| | | } |
| | | else if (transfer.TaskType == 300) |
| | | { |
| | | // æ£å¸¸åå»ºä»»å¡ |
| | | transfer.TaskNum = BaseDal.GetTaskNum(nameof(SequenceEnum.SeqTaskNum)); |
| | | transfer.TaskState = 300; |
| | | transfer.CurrentAddress = transfer.SourceAddress; |
| | | transfer.NextAddress = transfer.TargetAddress; |
| | | transfer.Roadway = device.DeviceCode; |
| | | transfer.Creater = "WCS"; |
| | | transfer.Grade = 1; |
| | | transfer.CreateDate = DateTime.Now; |
| | | _unitOfWorkManage.BeginTran(); |
| | | BaseDal.AddData(transfer); |
| | | _unitOfWorkManage.CommitTran(); |
| | | content.OK("æå¨çç¹ä»»å¡å建æåï¼"); |
| | | WriteLog.Write_Log("æå¨ä»»å¡å建æå", "å建æå", $"ï¼ä»»å¡ç±»åï¼ãçç¹ãï¼ä»»å¡å·ï¼ã{transfer.TaskNum}ãï¼æçç¼å·ï¼ã{transfer.PalletCode}ãï¼ç®æ å°åï¼ã{transfer.TargetAddress}ã"); |
| | | |
| | | return content; |
| | | } |
| | | |
| | | |
| | | } |
| | | else |
| | | { |
| | | content.Error($"æå¨å建任å¡å¤±è´¥,åå :{device.DeviceCode}åºå°åä¸å¹é
,èµ·å§å°åï¼{transfer.SourceAddress}ï¼ç®æ å°åï¼{transfer.TargetAddress}"); |
| | | WriteLog.Write_Log("æå¨ä»»å¡å建失败", "å建失败", $"æçç¼å·ï¼{transfer.PalletCode}ï¼ä»»å¡ç±»åï¼{transfer.TaskType},èµ·å§å°åï¼{transfer.SourceAddress}ï¼ç®æ å°åï¼{transfer.TargetAddress}"); |
| | | WriteLog.Write_Log("æå¨ä»»å¡å建失败", "å建失败",$"ä»»å¡å·ï¼ã{transfer.TaskNum}ãï¼æçç¼å·ï¼ã{transfer.PalletCode}ãï¼ç®æ å°åï¼ã{transfer.TargetAddress}ã"); |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | |
| | | } |
| | | return content; |
| | | } |
| | | /// <summary> |
| | | /// ç¼è¾ |
| | | /// </summary> |
| | | /// <param name="saveModel"></param> |
| | | /// <returns></returns> |
| | | public override WebResponseContent UpdateData(SaveModel saveModel) |
| | | { |
| | | WebResponseContent content = new WebResponseContent(); |
| | | try |
| | | { |
| | | string json = JsonConvert.SerializeObject(saveModel.MainData); |
| | | Dt_Task task = JsonConvert.DeserializeObject<Dt_Task>(json); |
| | | content.Status = BaseDal.UpdateData(task); |
| | | }catch(Exception e) |
| | | { |
| | | WebResponseContent.Instance.Error(e.Message); |
| | | } |
| | | return content; |
| | | } |
| | | /// |
| | | |
| | | //agvè¿åºç¶æåé¦ |
| | | public WebResponseContent getManuaAGVStatus(AgvUpdateRequest agvUpdateRequest) |
| | | { |
| | | //è·åWMSè°åçåæ° |
| | | WriteLog.Write_Log("æå¨agvè¿åºç¶æå馿¥å£", "æå¨agvè¿åºç¶æä¿¡æ¯", $"åºå£åç§°ï¼ã{agvUpdateRequest.warehousenumber}ãï¼ç³è¯·ç¶æï¼ã{agvUpdateRequest.agvstatus}ã"); |
| | | |
| | | WebResponseContent content = new WebResponseContent(); |
| | | try |
| | | { |
| | | string DeciceCodes = "1003"; |
| | | if (agvUpdateRequest.warehousenumber.StartsWith("C")) DeciceCodes = "1004"; |
| | | |
| | | IDevice? device = Storage.Devices.FirstOrDefault(x => x.DeviceCode == DeciceCodes); |
| | | if (device == null) return content.Error("WCSæªè½è·åå°åºå£å®ä¾"); |
| | | CommonConveyorLine conveyorLine = (CommonConveyorLine)device; |
| | | |
| | | //æ¯å¦å¯è¿åº |
| | | DeviceProDTO? HandShake = conveyorLine.DeviceProDTOs.FirstOrDefault(x => x.DeviceChildCode == agvUpdateRequest.warehousenumber && x.DeviceProParamName == "HandShake"); |
| | | if (HandShake == null) return content.Error($"WCSæªæ¾å°åºå£ï¼{agvUpdateRequest.warehousenumber},对åºçåè®®"); |
| | | DeviceProDTO? Request = conveyorLine.DeviceProDTOs.FirstOrDefault(x => x.DeviceChildCode == agvUpdateRequest.warehousenumber && x.DeviceProParamName == "Request"); |
| | | |
| | | if (agvUpdateRequest.agvstatus == 1) |
| | | { |
| | | bool HandShakebool = conveyorLine.Communicator.Write<short>(HandShake.DeviceProAddress, 1); |
| | | if (HandShakebool) |
| | | { |
| | | if (Request != null) |
| | | { |
| | | conveyorLine.Communicator.Write<short>(Request.DeviceProAddress, 1); |
| | | } |
| | | //æ¯å¦å¯è¿åº 1å
许å 2å
è®¸æ¾ |
| | | DeviceProDTO? deviceProDTO = conveyorLine.DeviceProDTOs.FirstOrDefault(x => x.DeviceChildCode == agvUpdateRequest.warehousenumber && x.DeviceProParamName == "PermitHandShake"); |
| | | //æ¯å¦æè´§ |
| | | DeviceProDTO? StationNumProDTO = conveyorLine.DeviceProDTOs.FirstOrDefault(x => x.DeviceChildCode == agvUpdateRequest.warehousenumber && x.DeviceProParamName == "StationNum"); |
| | | if (deviceProDTO == null || StationNumProDTO == null) return content.Error($"WCSæªæ¾å°åºå£ï¼{agvUpdateRequest.warehousenumber},对åºçåè®®"); |
| | | int statusValue = 0; |
| | | int portStatus = conveyorLine.Communicator.Read<ushort>(deviceProDTO.DeviceProAddress); |
| | | int StationStatus = conveyorLine.Communicator.Read<ushort>(StationNumProDTO.DeviceProAddress); |
| | | |
| | | //æè´§ï¼å¯è¿ä¿¡å· |
| | | statusValue = ((portStatus == 1 && StationStatus == 1) || (portStatus == 2 && StationStatus == 0)) ? 1 : (portStatus == 0) ? 0 : 0; |
| | | if (agvUpdateRequest.warehousenumber == "G01" || agvUpdateRequest.warehousenumber == "G06" || agvUpdateRequest.warehousenumber == "G07") |
| | | { |
| | | if (statusValue == 1) |
| | | { |
| | | return content.OK("ç³è¯·è¿å
¥æå"); |
| | | |
| | | } |
| | | else |
| | | { |
| | | conveyorLine.Communicator.Write<short>(Request.DeviceProAddress, 0); |
| | | return content.Error("读åplcä¸å¯è¿å
¥ä¿¡æ¯"); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | return content.OK("ç³è¯·è¿å
¥æå"); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | return content.Error("åå
¥plcè¿å
¥ä¿¡å·å¤±è´¥"); |
| | | } |
| | | } |
| | | else if (agvUpdateRequest.agvstatus == 2) |
| | | { |
| | | //åå
¥è¾éçº¿ä¿¡å· |
| | | bool portStatus = conveyorLine.Communicator.Write<short>(HandShake.DeviceProAddress, 0); |
| | | if (portStatus) |
| | | { |
| | | if (Request != null) |
| | | { |
| | | conveyorLine.Communicator.Write<short>(Request.DeviceProAddress, 0); |
| | | } |
| | | return content.OK("ç³è¯·éåºæå"); |
| | | } |
| | | else |
| | | { |
| | | return content.Error("åå
¥plcæ¸
é¤ä¿¡å·å¤±è´¥"); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | return content.Error($"agv对åºçç³è¯·é误ï¼å段ï¼agvstatusï¼ç³è¯·çå¼ï¼{agvUpdateRequest.agvstatus}"); |
| | | } |
| | | |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | return content.Error($"WCS任塿·»å é误ï¼åå ï¼{ex.Message}"); |
| | | } |
| | | } |
| | | } |
| | | } |