diff --git a/core/modules/node/lib/Drupal/node/Form/NodeController.php b/core/modules/node/lib/Drupal/node/Form/NodeController.php
new file mode 100755
index 0000000..fd98a2a
--- /dev/null
+++ b/core/modules/node/lib/Drupal/node/Form/NodeController.php
@@ -0,0 +1,166 @@
+<?php
+namespace Drupal\node\Form;
+
+use Drupal\Core\Form\FormInterface;
+use Drupal\Core\Database\Query\SelectInterface;
+use Drupal\Core\Language\Language;
+
+/**
+* Builds an administrative list of nodes, on which operations may be executed.
+*/
+class NodeController implements FormInterface {
+
+  /**
+   * Implements \Drupal\Core\Form\FormInterface::getFormID().
+   */
+  public function getFormID() {
+    return 'node_admin_nodes';
+  }
+
+  /**
+   * Implements \Drupal\Core\Form\FormInterface::buildForm().
+   */
+  public function buildForm(array $form, array &$form_state) {
+    // Enable language column and filter if multiple languages are enabled.
+    $multilingual = language_multilingual();
+
+    $header = array(
+      'title' => array('data' => t('Title'), 'field' => 'n.name'),
+      'type' => array('data' => t('Content type'), 'field' => 'n.type', 'class' => array(RESPONSIVE_PRIORITY_MEDIUM)),
+      'author' => array('data' => t('Author'), 'class' => array(RESPONSIVE_PRIORITY_LOW)),
+      'status' => array('data' => t('Status'), 'field' => 'n.status'),
+      'changed' => array('data' => t('Updated'), 'field' => 'n.changed', 'sort' => 'desc', 'class' => array(RESPONSIVE_PRIORITY_LOW)),
+    );
+
+    if ($multilingual) {
+      $header['language_name'] = array('data' => t('Language'), 'field' => 'n.langcode', 'class' => array(RESPONSIVE_PRIORITY_LOW));
+    }
+
+    $header['operations'] = array('data' => t('Operations'));
+
+    $query = db_select('node_field_data', 'n')
+      ->extend('Drupal\Core\Database\Query\PagerSelectExtender')
+      ->extend('Drupal\Core\Database\Query\TableSortExtender');
+
+    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 DISTINCT nid FROM {node_field_data} WHERE uid = :uid AND status = :status', array(':uid' => $GLOBALS['user']->uid, ':status' => 0))->fetchCol()) {
+        $query->condition(db_or()
+          ->condition('n.status', 1)
+          ->condition('n.nid', $own_unpublished, 'IN')
+        );
+      }
+      else {
+        // If not, restrict the query to published nodes.
+        $query->condition('n.status', 1);
+      }
+    }
+    $nids = $query
+      ->distinct()
+      ->fields('n', array('nid'))
+      ->limit(50)
+      ->orderByHeader($header)
+      ->addTag('node_access')
+      ->execute()
+      ->fetchCol();
+    $nodes = node_load_multiple($nids);
+
+    // Prepare the list of nodes.
+    $languages = language_list(Language::STATE_ALL);
+    $destination = drupal_get_destination();
+    $form['nodes'] = array(
+      '#type' => 'table',
+      '#header' => $header,
+      '#empty' => t('No content available.'),
+    );
+    foreach ($nodes as $node) {
+      $l_options = $node->langcode != Language::LANGCODE_NOT_SPECIFIED && isset($languages[$node->langcode]) ? array('language' => $languages[$node->langcode]) : array();
+      $mark = array(
+        '#theme' => 'mark',
+        '#status' => node_mark($node->nid, $node->changed),
+      );
+      $form['nodes'][$node->nid]['title'] = array(
+        '#type' => 'link',
+        '#title' => $node->label(),
+        '#href' => 'node/' . $node->nid,
+        '#options' => $l_options,
+        '#suffix' => ' ' . drupal_render($mark),
+      );
+      $form['nodes'][$node->nid]['type'] = array(
+        '#markup' => check_plain(node_get_type_label($node)),
+      );
+      $form['nodes'][$node->nid]['author'] = array(
+        '#theme' => 'username',
+        '#account' => $node,
+      );
+      $form['nodes'][$node->nid]['status'] = array(
+        '#markup' => $node->status ? t('published') : t('not published'),
+      );
+      $form['nodes'][$node->nid]['changed'] = array(
+        '#markup' => format_date($node->changed, 'short'),
+      );
+      if ($multilingual) {
+        $form['nodes'][$node->nid]['language_name'] = array(
+          '#markup' => language_name($node->langcode),
+        );
+      }
+
+      // Build a list of all the accessible operations for the current node.
+      $operations = array();
+      if (node_access('update', $node)) {
+        $operations['edit'] = array(
+          'title' => t('Edit'),
+          'href' => 'node/' . $node->nid . '/edit',
+          'query' => $destination,
+        );
+      }
+      if (node_access('delete', $node)) {
+        $operations['delete'] = array(
+          'title' => t('Delete'),
+          'href' => 'node/' . $node->nid . '/delete',
+          'query' => $destination,
+        );
+      }
+      if ($node->isTranslatable()) {
+        $operations['translate'] = array(
+          'title' => t('Translate'),
+          'href' => 'node/' . $node->nid . '/translations',
+          'query' => $destination,
+        );
+      }
+      $form['nodes'][$node->nid]['operations'] = array();
+      if (count($operations) > 1) {
+        // Render an unordered list of operations links.
+        $form['nodes'][$node->nid]['operations'] = array(
+          '#type' => 'operations',
+          '#subtype' => 'node',
+          '#links' => $operations,
+        );
+      }
+      elseif (!empty($operations)) {
+        // Render the first and only operation as a link.
+        $link = reset($operations);
+        $form['nodes'][$node->nid]['operations'] = array(
+          '#type' => 'link',
+          '#title' => $link['title'],
+          '#href' => $link['href'],
+          '#options' => array('query' => $link['query']),
+        );
+      }
+    }
+
+    $form['pager'] = array('#theme' => 'pager');
+    return $form;
+  }
+
+  public function validateForm(array &$form, array &$form_state) {
+
+  }
+
+  public function submitForm(array &$form, array &$form_state) {
+
+  }
+
+}
diff --git a/core/modules/node/node.admin.inc b/core/modules/node/node.admin.inc
index c2b8524..cbfb313 100644
--- a/core/modules/node/node.admin.inc
+++ b/core/modules/node/node.admin.inc
@@ -179,161 +179,5 @@ function _node_mass_update_batch_finished($success, $results, $operations) {
     $message .= drupal_render($item_list);
     drupal_set_message($message);
   }
