UniversalEntry: add more entries

- e: search name of the folders/notes in current notebook;
- d: search content of the notes in current notebook;
- r: search name of the folders/notes in current folder;
- f: search content of the notes in current folder;
- t: list and search name of opened notes in buffer;
- g: search content of opened notes in buffer;
- b: search outline of opened notes in buffer;
- h: search path of the folders/notes in all the notebooks;
- n: search path of the folders/notes in current notebook
This commit is contained in:
Le Tan 2018-03-30 22:23:22 +08:00
parent 2bfa5f9f52
commit 9289a634b5
4 changed files with 399 additions and 12 deletions

View File

@ -3199,7 +3199,16 @@ void VMainWindow::initUniversalEntry()
// Register entries. // Register entries.
VSearchUE *searchUE = new VSearchUE(this); VSearchUE *searchUE = new VSearchUE(this);
m_ue->registerEntry('q', searchUE, VSearchUE::Name_Notebook_AllNotebook); m_ue->registerEntry('q', searchUE, VSearchUE::Name_FolderNote_AllNotebook);
m_ue->registerEntry('a', searchUE, VSearchUE::Name_FolderNote_AllNotebook); m_ue->registerEntry('a', searchUE, VSearchUE::Content_Note_AllNotebook);
m_ue->registerEntry('z', searchUE, VSearchUE::Content_Note_AllNotebook); m_ue->registerEntry('w', searchUE, VSearchUE::Name_Notebook_AllNotebook);
m_ue->registerEntry('e', searchUE, VSearchUE::Name_FolderNote_CurrentNotebook);
m_ue->registerEntry('d', searchUE, VSearchUE::Content_Note_CurrentNotebook);
m_ue->registerEntry('r', searchUE, VSearchUE::Name_FolderNote_CurrentFolder);
m_ue->registerEntry('f', searchUE, VSearchUE::Content_Note_CurrentFolder);
m_ue->registerEntry('t', searchUE, VSearchUE::Name_Note_Buffer);
m_ue->registerEntry('g', searchUE, VSearchUE::Content_Note_Buffer);
m_ue->registerEntry('b', searchUE, VSearchUE::Outline_Note_Buffer);
m_ue->registerEntry('h', searchUE, VSearchUE::Path_FolderNote_AllNotebook);
m_ue->registerEntry('n', searchUE, VSearchUE::Path_FolderNote_CurrentNotebook);
} }

View File

