beagle r4740 - in trunk/beagle: . Util tools



Author: dbera
Date: Thu May  1 01:11:53 2008
New Revision: 4740
URL: http://svn.gnome.org/viewvc/beagle?rev=4740&view=rev

Log:
Add the google backend related options to beagle-settings-qt.
* KdeUtils.cs: Fix a bug during storing passwords in kdewallet.
* beagle/tools/beagle-settings-qt.ui, beagle/tools/SettingsQt.cs, beagle/tools/Makefile.am: Add google backend specific options. Disable the whole tab when build without google backend support.
* configure.in: Some distributions do not ship qyoto.pc; fallback on checking presence of qt-dotnet.dll. This should cover most of the mainline distros.


Modified:
   trunk/beagle/Util/KdeUtils.cs
   trunk/beagle/configure.in
   trunk/beagle/tools/Makefile.am
   trunk/beagle/tools/SettingsQt.cs
   trunk/beagle/tools/beagle-settings-qt.ui

Modified: trunk/beagle/Util/KdeUtils.cs
==============================================================================
--- trunk/beagle/Util/KdeUtils.cs	(original)
+++ trunk/beagle/Util/KdeUtils.cs	Thu May  1 01:11:53 2008
@@ -211,7 +211,7 @@
 			pc.Start ();
 			string ret = null;
 			using (StreamReader pout = new StreamReader (pc.StandardOutput))
-				password = pout.ReadLine ();
+				ret = pout.ReadLine ();
 			pc.Close ();
 
 			if (ret != "0")

Modified: trunk/beagle/configure.in
==============================================================================
--- trunk/beagle/configure.in	(original)
+++ trunk/beagle/configure.in	Thu May  1 01:11:53 2008
@@ -572,16 +572,36 @@
 	enable_qt=$enableval,
 	enable_qt=no)
 
+QYOTO_ASSEMBLY=""
+
+dnl The location and detection is a mess; this would improve once Qyoto gets more attention
+dnl First try to locate qyoto.pc for Ubuntu and other sane distributions
 if test "x$enable_qt" != "xno"; then
 	PKG_CHECK_MODULES(QYOTO, qyoto >= 4.3.0, has_qyoto=yes, has_qyoto=no)
 	if test "x$enable_qt" = "xyes" -a "x$has_qyoto" != "xyes"; then
-		AC_MSG_ERROR([qyoto >= 4.3.0 not found])
+		AC_MSG_NOTICE([qyoto.pc >= 4.3.0 not found])
 	else
 		enable_qt=$has_qyoto
+		QYOTO_ASSEMBLY="-pkg:qyoto"
+	fi
+fi
+
+dnl Some distributions do not ship a qyoto.pc file (opensuse)
+dnl I hope checking the presence of the qt-dotnet.dll should be enough
+if test "x$enable_qt" != "xno" -a "x$has_qyoto" = "xno"; then
+	i="qt-dotnet"
+	AC_MSG_CHECKING([for $i.dll])
+	if test ! -e `$PKG_CONFIG --variable=prefix mono`/lib/mono/2.0/$i.dll; then
+		AC_MSG_ERROR([missing required mono DLL: $i.dll])
+	else
+		AC_MSG_RESULT([found])
+		QYOTO_ASSEMBLY="-r:qt-dotnet"
+		enable_qt="yes"
 	fi
 fi
 
 AM_CONDITIONAL(ENABLE_QT, test "x$enable_qt" = "xyes")
+AC_SUBST(QYOTO_ASSEMBLY)
 
 dnl ----------------------------------------------
 

Modified: trunk/beagle/tools/Makefile.am
==============================================================================
--- trunk/beagle/tools/Makefile.am	(original)
+++ trunk/beagle/tools/Makefile.am	Thu May  1 01:11:53 2008
@@ -113,6 +113,10 @@
 SETTINGS_CSFLAGS += -define:ENABLE_AVAHI
 endif
 
+if ENABLE_GOOGLEBACKENDS
+SETTINGS_CSFLAGS += -define:ENABLE_GOOGLEBACKENDS
+endif
+
 $(SETTINGS_TARGET): $(SETTINGS_CSFILES) $(SETTINGS_RESOURCES) $(LOCAL_ASSEMBLIES)
 	$(CSC) -out:$@ $(SETTINGS_RESOURCES_BUILD) $(CSFLAGS) $(SETTINGS_CSFLAGS) $(SETTINGS_CSFILES) $(ASSEMBLIES) $(SETTINGS_ASSEMBLIES)
 