-}
-
-/**
- * Returns the admin form object to node_admin_content().
- *
- * @ingroup forms
- */
-function node_admin_nodes() {
-  // Enable language column and filter if multiple languages are enabled.
-  $multilingual = language_multilingual();
-
-  // Build the sortable table header.
-  $header = array(
-    'title' => array(
-      'data' => t('Title'),
-      'field' => 'n.title',
-    ),
-    'type' => array(
-      'data' => t('Content type'),
-      'field' => 'n.type',
-      'class' => array(RESPONSIVE_PRIORITY_MEDIUM),
-    ),
-    'author' => array(
-      'data' => t('Author'),
-      'class' => array(RESPONSIVE_PRIORITY_LOW),
-    ),
-    'status' => array(
-      'data' => t('Status'),
-      'field' => 'n.status',
-    ),
-    'changed' => array(
-      'data' => t('Updated'),
-      'field' => 'n.changed',
-      'sort' => 'desc',
-      'class' => array(RESPONSIVE_PRIORITY_LOW)
-    ,)
-  );
-  if ($multilingual) {
-    $header['language_name'] = array('data' => t('Language'), 'field' => 'n.langcode', 'class' => array(RESPONSIVE_PRIORITY_LOW));
-  }
-  $header['operations'] = array('data' => t('Operations'));
-
-  $query = db_select('node_field_data', 'n')
-    ->extend('Drupal\Core\Database\Query\PagerSelectExtender')
-    ->extend('Drupal\Core\Database\Query\TableSortExtender');
-
-  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 DISTINCT nid FROM {node_field_data} WHERE uid = :uid AND status = :status', array(':uid' => $GLOBALS['user']->uid, ':status' => 0))->fetchCol()) {
-      $query->condition(db_or()
-        ->condition('n.status', 1)
-        ->condition('n.nid', $own_unpublished, 'IN')
-      );
-    }
-    else {
-      // If not, restrict the query to published nodes.
-      $query->condition('n.status', 1);
-    }
-  }
-  $nids = $query
-    ->distinct()
-    ->fields('n', array('nid'))
-    ->limit(50)
-    ->orderByHeader($header)
-    ->addTag('node_access')
-    ->execute()
-    ->fetchCol();
-  $nodes = node_load_multiple($nids);
-
-  // Prepare the list of nodes.
-  $languages = language_list(Language::STATE_ALL);
-  $destination = drupal_get_destination();
-  $form['nodes'] = array(
-    '#type' => 'table',
-    '#header' => $header,
-    '#empty' => t('No content available.'),
-  );
-  foreach ($nodes as $node) {
-    $l_options = $node->langcode != Language::LANGCODE_NOT_SPECIFIED && isset($languages[$node->langcode]) ? array('language' => $languages[$node->langcode]) : array();
-    $mark = array(
-      '#theme' => 'mark',
-      '#status' => node_mark($node->nid, $node->changed),
-    );
-    $form['nodes'][$node->nid]['title'] = array(
-      '#type' => 'link',
-      '#title' => $node->label(),
-      '#href' => 'node/' . $node->nid,
-      '#options' => $l_options,
-      '#suffix' => ' ' . drupal_render($mark),
-    );
-    $form['nodes'][$node->nid]['type'] = array(
-      '#markup' => check_plain(node_get_type_label($node)),
-    );
-    $form['nodes'][$node->nid]['author'] = array(
-      '#theme' => 'username',
-      '#account' => $node,
-    );
-    $form['nodes'][$node->nid]['status'] = array(
-      '#markup' => $node->status ? t('published') : t('not published'),
-    );
-    $form['nodes'][$node->nid]['changed'] = array(
-      '#markup' => format_date($node->changed, 'short'),
-    );
-    if ($multilingual) {
-      $form['nodes'][$node->nid]['language_name'] = array(
-        '#markup' => language_name($node->langcode),
-      );
-    }
-
-    // Build a list of all the accessible operations for the current node.
-    $operations = array();
-    if (node_access('update', $node)) {
-      $operations['edit'] = array(
-        'title' => t('Edit'),
-        'href' => 'node/' . $node->nid . '/edit',
-        'query' => $destination,
-      );
-    }
-    if (node_access('delete', $node)) {
-      $operations['delete'] = array(
-        'title' => t('Delete'),
-        'href' => 'node/' . $node->nid . '/delete',
-        'query' => $destination,
-      );
-    }
-    if ($node->isTranslatable()) {
-      $operations['translate'] = array(
-        'title' => t('Translate'),
-        'href' => 'node/' . $node->nid . '/translations',
-        'query' => $destination,
-      );
-    }
-    $form['nodes'][$node->nid]['operations'] = array();
-    if (count($operations) > 1) {
-      // Render an unordered list of operations links.
-      $form['nodes'][$node->nid]['operations'] = array(
-        '#type' => 'operations',
-        '#subtype' => 'node',
-        '#links' => $operations,
-      );
-    }
-    elseif (!empty($operations)) {
-      // Render the first and only operation as a link.
-      $link = reset($operations);
-      $form['nodes'][$node->nid]['operations'] = array(
-        '#type' => 'link',
-        '#title' => $link['title'],
-        '#href' => $link['href'],
-        '#options' => array('query' => $link['query']),
-      );
-    }
-  }
 
-  $form['pager'] = array('#theme' => 'pager');
-  return $form;
 }
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 9d9d48f..44f2852 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -1254,10 +1254,8 @@ function node_menu() {
   $items['admin/content'] = array(
     'title' => 'Content',
     'description' => 'Find and manage content.',
-    'page callback' => 'node_admin_nodes',
-    'access arguments' => array('access content overview'),
+    'route_name' => 'node_admin_nodes',
     'weight' => -10,
-    'file' => 'node.admin.inc',
   );
   $items['admin/content/node'] = array(
     'title' => 'Content',
diff --git a/core/modules/node/node.routing.yml b/core/modules/node/node.routing.yml
index 9204a2b..06d9083 100644
--- a/core/modules/node/node.routing.yml
+++ b/core/modules/node/node.routing.yml
@@ -47,3 +47,10 @@ node_type_delete_confirm:
     _entity_form: 'node_type.delete'
   requirements:
     _entity_access: 'node_type.delete'
+
+node_admin_nodes:
+  pattern: '/admin/content'
+  defaults:
+    _form: '\Drupal\node\Form\NodeController'
+  requirements:
+    _permission: 'access content overview'
