OSDN Git Service

ノートコンテンツをwordテーブルに登録しないように変更。
authoryuki <kimaira7@gmail.com>
Wed, 10 Jul 2013 07:52:59 +0000 (16:52 +0900)
committeryuki <kimaira7@gmail.com>
Wed, 10 Jul 2013 07:52:59 +0000 (16:52 +0900)
キーワード検索でwordテーブルのResourceも表示できるように変更。
設定ページの索引wildcardを削除。

src/cx/fbn/nevernote/Global.java
src/cx/fbn/nevernote/NeverNote.java
src/cx/fbn/nevernote/dialog/ConfigDialog.java
src/cx/fbn/nevernote/dialog/ConfigIndexPage.java
src/cx/fbn/nevernote/sql/REnSearch.java
src/cx/fbn/nevernote/threads/IndexRunner.java

index 239520f..f73ea0a 100644 (file)
@@ -2019,27 +2019,27 @@ public class Global {
     }
     
     // If we should automatically wildcard searches
     }
     
     // If we should automatically wildcard searches
-    public static boolean automaticWildcardSearches() {
-               settings.beginGroup("General");
-               try {
-                       String value = (String)settings.value("automaticWildcard", "false");
-                       settings.endGroup();
-                       if (value.equals("true"))
-                               return true;
-                       else
-                               return false;
-               } catch (java.lang.ClassCastException e) {
-                       Boolean value = (Boolean) settings.value("automaticWildcard", false);
-                       settings.endGroup();
-                       return value;
-               }
-
-    }
-    public static void setAutomaticWildcardSearches(boolean value) {
-               settings.beginGroup("General");
-               settings.setValue("automaticWildcard", value);
-               settings.endGroup();    
-    }
+//    public static boolean automaticWildcardSearches() {
+//             settings.beginGroup("General");
+//             try {
+//                     String value = (String)settings.value("automaticWildcard", "false");
+//                     settings.endGroup();
+//                     if (value.equals("true"))
+//                             return true;
+//                     else
+//                             return false;
+//             } catch (java.lang.ClassCastException e) {
+//                     Boolean value = (Boolean) settings.value("automaticWildcard", false);
+//                     settings.endGroup();
+//                     return value;
+//             }
+//
+//    }
+//    public static void setAutomaticWildcardSearches(boolean value) {
+//             settings.beginGroup("General");
+//             settings.setValue("automaticWildcard", value);
+//             settings.endGroup();    
+//    }
 
     // If we should automatically select the children of any tag
     public static boolean displayRightToLeft() {
 
     // If we should automatically select the children of any tag
     public static boolean displayRightToLeft() {
index 57a014a..1607030 100644 (file)
@@ -453,8 +453,8 @@ public class NeverNote extends QMainWindow{
                indexThread = new QThread(indexRunner, "Index Thread");
         indexRunner.indexAttachmentsLocally = Global.indexAttachmentsLocally();
         indexRunner.indexImageRecognition = Global.indexImageRecognition();
                indexThread = new QThread(indexRunner, "Index Thread");
         indexRunner.indexAttachmentsLocally = Global.indexAttachmentsLocally();
         indexRunner.indexImageRecognition = Global.indexImageRecognition();
-        indexRunner.indexNoteBody = Global.indexNoteBody();
-        indexRunner.indexNoteTitle = Global.indexNoteTitle();
+//        indexRunner.indexNoteBody = Global.indexNoteBody();
+//        indexRunner.indexNoteTitle = Global.indexNoteTitle();
         indexRunner.specialIndexCharacters = Global.getSpecialIndexCharacters();
                indexThread.start();
                
         indexRunner.specialIndexCharacters = Global.getSpecialIndexCharacters();
                indexThread.start();
                
@@ -1461,8 +1461,8 @@ public class NeverNote extends QMainWindow{
         
         settings.exec();
         indexRunner.indexAttachmentsLocally = Global.indexAttachmentsLocally();
         
         settings.exec();
         indexRunner.indexAttachmentsLocally = Global.indexAttachmentsLocally();
-        indexRunner.indexNoteBody = Global.indexNoteBody();
-        indexRunner.indexNoteTitle = Global.indexNoteTitle();
+//        indexRunner.indexNoteBody = Global.indexNoteBody();
+//        indexRunner.indexNoteTitle = Global.indexNoteTitle();
         indexRunner.specialIndexCharacters = Global.getSpecialIndexCharacters();
         indexRunner.indexImageRecognition = Global.indexImageRecognition();
         if (Global.showTrayIcon() || Global.minimizeOnClose())
         indexRunner.specialIndexCharacters = Global.getSpecialIndexCharacters();
         indexRunner.indexImageRecognition = Global.indexImageRecognition();
         if (Global.showTrayIcon() || Global.minimizeOnClose())
index 98ec261..2613102 100644 (file)
@@ -179,7 +179,7 @@ public class ConfigDialog extends QDialog {
                Global.setIndexNoteBody(indexPage.getIndexNoteBody());\r
                Global.setIndexNoteTitle(indexPage.getIndexNoteTitle());\r
                Global.setIndexImageRecognition(indexPage.getIndexImageRecognition());\r
                Global.setIndexNoteBody(indexPage.getIndexNoteBody());\r
                Global.setIndexNoteTitle(indexPage.getIndexNoteTitle());\r
                Global.setIndexImageRecognition(indexPage.getIndexImageRecognition());\r
-               Global.setAutomaticWildcardSearches(indexPage.getAutomaticWildcardSearches());\r
+//             Global.setAutomaticWildcardSearches(indexPage.getAutomaticWildcardSearches());\r
                Global.setSpecialIndexCharacters(indexPage.getSpecialCharacters());\r
                Global.setIncludeTagChildren(appearancePage.getIncludeTagChildren());\r
                Global.setDisplayRightToLeft(appearancePage.getDisplayRightToLeft());\r
                Global.setSpecialIndexCharacters(indexPage.getSpecialCharacters());\r
                Global.setIncludeTagChildren(appearancePage.getIncludeTagChildren());\r
                Global.setDisplayRightToLeft(appearancePage.getDisplayRightToLeft());\r
index cad505a..3d1ec9b 100644 (file)
@@ -44,7 +44,7 @@ public class ConfigIndexPage extends QWidget {
        private final QCheckBox indexAttachmentsLocally;\r
        private final QCheckBox indexImageRecognition;\r
        private final QCheckBox indexTitle;\r
        private final QCheckBox indexAttachmentsLocally;\r
        private final QCheckBox indexImageRecognition;\r
        private final QCheckBox indexTitle;\r
-       private final QCheckBox automaticWildcard;\r
+//     private final QCheckBox automaticWildcard;\r
        private final QLineEdit specialStrip;\r
        private final QCheckBox indexBody;\r
        private final QLineEdit regexEdit;\r
        private final QLineEdit specialStrip;\r
        private final QCheckBox indexBody;\r
        private final QLineEdit regexEdit;\r
@@ -76,8 +76,8 @@ public class ConfigIndexPage extends QWidget {
                indexImageRecognition = new QCheckBox(tr("Index Image Recognition"));\r
                indexImageRecognition.setChecked(Global.indexImageRecognition());\r
                \r
                indexImageRecognition = new QCheckBox(tr("Index Image Recognition"));\r
                indexImageRecognition.setChecked(Global.indexImageRecognition());\r
                \r
-               automaticWildcard = new QCheckBox(tr("Automatically Wildcard All Searches"));\r
-               automaticWildcard.setChecked(Global.automaticWildcardSearches());\r
+//             automaticWildcard = new QCheckBox(tr("Automatically Wildcard All Searches"));\r
+//             automaticWildcard.setChecked(Global.automaticWildcardSearches());\r
                \r
                specialStrip = new QLineEdit();\r
                specialStrip.setText(Global.getSpecialIndexCharacters());\r
                \r
                specialStrip = new QLineEdit();\r
                specialStrip.setText(Global.getSpecialIndexCharacters());\r
@@ -87,7 +87,7 @@ public class ConfigIndexPage extends QWidget {
                attachmentLayout.addWidget(indexTitle);\r
                attachmentLayout.addWidget(indexAttachmentsLocally);\r
                attachmentLayout.addWidget(indexImageRecognition);\r
                attachmentLayout.addWidget(indexTitle);\r
                attachmentLayout.addWidget(indexAttachmentsLocally);\r
                attachmentLayout.addWidget(indexImageRecognition);\r
-               attachmentLayout.addWidget(automaticWildcard);\r
+//             attachmentLayout.addWidget(automaticWildcard);\r
                \r
                QHBoxLayout specialCharLayout = new QHBoxLayout();\r
                specialCharLayout.addWidget(new QLabel(tr("Special Word Characters")));\r
                \r
                QHBoxLayout specialCharLayout = new QHBoxLayout();\r
                specialCharLayout.addWidget(new QLabel(tr("Special Word Characters")));\r
@@ -150,9 +150,9 @@ public class ConfigIndexPage extends QWidget {
        public boolean getIndexImageRecognition() {\r
                return indexImageRecognition.isChecked();\r
        }\r
        public boolean getIndexImageRecognition() {\r
                return indexImageRecognition.isChecked();\r
        }\r
-       public boolean getAutomaticWildcardSearches() {\r
-               return automaticWildcard.isChecked();\r
-       }\r
+//     public boolean getAutomaticWildcardSearches() {\r
+//             return automaticWildcard.isChecked();\r
+//     }\r
        \r
        //*****************************************\r
        //* Word length get/set methods \r
        \r
        //*****************************************\r
        //* Word length get/set methods \r
index bafb04b..9dccbd6 100644 (file)
@@ -33,7 +33,6 @@ import com.evernote.edam.type.Note;
 import com.evernote.edam.type.Notebook;\r
 import com.evernote.edam.type.Tag;\r
 \r
 import com.evernote.edam.type.Notebook;\r
 import com.evernote.edam.type.Tag;\r
 \r
-import cx.fbn.nevernote.Global;\r
 import cx.fbn.nevernote.sql.driver.NSqlQuery;\r
 import cx.fbn.nevernote.utilities.ApplicationLogger;\r
 \r
 import cx.fbn.nevernote.sql.driver.NSqlQuery;\r
 import cx.fbn.nevernote.utilities.ApplicationLogger;\r
 \r
@@ -392,16 +391,16 @@ public class REnSearch {
                                searchPhrases.add(word.toLowerCase());\r
                        }\r
                        if (!searchPhrase && pos < 0) {\r
                                searchPhrases.add(word.toLowerCase());\r
                        }\r
                        if (!searchPhrase && pos < 0) {\r
-                               if (word != null && word.length() > 0 && !Global.automaticWildcardSearches())\r
+                               if (word != null && word.length() > 0/* && !Global.automaticWildcardSearches()*/)\r
                                        getWords().add(word); \r
                                        getWords().add(word); \r
-                               if (word != null && word.length() > 0 && Global.automaticWildcardSearches()) {\r
-                                       String wildcardWord = word;\r
-                                       if (!wildcardWord.startsWith("*"))\r
-                                               wildcardWord = "*"+wildcardWord;\r
-                                       if (!wildcardWord.endsWith("*"))\r
-                                               wildcardWord = wildcardWord+"*";\r
-                                       getWords().add(wildcardWord); \r
-                               }\r
+//                             if (word != null && word.length() > 0 && Global.automaticWildcardSearches()) {\r
+//                                     String wildcardWord = word;\r
+//                                     if (!wildcardWord.startsWith("*"))\r
+//                                             wildcardWord = "*"+wildcardWord;\r
+//                                     if (!wildcardWord.endsWith("*"))\r
+//                                             wildcardWord = wildcardWord+"*";\r
+//                                     getWords().add(wildcardWord); \r
+//                             }\r
 //                             getWords().add("*"+word+"*");           //// WILDCARD\r
                        }\r
                        if (word.startsWith("intitle:")) \r
 //                             getWords().add("*"+word+"*");           //// WILDCARD\r
                        }\r
                        if (word.startsWith("intitle:")) \r
@@ -702,7 +701,7 @@ public class REnSearch {
                }\r
 \r
                NSqlQuery insertQuery = new NSqlQuery(conn.getConnection());\r
                }\r
 \r
                NSqlQuery insertQuery = new NSqlQuery(conn.getConnection());\r
-//             NSqlQuery indexQuery = new NSqlQuery(conn.getIndexConnection());\r
+               NSqlQuery indexQuery = new NSqlQuery(conn.getIndexConnection());\r
                NSqlQuery mergeQuery = new NSqlQuery(conn.getConnection());\r
                NSqlQuery deleteQuery = new NSqlQuery(conn.getConnection());\r
                NSqlQuery ftlQuery = new NSqlQuery(conn.getConnection());\r
                NSqlQuery mergeQuery = new NSqlQuery(conn.getConnection());\r
                NSqlQuery deleteQuery = new NSqlQuery(conn.getConnection());\r
                NSqlQuery ftlQuery = new NSqlQuery(conn.getConnection());\r
@@ -713,20 +712,32 @@ public class REnSearch {
                \r
                if (subSelect) {\r
                        for (int i=0; i<getWords().size(); i++) {\r
                \r
                if (subSelect) {\r
                        for (int i=0; i<getWords().size(); i++) {\r
-//                             if (getWords().get(i).indexOf("*") == -1) {\r
-//                                     indexQuery.prepare("Select distinct guid from words where weight >= " +minimumRecognitionWeight +\r
-//                                                     " and word=:word");\r
-//                                     indexQuery.bindValue(":word", getWords().get(i));\r
-//                             } else {\r
-//                                     indexQuery.prepare("Select distinct guid from words where weight >= " +minimumRecognitionWeight +\r
-//                                             " and word like :word");\r
-//                                     indexQuery.bindValue(":word", getWords().get(i).replace("*", "%"));\r
-//                             }\r
+                               // wordsテーブルから検索\r
+                               if (getWords().get(i).indexOf("*") == -1) {\r
+                                       indexQuery.prepare("Select distinct guid from words where weight >= " +minimumRecognitionWeight +\r
+                                                       " and word=:word");\r
+                                       indexQuery.bindValue(":word", getWords().get(i));\r
+                               } else {\r
+                                       indexQuery.prepare("Select distinct guid from words where weight >= " +minimumRecognitionWeight +\r
+                                               " and word like :word");\r
+                                       indexQuery.bindValue(":word", getWords().get(i).replace("*", "%"));\r
+                               }\r
+                               indexQuery.exec();\r
+                               String guid = null;\r
+                               while(indexQuery.next()) {\r
+                                       guid = indexQuery.valueString(0);\r
+                                       if (i==0 || any) {\r
+                                               insertQuery.bindValue(":guid", guid);\r
+                                               insertQuery.exec();\r
+                                       } else {\r
+                                               mergeQuery.bindValue(":guid", guid);\r
+                                               mergeQuery.exec();\r
+                                       }\r
+                               }\r
                                \r
                                \r
+                               // luceneによる全文検索\r
                                ftlQuery.bindValue(":text", getWords().get(i));\r
                                ftlQuery.exec();\r
                                ftlQuery.bindValue(":text", getWords().get(i));\r
                                ftlQuery.exec();\r
-                               \r
-                               String guid = null;\r
                                while(ftlQuery.next()) {\r
                                        guid = ftlQuery.valueString(0);\r
                                        if (i==0 || any) {\r
                                while(ftlQuery.next()) {\r
                                        guid = ftlQuery.valueString(0);\r
                                        if (i==0 || any) {\r
@@ -737,6 +748,7 @@ public class REnSearch {
                                                mergeQuery.exec();\r
                                        }\r
                                }\r
                                                mergeQuery.exec();\r
                                        }\r
                                }\r
+                               \r
                                if (i>0 && !any) {\r
                                        deleteQuery.exec("Delete from SEARCH_RESULTS where guid not in (select guid from SEARCH_RESULTS_MERGE)");\r
                                        deleteQuery.exec("Delete from SEARCH_RESULTS_MERGE");\r
                                if (i>0 && !any) {\r
                                        deleteQuery.exec("Delete from SEARCH_RESULTS where guid not in (select guid from SEARCH_RESULTS_MERGE)");\r
                                        deleteQuery.exec("Delete from SEARCH_RESULTS_MERGE");\r
index c6a8dc3..abb7a86 100644 (file)
@@ -30,7 +30,6 @@ import java.util.TreeSet;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.locks.LockSupport;
 
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.locks.LockSupport;
 
-import org.apache.commons.lang3.StringEscapeUtils;
 import org.apache.tika.exception.TikaException;
 import org.apache.tika.metadata.Metadata;
 import org.apache.tika.parser.ParseContext;
 import org.apache.tika.exception.TikaException;
 import org.apache.tika.metadata.Metadata;
 import org.apache.tika.parser.ParseContext;
@@ -44,7 +43,6 @@ import org.xml.sax.ContentHandler;
 import org.xml.sax.SAXException;
 
 import com.evernote.edam.type.Data;
 import org.xml.sax.SAXException;
 
 import com.evernote.edam.type.Data;
-import com.evernote.edam.type.Note;
 import com.evernote.edam.type.Resource;
 import com.trolltech.qt.core.QByteArray;
 import com.trolltech.qt.core.QIODevice.OpenModeFlag;
 import com.evernote.edam.type.Resource;
 import com.trolltech.qt.core.QByteArray;
 import com.trolltech.qt.core.QIODevice.OpenModeFlag;
@@ -76,8 +74,8 @@ public class IndexRunner extends QObject implements Runnable {
        private final QDomDocument                      doc;
        private static String                           regex = Global.getWordRegex();
        public String                                           specialIndexCharacters = "";
        private final QDomDocument                      doc;
        private static String                           regex = Global.getWordRegex();
        public String                                           specialIndexCharacters = "";
-       public boolean                                          indexNoteBody = true;
-       public boolean                                          indexNoteTitle = true;
+//     public boolean                                          indexNoteBody = true;
+//     public boolean                                          indexNoteTitle = true;
        public boolean                                          indexImageRecognition = true;
        private final DatabaseConnection        conn;
        private volatile LinkedBlockingQueue<String> workQueue;
        public boolean                                          indexImageRecognition = true;
        private final DatabaseConnection        conn;
        private volatile LinkedBlockingQueue<String> workQueue;
@@ -163,62 +161,62 @@ public class IndexRunner extends QObject implements Runnable {
        }
        
        // Reindex a note
        }
        
        // Reindex a note
-       public void indexNoteContent() {
-               foundWords.clear();
-               
-               logger.log(logger.EXTREME, "Entering indexRunner.indexNoteContent()");
-               
-               logger.log(logger.EXTREME, "Getting note content");
-               Note n = conn.getNoteTable().getNote(guid,true,false,true,true, true);
-               String data;
-               if (indexNoteBody) {
-                       data = n.getContent();
-                       data = conn.getNoteTable().getNoteContentNoUTFConversion(n.getGuid());
-               
-                       logger.log(logger.EXTREME, "Removing any encrypted data");
-                       data = removeEnCrypt(data.toString());
-                       logger.log(logger.EXTREME, "Removing xml markups");
-               } else
-                       data = "";
-               String text;
-               if (indexNoteTitle)
-                       text =  removeTags(StringEscapeUtils.unescapeHtml4(data) +" "+ n.getTitle());
-               else
-                       text = removeTags(StringEscapeUtils.unescapeHtml4(data));
-                               
-               logger.log(logger.EXTREME, "Splitting words");
-               String[] result = text.toString().split(regex);
-               conn.commitTransaction();
-               conn.beginTransaction();
-               logger.log(logger.EXTREME, "Deleting existing words for note from index");
-               conn.getWordsTable().expungeFromWordIndex(guid, "CONTENT");
-               
-               logger.log(logger.EXTREME, "Number of words found: " +result.length);
-               for (int j=0; j<result.length && keepRunning; j++) {
-                       if (interrupt) {
-                               processInterrupt();
-                       }
-                       if (!result[j].trim().equals("")) {
-                               logger.log(logger.EXTREME, "Result word: " +result[j].trim());
-                               addToIndex(guid, result[j], "CONTENT");
-                       }
-               }
-               
-               // Add tags
-               for (int j=0; j<n.getTagNamesSize(); j++) {
-                       if (n.getTagNames() != null && n.getTagNames().get(j) != null && !n.getTagNames().get(j).trim().equals(""))
-                               addToIndex(guid, n.getTagNames().get(j), "CONTENT");
-               }
-               
-               // If we were interrupted, we will reindex this note next time
-               if (Global.keepRunning) {
-                       logger.log(logger.EXTREME, "Resetting note guid needed");
-                       conn.getNoteTable().setIndexNeeded(guid, false);
-               } 
-               conn.commitTransaction();
-               uncommittedCount = 0;
-               logger.log(logger.EXTREME, "Leaving indexRunner.indexNoteContent()");
-       }
+//     public void indexNoteContent() {
+//             foundWords.clear();
+//             
+//             logger.log(logger.EXTREME, "Entering indexRunner.indexNoteContent()");
+//             
+//             logger.log(logger.EXTREME, "Getting note content");
+//             Note n = conn.getNoteTable().getNote(guid,true,false,true,true, true);
+//             String data;
+//             if (indexNoteBody) {
+//                     data = n.getContent();
+//                     data = conn.getNoteTable().getNoteContentNoUTFConversion(n.getGuid());
+//             
+//                     logger.log(logger.EXTREME, "Removing any encrypted data");
+//                     data = removeEnCrypt(data.toString());
+//                     logger.log(logger.EXTREME, "Removing xml markups");
+//             } else
+//                     data = "";
+//             String text;
+//             if (indexNoteTitle)
+//                     text =  removeTags(StringEscapeUtils.unescapeHtml4(data) +" "+ n.getTitle());
+//             else
+//                     text = removeTags(StringEscapeUtils.unescapeHtml4(data));
+//                             
+//             logger.log(logger.EXTREME, "Splitting words");
+//             String[] result = text.toString().split(regex);
+//             conn.commitTransaction();
+//             conn.beginTransaction();
+//             logger.log(logger.EXTREME, "Deleting existing words for note from index");
+//             conn.getWordsTable().expungeFromWordIndex(guid, "CONTENT");
+//             
+//             logger.log(logger.EXTREME, "Number of words found: " +result.length);
+//             for (int j=0; j<result.length && keepRunning; j++) {
+//                     if (interrupt) {
+//                             processInterrupt();
+//                     }
+//                     if (!result[j].trim().equals("")) {
+//                             logger.log(logger.EXTREME, "Result word: " +result[j].trim());
+//                             addToIndex(guid, result[j], "CONTENT");
+//                     }
+//             }
+//             
+//             // Add tags
+//             for (int j=0; j<n.getTagNamesSize(); j++) {
+//                     if (n.getTagNames() != null && n.getTagNames().get(j) != null && !n.getTagNames().get(j).trim().equals(""))
+//                             addToIndex(guid, n.getTagNames().get(j), "CONTENT");
+//             }
+//             
+//             // If we were interrupted, we will reindex this note next time
+//             if (Global.keepRunning) {
+//                     logger.log(logger.EXTREME, "Resetting note guid needed");
+//                     conn.getNoteTable().setIndexNeeded(guid, false);
+//             } 
+//             conn.commitTransaction();
+//             uncommittedCount = 0;
+//             logger.log(logger.EXTREME, "Leaving indexRunner.indexNoteContent()");
+//     }
        
        
        private String removeTags(String text) {
        
        
        private String removeTags(String text) {
@@ -660,22 +658,22 @@ public class IndexRunner extends QObject implements Runnable {
        }
        
        private void scanUnindexed() {
        }
        
        private void scanUnindexed() {
-               List<String> notes = conn.getNoteTable().getUnindexed();
+//             List<String> notes = conn.getNoteTable().getUnindexed();
                guid = null;
                boolean started = false;
                guid = null;
                boolean started = false;
-               if (notes.size() > 0) {
-                       signal.indexStarted.emit();
-                       started = true;
-               }
-               for (int i=0; i<notes.size() && keepRunning; i++) {
-                       if (interrupt) {
-                               processInterrupt();
-                       }
-                       guid = notes.get(i);
-                       if (guid != null && keepRunning) {
-                               indexNoteContent();
-                       }
-               }
+//             if (notes.size() > 0) {
+//                     signal.indexStarted.emit();
+//                     started = true;
+//             }
+//             for (int i=0; i<notes.size() && keepRunning; i++) {
+//                     if (interrupt) {
+//                             processInterrupt();
+//                     }
+//                     guid = notes.get(i);
+//                     if (guid != null && keepRunning) {
+//                             indexNoteContent();
+//                     }
+//             }
                
                List<String> unindexedResources = conn.getNoteTable().noteResourceTable.getUnindexed();
                if (unindexedResources.size() > 0 && !started) {
                
                List<String> unindexedResources = conn.getNoteTable().noteResourceTable.getUnindexed();
                if (unindexedResources.size() > 0 && !started) {