diff --git a/core/modules/node/content_types.inc b/core/modules/node/content_types.inc
new file mode 100644
index 0000000..0a91f6b
--- /dev/null
+++ b/core/modules/node/content_types.inc
@@ -0,0 +1,496 @@
+<?php
+
+/**
+ * @file
+ * Content type editing UI.
+ */
+
+/**
+ * Page callback: Displays the content type admin overview page.
+ *
+ * @see node_menu()
+ */
+function node_overview_types() {
+  $types = node_type_get_types();
+  $names = node_type_get_names();
+  $field_ui = module_exists('field_ui');
+  $header = array(t('Name'), array('data' => t('Operations'), 'colspan' => $field_ui ? '4' : '2'));
+  $rows = array();
+
+  foreach ($names as $key => $name) {
+    $type = $types[$key];
+    if (node_hook($type->type, 'form')) {
+      $row = array(theme('node_admin_overview', array('name' => $name, 'type' => $type)));
+      // Set the edit column.
+      $row[] = array('data' => l(t('edit'), 'admin/structure/types/manage/' . $type->type));
+
+      if ($field_ui) {
+        // Manage fields.
+        $row[] = array('data' => l(t('manage fields'), 'admin/structure/types/manage/' . $type->type . '/fields'));
+
+        // Display fields.
+        $row[] = array('data' => l(t('manage display'), 'admin/structure/types/manage/' . $type->type . '/display'));
+      }
+
+      // Set the delete column.
+      if ($type->custom) {
+        $row[] = array('data' => l(t('delete'), 'admin/structure/types/manage/' . $type->type . '/delete'));
+      }
+      else {
+        $row[] = array('data' => '');
+      }
+
+      $rows[] = $row;
+    }
+  }
+
+  $build['node_table'] = array(
+    '#theme' => 'table',
+    '#header' => $header,
+    '#rows' => $rows,
+    '#empty' => t('No content types available. <a href="@link">Add content type</a>.', array('@link' => url('admin/structure/types/add'))),
+  );
+
+  return $build;
+}
+
+/**
+ * Returns HTML for a node type description for the content type admin page.
+ *
+ * @param $variables
+ *   An associative array containing:
+ *   - name: The human-readable name of the content type.
+ *   - type: An object containing the 'type' (machine name) and 'description' of
+ *     the content type.
+ *
+ * @ingroup themeable
+ */
+function theme_node_admin_overview($variables) {
+  $name = $variables['name'];
+  $type = $variables['type'];
+
+  $output = check_plain($name);
+  $output .= ' <small>' . t('(Machine name: @type)', array('@type' => $type->type)) . '</small>';
+  $output .= '<div class="description">' . filter_xss_admin($type->description) . '</div>';
+  return $output;
+}
+
+/**
+ * Form constructor for the node type editing form.
+ *
+ * @param $type
+ *   (optional) An object representing the node type, when editing an existing
+ *   node type.
+ *
+ * @see node_type_form_validate()
+ * @see node_type_form_submit()
+ * @ingroup forms
+ */
+function node_type_form($form, &$form_state, $type = NULL) {
+  if (!isset($type->type)) {
+    // This is a new type. Node module managed types are custom and unlocked.
+    $type = node_type_set_defaults(array('custom' => 1, 'locked' => 0));
+  }
+
+  // Make the type object available to implementations of hook_form_alter.
+  $form['#node_type'] = $type;
+
+  $form['name'] = array(
+    '#title' => t('Name'),
+    '#type' => 'textfield',
+    '#default_value' => $type->name,
+    '#description' => t('The human-readable name of this content type. This text will be displayed as part of the list on the <em>Add new content</em> page. It is recommended that this name begin with a capital letter and contain only letters, numbers, and spaces. This name must be unique.'),
+    '#required' => TRUE,
+    '#size' => 30,
+  );
+
+  $form['type'] = array(
+    '#type' => 'machine_name',
+    '#default_value' => $type->type,
+    '#maxlength' => 32,
+    '#disabled' => $type->locked,
+    '#machine_name' => array(
+      'exists' => 'node_type_load',
+    ),
+    '#description' => t('A unique machine-readable name for this content type. It must only contain lowercase letters, numbers, and underscores. This name will be used for constructing the URL of the %node-add page, in which underscores will be converted into hyphens.', array(
+      '%node-add' => t('Add new content'),
+    )),
+  );
+
+  $form['description'] = array(
+    '#title' => t('Description'),
+    '#type' => 'textarea',
+    '#default_value' => $type->description,
+    '#description' => t('Describe this content type. The text will be displayed on the <em>Add new content</em> page.'),
+  );
+
+  $form['additional_settings'] = array(
+    '#type' => 'vertical_tabs',
+    '#attached' => array(
+      'library' => array(array('node', 'drupal.content_types')),
+    ),
+  );
+
+  $form['submission'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Submission form settings'),
+    '#collapsible' => TRUE,
+    '#group' => 'additional_settings',
+  );
+  $form['submission']['title_label'] = array(
+    '#title' => t('Title field label'),
+    '#type' => 'textfield',
+    '#default_value' => $type->title_label,
+    '#required' => TRUE,
+  );
+  if (!$type->has_title) {
+    // Avoid overwriting a content type that intentionally does not have a
+    // title field.
+    $form['submission']['title_label']['#attributes'] = array('disabled' => 'disabled');
+    $form['submission']['title_label']['#description'] = t('This content type does not have a title field.');
+    $form['submission']['title_label']['#required'] = FALSE;
+  }
+  $form['submission']['node_preview'] = array(
+    '#type' => 'radios',
+    '#title' => t('Preview before submitting'),
+    '#default_value' => variable_get('node_preview_' . $type->type, DRUPAL_OPTIONAL),
+    '#options' => array(
+      DRUPAL_DISABLED => t('Disabled'),
+      DRUPAL_OPTIONAL => t('Optional'),
+      DRUPAL_REQUIRED => t('Required'),
+    ),
+  );
+  $form['submission']['help']  = array(
+    '#type' => 'textarea',
+    '#title' => t('Explanation or submission guidelines'),
+    '#default_value' => $type->help,
+    '#description' => t('This text will be displayed at the top of the page when creating or editing content of this type.'),
+  );
+  $form['workflow'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Publishing options'),
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#group' => 'additional_settings',
+  );
+  $form['workflow']['node_options'] = array('#type' => 'checkboxes',
+    '#title' => t('Default options'),
+    '#default_value' => variable_get('node_options_' . $type->type, array('status', 'promote')),
+    '#options' => array(
+      'status' => t('Published'),
+      'promote' => t('Promoted to front page'),
+      'sticky' => t('Sticky at top of lists'),
+      'revision' => t('Create new revision'),
+    ),
+    '#description' => t('Users with the <em>Administer content</em> permission will be able to override these options.'),
+  );
+  if (module_exists('language')) {
+    $lang_options = array();
+
+    $languages = language_list(LANGUAGE_ALL);
+    foreach ($languages as $langcode => $language) {
+      $lang_options[$langcode] = $language->locked ? t('- @name -', array('@name' => $language->name)) : $language->name;
+    }
+
+    $lang_options += array(
+      'site_default' => t("Site's default language"),
+      'current_interface' => t('Current interface language'),
+      'authors_default' => t("Author's preferred language"),
+    );
+
+    $form['language'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Language settings'),
+      '#collapsible' => TRUE,
+      '#collapsed' => TRUE,
+      '#group' => 'additional_settings',
+    );
+    $form['language']['node_type_language_default'] = array(
+      '#type' => 'select',
+      '#title' => t('Default language'),
+      '#options' => $lang_options,
+      '#default_value' => variable_get('node_type_language_default_' . $type->type, 'site_default'),
+      '#description' => t('Explanation of the language options is found on the <a href="@languages_list_page">languages list page</a>.', array('@languages_list_page' => url('admin/config/regional/language'))),
+    );
+    $form['language']['node_type_language_hidden'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Hide language selector'),
+      '#default_value' => variable_get('node_type_language_hidden_' . $type->type, TRUE),
+    );
+  }
+  $form['display'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Display settings'),
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#group' => 'additional_settings',
+  );
+  $form['display']['node_submitted'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Display author and date information.'),
+    '#default_value' => variable_get('node_submitted_' . $type->type, TRUE),
+    '#description' => t('Author username and publish date will be displayed.'),
+  );
+  // Get list of all available date types.
+  drupal_static_reset('system_get_date_types');
+  $format_types = system_get_date_types();
+  $types = array();
+  $format_date = array();
+  foreach ($format_types as $format_type) {
+    $types[$format_type['type']] = $format_type['title'];
+    $format_date[$format_type['type']] = format_date(REQUEST_TIME, $format_type['type']);
+  }
+  $default_format = variable_get('node_date_format_' . $type->type, 'medium');
+  $form['display']['node_date_format'] = array(
+    '#type' => 'select',
+    '#title' => t('Date format.'),
+    '#options' => $format_date,
+    '#default_value' => $default_format,
+    '#description' => t('Select the date format the content type will use.'),
+  );
+  $form['old_type'] = array(
+    '#type' => 'value',
+    '#value' => $type->type,
+  );
+  $form['orig_type'] = array(
+    '#type' => 'value',
+    '#value' => isset($type->orig_type) ? $type->orig_type : '',
+  );
+  $form['base'] = array(
+    '#type' => 'value',
+    '#value' => $type->base,
+  );
+  $form['custom'] = array(
+    '#type' => 'value',
+    '#value' => $type->custom,
+  );
+  $form['modified'] = array(
+    '#type' => 'value',
+    '#value' => $type->modified,
+  );
+  $form['locked'] = array(
+    '#type' => 'value',
+    '#value' => $type->locked,
+  );
+
+  $form['actions'] = array('#type' => 'actions');
+  $form['actions']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save content type'),
+    '#weight' => 40,
+  );
+
+  if ($type->custom) {
+    if (!empty($type->type)) {
+      $form['actions']['delete'] = array(
+        '#type' => 'submit',
+        '#value' => t('Delete content type'),
+        '#weight' => 45,
+      );
+    }
+  }
+
+  return $form;
+}
+
+/**
+ * Helper function for teaser length choices.
+ */
+function _node_characters($length) {
+  return ($length == 0) ? t('Unlimited') : format_plural($length, '1 character', '@count characters');
+}
+
+/**
+ * Form validation handler for node_type_form().
+ *
+ * @see node_type_form_submit()
+ */
+function node_type_form_validate($form, &$form_state) {
+  $type = new stdClass();
+  $type->type = trim($form_state['values']['type']);
+  $type->name = trim($form_state['values']['name']);
+
+  // Work out what the type was before the user submitted this form
+  $old_type = trim($form_state['values']['old_type']);
+
+  $types = node_type_get_names();
+
+  if (!$form_state['values']['locked']) {
+    // 'theme' conflicts with theme_node_form().
+    // '0' is invalid, since elsewhere we check it using empty().
+    if (in_array($type->type, array('0', 'theme'))) {
+      form_set_error('type', t("Invalid machine-readable name. Enter a name other than %invalid.", array('%invalid' => $type->type)));
+    }
+  }
+
+  $names = array_flip($types);
+
+  if (isset($names[$type->name]) && $names[$type->name] != $old_type) {
+    form_set_error('name', t('The human-readable name %name is already taken.', array('%name' => $type->name)));
+  }
+}
+
+/**
+ * Form submission handler for node_type_form().
+ *
+ * @see node_type_form_validate()
+ */
+function node_type_form_submit($form, &$form_state) {
+  $op = isset($form_state['values']['op']) ? $form_state['values']['op'] : '';
+
+  $type = node_type_set_defaults();
+
+  $type->type = trim($form_state['values']['type']);
+  $type->name = trim($form_state['values']['name']);
+  $type->orig_type = trim($form_state['values']['orig_type']);
+  $type->old_type = isset($form_state['values']['old_type']) ? $form_state['values']['old_type'] : $type->type;
+
+  $type->description = $form_state['values']['description'];
+  $type->help = $form_state['values']['help'];
+  $type->title_label = $form_state['values']['title_label'];
+  // title_label is required in core; has_title will always be true, unless a
+  // module alters the title field.
+  $type->has_title = ($type->title_label != '');
+
+  $type->base = !empty($form_state['values']['base']) ? $form_state['values']['base'] : 'node_content';
+  $type->custom = $form_state['values']['custom'];
+  $type->modified = TRUE;
+  $type->locked = $form_state['values']['locked'];
+  if (isset($form['#node_type']->module)) {
+    $type->module = $form['#node_type']->module;
+  }
+
+  if ($op == t('Delete content type')) {
+    $form_state['redirect'] = 'admin/structure/types/manage/' . $type->old_type . '/delete';
+    return;
+  }
+
+  $variables = $form_state['values'];
+
+  // Remove everything that's been saved already - whatever's left is assumed
+  // to be a persistent variable.
+  foreach ($variables as $key => $value) {
+    if (isset($type->$key)) {
+      unset($variables[$key]);
+    }
+  }
+
+  unset($variables['form_token'], $variables['op'], $variables['submit'], $variables['delete'], $variables['reset'], $variables['form_id'], $variables['form_build_id']);
+
+  // Save or reset persistent variable values.
+  foreach ($variables as $key => $value) {
+    $variable_new = $key . '_' . $type->type;
+    $variable_old = $key . '_' . $type->old_type;
+
+    if (is_array($value)) {
+      $value = array_keys(array_filter($value));
+    }
+    variable_set($variable_new, $value);
+
+    if ($variable_new != $variable_old) {
+      variable_del($variable_old);
+    }
+  }
+
+  // Saving the content type after saving the variables allows modules to act
+  // on those variables via hook_node_type_insert().
+  $status = node_type_save($type);
+
+  node_types_rebuild();
+  menu_router_rebuild();
+  $t_args = array('%name' => $type->name);
+
+  if ($status == SAVED_UPDATED) {
+    drupal_set_message(t('The content type %name has been updated.', $t_args));
+  }
+  elseif ($status == SAVED_NEW) {
+    node_add_body_field($type);
+    drupal_set_message(t('The content type %name has been added.', $t_args));
+    watchdog('node', 'Added content type %name.', $t_args, WATCHDOG_NOTICE, l(t('view'), 'admin/structure/types'));
+  }
+
+  $form_state['redirect'] = 'admin/structure/types';
+  return;
+}
+
+/**
+ * Implements hook_node_type_update().
+ */
+function node_node_type_update($info) {
+  if (!empty($info->old_type) && $info->old_type != $info->type) {
+    $update_count = node_type_update_nodes($info->old_type, $info->type);
+
+    if ($update_count) {
+      drupal_set_message(format_plural($update_count, 'Changed the content type of 1 post from %old-type to %type.', 'Changed the content type of @count posts from %old-type to %type.', array('%old-type' => $info->old_type, '%type' => $info->type)));
+    }
+  }
+}
+
+/**
+ * Resets all of the relevant fields of a module-defined node type to their
+ * default values.
+ *
+ * @param $type
+ *   The node type to reset. The node type is passed back by reference with its
+ *   resetted values. If there is no module-defined info for this node type,
+ *   then nothing happens.
+ */
+function node_type_reset($type) {
+  $info_array = module_invoke_all('node_info');
+  if (isset($info_array[$type->orig_type])) {
+    $info_array[$type->orig_type]['type'] = $type->orig_type;
+    $info = node_type_set_defaults($info_array[$type->orig_type]);
+
+    foreach ($info as $field => $value) {
+      $type->$field = $value;
+    }
+  }
+}
+
+/**
+ * Page callback: Form constructor for the content type delete form.
+ *
+ * @param $type
+ *   Content type object.
+ *
+ * @return
+ *   Form array for delete confirmation form.
+ *
+ * @see node_type_delete_confirm_submit()
+ */
+function node_type_delete_confirm($form, &$form_state, $type) {
+  $form['type'] = array('#type' => 'value', '#value' => $type->type);
+  $form['name'] = array('#type' => 'value', '#value' => $type->name);
+
+  $message = t('Are you sure you want to delete the content type %type?', array('%type' => $type->name));
+
+  $num_nodes = db_query("SELECT COUNT(*) FROM {node} WHERE type = :type", array(':type' => $type->type))->fetchField();
+  if ($num_nodes) {
+    drupal_set_title($message, PASS_THROUGH);
+    $caption = '<p>' . format_plural($num_nodes, '%type is used by 1 piece of content on your site. You can not remove this content type until you have removed all of the %type content.', '%type is used by @count pieces of content on your site. You may not remove %type until you have removed all of the %type content.', array('%type' => $type->name)) . '</p>';
+    $form['description'] = array('#markup' => $caption);
+    return $form;
+  }
+
+  $caption = '<p>' . t('This action cannot be undone.') . '</p>';
+
+  return confirm_form($form, $message, 'admin/structure/types', $caption, t('Delete'));
+}
+
+/**
+ * Form submission handler for node_type_delete_confirm().
+ */
+function node_type_delete_confirm_submit($form, &$form_state) {
+  node_type_delete($form_state['values']['type']);
+
+  variable_del('node_preview_' . $form_state['values']['type']);
+  $t_args = array('%name' => $form_state['values']['name']);
+  drupal_set_message(t('The content type %name has been deleted.', $t_args));
+  watchdog('node', 'Deleted content type %name.', $t_args, WATCHDOG_NOTICE);
+
+  node_types_rebuild();
+  menu_router_rebuild();
+
+  $form_state['redirect'] = 'admin/structure/types';
+  return;
+}
diff --git a/core/modules/node/content_types.js b/core/modules/node/content_types.js
index 96733a2..df64056 100644
--- a/core/modules/node/content_types.js
+++ b/core/modules/node/content_types.js
@@ -56,7 +56,15 @@
         }
         return vals.join(', ');
       });
-    }
-  };
+      if (!$context.find('#edit-node-submitted').is(':checked')) {
+        vals.unshift(Drupal.t("Don't display post information"));
+      }
+      $context.find(':selected').text(function() {
+        vals.push(Drupal.checkPlain($(this).text()));
+      });
+      return vals.join(', ');
+    });
+  }
+};
 
 })(jQuery);
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index a54fc0a..758fe7b 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -524,6 +524,1501 @@ function node_preprocess_html(&$variables) {
   if (($node = \Drupal::routeMatch()->getParameter('node')) && $node instanceof NodeInterface) {
     $variables['node_type'] = $node->getType();
   }
+  $query = db_select('node_type', 'nt')
+    ->addTag('translatable')
+    ->addTag('node_type_access')
+    ->fields('nt')
+    ->orderBy('nt.type', 'ASC');
+  if (!$rebuild) {
+    $query->condition('disabled', 0);
+  }
+  foreach ($query->execute() as $type_object) {
+    $type_db = $type_object->type;
+    // Original disabled value.
+    $disabled = $type_object->disabled;
+    // Check for node types from disabled modules and mark their types for removal.
+    // Types defined by the node module in the database (rather than by a separate
+    // module using hook_node_info) have a base value of 'node_content'. The isset()
+    // check prevents errors on old (pre-Drupal 7) databases.
+    if (isset($type_object->base) && $type_object->base != 'node_content' && empty($_node_types->types[$type_db])) {
+      $type_object->disabled = TRUE;
+    }
+    if (isset($_node_types->types[$type_db])) {
+      $type_object->disabled = FALSE;
+    }
+    if (!isset($_node_types->types[$type_db]) || $type_object->modified) {
+      $_node_types->types[$type_db] = $type_object;
+      $_node_types->names[$type_db] = $type_object->name;
+
+      if ($type_db != $type_object->orig_type) {
+        unset($_node_types->types[$type_object->orig_type]);
+        unset($_node_types->names[$type_object->orig_type]);
+      }
+    }
+    $_node_types->types[$type_db]->disabled = $type_object->disabled;
+    $_node_types->types[$type_db]->disabled_changed = $disabled != $type_object->disabled;
+  }
+
+  if ($rebuild) {
+    foreach ($_node_types->types as $type => $type_object) {
+      if (!empty($type_object->is_new) || !empty($type_object->disabled_changed)) {
+        node_type_save($type_object);
+      }
+    }
+  }
+
+  asort($_node_types->names);
+
+  cache()->set($cid, $_node_types);
+
+  return $_node_types;
+}
+
+/**
+ * Clears the node type cache.
+ */
+function node_type_cache_reset() {
+  cache()->deletePrefix('node_types:');
+  drupal_static_reset('_node_types_build');
+}
+
+/**
+ * Sets the default values for a node type.
+ *
+ * The defaults are appropriate for a type defined through hook_node_info(),
+ * since 'custom' is TRUE for types defined in the user interface, and FALSE
+ * for types defined by modules. (The 'custom' flag prevents types from being
+ * deleted through the user interface.) Also, the default for 'locked' is TRUE,
+ * which prevents users from changing the machine name of the type.
+ *
+ * @param $info
+ *   (optional) An object or array containing values to override the defaults.
+ *   See hook_node_info() for details on what the array elements mean.
+ *
+ * @return
+ *   A node type object, with missing values in $info set to their defaults.
+ */
+function node_type_set_defaults($info = array()) {
+  $info = (array) $info;
+  $new_type = $info + array(
+    'type' => '',
+    'name' => '',
+    'base' => '',
+    'description' => '',
+    'help' => '',
+    'custom' => 0,
+    'modified' => 0,
+    'locked' => 1,
+    'disabled' => 0,
+    'is_new' => 1,
+    'has_title' => 1,
+    'title_label' => 'Title',
+  );
+  $new_type = (object) $new_type;
+
+  // If the type has no title, set an empty label.
+  if (!$new_type->has_title) {
+    $new_type->title_label = '';
+  }
+  if (empty($new_type->module)) {
+    $new_type->module = $new_type->base == 'node_content' ? 'node' : '';
+  }
+  $new_type->orig_type = isset($info['type']) ? $info['type'] : '';
+
+  return $new_type;
+}
+
+/**
+ * Implements hook_rdf_mapping().
+ */
+function node_rdf_mapping() {
+  return array(
+    array(
+      'type' => 'node',
+      'bundle' => RDF_DEFAULT_BUNDLE,
+      'mapping' => array(
+        'rdftype' => array('sioc:Item', 'foaf:Document'),
+        'title' => array(
+          'predicates' => array('dc:title'),
+        ),
+        'created' => array(
+          'predicates' => array('dc:date', 'dc:created'),
+          'datatype' => 'xsd:dateTime',
+          'callback' => 'date_iso8601',
+        ),
+        'changed' => array(
+          'predicates' => array('dc:modified'),
+          'datatype' => 'xsd:dateTime',
+          'callback' => 'date_iso8601',
+        ),
+        'body' => array(
+          'predicates' => array('content:encoded'),
+        ),
+        'uid' => array(
+          'predicates' => array('sioc:has_creator'),
+          'type' => 'rel',
+        ),
+        'name' => array(
+          'predicates' => array('foaf:name'),
+        ),
+        'comment_count' => array(
+          'predicates' => array('sioc:num_replies'),
+          'datatype' => 'xsd:integer',
+        ),
+        'last_activity' => array(
+          'predicates' => array('sioc:last_activity_date'),
+          'datatype' => 'xsd:dateTime',
+          'callback' => 'date_iso8601',
+        ),
+      ),
+    ),
+  );
+}
+
+/**
+ * Determines whether a node hook exists.
+ *
+ * @param string $type
+ *   A string containing the node type.
+ * @param $hook
+ *   A string containing the name of the hook.
+ *
+ * @return string|false
+ *   A string containing the function name or FALSE if it isn't found.
+ */
+function node_hook($type, $hook) {
+  $base = node_type_get_base($type);
+  return module_hook($base, $hook) ? $base . '_' . $hook : FALSE;
+}
+
+/**
+ * Invokes a node hook.
+ *
+ * @param Drupal\node\Node $node
+ *   A Node entity.
+ * @param $hook
+ *   A string containing the name of the hook.
+ * @param $a2, $a3, $a4
+ *   Arguments to pass on to the hook, after the $node argument.
+ *
+ * @return
+ *   The returned value of the invoked hook.
+ */
+function node_invoke($node, $hook, $a2 = NULL, $a3 = NULL, $a4 = NULL) {
+  if ($function = node_hook($node->type, $hook)) {
+    return $function($node, $a2, $a3, $a4);
+  }
+}
+
+/**
+ * Loads node entities from the database.
+ *
+ * This function should be used whenever you need to load more than one node
+ * from the database. Nodes are loaded into memory and will not require
+ * database access if loaded again during the same page request.
+ *
+ * @param array $nids
+ *   (optional) An array of entity IDs. If omitted, all entities are loaded.
+ * @param bool $reset
+ *   (optional) Whether to reset the internal node_load() cache.
+ *
+ * @return array
+ *   An array of node entities indexed by nid.
+ *
+ * @see entity_load_multiple()
+ * @see Drupal\Core\Entity\EntityFieldQuery
+ */
+function node_load_multiple(array $nids = NULL, $reset = FALSE) {
+  return entity_load_multiple('node', $nids, $reset);
+}
+
+/**
+ * Loads a node entity from the database.
+ *
+ * @param int $nid
+ *   The node ID.
+ * @param bool $reset
+ *   (optional) Whether to reset the node_load_multiple() cache.
+ *
+ * @return Drupal\node\Node|false
+ *   A fully-populated node entity, or FALSE if the node is not found.
+ */
+function node_load($nid = NULL, $reset = FALSE) {
+  return entity_load('node', $nid, $reset);
+}
+
+/**
+ * Loads a node revision from the database.
+ *
+ * @param int $nid
+ *   The node revision id.
+ *
+ * @return Drupal\node\Node|false
+ *   A fully-populated node entity, or FALSE if the node is not found.
+ */
+function node_revision_load($vid = NULL) {
+  return entity_revision_load('node', $vid);
+}
+
+/**
+ * Prepares a node for saving by populating the author and creation date.
+ */
+function node_submit($node) {
+  global $user;
+
+  // A user might assign the node author by entering a user name in the node
+  // form, which we then need to translate to a user ID.
+  if (isset($node->name)) {
+    if ($account = user_load_by_name($node->name)) {
+      $node->uid = $account->uid;
+    }
+    else {
+      $node->uid = 0;
+    }
+  }
+
+  // If a new revision is created, save the current user as revision author.
+  if (!empty($node->revision)) {
+    $node->revision_uid = $user->uid;
+  }
+
+  $node->created = !empty($node->date) ? strtotime($node->date) : REQUEST_TIME;
+  $node->validated = TRUE;
+
+  return $node;
+}
+
+/**
+ * Saves changes to a node or adds a new node.
+ *
+ * @param Drupal\node\Node $node
+ *   The $node entity to be saved. If $node->nid is
+ *   omitted (or $node->is_new is TRUE), a new node will be added.
+ */
+function node_save(Node $node) {
+  $node->save();
+}
+
+/**
+ * Deletes a node.
+ *
+ * @param $nid
+ *   A node ID.
+ */
+function node_delete($nid) {
+  node_delete_multiple(array($nid));
+}
+
+/**
+ * Deletes multiple nodes.
+ *
+ * @param $nids
+ *   An array of node IDs.
+ *
+ * @see hook_node_predelete()
+ * @see hook_node_delete()
+ */
+function node_delete_multiple($nids) {
+  entity_delete_multiple('node', $nids);
+}
+
+/**
+ * Deletes a node revision.
+ *
+ * @param $revision_id
+ *   The revision ID to delete.
+ *
+ * @return
+ *   TRUE if the revision deletion was successful.
+ */
+function node_revision_delete($revision_id) {
+  if ($revision = node_revision_load($revision_id)) {
+    // Prevent deleting the default revision.
+    if ($revision->isDefaultRevision()) {
+      return FALSE;
+    }
+
+    db_delete('node_revision')
+      ->condition('nid', $revision->nid)
+      ->condition('vid', $revision->vid)
+      ->execute();
+    module_invoke_all('node_revision_delete', $revision);
+    field_attach_delete_revision('node', $revision);
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**
+ * Generates an array for rendering the given node.
+ *
+ * @param Drupal\node\Node $node
+ *   A node entity.
+ * @param $view_mode
+ *   (optional) View mode, e.g., 'full', 'teaser'... Defaults to 'full.'
+ * @param $langcode
+ *   (optional) A language code to use for rendering. Defaults to the global
+ *   content language of the current request.
+ *
+ * @return
+ *   An array as expected by drupal_render().
+ */
+function node_view(Node $node, $view_mode = 'full', $langcode = NULL) {
+  if (!isset($langcode)) {
+    $langcode = language(LANGUAGE_TYPE_CONTENT)->langcode;
+  }
+
+  // Populate $node->content with a render() array.
+  node_build_content($node, $view_mode, $langcode);
+
+  // Add language text element on node view if language module is enabled.
+  if (module_exists('language')) {
+    $node->content['language'] = array(
+      '#type' => 'item',
+      '#title' => t('Language'),
+      '#markup' => language_name($langcode),
+      '#weight' => 0,
+      '#prefix' => '<div id="field-language-display">',
+      '#suffix' => '</div>'
+    );
+  }
+
+  $build = $node->content;
+  // We don't need duplicate rendering info in node->content.
+  unset($node->content);
+
+  $build += array(
+    '#theme' => 'node',
+    '#node' => $node,
+    '#view_mode' => $view_mode,
+    '#langcode' => $langcode,
+  );
+
+  // Add contextual links for this node, except when the node is already being
+  // displayed on its own page. Modules may alter this behavior (for example,
+  // to restrict contextual links to certain view modes) by implementing
+  // hook_node_view_alter().
+  if (!empty($node->nid) && !($view_mode == 'full' && node_is_page($node))) {
+    $build['#contextual_links']['node'] = array('node', array($node->nid));
+  }
+
+  // Allow modules to modify the structured node.
+  drupal_alter(array('node_view', 'entity_view'), $build, $node);
+
+  return $build;
+}
+
+/**
+ * Builds a structured array representing the node's content.
+ *
+ * The content built for the node (field values, comments, file attachments or
+ * other node components) will vary depending on the $view_mode parameter.
+ *
+ * Drupal core defines the following view modes for nodes, with the following
+ * default use cases:
+ *   - full (default): node is being displayed on its own page (node/123)
+ *   - teaser: node is being displayed on the default home page listing, or on
+ *     taxonomy listing pages.
+ *   - rss: node displayed in an RSS feed.
+ *   If search.module is enabled:
+ *   - search_index: node is being indexed for search.
+ *   - search_result: node is being displayed as a search result.
+ *   If book.module is enabled:
+ *   - print: node is being displayed in print-friendly mode.
+ * Contributed modules might define additional view modes, or use existing
+ * view modes in additional contexts.
+ *
+ * @param Drupal\node\Node $node
+ *   A node entity.
+ * @param $view_mode
+ *   (optional) View mode, e.g., 'full', 'teaser'... Defaults to 'full.'
+ * @param $langcode
+ *   (optional) A language code to use for rendering. Defaults to the global
+ *   content language of the current request.
+ */
+function node_build_content(Node $node, $view_mode = 'full', $langcode = NULL) {
+  if (!isset($langcode)) {
+    $langcode = language(LANGUAGE_TYPE_CONTENT)->langcode;
+  }
+
+  // Remove previously built content, if exists.
+  $node->content = array();
+
+  // Allow modules to change the view mode.
+  $context = array('langcode' => $langcode);
+  drupal_alter('entity_view_mode', $view_mode, $node, $context);
+
+  // The 'view' hook can be implemented to overwrite the default function
+  // to display nodes.
+  if (node_hook($node->type, 'view')) {
+    $node = node_invoke($node, 'view', $view_mode, $langcode);
+  }
+
+  // Build fields content.
+  // In case of a multiple view, node_view_multiple() already ran the
+  // 'prepare_view' step. An internal flag prevents the operation from running
+  // twice.
+  field_attach_prepare_view('node', array($node->nid => $node), $view_mode, $langcode);
+  entity_prepare_view('node', array($node->nid => $node), $langcode);
+  $node->content += field_attach_view('node', $node, $view_mode, $langcode);
+
+  // Always display a read more link on teasers because we have no way
+  // to know when a teaser view is different than a full view.
+  $links = array();
+  $node->content['links'] = array(
+    '#theme' => 'links__node',
+    '#pre_render' => array('drupal_pre_render_links'),
+    '#attributes' => array('class' => array('links', 'inline')),
+  );
+  if ($view_mode == 'teaser') {
+    $node_title_stripped = strip_tags($node->label());
+    $links['node-readmore'] = array(
+      'title' => t('Read more<span class="element-invisible"> about @title</span>', array('@title' => $node_title_stripped)),
+      'href' => 'node/' . $node->nid,
+      'html' => TRUE,
+      'attributes' => array('rel' => 'tag', 'title' => $node_title_stripped),
+    );
+  }
+  $node->content['links']['node'] = array(
+    '#theme' => 'links__node__node',
+    '#links' => $links,
+    '#attributes' => array('class' => array('links', 'inline')),
+  );
+
+  // Allow modules to make their own additions to the node.
+  module_invoke_all('node_view', $node, $view_mode, $langcode);
+  module_invoke_all('entity_view', $node, $view_mode, $langcode);
+}
+
+/**
+ * Page callback: Generates an array which displays a node detail page.
+ *
+ * @param Drupal\node\Node $node
+ *   A node entity.
+ * @param $message
+ *   (optional) A flag which sets a page title relevant to the revision being
+ *   viewed.
+ *
+ * @return
+ *   A $page element suitable for use by drupal_render().
+ *
+ * @see node_menu()
+ */
+function node_show(Node $node, $message = FALSE) {
+  if ($message) {
+    drupal_set_title(t('Revision of %title from %date', array('%title' => $node->label(), '%date' => format_date($node->revision_timestamp))), PASS_THROUGH);
+  }
+
+  // For markup consistency with other pages, use node_view_multiple() rather than node_view().
+  $nodes = node_view_multiple(array($node->nid => $node), 'full');
+
+  // Update the history table, stating that this user viewed this node.
+  node_tag_new($node);
+
+  return $nodes;
+}
+
+/**
+ * Checks whether the current page is the full page view of the passed-in node.
+ *
+ * @param Drupal\node\Node $node
+ *   A node entity.
+ *
+ * @return
+ *   The ID of the node if this is a full page view, otherwise FALSE.
+ */
+function node_is_page(Node $node) {
+  $page_node = menu_get_object();
+  return (!empty($page_node) ? $page_node->nid == $node->nid : FALSE);
+}
+
+ /**
+ * Implements hook_preprocess_HOOK() for block.tpl.php.
+ */
+function node_preprocess_block(&$variables) {
+  if ($variables['block']->module == 'node') {
+    switch ($variables['block']->delta) {
+      case 'syndicate':
+        $variables['attributes']['role'] = 'complementary';
+        break;
+      case 'recent':
+        $variables['attributes']['role'] = 'navigation';
+        break;
+    }
+  }
+}
+
+/**
+ * Processes variables for node.tpl.php.
+ *
+ * Most themes utilize their own copy of node.tpl.php. The default is located
+ * inside "modules/node/node.tpl.php". Look in there for the full list of
+ * variables.
+ *
+ * @param $variables
+ *   An array containing the following arguments:
+ *   - $node
+ *   - $view_mode
+ *   - $page
+ *
+ * @see node.tpl.php
+ */
+function template_preprocess_node(&$variables) {
+  $variables['view_mode'] = $variables['elements']['#view_mode'];
+  // Provide a distinct $teaser boolean.
+  $variables['teaser'] = $variables['view_mode'] == 'teaser';
+  $variables['node'] = $variables['elements']['#node'];
+  $node = $variables['node'];
+
+  // Find the date format set for the content type
+  $format = variable_get('node_date_format_' . $node->type, 'medium');
+  $variables['date']      = format_date($node->created, $format);
+  $variables['name']      = theme('username', array(
+    'account' => $node,
+    'link_attributes' => array('rel' => 'author'),
+  ));
+
+  $uri = $node->uri();
+  $variables['node_url']  = url($uri['path'], $uri['options']);
+  $variables['label']     = check_plain($node->label());
+  $variables['page']      = $variables['view_mode'] == 'full' && node_is_page($node);
+
+  // Flatten the node entity's member fields.
+  $variables = array_merge((array) $node, $variables);
+
+  // Helpful $content variable for templates.
+  $variables += array('content' => array());
+  foreach (element_children($variables['elements']) as $key) {
+    $variables['content'][$key] = $variables['elements'][$key];
+  }
+
+  // Make the field variables available with the appropriate language.
+  field_attach_preprocess('node', $node, $variables['content'], $variables);
+
+  // Display post information only on certain node types.
+  if (variable_get('node_submitted_' . $node->type, TRUE)) {
+    $variables['display_submitted'] = TRUE;
+    $variables['submitted'] = t('Submitted by !username on !datetime', array('!username' => $variables['name'], '!datetime' => $variables['date']));
+    $variables['user_picture'] = theme_get_setting('toggle_node_user_picture') ? theme('user_picture', array('account' => $node)) : '';
+  }
+  else {
+    $variables['display_submitted'] = FALSE;
+    $variables['submitted'] = '';
+    $variables['user_picture'] = '';
+  }
+
+  // Add article ARIA role.
+  $variables['attributes']['role'] = 'article';
+
+  // Gather node classes.
+  $variables['attributes']['class'][] = drupal_html_class('node-' . $node->type);
+  if ($variables['promote']) {
+    $variables['attributes']['class'][] = 'promoted';
+  }
+  if ($variables['sticky']) {
+    $variables['attributes']['class'][] = 'sticky';
+  }
+  if (!$variables['status']) {
+    $variables['attributes']['class'][] = 'unpublished';
+  }
+  if ($variables['view_mode']) {
+    $variables['attributes']['class'][] = drupal_html_class('view-mode-' . $variables['view_mode']);
+  }
+  if (isset($variables['preview'])) {
+    $variables['attributes']['class'][] = 'preview';
+  }
+
+  // Clean up name so there are no underscores.
+  $variables['theme_hook_suggestions'][] = 'node__' . $node->type;
+  $variables['theme_hook_suggestions'][] = 'node__' . $node->nid;
+}
+
+/**
+ * Implements hook_permission().
+ */
+function node_permission() {
+  $perms = array(
+    'bypass node access' => array(
+      'title' => t('Bypass content access control'),
+      'description' => t('View, edit and delete all content regardless of permission restrictions.'),
+      'restrict access' => TRUE,
+    ),
+    'administer content types' => array(
+      'title' => t('Administer content types'),
+      'restrict access' => TRUE,
+    ),
+    'administer nodes' => array(
+      'title' => t('Administer content'),
+      'restrict access' => TRUE,
+    ),
+    'access content overview' => array(
+      'title' => t('Access the content overview page'),
+      'description' => t('Access the content overview page at <a href="@url">admin/content</a>.', array(
+        '@url' => url('admin/content'),
+      )),
+    ),
+    'access content' => array(
+      'title' => t('View published content'),
+    ),
+    'view own unpublished content' => array(
+      'title' => t('View own unpublished content'),
+    ),
+    'view revisions' => array(
+      'title' => t('View content revisions'),
+    ),
+    'revert revisions' => array(
+      'title' => t('Revert content revisions'),
+    ),
+    'delete revisions' => array(
+      'title' => t('Delete content revisions'),
+    ),
+  );
+
+  // Generate standard node permissions for all applicable node types.
+  foreach (node_permissions_get_configured_types() as $name => $type) {
+    $perms += node_list_permissions($type);
+  }
+
+  return $perms;
+}
+
+/**
+ * Gathers the rankings from the the hook_ranking() implementations.
+ *
+ * @param $query
+ *   A query object that has been extended with the Search DB Extender.
+ */
+function _node_rankings(SelectExtender $query) {
+  if ($ranking = module_invoke_all('ranking')) {
+    $tables = &$query->getTables();
+    foreach ($ranking as $rank => $values) {
+      if ($node_rank = variable_get('node_rank_' . $rank, 0)) {
+        // If the table defined in the ranking isn't already joined, then add it.
+        if (isset($values['join']) && !isset($tables[$values['join']['alias']])) {
+          $query->addJoin($values['join']['type'], $values['join']['table'], $values['join']['alias'], $values['join']['on']);
+        }
+        $arguments = isset($values['arguments']) ? $values['arguments'] : array();
+        $query->addScore($values['score'], $arguments, $node_rank);
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_search_info().
+ */
+function node_search_info() {
+  return array(
+    'title' => 'Content',
+    'path' => 'node',
+  );
+}
+
+/**
+ * Implements hook_search_access().
+ */
+function node_search_access() {
+  return user_access('access content');
+}
+
+/**
+ * Implements hook_search_reset().
+ */
+function node_search_reset() {
+  db_update('search_dataset')
+    ->fields(array('reindex' => REQUEST_TIME))
+    ->condition('type', 'node')
+    ->execute();
+}
+
+/**
+ * Implements hook_search_status().
+ */
+function node_search_status() {
+  $total = db_query('SELECT COUNT(*) FROM {node}')->fetchField();
+  $remaining = db_query("SELECT COUNT(*) FROM {node} n LEFT JOIN {search_dataset} d ON d.type = 'node' AND d.sid = n.nid WHERE d.sid IS NULL OR d.reindex <> 0")->fetchField();
+  return array('remaining' => $remaining, 'total' => $total);
+}
+
+/**
+ * Implements hook_search_admin().
+ */
+function node_search_admin() {
+  // Output form for defining rank factor weights.
+  $form['content_ranking'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Content ranking'),
+  );
+  $form['content_ranking']['#theme'] = 'node_search_admin';
+  $form['content_ranking']['info'] = array(
+    '#value' => '<em>' . t('The following numbers control which properties the content search should favor when ordering the results. Higher numbers mean more influence, zero means the property is ignored. Changing these numbers does not require the search index to be rebuilt. Changes take effect immediately.') . '</em>'
+  );
+
+  // Note: reversed to reflect that higher number = higher ranking.
+  $options = drupal_map_assoc(range(0, 10));
+  foreach (module_invoke_all('ranking') as $var => $values) {
+    $form['content_ranking']['factors']['node_rank_' . $var] = array(
+      '#title' => $values['title'],
+      '#type' => 'select',
+      '#options' => $options,
+      '#default_value' => variable_get('node_rank_' . $var, 0),
+    );
+  }
+  return $form;
+}
+
+/**
+ * Implements hook_search_execute().
+ */
+function node_search_execute($keys = NULL, $conditions = NULL) {
+  // Build matching conditions
+  $query = db_select('search_index', 'i', array('target' => 'slave'))
+    ->extend('Drupal\search\SearchQuery')
+    ->extend('Drupal\Core\Database\Query\PagerSelectExtender');
+  $query->join('node', 'n', 'n.nid = i.sid');
+  $query
+    ->condition('n.status', 1)
+    ->addTag('node_access')
+    ->searchExpression($keys, 'node');
+
+  // Insert special keywords.
+  $query->setOption('type', 'n.type');
+  $query->setOption('langcode', 'n.langcode');
+  if ($query->setOption('term', 'ti.tid')) {
+    $query->join('taxonomy_index', 'ti', 'n.nid = ti.nid');
+  }
+  // Only continue if the first pass query matches.
+  if (!$query->executeFirstPass()) {
+    return array();
+  }
+
+  // Add the ranking expressions.
+  _node_rankings($query);
+
+  // Load results.
+  $find = $query
+    // Add the language code of the indexed item to the result of the query,
+    // since the node will be rendered using the respective language.
+    ->fields('i', array('langcode'))
+    ->limit(10)
+    ->execute();
+  $results = array();
+  foreach ($find as $item) {
+    // Render the node.
+    $node = node_load($item->sid);
+    $build = node_view($node, 'search_result', $item->langcode);
+    unset($build['#theme']);
+    $node->rendered = drupal_render($build);
+
+    // Fetch comments for snippet.
+    $node->rendered .= ' ' . module_invoke('comment', 'node_update_index', $node, $item->langcode);
+
+    $extra = module_invoke_all('node_search_result', $node, $item->langcode);
+
+    $language = language_load($item->langcode);
+    $uri = $node->uri();
+    $results[] = array(
+      'link' => url($uri['path'], array_merge($uri['options'], array('absolute' => TRUE, 'language' => $language))),
+      'type' => check_plain(node_get_type_label($node)),
+      'title' => $node->label($item->langcode),
+      'user' => theme('username', array('account' => $node)),
+      'date' => $node->get('changed', $item->langcode),
+      'node' => $node,
+      'extra' => $extra,
+      'score' => $item->calculated_score,
+      'snippet' => search_excerpt($keys, $node->rendered, $item->langcode),
+      'langcode' => $node->langcode,
+    );
+  }
+  return $results;
+}
+
+/**
+ * Implements hook_ranking().
+ */
+function node_ranking() {
+  // Create the ranking array and add the basic ranking options.
+  $ranking = array(
+    'relevance' => array(
+      'title' => t('Keyword relevance'),
+      // Average relevance values hover around 0.15
+      'score' => 'i.relevance',
+    ),
+    'sticky' => array(
+      'title' => t('Content is sticky at top of lists'),
+      // The sticky flag is either 0 or 1, which is automatically normalized.
+      'score' => 'n.sticky',
+    ),
+    'promote' => array(
+      'title' => t('Content is promoted to the front page'),
+      // The promote flag is either 0 or 1, which is automatically normalized.
+      'score' => 'n.promote',
+    ),
+  );
+
+  // Add relevance based on creation or changed date.
+  if ($node_cron_last = variable_get('node_cron_last', 0)) {
+    $ranking['recent'] = array(
+      'title' => t('Recently posted'),
+      // Exponential decay with half-life of 6 months, starting at last indexed node
+      'score' => 'POW(2.0, (GREATEST(n.created, n.changed) - :node_cron_last) * 6.43e-8)',
+      'arguments' => array(':node_cron_last' => $node_cron_last),
+    );
+  }
+  return $ranking;
+}
+
+/**
+ * Implements hook_user_cancel().
+ */
+function node_user_cancel($edit, $account, $method) {
+  switch ($method) {
+    case 'user_cancel_block_unpublish':
+      // Unpublish nodes (current revisions).
+      module_load_include('inc', 'node', 'node.admin');
+      $nodes = db_select('node', 'n')
+        ->fields('n', array('nid'))
+        ->condition('uid', $account->uid)
+        ->execute()
+        ->fetchCol();
+      node_mass_update($nodes, array('status' => 0));
+      break;
+
+    case 'user_cancel_reassign':
+      // Anonymize nodes (current revisions).
+      module_load_include('inc', 'node', 'node.admin');
+      $nodes = db_select('node', 'n')
+        ->fields('n', array('nid'))
+        ->condition('uid', $account->uid)
+        ->execute()
+        ->fetchCol();
+      node_mass_update($nodes, array('uid' => 0));
+      // Anonymize old revisions.
+      db_update('node_revision')
+        ->fields(array('uid' => 0))
+        ->condition('uid', $account->uid)
+        ->execute();
+      // Clean history.
+      db_delete('history')
+        ->condition('uid', $account->uid)
+        ->execute();
+      break;
+  }
+}
+
+/**
+ * Implements hook_user_predelete().
+ */
+function node_user_predelete($account) {
+  // Delete nodes (current revisions).
+  // @todo Introduce node_mass_delete() or make node_mass_update() more flexible.
+  $nodes = db_select('node', 'n')
+    ->fields('n', array('nid'))
+    ->condition('uid', $account->uid)
+    ->execute()
+    ->fetchCol();
+  node_delete_multiple($nodes);
+  // Delete old revisions.
+  $revisions = db_query('SELECT vid FROM {node_revision} WHERE uid = :uid', array(':uid' => $account->uid))->fetchCol();
+  foreach ($revisions as $revision) {
+    node_revision_delete($revision);
+  }
+  // Clean history.
+  db_delete('history')
+    ->condition('uid', $account->uid)
+    ->execute();
+}
+
+/**
+ * Returns HTML for the content ranking part of the search settings admin page.
+ *
+ * @param $variables
+ *   An associative array containing:
+ *   - form: A render element representing the form.
+ *
+ * @see node_search_admin()
+ * @ingroup themeable
+ */
+function theme_node_search_admin($variables) {
+  $form = $variables['form'];
+
+  $output = drupal_render($form['info']);
+
+  $header = array(t('Factor'), t('Weight'));
+  foreach (element_children($form['factors']) as $key) {
+    $row = array();
+    $row[] = $form['factors'][$key]['#title'];
+    $form['factors'][$key]['#title_display'] = 'invisible';
+    $row[] = drupal_render($form['factors'][$key]);
+    $rows[] = $row;
+  }
+  $output .= theme('table', array('header' => $header, 'rows' => $rows));
+
+  $output .= drupal_render_children($form);
+  return $output;
+}
+
+/**
+ * Access callback: Checks node revision access.
+ *
+ * @param Drupal\node\Node $node
+ *   The node to check.
+ * @param $op
+ *   (optional) The specific operation being checked. Defaults to 'view.'
+ * @param object $account
+ *   (optional) A user object representing the user for whom the operation is
+ *   to be performed. Determines access for a user other than the current user.
+ * @param $langcode
+ *   (optional) Language code for the variant of the node. Different language
+ *   variants might have different permissions associated. If NULL, the
+ *   original langcode of the node is used.
+ *
+ * @return
+ *   TRUE if the operation may be performed, FALSE otherwise.
+ *
+ * @see node_menu()
+ */
+function _node_revision_access(Node $node, $op = 'view', $account = NULL, $langcode = NULL) {
+  $access = &drupal_static(__FUNCTION__, array());
+
+  $map = array(
+    'view' => 'view revisions',
+    'update' => 'revert revisions',
+    'delete' => 'delete revisions',
+  );
+
+  if (!$node || !isset($map[$op])) {
+    // If there was no node to check against, or the $op was not one of the
+    // supported ones, we return access denied.
+    return FALSE;
+  }
+
+  if (!isset($account)) {
+    $account = $GLOBALS['user'];
+  }
+
+  // If no language code was provided, default to the node revision's langcode.
+  if (empty($langcode)) {
+    $langcode = $node->langcode;
+  }
+
+  // Statically cache access by revision ID, language code, user account ID,
+  // and operation.
+  $cid = $node->vid . ':' . $langcode . ':' . $account->uid . ':' . $op;
+
+  if (!isset($access[$cid])) {
+    // Perform basic permission checks first.
+    if (!user_access($map[$op], $account) && !user_access('administer nodes', $account)) {
+      return $access[$cid] = FALSE;
+    }
+
+    // There should be at least two revisions. If the vid of the given node
+    // and the vid of the default revision differ, then we already have two
+    // different revisions so there is no need for a separate database check.
+    // Also, if you try to revert to or delete the default revision, that's
+    // not good.
+    if ($node->isDefaultRevision() && (db_query('SELECT COUNT(vid) FROM {node_revision} WHERE nid = :nid', array(':nid' => $node->nid))->fetchField() == 1 || $op == 'update' || $op == 'delete')) {
+      $access[$cid] = FALSE;
+    }
+    elseif (user_access('administer nodes', $account)) {
+      $access[$cid] = TRUE;
+    }
+    else {
+      // First check the access to the default revision and finally, if the
+      // node passed in is not the default revision then access to that, too.
+      $access[$cid] = node_access($op, node_load($node->nid), $account, $langcode) && ($node->isDefaultRevision() || node_access($op, $node, $account, $langcode));
+    }
+  }
+
+  return $access[$cid];
+}
+
+/**
+ * Access callback: Checks whether the user has permission to add a node.
+ *
+ * @return
+ *   TRUE if the user has permission, otherwise FALSE.
+ *
+ * @see node_menu()
+ */
+function _node_add_access() {
+  $types = node_type_get_types();
+  foreach ($types as $type) {
+    if (node_hook($type->type, 'form') && node_access('create', $type->type)) {
+      return TRUE;
+    }
+  }
+  if (user_access('administer content types')) {
+    // There are no content types defined that the user has permission to create,
+    // but the user does have the permission to administer the content types, so
+    // grant them access to the page anyway.
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**
+ * Implements hook_menu().
+ */
+function node_menu() {
+  $items['admin/content'] = array(
+    'title' => 'Content',
+    'description' => 'Find and manage content.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('node_admin_content'),
+    'access arguments' => array('access content overview'),
+    'weight' => -10,
+    'file' => 'node.admin.inc',
+  );
+  $items['admin/content/node'] = array(
+    'title' => 'Content',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'weight' => -10,
+  );
+
+  $items['admin/reports/status/rebuild'] = array(
+    'title' => 'Rebuild permissions',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('node_configure_rebuild_confirm'),
+    // Any user than can potentially trigger a node_access_needs_rebuild(TRUE)
+    // has to be allowed access to the 'node access rebuild' confirm form.
+    'access arguments' => array('access administration pages'),
+    'type' => MENU_CALLBACK,
+    'file' => 'node.admin.inc',
+  );
+
+  $items['admin/structure/types'] = array(
+    'title' => 'Content types',
+    'description' => 'Manage content types, including default status, front page promotion, comment settings, etc.',
+    'page callback' => 'node_overview_types',
+    'access arguments' => array('administer content types'),
+    'file' => 'content_types.inc',
+  );
+  $items['admin/structure/types/list'] = array(
+    'title' => 'List',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'weight' => -10,
+  );
+  $items['admin/structure/types/add'] = array(
+    'title' => 'Add content type',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('node_type_form'),
+    'access arguments' => array('administer content types'),
+    'type' => MENU_LOCAL_ACTION,
+    'file' => 'content_types.inc',
+  );
+  $items['admin/structure/types/manage/%node_type'] = array(
+    'title' => 'Edit content type',
+    'title callback' => 'node_type_page_title',
+    'title arguments' => array(4),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('node_type_form', 4),
+    'access arguments' => array('administer content types'),
+    'file' => 'content_types.inc',
+  );
+  $items['admin/structure/types/manage/%node_type/edit'] = array(
+    'title' => 'Edit',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+  );
+  $items['admin/structure/types/manage/%node_type/delete'] = array(
+    'title' => 'Delete',
+    'page arguments' => array('node_type_delete_confirm', 4),
+    'access arguments' => array('administer content types'),
+    'file' => 'content_types.inc',
+  );
+
+  $items['node'] = array(
+    'page callback' => 'node_page_default',
+    'access arguments' => array('access content'),
+    'menu_name' => 'navigation',
+    'type' => MENU_CALLBACK,
+  );
+  $items['node/add'] = array(
+    'title' => 'Add content',
+    'page callback' => 'node_add_page',
+    'access callback' => '_node_add_access',
+    'file' => 'node.pages.inc',
+  );
+  $items['rss.xml'] = array(
+    'title' => 'RSS feed',
+    'page callback' => 'node_feed',
+    // Pass a FALSE and array argument to ensure that additional path components
+    // are not passed to node_feed().
+    'page arguments' => array(FALSE, array()),
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+  );
+  $items['node/add/%node_type'] = array(
+    'title callback' => 'node_type_get_clean_name',
+    'title arguments' => array(2),
+    'page callback' => 'node_add',
+    'page arguments' => array(2),
+    'access callback' => 'node_access',
+    'access arguments' => array('create', 2),
+    'description callback' => 'node_type_get_description',
+    'description arguments' => array(2),
+    'file' => 'node.pages.inc',
+  );
+  $items['node/%node'] = array(
+    'title callback' => 'node_page_title',
+    'title arguments' => array(1),
+    // The page callback also invokes drupal_set_title() in case
+    // the menu router's title is overridden by a menu link.
+    'page callback' => 'node_page_view',
+    'page arguments' => array(1),
+    'access callback' => 'node_access',
+    'access arguments' => array('view', 1),
+  );
+  $items['node/%node/view'] = array(
+    'title' => 'View',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'weight' => -10,
+  );
+  $items['node/%node/edit'] = array(
+    'title' => 'Edit',
+    'page callback' => 'node_page_edit',
+    'page arguments' => array(1),
+    'access callback' => 'node_access',
+    'access arguments' => array('update', 1),
+    'weight' => 0,
+    'type' => MENU_LOCAL_TASK,
+    'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
+    'file' => 'node.pages.inc',
+  );
+  $items['node/%node/delete'] = array(
+    'title' => 'Delete',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('node_delete_confirm', 1),
+    'access callback' => 'node_access',
+    'access arguments' => array('delete', 1),
+    'weight' => 1,
+    'type' => MENU_LOCAL_TASK,
+    'context' => MENU_CONTEXT_INLINE,
+    'file' => 'node.pages.inc',
+  );
+  $items['node/%node/revisions'] = array(
+    'title' => 'Revisions',
+    'page callback' => 'node_revision_overview',
+    'page arguments' => array(1),
+    'access callback' => '_node_revision_access',
+    'access arguments' => array(1),
+    'weight' => 2,
+    'type' => MENU_LOCAL_TASK,
+    'file' => 'node.pages.inc',
+  );
+  $items['node/%node/revisions/%node_revision/view'] = array(
+    'title' => 'Revisions',
+    'page callback' => 'node_show',
+    'page arguments' => array(3, TRUE),
+    'access callback' => '_node_revision_access',
+    'access arguments' => array(3),
+  );
+  $items['node/%node/revisions/%node_revision/revert'] = array(
+    'title' => 'Revert to earlier revision',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('node_revision_revert_confirm', 3),
+    'access callback' => '_node_revision_access',
+    'access arguments' => array(3, 'update'),
+    'file' => 'node.pages.inc',
+  );
+  $items['node/%node/revisions/%node_revision/delete'] = array(
+    'title' => 'Delete earlier revision',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('node_revision_delete_confirm', 3),
+    'access callback' => '_node_revision_access',
+    'access arguments' => array(3, 'delete'),
+    'file' => 'node.pages.inc',
+  );
+  return $items;
+}
+
+/**
+ * Implements hook_menu_local_tasks_alter().
+ */
+function node_menu_local_tasks_alter(&$data, $router_item, $root_path) {
+  // Add action link to 'node/add' on 'admin/content' page.
+  if ($root_path == 'admin/content') {
+    $item = menu_get_item('node/add');
+    if ($item['access']) {
+      $data['actions']['output'][] = array(
+        '#theme' => 'menu_local_action',
+        '#link' => $item,
+      );
+    }
+  }
+}
+
+/**
+ * Title callback: Provides the title for a node type edit form.
+ *
+ * @param $type
+ *   The node type object.
+ *
+ * @see node_menu()
+ */
+function node_type_page_title($type) {
+  return $type->name;
+}
+
+/**
+ * Title callback: Displays the node's title.
+ *
+ * @param Drupal\node\Node $node
+ *   The node entity.
+ *
+ * @see node_menu()
+ */
+function node_page_title(Node $node) {
+  return $node->label();
+}
+
+/**
+ * Finds the last time a node was changed.
+ *
+ * @param $nid
+ *   The ID of a node.
+ *
+ * @return
+ *   A unix timestamp indicating the last time the node was changed.
+ */
+function node_last_changed($nid) {
+  return db_query('SELECT changed FROM {node} WHERE nid = :nid', array(':nid' => $nid))->fetch()->changed;
+}
+
+/**
+ * Returns a list of all the existing revision numbers for the node passed in.
+ *
+ * @param Drupal\node\Node $node
+ *   The node entity.
+ */
+function node_revision_list(Node $node) {
+  $revisions = array();
+  $result = db_query('SELECT r.vid, r.title, r.log, r.uid, n.vid AS current_vid, r.timestamp, u.name FROM {node_revision} r LEFT JOIN {node} n ON n.vid = r.vid INNER JOIN {users} u ON u.uid = r.uid WHERE r.nid = :nid ORDER BY r.vid DESC', array(':nid' => $node->nid));
+  foreach ($result as $revision) {
+    $revisions[$revision->vid] = $revision;
+  }
+
+  return $revisions;
+}
+
+/**
+ * Implements hook_block_info().
+ */
+function node_block_info() {
+  $blocks['syndicate']['info'] = t('Syndicate');
+  // Not worth caching.
+  $blocks['syndicate']['cache'] = DRUPAL_NO_CACHE;
+
+  $blocks['recent']['info'] = t('Recent content');
+  $blocks['recent']['properties']['administrative'] = TRUE;
+
+  return $blocks;
+}
+
+/**
+ * Implements hook_block_view().
+ */
+function node_block_view($delta = '') {
+  $block = array();
+
+  switch ($delta) {
+    case 'syndicate':
+      $block['subject'] = t('Syndicate');
+      $block['content'] = array(
+        '#theme' => 'feed_icon',
+        '#url' => 'rss.xml',
+        '#title' => t('Syndicate'),
+      );
+      break;
+
+    case 'recent':
+      if (user_access('access content')) {
+        $block['subject'] = t('Recent content');
+        if ($nodes = node_get_recent(variable_get('node_recent_block_count', 10))) {
+          $block['content'] = array(
+            '#theme' => 'node_recent_block',
+            '#nodes' => $nodes,
+          );
+        } else {
+          $block['content'] = t('No content available.');
+        }
+      }
+      break;
+  }
+  return $block;
+}
+
+/**
+ * Implements hook_block_configure().
+ */
+function node_block_configure($delta = '') {
+  $form = array();
+  if ($delta == 'recent') {
+    $form['node_recent_block_count'] = array(
+      '#type' => 'select',
+      '#title' => t('Number of recent content items to display'),
+      '#default_value' => variable_get('node_recent_block_count', 10),
+      '#options' => drupal_map_assoc(array(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 25, 30)),
+    );
+  }
+  return $form;
+}
+
+/**
+ * Implements hook_block_save().
+ */
+function node_block_save($delta = '', $edit = array()) {
+  if ($delta == 'recent') {
+    variable_set('node_recent_block_count', $edit['node_recent_block_count']);
+  }
+}
+
+/**
+ * Finds the most recently changed nodes that are available to the current user.
+ *
+ * @param $number
+ *   (optional) The maximum number of nodes to find. Defaults to 10.
+ *
+ * @return
+ *   An array of node entities or an empty array if there are no recent
+ *   nodes visible to the current user.
+ */
+function node_get_recent($number = 10) {
+  $query = db_select('node', 'n');
+
+  if (!user_access('bypass node access')) {
+    // If the user is able to view their own unpublished nodes, allow them
+    // to see these in addition to published nodes. Check that they actually
+    // have some unpublished nodes to view before adding the condition.
+    if (user_access('view own unpublished content') && $own_unpublished = db_query('SELECT nid FROM {node} WHERE uid = :uid AND status = :status', array(':uid' => $GLOBALS['user']->uid, ':status' => NODE_NOT_PUBLISHED))->fetchCol()) {
+      $query->condition(db_or()
+        ->condition('n.status', NODE_PUBLISHED)
+        ->condition('n.nid', $own_unpublished, 'IN')
+      );
+    }
+    else {
+      // If not, restrict the query to published nodes.
+      $query->condition('n.status', NODE_PUBLISHED);
+    }
+  }
+  $nids = $query
+    ->fields('n', array('nid'))
+    ->orderBy('n.changed', 'DESC')
+    ->range(0, $number)
+    ->addTag('node_access')
+    ->execute()
+    ->fetchCol();
+
+  $nodes = node_load_multiple($nids);
+
+  return $nodes ? $nodes : array();
+}
+
+/**
+ * Returns HTML for a list of recent content.
+ *
+ * @param $variables
+ *   An associative array containing:
+ *   - nodes: An array of recent node entities.
+ *
+ * @ingroup themeable
+ */
+function theme_node_recent_block($variables) {
+  $rows = array();
+  $output = '';
+
+  $l_options = array('query' => drupal_get_destination());
+  foreach ($variables['nodes'] as $node) {
+    $row = array();
+    $row[] = array(
+      'data' => theme('node_recent_content', array('node' => $node)),
+      'class' => 'title-author',
+    );
+    if (node_access('update', $node)) {
+      $row[] = array(
+        'data' => l(t('edit'), 'node/' . $node->nid . '/edit', $l_options),
+        'class' => 'edit',
+      );
+    }
+    if (node_access('delete', $node)) {
+      $row[] = array(
+        'data' => l(t('delete'), 'node/' . $node->nid . '/delete', $l_options),
+        'class' => 'delete',
+      );
+    }
+    $rows[] = $row;
+  }
+
+  if ($rows) {
+    $output = theme('table', array('rows' => $rows));
+    if (user_access('access content overview')) {
+      $output .= theme('more_link', array('url' => 'admin/content', 'title' => t('Show more content')));
+    }
+  }
+
+  return $output;
+}
+
+/**
+ * Returns HTML for a recent node to be displayed in the recent content block.
+ *
+ * @param $variables
+ *   An associative array containing:
+ *   - node: A node entity.
+ *
+ * @ingroup themeable
+ */
+function theme_node_recent_content($variables) {
+  $node = $variables['node'];
+
+  $output = '<div class="node-title">';
+  $output .= l($node->label(), 'node/' . $node->nid);
+  $output .= theme('mark', array('type' => node_mark($node->nid, $node->changed)));
+  $output .= '</div><div class="node-author">';
+  $output .= theme('username', array('account' => user_load($node->uid)));
+  $output .= '</div>';
+
+  return $output;
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter() for block_add_block_form().
+ *
+ * Adds node-type specific visibility options to add block form.
+ */
+function node_form_block_add_block_form_alter(&$form, &$form_state) {
+  node_form_block_admin_configure_alter($form, $form_state);
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter() for block_admin_configure().
+ *
+ * Adds node-type specific visibility options to block configuration form.
+ *
+ * @see node_form_block_admin_configure_submit()
+ */
+function node_form_block_admin_configure_alter(&$form, &$form_state) {
+  $default_type_options = db_query("SELECT type FROM {block_node_type} WHERE module = :module AND delta = :delta", array(
+    ':module' => $form['module']['#value'],
+    ':delta' => $form['delta']['#value'],
+  ))->fetchCol();
+  $form['visibility']['node_type'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Content types'),
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#group' => 'visibility',
+    '#weight' => 5,
+  );
+  $form['visibility']['node_type']['types'] = array(
+    '#type' => 'checkboxes',
+    '#title' => t('Show block for specific content types'),
+    '#default_value' => $default_type_options,
+    '#options' => node_type_get_names(),
+    '#description' => t('Show this block only on pages that display content of the given type(s). If you select no types, there will be no type-specific limitation.'),
+  );
+  $form['#submit'][] = 'node_form_block_admin_configure_submit';
+>>>>>>> Applying patch from issue 477170 comment-6503850
 }
 
 /**
