]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
LockMgr is removing, ModifiedInViewer widget value state is used instead of it.
authornds <nds@opencascade.com>
Fri, 30 Oct 2015 07:27:58 +0000 (10:27 +0300)
committernds <nds@opencascade.com>
Fri, 30 Oct 2015 07:27:58 +0000 (10:27 +0300)
16 files changed:
src/ModuleBase/ModuleBase_ModelWidget.cpp
src/ModuleBase/ModuleBase_ModelWidget.h
src/ModuleBase/ModuleBase_WidgetSelector.cpp
src/PartSet/CMakeLists.txt
src/PartSet/PartSet_LockApplyMgr.cpp [deleted file]
src/PartSet/PartSet_LockApplyMgr.h [deleted file]
src/PartSet/PartSet_Module.cpp
src/PartSet/PartSet_SketcherMgr.cpp
src/PartSet/PartSet_WidgetPoint2d.cpp
src/PartSet/PartSet_WidgetPoint2d.h
src/PartSet/PartSet_WidgetPoint2dDistance.cpp
src/PartSet/PartSet_WidgetPoint2dDistance.h
src/PartSet/PartSet_WidgetSketchLabel.cpp
src/XGUI/XGUI_OperationMgr.cpp
src/XGUI/XGUI_OperationMgr.h
src/XGUI/XGUI_Workshop.cpp

index c84b8e6462063d7de4692decf84aea7ed3365414..7f7e1fa1487630f337e77b48450936a964600a3b 100644 (file)
@@ -28,7 +28,8 @@ ModuleBase_ModelWidget::ModuleBase_ModelWidget(QWidget* theParent,
     : QWidget(theParent),
       myParentId(theParentId),
       myIsEditing(false),
-      myState(Stored)
+      myState(Stored),
+      myIsValueStateBlocked(false)
 {
   myDefaultValue = theData->getProperty(ATTR_DEFAULT);
   myUseReset = theData->getBooleanAttribute(ATTR_USE_RESET, true);
@@ -128,6 +129,12 @@ void ModuleBase_ModelWidget::activate()
   activateCustom();
 }
 
+void ModuleBase_ModelWidget::deactivate()
+{
+  myIsValueStateBlocked = false;
+  myState = Stored;
+}
+
 void ModuleBase_ModelWidget::initializeValueByActivate()
 {
   if (isComputedDefault()) {
@@ -178,13 +185,21 @@ bool ModuleBase_ModelWidget::storeValue()
   return isDone;
 }
 
-void ModuleBase_ModelWidget::setValueState(const ValueState& theState)
+ModuleBase_ModelWidget::ValueState ModuleBase_ModelWidget::setValueState(const ValueState& theState)
 {
-  if (myState == theState)
-    return;
+  ValueState aState = myState;
+  if (myState != theState && !myIsValueStateBlocked) {
+    myState = theState;
+    emit valueStateChanged();
+  }
+  return aState;
+}
 
-  myState = theState;
-  emit valueStateChanged();
+bool ModuleBase_ModelWidget::blockValueState(const bool theBlocked)
+{
+  bool isBlocked = myIsValueStateBlocked;
+  myIsValueStateBlocked = theBlocked;
+  return isBlocked;
 }
 
 bool ModuleBase_ModelWidget::restoreValue()
@@ -256,7 +271,7 @@ void ModuleBase_ModelWidget::onWidgetValuesChanged()
 //**************************************************************
 void ModuleBase_ModelWidget::onWidgetValuesModified()
 {
-  setValueState(Modified);
+  setValueState(ModifiedInPP);
 }
 
 //**************************************************************
index f1d257362076ea7b0204cb8f1219782adba2afd7..f855496739a7a8efa6219502ffd84e56e6d2a2af 100644 (file)
@@ -35,8 +35,9 @@ Q_OBJECT
  public:
    /// State of the widget
    enum ValueState { Stored, /// modification is finished and applyed to the model
-                     Modified, /// modification has not been finished and set to the model yet
-                     Reset };
+                     ModifiedInPP, /// modification has not been finished and set to the model yet
+                     ModifiedInViewer, /// modification performed by viewer events
+                     Reset }; /// the value is reset
 
    /// Constructor
   /// \param theParent the parent object
@@ -114,7 +115,7 @@ Q_OBJECT
   void activate();
 
   /// The method called when widget is deactivated
-  virtual void deactivate() {}
+  virtual void deactivate();
 
   /// Returns list of widget controls
   /// \return a control list
@@ -222,8 +223,15 @@ protected:
   }
 
   /// Sets the current value state. If the value is changed, the signal is emitted
