zhangweicheng před 5 roky
rodič
revize
e389fc1fe5

+ 1 - 0
config/gulpConfig.js

@@ -154,6 +154,7 @@ module.exports = {
         'web/building_saas/main/js/views/zlfb_view.js',
         'web/building_saas/main/js/views/installation_fee_view.js',
         'web/building_saas/main/js/views/project_glj_view.js',
+        'web/building_saas/main/js/views/config_material_view.js',
         'web/building_saas/main/js/views/importBills.js',
         'public/web/rpt_tpl_def.js',
         'public/web/treeDataHelper.js',

+ 13 - 0
modules/glj/controllers/glj_controller.js

@@ -812,6 +812,19 @@ class GLJController extends BaseController {
         res.json(result);
     }
 
+    async updateEvaluateMaterial(request, response){
+      let result={error:0};
+      try {
+          let data = JSON.parse(request.body.data);
+          result.data = await glj_facade.updateEvaluateMaterial(data);
+      }catch (err){
+          logger.err(err);
+          result.error=1;
+          result.message = err.message;
+      }
+      response.json(result);
+  }
+
     async modifyKeyValue(req,res){//修改工料机关键的属性:名称、类型、规格、型号等
         let result={
             error:0

+ 34 - 1
modules/glj/facade/glj_facade.js

@@ -11,7 +11,8 @@ module.exports={ //先导出后require可以解决循环引用问题
     updateUserFreight:updateUserFreight,
     getUserFreights:getUserFreights,
     insertElectrovalence:insertElectrovalence,
-    updateElectrovalence:updateElectrovalence
+    updateElectrovalence:updateElectrovalence,
+    updateEvaluateMaterial:updateEvaluateMaterial
 };
 
 const mongoose = require('mongoose');
@@ -28,6 +29,11 @@ let unit_price_model = mongoose.model('unit_price');
 let user_freights_model = mongoose.model('user_freights');
 let std_glj_lib_model = mongoose.model('std_glj_lib_map');
 let com_electrovalence_model = mongoose.model('com_electrovalence');
+let evaluateListModel = mongoose.model("evaluate_list");
+let bidEvaluationMode = mongoose.model("bid_evaluation_list");
+let contractorListModel = mongoose.model("contractor_list");
+let projectGLJModel = mongoose.model("glj_list");
+
 
 let ration_glj = require('../../ration_glj/facade/ration_glj_facade');
 const uuidV1 = require('uuid/v1');
@@ -298,4 +304,31 @@ async function updateMaterialCalcTasks(data) {
 async function updateMaterialCalc(data) {
     if(data.tasks.length > 0) await unit_price_model.bulkWrite(data.tasks);
     return {}
+}
+
+async function updateEvaluateMaterial(data) {
+  let modelMap = {
+      "glj_list":projectGLJModel,
+      "evaluate_list":evaluateListModel,
+      "unit_price":unit_price_model,
+      "bid_evaluation_list":bidEvaluationMode,
+      "contractor_list":contractorListModel
+  };
+  for(let t of data.tasks){
+      let model = modelMap[t.type];
+      switch (t.action) {
+          case "update":
+              let query = {};
+              if(t.hasOwnProperty('ID')) query['ID'] = t.ID;
+              if(t.hasOwnProperty('id')) query['id'] = t.id;
+              await model.update(query,t.doc);
+              break;
+          case "add":
+              await model.create(t.doc);
+              break;
+          case "delete":
+              await model.deleteOne({ID:t.ID});
+              break;
+      }
+  }
 }

+ 1 - 0
modules/glj/routes/glj_router.js

@@ -36,6 +36,7 @@ router.post('/updateMaterialCalcTasks',gljController.init, gljController.updateM
 router.post('/insertElectrovalence',gljController.init, gljController.insertElectrovalence);
 router.post('/updateElectrovalence',gljController.init, gljController.updateElectrovalence);
 router.post('/updateUserFreight',gljController.init, gljController.updateUserFreight);
+router.post('/updateEvaluateMaterial', gljController.updateEvaluateMaterial);
 
 router.get('/getVvTaxList', gljController.init, gljController.getVvTaxList);
 router.get('/getUserFreights', gljController.init, gljController.getUserFreights);

+ 2 - 0
modules/main/models/project.js

@@ -19,6 +19,7 @@ import GLJController from "../../glj/controllers/glj_controller";
 let installation_facade = require('../facade/installation_facade');
 let pmController = require('../../pm/controllers/pm_controller');
 let divide_facade = require('../facade/divide_facade');
+let evaluate_facade = require('../facade/evaluate_facade');
 
 const ProjectModel = require('../../pm/models/project_model').project;
 import GLJListModel from "../../glj/models/glj_list_model";
@@ -46,6 +47,7 @@ moduleMap[projectConsts.INSTALLATION_FEE] = installation_facade;
 moduleMap[projectConsts.RATION_TEMPLATE] = ration_template;
 moduleMap[projectConsts.PROJECT_INFO] = pmController;
 moduleMap[projectConsts.DIVIDE_SETTING] = divide_facade;
+moduleMap[projectConsts.EVALUATE_LIST] = evaluate_facade;
 
 var Project = function (){};
 

+ 1 - 0
modules/main/models/project_consts.js

@@ -22,6 +22,7 @@ let projectConst = {
     CALC_PROGRAM:'calc_program',
     INSTALLATION_FEE:'installation_fee',
     PROJECT_INFO: 'project_info',
+    EVALUATE_LIST:'evaluate_list',
     DIVIDE_SETTING:'divide_setting'
 };
 

+ 34 - 4
modules/pm/facade/pm_facade.js

@@ -91,6 +91,7 @@ let importLogsModel = mongoose.model("import_logs");
 const shareListModel = mongoose.model('share_list');
 let welcomeModel = mongoose.model("welcome_setting");
 let divideModel = mongoose.model("divide_setting");
+let evaluateListModel = mongoose.model("evaluate_list");
 
 let featureLibModel =  mongoose.model("std_project_feature_lib");
 let scMathUtil = require('../../../public/scMathUtil').getUtil();
@@ -579,7 +580,8 @@ async function copyProject(userID, compilationID, data, newProjectID = null, del
         copyRationSubList(originalID,newProjectID,billMap.uuidMaping,rationMap.uuidMaping,projectGLJMap.IDMap,rationCoeModel),
         copyRationSubList(originalID,newProjectID,billMap.uuidMaping,rationMap.uuidMaping,projectGLJMap.IDMap,quantityDetailModel),
         copyRationSubList(originalID,newProjectID,billMap.uuidMaping,rationMap.uuidMaping,projectGLJMap.IDMap,rationInstallationModel),
-        copyRationSubList(originalID,newProjectID,billMap.uuidMaping,rationMap.uuidMaping,projectGLJMap.IDMap,rationTemplateModel)
+        copyRationSubList(originalID,newProjectID,billMap.uuidMaping,rationMap.uuidMaping,projectGLJMap.IDMap,rationTemplateModel),
+        copyMaterialList(originalID,newProjectID,projectGLJMap.IDMap,evaluateListModel)
     ];
     if(originalProperty.calcProgramFile){
         copyTasks.push(commonCopy(newProjectID,originalProperty.calcProgramFile.ID,calcProgramFileID,calcProgramsModel));
@@ -876,6 +878,22 @@ async function copyRationSubList(originalPID,newProjectID,billIDMap,rationIDMap,
     await insertMany(newList,model);
 }
 
+async function copyMaterialList(originalPID,newProjectID,projectGLJIDMap,model) {//暂估材料等信息
+  let materialList = await model.find({projectID:originalPID}, '-_id').lean();
+  let newList = [];
+  for(let m of materialList){
+      newList.push(getNewMaterial(m,newProjectID,projectGLJIDMap))
+  }
+  await insertMany(newList,model);
+}
+
+function getNewMaterial(m,newProjectID,projectGLJIDMap) {
+  m.ID = uuidV1();
+  m.projectID = newProjectID;
+  if(projectGLJIDMap[m.projectGLJID]) m.projectGLJID = projectGLJIDMap[m.projectGLJID];
+  return m;
+}
+
 function getCopyRationSubData(doc,newProjectID,billIDMap,rationIDMap,projectGLJIDMap){
     doc.ID = uuidV1();
     doc.projectID = newProjectID;
@@ -1616,6 +1634,7 @@ async function exportTenderData(data){
     result.calcProgramsFile = await calcProgramsModel.findOne({projectID:data.projectID}).lean();
     result.labourCoes = await labourCoesModel.findOne({projectID:data.projectID}).lean();
     result.divide_setting = await divideModel.findOne({projectID:data.projectID}, '-_id').lean();
+    result.evaluateList = await evaluateListModel.find({projectID:data.projectID}, '-_id').lean();
 
     return cipher.aesEncrypt(JSON.stringify(result));
 }
@@ -1763,7 +1782,7 @@ async function importProject(data,req,updateData) {
             if(datas.length > 1 ){//生成后统一次插入 2020-05-29
               let newProjectSettings=[],bills=[],rations=[],projectGLJs=[],rationGLJs=[],rationCoes=[],quantityDetails=[],rationInstallations=[],rationTemplates=[],newCalcProgramsFiles=[],newLabourCoes=[],newDivides=[];
                 for(let i = 1;i<datas.length;i++){
-                  let [newProjectSetting,tbills,trations,tprojectGLJs,trationGLJs,trationCoes,tquantityDetails,trationInstallations,trationTemplates,newCalcProgramsFile,newLabourCoe,newDivide] =  await handleEachProject(datas[i],projectIDMap,labourCoeFileIDMap,calcProgramFileIDMap)
+                  let [newProjectSetting,tbills,trations,tprojectGLJs,trationGLJs,trationCoes,tquantityDetails,trationInstallations,trationTemplates,newCalcProgramsFile,newLabourCoe,newDivide,tevaluateList] =  await handleEachProject(datas[i],projectIDMap,labourCoeFileIDMap,calcProgramFileIDMap)
                   if(newProjectSetting) newProjectSettings.push(newProjectSetting);
                   if(tbills.length > 0) bills = bills.concat(tbills);
                   if(trations.length > 0) rations = rations.concat(trations);
@@ -1776,6 +1795,7 @@ async function importProject(data,req,updateData) {
                   if(newCalcProgramsFile) newCalcProgramsFiles.push(newCalcProgramsFile);
                   if(newLabourCoe) newLabourCoes.push(newLabourCoe);
                   if(newDivide) newDivides.push(newDivide);
+                  if(tevaluateList.length > 0) evaluateList = evaluateList.concat(tevaluateList);
                 }
 
                 if(newProjectSettings.length > 0) await insertMany(newProjectSettings,projectSettingModel);
@@ -1790,6 +1810,7 @@ async function importProject(data,req,updateData) {
                 if(newCalcProgramsFiles.length > 0) await insertMany(newCalcProgramsFiles,calcProgramsModel);
                 if(newLabourCoes.length>0) await insertMany(newLabourCoes,labourCoesModel);
                 if(newDivides.length>0) await divideModel.insertMany(newDivides);
+                if(evaluateList.length > 0) await insertMany(evaluateList,evaluateListModel);
             }
 
          }
@@ -1798,7 +1819,7 @@ async function importProject(data,req,updateData) {
 }
 
 async function handleEachProject(data,projectIDMap,labourCoeFileIDMap,calcProgramFileIDMap){
-    let bills = [],rations = [],projectGLJs = [],rationGLJs=[],rationCoes=[],quantityDetails=[],rationInstallations=[],rationTemplates=[];
+    let bills = [],rations = [],projectGLJs = [],rationGLJs=[],rationCoes=[],quantityDetails=[],rationInstallations=[],rationTemplates=[],evaluateList=[];
     let newProjectSetting =null,newCalcProgramsFile = null,newLabourCoe = null,newDivide=null;
     let billsIDMap = {},projectGLJIDMap={},rationIDMap = {};
     let newProjectID = projectIDMap[data.projSetting.projectID];
@@ -1846,6 +1867,7 @@ async function handleEachProject(data,projectIDMap,labourCoeFileIDMap,calcProgra
     if(data.quantityDetails && data.quantityDetails.length > 0) quantityDetails = setRationSubList(data.quantityDetails,newProjectID,billsIDMap,rationIDMap,projectGLJIDMap);
     if(data.rationInstallations && data.rationInstallations.length > 0) rationInstallations = setRationSubList(data.rationInstallations,newProjectID,billsIDMap,rationIDMap,projectGLJIDMap);
     if(data.rationTemplates && data.rationTemplates.length > 0) rationTemplates = setRationSubList(data.rationTemplates,newProjectID,billsIDMap,rationIDMap,projectGLJIDMap);
+    if(data.evaluateList && data.evaluateList.length > 0) evaluateList = setMaterialList(data.evaluateList,newProjectID,projectGLJIDMap);
 
     //生成projectSetting 文件
     if(data.projSetting){
@@ -1879,7 +1901,7 @@ async function handleEachProject(data,projectIDMap,labourCoeFileIDMap,calcProgra
       delete newDivide._id;
     } 
 
-    return [newProjectSetting,bills,rations,projectGLJs,rationGLJs,rationCoes,quantityDetails,rationInstallations,rationTemplates,newCalcProgramsFile,newLabourCoe,newDivide]
+    return [newProjectSetting,bills,rations,projectGLJs,rationGLJs,rationCoes,quantityDetails,rationInstallations,rationTemplates,newCalcProgramsFile,newLabourCoe,newDivide,evaluateList]
 
 }
 
@@ -1894,6 +1916,14 @@ function setRationSubList(datas,newProjectID,billIDMap,rationIDMap,projectGLJIDM
     return arrs;
 }
 
+function setMaterialList(datas,newProjectID,projectGLJIDMap){
+  let arrs = [];
+  for(let d of datas){
+     arrs.push(getNewMaterial(d,newProjectID,projectGLJIDMap))
+  }
+  return arrs
+}
+
 async function handleMainProjectDatas(mainData,updateData,userID) {
     let mainProjectID = -1;
     let projectIDMap = {},feeRateFileIDMap={},unitPriceFileIDMap={},labourCoeFileIDMap={},calcProgramFileIDMap={};

+ 37 - 6
web/building_saas/glj/html/project_glj.html

@@ -20,13 +20,44 @@
 
 <div class="container-fluid">
     <div class="row">
-        <div class="main-content col p-0 " id="project-glj-main" style="overflow: hidden">
-            <div class="top-content" id="projectGljTop" style="overflow: hidden;">
-                <div class=" gl-side  filterType" id='filterType'>
-                    <ul class="nav flex-column nav-side mt-2 mb-2"  style="margin-top: 0px!important;">
-                        <li class="nav-item"><a class="nav-link active" href="#" id="ALL">所有工料机</a></li>
-                    </ul>
+      <div class=" gl-side  filterType" id='filterType'>
+        <ul class="nav flex-column nav-side mt-2 mb-2"  style="margin-top: 0px!important;">
+            <li class="nav-item"><a class="nav-link active" href="#" id="ALL">所有工料机</a></li>
+            <li class="nav-item"><a class="nav-link" href="javascript:void(0)" id="ZGCL">暂估材料</a></li>
+        </ul>
+      </div>
+
+      <div class="main-content col p-0" id="config_material" style="overflow: hidden; display: none"><!--暂估材料,主要材料等-->
+        <div class="top-content" id="configMaterialTop" style="overflow: hidden">
+            <div class="main-data-top" style="width: 100%; overflow: hidden" id="config_material_sheet">
+            </div>
+        </div>
+        <div class="resize-y" id="configMaterialResize"></div>
+        <div class="bottom-content" id="configMaterialBottom">
+            <ul class="nav nav-tabs" role="tablist">
+                  <li class="nav-item">
+                      <a class=" nav-link  active " data-toggle="tab" data-name="related_sheet" id="related_link" href="#related_div" role="tab">关联暂估材料</a>
+                  </li>
+              <!--   <li class="nav-item">
+                     <a class=" nav-link " data-toggle="tab" data-name="detail_sheet" id="detail_link" href="#related_div" role="tab">关联暂估材料明细</a>
+                 </li>-->
+            </ul>
+            <!-- Tab panes -->
+            <div class="tab-content">
+                <div class="tab-pane active" id="related_div" role="tabpanel">
+                    <div class="form-inline py-1 toolsbar_feeRate" id="filterToolDiv">
+                        <label class="mx-2" for="filterGljName">材料名称包括:</label>
+                        <input type="text" class="form-control form-control-sm" id="filterGljName">
+                        <button type="button" class="btn btn-outline-primary btn-sm" id = "filterAgain">重新过滤</button>
+                       <!-- <button type="button" class="btn btn-outline-primary btn-sm" id = "autoRelated">自动关联招标材料</button>-->
+                    </div>
+                    <div class="main-data-bottom" id="related_sheet" style="overflow:hidden"></div>
                 </div>
+            </div>
+        </div>
+      </div>
+      <div class="main-content col p-0 " id="project-glj-main" style="overflow: hidden">
+            <div class="top-content" id="projectGljTop" style="overflow: hidden;">
             <div class="main-data-top left" id="project_glj_sheet"></div>
          </div>
          <div class="resize-y" id="projectGljResize"></div>

+ 1 - 0
web/building_saas/main/html/main.html

@@ -2027,6 +2027,7 @@
     <script type="text/javascript" src='/web/building_saas/main/js/views/confirm_modal.js'></script>
     <script type="text/javascript" src='/web/building_saas/main/js/views/zlfb_view.js'></script>
     <script type="text/javascript" src='/web/building_saas/main/js/views/installation_fee_view.js'></script>
+    <script type="text/javascript" src='/web/building_saas/main/js/views/config_material_view.js'></script>
     <script type="text/javascript" src="/web/building_saas/main/js/views/importBills.js"></script>
     <!--报表-->
     <script type="text/javascript" src="/public/web/rpt_tpl_def.js"></script>

+ 2 - 1
web/building_saas/main/js/models/main_consts.js

@@ -18,7 +18,8 @@ const ModuleNames = {
     calc_program: 'calc_program',
     installation_fee:'installation_fee',
     projectInfo: 'project_info',
-    divide_setting:'divide_setting'
+    divide_setting:'divide_setting',
+    evaluate_list:'evaluate_list',
 };
 
 let gljType = gljUtil.gljType;

+ 1 - 1
web/building_saas/main/js/models/project.js

@@ -100,7 +100,7 @@ var PROJECT = {
             this.calcProgram = new CalcProgram(this);
             this.calcBase = calcBase;
             this.divide_setting = new DivideSetting(this);
-
+            this.evaluate_list = new EvaluateList(this);
             // this.masterField = {ration: 'billsItemID', volumePrice: 'billsItemID'};
             this.masterField = {ration: 'billsItemID'};
         };

+ 11 - 0
web/building_saas/main/js/models/project_glj.js

@@ -1793,3 +1793,14 @@ class DivideSetting {
       this.datas = datas;
   };
 }
+
+class EvaluateList {
+  constructor (project) {
+      this.project = project;
+      this.datas = [];
+      project.registerModule(ModuleNames.evaluate_list, this);
+  };
+  loadData (datas) {
+      this.datas = datas;
+  };
+}

+ 67 - 11
web/building_saas/main/js/views/project_glj_view.js

@@ -63,6 +63,11 @@ projectGljObject={
         /*{ID:'MAIN_MATERIAL',text:'主材'},
         {ID:'EQUIPMENT',text:'设备'}*/
     ],
+    initSpreads:function(){
+      if(this.projectGljSpread==null) this.initProjectGljSpread();
+      //if(materialAdjustObj.spread == null) materialAdjustObj.initSpread();
+      if(configMaterialObj.configSpread == null) configMaterialObj.initSpread();
+    },
     initProjectGljSpread:function () {
         if(!this.projectGljSpread){
             this.projectGljSpread = SheetDataHelper.createNewSpread($("#project_glj_sheet")[0],2);
@@ -695,6 +700,21 @@ projectGljObject={
         this.materialTreeSheet.setSelection(sel.row==-1?0:sel.row,sel.col,sel.rowCount,sel.colCount);
         this.materialTreeController.setTreeSelected(this.materialTree.items[sel.row==-1?0:sel.row]);
     },
+    initSheetViews(){
+      let me = projectGljObject;
+      if(me.displayType == filterType.ZGCL ){
+        $('#project-glj-main').hide();
+        $('#config_material').show();
+      } else { 
+        $('#config_material').hide();
+        $('#project-glj-main').show();
+      }
+    },
+    refreshViewsData:function(){
+      let me = projectGljObject;
+      if(me.displayType == filterType.ZGCL) return configMaterialObj.refreshSheetDatas();
+      me.refreshDataSheet();
+    },
     refreshDataSheet:function (refresh) {//refresh = true 的时候不用更新表头信息
         let me = projectGljObject;
         if(!me.projectGljSpread)  return;
@@ -1309,16 +1329,45 @@ function getProjectResizeEles() {
     return pojGljResizeEles;
 }
 
+function getConficMaterialResizeEles() {
+  let conficMaterialResizeEles = {};
+  conficMaterialResizeEles.eleObj = {
+      module: 'conficMaterial',
+      resize: $('#configMaterialResize'),
+      top: $('#configMaterialTop'),
+      topSpread: $('#config_material_sheet'),
+      bottom: $('#configMaterialBottom'),
+      bottomSpread: $('#related_sheet')
+  };
+  conficMaterialResizeEles.limit = {
+      min: 150,
+      max: `$(window).height()-$('.header').height()-$('#projectGljToolsBar').height()-150-5`,//5: resize.height()
+      notTopSpread: 0,
+      notBottomSpread: 0,
+      totalHeight: `$(window).height()-$('.header').height()-$('#projectGljToolsBar').height()-5`,
+      bottomNav:`$('#configMaterialBottom ul').height() + $('#filterToolDiv').height()+10`
+  };
+  return conficMaterialResizeEles;
+}
 
 function loadProjectGljSize() {
-    if(!$('#project-glj-main').is(':visible')) return;
-    let me = projectGljObject;
-    let pojGljResizeEles = getProjectResizeEles();
-    SlideResize.loadVerticalHeight(pojGljResizeEles.eleObj.module, pojGljResizeEles.eleObj, pojGljResizeEles.limit, function () {
-        me.projectGljSpread?me.projectGljSpread.refresh():'';
-        materialCalcObj.initTabWidth();
-        me.refreshSubViews();
-    });
+    if($('#project-glj-main').is(':visible')){
+      let me = projectGljObject;
+      let pojGljResizeEles = getProjectResizeEles();
+      SlideResize.loadVerticalHeight(pojGljResizeEles.eleObj.module, pojGljResizeEles.eleObj, pojGljResizeEles.limit, function () {
+          me.projectGljSpread?me.projectGljSpread.refresh():'';
+          materialCalcObj.initTabWidth();
+          me.refreshSubViews();
+      });
+    }else if($('#config_material').is(':visible')){
+      let  configMaterialResizeEles = getConficMaterialResizeEles();
+      SlideResize.loadVerticalHeight(configMaterialResizeEles.eleObj.module, configMaterialResizeEles.eleObj, configMaterialResizeEles.limit, function () {
+          configMaterialObj.configSpread? configMaterialObj.configSpread.refresh():'';
+          configMaterialObj.relatedSpread? configMaterialObj.relatedSpread.refresh():'';
+          /*
+          me.mixRatioSpread?me.mixRatioSpread.refresh():'';*/
+      });
+  }
 }
 //从其他建设项目中复制中,建设项目的文件层次结构名称和顺序
 function getFileHierarchyInfo(treeData){
@@ -1351,17 +1400,23 @@ $(function () {
         projectGljObject.projectGljSpread.refresh();
         projectGljObject.refreshSubViews();
     });
+    let tr = getConficMaterialResizeEles();
+    SlideResize.verticalSlide(tr.eleObj, tr.limit, function(){
+        configMaterialObj.configSpread? configMaterialObj.configSpread.refresh():'';
+        configMaterialObj.relatedSpread? configMaterialObj.relatedSpread.refresh():'';
+    });
     $('#tab_project_glj').on('shown.bs.tab', function (e) {
         sessionStorage.setItem('mainTab', '#tab_project_glj');
         let me = projectGljObject;
         $(e.relatedTarget.hash).removeClass('active');
         if(me.projectGljSpread==null){
-            me.initProjectGljSpread();
+            me.initSpreads();
         }
         me.unitPriceFileInit();
         me.initMixRatio();
         //projectObj.project.projectGLJ.calcQuantity(); 在工程量有更新的地方调用
-        me.refreshDataSheet();
+        me.initSheetViews();
+        me.refreshViewsData();
         loadProjectGljSize();
         me.initVvTax();
         materialCalcObj.initTabWidth();
@@ -1581,7 +1636,8 @@ $(function () {
         $(this).addClass('active');
         let me = projectGljObject;
         me.displayType = filterType[this.id];
-        me.refreshDataSheet();
+        me.initSheetViews();
+        me.refreshViewsData();
     });
 
     $("#mixRatio-nav").on('shown.bs.tab', function () {