[gdm: 55/70] Enable XDMCP configuration so it works. Previously only xdmcp/Enable was



commit 107279dcaf81826b261a8cc954b5ff139b549e92
Author: Brian Cameron <brian cameron sun com>
Date:   Tue Feb 17 19:44:59 2009 +0000

    Enable XDMCP configuration so it works. Previously only xdmcp/Enable was
    
    2009-02-17 Brian Cameron <brian cameron sun com>
    
            * common/gdm-settings-direct.[ch], common/gdm-settings-keys.h,
            daemon/gdm-simple-slave.c, daemon/gdm-xdmcp-chooser-slave.c,
            daemon/gdm-xdmcp-display-factory.c, data/gdm.schemas.in.in,
            docs/C/gdm.xml: Enable XDMCP configuration so it works.  Previously
            only xdmcp/Enable was being used in the code.  Also add support for
            chooser/Multicast and chooser/MulticastAddr configuration options.
            Now set the default values of MAX_DISPLAY_PER_HOST to 1 and MAX_WAIT to
            30 as specified in the docs.  Add a gdm_settings_direct_get_uint
            function to get unsigned integer configuration values more cleanly
            without the need to cast.  Fixes bug #569876.
    
    svn path=/trunk/; revision=6715
---
 ChangeLog                          |   13 ++++
 common/gdm-settings-direct.c       |   18 ++++++
 common/gdm-settings-direct.h       |    2 +
 common/gdm-settings-keys.h         |    7 +-
 daemon/gdm-simple-slave.c          |   10 +++-
 daemon/gdm-xdmcp-chooser-slave.c   |   10 +++-
 daemon/gdm-xdmcp-display-factory.c |   58 +++++++++++++++++-
 data/gdm.schemas.in.in             |   39 ++++--------
 docs/C/gdm.xml                     |  119 +++++++++++-------------------------
 9 files changed, 159 insertions(+), 117 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index acce993..f672282 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,18 @@
 2009-02-17 Brian Cameron <brian cameron sun com>
 
+	* common/gdm-settings-direct.[ch], common/gdm-settings-keys.h,
+	daemon/gdm-simple-slave.c, daemon/gdm-xdmcp-chooser-slave.c,
+	daemon/gdm-xdmcp-display-factory.c, data/gdm.schemas.in.in,
+	docs/C/gdm.xml: Enable XDMCP configuration so it works.  Previously
+	only xdmcp/Enable was being used in the code.  Also add support for
+	chooser/Multicast and chooser/MulticastAddr configuration options.
+	Now set the default values of MAX_DISPLAY_PER_HOST to 1 and MAX_WAIT to
+	30 as specified in the docs.  Add a gdm_settings_direct_get_uint
+	function to get unsigned integer configuration values more cleanly
+	without the need to cast.  Fixes bug #569876.
+
+2009-02-17 Brian Cameron <brian cameron sun com>
+
 	* daemon/gdm-xdmcp-display-factory.c: Remove double free.  Fixes bug
 	#565018.  Patch by William Jan Palenstijn <wjp usecode org>.
 
diff --git a/common/gdm-settings-direct.c b/common/gdm-settings-direct.c
index ebe80c4..a90eed2 100644
--- a/common/gdm-settings-direct.c
+++ b/common/gdm-settings-direct.c
@@ -125,6 +125,24 @@ gdm_settings_direct_get_int (const char        *key,
 }
 
 gboolean