@@ -125,14 +129,14 @@
 QT_SETTINGS_CSFILES = $(srcdir)/SettingsQt.cs
 QT_SETTINGS_UIFILE = $(srcdir)/beagle-settings-qt.ui
 QT_SETTINGS_UI_CSFILE = $(srcdir)/beagle-settings-qt.cs
-QT_SETTINGS_ASSEMBLIES = -r:../Util/Util.dll -pkg:qyoto
+QT_SETTINGS_ASSEMBLIES = -r:../Util/Util.dll $(QYOTO_ASSEMBLY)
 QT_SETTINGS_ICON = $(srcdir)/kerry.png
 
 $(QT_SETTINGS_UI_CSFILE): $(QT_SETTINGS_UIFILE)
 	uics $(QT_SETTINGS_UIFILE) -o $@
 
 $(QT_SETTINGS_TARGET): $(QT_SETTINGS_CSFILES) $(QT_SETTINGS_UI_CSFILE) $(LOCAL_ASSEMBLIES)
-	$(CSC) -out:$@ $(CSFLAGS) $(QT_SETTINGS_CSFILES) $(QT_SETTINGS_UI_CSFILE) $(ASSEMBLIES) $(QT_SETTINGS_ASSEMBLIES)
+	$(CSC) -out:$@ $(CSFLAGS) $(SETTINGS_CSFLAGS) $(QT_SETTINGS_CSFILES) $(QT_SETTINGS_UI_CSFILE) $(ASSEMBLIES) $(QT_SETTINGS_ASSEMBLIES)
 
 $(QT_SETTINGS_WRAPPER): $(WRAPPER_IN)
 	$(WRAPPER_SED) -e "s|\ target\@|$(QT_SETTINGS_TARGET)|g" < $(srcdir)/$(WRAPPER_IN) > $@

Modified: trunk/beagle/tools/SettingsQt.cs
==============================================================================
--- trunk/beagle/tools/SettingsQt.cs	(original)
+++ trunk/beagle/tools/SettingsQt.cs	Thu May  1 01:11:53 2008
@@ -1,3 +1,30 @@
+//
+// SettingsQt.cs
+// A Qt based beagle settings program.
+//
+// Copyright (C) 2008 D Bera <dbera web gmail com>
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+
 using System;
 using System.Reflection;
 using System.Collections.Generic;
@@ -8,7 +35,7 @@
 // Assembly information
 [assembly: AssemblyTitle ("beagle-settings-qt")]
 [assembly: AssemblyDescription ("Qt interface to the Beagle configuration options.")]
-[assembly: AssemblyCopyright ("Copyright (C) 2007 Debajyoti Bera <dbera web gmail com>")]
+[assembly: AssemblyCopyright ("Copyright (C) 2007-2008 Debajyoti Bera <dbera web gmail com>")]
 
 public class Settings {
 	public static void Main (string[] args)
@@ -38,10 +65,11 @@
 		string usage =
 			"Usage: beagle-settings-qt [OPTIONS]\n\n" +
 			"Options:\n" +
-			"--general    : Open the page with general options.\n" +
+			"--general    : Open the page with general options.(default)\n" +
 			"--indexing   : Open the page with indexing specific options.\n" +
 			"--backends   : Open the page with a list of backends to choose.\n" +
-			"--networking : Open the page with networking related options.\n\n";
+			"--networking : Open the page with networking related options.\n\n" +
+			"--google     : OPen the page with google backend specific options.\n\n";
 
 		Console.WriteLine (usage);
 
@@ -65,6 +93,7 @@
 		// create the checkbox mapping
 		backend_checkboxes = new Dictionary<string, QCheckBox> (20);
 		backend_checkboxes ["Files"] = main.filesBackend;
+		backend_checkboxes ["Locate"] = main.locateBackend;
 		backend_checkboxes ["KMail"] = main.kmailBackend;
 		backend_checkboxes ["EvolutionMail"] = main.evoBackend;
 		backend_checkboxes ["Thunderbird"] = main.tbirdBackend;
@@ -89,6 +118,7 @@
 		backend_checkboxes ["applications"] = main.appBackend;
 		backend_checkboxes ["manpages"] = main.manpagesBackend;
 		backend_checkboxes ["monodoc"] = main.monodocBackend;
+		backend_checkboxes ["GMailSearch"] = main.gmailLiveBackend;
 
 		Connect (main.CancelButton, SIGNAL ("clicked()"), qApp, SLOT ("quit()"));
 		Connect (main.OkButton, SIGNAL ("clicked()"), this, SLOT ("saveSettings()"));
@@ -100,6 +130,7 @@
 		Connect (main.PatternRemove, SIGNAL ("clicked()"), this, SLOT ("removeNamePattern()"));
 		Connect (main.MailFolderAdd, SIGNAL ("clicked()"), this, SLOT ("addFolderPattern()"));
 		Connect (main.MailFolderRemove, SIGNAL ("clicked()"), this, SLOT ("removeFolderPattern()"));
+		Connect (main.IsGoogleAppsAccount, SIGNAL ("stateChanged(int)"), this, SLOT ("isGoogleAppsToggled(int)"));
 
 		LoadSettings ();
 
@@ -112,6 +143,8 @@
 			main.TabWidget.SetCurrentWidget (main.BackendsTab);
 		else if (Array.IndexOf (args, "--networking") != -1)
 			main.TabWidget.SetCurrentWidget (main.NetworkingTab);
+		else if (Array.IndexOf (args, "--google") != -1)
+			main.TabWidget.SetCurrentWidget (main.GoogleTab);
 		else
 			main.TabWidget.SetCurrentWidget (main.GeneralTab);
 	}
