Index: includes/menu.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/menu.inc,v
retrieving revision 1.212
diff -u -p -r1.212 menu.inc
--- includes/menu.inc	5 Oct 2007 13:17:09 -0000	1.212
+++ includes/menu.inc	7 Oct 2007 22:45:49 -0000
@@ -585,15 +585,29 @@ function menu_tree($menu_name = 'navigat
 function menu_tree_output($tree) {
   $output = '';
 
+  // Pull out just the menu items we are going to render so that we 
+  // get an accurate count for the first/last classes.
   foreach ($tree as $data) {
     if (!$data['link']['hidden']) {
-      $link = theme('menu_item_link', $data['link']);
-      if ($data['below']) {
-        $output .= theme('menu_item', $link, $data['link']['has_children'], menu_tree_output($data['below']), $data['link']['in_active_trail']);
-      }
-      else {
-        $output .= theme('menu_item', $link, $data['link']['has_children'], '', $data['link']['in_active_trail']);
-      }
+      $items[] = $data;
+    }
+  }
+  
+  $num_items = count($items);
+  foreach ($items as $i => $data) {
+    $extra_class = NULL;
+    if ($i == 0) {
+      $extra_class = 'first';
+    }
+    if ($i == $num_items - 1) {
+      $extra_class = 'last';
+    }
+    $link = theme('menu_item_link', $data['link']);
+    if ($data['below']) {
+      $output .= theme('menu_item', $link, $data['link']['has_children'], menu_tree_output($data['below']), $data['link']['in_active_trail'], $extra_class);
+    }
+    else {
+      $output .= theme('menu_item', $link, $data['link']['has_children'], '', $data['link']['in_active_trail'], $extra_class);
     }
   }
   return $output ? theme('menu_tree', $output) : '';
@@ -921,8 +935,11 @@ function theme_menu_tree($tree) {
 /**
  * Generate the HTML output for a menu item and submenu.
  */
-function theme_menu_item($link, $has_children, $menu = '', $in_active_trail = FALSE) {
+function theme_menu_item($link, $has_children, $menu = '', $in_active_trail = FALSE, $extra_class = NULL) {
   $class = ($menu ? 'expanded' : ($has_children ? 'collapsed' : 'leaf'));
+  if (!empty($extra_class)) {
+    $class .= ' '. $extra_class;
+  }
   if ($in_active_trail) {
     $class .= ' active-trail';
   }
Index: includes/theme.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/theme.inc,v
retrieving revision 1.388
diff -u -p -r1.388 theme.inc
--- includes/theme.inc	4 Oct 2007 19:24:50 -0000	1.388
+++ includes/theme.inc	7 Oct 2007 22:45:49 -0000
@@ -1469,7 +1469,8 @@ function theme_item_list($items = array(
 
   if (!empty($items)) {
     $output .= "<$type". drupal_attributes($attributes) .'>';
-    foreach ($items as $item) {
+    $num_items = count($items);
+    foreach ($items as $i => $item) {
       $attributes = array();
       $children = array();
       if (is_array($item)) {
@@ -1491,6 +1492,12 @@ function theme_item_list($items = array(
       if (count($children) > 0) {
         $data .= theme_item_list($children, NULL, $type, $attributes); // Render nested list
       }
+      if ($i == 0) {
+        $attributes['class'] = empty($attributes['class']) ? 'first' : ($attributes['class'] .' first');
+      }
+      if ($i == $num_items - 1) {
+        $attributes['class'] = empty($attributes['class']) ? 'last' : ($attributes['class'] .' last');
+      }
       $output .= '<li'. drupal_attributes($attributes) .'>'. $data .'</li>';
     }
     $output .= "</$type>";