+  /// If the current value state is Blocked, this method do nothing
   /// \param theState a new state
-  void setValueState(const ValueState& theState);
+  /// \return the previous value state
+  ValueState setValueState(const ValueState& theState);
+
+  /// Blocks the value state change.
+  /// \param theBlocked a block state
+  /// \return the previous value
+  bool blockValueState(const bool theBlocked);
 
   /// Compute the feature default value and fill the controls with it
   /// or store the control value to the feature
@@ -288,6 +296,8 @@ private:
 
   /// the reset state. If it is false, the reset method of the widget is not performed
   bool myUseReset;
+  /// blocked flag of modification of the value state
+  bool myIsValueStateBlocked;
 };
 
 #endif
index 268a2515f95c8d40f71c7b42ae7b0a8e797dd160..130079870bb186c835a1970033a42e5fa9af9d9d 100755 (executable)
@@ -166,6 +166,7 @@ bool ModuleBase_WidgetSelector::setSelectionCustom(const ModuleBase_ViewerPrs& t
 //********************************************************************
 void ModuleBase_WidgetSelector::deactivate()
 {
+  ModuleBase_ModelWidget::deactivate();
   disconnect(myWorkshop, SIGNAL(selectionChanged()), this, SLOT(onSelectionChanged()));
   activateSelection(false);
   activateFilters(false);
index 0db713356e0ec54a8ba83343e567399160c1aa78..cf33a07ed8bd19e695ecec1e13461c12d8c55348 100644 (file)
@@ -22,7 +22,6 @@ SET(PROJECT_HEADERS
        PartSet_WidgetShapeSelector.h
        PartSet_WidgetFileSelector.h
        PartSet_Filters.h
-       PartSet_LockApplyMgr.h
        PartSet_FilterInfinite.h
        PartSet_SketcherMgr.h
        PartSet_MenuMgr.h
@@ -46,7 +45,6 @@ SET(PROJECT_SOURCES
        PartSet_WidgetShapeSelector.cpp
        PartSet_WidgetFileSelector.cpp
        PartSet_Filters.cpp
-       PartSet_LockApplyMgr.cpp
        PartSet_FilterInfinite.cpp
        PartSet_SketcherMgr.cpp
        PartSet_MenuMgr.cpp
diff --git a/src/PartSet/PartSet_LockApplyMgr.cpp b/src/PartSet/PartSet_LockApplyMgr.cpp
deleted file mode 100755 (executable)
index 547d730..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File:        PartSet_LockApplyMgr.cpp
-// Created:     25 Jun 2015
-// Author:      Natalia Ermolaeva
-
-#include "PartSet_LockApplyMgr.h"
-#include "PartSet_Module.h"
-
-#include <ModuleBase_IWorkshop.h>
-#include <ModuleBase_IViewer.h>
-
-#include <XGUI_Workshop.h>
-#include <XGUI_ViewerProxy.h>
-#include <XGUI_ModuleConnector.h>
-#include <XGUI_OperationMgr.h>
-
-PartSet_LockApplyMgr::PartSet_LockApplyMgr(QObject* theParent,
-                                           ModuleBase_IWorkshop* theWorkshop)
-: QObject(theParent), myWorkshop(theWorkshop)
-{
-}
-
-void PartSet_LockApplyMgr::activate()
-{
-  XGUI_ViewerProxy* aViewer = dynamic_cast<XGUI_ViewerProxy*>(myWorkshop->viewer());
-  connect(aViewer, SIGNAL(enterViewPort()), this, SLOT(onLockValidating()));
-  connect(aViewer, SIGNAL(leaveViewPort()), this, SLOT(onUnlockValidating()));
-
-  PartSet_Module* aModule = dynamic_cast<PartSet_Module*>(myWorkshop->module());
-  if (aModule->isMouseOverWindow())
-    onLockValidating();
-}
-
-void PartSet_LockApplyMgr::deactivate()
-{
-  XGUI_ViewerProxy* aViewer = dynamic_cast<XGUI_ViewerProxy*>(myWorkshop->viewer());
-  disconnect(aViewer, SIGNAL(enterViewPort()), this, SLOT(onLockValidating()));
-  disconnect(aViewer, SIGNAL(leaveViewPort()), this, SLOT(onUnlockValidating()));
-
-  onUnlockValidating();
-}
-
-void PartSet_LockApplyMgr::valuesChanged()
-{
-  operationMgr()->setLockValidating(false);
-}
-
-void PartSet_LockApplyMgr::onLockValidating()
-{
-  XGUI_OperationMgr* anOperationMgr = operationMgr();
-
-  anOperationMgr->setLockValidating(true);
-  // the Ok button should be disabled in the property panel by moving the mouse point in the viewer
-  // this leads that the user does not try to click Ok and it avoids an incorrect situation that the
-  // line is moved to the cursor to the Ok button
-  //anOperationMgr->setApplyEnabled(false);
-}
-
-void PartSet_LockApplyMgr::onUnlockValidating()
-{
-  XGUI_OperationMgr* anOperationMgr = operationMgr();
-
-  // it is important to restore the validity state in the property panel after leaving the
-  // view port. Unlock the validating.
-  if (anOperationMgr->isValidationLocked()) {
-    anOperationMgr->setLockValidating(false);
-    //anOperationMgr->onValidateOperation();
-  }
-}
-
-XGUI_OperationMgr* PartSet_LockApplyMgr::operationMgr() const
-{
-  XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myWorkshop);
-  XGUI_Workshop* aWorkshop = aConnector->workshop();
-
-  return aWorkshop->operationMgr();
-}
diff --git a/src/PartSet/PartSet_LockApplyMgr.h b/src/PartSet/PartSet_LockApplyMgr.h
deleted file mode 100755 (executable)
index a73cb14..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File:        PartSet_LockApplyMgr.h
-// Created:     25 Jun 2015
-// Author:      Natalia Ermolaeva
-
-#ifndef PartSet_LockApplyMgr_H
-#define PartSet_LockApplyMgr_H
-
-#include "PartSet.h"
-
-#include <QObject>
-
-class ModuleBase_IWorkshop;
-class XGUI_OperationMgr;
-
-/**
-* \ingroup Modules
-* Customosation of ModuleBase_WidgetShapeSelector in order to provide 
-* working with sketch specific objects.
-*/
-class PARTSET_EXPORT PartSet_LockApplyMgr : public QObject
-{
-  Q_OBJECT
-
-public:
-  /// Constructor
-  /// \param theParent a parent object
-  /// \param theWorkshop a reference to workshop
-  PartSet_LockApplyMgr(QObject* theParent,
-                       ModuleBase_IWorkshop* theWorkshop);
-
-  virtual ~PartSet_LockApplyMgr() {}
-
-  /// Activates the object
-  void activate();
-
-  /// Deactivates the object
-  void deactivate();
-
-  /// Unlocks validation in operations manager
-  void valuesChanged();
-
-protected slots:
-  /// Set lock validating in the operation manager. Set apply is disabled
-  void onLockValidating();
-
-  /// Set unlock validating in the operation manager. Call method to update the apply state.
-  void onUnlockValidating();
-
-private:
-  XGUI_OperationMgr* operationMgr() const;
-
-private:
-  ModuleBase_IWorkshop* myWorkshop; // the current application workshop
-};
-
-#endif
\ No newline at end of file
index dd096b6a4a095a85fbcb0e8ba3499d0ea7a39a0b..100b7ea3ef5fa4c75fb0ad5676faf04f39c09929 100755 (executable)
@@ -420,21 +420,9 @@ void PartSet_Module::updateViewerMenu(const QMap<QString, QAction*>& theStdActio
 QString PartSet_Module::getFeatureError(const FeaturePtr& theFeature)
 {
   QString anError = ModuleBase_IModule::getFeatureError(theFeature);
-
   if (anError.isEmpty())
     anError = sketchMgr()->getFeatureError(theFeature);
 
-  if (anError.isEmpty()) {
-    XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(workshop());
-    XGUI_OperationMgr* anOpMgr = aConnector->workshop()->operationMgr();
-    
-    if (anOpMgr->isValidationLocked()) {
-      ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
-                                                             (anOpMgr->currentOperation());
-      if (!aFOperation || theFeature == aFOperation->feature())
-        anError = "Validation is locked by the current operation";
-    }
-  }
   return anError;
 }
 
index 6c94099d987ac067eb11a9dbc795cafc868c6af4..167fad75943ce7978e04d5d2b5f3560b8b6e6228 100644 (file)
@@ -687,10 +687,14 @@ QString PartSet_SketcherMgr::getFeatureError(const FeaturePtr& theFeature)
         if (anAttr.get()) {
           QString anAttributeName = anAttr->id().c_str();
           switch (aState) {
-            case ModuleBase_ModelWidget::Modified:
+            case ModuleBase_ModelWidget::ModifiedInPP:
               anError = "Attribute \"" + anAttributeName +
                         "\" modification is not applyed. Please click \"Enter\" or \"Tab\".";
               break;
+            case ModuleBase_ModelWidget::ModifiedInViewer:
+              anError = "Attribute \"" + anAttributeName +
+                        "\" is locked by modification value in the viewer.";
+              break;
             case ModuleBase_ModelWidget::Reset:
               anError = "Attribute \"" + anAttributeName + "\" is not initialized.";
               break;
index 9fbffa98cf98ca0f914bb8e9e202e2083db9224b..8f62484fba31d5c2c42aa86374b92d26878c45e3 100644 (file)
@@ -7,7 +7,6 @@
 #include "PartSet_WidgetPoint2d.h"
 #include <PartSet_Tools.h>
 #include <PartSet_Module.h>
-#include <PartSet_LockApplyMgr.h>
 
 #include <ModuleBase_ParamSpinBox.h>
 #include <ModuleBase_Tools.h>
@@ -66,7 +65,6 @@ PartSet_WidgetPoint2D::PartSet_WidgetPoint2D(QWidget* theParent,
       << SketchPlugin_Point::ID().c_str()
       << SketchPlugin_Circle::ID().c_str();
   }
-  myLockApplyMgr = new PartSet_LockApplyMgr(theParent, myWorkshop);
 
   // the control should accept the focus, so the boolen flag is corrected to be true
   myIsObligatory = true;
@@ -269,12 +267,11 @@ void PartSet_WidgetPoint2D::activateCustom()
   aModes << TopAbs_VERTEX;
   aModes << TopAbs_EDGE;
   myWorkshop->activateSubShapesSelection(aModes);
-
-  myLockApplyMgr->activate();
 }
 
 void PartSet_WidgetPoint2D::deactivate()
 {
+  ModuleBase_ModelWidget::deactivate();
   ModuleBase_IViewer* aViewer = myWorkshop->viewer();
   disconnect(aViewer, SIGNAL(mouseMove(ModuleBase_IViewWindow*, QMouseEvent*)),
              this, SLOT(onMouseMove(ModuleBase_IViewWindow*, QMouseEvent*)));
@@ -282,8 +279,6 @@ void PartSet_WidgetPoint2D::deactivate()
              this, SLOT(onMouseRelease(ModuleBase_IViewWindow*, QMouseEvent*)));
 
   myWorkshop->deactivateSubShapesSelection();
-
-  myLockApplyMgr->deactivate();
 }
 
 bool PartSet_WidgetPoint2D::getPoint2d(const Handle(V3d_View)& theView, 
@@ -438,7 +433,11 @@ void PartSet_WidgetPoint2D::onMouseMove(ModuleBase_IViewWindow* theWnd, QMouseEv
 
   double aX, anY;
   PartSet_Tools::convertTo2D(aPoint, mySketch, theWnd->v3dView(), aX, anY);
+  // we need to block the value state change 
+  bool isBlocked = blockValueState(true);
   setPoint(aX, anY);
+  blockValueState(isBlocked);
+  setValueState(ModifiedInViewer);
 }
 
 double PartSet_WidgetPoint2D::x() const
@@ -477,7 +476,6 @@ bool PartSet_WidgetPoint2D::isFeatureContainsPoint(const FeaturePtr& theFeature,
 
 void PartSet_WidgetPoint2D::onValuesChanged()
 {
-  myLockApplyMgr->valuesChanged();
   emit valuesChanged();
 }
 
index d2e5741cd8f65519c2501c5dd89a616234f8056c..e4c426ba7d775c4e3c18d21a9daa0d57c9ef142a 100644 (file)
@@ -22,7 +22,6 @@ class ModuleBase_ParamSpinBox;
 class ModuleBase_IViewWindow;
 class GeomAPI_Pnt2d;
 class ModuleBase_IWorkshop;
-class PartSet_LockApplyMgr;
 
 class QGroupBox;
 class QMouseEvent;
@@ -143,7 +142,6 @@ private slots:
    void setConstraintWith(const ObjectPtr& theObject);
 
   ModuleBase_IWorkshop* myWorkshop;
-  PartSet_LockApplyMgr* myLockApplyMgr; ///< a manager to lock/unlock Apply button in PP
 
   QGroupBox* myGroupBox;  ///< the parent group box for all intenal widgets
   ModuleBase_ParamSpinBox* myXSpin;  ///< the spin box for the X coordinate
index 2e665cf97fb2a86eb8df0fa55e0aa560e93dc965..d2f1a08aaef00d9598a035cdfed552b6f627159a 100644 (file)
@@ -6,7 +6,6 @@
 
 #include "PartSet_WidgetPoint2dDistance.h"
 #include "PartSet_Tools.h"
-#include "PartSet_LockApplyMgr.h"
 
 #include <ModuleBase_ParamSpinBox.h>
 #include <ModuleBase_IWorkshop.h>
@@ -31,8 +30,6 @@ PartSet_WidgetPoint2dDistance::PartSet_WidgetPoint2dDistance(QWidget* theParent,
                                                              const std::string& theParentId)
  : ModuleBase_WidgetDoubleValue(theParent, theData, theParentId), myWorkshop(theWorkshop)
 {
-  myLockApplyMgr = new PartSet_LockApplyMgr(theParent, myWorkshop);
-
   myFirstPntName = theData->getProperty("first_point");
 
   // Reconnect to local slot
@@ -84,19 +81,16 @@ void PartSet_WidgetPoint2dDistance::activateCustom()
           this, SLOT(onMouseMove(ModuleBase_IViewWindow*, QMouseEvent*)));
   connect(aViewer, SIGNAL(mouseRelease(ModuleBase_IViewWindow*, QMouseEvent*)), 
           this, SLOT(onMouseRelease(ModuleBase_IViewWindow*, QMouseEvent*)));
-
-  myLockApplyMgr->activate();
 }
 
 void PartSet_WidgetPoint2dDistance::deactivate()
 {
+  ModuleBase_ModelWidget::deactivate();
   ModuleBase_IViewer* aViewer = myWorkshop->viewer();
   disconnect(aViewer, SIGNAL(mouseMove(ModuleBase_IViewWindow*, QMouseEvent*)), 
              this, SLOT(onMouseMove(ModuleBase_IViewWindow*, QMouseEvent*)));
   disconnect(aViewer, SIGNAL(mouseRelease(ModuleBase_IViewWindow*, QMouseEvent*)), 
              this, SLOT(onMouseRelease(ModuleBase_IViewWindow*, QMouseEvent*)));
-
-  myLockApplyMgr->deactivate();
 }
 
 void PartSet_WidgetPoint2dDistance::onMouseRelease(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
@@ -132,12 +126,14 @@ void PartSet_WidgetPoint2dDistance::onMouseMove(ModuleBase_IViewWindow* theWnd,
   PartSet_Tools::convertTo2D(aPoint, mySketch, theWnd->v3dView(), aX, aY);
 
   std::shared_ptr<GeomAPI_Pnt2d> aPnt = std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(aX, aY));
+  bool isBlocked = blockValueState(true);
   setPoint(feature(), aPnt);
+  blockValueState(isBlocked);
+  setValueState(ModifiedInViewer);
 }
 
 void PartSet_WidgetPoint2dDistance::onValuesChanged()
 {
-  myLockApplyMgr->valuesChanged();
   emit valuesChanged();
 }
 
index 857212aca8288da21fb1a91118b9972402401da7..47256180451265fc62da45790fe9551a464bc025 100644 (file)
@@ -12,7 +12,6 @@
 
 #include <ModelAPI_CompositeFeature.h>
 
-class PartSet_LockApplyMgr;
 class GeomAPI_Pnt2d;
 class ModuleBase_IWorkshop;
 class ModuleBase_IViewWindow;
@@ -96,9 +95,6 @@ protected:
   /// A reference to workshop
   ModuleBase_IWorkshop* myWorkshop;
   
-  /// A manager to lock/unlock Apply button in PP
-  PartSet_LockApplyMgr* myLockApplyMgr;
-
   /// A name of the first point
   std::string myFirstPntName;
 
index e28724ddc37d179bc79105bfd74af476d9c6ac96..8274ee0526697ac7f1fe73066ad6a12cd4f25c70 100644 (file)
@@ -294,6 +294,7 @@ void PartSet_WidgetSketchLabel::activateCustom()
 
 void PartSet_WidgetSketchLabel::deactivate()
 {
+  ModuleBase_ModelWidget::deactivate();
   erasePreviewPlanes();
   activateSelection(false);
 
index 59ad78bf304498df583481ab659e548548b9f601..786ce094689ddd97ea3416949b883c3ea01bcaf5 100644 (file)
@@ -27,8 +27,7 @@
 
 XGUI_OperationMgr::XGUI_OperationMgr(QObject* theParent,
                                      ModuleBase_IWorkshop* theWorkshop)
-: QObject(theParent), myIsValidationLock(false), myIsApplyEnabled(false),
-  myWorkshop(theWorkshop)
+: QObject(theParent), myIsApplyEnabled(false), myWorkshop(theWorkshop)
 {
 }
 
@@ -195,12 +194,6 @@ void XGUI_OperationMgr::onValidateOperation()
     setApplyEnabled(myWorkshop->module()->getFeatureError(aFOperation->feature()).isEmpty());
 }
 
-void XGUI_OperationMgr::setLockValidating(bool toLock)
-{
-  myIsValidationLock = toLock;
-  onValidateOperation();
-}
-
 void XGUI_OperationMgr::setApplyEnabled(const bool theEnabled)
 {
   myIsApplyEnabled = theEnabled;
index 5ea3af47cfd2b36fc3013142bbb1ad614f02a901..fcea3a96301de3d42306e1d984b29205a478d215 100644 (file)
@@ -98,13 +98,6 @@ Q_OBJECT
   /// \param theOperation an aborted operation
   void abortOperation(ModuleBase_Operation* theOperation);
 
-  /// Blocking/unblocking enabling of Ok button in property panel.
-  /// It is used when operation can not be validated even all attributes are valid
-  void setLockValidating(bool toLock);
-
-  /// Returns state of validation locking
-  bool isValidationLocked() const { return myIsValidationLock; }
-
   /// Returns enable apply state 
   /// \return theEnabled a boolean value
   bool isApplyEnabled() const;
@@ -207,9 +200,6 @@ private:
   /// Current workshop
   ModuleBase_IWorkshop* myWorkshop;
 
-
-  /// Lock/Unlock access to Ok button in property panel
-  bool myIsValidationLock;
   /// Lock/Unlock access to Ok button in property panel
   bool myIsApplyEnabled;
 };
index 56228ab22b1b27868d59c78d5a38f3a81be80226..c09f7d58414d77ce39e6758901969b1c67eb527c 100644 (file)
@@ -865,7 +865,7 @@ void XGUI_Workshop::onValueStateChanged()
     if (aPanel)
       anActiveWidget = aPanel->activeWidget();
   }
-  if (anActiveWidget && anActiveWidget->getValueState() != ModuleBase_ModelWidget::Stored)
+  if (anActiveWidget)
     operationMgr()->onValidateOperation();
 }