using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data; using System.IO.MemoryMappedFiles; using QMAPP.FJC.Entity.FIS; using QMFrameWork.Data; using QMFrameWork.Log; using QMAPP.Entity; using QMAPP.DAL; using QMAPP.Entity.Sys; using QMAPP.FJC.Entity.FileCopy.FIS; namespace QMAPP.FJC.DAL.FIS { /// /// 模块名称:仪表板计划 /// 作 者:郭兆福 /// 创建时间:2017年09月15日 /// public class DashBoardPlanDAL : BaseDAL { #region 获取信息 /// /// 获取信息 /// /// 条件 /// 信息 public OrderPlan Get(OrderPlan model) { string sql = null; List parameters = new List(); try { sql = "SELECT * FROM T_PP_ORDERPLAN WHERE '1'='1'"; if (string.IsNullOrEmpty(model.PID) == false) { sql += " AND PID = @PID"; parameters.Add(new DataParameter("PID", model.PID)); } if (string.IsNullOrEmpty(model.PLAN_NO) == false) { sql += " AND PLAN_NO = @PLAN_NO"; parameters.Add(new DataParameter("PLAN_NO", model.PLAN_NO)); } using (IDataSession session = AppDataFactory.CreateMainSession()) { //获取信息 model = session.Get(sql, parameters.ToArray()); } return model; } catch (Exception ex) { LogManager.LogHelper.Error(new LogInfo() { ErrorInfo = ex, Tag = ex.StackTrace, Info = "仪表板信息数据层-获取信息" }); throw; } } #endregion #region 获取列表 /// /// 获取列表 /// /// 条件 /// 数据页 /// 数据页 public DataPage GetList(OrderPlan condition, DataPage page) { string sql = null; List parameters = new List(); try { sql = this.GetQuerySql(condition, ref parameters); //分页关键字段及排序 page.KeyName = "PID"; if (string.IsNullOrEmpty(page.SortExpression)) { page.SortExpression = "PLAN_DATE DESC,PLAN_SEQ DESC"; } using (IDataSession session = AppDataFactory.CreateMainSession()) { page = session.GetDataPage(sql, parameters.ToArray(), page); } return page; } catch (Exception ex) { LogManager.LogHelper.Error(new LogInfo() { ErrorInfo = ex, Tag = ex.StackTrace, Info = "公司信息数据层-获取列表" }); throw; } } #endregion #region 获取查询语句 /// /// 获取查询语句 /// /// 查询条件 /// 参数 /// 查询语句 private string GetQuerySql(OrderPlan condition, ref List parameters) { StringBuilder sqlBuilder = new StringBuilder(); StringBuilder whereBuilder = new StringBuilder(); try { //构成查询语句 sqlBuilder.AppendLine(" SELECT DISTINCT O.PID "); sqlBuilder.AppendLine(" ,O.FACTORY_CODE "); sqlBuilder.AppendLine(" ,F.FACTORY_NAME "); sqlBuilder.AppendLine(" ,O.PLAN_NO "); sqlBuilder.AppendLine(" ,O.PLAN_SEQ "); sqlBuilder.AppendLine(" ,O.PLAN_STATE "); sqlBuilder.AppendLine(" ,O.MATERIAL_CODE "); sqlBuilder.AppendLine(" ,M.MATERIAL_NAME "); sqlBuilder.AppendLine(" ,O.MACHINECODDE "); sqlBuilder.AppendLine(" ,O.PBOM_CODE "); sqlBuilder.AppendLine(" ,O.ROUTE_CODE "); sqlBuilder.AppendLine(" ,R.ROUTE_NAME "); sqlBuilder.AppendLine(" ,O.REMARK "); sqlBuilder.AppendLine(" ,O.QTY "); sqlBuilder.AppendLine(" ,O.COMPLETE_QTY "); sqlBuilder.AppendLine(" ,CONVERT(VARCHAR(19),O.PLAN_DATE,120) AS PLAN_DATE "); sqlBuilder.AppendLine(" ,O.SHIFT_CODE "); sqlBuilder.AppendLine(" ,P.PRODUCESHIFTNAME AS SHIFT_NAME "); sqlBuilder.AppendLine(" ,O.PLANSOURCE "); sqlBuilder.AppendLine(" ,O.PRODUCEREQUIRE "); sqlBuilder.AppendLine(" ,O.CREATEUSER "); sqlBuilder.AppendLine(" ,O.CREATEDATE "); sqlBuilder.AppendLine(" ,O.UPDATEUSER "); sqlBuilder.AppendLine(" ,O.UPDATEDATE "); sqlBuilder.AppendLine(" ,O.IGNORE_FISBREAK "); sqlBuilder.AppendLine(" ,O.FIS_ASMSETCODE "); sqlBuilder.AppendLine(" ,O.STARTTIME AS STARTTIMEVIEW "); sqlBuilder.AppendLine(" ,O.ENDTIME AS ENDTIMEVIEW"); sqlBuilder.AppendLine(" ,C.USERNAME AS CREATEUSERNAME "); sqlBuilder.AppendLine(" ,U.USERNAME AS UPDATEUSERNAME "); sqlBuilder.AppendLine(" FROM T_PP_ORDERPLAN O "); sqlBuilder.AppendLine(" LEFT JOIN T_MD_FACTORY F ON F.FACTORY_CODE=O.FACTORY_CODE "); sqlBuilder.AppendLine(" LEFT JOIN T_MD_MATERIAL M ON M.MATERIAL_CODE=O.MATERIAL_CODE "); sqlBuilder.AppendLine(" LEFT JOIN T_MD_PBOM PB ON PB.MATERIAL_CODE=O.MATERIAL_CODE "); sqlBuilder.AppendLine(" LEFT JOIN T_MD_MATERIAL_ROUTE MR ON MR.MATERIAL_CODE=PB.MATERIAL_CODE "); sqlBuilder.AppendLine(" LEFT JOIN T_MD_PROCESS_ROUTE PR ON PR.ROUTE_CODE=MR.ROUTE_CODE "); sqlBuilder.AppendLine(" LEFT JOIN T_MD_PROCESS_ROUTE_WORKCELL PRW ON PRW.ROUTE_CODE=PR.ROUTE_CODE "); sqlBuilder.AppendLine(" LEFT JOIN T_MD_WORKCELL WC ON WC.WORKCELL_CODE=PRW.WORKCELL_CODE "); sqlBuilder.AppendLine(" LEFT JOIN T_BD_PRODUCESHIFT P ON P.PRODUCESHIFTTCODE=O.SHIFT_CODE "); sqlBuilder.AppendLine(" LEFT JOIN T_BD_PROCESS_ROUTE R ON R.ROUTE_CODE=O.ROUTE_CODE "); sqlBuilder.AppendLine(" LEFT JOIN T_QM_USER C ON C.USERID=O.CREATEUSER "); sqlBuilder.AppendLine(" LEFT JOIN T_QM_USER U ON U.USERID=O.UPDATEUSER "); whereBuilder.AppendFormat(" AND O.WORKCENTER_CODE in (select distinct WORKCENTER from T_PP_ORDERINDENTITY where ORDER_TYPE='{0}')", condition.ORDER_TYPE); //查询条件 //工厂编号 if (string.IsNullOrEmpty(condition.FACTORY_CODE) == false) { whereBuilder.Append(" AND O.FACTORY_CODE = @FACTORY_CODE "); parameters.Add(new DataParameter { ParameterName = "FACTORY_CODE", DataType = DbType.String, Value = condition.FACTORY_CODE }); } //计划单号 if (string.IsNullOrEmpty(condition.PLAN_NO) == false) { whereBuilder.Append(" AND PLAN_NO = @PLAN_NO "); parameters.Add(new DataParameter { ParameterName = "PLAN_NO", DataType = DbType.String, Value = condition.PLAN_NO }); } //物料号 if (string.IsNullOrEmpty(condition.MATERIAL_CODE) == false) { whereBuilder.Append(" AND O.MATERIAL_CODE = @MATERIAL_CODE "); parameters.Add(new DataParameter { ParameterName = "MATERIAL_CODE", DataType = DbType.String, Value = condition.MATERIAL_CODE }); } //工艺路线 if (string.IsNullOrEmpty(condition.ROUTE_CODE) == false) { whereBuilder.Append(" AND ROUTE_CODE = @ROUTE_CODE "); parameters.Add(new DataParameter { ParameterName = "ROUTE_CODE", DataType = DbType.String, Value = condition.ROUTE_CODE }); } //班次编码 if (string.IsNullOrEmpty(condition.SHIFT_CODE) == false) { whereBuilder.Append(" AND O.SHIFT_CODE = @SHIFT_CODE "); parameters.Add(new DataParameter { ParameterName = "SHIFT_CODE", DataType = DbType.String, Value = condition.SHIFT_CODE }); } //计划时间 if (condition.PLANTIMESTART != DateTime.MinValue) { whereBuilder.Append(" AND O.PLAN_DATE >= @PLANTIMESTART"); parameters.Add(new DataParameter { ParameterName = "PLANTIMESTART", DataType = DbType.String, Value = condition.PLANTIMESTART }); } if (condition.PLANTIMEEND != DateTime.MinValue) { whereBuilder.Append(" AND O.PLAN_DATE <= @PLANTIMEEND"); parameters.Add(new DataParameter { ParameterName = "PLANTIMEEND", DataType = DbType.String, Value = condition.PLANTIMEEND }); } if (whereBuilder.Length > 0) { sqlBuilder.Append(" WHERE " + whereBuilder.ToString().Substring(4)); } return sqlBuilder.ToString(); } catch (Exception ex) { throw ex; } } #endregion #region 信息是否重复 /// /// 判断计划单号是否存在 /// /// /// true:已存在;fasel:不存在。 public int ExistsOrderPlan(OrderPlan model) { string PID = ""; int count = 0; StringBuilder sqlBuilder = new StringBuilder(); try { if (string.IsNullOrEmpty(model.PID) == false) { PID = model.PID; } sqlBuilder.AppendLine("SELECT COUNT(*) FROM T_PP_ORDERPLAN "); sqlBuilder.AppendLine(" WHERE PID <> @PID AND PLAN_NO=@PLAN_NO"); using (IDataSession session = AppDataFactory.CreateMainSession()) { count = Convert.ToInt32(session.ExecuteSqlScalar(sqlBuilder.ToString(), new DataParameter("PID", PID), new DataParameter("PLAN_NO", model.PLAN_NO))); } return count; } catch (Exception ex) { throw ex; } } #endregion #region 插入信息 /// /// 插入信息(单表) /// /// 信息 /// 插入行数 public int Insert(OrderPlan model) { int count = 0; try { using (IDataSession session = AppDataFactory.CreateMainSession()) { //插入基本信息 count = session.Insert(model); new OrderPlanDAL().InsertOrderPlanTrace(session,model, "新增"); } return count; } catch (Exception ex) { throw ex; } } #endregion #region 更新信息 /// /// 更新信息 /// /// /// 更新行数 public int Update(OrderPlan model) { int count = 0; try { using (IDataSession session = AppDataFactory.CreateMainSession()) { //更新基本信息 count = session.Update(model); new OrderPlanDAL().InsertOrderPlanTrace(session,model, "修改"); } return count; } catch (Exception ex) { throw ex; } } #endregion #region 删除 /// /// 删除信息 /// /// /// 删除个数 //提交事务 public int Delete(OrderPlan model) { int count = 0; try { using (IDataSession session = AppDataFactory.CreateMainSession()) { //删除基本信息 count = session.Delete(model); new OrderPlanDAL().InsertOrderPlanTrace(session,model, "删除"); } return count; } catch (Exception ex) { throw ex; } } #endregion #region 删除校验 /// /// 删除校验 /// /// /// public int DelCheck(OrderPlan model) { int num = 0; int state; StringBuilder sqlBuilder = new StringBuilder(); StringBuilder sqlBuilder2 = new StringBuilder(); sqlBuilder.AppendLine(" SELECT COMPLETE_QTY "); sqlBuilder.AppendLine(" FROM T_PP_ORDERPLAN "); sqlBuilder.AppendLine(" WHERE PID = @PID "); sqlBuilder2.AppendLine(" SELECT PLAN_STATE "); sqlBuilder2.AppendLine(" FROM T_PP_ORDERPLAN "); sqlBuilder2.AppendLine(" WHERE PID = @PID "); using (IDataSession session = AppDataFactory.CreateMainSession()) { num = Convert.ToInt32(session.ExecuteSqlScalar(sqlBuilder.ToString(), new DataParameter("PID", model.PID))); state = Convert.ToInt32(session.ExecuteSqlScalar(sqlBuilder2.ToString(), new DataParameter("PID", model.PID))); } return num + state; } #endregion #region 发布 /// /// 发布信息 /// /// /// 发布个数 public int PutOut(OrderPlan model, DataTable workOrderDt) { BaseSession = AppDataFactory.CreateMainSession(); IDbConnection dbConn = DbManager.MainConnectionInfo.Connection; IDbTransaction ids = dbConn.BeginTransaction(); try { if (workOrderDt.Rows != null) { BaseSession.DbHelper.BulkCopyData(workOrderDt, "T_PP_WORKORDER", dbConn, ids); ids.Commit(); } } catch (Exception ex) { ids.Rollback(); throw ex; } int count = 0; int count2 = 0; StringBuilder sqlBuilder = new StringBuilder(); StringBuilder sqlBuilder2 = new StringBuilder(); List parameters = new List(); using (IDataSession session = AppDataFactory.CreateMainSession()) { sqlBuilder.AppendLine(" UPDATE T_PP_ORDERPLAN "); sqlBuilder.AppendLine(" SET PLAN_STATE='1' "); sqlBuilder.AppendLine(" WHERE PID = @PID "); sqlBuilder2.AppendLine(" UPDATE T_PP_WORKORDER "); sqlBuilder2.AppendLine(" SET STATE='1' "); sqlBuilder2.AppendLine(" WHERE ORDERPLANID = @PID "); //发布更新基本信息 parameters.Add(new DataParameter { ParameterName = "PID", DataType = DbType.String, Value = model.PID }); count = session.ExecuteSql(sqlBuilder.ToString(), parameters.ToArray()); count2 = session.ExecuteSql(sqlBuilder2.ToString(), parameters.ToArray()); } return count; } #endregion #region 发布校验 /// /// 发布校验 /// /// /// public int PutOutCheck(OrderPlan model) { int num = 0; StringBuilder sqlBuilder = new StringBuilder(); sqlBuilder.AppendLine(" SELECT PLAN_STATE "); sqlBuilder.AppendLine(" FROM T_PP_ORDERPLAN "); sqlBuilder.AppendLine(" WHERE PID = @PID "); using (IDataSession session = AppDataFactory.CreateMainSession()) { num = Convert.ToInt32(session.ExecuteSqlScalar(sqlBuilder.ToString(), new DataParameter("PID", model.PID))); } return num; } #endregion #region 导入 public ImportMessage GetImportData(List list) { ImportMessage em = new ImportMessage(); List parameters = new List(); try { using (IDataSession session = AppDataFactory.CreateMainSession()) { //设置祖先对象数据会话 session.OpenTs(); foreach (OrderPlan info in list) { string operatType = ""; if (info.IsNewInfo == true) { //插入信息 int count = session.Insert(info); operatType = "新增"; em.insertNum++; } else { //更新信息 int count = session.Update(info); operatType = "修改"; em.updateNum++; } new OrderPlanDAL().InsertOrderPlanTrace(session,info, operatType); } session.CommitTs(); } } catch (Exception ex) { throw ex; } return em; } #endregion #region 导入校验工厂区域信息是否匹配(后期校验导入,暂且注释) ///// ///// 导入校验工厂区域信息是否匹配 ///// ///// 工厂 ///// 区域 ///// 结果 //public int ImportCheck(Plant plantmodel, Area areamodel) //{ // int num = 0; // StringBuilder sqlBuilder = new StringBuilder(); // try // { // sqlBuilder.AppendLine("SELECT COUNT(1) FROM T_BD_FACTORY "); // sqlBuilder.AppendLine(" WHERE PID=@PID AND AREAID=@AREAID"); // using (IDataSession session = AppDataFactory.CreateMainSession()) // { // num = Convert.ToInt32(session.ExecuteSqlScalar(sqlBuilder.ToString(), new DataParameter("PID", plantmodel.PID), // new DataParameter { ParameterName = "AREAID", Value = areamodel.PID })); // } // return num; // } // catch (Exception ex) // { // throw ex; // } //} #endregion #region 获取导出的数据 /// /// 获取导出的数据 /// /// 查询条件 /// 数据 public DataTable GetExportData(OrderPlan model) { DataTable dt = null; string sql = null; List parameters = new List(); try { //构成查询语句 sql = this.GetQuerySql(model, ref parameters); using (IDataSession session = AppDataFactory.CreateMainSession()) { dt = session.GetTable(sql, parameters.ToArray()); dt.TableName = "DashBoardPlanExp"; } return dt; } catch (Exception ex) { throw ex; } } #endregion #region 获取列表(为了修改顺序号使用) /// /// 获取列表 /// /// 条件 /// 数据页 /// 数据页 public DataPage GetDashBoardPlanList(OrderPlan condition, DataPage page) { string sql = null; List parameters = new List(); try { #region 排序 //分页关键字段及排序 page.KeyName = "PID"; page.SortExpression = "UPDATEDATE DESC"; #endregion sql = this.GetQuerySqlForSeq(condition, ref parameters); using (IDataSession session = AppDataFactory.CreateMainSession()) { page = session.GetDataPage(sql, parameters.ToArray(), page); } return page; } catch (Exception ex) { LogManager.LogHelper.Error(new LogInfo() { ErrorInfo = ex, Tag = ex.StackTrace, Info = "信息数据层-获取列表" }); throw; } } /// /// 为了修改顺序号 /// /// /// /// private string GetQuerySqlForSeq(OrderPlan condition, ref List parameters) { StringBuilder sqlBuilder = new StringBuilder(); StringBuilder whereBuilder = new StringBuilder(); try { //构成查询语句 sqlBuilder.AppendLine(" SELECT DISTINCT O.PID "); sqlBuilder.AppendLine(" ,O.FACTORY_CODE "); sqlBuilder.AppendLine(" ,F.FACTORY_NAME "); sqlBuilder.AppendLine(" ,O.PLAN_NO "); sqlBuilder.AppendLine(" ,O.PLAN_SEQ "); sqlBuilder.AppendLine(" ,O.PLAN_STATE "); sqlBuilder.AppendLine(" ,O.MATERIAL_CODE "); sqlBuilder.AppendLine(" ,M.MATERIAL_NAME "); sqlBuilder.AppendLine(" ,O.MACHINECODDE "); sqlBuilder.AppendLine(" ,O.PBOM_CODE "); sqlBuilder.AppendLine(" ,O.ROUTE_CODE "); sqlBuilder.AppendLine(" ,R.ROUTE_NAME "); sqlBuilder.AppendLine(" ,O.REMARK "); sqlBuilder.AppendLine(" ,O.QTY "); sqlBuilder.AppendLine(" ,O.COMPLETE_QTY "); sqlBuilder.AppendLine(" ,O.PLAN_DATE "); sqlBuilder.AppendLine(" ,O.SHIFT_CODE "); sqlBuilder.AppendLine(" ,P.PRODUCESHIFTNAME AS SHIFT_NAME "); sqlBuilder.AppendLine(" ,O.PLANSOURCE "); sqlBuilder.AppendLine(" ,O.PRODUCEREQUIRE "); sqlBuilder.AppendLine(" ,O.CREATEUSER "); sqlBuilder.AppendLine(" ,O.CREATEDATE "); sqlBuilder.AppendLine(" ,O.UPDATEUSER "); sqlBuilder.AppendLine(" ,O.UPDATEDATE "); sqlBuilder.AppendLine(" ,O.IGNORE_FISBREAK "); sqlBuilder.AppendLine(" ,O.FIS_ASMSETCODE "); sqlBuilder.AppendLine(" ,O.STARTTIME AS STARTTIMEVIEW "); sqlBuilder.AppendLine(" ,O.ENDTIME AS ENDTIMEVIEW"); sqlBuilder.AppendLine(" ,C.USERNAME AS CREATEUSERNAME "); sqlBuilder.AppendLine(" ,U.USERNAME AS UPDATEUSERNAME "); sqlBuilder.AppendLine(" FROM T_PP_ORDERPLAN O "); sqlBuilder.AppendLine(" LEFT JOIN T_MD_FACTORY F ON F.FACTORY_CODE=O.FACTORY_CODE "); sqlBuilder.AppendLine(" LEFT JOIN T_MD_MATERIAL M ON M.MATERIAL_CODE=O.MATERIAL_CODE "); sqlBuilder.AppendLine(" LEFT JOIN T_MD_PBOM PB ON PB.MATERIAL_CODE=O.MATERIAL_CODE "); sqlBuilder.AppendLine(" LEFT JOIN T_MD_MATERIAL_ROUTE MR ON MR.MATERIAL_CODE=PB.MATERIAL_CODE "); sqlBuilder.AppendLine(" LEFT JOIN T_MD_PROCESS_ROUTE PR ON PR.ROUTE_CODE=MR.ROUTE_CODE "); sqlBuilder.AppendLine(" LEFT JOIN T_MD_PROCESS_ROUTE_WORKCELL PRW ON PRW.ROUTE_CODE=PR.ROUTE_CODE "); sqlBuilder.AppendLine(" LEFT JOIN T_MD_WORKCELL WC ON WC.WORKCELL_CODE=PRW.WORKCELL_CODE "); sqlBuilder.AppendLine(" LEFT JOIN T_BD_PRODUCESHIFT P ON P.PRODUCESHIFTTCODE=O.SHIFT_CODE "); sqlBuilder.AppendLine(" LEFT JOIN T_BD_PROCESS_ROUTE R ON R.ROUTE_CODE=O.ROUTE_CODE "); sqlBuilder.AppendLine(" LEFT JOIN T_QM_USER C ON C.USERID=O.CREATEUSER "); sqlBuilder.AppendLine(" LEFT JOIN T_QM_USER U ON U.USERID=O.UPDATEUSER "); whereBuilder.AppendFormat(" AND O.WORKCENTER_CODE in (select distinct WORKCENTER from T_PP_ORDERINDENTITY where ORDER_TYPE='{0}')", condition.ORDER_TYPE); //查询条件 //工厂编号 if (string.IsNullOrEmpty(condition.FACTORY_CODE) == false) { whereBuilder.Append(" AND O.FACTORY_CODE = @FACTORY_CODE "); parameters.Add(new DataParameter { ParameterName = "FACTORY_CODE", DataType = DbType.String, Value = condition.FACTORY_CODE }); } //计划单号 if (string.IsNullOrEmpty(condition.PLAN_NO) == false) { whereBuilder.Append(" AND PLAN_NO = @PLAN_NO "); parameters.Add(new DataParameter { ParameterName = "PLAN_NO", DataType = DbType.String, Value = condition.PLAN_NO }); } //物料号 if (string.IsNullOrEmpty(condition.MATERIAL_CODE) == false) { whereBuilder.Append(" AND O.MATERIAL_CODE = @MATERIAL_CODE "); parameters.Add(new DataParameter { ParameterName = "MATERIAL_CODE", DataType = DbType.String, Value = condition.MATERIAL_CODE }); } if (string.IsNullOrEmpty(condition.PIDList) == false) { whereBuilder.Append(" AND O.PID IN ( " + condition.PIDList + ") "); } //工艺路线 if (string.IsNullOrEmpty(condition.ROUTE_CODE) == false) { whereBuilder.Append(" AND ROUTE_CODE = @ROUTE_CODE "); parameters.Add(new DataParameter { ParameterName = "ROUTE_CODE", DataType = DbType.String, Value = condition.ROUTE_CODE }); } //班次编码 if (string.IsNullOrEmpty(condition.SHIFT_CODE) == false) { whereBuilder.Append(" AND O.SHIFT_CODE = @SHIFT_CODE "); parameters.Add(new DataParameter { ParameterName = "SHIFT_CODE", DataType = DbType.String, Value = condition.SHIFT_CODE }); } //计划时间 if (condition.PLANTIMESTART != DateTime.MinValue) { whereBuilder.Append(" AND O.PLAN_DATE >= @PLANTIMESTART"); parameters.Add(new DataParameter { ParameterName = "PLANTIMESTART", DataType = DbType.String, Value = condition.PLANTIMESTART }); } if (condition.PLANTIMEEND != DateTime.MinValue) { whereBuilder.Append(" AND O.PLAN_DATE <= @PLANTIMEEND"); parameters.Add(new DataParameter { ParameterName = "PLANTIMEEND", DataType = DbType.String, Value = condition.PLANTIMEEND }); } if (whereBuilder.Length > 0) { sqlBuilder.Append(" WHERE " + whereBuilder.ToString().Substring(4)); } return sqlBuilder.ToString(); } catch (Exception ex) { throw ex; } } #endregion } }