From 42857ce43f4e88bf4fd4022590bbc187ce0030cd Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Tue, 10 May 2022 10:59:47 +0200 Subject: [PATCH 01/35] QtDesignStudio: Fix assets library external drop Fix external drops onto assets library for ubuntu. The file paths were missing the leading slash ("/") which caused external drops to fail. Change-Id: I4c554df2ac4422d935ec06b835ce34de25b9e2e8 Reviewed-by: Mahmoud Badri --- .../itemLibraryQmlSources/Assets.qml | 3 --- .../assetslibrary/assetslibrarywidget.cpp | 22 ++++++++++++------- .../assetslibrary/assetslibrarywidget.h | 4 ++-- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/Assets.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/Assets.qml index 66760b1a24d..a90dfa50f19 100644 --- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/Assets.qml +++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/Assets.qml @@ -59,9 +59,6 @@ Item { var complexSuffixes = rootView.supportedAssetSuffixes(true); for (const u of drag.urls) { var url = u.toString(); - if (url.startsWith("file:///")) // remove file scheme (happens on Windows) - url = url.substr(8) - var ext = '*.' + url.slice(url.lastIndexOf('.') + 1).toLowerCase() if (simpleSuffixes.includes(ext)) root.dropSimpleExtFiles.push(url) diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp index 162fadcf78c..7f7831dfbde 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp @@ -213,26 +213,32 @@ void AssetsLibraryWidget::handleAddAsset() addResources({}); } -void AssetsLibraryWidget::handleExtFilesDrop(const QStringList &simpleFilesPaths, - const QStringList &complexFilesPaths, +void AssetsLibraryWidget::handleExtFilesDrop(const QList &simpleFilePaths, + const QList &complexFilePaths, const QString &targetDirPath) { - if (!simpleFilesPaths.isEmpty()) { + auto toLocalFile = [](const QUrl &url) { return url.toLocalFile(); }; + + QStringList simpleFilePathStrings = Utils::transform(simpleFilePaths, toLocalFile); + QStringList complexFilePathStrings = Utils::transform(complexFilePaths, + toLocalFile); + + if (!simpleFilePathStrings.isEmpty()) { if (targetDirPath.isEmpty()) { - addResources(simpleFilesPaths); + addResources(simpleFilePathStrings); } else { - AddFilesResult result = ModelNodeOperations::addFilesToProject(simpleFilesPaths, + AddFilesResult result = ModelNodeOperations::addFilesToProject(simpleFilePathStrings, targetDirPath); if (result == AddFilesResult::Failed) { Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"), tr("Could not add %1 to project.") - .arg(simpleFilesPaths.join(' '))); + .arg(simpleFilePathStrings.join(' '))); } } } - if (!complexFilesPaths.empty()) - addResources(complexFilesPaths); + if (!complexFilePathStrings.empty()) + addResources(complexFilePathStrings); } QSet AssetsLibraryWidget::supportedAssetSuffixes(bool complex) diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h index 3128b823b3c..125755409e9 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h @@ -79,8 +79,8 @@ public: Q_INVOKABLE void startDragAsset(const QStringList &assetPaths, const QPointF &mousePos); Q_INVOKABLE void handleAddAsset(); Q_INVOKABLE void handleSearchfilterChanged(const QString &filterText); - Q_INVOKABLE void handleExtFilesDrop(const QStringList &simpleFilesPaths, - const QStringList &complexFilesPaths, + Q_INVOKABLE void handleExtFilesDrop(const QList &simpleFilePaths, + const QList &complexFilePaths, const QString &targetDirPath = {}); Q_INVOKABLE QSet supportedAssetSuffixes(bool complex); From 6b781b4fe9ea80b6ff2ccd7333bf8ae82e43d03d Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Tue, 10 May 2022 13:14:14 +0200 Subject: [PATCH 02/35] CMakePM: Fix crash when file system progress bar was cancelled If the user cancelled the file system progress bar, the the m_allFiles will be null and shouldn't be used. Fixes: QTCREATORBUG-27499 Change-Id: I92c509f1e66d0968f921ec103fd81631eed9ab38 Reviewed-by: Eike Ziller --- src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index 99cb43eab40..e89878a6b30 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -702,7 +702,8 @@ void CMakeBuildSystem::updateFileSystemNodes() addCMakeLists(newRoot.get(), std::move(fileNodes)); } - addFileSystemNodes(newRoot.get(), m_allFiles); + if (m_allFiles) + addFileSystemNodes(newRoot.get(), m_allFiles); setRootProjectNode(std::move(newRoot)); m_reader.resetData(); From 57a69d9d0bc6b930faf4955944ab4aaf11d459fd Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 10 May 2022 13:48:38 +0200 Subject: [PATCH 03/35] CMake build: Avoid endless loop if plugin does not exist get_property fails if the target does not exist, and _dep stays at some old value. This leads to a) a lot of cmake backtraces with an error message that doesn't add anything useful, and b) an endless loop in find_dependent_plugins. Which in the end leads to 500.000 lines of useless CMake output, repeating "qtcreator/cmake/QtCreatorAPIInternal.cmake:340 (find_dependent_plugins)" Skip get_property if the target doesn't exist. Change-Id: Ic694bc05b3dce5b83220a2f5dab8f063ef692c12 Reviewed-by: Eike Ziller --- cmake/QtCreatorAPIInternal.cmake | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmake/QtCreatorAPIInternal.cmake b/cmake/QtCreatorAPIInternal.cmake index d7bef93491f..53522ee5f70 100644 --- a/cmake/QtCreatorAPIInternal.cmake +++ b/cmake/QtCreatorAPIInternal.cmake @@ -295,6 +295,10 @@ function(find_dependent_plugins varName) set(_RESULT ${ARGN}) foreach(i ${ARGN}) + if(NOT TARGET ${i}) + continue() + endif() + set(_dep) get_property(_dep TARGET "${i}" PROPERTY _arg_DEPENDS) if (_dep) find_dependent_plugins(_REC ${_dep}) From d4aa9eb0b7a89479673c35558e5d0d5fa1bc2620 Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Tue, 10 May 2022 01:10:22 +0300 Subject: [PATCH 04/35] QmlDesigner: Integrate drag and drop into the model/views system so that any view can easily gets notified when a drag in another view is started/ended. This allows a view to show a highlight when a valid drag is started in another view without coupling the 2 views. Change-Id: I030d3dfe23ee06e2afdc0e4bbffc0b8d0c59f2f8 Reviewed-by: Thomas Hartmann Reviewed-by: Reviewed-by: Miikka Heikkinen Reviewed-by: Samuel Ghinet --- .../itemlibrary/itemlibrarywidget.cpp | 30 ++++++------------- .../components/navigator/navigatorview.cpp | 23 +++++++++++++- .../components/navigator/navigatorview.h | 3 ++ .../designercore/include/abstractview.h | 3 ++ .../qmldesigner/designercore/include/model.h | 3 ++ .../designercore/model/abstractview.cpp | 3 ++ .../qmldesigner/designercore/model/model.cpp | 27 +++++++++++++++++ .../qmldesigner/designercore/model/model_p.h | 3 ++ 8 files changed, 73 insertions(+), 22 deletions(-) diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp index 5f18557d88b..9f6d33e9349 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp @@ -40,7 +40,6 @@ #include "modelnodeoperations.h" #include #include -#include #include #include #include @@ -89,6 +88,9 @@ static QString propertyEditorResourcesPath() bool ItemLibraryWidget::eventFilter(QObject *obj, QEvent *event) { + auto document = QmlDesignerPlugin::instance()->currentDesignDocument(); + Model *model = document ? document->documentModel() : nullptr; + if (event->type() == QEvent::FocusOut) { if (obj == m_itemsWidget.data()) QMetaObject::invokeMethod(m_itemsWidget->rootObject(), "closeContextMenu"); @@ -115,33 +117,19 @@ bool ItemLibraryWidget::eventFilter(QObject *obj, QEvent *event) } } } - QWidget *view = QmlDesignerPlugin::instance()->viewManager().widget("Navigator"); - if (view) { - NavigatorWidget *navView = qobject_cast(view); - if (navView) { - navView->setDragType(entry.typeName()); - navView->update(); - } + + if (model) { + model->startDrag(m_itemLibraryModel->getMimeData(entry), + Utils::StyleHelper::dpiSpecificImageFile(entry.libraryEntryIconPath())); } - auto drag = new QDrag(this); - drag->setPixmap(Utils::StyleHelper::dpiSpecificImageFile(entry.libraryEntryIconPath())); - drag->setMimeData(m_itemLibraryModel->getMimeData(entry)); - drag->exec(); - drag->deleteLater(); m_itemToDrag = {}; } } } else if (event->type() == QMouseEvent::MouseButtonRelease) { m_itemToDrag = {}; - QWidget *view = QmlDesignerPlugin::instance()->viewManager().widget("Navigator"); - if (view) { - NavigatorWidget *navView = qobject_cast(view); - if (navView) { - navView->setDragType(""); - navView->update(); - } - } + if (model) + model->endDrag(); } return QObject::eventFilter(obj, event); diff --git a/src/plugins/qmldesigner/components/navigator/navigatorview.cpp b/src/plugins/qmldesigner/components/navigator/navigatorview.cpp index d9d713b5eb0..8a368c3d2a0 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatorview.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatorview.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -57,8 +58,9 @@ #include #include -#include +#include #include +#include static inline void setScenePos(const QmlDesigner::ModelNode &modelNode,const QPointF &pos) { @@ -264,6 +266,25 @@ void NavigatorView::bindingPropertiesChanged(const QList & prop } } +void NavigatorView::dragStarted(QMimeData *mimeData) +{ + if (mimeData->hasFormat("application/vnd.bauhaus.itemlibraryinfo")) { + QByteArray data = mimeData->data("application/vnd.bauhaus.itemlibraryinfo"); + QDataStream stream(data); + ItemLibraryEntry itemLibraryEntry; + stream >> itemLibraryEntry; + + m_widget->setDragType(itemLibraryEntry.typeName()); + m_widget->update(); + } +} + +void NavigatorView::dragEnded() +{ + m_widget->setDragType(""); + m_widget->update(); +} + void NavigatorView::customNotification(const AbstractView *view, const QString &identifier, const QList &nodeList, const QList &data) { diff --git a/src/plugins/qmldesigner/components/navigator/navigatorview.h b/src/plugins/qmldesigner/components/navigator/navigatorview.h index a8a87c00828..ee29e7691ad 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatorview.h +++ b/src/plugins/qmldesigner/components/navigator/navigatorview.h @@ -92,6 +92,9 @@ public: void bindingPropertiesChanged(const QList &propertyList, PropertyChangeFlags) override; + void dragStarted(QMimeData *mimeData) override; + void dragEnded() override; + void customNotification(const AbstractView *view, const QString &identifier, const QList &nodeList, const QList &data) override; void handleChangedExport(const ModelNode &modelNode, bool exported); diff --git a/src/plugins/qmldesigner/designercore/include/abstractview.h b/src/plugins/qmldesigner/designercore/include/abstractview.h index b303a4fdef7..e37ed0fb4b6 100644 --- a/src/plugins/qmldesigner/designercore/include/abstractview.h +++ b/src/plugins/qmldesigner/designercore/include/abstractview.h @@ -254,6 +254,9 @@ public: virtual void updateImport3DSupport(const QVariantMap &supportMap); virtual void modelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap); + virtual void dragStarted(QMimeData *mimeData); + virtual void dragEnded(); + void changeRootNodeType(const TypeName &type, int majorVersion, int minorVersion); NodeInstanceView *nodeInstanceView() const; diff --git a/src/plugins/qmldesigner/designercore/include/model.h b/src/plugins/qmldesigner/designercore/include/model.h index 48700376b9d..d46fbfe4930 100644 --- a/src/plugins/qmldesigner/designercore/include/model.h +++ b/src/plugins/qmldesigner/designercore/include/model.h @@ -129,6 +129,9 @@ public: QString generateNewId(const QString &prefixName) const; QString generateNewId(const QString &prefixName, const QString &fallbackPrefix) const; + void startDrag(QMimeData *mimeData, const QString iconPath = {}); + void endDrag(); + protected: Model(); diff --git a/src/plugins/qmldesigner/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/designercore/model/abstractview.cpp index 790b6ad5a53..3be9ae3a38c 100644 --- a/src/plugins/qmldesigner/designercore/model/abstractview.cpp +++ b/src/plugins/qmldesigner/designercore/model/abstractview.cpp @@ -398,6 +398,9 @@ void AbstractView::modelNodePreviewPixmapChanged(const ModelNode & /*node*/, con { } +void AbstractView::dragStarted(QMimeData *mimeData) {} +void AbstractView::dragEnded() {} + QList AbstractView::toModelNodeList(const QList &nodeList) const { return QmlDesigner::toModelNodeList(nodeList, const_cast(this)); diff --git a/src/plugins/qmldesigner/designercore/model/model.cpp b/src/plugins/qmldesigner/designercore/model/model.cpp index 64a45e0a894..f4ca504cc50 100644 --- a/src/plugins/qmldesigner/designercore/model/model.cpp +++ b/src/plugins/qmldesigner/designercore/model/model.cpp @@ -67,6 +67,7 @@ #include +#include #include /*! @@ -588,6 +589,16 @@ void ModelPrivate::notifyImport3DSupportChanged(const QVariantMap &supportMap) notifyInstanceChanges([&](AbstractView *view) { view->updateImport3DSupport(supportMap); }); } +void ModelPrivate::notifyDragStarted(QMimeData *mimeData) +{ + notifyInstanceChanges([&](AbstractView *view) { view->dragStarted(mimeData); }); +} + +void ModelPrivate::notifyDragEnded() +{ + notifyInstanceChanges([&](AbstractView *view) { view->dragEnded(); }); +} + void ModelPrivate::notifyRewriterBeginTransaction() { notifyNodeInstanceViewLast([&](AbstractView *view) { view->rewriterBeginTransaction(); }); @@ -1492,6 +1503,22 @@ QString Model::generateNewId(const QString &prefixName, const QString &fallbackP return newId; } +void Model::startDrag(QMimeData *mimeData, const QString iconPath) +{ + d->notifyDragStarted(mimeData); + + auto drag = new QDrag(this); + drag->setPixmap(iconPath); + drag->setMimeData(mimeData); + drag->exec(); + drag->deleteLater(); +} + +void Model::endDrag() +{ + d->notifyDragEnded(); +} + QString Model::generateNewId(const QString &prefixName) const { return generateNewId(prefixName, QStringLiteral("element")); diff --git a/src/plugins/qmldesigner/designercore/model/model_p.h b/src/plugins/qmldesigner/designercore/model/model_p.h index 43a85858092..09595670534 100644 --- a/src/plugins/qmldesigner/designercore/model/model_p.h +++ b/src/plugins/qmldesigner/designercore/model/model_p.h @@ -183,6 +183,9 @@ public: void notifyModelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap); void notifyImport3DSupportChanged(const QVariantMap &supportMap); + void notifyDragStarted(QMimeData *mimeData); + void notifyDragEnded(); + void setDocumentMessages(const QList &errors, const QList &warnings); void notifyRewriterBeginTransaction(); From 666a03284042efebf8640917c09e64cfc68565c6 Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Tue, 10 May 2022 20:31:05 +0300 Subject: [PATCH 05/35] QmlDesigner: Move QDS mime types to constants Also: - Rename libraryresource to asset to match the assets view name. - Replace the outdated "bauhaus" name with "qtdesignstudio". Change-Id: I4cacfdc33c029431b1a7b906439dabc3d9a7ee26 Reviewed-by: Thomas Hartmann --- .../assetslibrary/assetslibrarywidget.cpp | 14 ++++---- .../components/edit3d/edit3dcanvas.cpp | 2 +- .../formeditor/abstractformeditortool.cpp | 18 +++++----- .../components/formeditor/dragtool.cpp | 13 ++++--- .../itemlibrary/itemlibrarymodel.cpp | 5 +-- .../navigator/navigatortreemodel.cpp | 34 +++++++++---------- .../components/navigator/navigatorview.cpp | 4 +-- .../qmldesigner/qmldesignerconstants.h | 10 ++++++ 8 files changed, 55 insertions(+), 45 deletions(-) diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp index 7f7831dfbde..85f7cfc8542 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp @@ -87,7 +87,7 @@ bool AssetsLibraryWidget::eventFilter(QObject *obj, QEvent *event) auto drag = new QDrag(this); drag->setPixmap(m_assetsIconProvider->requestPixmap(m_assetsToDrag[0], nullptr, {128, 128})); QMimeData *mimeData = new QMimeData; - mimeData->setData("application/vnd.bauhaus.libraryresource", m_assetsToDrag.join(',').toUtf8()); + mimeData->setData(Constants::MIME_TYPE_ASSETS, m_assetsToDrag.join(',').toUtf8()); drag->setMimeData(mimeData); drag->exec(); drag->deleteLater(); @@ -307,25 +307,25 @@ QPair AssetsLibraryWidget::getAssetTypeAndData(const QStrin if (!suffix.isEmpty()) { if (AssetsLibraryModel::supportedImageSuffixes().contains(suffix)) { // Data: Image format (suffix) - return {"application/vnd.bauhaus.libraryresource.image", suffix.toUtf8()}; + return {Constants::MIME_TYPE_ASSET_IMAGE, suffix.toUtf8()}; } else if (AssetsLibraryModel::supportedFontSuffixes().contains(suffix)) { // Data: Font family name QRawFont font(assetPath, 10); QString fontFamily = font.isValid() ? font.familyName() : ""; - return {"application/vnd.bauhaus.libraryresource.font", fontFamily.toUtf8()}; + return {Constants::MIME_TYPE_ASSET_FONT, fontFamily.toUtf8()}; } else if (AssetsLibraryModel::supportedShaderSuffixes().contains(suffix)) { // Data: shader type, frament (f) or vertex (v) - return {"application/vnd.bauhaus.libraryresource.shader", + return {Constants::MIME_TYPE_ASSET_SHADER, AssetsLibraryModel::supportedFragmentShaderSuffixes().contains(suffix) ? "f" : "v"}; } else if (AssetsLibraryModel::supportedAudioSuffixes().contains(suffix)) { // No extra data for sounds - return {"application/vnd.bauhaus.libraryresource.sound", {}}; + return {Constants::MIME_TYPE_ASSET_SOUND, {}}; } else if (AssetsLibraryModel::supportedVideoSuffixes().contains(suffix)) { // No extra data for videos - return {"application/vnd.bauhaus.libraryresource.video", {}}; + return {Constants::MIME_TYPE_ASSET_VIDEO, {}}; } else if (AssetsLibraryModel::supportedTexture3DSuffixes().contains(suffix)) { // Data: Image format (suffix) - return {"application/vnd.bauhaus.libraryresource.texture3d", suffix.toUtf8()}; + return {Constants::MIME_TYPE_ASSET_TEXTURE3D, suffix.toUtf8()}; } } return {}; diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp index 65e1b763e59..422ceaab7bb 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp @@ -169,7 +169,7 @@ void Edit3DCanvas::dragEnterEvent(QDragEnterEvent *e) // Allow drop when there is no valid active scene, as the drop goes under the root node of // the document in that case. if (!node.isValid() || !ModelNode::isThisOrAncestorLocked(node)) { - QByteArray data = e->mimeData()->data(QStringLiteral("application/vnd.bauhaus.itemlibraryinfo")); + QByteArray data = e->mimeData()->data(Constants::MIME_TYPE_ITEM_LIBRARY_INFO); if (!data.isEmpty()) { QDataStream stream(data); stream >> m_itemLibraryEntry; diff --git a/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.cpp b/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.cpp index f9d05307aad..d24ff3a35b4 100644 --- a/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.cpp +++ b/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.cpp @@ -24,12 +24,12 @@ ****************************************************************************/ #include "abstractformeditortool.h" +#include "assetslibrarywidget.h" +#include "formeditorscene.h" #include "formeditorview.h" #include "formeditorwidget.h" -#include "formeditorscene.h" -#include "assetslibrarywidget.h" - -#include +#include "modelnodecontextmenu.h" +#include "qmldesignerconstants.h" #include #include @@ -236,20 +236,20 @@ void AbstractFormEditorTool::dropEvent(const QList &/*itemList*/ void AbstractFormEditorTool::dragEnterEvent(const QList &itemList, QGraphicsSceneDragDropEvent *event) { bool hasValidAssets = false; - if (event->mimeData()->hasFormat("application/vnd.bauhaus.libraryresource")) { + if (event->mimeData()->hasFormat(Constants::MIME_TYPE_ASSETS)) { const QStringList assetPaths = QString::fromUtf8(event->mimeData() - ->data("application/vnd.bauhaus.libraryresource")).split(","); + ->data(Constants::MIME_TYPE_ASSETS)).split(','); for (const QString &assetPath : assetPaths) { QString assetType = AssetsLibraryWidget::getAssetTypeAndData(assetPath).first; - if (assetType == "application/vnd.bauhaus.libraryresource.image" - || assetType == "application/vnd.bauhaus.libraryresource.font") { + if (assetType == Constants::MIME_TYPE_ASSET_IMAGE + || assetType == Constants::MIME_TYPE_ASSET_FONT) { hasValidAssets = true; break; } } } - if (event->mimeData()->hasFormat(QLatin1String("application/vnd.bauhaus.itemlibraryinfo")) || hasValidAssets) { + if (event->mimeData()->hasFormat(Constants::MIME_TYPE_ITEM_LIBRARY_INFO) || hasValidAssets) { event->accept(); view()->changeToDragTool(); view()->currentTool()->dragEnterEvent(itemList, event); diff --git a/src/plugins/qmldesigner/components/formeditor/dragtool.cpp b/src/plugins/qmldesigner/components/formeditor/dragtool.cpp index b3650aaae0d..f01500b6d46 100644 --- a/src/plugins/qmldesigner/components/formeditor/dragtool.cpp +++ b/src/plugins/qmldesigner/components/formeditor/dragtool.cpp @@ -31,6 +31,7 @@ #include #include #include +#include "qmldesignerconstants.h" #include #include @@ -219,9 +220,7 @@ void DragTool::abort() static ItemLibraryEntry itemLibraryEntryFromMimeData(const QMimeData *mimeData) { - QByteArray data = mimeData->data(QStringLiteral("application/vnd.bauhaus.itemlibraryinfo")); - - QDataStream stream(data); + QDataStream stream(mimeData->data(Constants::MIME_TYPE_ITEM_LIBRARY_INFO)); ItemLibraryEntry itemLibraryEntry; stream >> itemLibraryEntry; @@ -236,7 +235,7 @@ static bool canBeDropped(const QMimeData *mimeData) static bool hasItemLibraryInfo(const QMimeData *mimeData) { - return mimeData->hasFormat(QStringLiteral("application/vnd.bauhaus.itemlibraryinfo")); + return mimeData->hasFormat(Constants::MIME_TYPE_ITEM_LIBRARY_INFO); } void DragTool::dropEvent(const QList &/*itemList*/, QGraphicsSceneDragDropEvent *event) @@ -326,12 +325,12 @@ void DragTool::createDragNodes(const QMimeData *mimeData, const QPointF &scenePo scenePosition); } else { const QStringList assetPaths = QString::fromUtf8(mimeData - ->data("application/vnd.bauhaus.libraryresource")).split(","); + ->data(Constants::MIME_TYPE_ASSETS)).split(','); for (const QString &assetPath : assetPaths) { QString assetType = AssetsLibraryWidget::getAssetTypeAndData(assetPath).first; - if (assetType == "application/vnd.bauhaus.libraryresource.image") + if (assetType == Constants::MIME_TYPE_ASSET_IMAGE) createQmlItemNodeFromImage(assetPath, targetContainerQmlItemNode, scenePosition); - else if (assetType == "application/vnd.bauhaus.libraryresource.font") + else if (assetType == Constants::MIME_TYPE_ASSET_FONT) createQmlItemNodeFromFont(assetPath, targetContainerQmlItemNode, scenePosition); } diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp index e1d078306ce..76795d2817e 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp @@ -36,6 +36,7 @@ #include #include #include +#include "qmldesignerconstants.h" #include "qmldesignerplugin.h" #include #include @@ -512,9 +513,9 @@ QMimeData *ItemLibraryModel::getMimeData(const ItemLibraryEntry &itemLibraryEntr QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); stream << itemLibraryEntry; - mimeData->setData(QStringLiteral("application/vnd.bauhaus.itemlibraryinfo"), data); + mimeData->setData(Constants::MIME_TYPE_ITEM_LIBRARY_INFO, data); - mimeData->removeFormat(QStringLiteral("text/plain")); + mimeData->removeFormat("text/plain"); return mimeData; } diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp index 5f4ae027441..de4d7de88aa 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp @@ -71,7 +71,7 @@ namespace QmlDesigner { static QList modelNodesFromMimeData(const QMimeData *mineData, AbstractView *view) { - QByteArray encodedModelNodeData = mineData->data(QLatin1String("application/vnd.modelnode.list")); + QByteArray encodedModelNodeData = mineData->data(Constants::MIME_TYPE_MODELNODE_LIST); QDataStream modelNodeStream(&encodedModelNodeData, QIODevice::ReadOnly); QList modelNodeList; @@ -465,9 +465,9 @@ void NavigatorTreeModel::setView(NavigatorView *view) QStringList NavigatorTreeModel::mimeTypes() const { - const static QStringList types({"application/vnd.modelnode.list", - "application/vnd.bauhaus.itemlibraryinfo", - "application/vnd.bauhaus.libraryresource"}); + const static QStringList types({Constants::MIME_TYPE_MODELNODE_LIST, + Constants::MIME_TYPE_ITEM_LIBRARY_INFO, + Constants::MIME_TYPE_ASSETS}); return types; } @@ -490,7 +490,7 @@ QMimeData *NavigatorTreeModel::mimeData(const QModelIndexList &modelIndexList) c } } - mimeData->setData("application/vnd.modelnode.list", encodedModelNodeData); + mimeData->setData(Constants::MIME_TYPE_MODELNODE_LIST, encodedModelNodeData); return mimeData; } @@ -560,10 +560,10 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData, widget->setDragType(""); if (dropModelIndex.model() == this) { - if (mimeData->hasFormat("application/vnd.bauhaus.itemlibraryinfo")) { + if (mimeData->hasFormat(Constants::MIME_TYPE_ITEM_LIBRARY_INFO)) { handleItemLibraryItemDrop(mimeData, rowNumber, dropModelIndex); - } else if (mimeData->hasFormat("application/vnd.bauhaus.libraryresource")) { - const QStringList assetsPaths = QString::fromUtf8(mimeData->data("application/vnd.bauhaus.libraryresource")).split(","); + } else if (mimeData->hasFormat(Constants::MIME_TYPE_ASSETS)) { + const QStringList assetsPaths = QString::fromUtf8(mimeData->data(Constants::MIME_TYPE_ASSETS)).split(','); NodeAbstractProperty targetProperty; const QModelIndex rowModelIndex = dropModelIndex.sibling(dropModelIndex.row(), 0); @@ -579,9 +579,9 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData, QSet neededImports; for (const QString &assetPath : assetsPaths) { QString assetType = AssetsLibraryWidget::getAssetTypeAndData(assetPath).first; - if (assetType == "application/vnd.bauhaus.libraryresource.shader") + if (assetType == Constants::MIME_TYPE_ASSET_SHADER) neededImports.insert("QtQuick3D"); - else if (assetType == "application/vnd.bauhaus.libraryresource.sound") + else if (assetType == Constants::MIME_TYPE_ASSET_SOUND) neededImports.insert("QtMultimedia"); if (neededImports.size() == 2) @@ -598,20 +598,20 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData, auto assetTypeAndData = AssetsLibraryWidget::getAssetTypeAndData(assetPath); QString assetType = assetTypeAndData.first; QString assetData = QString::fromUtf8(assetTypeAndData.second); - if (assetType == "application/vnd.bauhaus.libraryresource.image") { + if (assetType == Constants::MIME_TYPE_ASSET_IMAGE) { currNode = handleItemLibraryImageDrop(assetPath, targetProperty, rowModelIndex, moveNodesAfter); - } else if (assetType == "application/vnd.bauhaus.libraryresource.font") { + } else if (assetType == Constants::MIME_TYPE_ASSET_FONT) { currNode = handleItemLibraryFontDrop(assetData, // assetData is fontFamily targetProperty, rowModelIndex); - } else if (assetType == "application/vnd.bauhaus.libraryresource.shader") { + } else if (assetType == Constants::MIME_TYPE_ASSET_SHADER) { currNode = handleItemLibraryShaderDrop(assetPath, assetData == "f", targetProperty, rowModelIndex, moveNodesAfter); - } else if (assetType == "application/vnd.bauhaus.libraryresource.sound") { + } else if (assetType == Constants::MIME_TYPE_ASSET_SOUND) { currNode = handleItemLibrarySoundDrop(assetPath, targetProperty, rowModelIndex); - } else if (assetType == "application/vnd.bauhaus.libraryresource.texture3d") { + } else if (assetType == Constants::MIME_TYPE_ASSET_TEXTURE3D) { currNode = handleItemLibraryTexture3dDrop(assetPath, targetProperty, rowModelIndex, moveNodesAfter); } @@ -627,7 +627,7 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData, m_view->setSelectedModelNodes(addedNodes); } } - } else if (mimeData->hasFormat("application/vnd.modelnode.list")) { + } else if (mimeData->hasFormat(Constants::MIME_TYPE_MODELNODE_LIST)) { handleInternalDrop(mimeData, rowNumber, dropModelIndex); } } @@ -673,7 +673,7 @@ void NavigatorTreeModel::handleItemLibraryItemDrop(const QMimeData *mimeData, in NodeAbstractProperty targetProperty; const ItemLibraryEntry itemLibraryEntry = - createItemLibraryEntryFromMimeData(mimeData->data("application/vnd.bauhaus.itemlibraryinfo")); + createItemLibraryEntryFromMimeData(mimeData->data(Constants::MIME_TYPE_ITEM_LIBRARY_INFO)); const NodeHints hints = NodeHints::fromItemLibraryEntry(itemLibraryEntry); diff --git a/src/plugins/qmldesigner/components/navigator/navigatorview.cpp b/src/plugins/qmldesigner/components/navigator/navigatorview.cpp index 8a368c3d2a0..495982c6fc1 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatorview.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatorview.cpp @@ -268,8 +268,8 @@ void NavigatorView::bindingPropertiesChanged(const QList & prop void NavigatorView::dragStarted(QMimeData *mimeData) { - if (mimeData->hasFormat("application/vnd.bauhaus.itemlibraryinfo")) { - QByteArray data = mimeData->data("application/vnd.bauhaus.itemlibraryinfo"); + if (mimeData->hasFormat(Constants::MIME_TYPE_ITEM_LIBRARY_INFO)) { + QByteArray data = mimeData->data(Constants::MIME_TYPE_ITEM_LIBRARY_INFO); QDataStream stream(data); ItemLibraryEntry itemLibraryEntry; stream >> itemLibraryEntry; diff --git a/src/plugins/qmldesigner/qmldesignerconstants.h b/src/plugins/qmldesigner/qmldesignerconstants.h index 81b9d8a4a7a..a5c7bbf33de 100644 --- a/src/plugins/qmldesigner/qmldesignerconstants.h +++ b/src/plugins/qmldesigner/qmldesignerconstants.h @@ -85,6 +85,16 @@ const char QUICK_3D_ASSET_IMPORT_DATA_OPTIONS_KEY[] = "import_options"; const char QUICK_3D_ASSET_IMPORT_DATA_SOURCE_KEY[] = "source_scene"; const char DEFAULT_ASSET_IMPORT_FOLDER[] = "/asset_imports"; +const char MIME_TYPE_ITEM_LIBRARY_INFO[] = "application/vnd.qtdesignstudio.itemlibraryinfo"; +const char MIME_TYPE_ASSETS[] = "application/vnd.qtdesignstudio.assets"; +const char MIME_TYPE_ASSET_IMAGE[] = "application/vnd.qtdesignstudio.asset.image"; +const char MIME_TYPE_ASSET_FONT[] = "application/vnd.qtdesignstudio.asset.font"; +const char MIME_TYPE_ASSET_SHADER[] = "application/vnd.qtdesignstudio.asset.shader"; +const char MIME_TYPE_ASSET_SOUND[] = "application/vnd.qtdesignstudio.asset.sound"; +const char MIME_TYPE_ASSET_VIDEO[] = "application/vnd.qtdesignstudio.asset.video"; +const char MIME_TYPE_ASSET_TEXTURE3D[] = "application/vnd.qtdesignstudio.asset.texture3d"; +const char MIME_TYPE_MODELNODE_LIST[] = "application/vnd.qtdesignstudio.modelnode.list"; + // Menus const char M_VIEW_WORKSPACES[] = "QmlDesigner.Menu.View.Workspaces"; From e33923ccd55b4fb77fdda1ab7a1e773980134a25 Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Wed, 11 May 2022 10:02:05 +0200 Subject: [PATCH 06/35] QmlDesigner: Fix compilation Change-Id: I683ec452e8346486dd3c55fd27832245279404a5 Reviewed-by: Mahmoud Badri --- .../qmldesigner/components/navigator/navigatortreemodel.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp index de4d7de88aa..138a4aad844 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp @@ -27,6 +27,7 @@ #include "navigatorview.h" #include "navigatorwidget.h" #include "choosefrompropertylistdialog.h" +#include "qmldesignerconstants.h" #include "qmldesignerplugin.h" #include "assetslibrarywidget.h" From 9d5512b1374998d2928d14e14257253dfa9a0d26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20L=C3=B6hning?= Date: Mon, 9 May 2022 21:30:51 +0200 Subject: [PATCH 07/35] Squish: Retire Qt4 It can't be built with current compilers anymore and there are no more binary packages publicly available. Change-Id: I906789bbcca053690f39246ff7c3e602703ada37 Reviewed-by: Christian Stenger Reviewed-by: --- tests/system/README | 30 ++--------- .../mac/QtProject/qtcreator/profiles.xml | 54 +------------------ .../mac/QtProject/qtcreator/qtversion.xml | 12 +---- .../unix/QtProject/qtcreator/profiles.xml | 52 ++---------------- .../unix/QtProject/qtcreator/qtversion.xml | 14 +---- .../windows/QtProject/qtcreator/profiles.xml | 34 ++---------- .../windows/QtProject/qtcreator/qtversion.xml | 14 +---- tests/system/shared/build_utils.py | 28 +++++----- tests/system/shared/classes.py | 20 ++----- tests/system/shared/project.py | 23 ++------ tests/system/shared/qtcreator.py | 6 --- tests/system/suite_CCOM/tst_CCOM01/test.py | 1 - .../suite_editors/tst_memberoperator/test.py | 1 - 13 files changed, 39 insertions(+), 250 deletions(-) diff --git a/tests/system/README b/tests/system/README index 9e1a5d4264a..e7775af3a84 100644 --- a/tests/system/README +++ b/tests/system/README @@ -4,29 +4,7 @@ Squish tests inside this folder have several prerequisites to get them running. First - and most important - you have to own a valid Squish license. At least Squish 6.0 is required. -Second - some of the test suites/test cases expect a build of Qt 4.8.7 to be available: -[ this is optional and if Qt4 is not available some Qt5 will be tried to use instead ] - 1. Download the source code from: - * Windows: https://download.qt.io/archive/qt/4.8/4.8.7/qt-everywhere-opensource-src-4.8.7.zip - * Other: https://download.qt.io/archive/qt/4.8/4.8.7/qt-everywhere-opensource-src-4.8.7.tar.gz - 2. Extract the contents of the archive's directory qt-everywhere-opensource-src-4.8.7 to: - * Windows: C:\Qt\Qt4.8.7 - * Other: $HOME/Qt4.8.7 - 3. Apply the changes from patch.txt next to this README. - 4. In the directory you extracted the sources to, configure Qt: - * Windows (MSVC2013 32 bit): - .\configure.exe -opensource -developer-build -confirm-license -debug-and-release -nomake tests -nomake examples -nomake demos -no-webkit -no-phonon - * Linux (gcc < 6): - ./configure -opensource -developer-build -confirm-license -debug-and-release -nomake tests -nomake examples -nomake demos -no-webkit -no-phonon - * macOS: - ./configure -opensource -developer-build -confirm-license -debug-and-release -nomake tests -nomake examples -nomake demos -no-webkit -no-phonon -sdk - 5. Make: - * Windows (do not use jom): - nmake - * Other: - make -j - -Third - some of the test suites/test cases expect Qt versions to be installed in their default +Second - some of the test suites/test cases expect Qt versions to be installed in their default locations. On Linux/macOS this is ~/Qt5.x.1 and on Windows this is C:\Qt\Qt5.x.1. It's easiest to use installations of the official opensource Qt packages. Just install the Qt version for the respective toolchain with the components (if available): @@ -50,7 +28,7 @@ Qt 5.4.1 (gcc) Qt 5.10.1 (MSVC2015, 32 bit) Qt 5.14.1 (MSVC2017, 64 bit) -Fourth - you'll have to provide some additional repositories. +Third - you'll have to provide some additional repositories. These additional repositories are located inside ~/squish-data or C:\Users\\squish-data (depending on the OS you're on). You can also just provide them inside a different folder and specify the folder with the environment variable SYSTEST_SRCPATH. This folder must contain the following: @@ -58,12 +36,12 @@ This folder must contain the following: * a subfolder called 'creator-test-data' * a speedcrunch 0.11 repository (or source copy) inside 'creator-test-data' named 'speedcrunch' -Fifth - you'll have to make sure that some needed tools are available (no matter on which OS you're on). +Fourth - you'll have to make sure that some needed tools are available (no matter on which OS you're on). * cmake 3.14 or newer * wget or curl, capable of HTTPS Normally it should be okay to just install them as usual and add their executables' path(s) to the PATH variable. -Sixth - Qt Creator must be built on a Qt without Qt WebEngine or Qt WebKit. +Fifth - Qt Creator must be built on a Qt without Qt WebEngine or Qt WebKit. On macOS make sure you are using the correct keyboard layout to avoid problems when using keyboard interaction. Tested and known to be working would be 'U.S. International - PC', while pure 'U.S.' had problems. diff --git a/tests/system/settings/mac/QtProject/qtcreator/profiles.xml b/tests/system/settings/mac/QtProject/qtcreator/profiles.xml index cf36fa263fc..51024f82880 100644 --- a/tests/system/settings/mac/QtProject/qtcreator/profiles.xml +++ b/tests/system/settings/mac/QtProject/qtcreator/profiles.xml @@ -4,31 +4,6 @@ Profile.0 - - false - - - {70e26273-2c0b-4534-bbc0-eb6ca670821a} - {7c5a3673-e300-4286-9666-0f86d3e3dc38} - GenericLinuxOsType - - ProjectExplorer.ToolChain.Gcc:{c3f59b87-6997-4bd8-8067-ee04dc536371} - - {461bb8dc-22ff-461f-82fe-ebe8b21b697f} - ProjectExplorer.ToolChain.Gcc:{c3f59b87-6997-4bd8-8067-ee04dc536371} - - - 2 - - :///DESKTOP/// - {f16848fc-b615-43b5-b0cc-16a9f57fb573} - - Embedded Linux - false - - - - Profile.1 false @@ -55,32 +30,7 @@ - Profile.2 - - false - - - {2f514661-b9f7-4f83-8822-a9a9d0699600} - Desktop Device - Desktop - - ProjectExplorer.ToolChain.Gcc:{c3f59b87-6997-4bd8-8067-ee04dc536371} - - {461bb8dc-22ff-461f-82fe-ebe8b21b697f} - ProjectExplorer.ToolChain.Gcc:{c3f59b87-6997-4bd8-8067-ee04dc536371} - - - 2 - - :///DESKTOP/// - {1dcb5509-1670-470d-80a5-8a988f36e4e2} - - Desktop 4.8.7 default - false - - - - Profile.3 + Profile.1 false @@ -108,7 +58,7 @@ Profile.Count - 4 + 2 Profile.Default diff --git a/tests/system/settings/mac/QtProject/qtcreator/qtversion.xml b/tests/system/settings/mac/QtProject/qtcreator/qtversion.xml index 6521f404a1a..340cbe918ea 100644 --- a/tests/system/settings/mac/QtProject/qtcreator/qtversion.xml +++ b/tests/system/settings/mac/QtProject/qtcreator/qtversion.xml @@ -4,16 +4,6 @@ QtVersion.0 - - 2 - Desktop Qt 4.8 for GCC - ~/Qt4.8.7/bin/qmake - Qt4ProjectManager.QtVersion.Desktop - false - - - - QtVersion.1 9 Qt %{Qt:Version} (SQUISH_DEFAULT_COMPILER) @@ -23,7 +13,7 @@ - QtVersion.2 + QtVersion.1 11 Qt %{Qt:Version} (SQUISH_DEFAULT_COMPILER) diff --git a/tests/system/settings/unix/QtProject/qtcreator/profiles.xml b/tests/system/settings/unix/QtProject/qtcreator/profiles.xml index 81f328703d3..54076fa5e1b 100644 --- a/tests/system/settings/unix/QtProject/qtcreator/profiles.xml +++ b/tests/system/settings/unix/QtProject/qtcreator/profiles.xml @@ -4,52 +4,6 @@ Profile.0 - - false - - - {70e26273-2c0b-4534-bbc0-eb6ca670821a} - {7c5a3673-e300-4286-9666-0f86d3e3dc38} - GenericLinuxOsType - - ProjectExplorer.ToolChain.Gcc:{c3f59b87-6997-4bd8-8067-ee04dc536371} - - {7bfd4fd4-e64a-417f-b10f-20602e1719d1} - ProjectExplorer.ToolChain.Gcc:{c3f59b87-6997-4bd8-8067-ee04dc536371} - - - 2 - - :///DESKTOP/// - {f16848fc-b615-43b5-b0cc-16a9f57fb573} - - Embedded Linux - false - - - - Profile.1 - - false - - - {70e26273-2c0b-4534-bbc0-eb6ca670821a} - Desktop Device - Desktop - - ProjectExplorer.ToolChain.Gcc:{c3f59b87-6997-4bd8-8067-ee04dc536371} - - 2 - - :///DESKTOP/// - {1dcb5509-1670-470d-80a5-8a988f36e4e2} - - Desktop 4.8.7 default - false - - - - Profile.2 false @@ -73,7 +27,7 @@ - Profile.3 + Profile.1 false @@ -97,7 +51,7 @@ - Profile.4 + Profile.2 false @@ -126,7 +80,7 @@ Profile.Count - 5 + 3 Profile.Default diff --git a/tests/system/settings/unix/QtProject/qtcreator/qtversion.xml b/tests/system/settings/unix/QtProject/qtcreator/qtversion.xml index cb208914864..829b5c07edb 100644 --- a/tests/system/settings/unix/QtProject/qtcreator/qtversion.xml +++ b/tests/system/settings/unix/QtProject/qtcreator/qtversion.xml @@ -4,16 +4,6 @@ QtVersion.0 - - 2 - Desktop Qt 4.8 for GCC - ~/Qt4.8.7/bin/qmake - Qt4ProjectManager.QtVersion.Desktop - false - - - - QtVersion.1 13 Qt %{Qt:Version} (SQUISH_DEFAULT_COMPILER) @@ -23,7 +13,7 @@ - QtVersion.2 + QtVersion.1 15 Qt %{Qt:Version} (SQUISH_DEFAULT_COMPILER) @@ -33,7 +23,7 @@ - QtVersion.3 + QtVersion.2 17 Qt %{Qt:Version} (SQUISH_DEFAULT_COMPILER) diff --git a/tests/system/settings/windows/QtProject/qtcreator/profiles.xml b/tests/system/settings/windows/QtProject/qtcreator/profiles.xml index fab39649776..56ed350666f 100644 --- a/tests/system/settings/windows/QtProject/qtcreator/profiles.xml +++ b/tests/system/settings/windows/QtProject/qtcreator/profiles.xml @@ -4,34 +4,6 @@ Profile.0 - - false - - - - {1b25f20a-d584-4fb7-85b3-74dd15b82f6f} - Desktop Device - Desktop - - - {7ca0887f-a9a5-4251-aba6-560a15595d20} - - {d35e7a1a-5ab8-4fd6-8a2c-634846c669bb} - {7ca0887f-a9a5-4251-aba6-560a15595d20} - - - 2 - - :///DESKTOP/// - {9b35bbe6-25a7-4cce-ba07-487c795f5265} - - Desktop 4.8.7 default - false - - - - - Profile.1 false @@ -59,7 +31,7 @@ - Profile.2 + Profile.1 false @@ -87,7 +59,7 @@ - Profile.3 + Profile.2 false @@ -116,7 +88,7 @@ Profile.Count - 4 + 3 Profile.Default diff --git a/tests/system/settings/windows/QtProject/qtcreator/qtversion.xml b/tests/system/settings/windows/QtProject/qtcreator/qtversion.xml index 2939316b75f..499c44893f7 100644 --- a/tests/system/settings/windows/QtProject/qtcreator/qtversion.xml +++ b/tests/system/settings/windows/QtProject/qtcreator/qtversion.xml @@ -4,16 +4,6 @@ QtVersion.0 - - 2 - Qt 4.8 for Desktop - MSVC2013 - C:/Qt/Qt4.8.7/bin/qmake.exe - Qt4ProjectManager.QtVersion.Desktop - false - - - - QtVersion.1 22 Qt %{Qt:Version} (mingw491_32) @@ -23,7 +13,7 @@ - QtVersion.2 + QtVersion.1 24 Qt %{Qt:Version} (msvc2017_64) @@ -33,7 +23,7 @@ - QtVersion.3 + QtVersion.2 26 Qt %{Qt:Version} (msvc2015) diff --git a/tests/system/shared/build_utils.py b/tests/system/shared/build_utils.py index a58a1fa93d7..b90561fedf6 100644 --- a/tests/system/shared/build_utils.py +++ b/tests/system/shared/build_utils.py @@ -190,13 +190,12 @@ def verifyBuildConfig(currentTarget, configName, shouldBeDebug=False, enableShad # it will wait here until compilation of the debug libraries has finished. runCMakeButton = ("{type='QPushButton' text='Run CMake' unnamed='1' " "window=':Qt Creator_Core::Internal::MainWindow'}") - if currentTarget not in (Targets.DESKTOP_4_8_7_DEFAULT, Targets.EMBEDDED_LINUX): - qmlDebuggingCombo = findObject(':Qt Creator.QML debugging and profiling:_QComboBox') - if selectFromCombo(qmlDebuggingCombo, 'Enable'): - if buildSystem is None or buildSystem == "CMake": # re-run cmake to apply - clickButton(waitForObject(runCMakeButton)) - elif buildSystem == "qmake": # Don't rebuild now - clickButton(waitForObject(":QML Debugging.No_QPushButton", 5000)) + qmlDebuggingCombo = findObject(':Qt Creator.QML debugging and profiling:_QComboBox') + if selectFromCombo(qmlDebuggingCombo, 'Enable'): + if buildSystem is None or buildSystem == "CMake": # re-run cmake to apply + clickButton(waitForObject(runCMakeButton)) + elif buildSystem == "qmake": # Don't rebuild now + clickButton(waitForObject(":QML Debugging.No_QPushButton", 5000)) try: problemFound = waitForObject("{window=':Qt Creator_Core::Internal::MainWindow' " "type='QLabel' name='problemLabel' visible='1'}", 1000) @@ -205,14 +204,13 @@ def verifyBuildConfig(currentTarget, configName, shouldBeDebug=False, enableShad except: pass else: - if currentTarget not in (Targets.DESKTOP_4_8_7_DEFAULT, Targets.EMBEDDED_LINUX): - qmlDebuggingCombo = findObject(':Qt Creator.QML debugging and profiling:_QComboBox') - if selectFromCombo(qmlDebuggingCombo, "Disable"): - test.log("Qml debugging libraries are available - unchecked qml debugging.") - if buildSystem is None or buildSystem == "CMake": # re-run cmake to apply - clickButton(waitForObject(runCMakeButton)) - elif buildSystem == "qmake": # Don't rebuild now - clickButton(waitForObject(":QML Debugging.No_QPushButton", 5000)) + qmlDebuggingCombo = findObject(':Qt Creator.QML debugging and profiling:_QComboBox') + if selectFromCombo(qmlDebuggingCombo, "Disable"): + test.log("Qml debugging libraries are available - unchecked qml debugging.") + if buildSystem is None or buildSystem == "CMake": # re-run cmake to apply + clickButton(waitForObject(runCMakeButton)) + elif buildSystem == "qmake": # Don't rebuild now + clickButton(waitForObject(":QML Debugging.No_QPushButton", 5000)) clickButton(waitForObject(":scrollArea.Details_Utils::DetailsButton")) switchViewTo(ViewConstants.EDIT) diff --git a/tests/system/shared/classes.py b/tests/system/shared/classes.py index efe60daa701..9ee95e2de48 100644 --- a/tests/system/shared/classes.py +++ b/tests/system/shared/classes.py @@ -30,37 +30,27 @@ except ImportError: # for easier re-usage (because Python hasn't an enum type) class Targets: - ALL_TARGETS = tuple(range(5)) + ALL_TARGETS = tuple(range(3)) - (DESKTOP_4_8_7_DEFAULT, - EMBEDDED_LINUX, - DESKTOP_5_4_1_GCC, + (DESKTOP_5_4_1_GCC, DESKTOP_5_10_1_DEFAULT, DESKTOP_5_14_1_DEFAULT) = ALL_TARGETS __TARGET_NAME_DICT__ = dict(zip(ALL_TARGETS, - ["Desktop 4.8.7 default", - "Embedded Linux", - "Desktop 5.4.1 GCC", + ["Desktop 5.4.1 GCC", "Desktop 5.10.1 default", "Desktop 5.14.1 default"])) @staticmethod def availableTargetClasses(ignoreValidity=False): availableTargets = set(Targets.ALL_TARGETS) - if not qt4Available and not ignoreValidity: - availableTargets.remove(Targets.DESKTOP_4_8_7_DEFAULT) - if not (qt4Available or ignoreValidity) or platform.system() in ('Windows', 'Microsoft'): - availableTargets.remove(Targets.EMBEDDED_LINUX) - elif platform.system() == 'Darwin': + if platform.system() == 'Darwin': availableTargets.remove(Targets.DESKTOP_5_4_1_GCC) return availableTargets @staticmethod def desktopTargetClasses(): - desktopTargets = Targets.availableTargetClasses() - desktopTargets.discard(Targets.EMBEDDED_LINUX) - return desktopTargets + return Targets.availableTargetClasses() @staticmethod def getStringForTarget(target): diff --git a/tests/system/shared/project.py b/tests/system/shared/project.py index 4774bca9a5b..17d0580d016 100644 --- a/tests/system/shared/project.py +++ b/tests/system/shared/project.py @@ -161,11 +161,8 @@ def __createProjectHandleQtQuickSelection__(minimumQtVersion): # param buildSystem is a string holding the build system selected for the project # param checks turns tests in the function on if set to True # param available a list holding the available targets -# withoutQt4 if True Qt4 will get unchecked / not selected while checking the targets -def __selectQtVersionDesktop__(buildSystem, checks, available=None, withoutQt4=False): +def __selectQtVersionDesktop__(buildSystem, checks, available=None): wanted = Targets.desktopTargetClasses() - if withoutQt4: - wanted.discard(Targets.DESKTOP_4_8_7_DEFAULT) checkedTargets = __chooseTargets__(wanted, available) if checks: for target in checkedTargets: @@ -183,9 +180,8 @@ def __selectQtVersionDesktop__(buildSystem, checks, available=None, withoutQt4=F objectMap.realName(detailsWidget))) verifyChecked(cbObject % ("Minimum Size Release", objectMap.realName(detailsWidget))) - elif (buildSystem == "qmake" - and target not in (Targets.DESKTOP_4_8_7_DEFAULT, Targets.EMBEDDED_LINUX)): - verifyChecked(cbObject % ("Profile", objectMap.realName(detailsWidget))) + elif buildSystem == "qmake": + verifyChecked(cbObject % ("Profile", objectMap.realName(detailsWidget))) clickButton(detailsButton) clickButton(waitForObject(":Next_QPushButton")) @@ -207,11 +203,6 @@ def __verifyFileCreation__(path, expectedFiles): def __modifyAvailableTargets__(available, requiredQt, asStrings=False): versionFinder = re.compile("^Desktop (\\d{1}\.\\d{1,2}\.\\d{1,2}).*$") tmp = list(available) # we need a deep copy - if Qt5Path.toVersionTuple(requiredQt) > (4,8,7) and qt4Available: - toBeRemoved = Targets.EMBEDDED_LINUX - if asStrings: - toBeRemoved = Targets.getStringForTarget(toBeRemoved) - available.discard(toBeRemoved) for currentItem in tmp: if asStrings: item = currentItem @@ -260,7 +251,7 @@ def createProject_Qt_GUI(path, projectName, checks=True, addToVersionControl=" Date: Thu, 12 May 2022 11:10:19 +0200 Subject: [PATCH 08/35] StudioWelcome: Add import path for dataImports This will be the im[port path for the data driving tutorials and examples. Change-Id: I358de354565e9670fefeb7a4194af4aec5182184 Reviewed-by: Thomas Hartmann --- src/plugins/studiowelcome/studiowelcomeplugin.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/studiowelcome/studiowelcomeplugin.cpp b/src/plugins/studiowelcome/studiowelcomeplugin.cpp index 0637f04ef75..17c37fccf39 100644 --- a/src/plugins/studiowelcome/studiowelcomeplugin.cpp +++ b/src/plugins/studiowelcome/studiowelcomeplugin.cpp @@ -693,6 +693,7 @@ WelcomeMode::WelcomeMode() const QString welcomePagePath = Core::ICore::resourcePath("qmldesigner/welcomepage").toString(); m_modeWidget->engine()->addImportPath(welcomePagePath + "/imports"); + m_modeWidget->engine()->addImportPath(welcomePagePath + "/dataImports"); m_modeWidget->setSource(QUrl::fromLocalFile(welcomePagePath + "/main.qml")); QShortcut *updateShortcut = nullptr; From bf3c3b624ac0d7c3386cd93418971a43e203bd27 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Wed, 11 May 2022 21:43:26 +0200 Subject: [PATCH 09/35] QmlDesigner: Fix 3D formeditor preview I remember testing this and ContentUpdateMask seemed to work. This might have changed with Qt 6.3 and using AllMask instead, which works for all cases I tested should not have any negative impact. Task-number: QDS-6896 Change-Id: I648c10fe75df813ae25a54a13a862cad0228bfdb Reviewed-by: Miikka Heikkinen --- .../qml2puppet/instances/qt5rendernodeinstanceserver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp index ae333343726..553b69e4815 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp @@ -135,7 +135,7 @@ void Qt5RenderNodeInstanceServer::collectItemChangesAndSendChangeCommands() if (rootNodeInstance().isSubclassOf("QQuick3DNode") && rootNodeInstance().contentItem() && DesignerSupport::isDirty(rootNodeInstance().contentItem(), - DesignerSupport::ContentUpdateMask) + DesignerSupport::AllMask) && nodeInstanceClient()->bytesToWrite() < 10000) { Internal::QuickItemNodeInstance::updateDirtyNode(rootNodeInstance().contentItem()); nodeInstanceClient()->pixmapChanged(createPixmapChangedCommand({rootNodeInstance()})); From 839502650cc5df3fe64756276a6fc79d940c6aa9 Mon Sep 17 00:00:00 2001 From: Tim Jenssen Date: Tue, 10 May 2022 17:50:09 +0200 Subject: [PATCH 10/35] qds: ENABLE_CRASHPAD on macos (universal builds) using a newer crashpad version build with: git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git export PATH=$PWD/depot_tools:$PATH mkdir crashpad cd crashpad ../depot_tools/fetch crashpad cd crashpad gn gen out/Default --args='target_cpu="mac_universal"' ninja -C out/Default Change-Id: I782c09cb564aff725652cd1419a8dec78bc04fc5 Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: Tim Jenssen --- CMakeLists.txt | 2 +- cmake/FindCrashpad.cmake | 32 +++++++------------------------- src/app/main.cpp | 5 ----- 3 files changed, 8 insertions(+), 31 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d2359e6a21c..aec846721de 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,7 +91,7 @@ set(CRASHPAD_BACKEND_URL "" CACHE STRING "Crashpad backend URL") set(BUILD_WITH_CRASHPAD OFF) # Linux is not supported for now # x86_64;arm64 is not supported for now -if(CRASHPAD_BACKEND_URL AND (WIN32 OR (APPLE AND NOT "${CMAKE_OSX_ARCHITECTURES}" STREQUAL "x86_64;arm64"))) +if(CRASHPAD_BACKEND_URL AND (WIN32 OR APPLE)) # Linux is not supported for now find_package(Crashpad QUIET) if(TARGET Crashpad::Crashpad) set(BUILD_WITH_CRASHPAD ON) diff --git a/cmake/FindCrashpad.cmake b/cmake/FindCrashpad.cmake index 8b16fd83be2..181c4b0518d 100644 --- a/cmake/FindCrashpad.cmake +++ b/cmake/FindCrashpad.cmake @@ -57,25 +57,9 @@ find_path(CRASHPAD_GEN_DIR "${CMAKE_PREFIX_PATH}" ) -if(APPLE) - find_path(CRASHPAD_OBJ_DIR - NAMES mig_output.child_portServer.o - PATH_SUFFIXES gen/util/mach - HINTS - "${CRASHPAD_OBJECT_DIR}" - "${CRASHPAD_LIB_DIR}/out/Default" - "${CMAKE_PREFIX_PATH}" - ) - set(CRASHPAD_APPLE_VARS CRASHPAD_OBJ_DIR CRASHPAD_GEN_DIR) - find_library(FWbsm bsm) - find_library(FWAppKit AppKit) - find_library(FWIOKit IOKit) - find_library(FWSecurity Security) -endif() - include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Crashpad DEFAULT_MSG - CRASHPAD_BIN_DIR CRASHPAD_INCLUDE_DIR CRASHPAD_LIB_DIR ${CRASHPAD_APPLE_VARS} + CRASHPAD_BIN_DIR CRASHPAD_INCLUDE_DIR CRASHPAD_LIB_DIR ) if(Crashpad_FOUND) @@ -93,18 +77,16 @@ if(Crashpad_FOUND) set_target_properties(Crashpad::Crashpad PROPERTIES IMPORTED_LOCATION "${CRASHPAD_LIB_DIR}/client/client.lib") elseif(APPLE) + find_library(FWbsm bsm) + find_library(FWAppKit AppKit) + find_library(FWIOKit IOKit) + find_library(FWSecurity Security) target_link_libraries(Crashpad::Crashpad INTERFACE "${CRASHPAD_LIB_DIR}/third_party/mini_chromium/mini_chromium/base/libbase.a" "${CRASHPAD_LIB_DIR}/util/libutil.a" + "${CRASHPAD_LIB_DIR}/util/libmig_output.a" "${CRASHPAD_LIB_DIR}/client/libclient.a" - "${CRASHPAD_OBJ_DIR}/mig_output.child_portServer.o" - "${CRASHPAD_OBJ_DIR}/mig_output.child_portUser.o" - "${CRASHPAD_OBJ_DIR}/mig_output.excServer.o" - "${CRASHPAD_OBJ_DIR}/mig_output.excUser.o" - "${CRASHPAD_OBJ_DIR}/mig_output.mach_excServer.o" - "${CRASHPAD_OBJ_DIR}/mig_output.mach_excUser.o" - "${CRASHPAD_OBJ_DIR}/mig_output.notifyServer.o" - "${CRASHPAD_OBJ_DIR}/mig_output.notifyUser.o" + "${CRASHPAD_LIB_DIR}/client/libcommon.a" ${FWbsm} ${FWAppKit} ${FWIOKit} ${FWSecurity}) set_target_properties(Crashpad::Crashpad PROPERTIES IMPORTED_LOCATION "${CRASHPAD_LIB_DIR}/client/libclient.a") diff --git a/src/app/main.cpp b/src/app/main.cpp index e17ef27e209..202b0461df9 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -412,11 +412,6 @@ QStringList lastSessionArgument() #ifdef ENABLE_CRASHPAD bool startCrashpad(const QString &libexecPath, bool crashReportingEnabled) { - if (QSysInfo::currentCpuArchitecture() == "arm64") { - qDebug() << "The crashpad_handler binary does not work on arm64 properly. So it is disabled for now."; - return false; - } - using namespace crashpad; // Cache directory that will store crashpad information and minidumps From d027c5855b3c2733e87a063b3d2971b4124dfbf1 Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Thu, 12 May 2022 15:38:13 +0200 Subject: [PATCH 11/35] QmlDesigner: Align UX of ComboBox with FilterCB * Change trigger signal for CheckIndicator * Change edit state color for ComboBox Change-Id: I7fa16ccc5cf33161ae3287cd64f481a675403670 Reviewed-by: Brook Cronin Reviewed-by: Reviewed-by: Thomas Hartmann --- .../imports/StudioControls/CheckIndicator.qml | 2 +- .../imports/StudioControls/ComboBox.qml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/CheckIndicator.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/CheckIndicator.qml index 1997419bab4..ca4f4688929 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/CheckIndicator.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/CheckIndicator.qml @@ -50,7 +50,7 @@ Rectangle { id: checkIndicatorMouseArea anchors.fill: parent hoverEnabled: true - onPressed: { + onClicked: { if (myPopup.opened) { myPopup.close() } else { diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml index b6fd6fc3c64..ac1908243fb 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml @@ -276,7 +276,7 @@ T.ComboBox { PropertyChanges { target: comboBoxBackground color: StudioTheme.Values.themeControlBackgroundInteraction - border.color: StudioTheme.Values.themeControlOutline + border.color: StudioTheme.Values.themeControlOutlineInteraction } StateChangeScript { script: comboBoxPopup.close() From e703ee97d6c9949fac3928655e7ea42b4f5c30b9 Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Sun, 8 May 2022 23:43:46 +0200 Subject: [PATCH 12/35] QmlDesigner: Add FilterComboBox * Add FilterComboBox and SortFilterModel * Use FilterComboBox in UrlChooser * Add group attribute to UrlChooser model in order to sort according to groups (default items) and alphabetically * Add escape to cancel modification after editing text * Fix accepted and activated signal endpoints Task-number: QDS-6397 Change-Id: I8fd1371d01d86fbbf5fc74ca9f20677d4ea49587 Reviewed-by: Reviewed-by: Thomas Hartmann --- .../imports/HelperWidgets/UrlChooser.qml | 135 ++-- .../imports/StudioControls/FilterComboBox.qml | 754 ++++++++++++++++++ .../StudioControls/SortFilterModel.qml | 86 ++ .../imports/StudioControls/qmldir | 2 + 4 files changed, 916 insertions(+), 61 deletions(-) create mode 100644 share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml create mode 100644 share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SortFilterModel.qml diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml index dd4a11d9cff..ce2584c4be5 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml @@ -32,7 +32,7 @@ import StudioTheme 1.0 as StudioTheme import QtQuickDesignerTheme 1.0 Row { - id: urlChooser + id: root property variant backendValue property color textColor: colorLogic.highlight ? colorLogic.textColor @@ -47,22 +47,24 @@ Row { FileResourcesModel { id: fileModel modelNodeBackendProperty: modelNodeBackend - filter: urlChooser.filter + filter: root.filter } ColorLogic { id: colorLogic - backendValue: urlChooser.backendValue + backendValue: root.backendValue } - StudioControls.ComboBox { + StudioControls.FilterComboBox { id: comboBox - property ListModel items: ListModel {} + property ListModel listModel: ListModel {} implicitWidth: StudioTheme.Values.singleControlColumnWidth + StudioTheme.Values.actionIndicatorWidth width: implicitWidth + allowUserInput: true + // Note: highlightedIndex property isn't used because it has no setter and it doesn't reset // when the combobox is closed by focusing on some other control. property int hoverIndex: -1 @@ -70,7 +72,7 @@ Row { ToolTip { id: toolTip visible: comboBox.hover && toolTip.text !== "" - text: urlChooser.backendValue.valueToString + text: root.backendValue.valueToString delay: StudioTheme.Values.toolTipDelay height: StudioTheme.Values.toolTipHeight background: Rectangle { @@ -88,27 +90,39 @@ Row { delegate: ItemDelegate { required property string fullPath required property string name + required property int group required property int index - id: delegateItem - width: parent.width + id: delegateRoot + width: comboBox.popup.width - comboBox.popup.leftPadding - comboBox.popup.rightPadding + - (comboBox.popupScrollBar.visible ? comboBox.popupScrollBar.contentItem.implicitWidth + 2 + : 0) // TODO Magic number height: StudioTheme.Values.height - 2 * StudioTheme.Values.border padding: 0 - highlighted: comboBox.highlightedIndex === index + hoverEnabled: true + highlighted: comboBox.highlightedIndex === delegateRoot.DelegateModel.itemsIndex + + onHoveredChanged: { + if (delegateRoot.hovered && !comboBox.popupMouseArea.active) + comboBox.setHighlightedIndexItems(delegateRoot.DelegateModel.itemsIndex) + } + + onClicked: comboBox.selectItem(delegateRoot.DelegateModel.itemsIndex) indicator: Item { id: itemDelegateIconArea - width: delegateItem.height - height: delegateItem.height + width: delegateRoot.height + height: delegateRoot.height Label { id: itemDelegateIcon text: StudioTheme.Constants.tickIcon - color: delegateItem.highlighted ? StudioTheme.Values.themeTextSelectedTextColor + color: delegateRoot.highlighted ? StudioTheme.Values.themeTextSelectedTextColor : StudioTheme.Values.themeTextColor font.family: StudioTheme.Constants.iconFont.family font.pixelSize: StudioTheme.Values.spinControlIconSizeMulti - visible: comboBox.currentIndex === index ? true : false + visible: comboBox.currentIndex === delegateRoot.DelegateModel.itemsIndex ? true + : false anchors.fill: parent renderType: Text.NativeRendering horizontalAlignment: Text.AlignHCenter @@ -119,7 +133,7 @@ Row { contentItem: Text { leftPadding: itemDelegateIconArea.width text: name - color: delegateItem.highlighted ? StudioTheme.Values.themeTextSelectedTextColor + color: delegateRoot.highlighted ? StudioTheme.Values.themeTextSelectedTextColor : StudioTheme.Values.themeTextColor font: comboBox.font elide: Text.ElideRight @@ -127,17 +141,17 @@ Row { } background: Rectangle { - id: itemDelegateBackground x: 0 y: 0 - width: delegateItem.width - height: delegateItem.height - color: delegateItem.highlighted ? StudioTheme.Values.themeInteraction : "transparent" + width: delegateRoot.width + height: delegateRoot.height + color: delegateRoot.highlighted ? StudioTheme.Values.themeInteraction + : "transparent" } ToolTip { id: itemToolTip - visible: delegateItem.hovered && comboBox.highlightedIndex === index + visible: delegateRoot.hovered && comboBox.highlightedIndex === index text: fullPath delay: StudioTheme.Values.toolTipDelay height: StudioTheme.Values.toolTipHeight @@ -161,7 +175,7 @@ Row { ExtendedFunctionLogic { id: extFuncLogic - backendValue: urlChooser.backendValue + backendValue: root.backendValue onReseted: comboBox.editText = "" } @@ -181,20 +195,15 @@ Row { // Takes into account applied bindings property string textValue: { - if (urlChooser.backendValue.isBound) - return urlChooser.backendValue.expression + if (root.backendValue.isBound) + return root.backendValue.expression - var fullPath = urlChooser.backendValue.valueToString + var fullPath = root.backendValue.valueToString return fullPath.substr(fullPath.lastIndexOf('/') + 1) } onTextValueChanged: comboBox.setCurrentText(comboBox.textValue) - editable: true - textRole: "name" - valueRole: "fullPath" - model: comboBox.items - onModelChanged: { if (!comboBox.isComplete) return @@ -206,20 +215,14 @@ Row { if (!comboBox.isComplete) return - var inputValue = comboBox.editText + let inputValue = comboBox.editText // Check if value set by user matches with a name in the model then pick the full path - var index = comboBox.find(inputValue) + let index = comboBox.find(inputValue) if (index !== -1) - inputValue = comboBox.items.get(index).fullPath + inputValue = comboBox.items.get(index).model.fullPath - // Get the currently assigned backend value, extract its file name and compare it to the - // input value. If they differ the new value needs to be set. - var currentValue = urlChooser.backendValue.value - var fileName = currentValue.substr(currentValue.lastIndexOf('/') + 1); - - if (fileName !== inputValue) - urlChooser.backendValue.value = inputValue + root.backendValue.value = inputValue comboBox.dirty = false } @@ -234,14 +237,16 @@ Row { } function handleActivate(index) { - if (urlChooser.backendValue === undefined || !comboBox.isComplete) + if (root.backendValue === undefined || !comboBox.isComplete) return - if (index === -1) // select first item if index is invalid - index = 0 + let inputValue = comboBox.editText - if (urlChooser.backendValue.value !== comboBox.items.get(index).fullPath) - urlChooser.backendValue.value = comboBox.items.get(index).fullPath + if (index >= 0) + inputValue = comboBox.items.get(index).model.fullPath + + if (root.backendValue.value !== inputValue) + root.backendValue.value = inputValue comboBox.dirty = false } @@ -250,7 +255,7 @@ Row { // Hack to style the text input for (var i = 0; i < comboBox.children.length; i++) { if (comboBox.children[i].text !== undefined) { - comboBox.children[i].color = urlChooser.textColor + comboBox.children[i].color = root.textColor comboBox.children[i].anchors.rightMargin = 34 } } @@ -261,36 +266,44 @@ Row { function createModel() { // Build the combobox model - comboBox.items.clear() + comboBox.listModel.clear() + // While adding items to the model this binding needs to be interrupted, otherwise the + // update function of the SortFilterModel is triggered every time on append() which makes + // QtDS very slow. This will happen when selecting different items in the scene. + comboBox.model = {} - if (urlChooser.defaultItems !== undefined) { - for (var i = 0; i < urlChooser.defaultItems.length; ++i) { - comboBox.items.append({ - fullPath: urlChooser.defaultItems[i], - name: urlChooser.defaultItems[i] + if (root.defaultItems !== undefined) { + for (var i = 0; i < root.defaultItems.length; ++i) { + comboBox.listModel.append({ + fullPath: root.defaultItems[i], + name: root.defaultItems[i], + group: 0 }) } } for (var j = 0; j < fileModel.fullPathModel.length; ++j) { - comboBox.items.append({ + comboBox.listModel.append({ fullPath: fileModel.fullPathModel[j], - name: fileModel.fileNameModel[j] + name: fileModel.fileNameModel[j], + group: 1 }) } + + comboBox.model = Qt.binding(function() { return comboBox.listModel }) } Connections { target: fileModel function onFullPathModelChanged() { - urlChooser.createModel() + root.createModel() comboBox.setCurrentText(comboBox.textValue) } } - onDefaultItemsChanged: urlChooser.createModel() + onDefaultItemsChanged: root.createModel() - Component.onCompleted: urlChooser.createModel() + Component.onCompleted: root.createModel() function indexOf(model, criteria) { for (var i = 0; i < model.count; ++i) { @@ -305,16 +318,16 @@ Row { function onStateChanged(state) { // update currentIndex when the popup opens to override the default behavior in super classes // that selects currentIndex based on values in the combo box. - if (comboBox.popup.opened && !urlChooser.backendValue.isBound) { - var index = urlChooser.indexOf(comboBox.items, + if (comboBox.popup.opened && !root.backendValue.isBound) { + var index = root.indexOf(comboBox.items, function(item) { - return item.fullPath === urlChooser.backendValue.value + return item.fullPath === root.backendValue.value }) if (index !== -1) { comboBox.currentIndex = index comboBox.hoverIndex = index - comboBox.editText = comboBox.items.get(index).name + comboBox.editText = comboBox.items.get(index).model.name } } } @@ -324,11 +337,11 @@ Row { IconIndicator { icon: StudioTheme.Constants.addFile - iconColor: urlChooser.textColor + iconColor: root.textColor onClicked: { fileModel.openFileDialog() if (fileModel.fileName !== "") - urlChooser.backendValue.value = fileModel.fileName + root.backendValue.value = fileModel.fileName } } } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml new file mode 100644 index 00000000000..bdd3cb5aef5 --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml @@ -0,0 +1,754 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Quick 3D. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick +import QtQuick.Templates as T +import StudioTheme 1.0 as StudioTheme + +Item { + id: root + + enum Interaction { None, TextEdit, Key } + + property int currentInteraction: FilterComboBox.Interaction.None + + property alias model: sortFilterModel.model + property alias items: sortFilterModel.items + property alias delegate: sortFilterModel.delegate + + property alias font: textInput.font + + // This indicates if the value was committed or the user is still editing + property bool editing: false + + // This is the actual filter that is applied on the model + property string filter: "" + property bool filterActive: root.filter !== "" + + // Accept arbitrary input or only items from the model + property bool allowUserInput: false + + property alias editText: textInput.text + property int highlightedIndex: -1 // items index + property int currentIndex: -1 // items index + + property string autocompleteString: "" + + property bool __isCompleted: false + + property alias actionIndicator: actionIndicator + + // This property is used to indicate the global hover state + property bool hover: actionIndicator.hover || textInput.hover || checkIndicator.hover + property alias edit: textInput.edit + property alias open: popup.visible + + property alias actionIndicatorVisible: actionIndicator.visible + property real __actionIndicatorWidth: StudioTheme.Values.actionIndicatorWidth + property real __actionIndicatorHeight: StudioTheme.Values.actionIndicatorHeight + + property bool dirty: false // user modification flag + + property bool escapePressed: false + + signal accepted() + signal activated(int index) + signal compressedActivated(int index, int reason) + + enum ActivatedReason { EditingFinished, Other } + + property alias popup: popup + property alias popupScrollBar: popupScrollBar + property alias popupMouseArea: popupMouseArea + + width: StudioTheme.Values.defaultControlWidth + height: StudioTheme.Values.defaultControlHeight + implicitHeight: StudioTheme.Values.defaultControlHeight + + function selectItem(itemsIndex) { + textInput.text = sortFilterModel.items.get(itemsIndex).model.name + root.currentIndex = itemsIndex + root.finishEditing() + root.activated(itemsIndex) + } + + function submitValue() { + if (!root.allowUserInput) { + // If input isn't according to any item in the model, don't finish editing + if (root.highlightedIndex === -1) + return + + root.selectItem(root.highlightedIndex) + } else { + root.currentIndex = -1 + + // Only trigger the signal, if the value was modified + if (root.dirty) { + myTimer.stop() + root.dirty = false + root.editText = root.editText.trim() + //root.compressedActivated(root.find(root.editText), + // ComboBox.ActivatedReason.EditingFinished) + } + + root.finishEditing() + root.accepted() + } + } + + function finishEditing() { + root.editing = false + root.filter = "" + root.autocompleteString = "" + textInput.focus = false // Remove focus from text field + popup.close() + } + + function increaseVisibleIndex() { + let numItems = sortFilterModel.visibleGroup.count + if (!numItems) + return + + if (root.highlightedIndex === -1) // Nothing is selected + root.setHighlightedIndexVisible(0) + else { + let currentVisibleIndex = sortFilterModel.items.get(root.highlightedIndex).visibleIndex + ++currentVisibleIndex + + if (currentVisibleIndex > numItems - 1) + currentVisibleIndex = 0 + + root.setHighlightedIndexVisible(currentVisibleIndex) + } + } + + function decreaseVisibleIndex() { + let numItems = sortFilterModel.visibleGroup.count + if (!numItems) + return + + if (root.highlightedIndex === -1) // Nothing is selected + root.setHighlightedIndexVisible(numItems - 1) + else { + let currentVisibleIndex = sortFilterModel.items.get(root.highlightedIndex).visibleIndex + --currentVisibleIndex + + if (currentVisibleIndex < 0) + currentVisibleIndex = numItems - 1 + + root.setHighlightedIndexVisible(currentVisibleIndex) + } + } + + function updateHighlightedIndex() { + // Check if current index is still part of the filtered list, if not set it to 0 + if (root.highlightedIndex !== -1 && !sortFilterModel.items.get(root.highlightedIndex).inVisible) { + root.setHighlightedIndexVisible(0) + } else { + // Needs to be set in order for ListView to keep its currenIndex up to date, so + // scroll position gets updated according to the higlighted item + root.setHighlightedIndexItems(root.highlightedIndex) + } + } + + function setHighlightedIndexItems(itemsIndex) { // items group index + root.highlightedIndex = itemsIndex + + if (itemsIndex === -1) + listView.currentIndex = -1 + else + listView.currentIndex = sortFilterModel.items.get(itemsIndex).visibleIndex + } + + function setHighlightedIndexVisible(visibleIndex) { // visible group index + if (visibleIndex === -1) + root.highlightedIndex = -1 + else + root.highlightedIndex = sortFilterModel.visibleGroup.get(visibleIndex).itemsIndex + + listView.currentIndex = visibleIndex + } + + function updateAutocomplete() { + if (root.highlightedIndex === -1) + root.autocompleteString = "" + else { + let suggestion = sortFilterModel.items.get(root.highlightedIndex).model.name + root.autocompleteString = suggestion.substring(textInput.text.length) + } + } + + // TODO is this already case insensitiv?! + function find(text) { + for (let i = 0; i < sortFilterModel.items.count; ++i) + if (sortFilterModel.items.get(i).model.name === text) + return i + + return -1 + } + + Timer { + id: myTimer + property int activatedIndex + repeat: false + running: false + interval: 100 + onTriggered: root.compressedActivated(myTimer.activatedIndex, + ComboBox.ActivatedReason.Other) + } + + onActivated: function(index) { + myTimer.activatedIndex = index + myTimer.restart() + } + + onHighlightedIndexChanged: { + if (root.editing || (root.editText === "" && root.allowUserInput)) + root.updateAutocomplete() + } + + DelegateModel { + id: noMatchesModel + + model: ListModel { + ListElement { name: "No matches" } + } + + delegate: ItemDelegate { + id: noMatchesDelegate + width: popup.width - popup.leftPadding - popup.rightPadding + - (popupScrollBar.visible ? popupScrollBar.contentItem.implicitWidth + 2 + : 0) // TODO Magic number + height: StudioTheme.Values.height - 2 * StudioTheme.Values.border + padding: 0 + + contentItem: Text { + leftPadding: StudioTheme.Values.inputHorizontalPadding + text: name + font.italic: true + color: StudioTheme.Values.themeTextColor + elide: Text.ElideRight + verticalAlignment: Text.AlignVCenter + } + + background: Rectangle { + x: 0 + y: 0 + width: noMatchesDelegate.width + height: noMatchesDelegate.height + color: "transparent" + } + } + } + + SortFilterModel { + id: sortFilterModel + + filterAcceptsItem: function(item) { + return item.name.toLowerCase().startsWith(root.filter.toLowerCase()) + } + + lessThan: function(left, right) { + if (left.group === right.group) { + return left.name.toLowerCase().localeCompare(right.name.toLowerCase()) + } + + return left.group - right.group + } + + delegate: ItemDelegate { + id: delegateRoot + width: popup.width - popup.leftPadding - popup.rightPadding + - (popupScrollBar.visible ? popupScrollBar.contentItem.implicitWidth + 2 + : 0) // TODO Magic number + height: StudioTheme.Values.height - 2 * StudioTheme.Values.border + padding: 0 + hoverEnabled: true + highlighted: root.highlightedIndex === delegateRoot.DelegateModel.itemsIndex + + onHoveredChanged: { + if (delegateRoot.hovered && !popupMouseArea.active) + root.setHighlightedIndexItems(delegateRoot.DelegateModel.itemsIndex) + } + + onClicked: root.selectItem(delegateRoot.DelegateModel.itemsIndex) + + indicator: Item { + id: itemDelegateIconArea + width: delegateRoot.height + height: delegateRoot.height + + T.Label { + id: itemDelegateIcon + text: StudioTheme.Constants.tickIcon + color: delegateRoot.highlighted ? StudioTheme.Values.themeTextSelectedTextColor + : StudioTheme.Values.themeTextColor + font.family: StudioTheme.Constants.iconFont.family + font.pixelSize: StudioTheme.Values.spinControlIconSizeMulti + visible: root.currentIndex === delegateRoot.DelegateModel.itemsIndex ? true + : false + anchors.fill: parent + renderType: Text.NativeRendering + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + } + + contentItem: Text { + leftPadding: itemDelegateIconArea.width + text: name + color: delegateRoot.highlighted ? StudioTheme.Values.themeTextSelectedTextColor + : StudioTheme.Values.themeTextColor + font: textInput.font + elide: Text.ElideRight + verticalAlignment: Text.AlignVCenter + } + + background: Rectangle { + x: 0 + y: 0 + width: delegateRoot.width + height: delegateRoot.height + color: delegateRoot.highlighted ? StudioTheme.Values.themeInteraction + : "transparent" + } + } + + onUpdated: { + if (!root.__isCompleted) + return + + if (sortFilterModel.count === 0) + root.setHighlightedIndexVisible(-1) + else { + if (root.highlightedIndex === -1 && !root.allowUserInput) + root.setHighlightedIndexVisible(0) + } + } + } + + Row { + ActionIndicator { + id: actionIndicator + myControl: root + x: 0 + y: 0 + width: actionIndicator.visible ? root.__actionIndicatorWidth : 0 + height: actionIndicator.visible ? root.__actionIndicatorHeight : 0 + } + + TextInput { + id: textInput + + property bool hover: textInputMouseArea.containsMouse && textInput.enabled + property bool edit: textInput.activeFocus + property string preFocusText: "" + + x: 0 + y: 0 + z: 2 + width: root.width - actionIndicator.width + height: root.height + leftPadding: StudioTheme.Values.inputHorizontalPadding + rightPadding: StudioTheme.Values.inputHorizontalPadding + checkIndicator.width + + StudioTheme.Values.border + horizontalAlignment: Qt.AlignLeft + verticalAlignment: Qt.AlignVCenter + color: StudioTheme.Values.themeTextColor + selectionColor: StudioTheme.Values.themeTextSelectionColor + selectedTextColor: StudioTheme.Values.themeTextSelectedTextColor + selectByMouse: true + clip: true + + Rectangle { + id: textInputBackground + z: -1 + width: textInput.width + height: textInput.height + color: StudioTheme.Values.themeControlBackground + border.color: StudioTheme.Values.themeControlOutline + border.width: StudioTheme.Values.border + } + + MouseArea { + id: textInputMouseArea + anchors.fill: parent + enabled: true + hoverEnabled: true + propagateComposedEvents: true + acceptedButtons: Qt.LeftButton + cursorShape: Qt.PointingHandCursor + onPressed: function(mouse) { + textInput.forceActiveFocus() + mouse.accepted = false + } + + // Stop scrollable views from scrolling while ComboBox is in edit mode and the mouse + // pointer is on top of it. We might add wheel selection in the future. + onWheel: function(wheel) { + wheel.accepted = root.edit + } + } + + onEditingFinished: { + if (root.escapePressed) { + root.escapePressed = false + root.editText = textInput.preFocusText + } else { + if (root.currentInteraction === FilterComboBox.Interaction.TextEdit) { + if (root.dirty) + root.submitValue() + } else if (root.currentInteraction === FilterComboBox.Interaction.Key) { + root.selectItem(root.highlightedIndex) + } + } + + sortFilterModel.update() + } + + onTextEdited: { + root.currentInteraction = FilterComboBox.Interaction.TextEdit + root.editing = true + popupMouseArea.active = true + root.dirty = true + + if (textInput.text !== "") + root.filter = textInput.text + else { + root.filter = "" + root.autocompleteString = "" + } + + if (!popup.visible) + popup.open() + + sortFilterModel.update() + + if (!root.allowUserInput) + root.updateHighlightedIndex() + else + root.setHighlightedIndexVisible(-1) + + root.updateAutocomplete() + } + + onActiveFocusChanged: { + if (textInput.activeFocus) { + popup.open() + textInput.preFocusText = textInput.text + } else + popup.close() + } + + states: [ + State { + name: "default" + when: root.enabled && !textInput.edit && !root.hover && !root.open + PropertyChanges { + target: textInputBackground + color: StudioTheme.Values.themeControlBackground + } + PropertyChanges { + target: textInputMouseArea + cursorShape: Qt.PointingHandCursor + acceptedButtons: Qt.LeftButton + } + }, + State { + name: "globalHover" + when: root.hover && !textInput.hover && !textInput.edit && !root.open + PropertyChanges { + target: textInputBackground + color: StudioTheme.Values.themeControlBackgroundGlobalHover + } + }, + State { + name: "hover" + when: textInput.hover && root.hover && !textInput.edit + PropertyChanges { + target: textInputBackground + color: StudioTheme.Values.themeControlBackgroundHover + } + }, + State { + name: "edit" + when: root.edit + PropertyChanges { + target: textInputBackground + color: StudioTheme.Values.themeControlBackgroundInteraction + border.color: StudioTheme.Values.themeControlOutlineInteraction + } + PropertyChanges { + target: textInputMouseArea + cursorShape: Qt.IBeamCursor + acceptedButtons: Qt.NoButton + } + }, + State { + name: "disable" + when: !root.enabled + PropertyChanges { + target: textInputBackground + color: StudioTheme.Values.themeControlBackgroundDisabled + } + PropertyChanges { + target: textInput + color: StudioTheme.Values.themeTextColorDisabled + } + } + ] + + Text { + visible: root.autocompleteString !== "" + text: root.autocompleteString + x: textInput.leftPadding + textMetrics.advanceWidth + y: (textInput.height - Math.ceil(textMetrics.height)) / 2 + color: "gray" // TODO proper color value + font: textInput.font + renderType: textInput.renderType + } + + TextMetrics { + id: textMetrics + font: textInput.font + text: textInput.text + } + + Rectangle { + id: checkIndicator + + property bool hover: checkIndicatorMouseArea.containsMouse && checkIndicator.enabled + property bool pressed: checkIndicatorMouseArea.containsPress + property bool checked: popup.visible + + x: textInput.width - checkIndicator.width - StudioTheme.Values.border + y: StudioTheme.Values.border + width: StudioTheme.Values.height - StudioTheme.Values.border + height: textInput.height - (StudioTheme.Values.border * 2) + color: StudioTheme.Values.themeControlBackground + border.width: 0 + + MouseArea { + id: checkIndicatorMouseArea + anchors.fill: parent + hoverEnabled: true + onClicked: { + if (popup.visible) + popup.close() + else + popup.open() + + if (!textInput.activeFocus) { + textInput.forceActiveFocus() + textInput.selectAll() + } + } + } + + T.Label { + id: checkIndicatorIcon + anchors.fill: parent + color: StudioTheme.Values.themeTextColor + text: StudioTheme.Constants.upDownSquare2 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.pixelSize: StudioTheme.Values.sliderControlSizeMulti + font.family: StudioTheme.Constants.iconFont.family + } + + states: [ + State { + name: "default" + when: root.enabled && checkIndicator.enabled && !root.edit + && !checkIndicator.hover && !root.hover + && !checkIndicator.checked + PropertyChanges { + target: checkIndicator + color: StudioTheme.Values.themeControlBackground + } + }, + State { + name: "globalHover" + when: root.enabled && checkIndicator.enabled + && !checkIndicator.hover && root.hover && !root.edit + && !checkIndicator.checked + PropertyChanges { + target: checkIndicator + color: StudioTheme.Values.themeControlBackgroundGlobalHover + } + }, + State { + name: "hover" + when: root.enabled && checkIndicator.enabled + && checkIndicator.hover && root.hover && !checkIndicator.pressed + && !checkIndicator.checked + PropertyChanges { + target: checkIndicator + color: StudioTheme.Values.themeControlBackgroundHover + } + }, + State { + name: "check" + when: checkIndicator.checked + PropertyChanges { + target: checkIndicatorIcon + color: StudioTheme.Values.themeIconColor + } + PropertyChanges { + target: checkIndicator + color: StudioTheme.Values.themeInteraction + } + }, + State { + name: "press" + when: root.enabled && checkIndicator.enabled + && checkIndicator.pressed + PropertyChanges { + target: checkIndicatorIcon + color: StudioTheme.Values.themeIconColor + } + PropertyChanges { + target: checkIndicator + color: StudioTheme.Values.themeInteraction + } + }, + State { + name: "disable" + when: !root.enabled + PropertyChanges { + target: checkIndicator + color: StudioTheme.Values.themeControlBackgroundDisabled + } + PropertyChanges { + target: checkIndicatorIcon + color: StudioTheme.Values.themeTextColorDisabled + } + } + ] + } + } + } + + T.Popup { + id: popup + x: textInput.x + StudioTheme.Values.border + y: textInput.height + width: textInput.width - (StudioTheme.Values.border * 2) + height: Math.min(popup.contentItem.implicitHeight + popup.topPadding + popup.bottomPadding, + root.Window.height - popup.topMargin - popup.bottomMargin, + StudioTheme.Values.maxComboBoxPopupHeight) + padding: StudioTheme.Values.border + margins: 0 // If not defined margin will be -1 + closePolicy: T.Popup.NoAutoClose + + contentItem: ListView { + id: listView + clip: true + implicitHeight: listView.contentHeight + highlightMoveVelocity: -1 + boundsBehavior: Flickable.StopAtBounds + flickDeceleration: 10000 + + model: { + if (popup.visible) + return sortFilterModel.count ? sortFilterModel : noMatchesModel + + return null + } + + ScrollBar.vertical: ScrollBar { + id: popupScrollBar + visible: listView.height < listView.contentHeight + } + } + + background: Rectangle { + color: StudioTheme.Values.themePopupBackground + border.width: 0 + } + + onOpened: { + // Reset the highlightedIndex of ListView as binding with condition didn't work + if (root.highlightedIndex !== -1) + root.setHighlightedIndexItems(root.highlightedIndex) + } + + onAboutToShow: { + // Select first item in list + if (root.highlightedIndex === -1 && sortFilterModel.count && !root.allowUserInput) + root.setHighlightedIndexVisible(0) + } + + MouseArea { + // This is MouseArea is intended to block the hovered property of an ItemDelegate + // when the ListView changes due to Key interaction. + + id: popupMouseArea + property bool active: true + + anchors.fill: parent + enabled: popup.visible && popupMouseArea.active + hoverEnabled: true + onPositionChanged: { popupMouseArea.active = false } + } + } + + Keys.onDownPressed: { + if (!sortFilterModel.visibleGroup.count) + return + + root.currentInteraction = FilterComboBox.Interaction.Key + root.increaseVisibleIndex() + + popupMouseArea.active = true + } + + Keys.onUpPressed: { + if (!sortFilterModel.visibleGroup.count) + return + + root.currentInteraction = FilterComboBox.Interaction.Key + root.decreaseVisibleIndex() + + popupMouseArea.active = true + } + + Keys.onEscapePressed: { + root.escapePressed = true + root.finishEditing() + } + + Component.onCompleted: { + let index = root.find(root.editText) + root.currentIndex = index + root.highlightedIndex = index // TODO might not be intended + + root.__isCompleted = true + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SortFilterModel.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SortFilterModel.qml new file mode 100644 index 00000000000..e70b0093e39 --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SortFilterModel.qml @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Quick 3D. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick +import QtQml.Models + +DelegateModel { + id: delegateModel + + property var visibleGroup: visibleItems + + property var lessThan: function(left, right) { return true } + property var filterAcceptsItem: function(item) { return true } + + signal updated() + + function update() { + if (delegateModel.items.count > 0) { + delegateModel.items.setGroups(0, delegateModel.items.count, "items") + } + + // Filter items + var visible = [] + for (var i = 0; i < delegateModel.items.count; ++i) { + var item = delegateModel.items.get(i) + if (delegateModel.filterAcceptsItem(item.model)) { + visible.push(item) + } + } + + // Sort the list of visible items + visible.sort(function(a, b) { + return delegateModel.lessThan(a.model, b.model); + }); + + // Add all items to the visible group + for (i = 0; i < visible.length; ++i) { + item = visible[i] + item.inVisible = true + if (item.visibleIndex !== i) { + visibleItems.move(item.visibleIndex, i, 1) + } + } + + delegateModel.updated() + } + + items.onChanged: delegateModel.update() + onLessThanChanged: delegateModel.update() + onFilterAcceptsItemChanged: delegateModel.update() + + groups: DelegateModelGroup { + id: visibleItems + + name: "visible" + includeByDefault: false + } + + filterOnGroup: "visible" +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/qmldir b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/qmldir index b5f8c7a4e30..25be4d0acf2 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/qmldir +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/qmldir @@ -8,6 +8,7 @@ CheckIndicator 1.0 CheckIndicator.qml ComboBox 1.0 ComboBox.qml ComboBoxInput 1.0 ComboBoxInput.qml ContextMenu 1.0 ContextMenu.qml +FilterComboBox 1.0 FilterComboBox.qml InfinityLoopIndicator 1.0 InfinityLoopIndicator.qml ItemDelegate 1.0 ItemDelegate.qml LinkIndicator2D 1.0 LinkIndicator2D.qml @@ -30,6 +31,7 @@ SectionLabel 1.0 SectionLabel.qml SectionLayout 1.0 SectionLayout.qml Slider 1.0 Slider.qml SliderPopup 1.0 SliderPopup.qml +SortFilterModel 1.0 SortFilterModel.qml SpinBox 1.0 SpinBox.qml SpinBoxIndicator 1.0 SpinBoxIndicator.qml SpinBoxInput 1.0 SpinBoxInput.qml From 0334d4886b67dc9fe7393fdb04d636dc44e8f492 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 12 May 2022 17:10:09 +0300 Subject: [PATCH 13/35] QmlDesigner: Fix puppet crash when property animation has no target Fixes: QDS-6935 Change-Id: Ib6dae3a6c39a12e9e62bd494d5a27917d7f97048 Reviewed-by: Reviewed-by: Mahmoud Badri --- .../qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp | 2 +- .../qml2puppet/instances/qt5informationnodeinstanceserver.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp index a6e7e259e28..8400c3d4474 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp @@ -1610,7 +1610,7 @@ void NodeInstanceServer::addAnimation(QQuickAbstractAnimation *animation) m_animations.push_back(animation); QQuickPropertyAnimation *panim = qobject_cast(animation); - if (panim) { + if (panim && panim->target()) { QObject *target = panim->target(); QString property = panim->property(); QVariant value = target->property(qPrintable(baseProperty(property))); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index acc7894a963..a57df6bd9f0 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -534,7 +534,7 @@ void Qt5InformationNodeInstanceServer::handleParticleSystemDeselected() for (auto a : anim) { a->stop(); QQuickPropertyAnimation *panim = qobject_cast(a); - if (panim) + if (panim && panim->target()) panim->target()->setProperty(qPrintable(baseProperty(panim->property())), animationDefaultValue(i)); i++; } From 9be10225cc5a85a87e70638952e742ba5dab2503 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 13 May 2022 10:05:47 +0200 Subject: [PATCH 14/35] Dumper: Fix Environment dumper Change-Id: I48349ca550981d19cf0087bccd38e4d2677d1897 Reviewed-by: hjk --- share/qtcreator/debugger/creatortypes.py | 54 +++++++++++++++--------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/share/qtcreator/debugger/creatortypes.py b/share/qtcreator/debugger/creatortypes.py index 5d6b5e04141..1a75590e4e4 100644 --- a/share/qtcreator/debugger/creatortypes.py +++ b/share/qtcreator/debugger/creatortypes.py @@ -263,32 +263,44 @@ def qdump__Utils__Environment(d, value): qdump__Utils__NameValueDictionary(d, value) +def qdump__Utils__DictKey(d, value): + d.putStringValue(value["name"]) + + def qdump__Utils__NameValueDictionary(d, value): - dptr = d.extractPointer(value["m_values"]) - (ref, n) = d.split('ii', dptr) - d.check(0 <= n and n <= 100 * 1000 * 1000) - d.check(-1 <= ref and ref < 100000) + dptr = d.extractPointer(value) + if d.qtVersion() >= 0x60000: + if dptr == 0: + d.putItemCount(0) + return + m = value['d']['d']['m'] + d.putItem(m) + d.putBetterType('Utils::NameValueDictionary') + else: # Qt5 + (ref, n) = d.split('ii', dptr) + d.check(0 <= n and n <= 100 * 1000 * 1000) + d.check(-1 <= ref and ref < 100000) - d.putItemCount(n) - if d.isExpanded(): - if n > 10000: - n = 10000 + d.putItemCount(n) + if d.isExpanded(): + if n > 10000: + n = 10000 - typeCode = 'ppp@{%s}@{%s}' % ("Utils::DictKey", "QString") + typeCode = 'ppp@{%s}@{%s}' % ("Utils::DictKey", "@QPair<@QString,bool>") - def helper(node): - (p, left, right, padding1, key, padding2, value) = d.split(typeCode, node) - if left: - for res in helper(left): - yield res - yield (key["name"], value) - if right: - for res in helper(right): - yield res + def helper(node): + (p, left, right, padding1, key, padding2, value) = d.split(typeCode, node) + if left: + for res in helper(left): + yield res + yield (key["name"], value) + if right: + for res in helper(right): + yield res - with Children(d, n): - for (pair, i) in zip(helper(dptr + 8), range(n)): - d.putPairItem(i, pair, 'key', 'value') + with Children(d, n): + for (pair, i) in zip(helper(dptr + 8), range(n)): + d.putPairItem(i, pair, 'key', 'value') def qdump__Utf8String(d, value): From 4d58f8dee8ff82fe6134f6b9a0a8a6dd597b778d Mon Sep 17 00:00:00 2001 From: Knud Dollereder Date: Fri, 6 May 2022 14:28:20 +0200 Subject: [PATCH 15/35] Make the curveeditor state aware Fixes: QDS-6872 Change-Id: I2fe733bf6c25d3517ff80d122977113e10bac627 Reviewed-by: Reviewed-by: Thomas Hartmann --- .../components/curveeditor/curveeditorview.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditorview.cpp b/src/plugins/qmldesigner/components/curveeditor/curveeditorview.cpp index c449d0e8640..eee4b69db65 100644 --- a/src/plugins/qmldesigner/components/curveeditor/curveeditorview.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/curveeditorview.cpp @@ -215,10 +215,9 @@ QmlTimeline CurveEditorView::activeTimeline() const if (node.hasVariantProperty("enabled") && node.variantProperty("enabled").value().toBool()) return QmlTimeline(node); - - return {}; } } + return {}; } for (const ModelNode &node : allModelNodesOfType("QtQuick.Timeline.Timeline")) { @@ -227,8 +226,9 @@ QmlTimeline CurveEditorView::activeTimeline() const if (!propertyChanges.isValid()) continue; - if (node.hasVariantProperty("enabled") && node.variantProperty("enabled").value().toBool()) - return QmlTimeline(node); + if (propertyChanges.modelNode().hasProperty("enabled") && + propertyChanges.modelNode().variantProperty("enabled").value().toBool()) + return QmlTimeline(node); } } return {}; From 17982e661c50a0472e93e7e7d19389162dcd250e Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Fri, 13 May 2022 13:15:25 +0300 Subject: [PATCH 16/35] QmlDesigner: Disable shadows for gizmos Some gizmos (selection box and helper grid) are drawn to main 3D editor scene. Disabled receiving and casting shadows for those gizmos so they do not interfere with scene lighting. Change-Id: Ia589d3896c2591061966f6a4d532a0dedbf6fe12 Reviewed-by: Mahmoud Badri --- .../qtcreator/qml/qmlpuppet/mockfiles/qt5/HelperGrid.qml | 8 ++++++++ .../qml/qmlpuppet/mockfiles/qt5/SelectionBox.qml | 3 +++ .../qtcreator/qml/qmlpuppet/mockfiles/qt6/HelperGrid.qml | 8 ++++++++ .../qml/qmlpuppet/mockfiles/qt6/SelectionBox.qml | 3 +++ 4 files changed, 22 insertions(+) diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/HelperGrid.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/HelperGrid.qml index dbd7f38523c..e450a5a796c 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/HelperGrid.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/HelperGrid.qml @@ -39,6 +39,8 @@ Node { // Note: Only one instance of HelperGrid is supported, as the geometry names are fixed Model { // Main grid lines + castsShadows: false + receivesShadows: false geometry: GridGeometry { id: gridGeometry name: "3D Edit View Helper Grid" @@ -55,6 +57,8 @@ Node { } Model { // Subdivision lines + castsShadows: false + receivesShadows: false geometry: GridGeometry { lines: gridGeometry.lines step: gridGeometry.step @@ -73,6 +77,8 @@ Node { } Model { // Z Axis + castsShadows: false + receivesShadows: false geometry: GridGeometry { lines: gridGeometry.lines step: gridGeometry.step @@ -89,6 +95,8 @@ Node { ] } Model { // X Axis + castsShadows: false + receivesShadows: false eulerRotation.z: 90 geometry: GridGeometry { lines: gridGeometry.lines diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/SelectionBox.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/SelectionBox.qml index 201d1a63775..5ab4a599c44 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/SelectionBox.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/SelectionBox.qml @@ -54,6 +54,9 @@ Node { visible: selectionBox.targetNode && !selectionBoxGeometry.isEmpty + castsShadows: false + receivesShadows: false + materials: [ DefaultMaterial { diffuseColor: "#fff600" diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/HelperGrid.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/HelperGrid.qml index 10c7afd65b8..66f383518eb 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/HelperGrid.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/HelperGrid.qml @@ -40,6 +40,8 @@ Node { Model { // Main grid lines readonly property bool _edit3dLocked: true // Make this non-pickable + castsShadows: false + receivesShadows: false geometry: GridGeometry { id: gridGeometry name: "3D Edit View Helper Grid" @@ -57,6 +59,8 @@ Node { Model { // Subdivision lines readonly property bool _edit3dLocked: true // Make this non-pickable + castsShadows: false + receivesShadows: false geometry: GridGeometry { lines: gridGeometry.lines step: gridGeometry.step @@ -76,6 +80,8 @@ Node { Model { // Z Axis readonly property bool _edit3dLocked: true // Make this non-pickable + castsShadows: false + receivesShadows: false geometry: GridGeometry { lines: gridGeometry.lines step: gridGeometry.step @@ -93,6 +99,8 @@ Node { } Model { // X Axis readonly property bool _edit3dLocked: true // Make this non-pickable + castsShadows: false + receivesShadows: false eulerRotation.z: 90 geometry: GridGeometry { lines: gridGeometry.lines diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/SelectionBox.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/SelectionBox.qml index dd3300fd941..76fc14e3213 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/SelectionBox.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/SelectionBox.qml @@ -55,6 +55,9 @@ Node { visible: selectionBox.targetNode && !selectionBoxGeometry.isEmpty + castsShadows: false + receivesShadows: false + materials: [ DefaultMaterial { diffuseColor: "#fff600" From 1bfd5da0248be7b7992075b12a65157412a92cea Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 13 May 2022 13:59:55 +0200 Subject: [PATCH 17/35] LanguageClient: Track quick fix assist processor Same as for the completion and function hint processor, these processors need to be tracked so they get cleaned up on client destruction. Change-Id: Ib24eb8c652e7a44d8b79e1edddda9ad659d145a3 Reviewed-by: Christian Kandeler --- src/plugins/languageclient/languageclientquickfix.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/languageclient/languageclientquickfix.cpp b/src/plugins/languageclient/languageclientquickfix.cpp index 93d85b15f21..cf9f7196d0c 100644 --- a/src/plugins/languageclient/languageclientquickfix.cpp +++ b/src/plugins/languageclient/languageclientquickfix.cpp @@ -117,6 +117,7 @@ IAssistProposal *LanguageClientQuickFixAssistProcessor::perform(const AssistInte handleCodeActionResponse(response); }); + m_client->addAssistProcessor(this); m_client->requestCodeActions(request); m_currentRequest = request.id(); return nullptr; From d0a9b873cb3c8a8b54cbfaa51fbf9a913bf192e7 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Fri, 13 May 2022 13:17:02 +0200 Subject: [PATCH 18/35] ProjectExplorer: Include symlinks for compiler import name matching On macOS /Library/Developer/CommandLineTools/usr/bin/cc is a symlink to /Library/Developer/CommandLineTools/usr/bin/clang, and should not be matched as a GCC toolchain. Fixes: QTCREATORBUG-27523 Change-Id: I8885a263b46fa8d8a8145f7c0faa31f21aae920a Reviewed-by: Eike Ziller --- src/plugins/projectexplorer/gcctoolchain.cpp | 36 ++++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp index 047ddb02b48..666ef9624eb 100644 --- a/src/plugins/projectexplorer/gcctoolchain.cpp +++ b/src/plugins/projectexplorer/gcctoolchain.cpp @@ -1077,12 +1077,19 @@ Toolchains GccToolChainFactory::autoDetect(const ToolchainDetector &detector) co Toolchains GccToolChainFactory::detectForImport(const ToolChainDescription &tcd) const { const QString fileName = tcd.compilerPath.completeBaseName(); - if ((tcd.language == Constants::C_LANGUAGE_ID && (fileName.startsWith("gcc") - || fileName.endsWith("gcc") - || fileName == "cc")) - || (tcd.language == Constants::CXX_LANGUAGE_ID && (fileName.startsWith("g++") - || fileName.endsWith("g++") - || fileName == "c++"))) { + const QString resolvedSymlinksFileName = tcd.compilerPath.resolveSymlinks().completeBaseName(); + + const bool isCCompiler = tcd.language == Constants::C_LANGUAGE_ID + && (fileName.startsWith("gcc") + || fileName.endsWith("gcc") + || (fileName == "cc" && !resolvedSymlinksFileName.contains("clang"))); + + const bool isCxxCompiler = tcd.language == Constants::CXX_LANGUAGE_ID + && (fileName.startsWith("g++") + || fileName.endsWith("g++") + || (fileName == "c++" && !resolvedSymlinksFileName.contains("clang"))); + + if (isCCompiler || isCxxCompiler) { return autoDetectToolChain(tcd, [](const ToolChain *tc) { return tc->targetAbi().osFlavor() != Abi::WindowsMSysFlavor; }); @@ -1756,9 +1763,18 @@ Toolchains ClangToolChainFactory::autoDetect(const ToolchainDetector &detector) Toolchains ClangToolChainFactory::detectForImport(const ToolChainDescription &tcd) const { - const QString fileName = tcd.compilerPath.toString(); - if ((tcd.language == Constants::C_LANGUAGE_ID && fileName.startsWith("clang") && !fileName.startsWith("clang++")) - || (tcd.language == Constants::CXX_LANGUAGE_ID && fileName.startsWith("clang++"))) { + const QString fileName = tcd.compilerPath.completeBaseName(); + const QString resolvedSymlinksFileName = tcd.compilerPath.resolveSymlinks().completeBaseName(); + + const bool isCCompiler = tcd.language == Constants::C_LANGUAGE_ID + && ((fileName.startsWith("clang") && !fileName.startsWith("clang++")) + || (fileName == "cc" && resolvedSymlinksFileName.contains("clang"))); + + const bool isCxxCompiler = tcd.language == Constants::CXX_LANGUAGE_ID + && (fileName.startsWith("clang++") + || (fileName == "c++" && resolvedSymlinksFileName.contains("clang"))); + + if (isCCompiler || isCxxCompiler) { return autoDetectToolChain(tcd); } return {}; @@ -2014,7 +2030,7 @@ Toolchains LinuxIccToolChainFactory::autoDetect(const ToolchainDetector &detecto Toolchains LinuxIccToolChainFactory::detectForImport(const ToolChainDescription &tcd) const { - const QString fileName = tcd.compilerPath.toString(); + const QString fileName = tcd.compilerPath.completeBaseName(); if ((tcd.language == Constants::CXX_LANGUAGE_ID && fileName.startsWith("icpc")) || (tcd.language == Constants::C_LANGUAGE_ID && fileName.startsWith("icc"))) { return autoDetectToolChain(tcd); From 96144d12bb0a0188e29266bbc59c715a1ccec965 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Thu, 12 May 2022 17:22:58 +0200 Subject: [PATCH 19/35] StudioWelcome: Download data from Qt.io MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We try to download new updated data from Qt.io if it is newer. In any case we provide a default that comes with QDS. I removed the check for QmlData, since they should not be required and they stop FileDownloader from running from "pure" C++. Task-number: QDS-6886 Change-Id: I1332c194286e6e91dfcd1c6605931f1ed020bc29 Reviewed-by: Henning Gründl Reviewed-by: Reviewed-by: Qt CI Bot --- src/plugins/studiowelcome/examplecheckout.cpp | 84 ++++++++++++++++--- src/plugins/studiowelcome/examplecheckout.h | 26 +++++- .../studiowelcome/studiowelcomeplugin.cpp | 26 +++++- 3 files changed, 122 insertions(+), 14 deletions(-) diff --git a/src/plugins/studiowelcome/examplecheckout.cpp b/src/plugins/studiowelcome/examplecheckout.cpp index 057be29789d..aae7eb07781 100644 --- a/src/plugins/studiowelcome/examplecheckout.cpp +++ b/src/plugins/studiowelcome/examplecheckout.cpp @@ -196,17 +196,6 @@ void FileDownloader::probeUrl() }); QNetworkReply::connect(reply, &QNetworkReply::finished, this, [this, reply]() { - QQmlData *data = QQmlData::get(this, false); - if (!data) { - qDebug() << Q_FUNC_INFO << "FileDownloader is nullptr."; - return; - } - - if (QQmlData::wasDeleted(this)) { - qDebug() << Q_FUNC_INFO << "FileDownloader was deleted."; - return; - } - if (reply->error()) return; @@ -435,3 +424,76 @@ void FileExtractor::extract() QTC_ASSERT(ret, ;); }); } + +static Utils::FilePath tempFilePath() +{ + QStandardPaths::StandardLocation location = QStandardPaths::CacheLocation; + + return Utils::FilePath::fromString(QStandardPaths::writableLocation(location)) + .pathAppended("QtDesignStudio"); +} + +DataModelDownloader::DataModelDownloader(QObject * /* parent */) +{ + auto fileInfo = targetFolder().toFileInfo(); + m_birthTime = fileInfo.birthTime(); + m_exists = fileInfo.exists(); +} + +void DataModelDownloader::start() +{ + m_fileDownloader.setUrl(QUrl::fromUserInput( + "https://download.qt.io/learning/examples/qtdesignstudio/dataImports.zip")); + + connect(&m_fileDownloader, &FileDownloader::availableChanged, this, [this]() { + + m_available = m_fileDownloader.available(); + + emit availableChanged(); + + if (!m_available) { + qWarning() << m_fileDownloader.url() << "failed to download"; + return; + } + + if (!m_forceDownload && m_fileDownloader.lastModified() < m_birthTime) + return; + + m_fileDownloader.start(); + connect(&m_fileDownloader, &FileDownloader::finishedChanged, this, [this]() { + if (m_fileDownloader.finished()) { + Utils::Archive *archive = Utils::Archive::unarchive(Utils::FilePath::fromString( + m_fileDownloader.tempFile()), + tempFilePath()); + + archive->setParent(this); + QTC_ASSERT(archive, return ); + + QObject::connect(archive, &Utils::Archive::finished, this, [this](bool ret) { + emit finished(); + QTC_ASSERT(ret, ;); + }); + } + }); + }); +} + +bool DataModelDownloader::exists() const +{ + return m_exists; +} + +bool DataModelDownloader::available() const +{ + return m_available; +} + +Utils::FilePath DataModelDownloader::targetFolder() const +{ + return Utils::FilePath::fromUserInput(tempFilePath().toString() + "/" + "dataImports"); +} + +void DataModelDownloader::setForceDownload(bool b) +{ + m_forceDownload = b; +} diff --git a/src/plugins/studiowelcome/examplecheckout.h b/src/plugins/studiowelcome/examplecheckout.h index af2be4893ec..a6c0df3acef 100644 --- a/src/plugins/studiowelcome/examplecheckout.h +++ b/src/plugins/studiowelcome/examplecheckout.h @@ -154,5 +154,29 @@ private: int m_progress = 0; QFile m_tempFile; QDateTime m_lastModified; - bool m_available; + bool m_available = false; +}; + +class DataModelDownloader : public QObject +{ + Q_OBJECT + +public: + explicit DataModelDownloader(QObject *parent = nullptr); + void start(); + bool exists() const; + bool available() const; + Utils::FilePath targetFolder() const; + void setForceDownload(bool b); + +signals: + void finished(); + void availableChanged(); + +private: + FileDownloader m_fileDownloader; + QDateTime m_birthTime; + bool m_exists = false; + bool m_available = false; + bool m_forceDownload = false; }; diff --git a/src/plugins/studiowelcome/studiowelcomeplugin.cpp b/src/plugins/studiowelcome/studiowelcomeplugin.cpp index 17c37fccf39..338793e4057 100644 --- a/src/plugins/studiowelcome/studiowelcomeplugin.cpp +++ b/src/plugins/studiowelcome/studiowelcomeplugin.cpp @@ -498,6 +498,7 @@ public: private: QQuickWidget *m_modeWidget = nullptr; + DataModelDownloader *m_dataModelDownloader = nullptr; }; void StudioWelcomePlugin::closeSplashScreen() @@ -647,6 +648,28 @@ WelcomeMode::WelcomeMode() { setDisplayName(tr("Welcome")); + const QString welcomePagePath = Core::ICore::resourcePath("qmldesigner/welcomepage").toString(); + + m_dataModelDownloader = new DataModelDownloader(this); + if (!m_dataModelDownloader->exists()) { //Fallback if data cannot be downloaded + Utils::FileUtils::copyRecursively(Utils::FilePath::fromUserInput(welcomePagePath + + "/dataImports"), + m_dataModelDownloader->targetFolder()); + m_dataModelDownloader->setForceDownload(true); + } + Utils::FilePath readme = Utils::FilePath::fromUserInput(welcomePagePath + + "/dataImports/readme.txt"); + + if (!readme.exists()) // Only downloads contain the readme + m_dataModelDownloader->setForceDownload(true); + + m_dataModelDownloader->start(); + + connect(m_dataModelDownloader, &DataModelDownloader::finished, this, [this](){ + auto source = m_modeWidget->source(); + m_modeWidget->engine()->clearComponentCache(); + m_modeWidget->setSource(source); + }); const Utils::Icon FLAT({{":/studiowelcome/images/mode_welcome_mask.png", Utils::Theme::IconsBaseColor}}); const Utils::Icon FLAT_ACTIVE({{":/studiowelcome/images/mode_welcome_mask.png", @@ -691,9 +714,8 @@ WelcomeMode::WelcomeMode() m_modeWidget->engine()->addImportPath(Core::ICore::resourcePath("qmldesigner/propertyEditorQmlSources/imports").toString()); - const QString welcomePagePath = Core::ICore::resourcePath("qmldesigner/welcomepage").toString(); m_modeWidget->engine()->addImportPath(welcomePagePath + "/imports"); - m_modeWidget->engine()->addImportPath(welcomePagePath + "/dataImports"); + m_modeWidget->engine()->addImportPath(m_dataModelDownloader->targetFolder().toString()); m_modeWidget->setSource(QUrl::fromLocalFile(welcomePagePath + "/main.qml")); QShortcut *updateShortcut = nullptr; From 11f55c7173539b2ac68e887cb80e800dd28a13f6 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 13 May 2022 16:50:54 +0200 Subject: [PATCH 20/35] QmlDesigner: Add simple tracing to AssetsLibraryModel Change-Id: I5306ce637e44ac275411fdb60c5e83f96039ec62 Reviewed-by: Mahmoud Badri --- .../assetslibrary/assetslibrarymodel.cpp | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp index 6dd1504f95d..719406ea1ad 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp @@ -36,19 +36,24 @@ #include +#include +#include + +#include #include #include #include +#include #include #include +#include +#include #include #include #include #include -#include -#include -#include -#include + +static Q_LOGGING_CATEGORY(assetsLibraryBenchmark, "qtc.assetsLibrary.setRoot", QtWarningMsg) namespace QmlDesigner { @@ -298,6 +303,12 @@ void AssetsLibraryModel::refresh() void AssetsLibraryModel::setRootPath(const QString &path) { + QElapsedTimer time; + if (assetsLibraryBenchmark().isInfoEnabled()) + time.start(); + + qCInfo(assetsLibraryBenchmark) << "start:" << time.elapsed(); + static const QStringList ignoredTopLevelDirs {"imports", "asset_imports"}; m_fileSystemWatcher->clear(); @@ -345,6 +356,8 @@ void AssetsLibraryModel::setRootPath(const QString &path) return isEmpty; }; + qCInfo(assetsLibraryBenchmark) << "directories parsed:" << time.elapsed(); + if (m_assetsDir) delete m_assetsDir; @@ -360,6 +373,8 @@ void AssetsLibraryModel::setRootPath(const QString &path) m_assetsDir->setDirVisible(!noAssets); // if there are no assets, hide all empty asset folders endResetModel(); + + qCInfo(assetsLibraryBenchmark) << "model reset:" << time.elapsed(); } void AssetsLibraryModel::setSearchText(const QString &searchText) From 95bbe6bde6655a96bb90906452ef0e2f7e6b1e53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20L=C3=B6hning?= Date: Wed, 11 May 2022 22:11:50 +0200 Subject: [PATCH 21/35] Squish: Fix toolchains in Qt 5.14.1 kit This referred to MSVC2013 which has nothing to do with this kit. Change-Id: Iad72dfd7632e7039ac5d528a3e750264b192df63 Reviewed-by: Reviewed-by: Christian Stenger --- tests/system/settings/windows/QtProject/qtcreator/profiles.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/system/settings/windows/QtProject/qtcreator/profiles.xml b/tests/system/settings/windows/QtProject/qtcreator/profiles.xml index 56ed350666f..3bd4752b3dc 100644 --- a/tests/system/settings/windows/QtProject/qtcreator/profiles.xml +++ b/tests/system/settings/windows/QtProject/qtcreator/profiles.xml @@ -42,8 +42,7 @@ Desktop - {7ca0887f-a9a5-4251-aba6-560a15595d20} - + {ce3a8004-e9ae-46f2-b62d-d7daf69435ca} {3df7c776-a480-4a04-9099-6c75adac2dca} From 05b5b864c939c2ac39d2f69311e8040e0d4c6cfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20L=C3=B6hning?= Date: Wed, 11 May 2022 22:16:31 +0200 Subject: [PATCH 22/35] Squish: Remove unused MSVC2013 toolchains Change-Id: I2a809150e93e1b17eb13482cc85985cd9ce64e1d Reviewed-by: Reviewed-by: Christian Stenger --- .../QtProject/qtcreator/toolchains.xml | 33 +++---------------- 1 file changed, 5 insertions(+), 28 deletions(-) diff --git a/tests/system/settings/windows/QtProject/qtcreator/toolchains.xml b/tests/system/settings/windows/QtProject/qtcreator/toolchains.xml index 49518d2d28b..b95c78667d9 100644 --- a/tests/system/settings/windows/QtProject/qtcreator/toolchains.xml +++ b/tests/system/settings/windows/QtProject/qtcreator/toolchains.xml @@ -19,18 +19,6 @@ ToolChain.1 - - x86-windows-msvc2013-pe-32bit - C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/vcvarsall.bat - x86 - true - Microsoft Visual C++ Compiler 12.0 (x86) - ProjectExplorer.ToolChain.Msvc:{d35e7a1a-5ab8-4fd6-8a2c-634846c669bb} - 1 - - - - ToolChain.2 i686-w64-mingw32 C:/Qt/Qt5.4.1/Tools/mingw491_32/bin/gcc.exe @@ -47,7 +35,7 @@ - ToolChain.3 + ToolChain.2 x86-windows-msvc2017-pe-64bit C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Auxiliary/Build/vcvarsall.bat @@ -60,7 +48,7 @@ - ToolChain.4 + ToolChain.3 x86-windows-msvc2015-pe-32bit C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/vcvarsall.bat @@ -73,7 +61,7 @@ - ToolChain.5 + ToolChain.4 x86-windows-msvc2015-pe-32bit C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/vcvarsall.bat @@ -86,18 +74,7 @@ - ToolChain.6 - - x86-windows-msvc2013-pe-32bit - C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/vcvarsall.bat - x86 - true - Microsoft Visual C++ Compiler 12.0 (x86) - ProjectExplorer.ToolChain.Msvc:{7ca0887f-a9a5-4251-aba6-560a15595d20} - - - - ToolChain.7 + ToolChain.5 x86-windows-msvc2017-pe-64bit C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Auxiliary/Build/vcvarsall.bat @@ -111,7 +88,7 @@ ToolChain.Count - 8 + 6 Version From bf49d143e81f9ffaa42e4e64a3a129abe082819e Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Mon, 16 May 2022 11:17:51 +0300 Subject: [PATCH 23/35] QmlDesigner: Fix warning in AbstractView::dragStarted() Change-Id: I3fc0bede9fd58b7c63cf6c28a982e4662766f375 Reviewed-by: Reviewed-by: Miikka Heikkinen --- src/plugins/qmldesigner/designercore/model/abstractview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/designercore/model/abstractview.cpp index 3be9ae3a38c..26040ba23d2 100644 --- a/src/plugins/qmldesigner/designercore/model/abstractview.cpp +++ b/src/plugins/qmldesigner/designercore/model/abstractview.cpp @@ -398,7 +398,7 @@ void AbstractView::modelNodePreviewPixmapChanged(const ModelNode & /*node*/, con { } -void AbstractView::dragStarted(QMimeData *mimeData) {} +void AbstractView::dragStarted(QMimeData * /*mimeData*/) {} void AbstractView::dragEnded() {} QList AbstractView::toModelNodeList(const QList &nodeList) const From 0d9fc1fe11e772d9a180f10b4132e489e2f63abd Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 16 May 2022 15:20:16 +0200 Subject: [PATCH 24/35] Add change log for 7.0.2 Change-Id: I0a3dc8ef5a4bcb56be30cc16537a221368228780 Reviewed-by: Leena Miettinen --- dist/changes-7.0.2.md | 83 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 dist/changes-7.0.2.md diff --git a/dist/changes-7.0.2.md b/dist/changes-7.0.2.md new file mode 100644 index 00000000000..4741a483152 --- /dev/null +++ b/dist/changes-7.0.2.md @@ -0,0 +1,83 @@ +Qt Creator 7.0.2 +================ + +Qt Creator version 7.0.2 contains bug fixes. + +The most important changes are listed in this document. For a complete list of +changes, see the Git log for the Qt Creator sources that you can check out from +the public Git repository. For example: + + git clone git://code.qt.io/qt-creator/qt-creator.git + git log --cherry-pick --pretty=oneline origin/v7.0.1..v7.0.2 + +General +------- + +### Locator + +* Fixed saving of command history of `Execute` filter + +Editing +------- + +* Fixed that actions could be applied to wrong editor after switching split + (QTCREATORBUG-27479) + +### C++ + +* Fixed wrong `__cplusplus` value for older GCC versions +* ClangFormat + * Fixed disappearing settings drop down (QTCREATORBUG-26948) + +### Language Client + +* Fixed crash with function argument and quick fix hints (QTCREATORBUG-27404) +* Fixed selection in `Outline` view +* Fixed `Sort Alphabetically` for outline dropdown + +Projects +-------- + +* Fixed crash with `Recent Projects` (QTCREATORBUG-27399) +* Fixed that `-include` flags were ignored by code model (QTCREATORBUG-27450) + +### CMake + +* Fixed crash when cancelling progress indicator (QTCREATORBUG-27499) +* Fixed application of build directory after `Browse` (QTCREATORBUG-27407) + +Debugging +--------- + +* Fixed pretty printer for `QFile` in Qt 6.3 + +Platforms +--------- + +### macOS + +* Fixed compilier identification of `cc` and `c++` (QTCREATORBUG-27523) + +Credits for these changes go to: +-------------------------------- +Alessandro Portale +Artem Sokolovskii +Brook Cronin +Christian Kandeler +Christian Stenger +Cristian Adam +David Schulz +Eike Ziller +Henning Gruendl +Jaroslaw Kobus +Kai Uwe Broulik +Knud Dollereder +Leena Miettinen +Mahmoud Badri +Mats Honkamaa +Miikka Heikkinen +Orgad Shaneh +Robert Löhning +Thomas Hartmann +Tim Jenssen +Vikas Pachdha From 6537f1cadc5a5083bf758a098b279a4e503f4f16 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Mon, 2 May 2022 15:56:18 +0200 Subject: [PATCH 25/35] Doc: Remove obsolete instructions for registering QML types QML types are now registered automatically in most cases. Task-number: QTCREATORBUG-26617 Change-Id: I4f1e2a731893081cbb0c399e7742b3656f201a1d Reviewed-by: Fabian Kosmale Reviewed-by: Thomas Hartmann --- .../qtquick/qtquick-modules-with-plugins.qdoc | 40 ++++++------------- 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/doc/qtcreator/src/qtquick/qtquick-modules-with-plugins.qdoc b/doc/qtcreator/src/qtquick/qtquick-modules-with-plugins.qdoc index a7518096ba1..e49b17fad1f 100644 --- a/doc/qtcreator/src/qtquick/qtquick-modules-with-plugins.qdoc +++ b/doc/qtcreator/src/qtquick/qtquick-modules-with-plugins.qdoc @@ -41,16 +41,14 @@ \title Using QML Modules with Plugins - QML modules may use plugins to expose components defined in C++ to QML - applications. \QC cannot load the plugins to determine the details of - the contained components, and therefore, the modules must provide extra type - information for code completion and the semantic checks to work correctly. + \l{Defining a QML Module}{QML modules} may use \l{Creating C++ Plugins for QML} + {C++ plugins} to expose components defined in C++ to QML applications. - To create a QML module + To create a QML \if defined(qtdesignstudio) - and make it appear in the \l Components view: + module and make it appear in the \l Components view: \else - : + module: \endif \list 1 @@ -97,26 +95,13 @@ \c .metainfo file is in place. \endif - \if defined(qtcreator) - \section1 Registering QML Types - - When you write a QML module or use QML from a C++ application, and the C++ - is a part of your qmake project, you typically register new types with the - \c qmlRegisterType() function or expose some class instances with - \l{QQmlContext::setContextProperty()}. The \QC C++ code model now scans for - these calls and tells the QML code model about them. This means that properties - are displayed during code completion and the JavaScript code checker does not - complain about unknown types. However, this works only when the source code - is available, and therefore, you must explicitly generate type information - for QML modules with plugins before distributing them. - \endif - \section1 Generating Type Description Files - Ideally, QML modules have a \c{plugins.qmltypes} file in the same directory - as the \c qmldir file. The \c qmltypes file contains a description of the - components exported by the module's plugins and is loaded by \QC when the - module is imported. + When \l{Defining QML Types from C++}{registering QML types}, make sure that + the QML module has a \c{plugins.qmltypes} file. Ideally, it should be located + in the same directory as the \c qmldir file. The \c qmltypes file contains a + description of the components exported by the module's plugins and is loaded + by \QC when the module is imported. For more information, see \l{Type Description Files}. @@ -127,7 +112,6 @@ However, this automatic dumping is a fallback mechanism with many points of failure and you cannot rely upon it. - \if defined(qtcreator) \section1 Importing QML Modules By default, \QC will look in the QML import path of Qt for QML modules. @@ -145,7 +129,7 @@ The import path affects all the targets built by the CMake project. - \else + \if defined(qtdesignstudio) \section1 Running QML Modules in Design Mode A QML emulation layer (also called QML Puppet) is used in the @@ -169,7 +153,7 @@ by an application or edited in the \uicontrol Design mode. If you want to use a different module in the \uicontrol Design mode - than in your actual application for example to mockup C++ items, + than in your actual application for example to mockup C++ items, you can use \c{QML_DESIGNER_IMPORT_PATH} in the \c{.pro} file (for qmake projects), or declare and set the property \c qmlDesignerImportPaths in your product (for Qbs projects). From cf5588924c8265aa0823d94dfd9ef79f6afe2917 Mon Sep 17 00:00:00 2001 From: Vikas Pachdha Date: Fri, 6 May 2022 17:38:50 +0200 Subject: [PATCH 26/35] Doc: Update the 2d asset import documentation Task-number: QDS-6754 Change-Id: Ied5026a12f08fcf672e1d7563514c5b1054f6532 Reviewed-by: Mats Honkamaa Reviewed-by: Thomas Hartmann --- .../images/studio-asset-import.png | Bin 0 -> 36190 bytes .../images/studio-import-metadata.png | Bin 17685 -> 0 bytes .../images/studio-imported-assets.png | Bin 69956 -> 52023 bytes .../src/qtbridge/qtbridge-figma-overview.qdoc | 4 +- .../src/qtbridge/qtbridge-figma-using.qdoc | 5 +- .../src/qtdesignstudio-importing-2d.qdoc | 54 ++++++++---------- 6 files changed, 28 insertions(+), 35 deletions(-) create mode 100644 doc/qtdesignstudio/images/studio-asset-import.png delete mode 100644 doc/qtdesignstudio/images/studio-import-metadata.png diff --git a/doc/qtdesignstudio/images/studio-asset-import.png b/doc/qtdesignstudio/images/studio-asset-import.png new file mode 100644 index 0000000000000000000000000000000000000000..9b047caa1fc84882698453bf5e053805c550dfc0 GIT binary patch literal 36190 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 literal 0 HcmV?d00001 diff --git a/doc/qtdesignstudio/images/studio-import-metadata.png b/doc/qtdesignstudio/images/studio-import-metadata.png deleted file mode 100644 index e7317402f821f814dc54e75671b547073891c4b5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17685 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 WzFS@s)y}}cz~JfX=d#Wzp$P!b{Bx@S diff --git a/doc/qtdesignstudio/images/studio-imported-assets.png b/doc/qtdesignstudio/images/studio-imported-assets.png index 7915769ffabc850721b069a2082f2443d0caa277..92042383078f029a21a30eefc75e16bddb255b73 100644 GIT binary patch literal 52023 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYU}EH8W?*1w)6}kIU|?WLcl32+VA$Bt{U?!? zfq~02)7d$oILO^e!PC{*%+S)zOxH-ykb%LYb8c{X#N_W{cK5%h@`pLy_^@$$P9uYo z@*0j40+EXZCNU(o2nabGZSCL+6A=}h;}LqK=_;4U+>S>JG5EN3I_-s)YgJn>wjnxhLet(Z6C-*imiF!O>Q4n}` z`cOLSQ3i$&%#{^&B^&JjFs{#MU}7k^s;44!{NexRT>)z03S`!JAXK7^W~V&Ze#2IcZl3B^Y(96g$Q^Q?_ z$zeA`LTF=<4%2}{3=7scDCw~rSjX59xy{I(sbMcGLs?(M1b&AEhK89=I%gOZESMOa z<%G{NEBG)kFu1h;!OHl8)*T*<3cL?ab2kT**Y_+kEo?z(S(9OVApuKK`GILl$?+5?N5{}v|Zm8}cvdw!b5 z$uRHxbLD@>TkHS!XZ}nAdqfiRQa8OVee= zdCb7D=Y>SfiYekg$2b@mToyEHZE$4gIViH`0Nr5S;Z;V9P;63*P4sgkl!ZfVkG+8#nyi8R3z`Vrw94buR4Z?3Y;#vd_ z>`ScRq#aA!P%1qDvo}vG;WEbb%W;xgC7p7mze!>3o`OD@n zcqQi*vDH^s%7*S) z!1=)V#rxv_HvLNG-PG3VwxG>paY*v^W0Jj!V#kb9KSnrRD+*(Nt&=^&Hz|74&o@40 ztiPqp^s9Y>or_nctx21hHuqWKSw_BN8y|eIygA3~oZ>m&bJe=cy7syouVt-GTU)o* z{8rVieYcX{7QGdF`})@V(t^1Tb9Lr^waT^nUdp-4Y**l})?K$t&%d&}ocy}-CFj>u zU-@3%z3Bcm_sin1;;-Icdw)^h+`xpxY=UHtp+)kCGZT_uWY5Ulaq&aT!xe(3Gj>fp zlCk)r=VJ98YVX?9ADdQ)+oi3^mq}V*;IU)_k`0z)61rd2j?#DTAnw*>h#p7Qtx(M+Isox;@P`r-&uPz_sZQfwnuAM z|Mu0JEqyZfuw&2!Y|T{Fl%ar;R0 zgT1G#6RhlPQ-7U%$!vGbj%j|?{Pumz_9@-B-KSi4t!`!=`=5Egt$&^V+y7(#!^%%$ zAN^Pp7!NW&W!&2+)wr2Cn^~S^Cd*QGQ`TPA-E8_icA`!^oV=0pMU(Rnh<}p)nQVL~ zU1!!s(Ni3AMWdvD8Jtn`k-H|?*LI%czCd06vY$RL&uru9c;KGXu|qyna;EstS`kex zqg8sZ0=ER06qbC~xwhs>%9o#M}4o;y9S+$PdAazc$o z>kOgko9v%9D>wz{OZY!sp64qo{HbMjtH0~MMZJpxH*VkIWi#p7+_0(NEbdy@I{(UO z^LHyfX3Xgyq+K~ta?(!a&%R+U*Y2%3f3xtWuH}?DQ|2rV;?114MfTM`>D6DJzg()oww$D%MRM|GM{vkCRJ}oA!s#TQFC{ z_T$edO_LulPgy>1uAjZ_m6>-czx(`|nH?J#yEonW{5*T{l6OAako(|A z!hwYIha>sl^KrJ%`#0tP<@Se{+|RgQRd!SE?Vl?zFU>2p_fyKb$q$!rS}uJ4R9)Er z%GbrKpWpxc=(qRzh(9+zaR2N+zkglj%FjjbSFc=ebzJ$l{GM}_wjY=MS$pnw?fV_? zcilg}SAM3(ABTSdpD+GOKEC{d|989RHUIwTe{cExTi4yy6l@c;jRBO@a{eFI}- zV+Thkd3pIYOP1!Oq{W4V>#&PUvWWP)_-tLXMORtJ*2qRhM#V(OB*Z%;B_^e&q~^?# zGe`Cu*|TNOohx^q+<9W9Xrm))s=%SItL4DL!XqLgqoSgtqhn%XVq;_D;^N{H5)!jz z%bqJ&?$p%O?%A_<%9N=rY*yYrq3oRE(J?8BDY>0JQ&+Cpx^T&w8FQ8$IC3^Ur|iU; zD~dXf>Y;O29s6?d>NnY}%NHL1DXyqz(F|e}R@Al&@tpQNVCkQXd6!jmOms|anp;{~ zd?pyo`J?TTl2tdMtaG-YjH-%-r*Bg6`rSu)rv715wFxh3Z=1P7O51$eimj}+39K?& zl_!33^xRT0v01TY*QYOEBX>NJG;uJF%JmM3=$bM^$TeI$x7E}qR5(0GXU!GuIR~># z%I`dVp|a(U(wfU+>9sn0p6G13qqX9cPXAi-)n~ODX6mGrT)K0gbL|zqBd>I}Tv6F_ zMQ6_)oruKKSFTBG>9AYb?>ut!(3!J3HnzI%9xOaODkdf(GBPqMXaVLE922v7&z>b~ z)+DE-JbV7UyQha+L^vfUTPMt4$IeLenDgN?M~r)HtaEKxcvwVaL}XNCRCFLAVd4|w zvw6?vHCxs!S+nHIohxUqoN@7W4oL_|sSTXGFQe=`Xu<5AEHwx!1lhCrMU>HOSi`(t<79Uw!-9 z`KI!$&U&H~+bT9Lop$!f&PlatSuwsV=k)I1vZA4~aOT90a3`I@l<=jK8`edzwH3zA z?I^u^=166vouR69OS)fNkcXRtwT>9;`T5nAdFfB@+>qjAG11Xdm65)C<+2MWiw--> z*Z6QA78V&15gip3TN9JLTeh4za^%jPJ6En;IdkUBkt0X8Y}vAA&6*`kmdu$mr=+AL zCnqN+CMF~##K*_S#l^+O#>T|NL`O$QMMXtMMn*(LgolTRg@xt+|NqsoaSs?67#T`} z{DS|FY`_rwon4iIfq}EYBeIx*K};2d89jqkJ}@xsaqx6;45_&FW^Z#Zku=KOiDswQ({`-#Q}B8mr@c$iWQ78ZW*WZN&fD zaCiEy^7rrV_TT+|egD>Px2jEl<#V{YO3mm0Ie~xgLqp%ohGrM)|8EamCh3;)B*D#1 z`pm^=X78^`DwmfY+r69TbF>aqv5|;lN{xu)ep{Z{%Qg)XQklV1T=%92%BQGXSFJAh zTK@3uwd%uXjV~|A-1%~5r_|p2;RTFuuvm|MT7o{T1(b?)T*6 zom}1HYH-GuZ({nAMRJO{KaB59R+9LX*S=T!{|b>*X(_gjv`CeZ&g|>!QnT3mCf^k8 z{^NS?lnQ_AI%&T4;3eh9RXqDDp0_f8_ej^1`I&O>WA%B*zHM_(-g~XgemjUm{rzs$ za`#Ddtj>R4$CT;*<-c2-W1`2O-{_)0}UF?V2}vnrTMw_UC*aTM1Vx3V;Mqc>vTZYrivtmc@+ zV}?`DOqA^YvgB#a6Yh+!yce-9Moab64q4@-E+lzs2epyLp0^ zeE)WK&yKs5_{0XC*zYr1Ol18E&b;Ac zJZ0UU`&<3!?+GCc*FQBZ{qYulb|F{(YkLRJj-9npR^Z!d9s<*Rpm0&q4mCoFr zGhrcDYlhpj5Tl&vzTibKI-cf#%Kxrn#U|OOSQ20 ztcd!|me;#f&d3Ov2`k1e)lh#E6lU>+E!gDsvJlrm?k!1Df)3^n0~n9DKKxxIwNt{6O6>=7E-T6SiGf}@91o_51ir&+F?Zj&O~Cog%l z_~GK^W^Z^IHh3Dl;neoClB1&AndiOMU?Mxw})kGWyq73j>ayB zeZOulm$Um<`856dn(S=b8V09pahp%bSNvdT`O`2*iGh*rW#4hBN_MTv!V0#<8#$ex z-khmr>+Kb>N~a}l!6`kCrVzBCzgwgY;HkbR;q**$rhfKSe>N&%co5yzU!<1I>NLM2fP05KB zy^UN_ftj6G)3iKY4GT>axi+ow?8?iqdh=bvynEhJ$Gp&B#zlEfa}`f(o&7c;ME5{} zqhU^{+(O1iA^XR&$|qGK-4>qQ*~F7zv}F;;%%rCbTFH|vsynpRI4?bsv^?o$;;bIR zXLQC(MZz)6WLe|6=0*GtUK75>E&Lk9rf_}HG*REjkI&zelWg$emE>klDf>R>-7(%j zM*!C zZ86#2=$y4Ng^MdlB`odqlh&LGbzBoQ`+{2~xz3(rb$upy?Y5RmO6zW2lLeAJF=v7r zSx&Fun2@lOsUx`MwAU2ICrsjbZ95{Ow`(n%X{ z)G>J6D0!I_a7lAr#KdVr3Zje)MNUonJut=x<}Z%#B|Ng4UVs#xXfIl zE%V};!k-J1mIy5{(C5$@;_3So8Glr(SJR z+PwZ0pL%<1Qq?+N%acjdLQ-b>+g)04C3_MVSN|zB`N!Q1@?i@c9ik2^Z#rhHwAnE( zX|mAE8IA$>o~A^xD{@SbVRlgA>2|oM?7^<*{is{+;r`_ZzlvY%*9cnV5~L&gr8f3a zr;P*KD+Nj2zo+`;Sb2M6s#U!eB)NWmy^?vfYDJ;*<2GJtx#9<36C~1PQ>B+=29>p_ zoZ)bMwJq08=kgYx(`vlhOu>qoH`8pL?HRR~JUx42io(oNL1iDoHphyS%W@^f7P=ow zInp%W*GpNd3;OZmyxiX}m$S3~Za=-BXpJEv`Jj@bXNv}9ET*U1BV*SJeW z)(4rHxji_?Q{fjRpAgOba{a-oDWA4Gns^jRCH~Z&viyDVhi3=Pc(~HyiWKkh%U?L3 zID1asW0P(ldHH`Tu8|kN@J*?Aoshx0G1hLv&C6Z~75^?%(>Krgdd?~BobN5h?njwg z&-ZEE=3Ksca>xO%`QmxY1k@j1b+VpiS7Z0(x}$*x*Y$sIE@r>Hl6~#g){EIU=hl5_ zUYVS!y1#qRg~@TMm$#bi{%~g1OVLf`oWC~A?fhBYzTyjC>&@EVItuKmU*(jm87-~9 zSgyQZzV!aPl=+d{YQ^HWz5TY=(5QOBy+3s-wK1Cv@&o04j$FEw-#cer#NV(J@jeTM z6wh{;_u3}^j|)_OzGJ`nr1fvUw>frg+A=F!q3hXcHTh2mlLffBx3tE+->JAv(cI^l z=I?DYK9~p1nE$TIs8pn|!?D@erONKf;VGPbxlGMGdWV84d*4Q1kdgbccS7yEfiyge=GN7&-;54w)U zL@vyE&3-@0I&-Gt^J_eNQ~W#UO+M(Y(OL6ZY4?4F^KL5{rhXPUw5{^JUxF~BzCeYI ze~Ji$;Y$AXVtrq-&a2HzR8>1B&l%x%|E<(|>$tau%wa7GA5Zt3*>j=b>Z8oAH@>Z| zmnsU@8_92q(wBYU@$h}uuh_=O?cPVjj{LgQ?mSEHj`l)T=9CK_56Y6FFF%Yc$)2)Y z_Q}&3C$l7yt39K3~s1^ zw!u>47yLrhk%C8ygj^N8f@F82AnN~6vy)y?hE#;$KJZgt5Ks%=x( zo>>xhrFxlBXJ}!9YE5u!U1+s*xv)a_rl6^vi_PwoEu89@y5yb#&x)Ft<>j?U{0;uT z$`Iq#WxV^lJ$wdZN9M~%;XOG)@Bi6kSS?j_TI#%z>5<;KjHtj<%p6B%s`ek>tKi5g zBdMVFGr#`d>F(=A{9)Jrdme0De6xGL^z92bZtPXm`=jLE$$7ataOR3)*JTrWyh~z? zGG~@fT5~8$Z7JtNm2j8aYK)z8)HIlMFJFwj#mvkR^mM~h+uR)zty>Q5$>RM~x25E2 z(o89}o!)0x{t4TwquC)S6BzvAQmwaWNYsRj9X}kJT-eSssxWvdu8(d@n=mU)fk8eZ&MjauVVa}Go&^z(Yu$Gp+PLTLX$6G|5BHYb^)cp{wy8?E zVZwta0uSE&n-Fu?U@uG1_g4)si`UFgnZ>tEE+Uojx>W_SOW zBL>YT{~qh7FHSqRJ3K|zQdRBb%-s^L;#XTV4AuxNcU{-FKvLzzmXK^!*F>?&J=}|q zbREl=7ipg1SbEaz=9iBNRx!=NYL%^b`yG9zdtWH*T`S0ICcfubj9;gb)FjJJw^c^h z{X`Dm{ot9^a#_f!=C*ZJJ>N#JlG99f*BBIcg{_y4>Rjip7`G_<@D%or4Gr?EmmKj5 zFB6jMbX>N2jpU7`T2dDrW-gi*Xvx4Ra@G0hwLk1!3>&*@wr8gOih9-SVY}{sWP^mo zLX}0*t$TTrDvBgp&KzZ#WV8SD-tvC_`>~#V9iqBPA(33%tE{^Fi@Ve=b{#P)SDZZi z)3zN_E!&yzh&DeI?6-Ew~C_bT7Zr?%wecI~mQKHSF3|M&6xdhuUO zE&*MpnbVI(7`3a+3l-4i<_fymRN&+^XU>E}0lNd7noMo>bxfC=(UI!+-1I`lpXIst zmPt$f5U?w?mp!s3wbJ#gx}dGn00>E8b>MP=2lO ztpDGq=lq(R_lrzWPL#0W&!0QzRa5DN^Z&n7HADJYWWT6?UKWS3K43_re8y;RP zT9d0H(V;HKIisniC5cDiTIB+Un@2zIWl;2zxT(s1(ecdtjeE4Nv0E4(+&e4yr?TdR zvHjjzy0s_x2@i0{wJlN5; zQN7*KCs_ZK%=L7E2f_{;@?PvcKYMAbV7x$bR^{K=CH)<$XI&?0t(^0t%!pIwkY{JZ zhqIDPE-;+(o|P$^QtvC1tP+;fzfAP>od479{~zbttZ(POqw%Bo(hzm5C{?v7(iof|Wc1juT`(ay?GiBpV!EbY5XAzktHBwRzo%f~!yL z4vM>!c~ja$@Z#^+FJfk%@Vvcb#jM{tXLeS+(KXI~AI%xaG_QSj>Y1vU3tyj^=(6U9 zH8UgAQ_hwgCjINu3Ym;kT~3+oi@Pr@>Bnw(+D4FDYg2sb!_*Av{ARVs;VB6Mt-o(h ztzWmd;+M5010%~zmH4z&$t4^I0^MFovT5E-esIvhlBek_zr~7&mC~nPD15E55=qO` zbyVNE{oUG*rOz2uR&~Gk=vn6>blCWESEc2_&i8Njc8B=~_vI$%3T)K5{Oplo+v3bw z-cd7@-LE*VV{|%kCoOLAnK!>3Ds`tjR_!vhGs_7Gc=x%-$Nx=NR9F*xRQvTbBd1GI z5^=pB`Yts%JIuM@GtX$!7oDKZT?NTYzdg{&?a1|roVSPJiSFlza()|a85hN04A5GC z@@SUBgP6_pLtIocyLmE7SZ;`|v(L)h{YG$ViQgtBX5Cc^j~{=QT9$5T^kL1t{@I7G zDf)Y!&pfJCIbZ*h_bc81tV=JQy1o2=-LF$qSMRm*II^OBk(q+O)Q7KajOT;2PaB>1 z-YDb6W4r13Z^?#+uqBTlFPr-1i)!_`yyCToSv>DVtL{B=D)*V`PnStN69VSyG+&cF zyW+9%x7Za5VIFC=s2{SZNCJ>H%xGu(NG!7AlIKfkYRL`y@atj!> zBy@a?IXIsB9a;1FLgfAPd`WJ+Q?(86rM1=_Y8GwPdhy6?LzMsXZ4SQ|xvf(uxaC-F z7-3nwso#Is#J38ndl?M79IS3nzPVt<8l%Tw?ET|4-=qqx76|6MvWLe($LLl#yP<)T zW0~H>c0{&YF_ScBnj*c};@Ay_^MK z90M@=eOsn7I|9{fO8;tLM`hH6k;6CkkQ#bL{ zFY#CG;dXx=6W5*O-OYOG-nA`n>RRm_Hhp1-Z{bG}SEVo6Q>+SC34XX)DoX@Ma^V|Jj z<}wv?`_9-ooELqz;X}%^Q-1$;{d{Y`_IG$qZB^w;ECOeyxro@bKNH(ii% zmRNrDnsm>v4nf1?Qt$qk_8Ljtm#pwSY@eR}fKSXa)hX=Arc3*CWXh||-XD!VBj^17 zH$!5tbH|KpvAmib0xn%5$tCcBDl4?IvhxZmPE)9&vFdk^r38FvcsJ-Yp>@1gYP z?}ujZet3-U(A=ZDrhbWSt?HNJdaiP2@8#y8hx?X)^%l4!yE(n%wO7^i@AY>#rys8T zzV!UvUj4#v`)<7Xk}B^L|K28_aboS}$&c4BIi6gw*2G~?*^)0h%o7Ay#20>FuxodV zaFOisQVw&L9YxMBS=2=ic_z+i4Lot1_tPCS-zQ6C0`l|ri@!hDcJuRx=G)I5LBlPz z0kwa)#J(3ai5mx4n4D{3W;oeaySZ@gYdeeg3FYPQdS!dwcPDRooHcWwJHP&h@|tgR z*jl<(uQqd4Eocb}sOfvHx^Uh+ISsc%n@q*IEQ3$|*kaY>TzAv5G_(|o0!w$(|N!9#k|`ugWesy zAP^z4qj!o5*R22P84Yh{U)Rm@jPr^Yc-C*paPL^&d#xvKt*6CyxYr0-v+GHDRmICG zEN1eU&M$Dq0 zDmXvE*LImh)+4@iZ9I|eHA||T7zF%Rb^Vh|;a#eD?d*z2b1byaCI_5IuIx*+{?8ylaOJ%~BzO%TjVD#zU4y|Ruj%~M28~1p;{#e_!N&nc1 zp7XLXdjb!Ax!h3J?qu6`asy+`1Ws<%R*AcposU!=cW66cs5ZZ6qer^%2@j4GMmLVr zi{w~WZA?BRE2Qw@-Av_7!=oL>T@vZ_*6t}H4BaQX?)Gd6cbjzLOkzY~U-+j8vzAHo zE}wnJs_~T3NUNd6wqb@#kjT+0)wsn{0uT2(a!DxgEplyn_u|iEFPoFcrp`E{QT5#< zaHsC6MH4z!7S0k6y_n`Q)ALZVP^czjzPC>7$}Lh(59Js*>WqxkHF_J=U5##}%n{$R zca`=@tJz;g9EG`*LeB5`{yVa-JRp7JTZ93 z_w-9P{>KH+msG!MIKgCIcKn%-bLR+5A{sCM2kn{U_l(g>S?2HE{53iqXhcIkBe6WwXa4SC;io zoT{pRPODaRbk0yvz34Oh;lvdxGCGFKHC)b{O_V*P6lPv`k!#I05A~-%;=Dzd-tL-K zVRKW%Ira57)BDFUs0-nu_k)?jusEB8QcHo0mrldUzFlWKmXD>+=vi>sxwMmGcGjk%(T$N4a5c zU*a6UbtydkvfzhFOjF;-rx$pbTu+x=G_wxQ4|%~G34xn zT;{QT)m7G0zI<^}4h#9jW2DB$$k}Lk^{tY0qldmj%#q{G9?xqUR%Be8_tJ==A+twcWA+mA7uJa409&@w2sqyKu#f;L`hh*eR_@eGzkWfy(+jhc}i<_Y{ zQ|N+{o5%}!t!vKT7@OZ53zcJb@!{e;@@D_y&KLi`ur$n@$Uot})kis=3GOVcf|~0K zT^?GB?bJLj6LjQ|!5rm}lPuaFN=L2}WSDeALA6zdBWBALiR;fb)=WqcVe^{zP4s8p zG)CJa`TA$B|G#L|k$!IT;u}j`1zk35*e-h7anp%op~~xyEMI*<;g_C3W$MTMRSriU zJ-Dd#qdBR^PP@}3D5+#Zx#g1vuK58@^W+}ARQUaD!^vZAQ4d;L6h5y}%yKG zNZGHh*6{D)OU1`i9SghzoaPFDc3HEx)9vC6=C6V5YzuuA6}cjgEK+4NR7fgJQh8>2 zxwQG8A^VpJJk1Oa7U3c3st!kzsvdE9Sr%r_N^%T5#;D(uW21LmxIu_#f}Hpl{x$78 z{QiF6QBsxK{oJFf{EwJ>W5?0Pj?_(iW=wg0Bu3OlXO9y%XWqGeC7$J{v&!Q<<)xc% zL^Us(;naLavg^`<%DXFc)c4%J`S#w!kcuFwGZk{G8W)~OM!onnrNp-L$IAnv3(97# zbTLqhuzB;WW$x`=kG@5Cgm+AMYO2#^(BEC?$~G~w^L(dv_486=p1x|P8*w`e@9%Sq zZ2Q&5VWHh(mA*ZA`)%`UC0DQh6!bXoQs7X9agOKvnfKlt-&JttX6$wKjsEW(`7N(V za;~3QzO9`9ZsCQ-$4TWq2aD6}@61$b{<6r!hiBV+(cQ~WZj^YuefKfjzs@Z`O>W?u2(-I>!wgWhlMTr%^=|L&Fvd`Fjm+~2-iSzyZgw+a`WbePST z^Y55@*CmR*k^5%5{)*jhQ>Cu9u&hW8Ikr0{u#0);0WQ7D9GRKQ&YtJzEq*hXnL+W; zzln!-s&284UB!Iv#?|F5hn#cI*-dtoi!|H#UUF{W+`U%OV<9Ci*zQF9!lw&2k!f*863$5xup#8G;-cr>-yB;+GIR}}2%iK(^N-=o!Mm%O# zS(RN^;qzL!WbgZ3*MBaGk2$Z?Rk2=CJiB%C!;5EbKaX5wd-=q^oBMpPU%tejRBUZy ze(=Jv*ba`mr?bqf@7wIC`TwYv*=(N8DU{amo|*q-3W-OL}3JgXGnp`U9%=k0V8b3X5? zKdc&6{_G1&!URsRoL2L26xb8@Jpp z<(}Jb&YAIMUY}3y=IQ*C|04d9c4eR6YXzlij#aGPjhwAkF z%Ky&&c+5(??}@{i^S$*Iv;VIyJ^N?#&iRTDD$B1Mw;g($bSq$oZL-Fe&*$F%UGUqk zwCK<4iu)PfyPf{au5l^!_EQrls0p-_+C@koke_%=~Pp#77y9 z(k|J7jvKfi>Xoc8yFa&fMnXkj_trRPMNWpq*VVkOjSdG2H|w9-=o5QiyW;ZSp0vnfZD5)E;YwxV4u-Y|2Lw27R4>@HPu<}`!lJ#~+h1r)lc)AtpELMqbvJ`Nn$Ol{lMXUifJ)y&DG;- zzVyJjW9eniK4w?_i6?&TmpYR;rP1Pz8mA)nMy*p14uo2m%yr(C@ts+8<*mH??3%3mihTvY4O_Owuh~_T^Y5E-|G#a_oifcAHYWvctXTTzP1dtoIo*`L z#c$7+o5g-;Tk_;^0K-o|zUCBmpQkmu*t;W2U%nR!`r-O@&RZYRh8yOGC0kM$4oQBv zw=O;O{%0No4o@RzS+`}n$7zolod+1q z#XI_ss)Uxtnr`!5X!MWi$*(0bXRhjceG%NGG4J~1d5^6QmkNsaZ?;``{c`rj$dpAt zlZr*w+OIU5qceT^-_w(nP1CibCtA**`R~N-o(1drG%s7t+qLQ6oqMY@E^3x&Og(<^ z0)wIL%qZ!q6Kjtv#NFL^F(@+3PRrLiVL?uoKse90CyX7kbzie?ygRP&L2h|Z%B`7t z1|E|P7Vc7?bdjfd#`d|^AxepNzLg00AGsv_YM#M`rUU7B9t6s?{ImObhG9?rBYxWy z*2e4?YodcA^@E-+S*+5zZ=KG~rE8wo-aByEErW6CpTgLu3Sqgw3eK{A$@%jqc>Y@Z zPfx=8yX3Q9wEi%>@g?8b`t<*jZ9*PwYwd08Pd@B7nD>c6l25@+o=uWZ!EDv9Sx@I# z6{JO8h<9CaK&>g_*Cys4)uAp59wk$6HF`1$ta^Ks*L}j(`Hni#*SR~kZ1znMXi{4I zWp#w(2MHI`_X>YzGATc8>TnfX%9yl6L}&+3^NdENso`u>wiX|E`z?PffpvrZJrB1d zLE;bI<(=GHyWds(C8KLcsc*a||6|9wFAKF_&wQjDpVM>NH2vbeXRDMyKXqR!yx>NN zOh!k1WmuNmZU4V1^N!4kuaKH5Z`Wux*Y)~mkoy_>*YFv!I2`Izj}P7QK#Lb^Cli4!^-Y!Li={{ zZZ((mYq6O2^@)5u`^w86(^501e&?qrFs2$lbL2dQMs`~YJ)Z{W|r|gtlt|&L% zxa;I@&WTr*OA6yTPj9Jg6z}MnBv-VVH?ZEt|DUL?bGC4J;ElrSs-Wx6F4Jefa#H=` zUjEAAzJuQ?m&<&uyJJFbPhFLL>Tq&JLrs0ZAye~>-G&Ztn#%Q*F70c(7US|>@L=Dm zzw_5v7c6@4()h(OzF!x*x4&Axc+>txMQnYk{!9%CO>_1y6rIg!;IxS+Y15r(k=bty zFY_$gC?ph;nt9{8YVpm_Y zc;9se>wR8%%PKNgYME=C{MRR=yiIcJCWe>1TVpv|o!`j|YTS?G|G9IaT>cADr_*z; z#2gSRGjD#jEJ)xmU+5==9p+XizHWU#r_%62z=~Hwn>c=_J$*iZf%yHXFIT@^)|OoP z^vJItJALEx?e|%!9ryD~X<5RUWWRli?e=#I4>O&fcd*JMUt8>~AZNmaj41Y-uG$_6 zq3?sOW;lvO3vh(JIIU1}==F{bCKF#Dy(@ENbH44rPi^UYzIG}_&iS!3Tk2hdoBrzS ze3$B9beV6uUidrg@08aqMw;tpZ?C!IE&F75={%pU&rFn7W@r39%4D;FE4Se!JM#+9N9b;C;6)7q_=HTdwDBU#e2|%J)rURmS@I zzuLb8=1h3r^?PY^1&>o{h+GC+UfVB!K^KKDW$ICq(E`C!CqM0x`knK4syJVXlEB7* z)|N%*TGA(cnEd7VQ)xZ_XoWJaDPE!pxM!O!XezCgQ=5Q9pF{86hDf?xDjZQeZX z%a`4@&v)}=>c7}0{!gJpkMCV>$MGeOclL_gwYl50B=V>II^SL`%%L34zR_vxzMih> zVe30szy7t|vTkYeR;9UbK18p~2?^AxZ42}MG;=Gr=)=ED(=TZAUYZ%cWA^HoeVyx@ zS(pPqT{zVqHR0y%F4LlVH?1t!#bSR}YNR^;u`8c{hDk;KUA)1*`Bxo3Tt8UsROMrJ zWx5snhYjnNes=#5=4ySp*4M_`nSg`G-P_kYWW0Y>><+Q!pTN#I;a-@|`rXxR3YK^8Hb<~?E}HN6 zDX**f%h4iPYl}KYp)bwZqYL8#ACH3%ZiVbODtvJ)HbncCElJ87|FBKC$atQEDWM>n& zzH)ZTv~%$APB^)undM`~PeXXp#UbBw6)YWZzrWqZ-N3?G z)Sr5QQRDU^9qHW-Qeq0<&MvptyZSzWaJ) z4_khy|2wXuF5@uA^Q6L=sp(5um&aK&#Z8dfC)TAu?VgmJg0yQ$@w=<%wW2P5OBOvI zSi)u4@m^e8y6Sjy0^7m+2R|wl$?Dp5U-+fGBI~fKN&UT6kE@Pb-kMZ>>pkzk;8c5` za!B#RpOcQRo%lUC_I&2*-Tqk{&YwQnS32E)&Ajqm|4zP}oL_J7QR4`&-?_B7M;HFQ z6~DOX@cexreyYEY((V)4czvF9*pXEh*7YY}7A^Y`^i=*r{_NBKz9kJkC;5!NbU2CY zPL=w$s^UW0E6$KQhO_s-z5HWQ{p8u7cvEey{{8-zZSf3$=D6-Z zZemjZ-_WG~5k`CFg&xhuZ?yxlZh?f^4; zww>$kz7^fk7bacK__*NkL~l;F*dBRZ1tMt`R~Z)+jhFTH@@{(yh(cb=-rLT zD_g{bb~#nDNt)MgY%0I=^o-}0UxF9p^B3NJ(fMElL*c8YcUrGcH_h$4{xxAy`6cPu zvMC-7B}?zz_Ar?6-rw7{+-Wsd(NNMGVXT8h+_`ud1!UhIQ^gq{}Ak5#7o>Etl2( zO%{_n7Qgb!@lXpW0hx>s^a+S+OVeC1c4K zR(^%_iwh@2-|mxKQgZwGqkosD-hDLbeE-6&l?^?{YzO~t++bv6YOUQD$KI*RR@yv& z75BI8%`JECyRTa~DO>T;>0jB$77A$nIlZz3`XKl!YH57E_7wILwy&~2H5_mDv8rJ?wxIclp~HrahtIO;ixsgksXV=> zQxK@B6UaDAy6EEW73>d7_B8a`^S53&fBE;K?U#qftS&A}o#QT5SqHyRdH0v%Vrp z6gN* zw2RYP-|SPkUhQL?EX(7^`SsS@xSWrMU*eoyu)IuSI#1DC#(vNB#rry+PuP7cru_Z+ z8P+==27W(!>zV22DiI;Bzwrzw?%#6CY&fv`@VTCuhkUK>Jy3t+D}S5+qj1paKT03Z&n`J!WnC-mycFq5D9Ofctj8BMs&k{QSN@0e*7o+@Xn>7_y9m&GYCMgg5 z`4->Ov*9mqEqH!J#A$mXALr^ho?lJ7KHlz{y1n_%+=T@${$i5W9#QNEe^{`6DSUKn z(_On}78}9SFLRH5%|0V5!gbd{_2ldoynAhB6{j2VTwZDZwrVry-brsuGQ@OUr_us`(woE$=*rDN$j((mmcSjo6}+IwJa@sa?T5`K=~d9 z0rNSn&yW0n^8G=q@0)c_v6p?*1*|>v?QYrB?AW)^V28A^$Ej^|H@N=TQ;_`cQGJZd zRQCN2q06=G-825Semb3Tb8f-$W6ftX9=}Q3vQG5s(oag)YS}tU-%F@?uymaGz2ZxA zBIBb!hmO3fWBTB1yUg|JsWUNU6T5e0Vn|&|u=cGVw_39~Le1vcv;-V&PWAayX4*~#qJ%I0fa@qcE#Ug4Y($uQ;ob2Z*(mbvjN>&0KO z9gOF_&HPqj-ap1a8?C39bu8g+-8Q)>FsR1;yWQUDTnkLapBB`lJ1s&Pj&^bNUHx_e0cZYiDGk|@3fz`Usv-s z$o28jt=vzI^*Otj)qaUdn8a|T?DV>QGb`$^w|}jfZhL@l($w`fUzM{x-zybpPwTF@ zD{mZn+wOnwd2#c3$JY0mPEY)o=9^u~{mYW;J`0=XRza@y|MxszUfJLyBYVUtRNZ{8 zQ^whsO%Laq#ni2Nw)v5^y=9Ql{-B-z7q1EyO}e=6{I>aX7u@q@(|TF9kTc7Bb|N2Tklk4N}q@Qae5?lTl2D41L+%6xsb&cHz!BsnA?p^9!)z`rHDdxmp zPM)SPd5iv2{N?Lr`7m($Jz@;bY=}AZ=<>IRduCY#>Ljh5{q4$feVIt>*WJ4NUAt!o ze)QxF{gc>al`qlaXy9;e!6yEC!wHV-s+q32pPuz^eSg25700wSWy_;0Ww-nja?$I;`ZVAkZ3)}TCVbAX`3l4j$nK&G~eR=Eq#`rZdg0C;_x^^O1 zckY!9N?}(U-{;!*&Q9@~9`n<4Pvzg6SL5w9@5Pu0-u=%Law+%w+xGB1tKL5P`TcM1 z&N6`s8)n)5J?yJ|Of7Ob(zY0Be(|WQj>wkw= z*<6Q*A#w`BosL>|)loI>R{w*mE$;8hSo!ISd|sFlm%vHQFIP@J6)OIC{JGV%BH=6E z?-jg$ea-k3b!A6revEtq`%3S<(Yth!jZn%49>oRH9w+~-Uw)1RgezHLMa+m0e!#qYA^84=cof9nkwcI*S<9=kJk|D>P`MLEC zwtM;$Jo~HW+iu8h;u4y2U6c9VJZtq;(c|hS@h`jOC|85Vj ze9W3;JxS~MYR|g~m&$K^E1AIPF7>oxjg5m^SBI(T?%nzb2`mh=}LxT3=Sa9vCu~5Bw;o^^HXD>Q7Sn|ZyM_m5#a`&>& zw{G*luI8D%Wf_aZvAKMo8jdevU%n`M@|}EQ)e)cVmGXa3P|ZZ*%G-)>%yMI=aMS-&sYo2 zt~~yyb!ErWy~&%~qbhfg#JR87xg{mfALfMMrp!+nbK zz`pBgHqx8Cum6==Z{fyf$n4}a)wECV_UcPb{1anjkN6bnoCrU<_Xk6Z$D}nIVm5{I za^4E~G(z0pHoVHztG~o_h?$F zc7m(!?M=+nQf)mNY!=3=bDT2E(F&+vt9L=v@D2m3_O|!htz3ItZlF^|UtozRmw44hC*H({y{y(gi;l`M&jvIE97tJ6W$Z zdo$m};v$35&Zvz|*RSs@+_`v9={u#D>(A>)RP;?gw*b^tt8!o{T(siV+^{cyf`k6l zux|drWVLZtqTlqqs#Q-9FXesYxy578heO%v^V4P+ht5}jIsIDq{Jo3z6z{2hzWs#4 zvbiA}7+M)O%?&K8%-tI)dql0oQBFvqUZ6xN-`F(Yv2CtN7Sz76t?2!s$5Yp;zG<3v zb>sPMbJu3A&8al4OP%>Qf#H+O?f(7${Cq#}x_0XDm&W$#F%BzU<+y5BJr26Ma+UJb z_~Q8KI(8>x?tJ<9>sr^fuE(HWqSz6+xT1{@=Jmam?d6-4&0ZM8>7vu`xMV`^w~LNB z?1$4i8agH!-QCE)cT2^sZ^6?149!Q@?<-7sc<^(myO`|H`M3MmXC7twwbSao)6@A^ za@T%-zSZvQa{u@}Q`0BpPj;L&ty}$?z0upJZLPZg=bT=z|MTR>p=qp_3gUdE8A0}mg1oN<>mWY><=zX!9k_pO+-?Zu@(?(+`43x1L;`pJ6j({%0c=d$+w zjDBhnRsZWAU!DBx@=MAczTFX~I;-BVZoU!wWx|I8GLs5)cRW3Rt@huS>-xv{|Nn9L z_PPaMm#@SyWk z*{qLt{MpiR&ocIARG~}qdfV>}E^C}Wi_dT2+PGrtpM*!@^K~t|wfN>VSRFD6|C9Kz zHQn{y>zCd3_s*TOj=dUGmvZo9>srw>P0AT(msaykxVuvnip zl`onTXz%E4?g=MTyICt=>?$nTV0ndc8rTgYoK2>>iPKVnjg6(BC zdtt`CjE>b_F`X(e>&gUfd-9xC@NCbzFJZm+<(pTh_49w%y?G_Q*8BdB9WR`o+S{$P z-1*?js^zn;*Vxs5{P>A^#h*{*)3=C}*Z)$QD!%dEI>{IBW>q$~3nbokF~8vZMB#VZ zk19ujyN>=W@*&#On&)xII3>1R@VirzdS7SjTWOA~cYjo#*J4WS-#_L0j<#6>TCM*# zEn|{iyKB4J;f=Q(PgtqXSv38Uw{wg0m(9%$d`2=3D)%^}GF~P_V7SL7t!&ee}B zzkIPaws-T-7uR1``|8iHYhTyS^`Gaw`h0BtEbZI>Pj1@7S9G0W=k9fC7abaQrQTm; z#}UMMo9~w6X}NXINA_-OPFTz)+7Tt<7*yCY&s*BsTFWCR%PR!m)xS37OO}z^{s{ROo>2*m%0X!XyW07tEuK6%?$9aY6IVnx zy1f-YZC1+b>@qPmb6QLD8jUp$>ZW(k^n1?#V$~u2u9QpYT`BLUyN*J|$;tO^4k^CR zE57ma@zswnEKEPj8)K@$fD z-kaQ$*DyH*#+pUh&3S?j2*Y@UO zsj1`={b{LYM^x_`v41|>UEJ_){%6HidT-{YW-+9Eda2NU;dZ#-RmU5FuWf&S_dk&2 zvR=)){9Va{r1y6`EpjV#d%Nbw#h#B$ncVrM{`t8xx4O&=J>S`U{Gn?ah)^ z@J}3M3j>X*9 zY~CyTZuopo?FM_%!=ATuU4qlApC5Zw*5G*i*!B4JdAIf~{_L`xdF8)Czmjdj8}4_W z(_6lGb8Y3y586S=IW8ijXQtYoBdxOzb|O-PEN7^T-o_NkkN|Nr#!mF)Wa*$pzY_W!W>b+q%R z_qi&cPrOkZecT0Ik0v~>IUwW0e)3e>731^rv!WOz%Xx~n-)G`x_o8En6^+^Li>9Vr0@ccWwK7L)M8@<|mea+sLRiB?_H8@@VbbWi?y`R6P)!*Io z@vHgj?FVkXj?RA*b8+X-ui({SoQ#Wk8lsw_v+4bS?8K&sm zZ~7b(UjFV*Wzyr<(R=R{+z_3;ea}0?6Sm)4T(_K!FOoTXzl_Uu?#AEGzRubZ#H*xi z^l|T%2UZ@ta%P9wZQi6gBYgtr+U6T8avnYvelHWPsr_+VHazQ{`{&Bd4J=R)dttudl%IjtK_YG_vb%@ z@`S~ke;t{2c74veb@!s~?n_EfNPqsBVZkfe3Gd?{TFky3X7f=xVTo?RjaTt{>*E4@ zx9=-D@2Yd5_Sy9-`ow)u*mWzGPd|;jhZlS90dy zKK@CZ2b~!vh*k=|jy4mCD%VWPO*%4p#iJjmCoP(@BIECT+g@=Tk8Gw zneN-G(T)Dw_H8P99d<#-tohkS=2i9?5(~O=?llIR=e@l1NA1d2^YFZvF*`pVd$z1M z+R^0pr&H5pqr>y=Zrr%5>T~bed?t}a8_w&;-`w>{)Z*SWbMx)_H#gRt{#>v|cJ}=* zrIV}ADEe{)&J=sT(XgYRU$d#M&f2O)Rz*AU?}v8#n42lj8I2~sRWQ?f>ma7Jqp`04 z&1{a{FJup{_LMeYzW8#>;Yk_gvu^n}l(25ywRxqiS*hcu%h&w2l$ScaUBB*MzqJ3H zh9}?FE!*Z0EY0|F-L`GQx#xKG{i~(Vv9xC?H`x3WO~1i)yfEQvVS=>Xw994oTzUz& z7n_NE+uAH5Bq6UBm_JL+lW%cz0_W>?`EMz$Y^Wu95Te3`U&-=B61o&9oioET1ieS)U>h#zMuQzJ1_LUjpOeBzjgU1{Jt*! zdLL7YQc1b|V%e5gmF8J|mU2%5qJzzB9y30fd9P*L>w6E|o_+d~EOVo_Bt?MbZ6TvT z(kf$*yGx`4B;HBwmQ8tK`0{kPUi*Eo{EyD|YtE<~kiVW1aBK1Qny36fj-9&5%Dh#C zQES25mXAi88OziTiNy8ZdKr5B_X$P6MLP2tn-5Nq-J;2(`#@9c?@lePYOd3D0*AML zO1`xG$%NY*dpzTRp5brjJHLh}z&%{vQt)j=8mqm-Y8|BlX4k)~O1ZDfMJ+6K*)4EY zq;mg(Eaxfz1J=%7eM>v~;wFv0NQ2**$1mBJ+)(6B-#Y8UuFWTyTAy3K?RR;Qp?jyt zIl`U$gQ{Q|yWLTFZjBS6(iIHxE^~73-QC~mWN&4!AgtMQDD&`(<4fY>|D7@T!65kh zm;Mju7blHh2vmL5(#om&xjtigy0K<#m1wBUzOJ~RKLl1~?X3Ge^}N-*1OB3A|5&DO z|C496>Eh+|3%Yxv3K{k;Sv=i-xAVeHpF@vNbPbq0b))~vf}6jm$*R~pq}IEZHEgJw zx2NmGI;99l|G2eVJN9%;<^QfMkSsA-ZjT>N>xA^MnB(!jv45|g{rXY$_{CZ4x5ri` zcAC7m5ODl(;nr85KPjP)TbDmJj<$>Wv;4CEaq;cj)^o7sOnZMus#_AWCxWkfLFw-$xyu_I?Hod-{iYs|605oT=g^sFr5|SnceuRf6M4UTOVR8v z#|pRn+py(-Qe)|VMx(1!zpRuz_DG!DBju^Um&R0?imUa1v)**CeYNcLiccRV-#x4U zCi~yS-1#?dR6Lz(yjp+p)%k1hmhF1PajUHCpS1V{(Y=v%JBlAi&IpaGtBNl^>ZsQi z&Mz`w`$pNro92FcJ39*IZ(_K*&-7ko-G=1H4~6xQEYIJ)W8?2r-YZ@i%z5-z$nDP775AlZ8SEuiU8h$(V~Q#$o$6Z}@@Veq#=J-V$7hGnUt@EFXSMFr|2yJ} zS5DErQ?{~1?waG9Z@rsmYe!u;_AYtq|B8y+Q`67OF0x-`btka!=gW%c$9CAgzq0ID zH>f>O0t zS?#Vmxoy4G>F0)LEM0ayTz1LSeVW{RjkQ)0XH3H1+^?6(-M{1AC+qp~cQk4@24%(R za`Lx19-GhiXnWGml>zf7cvWr=Nt@>B`>_7h{drOo4&R=_|JV7H%!{ik$F;95NWL_? z$a0B)yX*6{(HTceQx<1bH`34rwuaRP4aN6O)3-6=p=12SP{?GU7kGJl){eGs9qj_ul@wTASZIijK9xN*_=U8`dt+LFb z)nZButvpUY^R}G8ylrP?2MVaVjWEZ+T!dBXGJTa%j04(#%aU_8B1 z^TAYwk4F3tYj5AI}rW zf_5kC+wYIqMOA5g{OFVo5S4RqKKJ8mH)~B}@1eTVa_hJ|OXj%ibH6zm{o-od9zj(e$7+r-q-8@wHt@Vul{HpDt=*>_X)<7 zR+*54IysKr(NlkjUYXKfB0-M}Z~nT(S}Lu(tHJDK`1PYpf~BLaUSIsxFZ$AJXGvD&8||0ETME;R zSN+=c@PPV?NB(CQl#ApFt(&^5{6g?@fnwIRcm5siuJriAe&YLgiJOA0Ti2X0NNG^5 zNSGMg{Ojl8ak$al2{@-b)DtzmoiS-^;dhI z$?woA=H)V9%Ob&2y2j>{;DzJ6#I9`oxO(>a)(cr*@3gbBtg>i*W_)&q&3OgomkLK2 z1RVPcua&u_I8QuSGC}lTLUh2{w+HrDe7w)HjLqTL#!2&Dael4n-SY0@*4zF10*>s7 zj_f-u^9D^JB=^lEUts=DQ`P}JFyetviN7p=UZ>nsliRO89+wsr*>s_Uv zm-@bv{PKzE+Y|SUl|@2(PsrE)J}jSET&OMf>-+Ir0T+M2NR``rQvPUl^Q3o+)L9)f zs;d~QMW5cTY`^U2({#U2Q0eT_Mh}-tgZq0TSSz3Xe7!e!pF)~1FMs#r?dJLNzvE8X za&2kQRmc$CmfMoQAS&d8`+dGg{{$1St=QdpM?dgb)uWFbRov%4{g8-b-*_fTFh%?5 zkxA25>}vk?toE4j`b}rI9{HL+kMo)9n*93#GkEpPIulNFWT;fM?GIrzz8}<7uP|w+ zW!aYr`-?4-Jx{hPmI@TFYnu46@03BqWS6;?9ehdp`LB#?^nd)nQT_de+B%*5lHIFx zChat~eSP{A^ZJ=)iz>FL6fh~KsLgCJ=DfyhcJN@Ivs#!rWAojEd27U8`ujOaA7Y92 zbP)Oy`}1)$j|ub6&nAivVbiSl@R-d=cTQ@u&XuT=?nGIJ(G*eq|9pS$V@b4$OFLg3S9Z;vZ|$(mg^_-5S|Uf&&BQEqTA-DXC=&hr{;F5>2!Ag`U08n&Q`boDeE{FvT%5v-yXvvQsei1$@+Z^ z+@fnW_;?T7cqdB>=gerX6i?W>xvw(7p5r*{ zufGic=xh|8Z)48lbnKU9s^ad46VHZU4m`k?cze_S+_ihy+>`GYc;8F!e=zME%QH`R z-O6@_?S&8CYz_SB$Rf>hv1+-pj+0lw>Kd;f4Z;4K&z|1DLV0rD<%6EvopTi4OwzoX zktmgS#Bd?klI*CujehOg0@s*7zFWIoZ(D)M?Z)#7mH}}J1&-gt=i8q$ih1_x^y$7w zTt({&tYeZa+Dwjam~3JGoC= zZgH$ina>@q{I+R#Yqdoke zD+n7|Zkk=Zf_2lZkCJyb@+AIZ?pj;@I6d8S+nJv9bqBX3E6nN6aJiJ3x2myU;j@Mv z(`5gnPK#$Pp0IQ059Xhn#l=mW9FyzT3UaM~9zXMQ^-`Hn=hm-lzq49WqmE&wK0^!d zErpoqc@JMX?0; za@y{6h5Jc=^IrD-e3t#>{N2eLt3KZ?Ze4Y3ySDD~X|~xGzmt}_{#f{cVSbJ2d87ZY zxm9LCFX;lO~*<&Od2qB$sr$-kqAIAF>?(&bj4!?b@7R35BWG zAF~U{{uJ05-m%Pip5B!$S5|GAQzLtH;lnvmf381H*S2_j_M+v~=V3+{yd7Z+MuZvUEG@$B}rJHa>W?E-I1NVl5#`Rd83lLZtO2W$*D z+x^>bz0I#jWk2UWW4it3H0$-xe71Yumo(m~(pxV0EdE@Nw8M*8M{hrU{(2evUxkQ^ znJO)Zj_ym$N?o|;+ZQ#hgysp6OyB29Kl!-O-Nc?_QO5T^IWA74j=N{ME0><+3I3e5 zur0%_*e>{9ZtR|)DhHpQ`pNEh_nh^WU1jrY_Zu9(GIzQBZl;vBmA4M?1WT`7{oQ)o zb-P+SgTq(en%}eC|9IVHsTqk}v(4V$-@ErtntAMb+u6Bwe|FE&m)*Q^l~2)Wz5U&{ zPw)P0l9&Iv+>rf5izL5Oa_NrDrO#)W+%2}5yKq<9od^8~)-0CnNdHk$_BqH``|I%! z$x^=*pYQs3=*Z&P+iip6w{yB$aJ@9_I_kvpKJ>&|K@q1b+IAPpPj7o>s`E=qEdGGb z#*3d$AJ5yr|L2qYg)*~Vd!EmY_-blX&1GjX`*K6Lj2I$Gv|KtSg?0{Md12SLn2B>C(^tyvcgEwSRWezB%pZOYeS} zcxn#YnW>grZ^q9*z_aPmi6_h_UL0>$FyU1!iSV*=^l%X>pCPBm`s0TE@~b8S?;S6& zEv#s<_pXs?74cbKCDZEMHp}H9d*_EG+*x5Qyh{A5!WrGqe>xsj#BW<&cP{NUd#|_d z_Uks)O)1e)dw!mKrd@n*?fL&zr_P_tGl@BEc$z;}=+ngKa=#vg#5vzC%Fccl`)5!1 zy}t|Wc8i&rKdXtYT#|4 zP#ysvN7iS{b?^IHiE{T&b8LziSGKs=x>CI*DPvk^gn|L_Ss=t`ZC$^o@MfRRj(CmjsRcm6=ASI1PQ^Q zJYf^fGJc^OGR_T((OcSmxLH}e4*kh)Jk7LFwPO05gPcqH^SGAh3cV6+UN6>kvt{?< zZMky_teVfCYWcmf&PQzquaQ*45v{Kxx=)WUPu#bv_Qw9IBaa;?#H;lu2<$vaL%(I;geJ6HX3J~fl~1!Uk+glOagOJZce3*CcIg|(eE%ghc)aM@}jmn&%7sbd+;Qnq;atYYA`0o9G@hwz+aIZC-Y~-x4jae$H|InY5!z zPa0{sY;jys=&d*DMWnA%uE3S2N@o(wlbPM~)n$x4C(TxQC)4_P*3}mN^=$^N?KkBk z!zL$2$=qb`Vp354+?>D`m=L02kgITndt+qR-A6L5lNXDh)>mP^DSJv;Y0s_JJ&I1x zCLCB@zSVw$OG^2Uz7*li_vMcYB7J|w%2s|1kk9x&K|bUAjoS)`5^k%f^cYCVeyrXw z%ha<($1u}*{k>}si#uKB=c@SK-4pVk`C^Z!{7iY4pYoG#m$N2&YaIFUm2Y*lktKuD zFUKU+ONF1CLwYyLw=B$9dg!*?yX{F6?ynBG#G`C`0TQ#wdK|$D%$Nkc*Bbuu{gSF#huix>xd^Sb2>uA$U_Y>WH zh7JX@Yf6iYwdKP$2Fw<@+j8-@V^zD=x8UV!p6_;WW-VF#~Fo_)>e&&(?FKX4w;QW|XEA^`6or5Jh4mrLH zji~v4Bzp1J=8j1R`VO(D2yCm|x%48lO7&4WS(Cy zEE{&#+&pc5`_XN;S=*;f+x*f!Ilp~?-Oqu%ToL*}fwB|ifeFEnLL z;c9+ZoGtp9pZAQy#UG9?o*~jt4pwgrxP7QQpv0q0Zrl7;)~%bT9ACQ8|5iXR<0h}m zt8PZPgdKb?ayMqusoEx+C$=Dn6c_yelHE39mO+YVN3;u&+M! z@~!lDHf6f&4R3E+{PF19ZM7dgWWxW7yT1S5>b7|0Pt7>fzudA$tX!`><@#@=nI2@D z;P&~Uzlqe>Y2OyeKhb!zgJJc#`Tx?>rql@ps%_{xdhgVYQW=5%p!CZ8z3(!ml)4Yj z$g-;WeM@RzTm0=K?SBt@ly+%Go3Om8HQIqEeIlE*uCpJhJTJyf^QhJwxgQ0#|g(bi4jJk)mO; zNJ2#3zslhv*ZM<|zB6{Dn6B)5VEA&v%Mcef&wqLMIt9B!P2+e!Cr=djp3-@{d#VD1 z=esp(i&WO|3f(XGE|F%Mcx-86oRwPTMwgj8=6#vSv43`oLZ^qDP}KW(#W_1(-QByY z{cP5umQAyILc49RzEx`WDN(lVGxM;hbV}%M5qdRWXUX!a12IY=^SwXVb*;Mj@#HOq zUyf>(=I>8@G}Jrkdd$~_O)z(YhHA$3OAkGdRbOiUB2pcCnK|sc?!^+Oehs0&3Q785 zSKM~l&+tzvS6F!>FH>W;#{!W`gMu^m0i_B{J>F;862uyUGbkIY7Gh^`Io(Zdtuy(v)pIO4wbSTp& zpu+jMpn^`)VQI029&DXv`@2pkC^;-+MBYP+tA|}Q*>?YqMcV=**x>u9=e@Tu#6A?=l}Y0_<{#f z|6FG*ulQE=Z>r_~@OzDWKCgbQ_&v+bXR_Iw#wNED2N@1pocx(|P?Sl)ETh@LJic6h zrI&@M_m^fLEw+PN*H&82pL@jq(av=4bvb{2JxpK!?E3kYu_?J{En69bDs2}lPh&__ zTrS2Xy-;;GBiH%_qtkoYs;i!PvRi%ZDVgYaY=+}1;ahA6{WY!?z6w9_v^;9_d%G=n z11oLcUpV~RPyEE%=S5P9|DK+?vFz{8or?nMmZu&x)tGYHU+12lef;(ouHTLVUKTYS zbrTHJCoGe)+Lh?^_=(1n%90tmQ77r0S6 zJ+Q*kHu(OQHEB!tr3$N7T~ZfrPB9hV`=$Tl32)W2k&jK~ST1suPPF{8LRrW~abB9n zJF)%gGgcpCQxKWzmtL87>4lx%rI$_ZeWpVGs)=pExB?fiWoPGzru@HafJ^6Ad$an*eJ@zrlt|J3E?Fc>** zniZhb>|-VRdg=r3uXjG@C*|z-4zbyZf zWvmjm%4~kY-r2}2l-QTNDqwG?q>Jhl4u^U5a@mo|tO9vWDW;Ov5bH zPup+1#;e3>tybG$qbgz>@NQDTL@A5jlMUhh%(We#n|s=MKYd^Caw^+}DSJ=vl=`a2 z|K%e7&3hz#iS6TMVZR?*6CEG%2&_r671z`ksQlM@U|IcH?!Vdd>MIL*MVEG&IzD5U zv~S>f-yrx`A^EJr{}1oxAO7?-Tyx^5=LfSw>i=nNsrh-exZB^qzsu3$9pmKi&F(kn zy)WM(a_J%-M^Db$has9#js9uRDHHCfVZ{L&&5fU$FJ>PFK^BcGRWX-kWJo`+( zb}S6eIAKKgee{R6FY~N*Wwq=ftLXpC%%^zaY9o$~0 zCHLEgR=#-D&(Zuu&Ed9E`f1%8EovMN0nzi`URuUC$$6=2v7*{hWVc+{>_vbz-1=(V=`LR{c zpLA8G=jF~U->CbW&*teLJ7HgrhJbeaxw-rHY*KxHA>OXoG}`X_%-50{7K;i$n|i!$ zh?%70G~>wRW>&ZA*MGQQ&UwM!+0QF5Vjld?jQsa5 zvf)nKwO0!!o;zq${dkYts%9}sm2V6WZ#M7>P5Ik4adkv}U0$JY2*b_KC*uCxeJg9~ zuwvHl)$=nWG}?K-EJ^zJ^Nl7qpQgO^?79*shL%+`gDWi=1dd;J`XnOqrzzp;?sRVH z2c?QjALq3t1gQFZn$Elgu#1+`iC|nIR z;@Bwf&MojK!6N_gv+k+t(_U*!f6m^#KO)xJyE4YgP@?7Ci4}Y1DLx6wHV^ z1j+B=doMG1&-f7F_Kf3<{q_eWZE$bacH8z<9|H^wXp4GR-LS@0&Z8CHD% zzSYs7*(JC6f&Tl6=Pv$pm3_$?_OtTD_NevG?$3<%#CntG08c4K`;6Pw?Ns>$GvgU5=Zdx^q3gG#^RA89I(;na#Y@ z#T*ut>=C?F;>)tSQ{h|Oth^s={Qh7?=$b6Hd)KyKH2BW;W=?5|wD0{}Pj+t2Op#O}WH#Fpky`Pb-$^1D76hyAKs@yA^CAnmFc*+FBZH`qTYyLX2 z&6Hy35M0WeQ={22ZjfDHx(r0Z+P@yuUGh)v~fn_|Mp7{n?+siPu#eraQ6R#SJ&&aCoGTRQENW> z+`xLOre3sHS6tp@&8cp?mj>s(xc&Th%oGMrgA>gwB7|iX0$H@XF77F0KXLy%dxz({ z&9ly^{oFf6WU=AXK=-aLquKBLO(S$A6#njMlTc9J;P~wrzrvpu;g@-ZHXeI+S5_N) zcnK&p)OXww+kXD+&ft{0Mo}{t60|ki>9&xO4 zuRYtmRU=niQsv!3wX?Ite;Ic~`W;zdG@B<=ldU;(zm{w2wA*Wztz2^7{E4ZIqJ!KO zexs!GkCvPPwLy>F;WujNYAsCsu`0i$^WX%r4>I46qcp6FWLjC?ua# zU|tci?C-MqU;F+46g@bwX5vkSdpj6a%9a_;-4VarLN4V^^~N{}6)wYDCyq}1nsl_^ zu_Z+1Z`?r@mBqF%j3`tzmY&QkL+)|C~1{*brU2CIn4eGTbi$b!7iCBx_UeB zr>6-999L>A4IJDOnk&>BS^xgE*eZ$u2<<-nj?lxwJTx4o-vy0DKrC*x= zDcw}?Ir~f(t+2cI_y1}5)L&n2yvw2M;(7k2ZyRDh%!qc3$%y;s! zVRYiObQh}WbGpcHw9JgdH+=KNrU;R`jkVcTuas18RW5O#TP2dJH{tf0=V3}L59U8? zoXwEo&wb#NzTf*bU5_gSrp%M~Fjq13<)@-^+tsHn@OgT4+Mo6M zYh!Ddz5M5Nbm`Nrx!nEXM{`{ixo`3so5%aQcjkh6VJd7VG;#&5*ew54wTqwYoz9L4 z|LyOuFMAeudiU=yKbP0-fAQz#s~wCj%}v_hKYRX?o#?1GnODf%aq&F$xy^^%9+Ygj zRrS&3p5~9GN!5S*HV16}b9a4o_%Z*Zj}rcgp7_rcQ8=$eP=WKPf{f?4g^OpbQn%f? z{F9W?Jlp7q_<;F()vt`D|Jn9SJCsbQmn&L-P;R25OM}W3-lCLq#_ij#$K7LD{r<)| zooz7{x9oNo`Y!!*W%>VEft9w#b(!^9VL8+1ub=JLStoFjt&`Wm?KOMii;xH?!)5KS-p`&iX$y?p6S#i2suGH;c!*G?v$pP9vSMdcih!Vk=K+PqVH+(@*xnDkaN*aIPm1MtqmG)h zr@u^p7Zfwk?8}TVYpyN&zD0V=`^>1#YTOPk_9vF42yDxHdH42&yuS}`26NB1_~(=S zbmg00bMnPyc5O*HA=r9#t*dmGclXv=*Iu1ml+?*%q?tRxwsf^r-tS9KH@)3{e~0mV zo0Q~+HQ<>R*~11M+ji`zIjoW-aFKt~9)?N*`x6r_XRmj>x7}FYe&f53vD1oMmly5h zU|``rtnj*9yGvc%!G+D!Pn6p>z+C_Krauj5i^`7v5zhY;de`Q7pT1b^nYFwvT zoN^{Sdi1Evb8%8<-Gn7%jHHsv@4pQyL`s7@bZ{5xh=Nlt1kp>UdVZO&!6`9 z!aqN#FOqj*@pyDwfnOx6sgL1o;0-nRf6M2j_i=hkw@qr0U$S?m$L<&Gf{aEBdrOpf zyeG{HXnZLUp}3UOSjS<-D;=Fh>ai>yMFuBs^sqa|h}{3I(tA|sufoZ!=AQa6VQ_{q zb9f~E?w-DMCn%|%aM|YQrct9Hdh%U>-=w>pbJn_pBIcvqtQJefdgof6E@#*h#C(VqSdO{=2odhJpM2^hs7VHWyu#UV8a>&VBj$ z=bpJr4wD2G<|H&vIKJQgou|sbckkZizGbKh-@b%5U*+zkygw}eZnTy&yvv>Z@V&(eN< zuq^psx#Wb$F&gI4=bxB6ozq+)H2-e~W0Pyjge7Sc^3FZ}T2*uR$L}dlak@|D#{c=@ z^Eo$Q-PHdf_jdgVh<&>B=5=EZ9V0FO1CP$jt^31w>u9=tRYQkX*e4^7jgGq}-p!i( z_HX{86w}lk`@n+SjeC|JD0+TGdTagfH!IU$E&RmB=W7P;eD#hur zXHnPG76wN}wvWvF{ok=34`+vW6g&m#4n z$F0hVDbf5dvgXH|-@ko}}Ixe$2c>3g<%hs;-5>_<~8F5Z}y zyt#Jsr5PI!q5wVDO(w)0|_O|A~zjf@fX@9uTyyeW&`|j?S zzRs!MalZD8l97iIv&z=`6`dN%+Kc2>UM{Zu*?9QPlDfcS4lbb45y4~428)h(XK!?_c?;GDf6GHUViq+%dpSM=gEJMKmQKL#@_uGvWY)-rR3UIUyq6|6@9%iBxK68Fb?m`4K3GS zGfOKieGTh3ATkF zlLZuC&bYsh{n$(99^n_ac;}q;W|NqZBXxI*T)oQ(u3&%XL9D0gGj-nh-1Tc)tK1QmO>z;_XD9xDbAs9z&a!2aU$HM*lELG+ z%+JshmhX4+_}B7x=ZVald3(=~&6790t~fUD#;S;2(`-&3y}31e?eSE1yI)@_tfc(e zUOsyg#(u*3`^~lMYTYL6&as;vlb4tqyvAsG_S_h+naN)O)G z+}F@`)bXF@jk?mWSFf7ge)=b$D?5GueC7R9`pb<1eHafpz7st$!8Y}?#k?)I)`lDR z9qV%pYG*!SoAP$cshqj%+@GFve=E1sMQ^h6s;R}NpZKlked4x3^NpK=^3`1#44avD ztjpcLk#~{qwP|a$Z$}1&eOYb#>if0KQ&;xuYW?!qyKF~H?51boso7UlXV`mv%-pXP zy)n*P#7IzKqv@rK6GcD0-#-6De#~73>%9vM|J#Vf>FkNB_&HO!HC#OUe^A}auM6j0 ze)TL=^Zp@Y33(ZL298zHp})7uaGe*qwkwMJyqJm8)7JaD=h@D#mfJDomV&J0r`7u{ z_*Osh|68|^wJ58xSF!nwOrPTf(Vb_DwqMmKZ#e5_afC~5^}VbumR}_lj0!Ad`?)I9 z|6J&md~#8tSwM8PPwb|JKA-Q+niM}Z^OQ-pNmg%FZ&>uIxXlY=_U6g5wJ%8K9d-z7Fj>3XFPT1S7q;Ne@Dm1f8@FJpU0iD<@SG{-Eweh<)=BX6#SP4 z#kPjn-RO2Le(8T&I`QAush`)RbLol1HQzD*Ef#rBL;sGG;a0~D>uzuqPdQ!xe@gB` znNLr2-&m}Q_&(t%GvDOXN}F#S%v+?9y~Y(JDQobAqKJX~(@ z-)CR(@2O3jS$X}<|7`tJ@o>t|^vgGAtcu9_tX2H?+vjYtfwT` zlatYbb6L-(Nsr>EOvyUswdJW)Z^GKiymreME#Y|`euM8~QbW$IX)}UM1Cut+P@T8< zl0Tnbpw?`AOS|G}pJH~k&n{iO`LT0kY?*WRHG{noCbyX+t?Uj3dTgFIJ9MsjnuPuV zo%`zkTK((4-1%euxOH~&a~{bX{6$+**E-$&HSPIh>B_C|xN|oeUuxgz$hTd_x@-+= z6yNp(8y&PHcU)z9up#lZ@|J#cUxxORo!j#qf=}yOlrcwb-go^Dj{%$ag$s!$Np2=A66a}U3$dh|HlX?uhVNgA89O^p(l0KLz7|8Gt~_} zlP}cW^S|E`|K^9<;^Z68MHH``o_sFgvcM<*{hS+)pa0yxkjrz1GQ(BFa*<6xW;(m8 z_}pIZ<b43*FSnH zzCI``sd>sYVQJ+ZTI&VO_UrL^?)3e zGfM9JuF;q}O>8>XUf+YQYqnJAzG)5L&w1rh(aZe0=6KbmOQY779cIft%C_gw={ASN z!@ur_WE4tq**T+AKdJ z+!pg5SCEzNUNmXboIjf!G8aF4uKzz~Lj2_H)7L~Nvd(^*deG?}yX$KY%Sx60HTUx7 zKXJ}e&)@NTf|*Bgc1h6lkZluki(elzZ~pZ8+OucV9*a%hdN$+Vr5lNVgZQ{EPoG!s zTlr_f*VERy7w=W>S^92^!lQgIgxDZl&Nk|pAHeGHuwmOVRs_Uzg1v+}>y2r$}Cv=W_a^Z!Uont-5! zA^Qn~x(R_M(Q6-<7?)hVx{!b3lmACMGny|c70yY8>{(#HoCrWhFB3p4w$QlpQ1 z$$=O3aq+s`hMlXEd^Mz79tQpH+y8jQ#1vCcuEbXTe&-!W7P16w4A_3J=_sp=YDs?L zh7!X)35yI8qgmHW>`z$U{_P{vv@~Y%Ze{)O>+`* z*}P{8?;pmya^2_sH;39BdNHx6j)gB$X_uSY9Nwm^xcGwSObR6tUEl7UN(f{RsDEzr zFDxX|cM_ZY@i^0a6O>cz=L3964O`HVRHe%yVW(45e)f@hUU^TCDw z?i_NVH_x!~S@5YCh_7mR%E6^#GWT6+(GUFt_Hh}n{c4z))7T3*f9&V`n&dm-&Ym+9 zEvIh%JZ~@4ZhPB#m9O9CNBuYxyWBYSe|EJ=r0*ox72me*T=qWf+S*?}8-MP8I$x8o zcE8brxh89G))~$9Zv9i0aNP4Kmtn^%|M0TXVg=*F>hVjheALu)4QDQw^v&d25X@gv z7G+Z;&&t(&^U1bZKG)_;rbW%^RJ+ij{S z+2S9=CONfhY4e=mf|`{vX^nF}dr#rcD$aU1JwKdn)2xuVTPBJUE$i}{PQBJPuu?ew z@r$UFgluCMU(bZwmhtmMz8#dbj8ROWEYBxf@Q&zh;S# z%375<{UrC?%$EsaQD5?ePvjQ0pHSFne(C14J-@ydLr?kdi8*&(GyHtM@Bx<_d)frsgIysfDxYVsN&EOXy;&oO!)~8fw)2dO zDQ&Sv%}p&kcjx>PS)AE*X4X8!L&B>1#p6r(K=?Y$>9v&%s&3m@fy3Cvf+UHq6 zZ|V_lPH0H@=P~otXOUOmW-Oca=EM4B%%A)=pKRki`sBh)Ytd!QVf|OL>rTu~Gdqz} zwO6#v;_a~oi)J*qRV^|)q47uI%)}nobEjuG-w}WCeu{mG*?QBsb91g5I)_cKE&s7b z%~Lt({G7Mp4|9)xpLyIaROb8=rTG`8${w7^7kEqIp5Ye9ibYAazmKmE3c9qb^}Oev zHjzl*!`!}HHXh8=`X5VyN2#UgTbv1LnsiRmn!ad^Yp>FvF#PKRe6Yj9k(d6m1`o04;Ns|vd= zE8adfDOPs%?7+3j=`SwyypoKx+B3WLe#9oG)~xN@XPv$D(EN0m`l1&?SJ`$Nz6ubY z=Im3wi*KT)Et93k2c;C#h3b3`8o%uPjgKgMY;6AXsjrpyl26-A_jN74{wwbX{%LA3 z;dZ_>je88Uj!5vXW!rLp7YzpqKRMR;*E^Fn^R8tE{R*CSk$U++UYkuv$$31`ZI!V31U7 z=HZ*r?>{}`bT{+Lhrjl-t+skixY>&~3j{qy&Hz4N@U zT}8ca!HZNaS8aXzRQkl{^=lPAw~4T;*(q%Hp7?potqYF1k)35Oyx-Q#JzJyr{^t8z zyss|HFZXkhcA2tKV)DD)EAJ`Tn5HOZu4v7<{LtzBtOpP8|Jh@-eba`5>VxaGyH1<0 zaNPWE`_rXQZxy|@I{V8sYwb3c>D{MKZ&lf>u9UHnsqbFYAIn>F}$?VW}>TL9)-amo5y#L;@bMMV^ z%08pe;#71#?oZ{)vf7igzCPWrtFOH>VtL#~x6MVqo;SPhPkZnv-*D}eHHZHM2DQBp z`gYqiRds*t=4CmqkuPU4G-r7KzGJ?H?+WWV#r2mu_(N{J-omKg|3lbG=i2L@OLp~d z+FZ6ey0Ce&uvx|m{RreWbaPo)(IB-*iIZXFnmt9j^L?rUn6eXMkItIJyI)uL@|yVY zMgMYFrp^7e{nn;UyrL2|uZ+H0{ZZb#C}#7rl+?_dyFN`-eeJbnsbKk=z3;9@Wxgov zvsk>y;()?l`>_3`t`)a`+vM(dW73+I(d?7du!Qes_flTF9}9Qdbv3{5dcdFeAv|V< z(kjoL3z9L-^Qukk)vUmH!l)Kfc zsj9EH>=)u&b$xI6vYQ*)7?xP%?BkXS{_u`*ue*iRhBsRs4Klh9-%;D1`ry2$-q;M`HT)sfmyGq{K!>YSw)*oVw!rl&PysUti5Cy;;S} z=GVC_C3fYr-qIN{*RrofHO)Toz9OQXJ0oW4Ub#12as5>u>fGYY>8^1%g4c1#^8|T4 znfmZ@)AlQDyDNn&e5|@B`Q3OD*|yzr%ft^awsOtfDyn#Pf5Z!(UuVyooB!KbP@I|= z&=|SDt~T>%)!Vj5UA&^AqDw_9HqXnsHu-Ip5&!L~+@sY`v%R#vu7_usPnq`3xUi{2 z$YJre<1sH@Uc4mcK2OFI`l84Ty(pX^y0}Smu-$LqOa3}eS=%R+<06-9E#Z6`Y*c6oLe6+}Hei$8uV9zu*$38sGD24Rar4J3slzwdQ6>hVtwST<%&e zb06JX`#sD4(_)u9%AeH!YX6Sy%s$L6e2tAWW$yckd&cH*n{=M4yz{&K{Og#@wj=J^k zI_vjYe)rc%f4Q^k^24I}tDe<~^Oik(a9YFeH-mSuL33i#stEV#-z{pD9&x(;=PKX( z#a`~|!Nhm{S6}LuT)WYG{bbk6j0K5*6c$SuEInOPZ+UgkeGVDP|1HxdOjO*J6>C}< zx;bZSpX%ZjP0#h3Ra3TGWuG@ntPow7(pr3T)fpE_yQQBwCvD&ndiX{2-N%UDGFhGu z?RSNRyoH|ww|L~m%?mZ&wBWYg?YK)5o1tnDnZ%z45=w~i?3PYXV=M&sp_ zX!&9$<}LC9XUj`BZ zS6K^Bact5Gb6s&bspCas#&uOy(Wke9gc7_Sd2MyRS0kc3EvcdB?*C1hFMmrY)_nFq z;e0mS+%$ah&(B$#w)I?Ga>UT{_u`<5XS%kv8%a*O`Xv6lpJV&nptal<^QE{``6#-d1zG2 zy?^OSkI(v@yaH1lzb?0bn0y>k|e;>f9}ZJqpLVtC$}a)*>W&o+r;Uuf=N=j7u$NJN+(8rzIQBXYueug zbNRyVg95J%Qz!J!dbZ|UsPxtM$ssvc{;Uh#+{KWxa@kg^M9CJFzTm$P`|ImAwyua+ z)}E5Ey{Y!UFx&Lb@Q8JT@=6IfQBHPVEhMdj05(;A07CJNh`A+OfTWr~w zBfzM{ncLiwY^tpM)GhGZq#r@PmTVonmbk3F84%JJzVM-Wt-oAh_o0_dlh-7PZr!FA zx_^D$f7jk+Zl8DWKd|Kbs+%2wMzw1g4)tcntx;(H^RR!_`dbn?X&Sx?jI$+u#9X^h zPk41iW#NSAl(4=pd7jH8WBgiuo(7#<%eOczFHZ?D^Kdfa;41wr=H6lz z;*zIyoYf_g&xoUqJ#Zt3!v`%H-HXqkbT#tv1@hGy<^G&z$Z|q!tJ`KV?WXtJSDCJj zIC^PI(yQA)R{bh}+j&Nz{>S5RO|^N;XO!%XZBl&9aGi1Won+_!cMR=5S*DgTZc8uS z*m-r^^@j|%8CPG_EWY)S^Yg#sF=ZQe*Ou+^lwf=5b0tpapa*}S+~qdq(@MX3wA>>2 zN{>(DcC+G?zBKK7OUpOAokku*8Q#Kdw!gXZ zENfxg!GF1>=_1p2L63?TO)Q?9XB;r&5D(kf^5Xe|N%C^{FBy9&o-*3E#U#fkd#m7K zbMLKt-A`p!v#;W-fBv9j&H~;|t?T7>|9AeqcG*i)-;&G6dVMdizCC+Y=048oi=ze4greN{53)9C>hq~&3ntA!)qK8aXMv4CK-4W^uBeN} zX-9TEzEtoaEz@F|$bBt~6KiaWM2Z#m9thBF>t|V~xjs+*-?~{3X0JK?bk>FJ1FvQU zq`GwO*Ie`SSyNY!Na(ka@T(m)MgH^=o zHt)t)4w$7oYwqo>64SrJgPEB#67nK za*w0_U9108 z>^Lt}@l}sE{Qh>67rbn{QlD&G_^Mv!^G`>ogI!weArtdI&U9)ekTE<81KKohzYvg9P=T3@N z$YtIyZ}+MEpxLF$6WbqNb^kHwGHfaCB%bubpT(Q?kHbVY( z<{Osn+$DB5Jx=jRlsN=}y+7sc2+7m_c@ zD@0uUu-slZ$D4IIS_fwTe7rTtSHGpDD9i{Ic$n_68T zHS1)~hZDI<%`WdXRCq4wewoS5aWl;P`CYe&Upcjj&ac0%o)F8u^FEW!ZHCoP0uo{i z9#oxET>kn0Dx3WeZoa;tXZQaigNobcJ4rP$XC7G!rC#F9Jht+;g73o$CLgcnd)X5t zYrKS)prY*KpW5pSKfK=DoqgS|OnO@Ux%?xqu6~<5;W9($qtEiH4tD*n8y?C3 z`}3+_MBU(o-_+AgM^l2A13pzEOrhGv)U1mFFjVyEewdF^p?(Q@CE2^qa# zCh$Jm67lBFe?^9sjc>!b*Y8){&vNs*`2EDEYc0Q8E>HNz`jh{6T_pECu@nDqePgv- z{#$$03@$5^c;{KXV{8)j)me6AYX_o~9HvZAgo;UZC&)+0V2S?jC zGwyRt-TImT;G4;n=jX*&Zx_8*XWwsd;=R99+2Oywk3P%GHgohj$(k>C;dWf1{>Ng) zr{_a$To+ewUX!+y-zThFI4yE&-#LF>vD#I&v+jNDyt91!iCp&birjVQn2VY(J^c8F zq4ms+h|P}N&UwPS#8;obe^vM8x8&KoyW9U%RUEeBzOB%%=Xft%-R#=7gnu*Y#kltG ziNCO5OU&7yVU9Tymg|NubgTKdc)R1Bxy+~4|D0f4JqKstli^( z??=Y0dC^M@=Cv)m9=oP`>Z4;|HSjv zwU*CI-q)%ulw2}hT*XA3V9ZS5Y+&CHW z^ys6^_*L(fGfz|{SX3?YIKcK%Z5^-E=S4^Sn3$KznTT~SS}Nu|%kkZR4THWp6B#;B zsa|6dHqhK~(($2D^LCT@B@8!bpV%AGk>t`jv*&Dw)3Nzk3Kvy_GwmChn_~M5Yecv4 zMQX+=&T_B&;i2@GW7$u}FJbeRPvTMlt@ktbIhxz&G(SHrLvghrgUczwh8ZE(a)a8w ze7O}g<-yloDGy#B(U!XVSu(x!SK3J%yTwQ5hD}Xj@O)zUQpw?wh5N!Uapf%v_c
E3_3dVsaU|OGi|bYqMY7K>>nvXn}lw%2|m~8IWN=d zDBUtyQ{?lZ(^7w;oJg(8D%i=7&?MKUm%bAIuA?V@;D@qWS%@ z=P`w9VXIl@c?>VtFYwo5`{+3}tg~8{ka-i{wT00%$>L4&D79yNsHM#em6hoGPB>lbJK z{aEy^ImdWO$iC*KL6zN!%NQ3$7@T4}kfFM;>j2{mT?Q+US!}v0PKL^lB0@8+Zl1klp_=e2aqfrn*Uifg zs8AJ|v4WwADQpRYK#Q7P^BEq46E>Cl(no%6ykw`+JVDZ}`d@mC>FGkNE8ZWu*1ov6 zbjfB%wMp_US0^}HbTqK+m*hNbxTQtNVDak-7tVZOcz9FZxOIUwlfad}_e&3JBnpUf z?%`yeaK4#GD6#p4Ve^kE*Zi)$-}tU`S8i5b-m}fCma`j`{{G8c=C{$atNTd0fQgpB zRaTUBwBCNM_Jv%s&AHk#>I*a9PPrU9;iQts{f~c*OiUasjuh*9^Il)z%)s%g>i6#+ zsTt3f|H!>#SaY894g1dJH{Sg%2}>{dnKJR}Zg2g!>yt`ZS1#C9x${@**@;#LK#fp7qRTGYJIuJaCPu1K(El5Y~_N3bHJN_NJ(|YXjOn=MssUhk@BcCJoZ zs{N#@JmQPjYWG#I*C&0P&*sd#d6wz_FaH0(@Jnrt+Pg8&iv5$U!a?o}|K>7qJe;(S zd-Ben*OMHqCg0(ibm6h18`p$AyX`fixw4;M_bS&|GhOTa`Sr0{?{BMkKpEwN^!BI&waKmQ!Mb^GS>X{YCIoj%P#c$#BH`BG8urJ*+> z)_x0#|DP9^wmfiSu$RE0ZL9A8`8hlP(f9LL*G8T>=Pv*2$l4jN!+z|QTP*bMeCe)( zkIi23mVL1J8XXwKtg`TUbB~0A*z+mMt?AEA=FD4e@!{;Z*9zhPrhaM&dUvNzXpOV6 zN9pBR<@`dI}QiCYNj625ZM$JUuUeLzdfZeq0}lwZ0b=3^JNh{e3PsLpLuN53K5%rGV4~U zysDvtkoD@5C+2y?ddKOieY=@1e*K*FmnBb&p5C;azw@1rRf*qEkEd5H+1t_tX5~iy z@jDf+9;Rf)Gl6xv(HeDe`CW7Cwf2`y`{*WWT*x@-RJrFa)z51`rS~Yj6>@w0jh&;( z|IJ*XHijqH6&n)R4l)$_Y-~9A)J*fzfsAdD2mZ~t%al;|I+QOmE7Zu?BkB23DaB?J zee=_6r;E>t-Sd8>*YdA159glxb+rDf)qOSlnY9`FzW!LI$arY8uJ>AXV+%VL0UwWc zxo!3ApR>1L*T0u%UAn945MxWX4F99A(rZ=x1ZS)4V`TRU6zV^G_bi9Knk~;Ise}nP z6N+}9ak}NQQ$|E=x6Gg5ScS>bDGEj>ZZM~mJa+scIhXyU@Hv^;4=vBg-MhreQ)>M9 z#|w+CDaaSix!5x=dbdSLN=sI}cW`?1^+=HEY_7+0%SHl=r6lSeajTbE;a) zwKD&KVCxlkx9|sv=d%L8Ckb>P&O6GZjDCtsaEWCO4_VhY| zbLw9{p8HkuL2>(^Eew(yY|S{>IG7fnUdpokd+_4RIolNjqGT6@G#$zPY_*olBTv~j z@N-hHo*1{{q(z-c8V?KAwACIs%iq$JD-!us>*U)qoAsLTg_ZZr-|~x}czS@xP|fzm z&((Q)ze)qTX06_syXmW)!iUQXHZXojxs}ex5cvIIf4AowT@|wqiEhzC(kJC z*|PqFQZo;yz`U#WE8n*;ww0H7vs=VQOk4}1eBGbz;OOjyBq zsCa{as=Qd^O+A%jV8dlK@7A*Emey1Kru<5CUag-Rj$Rie@_USxXPgE zPiG2i#|&|AgG$Y8O`vGwb~%1qxr7>0vPV*%P+h(UBo(V(Cl{hX{j{XR2m) zG8~z9#H?e6c=jiz7Ve`-f@}vr$^U=vAH4YE694xnbTulrJ$Tx5hsm6+<0xC(Os?+3 z4?F^A^`=Qm*hr|WWp~|vGEK5zt8S*Gied7`3oCY4S{^C=(tklp&;F#!xvWdwjvM|g z*I$#)dr+Y|;qzzKsk7~G%!&TNykS8}Zs?nj5(g8*E2hXLFTZj^^NY~z%S%G4tVI`; z?4D%&toG4a{w9yAWwss89g8)>Jkk#Z`b=N9x6An=LrZ%9+BZ|LwjA89b7wEl+r}x-T@?Y3v)Mu_G?jdAU4U^M?01+J%6oQ;eEs9H+O1O z&%er8p}i$P|BP|$dHXF7E(k<={z(y8IpOM))_H5x+?ykPpKLEy%L|))BJbXWKiBWO z2(CGC_}tn_k{JePH7AtxNf|x$Us2>>uj?hy;G-ek^6XaJocwk15!~nJocO)yfz+9D zyNkcv4#%HT+%H$OKCOi3sDjGs&i8ZISEZWnoRnv~amT~5GK1Bg$B&p^vgb2CvEQ>^ z$aO^pNc2W zbq(X5djIJa`@0;s_3i4CD&O8YA0^Jg(5bbW^K?6-(21-f^9fg7Dr2k`R&QkD`6NI8 zf9{U?ds$%ZB%y5P8o{?PbAhs~ zoXXE?bx)ygh8iY`0@bq*f;GdA2Zqkk7F;vU<=olRy;|n)yQh9iU#Ih*>Dl}T-S3_q7wQy4dZmYprogGkqyJS#FEtzt{N_ z^`rcEIi?0#GRrtw@gGc9Va{F1z3gFZ_aqskD28o840W>iF6OGX-!T%p-qC;e^S?9A z-{0?CF16zhz^@ zCy}XIXA=U1S^^dnoJhMFqPOYmjxP$IPo*_po|k9ReDUtvf+bC-m$7WWw2r0w;Nu{T zZC2$4a}K`VsChu?ewxCCpj&qz6kF`tA z%H1wW^4&C%$^QyY1zzAkR1l)?U!}16q}-&dEic`Kcg>!DLt*~^w>(!&VC`iiRvxd-LG#kgwAXMopHG@qbs%?xREpVEVXf&$H=JH#6y=*X z`TP^J8)r7nv_7c7T=2-aZ01?D*ON8Fn$ND>qv>(MAWhP#1nf1oeL{#RyVv3pKc~dy%Ar-4JMWHLboBR^Z zGwV!N8;UBN?K&$^!`-jM8|2F+{9yXR-^yBw5-uAYts?t)?IuUun8$m2xk-ZQ@t?oA z%`cel(#U@~U2}@to;SVIFWGlCi`w%uw)o0^Y|zy4|H9yssm5^g{RRsI)d&$a{ujM$ z&Bj+R)Yj{`pw`^=Wl5q6KZ3ScgzPuB;0t#l1M~hZH(d6^*y6E`K zL;csZ?ERlOnZq{f#7#YuH7o0&*0fWq$9Wb_SQ(S1%%K%F>r9Hd#9Pgx?t5zCtJbjn zt=sJR&ZyyX&)doCjxcbXJZrt(c#5UYpY@(^ErmYbfBY+q-S0yw+w<$+zU2h(+&7)4 z;xyyx+TE%AjJi)(A6cVTSS->fp)gHEw9SKSqhkh}h~F7OE@cZ*_M8U=QhSZ~EtbEq znyL`&bi$*2r{gmA~u9P0iePhnmCKCpDZ`d8p-7HpOp~sM}8WdkwGq*D$`9(E7Qg|DD(I8w(y! zznW5RF!SWQlT)v@NT-Gg^9bxd)!_P6fkE-^9zS)44Gk9^t&0CD96Y|HPVumkUV+o5 zqic0)T&h}BI}RP!Sin4;gZWmg@sb}onhW$|CNrp6`F>n^@Xnsa;q5I)93Wct?&*;>zE&lxNzmkCUjYFG4o%r1P_+>o4eyr;; z+cWjo$-5oXe3TEe+10@%FQ~yhM_;sXw6Ek zlncGcvu^dHEOrpl``T=J!W@R8tj z^|zlH4y9QCsY$M{SMFN$xA$-F`R_;Lat;}<;XGufwcp^5IHUB!8_nAb>f~};o~*Gu zXFgG6nUCz*{HkkjrdsuFdayiZ#yuU+*15%Jy&e_&uiId{ch>QFb5}QSu>F7F_N`Cb z9Ik)ZrgeSV_C2AA+;Z}vbsIXhA3Ql=T`<8a^78yyW!JVp5WT3Vak)2kP3YzbpRIcy ze*CyLS$or-T5r}nheIp+W0!`^<cagW&Zro*Q@5kq}8aD9Hv-$a`S@m>bPEO_azP;aDSa&Rce|z!qvW^W;XXU=$ zxcljG#i9oHIXwK6ES9}1e3EecGpE>fhMKl>FC;z`ax;9o`Acv8%d@N<$DUulyZ?&# z*`$phe;-ia);DSGL$S^m8B6xKE6eA)taRP}&r&jV+H>1;dA}l4qW|>G{BcxcqjIIj zj1#)~FJ>t}j4GaBx>r_@$RR(=`JTTX2_{udt8#u?f&Gz ztuGrAM0ze&ys+|mz{38dLx{bfLH0PWLtbSz-=<~T+nYH$&YVq>OjcB??4MuvuJyc| z`n08dACF~R-#+7LTj8U^1Lr$_-gBJOzv%*JeY>vAUUB}tZbyFge)gZ*vGtikcGYLg z6L<8kO|QRdFmYCMMcjcELUKnWk8NM1bHbqCMt$kIX`Su&3>Ym>9rrA|%*SWbnVODrIXgr`dj%)U*2bT<@N^2hAmH;;}m!0Hm-5My0M7=^}97% zFCtz%J6@{7F!gD-x2yU3-)!rd_AWCOwY1I^e;vL({jtJ@TiOl|kJ&jGPII)j1?J!T zu%oEk?mnC1c9%1|q*qVdvd4GJGSj^`x1@-_?))q7Ul&`N7OMPmdB(-;)4Qi^Ta)3N zUDd3)Mf`1&?a!&7yXXJCw8BmxDb?cB^q2hqiZ8z?s(Na z|D0W0DsR~QIFr4lsC+8_D&H4xUM>Ir>TN-g?DFN$bDmeneSCHJsMMOUq@7mFmGrKE zT($i{Kd0X5=O;d@io7V@!8-lvjf=1IMa5j#{QpvWTx#Zuc;C!@cYXY8AHMY}_WON| z+h>!>l4pYA^G*A%?wN9Ifumk|e6QoIuPnE>_xc?v=gi%8z;Vvv`VDjZ{~TCrFZ%S9 zw!*wL{Ym|6uI<=ip2ra6+3M!{)x+q8v6PB|_sX8I_2J<#bluY-zdDX*xt zZerot1^hvMQ$r%=O+RO>y`SyG*5)IZc<$D0Qr@>s^Tw2B6NbPYf1Y<;GA}Kf|3d9; zt-O-h=0hJZ;3o@M0e!u1}qiw9Hm(}T;>hiqq3*)Xjm_*42 zTIZ_rJ#b*+D`I}$qB*OTqDKE15iq8IQ&uPh<@n*wKp0e3JsiA(!iE=j9GhZvD zo81jx*(|Zt_|t#AG97J=S&xhkFfaBtTX}2Bxl)0H4*UMG)qUT$%A%t}UPD>m$s=z{ zN#>!X>m@$xLKzN5PE*&({2O!9XI6lh`Xwoa>(TqXoP{qcUrI7=sF@)fd9pcT9mAwF zZl!DA*(Yep+x}>^FZ!M$=D+#vebHrsmzUmn*~F(L(ZO)ydi7Mkpp7RAMW*CExnk9^ zBz2>8*w@Y_jY)B8H_JF>TAnO9Yc|znaYQWhlUc?BNsD}r_L;DIGzqb%nzCE!Ce`LM zBwFzvHdx@XSN5~2XzfmcnuW8!tN&+x@I&;Ew(gR!l$7I+Py8l@TXmR}-7Qo+86`Bk zb>9()XDXR&CuEJcPJesDP|@D}?h0)NB_8AD>$%wjyPWP7 zKep)lw3?@l!QtKC-{z)&zwbSNYFV=5$=e5Fp184VMy%F888mTnou(;w?tx{Ud^&5V zbeHO1+tpvba`E)1%+e>e+FyxR=QGmP4lXc~SQ36JtY^vpl;8LE=H4i?|9yIs@muY6 zIjc;qI@VlGmOUDrJ2Bkj^8G56T3_vk%!PN~zFofJc2Bd-se3>7F)q^KtKpda@7L6I zTE|{R{9U!saLyd9H#K|JHZt7z-u`6wGlhJ1ryjeU%M-u2zh9^IvW8J~&gSrVn`7&y zXr9)eTA(F;`;k81*^gOM_B#};TQ7b6wp&y4nimS1wGQb@eCOknXPI7E`MP9E`!DAo z&-sroGe5pM=a=)}oz1P!XWcVmQvG{ZR95A%!{)D3w0gh2dE2zWyE*>Nt*4har_2eC zHvD@!oo)Vh-|6RS<~>N8cs9I}JMO4&{adatUd3y~N)~!EJY+leeL2U&*Z$wGm&|>+ zW~JI5|8$!a-U+6$+0AM*Bee6UHeV=fo$zW&#N}D*3`4s(&WkZ7U2yz$w6Hr> zmznO}cck|yYsriUvI?oG(`$-;@73>R3)oj>c+J1kce?3=&x`8}*-zxU75>&@ZZ&@D zQuE;NU!C{fGFzW<3rvlDcuh~@_&i3J7teE_S~4hQ?w&kXThXOz z;R5azY#xgHw(gztMG5r00H*EsZ}Foygjw-P@wqGd)h?@1`v`x?{h6 zV_tIEgs+9~bdc^kg`~#1KKVJOS5tOPd7|Z@GBtPBj^O>5&PPdB-21ls`C_NZtMy(a z%{mim=@G@~GWGP_SGfW2<{o#jGUiKqa`)w$XE9cbJGacb_3~Gi^tqoe!*aJQ**rV) z9Cxi?=g~_~ypJvEU*5U#bK>OFYcuyRIumK!IrIFrS!b6|mMN+;v`P7U#%Y`0u_vYs z9+7L4!xyPMnjG|2?;h(hvH5326qw|-CvTE!2&kFA?Cnwh=~@jQOCRzDwR6ZReVli$ z^x_BYg{vp-IdzOxH|1dbpRGGfj&XI0x2`Kc`swA)qNDi<%ay{!7q(BmD{rdrrKukx z*;f>KDr;i5vz}e-{IJ@7p|vwDd^R4_zAd^z_;a*YvRL!2xB$0ckNLjL4-XVZzcM@; z@hhfII=OUV;pSINHwxzn-4gcftTf)URA7yHXJ^Jl&rlswexbc_bhAC26ruytg!ki)b8&`e#dM@DAr`MH}rgbIxY@Q#gl^D8Y z>Pc&>-EItm@e7$=Z}{%J`@GBrhdLDF3sJ zw}M+e=Q??ED6YIE#B_JZge@DjZm><|emKd*O{+bo&$`G^PF(6Ncdq{f_gwx{jD}p3 zo=j1)NjUkLVTp#|O|FS+rm^mN$?>_X)nH@CmBOb2e}tz7%N~)qeSEvl$7|`8IgyHw zg_juf_D-$Yw0OmCVW|v`xHEeXY--x=B`&(=d&z8X%hMMp&YZFP)Wgk|`Uz1VlGpz# zh)kTTaLY91>&#TYz(H}PVeyvE?~fp(Ka8!z(a2(5Z>oz-4jEOq*p28B*W=eJsW-_GTG zel@Rrw)U&C?w2c5BMZGP@0^R=`PrvkXll=Uxl=FaZrNI$pSeo*@(Ee3&DqQXTMZX= zT#%dNW7%O)ec-o5^0rfsVP8I{@-=N1{hYV;sOAASceT6B`xY+s+s`Le? zYeB;0n@=5`w5h)N)YI5GWtPYGo;h-KvC37INM*?e<%67wQ^yOa9D zO|lc$ZGO1zkf7p@*LgFvT4u`sfAHb6wbAxRS0sgndOaQ;EA#X??xRybZO0||eY(%T zGB;PvT&yE^sqoRxv<=J*H;bKl_doAaT4c~Sr_Z@m-COy#uY6~$ecz=sy`AgiSa;u$ zDp;XW{)R*RT$}Rp!Yk+Yy*?n7^JR{wg2YQE)J2`$ z{!7t%Y4Z|(k*7&~Mb(lDKQ}k->s}0i9utMih8coX(i*^XKLJcL@dg& zQQ&*ADl<~FRMXZ67|MBvzdNe+%|c<(GlhR?7F(RlPj7uO z;j-YjHw&|?*QvfgTQY%X=DZ4B?Kf!;q&|dgTdPx|b6jrb#?ur>g zXAgYiV#ek1#LYZX;8tPzIj3D8KSY1rxPK$}LcL8j;(85tdoS>G=w7 z9Gi3O-@X*PST^SXXTYAs-)}3P{PL4oe1VtQs(SI}yA#cM9+aL7IX+85qaerLZ6ZIz zP3H3(rB|M?Th%4u)aU77^14ponDd|Xr0s%78Ra;cPlqk~Y9!aTaq6#&bsJtpMKnCmJ+xFc)-& zcvLtD+bvVeoGx3X+HfLRb+5z5s|5m=CD}?0wshD%%GJKNsazdv6Bs_^Mm5^g>as_^h2wx%Mj3^1BS5r08!+tdsb? z_|?28bs{YnIs#Le|93o?y3etRW#gHxwbLDfo=w!;$aXBn;+MMj6<({$JC}GBmDkq~<;afFcQ@-RWK6hEf znWf&;yo6;br*E0DTZUK4A$xUGc}{=MP&oC;=e6Y< zY8~2GfjtwRvXwou_@^Mi!09l-lS!4crQ_>?Ede3{ z<_DV-WM0mHdEldOH#ymGoA1Qn~uf>;i{G5}%*b4>Qya)2oay8KiJ`Km#s5fuCMM@f5#bz z`VCD7lGcf~9dNt1+3|>Ami_`|PKT8Z+xMq#Uwh$DqQs5abrw=@x{tBfC}}<0o@FBQ z&+)_3!?g|358M{`NGraH$Y^W%;pnjD#P-XAC;mzVr7vWbad~y|yW)GDtxooB2IV5Z zI2(1$d;_;=vhNhHSo}~qA>8fwH)ef@3C9e!<{EJ^FAueN-x_w|@U?xeu6=E}vb~r1 z*Yegotf`g1ZQjoyYPG=PqvE2p=&+0kP0>A1)5M~~u56!T!Li77?i|s~HBYXyD9Wg; z@t+@R#`)#X%?igOMj5lViM#65U3a)?8Q*BmU^rvq*UkSUpm$0O? zqqV_z1oe_97q0nY=yG`GJU*{i0g;BD-d-GMGj4gUNSRb~Z{C+fg+&X)isu-%-s6>V zVpLxeo6xb&vFgL}T*)WLLl&p0F-sq-Jr`AbJfzAtD@lv@l7`fs9~Q@5QX0goBES30 z4&63u2HR3T(OFtsuKWFNnX$ky?a5*3*rlpn9xG>Vvrr7_j6Kf8!`S{pK=?^UV4!7b z$C;%^p2!%t6~D1LRm^ntfY(0HY4fcfCqI=c{k$sG@?LYUk>+$ZE@Oq{h1_%OA9!TX z&t;yjf8%~+pMum&7Y+FX)?OEvYInx1R(Y?rMda9J>$|5km=uWzzE+|@ny;l0w5vgg6R zT^}Fj<;r*nZd*6=&d#%6jKqx#Bi1z;Ei7ncm~eOJkuQc@!YA;}T=O*MxzDx8o3S;I zHyu7)m9kd#&8g{nZe8#0Im`*Y7(JnkFLU!Wmh@d(d#3KmYR_WlS}$*CSNkJujtg;mWSqJdveAPgSLC zH68_Ad}Wiq)-Yr@gZ_%-?^nKbWiMXDEtuUY#!xg{-?VJP&VA1J3s0S!_4xYZuS@hA z`)_al8M{64by@ein3CPGYokS4Ee>q_6QZr4ZPC6zto7=^#GO0aM zr&r%e%JG}ye0CYPZHRZ4>HR0+`>j5d8Mo=VZC>5|Z2NHm!&N`FE2f3Ncz;)Jw$$gW zOK}#n)#6nzx179m=;W7wU9!egUfyM&S&*jCV=BJ+m1Ee-FiA(Ir|0IWz4OpKw|wPQ z!_{5qw3c2;|9tDtzKV6vyIJiQ3&nzy}O))7x-!(&W^Ad%PS?1bR zQ)5amZn<{sjh;#C{O3EKSl#|SDIrj zUV@|MqD4u+BkXd^^Kb6`Z9Um@<{6(!GgT%qyubd~=GbK8biYZ7b1I+xwR`{l=k9lj z%a0s65~%Q)b8fxg`2WC< zk?9{Z7&h;=;$Zp1Ud|=(K^_9{Ty<1K%k|xomXdNa`u|r;E&0qYwOg?({{DAc(j)UPxq9w_|7vRK znLCtZL1sR_S6T94|7K~kIYKw^tUdPTamy()lYHmLHR-kuQ)~mhM-`(EKJ#_wj z|Jyj@rVFP-SBFJLL}+|l7rD8us$=ci+}PN;)2EBCl--(hb5ra2=bNAHzx8<9sU!=j z%NA==3-8Hy^%u|T>p!-QtvdMi-R*UvbM3ahQ&}my^^bSOrmN?~%Kkj}oYoiKcFfRb zvbWbH+l}>;ZFwt9H|_O%P%k`r^N|PB)?7Jozvt=q`W>sA9i0E1TRio@*^xT&-Hu=P z@8|h_POQtNHJ$zS@kfi@`!Ae*^yTH{F0l~z{etp#H5QX>S(h$d`byy7)vKj%Z*9F& z_N6CMS9DjBle6>87;}%Xu&@`G6yrKp^yP?}nVBt_$Ma+Tuk!nx^|Atgts_rvHsR^Y zl)PpX`s4ML$8&DIvR@MBT`v3I+2Kou^Pa6||NZ7*JRTw+8uf2gztZXXU+?YC`Mdw5 zD({R7&Kq||MrmJk%b53~BjuC<@2AHf9c@k?H!)vqX34fn(nWmZE|}-UbcK$dQu&pq zkasGbJNcjSN~JKBP{V@zGD4^ZQHgzd-iOebvfVFi()(Z15R_y z*HjYWGS9hTkak8Q$U4hWocETuElaFM@=~YT3;yhF*Lj7epI*Ce-M4Sw+)B5&9!t66 z^!8ZK{}%_lEjgk#Ns7JKe{7%n_@n)eNx!3CCA0RNmW!@t+WhD0JO{tTD~o>ru|JZ( z%I4Y1#{aW2fBNg5uhjbC|5(9Fnr&vh`iK3UCnJ-}yRQ`-PGhQi^}~NjTEHylbB90) zTc})4_Dy}!8|SI-FYx>O+<$0qwJ~;M>kD-aE0(`WBA)eAyPoX#;H(xG&QqV2r(3dL z{NmX~%a*a-Ra>!N(EZt5B^{ldcXxK~5R6!8S^VtC@#B}jtzWZ7WuMFR>6Efw#K4I{V+Y1-G=mJlubg@zDF6i5K~9C+*JqT$d~Tm;H;-SC`V18=H@wD&OXG z#Xai(JL~94t^M=*c^_k&I7@u@(&m%Ly~1Q&?(yDMJAH4( zLYCK;58UB8@x-d}zpu|Zq219Yb@rvzS_F$W z>ej74p7*9}{@*9gAHEA7^|Icy!3h+8MyKYw+y4u`@&7`7O~}za?JNJk7adT3=lVBw z@uoxeKJ9$6PQfV`#FUN}EYwbWd1&c8g71r&4;|*UjyiQj?fo%!;3H zm6Vij-M)P>ES7!QANBbwjvq|aUJ$iyyG4{+=6%=yjPnnxtDE(8@$yH$Z>e7q`ucxp z^_oqs3I8wuVU!U6e9HF!dRG42uf6|6KS&=mP+$M(%CZLzrQhtA{tr)ksVwpL$-j6d z?@9OF*m^3q=XG&M&YlqiO&F!!)9y~~G>?9y8&yL+>%pPJJ{=su%*QQ^cTHS@I+~mMC0v{S1t2S zB)LDd4_y=Tc75l6lX`|U*5co8{@d=9MLy&(WB9Mg{-9TC>B;}zUH=Xw z`f2|c+;wu6=Dj56Sg1dY|Mw?6R2H1KOWO2a(_aPsI}P5B6P_FndH?^4vzdt3*`5^> z?{1L?6-sV9Kl4cZPdqN__4wkGwX0UB@75H2?|Z9d5|f4u%Z}3x7KIfp_ca4z$}1}^ zXK^*uIcM;xE!vyM!gO#`>gg@}S`P)bN>9kV?;-wwJ>$>*FLBLB>ou-+A9~wu-PHL| zq3z-Rl*%o7&i@u~;pO{pxF1?{yb$x{`hT_kznKSfP2|V>Y^gp5|2D^ekqutY2P)W; z?^g00u20vrm&{zH@_NA+(c(YO!IRZ|XSw)rH7w)2yo_IBV|mw1hP)`D7TxdA zP!=i8GMH!AFvX?h$URNBez~`g9yM)a+n;wqpRMF#!15K34?bBkWl~%B{|k-(KUDDT zd63_z;D7OlEaw{m!KD0EX8)Q6|0|xBKlRz2_s0a))<9q0vv&Uu2TN|bxF)M-@^yo3 zg;x%J{|`L2EYOSyx_HBv$@-B($w&E~AN_Ajnf}k7F-NubXTRM)=U2vJC!=?rKlS^_ zqwSTi&X?w__xi*BbOLY16ZXUqP-;-Cd493_FMqG5`}wThg@!$UXPD>9Y07FCc4~N4 z^Okcx+g0-Nl3&-icXzwboO{LRI9)_jcde7g(kGKty(2!!uU@0arg>cQ-KB@jf3l+( zHBTB}@i<9%3{|ildx2S(!DDm!7%74w9agcOs6d`19BpZ}}ch>W_b5o~0?EZMi z9^{N;dp}DQ|24n1aQ}v&CjkO${&TX{ZBg6ANKN60Z^+1t&zg?vU)k&xn`!L z0rnCPrZF)!vN;{7S9oBr5zz48LE!?&V|zu8lz_(NY%EOrmK-cbsS9H+9H?I)c(DGy zq({MZ2FCx54hj$K1vq~2voQT*Zgc?ah6ynKZ*2JACi(yAlP5eE++}x6baa_Hb7o~# zm6)jLLf6UPJVQf6Ma9IHl|DVoD8&vkg7JT2oAm#`?8cdUQ%dF9TMGZn8#Dgr4Og@{ zed5H5l`B2{{lz<7%F4vuj1I3DRPS6*s5y<*nM zZ%I|xF4jH%(51qz`6x?b)$6d*o~b1>3?Ht}kB@wm?kB+#9DcpEH7@PT+~(x$ci&2c zuH3Co&t1YAvsXdjgM3ED2YIGVQE8WY8ZzD&rY-7oZnAHC93U8=z4T%J*%a$TKi|KX z$arwC_Ro)x+1J;7{qR9y>tb$+wUg$}o}HbSXE)<9kIw(dzSXaP6)ZKmH8K6PaL1h5 z<~uC=mVUo?KXUeyQ;%=ms!TVxt1K_ zZ*$*S8y>!V^6c5W+A76=|MKTPWnApOTK?73uanK^$)4PDc;dQsuM=Ch&rA|1UwP+F z%$qe=O1^E}SpL<)f8~Tn#e37A|FB%VYx#_1Hvc?OyqcK&cz^%@-}|dqude^PI{t6e z;=0eX?`Njg85v2OhuZSX0j7d!x@;=yM_4 ztpCSa*1oUYs(Wox!Zx0myB{|h-t+nwHKBOV|8Gv=GUxoR=IyQDe1)IgVR@6cKmT=^ zH+z>q*e|nhPT}&omDO7>L|zV1=SqL~dY94lnTP7T9G@hwe5o@v_T5SG@AHHI zqWZ6vjNiNO|LrU5e$V>vFz5SxmX`rwW?Fk>5uBH z^X8#i+a6CiQX}*1PkYVT5bdqkxZ9=|J~_KqNZg6r{&mLvtxE1s)4#5*`IGg#LVM2P zWvXkdbv83tiN)0HGPYg2@w*-Ge_#9G-@F#iKen*w$iuDvx58O_6+gzWYhLT1wXSt$ z)Bg-B=Kr8fw;=IkJxB8dc3#OqHNQD4O8?Dg`{#T-Ej4xF-WP?dA>13&XU*#Rw&-HX zjQ{Ri{;#}ju=)Q&%{+_U+FH%W>eWMzeyA0kmYSA!ZiXTA%)b}j?42-S!jdIRcJ12r z=FOWOJ1p*SbsSi?Wy_Se7LT7Mnf5)q?D6-$i<5&|c=z8c!Rz(KEd-*DY@QWAcV^!D zoPyYj=Vuq1L`$}FHea{RTgxSp{Vb$pX?FOcSeuFems#ETR9Rzv{m9jF`z_OcT4u?0 z<-dz8+POAy5AVePcK?5TjJ3bCo4@usSIm?@?r(Yiu!G}E{{O<~F-}fQP4-*F-5t&{ zEbRM#A@Ie+wG~Q!v(0*~_=NvCADBLE+A@iDF~*rU{!f_Of6c!)D!@9ARYvYldUp2i z($`_>>FF-I6|I&`uTIvhzc@1C|Anhf7kEP_yyT13Jw09j{?1}`u3NDi5*Xz+HZobv z_#mG-N4039l>6t*C13w*2~2pn^w8{@CvWc_&2#x3uV!@Xtg6J@8ZEi6Z#^bRzx|Qy z6n1Y{pr~L#&B9#ormd=t|Ly*Nd3m_~yZpWV)qmf7YU8>c`Uis!?;WnT}f z%sY5+-XzDz`|E#iuXn!u@59OZ73+-uKMZJ1zLsDAJ9_TV_wxTg%3s`KU-L}*&1*O`26%ihXspMJ!? zKNq6D*PT1M?&rsQE9Kf2>|fG*_y6Dfccmw*G#{y#iZgm{|0lxcbN4PsiBI$A{fzJU zX3zV_e9p7~idpV)ekog>?(?nR@W_7A3LOiF`I4!bjyEC^}#Yunm z>|qjmCjatP{<&f!<$@b88ctQq?|XlviM4FPkN%dtXSdp%ntx8apJ#vh&P}c7`!9b^ zek`=q%cJ9~;Ea{vBrVzge@<}aZT*i)cYP)rm)|m4>uuW-R)dtEZ~t)@D=&ZZ zI%l=y`tRl(t9Sf=^`gYzd4_6m`Io<6*VkGH$+A!QU*O^#ox&J;X6|v@j5TlSyUwj> zsyV)UNzikbYX|Bro-cfRX{q;gftI+Yzy6yqtaMY;KH?zMdF0?h#?T95k(=2X|CfCG z|H$cF?U(PN2J@X>Sk194ezwT9+a%&Ek6mBe<%|`7>Yshv*!?|b&;K2dJ%7LL_Wc@c zbLMPL^QTw-_p7d4ym+r@QQ9nh_gnsRwmyxim1>Jho78b;O-6c-)Z)-DU6X%5ub3(P zZI#FE01rM(-m~I*a$4Wydv8gfi?`6f-rD_}YtPxMWz)P&cK%DrUBxi(hQfshALB0s zz5CW%rne-F{r8is+iS1y+?`)!{`Qf(_r}B94{Xb`UjId+Je_;{#!mBO!Tht4@7_h< zkv(21{O5_RRORWuB-w59k9|2LF8+CL{yypd*`)`a=KnFymk(*_F8J0JSMlZI?ep>b zYybZHJ6rvC`p*knI9wTnx8JS%`ttSm^ZD{}dUEXsXV<@|IDdTp|1Xc*|80L??Jx4{ zqHLr9YZOPP_{W2xyo$S?jPh5f9(KJ^QfW!qnz{OrLfwT3MZ%n%Z%gtyqS4x!|?`42=%Q9_(MS^-dd? zQNmA=8}BU6$UoODDcI=0>Z#ef?Zs}r#kt!}xs;gR%#C@gZd$NCPo(ANZR`Z%2G)RBG#7ST3<9$<^Hek_;&R8!Q1uPQ?1wyb^mKFs{J3S)%;=pp+n34 z4(I%nPbx1tBr5vs_^bE-Rh1O9e>l4(P05kD`!C>0esZ!h*FV?3s41)S&(E{%crMV( z`^;jNzw!rp4i+P}|3|MCm`|UmcH^dh#)Ea*o2JiX60VFs|It}B=wEbx`}vg5r?%(b zQ93a9SX||{-sp{1kM^(q#K-5kXKngV#Wx4fR!ikS7R^(RTUW$y^GIfgW_@Mr?!w6j zqD@3ToVTp4e*T!(Q(}7OA?^o~l?sz9P2%=JL4vn!JLE zMH1UT9kl)v@Z|qnYon{NcLSrCYMi{z+0?6F{{8*_zd!r`|9+mYvB!VeyvwQ!m7G7y zZ|Z(^2{xpYpq% zdvdK=mzr}pxu+F0IouXMxX?C%>jGTc;ZKhQK;|JJo59U8j(SfAg!7uR?Dzro3G z?dx`2FVC^E{5RdIuWhr|M6Wk8PsI;E z%5(htu(R;R%&s`2Ise;tDTeD;u?hd(ZxO%g>;FY6`jgds5B=mnS|jj~fA5vX{{c$U zUl_OKHU4Ld@A#^%tvxe+h2)DuP-kqy%1`qz_y<%r@6Opacl-3ctC#QfZ<)KlJ?CHi zl=&A<-mP=eEuWqAPoDW-aj}?H<;~RhPx7MMOZnnbc5gg(E_BwJ)VrKwIN=HrBLh-dsE4Y|LFpZ|9K|_#HE(h z&N^ptpk6`XM9NQpjS}he@okH$@{7v17i^!iWv-lh@Bi5B-A~!d&->>6Evple`)_@G zTVC&+|3#HwXS2$E`gM#=^8ed?=k69x-u+#z{BK&F#j_70Z2BAS2IxNCzx8-!VV=bQ zvv=~N4SIf_um1M0U3{AG%rol$FD!nxG?9_DUH*IRk57mD@7wLqv)@&+XZ3_zO{|>y z8C5s_e|5j|?W6DerJp=j7M@Q(_3hff_x81~c5hMXd8eWLdA{ZgYi7=OQVR}>{JO8g z(&(Vz+|Br3(raH3^TN%H=@*ZFGT&ZoHvP8egZCL0mdkRgKThAj=f*Tpubds)VOBd{ z@A1#G?4RC;aFaE6l#Pv)?tYbI1oeg?9qOQ;XP>OqFg5t!=o4g+%n9pfFAzLlUm)b5 z(Dvz)#*h0fOpOiyLA`GQP~iw_FN4wys3Q(i59+3a!WKFL08**|>f3=b4oFVnfxU{~ z<;RIJJ*A8Oo2_95x43ze9p#iJXmb4E2SJcAyjuScdNS~C?iTp7U*RzKya-UY*QUx5 zGy(v&_FuERKFkjA1PMq1bZh`LHv+O4houZ$LvkE|Mf)JS!ub>-3`w#{A*h}xklij zRm+m|>sMsoss3azW2TtNnE%_b30~cWjrbcKF)J-5OVKx9kIjIw-^&8~(F3 z{a4}Kx;D48Q)rED!o#i8m#0;G3Q1ShR~2SfKW+NC`uv_>McZv+o=mP^wf=cT=)In% zuh)O=mJW{fnf!l)|3ByFFVCia?hc<<@$d5Ye*Zizea*@;7iZ&|EBt(&Rc>)%al?XXFgsjtkA+z`*rVR zn7{LPNd?RL&i&t#n7ZAnJl!Js>H$?<{n^WQc`7|KwSD#f$HMi`J+r^FAE{4TKIPc+ z_2>1@d-=`X`S9KG-=Yr}aRj6IRpOs;)${pvb(M}j-|j6hU%kj>)t~34&)>|J?pD{? z`}5Hc9({Io@s)E_j`fHqo~U2Abo;Jv5B`X6ka%o={>ZLx-+pmQoKL*}LGzJ4%l^#U z@3zEQ+}px_mg9@d`exskvzuVK^hbWf4}XarA8vIQ&*uMTb5}tB;L8=SUq1UXVZw$N zE2ZCk-M+4?tYdxkt@>2gDi;rrA3I*`@TgCgI$HA7zW>Lo_Pg!r?A5GpzO(9|R6f5Z z624Jm*RPMCg;RfSUiN%RFMp9Rx9YMlzK#d#d7g;O*j8|PV>Z8)m9_l+-8<@Y>-J3l zsHSVNW5;f*L;Y%?GULbjl&AL9zkljpF8n9#s*|bE}g#M!rdjOg59UPJp6b65%cov z%O3p+-|+j-vKaq`%Y(2 z*T>s^+y7=yfY?&=9Vc~OGcZe%YZC`wJ5u+F$Q{Ex+gWjoIQ(yE5(`n?Cn_b#a~Jj5Ol~{s(vR+g7KwRPNll ztNJHfduzq(`j5<@F;|BJ_0C?6-Rt&GYTetX^6&GEswZc6TUW0-eLC#QyS-mGeLvxo z|HGa^O6t$^83DgPoPB!q;g$){r)_$9aW?nSS!=E@dSUu@@9)hkIQu*}4OV6v%O-yc zUwfkWga54PVAHGaFT^HqPy2naxq4fOz8~+AXMJyUA_F#mKG1lqYfi!sOGsHgbJLt= z^(QIEPF(k&%%bLdvg4B!?5~Ks_~+|7zPL9$#Ns*4Mwx+;#PRovfU?AJ5wD|9<+H_xK9Kk*qA?1fff5Ua~Bug_mUO zKI`w_8S-ZJ4_nt0vH}|(ygEI3b7H6)I8}mbfTr#X3V)tY2r2&`=iAiWR(*5LWc_@d zG_n0pBxYRy^6P2Y6ur5#7%sO?GMj91Qh(8-y7!Ga;#U7YpRvB{?%)ir9shu8-h-|y z`2Tkv^3E@jow@GbF10R=-B(L9RGF>|rsnb2n>G4Y z|31&C{Ur*T(}z}a2VFB1{t0_MS|z{NHhKZydKJUf@?YlaezKAJMUlk`LXQll^unGfg1z=y#p;KfYp}b4;enn&st^v z+N1pWLCHE3L9xDzsn_q>+*)F1#S(ns%dW%e>+a>gulTm*?W=uHg;Tbw~ZCnHw&@=pX-k6WyMf5v6YXPNyHc_PKX+!+&Ur^Ff|N&&m1Y{1fG` z-mQzTduO@L;Mmjy4MO)%n(Dr{-xhMr^6-7mAN+pY94vp#=e#RYm~b&Q=HKB5?{Btm z^9{Z%W^ViQ$J^THYo9HvW%rAz`|#)Sbo26U=lNRCRKvZ(VwAb@k^MyfbA5f^*GgYb z(TjGU|DwmTTRUv+st6Np)ibe7%Y|W$i$;gT9sdn}RDar68Z4D^4b&t6H3bARete$K z^UsXwPa|8yf4SQ^O-Wyv!i_*ljp?8ANyRk_wrSnvJ|}+S!5{Vqtbf=+kg3sU@_*30 z!~=VQ5BE>(J>BS_Z1YbXRH1^J7``8=VP|@2tQlJWZ?V{x?nCvybH#bO<9E-`%YK<~&xF$ zS^Jgm#5IB%d&7^0{Xf6yQ@nnJ;FPUiw*L(`_1a!^ zDxLM?edn=x{w4MCzwG=yHr(#LH}TiL-7D`my;WxiHO|1ZH4X~NpW>Zf&3bcW>lQT! z6XgvCRkFPQSs$&tA-3i1v~4z#m#)oJbeFH(n=F0n_9e}`Wgh*nZe3F;f3~ee_hxUY zgOl?@zKr*+)0RhYUz2?MYLaYs@A@}8eZNiG@qOd5u7xXgU)fu>GCkbI3JzURYJL16-qGjlp+eJ;AFKIROg$5` z^ZHu9#s9ir>ey!3b15oCF3!o{vTo%!mA6-GblloM_51!+`I6rr zx@3O9&#O~(&AcwDZq4}l1e`=csY9M4h3n6Dtqp0p3A$7NdnsiH1bj$+=oa;_TIj}= zjVzHnqjsf;ncj)^YS5K@D7eBy`@f)OZgjD`n{Zf4kLwH1yQ_ajT-|&3g|UGB>|5J| zeaxrSzvem9ccb&`6zhGNQ6_ao59}YrPanRrnNjr>sPSk1)Z+{5qI|ZrbqTS zZ!6Audo1=C%leH%HM@6B^;mvs(a*`Cs%YkvKV9cb7)Fxk2KW^}A)xFB&arLjNZ(ZD1zwP^jISj|A?6Q9G{^G@u z7v>)K1x+;mus>X_u+8X!aQBJ&{hE=D0u#3N%!}^yX?`m+>qmUk{os@J6^nbAuKuj| ztczGQvvw3e%_ikbc-BdI^`@aOr?MallZS8=fAJh8}3&;R|ZusP$G@bPP9 zUre4&y;o71wCwqU8h6l~+mjFXbq~6=G`#X!93I=9pj`WJy2G9Kn!VKyi~_f3J?XuB zm*ud8B>>gqM_ps2e1bbm2xT+ywW8=n4LJ$LdPpDF)koGv{N zzhe5%wj$yBuSYEW6AcuSf4+L8V!kK(!;~)5pN4!+3s3KO85+$mW4B{%)-Mb3g%@-) z@4b3Dlktd!&OV)?s%?0H;~Tl)2u>defatHYkS{ZK!4;mip=mUe@0J&bp)^{P3-%mJj{5 z=q_1UbBW`=;aTy2ubDwJw>*IvLTfY@JD8LtPqA-xtdp$$cB#%RZRI@X^6dPDl3C_A z{x|$@9nqUQFFx;Opy@?~dNTYmp@@!%;@ z(WggOM)KaB|LcC;i=A}~YA)^g6I^S1eATBkkv03T-M>3SYJ$b`cb~ey)rN|SdK)#@ zdRE7(bV~Id{r2tOh1$Gq*OPlL?S1=RKE$>2@U;8?K0R~#`>4|Ov$**3Uq2`CJI=pQ z|LE{%t|CtZ%x36@+zb&kF=C=RgNIjYQbZLN$ve4%@Eno~*Pa|6=RC%axZVD|)WU z&UR0EIjMNZ`){8Ve(m*>>UXWKo_Ed7TXsXotGGF{Z1es-HJ{!kddySy_g%ONXA= z9DW;G|4(^t`UCsJALhrOocjH`*pHdl7Kb0KpVU$5+yBeH?#1iMOSk?qew-iiVp{c+ zt9LgEOnlz+SU+Ev+pQ)1>w@%rwRh&F=WcvoRU5jd?4Pqr=iA;DD7`VxKkj#5FZviE z&h&rhd5e#qias9c`n{KZQ|y!b-Ot`$P_MhVZTXg(qg|p;Q@@7C-HVY@5n(->vFGQf z)AIE{zkR!SQdIa(tBJ0OGvj|=_kWxDPoF$}{``5)&B2*wlU@9d-rDTUx>)DVG5_AOE&VEC;u)Ai|Vvn%W4Hzyrjvqi(aPjcVkQ;JH}b*X3Dc9o{K zu5A34d~=WW!r38}o0lzft^ROK;CHrkebkgAKKD|jEiCih7PYHpM$AlG{v#sW;?yzC zG_9WkZ;Vshlj0M4VlO;-w2C)+n^{go_(lW!^rVIYlMnJ!8lTx~u-TtKP|xSC>_Iqt-Img)FI8*s<>-zdXkLznKO+`&-?-q;sb7#ByO#S=0vOE91oNj&k z?{Oi%jXYYrzaE}%Z)>@~{`E86+uzMh?^}e++Zh)_2IPs-Q8;4OG=jI{yCp-wd?-&wLH`6!{Tlo zEZ-}wtQ*=s_4SieEbH19=lpplx1%I-)wFl|@8x3;z806-q?-I!JpS*O)4#V}wtk(R z{d)Vm%&dL4Oz!jl;OF`v|KYyJqy6U3r!QZcnwH|Ld#~j4<>{}xon4(SKd~>Y`Fi-> z;myr^nHH;^wg0rIIJ--m>A->3>v3~#*KBzHvaO;gTD9=C^}RSfe_n1rzqq=GuGL>F zJU@K8{XQyenX9Y1pQi1%HJb}3E!HS{`#9X4JL!ppMabio;^FJ67~FZX6%Vv+JLs^aJ8?qe>|k1Y6%&(%~ETSVu$NySgt^*r_e zO`C95j>z`4H6Ol4<}MNaTz-7F?zbQbg|*77KS+v6r|IWTaZPZp>zo>xHmyp` zIQ8zS9#6yR`7=d}i?c({EIAqzE4g-8sP2`|Id-?$re3^a@?Ts{YCA*sG>J_W~HQj|LnKk?)twij}K05em!liUB&C9 z&@~blA1+!p`~1D{Cd*FP?Mklrcda{jZtUD#@$Di#hoxeLz54G~|9bQAYqPY}taEFe zlso?vZ;yHX;#H3Q#*(n7E0et!r=EE&Vp)EDtNYy8^K#qo?YUuL9q?jSVEM-fdlG)_ z?em<~cl4WFtdQ#6*S2dP{`q!upVRUcmDcO+Tx#X+WkyLTD#;oxO!&UjcPH2H1pz|4 z{~XzQ)wp}x{QXzIiIncDU1X)rpqTGrx3l%xWZ`{}7Zq$^;#2<@J#X)(zh^&cDzP?* z#?=+q{`|sw-tH7<&Xm|&|IFX_`#aX8TPHqW?SFRjoDh%x>2)s-A6K5t`sCqG;j;aI zD^!|qB8ih`>px1=AA0v(sSp=@3(()I46I6KgGRweO`5;j=RhG`gv(3 z&t3ioYW+!H_+ydg?|ZctQ;tb5{3w6sr$4jEEd#Bhf6}R%+G(qzzj0)=iE3xM+J2iD zbww=u(X|-kKbj}{`TiCBQ=WP;=-*;@2Ud<#C(gHteeIZPX!7Uy(uek}Onq15GJf=H z{+y_BVVdmENRNm8K8>dq&HS(Mk6CUnSL^iqukK8L%k`YkB;<#_vhrgKS4&GvpC9l2 zDpSs!Vqf2Pa_)w6t>O1#^}lgNU;pWOuzvBGyIp!;?PKQ4#Miw(+$a<{4=UDtJ<7;bw{Q5nc z`_9>wf6CK4zh~SkRWj*$=}F z|5pYrsQM@E-DV%XQ#2s`-{XxB>?J=4`Zj2BWSrdbLcoXlkGYKeUhv=%>;5JO=cE7J zogCOcEKia3{@=B&Zl>_HoezTUPu;1P>>Togf2W1=D*3&YUtWAYy;rlw=y|2y?*E7P zE|p6OzLl~6lzaU8v!y}2!kkgR-`t++cGcl@lM*`sfJK`*)f`rpt* zu_r(4*yk+f(c2q`W!t#D1=C z!U&IX))F_Nusk&Fikv4Z4>frA>IWHfp(kUQ1WjN5zm0i<}z2 zaAd5``k9>efAL}m?k4Vt`hUS2WQE08{x!Snt37|fX*tudp?-nl^Z%g=3dTQ_&ooNE zjsEuFYvCET=OG0@&t6qZ-)xxj&)M(6m%r=nV`n_}GAx)`skirkaP&_8%J!Y_yS}YA ze`dM*Q{)G$Bk8PtXYR|E{{Hgj%e3AZX74k0UHkmjzqY+t_KZYdf8%1`Gt172?^gTd z#(9Zf@NIqhb-%6&+GoO3482|lzWU)`rl!LpchSToV13+`>CxMAxOsRE z3mO<2vgT^94y&yAv8Zg%g6S4N7w&T0;BVLW{Z6H-#l6akU!h@Z?`>Kts4pmJSYf?t zcjhB|$v-=H{?2H#*W%9F_&;)mDPz=$p8ATpH$@!0xmYjFWY9hEkG(%mAfw{5{3Vf< zH_rY)9Fe}|{H58p?weXU4%~~=EHRUIJzPI6Pttm+{zrE_c6cXJ@-{CEw*=uR^`kkL`?_y-`Yj=JT3qcWZ0)&WFw^ zoN@Ax{a5$QXZAaF4rN=}&z-F(7x?G9dFa(^*CdZERQ%@Z!wv*C4<%Rz3KKn zVOt-R3can=w@(fDEq||AWF zYu^8=+SwqXV{~l)p0B6>rUpeT9xe}O&(b+Iy-j2O+ueIpVvaeA{c$fAG5#klyyex& z^e+e9jQ(FWcxFH8`EY2H1@s$trx6W<0yepwk=aS<77e6<- z(NuXs(x>^C{(IkC*NI`lmGXF^0jY=`|baId3-zib+F2_ zHTPs+mt_m;{?C-3U$DUS#HsfBU$5i;udZf3SKm6l{>SO~f9@;y{|Ud}*BPVhe)4C2 ze!lzKN&k%?`^DkWg|8shL-OpRaHS_k19;ts}`15>Q8x!lNpY>Y*?(dg$ zo^76gb)(6J&@EHhG6O@lOwIkYma$9Mf62lRFQS&XuG#isscT@MZjEeLLqMQd=OPXk zq3mqy2lf?Tnj8+)w=}dGiY2>Wo-}plPl;~BRg64oi;u5*sl(s2^-;IXTp1UpzSdI{ z(~>RAgw)kH9;oV>$@hNUKIzjRFD{ritxN4osZL1i`-?SG{)7bBPx={=9c?|axw#|V zv}#JGR?y;}L-l66o-lHV{y6BE^5j8>B~Zg zg?u6>IR5>};?Cw0S&{eh0soJD75gejg~i;Ux!dDe%Ivry2r|Tdh2;KCbT{e&t#esu(p8-H27~4!}5n+s_oD6 zLdArsstyMK*Uw~q$9k>*&l`_6hqoV=&;9?VQ_Vr_T)gwA`BNU|v{v2tU$Xg+<`4fP z(|&q9Iez)*f9+;_#vA_~z=Q0d>50An!#Dn0-|G0bzN~Al*k<|1GeNa|@w54U94plS zZ*+E$tG#%aWyR|!_MIaCP8^g6%_L<+e3YNVI)U$cFXyNEz1yBPXMWoM;7@uQ!@tKX zX8heUlR;8kPy63vsjN@)leiYtC@tu_{IBIqvYp7E<0k)_*WVRb!Tsl>>ZM&RFaC%& z{N-l>jWIhoANrSmIO#7x_u;euFPpJWxcJ1rI_N`t(|-%M0>;~~v;HUNGEHe-5V8Aa zzyFO-JSPABYoF*}6a=k{g-oa~v-^MEEm=>(`J;S$Ot^ntjBHM$*S5zQy+2Kt{Pmar zbXoOhx9;sH`cj|&f4sp~&(Wcvu~6#&fq&*nti^Q>hmHS<|I2S~)BYcMIi*hRiZ*M@qhg>kqb#JI&<+)6r`iKFaqr)$e@sY5#^3|8q_s`k%epRM6yn z+{{0bybSR^W^{M`yTwcs?BP$ z_W$(5HP7bT=_Smwc|M=u*-p<+e6I_^;~r@72zK?D79w8-8Xz z|L^#R9k!-n{>hK?d7J0xPx)%kbD&;E%6Y-uZ=ntnD*qn~{n;$29sfA)tD$iEgy zm=|EidZFyYV|$4m4ZKtTxW3hKFf@E?{6QXO|NRS(?U|S+J+jx~+3`b0gwls8UHdMLRaYX9<^DbfR{_4qiHa(qV%85z#*{7M{*_q{!xyVm{u6mh$ zjF0OrSw3wJWUr42efHSkbiAU>~ ze6{D9`M-5>=|A~y5d*EC@jP39wChgR5RgmcwAg#1|Lr4rmrs|u8NYV_Q8@me3*4$d z?6Pj*$(fRd_mpARjz8>D%l=HC zYn^=RO5{w-%bSbSwX`^eFI`x7qh-oR;h;cOy@>&yK`W1_`%Ma+q;~OVz389x#0g*P zLmel~d_LV(q~qY9{W`k!pJEJ{bN(!j{x;oLq$BV1f0k7fw%yIk zzyJJuR+9eGyS?-4_vo-=T@Np2YjH)@JpS7sZzZi}b@5Hf{JJ-nyLCH--u6bdUvgzM z=HC*p$9r+pb=B7gc5kn~G}rA~viJ{vmT&flZ~f<)_P<~G{QpCVLac{O-p-e8U-pAmDknO~Rv{GONgHb-Mq+mGBl8u(~(c~?i(mfooLLw&_XWh%z@v5Rk9 zJbKgdq8e9R-S69bMHePLjXRY0G|s&|-(S3QmZM1>+YS!!5MS5V`)71`6aQ}xp8IXN zK2y=lH}yV$_s2N@sOR1MW44_)L-)*eOv~r}kI-jaWB8BxO+C-g_or?bdp|R`&5smw zdSKr^;mc3a(%x!*xf@&eSsY~kxFEUY-lQ(c+^J{s0zMlV#P0PREy~z|WsactBx~1;l=lTDB z96$g4-2I6Q<#HEqTNqQ!XH#GD>cn3D{eOPi|9}1bx%($(*DR@4r~WCgq~F*5{H(wK z&&T8YyhA(JIeq-GtIz)L`S}0O_y4~WC@el_`}dFE_y76x_$d+6FZlf5 z!i(z)TYb#4Fo!e$jyL_;p%eBmVKP(Ihim_zUUX^9P_{p;$GCin1Lu+duMXFhr@86>9LxnYs-3)h?Mvp}i!s|@@wD@~eeM4rPnLa}G->Mb`Sta+i3~nDjL6`y1x>OaH~+a?H5T_ai^zV|>gbmk0KHdK~_3 zUiDM=)-L~I?(V+t=RRHR{LjMn$lf}X>q=Wg&!v4gg1MEq>rbEfvHx_}{~Y$)|Bjom z%rJNODBq6KcFSaynIA(YE`u_zV|8yz-?_T$(U90u^Jacij zQ$PHL4A;L5{C}Lk*4962x4ptYVc{SC5@BVli_6o+Iai@b)BpK z2Zt{lVxWNz(Vj<2AQ zXkB=(`bfg1!yl~9)lYHzE_wXk-W$`De$Tc_m#g^y&tci-rVn$3uiyLoX}SFG`FE{0 zZ(sKC)AH-qFMjmb3EVo*0Gj;%W8U&pUq$bjy=u#iM~ctwCGV~MSw8KX{m(!4FT?)- ztnYbbKVxa_GT-0F4Ue44kJMA7#_u z_wVv@VdK5WLbulLjFwX~J<>Mq-oKx$MPIvKNNweNdUD49BO6U+@4uVkd0gCU(RJHj zE7xi{wFt*mc4R-hcU}Ixm+$39 zMV0!*H-AF;>w5$O7Fa#^w|v__=bJ0TH~ZKh{u-T;-yfVjdfK)>Ymv&wtNgq9&+~ob z>X~Ko|HS8WYc<#PN&WQ496LVz@?tg*tA6IsUq$UYy8R(`#eVgFYBK8@zV|HKzJJfI zO>4`FKW{d_Utg=|YJ1Bq*SXdBseQ|YpX&Gje)K&(Zx`?Hy#2p_UOkw3L-ld&jX!Uv zi*KLxYTLd4KeJ!Yo4Pc#clxg1b~Uy4r@UTvCwk`>0lWYGWdaZOFFae%m>PGWe#M%# zE1CZt?oQd~5coWF#^gWyyOg4i@OtoFJyCz@1pncm^`X8EJ~GIPc{A${gQ@8qVA&`Zxa1IAve|{pqopc0algG{sI|A8Q}j^{lOO zdHDS7`dc3#oH|%~I!t~~=|-(Yr>83ydw-bOn0S=kZ@ur)pX(F8|McBCPvd|>(Ytlo z{Z_l@+2-x7+*nwq@L|545bF|M4c)Wd;hc*E^7@eX^zAM$XKWpXtO}*`D&;SblI$<>~1@y&=XOyS6j`lV!TOUa-`VhErLVj=L8urBzLR!#;o}tW~@0&-1+pFMc%;H)_;)r_D5Vo zF4m-e;-jZ;4pr{{_9lMEmXM2&-bqiHFvo1tPkzzYrTdjze|bGiZr^dPDDA=jr_x>j zKZMlF6y0cVI8ra{~!95|KSB|W5a)*ll2dSmG6B26sVfwXK?YK_?83y z&&1>2STFjs|8lzcgg^T$ynT|4j?`P66IIeysLbcQpFGQY_s{yEo?xGU$*=!Ey}d3$2>JtBZUNM=?`q&@x;z$4ajA!!x`u`Tk|KSA>X9;|mulSQc_qcCY=#JW{Q~%m* zXWk=d`al2iwA^T^@(DlkZ@sa!e8ue8#{2(f#uIzjXX!Qbpng5zVVB-MRG06sqM@$e>kJ}IB7iW+LU}ePwJm>#UFMho3DS^ zVO=cdL-lgI-*9~XpK|8;RRy`mkMdik%@*dS)C47Y{n`>)9ALYCLq)~$`WqRK?XwE! zzE#oK>afk>+^hTAQqIZAfs4!jJ(g(rZ?Q@z)ri&zOVn{P|WDA@PF;fmC+j8|0JHfzo%(e zFYko^lHTvPUl3cr<7~;ocTd;-;@5p$U%>P1|I!_`U!U4@bN!E$(EfB-;$OVCCF`ZC zx|cuCZ^er&cSr{eATLe}K0~;DwGy`%hY4zEF1e7jM_J zDPMB7%-vpa^24_Onq6sa&YB4ye%8m`yq9r0-cU+;|J21-d4%{efTdA6~RhW?=efZ1aDo+}4Aa|0T}5 zUu)Bzo%U`wE8lhZ$~RLgTkd}6_!G99ulnEYiQy|EJ{&%*FOj?YTFBzHN*XsV+ov3y z^z`tI|7#?F*B|AsNWA#*#O>E}-!^OY#2mX=^jn_s?w5`KS4O|}&EKwn{>04qH9Z+W zg)gwx8+`x2iSM7lgbn^{^8T7{_}}}%U7sVRgxC4sx>=S?Nzy4W%@89yrf9xBRI1_w7?gtNp+&FRM+W&|*(m?_}J`F46CW^LBV(Po` z^}d&OnAUXW$gO2J*8e|t=l|&oSC(J|=3L7u@C1Xb^Chw&6y!4 zIJZHIGlDhSbH;?WvZJa?RD3*KbHt}>taa(__n%`Tw_fF92+z@anO}d-w>`DL9Pusp z!sUOFEBt@E&-;H|zTpA?u9Njly95M4V@fQ4%oYB$ch&D)e$7s~@xO%FhW{65Gc4Bp zX5Sb0=Xl`8|B^TUXFE39CkHLqDrjuaz2&ofe!`=A&13c_{xg9#T=1N)=M+{ys;+um z)vw2Y&I|)X*1ayOnyRHquTnw+So1w+OlbObMAgq>?#F3IIwv>$ZRGPeEwfj@!|Zyzx&0` z{M}#kmSe^I&*6*C{p3cN!^s?vQ~@^+>(jSCa`KLzDy-SCtBUwCDC)wP75 zm(Tx8XPOz`bG&|9meKwfV*gK{W6@X;`^OnJQni5bnSEc{o5|r8t6Gi+MxF^*-7ddU z+WX(;i%06S)czNiKCrhdJ$PU6#h_Oqd$&d>9G0)Mh2e#_rKBx1AwTJzjL=O^X-S**|VdH)NepZ)&a^+}C< zf6_tAq#=W4Rv+Zu7hGHI&FXUYU%c~Y`Swlc-ZPx}Z@lX1`Ha(b946BLB|gc=KUZ}S zd2)RD`9Dct{^)ObBg(;Iw4>p_!?J_*GNvuZFS<3#?3!7>>+^is=BstQr|Y$Z|Mk52 zW*YTjeM9U2>FZVhch?=17uuI~?z!WK|5<cD(;N*;M~AgZ2c0 zYiyP;D$m^(IGDQ~IL^Xo`n&#V_Z~x4`(uBOU*GWT_Kk@tf08%-kmmg_nZ>2B@0tEl z7L5Ssx?4ZbbHNQLd2BEAO0wxs$pibQr~b-63!g?;wl00zpPs0c7oV;CX}-h%pY=A+ zo~U1#@Xg=n)SpA_kiAF>7Z}d{pX`5E*?HdVRsX}oe<>rpv&;(n$NFENgN5ne;=nmRQP#Z0a#BLi71wR} zS5uoPvoNXXkGihK>Z|MS2SjV@zcxP+x9)yJ*-?KF?-?`tv@*KGg@V-QkGa;;)!~hqE+c`cJYfuCp>N1e=P39*;#!|?1rD`w;r2WpYymr^7j81 zM*lglNdMpRasGjnpZPt-QD=Ylna{VY|M%rx>hZhWS5MkJ{Bn5i-MK}jrLhq&QroKf zrm2L^t@b_@Pin8glm3OXQjd_%5)@3!N-skMyd45g1 zs^71fYZ86$?aj;W=KX7DzB$GjRkpG8zR1QLkJm3s&EK0Z;n-3mncY62)7Z-^d|hPh ztoaYJdd;=$4{tvHUH^@SoVr1?yA6kl!yobRdbvWDpuaz#Kj*%x|fG?777QR_~5+B?)&dXvc1oV|Ji>s z>(~6%H~MKRdQEG01Z3+wHF0{rp`} zd5(UiMs{{}IRBLWYD<2^yuWE#cW%Wy&9d38rJoCmii^MVc*Pfg{=4~W;G-#f_2*x6 zi&!LhHs*O;ZSB$%uF~6QR*Jo`x)l)|xh?7KJL$ji@>AG*B$xi-x$!{prgXIZmbE-v z8`^C+OalI>D|1%ru9N%k&ZYkKYwOn;Ggp52^Z8emrqanD&c_s6S19tmt@$TYdT)PJ z*vkH3ne{LFCr&+-q*|-rE3o+EhsKBY%5&I{&bAM4pL*nQpn1-XUx#cekG}Y3|Hso) zC+Fw-g1pXuf70E~*PltU+hO%-e(TDQ^S54{{`cy{|0U)BCLONJT+^`Tk^PG6n_qso zKjT5^`MA99%|W?SnS%M^m*$o{c-1$(_hZ+*ra6!QZWrG*%hP)Ps=HPH(^ks!HTbbk zpC`A@@dZ7dw1VBduHc@OQ*eA_0qNpm+ybEf^&Py z*Q+g;&+pqE^}<22CMP2|{QWWw1_yzR1#jz(7$(iyF-4%|zxMWO(MNlq=%?;pS*E$h zd5+irszcsJMHgq?+#+k2@NNG=JASD(T}ux8p8wY_H=$m+L-+qv(KDyd&7C>V^s2%) zdzVI;rvK9qpL(;rtD$G}-E()X!0pRAYq(ZAmL1H0{iP0fG>tN->_+48ge zPfbaYS+1e3?*6$qZbI#!uU{+u7H9m>zkV=GLG(J4@$QeC`@Y3$7lq8aRiiDx|CZf7 zuJ<;&nRkHu;L+u|FEe}hei!}YF6E{DpL6-#y4p%UC-d$LTl=fO>BND3EIt{9no5cUXI3q3}nqI>(KTfA*L0Ot!h~R%bBpe|pl* zdA(WxH(#m#YaT21XTkUXN_#G!{%6kd$KBOo?T2=ic{l(3y5lqPN{)H<|GCxQ-`%}2 z<&^V*FF%j>zyCGyUhNC(@CQv_=Un~s>P$)X(}nA}-|w-UlBT^_JMqJ=<7-11lh4lS zT37PcYfE?dC;3#3s(;ltF9pPf#qCS_dQ7aHjlN{y6VfIOFpy_nfHJ88{eyEo+``Q9r?-c`*pTasoBax zzl$|N-QD3AzC^M{{qz@nlCAdK{?7l^&D*E5)Jy$1?=woIZ z&oi$HcnJSIt@ZzO!Y9yT3yFI#&i>Vs|N7Q%Q{bYBR{x~m?*DXh^<2(tUgtk<++HrW zbGGJ-teg+GuCZI2#lO8VF~Qi2{omyB$7*kDZf@3$vb#88vd`gqDU(~3w=Rmu?hbNI z%UWjqDTseh?KZOv6B|&{eqgU?eExBQYP{iA9pl44Y{5&5LRxKTKe!Xh#?gqs_8&CaTbNN@k(5(~k z{|vhROQgOFEc#n}{9aRpy}$qZh98?&7yYxgwKvlXT-DMNAwR|N=pF1wnOwLEKg#52 z$BGZ~sTyZL|39;L`u+Fz*0F1t|Ih5a^u4T9c8wY-sf3~}?v)|ui z-o|gI+RsP$aN0a^TyXG-{h5Z+eRAj9j6QfqU07n>>chj({=QP;&mVm|$Hz^Fl0W{M zlDXOQUwry`hdoV~7_&M!7N%8%N&H{(&Hh^O-xK<#ALZwleYzhJ9P#1s4CDVSRmbW- zl=}TsU*P|5dF99cg|q+PJY%Mje|hHZek&`vd-<02Dbb!=)>^E7_^0)AQS6Q#>kr(H zxwiS=7u_qH_dazwYZA|A*J_Y`dgm{bp2ufY1ZPHGJa=P`_39U*>fg_QG?HJMrg7$) z#ZJ&^BsvS{7YW>4xA}Kh%~Cb1xJ$Dp_g|3mPUC3$j)H|h zzbri4t+vDAjXsCTi$CmA?~J(q3tIMD{ns}svWYv`+qC4-iq`*Yu6&Z8zVi0;zW+a7 zG1(pK`(b)NL@>ZR@zMXM{0C0Szxi>VOO$cVe@1XS_dq?{Gy9;EbC=B#ln|WUv7C9% znv4IA2m1YUemVE;k|*lgyIg-~ZTlZN!Eu85wUU~B#}3;)o4B9(P(4%9CvmCg>mBxf z^k4kfKjGBt`UVHkgm(tV=lFLelAq7&#yyc25;cz7wk>+f9kCTx|9f-17d3cfucy3O zzVZJLmD%?rytW*V2#$DOUNCq6G?VOok`4cVR2}<2>GS@KQ-2ms{LiAc@1HaWc;>pz z;Qzu6{Xe;>Y3U5Io4-y`9HCE_l6Ds3uk_oe|yG0IO_S?6KW2O#h;RA z{P(|pg8$JY`Cn)L3u|lxbtS>`q|3$sTL%3&e^%Y))wi?7A*{O}O*)!ko$I!5%Kv2( z`O2qUw>-sje$}6JzX$f~wu#=`!Sl90E7-Q*bfS%ZnA?eOP7m$xKL7u*)cfC=jiY z+PV3eI$zz)|NAef|Fizx%=s_p>}QgFWWPq_*#5>-|C!8X1UO6t&KEwgpYZW#|Kh@b z@)rdnLiPyMcV1!?N@whwKjGPmTa#J;&s_aUetPCA@moobp1+e4Hyu4;xSwst|Kr!o zZ^nzxmY-kxr@bMCg9X}Xe_(&@oBb1xYiH{FKG~eFP_->y#eDSq>h*v7PwPEsKKJjq zdFc=1xB~0$D_9&Ju?G8 z3Y#*>Xa9Tr>fN`e1#dq(o%)}o#W}y%>%%fmT_$RW^ZG3-OcX*`9`4w3vX^;t^9wc@Q?o0$NnAXV|=^f^zND0&e&@! zAFGkL_y6=|?dS7bGMGeOO#ROf>A+-8UR~bs&sC>T=2iOt{G2QI@7u3=TYqZKnJWx& za~u7I{}+b7t$!A#HO)R&ARz7kW`n}#>$hH1uD>byf5pG}yUq2PM*lr$togaD_5YJ& z_8PPA~9I;!ssp;^1qyOElD-{=PJX}{= z_AhJ0|Cjq8uorLFZ~f2GHK)Gi2R~%|0kmE5__=@T+I?)BzFoZiKP3If#JBake%0)J z^0R(f*5}Pe6ItuOKC<5z_h)&;hj5(*(Lcl0f6rIq2Jf|n9Oh{3_%E3E%~aL;iDI_T z{%H2pd;MSEsu}!XLX&;efBpFFXY^Bk%lrNlH~VIvdCp#2^5;Vl4n((J;-;!BZ$oI4LU^2y$%DfcIvJT6{~o`d{Bx%NnLp}jqCXeT z`=4^m{=xo-s|5E2Nc>T3dn$kE$q#+QRHHb})iI`Te&&1p&y&#j_xKfWeT=Dv#~};8 zga4NI{@1i&-tLy?CI04R75kvCg&=@oz;k)E9F9X8nEt!*lx| z?>;29-7GiP{pWplj#Jjjd1l-{@>4#_J0F&t9-02iOKz3UiJt#&RvtL6`n!JWTeasu zw;IWAU$1w}p7(YA1~-SVnei-Z-qtgTo|b=7-{`JiQ~tx5;s3^``+s&%)6-rZvL|NW zBCYgaIY&>Q__1Wqp+|`)>*wV>dH2q)=|}(R8v-Xn^Is(koIiN)zxM1`$CrNoQ{+4I z{~900-zAOqrJw(o6#o7sI&pu>r{undRp0EFKIMN?|KUaJd%k*(2li!u+8gu@Rp(yW zQJJkAH*;ou$eseuBlSIVe(*2zi(BXReEq{8{odz3FX#FCV3x@L$k|ET(t|htUm5v1 z{6N~X`IG*y=`jBPB+LP{_Uur3yFJSXdF_9n`FIX%t9DQKojY@VhJNIpny`a09sgPX z1;73l`us_%%rR|M`|KKT^S%9Qd$}(@b8oeuyx~9Zub}_tn4$43I zqhGXLA2f{naQ9((rXT+0|7Kfh-#52VQcj<>#V)<}Z`z6fMomBZtvCFPFWLJ4VM<%2cQ3Md|;n?K!5tAxBjv}XTJDj|Jc2bgU8~3f9aw0tETopO0w%V zXq{rczvjfbcqDIU|69HCwnx|J6LTkqo74+_xPRi2{kn}m&d+-F=jkQZKSf)oPTX^@ zo#_Y9qig|<1_vg5&)&Ib^^pX~2C zb#-cJ_Nh~=wL-O4UtD)G@-no{nfm5VR z1*b5k;|mv^6Ie0pXXTT#|38CP$=p^By*}AmeRVODYER!}mE5{-JJj4%M7nB|FR34| z=nj!;Z0u1w&aiun(7!jVO*;Y>dbGcni@0*7Y^RZ59Vd&}{0!^e8cr5 z-}cSz+|Q&dE&4~6-m}=IWWCUM)rYq-Yc0R6$U8kl0q*1wk@zp_wc z(fB4mf2P?v;j1!}q^oa*dn!8K~TLOf3Zu)xn>CeW9ySl~qS5L1ty3;n}FF$L&L5n?T zqiFg4fW1HYz5h8qu$P_5ukH5GUiib$sI2pUatt2N|My4z!p#3~I)27;%#7D@SNK0y z`@^LDv&ui-J-hV9%*RG~RadVuxAW(%o@IBA_4Z>S!@WhX_c^ndo34qSCHzjMq-XBt zRZ8YQPbP1xxP0`v?D6c?tFP;w^f@lQlzm0t1BtoYH*LyDyZ9>iH=jw^6BcWx|B?~k zgr#&fI@Z?FBIzxR7X_p4LC|9`HZ_vYEn9J8Au)k*71W-RnzXJmb8@Z}!s zQsYY@vlO&kStOIq%S>k7Xts5md?SEa?3l*16)U4ZdF$N#TA%iAiuF`U36{3=&%b^x zdT053TCx80&)=$VRXNYrn{wA?$->s(p1T%@zFGE7`t@R+k4jZ9U1vlb&D(eMu1NCH zFY9c|zh}(r=Bls!74uvFCF_o|!)l?oT7UnJJ|E(K^5n?}_PZvA-JS3u!uP}dlvAu4 z2`f}!ld+NJ4@%!dK;Yx3JH_CvqBhM)?4mu{c`uiizDwo+?SC0zw-7~|D*rvC!dX7 z7O~5JTao%h&tuni880f4Vg7nY_=(WGt!tGHg*I#|-Lhrd@+22eHn(L*R!9W;IVKqC z8$=#IaplgeTUSjJIvy=$3i@My@`&5xc^*U+-2LEw2B`V=f5mc`uWjVHYROSNFa~lamjaO=kgxxZ#-GAXI%So_ddpl ziwvyu6hSp6})93K2J`0bqKFS@GV&)l`arQN{zy7z(jXH|idR(98$|E-tH)DivtU-j(C zP4geFE&6XC?5b?PLh%4|)Bn1E-}~>^|Nrs(c>lZmHhb-gm(A?FK8gEn^yB59E-ycp zyZds`Q&Z*AzcX*!|J@&7zq3B|{-S`{=YIHqfaUrOg_w4OHG@yH(dX! z_m02&e0Y zm#q5`pVbiV^?_%fazNLAo~J+mPkNTJ$!SsO=l_ygS$||3-tM20CNlr!jp=?rpXXfu ze%ChG$oayS)V$YwADpyiaCx=< zcJhNW0sG&GCH79gwN2$##PQsnNAKRbIfHpmhg`Mb1N#s2r+tcd6N}`$HFcji>yiZ% zL}fI&TTlJW=Q;cTx~{O$LXq>W?nm5?t4K-B7M|19(d9pH?mKw_FO3VSZSJ4m^hDT6 zd3}&SxbJ0M$-m8;=IeP)`t<+fq#rlbkJg9S^#5luE(jQgi}@t@O=?hfy15ABU-e!b7O?Z1E9f1gO+wcq>0U3Tu? z)iz!B=eDJK7Y^#{DcT&kefYBe%73eOpWWGK@-MmKdfeX4>c`I?zI<6VNI$XZ(?p+uDS-ZXX^IGZu%ac2pci;V|eY#%cZD0k+V-C~) zYuuXr)Sml&MAD`|=AOqjjI8e6y=-q~HZd{H_t265?iO1&f4lFtc|%QH@!K^~LJQV^ z_AZ#P%r>jaZ3&)hDps9fU}cjMke`xX0Fmmjb9;AiRcob~YG{jDG6r5@PZzKrGld_P6; zzwax@f3H8Ch)?FOzT9$@?bx$TkL}OYOg@w3^`z&&LBfn<;YM$5pY;4M_@Lma;v9ag zUc&4A|D=s4j_FTdvo#;?_k3U8otyrD37PTDfBo)d>XH{;U-^>CRHbHf`T7FGU1`6BqL`4qDY*0V zlVcnk&QI~HD+!+c$0b^MUgQ6OuZ!O7ko+Le@~_(SkGPPay7WtfyTMv&`!{H4l}%&& zQ(t9dXYYG>{=BFU%iY`UAMazRFX4LA^5?~t>yqCBpDfp6@;WqM%Xe4MWBZWo|E7y~ zGo=2^pCs__K>doUz_L9YAd@ev{GX_KE9H6pG}EWdjZ;6~zj3mt>i0`czSYMncTGC5 ze6`;Hz%A;>9M4w$+tpob^x^o6JI|MEKA&%MUS846sH)j~QnP(Sv(y>K`%@p;Z~DZZ z>UF&S!kqe$-|Lf}%m3gH)j!oI&iJqSK>e&I_6I-7y{qe*^sFrN?{>dm|6i8M{&;d| z{yeD<=}KjcK{u9HZjTSw2#CKIwl^)l_H5$(B{z4jFkIs7`+t50M~BhB!$0D|VSU8m zq5U+6xoNM?E*TyVtKUV)v=+G9&q;YaciQ1|B5YN27)9;GR-FjxT(RIuv(TNLAH-a5X81R#{!~f% zv{}?9UH6H7(l)<$QqupmU;SUc+;egB+*@%DwNcym+dcj>`T5V_b|&l3KTA_TtS^`( zF1X#d`198J4|Q*SHDky+5buwyw5cI zxwuMSP$hrYw*xIVGx#U0w%LEAdD5;GW}oKoy2klG^Th4tER3Pj549~HIPX7y_S>RY z4g6n^*OaX0UXb!TKcPZK@`j+?>^JYk7cKcaUFV0GxpwG*dd|(VcWY8^)%&{Y?hksq ze{#wL{y*%F7aAVg&-3m&`q`_nmE+KJ`%JmS*&T)}jQa z>p#rjbKL2<{YAaMjvr&D9@>^$Wj0e?p`cdllz#Qpe<$iEZuCsqW-rvy=fCV)rE=qu zCnZ81zB6R!ADR7jX3k26PW6c)4JpcuMI4sQrl|=_3fv@q{xJ_*_IJCqh{o#=mqS+` zoc_q>rd|E9y%rCg<5gKgZa%*rc{)G*;rS4gxAL-gPZ;gH;<_6Yh)E=VtX zu}tKbcs$$xleIdRR3}vhY+`-W^Z&{7>wN#JHUHT^HcVb#()j<2mGtw~{~Gu!>kiu8 zeY2X0NovKFx9d-D-rF&|A@x?h=j6PE3LVitZ@<@5{yQxe7UdV4*kJGacE7}bZpRA; z9@%eX_PTOJJ7eb(A(nskS^e5sd!Jm|6V{Z%=Pe?T_P}cwzh+8}{&gjvE>C~;cKJ$1`JQ(N z=I`qf59l@A&$f#1_lsX=^xH07oBMG;mr?ifzmp%??>uM!L7v5tx%t1<*LqF)pQ|^% z-uUZfjkf-8N8W&c#eoOvk2(FD?NrHlRqFi0+h4E6RleQ-Ytm)w?Xr{4F{3SId>->dxBpVIYbueX>zobSnR z@_Uux^X|HIVY}5AZ~Je(`R_^@qmfHW$Qg0W|oG4%Q%J0+iLo?#PM%6w2^=HY$^C356bQWx1cXR=&YMJ~7|k^m)z2 z_Zx5iJMtmj%lW{&-G4J)|2f6;d&1oRu3{(^)@!N%rOQ3TuboWS(T`L8cR6@N!|c58 z>SY%foBn?FbZWCXo^0U*nK6bf-a_}!J`7WP{ z&-wqfuM$r^-p%me@xlIiAO1^fyV)jJ+Syk%Y~MC}*PrFrkFwTG)qkTn>(x$uvmaiT z|G(_ob|^YMxsG>NX4@u(8=-HECw=`t(^L1y>J@**kqvwIdH%*Gwb*3I6UJc-l|?o+ zr+UxTPgZ;R`s9wkRSUMqpXdGbcF}GBr=Ig9S8et6y!?_Ri0`Jg?}VvRRmsL735krk5N{kAJA$TI&AE$6Z%iedpBl zT}Hb<<naGa{SoX?r}Sg-`?86D)J{yA&+^~1aRC=c#tD82E+!?hkokX5QWewxm07#)9FgrF8R&(#hm{x^Xvt` z^}c8N!}-Ji&~x>t|7Wid`*YHek=t)phQ`(tv%5a9|9kD?vwX=hVRN~EKTe;wx2-Gq z{cB>8d|PMciB;L*(|;QtaEKKrvLl5PFG!D~0&UY@_ZWXFxUw+cP(7JNHx>KS%rp8L;_ z)B4kHK5{)#yC*ny@#kr4BKGbo%&c28JN0`!i|XYIPt*N$c?D#x7AO2~_0=?cV80^& zlYD6KC0}Jd+gMMBE1_N!f>g|xX>U=VY|`h~=+q#+x~zG9)|us7&Q9kq-gG`P@bvqN zpJ(@JS^N*#z{w==CTR2e9cQ--|9HK~S7_V+t~IN5_m?pL_dIF%{KMjJx+~v(yB22l z?Q+cByE11u*I2M0bFaR6ko}tJ%(F8#zdQ6e{@>TXD}U;VG@qGM{^z3q{WtM@*VMh9 z&Mz;gTcDb8_Jh`~%7WXke%;zNb@#riAN{9KM=VoW9r|ULwEZ^o^{dy$?%n@2@b@zn zY132ZKExG$3=3A0|9R$6Sp2T?|3dAD_-}97`+c8IvFr^ohrpE2ol{VpwQrl|$< z)+M>UsrvlRLUw7%3gwJ%ve$KATm9*s{=k0a^EFY;`RO;*pZ*Wdm~z;^|Ne9Te5dI@ z^P6(c+cRsvUiIIfqvp$6n>VjZo~*x8%=X_?usPrN^xC(a(qJ=;ompsCVSr2w^|)q76s2gv(~&x_@%$QsQSE2 z*Yf3Vc~9;|h~}sjp4svzx&Pc0pXZN%96o*3?#krSndP7Uef*P|HRY~R-tD)iug2|p zaK<$~noriEe9ej8@3a0&-`er|@LBdB-4lLS_&SHh{VtpRLD-=G#)ZQA>^E2P_I1=9 ztG_%aeaD#@o;kZ#|L&PN??_rzmGI{e-#&l%_WjGp?;p7po{0dcjvyvyb8#K@;|{+q000%rO*O_fbyNm=VhWVeYp4I?AFr2ra3;>x?XQLcbl;~ zu-=KqcVfA!Dc zOXR**U-t8!eckV`53j!tj*&?EC;Y5ncKxG^TdxX+U4ACFvsB^oJf|a~)1$&zW;gv8 zIiZ(4|HRvr*?V5^o*!*Cb=mSWGk0gaUHIC5tL}Hv@^y2hBB~!=JepPiNN7vP-xtqB zHy%H+_mk7{<0r3WO}T4Q@bv38{^m1l7nyIJ7xmy#*uSS&`I~(>J7RVQJU%b;Lf`4& z<5a)yY@7d=^Z);O`Mmz`x4+@NoadI^trryezxL6;Z?DhWbAJ77U-vifyUYjqAM5Xb zn9q5I`B3q@$LA{@`u>~FpSSb(ySKbY&MF?P7i&DNSNr{`Qhby8yl(w}e;(hxJw>jj zKDl;E<@>vN_K)o2{I?uAI{TY!=Dq#3u8ue7?GDf0!}2HnS!m6le`nWjmRS)luyfnn zqS^%v))H}7r@uE-jan64c6*Ee?SAoH>>=}i&U(-tdE!<6xhXq$=~x{7yJK=AJM%+O z*%fxL`@Fry-j3AdQwavSe@^$=?>WY~?cKL-fnWcnnp*z5C+(P8!}wqR$9n(I@z;Ny zc79dFIj=ar?i_Q;zv(l(&)vW6e2Y8tPrCH}kGJ0bwbZMLDb%(6{C4@uZ)sxFY9eQR zd&cpw?r43I;ofO6H5=@k?@La2Ijwp_^KRp-o?m3{p5Fh)VuI_z1)aX9-u({Gu9e7| zdUx}q?rFSlCM~{RzFeSwYV5D&YpaVcZQD}6^#U)rbUANR@cxeye`4A7*7(}`MHg27 z)?Z}*^*<<~C~!z+#82M(f6bZ5i;6n&^805jvVGg{cV@O<_W#mE`90;u*Z&-uv17-M z8!r;RcZlZl`{{IjEGho{;Ztg*_4h@;*V`wuUsg3R(>ZYc^l5900J8ndLsz_e+=j7v*9nI!MSCt`}f7YIUBP6jhNx=_4Dsm zKKS)AsZQLv|C7Gn+k2(&p0#ll@8Q_lKmBCXzq9+_%fw6(I`xU)H?rixx&6`7OuoDS zD;=nhI#I8vsQAF1gXw=}d)k@Ejjtb^Tpt~^erv4N&b2yI-cL7z3@gRAMOIv080=L0 z@947}ckcIhe3!3_**+r1|1~Eizq++}cCp5r4Sg#uKm2T6eLX*Be@#_- zYLD=K*9%6gzFk;3S!u4-tr-X2C!|ToZ2B5W)&^Jfb{Ah;CcND5?P`t( z@u^uZXBVFLmyMtQu0uR=(Swh({JPiOsC$(3x_5T2xPQ+24k4bL_wTwD{`W?0d4Jhx zTF3vGo6&aJJ}m#g+W+I`<>h_Y&Elf4qJ=du*-_vJzto05<^`wv#1}d?{{N-)f9mw< z$B!L5H_KGp$Y@g6$&)8J`T5!ZgA_8AHT?gebfEs$$@<&d^Zh+NPo6r})!Df)Y1Qi0 zix(|AP%pspuem|?f&Cti5A)4F%YXdeSyT7=+FE85-BIW2B_$;n&A7Tc{QOK~_CM^7 z59~Q^F#bE-&G0|d_zY-Kgj6D>}@%dx9<6=YRT%_dX)RQn3(YF$y2v)*p&5d&!bDO-rQZM zHhp>)_>o&YJlp*L-%qFY7tLsDV%qZGN#F-R#8ba){~!Fne9nKr`F6TpE7z_)`h%Z? z>A&Lvz7O(oEI<5D|Lpe=* zRaMoL*|TOv1qM!>Ig|5WvjV7lBk;qY`=`E+&YDe|iY_j4RoRn&-)@uY2Y02F5@7Qb zIGPUB-#S*Ga`t}7z7?$xPE2d*44%-%2oAO;1&%+ejZ9RoM1Z28%1@$RA=o`v_w`pl?@oz?S2D|S}xsIFjNy4L3Vk7u`5 ztlV_-%%SVsw}(_}9k7bhx@>7+ckA@J^ZOUq9jFhx_&V>;jeC36Z7ciw@0$DD*^_gu zd_(IxPNkNoz5lV~Mswn$8CSQYA1tZ4@W5WKzF^jD%a+(1bJFsRqwCl}BT(-+e@k&^ z?KzQiuQGy(C1mrSH)%V!Gl0@Wy!ns!1$}!H&YLCwKkV&&r<3_a_PI%0t;pDx;fo`MV~m8ybE; z8?&n-@7A4HrMJu0toJE0W&f`^Ir-ef_UWr@HRR`=-ZS}o|8xJ>Dxp6WS53d0ckbHb zY~i_YonQC8O|yQ`%=X_?q0ivRBaR2{XB91+Z?v7x&C9zNr_1p{$WuuFh?s*=dwbBM zSXOlrnInnCESA+1|C>amWO^+*=XUz=B3rqa$5o%$ciKRT$d3QZp33d4-<7fJbyIME z-rLnPXCGa6@AkjD&s`lKBG04Fo)8^sXK!w8yn4&aTg}gQ`tg0avZCec+uX1FTK+Hb zf0QP*=hrp+Jh`~&$Qj!UvQHo8_O7YgICaPQ&+{`q9-Cjk=E|us^JG-v-*3k_ikGgO z=EWbl`c2rHKm4=H*2M}Wb)T2~qyCmhIH0G)Lu1Xv(zcIA8&=HU!*P)Rp+Bp-$l_^U zdRyh5+4qXiELg;my>c_>dC!cXMGqb&?`#U*sCsU_W4^)<{w6lH|FZjke|?s^_4Kr> zrg?wf+&cgLTdI|%_`Dsr&y+3s;{%$^)F_#h`#*Ko%;?tj+4*bLYyW1fWcj4=Z?bJ? zw?XHLoezF&|7~0)sQ1g}f8>$6lFz3;F(iuHeLux5E3Y1{?OPgB{y%$k*1hHbjG~|Z-&CNJiP3eBRetnOs(f;5+v%^3Of!-zLgV+{o|3WB!~~9Aw_4eNFHX2$&N8t0jl;{_AVMYZ*=BQYLE5pO^K=-9D7x()D1yfQi9R z|11BpCtoS~e!Dm2%kiE^#65sBsmB|29N$~do^tp5`fHb@&OBYFWzX`5{oiXbp3Yc*C4+~T zY6JJYE2vpM*FfRS0a4QouS1i+aJo)V^>|VHe|}oGPbsg+{B_3v9-o@$Rl+P)Yw^II zL+Zhw^g~}(=2e#HoWD8c>V>NR6|Pfuug_r z;cct`mdroV)W7rkb+-t^qbuj>O=LPT*|wAQhrg`h9q;phF6`T^aObwMMf&Bd?(zEH z(q=`d}%qZK7v9EmQa_FR2^yNA9WjH+(vw2sV4QGpE^m+q|ruWq(h-T=uEp-IW2am7Xj4x|bLQiJfcY;t~J&tWPCsX^GBZYq9|Z;|3|QmFC$JG+r> z(+6%)@d!~2s_a^%xJ|`a9%h5;!0RjhGCeBlAqKO6nj=sfL6s-8PI3g*egVm#s>?&P zw@G2GbO-OhW{AKF;eUsn8@9ZeEzKodia{}<$4kN6f4KdJoxMTQ#d$y2%hu!G8I zd5}LE|8JS_e@adE1JE#KG(%N9 z1la;n4;KF5%>mK`GUms6|C3iP9lO;8X&pdpIZ*%CAKP$=+jDk9o7H;tzXO+8{@}05 zOuE6EDza=-PHHe}eVCb&|6j;R<`CEF)!a^ReSOl>u1{@^Y6iKCNzrL(`0(t=awI$MpKz`mBB3A(OC-Ft|=!^{@Yg@m_^v zagltxUo@5Ir-|2b=BB;>Q}z4Ko@K?>lWM#8-kdFO`p?hw-w{++tp5>GlO2_p>%U=& z=Z0^m*WA2tWlO4WY~U51?K7HAiN4-$_V&h=3GykYCp@t)zTWc5)VeJ1=^5_gH+RJn zKg^$YYG&<&u-ogJRx~k}+r>Xn`Yb;KRGF=~Z!^78{k{D8`D*q-rIGF?b-T>s7@2Mz zHGj9Jd(+EH`U{iq9n{bI`{(t(8~ZCRuJac=6Y@0eKz%?zs1-IV$o{W(;@lmN@7b@b z51K3ZDlJ!Qk<<50`t`fYTY{&UZ(pEce@fS4`>L9{yt1^g%*$KZ&lbvz>LmXe^Je~ec59bLqxvjph2&j1@s;K3T&34#W~Y=E#NOdb{c!!I{=<@Q z_pasNj{c^z?q2ndOLG^Vn%nSyf!xFWvzZ;1%vh|jqW$XpYK?A?YnRE=fy?JDU{gk4v%~B!{TOO+>))krceIJRQBj+@Z;$htSV1G)RLe2 zf&ULXD47cUSf8G1XIuRJ?rrIg#YZ-O`mEGv=nvc)r-``vI<-u?1 z*Ndw*`YZg%fADcWtm?P|t2)&6H)+qyoF%@Y`274=`&+^arTf;Lj^6O`MCaY9iF4-) z!L4pLEx!1(x;ia-wvWD5?e~Cb7d|`6RO{-_2`H{B_i^DZbAEoi98zt}?Y&RO zM{;k)?+5!EkJqccdm3LRbD~J#Llm^LTBN+YEO4IqhsB2uUDY}`KWl%>vqbIL=2uPU z-kdly+syisqRzGpLw8b8@syL(TZI=D=U6(+B3Jh*u&sQ z{(}$mQx8r1ru}tE=k$khRnOYL&1HRfZ{9)6+3W0nRc+kfbYfk+`K~1@xBQa#w=84) zdR98^{JoMg_ozFYCbvHWW!U+rynKA_?62Q{M@2|pR+jf)^OWqTr>6e=`Lnq7*6#B4 zIrG}u*wWL}ceYRdadmZgHv9jxGd3q(KR7vl`L-<%aZ!b9cYIB0A|ayszqLt8)Cx zR(JE~0e{kEuNS1$TXy@GZab(N?Y}i`vCV9|`I`%V%mP_bT(>?t+I-PELo?=hv!<`X?<~wCLPiYxaMa z^DHebSI)MYrM4+LG}JWl5KCZ|uW#=g#j2_*?XWcp@m(P{ospZ57qbn%Qu$z$7FafZ3BO4UwzKDE{2MZx9{)Y2xZw*^pwl-05dyZN0P^k zihp|X`+B~`uf2Y#mHX|RH&4_eBO|X~yLRfBaMJ2$-4pJgnQ0vQ(0-BUWHmvSCCsXv z!sqW#(G1?Q`M>tZKG4A_VGtuS<>k6g+f-hgax_0%d zrG>==gPW7w5``9TeQY1_72FN|?>5}XxMr2B|fg=5B)DK0gQo95YnkpIEobfA8M z+2{ETZ%_1ZZ|!j_e<;|pI7su>VpYzjOaJUX+VM(Vy>@P{wWq(%rlUXZGpah(sj8~x z<>f7s2oJx`$}Q$0xKQa|cXxNR!{t9eKTnN6clq+>rAu3Lw$}U;57{fg0;>Eb{r&%> z;s?ta^|!K5+$XBkmno}i_05aqlJn%7CqD6s{Sq;@ptJkpYd*HFP?Y#%Uf?43L^aP+ zR#sMMo<*V3PuIz}jkKr#*O-{>sej2&-(^;9=kxv@oUXhFLA5Gqq#*bEe^1{3Z<+p^ zemc&g{m}kkK(bR8i*cx|h|{tvLDSzsya&HL1RbTLV8rk3>dN}^l6y_#DR$P=PwkzZ z4_~@;$xmM~>)TSPrl)Zne;{puC9!|hjdQ}!)UVq5U+a-=<=TCl+E0qle5Gn+G|BEN zx8xti@*s&1^UJh#b$fg6DbzAfO@A%*|D@knr(}+FU0srFTa@Iu>ulR~F{* zVZM}7cD>B5o7cgqL4YMw`9J4JSCN#BKLa#+p1lqHt;1)}EPD9i2FoUoZ9f=1Ws(Hj z9v4;4jBHA-WZxXQ<#UndzsDE!boXpycoT8uYoy7Q$vd3o)QgV%zOqu~eODZZqujO^ zZYIa;xz;QFJhJ3n{Hw5~a!n|F0$BlD|pe?KAs*>=TYhBwd^Iz_Mxp8X6zQ4{%nKFC6zq4PkgTFVlt{$Q;*#BoEG+A z$s5K0^S^{Xu`yivTRd&L*4%_}tI$t|mx93&^M~D0;0o)%$EMrNJ|7ijV1IfbdGnD! z>aDs$E>55Scz#%%VzzPp#AEf3j4zz@J5j9S>Ct$pTqEPZsPmFDv4Z82_uVxzJf>wC zU0d+q|6b^lc{4u!o?gdM?~cuAN);KkM~QiSfRl2O7`F6#~*~d&+9qqJpQno zXOl{V?=y!}s#jJ2Ew(;$LuR7>1eTjc`YP<5D#}aWZ%qH;|1nerY~1gZkh`ql!KGKL z4Bm)HMf_1Oa4X!I^iE*Ma+W^hM5E|8(}ZP|kN;Oc<1edl>dfo^*Uv1q+`FXA_037q z@0=ocWdGWHdKXY)Efi-ix#AI*P4Of>bKej1FU&r^^47u^T9f>JF8=jiRy1{)S5^8^ z|2L|iA$KuuqKxtmr`f zgs`g-M?Slscz^Tr^Yim;>wmqud3pKyc^`T|-2Z;R{{F37QPI13@&%w{T_5CGGW~m9 zXVq5zaX&bJ#{YRj|DsQY=f=w3Q)pSw3F;p`u;;imPpbRNPvt-Aob@*Usy{t>`QCq? zUHw1zvkf2qPiz(2eUo$g(U%LaCM$f9hmV+@?c(|Iqxq4&;UC+@5BeYNUo}hWsQc#G z@fk-Sl#1=X{pFf-_Hl;?_VDi5EHTNq-fq<%2kr+m{`vdw3FpK8OGB@|`aJ)WD`TXV zYpG`cvy%Z=CpG;4VET2{8J*lUXCy%Z%kn1RzcOpmA{|~06dfe?Z^Ux>u zV%@&FaVJD8pJm9Xozd$NJ@fMHbe=R$hhD$1ke(d5rylP9p%edSh);cLU$x4BcKzzrx_#Vznk!;9 z)@5Jr^X2{NxJ~3)6*;Mpcw)BU;-{BQ1QJ%q*L}t#^$fyYI$>w_Kb8jt& zT4mt0$QkWnMjzz&sr7cfj4bLs0XGOw~u=qXuv}@Z~*GA9G`K^EX%pI+o*lKM? z+vQD`2SqrY-GOu zLdVzd%h#_z|70fPFm;r*%49o=FgHi7RE`hRMl>q4_h zf6`yg-2VGi^YMPGTl;rbd=`9YzbyUf&uD8Q-ONAbufNy-{c_s={Tt8nH*bxyl$mF` zugl#XBd_tmzAgOg)7`$0j`RNm&F@tOg@y4s{Y&b+Vbw{FiS|XX80kFRcD@^JC^`YAnxG zS)ZQeIyGN(PgbGh!8Z?!_v7?ZO&xuI`Fif zx9r8@Uq()ittSs=PkSb=_FMeSCv7j@h#7)gX2|YaW3XzUik{&eaZ|C_luGkWhuCL6 z`T6FizGwJ;Z(ZG|-D0{r>osB{;)24$LV|WJ*x^zfp1g6k>)QQXVs`>kHTis>27X<( zaf|d1e`O=?$eIr(zVUM+=IZ23C^&uVLe00J+r8Q0`|m_ge{jg1o4}}O)Q=~%C7(Wh zmA^QZmzBooB9GQ0m>yi69~zsp-thelaH8-a#HXFaz+p6O?NcW+GE zj+Lq3`Yvy2`#&S?+O=(d*S4KomUivP|8NuaKhMl{zvmTqUsmeAq#UMy&VKK<#KW5& zJ-V`C(Uk|KS6Nk8Dt->C_!B-)bd!nwro1|z+Q1yA75tE<%>(->vajU-Jb(C7R#5i6 zyvVX?XJ@=zX!<8T`~9P*@{iuiCp|Zq`{lp3Z~w37_H}AuljK4tiS2!V_|>m1Gfcg? zyDlH{zH}&?Ym!)6tLXCfkS8trXL#al%=c*NFUpJaiRmzhSOco)U#U6{6a zkeAUSugix|8z1sEZt}k5+;zF>lu?sbk<+TrhoxXR?k$RwJsRI@Bd ztg47~bEyogs0_Pts3*bb-(nrx4LaHtC+~bXb}8~>Vr}7{_H*x68%X$wGXIB6G@5U? zRnPgYvio*Duh!;6+D6J8|EDf-7x-trHSOl1i21tQ&!?riOi69iKhqa6MKo-p0yjkAM&IJZ%4(K@*%T|6Z#bZQroDe2(Lpq*byH_b+YvV5D4mZ{L@W zPg_nrmJeG$+kClRuX_u(@nP*v$|q;sf3@evsW}|;{_87murc1DWv`@lK=_aQ_Cuo8 zTvBDvuh-AnUK5^ociqm@vu>Q8Rg|?YJv{&Pirbm{zG^eD^Za24`QSr*{<;4~S5F&8h>>OzSp%yD)Xj zEj0xNgsq?EPhGqCtV#IR9+^e9pZCwW?YDKdUk}TPQ~9Thl%}U0owB@LNc_P%QPJgQ zg+_aHmFFxM_@{lALosHDhIYxzJ2RFRC!Y>t?oR(5{;Wm!6kqR$?+pJh_E!Ak_$j;V zlk&#qBYOWU8uDBIm(APhEMTy;%6bMfG@O5|U;knLZ1L_0HtYIXtHp0_EiEc8`mD5U z>!0+*-Pz~wEoz;*Osp*B=6$QO6khABz_f@;wmsjm^y|$6_ zPd5jHB`JOfnndC+{o8GzY;Y%E?MHv!lAF^X?Qa(P^PTzO{wb}mJC=sku{>*N{12YG z`1jiR-~Jy@wk+D@ni6Isw5@oaq}*f)vAGM5{xQE=_v;Oh+0pu~GZ|0c2=v~hq-CVE zO>ge@eF{5Gt{I;@y23pXOj)#y)*1o6d}<(G#8o8?}edc_jbFmidpnxzU5i21o0Ye*B);WZ(5a zNXtyaZqKW;;W78#OHPwYS@~#YIlq);-Gxnd4Qi)X?efhJ&F}MJ0}oCx{crp)@^OBk z^S1ojxHG%D-k45(BkH=jKR;%ho_(XN+1?Vqhx;FFGI{iqTi2IYVeJ9apC7w#PHgRr zJ0d9Y=qcB~#nQ0uNGju>xA{Nk9k1uUzWRLq?$E{=g>wVu8vT=AZt{G`y7=(Ad3i=R zccf~?af4d;3LJmb57#r-{8_(pr>yC}!!3!PKl+WY?^iTm)g~J_)6^R5d2!*Z zJuKfRU3u^*HZ!y;mvIM_lEW-)j9sCXQr$YKUB}25>?0f=k5L@ zkN4k_T|T|`uffM3+qFL4H(I56tu-h9;o>tp7JSTq#^LBLQFnjRl3jaF-rslL{*~!z zt;FPYr?VY*S4wuASn0tw$?8(7fPUNbnJRnLET)y$75aG})UyqBf4Onbm2eN9^Kq4} zMM|IaZHsJ9I^Ui2MRCg{ue-+oqb_|>vzdK5TRC3viD2x+U0nKqx;{L40Gc>*d|?0M zzsRruZ%UU*tUs4(`po_M6BpfcJyA2n@?IxoTAwX#niuKn7V&Y8!z0!w2jh)aE8MHj zo3q^Cp&)0+`f`VW1p``zRjE7_EKZr2kVQD z)z{QK{5Wm>KI@97=@(-flx`O-n)@OC@lSWHPxp7EhQ4Rt`N1Y`J;%&vqKe-F3zQXX zq+Cl+)t7i}_NlX9-j&W&x9I5<-_W`>DX+Aj$i4Wk_P^-W2l=--kDuJ@H<-GE6V!qN zO#*6tl$ZQqefRM7gGcAGoLJW$AMo?hsue#{bf4}2GN)<7i^yfcn*X>TJ#h_BZ4aNY zaNo+r+pkY)J+e)2Kda-#sWD4-i$bfZ{zY^1d)n&Pnj?~y)K~T7JMCEi-zWWp{N1p3 zdjq0?|Eu_WB<;!8$Rf|6g_f^X~Z;|LA}5){+9%Kg(BVZ_?7= zps2q}OS^~XQ|t_>s-F+O{aRyCcI3;Wn~klTnYe^%iyrSOPO{mw*k;qByNe$QB^~~2 z^SAT=dDcJf+s~@!^~LU}KEAVE_D zF}phN!2GGrt0nvYOZ4Xae|qy__vK3CKNA=3TRXpYkCwik@{NrO7wz>A=I71vFY9qn zTOxhGqu4}2?acMl_80E+{W}sx-tzX@<5NHTrIsEv@0uUC zu+92Io9P6JhX&o@aSJCd`tpNc?(oHPhnFic`RuW2`Y5lYbxYS~S~=&-fAyPIp6Z|a z)c)Qc}#P*JBgaX8V?XN^!lcsXae_nf1z|_r50; zSNZ(d6Me~;3)C+Hk2U^TzDvU9Q}PF2|9(%O`1vz54VjsZliJ#zxwVP8xdnGhN=MI{ z5n<@FMv^C6?Qq-4EvBYhjg`~V`2Q`Ij=a|!^(XwwKkd|({~UiT-|oM+mh;0Bw)1>8 z5aS=%ulV2fr?QgOpYf8~KjqWACyLsgP&xlqzTS1$ueEo|4L7EgI(=NVV^L@!ci6Er z&ySpWoRN^YWx}FegPJ7Bt0gZNm2Ma*+;9nX4H6H{!8nm$N2R|G0f6#aucs^GG z)S3X#C1+0f|DgjkvkwYs$jUGl-j4Mruc)qExbyA5e*6D_4&OapJ>AX9V2N?dnq6h3 zJLR44ZS0!-OXt64;kzb~AuUp`RWm<7J1d`iYfItdW4zL4YofQ;y}h+{_4PH8TeGg7 z;ucd^J7+cjS6K1?vwZj2%x4=Si-aO{*4EvbbToMPmNj;tYkn2= zy4uvY{F!H4|L@Js&&$uxv#tI0hVwqh|Jwh5zpq`pcI(#DAD%it*gsFp@7lrN>E7ub z-z4i!-+q_dKR-)q&#!0S`QO=R{jYI%ExGgR+qSBBrpkl8;ra4w&w0$5y8Yduv&yBP zjhtFNRsOH7zhkp!+a`njhu5aHi%{^-n$eayFm+&-MPU$(m39 ze^&jsUzT%P&A-*l*~&U@oKs4&{r+y@rj`#Ywj5h8KY#s~gcDEgXJ6U7z5lsCX#CIq zv3--(AFEd1js0u>`_FI`aI{HInXg)_cai@c_rJ;&mp$jk{JOF4SiR20+DW&kl$3Lo zyFL|qR~TW$?>Ohw)Xml#vUQ9eJm&BEf8@jW9#Dg9RaVxN39+BM{bJYb`G2V3NQ9oc zz3uVSNA~AkzU}>+w`t3?|1;KzUVmq*+VT5;s{F5ahm!1WocuJuv$OQeuJw9yKTEz( zYx|>Mt)|QQhu!h-y#E!YiN^6Eb2SdvUlPno>^-&me1)8`W31Ptn@Q?YQzL&pdGl=F zMTb>CW`1}-L07NQ$M9&3Hs^kub*URQt|VW+)3N1@{@Ne4JC7+Xu05H-&-tTTt6~5B z`8JAwwr^Rri~EndKAu=D4-nhlc=*Yn)pwffH9r;#s*RZ_Le!K>bu9L(B)6Yq7Nd>yN)RZ?-lr0t#tX5 z_k;J_?^pgQ|MX<#<>mh2At5VH)aN+5vtFtW{-6~n@bPy2YS%=)ua_!pZGJ}nto-@k z`r(IfKkmgH%w&1KaH8_=$d>Ly5i7gB=6FrB(af3bKKD=bqS$HoIj0KQ#|enUu!0Ud zXpz|F_}N^>@_yChU*_@hadTg%pY1l`kKFTrvQXFaGtSdx{%o1jB6)f9_n6&PTQZ-| zt8Mq+Znx`yp&u#ehHT~S2z|Q{}GgNuBKK#G;M zucw}U=vDo0$)1WYcKk*TZc^`A56_A7I3V_4BuP!Ata0j|6*1dhPx(LPzL0LH1jOQ; zV7qGBO`@@lsiEq-ogWwq->eU91e)Jv}a9?zX|c>XPS5pP-V`&_Y2o5WfFH~!xeyzJYW zo2}f_uZ2y2ezbbhzxvu>@ER@0+P%kiUA|~o_j1|$e?PTd>#lse^?3gM^*0LMe)Lz? zHoq6x{r?H?hY3&Y*R8NV%)N5i13#(gpX!e;NKJM9Y<((jN|`{k&BRG6`%XR!tnz+f zU*ij2?BzIN+LZ`#y%-(avbvzFVoWtk|9&@b+gt2z`G2nf--HEhr5lbcw%W1j?|+uf zRp#6^75Yb-wU;D#Pgoy0L2J&|7p%E2S}k;{19x2x@af+Yy)@p>ivPckejI4F23p_V zicFsPQNHD8UH!M1X@6S&9GCuI_~C(L>A6*(c(lBp=LA+Cv={v}W5u-P<;zrBKzS0p z#4I3rFU!QIcPqO8+tvHERSBH?y}l>!{!Zry`UVCC4tv3a;vC?`_8!^UI-B-LM?P%! z`Bd}m&GaR!?=PJ;?UQS_*tGB|dOG@=+S*#0u>mng4Dpfrx}M+#Lf|k3t@Y-J7e>_m zE$cbsgXN#^pC=%v!vb4qSK})HnvI97;)@q%0eK6yiVr*qrLv{+^Rs@l+*>;eAGh&J zpNKk;eSKZ*-n6r;LRX*I)4*wcJQ45->Yx*#Kx%iLsr*F@m5u9;s%LW;tf`{6= zy1J&OS6x>;dh}?i_w-2(V)lPazU{dgSvh5C%CmDP&n?d>OS?Dc4b#M>&qTU%{QMH7 zs^wBwTC#37er6=Wb0wlg@W=1|fRsbe?f(hfn5G+j>(;GT)AZSyoF3S7KrDPOy71rg z`u|^^U;p>(*8O{b_iw*f{rTnwT{`}nBwQFPB^yQiUgO)MAHvRYe{{O$1v;TiTCY`_c_xAn!e_y-Z z{Lk;r+VA)3%0Db{bY|z3vdOy=(7n-Fy;m;BChf(MiHDE(%NS+cSWw=^^ZWPi=6iMN z28JKxQ&((!p>%ei&A-JD{Lj?;bN<(T+N~qd1h$<*B`-ulUwZN{@Yf5`tn`ff4=?y#cn(Q_aB`USvGxXg<_o8 z?#ZsE5jtYt#i#R1s&<|`-;nBXpk9E*aqqGE6v=B}Utbsgr~Gz*{=Tp8;{X49XWiU( z>xOmTT#JocavpZ@xAn{YJ=kKXtkxryWRN!F=Z=SJ$!#xtqzs!19zIz3ey@4So!`yv z{GcM@Ne9aOs{JObIgb|KJgXnK=YiSgmj{lh2A<7fwOJ;!{KU&ymS?4+E5n()cWj)! zk;mW%f0M$Wr!RH?{hqM?f9=$)|F!P!=QIAK#8$H}Pdt2IUq3z~IyyEe$R_U!yZj#e ziaYGhCC7P8C2Vv4oLIQ{p1jqR5+)g=Gc|7v_7*B{nf+hun(pjv`Ooh7i?yuvVEMmN z&*;|lo^KNx_Ah7p@%!&d;Y0N)nF&u1T)X4L?9fzyR;EuyaMcj#v->g&b zJ6S=!8v&NDtp65&d9`}|zJI@>o7?&}Y}=@vv>b+7{l}{dgcju8Z{IfUFx!vFxPx`CA>tX*+>*#Q0@b>zj6+0@jP0aP_ zvc~@*cxH(eH*P%2a3bAY@xaE4bvAna{5$nEx|B2*9pKhmDz4wsqH5HI%$nJcSlKq&=FFF^ zlm35Ncdq}$Y~A!Z`qt)uz072}4%QdBKKuFj^Zj6{pC8|rGycE3vp7BC=P%>*a~j`n zbTUkEGKgfC>wUAtVM1HPBa2@@muxy|9l-l<@llSZO@=~_;MGtHE4Kf9U;pp<)$9L0 z{hDy_eXoR7$3cTxnbxK^?yDcVpFL}0-h!<&x1Z}sXcm0ag?7$xS&uTl@dZth4Msw3PSiJ$B~j?{)bjh4i~(ein%S@ZX6x$E+ml53g~P z{s}Ld{)Au7Z6c$@oV0nHeV^=|e7ycpv4*3QRJ7O86-Vn$=1hjpErT{!v3zCx_xtkv z`2VkG=SRQvP3)7*vQ2d9n7noKIgRkWh4a{wYk80Tlb>$y&FiLo zd}3Jl?%X@RX=TSI>#Fx|xh(y7f$^=#`ZcrvMTGw~O#JpN>STS&?7GMe+K=p$%+!~C zjA}nvKli1d`|%%3XYc#{d_8CgB)h-9Zhz9@t;g+q*W9Ua7yb7*StNXsXhdA`DxrVE zb3H2`uh}!1ORX~ST7=FS=iOYOTFp`5O8$@cSMC3Q^{=n}{dS@9eThH+T2_|T|NMR7 z;$!vwwka+96qBFa=zL#qkadN9v5&+V&B>*1eG-PBngxT^`nFw~pRv~dT;?jlAN+sR zS96Q&O_Q^>Uzx?tXeappujB1|I~Q~P50p7N?cLk&O;VW$fKW#O?1+ z23n6>f6Os5bULy463e2^b4%p@+3p1$vkR&bzB2z)eqF!k-}UWkFD3fS%%qH}{!Azg zZtI`>=iY{i&h`?YzfJgl{Dl&(s4zt2kNt=qb-=3`;%ikA_cS8Uf>3-M-#FP=1`?)3h={eG9v z=C7Y;Q=WNSXPLt7l>4da=hpWbxR~-dGEe;fZ~yDero6DTkuV8)%h7)%id-b zpFY@@*5|jb@Z;t;wl#-7cRO7wa(b5HUo^*1Nwe_nP2=~HGxr;R`Fn8j@tF~RSHu2A z*Db!7?#*Gl@6%_g)0e+Jun%>?F+F=AZinSk<_gogJdfy~`kI=abN7E<{I+}luAQ1b z?i*H%@BI2~=Fe@5eJ|O){$X-4VM^hpd+*n+@7-i{VdkRjgrvmWOpC_$!lsbAg#1~1 zm#$sA_VAe{Tkrp=u(}_lWqPvVT>T%F!zYi0ZF}uV-P2Y&S7mzRxI zzP;l}kG|h|%i2vJy3aS;{XDX-F?i?y4;^%XF;k zi)$~atW16)d@thqD(~>udykc$sy`&L_(|>kcm8HV4KJ?DN#5T7G@|bs_w7HquZ#LS zS2QbTEckSP_5a`Z9wa8KzuL9_mc@;OrD>^a106IDx2I;lUy^=e3ol=M#lJc4Z}ql) z_G&iI`xd)>r5E?G3?B+wWM$XC42%t+!BPe@S)ng%raTFIn>6{CGNBc4^_e;L>AS z5B8@R+d4BlKVG?J*5~r?s^{~$n!l=`>wi#J(PO^l34h}`nEsbe{qGhjKId6p{}t(_^1EN(K3}~2RFl-z zfE=;?Z_Ub=Uay$>E&iZIZ|7yPIe)$-Xl;J|$J|Rj>Gt;JpO-KC)w+Q3T>bigKfnI} zeS7zjxc{$juiyLe+wSHze#vi*OBYY}FX8!p=D8iOeA=5^XYXyUKKzq=`Mc69^`ChU z?sHUj>z%vg^D~aOU;cOI`1v`W+G=u%MP~ZEl`7JZ9eqcS9$oowd)*rEujc0ARWE<8 z%iF)H;+6#KAM>m!Pxow=y{%j-^7a4Ytt#a)TAPzgn*SdhvK0!Uq1f z{+S={eVBObZ2c;*8>IfPWUaUHO}-@}0F)&$Dm_TrTA5=KnhP<(n4UeIZJri&I zpR$#Rt{Vg2iv6GG-}-R;eTDeGHw-iP{&Dc_kP|)V6H&aw@K(W;%8;wi{QGJO|9!fu z{e0H-=eu6_FI(Q1q_!^4&WX>aXvxpb%+}#z8+?vm3>IDy;>Dij^wq_)#xTk9_p8M( zHvf6qe&tQH{cWbJ`YgOD|9haC|NQ*Q~(t>i!?|loKCL27mF~{Qih%)%$vbYnRSk@o>L>qr))d z`UFe!^I4ULr)59(w6>s(PCmxg! zKGwh0z;KpD;-w1ZV=S`G5=OhPeiZKc^KYUwQI=f$0xL zY#;yoS6*M1mKWpY_MP{SyLjferyu26>y!Rfd;Q4Qj8AD4FklCboP&l1ZXK>)a$f$S zz2}d|AMa0A_ph)2^yTMg`>ZLy|3~P|+*%RY75+SR<5ZoU2ZdHwrzWl3u&Mo$^~D>Z z;4SH(O?_eaAKRmjdY*Vy(AA%2zQ5vQ)9o|Mf(56$TufG3;B9C;F}QH&p}LQE#P3GV zo__bv%ZpMGe|=k5Lp?5#wZ`s5eaaSn$+wD(_5Q3MzW<)A-tzy%r2}3+``xpX?kNAb ze&(Tv(88<zGbP?9IJ^G3!Z*W zcDqm2Z;@~eFmqD^Efi$|?QCrNmEP;x`~Szw>-Vkd{$0QP{QtyD_5Xk0@9W#$^8eg? z`}H&ax74WqY(DOlGKIDM+I)Y;{~ymgzW;x`_To!Pl?Rg#FH`Y&BlQ0w-y~=!;qZ01 zxx_W#*I(fMzG&v>|J%#u>U@{pzE}UhwfO$;o!{qGKc8oL`MHM^hpT|2fa6k*pluvx z4lJiTrfM`bm540$3}j?v+}$T?YNqp|r(uP&;3Br$D~zksp8e1|YWV(E_3}3^&w`DskNXpY+B3%M9J$J!+HA+rj(JtmV&gxzdaqJQ;uIo8&$S zUd#L4S7Hw5V>iS9rY0t8u`B+kd7CoKpY;Ep@wcFrc7NOtPx3f>%k8Lt$J0XLCGOJ= zCj2k?x**FVpinw#*Q{GV?Ae}7+UsNBNnCJGF>aw$(w69<;(J?Y6bCI?`YpRzSWua=;>IS8vShL z{{IZms;^%@t!B^qf8s}ZQ&ZEwHLIBa$9;MHpYQK`&&hs)C+c@7{$Cj2e4^eUb5_$) zhErWnwm4l#zAtKg^-vcx%ieblD?DbNR*)8Ye#3Xh)Tgmpc9N3+Gk0>{3HMF!n)=T% zE%lYr!H6X@BvbB(RW@b0+*J&t3l=1+&{}%B|5v`5c`AwX z@Bz=(i5;1{mF5P7Oepwh_z7a~CwZ=~8-MVd?z$gQ(H)@i#Qx5N{{biJHJ;duaJBwf zetg=_Ye{8|l9!}E&39DV_918*XZxab_k3=7|AnHTY-MV|zrbUYu?b#!9 zjY&^eS65H-=FVdEGu$)g&wu~wRaZZM>!0*Hf3`clnBV=U{ZG2W|6JqSyRtlfoHw1e z-S+Assh|9uKc-A*}t*!=7zvzhK)XQrpm zSbsNV-@gSnC*Dr`+4_t-oO9aKPp9$~|MzPB6W*mSpyO-WfA-<}h_r_Zxi1AYB6v7= z6*ReKtT}M|;-#WB1;4yLm+q{&SatBq$7$2T4oMn5YYfiZJ>S)1&4K!D4|Y4<`xf;1 zz1fU*c5dI-`uv~dPc8YuuT$?(_eA7^?cTe#ws-H^#$I9j^ZnD))6bqgd-F!7rb*-R z#ge&FSO09+^LQbaCl`FAzkAz;a*=aU=kM=mmbY|%vH9kk53!ri5`{DUr|93V1H_|-Fr1*m+ z@I<|Gd@w$A%Uwa8R{)4rP%6Ae|{${(oZ|1;@sIh~Sr z)vxh((!Y6ZaZgIRzlyJ%HT}oGxTdvVPt-4N|Nmsuwykr7j^Cb`X?V?R#}9^lQ&au6 z{ArQrq!upSd-Rv_9@gL$Rb^s^%PY8TO@8JtWByeixMJeLdV^>DKm29?dHj3*>Q&wK zt9Nhzw)5Wpw?DZwEtOC4(ylJH#T@}BZ~Sw3WTbGSUU~BWb)TR62rr3Kzg%6;edo~6 zsR{qPH_v#YHOJ)aq1)jWqCejE-Mppnu!kq^U*Nr2Kb^k2+*_Fa=Yi)TPdO)Z|DxhK zIwyWG{>(SI`QNBw>DIKR%PT9@&unA<9~o7(Y?f$_NL26Eh@ZCat@A6Ua$Y+6C(AT_o7s$olFsWrZVYCk%^Jy)Wyk? zrlEpg7R)#-sFpeV?3Wh#f7S5Ed!_na?Fpy*Q~Wa3 zQvdI^e)b^qvt*0wiK2s_YT{Ba&rr7i@T@X2$HM-Z!{Zr$d7qR?{N2B}{l6M_(UCt5 zA5)5gcvAmw-m-=F*?XIuch7R;3QpbOwzH1N5&3*bE%58{C>MEl4G}%dBhjJ@j@3_2 zs<^praxX!JA8llI=u(>5mFKA{{xFNyCr_8>uF7TaXvkT|ID?h zj_!mno*RCfcU&sDEy?-B{)xTtll@Wq{-<<*HBH-n{2zNt?j!5w*ym@;uFQDr`p-D?-)X-sALiyhv~RzoR>`$3?n!Gk zx4O^P88Z*wo|){(_eVN^R+Gc$q$Yab#(bIqiM6I?uh# zY1304T7|yYJ!QYI&!_t>8gZE`51b9PC}jF1&-L?s#ZUfaRgC{$Cso!l{=2tN`RDp= z-#%Sk9e(-Jr7f3cd$2Z$%+mbf<5}FJx+--`t3PX1%%9^dHeCl3)RlRApGaMw+GDa+ zkLQc;Y(7!;s}|FCIreWe^UCm6-fT2;{YAc?{6F(ma-t`*OgyUcUv-_(8e6Z=^7>kr zY#vL^ytnzdO@(g#_q&F!JDK9^x#tHQ{3P@5(N8gLzL}{qIEdFutF(sM~c- z#hHas_da=W_rDa2YZNmM|J+X-dtE;B z{0xU#oYO@(XsrvKbL_oJJ_|Ajui|6ly*56{0>w(sBK-QWFr zYkz!LxcRf-hxppsy=DJ`6K4FfzxBi4OFZrkj{tXT6YMb9rJf z^69=np27d(YkqZS)IOKG?vXYB(5CReFr#UG>-y<0b)SK1=zp81;BPD{X?D&M-x2?3 zdE}`l_P!OD9UT4s>*vlD=``VQ{nHL<8fZMRzw+Yg{SJ+Q zSKI$*Oc9Fw*8V@Gr-65)hoHft6Dh|goN(@)nc4S)f9>%_yO$o5Je6{y{zUx_P>Vr| z@y~OElg_u7?LHK-`=i=VgEw#Aet&mYT2^+g&xM~88u}-!^ilZ#Qs78E!{@!PU#3o; z-}L{)kN#P+X7$%)wVac2Di6JTH*0rC&Y5@5BdH&?x>fFnlnLur^=nZ?McmBxF z*Kes}cwU?Ea$yM92XP6B46k@OPyukK!1y` zv!+d%G;7A3ITL1x>^HplWuJ}JG&M(PyGT;@KkNB;p5MGDXD8U(YP3xLU(@UyyN7An zk8>u8|2}{Da^}>jTdUhQZQi`l2-*_L+wt(){<9iy>R+2J+g0)N^@snvs?N_4mrOnM z&7PmX|J12dd#kv$oQ0p*i)5L6xW8OOgv<1X5!XNO^S9h~H(37EH&6+h84$Ffb1#FD zkx|Bm)hkw9n2b^7PLFkpq?$@*fYX@~3#Yqj6lGN*0)sh{%D z=$OI5scI+duU@@sa`o%W8?9U=z8OiWra8e8O8*yv8e}3|Kl2^F*-L%e!~DE&+mHK2 ztyB79Ym=&{PCY2*VebCVdEtcr0U9D%M?T26l(3wcCoi+B;8u_2=*0V8M_ap{LuGX`0wNWHeTr$&ra0)gocK`UAJb*LkUW{ z`}6asN|6R%)Vj2y=W8X{QLW-=RYva z&&)h|_OvsL3#d1s@x(snKkv`;gxW=aPAzm3{~xJmduxyWp*cP>S=ss4`wK6npEA1r zwEg|P-Q{NIUcSF_e0`14`fb~`-o3Z^hF9R@?!twYkDeXZumAh?>E`yc_VZ59J-qyP z;EQ{Ei>2rM@6!(v;ri*X-&;IuN$%y?gU7C&Gx_&!@&9rSmb~~$|1*9Be~dT(5U-{h zp};be+4R(p{F^t=B~MiOuWMbr|6lvIHXc=mTV3b2U%UI_hvCJEzkbYoz3g^wEBCe7 z9rXr1{+I7h@!dY}{)u@{6&`#%+iJ#_7dLs0ow~J++|!ij9w!eTy!S}DX8xjp6ZOA1 zuh$>`(Z5ij=O^>O;CA~-|99=$b-%Rq`?r1PFXjGMc6g&x>9nM@msi%+c~ztQ^aE3! z-9-P-eQUFG?UsFdN2jtm?0&(m+y05~&VJ43`#%upW`T>Qhn`fz5xuF&Zeqt1vUN0d2J z0xhk?BBj@Tz0USK6lSvO7X{+;_qkeujPOI^XRfa>%`-7v7H+qzxeRu(MB6a)y?ZK{Oop8{QtH4 zztVKq*AMI?l=D7)nYnqzg@if(C7;({)5Y3==scRl#=!Kiv%Bj`$Atoq%gX5=PENS+ zdCG+UZZrP+Gc*2fvlsiXyQSp(&f7aGKTWUS9$ox0E_K3D9@hUK4}aU<8Gh60)$E2z z)n88{?6bvopKqYX6Z^wI z^eg@;MclrA^Dw_yWpnS@`nrROUqmiU47_+b?aa}y_Y3}--)&kM*YJN=#Ju>1{oCJr z{9C^HvxgGnl$2|WGP}=+ zd8b(I3c9q6ZT80QDaS+2Uz~iAe1ZMtW0240{SWVKs5&S=`~R8!A5QG4E8YD4N$K;v zsb~It%VzywYrJ^PQ#py{TEvvSg~k#{xMhjdEQ{-kN20)tLN|f`DgmGNshST4No|XH2vt@_2z4`l2zJk)CqIovTTf+|4FHd6bQ1CKNXWPM1 zz@fm^3hK%x{$bbU_{aJ=uB2p(k>hjcCO+OUwF&=AR&3m8_|xg{j5W5`Zu2obXZ(Ed zo>9JiU@6--&gc1MWo6$^*6ZwlFYsZ0N7o(Kf6o7YbNoq{4J=w_5aOWT<)o|d`n}mb zZlyoRYCZeDe)hKCn7{S&j#ky<#c8W^s^;%LCSx z`QLYaejMp8(tW;D)T+EL|I3l{A6mPd6#u_GT`$MDSz(oO%}1{Nk%{Xrb3}0KCB4*A z`>$!-d|1r)EAJ+G-cn=e(k{97>b^0xzHRVIRvvcyL)?fMC zLYO~j{(NtntUvYD;d&F(P965?{~Ioyc)(*QI_IF_KmUg{(=?gPOc?yCC#K21Vla~Y zBoC^Tog~HogQ^@Sf&YwWzOP$8-M5bGpYmh-tgNiI_cENe72PkwCq~JxdypUkR<8Je zp-;Zd*{W;DJekR$t(GP;^}~uYs1z@tmxuS?+A2gcbOOwqrxQGdGfcCQ1%*@)m!&@ zT=}k&7w}X0+?VV#f7qwlE7%uty_k3J-Mo44-p$j?V*XeC^HXYZadBB0-@i|RATM$K z%s)}Ee1*qB3kGY~A}7VJ6{2qw)1m}fEk2ogn;LPtEmSp~y!MrHdi1KkK>xDS4knZS ziu`fU*ePOmDbQ3hG}OFt!G~EoDt6btAItd3e`lY{|BD}%KiZ%7V84&o1_us=H5`TR ze3nn_x#ld~?2`0U{ZoAEvW{cQM`wLorM7C>om~5EoH+`A+@rp^tnyBakqUK>oA}3l z$)|rtS*O;|suaHPZ#k}t_C{R!p@viwjwT7Y?Y52CwF>_i253y#_(A@x>6N~t^*$Mo z(nNMYOAvvP*eTc>9^)#zsEAAvzD{)pZ%1TALY+{cK;Y}-u!39+qrZ8 zF9~`XAAI`Nt5?6C*t6bSd2F#3r|;Kz;Z0qWm{&eKbFtp%vfSO?F3G8~#W(*;Tz%qM z))yrN8oO@&(|$-_@soVkmQV7s|3AJud;8q=`jYSeRxae1w<{^LWBRvx{rc;N>Q6D& zoch@UhfAjrYnJEcj>ef16hMyK|NC27inC&6_s|tN+*Jt;IJr{^zFl%$x8ZGUob6NC{NPl&oC1(D0?xU-Rfyj6bIQ z`95#sbg$p1>#x|{HnQS!UzB&+SmU4bFY(zvusol`CJq7yMAYvtt~sD`{`&g+4GZhG&zco<`Eqd3K za{Xhu`O)J&cXGNv{$O@OGDmUx3*+BYVu+%D?FQrx_X9QRiPIf0*yv@blZ@ zXOq9Iv^-pMJh3=D`_J1RgUD+Ae%|71p@%h1%69gf!b)&y#{FvA``0Y{{afixB`M}^KU-=S@Jc{tvuWkQlvO8c1CL#sTKD*Gc&=yso3~pEpBnj; zoiAki6SbBdQBk*cxi6Xa#(u~0jK4Y4AGXTI{xL6HreJi?My-9nn&Sh$XBOh!A4-}0 zf1VX!>p0WAcf~KormL2JZkQb8DgU(ic+%$&2@5y*UEt~7pz^OT`Ok{4&%CEaSLhq` z&(NOpKs{pDwL^^m9-I?ebL!b~6|OyM2V%F(n11MXVaxuKy_H8~HnDFF@;-gi>XuXH zj>;!a-8VNrd%fwbayoZrU8_$ZpS{{un-VtncCU-M&yUPpe>+R=k@}WLZ_awX_&WFJ zES+$M$WDqr=a9DhP-?a_6zW{r-BT?6X=IuRWGMzfPs1CwjyCgJ(_nS6xWIeD>O> z%5RQG-|Ek|tGrj3T7PTL%#-GEwszrD1U9RgCB}BFKD}!4Tv>PX^*vqZ_W#+kSLet* zkDuq0C;n{GaQwjJSizSczVg7uTS~74@@MLYo^;*tQm1~|;-#OB;(liSo7CEL^YxG0 z`X3M7(W%{hX49glf3_Fc>sQS?I*0eq+xwrD7qbd_>--5iqop@v>ikDX-J*BsJ(xb{ zkv`A%8B-73EbRu4?2+T@9vrPv>}cPQYrzEDhG&?{glyuNOSi{Zu^uv8&J17iW`|*H=vcdFG~A z@ukY!@f6YIzS@(&(NLI*4`HF37 z=lb-mtABsY&%giYPx8%4CljQLx_5u^&?#DI=~43S;!+ELzkk`93L0r8y?cNBIApc- zfAOVR#oztcE{U6L=E%Bz7FSbF+xt(yzWtB78F8zT`TGpZm|fq~Ht&hJWMgJGDSnUl zgAC0%;d#?G1^88O_BvyQ`URl}-4s(li=5Ll_2yZgbt^(=@rg@ieEU<@ zAMo^E`EFZE=AH>sb3NyUKB_62zb#_L4!%A$pMSyI=59W%^VeF@Jzq3U`tXWd!7P@` zf7)&P!F>HN*Nyh4{Gh`8=Xryp&);6y=niV!Icy6KldJr)p=RCMrRSfu_1SVC3*7nm z(08xd+gJ)d-#4r0QrKhs>izrvkf`oG=BE4peZA-$%7G_3kCziG9YoY8IGi*o5F zbFYgUuQ>U{zHH^YZ9PHW7JI*_icMrcla#Kh-@TYq{Qt!8iJRR{yz;fsy}Kr5`2qa{ zN(K|d>l_|5eLPtk#rS*MAI1M5_;U4^;OT0=&+hp6CEQ&8Kldf^4feM_ihP@TcJ7Ar zdoJ#Insxb+<+&f`9Ib!Me|+*;U;pQCIp4Hk^J}H^BK-OlW^ed&Wbv*enTosR@0^^K zcl2z1u+Ta?tG!-7H<$RYsV>ktRk>!at*Z6xhbo+J|D@+`d}ENm(>|5?tLgo^IZy0Q zb2c53itCu}dZzG_Dp!DL*xC(Ukx}P#lon3dCTR5Y{H^;nzrR0Q7dGpU`TkoviXj=f z*_qkyc?ma?KgsV7DUUY$-x@koRX5<~{~Nv*Z|e_QpEc8e{J`G3y8G(yij}N?BqVrW zcI+2&9eV0A2zji*;J7=Z+ zKTjUrBA{RX-SXsfIg_Vsw|1!CuPD-y zG4u9&#?0rplp!n2X8o3!2ez&+-spSS9*%yM{BqBv@UYZ(j}^bnQ0}mI{4{@Q`%g2& z`f1Y(E`=;KZ(hAD@5x&&@gF{-R{ny!e1)z0Qa{PNuWUcJEhnkjO0@bcXZ}MK{)M+) z`qcJCpZT;xE#-DfcW0i{_R42B#VfjPEvq(vGPz$iYkxxH(H={&;Ml?{r@KX5zCJvq zul`RL`04LFapFXE|9MYzn*Ln45b(sFH~0R&+Pk|-vqh}x{#fkxtE<~Ld$x3X@dWn+v}k-yOZgde%GjIr}4n?sxrZ zclsx-;~N`QuwvP_7`x)CVhfSTg|7zL#x7U77%8)mjknrcsl*Q)J zQTg$f0TDGz(oV~?Kk!xWSNnBR^WZu2wDPxaw^gs*UT?AK;O$d+ziyp6UH;(l-DA5x zr)n>g5dXhZ_qqDo#o> zJ$LiW>E>Dc_8_;dZjg^Ef_kKWweEcJ7Ou#iyE=V!jckL|<5!=1hVpA)FLvnlm- zczo?rowKJ-C7D0`Si#E5`l0mViS{{@CJ7Z67e9WuzhjB7WV`>}iVr_d{dE_=wRCxu zoXpPK8=r^WUe`9QNxJ;tr|pk6ROCBRUSb^^D{L6}Ob z*>U6+pL>T#n6m0*UcOBanU0>Q|MBYTgzkjTk#!R?c^fV_|JUiX*}SRt&(e!cCo29; z+ngqS=)ynqOF#7&Y%p+Otd;sxeoNr@y-dE#N|XPuG5NXv{;|WyjvYJNEk56}nC;RA z_T>goW<2>}U(wat+6p?Y)y?h+!=H=sQoM{GYCSn$HE;&_|6`sxbLP`$&-~_C2tss7 z-2Snjce&njvG6Nia&vdPOa14&|Mo`p>$phg?1R1YH?6ztx$DY?4Zofo7T^EsnSE2j zpc#HoRjQZJs!L8Fs_b>0G$b}RByWL$~zGii6{e}ximf4kk z+Wg_`o9^dpT7#c)iXEAuAE*0aZr9`gK284<^xKVD|2J;sThqkIxZ!`djdN@Mr!8Hg zCq*JH54_S>&`2@WpCUeSXX_XDRX_Ag)~B#DDsA#>_!s8jaA40Kn+E%BPtQ*|_P?^S za&7GHX=Tr}wpM+8C25>iaP9t^R89dayFYzio*Jo5>e%r{-FW0g#bA$QYAMpzNj~sE~=jTuD+r7KG zre+VDVAkXPA3l7jXfw;XvEX;Xy?gh3eSJ5WANmo0-g2Sze)0A91Iw1ZeYo-2Z}#_F z!tZBkugzENtq;#%9+MYS{wnIt#_sj?|L4yBFA-+tI;pYZO_1!L<%uG}Pn>lt&2~41 zO$m84=hw*-M^oag_4db|C8Q)J$m8HN-7{d&FrVB7JR zGoL=OkGden=KHNuq2PDZQ~on8UhW$LKgMT#dd54IJ()fZ_6H%QFXUBuKJnxS^wOm*+d zpY@sd*G--C(P9?A+W&(g`d-`h-*Tk2HP3kRN8fyRY4NHD;KuE?oECEM5g+W(uepj z--@c9$hZ8>`@hk0`@3_`R&Ni^mcAapV`s(rmDT6tGPeE?%!|6^uic*)P??u`d%BzE z+{F{B{p`TlA%KU3T_^URFTP3vWE%b{lJ(qOUwP@b9 zxODIgGbl;3{5-#bGj@yNl3DiQna^IYK3#X_zmTx-V#AZh#aS5+HtsAcN%u)EF_w<$bat`L#uU9PEd*H!=n8To~m3|835Q$~g#!COP zuh0H}C8r~7QU6{oj&=Wk3#RhqujykCGWhiJ#;-a5Bg>!Y_*M3R=Tnu#<#YeW7X>Uh z^jllYMCh0EKjYYc(OYlubNCqWLC0o5E$u0uALS$dHTYj^do6}&&* zKRrGD?Afz7Z(9CX&H|d51?8EA0m}~8KlrBlv%k$=^nWSy|J0yU=guCrR|PHR1C4I1 z=l|P#DPiH^1z*1H|Nnb`bCFtn&Bvn(aZ;b=8}8Yda7O;ae5*eb|6IR%_3ygXySIO@ z4U_+7-z0F-RpKj?e8DVc8+)ef2998>Cj8&xbm>T^u(Pu>d+X!{!Y{b2WIXa2>W}xy zN-HoO;`Etez?kEtr>FPVV&?y=noss8{+Z}-;CS_{{~;f)J0F%mTOYk?Q;EPt7d1ig zi$B6cOj5M}2)QP8`lw9|a96&vpif7z`^&-ojF)G7^khpYgNDTdPSoF0;AGNTcyB=h zZ^@$v4;W;>_3z5~d;b3){txnR*qQ1JTnnTw@Yj~I&E?@;V3qQTBjZfI4%%Gf{xiDK zzujG|0y+(r7@kE<^(u}P1rmo zjW0ELiR$7_Gkz@RYY^Glx#I_amZouLPVjrzNTtR7x`8sDl^MVOgr+zCY5!xMaPx+> z)s0AF;bz5bYxm=Y*OvW#b#>LoZ+(w**M10Zlydtgt@J}$ghhtqzve^!b+7IJJ+@yk z|No!!|4qK6*!_GmIrH)|S(}OpzIE+<@458S z{$XVgz54WU>oSZzz((BBk4)5kWCYo#R|2eMWX?5~k zptsV0#s4oAua~M@y(`x!+5b1?&Z4<%%Rm2FtFv~`_B(YOs^_iMGL+c#>2_3ob@hhc ziTkV8#)^x@?fU+C{r{T3uZ~`B&wUW>w{;&82pZ)GT3(Z>i{{OnZ|JKc$U-=o?57qnm`FX8ib+q4LKE-_@-<#V&IA=b72& z{0pXS%P{)gD08Ac=x_Tw#-mQFr)q~^65mwzHcCp>@Lzew{RjeM*PH$S1v4Ak{`7Y_ z`gl|EuLt&G$3eB2r0oB>ooRcv<}iolpNx33^zy&-*V~PXFW;K_x=8!m+nf99wjKZC z+Sz)Q{ky38x#ER4kKIdu`Rvl)cD^^a_FOqW@08^8zjvR-vh&HV(6PMc@p=B*YL~2& z|C+12uAMKFjH@?zeKq^(^s6QH@h!H@9L~aJbEccf-<~#m_TECr7prt%cJIC0bp2Uw z+@nQ>idm-4>XBAI)}PU`FIcck#auDPE8yeaX?F`>e=d7}KYrTA3wOop<<(Tt2P4~W z{$o#ZmVW-`?c4uv@Be%Izv$)t|9|g)eQ3Yp*iD&Tvesofxm~X>N3RkzJ@dq@`OxHr zd?-ty_1`1*g- z0u`@L{y*izk#GNvEWMkrS`=UT=^y=vUHreMT4mzoIa=<4?H2_=3;bUE;Liz>)xG_v ztFTx z8{SKA{p>Hf>1DD=<;mu)7j{a0QRC+o3|163`LVI+#vk{7#VIHI7iGRl{v^-*Nkmt} z@TT8pzS4xUC7hq+KgHMoeE;aP`dMG!?GC=Y$IUBVo~$pCHJHkpVs1A5oGSOpD*n}n z-`shmXDielld*f|i#LnC3;$)Gx7{W3+HLkVjsNR!gGW9~mRW1>xEdm0(j%9+E`0sh zBR4;$rsv!Ld;50w{Cb^eqnlk1uP(i_gO#Q9*yJ1HhgQ6ls{Z(~wREz?_qBUx?#rJx z`TBJ`o1KR^>lK&fv%Wd}>HEf?`7Z=61pG*z&%?7}@$t9322QCOKluHeEzewRac7jO z#F%O^+>-uw#gTc1uIpDW=A9ou>%wNf@B#y_pX={`+rRl^qlSUai`?>mkv!&wy|9YXgcDerh zsjWPV^+TSozFv0flybk^wDYp-57vK5thx7wJMqK(a<{*K|4#fC^XK`NPa)4;MWq(` zT;aO0{b|0$kNggS36hP80rO8yZj@`-p73oNW1Bj^)&GN;Ev>DZ?PhK+E;F>4q&`b? zPb*gz|Nr)FYXJX)J^VVhQ@j}eF)=gy{^;laB>(CDf=}`FfA)L*`|Pu`ZvCuh`%iL; z{P(>ZalJC>C(Ej5El<_uuBx8%{rmCc%Bg-l|2})IK_12|Y5Df?)mO+k=()|ORmwLl z%loF~Qnvx=DC zrcb~3f2mn+U;q6#sk8gc?`v{xn;m%J)0d#C8Qa^Bo5Tn_}6TtDpBoPqAiCEpyFX znTh}1CeLva7IvQd>#wRz(ZAR62`%#kCH`jfZPc7Pb?V=?69=E#&-!`j@ZpylV!xCd zR&pMmKk+kY?}qt|qUg}ljXGJ2v<{bDdp0ZC^MJ;+ebW8&PR>eR?X}_+OTN|5zi#oj z{_oEFzw(X1tpAHvAF&oY%zeJ>)~ZXNx8HiV^{!RC(A#8o*T?B<^7}pp7YDz+cj(e$ z^-GCc=HLCYb?Wr@TkdA>y&X}$FXyPp;z#>edUNw#z4GtIl{>eJR+r^}()pyC_jKEi zCq-a^R)R~n^`Z^%_BGIyM!9o-Lkkp!d`-^X7{J*#6=cb)IEv>ED=PPj4`$C)9saE+q1z2`V z{Ky8a0CBVaU)$>>sgYcld~k;S1N+h+%0JhyUi~{ZygdK??=^OB>RA*gb-#GdCDoGj zk=OOml4*|{ZW|x)RxBtK0`&;M-I71%GnyLuznlDD`Cxr}oBgc+38faYDM}MPkGPur z6BYeh%o#f|V&9K-N(-+S?QxkHq4UT?njy_Ksq@T-GB)|t1z(o!vDbLAU-0uQ*M)7d z&L`@tB`l?TNBhLUz~bmYR{Gqt?7a66E5b? zc)r*|<$(A?i~8C(`L*RI*aClL?TDE6YC<7@$$dje=ztT2bj(4UdXfL7#wYr3-8=cy zUu)_=)2(aPt@E2L+v}uXz@+^qlIPJwzpPD@{C>}$w8&(K*X+Ok=8c&Prr7;S4`~1O zLH_r$FNMd!^YR)~UVfOLo|iY}dBI1IkUZb&>T2J0>Wd_g)dzgU)r^eoaS2fHSllmW z6Qp*sK~Q47`_0Q&eztZ0&scP6{{I;pmgJna;52=3x&1%Ss{r|b$t5SA*{`#11CM?z z?CJc!rT6pY{4?<(zP}$lnx3BL>pNwh>FwKse<%FUFf}t%i(er>dF%12+l&uv66|h7 zKYOdb>f8alhkwqVJ9p0Rr$29N$z`6%)g7PqZF(CGTKElGy_2=%6UJw9cVjI)ZuMPeBhGC^=i}4C~CWE@;Q88zbaDs{|TMHQR&f}rdY9g zEIYC2+}gQ&7+y^=nZ2NA_J1iUsmXd*>NhWyYVbc<|6a0sWr+3v&Mp<9vW!;0Sqqo< zOgwHefl;*O+7EuitE(@qT*JXRafQX?H=U~v_!PHf^R)c`@^S)W<*er?8;_RAz7jhD zULUV^vcBSNg^^m>TjvAyIh$psoVe*X@$e$sKAAKz&&;lawXbf@y1Q}muG>bj$KM!V zyk-7re&BJGW%B$AzZ`8=)D<7wpzfhq^36q}ro+)bo%z)(+l#zhKlvp&*2~Jbcz&9{ zJYD2SvVl%ops5k-a!sRVZe)+?M} zzx9)R?5f>s9sj7?%bZ&AlYd%yv#4Fdr01`%=N|~zAMNYA^5sj-m6@KJD?3k~%T&>)`;AtW zdyDpwH=c6;7aB=u-3ls{oOPHpaw*81ey)Ux^EtmxEVY1E0uZk)J5=Ai<6pbFy8NaW zCpW(@yCt)3*YoL;9-7Y^Z7+W8hSe48W&PQHp5O5G{)K+fEZD*c|36&qzTU^56!LL? zx`+;c`<)iZ^1KO+A8vhgl#u@a)$*MG{*4V9PxdDUhlXB#cj{DESJ$UcMG@RPwrtt5 zV@b;Mb8`*!6YA>rtzNCY?@YjndacOadOCYb-an83|MS)!}tc_s+C!S{H84I=5-Q(3XnWsIr6K7OnZ= zp!rR@f6?X$L8g%h`2cmGKF{JC#cYad(8?yFzU_I~Gg z2|8h3R`zl2asNEgi$4q#Z+<*(KIyLe@8$=4_VRr$zyJUGX6g3wXHWC&1HS)=pZi2n$(KGY^fw$hDv()!-G7&BvqBfGJ#IZO*7JkJ_JsS*voqyF7M@==d+pQDZ<@Pq$J^C@ z+Vl9-zb%!<$i2&50^!p`)vc}j^5P^#=hpwstd8v9(pNtoTXCsKBRTiWtQ}8uZ(lnv zmkt`&xwz@<`BTTzBh&cSe#$;SUna)JH(UKgJ*(8MXD45t zez@G-dcC@DAakqa&h6IwIdjjg z&Whq+-)md-{6RV20o&{&K_8{2U;L-ABY*wtTgCR~)6bM|+`4VkOo^Z?Urv8b>1VX( zVEuphp55`nI~D8~D%kIDv3g>EWyNEAiO=kRmh;uC{4Xsn-T(U4ySKITueSf~S8yp3 z{2Oz!DL|)bp@+o(O%jWgiq={fZY`5GUi(+dm3glM({wIFwtvmy=g|A0l6PA33a86; zx_;5VLcx>Zq-?EdPJSEB)10k&uGbD-}E(r-ju;OW)?xou9Sb z=(*+(|3Wi4X+7I~-Fen=)#@keXB9;iI%Ss4+VJDT=Ig#wJx@>9iJcr*wd-xD_q_R8 z1y6Szc+>X0H=6l?N``rT`ES{&M^9)kUikS#5_z{4z3{>Pv-}#q<;|WdMhfy$|GT<= z?VO^!X1DkD5S1@cV$(H*x?N>5YXiJ?URv*SO?*e@&YY(|Uv6)CuOP7Ylb+&#NzXs) z-%gq8E@!L5ez_UCQ0U?jfqmh(wx~AD{=e;Fq4Yh;uiwABYw?!cL+LGRtd$H4UVQ46 z+`eD+`Tu@CIoJ6mvQO$yy7-LZ*Ef4h_HVSZcKmnwVEq%1Ehl`Zs-Nrhf2ZBy`|sby zyE^ig|9ijQtoZ2pd!DQC%j34|w>{YyOmw0nyUw2`g@wRJ! zIer+K?f9{LSIYO3AE&Ff|K_lf;N@@n{H<^PzLo!8UM)Fv@z|+Tw+t12K03eF)sc_6 zPJruo{6C+k^;>L&*7G*~<^RcVy6Ff1qFTjU&bV1{L|RvEG7%&tbTal zr~jb`_MK|~Uv_&bZS=7(QTbxGB~i!oMP_Xp-*MJ%w)FgYF^;@!TfRj^U)Hpgc)Ds&f80uQ zEC02N5-(gTJULOleDltv{iQLx%WrL6RuuT?=Qd^U194Bc{E7Jd{o?6W)^#2q53nDs ztezV_uPSD~o$pU)&z}#UF15JcXy36=>i_cD|Lt6Ry(Eo6bB_n=V|C8!AGm+JT;>1O zYjOLkzGg*5%`&S{+R@Wg^jYeM>rpT7*>m1%WGRE>-L^_QBQfWf2kWI|SMllU-8$tVJg3GZUReBM&|RZgWPlGf?FEdM`rSQ;<$|NJd}$J=)IM_cu@ z{>|1|Re7f_!#O3QqTK_PVGKlf5+tRtqs}RxmRcHuKN&j z`)cnMfy0?Aujk2HmTcZzvrZS(Y{>R~^7o5=rthywkuC?;sJ>jjmk+pNL*<`27-(s_J z_FcbssUkBzs>5bO?E-$Lf6`Oy9z_@}d}3c7`1R(Y6a7c(t9eC~L_XaY=ZB3|)0L%2$*NZ>N&s=-{ zge|yZox~0r`BV5L-ypkY4a4H~Wp8giefxH8vmB_C+~#-b+&O(??fHNIwW--x-T(FI zt9s_swfb>?br(CWQva{{(N+EUi!V7vALf^tT@q@!J^g?9(G^u~xe^clhx&Xv^m2b# zg#FV}6Auy4^3eFb6>onixbgo_O;5l4F4p0|{{Mg9SACxUc>2W6cG7y&K6d`x_2J3( zkB0IeS!C=tm;T}TnV)e5+gP-Jh|0tbPTD2KJhrJlHoF>mRw!&aR^RdRXQYTQWecXS`ES~{>j!_rzH-~W zIiG?*$V>hY3=TH#V85DwPU71Yjh1usIGXtlUp&t#;NH7@x1-{JMdpWFA2%CF{=59_ zzwd%2=Ko)&O8;KNzv}W)xA`yE{EYnHe>(QLac{RRlY5H%^@+8jZSyQY$#YD@K34np zd}~%%#?G65UpDgffJPP|&R^X1-y)K6+R??mO%q-;|If(`&ry7HJiv0k>%2d=+#Bt> zzKDMei27l=^?y^=*W5okt;X9w-1czabZFx4W#qEaf8OlnfFAhx(Xtz^6tJbqQHAX7tU+ju+Yftf>J$JG0*tO;_d%XiR}%~pX4k*k$6$go$s=l zTTs-(JBLrNSb0GI>ny3IyKYY^Sz(d;ZDxUdpHD#gid`n5=ay?-x_aW}<1?T`ES}hl zfD*J_$HAxeveN4ReHXecKi(r592x2PSzhJA;=F&q&y-ygpP2Ae>rYr-;NrbYd2UP+ zmTT_%^~7Fn>Cxjg4~@I;Jn1>Q;-ucyyJ34vc;+yFzOzNn&+<+{;Z?gOvLCZIEj#q_ z?8L>NQLS@)vfs|%qxt{7U$0g>c}-~OPfScalR5w4V!eOLnp$j0$usA$^!XVrbXk4y zk^PMv`>UtwOIE(y#`bakpMr+X<(bnB4`;7ox}V>_VuGKp`}dj3;Jx817S??2OMBRC zaFX5d#~*P?NzcV{Dt7<>e17yON$vkZ_Y+r+)${CM-u3^5k0oo?=l@wh5@)8FrLAnM z{}#OV-+h1ktBZAK|KIYv-aa+#@~h`hIk+BvsN#=*0^J$!w9x0V{`rJY@-7u2;o+B8 zuy?j{i*E|A`~3OyWx@ZBKW$g;VCQJ)n7{PI9_zM5iOW6z6+AooS{9gftzcMt!s^ox z{-+O|++CwT39Jb$Src?O_vRn>b0>>}>eQ~d_o|&K5EE7Sb)itM^^59h%`oNm$7dw3 zcYyox3j;K+6nu>L^75Lm{XZ==^<~`u=Hw>PP?3(ltg5r~7ajj&#H{($#{BQHs%@oj ztlJlByKniQxdLe!hUFU8n5d|zm>{OhLI?LW{QUXTz*X?y8_0gP|DSlI{!6MfXEglcg#D>*U5i&wse4oDn|}1KQe+_q3lsPZxuC z<$s#L@iypKrC;3Gx4o^X+w(F&qv!w8c-BwzCw`L0vQhli;eYM|N;^C1)+IV>Oxquz z(o^rq6DYVdY|f0Rt-Uj^)%7lFj1y?=Zc+H(tMCtbT?#*w-M!0ymN)H}llqtOulef3 z5`#_`wkOVy;{yZj#W%K=mcN|V)e^`3NXRv5V~6ruaWBoVUsF$}{EeuZURn1`_ntL} z%j!Me(2>L|9*^y>yqIG6SsrtTnoWUPVrbGWuHUEYh1mXkn*8*S4-x82{k2ee;rE5S z$(~NCm#Fejqy4{O zM7#A$Pfx42^ob~v^w(zp+K~?p8qh%1&-@84 z$Lsf0ectx@tNh))^;s_txAV`P+u!j2)$7-#hC+^w3cR*+_8fK5?`U1{!aI@S%E@{Y z@0a|EK0ZO)Qs=Z>y5&A$QIdIyu)^-cjt}kKw&(nNybH~OD}>J}G2M3QtYOMpr6z?P zI??h||L^z#+Sv;_P~;G3wNjSIhxuDJe?EQYRQmq?3s3gn+rF>juV+-{>+bOS(<>&t zI$7^kbMd61mF;YqKg;L#Zee-&?dkukPxjj-`|^DF4<7H0*IqOKla-G*XgvgYStn>! z)BWQin0tP+p4$gbbUDPe_QF}iFH;OZy62_Vb&5`z zxc_Nq`!ATa{BHV>b!qKZZE{-f;#qTa*<~)5u8>xotoXmz;NRwr_G z)wR6p|8Jht{jqTI;>ABZI^uY4pQ=9nmVNj0n^Ct|-skL{{XGBcM!kDglj?8O{O^2q zyf`-ea#_h&m!row7MGjE-F{*|Ct~T-tJWUd1Al+L^?UvO`2Qb{zP`SHUq#XXcb&X( zVSo25)d01crkwnY;y{lST zsjFSG>N1OZdN}|8nU~eRe4n|)5(YDlwK|1>WzJu+zXo1dOe+p162g)KM-hE z*L$0G=g;$*WuG4&Y~{N*bGzIdPWj_3;

FMjMF*r>VW}-2C{H_P4jX+70uA!^&!Y z?3p@q_BEa8&864x{Y{nRzPoUf{F61YJN33F-JkdNb$Yc={FI1@+JgAPM>gWK>~iiZ z2YG*!zZ1NrZX5TWD=U7Tk&AIcS|nmva>?WIe#c$Cx7L-vS#ycK|N9yFRo7R@Z;vs>4nM=C zzwdwa@0pi+cFdS!>uYbG^G#No#WHt!*|KBnPTT1Hd^~-(dfAerM^oh{|0zm6EaL5r zG48e3cY+&#@$+L(=1#n0xk1xbIrnaixamLPowuw5q|)urTl~!5khgg1wAZCkg`YBO zcd37#&~`57*zx2(D<<`{4}gr7aBjku9}g&NSJ#D|+X1 ztt?Co{XTmeQ{={jM|Iy_I{f&wM*ZUJ%Z~lNnpk#9Nvc+EPRzqKr#5n($ji~2o2_l$ zWZUv<^0hg;>$6n9&fCnX1zIqXa{N_dliC0G_V@pN`}I|OXWagu_4bnT|9Nla&ROuZ zN`0-U{mxkit(D0pTZ_LU3_3=E#G KelF{r5}E)!`IN!{ diff --git a/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-overview.qdoc b/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-overview.qdoc index 3c71da8eb9e..dcfce292147 100644 --- a/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-overview.qdoc +++ b/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-overview.qdoc @@ -32,8 +32,8 @@ \title Exporting Designs from Figma - You can use \QBF to export designs from Figma to \e {.metadata} - format that you can \l{Importing 2D Assets}{import} to projects in \QDS. + You can use \QBF to export designs from Figma to a \e {.qtbridge} + archive that you can \l{Importing 2D Assets}{import} to projects in \QDS. \image studio-figma-export.png diff --git a/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-using.qdoc b/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-using.qdoc index 1d38ca9b5ee..03b354797b6 100644 --- a/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-using.qdoc +++ b/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-using.qdoc @@ -128,9 +128,8 @@ \li When the exporting is done, select \uicontrol OK. \endlist - \QBF exports everything into a single archive. Before importing the design - into \QDS, you have to manually extract the archive. Then you can import the - \e .metainfo into a project in \QDS, as described in \l{Importing 2D Assets}. + \QBF exports everything into a .qtbridge archive. You can import the archive + into a project in \QDS, as described in \l{Importing 2D Assets}. \section1 Export Settings diff --git a/doc/qtdesignstudio/src/qtdesignstudio-importing-2d.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-importing-2d.qdoc index 0fd20c0467a..c1d14667813 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio-importing-2d.qdoc +++ b/doc/qtdesignstudio/src/qtdesignstudio-importing-2d.qdoc @@ -55,48 +55,47 @@ \image studio-imported-assets.png "UI imported into Qt Design Studio" \QB enables you to export assets and then import them to a \QDS project - as image and QML files for editing in \l {Form Editor}. If you make changes + as images and QML files for editing in \l {Form Editor}. If you make changes to your design in the design tool that you originally used to create it, you can merge the changes into existing QML files without overwriting the changes you have made in \QDS. For more information, see \l {Exporting from Design Tools}. - \note Attempting to import assets exported on another system might fail. + \QB exports the designs either as an archive(.qtbridge) or as images with + a .metadata file. \QDS support both formats. The following instructions use an empty project as an example. For more information about the options you have, see \l {Creating Projects}. - To import assets exported in \QB to \QDS projects: + To import the exported assets to \QDS projects: \list 1 \li Select \uicontrol File > \uicontrol {New Project} > - \uicontrol General > \uicontrol {Qt Quick Application - Empty} > - \uicontrol Choose, and follow the instructions of the wizard to - create an empty project. + \uicontrol General > \uicontrol {Empty}. Add \uicontrol {Details} about + the project and select \uicontrol Create. \li In \uicontrol Projects, double-click \e Screen01.ui.qml to move to the Design mode. \li Select \uicontrol Assets > \inlineimage icons/plus.png . \li Select the folder where you exported the assets. - \li Select \uicontrol {Exported Assets (*.metadata)} in the dropdown - menu to filter \e .metadata files. - \li Select a \e .metadata file to import, and then select - \uicontrol Open. + \li Select \uicontrol {Compressed Metadata (*.qtbridge)} or + \uicontrol {Exported Metadata (*.metadata)} in the dropdown menu to + filter the exported files. + \li Select a the file to import and then select \uicontrol Open. \li Select \uicontrol Details next to the - \uicontrol {Metadata Import Paths} field to display the path where - the metadata is imported from. - \image studio-import-metadata.png "Asset Import dialog" + \uicontrol {Import Paths} field to display the path where the exported + assets are imported from. + \image studio-asset-import.png "Asset Import dialog" \li Select \uicontrol Details next to the - \uicontrol {QML/Asset Export Paths} field to display the paths to + \uicontrol {Export Paths} field to display the paths to copy the assets to. \li In the \uicontrol QML field, you can change the folder to copy the QML files to. \li In the \uicontrol Assets field, you can change the folder to copy the image files to. - \li Select the \uicontrol {Create sub directory for each metadata} - check box to copy the directory structure from the metadata file - to \QDS. + \li Select the \uicontrol {Create sub directory} check box to import the + assets in a sub directory inside \uicontrol {Export Paths}. \li Deselect the \uicontrol {Import assets} check box if you only want to create QML files. \li Deselect the \uicontrol {Generate QML} check box if you only @@ -104,26 +103,21 @@ \li Select the \uicontrol {Merge QML} check box if you have imported the assets before and want to merge the changes into existing QML files instead of overwriting the existing files. See \l {Merging QML Files}. + \li Select the \uicontrol {Round off coordinates} check box to round off + the position and dimension values to integers in the generated QML files. + \li Select the \uicontrol {Save Logs} check box to write the export logs + to a text file inside the directory selected in \uicontrol QML export path. \li Select \uicontrol Import to import the QML files and assets. This might take a little while for complex projects. \endlist - The imported assets are displayed in \uicontrol Assets - as PNG images. The components that you specified in the design tool are - displayed in \uicontrol Components > \uicontrol {My Components} as well as - in the \uicontrol Projects view as separate QML files. To start using them, + The imported assets are displayed in \uicontrol Assets as images. + The components that you specified in the design tool are displayed in + \uicontrol Components > \uicontrol {My Components} as well as in the + \uicontrol Projects view as separate QML files. To use them, drag-and-drop them from \uicontrol Components to \uicontrol {Form Editor} or \l Navigator. - \note The layer that was the bottom layer in the design tool becames the top - layer in \uicontrol Navigator to reflect the QML code model. You - can view the QML code in \l{Text Editor}. - - After importing the metadata files, wait a few moments to allow all - imported assets to appear in your project files before selecting your - metadata filename from \uicontrol Assets > \inlineimage icons/plus.png - . - If asset importer conflicts, warnings, and errors are displayed in the \uicontrol {Asset Import} dialog while importing, fix the issues in design tool and export the assets again. From 3967bbc22f7ae50e10dd78d2c94af8646d7b4b66 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 16 May 2022 14:51:24 +0200 Subject: [PATCH 27/35] Macros: Fix shortcut display on macOS Some "NativeText" parameters were missing. Change-Id: Id08b8281d1458c05ff302011e32d8babbaf7b2bc Reviewed-by: Christian Stenger --- src/plugins/macros/macromanager.cpp | 13 +++++++++---- src/plugins/macros/macrooptionswidget.cpp | 6 ++++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/plugins/macros/macromanager.cpp b/src/plugins/macros/macromanager.cpp index 1db0b30d275..0b757c41546 100644 --- a/src/plugins/macros/macromanager.cpp +++ b/src/plugins/macros/macromanager.cpp @@ -280,10 +280,15 @@ void MacroManager::startMacro() foreach (IMacroHandler *handler, d->handlers) handler->startRecording(d->currentMacro); - QString endShortcut = Core::ActionManager::command(Constants::END_MACRO)->keySequence().toString(); - QString executeShortcut = Core::ActionManager::command(Constants::EXECUTE_LAST_MACRO)->keySequence().toString(); - QString help = tr("Macro mode. Type \"%1\" to stop recording and \"%2\" to play the macro.") - .arg(endShortcut).arg(executeShortcut); + const QString endShortcut = Core::ActionManager::command(Constants::END_MACRO) + ->keySequence() + .toString(QKeySequence::NativeText); + const QString executeShortcut = Core::ActionManager::command(Constants::EXECUTE_LAST_MACRO) + ->keySequence() + .toString(QKeySequence::NativeText); + const QString help + = tr("Macro mode. Type \"%1\" to stop recording and \"%2\" to play the macro.") + .arg(endShortcut, executeShortcut); Core::EditorManager::showEditorStatusBar(Constants::M_STATUS_BUFFER, help, tr("Stop Recording Macro"), this, [this] { endMacro(); }); diff --git a/src/plugins/macros/macrooptionswidget.cpp b/src/plugins/macros/macrooptionswidget.cpp index 9bade1fea56..0408dd9377b 100644 --- a/src/plugins/macros/macrooptionswidget.cpp +++ b/src/plugins/macros/macrooptionswidget.cpp @@ -96,8 +96,10 @@ void MacroOptionsWidget::createTable() Core::Command *command = Core::ActionManager::command(base.withSuffix(macro->displayName())); - if (command && command->action()) - macroItem->setText(2, command->action()->shortcut().toString()); + if (command && command->action()) { + macroItem->setText(2, + command->action()->shortcut().toString(QKeySequence::NativeText)); + } } } } From 87a7d94629a2a0aae5dcae4df7a68bed9f621977 Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Tue, 17 May 2022 15:17:42 +0200 Subject: [PATCH 28/35] QmlDesigner: Disable style name ComboBox if empty Change-Id: I7c2a997f97cc1c45b6700885f3dd5a8e7f6c4155 Reviewed-by: Thomas Hartmann Reviewed-by: --- .../imports/HelperWidgets/CharacterSection.qml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/CharacterSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/CharacterSection.qml index acca2a0dd19..47fc7e4f025 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/CharacterSection.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/CharacterSection.qml @@ -143,7 +143,8 @@ Section { PropertyLabel { text: qsTr("Style name") tooltip: qsTr("Font's style.") - blockedByTemplate: !styleNameComboBox.enabled + enabled: styleNameComboBox.model.length + blockedByTemplate: !backendValue.isAvailable } SecondColumnLayout { @@ -156,7 +157,7 @@ Section { backendValue: getBackendValue("styleName") model: styleNamesForFamily(fontComboBox.familyName) valueType: ComboBox.String - enabled: backendValue.isAvailable + enabled: backendValue.isAvailable && styleNameComboBox.model.length } ExpandingSpacer {} From e865b03448a0c465e55fbfe318c9ac8e19e6663e Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Tue, 17 May 2022 15:17:06 +0200 Subject: [PATCH 29/35] QmlDesigner: Fix bound properties change behavior Changing a bound property was triggering a value change twice. Once with the previous value and another time with the newly set value. This was solved by locking the binding property change emit with a scope lock. Change-Id: I9605269e911f0468b2d52d74ad8a2a43f907a18c Reviewed-by: Marco Bubke --- .../components/propertyeditor/propertyeditorview.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp index fb1baed3f36..d0f8dd70435 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp @@ -256,6 +256,9 @@ void PropertyEditorView::changeExpression(const QString &propertyName) if (noValidSelection()) return; + QScopeGuard unlock([&](){ m_locked = false; }); + m_locked = true; + executeInTransaction("PropertyEditorView::changeExpression", [this, name](){ PropertyName underscoreName(name); underscoreName.replace('.', '_'); @@ -317,9 +320,9 @@ void PropertyEditorView::changeExpression(const QString &propertyName) return; } - if (qmlObjectNode->expression(name) != value->expression() || !qmlObjectNode->propertyAffectedByCurrentState(name)) + if (qmlObjectNode->expression(name) != value->expression() + || !qmlObjectNode->propertyAffectedByCurrentState(name)) qmlObjectNode->setBindingProperty(name, value->expression()); - }); /* end of transaction */ } @@ -692,6 +695,9 @@ void PropertyEditorView::variantPropertiesChanged(const QList& void PropertyEditorView::bindingPropertiesChanged(const QList& propertyList, PropertyChangeFlags /*propertyChange*/) { + if (locked()) + return; + if (noValidSelection()) return; From 414fb08bc6fd29c6dd8908426bf3c95b6a9bdc68 Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Mon, 16 May 2022 08:31:22 +0200 Subject: [PATCH 30/35] QmlDesigner: Input lose focus after pressing enter * Add losing focus after pressing Return/Enter for all TextInputs * Add losing focus and reverting values after pressing Escape for all TextInputs * FontComboBox fix initial value selection * Code cleanup Task-number: QDS-5972 Task-number: QDS-6028 Change-Id: Ice7449e89088f6e7da76eb7c2edefab647b109de Reviewed-by: Thomas Hartmann --- .../imports/HelperWidgets/ComboBox.qml | 16 +++- .../imports/HelperWidgets/FontComboBox.qml | 81 +++++++++-------- .../imports/HelperWidgets/LineEdit.qml | 91 +++++++++---------- .../imports/StudioControls/CheckIndicator.qml | 6 +- .../imports/StudioControls/ComboBox.qml | 17 +++- .../imports/StudioControls/ComboBoxInput.qml | 4 +- .../imports/StudioControls/FilterComboBox.qml | 2 - .../imports/StudioControls/RealSpinBox.qml | 19 +++- .../imports/StudioControls/TextField.qml | 88 ++++++++++-------- 9 files changed, 182 insertions(+), 142 deletions(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComboBox.qml index 76ed79fc4da..1b2df5756b5 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComboBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComboBox.qml @@ -92,7 +92,6 @@ StudioControls.ComboBox { onValueFromBackendChanged: colorLogic.invalidate() function invalidate() { - if (comboBox.block) return @@ -140,6 +139,21 @@ StudioControls.ComboBox { } } + onAccepted: { + if (!comboBox.__isCompleted) + return + + let inputValue = comboBox.editText + + let index = comboBox.find(inputValue) + if (index !== -1) + inputValue = comboBox.textAt(index) + + comboBox.backendValue.value = inputValue + + comboBox.dirty = false + } + onCompressedActivated: { if (!comboBox.__isCompleted) return diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml index 61ffd0ce407..4b5f5caf4ac 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml @@ -29,7 +29,7 @@ import HelperWidgets 2.0 import StudioControls 1.0 as StudioControls StudioControls.ComboBox { - id: comboBox + id: root property variant backendValue property color textColor: colorLogic.textColor @@ -39,17 +39,17 @@ StudioControls.ComboBox { labelColor: colorLogic.textColor editable: true - onTextColorChanged: setColor() + onTextColorChanged: root.setColor() FileResourcesModel { id: fileModel modelNodeBackendProperty: modelNodeBackend - filter: comboBox.fontFilter + filter: root.fontFilter } function createFontLoader(fontUrl) { return Qt.createQmlObject('import QtQuick 2.0; FontLoader { source: "' + fontUrl + '"; }', - comboBox, "dynamicFontLoader") + root, "dynamicFontLoader") } function setupModel() { @@ -63,80 +63,83 @@ StudioControls.ComboBox { // Remove duplicate family names familyNames = [...new Set(familyNames)] familyNames.sort() - comboBox.model = familyNames + root.model = familyNames + root.currentIndex = root.find(root.backendValue.value) } - onModelChanged: editText = comboBox.backendValue.valueToString + function setColor() { + // Hack to style the text input + for (var i = 0; i < root.children.length; i++) { + if (root.children[i].text !== undefined) { + root.children[i].color = root.textColor + } + } + } + + onModelChanged: root.editText = root.backendValue.valueToString ExtendedFunctionLogic { id: extFuncLogic - backendValue: comboBox.backendValue + backendValue: root.backendValue } actionIndicator.icon.color: extFuncLogic.color actionIndicator.icon.text: extFuncLogic.glyph actionIndicator.onClicked: extFuncLogic.show() actionIndicator.forceVisible: extFuncLogic.menuVisible - actionIndicator.visible: comboBox.showExtendedFunctionButton + actionIndicator.visible: root.showExtendedFunctionButton ColorLogic { id: colorLogic - property string textValue: comboBox.backendValue.valueToString - backendValue: comboBox.backendValue - onTextValueChanged: comboBox.editText = colorLogic.textValue + property string textValue: root.backendValue.valueToString + backendValue: root.backendValue + onTextValueChanged: root.editText = colorLogic.textValue } onAccepted: { - if (backendValue === undefined) + if (root.backendValue === undefined) return - if (editText === "") + if (root.editText === "") return - if (backendValue.value !== editText) - backendValue.value = editText; + if (root.backendValue.value !== root.editText) + root.backendValue.value = root.editText } - onActivated: { - if (backendValue === undefined) + onCompressedActivated: function(index, reason) { root.handleActivate(index) } + + function handleActivate(index) + { + if (root.backendValue === undefined) return - if (editText === "") + if (root.editText === "") return - var indexText = comboBox.textAt(index) + var indexText = root.textAt(index) - if (backendValue.value !== indexText) - backendValue.value = indexText + if (root.backendValue.value !== indexText) + root.backendValue.value = indexText } Connections { target: modelNodeBackend function onSelectionChanged() { - comboBox.editText = backendValue.value - setupModel() + root.editText = root.backendValue.value + root.setupModel() } } Component.onCompleted: { - setupModel() + root.setupModel() // Hack to style the text input - for (var i = 0; i < comboBox.children.length; i++) { - if (comboBox.children[i].text !== undefined) { - comboBox.children[i].color = comboBox.textColor - comboBox.children[i].anchors.rightMargin = 34 - comboBox.children[i].anchors.leftMargin = 18 + for (var i = 0; i < root.children.length; i++) { + if (root.children[i].text !== undefined) { + root.children[i].color = root.textColor + root.children[i].anchors.rightMargin = 34 + root.children[i].anchors.leftMargin = 18 } } } - - function setColor() { - // Hack to style the text input - for (var i = 0; i < comboBox.children.length; i++) { - if (comboBox.children[i].text !== undefined) { - comboBox.children[i].color = comboBox.textColor - } - } - } - } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/LineEdit.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/LineEdit.qml index 93a0878d377..d52c2ca6389 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/LineEdit.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/LineEdit.qml @@ -32,36 +32,43 @@ StudioControls.TextField { id: lineEdit property variant backendValue - property color borderColor: "#222" - property color highlightColor: "orange" - color: lineEdit.edit ? StudioTheme.Values.themeTextColor : colorLogic.textColor - - property bool showTranslateCheckBox: true - translationIndicatorVisible: showTranslateCheckBox property bool writeValueManually: false property bool writeAsExpression: false - property bool __dirty: false - + property bool showTranslateCheckBox: true property bool showExtendedFunctionButton: true + property string context - actionIndicator.visible: showExtendedFunctionButton + property bool __dirty: false signal commitData - property string context + color: lineEdit.edit ? StudioTheme.Values.themeTextColor : colorLogic.textColor + actionIndicator.visible: lineEdit.showExtendedFunctionButton + translationIndicatorVisible: lineEdit.showTranslateCheckBox function setTranslateExpression() { if (translateFunction() === "qsTranslate") { - backendValue.expression = translateFunction() - + "(\"" + backendValue.getTranslationContext() - + "\", " + "\"" + escapeString(text) + "\")" + lineEdit.backendValue.expression = translateFunction() + + "(\"" + lineEdit.backendValue.getTranslationContext() + + "\", " + "\"" + lineEdit.escapeString(lineEdit.text) + "\")" } else { - backendValue.expression = translateFunction() + "(\"" + escapeString(text) + "\")" + lineEdit.backendValue.expression = translateFunction() + + "(\"" + lineEdit.escapeString(lineEdit.text) + "\")" } } + function escapeString(string) { + var str = string + str = str.replace(/\\/g, "\\\\") + str.replace(/\"/g, "\\\"") + str = str.replace(/\t/g, "\\t") + str = str.replace(/\r/g, "\\r") + str = str.replace(/\n/g, '\\n') + return str + } + ExtendedFunctionLogic { id: extFuncLogic backendValue: lineEdit.backendValue @@ -79,60 +86,58 @@ StudioControls.TextField { if (colorLogic.valueFromBackend === undefined) { lineEdit.text = "" } else { - if (writeValueManually) + if (lineEdit.writeValueManually) lineEdit.text = convertColorToString(colorLogic.valueFromBackend) else lineEdit.text = colorLogic.valueFromBackend } - __dirty = false + lineEdit.__dirty = false } } - onTextChanged: { - __dirty = true - } + onTextChanged: lineEdit.__dirty = true Connections { target: modelNodeBackend function onSelectionToBeChanged() { - if (__dirty && !writeValueManually) { - if (writeAsExpression) - lineEdit.backendValue.expression = text + if (lineEdit.__dirty && !lineEdit.writeValueManually) { + if (lineEdit.writeAsExpression) + lineEdit.backendValue.expression = lineEdit.text else - lineEdit.backendValue.value = text - } else if (__dirty) { + lineEdit.backendValue.value = lineEdit.text + } else if (lineEdit.__dirty) { commitData() } - __dirty = false + lineEdit.__dirty = false } } onEditingFinished: { - if (writeValueManually) + if (lineEdit.writeValueManually) return - if (!__dirty) + if (!lineEdit.__dirty) return - if (backendValue.isTranslated) { - setTranslateExpression() + if (lineEdit.backendValue.isTranslated) { + lineEdit.setTranslateExpression() } else { - if (writeAsExpression) { - if (lineEdit.backendValue.expression !== text) - lineEdit.backendValue.expression = text - } else if (lineEdit.backendValue.value !== text) { - lineEdit.backendValue.value = text + if (lineEdit.writeAsExpression) { + if (lineEdit.backendValue.expression !== lineEdit.text) + lineEdit.backendValue.expression = lineEdit.text + } else if (lineEdit.backendValue.value !== lineEdit.text) { + lineEdit.backendValue.value = lineEdit.text } } - __dirty = false + lineEdit.__dirty = false } property bool isTranslated: colorLogic.backendValue === undefined ? false : colorLogic.backendValue.isTranslated translationIndicator.onClicked: { - if (translationIndicator.checked) { + if (lineEdit.translationIndicator.checked) { setTranslateExpression() } else { var textValue = lineEdit.text @@ -141,7 +146,8 @@ StudioControls.TextField { colorLogic.evaluate() } - property variant backendValueValueInternal: backendValue === undefined ? 0 : backendValue.value + property variant backendValueValueInternal: lineEdit.backendValue === undefined ? 0 + : lineEdit.backendValue.value onBackendValueValueInternalChanged: { if (lineEdit.backendValue === undefined) lineEdit.translationIndicator.checked = false @@ -155,15 +161,4 @@ StudioControls.TextField { else lineEdit.translationIndicator.checked = lineEdit.backendValue.isTranslated } - - function escapeString(string) { - var str = string - str = str.replace(/\\/g, "\\\\") - str.replace(/\"/g, "\\\"") - str = str.replace(/\t/g, "\\t") - str = str.replace(/\r/g, "\\r") - str = str.replace(/\n/g, '\\n') - return str - } - } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/CheckIndicator.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/CheckIndicator.qml index ca4f4688929..2d3bb74c3f7 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/CheckIndicator.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/CheckIndicator.qml @@ -51,15 +51,15 @@ Rectangle { anchors.fill: parent hoverEnabled: true onClicked: { + if (myControl.activeFocus) + myControl.focus = false + if (myPopup.opened) { myPopup.close() } else { myPopup.open() myPopup.forceActiveFocus() } - - if (myControl.activeFocus) - myControl.focus = false } } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml index ac1908243fb..eb48ab6dc09 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml @@ -65,6 +65,11 @@ T.ComboBox { comboBoxPopup.close() } + onActiveFocusChanged: { + if (myComboBox.activeFocus) + comboBoxInput.preFocusText = myComboBox.editText + } + ActionIndicator { id: actionIndicator myControl: myComboBox @@ -76,19 +81,22 @@ T.ComboBox { contentItem: ComboBoxInput { id: comboBoxInput + + property string preFocusText: "" + myControl: myComboBox text: myComboBox.editText onEditingFinished: { comboBoxInput.deselect() comboBoxInput.focus = false + myComboBox.focus = false // Only trigger the signal, if the value was modified if (myComboBox.dirty) { myTimer.stop() myComboBox.dirty = false - myComboBox.compressedActivated(myComboBox.find(myComboBox.editText), - ComboBox.ActivatedReason.EditingFinished) + myComboBox.accepted() } } onTextEdited: myComboBox.dirty = true @@ -312,7 +320,10 @@ T.ComboBox { ] Keys.onPressed: function(event) { - if (event.key === Qt.Key_Escape) + if (event.key === Qt.Key_Escape) { + myComboBox.editText = comboBoxInput.preFocusText + myComboBox.dirty = true myComboBox.focus = false + } } } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBoxInput.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBoxInput.qml index 6d926b034cb..de7dcc1f8c3 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBoxInput.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBoxInput.qml @@ -73,13 +73,13 @@ TextInput { acceptedButtons: Qt.LeftButton cursorShape: Qt.PointingHandCursor onPressed: function(mouse) { - if (textInput.readOnly) { + if (!textInput.myControl.editable) { if (myControl.popup.opened) { myControl.popup.close() myControl.focus = false } else { - myControl.forceActiveFocus() myControl.popup.open() + myControl.forceActiveFocus() } } else { textInput.forceActiveFocus() diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml index bdd3cb5aef5..30142652ab3 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml @@ -113,8 +113,6 @@ Item { myTimer.stop() root.dirty = false root.editText = root.editText.trim() - //root.compressedActivated(root.find(root.editText), - // ComboBox.ActivatedReason.EditingFinished) } root.finishEditing() diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBox.qml index 6cf763f3ab5..3020a3817a3 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBox.qml @@ -79,6 +79,8 @@ T.SpinBox { property alias compressedValueTimer: myTimer + property string preFocusText: "" + signal realValueModified signal compressedRealValueModified signal dragStarted @@ -162,6 +164,8 @@ T.SpinBox { validator: doubleValidator function handleEditingFinished() { + mySpinBox.focus = false + // Keep the dirty state before calling setValueFromInput(), // it will be set to false (cleared) internally var valueModified = mySpinBox.dirty @@ -174,7 +178,7 @@ T.SpinBox { mySpinBox.compressedRealValueModified() } - onEditingFinished: handleEditingFinished() + onEditingFinished: spinBoxInput.handleEditingFinished() onTextEdited: mySpinBox.dirty = true } @@ -281,7 +285,7 @@ T.SpinBox { id: myTimer repeat: false running: false - interval: 200 + interval: 400 onTriggered: mySpinBox.compressedRealValueModified() } @@ -306,8 +310,10 @@ T.SpinBox { } onDisplayTextChanged: spinBoxInput.text = mySpinBox.displayText onActiveFocusChanged: { - if (mySpinBox.activeFocus) // QTBUG-75862 && mySpinBox.focusReason === Qt.TabFocusReason) + if (mySpinBox.activeFocus) { // QTBUG-75862 && mySpinBox.focusReason === Qt.TabFocusReason) + mySpinBox.preFocusText = spinBoxInput.text spinBoxInput.selectAll() + } } Keys.onPressed: function(event) { @@ -333,8 +339,11 @@ T.SpinBox { mySpinBox.realStepSize = currStepSize } - if (event.key === Qt.Key_Escape) - mySpinBox.focus = false + if (event.key === Qt.Key_Escape) { + spinBoxInput.text = mySpinBox.preFocusText + mySpinBox.dirty = true + spinBoxInput.handleEditingFinished() + } } function clamp(v, lo, hi) { diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TextField.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TextField.qml index cd2fbf7f722..11a6106f523 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TextField.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TextField.qml @@ -28,15 +28,15 @@ import QtQuick.Templates 2.15 as T import StudioTheme 1.0 as StudioTheme T.TextField { - id: myTextField + id: root property alias actionIndicator: actionIndicator property alias translationIndicator: translationIndicator // This property is used to indicate the global hover state property bool hover: (actionIndicator.hover || mouseArea.containsMouse - || translationIndicator.hover) && myTextField.enabled - property bool edit: myTextField.activeFocus + || translationIndicator.hover) && root.enabled + property bool edit: root.activeFocus property alias actionIndicatorVisible: actionIndicator.visible property real __actionIndicatorWidth: StudioTheme.Values.actionIndicatorWidth @@ -46,6 +46,8 @@ T.TextField { property real __translationIndicatorWidth: StudioTheme.Values.translationIndicatorWidth property real __translationIndicatorHeight: StudioTheme.Values.translationIndicatorHeight + property string preFocusText: "" + horizontalAlignment: Qt.AlignLeft verticalAlignment: Qt.AlignVCenter @@ -78,7 +80,7 @@ T.TextField { cursorShape: Qt.PointingHandCursor onPressed: function(mouse) { if (mouse.button === Qt.RightButton) - contextMenu.popup(myTextField) + contextMenu.popup(root) mouse.accepted = false } @@ -86,43 +88,50 @@ T.TextField { onPersistentSelectionChanged: { if (!persistentSelection) - myTextField.deselect() + root.deselect() } ContextMenu { id: contextMenu - myTextEdit: myTextField + myTextEdit: root + } + + onActiveFocusChanged: { + if (root.activeFocus) + root.preFocusText = root.text } onEditChanged: { - if (myTextField.edit) + if (root.edit) contextMenu.close() } + onEditingFinished: root.focus = false + ActionIndicator { id: actionIndicator - myControl: myTextField + myControl: root x: 0 y: 0 - width: actionIndicator.visible ? myTextField.__actionIndicatorWidth : 0 - height: actionIndicator.visible ? myTextField.__actionIndicatorHeight : 0 + width: actionIndicator.visible ? root.__actionIndicatorWidth : 0 + height: actionIndicator.visible ? root.__actionIndicatorHeight : 0 } Text { id: placeholder - x: myTextField.leftPadding - y: myTextField.topPadding - width: myTextField.width - (myTextField.leftPadding + myTextField.rightPadding) - height: myTextField.height - (myTextField.topPadding + myTextField.bottomPadding) + x: root.leftPadding + y: root.topPadding + width: root.width - (root.leftPadding + root.rightPadding) + height: root.height - (root.topPadding + root.bottomPadding) - text: myTextField.placeholderText - font: myTextField.font - color: myTextField.placeholderTextColor - verticalAlignment: myTextField.verticalAlignment - visible: !myTextField.length && !myTextField.preeditText - && (!myTextField.activeFocus || myTextField.horizontalAlignment !== Qt.AlignHCenter) + text: root.placeholderText + font: root.font + color: root.placeholderTextColor + verticalAlignment: root.verticalAlignment + visible: !root.length && !root.preeditText + && (!root.activeFocus || root.horizontalAlignment !== Qt.AlignHCenter) elide: Text.ElideRight - renderType: myTextField.renderType + renderType: root.renderType } background: Rectangle { @@ -131,14 +140,14 @@ T.TextField { border.color: StudioTheme.Values.themeControlOutline border.width: StudioTheme.Values.border x: actionIndicator.width - width: myTextField.width - actionIndicator.width - height: myTextField.height + width: root.width - actionIndicator.width + height: root.height } TranslationIndicator { id: translationIndicator - myControl: myTextField - x: myTextField.width - translationIndicator.width + myControl: root + x: root.width - translationIndicator.width width: translationIndicator.visible ? __translationIndicatorWidth : 0 height: translationIndicator.visible ? __translationIndicatorHeight : 0 } @@ -146,15 +155,14 @@ T.TextField { states: [ State { name: "default" - when: myTextField.enabled && !myTextField.hover - && !myTextField.edit + when: root.enabled && !root.hover && !root.edit PropertyChanges { target: textFieldBackground color: StudioTheme.Values.themeControlBackground border.color: StudioTheme.Values.themeControlOutline } PropertyChanges { - target: myTextField + target: root color: StudioTheme.Values.themeTextColor placeholderTextColor: StudioTheme.Values.themePlaceholderTextColor } @@ -165,15 +173,15 @@ T.TextField { }, State { name: "globalHover" - when: (actionIndicator.hover || translationIndicator.hover) && !myTextField.edit - && myTextField.enabled + when: (actionIndicator.hover || translationIndicator.hover) && !root.edit + && root.enabled PropertyChanges { target: textFieldBackground color: StudioTheme.Values.themeControlBackgroundGlobalHover border.color: StudioTheme.Values.themeControlOutline } PropertyChanges { - target: myTextField + target: root color: StudioTheme.Values.themeTextColor placeholderTextColor: StudioTheme.Values.themePlaceholderTextColor } @@ -181,28 +189,28 @@ T.TextField { State { name: "hover" when: mouseArea.containsMouse && !actionIndicator.hover && !translationIndicator.hover - && !myTextField.edit && myTextField.enabled + && !root.edit && root.enabled PropertyChanges { target: textFieldBackground color: StudioTheme.Values.themeControlBackgroundHover border.color: StudioTheme.Values.themeControlOutline } PropertyChanges { - target: myTextField + target: root color: StudioTheme.Values.themeTextColor placeholderTextColor: StudioTheme.Values.themePlaceholderTextColor } }, State { name: "edit" - when: myTextField.edit + when: root.edit PropertyChanges { target: textFieldBackground color: StudioTheme.Values.themeControlBackgroundInteraction border.color: StudioTheme.Values.themeControlOutlineInteraction } PropertyChanges { - target: myTextField + target: root color: StudioTheme.Values.themeTextColor placeholderTextColor: StudioTheme.Values.themePlaceholderTextColorInteraction } @@ -213,14 +221,14 @@ T.TextField { }, State { name: "disable" - when: !myTextField.enabled + when: !root.enabled PropertyChanges { target: textFieldBackground color: StudioTheme.Values.themeControlBackgroundDisabled border.color: StudioTheme.Values.themeControlOutlineDisabled } PropertyChanges { - target: myTextField + target: root color: StudioTheme.Values.themeTextColorDisabled placeholderTextColor: StudioTheme.Values.themeTextColorDisabled } @@ -228,7 +236,9 @@ T.TextField { ] Keys.onPressed: function(event) { - if (event.key === Qt.Key_Escape) - myTextField.focus = false + if (event.key === Qt.Key_Escape) { + root.text = root.preFocusText + root.focus = false + } } } From 5e31fae6d9b87f47cd95d21bb2309d44632b1e28 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Mon, 16 May 2022 20:39:20 +0200 Subject: [PATCH 31/35] Hide Debug/Build side bar action if menu is disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I8c7a2e5f0bb76e74692c6b4463aa1feb806d6e49 Reviewed-by: Reviewed-by: Eike Ziller Reviewed-by: Henning Gründl --- src/plugins/debugger/debuggerplugin.cpp | 11 ++++++++++- src/plugins/projectexplorer/projectexplorer.cpp | 3 ++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 7ec66b5f109..033d72f3bee 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -435,6 +435,13 @@ static bool hideAnalyzeMenu() .toBool(); } +static bool hideDebugMenu() +{ + return Core::ICore::settings() + ->value(ProjectExplorer::Constants::SETTINGS_MENU_HIDE_DEBUG, false) + .toBool(); +} + QAction *addAction(const QObject *parent, QMenu *menu, const QString &display, bool on, const std::function &onTriggered) { @@ -921,7 +928,9 @@ DebuggerPluginPrivate::DebuggerPluginPrivate(const QStringList &arguments) m_visibleStartAction.setAction(&m_startAction); m_visibleStartAction.setObjectName("Debug"); // used for UI introduction - ModeManager::addAction(&m_visibleStartAction, /*priority*/ 90); + + if (!hideDebugMenu()) + ModeManager::addAction(&m_visibleStartAction, /*priority*/ 90); m_undisturbableAction.setIcon(interruptIcon(false)); m_undisturbableAction.setEnabled(false); diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 00c2ba035f3..a8182c56bf3 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -1298,7 +1298,8 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er dd->m_modeBarBuildAction->initialize(cmd->action()); dd->m_modeBarBuildAction->setAttribute(ProxyAction::UpdateText); dd->m_modeBarBuildAction->setAction(cmd->action()); - ModeManager::addAction(dd->m_modeBarBuildAction, Constants::P_ACTION_BUILDPROJECT); + if (!hideBuildMenu()) + ModeManager::addAction(dd->m_modeBarBuildAction, Constants::P_ACTION_BUILDPROJECT); // build for run config dd->m_buildForRunConfigAction = new ParameterAction( From de7a7b6ac882bf55fc699563aaadbc7c7b3b2061 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Tue, 10 May 2022 14:23:51 +0200 Subject: [PATCH 32/35] QmlProject: Allow setting main qml file and main ui.qml file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .qmlproject file already has the "mainFile" setting which indicates which qml file is run. This patch adds a main ui.qml file that indicates which ui.qml file is opened in the design mode if the .qmlproject is opened. The patch also adds two context menu actions that allow setting the main qml and main.ui.qml files without having to edit the .qmlproject file by hand. Changing the main ui.qml file also checks if the current ui.qml file is used as in the main qml file and if it is, then we switch the component there. For now the actions are only available in QDS. Task-number: QDS-6882 Change-Id: I1c6e19c039036dc635161fa6e06173356dc509aa Reviewed-by: Henning Gründl Reviewed-by: Qt CI Bot Reviewed-by: --- .../fileformat/qmlprojectfileformat.cpp | 4 + .../fileformat/qmlprojectitem.h | 4 + src/plugins/qmlprojectmanager/qmlproject.cpp | 191 +++++++++++++----- src/plugins/qmlprojectmanager/qmlproject.h | 10 + .../qmlprojectmanager/qmlprojectplugin.cpp | 114 +++++++++++ 5 files changed, 274 insertions(+), 49 deletions(-) diff --git a/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp b/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp index ce54df3d8d5..f385cc74660 100644 --- a/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp +++ b/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp @@ -91,6 +91,10 @@ QmlProjectItem *QmlProjectFileFormat::parseProjectFile(const Utils::FilePath &fi if (mainFileProperty.isValid()) projectItem->setMainFile(mainFileProperty.value.toString()); + const auto mainUiFileProperty = rootNode->property(QLatin1String("mainUiFile")); + if (mainUiFileProperty.isValid()) + projectItem->setMainUiFile(mainUiFileProperty.value.toString()); + const auto importPathsProperty = rootNode->property(QLatin1String("importPaths")); if (importPathsProperty.isValid()) { QStringList list = importPathsProperty.value.toStringList(); diff --git a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h index 02916555a7c..d437db61140 100644 --- a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h +++ b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h @@ -81,6 +81,9 @@ public: QString mainFile() const { return m_mainFile; } void setMainFile(const QString &mainFilePath) { m_mainFile = mainFilePath; } + QString mainUiFile() const { return m_mainUiFile; } + void setMainUiFile(const QString &mainUiFilePath) { m_mainUiFile = mainUiFilePath; } + bool widgetApp() const { return m_widgetApp; } void setWidgetApp(bool widgetApp) { m_widgetApp = widgetApp; } @@ -107,6 +110,7 @@ protected: QStringList m_supportedLanguages; QString m_primaryLanguage; QString m_mainFile; + QString m_mainUiFile; Utils::EnvironmentItems m_environment; QVector m_content; // content property bool m_forceFreeType = false; diff --git a/src/plugins/qmlprojectmanager/qmlproject.cpp b/src/plugins/qmlprojectmanager/qmlproject.cpp index 37fb78f033b..dc58282e0dc 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.cpp +++ b/src/plugins/qmlprojectmanager/qmlproject.cpp @@ -135,21 +135,38 @@ QmlProject::QmlProject(const Utils::FilePath &fileName) disconnect(m_openFileConnection); if (target && success) { - Utils::FilePaths uiFiles = getUiQmlFilesForFolder(projectDirectory() - + "/content"); - if (uiFiles.isEmpty()) - uiFiles = getUiQmlFilesForFolder(projectDirectory()); - if (!uiFiles.isEmpty()) { - Utils::FilePath currentFile; - if (auto cd = Core::EditorManager::currentDocument()) - currentFile = cd->filePath(); + auto target = activeTarget(); + if (!target) + return; - if (currentFile.isEmpty() || !isKnownFile(currentFile)) - QTimer::singleShot(1000, [uiFiles]() { - Core::EditorManager::openEditor(uiFiles.first(), + auto qmlBuildSystem = qobject_cast( + target->buildSystem()); + + const Utils::FilePath mainUiFile = qmlBuildSystem->mainUiFilePath(); + + if (mainUiFile.completeSuffix() == "qi.qml" && mainUiFile.exists()) { + QTimer::singleShot(1000, [mainUiFile]() { + Core::EditorManager::openEditor(mainUiFile, Utils::Id()); - }); + }); + } else { + Utils::FilePaths uiFiles = getUiQmlFilesForFolder(projectDirectory() + + "/content"); + if (uiFiles.isEmpty()) + uiFiles = getUiQmlFilesForFolder(projectDirectory()); + + if (!uiFiles.isEmpty()) { + Utils::FilePath currentFile; + if (auto cd = Core::EditorManager::currentDocument()) + currentFile = cd->filePath(); + + if (currentFile.isEmpty() || !isKnownFile(currentFile)) + QTimer::singleShot(1000, [uiFiles]() { + Core::EditorManager::openEditor(uiFiles.first(), + Utils::Id()); + }); + } } } }); @@ -253,6 +270,58 @@ void QmlBuildSystem::parseProject(RefreshOptions options) } } +bool QmlBuildSystem::setFileSettingInProjectFile(const QString &setting, const Utils::FilePath &mainFilePath, const QString &oldFile) +{ + // make sure to change it also in the qmlproject file + const Utils::FilePath qmlProjectFilePath = project()->projectFilePath(); + Core::FileChangeBlocker fileChangeBlocker(qmlProjectFilePath); + const QList editors = Core::DocumentModel::editorsForFilePath(qmlProjectFilePath); + TextEditor::TextDocument *document = nullptr; + if (!editors.isEmpty()) { + document = qobject_cast(editors.first()->document()); + if (document && document->isModified()) + if (!Core::DocumentManager::saveDocument(document)) + return false; + } + + QString fileContent; + QString error; + Utils::TextFileFormat textFileFormat; + const QTextCodec *codec = QTextCodec::codecForName("UTF-8"); // qml files are defined to be utf-8 + if (Utils::TextFileFormat::readFile(qmlProjectFilePath, codec, &fileContent, &textFileFormat, &error) + != Utils::TextFileFormat::ReadSuccess) { + qWarning() << "Failed to read file" << qmlProjectFilePath << ":" << error; + } + + const QString settingQmlCode = setting + ":"; + + QDir projectDir = project()->projectFilePath().toDir(); + projectDir.cdUp(); + const QString relativePath = projectDir.relativeFilePath(mainFilePath.toString()); + + if (fileContent.indexOf(settingQmlCode) < 0) { + QString addedText = QString("\n %1 \"%2\"\n").arg(settingQmlCode).arg(relativePath); + auto index = fileContent.lastIndexOf("}"); + fileContent.insert(index, addedText); + } else { + QString originalFileName = oldFile; + originalFileName.replace(".", "\\."); + const QRegularExpression expression(QString("%1\\s*\"(%2)\"").arg(settingQmlCode).arg(originalFileName)); + + const QRegularExpressionMatch match = expression.match(fileContent); + + fileContent.replace(match.capturedStart(1), + match.capturedLength(1), + relativePath); + } + + if (!textFileFormat.writeFile(qmlProjectFilePath, fileContent, &error)) + qWarning() << "Failed to write file" << qmlProjectFilePath << ":" << error; + + refresh(Everything); + return true; +} + void QmlBuildSystem::refresh(RefreshOptions options) { ParseGuard guard = guardParsingRun(); @@ -283,11 +352,68 @@ QString QmlBuildSystem::mainFile() const return QString(); } +QString QmlBuildSystem::mainUiFile() const +{ + if (m_projectItem) + return m_projectItem->mainUiFile(); + return QString(); +} + Utils::FilePath QmlBuildSystem::mainFilePath() const { return projectDirectory().pathAppended(mainFile()); } +Utils::FilePath QmlBuildSystem::mainUiFilePath() const +{ + return projectDirectory().pathAppended(mainUiFile()); +} + +bool QmlBuildSystem::setMainFileInProjectFile(const Utils::FilePath &newMainFilePath) +{ + + return setFileSettingInProjectFile("mainFile", newMainFilePath, mainFile()); +} + +bool QmlBuildSystem::setMainUiFileInProjectFile(const Utils::FilePath &newMainUiFilePath) +{ + return setMainUiFileInMainFile(newMainUiFilePath) + && setFileSettingInProjectFile("mainUiFile", newMainUiFilePath, mainUiFile()); +} + +bool QmlBuildSystem::setMainUiFileInMainFile(const Utils::FilePath &newMainUiFilePath) +{ + Core::FileChangeBlocker fileChangeBlocker(mainFilePath()); + const QList editors = Core::DocumentModel::editorsForFilePath(mainFilePath()); + TextEditor::TextDocument *document = nullptr; + if (!editors.isEmpty()) { + document = qobject_cast(editors.first()->document()); + if (document && document->isModified()) + if (!Core::DocumentManager::saveDocument(document)) + return false; + } + + QString fileContent; + QString error; + Utils::TextFileFormat textFileFormat; + const QTextCodec *codec = QTextCodec::codecForName("UTF-8"); // qml files are defined to be utf-8 + if (Utils::TextFileFormat::readFile(mainFilePath(), codec, &fileContent, &textFileFormat, &error) + != Utils::TextFileFormat::ReadSuccess) { + qWarning() << "Failed to read file" << mainFilePath() << ":" << error; + } + + const QString currentMain = QString("%1 {").arg(mainUiFilePath().baseName()); + const QString newMain = QString("%1 {").arg(newMainUiFilePath.baseName()); + + if (fileContent.contains(currentMain)) + fileContent.replace(currentMain, newMain); + + if (!textFileFormat.writeFile(mainFilePath(), fileContent, &error)) + qWarning() << "Failed to write file" << mainFilePath() << ":" << error; + + return true; +} + bool QmlBuildSystem::qtForMCUs() const { if (m_projectItem) @@ -663,43 +789,10 @@ bool QmlBuildSystem::deleteFiles(Node *context, const FilePaths &filePaths) bool QmlBuildSystem::renameFile(Node * context, const FilePath &oldFilePath, const FilePath &newFilePath) { if (dynamic_cast(context)) { - if (oldFilePath.endsWith(mainFile())) { - setMainFile(newFilePath.toString()); - - // make sure to change it also in the qmlproject file - const Utils::FilePath qmlProjectFilePath = project()->projectFilePath(); - Core::FileChangeBlocker fileChangeBlocker(qmlProjectFilePath); - const QList editors = Core::DocumentModel::editorsForFilePath(qmlProjectFilePath); - TextEditor::TextDocument *document = nullptr; - if (!editors.isEmpty()) { - document = qobject_cast(editors.first()->document()); - if (document && document->isModified()) - if (!Core::DocumentManager::saveDocument(document)) - return false; - } - - QString fileContent; - QString error; - Utils::TextFileFormat textFileFormat; - const QTextCodec *codec = QTextCodec::codecForName("UTF-8"); // qml files are defined to be utf-8 - if (Utils::TextFileFormat::readFile(qmlProjectFilePath, codec, &fileContent, &textFileFormat, &error) - != Utils::TextFileFormat::ReadSuccess) { - qWarning() << "Failed to read file" << qmlProjectFilePath << ":" << error; - } - - // find the mainFile and do the file name with brackets in a capture group and mask the . with \. - QString originalFileName = oldFilePath.fileName(); - originalFileName.replace(".", "\\."); - const QRegularExpression expression(QString("mainFile:\\s*\"(%1)\"").arg(originalFileName)); - const QRegularExpressionMatch match = expression.match(fileContent); - - fileContent.replace(match.capturedStart(1), match.capturedLength(1), newFilePath.fileName()); - - if (!textFileFormat.writeFile(qmlProjectFilePath, fileContent, &error)) - qWarning() << "Failed to write file" << qmlProjectFilePath << ":" << error; - - refresh(Everything); - } + if (oldFilePath.endsWith(mainFile())) + return setMainFileInProjectFile(newFilePath); + if (oldFilePath.endsWith(mainUiFile())) + return setMainUiFileInProjectFile(newFilePath); return true; } diff --git a/src/plugins/qmlprojectmanager/qmlproject.h b/src/plugins/qmlprojectmanager/qmlproject.h index 78a30187f6e..a5ce067be69 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.h +++ b/src/plugins/qmlprojectmanager/qmlproject.h @@ -77,7 +77,13 @@ public: Utils::FilePath canonicalProjectDir() const; QString mainFile() const; + QString mainUiFile() const; Utils::FilePath mainFilePath() const; + Utils::FilePath mainUiFilePath() const; + + bool setMainFileInProjectFile(const Utils::FilePath &newMainFilePath); + bool setMainUiFileInProjectFile(const Utils::FilePath &newMainUiFilePath); + bool setMainUiFileInMainFile(const Utils::FilePath &newMainUiFilePath); bool qtForMCUs() const; bool qt6Project() const; @@ -116,6 +122,10 @@ public: void parseProject(RefreshOptions options); private: + bool setFileSettingInProjectFile(const QString &setting, + const Utils::FilePath &mainFilePath, + const QString &oldFile); + std::unique_ptr m_projectItem; Utils::FilePath m_canonicalProjectDir; bool m_blockFilesUpdate = false; diff --git a/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp b/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp index bc7b6f3bde9..ff58349dc00 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp @@ -28,14 +28,20 @@ #include "qmlprojectconstants.h" #include "qmlprojectrunconfiguration.h" +#include +#include #include #include #include #include +#include #include +#include +#include #include #include +#include #include @@ -47,6 +53,7 @@ #include #include +#include #include #include #include @@ -197,6 +204,23 @@ void QmlProjectPlugin::openInQDSWithProject(const Utils::FilePath &filePath) } } +static QmlBuildSystem *qmlBuildSystemforFileNode(const FileNode *fileNode) +{ + if (!fileNode) + return nullptr; + + if (QmlProject *qmlProject = qobject_cast(fileNode->getProject())) { + auto target = qmlProject->activeTarget(); + if (!target) + return nullptr; + + return qobject_cast(target->buildSystem()); + + } + + return nullptr; +} + bool QmlProjectPlugin::initialize(const QStringList &, QString *errorMessage) { Q_UNUSED(errorMessage) @@ -206,6 +230,7 @@ bool QmlProjectPlugin::initialize(const QStringList &, QString *errorMessage) if (!qmlDesignerEnabled()) { connect(Core::EditorManager::instance(), &Core::EditorManager::currentEditorChanged, + this, [this](Core::IEditor *editor) { QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance(); @@ -258,6 +283,95 @@ bool QmlProjectPlugin::initialize(const QStringList &, QString *errorMessage) ProjectManager::registerProjectType(QmlJSTools::Constants::QMLPROJECT_MIMETYPE); Core::FileIconProvider::registerIconOverlayForSuffix(":/qmlproject/images/qmlproject.png", "qmlproject"); + + if (QmlProject::isQtDesignStudio()) { + Core::ActionContainer *menu = Core::ActionManager::actionContainer( + ProjectExplorer::Constants::M_FILECONTEXT); + QAction *mainfileAction = new QAction(tr("Set as main .qml file"), this); + mainfileAction->setEnabled(false); + + connect(mainfileAction, &QAction::triggered, this, []() { + const Node *currentNode = ProjectTree::currentNode(); + if (!currentNode || !currentNode->asFileNode() + || currentNode->asFileNode()->fileType() != FileType::QML) + return; + + const Utils::FilePath file = currentNode->filePath(); + + QmlBuildSystem *buildSystem = qmlBuildSystemforFileNode(currentNode->asFileNode()); + if (buildSystem) + buildSystem->setMainFileInProjectFile(file); + }); + + menu->addAction(Core::ActionManager::registerAction( + mainfileAction, + "QmlProject.setMainFile", + Core::Context(ProjectExplorer::Constants::C_PROJECT_TREE)), + ProjectExplorer::Constants::G_FILE_OTHER); + mainfileAction->setVisible(false); + connect(ProjectTree::instance(), + &ProjectTree::currentNodeChanged, + mainfileAction, + [mainfileAction](Node *node) { + const FileNode *fileNode = node ? node->asFileNode() : nullptr; + + const bool isVisible = fileNode && fileNode->fileType() == FileType::QML + && fileNode->filePath().completeSuffix() == "qml"; + + mainfileAction->setVisible(isVisible); + + if (!isVisible) + return; + + QmlBuildSystem *buildSystem = qmlBuildSystemforFileNode(fileNode); + + if (buildSystem) + mainfileAction->setEnabled(buildSystem->mainFilePath() + != fileNode->filePath()); + }); + + QAction *mainUifileAction = new QAction(tr("Set as main .ui.qml file"), this); + mainUifileAction->setEnabled(false); + + connect(mainUifileAction, &QAction::triggered, this, []() { + const Node *currentNode = ProjectTree::currentNode(); + if (!currentNode || !currentNode->asFileNode() + || currentNode->asFileNode()->fileType() != FileType::QML) + return; + + const Utils::FilePath file = currentNode->filePath(); + + QmlBuildSystem *buildSystem = qmlBuildSystemforFileNode(currentNode->asFileNode()); + if (buildSystem) + buildSystem->setMainUiFileInProjectFile(file); + }); + + menu->addAction(Core::ActionManager::registerAction( + mainUifileAction, + "QmlProject.setMainUIFile", + Core::Context(ProjectExplorer::Constants::C_PROJECT_TREE)), + ProjectExplorer::Constants::G_FILE_OTHER); + mainUifileAction->setVisible(false); + connect(ProjectTree::instance(), + &ProjectTree::currentNodeChanged, + mainUifileAction, + [mainUifileAction](Node *node) { + const FileNode *fileNode = node ? node->asFileNode() : nullptr; + const bool isVisible = fileNode && fileNode->fileType() == FileType::QML + && fileNode->filePath().completeSuffix() == "ui.qml"; + + mainUifileAction->setVisible(isVisible); + + if (!isVisible) + return; + + QmlBuildSystem *buildSystem = qmlBuildSystemforFileNode(fileNode); + if (buildSystem) + mainUifileAction->setEnabled(buildSystem->mainUiFilePath() + != fileNode->filePath()); + }); + } + return true; } // namespace Internal From 259759b5c9fb7ca92bb08d6663aff432a2caf781 Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Tue, 17 May 2022 15:14:05 +0200 Subject: [PATCH 33/35] QmlDesigner: Fix typo Change-Id: If6860fe3094124dcac381f72ae88722759167354 Reviewed-by: Qt CI Bot Reviewed-by: Thomas Hartmann --- .../imports/HelperWidgets/ExtendedFunctionLogic.qml | 2 +- .../components/propertyeditor/propertyeditorqmlbackend.cpp | 2 +- .../components/propertyeditor/propertyeditorvalue.cpp | 4 ++-- .../components/propertyeditor/propertyeditorvalue.h | 4 ++-- .../components/propertyeditor/propertyeditorview.cpp | 6 +++--- .../components/propertyeditor/propertyeditorview.h | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExtendedFunctionLogic.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExtendedFunctionLogic.qml index bdefc13a977..601f9087f0d 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExtendedFunctionLogic.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExtendedFunctionLogic.qml @@ -131,7 +131,7 @@ Item { checkable: true onTriggered: { if (checked) - backendValue.exportPopertyAsAlias() + backendValue.exportPropertyAsAlias() else backendValue.removeAliasExport() } diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp index 135bbca9dfa..c73290bf76a 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp @@ -294,7 +294,7 @@ void PropertyEditorQmlBackend::createPropertyEditorValue(const QmlObjectNode &qm valueObject = new PropertyEditorValue(&backendValuesPropertyMap()); QObject::connect(valueObject, &PropertyEditorValue::valueChanged, &backendValuesPropertyMap(), &DesignerPropertyMap::valueChanged); QObject::connect(valueObject, &PropertyEditorValue::expressionChanged, propertyEditor, &PropertyEditorView::changeExpression); - QObject::connect(valueObject, &PropertyEditorValue::exportPopertyAsAliasRequested, propertyEditor, &PropertyEditorView::exportPopertyAsAlias); + QObject::connect(valueObject, &PropertyEditorValue::exportPropertyAsAliasRequested, propertyEditor, &PropertyEditorView::exportPropertyAsAlias); QObject::connect(valueObject, &PropertyEditorValue::removeAliasExportRequested, propertyEditor, &PropertyEditorView::removeAliasExport); backendValuesPropertyMap().insert(QString::fromUtf8(propertyName), QVariant::fromValue(valueObject)); } diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp index c37549e074a..c447d6c4a96 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp @@ -367,9 +367,9 @@ void PropertyEditorValue::setEnumeration(const QString &scope, const QString &na setValueWithEmit(QVariant::fromValue(newEnumeration)); } -void PropertyEditorValue::exportPopertyAsAlias() +void PropertyEditorValue::exportPropertyAsAlias() { - emit exportPopertyAsAliasRequested(nameAsQString()); + emit exportPropertyAsAliasRequested(nameAsQString()); } bool PropertyEditorValue::hasPropertyAlias() const diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.h index 52de9cbb707..8e29d0ae0ef 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.h +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.h @@ -130,7 +130,7 @@ public: static void registerDeclarativeTypes(); - Q_INVOKABLE void exportPopertyAsAlias(); + Q_INVOKABLE void exportPropertyAsAlias(); Q_INVOKABLE bool hasPropertyAlias() const; Q_INVOKABLE bool isAttachedProperty() const; Q_INVOKABLE void removeAliasExport(); @@ -153,7 +153,7 @@ signals: void valueChangedQml(); void expressionChanged(const QString &name); - void exportPopertyAsAliasRequested(const QString &name); + void exportPropertyAsAliasRequested(const QString &name); void removeAliasExportRequested(const QString &name); void modelStateChanged(); diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp index d0f8dd70435..7f190b62888 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp @@ -326,7 +326,7 @@ void PropertyEditorView::changeExpression(const QString &propertyName) }); /* end of transaction */ } -void PropertyEditorView::exportPopertyAsAlias(const QString &name) +void PropertyEditorView::exportPropertyAsAlias(const QString &name) { if (name.isNull()) return; @@ -337,7 +337,7 @@ void PropertyEditorView::exportPopertyAsAlias(const QString &name) if (noValidSelection()) return; - executeInTransaction("PropertyEditorView::exportPopertyAsAlias", [this, name](){ + executeInTransaction("PropertyEditorView::exportPropertyAsAlias", [this, name](){ const QString id = m_selectedNode.validId(); QString upperCasePropertyName = name; upperCasePropertyName.replace(0, 1, upperCasePropertyName.at(0).toUpper()); @@ -365,7 +365,7 @@ void PropertyEditorView::removeAliasExport(const QString &name) if (noValidSelection()) return; - executeInTransaction("PropertyEditorView::exportPopertyAsAlias", [this, name](){ + executeInTransaction("PropertyEditorView::exportPropertyAsAlias", [this, name](){ const QString id = m_selectedNode.validId(); for (const BindingProperty &property : rootModelNode().bindingProperties()) diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h index c6dd85d98f8..06e86fd57cd 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h @@ -89,7 +89,7 @@ public: void changeValue(const QString &name); void changeExpression(const QString &name); - void exportPopertyAsAlias(const QString &name); + void exportPropertyAsAlias(const QString &name); void removeAliasExport(const QString &name); bool locked() const; From 67f907f295d93eacf77b3c6dc20c863c43910160 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20L=C3=B6hning?= Date: Wed, 11 May 2022 20:18:33 +0200 Subject: [PATCH 34/35] Squish: Fix MSVC2017 toolchain Without this, Creator cannot set up CMake properly in the kit so configuring projects fails. MSVC2015 also needs a fix. Change-Id: I19c065eb087d098174c84301aa52cc3888ec42b7 Reviewed-by: Christian Stenger --- .../windows/QtProject/qtcreator/toolchains.xml | 16 ++++++++++++++-- tests/system/shared/qtcreator.py | 18 ++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/tests/system/settings/windows/QtProject/qtcreator/toolchains.xml b/tests/system/settings/windows/QtProject/qtcreator/toolchains.xml index b95c78667d9..a5d80d7dcbf 100644 --- a/tests/system/settings/windows/QtProject/qtcreator/toolchains.xml +++ b/tests/system/settings/windows/QtProject/qtcreator/toolchains.xml @@ -40,7 +40,13 @@ x86-windows-msvc2017-pe-64bit C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Auxiliary/Build/vcvarsall.bat amd64 - false + + + PATH + 0 + SQUISH_MSVC2017_PATH + + MSVC2017 (amd64) ProjectExplorer.ToolChain.Msvc:{ce3a8004-e9ae-46f2-b62d-d7daf69435ca} 1 @@ -79,7 +85,13 @@ x86-windows-msvc2017-pe-64bit C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Auxiliary/Build/vcvarsall.bat amd64 - false + + + PATH + 0 + SQUISH_MSVC2017_PATH + + MSVC2017 (amd64) ProjectExplorer.ToolChain.Msvc:{3df7c776-a480-4a04-9099-6c75adac2dca} 2 diff --git a/tests/system/shared/qtcreator.py b/tests/system/shared/qtcreator.py index 984d3700ccf..e9d2e18cfc6 100644 --- a/tests/system/shared/qtcreator.py +++ b/tests/system/shared/qtcreator.py @@ -231,6 +231,23 @@ def substituteCdb(settingsDir): __substitute__(debuggers, "SQUISH_DEBUGGER_BITNESS", bitness) test.log("Injected architecture '%s' and bitness '%s' in cdb path..." % (architecture, bitness)) + +def substituteMsvcPaths(settingsDir): + for msvcFlavor in ["Community", "BuildTools"]: + try: + msvc2017Path = os.path.join("C:\\Program Files (x86)", "Microsoft Visual Studio", + "2017", msvcFlavor, "VC", "Tools", "MSVC") + msvc2017Path = os.path.join(msvc2017Path, os.listdir(msvc2017Path)[0], "bin", + "HostX64", "x64") + __substitute__(os.path.join(settingsDir, "QtProject", 'qtcreator', 'toolchains.xml'), + "SQUISH_MSVC2017_PATH", msvc2017Path) + return + except: + continue + test.warning("PATH variable for MSVC2017 could not be set, some tests will fail.", + "Please make sure that MSVC2017 is installed correctly.") + + def __guessABI__(supportedABIs, use64Bit): if platform.system() == 'Linux': supportedABIs = filter(lambda x: 'linux' in x, supportedABIs) @@ -325,6 +342,7 @@ def copySettingsToTmpDir(destination=None, omitFiles=[]): substituteDefaultCompiler(tmpSettingsDir) elif platform.system() in ('Windows', 'Microsoft'): substituteCdb(tmpSettingsDir) + substituteMsvcPaths(tmpSettingsDir) substituteUnchosenTargetABIs(tmpSettingsDir) SettingsPath = ['-settingspath', '"%s"' % tmpSettingsDir] From e608243ee5fa4eb536d20d3c4c5d4e797a377cb0 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Wed, 18 May 2022 11:12:59 +0200 Subject: [PATCH 35/35] GitHub Actions / Coin: Update LLVM/Clang to 14.0.3 To be in sync with the official packaging. Change-Id: I28712ad1e8234d4911b2afcce949e1e919bf8e92 Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot --- .github/workflows/build_cmake.yml | 2 +- coin/instructions/common_environment.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_cmake.yml b/.github/workflows/build_cmake.yml index 794ce6b3d72..ab0cbacd8b1 100644 --- a/.github/workflows/build_cmake.yml +++ b/.github/workflows/build_cmake.yml @@ -8,7 +8,7 @@ on: env: QT_VERSION: 6.2.3 - CLANG_VERSION: 14.0.0 + CLANG_VERSION: 14.0.3 ELFUTILS_VERSION: 0.175 CMAKE_VERSION: 3.21.1 NINJA_VERSION: 1.10.2 diff --git a/coin/instructions/common_environment.yaml b/coin/instructions/common_environment.yaml index 19f8d3a61d1..bca60728d6e 100644 --- a/coin/instructions/common_environment.yaml +++ b/coin/instructions/common_environment.yaml @@ -7,7 +7,7 @@ instructions: variableValue: "RelWithDebInfo" - type: EnvironmentVariable variableName: LLVM_BASE_URL - variableValue: http://master.qt.io/development_releases/prebuilt/libclang/libclang-release_14.0.0-based + variableValue: http://master.qt.io/development_releases/prebuilt/libclang/libclang-release_14.0.3-based - type: Group instructions: