diff --git a/includes/QuizResult.class.inc b/includes/QuizResult.class.inc
index 985bba6..255a833 100644
--- a/includes/QuizResult.class.inc
+++ b/includes/QuizResult.class.inc
@@ -1,4 +1,6 @@
 <?php
 
 class QuizResult extends Entity {
-}
\ No newline at end of file
+
+}
+
diff --git a/includes/QuizResultAnswer.class.inc b/includes/QuizResultAnswer.class.inc
index d158d42..e4b0dab 100644
--- a/includes/QuizResultAnswer.class.inc
+++ b/includes/QuizResultAnswer.class.inc
@@ -2,4 +2,4 @@
 
 class QuizResultAnswer extends Entity {
 
-}
\ No newline at end of file
+}
diff --git a/includes/QuizResultAnswerController.class.inc b/includes/QuizResultAnswerController.class.inc
index b71dff9..cd595aa 100644
--- a/includes/QuizResultAnswerController.class.inc
+++ b/includes/QuizResultAnswerController.class.inc
@@ -2,4 +2,96 @@
 
 class QuizResultAnswerController extends EntityAPIController {
 
-}
\ No newline at end of file
+  public function buildContent($entity, $view_mode = 'full', $langcode = NULL) {
+    $out = parent::buildContent($entity, $view_mode, $langcode);
+    $node = node_load($entity->question_nid, $entity->question_vid);
+    $entity_info = entity_get_info('node');
+    $instance = _quiz_question_response_get_instance($entity->result_id, $node);
+    foreach ($entity_info['view modes'] as $view_mode => $info) {
+      if ($instance->canReview("quiz_question_view_" . $view_mode)) {
+        $build = node_view($node, $view_mode);
+        unset($build['#theme']);
+        unset($build['answers']);
+        unset($build['links']);
+
+        $out["quiz_question_view_" . $view_mode] = $build;
+      }
+    }
+
+    $rows = array();
+
+    $labels = array(
+      'attempt' => t('Your answer'),
+      'choice' => t('Choice'),
+      'correct' => t('Correct?'),
+      'score' => t('Score'),
+      'answer_feedback' => t('Feedback'),
+      'solution' => t('Correct answer'),
+    );
+    drupal_alter('quiz_feedback_labels', $labels);
+
+    foreach ($instance->getFeedbackValues() as $idx => $row) {
+      foreach ($labels as $reviewType => $label) {
+        if ((isset($row[$reviewType]) && $instance->canReview($reviewType))) {
+          $rows[$idx][$reviewType] = $row[$reviewType];
+          if (!empty($row[$reviewType])) {
+            $out[$reviewType] = array(
+              '#title' => $label,
+              '#type' => 'item',
+              '#markup' => $row[$reviewType],
+            );
+          }
+        }
+      }
+    }
+
+    if ($instance->isEvaluated()) {
+      $score = $instance->getScore();
+      if ($instance->isCorrect()) {
+        $class = 'q-correct';
+      }
+      else {
+        $class = 'q-wrong';
+      }
+    }
+    else {
+      $score = t('?');
+      $class = 'q-waiting';
+    }
+
+    if ($instance->canReview('score') || quiz_access_to_score()) {
+      $out['score']['#markup'] = theme('quiz_question_score', array('score' => $score, 'max_score' => $instance->getMaxScore(), 'class' => $class));
+    }
+
+    if ($rows) {
+      $headers = array_intersect_key($labels, $rows[0]);
+      $type = $instance->getQuizQuestion()->node->type;
+      $out['table']['#markup'] = theme('quiz_question_feedback__' . $type, array('labels' => $headers, 'data' => $rows));
+    }
+
+    if ($instance->canReview('question_feedback')) {
+      if ($properties = entity_load('quiz_question', FALSE, array('nid' => $instance->quizQuestion->node->nid, 'vid' => $instance->quizQuestion->node->vid))) {
+        $quiz_question = reset($properties);
+        $quiz_result = quiz_result_load($entity->result_id);
+        $account = user_load($quiz_result->uid);
+        $token_types = array(
+          'global' => NULL,
+          'node' => $instance->quizQuestion->node,
+          'user' => $account,
+        );
+        $quiz_question->feedback = token_replace($quiz_question->feedback, $token_types);
+        $out['question_feedback']['#markup'] = check_markup($quiz_question->feedback, $quiz_question->feedback_format);
+      }
+    }
+
+    if ($instance->canReview('score')) {
+      $out['max_score'] = array(
+        '#type' => 'value',
+        '#value' => $instance->getMaxScore(),
+      );
+    }
+
+    return $out;
+  }
+
+}
diff --git a/includes/QuizResultController.class.inc b/includes/QuizResultController.class.inc
index f1adcbc..4f5e3f4 100644
--- a/includes/QuizResultController.class.inc
+++ b/includes/QuizResultController.class.inc
@@ -46,7 +46,8 @@ class QuizResultController extends EntityAPIController {
           }
 
           $quiz_results[$quiz_result_answer->result_id]->layout[$quiz_result_answer->number] = array(
-            'display_number' => $quiz_result_answer->number,
+            'result_answer_id' => $quiz_result_answer->result_answer_id,
+            'display_number' => $quiz_result_answer->display_number,
             'nid' => $quiz_result_answer->question_nid,
             'vid' => $quiz_result_answer->question_vid,
             'tid' => $quiz_result_answer->tid,
@@ -170,4 +171,65 @@ class QuizResultController extends EntityAPIController {
     return FALSE;
   }
 
+  public function buildContent($entity, $view_mode = 'full', $langcode = NULL) {
+    $out = parent::buildContent($entity, $view_mode, $langcode);
+
+    if (!$entity->is_evaluated && empty($_POST)) {
+      $msg = t('Parts of this @quiz have not been evaluated yet. The score below is not final.', array('@quiz' => QUIZ_NAME));
+      drupal_set_message($msg, 'warning');
+    }
+
+    $score = quiz_calculate_score($entity->result_id);
+    $account = user_load($entity->uid);
+
+    $params = array(
+      '%num_correct' => $score['numeric_score'],
+      '%question_count' => $score['possible_score'],
+      '!username' => ($account->uid == $account->uid) ? t('You') : theme('username', array('account' => $account)),
+      '@score' => $score['percentage_score'],
+      '!yourtotal' => ($account->uid == $account->uid) ? t('Your') : t('Total'),
+    );
+
+    $out['questions'] = array();
+
+    foreach ($entity->layout as $question) {
+      // Loop through all the questions and get their feedback.
+      $question_node = node_load($question['nid'], $question['vid']);
+
+
+      $instance = _quiz_question_response_get_instance($entity->result_id, $question_node);
+      if ($instance->getQuizQuestion()->hasFeedback()) {
+        $qras = entity_load('quiz_result_answer', FALSE, array('result_id' => $entity->result_id, 'question_nid' => $question_node->nid, 'question_vid' => $question_node->vid));
+        $qra = reset($qras);
+
+        $out[$question_node->nid] = array(
+          '#title' => t('Question @num', array('@num' => $question['display_number'])),
+          '#type' => 'fieldset',
+          'feedback' => $qra->view(),
+          '#weight' => $question['number'],
+        );
+      }
+
+      $quiz_feedback['#markup'] = '';
+      if (quiz_feedback_can_review('quiz_feedback', $entity)) {
+        $summary = _quiz_get_summary_text($entity);
+        // Show quiz feedback.
+        if (!empty($summary['passfail'])) {
+          $quiz_feedback['#markup'] .= '<div id="quiz-summary">' . $summary['passfail'] . '</div>';
+        }
+        if (!empty($summary['result'])) {
+          $quiz_feedback['#markup'] .= '<div id="quiz-summary">' . $summary['result'] . '</div>';
+        }
+      }
+      $out['quiz_feedback'] = $quiz_feedback;
+
+      if (quiz_feedback_can_review('score', $entity)) {
+        // Show score.
+        $out['score']['#markup'] = '<div id="quiz_score_possible">' . t('!username got %num_correct of %question_count possible points.', $params) . '</div>' . "\n";
+        $out['score']['#markup'] .= '<div id="quiz_score_percent">' . t('!yourtotal score: @score%', $params) . '</div>';
+      }
+    }
+    return array('content' => $out);
+  }
+
 }
