From b801d5f85aa3dc5786510acf87c8003f1d59eadd Mon Sep 17 00:00:00 2001 From: vsv Date: Wed, 3 Sep 2014 12:27:04 +0400 Subject: [PATCH] Create Boolean operations --- src/Config/Config_Keywords.h | 1 + src/FeaturesPlugin/CMakeLists.txt | 3 + src/FeaturesPlugin/FeaturesPlugin_Boolean.cpp | 53 +++++++++++++++ src/FeaturesPlugin/FeaturesPlugin_Boolean.h | 63 +++++++++++++++++ src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp | 4 ++ src/FeaturesPlugin/boolean_widget.xml | 16 +++++ src/FeaturesPlugin/plugin-Features.xml | 5 +- src/GeomAlgoAPI/CMakeLists.txt | 2 + src/GeomAlgoAPI/GeomAlgoAPI_Boolean.cpp | 24 +++++++ src/GeomAlgoAPI/GeomAlgoAPI_Boolean.h | 29 ++++++++ src/ModuleBase/CMakeLists.txt | 2 + src/ModuleBase/ModuleBase_WidgetChoice.cpp | 64 ++++++++++++++++++ src/ModuleBase/ModuleBase_WidgetChoice.h | 52 ++++++++++++++ src/ModuleBase/ModuleBase_WidgetSelector.cpp | 24 +++++-- src/ModuleBase/ModuleBase_WidgetSelector.h | 6 ++ src/PartSet/PartSet_icons.qrc | 2 + src/PartSet/icons/cut_shape.png | Bin 0 -> 932 bytes src/PartSet/icons/cut_tool.png | Bin 0 -> 915 bytes 18 files changed, 344 insertions(+), 6 deletions(-) create mode 100644 src/FeaturesPlugin/FeaturesPlugin_Boolean.cpp create mode 100644 src/FeaturesPlugin/FeaturesPlugin_Boolean.h create mode 100644 src/FeaturesPlugin/boolean_widget.xml create mode 100644 src/GeomAlgoAPI/GeomAlgoAPI_Boolean.cpp create mode 100644 src/GeomAlgoAPI/GeomAlgoAPI_Boolean.h create mode 100644 src/ModuleBase/ModuleBase_WidgetChoice.cpp create mode 100644 src/ModuleBase/ModuleBase_WidgetChoice.h create mode 100644 src/PartSet/icons/cut_shape.png create mode 100644 src/PartSet/icons/cut_tool.png diff --git a/src/Config/Config_Keywords.h b/src/Config/Config_Keywords.h index 434857827..d15691700 100644 --- a/src/Config/Config_Keywords.h +++ b/src/Config/Config_Keywords.h @@ -29,6 +29,7 @@ const static char* WDG_TOOLBOX_BOX = "box"; const static char* WDG_SWITCH = "switch"; const static char* WDG_SWITCH_CASE = "case"; const static char* WDG_SELECTOR = "selector"; +const static char* WDG_CHOICE = "choice"; //Specific widget containers const static char* WDG_POINT_SELECTOR = "point_selector"; diff --git a/src/FeaturesPlugin/CMakeLists.txt b/src/FeaturesPlugin/CMakeLists.txt index 29e08785f..6d4cd90fc 100644 --- a/src/FeaturesPlugin/CMakeLists.txt +++ b/src/FeaturesPlugin/CMakeLists.txt @@ -4,11 +4,13 @@ SET(PROJECT_HEADERS FeaturesPlugin.h FeaturesPlugin_Plugin.h FeaturesPlugin_Extrusion.h + FeaturesPlugin_Boolean.h ) SET(PROJECT_SOURCES FeaturesPlugin_Plugin.cpp FeaturesPlugin_Extrusion.cpp + FeaturesPlugin_Boolean.cpp ) ADD_DEFINITIONS(-DFEATURESPLUGIN_EXPORTS ${BOOST_DEFINITIONS}) @@ -24,6 +26,7 @@ INCLUDE_DIRECTORIES( SET(XML_RESOURCES plugin-Features.xml extrusion_widget.xml + boolean_widget.xml ) INSTALL(TARGETS FeaturesPlugin DESTINATION plugins) diff --git a/src/FeaturesPlugin/FeaturesPlugin_Boolean.cpp b/src/FeaturesPlugin/FeaturesPlugin_Boolean.cpp new file mode 100644 index 000000000..220b4144c --- /dev/null +++ b/src/FeaturesPlugin/FeaturesPlugin_Boolean.cpp @@ -0,0 +1,53 @@ +// File: FeaturesPlugin_Boolean.cpp +// Created: 02 Sept 2014 +// Author: Vitaly SMETANNIKOV + +#include "FeaturesPlugin_Boolean.h" + +#include +#include +#include +#include +#include + +using namespace std; + +FeaturesPlugin_Boolean::FeaturesPlugin_Boolean() +{ +} + +void FeaturesPlugin_Boolean::initAttributes() +{ + data()->addAttribute(FeaturesPlugin_Boolean::TYPE_ID(), ModelAPI_AttributeReference::type()); + data()->addAttribute(FeaturesPlugin_Boolean::OBJECT_ID(), ModelAPI_AttributeReference::type()); + data()->addAttribute(FeaturesPlugin_Boolean::TOOL_ID(), ModelAPI_AttributeReference::type()); +} + +boost::shared_ptr FeaturesPlugin_Boolean::getShape(const std::string& theAttrName) +{ + boost::shared_ptr aObjRef = boost::dynamic_pointer_cast< + ModelAPI_AttributeReference>(data()->attribute(theAttrName)); + if (aObjRef) { + boost::shared_ptr aConstr = boost::dynamic_pointer_cast< + ModelAPI_ResultBody>(aObjRef->value()); + if (aConstr) + return aConstr->shape(); + } + return boost::shared_ptr(); +} + + +void FeaturesPlugin_Boolean::execute() +{ + boost::shared_ptr aObject = this->getShape(FeaturesPlugin_Boolean::OBJECT_ID()); + if (!aObject) + return; + + boost::shared_ptr aTool = this->getShape(FeaturesPlugin_Boolean::TOOL_ID()); + if (!aTool) + return; + + boost::shared_ptr aResult = document()->createBody(data()); + aResult->store(GeomAlgoAPI_Boolean::makeCut(aObject, aTool)); + setResult(aResult); +} \ No newline at end of file diff --git a/src/FeaturesPlugin/FeaturesPlugin_Boolean.h b/src/FeaturesPlugin/FeaturesPlugin_Boolean.h new file mode 100644 index 000000000..d4b0e22cf --- /dev/null +++ b/src/FeaturesPlugin/FeaturesPlugin_Boolean.h @@ -0,0 +1,63 @@ +// File: FeaturesPlugin_Boolean.h +// Created: 02 Sept 2014 +// Author: Vitaly SMETANNIKOV + +#ifndef FeaturesPlugin_Cut_H_ +#define FeaturesPlugin_Cut_H_ + +#include "FeaturesPlugin.h" +#include +#include + +class FeaturesPlugin_Boolean : public ModelAPI_Feature +{ + public: + /// Extrusion kind + inline static const std::string& ID() + { + static const std::string MY_CUT_ID("Boolean"); + return MY_CUT_ID; + } + /// attribute name of referenced object + inline static const std::string& OBJECT_ID() + { + static const std::string MY_OBJECT_ID("main_object"); + return MY_OBJECT_ID; + } + /// attribute name of tool object + inline static const std::string& TOOL_ID() + { + static const std::string MY_TOOL_ID("tool_object"); + return MY_TOOL_ID; + } + /// attribute name of operation type + inline static const std::string& TYPE_ID() + { + static const std::string MY_TOOL_ID("bool_type"); + return MY_TOOL_ID; + } + + + + /// Returns the kind of a feature + FEATURESPLUGIN_EXPORT virtual const std::string& getKind() + { + static std::string MY_KIND = FeaturesPlugin_Boolean::ID(); + return MY_KIND; + } + + /// Creates a new part document if needed + FEATURESPLUGIN_EXPORT virtual void execute(); + + /// Request for initialization of data model of the feature: adding all attributes + FEATURESPLUGIN_EXPORT virtual void initAttributes(); + + /// Use plugin manager for features creation + FeaturesPlugin_Boolean(); + +private: + boost::shared_ptr getShape(const std::string& theAttrName); + +}; + +#endif diff --git a/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp b/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp index c84ddf680..5c3fd3a43 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp @@ -1,5 +1,6 @@ #include "FeaturesPlugin_Plugin.h" #include "FeaturesPlugin_Extrusion.h" +#include "FeaturesPlugin_Boolean.h" #include #include @@ -19,6 +20,9 @@ FeaturePtr FeaturesPlugin_Plugin::createFeature(string theFeatureID) { if (theFeatureID == FeaturesPlugin_Extrusion::ID()) { return FeaturePtr(new FeaturesPlugin_Extrusion); + } else + if (theFeatureID == FeaturesPlugin_Boolean::ID()) { + return FeaturePtr(new FeaturesPlugin_Boolean); } // feature of such kind is not found return FeaturePtr(); diff --git a/src/FeaturesPlugin/boolean_widget.xml b/src/FeaturesPlugin/boolean_widget.xml new file mode 100644 index 000000000..d0ee131a4 --- /dev/null +++ b/src/FeaturesPlugin/boolean_widget.xml @@ -0,0 +1,16 @@ + + + + diff --git a/src/FeaturesPlugin/plugin-Features.xml b/src/FeaturesPlugin/plugin-Features.xml index 783d373fa..c8fc1511b 100644 --- a/src/FeaturesPlugin/plugin-Features.xml +++ b/src/FeaturesPlugin/plugin-Features.xml @@ -4,6 +4,9 @@ + + + - + diff --git a/src/GeomAlgoAPI/CMakeLists.txt b/src/GeomAlgoAPI/CMakeLists.txt index 135d27470..26b230a25 100644 --- a/src/GeomAlgoAPI/CMakeLists.txt +++ b/src/GeomAlgoAPI/CMakeLists.txt @@ -11,6 +11,7 @@ SET(PROJECT_HEADERS GeomAlgoAPI_PointBuilder.h GeomAlgoAPI_SketchBuilder.h GeomAlgoAPI_Extrusion.h + GeomAlgoAPI_Boolean.h ) SET(PROJECT_SOURCES @@ -20,6 +21,7 @@ SET(PROJECT_SOURCES GeomAlgoAPI_PointBuilder.cpp GeomAlgoAPI_SketchBuilder.cpp GeomAlgoAPI_Extrusion.cpp + GeomAlgoAPI_Boolean.cpp ) ADD_DEFINITIONS(-DGEOMALGOAPI_EXPORTS ${CAS_DEFINITIONS}) diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Boolean.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_Boolean.cpp new file mode 100644 index 000000000..0f68186e4 --- /dev/null +++ b/src/GeomAlgoAPI/GeomAlgoAPI_Boolean.cpp @@ -0,0 +1,24 @@ +// File: GeomAlgoAPI_Boolean.cpp +// Created: 02 Sept 2014 +// Author: Vitaly Smetannikov + +#include "GeomAlgoAPI_Boolean.h" + +#include + + +boost::shared_ptr GeomAlgoAPI_Boolean::makeCut( + boost::shared_ptr theShape, + boost::shared_ptr theTool) +{ + const TopoDS_Shape& aShape = theShape->impl(); + const TopoDS_Shape& aTool = theTool->impl(); + + BRepAlgoAPI_Cut aCut(aShape, aTool); + if (aCut.IsDone()) { + boost::shared_ptr aResult(new GeomAPI_Shape()); + aResult->setImpl(new TopoDS_Shape(aCut.Shape())); + return aResult; + } + return boost::shared_ptr(); +} diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Boolean.h b/src/GeomAlgoAPI/GeomAlgoAPI_Boolean.h new file mode 100644 index 000000000..790e7950c --- /dev/null +++ b/src/GeomAlgoAPI/GeomAlgoAPI_Boolean.h @@ -0,0 +1,29 @@ +// File: GeomAlgoAPI_Boolean.h +// Created: 02 Sept 2014 +// Author: Vitaly Smetannikov + +#ifndef GeomAlgoAPI_Boolean_H_ +#define GeomAlgoAPI_Boolean_H_ + +#include +#include +#include + +/**\class GeomAlgoAPI_Boolean + * \ingroup DataAlgo + * \brief Allows to perform of boolean operations + */ +class GEOMALGOAPI_EXPORT GeomAlgoAPI_Boolean +{ + public: + /* \brief Creates cut boolean operation + * \param[in] theShape face or wire to be extruded + * \param[in] theTool toole shape for boolean + * \return a solid as result of operation + */ + static boost::shared_ptr makeCut(boost::shared_ptr theShape, + boost::shared_ptr theTool); + +}; + +#endif diff --git a/src/ModuleBase/CMakeLists.txt b/src/ModuleBase/CMakeLists.txt index b21756a5c..19ba908e8 100644 --- a/src/ModuleBase/CMakeLists.txt +++ b/src/ModuleBase/CMakeLists.txt @@ -25,6 +25,7 @@ SET(PROJECT_HEADERS ModuleBase_SelectionValidator.h ModuleBase_ISelection.h ModuleBase_ViewerPrs.h + ModuleBase_WidgetChoice.h ) SET(PROJECT_SOURCES @@ -44,6 +45,7 @@ SET(PROJECT_SOURCES ModuleBase_WidgetPoint2dDistance.cpp ModuleBase_WidgetValue.cpp ModuleBase_WidgetValueFeature.cpp + ModuleBase_WidgetChoice.cpp ) SET(PROJECT_LIBRARIES diff --git a/src/ModuleBase/ModuleBase_WidgetChoice.cpp b/src/ModuleBase/ModuleBase_WidgetChoice.cpp new file mode 100644 index 000000000..6a1c455d9 --- /dev/null +++ b/src/ModuleBase/ModuleBase_WidgetChoice.cpp @@ -0,0 +1,64 @@ +// File: ModuleBase_WidgetChoice.cpp +// Created: 03 Sept 2014 +// Author: Vitaly Smetannikov + +#include "ModuleBase_WidgetChoice.h" + +#include + +#include +#include +#include +#include + +ModuleBase_WidgetChoice::ModuleBase_WidgetChoice(QWidget* theParent, + const Config_WidgetAPI* theData, + const std::string& theParentId) + : ModuleBase_ModelWidget(theParent, theData, theParentId) +{ + myContainer = new QWidget(theParent); + QHBoxLayout* aLayout = new QHBoxLayout(myContainer); + aLayout->setContentsMargins(0, 0, 0, 0); + + QString aLabelText = QString::fromStdString(theData->widgetLabel()); + QString aLabelIcon = QString::fromStdString(theData->widgetIcon()); + myLabel = new QLabel(aLabelText, myContainer); + myLabel->setPixmap(QPixmap(aLabelIcon)); + aLayout->addWidget(myLabel); + + myCombo = new QComboBox(myContainer); + aLayout->addWidget(myCombo); + connect(myCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onCurrentIndexChanged(int))); +} + +ModuleBase_WidgetChoice::~ModuleBase_WidgetChoice() +{ +} + +bool ModuleBase_WidgetChoice::storeValue() const +{ + return true; +} + +bool ModuleBase_WidgetChoice::restoreValue() +{ + return true; +} + +bool ModuleBase_WidgetChoice::focusTo() +{ + myCombo->setFocus(); + return true; +} + +QList ModuleBase_WidgetChoice::getControls() const +{ + QList aControls; + aControls.append(myLabel); + aControls.append(myCombo); + return aControls; +} + +void ModuleBase_WidgetChoice::onCurrentIndexChanged(int theIndex) +{ +} \ No newline at end of file diff --git a/src/ModuleBase/ModuleBase_WidgetChoice.h b/src/ModuleBase/ModuleBase_WidgetChoice.h new file mode 100644 index 000000000..15a95054e --- /dev/null +++ b/src/ModuleBase/ModuleBase_WidgetChoice.h @@ -0,0 +1,52 @@ +// File: ModuleBase_WidgetChoice.h +// Created: 03 Sept 2014 +// Author: Vitaly Smetannikov + +#ifndef ModuleBase_WidgetChoice_H +#define ModuleBase_WidgetChoice_H + +#include "ModuleBase.h" +#include "ModuleBase_ModelWidget.h" + +class QWidget; +class QLabel; +class QComboBox; + +class MODULEBASE_EXPORT ModuleBase_WidgetChoice : public ModuleBase_ModelWidget +{ +Q_OBJECT + public: + ModuleBase_WidgetChoice(QWidget* theParent, const Config_WidgetAPI* theData, + const std::string& theParentId); + + virtual ~ModuleBase_WidgetChoice(); + + /// Saves the internal parameters to the given feature + /// \param theObject a model feature to be changed + virtual bool storeValue() const; + + virtual bool restoreValue(); + + virtual bool focusTo(); + + /// Returns the internal parent wiget control, that can be shown anywhere + /// \returns the widget + QWidget* getControl() const + { + return myContainer; + } + + /// Returns list of widget controls + /// \return a control list + virtual QList getControls() const; + +private slots: + void onCurrentIndexChanged(int theIndex); + +private: + QWidget* myContainer; + QLabel* myLabel; + QComboBox* myCombo; +}; + +#endif diff --git a/src/ModuleBase/ModuleBase_WidgetSelector.cpp b/src/ModuleBase/ModuleBase_WidgetSelector.cpp index ff187372c..35cb90e18 100644 --- a/src/ModuleBase/ModuleBase_WidgetSelector.cpp +++ b/src/ModuleBase/ModuleBase_WidgetSelector.cpp @@ -74,6 +74,10 @@ ModuleBase_WidgetSelector::ModuleBase_WidgetSelector(QWidget* theParent, myTextLine->setToolTip(aToolTip); myTextLine->installEventFilter(this); + myBasePalet = myTextLine->palette(); + myInactivePalet = myBasePalet; + myInactivePalet.setBrush(QPalette::Base, QBrush(Qt::gray, Qt::Dense6Pattern)); + aLayout->addWidget(myTextLine); myActivateBtn = new QToolButton(myContainer); @@ -165,6 +169,7 @@ void ModuleBase_WidgetSelector::onSelectionChanged() myTextLine->setText(""); } emit valuesChanged(); + emit focusOutWidget(this); } } @@ -181,15 +186,13 @@ bool ModuleBase_WidgetSelector::isAccepted(const ObjectPtr theResult) const TopAbs_ShapeEnum aShapeType = aShape.ShapeType(); if (aShapeType == TopAbs_COMPOUND) { - foreach (QString aType, myShapeTypes) - { + foreach (QString aType, myShapeTypes) { TopExp_Explorer aEx(aShape, shapeType(aType)); if (aEx.More()) return true; } } else { - foreach (QString aType, myShapeTypes) - { + foreach (QString aType, myShapeTypes) { if (shapeType(aType) == aShapeType) return true; } @@ -237,7 +240,11 @@ void ModuleBase_WidgetSelector::enableOthersControls(bool toEnable) const void ModuleBase_WidgetSelector::activateSelection(bool toActivate) { enableOthersControls(!toActivate); - myTextLine->setEnabled(toActivate); + //myTextLine->setEnabled(toActivate); + if (toActivate) + myTextLine->setPalette(myBasePalet); + else + myTextLine->setPalette(myInactivePalet); if (toActivate) connect(myWorkshop, SIGNAL(selectionChanged()), this, SLOT(onSelectionChanged())); @@ -263,3 +270,10 @@ void ModuleBase_WidgetSelector::raisePanel() const aTabWgt->raise(); } } + +//******************************************************************** +bool ModuleBase_WidgetSelector::focusTo() +{ + myActivateBtn->setChecked(true); + return true; +} diff --git a/src/ModuleBase/ModuleBase_WidgetSelector.h b/src/ModuleBase/ModuleBase_WidgetSelector.h index 574ae0e8b..0eba6cdee 100644 --- a/src/ModuleBase/ModuleBase_WidgetSelector.h +++ b/src/ModuleBase/ModuleBase_WidgetSelector.h @@ -13,6 +13,7 @@ #include #include +#include class Config_WidgetAPI; class QWidget; @@ -36,6 +37,8 @@ Q_OBJECT virtual bool restoreValue(); + virtual bool focusTo(); + /// Returns the internal parent wiget control, that can be shown anywhere /// \returns the widget QWidget* getControl() const @@ -91,6 +94,9 @@ Q_OBJECT ObjectPtr mySelectedObject; QStringList myShapeTypes; + + QPalette myBasePalet; + QPalette myInactivePalet; }; #endif diff --git a/src/PartSet/PartSet_icons.qrc b/src/PartSet/PartSet_icons.qrc index 2944e95cc..c65485e76 100644 --- a/src/PartSet/PartSet_icons.qrc +++ b/src/PartSet/PartSet_icons.qrc @@ -9,6 +9,8 @@ icons/remove.png icons/extrusion.png icons/cut.png + icons/cut_tool.png + icons/cut_shape.png icons/fusion.png icons/revol.png icons/common.png diff --git a/src/PartSet/icons/cut_shape.png b/src/PartSet/icons/cut_shape.png new file mode 100644 index 0000000000000000000000000000000000000000..618d744c281d5fae57f2707b6b65fb5fa20ca962 GIT binary patch literal 932 zcmV;V16%xwP)cFx&kR*Y|6&kO zP-0-?U5NjY|1~^985sUBGW`Gb1&BW} z{Ac{j!0_w|!~cK(7#PIF7#JB?7#P`v7?`+(7#KMJF?=|?l|egnQw2Z(fy3bMzrVj3 zK3rsF`2L=Ok%^0ekzJI5ft81WK?sQd{b69>7lY709x^bz-4Arh2ZryTJ}`Xy%_s^G zKwty@G4nApaLWN*095ql5m3>2pdio%JSq$f!rBl`zg`2w0~mH}+zbp{!VG`ezyZ$z z5I_(ESb+Wm1=z1|!0-hsVq^sx1hnnT9iTWf(BM}K?VT*{2yrhzh4knfNW$Ih0;LH%xpllJU~l7feio%Acz6XKuJys zpaEZy3;;&=AD|)Zz;O5vw4H?u7%uD(LpXUE{}CI>$x?SKqm=71OiG~gd7kpD9<0|XG*045eTphtlUI7J|u!L9&mV*ULK3YmZ@=0DH{Ou#VV0GiDV zG>{FHkbrUwKtuj~XLx$!2`D`?0|XE_A$h3t>b&{I7;9%`=o6n5uC8xw%FMt4bivnm z3=G^qfto&nlmGK;j~I4uIQ3)AhVxI3UwM7=?f1WD0Rjk?7l7_!0J@(+oRyKmNJmk` zE!^MAGCbTvnook6VgJ_MKUS?e`}E-1$2VSn`Ewnp?j8_71>%eAHKqM%nh(N0rw3j4=LoyVM&*EufX5Nvi=bd*}y#j(;`L|2!sbfw~y zdudf^R&!6^jPuKmx^~&`+o|pUzW%Rn4!ynl_tRW=X4Tc&>rxrG6c|J1y^Q>KC%vm{ zRrvDbmD5BRHJQs9J{@pWak}aK+#>6wJcrvwOXA~gPVbAKs(Nd`*{izyx#9~Z zhtxBssVHC7+nDfc#ipI7%cn7}Ynqdh`Y~m#hJerydz+4kQ%C9<_I z>q=)XN-2FBnqX_7SgA2>$wA#iS@(|DoWFAEP>k)>7nfxxYRuVNvi;?wlV`U#q&?WY z^ud0HKlynqsl_=4rH|fB-Q>Gy;Zox_cf-RjOTWoriE3E)@KZYj!{-l+=49gBqxA)FZ{QURBOO@xG7oPb>zm`j`*t(r_t@0GVWws3kP63yC+x_2M z4VQY9e%|zZ9rGh*FA;|O%Qk*m$Mtg0?X(b0Sx!YG)krV%i*q=?-CL3uRCmX&Hm>Gs zM!VI=JAX55FR-hyC2x6p#H_!J_4@xGQ!1h^pUKsXRyZjXD|Bq7)hwYpC$DXux0X~W zK46^Ve9!S$Me=MJF_~(Y!)s!exs-~=FTVHg)WMr2jl7jheO|u|ciw91r9FWy!`bJ~ zULVUPyB=?wDOXhNB@tY1`?T=q$9>u}+mz=$y|g(=v#avUf}rX}dO`Aio#h9%Gdim_ z{OX-qZS(ne*^0+LU(eM(b^Uqp!_xwv8pgVet|`k_?&$64V9q_j{=i(o+fR{MgN19& z)_u%&s{@&3roGzm0Xkxq!^403=MP*jC2hRLJSP83@xk-fLt>mSvoC)7ezyEeoAIqB~XKbiLQaM huAym&p(#+El_`)5(h&RTR0mK4gQu&X%Q~loCIFB=jQ;=t literal 0 HcmV?d00001 -- 2.39.2