+gdm_settings_direct_get_uint (const char        *key,
+                              uint              *value)
+{
+        gboolean          ret;
+        int               intvalue;
+
+        ret = FALSE;
+        ret = gdm_settings_direct_get_int (key, &intvalue);
+   
+        if (intvalue >= 0)
+           *value = intvalue;
+        else
+           ret = FALSE;
+
+        return ret;
+}
+
+gboolean
 gdm_settings_direct_get_boolean (const char        *key,
                                  gboolean          *value)
 {
diff --git a/common/gdm-settings-direct.h b/common/gdm-settings-direct.h
index feb97d5..0b391b3 100644
--- a/common/gdm-settings-direct.h
+++ b/common/gdm-settings-direct.h
@@ -38,6 +38,8 @@ gboolean              gdm_settings_direct_set                        (const char
                                                                       GValue            *value);
 gboolean              gdm_settings_direct_get_int                    (const char        *key,
                                                                       int               *value);
+gboolean              gdm_settings_direct_get_uint                   (const char        *key,
+                                                                      uint              *value);
 gboolean              gdm_settings_direct_get_boolean                (const char        *key,
                                                                       gboolean          *value);
 gboolean              gdm_settings_direct_get_string                 (const char        *key,
diff --git a/common/gdm-settings-keys.h b/common/gdm-settings-keys.h
index 081b2b2..3b8016e 100644
--- a/common/gdm-settings-keys.h
+++ b/common/gdm-settings-keys.h
@@ -42,13 +42,12 @@ G_BEGIN_DECLS
 #define GDM_KEY_DISPLAYS_PER_HOST "xdmcp/DisplaysPerHost"
 #define GDM_KEY_UDP_PORT "xdmcp/Port"
 #define GDM_KEY_INDIRECT "xdmcp/HonorIndirect"
-#define GDM_KEY_MAX_INDIRECT "xdmcp/MaxPendingIndirect"
 #define GDM_KEY_MAX_WAIT_INDIRECT "xdmcp/MaxWaitIndirect"
 #define GDM_KEY_PING_INTERVAL "xdmcp/PingIntervalSeconds"
 #define GDM_KEY_WILLING "xdmcp/Willing"
-#define GDM_KEY_XDMCP_PROXY "xdmcp/EnableProxy"
-#define GDM_KEY_XDMCP_PROXY_XSERVER "xdmcp/ProxyXServer"
-#define GDM_KEY_XDMCP_PROXY_RECONNECT "xdmcp/ProxyReconnect"
+
+#define GDM_KEY_MULTICAST "chooser/Multicast"
+#define GDM_KEY_MULTICAST_ADDR "chooser/MulticastAddr"
 
 G_END_DECLS
 
diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c
index 6a00931..3a2623c 100644
--- a/daemon/gdm-simple-slave.c
+++ b/daemon/gdm-simple-slave.c
@@ -53,13 +53,16 @@
 #include "gdm-session-direct.h"
 #include "gdm-greeter-server.h"
 #include "gdm-greeter-session.h"
+#include "gdm-settings-direct.h"
+#include "gdm-settings-keys.h"
 
 #define GDM_SIMPLE_SLAVE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_SIMPLE_SLAVE, GdmSimpleSlavePrivate))
 
 #define GDM_DBUS_NAME              "org.gnome.DisplayManager"
 #define GDM_DBUS_DISPLAY_INTERFACE "org.gnome.DisplayManager.Display"
 
-#define MAX_CONNECT_ATTEMPTS 10
+#define MAX_CONNECT_ATTEMPTS  10
+#define DEFAULT_PING_INTERVAL 15
 
 struct GdmSimpleSlavePrivate
 {
@@ -862,6 +865,7 @@ start_greeter (GdmSimpleSlave *slave)
         char          *display_hostname;
         char          *auth_file;
         char          *address;
+        gboolean       res;
 
         g_debug ("GdmSimpleSlave: Running greeter");
 
@@ -889,6 +893,10 @@ start_greeter (GdmSimpleSlave *slave)
         /* FIXME: send a signal back to the master */
 
         /* If XDMCP setup pinging */
+        slave->priv->ping_interval = DEFAULT_PING_INTERVAL;
+        res = gdm_settings_direct_get_int (GDM_KEY_PING_INTERVAL,
+                                           &(slave->priv->ping_interval));
+
         if ( ! display_is_local && slave->priv->ping_interval > 0) {
                 alarm (slave->priv->ping_interval);
         }
diff --git a/daemon/gdm-xdmcp-chooser-slave.c b/daemon/gdm-xdmcp-chooser-slave.c
index 5898efd..3117ff9 100644
--- a/daemon/gdm-xdmcp-chooser-slave.c
+++ b/daemon/gdm-xdmcp-chooser-slave.c
@@ -48,13 +48,16 @@
 #include "gdm-server.h"
 #include "gdm-chooser-server.h"
 #include "gdm-chooser-session.h"
+#include "gdm-settings-direct.h"
+#include "gdm-settings-keys.h"
 
 #define GDM_XDMCP_CHOOSER_SLAVE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_XDMCP_CHOOSER_SLAVE, GdmXdmcpChooserSlavePrivate))
 
 #define GDM_DBUS_NAME              "org.gnome.DisplayManager"
 #define GDM_DBUS_DISPLAY_INTERFACE "org.gnome.DisplayManager.Display"
 
-#define MAX_CONNECT_ATTEMPTS 10
+#define MAX_CONNECT_ATTEMPTS  10
+#define DEFAULT_PING_INTERVAL 15
 
 struct GdmXdmcpChooserSlavePrivate
 {
@@ -164,6 +167,7 @@ run_chooser (GdmXdmcpChooserSlave *slave)
         char          *display_hostname;
         char          *auth_file;
         char          *address;
+        gboolean       res;
 
         g_debug ("GdmXdmcpChooserSlave: Running chooser");
 
@@ -185,6 +189,10 @@ run_chooser (GdmXdmcpChooserSlave *slave)
         /* FIXME: send a signal back to the master */
 
         /* If XDMCP setup pinging */
+        slave->priv->ping_interval = DEFAULT_PING_INTERVAL;
+        res = gdm_settings_direct_get_int (GDM_KEY_PING_INTERVAL,
+                                           &(slave->priv->ping_interval));
+
         if (slave->priv->ping_interval > 0) {
                 alarm (slave->priv->ping_interval);
         }
diff --git a/daemon/gdm-xdmcp-display-factory.c b/daemon/gdm-xdmcp-display-factory.c
index aa68ae0..05d0261 100644
--- a/daemon/gdm-xdmcp-display-factory.c
+++ b/daemon/gdm-xdmcp-display-factory.c
@@ -57,6 +57,8 @@
 #include "gdm-display-factory.h"
 #include "gdm-xdmcp-display-factory.h"
 #include "gdm-display-store.h"
+#include "gdm-settings-direct.h"
+#include "gdm-settings-keys.h"
 
 /*
  * On Sun, we need to define allow_severity and deny_severity to link
@@ -74,10 +76,11 @@ int deny_severity = LOG_WARNING;
 #define DEFAULT_USE_MULTICAST         FALSE
 #define DEFAULT_MULTICAST_ADDRESS     "ff02::1"
 #define DEFAULT_HONOR_INDIRECT        TRUE
-#define DEFAULT_MAX_DISPLAYS_PER_HOST 2
+#define DEFAULT_MAX_DISPLAYS_PER_HOST 1
 #define DEFAULT_MAX_DISPLAYS          16
 #define DEFAULT_MAX_PENDING_DISPLAYS  4
-#define DEFAULT_MAX_WAIT              15
+#define DEFAULT_MAX_WAIT              30
+#define DEFAULT_MAX_WAIT_INDIRECT     30
 #define DEFAULT_WILLING_SCRIPT        GDMCONFDIR "/Xwilling"
 
 #define GDM_MAX_FORWARD_QUERIES 10
@@ -186,6 +189,7 @@ struct GdmXdmcpDisplayFactoryPrivate
         guint            max_displays;
         guint            max_pending_displays;
         guint            max_wait;
+        guint            max_wait_indirect;
 };
 
 enum {
@@ -199,6 +203,7 @@ enum {
         PROP_MAX_DISPLAYS,
         PROP_MAX_PENDING_DISPLAYS,
         PROP_MAX_WAIT,
+        PROP_MAX_WAIT_INDIRECT,
 };
 
 static void     gdm_xdmcp_display_factory_class_init    (GdmXdmcpDisplayFactoryClass *klass);
@@ -1174,7 +1179,7 @@ indirect_client_lookup (GdmXdmcpDisplayFactory *factory,
                         break;
                 }
 
-                if (ic->acctime > 0 && curtime > ic->acctime + factory->priv->max_wait) {
+                if (ic->acctime > 0 && curtime > ic->acctime + factory->priv->max_wait_indirect) {
                         g_debug ("GdmXdmcpDisplayFactory: Disposing stale forward query from %s:%s",
                                  host, serv);
 
@@ -2905,10 +2910,33 @@ gdm_xdmcp_display_factory_start (GdmDisplayFactory *base_factory)
         gboolean                ret;
         GIOChannel             *ioc;
         GdmXdmcpDisplayFactory *factory = GDM_XDMCP_DISPLAY_FACTORY (base_factory);
+        gboolean                res;
 
         g_return_val_if_fail (GDM_IS_XDMCP_DISPLAY_FACTORY (factory), FALSE);
         g_return_val_if_fail (factory->priv->socket_fd == -1, FALSE);
 
+        /* read configuration */
+        res = gdm_settings_direct_get_uint    (GDM_KEY_UDP_PORT,
+                                               &(factory->priv->port));
+        res = gdm_settings_direct_get_boolean (GDM_KEY_MULTICAST,
+                                               &(factory->priv->use_multicast));
+        res = gdm_settings_direct_get_string  (GDM_KEY_MULTICAST_ADDR,
+                                               &(factory->priv->multicast_address));
+        res = gdm_settings_direct_get_boolean (GDM_KEY_INDIRECT,
+                                               &(factory->priv->honor_indirect));
+        res = gdm_settings_direct_get_uint    (GDM_KEY_DISPLAYS_PER_HOST,
+                                               &(factory->priv->max_displays_per_host));
+        res = gdm_settings_direct_get_uint    (GDM_KEY_MAX_SESSIONS,
+                                               &(factory->priv->max_displays));
+        res = gdm_settings_direct_get_uint    (GDM_KEY_MAX_PENDING,
+                                               &(factory->priv->max_pending_displays));
+        res = gdm_settings_direct_get_uint    (GDM_KEY_MAX_WAIT,
+                                               &(factory->priv->max_wait));
+        res = gdm_settings_direct_get_uint    (GDM_KEY_MAX_WAIT_INDIRECT,
+                                               &(factory->priv->max_wait_indirect));
+        res = gdm_settings_direct_get_string  (GDM_KEY_WILLING,
+                                               &(factory->priv->willing_script));
+
         ret = open_port (factory);
         if (! ret) {
                 return ret;
@@ -3027,6 +3055,15 @@ gdm_xdmcp_display_factory_set_max_wait (GdmXdmcpDisplayFactory *factory,
 }
 
 static void
+gdm_xdmcp_display_factory_set_max_wait_indirect (GdmXdmcpDisplayFactory *factory,
+                                                 guint                   num)
+{
+        g_return_if_fail (GDM_IS_XDMCP_DISPLAY_FACTORY (factory));
+
+        factory->priv->max_wait_indirect = num;
+}
+
+static void
 gdm_xdmcp_display_factory_set_willing_script (GdmXdmcpDisplayFactory *factory,
                                               const char             *script)
 {
@@ -3071,6 +3108,9 @@ gdm_xdmcp_display_factory_set_property (GObject       *object,
         case PROP_MAX_WAIT:
                 gdm_xdmcp_display_factory_set_max_wait (self, g_value_get_uint (value));
                 break;
+        case PROP_MAX_WAIT_INDIRECT:
+                gdm_xdmcp_display_factory_set_max_wait_indirect (self, g_value_get_uint (value));
+                break;
         case PROP_WILLING_SCRIPT:
                 gdm_xdmcp_display_factory_set_willing_script (self, g_value_get_string (value));
                 break;
@@ -3115,6 +3155,9 @@ gdm_xdmcp_display_factory_get_property (GObject    *object,
         case PROP_MAX_WAIT:
                 g_value_set_uint (value, self->priv->max_wait);
                 break;
+        case PROP_MAX_WAIT_INDIRECT:
+                g_value_set_uint (value, self->priv->max_wait_indirect);
+                break;
         case PROP_WILLING_SCRIPT:
                 g_value_set_string (value, self->priv->willing_script);
                 break;
@@ -3210,6 +3253,15 @@ gdm_xdmcp_display_factory_class_init (GdmXdmcpDisplayFactoryClass *klass)
                                                             G_MAXINT,
                                                             DEFAULT_MAX_WAIT,
                                                             G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+        g_object_class_install_property (object_class,
+                                         PROP_MAX_WAIT_INDIRECT,
+                                         g_param_spec_uint ("max-wait-indirect",
+                                                            "max-wait-indirect",
+                                                            "max-wait-indirect",
+                                                            0,
+                                                            G_MAXINT,
+                                                            DEFAULT_MAX_WAIT_INDIRECT,
+                                                            G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
         g_type_class_add_private (klass, sizeof (GdmXdmcpDisplayFactoryPrivate));
 }
diff --git a/data/gdm.schemas.in.in b/data/gdm.schemas.in.in
index bcb00e9..82a2223 100644
--- a/data/gdm.schemas.in.in
+++ b/data/gdm.schemas.in.in
@@ -2,6 +2,17 @@
   <schemalist>
 
     <schema>
+      <key>chooser/Multicast</key>
+      <signature>b</signature>
+      <default>false</default>
+    </schema>
+    <schema>
+      <key>chooser/MulticastAddr</key>
+      <signature>s</signature>
+      <default>ff02::1</default>
+    </schema>
+
+    <schema>
       <key>daemon/User</key>
       <signature>s</signature>
       <default>@GDM_USERNAME@</default>
@@ -61,12 +72,12 @@
     <schema>
       <key>xdmcp/MaxWait</key>
       <signature>i</signature>
-      <default>15</default>
+      <default>30</default>
     </schema>
     <schema>
       <key>xdmcp/DisplaysPerHost</key>
       <signature>i</signature>
-      <default>2</default>
+      <default>1</default>
     </schema>
     <schema>
       <key>xdmcp/Port</key>
@@ -79,14 +90,9 @@
       <default>true</default>
     </schema>
     <schema>
-      <key>xdmcp/MaxPendingIndirect</key>
-      <signature>i</signature>
-      <default>4</default>
-    </schema>
-    <schema>
       <key>xdmcp/MaxWaitIndirect</key>
       <signature>i</signature>
-      <default>15</default>
+      <default>30</default>
     </schema>
     <schema>
       <key>xdmcp/PingIntervalSeconds</key>
@@ -98,22 +104,5 @@
       <signature>s</signature>
       <default>@gdmconfdir@/Xwilling</default>
     </schema>
-
-    <schema>
-      <key>xdmcp/EnableProxy</key>
-      <signature>b</signature>
-      <default>false</default>
-    </schema>
-    <schema>
-      <key>xdmcp/ProxyXServer</key>
-      <signature>s</signature>
-      <default></default>
-    </schema>
-    <schema>
-      <key>xdmcp/ProxyReconnect</key>
-      <signature>s</signature>
-      <default></default>
-    </schema>
-
   </schemalist>
 </gdmschemafile>
diff --git a/docs/C/gdm.xml b/docs/C/gdm.xml
index 8f160ee..4d9939c 100644
--- a/docs/C/gdm.xml
+++ b/docs/C/gdm.xml
@@ -1106,6 +1106,34 @@ TimedLogin=you
         A full list of supported configuration keys follow:
       </para>
 
+      <sect3 id="choosersection">
+        <title>[chooser]</title>
+        <variablelist>
+
+          <varlistentry>
+            <term>Multicast</term>
+            <listitem>
+              <synopsis>Multicast=false</synopsis>
+              <para>
+                If true and IPv6 is enabled, the chooser will send a multicast
+                query to the local network and collect responses from the hosts
+                who have joined multicast group.
+              </para>
+            </listitem>
+          </varlistentry>
+         
+          <varlistentry>
+            <term>MulticastAddr</term>
+            <listitem>
+              <synopsis>MulticastAddr=ff02::1</synopsis>
+              <para>
+                This is the Link-local Multicast address.
+              </para>
+            </listitem>
+          </varlistentry>
+        </variablelist>
+      </sect3>
+
       <sect3 id="daemonsection">
         <title>[daemon]</title>
         <variablelist>
@@ -1175,8 +1203,9 @@ TimedLogin=you
             <listitem>
               <synopsis>AutomaticLoginEnable=false</synopsis>
               <para>
-                If true, the user given in <filename>AutomaticLogin</filename> should be
-                logged in immediately. This feature is like timed login with a delay of 0.
+                If true, the user given in <filename>AutomaticLogin</filename>
+                should be logged in immediately. This feature is like timed
+                login with a delay of 0.
               </para>
             </listitem>
           </varlistentry>
@@ -1293,31 +1322,6 @@ gdm:.my.domain
           </varlistentry>
           
           <varlistentry>
-            <term>EnableProxy</term>
-            <listitem>
-              <synopsis>EnableProxy=false</synopsis>
-              <para>
-                Setting this to true enables support for running XDMCP sessions
-                on a local proxy Xserver. This may improve the performance of
-                XDMCP sessions, especially on high latency networks, as many
-                X protocol operations can be completed without going over the
-                network.
-              </para>
-
-              <para>
-                Note, however, that this mode will significantly increase the
-                burden on the machine hosting the XDMCP sessions
-              </para>
-
-              <para>
-                See the <filename>FlexiProxy</filename> and
-                <filename>FlexiProxyDisconnect</filename> options for further
-                details on how to configure support for this feature.
-              </para>
-            </listitem>
-          </varlistentry>
-
-          <varlistentry>
             <term>HonorIndirect</term>
             <listitem>
               <synopsis>HonorIndirect=true</synopsis>
@@ -1348,19 +1352,6 @@ gdm:.my.domain
           </varlistentry>
           
           <varlistentry>
-            <term>MaxPendingIndirect</term>
-            <listitem>
-              <synopsis>MaxPendingIndirect=4</synopsis>
-              <para>
-                GDM will only provide <filename>MaxPendingIndirect</filename>
-                displays with host choosers simultaneously.  If more queries
-                from different hosts come in, the oldest ones will be
-                forgotten.
-              </para>
-            </listitem>
-          </varlistentry>
-
-          <varlistentry>
             <term>MaxSessions</term>
             <listitem>
               <synopsis>MaxSessions=16</synopsis>
@@ -1413,18 +1404,6 @@ gdm:.my.domain
           </varlistentry>
         
           <varlistentry>
-            <term>Port</term>
-            <listitem>
-              <synopsis>Port=177</synopsis>
-              <para>
-                The UDP port number <filename>gdm</filename> should listen to
-                for XDMCP requests. Do not change this unless you know what
-                you are doing.
-              </para>
-            </listitem>
-          </varlistentry>
-
-          <varlistentry>
             <term>PingIntervalSeconds</term>
             <listitem>
               <synopsis>PingIntervalSeconds=15</synopsis>
@@ -1449,44 +1428,18 @@ gdm:.my.domain
           </varlistentry>
 
           <varlistentry>
-            <term>ProxyReconnect</term>
+            <term>Port</term>
             <listitem>
-              <synopsis>FlexiProxyReconnect=</synopsis>
-              <para>
-                Setting this option enables experimental support for session
-                migration with XDMCP sessions. This enables users to disconnect
-                from their session and later reconnect to that same session,
-                possibly from a different terminal.
-              </para>
-
-              <para>
-                In order to use this feature, you must have a nested Xserver
-                available which supports disconnecting from its parent Xserver
-                and reconnecting to another Xserver. Currently, the Distributed
-                Multihead X (DMX) server supports this feature to some extent
-                and other projects like NoMachine NX are busy implementing it.
-              </para>
-
+              <synopsis>Port=177</synopsis>
               <para>
-                This option should be set to the path of a command which will
-                handle reconnecting the XDMCP proxy to another backend display.
-                A sample implementation for use with DMX is supplied.
+                The UDP port number <filename>gdm</filename> should listen to
+                for XDMCP requests. Do not change this unless you know what
+                you are doing.
               </para>
             </listitem>
           </varlistentry>
 
           <varlistentry>
-            <term>ProxyXServer</term>
-            <listitem>
-              <synopsis>ProxyXServer=</synopsis>
-              <para>
-                The Xserver command line for a XDMCP proxy. Any nested X
-                server like Xnest, Xephyr or Xdmx should work fairly well.
-              </para>
-            </listitem>
-          </varlistentry>
- 
-          <varlistentry>
             <term>Willing</term>
             <listitem>
               <synopsis>Willing=&lt;etc&gt;/gdm/Xwilling</synopsis>



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