@@ -159,6 +192,64 @@
 				backend_checkboxes [backend [0]].Checked = false;
 			}
 		}
+
+#if ENABLE_GOOGLEBACKENDS
+		LoadGoogleSettings ();
+#else
+		main.GoogleTab.SetDisabled (true);
+#endif
+	}
+
+	private void LoadGoogleSettings ()
+	{
+		Config google_config = Conf.Get ("GoogleBackends");
+		main.GMailSearchFolder.Text = google_config.GetOption ("GMailSearchFolder", null);
+
+		string username = google_config.GetOption ("GMailUsername", null);
+		if (! username.EndsWith ("@gmail.com"))
+			username = null;
+		else
+			main.GoogleUsername.Text = username.Remove (username.Length - 10);
+
+		string google_apps_domain = google_config.GetOption ("GoogleAppsAccountName", null);
+		if (google_apps_domain != null)
+			google_apps_domain = google_apps_domain.Trim ();
+		if (String.IsNullOrEmpty (google_apps_domain)) {
+			main.IsGoogleAppsAccount.Checked = false;
+			main.GoogleAppsAccountName.SetDisabled (true);
+		} else {
+			main.IsGoogleAppsAccount.Checked = true;
+			main.GoogleAppsAccountName.SetDisabled (false);
+			main.GoogleAppsAccountName.Text = google_apps_domain;
+		}
+
+		string password_source = google_config.GetOption ("GMailPasswordSource", "conf-file");
+		if (password_source == "gnome-keyring") {
+			QMessageBox.Critical (this, "Google password storage option", "Gnome keyring support not available from beagle-settings-qt");
+			return;
+		}
+
+		if (password_source == "kdewallet") {
+			if (String.IsNullOrEmpty (username))
+				return;
+
+			try {
+				string password = KdeUtils.ReadPasswordKDEWallet ("beagle", username);
+				main.GooglePassword.Text = password;
+				main.OptionStorePasswordKWallet.SetChecked (true);
+			} catch (ArgumentException e) {
+				QMessageBox.Warning (this, "KDEWallet", e.Message);
+			}
+			return;
+		}
+
+		if (password_source != "conf-file") {
+			QMessageBox.Warning (this, "Google password storage option", "Unknown password storage option.");
+			return;
+		}
+
+		main.GooglePassword.Text = google_config.GetOption ("GMailPassword", null);
+		main.OptionStorePasswordConf.SetChecked (true);
 	}
 
 	[Q_SLOT ("void saveSettings()")]
@@ -214,9 +305,44 @@
 		Conf.Save (daemon_config);
 		Conf.Save (networking_config);
 
+#if ENABLE_GOOGLEBACKENDS
+		SaveGoogleSettings ();
+#endif
+
 		QApplication.Quit ();
 	}
 
