From 413c73b78196ad4fc5142e5cbe3770cfdd4f2157 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Sun, 27 Feb 2022 12:51:30 +0100 Subject: [PATCH 01/11] fix build without QmlPrivate Change-Id: Ibc333a07137b7afb39676d4d3bc89d0c4dadb11d Reviewed-by: Reviewed-by: Eike Ziller --- src/plugins/qmlpreview/CMakeLists.txt | 36 ++++++++++++++------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/plugins/qmlpreview/CMakeLists.txt b/src/plugins/qmlpreview/CMakeLists.txt index 532dd8999f2..4b537c4cf97 100644 --- a/src/plugins/qmlpreview/CMakeLists.txt +++ b/src/plugins/qmlpreview/CMakeLists.txt @@ -21,20 +21,22 @@ extend_qtc_plugin(QmlPreview tests/qmlpreviewplugin_test.cpp tests/qmlpreviewplugin_test.h ) -# check if Qt version have_qml_debug_translation_protocol -# will be introduced in Qt 6.2, but there are users -# who needs it in older but special built Qt versions aswell -string(REGEX MATCH "^[0-9]*" QT_VERSION_MAJOR ${Qt5_VERSION}) -get_target_property(qmldebugprivate_include_directories - Qt${QT_VERSION_MAJOR}::QmlPrivate - INTERFACE_INCLUDE_DIRECTORIES -) -find_file(have_qml_debug_translation_protocol - NAMES private/qqmldebugtranslationprotocol_p.h - PATHS ${qmldebugprivate_include_directories} -) -extend_qtc_plugin(QmlPreview - CONDITION have_qml_debug_translation_protocol - PUBLIC_DEPENDS Qt5::QmlPrivate - PUBLIC_DEFINES "FOUND_QML_DEBUG_TRANSLATION_PROTOCOL" -) +if(TARGET Qt${QT_VERSION_MAJOR}::QmlPrivate) + # check if Qt version have_qml_debug_translation_protocol + # will be introduced in Qt 6.2, but there are users + # who needs it in older but special built Qt versions aswell + string(REGEX MATCH "^[0-9]*" QT_VERSION_MAJOR ${Qt5_VERSION}) + get_target_property(qmldebugprivate_include_directories + Qt${QT_VERSION_MAJOR}::QmlPrivate + INTERFACE_INCLUDE_DIRECTORIES + ) + find_file(have_qml_debug_translation_protocol + NAMES private/qqmldebugtranslationprotocol_p.h + PATHS ${qmldebugprivate_include_directories} + ) + extend_qtc_plugin(QmlPreview + CONDITION have_qml_debug_translation_protocol + PUBLIC_DEPENDS Qt5::QmlPrivate + PUBLIC_DEFINES "FOUND_QML_DEBUG_TRANSLATION_PROTOCOL" + ) +endif() From bec41a7a557f4e3ed1eafe6a3c59e305836e23a5 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Thu, 10 Mar 2022 10:36:08 +0100 Subject: [PATCH 02/11] QmlDesigner: Remove dependency of ModelNode on AbstractView * Moved AbstractView::hasId() and AbstractView::generateNewId to Model. I kept a convenience function AbstractView::hasId(), so we do not have to change too much code. * hasId() and generateNewId() do not mutate the model and therefore belong to the model. * This also allows to remove the dependency on AbstractView in ModelNode * Adjusting the usage of generateNewId() throughout the code base. Change-Id: I0b8bab995c48fd52760b509cbe53f0854230b4c8 Reviewed-by: Reviewed-by: Mahmoud Badri Reviewed-by: Miikka Heikkinen --- .../componentcore/layoutingridlayout.cpp | 2 +- .../connectioneditor/backendmodel.cpp | 2 +- .../components/eventlist/nodelistview.cpp | 2 +- .../navigator/navigatortreemodel.cpp | 13 ++--- .../componentsplugin/addtabdesigneraction.cpp | 2 +- .../designercore/include/abstractview.h | 2 - .../qmldesigner/designercore/include/model.h | 5 ++ .../designercore/model/abstractview.cpp | 48 +---------------- .../qmldesigner/designercore/model/model.cpp | 53 +++++++++++++++++++ .../designercore/model/modelnode.cpp | 6 +-- .../designercore/model/qmlitemnode.cpp | 4 +- .../designercore/model/qmlvisualnode.cpp | 2 +- 12 files changed, 76 insertions(+), 65 deletions(-) diff --git a/src/plugins/qmldesigner/components/componentcore/layoutingridlayout.cpp b/src/plugins/qmldesigner/components/componentcore/layoutingridlayout.cpp index f55f4807d91..439faec59d1 100644 --- a/src/plugins/qmldesigner/components/componentcore/layoutingridlayout.cpp +++ b/src/plugins/qmldesigner/components/componentcore/layoutingridlayout.cpp @@ -419,7 +419,7 @@ void LayoutInGridLayout::fillEmptyCells() newItemNode.setVariantProperty("y", yPos); newItemNode.setVariantProperty("width", 14); newItemNode.setVariantProperty("height", 14); - newItemNode.setId(m_selectionContext.view()->generateNewId("spacer")); + newItemNode.setId(m_selectionContext.view()->model()->generateNewId("spacer")); } m_layoutedNodes.append(m_spacerNodes); } diff --git a/src/plugins/qmldesigner/components/connectioneditor/backendmodel.cpp b/src/plugins/qmldesigner/components/connectioneditor/backendmodel.cpp index 36d30713032..402023b8289 100644 --- a/src/plugins/qmldesigner/components/connectioneditor/backendmodel.cpp +++ b/src/plugins/qmldesigner/components/connectioneditor/backendmodel.cpp @@ -241,7 +241,7 @@ void BackendModel::addNewBackend() if (!model->hasImport(import)) model->changeImports({import}, {}); - QString propertyName = m_connectionView->generateNewId(typeName); + QString propertyName = m_connectionView->model()->generateNewId(typeName); NodeMetaInfo metaInfo = model->metaInfo(typeName.toUtf8()); diff --git a/src/plugins/qmldesigner/components/eventlist/nodelistview.cpp b/src/plugins/qmldesigner/components/eventlist/nodelistview.cpp index a322d56ebc9..8569477bb5f 100644 --- a/src/plugins/qmldesigner/components/eventlist/nodelistview.cpp +++ b/src/plugins/qmldesigner/components/eventlist/nodelistview.cpp @@ -141,7 +141,7 @@ QString NodeListView::setNodeId(int internalId, const QString &id) { ModelNode node = modelNodeForInternalId(internalId); if (node.isValid()) { - QString newId = generateNewId(id); + QString newId = model()->generateNewId(id); node.setIdWithRefactoring(newId); return newId; } diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp index 654a18dfc9e..735df196afb 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp @@ -910,8 +910,8 @@ ModelNode NavigatorTreeModel::handleItemLibraryShaderDrop(const QString &shaderP // Rename the node based on shader source QFileInfo fi(relPath); - newModelNode.setIdWithoutRefactoring(m_view->generateNewId(fi.baseName(), - "shader")); + newModelNode.setIdWithoutRefactoring( + m_view->model()->generateNewId(fi.baseName(), "shader")); // Passes can't have children, so move shader node under parent if (targetProperty.parentModelNode().isSubclassOf("QtQuick3D.Pass")) { BindingProperty listProp = targetNode.bindingProperty("shaders"); @@ -956,9 +956,9 @@ ModelNode NavigatorTreeModel::handleItemLibrarySoundDrop(const QString &soundPat // Rename the node based on source QFileInfo fi(relPath); - newModelNode.setIdWithoutRefactoring(m_view->generateNewId(fi.baseName(), - "soundEffect")); - } + newModelNode.setIdWithoutRefactoring( + m_view->model()->generateNewId(fi.baseName(), "soundEffect")); + } return newModelNode; } @@ -1073,7 +1073,8 @@ ModelNode NavigatorTreeModel::createTextureNode(const NodeAbstractProperty &targ // Rename the node based on source image QFileInfo fi(imagePath); - newModelNode.setIdWithoutRefactoring(m_view->generateNewId(fi.baseName(), "textureImage")); + newModelNode.setIdWithoutRefactoring( + m_view->model()->generateNewId(fi.baseName(), "textureImage")); return newModelNode; } return {}; diff --git a/src/plugins/qmldesigner/componentsplugin/addtabdesigneraction.cpp b/src/plugins/qmldesigner/componentsplugin/addtabdesigneraction.cpp index 4f08a6eb830..12ba1d433a0 100644 --- a/src/plugins/qmldesigner/componentsplugin/addtabdesigneraction.cpp +++ b/src/plugins/qmldesigner/componentsplugin/addtabdesigneraction.cpp @@ -131,7 +131,7 @@ void AddTabDesignerAction::addNewTab() tabViewModelNode.majorVersion(), tabViewModelNode.minorVersion(), propertyList); - newTabModelNode.setIdWithRefactoring(newTabModelNode.view()->generateNewId(tabName)); + newTabModelNode.setIdWithRefactoring(newTabModelNode.model()->generateNewId(tabName)); tabViewModelNode.defaultNodeAbstractProperty().reparentHere(newTabModelNode); } } diff --git a/src/plugins/qmldesigner/designercore/include/abstractview.h b/src/plugins/qmldesigner/designercore/include/abstractview.h index 3908844dea4..b303a4fdef7 100644 --- a/src/plugins/qmldesigner/designercore/include/abstractview.h +++ b/src/plugins/qmldesigner/designercore/include/abstractview.h @@ -161,8 +161,6 @@ public: ModelNode modelNodeForId(const QString &id); bool hasId(const QString &id) const; - QString generateNewId(const QString &prefixName) const; - QString generateNewId(const QString &prefixName, const QString &fallbackPrefix) const; ModelNode modelNodeForInternalId(qint32 internalId) const; bool hasModelNodeForInternalId(qint32 internalId) const; diff --git a/src/plugins/qmldesigner/designercore/include/model.h b/src/plugins/qmldesigner/designercore/include/model.h index cb453a57566..48700376b9d 100644 --- a/src/plugins/qmldesigner/designercore/include/model.h +++ b/src/plugins/qmldesigner/designercore/include/model.h @@ -124,6 +124,11 @@ public: void clearMetaInfoCache(); + bool hasId(const QString &id) const; + + QString generateNewId(const QString &prefixName) const; + QString generateNewId(const QString &prefixName, const QString &fallbackPrefix) const; + protected: Model(); diff --git a/src/plugins/qmldesigner/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/designercore/model/abstractview.cpp index 78014142e3b..790b6ad5a53 100644 --- a/src/plugins/qmldesigner/designercore/model/abstractview.cpp +++ b/src/plugins/qmldesigner/designercore/model/abstractview.cpp @@ -42,7 +42,6 @@ #include #include -#include #include #include @@ -519,52 +518,7 @@ ModelNode AbstractView::modelNodeForId(const QString &id) bool AbstractView::hasId(const QString &id) const { - return model()->d->hasId(id); -} - -QString firstCharToLower(const QString &string) -{ - QString resultString = string; - - if (!resultString.isEmpty()) - resultString[0] = resultString.at(0).toLower(); - - return resultString; -} - -QString AbstractView::generateNewId(const QString &prefixName, const QString &fallbackPrefix) const -{ - // First try just the prefixName without number as postfix, then continue with 2 and further - // as postfix until id does not already exist. - // Properties of the root node are not allowed for ids, because they are available in the - // complete context without qualification. - - int counter = 0; - - QString newBaseId = QString(QStringLiteral("%1")).arg(firstCharToLower(prefixName)); - newBaseId.remove(QRegularExpression(QStringLiteral("[^a-zA-Z0-9_]"))); - - if (!newBaseId.isEmpty()) { - QChar firstChar = newBaseId.at(0); - if (firstChar.isDigit()) - newBaseId.prepend('_'); - } else { - newBaseId = fallbackPrefix; - } - - QString newId = newBaseId; - - while (!ModelNode::isValidId(newId) || hasId(newId) || rootModelNode().hasProperty(newId.toUtf8())) { - ++counter; - newId = QString(QStringLiteral("%1%2")).arg(firstCharToLower(newBaseId)).arg(counter); - } - - return newId; -} - -QString AbstractView::generateNewId(const QString &prefixName) const -{ - return generateNewId(prefixName, QStringLiteral("element")); + return model()->hasId(id); } ModelNode AbstractView::modelNodeForInternalId(qint32 internalId) const diff --git a/src/plugins/qmldesigner/designercore/model/model.cpp b/src/plugins/qmldesigner/designercore/model/model.cpp index 39b24186232..64a45e0a894 100644 --- a/src/plugins/qmldesigner/designercore/model/model.cpp +++ b/src/plugins/qmldesigner/designercore/model/model.cpp @@ -67,6 +67,8 @@ #include +#include + /*! \defgroup CoreModel */ @@ -1444,6 +1446,57 @@ bool Model::hasImport(const Import &import, bool ignoreAlias, bool allowHigherVe return false; } +bool Model::hasId(const QString &id) const +{ + return d->hasId(id); +} + +static QString firstCharToLower(const QString &string) +{ + QString resultString = string; + + if (!resultString.isEmpty()) + resultString[0] = resultString.at(0).toLower(); + + return resultString; +} + +QString Model::generateNewId(const QString &prefixName, const QString &fallbackPrefix) const +{ + // First try just the prefixName without number as postfix, then continue with 2 and further + // as postfix until id does not already exist. + // Properties of the root node are not allowed for ids, because they are available in the + // complete context without qualification. + + int counter = 0; + + QString newBaseId = QString(QStringLiteral("%1")).arg(firstCharToLower(prefixName)); + newBaseId.remove(QRegularExpression(QStringLiteral("[^a-zA-Z0-9_]"))); + + if (!newBaseId.isEmpty()) { + QChar firstChar = newBaseId.at(0); + if (firstChar.isDigit()) + newBaseId.prepend('_'); + } else { + newBaseId = fallbackPrefix; + } + + QString newId = newBaseId; + + while (!ModelNode::isValidId(newId) || hasId(newId) + || d->rootNode()->hasProperty(newId.toUtf8())) { + ++counter; + newId = QString(QStringLiteral("%1%2")).arg(firstCharToLower(newBaseId)).arg(counter); + } + + return newId; +} + +QString Model::generateNewId(const QString &prefixName) const +{ + return generateNewId(prefixName, QStringLiteral("element")); +} + bool Model::isImportPossible(const Import &import, bool ignoreAlias, bool allowHigherVersion) const { if (imports().contains(import)) diff --git a/src/plugins/qmldesigner/designercore/model/modelnode.cpp b/src/plugins/qmldesigner/designercore/model/modelnode.cpp index 288d9dadc4f..c6851548759 100644 --- a/src/plugins/qmldesigner/designercore/model/modelnode.cpp +++ b/src/plugins/qmldesigner/designercore/model/modelnode.cpp @@ -25,7 +25,6 @@ #include "modelnode.h" #include -#include #include #include #include "internalnode_p.h" @@ -144,7 +143,7 @@ QString ModelNode::id() const QString ModelNode::validId() { if (id().isEmpty()) - setIdWithRefactoring(view()->generateNewId(simplifiedTypeName())); + setIdWithRefactoring(model()->generateNewId(simplifiedTypeName())); return id(); } @@ -270,7 +269,8 @@ void ModelNode::setIdWithoutRefactoring(const QString &id) if (id == m_internalNode->id()) return; - if (view()->hasId(id)) + + if (model()->hasId(id)) throw InvalidIdException(__LINE__, __FUNCTION__, __FILE__, id.toUtf8(), InvalidIdException::DuplicateId); m_model.data()->d->changeNodeId(internalNode(), id); diff --git a/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp b/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp index bc5089f5305..844240f0b92 100644 --- a/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp +++ b/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp @@ -117,7 +117,7 @@ QmlItemNode QmlItemNode::createQmlItemNodeFromImage(AbstractView *view, const QS parentproperty.reparentHere(newQmlItemNode); QFileInfo fi(relativeImageName); - newQmlItemNode.setId(view->generateNewId(fi.baseName(), "image")); + newQmlItemNode.setId(view->model()->generateNewId(fi.baseName(), "image")); newQmlItemNode.modelNode().variantProperty("fillMode").setEnumeration("Image.PreserveAspectFit"); @@ -168,7 +168,7 @@ QmlItemNode QmlItemNode::createQmlItemNodeFromFont(AbstractView *view, metaInfo.minorVersion(), propertyPairList)); parentproperty.reparentHere(newQmlItemNode); - newQmlItemNode.setId(view->generateNewId("text", "text")); + newQmlItemNode.setId(view->model()->generateNewId("text", "text")); Q_ASSERT(newQmlItemNode.isValid()); }; diff --git a/src/plugins/qmldesigner/designercore/model/qmlvisualnode.cpp b/src/plugins/qmldesigner/designercore/model/qmlvisualnode.cpp index 6a78e11cdba..d6f417407c1 100644 --- a/src/plugins/qmldesigner/designercore/model/qmlvisualnode.cpp +++ b/src/plugins/qmldesigner/designercore/model/qmlvisualnode.cpp @@ -335,7 +335,7 @@ QmlObjectNode QmlVisualNode::createQmlObjectNode(AbstractView *view, if (!newQmlObjectNode.isValid()) return; - newQmlObjectNode.setId(view->generateNewId(itemLibraryEntry.name())); + newQmlObjectNode.setId(view->model()->generateNewId(itemLibraryEntry.name())); for (const auto &propertyBindingEntry : propertyBindingList) newQmlObjectNode.modelNode().bindingProperty(propertyBindingEntry.first).setExpression(propertyBindingEntry.second); From 1fcadf2cd2f624911720058fadc57ac95c55a5e3 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Sun, 27 Feb 2022 13:09:51 +0100 Subject: [PATCH 03/11] fix wording regarding toolchains Change-Id: I09c2d94af6791fab255d1a72a8484e78d6a239d2 Reviewed-by: Eike Ziller --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1a3456cdb2d..55ce5919e68 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ Prerequisites: * CMake * Ninja (recommended) -The installed toolchains have to match the one Qt was compiled with. +The used toolchain has to be compatible with the one Qt was compiled with. ### Linux and macOS From 860d8548ec5c55c5b9ac74efe5b25514e36017dc Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 11 Mar 2022 12:01:04 +0100 Subject: [PATCH 04/11] Bump version to 7.0.0 Change-Id: Ie403b97a027b15ddfbafa3ffbf46b8883951bb78 Reviewed-by: Eike Ziller --- cmake/QtCreatorIDEBranding.cmake | 6 +++--- qbs/modules/qtc/qtc.qbs | 10 +++++----- qtcreator_ide_branding.pri | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cmake/QtCreatorIDEBranding.cmake b/cmake/QtCreatorIDEBranding.cmake index 91d188b86aa..ade8b73ac23 100644 --- a/cmake/QtCreatorIDEBranding.cmake +++ b/cmake/QtCreatorIDEBranding.cmake @@ -1,6 +1,6 @@ -set(IDE_VERSION "6.84.0") # The IDE version. -set(IDE_VERSION_COMPAT "6.84.0") # The IDE Compatibility version. -set(IDE_VERSION_DISPLAY "7.0.0-rc1") # The IDE display version. +set(IDE_VERSION "7.0.0") # The IDE version. +set(IDE_VERSION_COMPAT "7.0.0") # The IDE Compatibility version. +set(IDE_VERSION_DISPLAY "7.0.0") # The IDE display version. set(IDE_COPYRIGHT_YEAR "2022") # The IDE current copyright year. set(IDE_SETTINGSVARIANT "QtProject") # The IDE settings variation. diff --git a/qbs/modules/qtc/qtc.qbs b/qbs/modules/qtc/qtc.qbs index b584c8280f4..f801369421a 100644 --- a/qbs/modules/qtc/qtc.qbs +++ b/qbs/modules/qtc/qtc.qbs @@ -3,15 +3,15 @@ import qbs.Environment import qbs.FileInfo Module { - property string qtcreator_display_version: '7.0.0-rc1' - property string ide_version_major: '6' - property string ide_version_minor: '84' + property string qtcreator_display_version: '7.0.0' + property string ide_version_major: '7' + property string ide_version_minor: '0' property string ide_version_release: '0' property string qtcreator_version: ide_version_major + '.' + ide_version_minor + '.' + ide_version_release - property string ide_compat_version_major: '6' - property string ide_compat_version_minor: '84' + property string ide_compat_version_major: '7' + property string ide_compat_version_minor: '0' property string ide_compat_version_release: '0' property string qtcreator_compat_version: ide_compat_version_major + '.' + ide_compat_version_minor + '.' + ide_compat_version_release diff --git a/qtcreator_ide_branding.pri b/qtcreator_ide_branding.pri index a3bbcd9fe48..7cbfec223da 100644 --- a/qtcreator_ide_branding.pri +++ b/qtcreator_ide_branding.pri @@ -1,6 +1,6 @@ -QTCREATOR_VERSION = 6.84.0 -QTCREATOR_COMPAT_VERSION = 6.84.0 -QTCREATOR_DISPLAY_VERSION = 7.0.0-rc1 +QTCREATOR_VERSION = 7.0.0 +QTCREATOR_COMPAT_VERSION = 7.0.0 +QTCREATOR_DISPLAY_VERSION = 7.0.0 QTCREATOR_COPYRIGHT_YEAR = 2022 IDE_DISPLAY_NAME = Qt Creator From 38cdbd2bcd6c11c69e2b03fd309df632acd70621 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20L=C3=B6hning?= Date: Mon, 7 Mar 2022 22:30:20 +0100 Subject: [PATCH 05/11] ManhattanStyle: Avoid crash when zooming invalid image Task-number: QTBUG-101581 Change-Id: I4070efe266fbbd579b021cd9c03465c85313e042 Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot --- src/plugins/coreplugin/manhattanstyle.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/plugins/coreplugin/manhattanstyle.cpp b/src/plugins/coreplugin/manhattanstyle.cpp index a6b94660f6f..d4a4cdbe6f5 100644 --- a/src/plugins/coreplugin/manhattanstyle.cpp +++ b/src/plugins/coreplugin/manhattanstyle.cpp @@ -189,6 +189,14 @@ QRect ManhattanStyle::subElementRect(SubElement element, const QStyleOption *opt QRect ManhattanStyle::subControlRect(ComplexControl control, const QStyleOptionComplex *option, SubControl subControl, const QWidget *widget) const { +#if QT_VERSION < QT_VERSION_CHECK(6, 2, 5) + // Workaround for QTBUG-101581, can be removed when building with Qt 6.2.5 or higher + if (control == CC_ScrollBar) { + const auto scrollbar = qstyleoption_cast(option); + if (scrollbar && qint64(scrollbar->maximum) - scrollbar->minimum > INT_MAX) + return QRect(); // breaks the scrollbar, but avoids the crash + } +#endif return QProxyStyle::subControlRect(control, option, subControl, widget); } From 8b272813541f230c8960b6ec7e4f430e3fc96c69 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 10 Mar 2022 15:11:33 +0200 Subject: [PATCH 06/11] QmlDesigner: Show error message on import log for failed 3D import The import is done on puppet side, so we use a log file to pass the error message. Also changed how import process is matched to the import, so that exit code is no longer needed for this purpose. Crashes are also now reported as import errors. Task-number: QDS-6402 Change-Id: Ie14cd1df0bbba965d8e5f2aa7302a955e944379b Reviewed-by: Samuel Ghinet Reviewed-by: Mahmoud Badri Reviewed-by: --- .../qml2puppet/import3d/import3d.cpp | 44 +++++++++++-------- .../qmlpuppet/qml2puppet/import3d/import3d.h | 2 +- .../qmlpuppet/qml2puppet/qml2puppetmain.cpp | 5 +-- .../itemlibrary/itemlibraryassetimporter.cpp | 39 ++++++++++++---- .../itemlibrary/itemlibraryassetimporter.h | 4 +- 5 files changed, 61 insertions(+), 33 deletions(-) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/import3d/import3d.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/import3d/import3d.cpp index c1cbca6f5ee..5f448b90da5 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/import3d/import3d.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/import3d/import3d.cpp @@ -29,18 +29,21 @@ #include #endif +#include +#include +#include #include #include -#include -#include #include -#include +#include +#include namespace Import3D { -void import3D(const QString &sourceAsset, const QString &outDir, int exitId, const QString &options) +void import3D(const QString &sourceAsset, const QString &outDir, const QString &options) { + QString errorStr; #ifdef IMPORT_QUICK3D_ASSETS QScopedPointer importer {new QSSGAssetImportManager}; @@ -48,32 +51,35 @@ void import3D(const QString &sourceAsset, const QString &outDir, int exitId, con QJsonDocument optDoc = QJsonDocument::fromJson(options.toUtf8(), &error); if (!optDoc.isNull() && optDoc.isObject()) { - QString errorStr; QJsonObject optObj = optDoc.object(); if (importer->importFile(sourceAsset, outDir, optObj.toVariantMap(), &errorStr) != QSSGAssetImportManager::ImportState::Success) { - qWarning() << __FUNCTION__ << "Failed to import 3D asset" - << sourceAsset << "with error:" << errorStr; - } else { - // Allow little time for file operations to finish - QTimer::singleShot(2000, nullptr, [exitId]() { - qApp->exit(exitId); - }); - return; } } else { - qWarning() << __FUNCTION__ << "Failed to parse import options:" << error.errorString(); + errorStr = QObject::tr("Failed to parse import options: %1").arg(error.errorString()); } #else + errorStr = QObject::tr("QtQuick3D is not available."); Q_UNUSED(sourceAsset) Q_UNUSED(outDir) - Q_UNUSED(exitId) Q_UNUSED(options) - qWarning() << __FUNCTION__ << "Failed to parse import options, Quick3DAssetImport not available"; #endif - QTimer::singleShot(0, nullptr, [exitId]() { - // Negative exitId means import failure - qApp->exit(-exitId); + if (!errorStr.isEmpty()) { + qWarning() << __FUNCTION__ << "Failed to import asset:" << errorStr << outDir; + + // Write the error into a file in outDir to pass it to creator side + QString errorFileName = outDir + "/__error.log"; + QFile file(errorFileName); + if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + QTextStream out(&file); + out << errorStr; + file.close(); + } + } + + // Allow little time for file operations to finish + QTimer::singleShot(2000, nullptr, []() { + qApp->exit(0); }); } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/import3d/import3d.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/import3d/import3d.h index eb2e4731724..3f53ef33c79 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/import3d/import3d.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/import3d/import3d.h @@ -29,5 +29,5 @@ namespace Import3D { - void import3D(const QString &sourceAsset, const QString &outDir, int id, const QString &options); + void import3D(const QString &sourceAsset, const QString &outDir, const QString &options); }; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/qml2puppetmain.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/qml2puppetmain.cpp index 8b6135c6222..5a7e0d7dd8b 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/qml2puppetmain.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/qml2puppetmain.cpp @@ -228,10 +228,9 @@ int internalMain(QGuiApplication *application) if (application->arguments().at(1) == "--import3dAsset") { QString sourceAsset = application->arguments().at(2); QString outDir = application->arguments().at(3); - int exitId = application->arguments().at(4).toInt(); - QString options = application->arguments().at(5); + QString options = application->arguments().at(4); - Import3D::import3D(sourceAsset, outDir, exitId, options); + Import3D::import3D(sourceAsset, outDir, options); return application->exec(); } diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp index 1ff31aad632..7e22efe016f 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp @@ -142,9 +142,10 @@ void ItemLibraryAssetImporter::addInfo(const QString &infoMsg, const QString &sr emit infoReported(infoMsg, srcPath); } -void ItemLibraryAssetImporter::importProcessFinished(int exitCode, QProcess::ExitStatus exitStatus) +void ItemLibraryAssetImporter::importProcessFinished(int exitCode, QProcess::ExitStatus exitStatus, + int importId) { - Q_UNUSED(exitStatus) + Q_UNUSED(exitCode) ++m_qmlImportFinishedCount; @@ -154,9 +155,32 @@ void ItemLibraryAssetImporter::importProcessFinished(int exitCode, QProcess::Exi return !entry || entry->state() == QProcess::NotRunning; })); - if (m_parseData.contains(-exitCode)) { - const ParseData pd = m_parseData.take(-exitCode); - addError(tr("Asset import process failed for: \"%1\".").arg(pd.sourceInfo.absoluteFilePath())); + if (m_parseData.contains(importId)) { + const ParseData &pd = m_parseData[importId]; + QString errStr; + if (exitStatus == QProcess::ExitStatus::CrashExit) { + errStr = tr("Import process crashed."); + } else { + bool unknownFail = !pd.outDir.exists() || pd.outDir.isEmpty(); + if (!unknownFail) { + QFile errorLog(pd.outDir.filePath("__error.log")); + if (errorLog.exists()) { + if (errorLog.open(QIODevice::ReadOnly)) + errStr = QString::fromUtf8(errorLog.readAll()); + else + unknownFail = true; + } + } + if (unknownFail) + errStr = tr("Import failed for unknown reason."); + } + + if (!errStr.isEmpty()) { + addError(tr("Asset import process failed: \"%1\".") + .arg(pd.sourceInfo.absoluteFilePath())); + addError(errStr); + m_parseData.remove(importId); + } } if (m_qmlImportFinishedCount == m_qmlPuppetCount) { @@ -565,15 +589,14 @@ bool ItemLibraryAssetImporter::startImportProcess(const ParseData &pd) QJsonDocument optDoc(pd.options); puppetArgs << "--import3dAsset" << pd.sourceInfo.absoluteFilePath() - << pd.outDir.absolutePath() << QString::number(pd.importId) - << QString::fromUtf8(optDoc.toJson()); + << pd.outDir.absolutePath() << QString::fromUtf8(optDoc.toJson()); QProcessUniquePointer process = puppetCreator.createPuppetProcess( "custom", {}, [&] {}, [&](int exitCode, QProcess::ExitStatus exitStatus) { - importProcessFinished(exitCode, exitStatus); + importProcessFinished(exitCode, exitStatus, pd.importId); }, puppetArgs); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h index 9abc315fbe0..83be9af5f4e 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h @@ -74,7 +74,7 @@ signals: void importFinished(); private slots: - void importProcessFinished(int exitCode, QProcess::ExitStatus exitStatus); + void importProcessFinished(int exitCode, QProcess::ExitStatus exitStatus, int importId); void iconProcessFinished(int exitCode, QProcess::ExitStatus exitStatus); private: @@ -125,7 +125,7 @@ private: std::vector m_qmlPuppetProcesses; int m_qmlPuppetCount = 0; int m_qmlImportFinishedCount = 0; - int m_importIdCounter = 1000000; // Use ids in range unlikely to clash with any normal process exit codes + int m_importIdCounter = 0; QHash m_parseData; QString m_progressTitle; QList m_requiredImports; From 6973ee14c4276a40271cbe4de066478cd8ab2b0c Mon Sep 17 00:00:00 2001 From: Tim Jenssen Date: Fri, 11 Mar 2022 11:33:31 +0100 Subject: [PATCH 07/11] qds: use double click to create a new project Change-Id: I77c1d8ed483d5971135469231657d5580617242d Reviewed-by: Samuel Ghinet Reviewed-by: Mahmoud Badri Reviewed-by: Thomas Hartmann --- .../imports/NewProjectDialog/NewProjectView.qml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/NewProjectView.qml b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/NewProjectView.qml index e8bb58cfa76..d0544c2f67a 100644 --- a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/NewProjectView.qml +++ b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/NewProjectView.qml @@ -101,6 +101,9 @@ ScrollView { height: DialogValues.presetItemHeight onClicked: delegate.GridView.view.currentIndex = index + onDoubleClicked: { + BackendApi.accept() + } background: Rectangle { id: delegateBackground From 1de60ddeaff6e7584be2e67e20ab3e5fbe2d75ba Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 11 Mar 2022 13:13:24 +0100 Subject: [PATCH 08/11] CMake: Don't be too eager to throw out SDK-registered cmakes Change-Id: I6a35e7599b61068deaf34aeb86ba53bc4120c47c Reviewed-by: Cristian Adam --- .../cmakeprojectmanager/cmaketoolsettingsaccessor.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp b/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp index 0629273d968..093e5f24ac7 100644 --- a/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp +++ b/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp @@ -128,7 +128,12 @@ mergeTools(std::vector> &sdkTools, std::unique_ptr userTool = std::move(userTools[0]); userTools.erase(std::begin(userTools)); - int userToolIndex = Utils::indexOf(result, Utils::equal(&CMakeTool::id, userTool->id())); + int userToolIndex = Utils::indexOf(result, [&userTool](const std::unique_ptr &tool) { + // Id should be sufficient, but we have older "mis-registered" docker based items. + // Make sure that these don't override better new values from the sdk by + // also checking the actual executable. + return userTool->id() == tool->id() && userTool->cmakeExecutable() == tool->cmakeExecutable(); + }); if (userToolIndex >= 0) { // Replace the sdk tool with the user tool, so any user changes do not get lost result[userToolIndex] = std::move(userTool); From 8e16d45d4caf866fcdbe00a0b80297cc32c34e4a Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 11 Mar 2022 12:40:14 +0100 Subject: [PATCH 09/11] ClangCodeModel: prevent crash on null project info Change-Id: Iff0c0413aa52821dc883b7f42b04bc8ca5dd4a29 Reviewed-by: Christian Stenger Reviewed-by: Qt CI Bot --- src/plugins/clangcodemodel/clangutils.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/clangcodemodel/clangutils.cpp b/src/plugins/clangcodemodel/clangutils.cpp index e906d6baf6f..466a062644b 100644 --- a/src/plugins/clangcodemodel/clangutils.cpp +++ b/src/plugins/clangcodemodel/clangutils.cpp @@ -379,6 +379,8 @@ GenerateCompilationDbResult generateCompilationDB(const CppEditor::ProjectInfo:: { QTC_ASSERT(!baseDir.isEmpty(), return GenerateCompilationDbResult(QString(), QCoreApplication::translate("ClangUtils", "Could not retrieve build directory."))); + QTC_ASSERT(projectInfo, return GenerateCompilationDbResult(QString(), + "Could not retrieve project info.")); QTC_CHECK(baseDir.ensureWritableDir()); QFile compileCommandsFile(baseDir.toString() + "/compile_commands.json"); const bool fileOpened = compileCommandsFile.open(QIODevice::WriteOnly | QIODevice::Truncate); From 2eca1c0ffc039a3508df03ee639baadd8a72c83c Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 14 Mar 2022 12:10:59 +0100 Subject: [PATCH 10/11] Docker: Add history to "Search in Selected Directories" Also set focus to the line edit when this item gets selected, and remove the arbitrary /usr/bin;/opt default. Slightly better UX. Change-Id: Icdc4e81d6cebd7aed1dd4999c4007a60c8ea53a2 Reviewed-by: Christian Stenger --- src/plugins/docker/dockerdevice.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 38db443ac41..25770163e35 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -382,12 +382,12 @@ public: searchDirsComboBox->addItem(tr("Search in PATH")); searchDirsComboBox->addItem(tr("Search in Selected Directories")); - auto searchDirsLineEdit = new QLineEdit; - searchDirsLineEdit->setText("/usr/bin;/opt"); + auto searchDirsLineEdit = new FancyLineEdit; searchDirsLineEdit->setToolTip( tr("Select the paths in the docker image that should be scanned for kit entries.")); + searchDirsLineEdit->setHistoryCompleter("DockerMounts", true); - auto searchPaths = [this, searchDirsComboBox, searchDirsLineEdit, dockerDevice] { + auto searchPaths = [searchDirsComboBox, searchDirsLineEdit, dockerDevice] { FilePaths paths; if (searchDirsComboBox->currentIndex() == 0) { paths = dockerDevice->systemEnvironment().path(); @@ -458,8 +458,10 @@ public: }.attachTo(this); searchDirsLineEdit->setVisible(false); - auto updateDirectoriesLineEdit = [this, searchDirsLineEdit](int index) { + auto updateDirectoriesLineEdit = [searchDirsLineEdit](int index) { searchDirsLineEdit->setVisible(index == 1); + if (index == 1) + searchDirsLineEdit->setFocus(); }; QObject::connect(searchDirsComboBox, qOverload(&QComboBox::activated), this, updateDirectoriesLineEdit); From 4594250b6cd44bf94d57b1213fbcdc992ce35284 Mon Sep 17 00:00:00 2001 From: Mats Honkamaa Date: Tue, 8 Mar 2022 12:55:33 +0200 Subject: [PATCH 11/11] Doc: Update text editor view docs - Add info about search function - Update screenshot Task-number: QDS-6371 Change-Id: I162ad6917823b8834de94513ed77edc8ee0c0344 Reviewed-by: Mahmoud Badri --- .../images/qtquick-text-editor.png | Bin 16168 -> 23333 bytes .../src/views/qtquick-text-editor.qdoc | 4 ++++ 2 files changed, 4 insertions(+) diff --git a/doc/qtdesignstudio/images/qtquick-text-editor.png b/doc/qtdesignstudio/images/qtquick-text-editor.png index ad1cb7a9ae62f417a4597ee3660151fabe7275c2..0d1acf87f0fdc468bfff9ae3147200ed9048f1e2 100644 GIT binary patch literal 23333 zcmeAS@N?(olHy`uVBq!ia0y~yU}9%rV7$h`#K6Fi5+v_9#lI(5xf8?RSk=O^j%Pf9<{%$D<^VS*$NTTkN5gUZG; z0vi~(&zl`idiX{~ZQ;9}>gt|zt?WW~J{7lI-gW)^`iSq>?@H}jnish#HG12=*!j1j zw?wVomiX81Z}q%?w&&OX`}BAJQ>n9O&;A!T%ek>3@p67j&Y$n~|G&o{d~eRXxXynWptgH67^zN&JU@8AFb zy#C+wHhJ~m`f+<^w29W;zWYmhd)vFIU)WzywZAs!VgLFyNA`Y={`BbO()&A@qqiTb zpEu*5^81bZBYw^Q=oRs6etpFKuk+pR9ROKydez(Q`~SXOc0Y9c?d|#hZ_fW4`K7=7 z{XJisWvf}*xsx?FpI^{!91^KR#_JE32<{o@6hAHMgN z-dBC|b8XSQ7UMO43g;!Ye*gc?`tkW?XY=#*{{$xYmmPD6`=3~=F36_jabrW`>20|+ zH8v+>|1`7n3w__deS5i^*{o&38<}ouX=%N?yL8~#@ckSAB$_^NFmAIhfA{C*{C}F2zW=7n%v{m(W$lMAm)2iZwEM@p^Y!+>AA`@HIZ&}~ zfo12P;|>+;9KM|pR5_b&di;-CRnMCqhaV~@(|O9LckulC^VWW1!=?ItmhCylW;r)D zl}SrTD42ih-2UzG;lpjm@9!v7zRM9*QoJ+fNyGksulK9{_g<1z;WI02$0ezmCK*lk zPvq>+e|!Dm$pMX~CFd9x8TV+fo!A^Mv{v9>&YKzazt={8^!+g-#M$$Irp}l8KdE&w zdW@jt6um7s#i#z;o15S7*UR7i9A5u5Jmrd6x6aYXMwgjeZa(v$Z>Rcy*R5N(>VHnJ z?>w!VbC0WwVbRLRCpgyKIr{(O<&?_S`;x~O`>b8i8~OLzU-nP0OV%i`_w6};LfJFr z*n+l6kbr!v=6Pvr_Vq>eDks}6T?*RV{CLfRJeB-2g?HNGm$3DnQ1*OMe>EV8?HSkp zzIq-{$(xHARe$zNM;xqKx8Ua+v1eQ=dv%@*O*t@8#w+WawB0%`?S#W^y47a;@B3dm z@ucFSe}OO6~5{eD%;?5X0Fbw||u zo*WN7X~p)p2NKp{xvj0ODrGMJ%zq}%-oP|dctR;>r@zd^Ib}&q$?=g7`Lp|HES=t| z^>4#MX;9?cj=O(vfBpT*8@_)1I&o#&O?MBgTRMAvAe92N=!3 zz%b#MtnnHK1_p4%=>=-V`pGsIJweq*UF2f5sVBB39TDMKYjk3$jZRbAiC)! z*Blkm$~9BE1zFTV+AMQflbEVG|F7AN=l)IVt`HYXyUd(C>^mNwbj1$&y7r(AFfioFhhIyiuOHo3#IF3NL3CfhRO`Rh`gOllT}3AbR@mNn zF_Hb#}sSZ(LpZWRMtUF&L z{@i};X`8pb((5&!>OOpF@pYceht{C{SG%1K1?Ybb`8(yC-~L&5esI59`6YR;k>UzH zIWEojZCy_#J@psMNh+_DJMmzJ^fhJXMMc^B*SXrBc~h}h*XFSB#EEwew+Y#L{t0-k z`2Eep$^0(&FGU=D$Uo_`N!2AoFRjZHKk&<$hu^qU$-q#3gKLlTnhANf0_^&o@9%y7 z|F8dccIyi1mW5eoQlY1jBMmEYg`-$$gmG733-`KROWlLJZslWfe zM{jqsdd|r3=Ix%Q2OC7K_pKJR|Hu1(f7ubP6rby=qDqHrkBEIbu}(&yR&Z*2QUCgj z&KBN+zm+YIStL99&C9B*zP?64pR<<5^IXK5<>Ip^`Oi4UyKklFB^!Q*g!AdMBi#d= ze-x&sueosgMY7$+mCi@RCSJ7v=A_>LV|U$K`O>xyZ>=Ts?q7S(`H1bWi}nn;`Rhb| zlD`+3&3;l{n|W6B#NFCi&O0}XUb5$BUsVGA8m^ykDR=jrk7nL{+Wn%E=PZTRPIzO(z!0HmT-=(aI)9Ixr-aM9N6OoOZk#xG z$*lQ(#;*?kU*awLq%5#s(-z3puU1H*|R?GJp_GoRRN#=V*>6~h;Hf=zqL zRL&cEO6NP5Nx6D{uV7&Kq35j~$HBMyY+y$5jaHqN%}e}EnHdMW-r%gB zz{79C^H2r<~-9ne?x7Ma*aJKGwXI1$0^Q|!Mm6Jm6 zZxrLRyW_?Xp(y=J+rY{5>_cv0{=B>Uij%**nrPKNwY1~KuFcbTzgwZaL*3@hB-2aw zD*OM%Zf1)7?tZOoh0%qOA2+;Hmd$PRyuSF%y;g<@#jQ;%nVzo5w70JN95w&{lbhb# z)27|Old*C^rdVvb&%e$0nPbZ*eRDdoKy;g(V)V`5w$esluIFC)s?oZ8+TV}XEH}-< zAIPkmw8?AY(k@+*&}&}`-hKYjxhu)b;kxYE1^ch>dZ+RI!NMJf&#bfe%)Oq`er{@G zfI(KP%Juat*+uVcFr9F3+5P+yxylPN0qfF}aw2|49=g6hgh%FGXWXj$lmApr`4qe_ z;&WiGVR7t4ZU0M;ee37nI=9S=bIp}>Kg~$Rg_mPknx&H2wM72_M&4 zKeTa=`m309eWm=?UL}uT+*Y8;;-}dib zee+}AwF|DCnyavx#ptldag+KR`LJU-L}cg z{_It_&7+<2OHw7>_x_VZs}tu3%$XjZqP;CB%=$dH>Wf{Q-FLl{D7ol4@2$y>y3Mb@ zWCZOv%q$(LSh?-y3#-Eqe;@hErFJtdSbGA;?q}{l>JH~@zNxYPv|0bsB-X?C(^XbZ zp77UfKey*{?@7#=Yw%@m-^yQh>)8hKPvHOairi9P#ey&+^ z*YWz?y^QnDv21X1n{PKM=4H6_I>z>~FaN+91?8VCIeX?50VFim`^X+H&6LqcopW~Rd) zQ+to=-QQ(g`1sjX@8zpmt#vIfmZtlc-@W-Dc&6mmv-8>Sx@j-4=4}w&R=csuSt@-GFP0v6VXj{I`dpaZ)TgUiF3e>+z-4`5`_3zYLB}?S zENm?@i<=ug(>BumriA*gcNuJd_g*VKeuGQxe)g@i&)6sHnWTjo{N8!#ZP8}I6}nsr zt-0%~4}MOmEOy+u_0@^Ft^E4dcTKj=m9@H9>TVvB7kqtgN-^u-@3YD_8@_hh{4nO= zf@xV+v3W)rtR>4CHylcvqEPUZ*Y^3kczL;f|3AE2x%g|DmxxQr-J6x#DLY>KNrf4# zbIrQenr0m4vHY}e+S-P9CJbRWdPHCCJ{KdYbon8haG$h6@QpZkP}zRed)0yl9fy9GTzN(STkW}`UIII&y}n9+{v4GT{~bZ`+WU>XCv~@nnf|jmhbZy zGCCD-eJ)Sr!6n?i?>MiNE}mzg8I{=lS^E4;aDd*vJukT6idk%($gaY7e{MD&T;2F| zXSKaq=#A~hO;fa9>|$nU5G|`)r?4@o^7Kb<<>bfL-H)~D%`5pVay0j|*0zx8;tO8$ zF))PPXx-D~ayew8Yv#`6+Y`IQH5=DiGcZIjUi}DaAU1%TiC_{@V^p8#Dx0+_Kt|p2 zVrlyOvb&wpvfE}YR28|ks_bQ4{ifns>%1n5tGJ(D!&u=6KEH|Aark$}e(x*6HQW<@e|MeOcM~=%)*;9B-1fIc#FD z{d;tJ|G%?uT;?7<$MIrUvQf>O)^*lTDlQ+iY7RSb(h&y7|qWJg7onXhTkb4b`9 z<*2|tEB1K4PrIFtKKuHs5i@f)G3|Qia%^kvyIsoLeH6+U|AJKqYtm8`M0%nWPkzmQ z<;ZHD$D5MIy1B~zS?L6y-QOkt*!kA;-?}j+XqVQ}|4RZ7i@q_|=4i@TJmb~A+n4#< z`QvLhiR{@|8`iOlF}9p1zuNd_sk__*H6FL;y;_aOZ)ztg7~N4n=E<|_fouPFcJsc~ zFFtc|HhEUAOSrc8_?z#UpQLdm@YmzV|9A8Xs%(B|>zVB978a0o z$8SO;(@XVP$KFfEHXNwi#B{ndXzBm57iXXLP1>_((WlS-)0@M!KCLn7UuUg$`1rk- zyOM3J-ur7y)J=T({_+*BhuY;oYHb%@nJ?wQ!udvB+hEV)zo*XF*Zti+b7lB?r_Gz? z|CfC|{p!r#g=+mN6C+CQ-kcp<{^UlW&LW|A$L2iwb#`6wK6ZY4t;OdogSr%4Kg$;$ zmo7hg(qr4rHP!t$-(UXnT|lLJk>HZXuex6+x```nNdL?=Y4xGdxX5?w^wzJjD)@S| z{leL>izmDNq+-jz@9wfSy8e}9wPK6*LI+A8PGq+`-AedWruZBDti_xO+R znZK$#RFZ`@Ut3nr|AL9-+e2fIrX!jLb0W&0UVZ;uEvwtpHWyUv$}%|gtxpn`S;xF@ z-@P*N&1YBN2#Sqs04MjvaP7DaJe!3@^@EsV%NZCpFs*vb$iT3ML7M?aA~M0Z4p9~M z-76ix~^tof+`FQ zCt|g4WP~42NT~a_@BfEJ=Cx;4m7Gsy9OhzRm@qj^K*jof)|-7ck`@1c-0TiNT`#_; zYDq{+#6FfV28M>1GiKb2ju?Dfl$4z~u{F;|Hs*)HyY(A`m3To`=B*14(8`=#+3eB% z^!a=}_H`x2VbhvK85k7U*B-zWq5)_^^^D{7Pa4M>}r&L+B&bI#dn|oKa!`H{{ zD_CJTQ&h|L>hj;`)SSMh?-f-$X7l4aJ41u$q;1sh(__I^8#L~R-Ln0Z_Uz@63p;C|z_mcWd|W{9NN}+MtmTkqIudL)W~t zu>O_s>D}6o!t8flMfTff&n}l)|X1`e_hI6_i>x5ZL{``ykCV33^(}0 z9#ou+yjYg?;?z=a`#2SzxOe*t-bJ`)&r}Go%wsJosGeUwd(DGPp0y{m)vsMwbGmp` zc;1I1E?(w;AKYb<4|e`|%*e38>DlVXg4!W+cGfmUUtfJ)sC~UoX6Mg;^8bE*eNlMv zT)??IT?)B3xlTFkzx4R#kKHFGGS~UL@Mj+@weYCz%ebnxNvqm6=7Xr|KTvZ(smWzx z-`Q4Iv3)NOy?&WKcj}s{cZ(}qZ%lYw+RrAdSGhbnMDoSc?R6hlvNTO8`*z`5Xzl9S zFRRUySW~?|c2C$=^2Gp%Uz|Fds{j=#%4^~3H(@9wSPZKYo7lk(qf`_S<|_S#v| zj=-L0Tu0=aL%J$ELIR%gc3NNGVtu&&3%~Y5WuXkO`?jDSxvxc3#$F@y?_UBe^ToeC zGxm6Ors2-Z>fcQ%Z~Dp|nna&iGFqNdX-Y|Iosq`F=OHe{H|s{mB7v< z-Qb$DcgLphM~@%%))iIxzbE~=_K9XYPyQ2+?FyUAzeLxxsONpV@NKHiq$g!7IoT|& zM5gC{Yi)L28L9X+XY;2W7rP=ivp4_Qd?zvFtXZ|x#9TH|=)5sowe9`A-52gkO>Y+c zwodek%OU+&Z}(3!{I{&{$Fi^q{M~7@+3zkctYk8J*pV{(s^(F*un6y;l1p}|2b9k5 z^44le_N}v-$;Gf{gEPmTqhYomzC7Pv-Z!0N$wcF8X3Pu@e$kFgT>OvEJb3T$S0(*| z6%~vO43=_^LM{`RWn9W~&q%`mE<6xwzYV zR{mr6{H>Sr;12`ChW0fI9E+xkt-kd~yl#)th5B79gSKqs6AbhC{)g?a#HIEt7MIpk z`mM=PG>^KV+u{c9VDKp4v}}L=;>7Ch>)+qqQ}+1e?w{$-TbG&~emY6isHiSjdr6?Y z=EA6~L%R<$<{k_wdCbTVcA}!)?_k`m0@ELtyS3eQ?$_sQTK~xT`1!=gRY_iV7GM47 zv+L2064%}pH#G9^^t$J57r0<{FEAycsP3|!t)TXr)I(hR8n6B^y0u~{D7bXPGWLA? zba(P;*=>8AvR8h8_~#UOwBW|#V%Ed!EL=F_WgmJ~#_EXQ*N!8_~Bw!fbygjJdf5kJB;F8pzktMDz#Xiq>|DJ!z|94(AUoXdF zwj<-WU5CQaw#=PL+up^+T@E{VhHK*IjQd_u#-_qy7ajyGcAh8^lH!+;zzXqcMqHzq z_o`dx`+Dw3?JxZO?5+FvW9Q7mrw8|J*}q0$Ipg9B!lLu*|FxF<`f}1&e9!&&dqk&n zOfWi?tu7#VCFpjC0waTVicQlI&Y-g!cN=fEmz(lwpZ1x>TEFD=THnppO@3qceBZ{V zOXZ4IDZ#nF;;h)h6fPWuKj(2tMKNt1g@}-({jr%l&Wv^ z_WyM=ZBkHNU^=tP+dCN_CjKxG-1U)xK|96bwvN%cRhK7U4(89F^Wue7U0F$4>d#Xf z)%qT-l!?1-^WrMs>nD{eI&sVlPkgq`d>nBq^0EA`|1T~+K6!Gtc+J_K-V;jGwc{q( zxa7Q2u-`25|Be;|!<%?*0mcta37cnlts@=Em*%yKRn&xoz5b?r``#w*2|Jn+?psO~ngbeNpib z{+?I1otm;P;DAZYyq~xE`}MAWsNM**!$m-HBsuKE-DDR+*` zoj=dJZF+Pj=XnK21_wR22^!(K#}E8C@p9ea*yHc_MD4IH@mX|ov1f&mC<8;$C9W+I z_iBoMe4M;|a{s)ZIeA+z$Y{keFgUz(o4^vd>GGCKMaQFjqTVgw6JlU^QWA&Rl?(&7 zrJ~NJ#BGz{Te{Nux`D?Q4s|x&{BwbY6QE#I4-*NN%2XhjZj(X4ZNG zflmk785(r9G^yOuEI;0w&ENFi?hLz?ZJ74+1c`-9cD?_2=FH>cs-!+rgzR)+TyMOxqJ1JDf7QOH zXI4vSak$S}WPLRuq-4KSZE?kZ3G00hCCf@|=RNG4!2kapBg4&f)=L#a5L> zS7XI(3CX37NDFpiVTJFdnr z;Q6caHy~gk-;1+9MbB1Vd}#Me^CypUWtgk<*C(4d8jD|P@Be@B)|~sxggYhsHckZ% zB%Qdlhe?pxx7)N`{a)Kzgsd$}G z($+X^zOiXjyq}l*`@bh2#MSR#;Jf#)d{?Amm4lDsePQPpn{LKRCC)f2^hBk2!^P(M z?+guVYS}syRo05yq}==Puks34-2LX4H=}b?rK1}!T)DK1ebd=xVH4uF@ILMKON~-s zpQSXvXjP-yQL$G`6mwd6O&WGGF(j;yZv2vK_diRsWRvFxBc-ELw#8PM3CrY(Xm%&> zw`oqvV>LR}{+z{6HBn$AljS6rt~E!*&iydXE*3hW&A{+&w&j z%4Ay;&cN`-T6@EskhuCspSBkBruNKL?=5HH4la9f=EdXb`to=8mu|V0mt4H(QL9X3 z*E!}V>Ag-X{kVG$-b!O|FpG8+WX|3=>1no~;-!lAFzNRZ8ePR4mhtQ-r8;$%Zq;LC zVEDF5G(eW0fgynvRH$GfThE3#3uU-nE_HVei28VdOWFywF`N7C$<@2s@w<#SK3S`{ zqfRkfJmj}iV}d>#6T_y%To2b-i}tefg=oZoXTP_@^QX6_d zOaAXG-wlVNPKAAFRcm^D_n>~`)~^R{iJ!d?dDlQ@)`aqPlbQ9_9C53eSd)@!`>&!m zb_%l-@4OeaRc~ybbT9hc*{1Nb;!E_RDTY_f2DDe|Oz5Ty~wG z;fAkvflAbqb;Z+nX?ggwF14E1t8B@Z?&+Ev+L~ftQ(E}5(0a{;Npf4lCggrRd-qvr zeD!p5Sw|)Fi;X8Z{Mu>+gfBf6zi)kzaFvElb82ody)5TE8C>=l9ru0i+R_{Gi>->$$F`@eNk)1 z*^ngGQuWg}cAne#w0wipudoT1c@{TIp3pv`%B=MLLCTG*ZOut5qb?gvw8`TCUbcSC z>*Mi%Kkk~MU#YFg|L`*Z{f!sn%jJ4?zg+k43;#Yl&YnTRdYrJ;xTAFZ1lkI?BE!?W27^<7}5%O=954 z{O0bK{+451^;*mQH$B$gd)&T%dX3qqy&ElC=9F?AS$Fe@7%2D~M87Q;ee%-Des)hN!t$TT`<%jg5pXru*OJ@34C>=kYA1ZzCv36$4S(zl?bMihc&bOwl zzv=9FanDAh&lk>QhAI6_ue1`f>yOjjl`-k%S7rv0A4_iYmEMgE+5IkK?Sx|C&37Y1NXKwz1$Uiv7jj9iPPd+rS5nAw=EMsyjWa{rL$4=oARRd;h*=s zv}*dzaDeOAI_qr_*JWANXX=Se4zpQNu`z$G0Jpg>&-bK7cxLQi?UkLc`Q+d3I{cBz z*VwFS?$*yjYc}MsOusJQnY`#(>z@4uIY%T{oj>sN@85G*&mDU6=ceu4M^*b%!|Ts8 zq%0RzxtONvJ?r%A=%`b3i>}M|T{)(`+WL)s@uMf2|2M9iWz_gcMrqB4{Iv&uZPia` zo%`FCc|vR0gx&8#WNeCGe%svo)N<)-KJB1IzaPx(Og}GwXHW6}le6b9lb=&;{YHmf z`;F+Om#>sBt$w8-TFa=N!+vakI>V;(Tt(OCCU2iEcAw||OwRJViK^R{TnfG)a!&Mb zK!8uETgSnb!L1FSGSyf;?{@N;D{{+j&K3>2{}Av9y3g{;PU9>0oo_}>ov(9d*d*|JhRiv~PQ3g2MR(7+UF)oy zH?FhxT{#=D{eqv#McNs5LURj_Oik)NYq@ByW2lh*?ojO`N*=!+OjBGCUh$4?=9~UG@&6+aGkD)QcSC-1q+;1$l_~4%cK@@{beV9b zj$iG$|EFTc4cq5AdaYRUR-|Ixjku~0Pj1|4e|b)mF>9&chIO}8#RPAC4m0?>li|kg zFa<9G?cMAA_t*b^kh6RDiDMsy=J}YmsPKFE*h`(1?0v#~g=5m|-9I=c?TPRGb0Sgx z{wKFEj~<1suFByX?=W8#n;-6BdppNYYTY+!x11v$Ob&7{7B9|nVmUc!M)-u}FJCtb z&RlWG`HhmAXoFspNN-H$bB&aeY2PPH_Q+Iu<+1+!HCOSg#KlE!?O!yf?Xc{Pd~)gv z*D_GZ-{9h@WLx>^#f{lJ)sxpQ-NwY7n_k%_oXGk)XLI7U>jt;ixXn>onfa+oS^GrL z#kASVJ6m?-6c>EH`AjA9TEVv&K72N_)O8M9dxp&AIkGWuYRg^Io6mkZHK$K_B4}^3 zbb{_8&y%OzJkwY==WKpfb;5Phb?FF4yLz3{J137tKMY(X%2UsOa!taYV#W>6*C>?V z{rRQIW@gsH%9YC=e|&WRp6rVi*;Y5oRy+=HcMq=Z4W5t@!I;8PzrXCobm9Gyl>%ke z%9+2PKWEzDq!n8(kt3T@fzpJgSqvq-)tNX7x#C5wbia&X_-#ZCz zzcrIh&u0rSd?@lytcLm2!9*v!KW`Z(D2Gi@u@0?!aOJ49|FdaR)>)ffDs5kDQ}XFq z_jdmGcWQsU`n&w(XZP5q10OdyZHrXwt#bdDkYIb`Mc~&Bn?7p1mz)Kw8@BshfzWde{qpNpPuE#b`_y;)y}iHu`b9ZBYZ6*Auggx(vs`j0 zc1>MiOfZYHcFL07e3nH?XBN+7XOT{1Wk_J1yw3V+uj$jLPtP6>-nGtJ=A_1rjANnp zU%oA$uwN|9;MkJaeVN2<|035Bnfe-3;7IB|LNu8H0q zqKh6bzWN}H>n$V0x2U+rE1Nb1?pkL(N1;gdUE8*EeT!qSt2YaaTeC|274yVie5-A+3}A{=H{KX z&yO?f&$HieU3mBY-FJG4kxxV?9i8|kw%lj;Q;k~jJt=$-KWVvn9^{gIxo&b9i>BS@ zJxwo}7%X#GFLn2-3vUmi9R%C5@ z)zf2{`G%?oKr{T0*I6ICTeK*){KP>O{{`EdE>)}R3C>;l&Pqif8n23) zu6MX}u6Kq8!-V3n6>oR!{qWMV(&(z!HMJ{d-}>*p{Ay;pWm{>lU+t`_8^uRMF zI}=%#zCJhep>(rvD$m)@oX+LXPffnQKHi>xU!9d@)q$fyHrGIdcIP4-ua~y}nP~EO z$qJ{fPy4RsxgX_bU^ro_jWN}aJnesgYqo>HTb=c0H!j+4IaOq$U9iFF+q#9pua%E> zy-4KxFF%oFu(<(Y1N zIbH3l#h$K;rnetUEjHcbN<5;dEN}7o_PgiN+dsc=y&`-kt9OELq~qtkeK*oCYqxPE zuHuFmDDNpSQvv$mq>e#@vX2Z=W@e<$fXO}*GDLwh~#C6uMq9@%|+s3yq=GWiz zrw?YEhD99w5*8l*(kkqvpQPtvK{?-6>&5G=PyKk;(b~Kvwu)!>uM^)twcVHQ{xjjR z>CwHs>)rKkS*?1*$#VD9d7-=OFE=b>S@ZF{YIt>TjL)1EN!J%=`s9}F`T5>)>!DlM z);QD%TymYZE2-*)a66ZhHMh(1O`CTv$X>A^j?Yar+cn3eNY?IMhC@h7xCIV zF^(&*ybViz5VY9gSeg#y9&X3 z{+EO<2Hrlx<-&QfrSZ79Ij6x)?F9l>Yc_mcXU&tmd{yoDXK8KLuU4P8tNC6f5q4vW zC{MJqMA_YoXvcl&)2kn<{t3MA99=!*W5BvI(@HY@ zxWNmOJa3=sSo8S6Qul)&gG*cQ{|zYm_VChadGGz&iz?KawR5g=rNx$;N%213{VQj) z=p(*sasIQyIM{E7a95d&+}4Y7yx4GZ;>{G+wQNDBwGVJ@ICO1I!qyv}FEXC(|FeC6 zy=CR&XM5fK)9nA=eQ$5KvuN46Ly1!@A`Y6EdoN95-Mr2^ZSlg)@cBywmt?eP=`~H+ zBs$5adCD@;6EjaLZ;nekI7P|tcuJ+W1{?B192-Hpa;F!@o_JD}@>KiM-r&HhE=)<4Lz8LRTaT5?f7nz5DYerq*ccQ;SpQ zgw}{WmaO^r`Lo&WCco z^b6U;F#CXX=L|{L0}N{zHr?P_(Z>#&hzHHAZ(zb84=vmE&cLgD?g`_Si{?Je5M3(G zzh(l@=6B{F|1zJLJnPn_g_>{s*J)3?F1<(wd44E%7x9K}FYP!$WJEPb(HR?eTFe3N@9pxpnbo?UL2Y9|uIIt~`(^ z8og<2l-k|=p53Qjgnv-Gz5a%h%_i+fH&eA+4A-e_^bYIb3!3+^@#|LG9c9ybwjOM} za4vpl;{Dbqu9JDzHvHrLeU{7X`rK!a)7{^-i>1wzoqFADveB)Y-18says!VS_Tj_B z&C~hS*2xtZmx+ZLDBpc&{xV|W+%NV4)7Vcxm1nxY?I@SzD*Y|D!)~moh?(Z}t7?+G zeUawMr&kVNKi_`mO#I(~4Bbt) z-tGx@VL6#HE#b;vHBa$bCC|AQJMKI%Cn)XQ+P9r)Ved6=@uz=T9iGiPeO*Lw+U}bw zFZ~{$S>16}{8E_K)i>cCSHz88)lL2tqZnrCC%I}-ZBMfO+`{WpzQ>bmZIv!R?md?u zC4Kde&BaHq`x--Y1y25`I^80dtpF`xe)^?wH+cbI09Yb$+78`BfRt(MNCX`0abD zl68OG0VU@0n6&|$*O}g`DofeF?D$O2>C%@!XX}~@+NN*%+!Fs<%}VWh@~x%E-~5q# zI^)A}+ur0`vufLzE<6_%TBh&D`XgXv_5Y`$Pu5wR*@YQT71dm~=IxoeKl|UOr-?tC zZtwRcY@^KigIv2)SxcWe9{avR^vo}f7vHm$JT~T(wWyT(o2Rl~zO|?_rC|O3c!9iL zOOee^Ul@FwjVHe|U+FgCkjL$0^4ZSoi^x(%Wb3^=6y{z2Draxo1_R5S}l-PQA zV^fT;huz6(Yc{Cz=3L|Y)V*zC&BdAGc@>fyop!Wt%Hl4)B(Uueo79a>qLb9*Z20#3 z_nminclm6;`Q|1yr6rYXPQ0<%a%Zx~$Lo`iaJ4;G|DDJhq39geVYkk!TlD!n z9sB*a4o63Dg`MaTEx9{m^1JK(&prw+Ir7fx(;S66e2y=tEq?od&D)y-^TQ)<7R4Pr z!j&?G|2*d$uR{t+tVJrFB9WcCK`-l)>*i)g9bA*mn_1_u$p0e8nFckZ9PM^HqqOdcKv#CD#lSDGA<#aukh;qIloF? z`)s~?EP34oP3@N7VZVgtne^VzPis}V`D|atw#o~(S<`a)@{DfhY>HF#WLaq`W1XeE zGI^5vg$PG+&0X{7ule2kvvgTD>*aN(MP=75q;rb)>=f;}E-x`hJ+WwkWO48M<9odO zGtK2D)m=!LUE8-q$GgUSo^J$WZ0)zzqDisk5{*TsCG+HWm#jG#`#N|3uUDVXTwZ5& z?3luO1|x~)OKx2!K6_|>bv{=aP$?aDW8*sOH6b@k^8TC)Fn+nqdDGdTqYE2<8(+?k z-^;nTqUv*jrF+!J2a+li4w_z4*(5TT{ls~x)v?uSI^zJ zl%-vqX1ik@WK||4u9k+X;lp*ZEeRBqeH;md7)>+4_dEM7^WJAr4 z*L?a1K`V=tK}AW1bo8rrYqdjnz0)veKA2WsF^g}j{9CI_bt`VYO|oPM70AEuaur>d zo&G)I{?^_3&ko0yr>I6$rthu)^YzN?1D~hs%isSdziQh}SJ3$Lx1FFGV%1_{@AuE& z*~NC1+%3G3xpB|mPn&Ow*M1F3Obl#nT@(>0BIwA((C{}8)J*)_xJ;`&GI+^rKII#8 zzuMc)oG+7;o--%nk&^e^iQ%9XPA9b|gmH!WUYA`xcls*+yH%FoAAGy)KV}9jZB~UFEU~Gy8@wH{Y=ZB355>>{i9>gHtu_H=}~C?;$AV( z(wBxg8<<}1dYorf|M=fku}h`x>eVc>ua^F}(>tB}vvKhHHvg>?HVDlF1xC!qrdy@Q z#a`}GUY|Qnr7cmX=(_B!V;xN`;1yKfVFV`fx7{dh-;-9ko2|`e4VSh`!dLN$x7 z1w{ux6;Y82GjNpA%K7{}_p8mhKihu)yjEiOh@Z{L?gwa%#^Km%=e0RCd`Pr++ zmg|(Q-16#&%ZIC<4|FeY6!)LE|JR@T|DSJ1*Dme3yT&SR>GEGC_iwtKsEbIPz1G0+ z*}-~yh67wP-|i|-srh*L&));PzkhzX&N{_)_R%EmO*go@bfzr-ee=temu~JGZ6n+L z9yOQ;2S=TlcW0jVlTPP}KQ8@cx+rPADO*GT*RFk*`fr+dc!XqCeE=`GdJme(o_toc zWm8+TuIapp>#}~qoXyky?nTyBziyeE^rQC^SCrulO~vvx4pRi=K6?II7-`LUV)YLH zdy|TVa-FLtnuwPyH4iU)}{tfnCcrPk2^Vy!lZIPg5R!@3F zKfQXq`2uUwo!y;G9>=*-rYWe;Z0?o&^PQPt&4#^Gw;T?eAThh(!>!pfZ`Xaw33}zf z%xvoxrQ2(Ien;`DJmcr$cqFz4G`Y3m(7C9_^lsU?{P*|DTRu`NR9O@5Vc)c5Ca=Zk zMU||P65qMC=D6`q*v!p3OBs|a!cItO8*Ev7$NXR3yTaf|PVEC+(Pz!VElNFGGu|m0 zN(*`iJeE{pNNBzLX4mDq?0=wv>UZlCwua5wx83INgOtt_MNHSs(lsO2Gcc^#kQ-Y* zi#^XjE3^jeZYjKC;CgY~dcP|uuD9GNt{fy#`%61OzH}TpgEc;_lxIE=~{JElP zce}H2_G{t8SAVQ#QFy&}LCM{f){pj^d`x<#`*N4FR-6ZqdROW4cdY5lmdEd%`Pb5- zZjVcXgvR^c!?OREY zZe7HjnvZsOO4|i9+}|FU+@GKSYv!N*+d_Zd-}C#&rE*X=pk~1~t!t(2f-^oX+qkm4{CCt^)+u|p{3?6#`K%py7-RP;_O+rZ z(KW@}E3aO^_f*$)Ld`;l4d!|3frnZj#u*klTw&R0Ab3;qji|Ym{~~V&hRAv03bExD z-J!Qj-50$*r*?nscH_y%`AoOW*=25PTDheyWWNK8X7(C|<&tjf##6!-w*TQg+0as5 ze|N^c>cpqsdxUznp z1H;WcR&L#0(d%2M%`czwTzvDStM4-8IL@%IH~%o@DyMczCt`XiXPc$W&%nbjDRmbX zbpC7!KARn{R248qV6L;u8Fij>&P?vRJVfp=9JsfU>E$kC_g(KM>||0dc)Irby?xbX zUtP9tK6AO`(M^B*`|=h_K{C%km8URhs$@&dp3fOOwl=B7mPbrWT+J6>YhrG1ZEkH{ z`~8$*=QGPSNz4olG8;kjmdi8rZk4u+yUf}at+9KmPIVef$Q}lUhC7>>R-rFJMjiRw zxz2jew%2?=l{M$)ipa zYMJ)>iiD{lhd9h$eb;_!cr7KYxp!XgcV>of+eJOD%kEmT?C*^OFE(#qs9tnkHf&Sz zo{ATLF0Xw0^TO*3f6gDgm@MQ!t904{u1L44yQMaA?Z?dp(pl>bHdwvk$X2!xtjygd z&#>YAT7~kvnewqec6|A9)qU&hz98B4kDtBq=RdzySNn}c z^Q?QEPrin?d#AT<-BPt~;vtuhVL#4Y7Uuf)!{yqiPFvWneRX6{SEmTR?xGy)!XI~#M`E@xxgYY< zdAi1~?&rP3?)>Zd`M<anRo#8Y$ECF9h=z*Go$>eOo3>fzaPnRz z28JhXpmgAW`oUiH#q3%cU80&N?|yuI`RUQ0+l`CQyH{1lshpm@v5S|1q39^r!*$l* zGOo*ZrbcQXy^(Qj*_Jzw;2}$0LPM6B-){#>zv-B>pi;|IATm{5+XJ+Z=}DU?OJnJ- zY^hn&v!bM4Wy>x)@kvPEQX)*iYxS#HQBu;CFf1$i>?1wmX=wT_UrJO z!`yz1*|RrK;3>Jwx!=@gqm;~rX$K~&3g#VLcFpBbzBIUXb|kX+ONR7J=_h{!GV*QA ze`mhSS$*4S`rJK+=KpgpWNKo^?ii%@Ll?!0;`R#dCtotTQ|w(P{I}YUl3XyQ5(7UdN(xyV!_56+714 zI2OHglJoVrv$i{9a@|$m#yY&*FIJ~(e(z%Fac}v>>#W_bZtfIi`;&6aU`cs=Dr&_QLP_)vI#D!WLz^7r#IJ@}>0Jr6C(xwBH;nQH*hj zUN>KB`jvA_L_K)4jMNP_G|5;;_0M->VEDFQlx6nR)vxUSS3G=v@}II&?)nT#&f1E5 zv8h{6hE3SBkNxuI?YB-Pw8qZW6R=I$<-GikMWSzfV)RTUg(emUJ@*MLtCw!s`~TUY z^P9!{w|_cXHcME0mfrrjy0`1o*YFg&c)p&gZXEphtlz0e4Webt$2C4OX08+9Rn67A zz31SMb@K&I917TccAi_xY{nBybBsf;75=+;=+Bb%JJ%dIwPDFBv*X@d-I&vax z*-#j^a8I_*kE};6myazFzpdw(8UNZCimQ|=fR8&8xEPR z%T=4nd@L<}C5MUjD(*WH(}KSn*t}ABE0)rD=#&0FUHd8)h6Y0Iq1^Yolvic!ez(G3 zX<`|-%$g0y=S5EPjNsUN_R8kh{YMM~KPyf3@0@m_qxi3&BhOXwchCNvjkRa^eUVG) z^_mr{zFsq}c%8Lcb?a-sLWaz}2Mo-vMMecG9^|U#snq?F7t#1NJN`&pg4GpIw|j>+ z*8Q#9^k~=powruaD-O`g&$}zxQPOUoL&>wKp^l zMqaIXa^%62JHOrE?#XBuExO3{@=B!8%g|DT-hCH1ltcbEC$UD=uR63*@bK-_FMF4CjVJdXGx`>w+IU zyJ^9KNe5Ga=hcIEUA=PuFVfyLH-q)_K>7J4b6jGo_+W4DS4;-nQFW%`Kws{au27UauJLTdqI;ReZODaZ2xR;zpr3ROR~gQ zPZguq7c$MFWxr=Gvdv{RoqIq?yXUL0cElg0H4F~h+$VTkpF63!R`|31`FOj+0F7E!=c2RwfQVxIM>Z*1=}3v+nSv>Q{Q;#*0i+_axVkd zJb3S4vw=N~LE-kA1BR|s_Z>L&X6rjPw}MIAtXn2cnlwXnmzrHo%{4~Qej>ey#?-fa zuGfG6y1O;w`rOv1>dtrhJR_f+Dg3k0TR+ZE=7B34xQ~6pjC;}CM9sFv$`jZpB)$K{ zboPS|cmk}?c4imuWx5LC3fb@20$!Vh+Ssl>=*C~izo9Aex~$%vQuj+GcRTNMYB%@> z#B6_OBjvur;--6*VTA!AhSYXxj4*biBY@6J;{}i zp1%|+WepSc2rbzBH|_aE@e2E{vXTHj&&Zq86Q4*uSi+T4BUya;{^1WSg3SLq4{^E0 zmdiYS_v+WHTfbIi`R{n$r|^+4yt1@;&*oL96uFid39Z?Xz2fM)&ChLSH}-rznL6R# z$DdE*TRvsoWiVg!e|hRPS9e*NP|1#I8_#`sp%Z@N-S&zrbCqWa+I)JKRdX=>@n5y) z6W0pt?g?2V@LJ6MRDZOI`Pa5QNB#ZR%LrCZdz{$%H>O1ZdVX)ZMiYAP+WFrTlSM>_g*}BA^%lZENE-f%gPSX8-`1>aDdSU9m zUo~xR%lxA^xK8fo{KtGUu|LNZgg+y(-MWw*Qxsk=}Aq$4TnE7rQUUN8G98QTC875mu`I z>T&DBm2QcwJ-Y()L@0asCEZz8XQk znojFWZz}$NZ<}*#rpqhyJ!yB%AGg2MjX3zj=Arn*$H7~gWIhM(4$kn`h_}xSQ}pK$ zdS>!6+2kzK2{ZTI?{@V4voQa^YxTl2=T^DutK2%bb5C=y{4#&jO=ia!wNrXUJ?^vq z-MfF?yOp2v7BOtgV->n_vF&$h`Io&Z_Z;3m>dx(4Y$NE9bZJHk-=fbwM;?F8SN(mD zCo)m}8P~)aLBEPyJ(hTEZMt;2V-90jgXp&PulZ6RYu);-_T1iH@`ctzN!9H-H{Lic z{eEQf(eIP5_j{WhSG+wZHq0P@s`7Jwru(;q`EKkI{c^bQk!Eq$@S|CSx#ES%@2xGtSh*m6Q@`?eF zx7CKuu2Qo)@WSS0>gIfR7;*L|FVA$b6K03G+G5N3 z=2jZ)|M9~m+O=`&)ZOnml+I2!o3r2E{O_-r)thgm9oO0x>pnfg?39`Nu8OwFTo?Uc zT5pn^r@l9*xX@zhpH|K5%VwQS@NN6_^+fbl%_XyV#gtBTa=lGr?UgpUf7@HOV}7NC z&CD#m$n_htw!|IG|8yihD$KyL|D9aC>G3x4%x@`KlV1CX+sx$BmMFcu@`J5%Z27KN znSM&SeQr%|AO&pL6w%18rqTw9Fz7u6cd# zulalN=g;q-JLiA?+3>bDk)AI&1IZh`>Fud*ya=WS8uW`E}%#h3XuYZC3qL{&dH8?!Ee+l_AVy zEx~J5cAHCXsSHQt@4aS%m-Od<`@t4=eaiMQwqrIw!nwY6 zf@W;irmM%D(eZ12W?vJtr+VY;lDivko#y*;Z_d9h0!rDp?R0obuW;=-ahPj&Tg-7K zkJKcM`&;93Rz^9#rs$v0eiqI4tbUf|-5}4xr>4E^t7EVIQCjux%jWrZY`e8GyIMud(x)X{D^-{1 z-QtqB?(n~YBZqtwr{`QKJ$}PE{%-BV&qsFsI`O#TiHcRAWclxl?k!vHHlA6dApTW3 z(5QU2`9b+*_hOe=Qt^2 z_S!9vFWvbw`<>gRQuhZ-g_f`0v}MhwGizTy_{;rN$B=!^1k?G+wf%fN)Wh(e; zA2}!dy>!{);-u~KpWJQqStC%`oV0^CH)TOf@4j;3Bcb<$)1)U_IW0MJ=Udrcwhf2+ zq8(LY%TMvm+hPCRvS4L<$=!{cb)rjOoLcCx77bNy{5S1erQDp?~En=js6aNGaV zJBO2NC;a+;Ogr)L`@2VU6xS)N*6EDsYYds?{9bB9zmmt2*L|C}mREfHd}-^xvXf4` z-mM7z{Di48>{MKN+Nb6G-Ou^F!mO=I(xO>Tew`c0a`Fn-ve@z|HZD#%$2FX$KAF_B z`|pf$_O9w}T4j?Wo~TbfF||?1?9aU`o6lw~-rjk{z2}P2m5n=@yn>qlCb3@ho4Rf8 zF7y3g-h5HqeyQ~MO0C8#o~r(fi}qxQpFVcKW?w0!+R3S6JE?O!Cy({=I_u7f@}{?K ze(Bcy+t>T(x96_E5@qa{Y%^D#7CIi5w&c@Z&WTEsbBYTl-%NYzp*zd}XQ#xJxvL#p z`VZ{e*mS4#`HjmzZ?2Bry2RT!bGNg=iT~HHe4S$%?tVnUa<$*x-#_nuc_}7W+$!@~ zK&+c_LUmYzr1kwP){?(=nCNf6GjaDjoqg56l9xxs)qcBo=yz-D%b!PIz7$_B9jo&T zwDP!N&Iz;0e;CybWFjxgIBFI;&ht#YVqes>=ayvl>_k=u2R*z^IM5kHDT`kFy-`&4 zYY;7)J@?(N$?uFkJa@e~(y{&;JHrVt?T$H5ib6v|cdS08eTvnw$1Fa0io&OJM(Lg_ z8MNPMS>G#7FZN%S_hIGQC`UcJ#?T`SVK=_5vrhUvvvaz!_rjO0{PN;?@h_g7oRp>* zWZJJS&Gq-~rPHrX!`d1}%Zk4q;48m-Q&M|La6d;F!-hkBrFSjM)-2xQqj6??2Roa1 z-7LGSkG2^vnY68W;fzy{%kTd^d|!8elW1A-va+;rUIXL2KMq z#8pjKx-VI!bj#g%PyD-j0o^36@J-#O*Gqmh3s0Q9K%c2W)a=!+V(mMn?I9kE-h>{P zXK$Xa*6e*SdxO)ov!Z3IU;BNETGbhLK~~;m#ok$bOEl9KIf*0+7``}O9;_{(+M;yV z#MaKoj$zG&C9nBXwKMlySleHHth+pO*N!EXFRs3M^78Q2boqVNwmjM?(?!cx?{9kf zeO82H{eiI0T+6~d-sC2vwYEsDc+t&}z`A*z^*ZK%yNk8Y>&t5=W@?Am*1Y-oIBS^2daU2lAf-9!u#3tOk#2>|Vxis>+6)l~7rgd+-MRbo=|RY+HDcdZY z^aAIc;ret$>6%dc9%2XEXh^BWk;8|QZsniHQ9gJBJ|UE4j`S(bAaomP%XpB0`*<*-q=~+EmgmK zfAyNY%OZz8R(hYGwgS3rpEdIN9nE$2MaKkJ`4`PQv~l7S_MFqDOdC%7FDnYl%$&J< z&7rqi+K*d5c(KM6S;dI1D=Mwusp4s~W<&LxitBTG>ee@khL~MHs`&Ndw6EFm86Un| zhg)+8Tbw@^aqx>3%K|h{W<;?|$^j zmrm_&Wer>TR_Nuf;!Qgb1)Zt(zr$^}KTiFrc(BgV6L)V4INn+tc_^>suHpZ4k=wYq57H&rO+fea@*Lf23p78$>rPdF`hh zsvv9g`^C}AjYV4PFSwmbQdmDBx48A~yIsk4;RRn)ZX_^Q-dN+b>sMC&aJz z*eJASf@|1~Z~wSXwiT^!p5n;cqAtIxR4Ki$=W(0w&7e(9YG=0ge$-yf5wvjmJigwJ z)vw;}N&C|8I^o2E_4m#lcdcGj-y`F&X2G2J--U-iGf!9=CZO4+o%`|byx2<1C)!Uv zZ=1G91jW5ux9-c8Eqr$WEC03LKONk|9Co5odqu7IFE&lppKm12?h##dne~%%?owC( zs<41}e}8B0k9fh!-ei=`y7@EngkC|FgK4D|{joFu{mJ_hv;1&U`XSekQ__Pf8_Pms zYqtH#S<$_{NMy}~SivQ4U++r(wpZnXJjeX`laxK8H#;RwpZ6hESboA}bq?jTdbXJn z2ZgFs+T7~{`#$6(v=*>vN(o+anb5N~p{$N!(>bmsul+o`|9`vlsk>M%LVi zZBO6q3D%nt^=PNupMv*)98Vp)yunG#wt36i*z!qFM3vT7oRE~6c>CwssDlf<{dKG- zRoG^hzw}gJe_++dxuKI>S1b=V-_TUK?WRssN=+TZrn4YhBELVjyi~e;*NIat&)J(2 z^w;LTwYwX5IO2^{>;G%d`HO3H_Z;ox5W1nbP5(S-I@9sG?7Ejv9^aflUECzLyv<5- z`R?i`XHOkJ`f}&dnLDrl)fIISjX26ymgQJ_=krR216%@Cf7>cr%3pTc%3@&FDQKHlY*qZPC@2AYxt6-SQu`64x1nm^TFx-0l z@7$-NL4k@Zm(*5%T)tg>mbNDMVbghY=FF9Sxn^6i$;(}bKde}?w^7u|?vFJa!<)Yx zLN9kYPY%nzwa(gIO0)Xu&g#qk>*Y57`TD&z?3UN(IW2pbo^dfW$ec1e9a}ELe%}9l zd!OkPqp54nnS#yR>-T)jX`JF-Wl*;4(lMhAPDWD4!_=-_SDR4G#_)z&yTjzD)!w`2 z>0xoPU#%s*R(;(2V|RVz44Is@>pz&t?==5!K3Uw_V-@3HQ3KHS$=@KyD4UkV^3~Sa z8(w(3}vMh37wmtx@ODbuQ4C~{&~xs3K{`dSkJ(4<2-0~&O~;%j26NAG$o0(mpbsh|$_7}D@9Kqrn-mm@epE;FBO)`nEvW9_yfx*+& K&t;ucLK6U=rNN*8 literal 16168 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 \uicontrol {Find/Replace} > \uicontrol {Find/Replace}. + You can also select \key Ctrl + \key {F}. + You can use a subset of the functions available in the \l{Writing Code}{Edit mode}: