Index: modules/aggregator/aggregator.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/aggregator/aggregator.test,v
retrieving revision 1.28
diff -u -p -r1.28 aggregator.test
--- modules/aggregator/aggregator.test	30 Jul 2009 19:24:20 -0000	1.28
+++ modules/aggregator/aggregator.test	14 Aug 2009 12:21:41 -0000
@@ -253,7 +253,7 @@ EOF;
       $edit = array();
       $edit['title'] = $this->randomName();
       $edit['body[0][value]'] = $this->randomName();
-      $this->drupalPost('node/add/article', $edit, t('Save'));
+      $this->drupalPost('node/add/article', $edit, t('Publish'));
     }
   }
 }
Index: modules/blog/blog.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/blog/blog.test,v
retrieving revision 1.17
diff -u -p -r1.17 blog.test
--- modules/blog/blog.test	3 Aug 2009 03:04:33 -0000	1.17
+++ modules/blog/blog.test	14 Aug 2009 12:21:41 -0000
@@ -153,7 +153,7 @@ class BlogTestCase extends DrupalWebTest
       $edit = array();
       $edit['title'] = 'node/' . $node->nid;
       $edit['body[0][value]'] = $this->randomName(256);
-      $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
+      $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Publish'));
       $this->assertRaw(t('Blog entry %title has been updated.', array('%title' => $edit['title'])), t('Blog node was edited'));
 
       // Delete blog node.
Index: modules/book/book.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/book/book.test,v
retrieving revision 1.13
diff -u -p -r1.13 book.test
--- modules/book/book.test	20 Jul 2009 18:51:32 -0000	1.13
+++ modules/book/book.test	14 Aug 2009 12:21:41 -0000
@@ -65,7 +65,7 @@ class BookTestCase extends DrupalWebTest
     $other_book = $this->createBookNode('new');
     $node = $this->createBookNode($book->nid);
     $edit = array('book[bid]' => $other_book->nid);
-    $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
+    $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Publish'));
 
     $this->drupalLogout();
     $this->drupalLogin($web_user);
@@ -180,10 +180,10 @@ class BookTestCase extends DrupalWebTest
       $this->drupalPost('node/add/book', $edit, t('Change book (update list of parents)'));
 
       $edit['book[plid]'] = $parent;
-      $this->drupalPost(NULL, $edit, t('Save'));
+      $this->drupalPost(NULL, $edit, t('Publish'));
     }
     else {
-      $this->drupalPost('node/add/book', $edit, t('Save'));
+      $this->drupalPost('node/add/book', $edit, t('Publish'));
     }
 
     // Check to make sure the book node was created.
Index: modules/dblog/dblog.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/dblog/dblog.test,v
retrieving revision 1.25
diff -u -p -r1.25 dblog.test
--- modules/dblog/dblog.test	11 Aug 2009 11:47:58 -0000	1.25
+++ modules/dblog/dblog.test	14 Aug 2009 12:21:41 -0000
@@ -262,14 +262,14 @@ class DBLogTestCase extends DrupalWebTes
     // Create node using form to generate add content event (which is not triggered by drupalCreateNode).
     $edit = $this->getContent($type);
     $title = $edit['title'];
-    $this->drupalPost('node/add/' . $type, $edit, t('Save'));
+    $this->drupalPost('node/add/' . $type, $edit, t('Publish'));
     $this->assertResponse(200);
     // Retrieve node object.
     $node = $this->drupalGetNodeByTitle($title);
     $this->assertTrue($node != NULL, t('Node @title was loaded', array('@title' => $title)));
     // Edit node.
     $edit = $this->getContentUpdate($type);
-    $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
+    $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Publish'));
     $this->assertResponse(200);
     // Delete node.
     $this->drupalPost('node/' . $node->nid . '/delete', array(), t('Delete'));
Index: modules/filter/filter.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/filter/filter.test,v
retrieving revision 1.29
diff -u -p -r1.29 filter.test
--- modules/filter/filter.test	13 Aug 2009 19:53:19 -0000	1.29
+++ modules/filter/filter.test	14 Aug 2009 12:21:42 -0000
@@ -112,7 +112,7 @@ class FilterAdminTestCase extends Drupal
     $edit['title'] = $this->randomName();
     $edit['body[0][value]'] = $body . '<random>' . $extra_text . '</random>';
     $edit['body[0][value_format]'] = $filtered;
-    $this->drupalPost('node/add/page', $edit, t('Save'));
+    $this->drupalPost('node/add/page', $edit, t('Publish'));
     $this->assertRaw(t('Page %title has been created.', array('%title' => $edit['title'])), t('Filtered node created.'));
 
     $node = $this->drupalGetNodeByTitle($edit['title']);
Index: modules/forum/forum.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/forum/forum.test,v
retrieving revision 1.27
diff -u -p -r1.27 forum.test
--- modules/forum/forum.test	3 Aug 2009 03:04:33 -0000	1.27
+++ modules/forum/forum.test	14 Aug 2009 12:21:43 -0000
@@ -243,8 +243,7 @@ class ForumTestCase extends DrupalWebTes
     // Instead, the post variables seem to pick up the first non-blank value in the select list.
 
     // Create forum topic.
-//    $this->drupalPost('node/add/forum/' . $forum['tid'], $edit, t('Save'));
-    $this->drupalPost('node/add/forum/', $edit, t('Save'));
+    $this->drupalPost('node/add/forum/', $edit, t('Publish'));
     $type = t('Forum topic');
     if ($container) {
       $this->assertNoRaw(t('@type %title has been created.', array('@type' => $type, '%title' => $title)), t('Forum topic was not created'));
@@ -324,7 +323,7 @@ class ForumTestCase extends DrupalWebTes
       $edit['body[0][value]'] = $this->randomName(256);
       $edit['taxonomy[1]'] = $this->root_forum['tid']; // Assumes the topic is initially associated with $forum.
       $edit['shadow'] = TRUE;
-      $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
+      $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Publish'));
       $this->assertRaw(t('Forum topic %title has been updated.', array('%title' => $edit['title'])), t('Forum node was edited'));
 
       // Verify topic was moved to a different forum.
Index: modules/locale/locale.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/locale/locale.test,v
retrieving revision 1.35
diff -u -p -r1.35 locale.test
--- modules/locale/locale.test	11 Aug 2009 11:52:46 -0000	1.35
+++ modules/locale/locale.test	14 Aug 2009 12:21:46 -0000
@@ -1401,7 +1401,7 @@ class LocaleContentFunctionalTest extend
     $edit = array(
       'language' => 'en',
     );
-    $this->drupalPost($path, $edit, t('Save'));
+    $this->drupalPost($path, $edit, t('Publish'));
     $this->assertRaw(t('Page %title has been updated.', array('%title' => $node_title)), t('Page updated.'));
 
     $this->drupalLogout();
Index: modules/node/node.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.admin.inc,v
retrieving revision 1.60
diff -u -p -r1.60 node.admin.inc
--- modules/node/node.admin.inc	30 Jul 2009 19:24:21 -0000	1.60
+++ modules/node/node.admin.inc	14 Aug 2009 12:21:46 -0000
@@ -75,6 +75,8 @@ function node_filters() {
     'options' => array(
       'status-1' => t('published'),
       'status-0' => t('not published'),
+      'draft-1' => t('pending drafts'),
+      'draft-0' => t('no pending drafts'),
       'promote-1' => t('promoted'),
       'promote-0' => t('not promoted'),
       'sticky-1' => t('sticky'),
@@ -599,4 +601,4 @@ function node_multiple_delete_confirm_su
 function node_modules_installed($modules) {
   // Clear node type cache for node permissions.
   node_type_clear();
-}
\ No newline at end of file
+}
Index: modules/node/node.css
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.css,v
retrieving revision 1.8
diff -u -p -r1.8 node.css
--- modules/node/node.css	4 Aug 2009 03:27:11 -0000	1.8
+++ modules/node/node.css	14 Aug 2009 12:21:46 -0000
@@ -3,6 +3,17 @@
 .node-unpublished {
   background-color: #fff4f4;
 }
+.node-unpublished div.unpublished {
+  height: 0;
+  overflow: visible;
+  color: #d8d8d8;
+  font-size: 75px;
+  line-height: 1;
+  font-family: Impact, "Arial Narrow", Helvetica, sans-serif;
+  font-weight: bold;
+  text-transform: uppercase;
+  text-align: center;
+}
 .preview .node {
   background-color: #ffffea;
 }
Index: modules/node/node.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.install,v
retrieving revision 1.25
diff -u -p -r1.25 node.install
--- modules/node/node.install	27 Jul 2009 19:26:31 -0000	1.25
+++ modules/node/node.install	14 Aug 2009 12:21:46 -0000
@@ -89,6 +89,12 @@ function node_schema() {
         'not null' => TRUE,
         'default' => 0,
       ),
+      'draft' => array(
+        'description' => 'A boolean indicating if the node has pending drafts.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
       'sticky' => array(
         'description' => 'Boolean indicating whether the node should be displayed at the top of lists in which it appears.',
         'type' => 'int',
@@ -113,6 +119,7 @@ function node_schema() {
       'node_changed'        => array('changed'),
       'node_created'        => array('created'),
       'node_moderate'       => array('moderate'),
+      'node_draft'          => array('draft'),
       'node_frontpage'      => array('promote', 'status', 'sticky', 'created'),
       'node_status_type'    => array('status', 'type', 'nid'),
       'node_title_type'     => array('title', array('type', 4)),
@@ -525,7 +532,22 @@ function node_update_7006() {
   return $ret;
 }
 
+/**
+ * Add new column draft.
+ */
+function node_update_7007() {
+  $ret = array();
+  $specification = array(
+    'description' => 'A boolean indicating if the node has pending drafts.',
+    'type' => 'int',
+    'not null' => TRUE,
+    'default' => 0,
+  );
 
+  db_add_field($ret, 'node', 'draft', $specification);
+  db_add_index($ret, 'node', 'node_draft', array('draft'));
+  return $ret;
+}
 
 /**
  * @} End of "defgroup updates-6.x-to-7.x"
Index: modules/node/node.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.module,v
retrieving revision 1.1098
diff -u -p -r1.1098 node.module
--- modules/node/node.module	13 Aug 2009 02:16:35 -0000	1.1098
+++ modules/node/node.module	14 Aug 2009 12:21:47 -0000
@@ -952,10 +952,14 @@ function node_save($node) {
   if (empty($node->created)) {
     $node->created = REQUEST_TIME;
   }
-  // The changed timestamp is always updated for bookkeeping purposes (revisions, searching, ...)
-  $node->changed = REQUEST_TIME;
-
-  $node->timestamp = REQUEST_TIME;
+  // The changed timestamp is always updated for bookkeeping purposes.
+  if (empty($node->timestamp_changed)) {
+    $node->changed = REQUEST_TIME;
+  }
+  // Set the revision timestamp.
+  if (empty($node->timestamp_revision)) {
+    $node->timestamp = REQUEST_TIME;
+  }
   $update_node = TRUE;
 
   // Generate the node table query and the node_revisions table query.
@@ -1075,6 +1079,28 @@ function node_delete_multiple($nids) {
 }
 
 /**
+ * Delete a node revision.
+ *
+ * This function should only be used to delete older revisions. Using it to
+ * delete the current revision will cause data inconsistencies in the node
+ * table.
+ *
+ * @param $nid
+ *   The node ID.
+ * @param $vid
+ *   The revision ID.
+ */
+function node_delete_revision($nid, $vid) {
+  $node_revision = node_load($nid, $vid);
+  db_delete('node_revision')
+    ->condition('nid', $node_revision->nid)
+    ->condition('vid', $node_revision->vid)
+    ->execute();
+  module_invoke_all('node_delete_revision', $node_revision);
+  field_attach_delete_revision('node', $node_revision);
+}
+
+/**
  * Generate an array for rendering the given node.
  *
  * @param $node
@@ -1180,10 +1206,14 @@ function node_show($node, $message = FAL
   if ($message) {
     drupal_set_title(t('Revision of %title from %date', array('%title' => $node->title, '%date' => format_date($node->revision_timestamp))), PASS_THROUGH);
   }
-
   // Update the history table, stating that this user viewed this node.
   node_tag_new($node->nid);
 
+  // Display a message if the node is published and there are pending drafts.
+  if ($node->draft && $node->status && (user_access('view revisions' && user_access('revert revisions') || user_access('administer_nodes')))) {
+    drupal_set_message(t('There are pending drafts for this content. <a href="@revisions">Review and publish</a> available revisions.', array('@revisions' => url('node/' . $node->nid . '/revisions'))));
+  }
+
   // For markup consistency with other pages, use node_build_multiple() rather than node_build().
   return node_build_multiple(array($node), 'full');
 }
@@ -1289,10 +1319,6 @@ function node_permission() {
       'title' => t('View revisions'),
       'description' => t('View content revisions.'),
     ),
-    'revert revisions' => array(
-      'title' => t('Revert revisions'),
-      'description' => t('Replace content with an older revision.'),
-    ),
     'delete revisions' => array(
       'title' => t('Delete revisions'),
       'description' => t('Delete content revisions.'),
@@ -1753,6 +1779,14 @@ function node_menu() {
     'weight' => 1,
     'type' => MENU_LOCAL_TASK,
   );
+  $items['node/%/edit/revision/%'] = array(
+    'title' => 'Edit',
+    'page callback' => 'node_revision_page_edit',
+    'page arguments' => array(1, 4),
+    'access callback' => 'node_revision_edit_access',
+    'access arguments' => array(1, 4),
+    'type' => MENU_CALLBACK,
+  );
   $items['node/%node/delete'] = array(
     'title' => 'Delete',
     'page callback' => 'drupal_get_form',
@@ -2304,6 +2338,21 @@ function node_access($op, $node, $accoun
 }
 
 /**
+ * Check access for editing a revision.
+ *
+ * @param $nid
+ *  The node ID.
+ * @param $vid
+ *  The revision ID.
+ * @return
+ *   Whether the user can access the node.
+ */
+function node_revision_edit_access($nid, $vid) {
+  $node = node_load($nid, $vid);
+  return _node_revision_access($node, 'revert');
+}
+
+/**
  * Generate an SQL join clause for use in fetching a node listing.
  *
  * @param $node_alias
@@ -2935,6 +2984,7 @@ function node_action_info() {
  */
 function node_publish_action($node, $context = array()) {
   $node->status = 1;
+  $node->draft = 0;
   watchdog('action', 'Set @type %title to published.', array('@type' => node_type_get_name($node), '%title' => $node->title));
 }
 
@@ -2944,6 +2994,7 @@ function node_publish_action($node, $con
  */
 function node_unpublish_action($node, $context = array()) {
   $node->status = 0;
+  $node->draft = 0;
   watchdog('action', 'Set @type %title to unpublished.', array('@type' => node_type_get_name($node), '%title' => $node->title));
 }
 
@@ -3120,6 +3171,10 @@ function node_list_permissions($type) {
       'title' => t('Delete any %type_name content', array('%type_name' => $info->name)),
       'description' => t('Delete any %type_name content, regardless of its author.', array('%type_name' => $info->name)),
     ),
+    "publish $type content" => array(
+      'title' => t('Publish and unpublish %type_name content', array('%type_name' => $info->name)),
+      'description' => t('Publish and unpublish %type_name content.'),
+    ),
   );
 
   return $perms;
Index: modules/node/node.pages.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.pages.inc,v
retrieving revision 1.73
diff -u -p -r1.73 node.pages.inc
--- modules/node/node.pages.inc	4 Aug 2009 06:44:48 -0000	1.73
+++ modules/node/node.pages.inc	14 Aug 2009 12:21:47 -0000
@@ -13,6 +13,22 @@
 function node_page_edit($node) {
   $type_name = node_type_get_name($node);
   drupal_set_title(t('<em>Edit @type</em> @title', array('@type' => $type_name, '@title' => $node->title)), PASS_THROUGH);
+  // If the node is published and has pending drafts, inform the user, since the
+  // drafts will be more up to date than the current published version.
+  if ($node->draft && $node->status && (user_access('view revisions') || user_access('administer_nodes'))) {
+    drupal_set_message(t('There are pending drafts for this content. <a href="@revisions">Review and publish</a> available revisions.', array('@revisions' => url('node/' . $node->nid . '/revisions'))));
+  }
+
+  return drupal_get_form($node->type . '_node_form', $node);
+}
+
+/**
+ * Menu callback to present the node editing form for a revision.
+ */
+function node_revision_page_edit($nid, $vid) {
+  $node = node_load($nid, $vid);
+  $type_name = node_type_get_name($node);
+  drupal_set_title(t('<em>Edit @type</em> @title', array('@type' => $type_name, '@title' => $node->title)), PASS_THROUGH);
   return drupal_get_form($node->type . '_node_form', $node);
 }
 
@@ -135,7 +151,7 @@ function node_form(&$form_state, $node) 
 
   // Basic node information.
   // These elements are just values so they are not even sent to the client.
-  foreach (array('nid', 'vid', 'uid', 'created', 'type', 'language') as $key) {
+  foreach (array('nid', 'vid', 'uid', 'created', 'type', 'language', 'draft') as $key) {
     $form[$key] = array(
       '#type' => 'value',
       '#value' => isset($node->$key) ? $node->$key : NULL,
@@ -232,9 +248,8 @@ function node_form(&$form_state, $node) 
     '#weight' => 95,
   );
   $form['options']['status'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Published'),
-    '#default_value' => $node->status,
+    '#type' => 'value',
+    '#value' => $node->status,
   );
   $form['options']['promote'] = array(
     '#type' => 'checkbox',
@@ -258,12 +273,18 @@ function node_form(&$form_state, $node) 
   // Add the buttons.
   $form['buttons'] = array();
   $form['buttons']['#weight'] = 100;
-  $form['buttons']['submit'] = array(
+  $form['buttons']['publish'] = array(
     '#type' => 'submit',
-    '#access' => variable_get('node_preview_' . $node->type, 1) != DRUPAL_REQUIRED || (!form_get_errors() && isset($form_state['node_preview'])),
-    '#value' => t('Save'),
+    '#access' => variable_get('node_preview_' . $node->type, 1) != DRUPAL_REQUIRED || (!form_get_errors() && isset($form_state['node_preview'])) && (user_access('publish content') || $node->status),
+    '#value' => t('Publish'),
     '#weight' => 5,
-    '#submit' => array('node_form_submit'),
+    '#submit' => array('node_form_publish_submit'),
+  );
+  $form['buttons']['draft'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save as draft'),
+    '#weight' => 6,
+    '#submit' => array('node_form_draft_submit'),
   );
   $form['buttons']['preview'] = array(
     '#access' => variable_get('node_preview_' . $node->type, 1) != DRUPAL_DISABLED,
@@ -272,6 +293,13 @@ function node_form(&$form_state, $node) 
     '#weight' => 10,
     '#submit' => array('node_form_build_preview'),
   );
+  $form['buttons']['unpublish'] = array(
+    '#access' => !empty($node->nid) && !empty($node->status) && (user_access('administer nodes') || user_access('publish content')),
+    '#type' => 'submit',
+    '#value' => t('Unpublish'),
+    '#weight' => 11,
+    '#submit' => array('node_form_unpublish_submit'),
+  );
   if (!empty($node->nid) && node_access('delete', $node)) {
     $form['buttons']['delete'] = array(
       '#type' => 'submit',
@@ -395,6 +423,74 @@ function theme_node_preview($node) {
   return $output;
 }
 
+/**
+ * Submit handler for saving as draft.
+ */
+function node_form_draft_submit($form, &$form_state) {
+  $node = node_form_submit_build_node($form, $form_state);
+
+  // Always create a new revision if saving as a draft.
+  $node->revision = TRUE;
+  $node->draft = 1;
+  if (empty($node->nid)) {
+    $node->status = FALSE;
+  }
+  else {
+    // Set $node->changed to the current value so that this draft does not
+    // affect the 'updated' mark on node listings.
+    $original = node_load($node->nid);
+    $node->timestamp_changed = $original->changed;
+  }
+  node_save($node);
+
+  // If the node is published, and there is already an existing revision
+  // we need to ensure that the data from the current active revision is used
+  // in both the {node} and field API tables.
+  if ($node->status && $node->old_vid) {
+    // Since we have already saved a new revision, load the original again.
+    $current = node_load($node->nid, $node->old_vid);
+
+    // Set taxonomy terms to tids to resolve inconsistencies between loaded
+    // and saved data.
+    if (module_exists('taxonomy')) {
+      $current->taxonomy = array_keys($current->taxonomy);
+    }
+    $current->revision = TRUE;
+
+    // Set both the updated and revision timestamps to those of the revision
+    // we are re-saving to ensure it is listed correctly on the revisions tab.
+    $current->timestamp_updated = $current->timestamp_revision = $original->changed;
+    node_save($current);
+
+    // We now have a duplicate copy of this revision, so delete the old one.
+    node_delete_revision($original->nid, $original->vid);
+  }
+
+  if ($node->nid) {
+    unset($form_state['rebuild']);
+    $form_state['nid'] = $node->nid;
+    $form_state['redirect'] = 'node/' . $node->nid;
+  }
+}
+
+/**
+ * Submit handler for saving as published.
+ */
+function node_form_publish_submit($form, &$form_state) {
+  $form_state['values']['status'] = 1;
+  $form_state['values']['draft'] = 0;
+  node_form_submit($form, $form_state);
+}
+
+/**
+ * Submit handler for saving as unpublished.
+ */
+function node_form_unpublish_submit($form, &$form_state) {
+  $form_state['values']['status'] = 0;
+  $form_state['values']['draft'] = 0;
+  node_form_submit($form, $form_state);
+}
+
 function node_form_submit($form, &$form_state) {
   global $user;
 
@@ -480,19 +576,23 @@ function node_delete_confirm_submit($for
 function node_revision_overview($node) {
   drupal_set_title(t('Revisions for %title', array('%title' => $node->title)), PASS_THROUGH);
 
-  $header = array(t('Revision'), array('data' => t('Operations'), 'colspan' => 2));
+  $header = array(t('Revision'), array('data' => t('Operations'), 'colspan' => 3));
 
   $revisions = node_revision_list($node);
 
   $rows = array();
-  $revert_permission = FALSE;
-  if ((user_access('revert revisions') || user_access('administer nodes')) && node_access('update', $node)) {
-    $revert_permission = TRUE;
+  $edit_permission = FALSE;
+  if ((user_access('edit own $node->type content') || user_access('edit any $node->type content') || user_access('administer nodes')) && node_access('update', $node)) {
+    $edit_permission = TRUE;
   }
   $delete_permission = FALSE;
   if ((user_access('delete revisions') || user_access('administer nodes')) && node_access('delete', $node)) {
     $delete_permission = TRUE;
   }
+  $publish_permission = FALSE;
+  if (user_access('publish $node->type content') && (user_access('edit own $node->type content') || user_access('edit any $node->type content')) && node_access('update', $node)) {
+    $publish_permission = TRUE;
+  }
   foreach ($revisions as $revision) {
     $row = array();
     $operations = array();
@@ -501,21 +601,24 @@ function node_revision_overview($node) {
       $row[] = array('data' => t('!date by !username', array('!date' => l(format_date($revision->timestamp, 'small'), "node/$node->nid"), '!username' => theme('username', $revision)))
                                . (($revision->log != '') ? '<p class="revision-log">' . filter_xss($revision->log) . '</p>' : ''),
                      'class' => 'revision-current');
-      $operations[] = array('data' => theme('placeholder', t('current revision')), 'class' => 'revision-current', 'colspan' => 2);
+      $operations[] = array('data' => theme('placeholder', t('current revision')), 'class' => 'revision-current', 'colspan' => 3);
     }
     else {
       $row[] = t('!date by !username', array('!date' => l(format_date($revision->timestamp, 'small'), "node/$node->nid/revisions/$revision->vid/view"), '!username' => theme('username', $revision)))
                . (($revision->log != '') ? '<p class="revision-log">' . filter_xss($revision->log) . '</p>' : '');
-      if ($revert_permission) {
-        $operations[] = l(t('revert'), "node/$node->nid/revisions/$revision->vid/revert");
+      if ($publish_permission) {
+        $operations[] = l(t('publish'), "node/$node->nid/revisions/$revision->vid/revert");
       }
       if ($delete_permission) {
         $operations[] = l(t('delete'), "node/$node->nid/revisions/$revision->vid/delete");
       }
+      if ($edit_permission) {
+        $operations[] = l(t('edit'), "node/$node->nid/edit/revision/$revision->vid");
+      }
     }
     $rows[] = array_merge($row, $operations);
   }
-  
+
   $build['node_revisions_table'] = array(
     '#theme' => 'table',
     '#rows' => $rows,
@@ -530,12 +633,13 @@ function node_revision_overview($node) {
  */
 function node_revision_revert_confirm($form_state, $node_revision) {
   $form['#node_revision'] = $node_revision;
-  return confirm_form($form, t('Are you sure you want to revert to the revision from %revision-date?', array('%revision-date' => format_date($node_revision->revision_timestamp))), 'node/' . $node_revision->nid . '/revisions', '', t('Revert'), t('Cancel'));
+  return confirm_form($form, t('Are you sure you want to publish the revision from %revision-date?', array('%revision-date' => format_date($node_revision->revision_timestamp))), 'node/' . $node_revision->nid . '/revisions', '', t('Publish'), t('Cancel'));
 }
 
 function node_revision_revert_confirm_submit($form, &$form_state) {
   $node_revision = $form['#node_revision'];
   $node_revision->revision = 1;
+  $node_revision->draft = 0;
   $node_revision->log = t('Copy of the revision from %date.', array('%date' => format_date($node_revision->revision_timestamp)));
   if (module_exists('taxonomy')) {
     $node_revision->taxonomy = array_keys($node_revision->taxonomy);
@@ -555,12 +659,7 @@ function node_revision_delete_confirm($f
 
 function node_revision_delete_confirm_submit($form, &$form_state) {
   $node_revision = $form['#node_revision'];
-  db_delete('node_revision')
-    ->condition('nid', $node_revision->nid)
-    ->condition('vid', $node_revision->vid)
-    ->execute();
-  module_invoke_all('node_delete_revision', $node_revision);
-  field_attach_delete_revision('node', $node_revision);
+  node_delete_revision($node_revision->nid, $node_revision->vid);
   watchdog('content', '@type: deleted %title revision %revision.', array('@type' => $node_revision->type, '%title' => $node_revision->title, '%revision' => $node_revision->vid));
   drupal_set_message(t('Revision from %revision-date of @type %title has been deleted.', array('%revision-date' => format_date($node_revision->revision_timestamp), '@type' => node_type_get_name($node_revision), '%title' => $node_revision->title)));
   $form_state['redirect'] = 'node/' . $node_revision->nid;
Index: modules/node/node.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.test,v
retrieving revision 1.38
diff -u -p -r1.38 node.test
--- modules/node/node.test	28 Jul 2009 19:18:06 -0000	1.38
+++ modules/node/node.test	14 Aug 2009 12:21:48 -0000
@@ -150,7 +150,7 @@ class NodeRevisionsTestCase extends Drup
     }
 
     // Confirm that revisions revert properly.
-    $this->drupalPost("node/$node->nid/revisions/{$nodes[1]->vid}/revert", array(), t('Revert'));
+    $this->drupalPost("node/$node->nid/revisions/{$nodes[1]->vid}/revert", array(), t('Publish'));
     $this->assertRaw(t('@type %title has been reverted back to the revision from %revision-date.',
                         array('@type' => 'Page', '%title' => $nodes[1]->title,
                               '%revision-date' => format_date($nodes[1]->revision_timestamp))), t('Revision reverted.'));
@@ -191,7 +191,7 @@ class PageEditTestCase extends DrupalWeb
     $edit = array();
     $edit['title'] = $this->randomName(8);
     $edit[$body_key] = $this->randomName(16);
-    $this->drupalPost('node/add/page', $edit, t('Save'));
+    $this->drupalPost('node/add/page', $edit, t('Publish'));
 
     // Check that the node exists in the database.
     $node = $this->drupalGetNodeByTitle($edit['title']);
@@ -213,7 +213,7 @@ class PageEditTestCase extends DrupalWeb
     $edit['title'] = $this->randomName(8);
     $edit[$body_key] = $this->randomName(16);
     // Stay on the current page, without reloading.
-    $this->drupalPost(NULL, $edit, t('Save'));
+    $this->drupalPost(NULL, $edit, t('Publish'));
 
     // Check that the title and body fields are displayed with the updated values.
     $this->assertText($edit['title'], t('Title displayed.'));
@@ -312,7 +312,7 @@ class PageCreationTestCase extends Drupa
     $edit = array();
     $edit['title'] = $this->randomName(8);
     $edit['body[0][value]'] = $this->randomName(16);
-    $this->drupalPost('node/add/page', $edit, t('Save'));
+    $this->drupalPost('node/add/page', $edit, t('Publish'));
 
     // Check that the page has been created.
     $this->assertRaw(t('!post %title has been created.', array('!post' => 'Page', '%title' => $edit['title'])), t('Page created.'));
@@ -501,7 +501,7 @@ class NodePostSettingsTestCase extends D
     $edit = array();
     $edit['title'] = $this->randomName(8);
     $edit['body[0][value]'] = $this->randomName(16);
-    $this->drupalPost('node/add/page', $edit, t('Save'));
+    $this->drupalPost('node/add/page', $edit, t('Publish'));
 
     // Check that the post information is displayed.
     $node = $this->drupalGetNodeByTitle($edit['title']);
@@ -522,7 +522,7 @@ class NodePostSettingsTestCase extends D
     $edit = array();
     $edit['title'] = $this->randomName(8);
     $edit['body[0][value]'] = $this->randomName(16);
-    $this->drupalPost('node/add/page', $edit, t('Save'));
+    $this->drupalPost('node/add/page', $edit, t('Publish'));
 
     // Check that the post information is displayed.
     $node = $this->drupalGetNodeByTitle($edit['title']);
Index: modules/path/path.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/path/path.test,v
retrieving revision 1.17
diff -u -p -r1.17 path.test
--- modules/path/path.test	11 Aug 2009 11:52:46 -0000	1.17
+++ modules/path/path.test	14 Aug 2009 12:21:48 -0000
@@ -113,7 +113,7 @@ class PathTestCase extends DrupalWebTest
     // Create alias.
     $edit = array();
     $edit['path'] = $this->randomName(8);
-    $this->drupalPost('node/' . $node1->nid . '/edit', $edit, t('Save'));
+    $this->drupalPost('node/' . $node1->nid . '/edit', $edit, t('Publish'));
 
     // Confirm that the alias works.
     $this->drupalGet($edit['path']);
@@ -122,7 +122,7 @@ class PathTestCase extends DrupalWebTest
     // Change alias.
     $previous = $edit['path'];
     $edit['path'] = $this->randomName(8);
-    $this->drupalPost('node/' . $node1->nid . '/edit', $edit, t('Save'));
+    $this->drupalPost('node/' . $node1->nid . '/edit', $edit, t('Publish'));
 
     // Confirm that the alias works.
     $this->drupalGet($edit['path']);
@@ -138,13 +138,13 @@ class PathTestCase extends DrupalWebTest
 
     // Set alias to second test node.
     // Leave $edit['path'] the same.
-    $this->drupalPost('node/' . $node2->nid . '/edit', $edit, t('Save'));
+    $this->drupalPost('node/' . $node2->nid . '/edit', $edit, t('Publish'));
 
     // Confirm that the alias didn't make a duplicate.
     $this->assertText(t('The path is already in use.'), 'Attempt to moved alias was rejected.');
 
     // Delete alias.
-    $this->drupalPost('node/' . $node1->nid . '/edit', array('path' => ''), t('Save'));
+    $this->drupalPost('node/' . $node1->nid . '/edit', array('path' => ''), t('Publish'));
 
     // Confirm that the alias no longer works.
     $this->drupalGet($edit['path']);
@@ -201,7 +201,7 @@ class PathLanguageTestCase extends Drupa
     $edit = array();
     $edit['language'] = 'en';
     $edit['path'] = $this->randomName();
-    $this->drupalPost('node/' . $english_node->nid . '/edit', $edit, t('Save'));
+    $this->drupalPost('node/' . $english_node->nid . '/edit', $edit, t('Publish'));
 
     // Confirm that the alias works.
     $this->drupalGet($edit['path']);
@@ -214,7 +214,7 @@ class PathLanguageTestCase extends Drupa
     $edit['title'] = $this->randomName();
     $edit['body[0][value]'] = $this->randomName();
     $edit['path'] = $this->randomName();
-    $this->drupalPost(NULL, $edit, t('Save'));
+    $this->drupalPost(NULL, $edit, t('Publish'));
 
     // Clear the path lookup cache.
     drupal_lookup_path('wipe');
Index: modules/php/php.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/php/php.test,v
retrieving revision 1.14
diff -u -p -r1.14 php.test
--- modules/php/php.test	13 Jul 2009 21:51:11 -0000	1.14
+++ modules/php/php.test	14 Aug 2009 12:21:48 -0000
@@ -61,7 +61,7 @@ class PHPFilterTestCase extends PHPTestC
     // Change filter to PHP filter and see that PHP code is evaluated.
     $edit = array();
     $edit['body[0][value_format]'] = 3;
-    $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
+    $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Publish'));
     $this->assertRaw(t('Page %title has been updated.', array('%title' => $node->title)), t('PHP code filter turned on.'));
 
     // Make sure that the PHP code shows up as text.
Index: modules/poll/poll.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/poll/poll.test,v
retrieving revision 1.21
diff -u -p -r1.21 poll.test
--- modules/poll/poll.test	20 Jul 2009 18:51:33 -0000	1.21
+++ modules/poll/poll.test	14 Aug 2009 12:21:49 -0000
@@ -44,7 +44,7 @@ class PollTestCase extends DrupalWebTest
       list($edit, $index) = $this->_pollGenerateEdit($title, $choices, $index);
     }
 
-    $this->drupalPost(NULL, $edit, t('Save'));
+    $this->drupalPost(NULL, $edit, t('Publish'));
     $node = $this->drupalGetNodeByTitle($title);
     $this->assertText(t('@type @title has been created.', array('@type' => node_type_get_name('poll'), '@title' => $title)), 'Poll has been created.');
     $this->assertTrue($node->nid, t('Poll has been found in the database.'));
@@ -79,7 +79,7 @@ class PollTestCase extends DrupalWebTest
 
   function pollUpdate($nid, $title, $edit) {
     // Edit the poll node.
-    $this->drupalPost('node/' . $nid . '/edit', $edit, t('Save'));
+    $this->drupalPost('node/' . $nid . '/edit', $edit, t('Publish'));
     $this->assertText(t('@type @title has been updated.', array('@type' => node_type_get_name('poll'), '@title' => $title)), 'Poll has been updated.');
   }
 }
Index: modules/system/system.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.install,v
retrieving revision 1.367
diff -u -p -r1.367 system.install
--- modules/system/system.install	12 Aug 2009 23:51:19 -0000	1.367
+++ modules/system/system.install	14 Aug 2009 12:21:50 -0000
@@ -1444,6 +1444,8 @@ function system_update_7000() {
     $renamed_permission = preg_replace('/(?<=^|,\ )delete\ own\ forum\ topics(?=,|$)/', 'delete own forum content', $role->perm);
     $renamed_permission = preg_replace('/(?<=^|,\ )edit\ any\ forum\ topic(?=,|$)/', 'edit any forum content', $role->perm);
     $renamed_permission = preg_replace('/(?<=^|,\ )edit\ own\ forum\ topics(?=,|$)/', 'edit own forum content', $role->perm);
+    // Also remove the 'revert revisions' permission.
+    $renamed_permission = preg_replace('/(?<=^|,\ )revert\ revisions(?=, |$)/', '', $role->perm);
 
     if ($renamed_permission != $role->perm) {
       $ret[] = update_sql("UPDATE {permission} SET perm = '$renamed_permission' WHERE rid = $role->rid");
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.744
diff -u -p -r1.744 system.module
--- modules/system/system.module	13 Aug 2009 11:31:26 -0000	1.744
+++ modules/system/system.module	14 Aug 2009 12:21:53 -0000
@@ -706,19 +706,13 @@ function system_menu() {
     'page arguments' => array('system_site_information_settings'),
     'access arguments' => array('administer site configuration'),
   );
-  $items['admin/settings/logging'] = array(
+  $items['admin/config/development/logging'] = array(
     'title' => 'Logging and errors',
     'description' => "Settings for logging and alerts modules. Various modules can route Drupal's system events to different destinations, such as syslog, database, email, etc.",
     'page callback' => 'drupal_get_form',
     'page arguments' => array('system_logging_settings'),
     'access arguments' => array('administer site configuration'),
   );
-  $items['admin/settings/logging/settings'] = array(
-    'title' => 'Settings',
-    'access arguments' => array('administer site configuration'),
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-    'weight' => -1,
-  );
   $items['admin/settings/file-system'] = array(
     'title' => 'File system',
     'description' => 'Tell Drupal where to store uploaded files and how they are accessed.',
Index: modules/system/system.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.test,v
retrieving revision 1.63
diff -u -p -r1.63 system.test
--- modules/system/system.test	12 Aug 2009 23:51:19 -0000	1.63
+++ modules/system/system.test	14 Aug 2009 12:21:54 -0000
@@ -701,7 +701,7 @@ class PageTitleFiltering extends DrupalW
      'body[0][value]' => '!SimpleTest! test body' . $this->randomName(200),
     );
     // Create the node with HTML in the title.
-    $this->drupalPost('node/add/page', $edit, t('Save'));
+    $this->drupalPost('node/add/page', $edit, t('Publish'));
 
     $node = $this->drupalGetNodeByTitle($edit['title']);
     $this->assertNotNull($node, 'Node created and found in database');
Index: modules/taxonomy/taxonomy.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.test,v
retrieving revision 1.43
diff -u -p -r1.43 taxonomy.test
--- modules/taxonomy/taxonomy.test	4 Aug 2009 06:50:07 -0000	1.43
+++ modules/taxonomy/taxonomy.test	14 Aug 2009 12:21:54 -0000
@@ -455,7 +455,7 @@ class TaxonomyTermTestCase extends Taxon
     $edit['title'] = $this->randomName();
     $edit['body[0][value]'] = $this->randomName();
     $edit['taxonomy[' . $this->vocabulary->vid . ']'] = $term1->tid;
-    $this->drupalPost('node/add/article', $edit, t('Save'));
+    $this->drupalPost('node/add/article', $edit, t('Publish'));
 
     // Check that the term is displayed when the node is viewed.
     $node = $this->drupalGetNodeByTitle($edit['title']);
@@ -464,7 +464,7 @@ class TaxonomyTermTestCase extends Taxon
 
     // Edit the node with a different term.
     $edit['taxonomy[' . $this->vocabulary->vid . ']'] = $term2->tid;
-    $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
+    $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Publish'));
 
     $this->drupalGet('node/' . $node->nid);
     $this->assertText($term2->name, t('Term is displayed when viewing the node.'));
@@ -496,7 +496,7 @@ class TaxonomyTermTestCase extends Taxon
     // free-tagging field created by the default profile.
     $edit['taxonomy[tags][' . $this->vocabulary->vid . ']'] =  implode(', ', $terms);
     $edit['body[0][value]'] = $this->randomName();
-    $this->drupalPost('node/add/article', $edit, t('Save'));
+    $this->drupalPost('node/add/article', $edit, t('Publish'));
     $this->assertRaw(t('@type %title has been created.', array('@type' => t('Article'), '%title' => $edit['title'])), t('The node was created successfully'));
     foreach ($terms as $term) {
       $this->assertText($term, t('The term was saved and appears on the node page'));
Index: modules/translation/translation.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/translation/translation.test,v
retrieving revision 1.15
diff -u -p -r1.15 translation.test
--- modules/translation/translation.test	11 Aug 2009 11:52:46 -0000	1.15
+++ modules/translation/translation.test	14 Aug 2009 12:21:54 -0000
@@ -61,7 +61,7 @@ class TranslationTestCase extends Drupal
     $edit = array();
     $edit['title'] = $this->randomName();
     $edit['body[0][value]'] = $this->randomName();
-    $this->drupalPost('node/add/page', $edit, t('Save'), array('query' => array('translation' => $node->nid, 'language' => 'es')));
+    $this->drupalPost('node/add/page', $edit, t('Publish'), array('query' => array('translation' => $node->nid, 'language' => 'es')));
     $duplicate = $this->drupalGetNodeByTitle($edit['title']);
     $this->assertEqual($duplicate->tnid, 0, t('The node does not have a tnid.'));
 
@@ -69,7 +69,7 @@ class TranslationTestCase extends Drupal
     $edit = array();
     $edit['body[0][value]'] = $this->randomName();
     $edit['translation[retranslate]'] = TRUE;
-    $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
+    $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Publish'));
     $this->assertRaw(t('Page %title has been updated.', array('%title' => $node_title)), t('Original node updated.'));
 
     // Check to make sure that interface shows translation as outdated
@@ -80,7 +80,7 @@ class TranslationTestCase extends Drupal
     $edit = array();
     $edit['body[0][value]'] = $this->randomName();
     $edit['translation[status]'] = FALSE;
-    $this->drupalPost('node/' . $node_translation->nid . '/edit', $edit, t('Save'));
+    $this->drupalPost('node/' . $node_translation->nid . '/edit', $edit, t('Publish'));
     $this->assertRaw(t('Page %title has been updated.', array('%title' => $node_translation_title)), t('Translated node updated.'));
   }
 
@@ -130,7 +130,7 @@ class TranslationTestCase extends Drupal
     $edit['title'] = $title;
     $edit['body[0][value]'] = $body;
     $edit['language'] = $language;
-    $this->drupalPost('node/add/page', $edit, t('Save'));
+    $this->drupalPost('node/add/page', $edit, t('Publish'));
     $this->assertRaw(t('Page %title has been created.', array('%title' => $edit['title'])), t('Page created.'));
 
     // Check to make sure the node was created.
@@ -154,7 +154,7 @@ class TranslationTestCase extends Drupal
     $edit = array();
     $edit['title'] = $title;
     $edit['body[0][value]'] = $body;
-    $this->drupalPost(NULL, $edit, t('Save'));
+    $this->drupalPost(NULL, $edit, t('Publish'));
     $this->assertRaw(t('Page %title has been created.', array('%title' => $edit['title'])), t('Translation created.'));
 
     // Check to make sure that translation was successful.
Index: modules/trigger/trigger.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/trigger/trigger.test,v
retrieving revision 1.15
diff -u -p -r1.15 trigger.test
--- modules/trigger/trigger.test	28 Jul 2009 19:18:08 -0000	1.15
+++ modules/trigger/trigger.test	14 Aug 2009 12:21:55 -0000
@@ -33,18 +33,30 @@ class TriggerContentTestCase extends Dru
       $this->drupalLogin($test_user);
       $edit = array('aid' => $hash);
       $this->drupalPost('admin/structure/trigger/node', $edit, t('Assign'));
-      // Create an unpublished node.
-      $web_user = $this->drupalCreateUser(array('create page content', 'access content', 'administer nodes'));
+      // Create a node.
+      $web_user = $this->drupalCreateUser(array('create page content', 'edit any page content', 'access content', 'administer nodes'));
       $this->drupalLogin($web_user);
       $edit = array();
       $edit['title'] = '!SimpleTest test node! ' . $this->randomName(10);
       $edit['body[0][value]'] = '!SimpleTest test body! ' . $this->randomName(32) . ' ' . $this->randomName(32);
-      $edit[$info['property']] = !$info['expected'];
-      $this->drupalPost('node/add/page', $edit, t('Save'));
-      // Make sure the text we want appears.
-      $this->assertRaw(t('!post %title has been created.', array('!post' => 'Page', '%title' => $edit['title'])), t('Make sure the page has actually been created'));
+
+      // Publish and unpublish are buttons rather than checkboxes.
+      if ($action == 'node_publish_action') {
+        $this->drupalPost('node/add/page', $edit, t('Publish'));
+      }
+      elseif ($action == 'node_unpublish_action') {
+        // The 'Unpublish' button does not appear on the node/add page
+        // so use 'save as draft' instead.
+        $this->drupalPost('node/add/page', $edit, t('Save as draft'));
+      }
+      else {
+        $edit[$info['property']] = !$info['expected'];
+        $this->drupalPost('node/add/page', $edit, t('Publish'));
+        // Make sure the text we want appears.
+        $this->assertRaw(t('!post %title has been created.', array('!post' => 'Page', '%title' => $edit['title'])), t('Make sure the page has actually been created'));
+      }
       // Action should have been fired.
-      $loaded_node = $this->drupalGetNodeByTitle($edit['title']);;
+      $loaded_node = $this->drupalGetNodeByTitle($edit['title']);
       $this->assertTrue($loaded_node->$info['property'] == $info['expected'], t('Make sure the @action action fired.', array('@action' => $info['name'])));
       // Leave action assigned for next test
 
Index: modules/upload/upload.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/upload/upload.test,v
retrieving revision 1.22
diff -u -p -r1.22 upload.test
--- modules/upload/upload.test	28 Jul 2009 19:18:08 -0000	1.22
+++ modules/upload/upload.test	14 Aug 2009 12:21:55 -0000
@@ -73,7 +73,7 @@ class UploadTestCase extends DrupalWebTe
       // Rename file.
       $edit = array();
       $edit['files[' . $upload->fid . '][description]'] = $new_name = substr($upload->description, 1);
-      $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
+      $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Publish'));
       $this->assertRaw(t('Page %title has been updated.', array('%title' => $node->title)), 'File renamed successfully.');
 
       $this->assertText($new_name, $new_name . ' found on node.');
@@ -82,7 +82,7 @@ class UploadTestCase extends DrupalWebTe
       // Delete a file.
       $edit = array();
       $edit['files[' . $upload->fid . '][remove]'] = TRUE;
-      $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
+      $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Publish'));
       $this->assertRaw(t('Page %title has been updated.', array('%title' => $node->title)), 'File deleted successfully.');
 
       $this->assertNoText($new_name, $new_name . ' not found on node.');
@@ -193,7 +193,7 @@ class UploadTestCase extends DrupalWebTe
   function uploadFile($node, $filename, $assert = TRUE) {
     $edit = array();
     $edit['files[upload]'] = $filename; //edit-upload
-    $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
+    $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Publish'));
     if ($assert) {
       $this->assertRaw(t('Page %title has been updated.', array('%title' => $node->title)), 'File attached successfully.');
     }