+	private void SaveGoogleSettings ()
+	{
+		Config google_config = Conf.Get ("GoogleBackends");
+		google_config.SetOption ("GMailSearchFolder", main.GMailSearchFolder.Text);
+
+		string username = main.GoogleUsername.Text.Trim ();
+		if (username != String.Empty) {
+			username = username + "@gmail.com";
+			google_config.SetOption ("GMailUsername", username);
+		}
+
+		if (main.IsGoogleAppsAccount.Checked)
+			google_config.SetOption ("GoogleAppsAccountName", main.GoogleAppsAccountName.Text);
+		else
+			google_config.SetOption ("GoogleAppsAccountName", String.Empty);
+
+		if (main.OptionStorePasswordConf.Checked) {
+			google_config.SetOption ("GMailPasswordSource", "conf-file");
+			google_config.SetOption ("GMailPassword", main.GooglePassword.Text);
+		} else if (main.OptionStorePasswordKWallet.Checked && ! String.IsNullOrEmpty (username)) {
+			try {
+				KdeUtils.StorePasswordKDEWallet ("beagle", username, main.GooglePassword.Text);
+				google_config.SetOption ("GMailPasswordSource", "kdewallet");
+			} catch (ArgumentException e) {
+				QMessageBox.Warning (this, "KDEWallet", e.Message);
+			}
+		}
+
+		Conf.Save (google_config);
+	}
+
 	[Q_SLOT ("showDirChooser()")]
 	private void ShowDirChooser ()
 	{
@@ -323,5 +449,16 @@
 
 		main.MailFolderList.TakeItem (main.MailFolderList.Row (folders [0]));
 	}
+
+	[Q_SLOT ("isGoogleAppsToggled(int)")]
+	private void IsGoogleAppsToggled (int _state)
+	{
+		Qt.CheckState state = (Qt.CheckState) Enum.ToObject (typeof (Qt.CheckState), _state);
+
+		if (state == Qt.CheckState.Unchecked)
+			main.GoogleAppsAccountName.SetDisabled (true);
+		else if (state == Qt.CheckState.Checked)
+			main.GoogleAppsAccountName.SetDisabled (false);
+	}
 }
 

Modified: trunk/beagle/tools/beagle-settings-qt.ui
==============================================================================
--- trunk/beagle/tools/beagle-settings-qt.ui	(original)
+++ trunk/beagle/tools/beagle-settings-qt.ui	Thu May  1 01:11:53 2008
@@ -23,7 +23,7 @@
    <item>
     <widget class="QTabWidget" name="TabWidget" >
      <property name="currentIndex" >
-      <number>3</number>
+      <number>4</number>
      </property>
      <widget class="QWidget" name="GeneralTab" >
       <attribute name="title" >
@@ -478,15 +478,23 @@
        <string>Backends</string>
       </attribute>
       <layout class="QVBoxLayout" >
-       <property name="bottomMargin" >
-        <number>0</number>
-       </property>
        <item>
-        <widget class="QCheckBox" name="filesBackend" >
-         <property name="text" >
-          <string>Files</string>
-         </property>
-        </widget>
+        <layout class="QHBoxLayout" >
+         <item>
+          <widget class="QCheckBox" name="filesBackend" >
+           <property name="text" >
+            <string>Files</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QCheckBox" name="locateBackend" >
+           <property name="text" >
+            <string>Supplement File backend results with matches from the 'locate' program</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
        </item>
        <item>
         <widget class="QGroupBox" name="groupBox_3" >
@@ -776,6 +784,13 @@
         </widget>
        </item>
        <item>
+        <widget class="Line" name="line" >
+         <property name="orientation" >
+          <enum>Qt::Horizontal</enum>
+         </property>
+        </widget>
+       </item>
+       <item>
         <widget class="QGroupBox" name="groupBox_8" >
          <property name="title" >
           <string>System backends </string>
@@ -873,6 +888,203 @@
        </item>
       </layout>
      </widget>
