From 2dca61c4e3a7a437854e0ec4a55ed09a6faabc74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20=C3=81ngel=20San=20Mart=C3=ADn?= Date: Sat, 4 Oct 2014 20:43:31 +0200 Subject: [PATCH] first working version of the new search engine. TODO: add search modifiers --- YACReaderLibrary/YACReaderLibrary.pro | 6 +- YACReaderLibrary/classic_comics_view.cpp | 57 +++++++++++++++++- YACReaderLibrary/classic_comics_view.h | 8 +++ YACReaderLibrary/comics_view.cpp | 2 +- YACReaderLibrary/comics_view.h | 1 + YACReaderLibrary/db/tablemodel.cpp | 3 +- YACReaderLibrary/db/tablemodel.h | 1 + YACReaderLibrary/grid_comics_view.cpp | 5 ++ YACReaderLibrary/grid_comics_view.h | 1 + YACReaderLibrary/images.qrc | 1 + YACReaderLibrary/images_osx.qrc | 1 + YACReaderLibrary/images_win.qrc | 1 + YACReaderLibrary/library_window.cpp | 54 ++++++++++++++--- YACReaderLibrary/library_window.h | 8 ++- YACReaderLibrary/no_search_results_widget.cpp | 40 ++++++++++++ YACReaderLibrary/no_search_results_widget.h | 25 ++++++++ custom_widgets/yacreader_search_line_edit.cpp | 2 +- images/empty_search.png | Bin 0 -> 4498 bytes images/searching_icon.png | Bin 0 -> 1788 bytes 19 files changed, 196 insertions(+), 20 deletions(-) create mode 100644 YACReaderLibrary/no_search_results_widget.cpp create mode 100644 YACReaderLibrary/no_search_results_widget.h create mode 100644 images/empty_search.png create mode 100644 images/searching_icon.png diff --git a/YACReaderLibrary/YACReaderLibrary.pro b/YACReaderLibrary/YACReaderLibrary.pro index c23cf6db..b0a33ca3 100644 --- a/YACReaderLibrary/YACReaderLibrary.pro +++ b/YACReaderLibrary/YACReaderLibrary.pro @@ -118,7 +118,8 @@ HEADERS += comic_flow.h \ ../common/exit_check.h \ comics_view.h \ classic_comics_view.h \ - empty_folder_widget.h + empty_folder_widget.h \ + no_search_results_widget.h SOURCES += comic_flow.cpp \ @@ -165,7 +166,8 @@ SOURCES += comic_flow.cpp \ ../common/exit_check.cpp \ comics_view.cpp \ classic_comics_view.cpp \ - empty_folder_widget.cpp + empty_folder_widget.cpp \ + no_search_results_widget.cpp diff --git a/YACReaderLibrary/classic_comics_view.cpp b/YACReaderLibrary/classic_comics_view.cpp index d0cb5f13..f241d5ea 100644 --- a/YACReaderLibrary/classic_comics_view.cpp +++ b/YACReaderLibrary/classic_comics_view.cpp @@ -6,7 +6,7 @@ #include "QsLog.h" ClassicComicsView::ClassicComicsView(QWidget *parent) - :ComicsView(parent) + :ComicsView(parent),searching(false) { QHBoxLayout * layout = new QHBoxLayout; @@ -74,7 +74,9 @@ ClassicComicsView::ClassicComicsView(QWidget *parent) #endif if(settings->contains(COMICS_VIEW_FLOW_SPLITTER_STATUS)) - sVertical->restoreState(settings->value(COMICS_VIEW_FLOW_SPLITTER_STATUS).toByteArray()); + sVertical->restoreState(settings->value(COMICS_VIEW_FLOW_SPLITTER_STATUS).toByteArray()); + + setupSearchingIcon(); } void ClassicComicsView::setToolBar(QToolBar *toolBar) @@ -192,6 +194,29 @@ void ClassicComicsView::setViewActions(const QList &actions) comicFlow->addActions(actions); } +void ClassicComicsView::enableFilterMode(bool enabled) +{ + if(enabled) + { + comicFlow->clear(); + comicFlow->setMinimumHeight(150); + if(previousSplitterStatus.isEmpty()) + previousSplitterStatus = sVertical->saveState(); + sVertical->setSizes(QList () << 150 << 10000000); + showSearchingIcon(); + }else + { + searchingIcon->setHidden(true); + comicFlow->setMinimumHeight(0); + + sVertical->restoreState(previousSplitterStatus); + previousSplitterStatus.clear(); + } + + //sVertical->setCollapsible(0,!enabled); + searching = enabled; +} + void ClassicComicsView::selectAll() { tableView->selectAll(); @@ -222,7 +247,8 @@ void ClassicComicsView::saveTableHeadersStatus() void ClassicComicsView::saveSplitterStatus() { - settings->setValue(COMICS_VIEW_FLOW_SPLITTER_STATUS, sVertical->saveState()); + if(!searching) + settings->setValue(COMICS_VIEW_FLOW_SPLITTER_STATUS, sVertical->saveState()); } void ClassicComicsView::applyModelChanges(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles) @@ -250,3 +276,28 @@ void ClassicComicsView::closeEvent(QCloseEvent *event) ComicsView::closeEvent(event); } +void ClassicComicsView::setupSearchingIcon() +{ + searchingIcon = new QWidget(comicFlow); + + QPixmap p(":/images/searching_icon.png"); + QLabel * l = new QLabel(searchingIcon); + l->setPixmap(p); + + searchingIcon->setFixedSize(p.size()); + + hideSearchingIcon(); +} + +void ClassicComicsView::showSearchingIcon() +{ + searchingIcon->move((comicFlow->width()-searchingIcon->width())/2,(comicFlow->height()-searchingIcon->height())/2); + + searchingIcon->setHidden(false); +} + +void ClassicComicsView::hideSearchingIcon() +{ + searchingIcon->setHidden(true); +} + diff --git a/YACReaderLibrary/classic_comics_view.h b/YACReaderLibrary/classic_comics_view.h index 6e3b3bde..a0b9525b 100644 --- a/YACReaderLibrary/classic_comics_view.h +++ b/YACReaderLibrary/classic_comics_view.h @@ -28,6 +28,7 @@ public: void updateConfig(QSettings * settings); void setItemActions(const QList & actions); void setViewActions(const QList & actions); + void enableFilterMode(bool enabled); public slots: void centerComicFlow(const QModelIndex & mi); @@ -47,6 +48,13 @@ private: ComicFlowWidget * comicFlow; QSettings * settings; void closeEvent ( QCloseEvent * event ); + + QByteArray previousSplitterStatus; + QWidget * searchingIcon; + bool searching; + void setupSearchingIcon(); + void showSearchingIcon(); + void hideSearchingIcon(); }; #endif // CLASSIC_COMICS_VIEW_H diff --git a/YACReaderLibrary/comics_view.cpp b/YACReaderLibrary/comics_view.cpp index 5c5e7725..5a1dac7b 100644 --- a/YACReaderLibrary/comics_view.cpp +++ b/YACReaderLibrary/comics_view.cpp @@ -7,5 +7,5 @@ ComicsView::ComicsView(QWidget *parent) : void ComicsView::setModel(TableModel *m) { - model = m; + model = m; } diff --git a/YACReaderLibrary/comics_view.h b/YACReaderLibrary/comics_view.h index 5ae8e485..d4739f02 100644 --- a/YACReaderLibrary/comics_view.h +++ b/YACReaderLibrary/comics_view.h @@ -32,6 +32,7 @@ public: virtual void setItemActions(const QList & actions) = 0; //actions for visual-oriented views virtual void setViewActions(const QList & actions) = 0; + virtual void enableFilterMode(bool enabled) = 0; signals: void selected(unsigned int); diff --git a/YACReaderLibrary/db/tablemodel.cpp b/YACReaderLibrary/db/tablemodel.cpp index ee78b810..0f44ec01 100644 --- a/YACReaderLibrary/db/tablemodel.cpp +++ b/YACReaderLibrary/db/tablemodel.cpp @@ -346,8 +346,7 @@ void TableModel::setupModelData(const QString &filter, const QString &databasePa QSqlDatabase::removeDatabase(_databasePath); endResetModel(); - if(_data.length()==0) - emit isEmpty(); + emit searchNumResults(_data.length()); } QString TableModel::getComicPath(QModelIndex mi) diff --git a/YACReaderLibrary/db/tablemodel.h b/YACReaderLibrary/db/tablemodel.h index 67a60624..3a2b61b8 100644 --- a/YACReaderLibrary/db/tablemodel.h +++ b/YACReaderLibrary/db/tablemodel.h @@ -116,6 +116,7 @@ signals: void beforeReset(); void reset(); void isEmpty(); + void searchNumResults(int); }; //! [0] diff --git a/YACReaderLibrary/grid_comics_view.cpp b/YACReaderLibrary/grid_comics_view.cpp index 257c2d63..0d96586b 100644 --- a/YACReaderLibrary/grid_comics_view.cpp +++ b/YACReaderLibrary/grid_comics_view.cpp @@ -168,6 +168,11 @@ void GridComicsView::setViewActions(const QList &actions) QLOG_ERROR() << "setViewActions invoked with the wrong number of actions"; } +void GridComicsView::enableFilterMode(bool enabled) +{ + +} + void GridComicsView::selectAll() { QLOG_INFO() << "selectAll"; diff --git a/YACReaderLibrary/grid_comics_view.h b/YACReaderLibrary/grid_comics_view.h index 3066ff68..137c9ab7 100644 --- a/YACReaderLibrary/grid_comics_view.h +++ b/YACReaderLibrary/grid_comics_view.h @@ -28,6 +28,7 @@ public: void updateConfig(QSettings * settings); void setItemActions(const QList & actions); void setViewActions(const QList & actions); + void enableFilterMode(bool enabled); QSize sizeHint(); signals: diff --git a/YACReaderLibrary/images.qrc b/YACReaderLibrary/images.qrc index a8b51e9d..356907f6 100644 --- a/YACReaderLibrary/images.qrc +++ b/YACReaderLibrary/images.qrc @@ -110,6 +110,7 @@ ../images/shortcuts_group_page.png ../images/shortcuts_group_reading.png ../images/shortcuts_group_visualization.png + ../images/searching_icon.png diff --git a/YACReaderLibrary/images_osx.qrc b/YACReaderLibrary/images_osx.qrc index e156480b..be86db51 100644 --- a/YACReaderLibrary/images_osx.qrc +++ b/YACReaderLibrary/images_osx.qrc @@ -20,6 +20,7 @@ ../images/flow_to_grid.gif ../images/grid_to_flow.gif ../images/empty_folder.png + ../images/empty_search.png ../images/iconSearch.png ../images/clearSearch.png diff --git a/YACReaderLibrary/images_win.qrc b/YACReaderLibrary/images_win.qrc index a32506a2..b41ecd8d 100644 --- a/YACReaderLibrary/images_win.qrc +++ b/YACReaderLibrary/images_win.qrc @@ -19,6 +19,7 @@ ../images/flow_to_grid.gif ../images/grid_to_flow.gif ../images/empty_folder.png + ../images/empty_search.png ../images/iconSearchNew.png ../images/clearSearchNew.png diff --git a/YACReaderLibrary/library_window.cpp b/YACReaderLibrary/library_window.cpp index 24822546..5eb1c743 100644 --- a/YACReaderLibrary/library_window.cpp +++ b/YACReaderLibrary/library_window.cpp @@ -68,6 +68,8 @@ #include "edit_shortcuts_dialog.h" #include "shortcuts_manager.h" +#include "no_search_results_widget.h" + #include "QsLog.h" #ifdef Q_OS_WIN @@ -175,7 +177,7 @@ void LibraryWindow::doLayout() //FOLDERS FILTER------------------------------------------------------------- //--------------------------------------------------------------------------- - foldersFilter = new YACReaderSearchLineEdit(); + searchEdit = new YACReaderSearchLineEdit(); //SIDEBAR-------------------------------------------------------------------- //--------------------------------------------------------------------------- @@ -214,6 +216,7 @@ void LibraryWindow::doLayout() comicsView->setToolBar(editInfoToolBar); comicsViewStack->addWidget(comicsViewTransition = new ComicsViewTransition()); comicsViewStack->addWidget(emptyFolderWidget = new EmptyFolderWidget()); + comicsViewStack->addWidget(noSearchResultsWidget = new NoSearchResultsWidget()); comicsViewStack->addWidget(comicsView); comicsViewStack->setCurrentWidget(comicsView); @@ -767,7 +770,7 @@ void LibraryWindow::createToolBars() libraryToolBar->helpButton->setDefaultAction(helpAboutAction); libraryToolBar->toggleComicsViewButton->setDefaultAction(toggleComicsViewAction); libraryToolBar->fullscreenButton->setDefaultAction(toggleFullScreenAction); - libraryToolBar->setSearchWidget(foldersFilter); + libraryToolBar->setSearchWidget(searchEdit); #endif editInfoToolBar->setIconSize(QSize(18,18)); @@ -1000,7 +1003,7 @@ void LibraryWindow::createConnections() //Folders filter //connect(clearFoldersFilter,SIGNAL(clicked()),foldersFilter,SLOT(clear())); - connect(foldersFilter,SIGNAL(textChanged(QString)),this,SLOT(setSearchFilter(QString))); + connect(searchEdit,SIGNAL(textChanged(QString)),this,SLOT(setSearchFilter(QString))); //connect(includeComicsCheckBox,SIGNAL(stateChanged(int)),this,SLOT(searchInFiles(int))); //ContextMenus @@ -1029,6 +1032,7 @@ void LibraryWindow::createConnections() connect(comicsViewTransition,SIGNAL(transitionFinished()),this,SLOT(showComicsView())); connect(comicsModel,SIGNAL(isEmpty()),this,SLOT(showEmptyFolderView())); + connect(comicsModel,SIGNAL(searchNumResults(int)),this,SLOT(checkSearchNumResults(int))); connect(emptyFolderWidget,SIGNAL(subfolderSelected(QModelIndex,int)),this,SLOT(selectSubfolder(QModelIndex,int))); connect(showEditShortcutsAction,SIGNAL(triggered()),editShortcutsDialog,SLOT(show())); @@ -1107,7 +1111,7 @@ void LibraryWindow::loadLibrary(const QString & name) //TODO encontrar el bug que provoca que no se carguen adecuadamente las carátulas en root. setRootIndex(); - foldersFilter->clear(); + searchEdit->clear(); } else if(comparation > 0) { @@ -1197,14 +1201,14 @@ void LibraryWindow::loadCovers(const QModelIndex & mi) //cambiado de orden, ya que al llamar a foldersFilter->clear() se invalidan los model index - if(foldersFilter->text()!="") + if(searchEdit->text()!="") { //setFoldersFilter(""); if(mi.isValid()) { index = static_cast(mi.internalPointer())->originalItem; column = mi.column(); - foldersFilter->clear(); + searchEdit->clear(); } } else @@ -1229,6 +1233,16 @@ void LibraryWindow::loadCovers(const QModelIndex & mi) emptyFolderWidget->setSubfolders(mi,foldersModel->getSubfoldersNames(mi)); } +void LibraryWindow::loadCoversFromCurrentModel() +{ + comicsView->setModel(comicsModel); + QStringList paths = comicsModel->getPaths(currentPath()); + + if(paths.size()>0) { + comicsView->setCurrentIndex(comicsModel->index(0,0)); + } +} + void LibraryWindow::selectSubfolder(const QModelIndex &mi, int child) { QModelIndex dest = foldersModel->index(child,0,mi); @@ -1259,6 +1273,13 @@ void LibraryWindow::checkEmptyFolder(QStringList * paths) void LibraryWindow::reloadCovers() { + //comics view switch when filter/search is enabled + if(!searchEdit->text().isEmpty()) + { + loadCoversFromCurrentModel(); + return; + } + if(foldersView->selectionModel()->selectedRows().length()>0) loadCovers(foldersView->currentIndex()); else @@ -1585,6 +1606,7 @@ void LibraryWindow::setSearchFilter(QString filter) if(filter.isEmpty() && foldersModel->isFilterEnabled()) { foldersModel->resetFilter(); + comicsView->enableFilterMode(false); //foldersView->collapseAll(); if(index != 0) { @@ -1603,6 +1625,7 @@ void LibraryWindow::setSearchFilter(QString filter) { foldersModel->setFilter(filter, true);//includeComicsCheckBox->isChecked()); comicsModel->setupModelData(filter, foldersModel->getDatabase()); + comicsView->enableFilterMode(true); foldersView->expandAll(); } } @@ -1720,6 +1743,11 @@ void LibraryWindow::showEmptyFolderView() comicsViewStack->setCurrentWidget(emptyFolderWidget); } +void LibraryWindow::showNoSearchResultsView() +{ + comicsViewStack->setCurrentWidget(noSearchResultsWidget); +} + //TODO recover the current comics selection and restore it in the destination void LibraryWindow::toggleComicsView() { @@ -1730,6 +1758,14 @@ void LibraryWindow::toggleComicsView() toggleComicsView_delayed(); } +void LibraryWindow::checkSearchNumResults(int numResults) +{ + if(numResults == 0) + showNoSearchResultsView(); + else + showComicsView(); +} + void LibraryWindow::asignNumbers() { QModelIndexList indexList = getSelectedComics(); @@ -1888,14 +1924,14 @@ void LibraryWindow::closeEvent ( QCloseEvent * event ) void LibraryWindow::showNoLibrariesWidget() { disableAllActions(); - foldersFilter->setDisabled(true); + searchEdit->setDisabled(true); mainWidget->setCurrentIndex(1); } void LibraryWindow::showRootWidget() { libraryToolBar->setDisabled(false); - foldersFilter->setEnabled(true); + searchEdit->setEnabled(true); mainWidget->setCurrentIndex(0); } @@ -1904,7 +1940,7 @@ void LibraryWindow::showImportingWidget() disableAllActions(); importWidget->clear(); libraryToolBar->setDisabled(true); - foldersFilter->setDisabled(true); + searchEdit->setDisabled(true); mainWidget->setCurrentIndex(2); } diff --git a/YACReaderLibrary/library_window.h b/YACReaderLibrary/library_window.h index 5b744eef..87fd65c4 100644 --- a/YACReaderLibrary/library_window.h +++ b/YACReaderLibrary/library_window.h @@ -54,6 +54,7 @@ class ClassicComicsView; class GridComicsView; class ComicsViewTransition; class EmptyFolderWidget; +class NoSearchResultsWidget; class EditShortcutsDialog; #include "comic_db.h" @@ -90,11 +91,10 @@ private: QSize slideSizeW; QSize slideSizeF; //search filter - YACReaderSearchLineEdit * foldersFilter; + YACReaderSearchLineEdit * searchEdit; TreeItem * index; //index al que hay que hacer scroll despu�s de pulsar sobre un folder filtrado int column; QString previousFilter; - QPushButton * clearFoldersFilter; QCheckBox * includeComicsCheckBox; //------------- @@ -104,6 +104,7 @@ private: QStackedWidget * comicsViewStack; ComicsViewTransition * comicsViewTransition; EmptyFolderWidget * emptyFolderWidget; + NoSearchResultsWidget * noSearchResultsWidget; YACReaderTreeView * foldersView; YACReaderLibraryListWidget * selectedLibrary; @@ -314,7 +315,10 @@ public slots: void toggleComicsView_delayed();//used in orther to avoid flickering; void showComicsView(); void showEmptyFolderView(); + void showNoSearchResultsView(); void toggleComicsView(); + void checkSearchNumResults(int numResults); + void loadCoversFromCurrentModel(); }; #endif diff --git a/YACReaderLibrary/no_search_results_widget.cpp b/YACReaderLibrary/no_search_results_widget.cpp new file mode 100644 index 00000000..f7506a27 --- /dev/null +++ b/YACReaderLibrary/no_search_results_widget.cpp @@ -0,0 +1,40 @@ +#include "no_search_results_widget.h" + +#include +#include +#include + +NoSearchResultsWidget::NoSearchResultsWidget(QWidget *parent) : + QWidget(parent) +{ + QVBoxLayout * layout = new QVBoxLayout; + + iconLabel = new QLabel(); + iconLabel->setPixmap(QPixmap(":/images/empty_search.png")); + iconLabel->setAlignment(Qt::AlignCenter); + + titleLabel = new QLabel("No results"); + titleLabel->setAlignment(Qt::AlignCenter); + titleLabel->setStyleSheet("QLabel {color:#CCCCCC; font-size:24px;font-family:Arial;font-weight:bold;}"); + + layout->addSpacing(100); + layout->addWidget(iconLabel); + layout->addSpacing(30); + layout->addWidget(titleLabel); + layout->addStretch(); + layout->setMargin(0); + layout->setSpacing(0); + + setContentsMargins(0,0,0,0); + + setStyleSheet("QWidget {background:#2A2A2A}"); + + setSizePolicy(QSizePolicy ::Expanding , QSizePolicy ::Expanding ); + setLayout(layout); +} + +void NoSearchResultsWidget::paintEvent(QPaintEvent *) +{ + QPainter painter (this); + painter.fillRect(0,0,width(),height(),QColor("#2A2A2A")); +} diff --git a/YACReaderLibrary/no_search_results_widget.h b/YACReaderLibrary/no_search_results_widget.h new file mode 100644 index 00000000..8bb6969a --- /dev/null +++ b/YACReaderLibrary/no_search_results_widget.h @@ -0,0 +1,25 @@ +#ifndef NO_SEARCH_RESULTS_WIDGET_H +#define NO_SEARCH_RESULTS_WIDGET_H + +#include + +class QLabel; + +class NoSearchResultsWidget : public QWidget +{ + Q_OBJECT +public: + explicit NoSearchResultsWidget(QWidget *parent = 0); + +signals: + +public slots: + +protected: + QLabel * iconLabel; + QLabel * titleLabel; + void paintEvent(QPaintEvent *); + +}; + +#endif // NO_SEARCH_RESULTS_WIDGET_H diff --git a/custom_widgets/yacreader_search_line_edit.cpp b/custom_widgets/yacreader_search_line_edit.cpp index 3826c674..1e0dff22 100644 --- a/custom_widgets/yacreader_search_line_edit.cpp +++ b/custom_widgets/yacreader_search_line_edit.cpp @@ -27,7 +27,7 @@ YACReaderSearchLineEdit::YACReaderSearchLineEdit(QWidget *parent) #ifdef Q_OS_MAC setStyleSheet(QString("QLineEdit {border-top:1px solid #9F9F9F; border-bottom:1px solid #ACACAC; border-right:1px solid #ACACAC; border-left:1px solid #ACACAC; border-radius: 10px; background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #CACACA, stop: 0.15 #FFFFFF); padding-left: %1px; padding-right: %2px; padding-bottom: 1px; margin-bottom: 1px;} ").arg(searchLabel->sizeHint().width() + frameWidth + 6).arg(clearButton->sizeHint().width() + frameWidth + 2)); #else - setStyleSheet(QString("QLineEdit {color: #ABABAB; border:none; border-radius: 5px; background-color:#404040; padding-left: %1px; padding-right: %2px; padding-bottom: 1px; margin-right: 9px;} ").arg(searchLabel->sizeHint().width() + frameWidth + 6 + 5).arg(clearButton->sizeHint().width() + frameWidth + 2)); + setStyleSheet(QString("QLineEdit {color: #ABABAB; border:none; border-radius: 4px; background-color:#404040; padding-left: %1px; padding-right: %2px; padding-bottom: 1px; margin-right: 9px;} ").arg(searchLabel->sizeHint().width() + frameWidth + 6 + 5).arg(clearButton->sizeHint().width() + frameWidth + 2)); #endif QSize msz = minimumSizeHint(); setMinimumSize(qMax(msz.width(), clearButton->sizeHint().height() + frameWidth * 2 + 2), diff --git a/images/empty_search.png b/images/empty_search.png new file mode 100644 index 0000000000000000000000000000000000000000..f012d8ec33506365c141bd9eb2013fd5f8c5b62e GIT binary patch literal 4498 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 literal 0 HcmV?d00001 diff --git a/images/searching_icon.png b/images/searching_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..95355bfc3f6829a4c9afe75f2d70195e048f9354 GIT binary patch literal 1788 zcmV9cMbfepOvv>F%US zKsz`%*xTEaR~Y_fXJ-e$>I*(TKEA%b^bhav@4sf2)M{w}E=Na4?RFbKfQZE%1Qu*O z9@oMvtq#rU=_$~NUVIrCfz->(3xw8GMo`Mh$qDHAMYC*R^z`%uSWRLCI;S(Ub0|B5 z8$QiUqFB6)YN4}0>fzx5q#|Vm&+7Ghb#r>j1v00TXCyFlvWK0 zgYkG~?ui)8I@NH&l&+5Sf&4Ug`7QZufwB+pU%x+Y*#KyyUPV4_gbBKn4-{+|f$_z~1?go1 zC}e5bBPPTXvediCsN3!GV;Nkmb_H2u0wY|^ba1vHqQPK5iU>iv#u!wBi4WmO1(*u& z4;*|=`ekNu&h_&=C*2=XVp4WBFCsEjL!xL$%q0<|X=D=1-a4(MT_=;NS0bewXfpf zO;%F4OG#;#8zv&72A98m#XDNFM5Lv}M5T7SUE*$v7g2;6BN-o<%StMCs{Fs_bE2(g z#8hJ&G2R#DN=)NRASiMPUPDF1H@-|qWLnf*9r2AXl9FN^O)qzCsPR)=dmTkmMXOp$ zg*svwH7+e$8M&?hmMW)h03*f~3U$N`Y8$|au_6@8;-l&&noBpUWIOCXqiSti7`ZHo zQyY-`RL+P=9GbOG)O*ZQRd+%p#th$uj9ikd|Gu_Sj9hADika-86XM(&LK?Ypve4Ja z{SPCup1;|QN+2kS zRZQgezF9vEAg0abDpAZu+Duoq*KXv3A&L?CVJ5nzLHQ)vS`6zHBiVPyJh<2EH3AR@ z8B+BCRG$6(o70kK2*{4RMtB(+J=gk>n!l9%fTiE>M?N)yi;*H?)^YtMSeLA-tL&;AI(jEg@X?O7SsBCpvtmu4aVDZRBwh z!a)j{LayeL^BIgb(^_c1a9_3re53N??(QzIf^UG0e~?eN+l7LxvsoTfRv!6{0+Xbd zNFDI_>2zA%iX8L==(tabNKDz<0TS;S0x^2F2nrhXeoCkeUPyF(O@VidH3<*fXNMV4CLzSqUud zkNTiree`eOG@=NT!C7N|F~w;sF&Ug$he7@I^%e1WgE6fP;b!Oh0h3fV8*#LsFHD)m zU63Mz6fiY#$-<~O~}tnUK9!|Y6Q@fbdvL`&p|A=ATI zN-)W3Qkmn8&>GoiYkd^G7dmo6l}=NAVM07X0-SkirJRZ$o|LAuJmc|#3GW3`$~?AM zNZ}Q6ia&TV=Yg!nkyAoF-gf-g_}QOP4R_hl4V8a)24Kmw z3vOt~OFkxqD6IGNx?l>yXu;;^Vk?7}p1%400v2mb!{IPAqZ-Wu6ME?8<|f-7MiwC) zgXVNP-6BS&n2`4&Yj?`CHyhLZ>AzdYh{1#`@BaQ?|C%P-YAe5ENHVsUktU@D eRg{AL7GMBf7n;cZ*{G!e0000