diff --git a/question_types/long_answer/long_answer.classes.inc b/question_types/long_answer/long_answer.classes.inc
index d63a31a..71b947b 100644
--- a/question_types/long_answer/long_answer.classes.inc
+++ b/question_types/long_answer/long_answer.classes.inc
@@ -14,28 +14,20 @@ class LongAnswerQuestion extends QuizQuestion {
 
   /**
    * Implementation of saveNodeProperties
-   * @see QuizQuestion#saveNodeProperties($is_new)
+   * @see QuizQuestion#saveNodeProperties()
    */
   public function saveNodeProperties($is_new = FALSE) {
-    if (!isset($this->node->feedback)) {
-      $this->node->feedback = '';
-    }
-    if ($is_new || $this->node->revision == 1) {
-      $id = db_insert('quiz_long_answer_node_properties')
-        ->fields(array(
-          'nid' => $this->node->nid,
-          'vid' => $this->node->vid,
-          'rubric' => $this->node->rubric,
-        ))
-        ->execute();
-    }
-    else {
-      db_update('quiz_long_answer_node_properties')
-        ->fields(array('rubric' => $this->node->rubric))
-        ->condition('nid', $this->node->nid)
-        ->condition('vid', $this->node->vid)
-        ->execute();
-    }
+    db_merge('quiz_long_answer_node_properties')
+      ->key(array(
+        'nid' => $this->node->nid,
+        'vid' => $this->node->vid,
+      ))
+      ->fields(array(
+        'nid' => $this->node->nid,
+        'vid' => $this->node->vid,
+        'rubric' => $this->node->rubric,
+      ))
+      ->execute();
   }
 
   /**
@@ -193,7 +185,7 @@ class LongAnswerResponse extends QuizQuestionResponse {
     $query->fields('r', array('title'));
     $query->fields('qnr', array('time_end', 'time_start', 'uid'));
     $query->fields('qnra', array('result_id', 'question_nid', 'question_vid'));
-    $query->join('quiz_node_results_answers','qnra', 'a.result_answer_id = qnra.result_answer_id');
+    $query->join('quiz_node_results_answers', 'qnra', 'a.result_answer_id = qnra.result_answer_id');
     $query->join('node_revision', 'r', 'qnra.question_vid = r.vid');
     $query->join('quiz_node_results', 'qnr', 'qnra.result_id = qnr.result_id');
     $query->join('node', 'n', 'qnr.nid = n.nid');
diff --git a/question_types/long_answer/long_answer.test b/question_types/long_answer/long_answer.test
index cd9b880..f87b553 100644
--- a/question_types/long_answer/long_answer.test
+++ b/question_types/long_answer/long_answer.test
@@ -53,13 +53,14 @@ class LongAnswerTestCase extends QuizQuestionTestCase {
     // Strange behavior - extra spacing in the HTML.
     //$this->assertText('Score ? of 10');
     $this->assertText('This answer has not yet been scored.');
-    $this->assertNoFieldByName('0[score]');
     $this->assertNoFieldByName('1[score]');
+    $this->assertNoFieldByName('2[score]');
     $url_of_result = $this->getUrl();
+    $admin_url_of_result = preg_replace('#quiz-results/(\d+)#', 'quiz/results/$1', $this->getUrl());
 
     // Test grading the question.
     $this->drupalLogin($this->admin);
-    $this->drupalGet($url_of_result);
+    $this->drupalGet($admin_url_of_result);
     $this->drupalPost(NULL, array(
       "0[score]" => 3,
       "1[score]" => 7,
diff --git a/question_types/quiz_question/quiz_question.core.inc b/question_types/quiz_question/quiz_question.core.inc
index c3dcc9e..620aa57 100644
--- a/question_types/quiz_question/quiz_question.core.inc
+++ b/question_types/quiz_question/quiz_question.core.inc
@@ -324,7 +324,7 @@ abstract class QuizQuestion {
   /**
    * Save question type specific node properties
    */
-  abstract public function saveNodeProperties($is_new = FALSE);
+  abstract public function saveNodeProperties();
 
   /**
    * Save this Question to the specified Quiz.
@@ -712,6 +712,7 @@ abstract class QuizQuestionResponse {
      * Add general data, and data from the question type implementation
      */
     $form = array();
+
     $form['nid'] = array(
       '#type' => 'value',
       '#value' => $this->question->nid,
@@ -728,112 +729,19 @@ abstract class QuizQuestionResponse {
       '#type' => 'value',
       '#value' => $this->display_number,
     );
-    if (quiz_access_to_score() && $submit = $this->getReportFormSubmit()) {
-      $form['submit'] = array(
-        '#type' => 'value',
-        '#value' => $submit,
-      );
-    }
-
-    if (quiz_access_to_score() && $submit) {
-      $form['score'] = $this->getReportFormScore();
-    }
-    if (quiz_access_to_score() && $submit) {
-      $form['answer_feedback'] = $this->getReportFormAnswerFeedback();
-    }
-
-    foreach ($this->getFeedback() as $type => $render) {
-      $form[$type] = $render;
-    }
-
-    return $form;
-  }
-
-  /**
-   * Returns a renderable array of question feedback.
-   */
-  public function getFeedback() {
-    $out = array();
-    $node = node_load($this->question->nid, $this->question->vid);
-    $entity_info = entity_get_info('node');
-    foreach ($entity_info['view modes'] as $view_mode => $info) {
-      if ($this->canReview("quiz_question_view_" . $view_mode)) {
-        $build = node_view($node, $view_mode);
-        unset($build['#theme']);
-        unset($build['answers']);
-        unset($build['links']);
-
-        $out['question'][$node->nid] = $build;
-      }
-    }
-
-    $rows = array();
-
-    $labels = array(
-      'attempt' => t('Your answer'),
-      'choice' => t('Choice'),
-      'correct' => t('Correct?'),
-      'score' => t('Score'),
-      'answer_feedback' => t('Feedback'),
-      'solution' => t('Correct answer'),
-    );
-    drupal_alter('quiz_feedback_labels', $labels);
-
-    foreach ($this->getFeedbackValues() as $idx => $row) {
-      foreach ($labels as $reviewType => $label) {
-        if ((isset($row[$reviewType]) && $this->canReview($reviewType))) {
-          $rows[$idx][$reviewType] = $row[$reviewType];
-        }
-      }
-    }
-
-    if ($this->isEvaluated()) {
-      $score = $this->getScore();
-      if ($this->isCorrect()) {
-        $class = 'q-correct';
-      }
-      else {
-        $class = 'q-wrong';
-      }
-    }
-    else {
-      $score = t('?');
-      $class = 'q-waiting';
-    }
-
-    if ($this->canReview('score') || quiz_access_to_score()) {
-      $out['score_display']['#markup'] = theme('quiz_question_score', array('score' => $score, 'max_score' => $this->getMaxScore(), 'class' => $class));
-    }
-
-    if ($rows) {
-      $headers = array_intersect_key($labels, $rows[0]);
-      $type = $this->getQuizQuestion()->node->type;
-      $out['response']['#markup'] = theme('quiz_question_feedback__' . $type, array('labels' => $headers, 'data' => $rows));
-    }
-
-    if ($this->canReview('question_feedback')) {
-      if ($properties = entity_load('quiz_question', FALSE, array('nid' => $this->quizQuestion->node->nid, 'vid' => $this->quizQuestion->node->vid))) {
-        $quiz_question = reset($properties);
-        $quiz_result = quiz_result_load($this->result_id);
-        $account = user_load($quiz_result->uid);
-        $token_types = array(
-          'global' => NULL,
-          'node' => $this->quizQuestion->node,
-          'user' => $account,
+    if (quiz_access_to_score()) {
+
+      if ($submit = $this->getReportFormSubmit()) {
+        $form['score'] = $this->getReportFormScore();
+        $form['answer_feedback'] = $this->getReportFormAnswerFeedback();
+        $form['submit'] = array(
+          '#type' => 'value',
+          '#value' => $submit,
         );
-        $quiz_question->feedback = token_replace($quiz_question->feedback, $token_types);
-        $out['question_feedback']['#markup'] = check_markup($quiz_question->feedback, $quiz_question->feedback_format);
       }
-    }
 
-    if ($this->canReview('score')) {
-      $out['max_score'] = array(
-        '#type' => 'value',
-        '#value' => $this->getMaxScore(),
-      );
+      return $form;
     }
-
-    return $out;
   }
 
   /**
diff --git a/question_types/quiz_question/quiz_question.module b/question_types/quiz_question/quiz_question.module
index da5cd7e..28bf612 100644
--- a/question_types/quiz_question/quiz_question.module
+++ b/question_types/quiz_question/quiz_question.module
@@ -985,12 +985,10 @@ function quiz_question_element_validate(&$element, &$form_state) {
   $result = _quiz_question_response_get_instance($_SESSION['quiz'][$quiz->nid]['result_id'], $current_question, $answer);
   if ($quiz->repeat_until_correct && !$result->isCorrect() && $result->isEvaluated()) {
     form_set_error('', t('The answer was incorrect. Please try again.'));
-
-    $feedback = quiz_question_feedback($quiz, $current_question);
-    $element['feedback'] = array(
-      '#weight' => 100,
-      '#markup' => drupal_render($feedback),
-    );
+    // Show feedback after incorrect answer.
+    $qra = entity_load_single('quiz_result_answer', $result->result_answer_id);
+    $element['feedback'] = $qra->view();
+    $element['feedback']['#weight'] = 100;
   }
 }
 
diff --git a/question_types/short_answer/short_answer.classes.inc b/question_types/short_answer/short_answer.classes.inc
index fc71412..a9b3346 100644
--- a/question_types/short_answer/short_answer.classes.inc
+++ b/question_types/short_answer/short_answer.classes.inc
@@ -33,27 +33,18 @@ class ShortAnswerQuestion extends QuizQuestion {
    * @see QuizQuestion#saveNodeProperties($is_new)
    */
   public function saveNodeProperties($is_new = FALSE) {
-    if ($is_new || $this->node->revision == 1) {
-      $id = db_insert('quiz_short_answer_node_properties')
-        ->fields(array(
-          'nid' => $this->node->nid,
-          'vid' => $this->node->vid,
-          'correct_answer' => $this->node->correct_answer,
-          'correct_answer_evaluation' => $this->node->correct_answer_evaluation,
-        ))
-        ->execute();
-    }
-    else {
-
-      db_update('quiz_short_answer_node_properties')
-        ->fields(array(
-          'correct_answer' => $this->node->correct_answer,
-          'correct_answer_evaluation' => $this->node->correct_answer_evaluation,
-        ))
-        ->condition('nid', $this->node->nid)
-        ->condition('vid', $this->node->vid)
-        ->execute();
-    }
+    db_merge('quiz_short_answer_node_properties')
+      ->key(array(
+        'nid' => $this->node->nid,
+        'vid' => $this->node->vid,
+      ))
+      ->fields(array(
+        'nid' => $this->node->nid,
+        'vid' => $this->node->vid,
+        'correct_answer' => $this->node->correct_answer,
+        'correct_answer_evaluation' => $this->node->correct_answer_evaluation,
+      ))
+      ->execute();
   }
 
   /**
@@ -286,7 +277,7 @@ class ShortAnswerResponse extends QuizQuestionResponse {
     $query->fields('r', array('title'));
     $query->fields('qnr', array('time_end', 'time_start', 'uid'));
     $query->fields('qnra', array('result_id', 'question_nid', 'question_vid'));
-    $query->join('quiz_node_results_answers','qnra', 'a.result_answer_id = qnra.result_answer_id');
+    $query->join('quiz_node_results_answers', 'qnra', 'a.result_answer_id = qnra.result_answer_id');
     $query->join('node_revision', 'r', 'qnra.question_vid = r.vid');
     $query->join('quiz_node_results', 'qnr', 'qnra.result_id = qnr.result_id');
     $query->join('node', 'n', 'qnr.nid = n.nid');
diff --git a/question_types/short_answer/short_answer.test b/question_types/short_answer/short_answer.test
index 7e1d2b0..bbab054 100644
--- a/question_types/short_answer/short_answer.test
+++ b/question_types/short_answer/short_answer.test
@@ -163,15 +163,13 @@ class ShortAnswerTestCase extends QuizQuestionTestCase {
     $this->assertNoFieldByName('1[answer_feedback][value]');
     $this->assertNoRaw(t('Save score'));
     $url_of_result = $this->getUrl();
+    $admin_url_of_result = preg_replace('#quiz-results/(\d+)#', 'quiz/results/$1', $this->getUrl());
 
     // Test grading the question.
     $this->drupalLogin($this->admin);
-    $this->drupalGet($url_of_result);
+    $this->drupalGet($admin_url_of_result);
     $this->assertFieldByName('0[score]');
     $this->assertFieldByName('1[score]');
-    // Admin has to provide feedback.
-    $this->drupalLogin($this->admin);
-    $this->drupalGet($url_of_result);
     $this->drupalPost(NULL, array(
       "0[score]" => 2,
       "1[score]" => 3,
diff --git a/quiz.admin.inc b/quiz.admin.inc
index 186a0af..60a0662 100644
--- a/quiz.admin.inc
+++ b/quiz.admin.inc
@@ -370,13 +370,12 @@ function quiz_admin_node_form_submit($form, &$form_state) {
  * @param $result_id
  *   The result id
  */
-function quiz_admin_results($quiz, $result_id) {
+function quiz_admin_results($quiz, $quiz_result) {
   // Preserve "Results" tab.
   $item = menu_get_item("node/$quiz->nid/quiz");
   menu_set_item(NULL, $item);
 
-  module_load_include('inc', 'quiz', 'quiz.pages');
-  return quiz_user_results($result_id);
+  return entity_ui_get_form('quiz_result', $quiz_result);
 }
 
 // MANAGE QUESTIONS
diff --git a/quiz.css b/quiz.css
index 016e8ad..a7086d6 100644
--- a/quiz.css
+++ b/quiz.css
@@ -119,15 +119,16 @@ div.quiz-report .quiz-report-question-header h3 {
   float:left;
 }
 
-div.quiz-report .dt div.quiz-report-score-container {
+div.quiz-report-score-container {
   border-right: solid 1px gray;
   border-left: solid 1px gray;
   border-bottom: solid 1px gray;
+  border-top: solid 1px gray;
   float: right;
   padding: 4px 6px;
 }
 
-div.quiz-report .dt div.quiz-report-score-container span div.form-item {
+div.quiz-report-score-container span div.form-item {
   display: inline;
 }
 
diff --git a/quiz.module b/quiz.module
index 516fec3..40f907c 100644
--- a/quiz.module
+++ b/quiz.module
@@ -174,8 +174,9 @@ function quiz_admin_paths() {
  * @return boolean
  *   TRUE if user has permission.
  */
-function quiz_access_results($quiz, $result_id = NULL) {
+function quiz_access_results($quiz, $quiz_result) {
   global $user;
+  $result_id = $quiz_result->result_id;
 
   if ($quiz->type !== 'quiz') {
     return FALSE;
@@ -188,6 +189,9 @@ function quiz_access_results($quiz, $result_id = NULL) {
       return FALSE;
     }
   }
+  if (user_access('score any quiz')) {
+    return TRUE;
+  }
   if (user_access('view any quiz results')) {
     return TRUE;
   }
@@ -346,8 +350,8 @@ function quiz_menu() {
     'title' => 'Feedback',
     'title callback' => 'quiz_title',
     'title arguments' => array(1),
-    'page callback' => 'quiz_take_question_feedback',
-    'page arguments' => array(1, 3),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('quiz_take_question_feedback_form', 1, 3),
     'access callback' => 'quiz_question_feedback_access',
     'access arguments' => array(1, 3),
   );
@@ -419,6 +423,14 @@ function quiz_menu() {
     'type' => MENU_NORMAL_ITEM,
   );
 
+  $items['admin/quiz/result_answer'] = array(
+    'title' => 'Quiz result answer',
+    'description' => 'Configure Quiz result answer behaviors',
+    'page callback' => 'quiz_result_answer_page',
+    'access arguments' => array('administer quiz'),
+    'type' => MENU_NORMAL_ITEM,
+  );
+
   $items['node/%quiz_menu/quiz-results/%quiz_rid/view'] = array(
     'title' => 'View',
     'type' => MENU_DEFAULT_LOCAL_TASK,
@@ -434,7 +446,7 @@ function quiz_menu() {
     'file' => 'quiz.pages.inc',
   );
 
-  $items['node/%quiz_menu/quiz/results/%quiz_rid/view'] = array(
+  $items['node/%quiz_menu/quiz/results/%quiz_result/view'] = array(
     'title' => 'Results',
     'page callback' => 'quiz_admin_results',
     'page arguments' => array(1, 4),
@@ -518,6 +530,13 @@ function quiz_result_page() {
 }
 
 /**
+ * Page for Quiz result answer configuration and fields.
+ */
+function quiz_result_answer_page() {
+  return t('Here, you can configure how Quiz result answers behave.');
+}
+
+/**
  * Implements hook_theme().
  */
 function quiz_theme($existing, $type, $theme, $path) {
@@ -736,6 +755,8 @@ function quiz_update($node) {
  * Implements hook_field_extra_fields().
  */
 function quiz_field_extra_fields() {
+  $extra = array();
+
   $extra['node']['quiz'] = array(
     'display' => array(
       'take' => array(
@@ -782,6 +803,39 @@ function quiz_field_extra_fields() {
       ),
     ),
   );
+
+  $options = quiz_get_feedback_options();
+  foreach ($options as $option => $label) {
+    $extra['quiz_result_answer']['quiz_result_answer']['display'][$option] = array(
+      'label' => $label,
+      'description' => t('Feedback for @label.', array('@label' => $label)),
+      'weight' => 0,
+    );
+  }
+  $extra['quiz_result_answer']['quiz_result_answer']['display']['table'] = array(
+    'label' => t('Feedback table'),
+    'description' => t('A table of feedback.'),
+    'weight' => 0,
+  );
+
+  $extra['quiz_result']['quiz_result']['display'] = array(
+    'score' => array(
+      'label' => t('Score'),
+      'description' => t('The score of the result.'),
+      'weight' => 0,
+    ),
+    'questions' => array(
+      'label' => t('Questions'),
+      'description' => t('The questions in this result.'),
+      'weight' => 0,
+    ),
+    'summary' => array(
+      'label' => t('Summary'),
+      'description' => t('The summary and pass/fail text.'),
+      'weight' => 0,
+    ),
+  );
+
   return $extra;
 }
 
@@ -2805,7 +2859,7 @@ function _quiz_update_resultoptions($node) {
  * @return
  *   Filtered summary text or null if we are not displaying any summary.
  */
-function _quiz_get_summary_text($quiz_result, $score) {
+function _quiz_get_summary_text($quiz_result) {
   $quiz = node_load($quiz_result->nid);
   $account = user_load($quiz_result->uid);
   $token_types = array(
@@ -2816,13 +2870,13 @@ function _quiz_get_summary_text($quiz_result, $score) {
   );
   $summary = array();
 
-  if ($result_option = _quiz_pick_result_option($quiz->nid, $quiz->vid, $score['percentage_score'])) {
+  if ($result_option = _quiz_pick_result_option($quiz->nid, $quiz->vid, $quiz_result->score)) {
     // Range option.
     $summary['result'] = check_markup(token_replace($result_option->option_summary, $token_types), $result_option->option_summary_format);
   }
 
   if (variable_get('quiz_use_passfail', 1) && $quiz->pass_rate > 0) {
-    if ($score['percentage_score'] >= $quiz->pass_rate) {
+    if ($quiz_result->score >= $quiz->pass_rate) {
       // Pass/fail is enabled and user passed.
       $summary['passfail'] = check_markup(token_replace($quiz->summary_pass, $token_types), $quiz->summary_pass_format);
     }
@@ -3579,11 +3633,21 @@ function quiz_entity_info() {
     ),
     'quiz_result_answer' => array(
       'base table' => 'quiz_node_results_answers',
+      'bundles' => array(
+        'quiz_result_answer' => array(
+          'label' => 'Quiz result answer',
+          'admin' => array(
+            'path' => 'admin/quiz/result_answer',
+            'access arguments' => array('administer quiz'),
+          ),
+        ),
+      ),
       'controller class' => 'QuizResultAnswerController',
       'entity class' => 'QuizResultAnswer',
       'entity keys' => array(
         'id' => 'result_answer_id',
       ),
+      'fieldable' => TRUE,
       'label' => 'Quiz result answer',
       'metadata controller class' => 'QuizResultAnswerMetadataController',
       'views controller class' => 'EntityDefaultViewsController',
@@ -3637,7 +3701,9 @@ function quiz_access_question($quiz, $question_number) {
 /**
  * Show feedback for a question response.
  */
-function quiz_take_question_feedback($quiz, $question_number) {
+function quiz_take_question_feedback_form($form, &$form_state, $quiz, $question_number) {
+  $form = array();
+
   if (empty($_SESSION['quiz'][$quiz->nid]['result_id'])) {
     $result_id = $_SESSION['quiz']['temp']['result_id'];
   }
@@ -3645,9 +3711,30 @@ function quiz_take_question_feedback($quiz, $question_number) {
     $result_id = $_SESSION['quiz'][$quiz->nid]['result_id'];
   }
   $quiz_result = quiz_result_load($result_id);
-  $question_node = node_load($quiz_result->layout[$question_number]['nid'], $quiz_result->layout[$question_number]['vid']);
-  $feedback = quiz_question_feedback(node_load(arg(1)), $question_node);
-  return $feedback;
+
+  $form['actions']['#type'] = 'actions';
+
+  if ($quiz_result->time_end) {
+    // Quiz is done.
+    $form['actions']['finish'] = array(
+      '#type' => 'submit',
+      '#submit' => array('quiz_take_question_feedback_end_submit'),
+      '#value' => t('Finish'),
+    );
+  }
+  else {
+    $form['actions']['next'] = array(
+      '#type' => 'submit',
+      '#submit' => array('quiz_take_question_feedback_submit'),
+      '#value' => t('Next question'),
+    );
+  }
+
+  // Add feedback.
+  $qra = entity_load_single('quiz_result_answer', $quiz_result->layout[$question_number]['result_answer_id']);
+  $form['feedback'] = $qra->view();
+
+  return $form;
 }
 
 /**
@@ -3952,10 +4039,39 @@ function quiz_result_form($form, &$form_state, $quiz_result) {
   }
 
   $form['actions'] = array('#type' => 'actions');
-  $form['actions']['submit'] = array(
-    '#type' => 'submit',
-    '#value' => t('Start @quiz', array('@quiz' => QUIZ_NAME)),
-  );
+
+  if (!empty($quiz_result->result_id)) {
+    $idx = 0;
+    foreach ($quiz_result->layout as $question) {
+      // Loop through all the questions and get their scoring form.
+      $question_node = node_load($question['nid'], $question['vid']);
+      $instance = _quiz_question_response_get_instance($quiz_result->result_id, $question_node);
+      $qras = entity_load('quiz_result_answer', FALSE, array('result_id' => $quiz_result->result_id, 'question_nid' => $question_node->nid, 'question_vid' => $question_node->vid));
+      $qra = reset($qras);
+      // Get the feedback elements.
+      $form['questions'][$idx] = $instance->getReportForm();
+      $form['questions'][$idx]['#tree'] = TRUE;
+      $form['questions'][$idx]['#type'] = 'fieldset';
+      $form['questions'][$idx]['#title'] = t('Question @num', array('@num' => $question['display_number']));
+      // The display of the question.
+      $form['questions'][$idx]['response'] = $qra->view();
+      $form['questions'][$idx]['response']['#weight'] = -1;
+      $idx++;
+    }
+  }
+
+  if (empty($quiz_result->result_id)) {
+    $form['actions']['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Start @quiz', array('@quiz' => QUIZ_NAME)),
+    );
+  }
+  else {
+    $form['actions']['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Save score'),
+    );
+  }
 
   return $form;
 }
@@ -3975,4 +4091,8 @@ function quiz_result_form_submit($form, &$form_state) {
   entity_save('quiz_result', $quiz_result);
   $_SESSION['quiz'][$quiz_result->nid]['result_id'] = $quiz_result->result_id;
   $_SESSION['quiz'][$quiz_result->nid]['current'] = 1;
+
+  // Call the grading handler.
+  module_load_include('inc', 'quiz', 'quiz.pages');
+  quiz_report_form_submit($form, $form_state);
 }
diff --git a/quiz.pages.inc b/quiz.pages.inc
index acac374..0e124b0 100644
--- a/quiz.pages.inc
+++ b/quiz.pages.inc
@@ -13,6 +13,7 @@
  */
 function quiz_user_results($result_id) {
   $quiz_result = quiz_result_load($result_id);
+  return entity_view('quiz_result', array($quiz_result));
 
   if ($quiz_result->nid) {
     $quiz = node_load($quiz_result->nid, $quiz_result->vid);
@@ -61,76 +62,6 @@ function quiz_check_feedback(QuizResult $quiz_result) {
 }
 
 /**
- * Form for showing feedback, and for editing the feedback if necessary...
- *
- * @param $form_state
- *   FAPI form state(array)
- * @param $questions
- *   array of questions to inclide in the report
- * @return $form
- *   FAPI form array
- */
-function quiz_report_form($form, $form_state, $questions, $result_id) {
-  $form = array();
-  // The submit button is only shown if one or more of the questions has input elements
-  $show_submit = FALSE;
-  foreach ($questions as $question) {
-    $module = quiz_question_module_for_type($question->type);
-    if (!$module) {
-      return array();
-    }
-    $function = $module . '_report_form';
-    $form_to_add = $function($question, $result_id);
-    if (isset($form_to_add['submit'])) {
-      $show_submit = TRUE;
-      $form_to_add['#element_validate'][] = 'quiz_report_form_element_validate';
-    }
-    if (!isset($form_to_add['#no_report'])) {
-      $form[] = $form_to_add;
-    }
-  }
-
-  $form['#tree'] = TRUE;
-  $form['navigation']['#type'] = 'actions';
-  if ($show_submit) {
-    $form['navigation']['submit'] = array(
-      '#type' => 'submit',
-      '#submit' => array('quiz_report_form_submit'),
-      '#value' => t('Save score'),
-    );
-  }
-
-  if (arg(4) == 'feedback') {
-    // @todo Ugh, there is no way to determine if we are showing feedback as
-    // part of a try-until-correct or actual quiz after-question feedback, so we
-    // have to check arg() here to fix the "Next question" button showing up
-    // during adaptive mode.
-    $quiz_result = quiz_result_load($result_id);
-
-    if (count($questions) != count($quiz_result->layout)) {
-      $form['#quiz_result'] = $quiz_result;
-      if (empty($_SESSION['quiz'][$quiz_result->nid])) {
-        // Quiz is done.
-        $form['navigation']['finish'] = array(
-          '#type' => 'submit',
-          '#submit' => array('quiz_take_question_feedback_end_submit'),
-          '#value' => t('Finish'),
-        );
-      }
-      else {
-        $form['navigation']['next'] = array(
-          '#type' => 'submit',
-          '#submit' => array('quiz_take_question_feedback_submit'),
-          '#value' => t('Next question'),
-        );
-      }
-    }
-  }
-
-  return $form;
-}
-
-/**
  * Validate a single question sub-form.
  */
 function quiz_report_form_element_validate(&$element, &$form_state) {
@@ -143,51 +74,37 @@ function quiz_report_form_element_validate(&$element, &$form_state) {
  * Submit the report form
  */
 function quiz_report_form_submit($form, &$form_state) {
-  /* We go through the form state values and submit all
-   * questiontypes with validation functions declared.
-   */
   global $user;
+  $quiz_result = $form_state['quiz_result'];
+  $quiz = node_load($quiz_result->nid, $quiz_result->vid);
+
   foreach ($form_state['values'] as $key => $q_values) {
     // Questions has numeric keys in the report form
-    if (!is_numeric($key)) {
-      continue;
-    }
-    // Questions store the name of the validation function with the key 'submit'
-    if (!isset($q_values['submit'])) {
-      continue;
-    }
-    // The submit function must exist
-    if (!function_exists($q_values['submit'])) {
-      continue;
-    }
-
-    // Load the quiz
-    if (!isset($quiz)) {
-      $result = db_query('SELECT nid, uid, vid FROM {quiz_node_results} WHERE result_id = :result_id', array(':result_id' => $q_values['result_id']))->fetchObject();
-      $quiz = node_load($result->nid, $result->vid);
-      $result_id = $q_values['result_id'];
+    if (is_numeric($key)) {
+      $question_node = node_load($q_values['nid'], $q_values['vid']);
+      $instance = _quiz_question_response_get_instance($quiz_result->result_id, $question_node);
+      if ($instance->getReportFormSubmit()) {
+        $q_values['quiz'] = node_load($quiz_result->nid, $quiz_result->vid);
+        call_user_func($instance->getReportFormSubmit(), $q_values);
+      }
     }
-
-    $q_values['quiz'] = $quiz;
-
-    // We call the submit function provided by the question
-    call_user_func($q_values['submit'], $q_values);
   }
+
   // Scores may have been changed. We take the necessary actions
-  quiz_end_scoring($result_id);
-  $results_got_deleted = _quiz_maintain_results($quiz, $result_id);
+  quiz_end_scoring($quiz_result->result_id);
+  $results_got_deleted = _quiz_maintain_results($quiz, $quiz_result->result_id);
 
   // Notify the user if results got deleted as a result of him scoring an answer.
   $add = $quiz->keep_results == QUIZ_KEEP_BEST && $results_got_deleted ? ' ' . t('Note that this @quiz is set to only keep each users best answer.', array('@quiz' => QUIZ_NAME)) : '';
 
-  $score_data = quiz_get_score_array($result_id, $quiz->vid, TRUE);
+  $score_data = quiz_get_score_array($quiz_result->result_id, $quiz->vid, TRUE);
 
-  module_invoke_all('quiz_scored', $quiz, $score_data, $result_id);
+  module_invoke_all('quiz_scored', $quiz, $score_data, $quiz_result->result_id);
 
   drupal_set_message(t('The scoring data you provided has been saved.') . $add);
   if (user_access('score taken quiz answer') && !user_access('view any quiz results')) {
-    if ($result && $result->uid == $user->uid) {
-      $form_state['redirect'] = 'node/' . $quiz->nid . '/quiz/results/' . $result_id;
+    if ($quiz_result && $quiz_result->uid == $user->uid) {
+      $form_state['redirect'] = 'node/' . $quiz->nid . '/quiz/results/' . $quiz_result->result_id;
     }
   }
 }
@@ -397,71 +314,6 @@ function theme_quiz_view_stats($variables) {
 }
 
 /**
- * Theme the result page.
- *
- * @param $quiz
- *  The quiz node object.
- * @param $questions
- *  The questions array as defined by _quiz_get_answers.
- * @param $score
- *  Array of score information as returned by quiz_calculate_score().
- * @param $summary
- *  Filtered text of the summary.
- * @return
- *  Themed html.
- *
- * @ingroup themeable
- */
-function theme_quiz_result($variables) {
-  global $user;
-  $quiz = $variables['quiz'];
-  $questions = $variables['questions'];
-  $score = $variables['score'];
-  $summary = $variables['summary'];
-  $quiz_result = quiz_result_load($variables['result_id']);
-  $account = $variables['account'];
-
-  if (!$score['is_evaluated'] && empty($_POST)) {
-    $msg = t('Parts of this @quiz have not been evaluated yet. The score below is not final.', array('@quiz' => QUIZ_NAME));
-    drupal_set_message($msg, 'warning');
-  }
-
-  // Display overall result.
-  $output = '';
-  $params = array(
-    '%num_correct' => $score['numeric_score'],
-    '%question_count' => $score['possible_score'],
-    '!username' => ($user->uid == $account->uid) ? t('You') : theme('username', array('account' => $account)),
-    '@score' => $score['percentage_score'],
-    '!yourtotal' => ($user->uid == $account->uid) ? t('Your') : t('Total'),
-  );
-
-  $score_out = '';
-  if (quiz_feedback_can_review('score', $quiz_result)) {
-    // Show score.
-    $score_out .= '<div id="quiz_score_possible">' . t('!username got %num_correct of %question_count possible points.', $params) . '</div>' . "\n";
-    $score_out .= '<div id="quiz_score_percent">' . t('!yourtotal score: @score%', $params) . '</div>';
-  }
-
-  $report_form = drupal_get_form('quiz_report_form', $questions, $quiz_result->result_id);
-
-  $quiz_feedback['#markup'] = '';
-  if (quiz_feedback_can_review('quiz_feedback', $quiz_result)) {
-    // Show quiz feedback.
-    if (!empty($summary['passfail'])) {
-      $quiz_feedback['#markup'] .= '<div id="quiz-summary">' . $summary['passfail'] . '</div>';
-    }
-    if (!empty($summary['result'])) {
-      $quiz_feedback['#markup'] .= '<div id="quiz-summary">' . $summary['result'] . '</div>';
-    }
-  }
-  $report_form['quiz_feedback'] = $quiz_feedback;
-
-  $form = drupal_render($report_form);
-  return $score_out . $form;
-}
-
-/**
  * Help us with special pagination.
  *
  * Why not the Drupal theme_pager()?
diff --git a/tests/QuizGradingTestCase.test b/tests/QuizGradingTestCase.test
index 6ff5a39..98dd370 100644
--- a/tests/QuizGradingTestCase.test
+++ b/tests/QuizGradingTestCase.test
@@ -104,10 +104,11 @@ class QuizGradingTestCase extends QuizTestCase {
       ), t('Finish'));
     $this->assertText('You got 3 of 10 possible points.');
     $url_of_result = $this->getUrl();
+    $admin_url_of_result = preg_replace('#quiz-results/(\d+)#', 'quiz/results/$1', $this->getUrl());
 
     // Test grading the question.
     $this->drupalLogin($this->admin);
-    $this->drupalGet($url_of_result);
+    $this->drupalGet($admin_url_of_result);
 
     $this->drupalPost(NULL, array(
       "0[score]" => 3,
diff --git a/tests/QuizResultTestCase.test b/tests/QuizResultTestCase.test
index 97a58a8..347ae18 100644
--- a/tests/QuizResultTestCase.test
+++ b/tests/QuizResultTestCase.test
@@ -494,7 +494,7 @@ class QuizResultTestCase extends QuizTestCase {
     $this->drupalPost(NULL, array('quiz_result_field_a[und][0][value]' => 'test 123'), t('Start Quiz'));
     $quiz_result = _quiz_active_result_id($this->user->uid, $quizNodeA->nid, $quizNodeA->vid);
     // Check the result exists now.
-    $this->assertTrue($quiz_result, 'Quiz result exists.');
+    $this->assertText('Question 1');
   }
 
   /**
