From 29cf3cffcf4536d96e3546f6c451359387e670e6 Mon Sep 17 00:00:00 2001 From: vsv Date: Thu, 8 May 2014 17:59:19 +0400 Subject: [PATCH] Added history branch into data tree (issue #22) Removed generated TS files --- .gitignore | 1 + src/PartSet/CMakeLists.txt | 24 +- src/PartSet/PartSet_msg_en.ts | 18 - src/PyConsole/CMakeLists.txt | 13 +- src/PyConsole/PyConsole_Console.cpp | 16 +- src/PyConsole/resources/PyConsole_msg_en.ts | 42 --- src/PyConsole/resources/PyConsole_msg_fr.ts | 42 --- src/PyConsole/resources/PyConsole_msg_ja.ts | 42 --- src/XGUI/XGUI_DocumentDataModel.cpp | 102 ++++-- src/XGUI/XGUI_DocumentDataModel.h | 13 +- src/XGUI/XGUI_msg_fr.ts | 348 -------------------- src/XGUI/XGUI_pictures.qrc | 2 - src/XGUI/pictures/ViewPort.png | Bin 4583 -> 0 bytes 13 files changed, 122 insertions(+), 541 deletions(-) delete mode 100644 src/PartSet/PartSet_msg_en.ts delete mode 100644 src/PyConsole/resources/PyConsole_msg_en.ts delete mode 100644 src/PyConsole/resources/PyConsole_msg_fr.ts delete mode 100644 src/PyConsole/resources/PyConsole_msg_ja.ts delete mode 100644 src/XGUI/XGUI_msg_fr.ts delete mode 100644 src/XGUI/pictures/ViewPort.png diff --git a/.gitignore b/.gitignore index 25d046ae1..f55ecf287 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ lib/ *.pro.user moc_*.* *.qm +*.ts #Resources resources !src/*/resources diff --git a/src/PartSet/CMakeLists.txt b/src/PartSet/CMakeLists.txt index 2f4c40ba7..7461196d2 100644 --- a/src/PartSet/CMakeLists.txt +++ b/src/PartSet/CMakeLists.txt @@ -28,9 +28,9 @@ SET(PROJECT_RESOURCES PartSet_icons.qrc ) -SET(TEXT_RESOURCES - PartSet_msg_en.ts -) +#SET(TEXT_RESOURCES +# PartSet_msg_fr.ts +#) SET(PROJECT_LIBRARIES ModuleBase @@ -45,10 +45,17 @@ SET(PROJECT_AUTOMOC ) QT4_ADD_RESOURCES(PROJECT_COMPILED_RESOURCES ${PROJECT_RESOURCES}) -QT4_ADD_TRANSLATION(QM_RESOURCES ${TEXT_RESOURCES}) +#QT4_ADD_TRANSLATION(QM_RESOURCES ${TEXT_RESOURCES}) +#QT4_CREATE_TRANSLATION(QM_RESOURCES +# ${PROJECT_SOURCES} +# ${TEXT_RESOURCES} +# OPTIONS -extensions cpp -no-recursive +# ) -SOURCE_GROUP ("Generated Files" FILES ${PROJECT_AUTOMOC} ${PROJECT_COMPILED_RESOURCES} ${QM_RESOURCES}) -SOURCE_GROUP ("Resource Files" FILES ${TEXT_RESOURCES} ${PROJECT_RESOURCES}) +#SOURCE_GROUP ("Generated Files" FILES ${PROJECT_AUTOMOC} ${PROJECT_COMPILED_RESOURCES} ${QM_RESOURCES}) +SOURCE_GROUP ("Generated Files" FILES ${PROJECT_AUTOMOC} ${PROJECT_COMPILED_RESOURCES}) +#SOURCE_GROUP ("Resource Files" FILES ${TEXT_RESOURCES} ${PROJECT_RESOURCES}) +SOURCE_GROUP ("Resource Files" FILES ${PROJECT_RESOURCES}) INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src/XGUI ${CMAKE_SOURCE_DIR}/src/Config @@ -68,8 +75,8 @@ ADD_LIBRARY(PartSet SHARED ${PROJECT_SOURCES} ${PROJECT_HEADERS} ${PROJECT_COMPILED_RESOURCES} - ${TEXT_RESOURCES} - ${QM_RESOURCES} +# ${TEXT_RESOURCES} +# ${QM_RESOURCES} ) # The Qt5Widgets_LIBRARIES variable also includes QtGui and QtCore @@ -78,3 +85,4 @@ TARGET_LINK_LIBRARIES(PartSet ${PROJECT_LIBRARIES} XGUI ModelAPI GeomAlgoAPI) ADD_DEPENDENCIES(PartSet ModuleBase) INSTALL(TARGETS PartSet DESTINATION bin) +#INSTALL(FILES ${QM_RESOURCES} DESTINATION bin) \ No newline at end of file diff --git a/src/PartSet/PartSet_msg_en.ts b/src/PartSet/PartSet_msg_en.ts deleted file mode 100644 index 4270bb8a8..000000000 --- a/src/PartSet/PartSet_msg_en.ts +++ /dev/null @@ -1,18 +0,0 @@ - - - - - @default - - - XGUI_Workshop - - HOME_MENU_TITLE - Home - - - NEW_MENU - New - - - diff --git a/src/PyConsole/CMakeLists.txt b/src/PyConsole/CMakeLists.txt index 4ba2ef124..aa79a1dc4 100644 --- a/src/PyConsole/CMakeLists.txt +++ b/src/PyConsole/CMakeLists.txt @@ -19,10 +19,9 @@ SET(PROJECT_AUTOMOC # resource files / to be processed by lrelease SET(TEXT_RESOURCES - resources/PyConsole_msg_en.ts - resources/PyConsole_msg_fr.ts - resources/PyConsole_msg_ja.ts + PyConsole_msg_fr.ts ) + # sources / static SET(PROJECT_SOURCES PyConsole_Console.cpp @@ -40,7 +39,12 @@ SET(PROJECT_LIBRARIES ${PYTHON_LIBRARIES} ) -QT4_ADD_TRANSLATION(QM_RESOURCES ${TEXT_RESOURCES}) +#QT4_ADD_TRANSLATION(QM_RESOURCES ${TEXT_RESOURCES}) +QT4_CREATE_TRANSLATION(QM_RESOURCES + ${PROJECT_SOURCES} + ${TEXT_RESOURCES} + OPTIONS -extensions cpp -no-recursive + ) SOURCE_GROUP ("Generated Files" FILES ${PROJECT_AUTOMOC} ${QM_RESOURCES}) @@ -61,5 +65,6 @@ ADD_LIBRARY(PyConsole SHARED TARGET_LINK_LIBRARIES(PyConsole ${PROJECT_LIBRARIES}) INSTALL(TARGETS PyConsole DESTINATION bin) +INSTALL(FILES ${QM_RESOURCES} DESTINATION bin) diff --git a/src/PyConsole/PyConsole_Console.cpp b/src/PyConsole/PyConsole_Console.cpp index 54391474f..79ae485e9 100644 --- a/src/PyConsole/PyConsole_Console.cpp +++ b/src/PyConsole/PyConsole_Console.cpp @@ -270,23 +270,23 @@ int PyConsole_Console::menuActions() const */ void PyConsole_Console::createActions() { - QAction* a = new QAction( tr( "EDIT_COPY_CMD" ), this ); - a->setStatusTip( tr( "EDIT_COPY_CMD" ) ); + QAction* a = new QAction( tr( "&Copy" ), this ); + a->setStatusTip( tr( "Copy" ) ); connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( copy() ) ); myActions.insert( CopyId, a ); - a = new QAction( tr( "EDIT_PASTE_CMD" ), this ); - a->setStatusTip( tr( "EDIT_PASTE_CMD" ) ); + a = new QAction( tr( "&Paste" ), this ); + a->setStatusTip( tr( "Paste" ) ); connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( paste() ) ); myActions.insert( PasteId, a ); - a = new QAction( tr( "EDIT_CLEAR_CMD" ), this ); - a->setStatusTip( tr( "EDIT_CLEAR_CMD" ) ); + a = new QAction( tr( "Clea&r" ), this ); + a->setStatusTip( tr( "Clear" ) ); connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( clear() ) ); myActions.insert( ClearId, a ); - a = new QAction( tr( "EDIT_SELECTALL_CMD" ), this ); - a->setStatusTip( tr( "EDIT_SELECTALL_CMD" ) ); + a = new QAction( tr( "Select &All" ), this ); + a->setStatusTip( tr( "Select all" ) ); connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( selectAll() ) ); myActions.insert( SelectAllId, a ); diff --git a/src/PyConsole/resources/PyConsole_msg_en.ts b/src/PyConsole/resources/PyConsole_msg_en.ts deleted file mode 100644 index 85393a2bf..000000000 --- a/src/PyConsole/resources/PyConsole_msg_en.ts +++ /dev/null @@ -1,42 +0,0 @@ - - - - - PyConsole_Console - - - EDIT_COPY_CMD - &Copy - - - - EDIT_PASTE_CMD - &Paste - - - - EDIT_CLEAR_CMD - Clea&r - - - - EDIT_SELECTALL_CMD - Select &All - - - EDIT_DUMPCOMMANDS_CMD - D&ump commands - - - - PyConsole_Editor - - TOT_DUMP_PYCOMMANDS - Dump commands - - - PYTHON_FILES_FILTER - PYTHON Files (*.py) - - - diff --git a/src/PyConsole/resources/PyConsole_msg_fr.ts b/src/PyConsole/resources/PyConsole_msg_fr.ts deleted file mode 100644 index 910911562..000000000 --- a/src/PyConsole/resources/PyConsole_msg_fr.ts +++ /dev/null @@ -1,42 +0,0 @@ - - - - - PyConsole_Console - - - EDIT_COPY_CMD - &Copier - - - - EDIT_PASTE_CMD - C&oller - - - - EDIT_CLEAR_CMD - &Effacer - - - - EDIT_SELECTALL_CMD - &Tout sélectionner - - - EDIT_DUMPCOMMANDS_CMD - &Générer le script des commandes - - - - PyConsole_Editor - - TOT_DUMP_PYCOMMANDS - &Générer le script des commandes - - - PYTHON_FILES_FILTER - Fichiers PYTHON (*.py) - - - diff --git a/src/PyConsole/resources/PyConsole_msg_ja.ts b/src/PyConsole/resources/PyConsole_msg_ja.ts deleted file mode 100644 index c8d0fb17d..000000000 --- a/src/PyConsole/resources/PyConsole_msg_ja.ts +++ /dev/null @@ -1,42 +0,0 @@ - - - - - PyConsole_Console - - - EDIT_COPY_CMD - コピー(&C) - - - - EDIT_PASTE_CMD - 貼り付け(&P) - - - - EDIT_CLEAR_CMD - 削除(&r) - - - - EDIT_SELECTALL_CMD - すべて選択します。(&A) - - - EDIT_DUMPCOMMANDS_CMD - スクリプト コマンドを生成します。(&u) - - - - PyConsole_Editor - - TOT_DUMP_PYCOMMANDS - スクリプト コマンドを生成します。 - - - PYTHON_FILES_FILTER - ファイル (*.py) PYTHON - - - diff --git a/src/XGUI/XGUI_DocumentDataModel.cpp b/src/XGUI/XGUI_DocumentDataModel.cpp index ebae53b82..e1d4aee48 100644 --- a/src/XGUI/XGUI_DocumentDataModel.cpp +++ b/src/XGUI/XGUI_DocumentDataModel.cpp @@ -52,12 +52,12 @@ void XGUI_DocumentDataModel::processEvent(const Events_Message* theMessage) XGUI_PartDataModel* aModel = new XGUI_PartDataModel(myDocument, this); aModel->setPartId(myPartModels.count()); myPartModels.append(aModel); - insertRows(partFolderNode(), aStart, aStart); + insertRow(aStart, partFolderNode()); } else { // Update top groups (other except parts QModelIndex aIndex = myModel->findParent(aFeature); int aStart = myModel->rowCount(aIndex) - 1; aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex)); - insertRows(aIndex, aStart, aStart); + insertRow(aStart, aIndex); } } else { // if sub-objects of first level nodes XGUI_PartModel* aPartModel = 0; @@ -72,7 +72,7 @@ void XGUI_DocumentDataModel::processEvent(const Events_Message* theMessage) QModelIndex aIndex = aPartModel->findParent(aFeature); int aStart = aPartModel->rowCount(aIndex) - 1; aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex)); - insertRows(aIndex, aStart, aStart); + insertRow(aStart, aIndex); } } @@ -84,15 +84,13 @@ void XGUI_DocumentDataModel::processEvent(const Events_Message* theMessage) if (aDoc == myDocument) { // If root objects if (aUpdMsg->group().compare(PARTS_GROUP) == 0) { // Updsate only Parts group int aStart = myPartModels.size(); - beginRemoveRows(partFolderNode(), aStart, aStart); removeSubModel(myPartModels.size() - 1); - endRemoveRows(); + removeRow(aStart - 1, partFolderNode()); } else { // Update top groups (other except parts QModelIndex aIndex = myModel->findGroup(aUpdMsg->group()); int aStart = myModel->rowCount(aIndex); aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex)); - beginRemoveRows(aIndex, aStart, aStart); - endRemoveRows(); + removeRow(aStart - 1, aIndex); } } else { XGUI_PartModel* aPartModel = 0; @@ -107,8 +105,7 @@ void XGUI_DocumentDataModel::processEvent(const Events_Message* theMessage) QModelIndex aIndex = aPartModel->findGroup(aUpdMsg->group()); int aStart = aPartModel->rowCount(aIndex); aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex)); - beginRemoveRows(aIndex, aStart, aStart); - endRemoveRows(); + removeRow(aStart - 1, aIndex); } } @@ -145,7 +142,8 @@ QVariant XGUI_DocumentDataModel::data(const QModelIndex& theIndex, int theRole) { if (!theIndex.isValid()) return QVariant(); - if (theIndex.internalId() == 0){ + switch (theIndex.internalId()) { + case PartsFolder: switch (theRole) { case Qt::DisplayRole: return tr("Parts") + QString(" (%1)").arg(rowCount(theIndex)); @@ -156,9 +154,37 @@ QVariant XGUI_DocumentDataModel::data(const QModelIndex& theIndex, int theRole) default: return QVariant(); } + break; + case HistoryNode: + { + int aOffset = historyOffset(); + FeaturePtr aFeature = myDocument->feature(FEATURES_GROUP, theIndex.row() - aOffset); + switch (theRole) { + case Qt::DisplayRole: + if (aFeature) + return aFeature->data()->getName().c_str(); + else + return QVariant(); + case Qt::DecorationRole: + { + std::string aType = aFeature->getKind(); + if (aType.compare("Point") == 0) + return QIcon(":pictures/point_ico.png"); + if (aType.compare("Part") == 0) + return QIcon(":pictures/part_ico.png"); + if (aType.compare("Sketch") == 0) + return QIcon(":icons/sketch.png"); + } + case Qt::ToolTipRole: + return tr("Feature object"); + default: + return QVariant(); + } + } + break; } QModelIndex aParent = theIndex.parent(); - if (aParent.isValid() && (aParent.internalId() == 0)) { + if (aParent.isValid() && (aParent.internalId() == PartsFolder)) { return myPartModels.at(theIndex.row())->data(QModelIndex(), theRole); } return toSourceModelIndex(theIndex).data(theRole); @@ -173,12 +199,18 @@ QVariant XGUI_DocumentDataModel::headerData(int theSection, Qt::Orientation theO int XGUI_DocumentDataModel::rowCount(const QModelIndex& theParent) const { if (!theParent.isValid()) { - int aVal = myModel->rowCount(theParent) + myPartModels.size(); - return myModel->rowCount(theParent) + 1;//myPartModels.size(); + // Size of external models + int aVal = historyOffset(); + // Plus history size + aVal += myDocument->size(FEATURES_GROUP); + return aVal; } - if (theParent.internalId() == 0) { + if (theParent.internalId() == PartsFolder) { return myPartModels.size(); } + if (theParent.internalId() == HistoryNode) { + return 0; + } QModelIndex aParent = toSourceModelIndex(theParent); if (!isSubModel(aParent.model())) return 0; @@ -200,11 +232,13 @@ QModelIndex XGUI_DocumentDataModel::index(int theRow, int theColumn, const QMode aIndex = myModel->index(theRow, theColumn, theParent); aIndex = createIndex(theRow, theColumn, (void*)getModelIndex(aIndex)); } else { - // Create Parts node - aIndex = partFolderNode(); + if (theRow == aOffs) // Create Parts node + aIndex = partFolderNode(); + else // create history node + aIndex = createIndex(theRow, theColumn, HistoryNode); } } else { - if (theParent.internalId() == 0) { + if (theParent.internalId() == PartsFolder) { aIndex = myPartModels.at(theRow)->index(0, theColumn, QModelIndex()); } else { QModelIndex* aParent = (QModelIndex*)theParent.internalPointer(); @@ -218,7 +252,7 @@ QModelIndex XGUI_DocumentDataModel::index(int theRow, int theColumn, const QMode QModelIndex XGUI_DocumentDataModel::parent(const QModelIndex& theIndex) const { - if (theIndex.internalId() == 0) + if ((theIndex.internalId() == PartsFolder) || (theIndex.internalId() == HistoryNode)) return QModelIndex(); QModelIndex aIndex = toSourceModelIndex(theIndex); @@ -286,7 +320,7 @@ void XGUI_DocumentDataModel::clearModelIndexes() FeaturePtr XGUI_DocumentDataModel::feature(const QModelIndex& theIndex) const { - if (theIndex.internalId() == 0) + if (theIndex.internalId() == PartsFolder) return FeaturePtr(); QModelIndex aIndex = toSourceModelIndex(theIndex); @@ -297,14 +331,28 @@ FeaturePtr XGUI_DocumentDataModel::feature(const QModelIndex& theIndex) const return aModel->feature(aIndex); } -void XGUI_DocumentDataModel::insertRows(const QModelIndex& theParent, int theStart, int theEnd) +bool XGUI_DocumentDataModel::insertRows(int theRow, int theCount, const QModelIndex& theParent) { - beginInsertRows(theParent, theStart, theEnd); + beginInsertRows(theParent, theRow, theRow + theCount - 1); + //endInsertRows(); + + // Update history + QModelIndex aRoot; + int aRow = rowCount(aRoot); + beginInsertRows(aRoot, aRow, aRow); endInsertRows(); - if (theStart == 0) // Update parent if this is a first child in order to update node decoration - emit dataChanged(theParent, theParent); + + return true; } +bool XGUI_DocumentDataModel::removeRows(int theRow, int theCount, const QModelIndex& theParent) +{ + beginRemoveRows(theParent, theRow, theRow + theCount - 1); + endRemoveRows(); + return true; +} + + void XGUI_DocumentDataModel::removeSubModel(int theModelId) { XGUI_PartModel* aModel = myPartModels.at(theModelId); @@ -339,5 +387,11 @@ bool XGUI_DocumentDataModel::isPartSubModel(const QAbstractItemModel* theModel) QModelIndex XGUI_DocumentDataModel::partFolderNode() const { int aPos = myModel->rowCount(QModelIndex()); - return createIndex(aPos, columnCount() - 1, 0); + return createIndex(aPos, columnCount() - 1, PartsFolder); } + +int XGUI_DocumentDataModel::historyOffset() const +{ + // Nb of rows of top model + Parts folder + return myModel->rowCount(QModelIndex()) + 1; +} \ No newline at end of file diff --git a/src/XGUI/XGUI_DocumentDataModel.h b/src/XGUI/XGUI_DocumentDataModel.h index e389cd800..3c90dcf1f 100644 --- a/src/XGUI/XGUI_DocumentDataModel.h +++ b/src/XGUI/XGUI_DocumentDataModel.h @@ -46,12 +46,19 @@ public: virtual bool hasChildren(const QModelIndex& theParent = QModelIndex()) const; + bool insertRows(int theRow, int theCount, const QModelIndex& theParent = QModelIndex()); + + bool removeRows(int theRow, int theCount, const QModelIndex& theParent = QModelIndex()); + //! Returns Feature object by the given Model index. //! Returns 0 if the given index is not index of a feature FeaturePtr feature(const QModelIndex& theIndex) const; private: + enum {PartsFolder, HistoryNode}; + + //! Converts QModelIndex of this model to QModelIndex of a one of sub-models. QModelIndex toSourceModelIndex(const QModelIndex& theProxy) const; @@ -64,9 +71,6 @@ private: //! Deletes all saved pointers on QModelIndex objects. void clearModelIndexes(); - //! Causes inserting of new nodes for given parent and indexes - void insertRows(const QModelIndex& theParent, int theStart, int theEnd); - //! Removes sub-model on removing a part object. Also it removes QModelIndex-es which refer to this model void removeSubModel(int theModelId); @@ -76,8 +80,11 @@ private: //! Returns true if the given model is a one of sub-models of Part type bool isPartSubModel(const QAbstractItemModel* theModel) const; + //! Returns Parts Folder node QModelIndex partFolderNode() const; + int historyOffset() const; + //! Document boost::shared_ptr myDocument; diff --git a/src/XGUI/XGUI_msg_fr.ts b/src/XGUI/XGUI_msg_fr.ts deleted file mode 100644 index 5562247ba..000000000 --- a/src/XGUI/XGUI_msg_fr.ts +++ /dev/null @@ -1,348 +0,0 @@ - - - - - XGUI_DocumentDataModel - - - Parts - - - - - Parts folder - - - - - XGUI_ErrorDialog - - - Application errors - - - - - XGUI_MainMenu - - - General - - - - - XGUI_MainWindow - - - New Geom - - - - - XGUI_OperationMgr - - - Operation launch - - - - - Previous operation is not finished and will be aborted - - - - - XGUI_PartDataModel - - - Parameters - - - - - Constructions - - - - - Bodies - - - - - XGUI_PropertyPanel - - - Property Panel - - - - - XGUI_TopDataModel - - - Parameters - - - - - Constructions - - - - - XGUI_ViewWindow - - - Dump view - - - - - Fit all - - - - - Fit area - - - - - Zoom - - - - - Panning - - - - - Global panning - - - - - Rotate - - - - - Reset - - - - - Front - - - - - Back - - - - - Top - - - - - Bottom - - - - - Left - - - - - Right - - - - - Clone - - - - - Images Files (*.bmp *.png *.jpg *.jpeg *.eps *.ps) - - - - - XGUI_Viewer - - - Horizontal gradient - - - - - Vertical gradient - - - - - First diagonal gradient - - - - - Second diagonal gradient - - - - - First corner gradient - - - - - Second corner gradient - - - - - Third corner gradient - - - - - Fourth corner gradient - - - - - Image files (*.bmp *.gif *.pix *.xwd *.rgb *.rs) - - - - - XGUI_Workshop - - - - Undo - - - - - - Undo last command - - - - - - Redo - - - - - - Redo last command - - - - - Save... - - - - - Save the document - - - - - Rebuild - - - - - Rebuild data objects - - - - - Save as... - - - - - Save the document into a file - - - - - Open... - - - - - Open a new document - - - - - Exit - - - - - Exit application - - - - - - Save current file - - - - - The document is modified, save before exit? - - - - - The document is modified, save before opening another? - - - - - - Warning - - - - - Unable to open the file. - - - - - Unable to save the file. - - - - - Information about module "%1" doesn't exist. - - - - - Error - - - - - Object browser - - - - diff --git a/src/XGUI/XGUI_pictures.qrc b/src/XGUI/XGUI_pictures.qrc index 40ad6a341..399af8230 100644 --- a/src/XGUI/XGUI_pictures.qrc +++ b/src/XGUI/XGUI_pictures.qrc @@ -9,8 +9,6 @@ pictures/rebuild.png - pictures/ViewPort.png - pictures/occ_view_back.png pictures/occ_view_bottom.png pictures/occ_view_camera_dump.png diff --git a/src/XGUI/pictures/ViewPort.png b/src/XGUI/pictures/ViewPort.png deleted file mode 100644 index b8273017dfce7169d1510100f0429f042fe82a92..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4583 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 selZ#7dc}7(