@ -13,6 +13,9 @@
#include "vmainwindow.h" #include "vmainwindow.h"
#include "vnotebookselector.h" #include "vnotebookselector.h"
#include "vnotefile.h" #include "vnotefile.h"
#include "vdirectory.h"
#include "vdirectorytree.h"
#include "veditarea.h"
extern VNote *g_vnote; extern VNote *g_vnote;
@ -34,13 +37,40 @@ QString VSearchUE::description(int p_id) const
{ {
switch (p_id) { switch (p_id) {
case ID::Name_Notebook_AllNotebook: case ID::Name_Notebook_AllNotebook:
return tr("List and search all notebooks"); return tr("List and search all the notebooks");
case ID::Name_FolderNote_AllNotebook: case ID::Name_FolderNote_AllNotebook:
return tr("Search the name of folders/notes in all notebooks"); return tr("Search the name of folders/notes in all the notebooks");
case ID::Content_Note_AllNotebook: case ID::Content_Note_AllNotebook:
return tr("Search the content of notes in all notebooks"); return tr("Search the content of notes in all the notebooks");
case ID::Name_FolderNote_CurrentNotebook:
return tr("Search the name of folders/notes in current notebook");
case ID::Content_Note_CurrentNotebook:
return tr("Search the content of notes in current notebook");
case ID::Name_FolderNote_CurrentFolder:
return tr("Search the name of folders/notes in current folder");
case ID::Content_Note_CurrentFolder:
return tr("Search the content of notes in current folder");
case ID::Name_Note_Buffer:
return tr("List and search buffer (opened notes)");
case ID::Content_Note_Buffer:
return tr("Search the content of opened notes in buffer");
case ID::Outline_Note_Buffer:
return tr("Search the outline of opened notes in buffer");
case ID::Path_FolderNote_AllNotebook:
return tr("Search the path of folders/notes in all the notebooks");
case ID::Path_FolderNote_CurrentNotebook:
return tr("Search the path of folders/notes in current notebook");
default: default:
Q_ASSERT(false); Q_ASSERT(false);
@ -96,9 +126,18 @@ QWidget *VSearchUE::widget(int p_id)
switch (p_id) { switch (p_id) {
case ID::Name_Notebook_AllNotebook: case ID::Name_Notebook_AllNotebook:
case ID::Name_FolderNote_AllNotebook: case ID::Name_FolderNote_AllNotebook:
case ID::Name_FolderNote_CurrentNotebook:
case ID::Name_FolderNote_CurrentFolder:
case ID::Name_Note_Buffer:
case ID::Path_FolderNote_AllNotebook:
case ID::Path_FolderNote_CurrentNotebook:
return m_listWidget; return m_listWidget;
case ID::Content_Note_AllNotebook: case ID::Content_Note_AllNotebook:
case ID::Content_Note_CurrentNotebook:
case ID::Content_Note_CurrentFolder:
case ID::Content_Note_Buffer:
case ID::Outline_Note_Buffer:
return m_treeWidget; return m_treeWidget;
default: default:
@ -131,6 +170,42 @@ void VSearchUE::processCommand(int p_id, const QString &p_cmd)
searchContentOfNoteInAllNotebooks(p_cmd); searchContentOfNoteInAllNotebooks(p_cmd);
break; break;
case ID::Name_FolderNote_CurrentNotebook:
searchNameOfFolderNoteInCurrentNotebook(p_cmd);
break;
case ID::Content_Note_CurrentNotebook:
searchContentOfNoteInCurrentNotebook(p_cmd);
break;
case ID::Name_FolderNote_CurrentFolder:
searchNameOfFolderNoteInCurrentFolder(p_cmd);
break;
case ID::Content_Note_CurrentFolder:
searchContentOfNoteInCurrentFolder(p_cmd);
break;
case ID::Name_Note_Buffer:
searchNameOfBuffer(p_cmd);
break;
case ID::Content_Note_Buffer:
searchContentOfBuffer(p_cmd);
break;
case ID::Outline_Note_Buffer:
searchOutlineOfBuffer(p_cmd);
break;
case ID::Path_FolderNote_AllNotebook:
searchPathOfFolderNoteInAllNotebooks(p_cmd);
break;
case ID::Path_FolderNote_CurrentNotebook:
searchPathOfFolderNoteInCurrentNotebook(p_cmd);
break;
default: default:
Q_ASSERT(false); Q_ASSERT(false);
break; break;
@ -191,7 +266,6 @@ void VSearchUE::searchNameOfAllNotebooks(const QString &p_cmd)
void VSearchUE::searchNameOfFolderNoteInAllNotebooks(const QString &p_cmd) void VSearchUE::searchNameOfFolderNoteInAllNotebooks(const QString &p_cmd)
{ {
const QVector<VNotebook *> &notebooks = g_vnote->getNotebooks();
if (p_cmd.isEmpty()) { if (p_cmd.isEmpty()) {
m_inSearch = false; m_inSearch = false;
emit stateUpdated(State::Success); emit stateUpdated(State::Success);
@ -206,14 +280,13 @@ void VSearchUE::searchNameOfFolderNoteInAllNotebooks(const QString &p_cmd)
p_cmd, p_cmd,
QString())); QString()));
m_search->setConfig(config); m_search->setConfig(config);
QSharedPointer<VSearchResult> result = m_search->search(notebooks); QSharedPointer<VSearchResult> result = m_search->search(g_vnote->getNotebooks());
handleSearchFinished(result); handleSearchFinished(result);
} }
} }
void VSearchUE::searchContentOfNoteInAllNotebooks(const QString &p_cmd) void VSearchUE::searchContentOfNoteInAllNotebooks(const QString &p_cmd)
{ {
const QVector<VNotebook *> &notebooks = g_vnote->getNotebooks();
if (p_cmd.isEmpty()) { if (p_cmd.isEmpty()) {
m_inSearch = false; m_inSearch = false;
emit stateUpdated(State::Success); emit stateUpdated(State::Success);
@ -228,6 +301,225 @@ void VSearchUE::searchContentOfNoteInAllNotebooks(const QString &p_cmd)
p_cmd, p_cmd,
QString())); QString()));
m_search->setConfig(config); m_search->setConfig(config);
QSharedPointer<VSearchResult> result = m_search->search(g_vnote->getNotebooks());
handleSearchFinished(result);
}
}
void VSearchUE::searchNameOfFolderNoteInCurrentNotebook(const QString &p_cmd)
{
if (p_cmd.isEmpty()) {
m_inSearch = false;
emit stateUpdated(State::Success);
} else {
QVector<VNotebook *> notebooks;
notebooks.append(g_mainWin->getNotebookSelector()->currentNotebook());
m_search->clear();
VSearchConfig::Option opt = VSearchConfig::NoneOption;
QSharedPointer<VSearchConfig> config(new VSearchConfig(VSearchConfig::CurrentNotebook,
VSearchConfig::Name,
VSearchConfig::Folder | VSearchConfig::Note,
VSearchConfig::Internal,
opt,
p_cmd,
QString()));
m_search->setConfig(config);
QSharedPointer<VSearchResult> result = m_search->search(notebooks);
handleSearchFinished(result);
}
}
void VSearchUE::searchContentOfNoteInCurrentNotebook(const QString &p_cmd)
{
if (p_cmd.isEmpty()) {
m_inSearch = false;
emit stateUpdated(State::Success);
} else {
QVector<VNotebook *> notebooks;
notebooks.append(g_mainWin->getNotebookSelector()->currentNotebook());
m_search->clear();
VSearchConfig::Option opt = VSearchConfig::NoneOption;
QSharedPointer<VSearchConfig> config(new VSearchConfig(VSearchConfig::CurrentNotebook,
VSearchConfig::Content,
VSearchConfig::Note,
VSearchConfig::Internal,
opt,
p_cmd,
QString()));
m_search->setConfig(config);
QSharedPointer<VSearchResult> result = m_search->search(notebooks);
handleSearchFinished(result);
}
}
void VSearchUE::searchNameOfFolderNoteInCurrentFolder(const QString &p_cmd)
{
if (p_cmd.isEmpty()) {
m_inSearch = false;
emit stateUpdated(State::Success);
} else {
VDirectory *dir = g_mainWin->getDirectoryTree()->currentDirectory();
m_search->clear();
VSearchConfig::Option opt = VSearchConfig::NoneOption;
QSharedPointer<VSearchConfig> config(new VSearchConfig(VSearchConfig::CurrentFolder,
VSearchConfig::Name,
VSearchConfig::Folder | VSearchConfig::Note,
VSearchConfig::Internal,
opt,
p_cmd,
QString()));
m_search->setConfig(config);
QSharedPointer<VSearchResult> result = m_search->search(dir);
handleSearchFinished(result);
}
}
void VSearchUE::searchContentOfNoteInCurrentFolder(const QString &p_cmd)
{
if (p_cmd.isEmpty()) {
m_inSearch = false;
emit stateUpdated(State::Success);
} else {
VDirectory *dir = g_mainWin->getDirectoryTree()->currentDirectory();
m_search->clear();
VSearchConfig::Option opt = VSearchConfig::NoneOption;
QSharedPointer<VSearchConfig> config(new VSearchConfig(VSearchConfig::CurrentFolder,
VSearchConfig::Content,
VSearchConfig::Note,
VSearchConfig::Internal,
opt,
p_cmd,
QString()));
m_search->setConfig(config);
QSharedPointer<VSearchResult> result = m_search->search(dir);
handleSearchFinished(result);
}
}
QVector<VFile *> getFilesInBuffer()
{
QVector<VEditTabInfo> tabs = g_mainWin->getEditArea()->getAllTabsInfo();
QVector<VFile *> files;
files.reserve(tabs.size());
for (auto const & ta : tabs) {
files.append(ta.m_editTab->getFile());
}
return files;
}
void VSearchUE::searchNameOfBuffer(const QString &p_cmd)
{
QVector<VFile *> files = getFilesInBuffer();
if (p_cmd.isEmpty()) {
// List all the notes.
for (auto const & fi : files) {
QSharedPointer<VSearchResultItem> item(new VSearchResultItem(VSearchResultItem::Note,
VSearchResultItem::LineNumber,
fi->getName(),
fi->fetchPath()));
handleSearchItemAdded(item);
}
m_inSearch = false;
emit stateUpdated(State::Success);
} else {
m_search->clear();
VSearchConfig::Option opt = VSearchConfig::NoneOption;
QSharedPointer<VSearchConfig> config(new VSearchConfig(VSearchConfig::OpenedNotes,
VSearchConfig::Name,
VSearchConfig::Note,
VSearchConfig::Internal,
opt,
p_cmd,
QString()));
m_search->setConfig(config);
QSharedPointer<VSearchResult> result = m_search->search(files);
handleSearchFinished(result);
}
}
void VSearchUE::searchContentOfBuffer(const QString &p_cmd)
{
if (p_cmd.isEmpty()) {
m_inSearch = false;
emit stateUpdated(State::Success);
} else {
m_search->clear();
VSearchConfig::Option opt = VSearchConfig::NoneOption;
QSharedPointer<VSearchConfig> config(new VSearchConfig(VSearchConfig::OpenedNotes,
VSearchConfig::Content,
VSearchConfig::Note,
VSearchConfig::Internal,
opt,
p_cmd,
QString()));
m_search->setConfig(config);
QSharedPointer<VSearchResult> result = m_search->search(getFilesInBuffer());
handleSearchFinished(result);
}
}
void VSearchUE::searchOutlineOfBuffer(const QString &p_cmd)
{
if (p_cmd.isEmpty()) {
m_inSearch = false;
emit stateUpdated(State::Success);
} else {
m_search->clear();
VSearchConfig::Option opt = VSearchConfig::NoneOption;
QSharedPointer<VSearchConfig> config(new VSearchConfig(VSearchConfig::OpenedNotes,
VSearchConfig::Outline,
VSearchConfig::Note,
VSearchConfig::Internal,
opt,
p_cmd,
QString()));
m_search->setConfig(config);
QSharedPointer<VSearchResult> result = m_search->search(getFilesInBuffer());
handleSearchFinished(result);
}
}
void VSearchUE::searchPathOfFolderNoteInAllNotebooks(const QString &p_cmd)
{
if (p_cmd.isEmpty()) {
m_inSearch = false;
emit stateUpdated(State::Success);
} else {
m_search->clear();
VSearchConfig::Option opt = VSearchConfig::NoneOption;
QSharedPointer<VSearchConfig> config(new VSearchConfig(VSearchConfig::AllNotebooks,
VSearchConfig::Path,
VSearchConfig::Folder | VSearchConfig::Note,
VSearchConfig::Internal,
opt,
p_cmd,
QString()));
m_search->setConfig(config);
QSharedPointer<VSearchResult> result = m_search->search(g_vnote->getNotebooks());
handleSearchFinished(result);
}
}
void VSearchUE::searchPathOfFolderNoteInCurrentNotebook(const QString &p_cmd)
{
if (p_cmd.isEmpty()) {
m_inSearch = false;
emit stateUpdated(State::Success);
} else {
QVector<VNotebook *> notebooks;
notebooks.append(g_mainWin->getNotebookSelector()->currentNotebook());
m_search->clear();
VSearchConfig::Option opt = VSearchConfig::NoneOption;
QSharedPointer<VSearchConfig> config(new VSearchConfig(VSearchConfig::CurrentNotebook,
VSearchConfig::Path,
VSearchConfig::Folder | VSearchConfig::Note,
VSearchConfig::Internal,
opt,
p_cmd,
QString()));
m_search->setConfig(config);
QSharedPointer<VSearchResult> result = m_search->search(notebooks); QSharedPointer<VSearchResult> result = m_search->search(notebooks);
handleSearchFinished(result); handleSearchFinished(result);
} }
@ -258,6 +550,11 @@ void VSearchUE::handleSearchItemAdded(const QSharedPointer<VSearchResultItem> &p
switch (m_id) { switch (m_id) {
case ID::Name_Notebook_AllNotebook: case ID::Name_Notebook_AllNotebook:
case ID::Name_FolderNote_AllNotebook: case ID::Name_FolderNote_AllNotebook:
case ID::Name_FolderNote_CurrentNotebook:
case ID::Name_FolderNote_CurrentFolder:
case ID::Name_Note_Buffer:
case ID::Path_FolderNote_AllNotebook:
case ID::Path_FolderNote_CurrentNotebook:
appendItemToList(p_item); appendItemToList(p_item);
if (itemAdded > 50) { if (itemAdded > 50) {
itemAdded = 0; itemAdded = 0;
@ -268,6 +565,10 @@ void VSearchUE::handleSearchItemAdded(const QSharedPointer<VSearchResultItem> &p
break; break;
case ID::Content_Note_AllNotebook: case ID::Content_Note_AllNotebook:
case ID::Content_Note_CurrentNotebook:
case ID::Content_Note_CurrentFolder:
case ID::Content_Note_Buffer:
case ID::Outline_Note_Buffer:
appendItemToTree(p_item); appendItemToTree(p_item);
if (itemAdded > 50) { if (itemAdded > 50) {
itemAdded = 0; itemAdded = 0;
@ -290,6 +591,11 @@ void VSearchUE::handleSearchItemsAdded(const QList<QSharedPointer<VSearchResultI
switch (m_id) { switch (m_id) {
case ID::Name_Notebook_AllNotebook: case ID::Name_Notebook_AllNotebook:
case ID::Name_FolderNote_AllNotebook: case ID::Name_FolderNote_AllNotebook:
case ID::Name_FolderNote_CurrentNotebook:
case ID::Name_FolderNote_CurrentFolder:
case ID::Name_Note_Buffer:
case ID::Path_FolderNote_AllNotebook:
case ID::Path_FolderNote_CurrentNotebook:
{ {
for (auto const & it : p_items) { for (auto const & it : p_items) {
appendItemToList(it); appendItemToList(it);
@ -301,6 +607,10 @@ void VSearchUE::handleSearchItemsAdded(const QList<QSharedPointer<VSearchResultI
} }
case ID::Content_Note_AllNotebook: case ID::Content_Note_AllNotebook:
case ID::Content_Note_CurrentNotebook:
case ID::Content_Note_CurrentFolder:
case ID::Content_Note_Buffer:
case ID::Outline_Note_Buffer:
{ {
for (auto const & it : p_items) { for (auto const & it : p_items) {
appendItemToTree(it); appendItemToTree(it);
@ -536,6 +846,11 @@ void VSearchUE::selectNextItem(int p_id, bool p_forward)
switch (p_id) { switch (p_id) {
case ID::Name_Notebook_AllNotebook: case ID::Name_Notebook_AllNotebook:
case ID::Name_FolderNote_AllNotebook: case ID::Name_FolderNote_AllNotebook:
case ID::Name_FolderNote_CurrentNotebook:
case ID::Name_FolderNote_CurrentFolder:
case ID::Name_Note_Buffer:
case ID::Path_FolderNote_AllNotebook:
case ID::Path_FolderNote_CurrentNotebook:
{ {
// Could not use postEvent method here which will induce infinite recursion. // Could not use postEvent method here which will induce infinite recursion.
m_listWidget->selectNextItem(p_forward); m_listWidget->selectNextItem(p_forward);
@ -543,6 +858,10 @@ void VSearchUE::selectNextItem(int p_id, bool p_forward)
} }
case ID::Content_Note_AllNotebook: case ID::Content_Note_AllNotebook:
case ID::Content_Note_CurrentNotebook:
case ID::Content_Note_CurrentFolder:
case ID::Content_Note_Buffer:
case ID::Outline_Note_Buffer:
{ {
m_treeWidget->selectNextItem(p_forward); m_treeWidget->selectNextItem(p_forward);
break; break;
@ -558,12 +877,21 @@ void VSearchUE::activate(int p_id)
switch (p_id) { switch (p_id) {
case ID::Name_Notebook_AllNotebook: case ID::Name_Notebook_AllNotebook:
case ID::Name_FolderNote_AllNotebook: case ID::Name_FolderNote_AllNotebook:
case ID::Name_FolderNote_CurrentNotebook:
case ID::Name_FolderNote_CurrentFolder:
case ID::Name_Note_Buffer:
case ID::Path_FolderNote_AllNotebook:
case ID::Path_FolderNote_CurrentNotebook:
{ {
activateItem(m_listWidget->currentItem()); activateItem(m_listWidget->currentItem());
break; break;
} }
case ID::Content_Note_AllNotebook: case ID::Content_Note_AllNotebook:
case ID::Content_Note_CurrentNotebook:
case ID::Content_Note_CurrentFolder:
case ID::Content_Note_Buffer:
case ID::Outline_Note_Buffer:
{ {
activateItem(m_treeWidget->currentItem(), 0); activateItem(m_treeWidget->currentItem(), 0);
break; break;

View File

@ -29,6 +29,33 @@ public:
// Search content of the note in all the notebooks. // Search content of the note in all the notebooks.
Content_Note_AllNotebook, Content_Note_AllNotebook,
// Search the name of the folder/note in current notebook.
Name_FolderNote_CurrentNotebook,
// Search content of the note in current notebook.
Content_Note_CurrentNotebook,
// Search the name of the folder/note in current folder.
Name_FolderNote_CurrentFolder,
// Search content of the note in current folder.
Content_Note_CurrentFolder,
// List and search the name of opened notes in buffer.
Name_Note_Buffer,
// Search content of opened notes in buffer.
Content_Note_Buffer,
// Search outline of opened notes in buffer.
Outline_Note_Buffer,
// Search path of folder/note in all the notebooks.
Path_FolderNote_AllNotebook,
// Search path of folder/note in current notebook.
Path_FolderNote_CurrentNotebook
}; };
explicit VSearchUE(QObject *p_parent = nullptr); explicit VSearchUE(QObject *p_parent = nullptr);
@ -68,8 +95,26 @@ private:
void searchNameOfFolderNoteInAllNotebooks(const QString &p_cmd); void searchNameOfFolderNoteInAllNotebooks(const QString &p_cmd);
void searchNameOfFolderNoteInCurrentNotebook(const QString &p_cmd);
void searchNameOfFolderNoteInCurrentFolder(const QString &p_cmd);
void searchContentOfNoteInAllNotebooks(const QString &p_cmd); void searchContentOfNoteInAllNotebooks(const QString &p_cmd);
void searchContentOfNoteInCurrentNotebook(const QString &p_cmd);
void searchContentOfNoteInCurrentFolder(const QString &p_cmd);
void searchNameOfBuffer(const QString &p_cmd);
void searchContentOfBuffer(const QString &p_cmd);
void searchOutlineOfBuffer(const QString &p_cmd);
void searchPathOfFolderNoteInAllNotebooks(const QString &p_cmd);
void searchPathOfFolderNoteInCurrentNotebook(const QString &p_cmd);
// Stop the search synchronously. // Stop the search synchronously.
void stopSearch(); void stopSearch();

View File

@ -21,6 +21,7 @@
#define MINIMUM_WIDTH 200 #define MINIMUM_WIDTH 200
#define CMD_EDIT_INTERVAL 500 #define CMD_EDIT_INTERVAL 500
#define CMD_EDIT_IDLE_INTERVAL 200
extern VPalette *g_palette; extern VPalette *g_palette;
@ -105,9 +106,13 @@ void VUniversalEntry::setupUI()
m_cmdEdit->setCtrlKEnabled(false); m_cmdEdit->setCtrlKEnabled(false);
m_cmdEdit->setCtrlEEnabled(false); m_cmdEdit->setCtrlEEnabled(false);
connect(m_cmdEdit, &VMetaWordLineEdit::textEdited, connect(m_cmdEdit, &VMetaWordLineEdit::textEdited,
this, [this]() { this, [this](const QString &p_text) {
m_cmdTimer->stop(); m_cmdTimer->stop();
m_cmdTimer->start(); if (p_text.isEmpty() || p_text.size() == 1) {
m_cmdTimer->start(CMD_EDIT_IDLE_INTERVAL);
} else {
m_cmdTimer->start(CMD_EDIT_INTERVAL);
}
}); });
m_container = new VUniversalEntryContainer(this); m_container = new VUniversalEntryContainer(this);
@ -293,8 +298,8 @@ void VUniversalEntry::keyPressEvent(QKeyEvent *p_event)
// Ctrl+E to eliminate input except the command key. // Ctrl+E to eliminate input except the command key.
QString cmd = m_cmdEdit->getEvaluatedText(); QString cmd = m_cmdEdit->getEvaluatedText();
if (!cmd.isEmpty()) { if (!cmd.isEmpty()) {
m_cmdEdit->setText(cmd.left(1));
m_cmdTimer->stop(); m_cmdTimer->stop();
m_cmdEdit->setText(cmd.left(1));
processCommand(); processCommand();
return; return;
} }