+     <widget class="QWidget" name="GoogleTab" >
+      <attribute name="title" >
+       <string>Google</string>
+      </attribute>
+      <attribute name="toolTip" >
+       <string>Settings for the Google backends</string>
+      </attribute>
+      <layout class="QVBoxLayout" >
+       <item>
+        <widget class="QCheckBox" name="gmailLiveBackend" >
+         <property name="text" >
+          <string>Enable live GMail search</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <layout class="QGridLayout" >
+         <item row="0" column="0" >
+          <widget class="QLabel" name="label_2" >
+           <property name="text" >
+            <string>Username</string>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="2" >
+          <widget class="QLabel" name="label" >
+           <property name="text" >
+            <string>@gmail.com</string>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="1" >
+          <widget class="QLineEdit" name="GoogleUsername" >
+           <property name="sizePolicy" >
+            <sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="minimumSize" >
+            <size>
+             <width>100</width>
+             <height>0</height>
+            </size>
+           </property>
+           <property name="maximumSize" >
+            <size>
+             <width>100</width>
+             <height>16777215</height>
+            </size>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="0" >
+          <widget class="QLabel" name="label_3" >
+           <property name="text" >
+            <string>Password</string>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="1" >
+          <widget class="QLineEdit" name="GooglePassword" >
+           <property name="sizePolicy" >
+            <sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="minimumSize" >
+            <size>
+             <width>100</width>
+             <height>0</height>
+            </size>
+           </property>
+           <property name="maximumSize" >
+            <size>
+             <width>100</width>
+             <height>16777215</height>
+            </size>
+           </property>
+           <property name="echoMode" >
+            <enum>QLineEdit::PasswordEchoOnEdit</enum>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="2" >
+          <widget class="QGroupBox" name="groupBox_9" >
+           <property name="sizePolicy" >
+            <sizepolicy vsizetype="Maximum" hsizetype="Maximum" >
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="title" >
+            <string/>
+           </property>
+           <property name="flat" >
+            <bool>true</bool>
+           </property>
+           <layout class="QHBoxLayout" >
+            <property name="leftMargin" >
+             <number>0</number>
+            </property>
+            <item>
+             <widget class="QLabel" name="label_4" >
+              <property name="text" >
+               <string>Stored in</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QRadioButton" name="OptionStorePasswordConf" >
+              <property name="text" >
+               <string>Plaintext in configuration file</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QRadioButton" name="OptionStorePasswordKWallet" >
+              <property name="text" >
+               <string>KDE Wallet</string>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </widget>
+         </item>
+         <item row="2" column="0" >
+          <widget class="QLabel" name="label_5" >
+           <property name="text" >
+            <string>IMAP folder to search</string>
+           </property>
+          </widget>
+         </item>
+         <item row="2" column="1" >
+          <widget class="QLineEdit" name="GMailSearchFolder" >
+           <property name="maximumSize" >
+            <size>
+             <width>100</width>
+             <height>16777215</height>
+            </size>
+           </property>
+           <property name="toolTip" >
+            <string>&lt;html>&lt;head>&lt;meta name="qrichtext" content="1" />&lt;style type="text/css">
+p, li { white-space: pre-wrap; }
+&lt;/style>&lt;/head>&lt;body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
+&lt;p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">You can only search one IMAP folder. To search in all emails use &lt;span style=" font-weight:600;">[GMail]/All Mail&lt;/span>&lt;/p>&lt;/body>&lt;/html></string>
+           </property>
+          </widget>
+         </item>
+         <item row="2" column="2" >
+          <spacer>
+           <property name="orientation" >
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" >
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+         <item row="3" column="0" >
+          <widget class="QCheckBox" name="IsGoogleAppsAccount" >
+           <property name="text" >
+            <string>Google Apps domain</string>
+           </property>
+          </widget>
+         </item>
+         <item row="3" column="1" >
+          <widget class="QLineEdit" name="GoogleAppsAccountName" >
+           <property name="maximumSize" >
+            <size>
+             <width>100</width>
+             <height>16777215</height>
+            </size>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
+       <item>
+        <spacer>
+         <property name="orientation" >
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeHint" >
+          <size>
+           <width>720</width>
+           <height>182</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+      </layout>
+     </widget>
     </widget>
    </item>
    <item>
@@ -948,6 +1160,7 @@
   <tabstop>MailFolderRemove</tabstop>
   <tabstop>MailFolderList</tabstop>
   <tabstop>filesBackend</tabstop>
+  <tabstop>locateBackend</tabstop>
   <tabstop>kmailBackend</tabstop>
   <tabstop>evoBackend</tabstop>
   <tabstop>tbirdBackend</tabstop>
@@ -973,6 +1186,12 @@
   <tabstop>manpagesBackend</tabstop>
   <tabstop>monodocBackend</tabstop>
   <tabstop>WebinterfaceOption</tabstop>
+  <tabstop>gmailLiveBackend</tabstop>
+  <tabstop>GoogleUsername</tabstop>
+  <tabstop>GooglePassword</tabstop>
+  <tabstop>OptionStorePasswordConf</tabstop>
+  <tabstop>OptionStorePasswordKWallet</tabstop>
+  <tabstop>GMailSearchFolder</tabstop>
   <tabstop>OkButton</tabstop>
   <tabstop>CancelButton</tabstop>
  </tabstops>



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]