<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.expertiza.ncsu.edu/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Shmehta</id>
	<title>Expertiza_Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.expertiza.ncsu.edu/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Shmehta"/>
	<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=Special:Contributions/Shmehta"/>
	<updated>2026-07-05T18:34:33Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.41.0</generator>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2015._Conflict_notification&amp;diff=134125</id>
		<title>CSC/ECE 517 Spring 2020 - E2015. Conflict notification</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2015._Conflict_notification&amp;diff=134125"/>
		<updated>2020-04-25T02:46:28Z</updated>

		<summary type="html">&lt;p&gt;Shmehta: /* Files Changed */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
Expertiza is an open-source project written using the Ruby on Rails framework.  The Expertiza platform aims to improve student learning by using active and cooperative learning, allowing distance education students to participate in active learning, and by discouraging plagiarism through the use of multiple deadlines. Expertiza helps to improve teaching and resource utilization by having students contribute to the creation of course materials and through peer-graded assignments. Expertiza manages objects related to a course such as instructors, TAs, students, and other users. It also manages assignments, teams, signup topics, rubrics, peer grading, and peer evaluations.&lt;br /&gt;
&lt;br /&gt;
== Reports Background ==&lt;br /&gt;
Students can form teams in Expertiza to work on an assignment in a group. Submissions made on Expertiza can be peer-reviewed by students within the course based on a rubric. Results of the peer review can be accessed by instructors and respective student teams in the form of statistical reports. The students have access to view their feedback in the form of a Summary Report. The student Summary Report shows the scores submitted by the reviewers for each question of the rubric for that assignment. If there are more than one round, it shows the scores separated by round number. The instructors have more options to view student submitted feedback in the form of Reviewees Summary Reports which shows the average review scores for an assignment for each round with each reviewer's comments, and Review Reports which shows what teams' assignment were reviewed by each student.&lt;br /&gt;
&lt;br /&gt;
== Review Conflict Background ==&lt;br /&gt;
In the current implementation, during the peer review phase of an assignment, email notifications are sent out to the instructor whenever a submitted review score differs “significantly” from the average score of other submitted reviews for that submission. The threshold to trigger a notification is specified in the “Notification limit” on the Rubrics tab of assignment creation. The email that gets sent to instructors contains three links: a link to the conflicting review, a link to the summary page of grades for the reviewee, and a link to edit the assignment.&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
When a review is submitted that triggers a conflict, an email gets sent to instructors that contains three links: a link to the conflicting review, a link to the summary page of grades for the reviewee, and a link to edit the assignment. Although the links sent in the email are helpful for reference, the process of examining a conflicting review could be made more efficient if we provide an easy to understand report of the conflicts. The information sent in the email should be updated to contain a link to a report page which should contain more details about the newest conflict as well as information on previous review conflicts for the assignment. The conflict report page should have an easy to understand visualization showing the assignment's reviews with scores that cause a conflict.&lt;br /&gt;
&lt;br /&gt;
= Existing Implementation =&lt;br /&gt;
The existing system has the following implementation for conflict notification. On submitting a new review for a particular artifact, the submitted score is compared to the average score of the previously submitted reviews. If the difference between the average score and the newly submitted score is more than the notification threshold specified for the assignment, an email is sent out to the instructor. The email sent to the instructor contains the names of the reviewer and reviewee and a link to the conflicting review, a link to the summary of review responses, and a link to edit the assignment. The flowchart below delineates the entire process:&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
[[File:Conflictflowchart.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
== Problems with Existing Implementation ==&lt;br /&gt;
The existing implementation has the following flaws:&lt;br /&gt;
&lt;br /&gt;
=== No dedicated report for analyzing the conflict ===&lt;br /&gt;
The current implementation does not provide any dedicated view or report containing a detailed analysis of the conflicts that occur during the entire review period. The link to the conflicting review is helpful, but doesn't provide any context for for why that review was in conflict. The link to the summary of review responses provides more insight into how the assignment is being scored overall, but it doesn't provide a clear picture of which reviews are in conflict and have scores that are outliers. &lt;br /&gt;
&lt;br /&gt;
=== Incorrect email URLs ===&lt;br /&gt;
When an review is in conflict and an email gets set to the instructor, the body of the email contains links to the review, review summary page, and a link to edit the assignment. See a copy of the email message below as it is being sent by the current implementation.&lt;br /&gt;
[[File:Conflictemail.png]]&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
The current implementation uses hardcoded URLs mentioned in the &amp;lt;code&amp;gt;notify_instructor_on_difference&amp;lt;/code&amp;gt; method of the &amp;lt;code&amp;gt;models/response.rb&amp;lt;/code&amp;gt; file. See the code:&lt;br /&gt;
&lt;br /&gt;
  conflicting_response_url: 'https://expertiza.ncsu.edu/response/view?id=' + response_id.to_s,&lt;br /&gt;
  summary_url: 'https://expertiza.ncsu.edu/grades/view_team?id=' + reviewee_participant.id.to_s,&lt;br /&gt;
  assignment_edit_url: 'https://expertiza.ncsu.edu/assignments/' + assignment.id.to_s + '/edit'&lt;br /&gt;
&lt;br /&gt;
Being hardcoded, these link would not work in on other servers where Expertiza is running. For example, the links won't be valid if the setup was done on the localhost.&lt;br /&gt;
&lt;br /&gt;
= Previous Work =&lt;br /&gt;
&lt;br /&gt;
The [https://expertiza.csc.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_E1931._Conflict_notification Previous Work] resolved the email related issues and also created a simple UI report page for analyzing the conflict. However, the implementation had quite a few issues that prevented it from being merged. See a screenshot from the previous implementation of a snippet of the information from the conflict report page:&amp;lt;br /&amp;gt; [[File:OldConflictGraph.PNG|center]]&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
==Issues with Previous Work ==&lt;br /&gt;
1. The UI for the conflict report included a bar graph that showed the grades of reviews that were in conflict. The information in the bar graph was showing percentages while the scores shown beside it were in raw points. This is an inconsistency; they should display the data in the same units.&amp;lt;br /&amp;gt;&lt;br /&gt;
2. The bar graph contained too much white space and took up too much area on the screen.&amp;lt;br /&amp;gt;&lt;br /&gt;
3. It was also not obvious from the bar graph which review scores caused a conflict as they were not highlighted or distinguished in any way.&amp;lt;br /&amp;gt;&lt;br /&gt;
4. The bars in the chart were also not sorted in any meaningful way (i.e., ascending or descending) &amp;lt;br /&amp;gt;&lt;br /&gt;
5. The list of students who reviewed an submission extended vertically down the page which contributed to each row of the table taking up considerable screen space, especially for submissions with many reviews.&amp;lt;br /&amp;gt;&lt;br /&gt;
6. The metrics listed in the screenshot above don't specify the threshold for conflict. Therefore, you can't tell what review scores would actually cause a conflict.&amp;lt;br /&amp;gt;&lt;br /&gt;
7. The code for the conflict report view included a lot of logic. &amp;lt;br /&amp;gt;&lt;br /&gt;
8. There was minimal effort spent on refactoring test cases and the test cases added in the pull request were shallow tests, meaning that they simply asserted that the expected value was not empty rather than the correct way of asserting the expected value matched a specific value. &amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Design of New Implementation =&lt;br /&gt;
== Proposed Solution ==&lt;br /&gt;
As the mailing functionality was implemented perfectly in the previous implementation, we plan to use their implementation as our starting point. Building on top of it, we plan to address the highlighted issues with the previous implementation and refactor the conflict report so that it is able to provide better insights into the review conflicts.&lt;br /&gt;
Once the existing code determines that a conflict has occurred, the code will create a report view for the conflict. The report view will contain all the relevant statistics(mean, max, standard deviation, etc.) of all the reviews received for the submission. Next, a URL for the report page will be added to the email body. All URLs in the email will be relative URLs and therefore the URLs will be valid on all servers. Following files need to be updated in order to implement these changes:   &lt;br /&gt;
&lt;br /&gt;
*Related to Email:&lt;br /&gt;
**&amp;lt;code&amp;gt;app/mailers/mailer.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Modify method &amp;lt;code&amp;gt;notify_grade_conflict_message&amp;lt;/code&amp;gt; to add the link to the conflict report in the email body.&lt;br /&gt;
**&amp;lt;code&amp;gt;app/models/response.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Modify method &amp;lt;code&amp;gt;notify_instructor_on_difference&amp;lt;/code&amp;gt; to add a relative links to various pages that get included in the email body.&lt;br /&gt;
**&amp;lt;code&amp;gt;app/views/mailer/notify_grade_conflict_message.html.erb&amp;lt;/code&amp;gt; &lt;br /&gt;
*** Modify the html to add a link to the email message using which the conflict report viewed.&lt;br /&gt;
**&amp;lt;code&amp;gt;app/controllers/response_contrller.rb&amp;lt;/code&amp;gt; &lt;br /&gt;
*** Modify &amp;lt;code&amp;gt;update&amp;lt;/code&amp;gt; method to add &amp;lt;code&amp;gt;request.base_url&amp;lt;/code&amp;gt; as a param sent to &amp;lt;code&amp;gt;notify_instructor_on_difference&amp;lt;/code&amp;gt; method&lt;br /&gt;
*** Modify &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method to add &amp;lt;code&amp;gt;request.base_url&amp;lt;/code&amp;gt; as a param sent to &amp;lt;code&amp;gt;notify_instructor_on_difference&amp;lt;/code&amp;gt; method&lt;br /&gt;
	&lt;br /&gt;
*Related to the conflict report view:&lt;br /&gt;
**&amp;lt;code&amp;gt;app/views/reports/_searchbox.html.erb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Modify the html to add the option to view a conflict report.&lt;br /&gt;
**&amp;lt;code&amp;gt;app/views/reports/response_report.html.haml&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Modify the html to render the conflict report partial if the option to view a conflict report was selected.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
What we need to create:&lt;br /&gt;
*Related to the conflict report view:&lt;br /&gt;
**&amp;lt;code&amp;gt;App/views/reports/_conflict_report.html.erb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Need to create this entire file to make the view for a conflict report&lt;br /&gt;
**&amp;lt;code&amp;gt;app/helpers/report_formatter_helper.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Need to add a method &amp;lt;code&amp;gt;conflict_reponse_map&amp;lt;/code&amp;gt; to make specific instance variables available to our conflict report view. This method will get called from the ReportsController. &lt;br /&gt;
**&amp;lt;code&amp;gt;app/helpers/summary_helper.rb&amp;lt;/code&amp;gt; &lt;br /&gt;
*** Need to add a method to get the maximum possible score of an assignment in each round&lt;br /&gt;
**&amp;lt;code&amp;gt;app/models/answer.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Need to add a method to get the answers from a review for an assignment submitted by a specific reviewer.&lt;br /&gt;
**&amp;lt;code&amp;gt;app/helpers/review_mapping_helper.rb&amp;lt;/code&amp;gt; &lt;br /&gt;
*** Need to add methods to get the review scores for a team in each round, calculate the average review score for a round, calculate the std. deviation of review scores for each round, and get the team members of each team. In addition, the code to create the formatted bar chart will also be placed in a helper method in this file. Apart from these, any other method to find and calculate data to be viewed in the report can be added to this helper file.	&lt;br /&gt;
	&lt;br /&gt;
&lt;br /&gt;
The conflict report view should:&lt;br /&gt;
*For each team that had a submission with a review that was in a conflict:&lt;br /&gt;
**List the team name and team members&lt;br /&gt;
**Provide a graphical view of the statistics displayed in the report&lt;br /&gt;
**For each round of reviews:&lt;br /&gt;
***List the students who reviewed the submission and the score they gave.&lt;br /&gt;
***Plot the review scores on a horizontal bar chart, highlighting those that caused a conflict.&lt;br /&gt;
***List the threshold for conflict review score, max review score, average review score, and standard deviation. &amp;lt;br \&amp;gt;&amp;lt;br \&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order to resolve the issues with the previous team's pull request, we will:&amp;lt;br \&amp;gt;&lt;br /&gt;
1. Modify the bar chart code to show the point values as raw scores instead of percentages.&amp;lt;br \&amp;gt;&lt;br /&gt;
2. Modify the bar chart code to eliminate unnecessary white space.&amp;lt;br \&amp;gt;&lt;br /&gt;
3. Modify the bar chart code to highlight bars representing scores that cause conflict. &amp;lt;br \&amp;gt;&lt;br /&gt;
4. Modify the bar chart code so that the bars are sorted by ascending score. &amp;lt;br \&amp;gt;&lt;br /&gt;
5. List the students who reviewed the submission in multiple columns rather than a single long column. &amp;lt;br \&amp;gt;&lt;br /&gt;
6. Add additional metrics specifying threshold for conflict to the conflict report so you can see what scores would cause a conflict. &amp;lt;br \&amp;gt;&lt;br /&gt;
7. Put the necessary logic into helper methods in helper files to ensure logic stays out of our views.&amp;lt;br \&amp;gt;&lt;br /&gt;
8. Refactor the necessary affected test cases and write new RSpec tests in accordance with our proposed test plan to ensure adequate coverage.&amp;lt;br \&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== UML Diagrams ==&lt;br /&gt;
=== Use Case Diagram ===&lt;br /&gt;
The usecase diagram highlights the simple workflow of the proposed system when trigger by the user.&amp;lt;br /&amp;gt;&lt;br /&gt;
[[File:usecase-1.png]]&lt;br /&gt;
&amp;lt;br /&amp;gt; &amp;lt;br /&amp;gt;&lt;br /&gt;
Actors participating:&lt;br /&gt;
&lt;br /&gt;
* Student: In this use case, fills out the reviews for different projects submitted by the peers.&lt;br /&gt;
* TA/Instructor: In this use case, goes over the conflicting review submitted by the students for the same project.&lt;br /&gt;
&lt;br /&gt;
=== Sequence Diagram ===&lt;br /&gt;
The sequence diagram models the interactions that will take place between various components of the system for the above use-case. &lt;br /&gt;
&amp;lt;br /&amp;gt; &amp;lt;br /&amp;gt;&lt;br /&gt;
[[File:conflictSeq.jpg]]&lt;br /&gt;
&lt;br /&gt;
= New Implementation =&lt;br /&gt;
== Addressing Problems with Conflict Emails and Mailer ==&lt;br /&gt;
In order to address the problem of hard coded URLs being sent in the email to instructors, we modified the &amp;lt;code&amp;gt;notify_instructor_on_difference&amp;lt;/code&amp;gt; method in the file &amp;lt;code&amp;gt;app/models/response.rb&amp;lt;/code&amp;gt;to accept a base_url parameter which gets set based on the request.base_url. This allows the links to be correct, even when the server is running on localhost. &amp;lt;br /&amp;gt;&lt;br /&gt;
[[File:Base_url_changes.PNG]]&lt;br /&gt;
&lt;br /&gt;
== Addressing Problems with Conflict Report and Previous Implementation ==&lt;br /&gt;
&lt;br /&gt;
= Testing =&lt;br /&gt;
Both manual testing and RSpec testing were used to test the new functionalities. &lt;br /&gt;
=== RSpec Testing ===&lt;br /&gt;
In order to test the changes implemented in the model, controller and helper file new RSpec tests have been added. &lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
'''1. Add a new test to &amp;lt;code&amp;gt;spec/controllers/reports_controller_spec.rb&amp;lt;/code&amp;gt;''' &amp;lt;br /&amp;gt;&lt;br /&gt;
The test checks if the new review conflict report is routed and rendered properly by the response controller.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: green&amp;quot;&amp;gt;&lt;br /&gt;
    describe '#review_conflict_response_map' do&lt;br /&gt;
      context 'when type is ReviewConflictResponseMap' do&lt;br /&gt;
        it 'renders response_report page with corresponding data' do&lt;br /&gt;
          allow(TeammateReviewResponseMap).to receive(:teammate_response_report)&lt;br /&gt;
            .with('1')&lt;br /&gt;
            .and_return([participant, participant2])&lt;br /&gt;
          params = {&lt;br /&gt;
              id: 1,&lt;br /&gt;
              report: {type: 'ReviewConflictResponseMap'},&lt;br /&gt;
              user: 'no one'&lt;br /&gt;
          }&lt;br /&gt;
          get :response_report, params&lt;br /&gt;
          expect(response).to render_template(:response_report)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. Add a new test to &amp;lt;code&amp;gt;spec/models/answer_spec.rb&amp;lt;/code&amp;gt;''' &amp;lt;br /&amp;gt;&lt;br /&gt;
This tests if the query in the newly added method 'answers_by_round_for_reviewee' works properly and fetches a valid result.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: green&amp;quot;&amp;gt;&lt;br /&gt;
    it &amp;quot;returns answers by reviewer for reviewee in round from db which is not empty&amp;quot; do&lt;br /&gt;
      expect(Answer.answers_by_round_for_reviewee(@assignment_id, @reviewee_id,@round)).not_to be_empty&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''3. Create and add a new tests to &amp;lt;code&amp;gt;spec/helpers/review_mapping_helper_spec.rb&amp;lt;/code&amp;gt;''' &amp;lt;br /&amp;gt;&lt;br /&gt;
This file tests various calculations performed by the newly added helper methods. The results of these calculations are not only used to display on the report but also used to generate the graph. &lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: green&amp;quot;&amp;gt;&lt;br /&gt;
describe &amp;quot;ReviewMappingHelper&amp;quot; do&lt;br /&gt;
  describe &amp;quot;#review_score_helper_for_team&amp;quot; do&lt;br /&gt;
    before(:each) do&lt;br /&gt;
      @review_answers = [{'reviewer_id': '2', 'answer': 54}, {'reviewer_id': '1', 'answer': 24}, {'reviewer_id': '2', 'answer': 25}]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;The review_score_helper_for_team method calculates the total review scores for each review&amp;quot; do&lt;br /&gt;
      question_answers = helper.review_score_helper_for_team(@review_answers)&lt;br /&gt;
      expect(question_answers).to include('1' =&amp;gt; 24,'2' =&amp;gt; 79)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe &amp;quot;#get_score_metrics&amp;quot; do&lt;br /&gt;
    before(:each) do&lt;br /&gt;
      @review_scores = {'1' =&amp;gt; 50, '2' =&amp;gt; 40, '3' =&amp;gt; 60}&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;The get_score_metrics method calculates various metrics used in the conflict report&amp;quot; do&lt;br /&gt;
      metric = helper.get_score_metrics(@review_scores, 50)&lt;br /&gt;
      expect(metric[:average]).to eq 50.0&lt;br /&gt;
      expect(metric[:std]).to eq 8.16&lt;br /&gt;
      expect(metric[:upper_tolerance_limit]).to eq 50&lt;br /&gt;
      expect(metric[:lower_tolerance_limit]).to eq 33.68&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''4. Add new test in &amp;lt;code&amp;gt;spec/features/review_mapping_helper_spec.rb&amp;lt;/code&amp;gt;''' &amp;lt;br /&amp;gt;&lt;br /&gt;
This UI test navigates to the conflict report page and tests if the report is rendered properly.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: green&amp;quot;&amp;gt;&lt;br /&gt;
describe &amp;quot;Test Review conflict report&amp;quot; do&lt;br /&gt;
  before(:each) do&lt;br /&gt;
    create(:instructor)&lt;br /&gt;
    create(:assignment, course: nil, name: 'Test Assignment')&lt;br /&gt;
    assignment_id = Assignment.where(name: 'Test Assignment')[0].id&lt;br /&gt;
    login_as 'instructor6'&lt;br /&gt;
    visit &amp;quot;/reports/response_report?id=#{assignment_id}&amp;quot;&lt;br /&gt;
    page.select(&amp;quot;Review conflict report&amp;quot;, :from =&amp;gt; &amp;quot;report[type]&amp;quot;)&lt;br /&gt;
    click_button &amp;quot;View&amp;quot;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  # Check if the page renders&lt;br /&gt;
&lt;br /&gt;
  it &amp;quot;has a conflicting review table&amp;quot; do&lt;br /&gt;
    expect(page).to have_css('table')&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it &amp;quot;can display teams&amp;quot; do&lt;br /&gt;
    expect(page).to have_content('Team')&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it &amp;quot;can display author reviewers and metrics&amp;quot; do&lt;br /&gt;
    expect(page).to have_selector(:link_or_button, 'Convert Points to Percents')&lt;br /&gt;
  end&lt;br /&gt;
end &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
All RSpec tests are passing for the current implementation as is evident by the passing Travis CI build.&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
[[File:TravisCI.PNG]]&lt;br /&gt;
&lt;br /&gt;
== Manual Testing ==&lt;br /&gt;
In order to test the functionality manually, we follow the following steps: &amp;lt;br \&amp;gt;&lt;br /&gt;
1. Create a new assignment with 15% as a conflict threshold limit. &amp;lt;br /&amp;gt;&lt;br /&gt;
2. Add 4 students to the assignment and divide them into 2 teams of 2 students in each. &amp;lt;br /&amp;gt;&lt;br /&gt;
3. Add submission for each team. &amp;lt;br /&amp;gt;&lt;br /&gt;
4. In the review phase, login to the first team student accounts and give scores of 100% and 50% to the second team's assignment. &amp;lt;br /&amp;gt;&lt;br /&gt;
5. Since the scores differ by more than 15% the email will be sent to the instructor. &amp;lt;br /&amp;gt;&lt;br /&gt;
6. Access the email and check if the email contains the following details: &amp;lt;br /&amp;gt;&lt;br /&gt;
* Names of the reviewer and reviewee&lt;br /&gt;
* Link to the conflicting review&lt;br /&gt;
* Link to the newly created report view corresponding to the conflict&lt;br /&gt;
* Link to edit the assignment notification limit&lt;br /&gt;
7. View the conflict report and ensure that Team 2 shows up as having a conflicting review submitted by student 2 of Team 1.&lt;br /&gt;
&lt;br /&gt;
== Demo ==&lt;br /&gt;
The video [https://drive.google.com/drive/u/0/folders/13_apTDwdFTm78dC_HAS9QVnynUMFc-Mr] demonstrates the functionalities implemented in this project.&lt;br /&gt;
&lt;br /&gt;
= Files Changed =&lt;br /&gt;
* [https://github.com/expertiza/expertiza/pull/1714/files#diff-0df434e3b51a1cb1604423db5db1ff66 Conflict Report] &amp;lt;br&amp;gt;&lt;br /&gt;
* [https://github.com/expertiza/expertiza/pull/1714/files#diff-7786ab741930f6bace28b7e5da61b8d6 Response Controller] &amp;lt;br&amp;gt;&lt;br /&gt;
* [https://github.com/expertiza/expertiza/pull/1714/files#diff-58ccb973f92cd2e70e2f56718ab05d59 Report Format Helper]&amp;lt;br&amp;gt;&lt;br /&gt;
* [https://github.com/expertiza/expertiza/pull/1714/files#diff-8f6215af8180fd708a629b4094f01c3c Review Mapping Helper]&amp;lt;br&amp;gt;&lt;br /&gt;
* [https://github.com/expertiza/expertiza/pull/1714/files#diff-7e2a53155464089f13c8462bd81b8116 Summary Helper]&amp;lt;br&amp;gt;&lt;br /&gt;
* [https://github.com/expertiza/expertiza/pull/1714/files#diff-5354a099931d64748967998ea42d1fc1 Mailer]&amp;lt;br&amp;gt;&lt;br /&gt;
* [https://github.com/expertiza/expertiza/pull/1714/files#diff-a983bfc492e6d1982c673bc208afe459 Answer]&amp;lt;br&amp;gt;&lt;br /&gt;
* [https://github.com/expertiza/expertiza/pull/1714/files#diff-f2caf2e29f94ec94cb27bdb86ec85d40 Response]&amp;lt;br&amp;gt;&lt;br /&gt;
* [https://github.com/expertiza/expertiza/pull/1714/files#diff-a847769ab4f73b3b644c52acd4aa6430 Notify Grade Conflict Message]&amp;lt;br&amp;gt;&lt;br /&gt;
* [https://github.com/expertiza/expertiza/pull/1714/files#diff-7adec512db194a439744ab4d2d8d10ea Review Conflict Metric] &amp;lt;br&amp;gt;&lt;br /&gt;
* [https://github.com/expertiza/expertiza/pull/1714/files#diff-6d120ad6f7e1d1e4d971f7fd9f0ea434 Review Conflict Report] &amp;lt;br&amp;gt;&lt;br /&gt;
* [https://github.com/expertiza/expertiza/pull/1714/files#diff-127fb0956fcd466778195f8814733934 Searchbox] &amp;lt;br&amp;gt;&lt;br /&gt;
* [https://github.com/expertiza/expertiza/pull/1714/files#diff-b3496c4d4cf7597d2ecfc22b28d78ab6 Response Report] &amp;lt;br&amp;gt;&lt;br /&gt;
* [https://github.com/expertiza/expertiza/pull/1714/files#diff-2f71e4cd74da63b4f65224bbebe44a1c Reports Controller Spec]&amp;lt;br&amp;gt;&lt;br /&gt;
* [https://github.com/expertiza/expertiza/pull/1714/files#diff-d431293fd1daca78b5d63309fe56e031 Review Mapping Helper Spec] &amp;lt;br&amp;gt;&lt;br /&gt;
* [https://github.com/expertiza/expertiza/pull/1714/files#diff-9252f13f8d7039091ec9afd7d65ee10f Review Mapping Helper Spec] &amp;lt;br&amp;gt;&lt;br /&gt;
* [https://github.com/expertiza/expertiza/pull/1714/files#diff-a68a7982922073b9602c0fd6097e0bd2 Answer Spec] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Useful Links =&lt;br /&gt;
&lt;br /&gt;
'''Github:''' https://github.com/sid189/expertiza/tree/beta &amp;lt;br /&amp;gt;&lt;br /&gt;
'''Pull Request:''' https://github.com/expertiza/expertiza/pull/1714&lt;br /&gt;
&lt;br /&gt;
= Team Information =&lt;br /&gt;
&lt;br /&gt;
'''Project Mentor:'''&lt;br /&gt;
&amp;lt;br&amp;gt;Pratik Abhyankar&lt;br /&gt;
&lt;br /&gt;
'''Project Members:'''&amp;lt;br&amp;gt;&lt;br /&gt;
Sahil Papalkar&amp;lt;br&amp;gt;&lt;br /&gt;
Sahil Mehta&amp;lt;br&amp;gt;&lt;br /&gt;
Siddharth Deshpande&amp;lt;br&amp;gt;&lt;br /&gt;
Carl Klier&amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Shmehta</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2015._Conflict_notification&amp;diff=134061</id>
		<title>CSC/ECE 517 Spring 2020 - E2015. Conflict notification</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2015._Conflict_notification&amp;diff=134061"/>
		<updated>2020-04-25T01:16:07Z</updated>

		<summary type="html">&lt;p&gt;Shmehta: /* Files Changed */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
Expertiza is an open-source project written using the Ruby on Rails framework.  The Expertiza platform aims to improve student learning by using active and cooperative learning, allowing distance education students to participate in active learning, and by discouraging plagiarism through the use of multiple deadlines. Expertiza helps to improve teaching and resource utilization by having students contribute to the creation of course materials and through peer-graded assignments. Expertiza manages objects related to a course such as instructors, TAs, students, and other users. It also manages assignments, teams, signup topics, rubrics, peer grading, and peer evaluations.&lt;br /&gt;
&lt;br /&gt;
== Reports Background ==&lt;br /&gt;
Students can form teams in Expertiza to work on an assignment in a group. Submissions made on Expertiza can be peer-reviewed by students within the course based on a rubric. Results of the peer review can be accessed by instructors and respective student teams in the form of statistical reports. The students have access to view their feedback in the form of a Summary Report. The student Summary Report shows the scores submitted by the reviewers for each question of the rubric for that assignment. If there are more than one round, it shows the scores separated by round number. The instructors have more options to view student submitted feedback in the form of Reviewees Summary Reports which shows the average review scores for an assignment for each round with each reviewer's comments, and Review Reports which shows what teams' assignment were reviewed by each student.&lt;br /&gt;
&lt;br /&gt;
== Review Conflict Background ==&lt;br /&gt;
In the current implementation, during the peer review phase of an assignment, email notifications are sent out to the instructor whenever a submitted review score differs “significantly” from the average score of other submitted reviews for that submission. The threshold to trigger a notification is specified in the “Notification limit” on the Rubrics tab of assignment creation. The email that gets sent to instructors contains three links: a link to the conflicting review, a link to the summary page of grades for the reviewee, and a link to edit the assignment.&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
When a review is submitted that triggers a conflict, an email gets sent to instructors that contains three links: a link to the conflicting review, a link to the summary page of grades for the reviewee, and a link to edit the assignment. Although the links sent in the email are helpful for reference, the process of examining a conflicting review could be made more efficient if we provide an easy to understand report of the conflicts. The information sent in the email should be updated to contain a link to a report page which should contain more details about the newest conflict as well as information on previous review conflicts for the assignment. The conflict report page should have an easy to understand visualization showing the assignment's reviews with scores that cause a conflict.&lt;br /&gt;
&lt;br /&gt;
= Existing Implementation =&lt;br /&gt;
The existing system has the following implementation for conflict notification. On submitting a new review for a particular artifact, the submitted score is compared to the average score of the previously submitted reviews. If the difference between the average score and the newly submitted score is more than the notification threshold specified for the assignment, an email is sent out to the instructor. The email sent to the instructor contains the names of the reviewer and reviewee and a link to the conflicting review, a link to the summary of review responses, and a link to edit the assignment. The flowchart below delineates the entire process:&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
[[File:Conflictflowchart.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
== Problems with Existing Implementation ==&lt;br /&gt;
The existing implementation has the following flaws:&lt;br /&gt;
&lt;br /&gt;
=== No dedicated report for analyzing the conflict ===&lt;br /&gt;
The current implementation does not provide any dedicated view or report containing a detailed analysis of the conflicts that occur during the entire review period. The link to the conflicting review is helpful, but doesn't provide any context for for why that review was in conflict. The link to the summary of review responses provides more insight into how the assignment is being scored overall, but it doesn't provide a clear picture of which reviews are in conflict and have scores that are outliers. &lt;br /&gt;
&lt;br /&gt;
=== Incorrect email URLs ===&lt;br /&gt;
When an review is in conflict and an email gets set to the instructor, the body of the email contains links to the review, review summary page, and a link to edit the assignment. See a copy of the email message below as it is being sent by the current implementation.&lt;br /&gt;
[[File:Conflictemail.png]]&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
The current implementation uses hardcoded URLs mentioned in the &amp;lt;code&amp;gt;notify_instructor_on_difference&amp;lt;/code&amp;gt; method of the &amp;lt;code&amp;gt;models/response.rb&amp;lt;/code&amp;gt; file. See the code:&lt;br /&gt;
&lt;br /&gt;
  conflicting_response_url: 'https://expertiza.ncsu.edu/response/view?id=' + response_id.to_s,&lt;br /&gt;
  summary_url: 'https://expertiza.ncsu.edu/grades/view_team?id=' + reviewee_participant.id.to_s,&lt;br /&gt;
  assignment_edit_url: 'https://expertiza.ncsu.edu/assignments/' + assignment.id.to_s + '/edit'&lt;br /&gt;
&lt;br /&gt;
Being hardcoded, these link would not work in on other servers where Expertiza is running. For example, the links won't be valid if the setup was done on the localhost.&lt;br /&gt;
&lt;br /&gt;
= Previous Work =&lt;br /&gt;
&lt;br /&gt;
The [https://expertiza.csc.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_E1931._Conflict_notification Previous Work] resolved the email related issues and also created a simple UI report page for analyzing the conflict. However, the implementation had quite a few issues that prevented it from being merged. See a screenshot from the previous implementation of a snippet of the information from the conflict report page:&amp;lt;br /&amp;gt; [[File:OldConflictGraph.PNG|center]]&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
==Issues with Previous Work ==&lt;br /&gt;
1. The UI for the conflict report included a bar graph that showed the grades of reviews that were in conflict. The information in the bar graph was showing percentages while the scores shown beside it were in raw points. This is an inconsistency; they should display the data in the same units.&amp;lt;br /&amp;gt;&lt;br /&gt;
2. The bar graph contained too much white space and took up too much area on the screen.&amp;lt;br /&amp;gt;&lt;br /&gt;
3. It was also not obvious from the bar graph which review scores caused a conflict as they were not highlighted or distinguished in any way.&amp;lt;br /&amp;gt;&lt;br /&gt;
4. The bars in the chart were also not sorted in any meaningful way (i.e., ascending or descending) &amp;lt;br /&amp;gt;&lt;br /&gt;
5. The list of students who reviewed an submission extended vertically down the page which contributed to each row of the table taking up considerable screen space, especially for submissions with many reviews.&amp;lt;br /&amp;gt;&lt;br /&gt;
6. The metrics listed in the screenshot above don't specify the threshold for conflict. Therefore, you can't tell what review scores would actually cause a conflict.&amp;lt;br /&amp;gt;&lt;br /&gt;
7. The code for the conflict report view included a lot of logic. &amp;lt;br /&amp;gt;&lt;br /&gt;
8. There was minimal effort spent on refactoring test cases and the test cases added in the pull request were shallow tests, meaning that they simply asserted that the expected value was not empty rather than the correct way of asserting the expected value matched a specific value. &amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Design of New Implementation =&lt;br /&gt;
== Proposed Solution ==&lt;br /&gt;
As the mailing functionality was implemented perfectly in the previous implementation, we plan to use their implementation as our starting point. Building on top of it, we plan to address the highlighted issues with the previous implementation and refactor the conflict report so that it is able to provide better insights into the review conflicts.&lt;br /&gt;
Once the existing code determines that a conflict has occurred, the code will create a report view for the conflict. The report view will contain all the relevant statistics(mean, max, standard deviation, etc.) of all the reviews received for the submission. Next, a URL for the report page will be added to the email body. All URLs in the email will be relative URLs and therefore the URLs will be valid on all servers. Following files need to be updated in order to implement these changes:   &lt;br /&gt;
&lt;br /&gt;
*Related to Email:&lt;br /&gt;
**&amp;lt;code&amp;gt;app/mailers/mailer.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Modify method &amp;lt;code&amp;gt;notify_grade_conflict_message&amp;lt;/code&amp;gt; to add the link to the conflict report in the email body.&lt;br /&gt;
**&amp;lt;code&amp;gt;app/models/response.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Modify method &amp;lt;code&amp;gt;notify_instructor_on_difference&amp;lt;/code&amp;gt; to add a relative links to various pages that get included in the email body.&lt;br /&gt;
**&amp;lt;code&amp;gt;app/views/mailer/notify_grade_conflict_message.html.erb&amp;lt;/code&amp;gt; &lt;br /&gt;
*** Modify the html to add a link to the email message using which the conflict report viewed.&lt;br /&gt;
**&amp;lt;code&amp;gt;app/controllers/response_contrller.rb&amp;lt;/code&amp;gt; &lt;br /&gt;
*** Modify &amp;lt;code&amp;gt;update&amp;lt;/code&amp;gt; method to add &amp;lt;code&amp;gt;request.base_url&amp;lt;/code&amp;gt; as a param sent to &amp;lt;code&amp;gt;notify_instructor_on_difference&amp;lt;/code&amp;gt; method&lt;br /&gt;
*** Modify &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method to add &amp;lt;code&amp;gt;request.base_url&amp;lt;/code&amp;gt; as a param sent to &amp;lt;code&amp;gt;notify_instructor_on_difference&amp;lt;/code&amp;gt; method&lt;br /&gt;
	&lt;br /&gt;
*Related to the conflict report view:&lt;br /&gt;
**&amp;lt;code&amp;gt;app/views/reports/_searchbox.html.erb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Modify the html to add the option to view a conflict report.&lt;br /&gt;
**&amp;lt;code&amp;gt;app/views/reports/response_report.html.haml&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Modify the html to render the conflict report partial if the option to view a conflict report was selected.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
What we need to create:&lt;br /&gt;
*Related to the conflict report view:&lt;br /&gt;
**&amp;lt;code&amp;gt;App/views/reports/_conflict_report.html.erb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Need to create this entire file to make the view for a conflict report&lt;br /&gt;
**&amp;lt;code&amp;gt;app/helpers/report_formatter_helper.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Need to add a method &amp;lt;code&amp;gt;conflict_reponse_map&amp;lt;/code&amp;gt; to make specific instance variables available to our conflict report view. This method will get called from the ReportsController. &lt;br /&gt;
**&amp;lt;code&amp;gt;app/helpers/summary_helper.rb&amp;lt;/code&amp;gt; &lt;br /&gt;
*** Need to add a method to get the maximum possible score of an assignment in each round&lt;br /&gt;
**&amp;lt;code&amp;gt;app/models/answer.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Need to add a method to get the answers from a review for an assignment submitted by a specific reviewer.&lt;br /&gt;
**&amp;lt;code&amp;gt;app/helpers/review_mapping_helper.rb&amp;lt;/code&amp;gt; &lt;br /&gt;
*** Need to add methods to get the review scores for a team in each round, calculate the average review score for a round, calculate the std. deviation of review scores for each round, and get the team members of each team. In addition, the code to create the formatted bar chart will also be placed in a helper method in this file. Apart from these, any other method to find and calculate data to be viewed in the report can be added to this helper file.	&lt;br /&gt;
	&lt;br /&gt;
&lt;br /&gt;
The conflict report view should:&lt;br /&gt;
*For each team that had a submission with a review that was in a conflict:&lt;br /&gt;
**List the team name and team members&lt;br /&gt;
**Provide a graphical view of the statistics displayed in the report&lt;br /&gt;
**For each round of reviews:&lt;br /&gt;
***List the students who reviewed the submission and the score they gave.&lt;br /&gt;
***Plot the review scores on a horizontal bar chart, highlighting those that caused a conflict.&lt;br /&gt;
***List the threshold for conflict review score, max review score, average review score, and standard deviation. &amp;lt;br \&amp;gt;&amp;lt;br \&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order to resolve the issues with the previous team's pull request, we will:&amp;lt;br \&amp;gt;&lt;br /&gt;
1. Modify the bar chart code to show the point values as raw scores instead of percentages.&amp;lt;br \&amp;gt;&lt;br /&gt;
2. Modify the bar chart code to eliminate unnecessary white space.&amp;lt;br \&amp;gt;&lt;br /&gt;
3. Modify the bar chart code to highlight bars representing scores that cause conflict. &amp;lt;br \&amp;gt;&lt;br /&gt;
4. Modify the bar chart code so that the bars are sorted by ascending score. &amp;lt;br \&amp;gt;&lt;br /&gt;
5. List the students who reviewed the submission in multiple columns rather than a single long column. &amp;lt;br \&amp;gt;&lt;br /&gt;
6. Add additional metrics specifying threshold for conflict to the conflict report so you can see what scores would cause a conflict. &amp;lt;br \&amp;gt;&lt;br /&gt;
7. Put the necessary logic into helper methods in helper files to ensure logic stays out of our views.&amp;lt;br \&amp;gt;&lt;br /&gt;
8. Refactor the necessary affected test cases and write new RSpec tests in accordance with our proposed test plan to ensure adequate coverage.&amp;lt;br \&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== UML Diagrams ==&lt;br /&gt;
=== Use Case Diagram ===&lt;br /&gt;
The usecase diagram highlights the simple workflow of the proposed system when trigger by the user.&amp;lt;br /&amp;gt;&lt;br /&gt;
[[File:usecase-1.png]]&lt;br /&gt;
&amp;lt;br /&amp;gt; &amp;lt;br /&amp;gt;&lt;br /&gt;
Actors participating:&lt;br /&gt;
&lt;br /&gt;
* Student: In this use case, fills out the reviews for different projects submitted by the peers.&lt;br /&gt;
* TA/Instructor: In this use case, goes over the conflicting review submitted by the students for the same project.&lt;br /&gt;
&lt;br /&gt;
=== Sequence Diagram ===&lt;br /&gt;
The sequence diagram models the interactions that will take place between various components of the system for the above use-case. &lt;br /&gt;
&amp;lt;br /&amp;gt; &amp;lt;br /&amp;gt;&lt;br /&gt;
[[File:conflictSeq.jpg]]&lt;br /&gt;
&lt;br /&gt;
= New Implementation =&lt;br /&gt;
== Addressing Problems with Conflict Emails and Mailer ==&lt;br /&gt;
== Addressing Problems with Conflict Report and Previous Implementation ==&lt;br /&gt;
&lt;br /&gt;
= Testing =&lt;br /&gt;
Both manual testing and RSpec testing were used to test the new functionalities. &lt;br /&gt;
=== RSpec Testing ===&lt;br /&gt;
In order to test the changes implemented in the model, controller and helper file new RSpec tests have been added. &lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
'''1. Add a new test to &amp;lt;code&amp;gt;spec/controllers/reports_controller_spec.rb&amp;lt;/code&amp;gt;''' &amp;lt;br /&amp;gt;&lt;br /&gt;
The test checks if the new review conflict report is routed and rendered properly by the response controller.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: green&amp;quot;&amp;gt;&lt;br /&gt;
    describe '#review_conflict_response_map' do&lt;br /&gt;
      context 'when type is ReviewConflictResponseMap' do&lt;br /&gt;
        it 'renders response_report page with corresponding data' do&lt;br /&gt;
          allow(TeammateReviewResponseMap).to receive(:teammate_response_report)&lt;br /&gt;
            .with('1')&lt;br /&gt;
            .and_return([participant, participant2])&lt;br /&gt;
          params = {&lt;br /&gt;
              id: 1,&lt;br /&gt;
              report: {type: 'ReviewConflictResponseMap'},&lt;br /&gt;
              user: 'no one'&lt;br /&gt;
          }&lt;br /&gt;
          get :response_report, params&lt;br /&gt;
          expect(response).to render_template(:response_report)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. Add a new test to &amp;lt;code&amp;gt;spec/models/answer_spec.rb&amp;lt;/code&amp;gt;''' &amp;lt;br /&amp;gt;&lt;br /&gt;
This tests if the query in the newly added method 'answers_by_round_for_reviewee' works properly and fetches a valid result.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: green&amp;quot;&amp;gt;&lt;br /&gt;
    it &amp;quot;returns answers by reviewer for reviewee in round from db which is not empty&amp;quot; do&lt;br /&gt;
      expect(Answer.answers_by_round_for_reviewee(@assignment_id, @reviewee_id,@round)).not_to be_empty&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''3. Create and add a new tests to &amp;lt;code&amp;gt;spec/helpers/review_mapping_helper_spec.rb&amp;lt;/code&amp;gt;''' &amp;lt;br /&amp;gt;&lt;br /&gt;
This file tests various calculations performed by the newly added helper methods. The results of these calculations are not only used to display on the report but also used to generate the graph. &lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: green&amp;quot;&amp;gt;&lt;br /&gt;
describe &amp;quot;ReviewMappingHelper&amp;quot; do&lt;br /&gt;
  describe &amp;quot;#review_score_helper_for_team&amp;quot; do&lt;br /&gt;
    before(:each) do&lt;br /&gt;
      @review_answers = [{'reviewer_id': '2', 'answer': 54}, {'reviewer_id': '1', 'answer': 24}, {'reviewer_id': '2', 'answer': 25}]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;The review_score_helper_for_team method calculates the total review scores for each review&amp;quot; do&lt;br /&gt;
      question_answers = helper.review_score_helper_for_team(@review_answers)&lt;br /&gt;
      expect(question_answers).to include('1' =&amp;gt; 24,'2' =&amp;gt; 79)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe &amp;quot;#get_score_metrics&amp;quot; do&lt;br /&gt;
    before(:each) do&lt;br /&gt;
      @review_scores = {'1' =&amp;gt; 50, '2' =&amp;gt; 40, '3' =&amp;gt; 60}&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;The get_score_metrics method calculates various metrics used in the conflict report&amp;quot; do&lt;br /&gt;
      metric = helper.get_score_metrics(@review_scores, 50)&lt;br /&gt;
      expect(metric[:average]).to eq 50.0&lt;br /&gt;
      expect(metric[:std]).to eq 8.16&lt;br /&gt;
      expect(metric[:upper_tolerance_limit]).to eq 50&lt;br /&gt;
      expect(metric[:lower_tolerance_limit]).to eq 33.68&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''4. Add new test in &amp;lt;code&amp;gt;spec/features/review_mapping_helper_spec.rb&amp;lt;/code&amp;gt;''' &amp;lt;br /&amp;gt;&lt;br /&gt;
This UI test navigates to the conflict report page and tests if the report is rendered properly.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: green&amp;quot;&amp;gt;&lt;br /&gt;
describe &amp;quot;Test Review conflict report&amp;quot; do&lt;br /&gt;
  before(:each) do&lt;br /&gt;
    create(:instructor)&lt;br /&gt;
    create(:assignment, course: nil, name: 'Test Assignment')&lt;br /&gt;
    assignment_id = Assignment.where(name: 'Test Assignment')[0].id&lt;br /&gt;
    login_as 'instructor6'&lt;br /&gt;
    visit &amp;quot;/reports/response_report?id=#{assignment_id}&amp;quot;&lt;br /&gt;
    page.select(&amp;quot;Review conflict report&amp;quot;, :from =&amp;gt; &amp;quot;report[type]&amp;quot;)&lt;br /&gt;
    click_button &amp;quot;View&amp;quot;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  # Check if the page renders&lt;br /&gt;
&lt;br /&gt;
  it &amp;quot;has a conflicting review table&amp;quot; do&lt;br /&gt;
    expect(page).to have_css('table')&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it &amp;quot;can display teams&amp;quot; do&lt;br /&gt;
    expect(page).to have_content('Team')&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it &amp;quot;can display author reviewers and metrics&amp;quot; do&lt;br /&gt;
    expect(page).to have_selector(:link_or_button, 'Convert Points to Percents')&lt;br /&gt;
  end&lt;br /&gt;
end &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
All RSpec tests are passing for the current implementation as is evident by the passing Travis CI build.&lt;br /&gt;
&lt;br /&gt;
== Manual Testing ==&lt;br /&gt;
In order to test the functionality manually, we follow the following steps: &amp;lt;br \&amp;gt;&lt;br /&gt;
1. Create a new assignment with 15% as a conflict threshold limit. &amp;lt;br /&amp;gt;&lt;br /&gt;
2. Add 4 students to the assignment and divide them into 2 teams of 2 students in each. &amp;lt;br /&amp;gt;&lt;br /&gt;
3. Add submission for each team. &amp;lt;br /&amp;gt;&lt;br /&gt;
4. In the review phase, login to the first team student accounts and give scores of 100% and 50% to the second team's assignment. &amp;lt;br /&amp;gt;&lt;br /&gt;
5. Since the scores differ by more than 15% the email will be sent to the instructor. &amp;lt;br /&amp;gt;&lt;br /&gt;
6. Access the email and check if the email contains the following details: &amp;lt;br /&amp;gt;&lt;br /&gt;
* Names of the reviewer and reviewee&lt;br /&gt;
* Link to the conflicting review&lt;br /&gt;
* Link to the newly created report view corresponding to the conflict&lt;br /&gt;
* Link to edit the assignment notification limit&lt;br /&gt;
7. View the conflict report and ensure that Team 2 shows up as having a conflicting review submitted by student 2 of Team 1.&lt;br /&gt;
&lt;br /&gt;
= Files Changed =&lt;br /&gt;
1. &amp;lt;code&amp;gt;app/assets/javascripts/conflict_report.js&amp;lt;/code&amp;gt;[https://github.com/expertiza/expertiza/pull/1714/files#diff-0df434e3b51a1cb1604423db5db1ff66] &amp;lt;br&amp;gt;&lt;br /&gt;
2. &amp;lt;code&amp;gt;app/controllers/response_controller.rb&amp;lt;/code&amp;gt;[https://github.com/expertiza/expertiza/pull/1714/files#diff-7786ab741930f6bace28b7e5da61b8d6] &amp;lt;br&amp;gt;&lt;br /&gt;
3. &amp;lt;code&amp;gt;app/helpers/report_formatter_helper.rb&amp;lt;/code&amp;gt;[https://github.com/expertiza/expertiza/pull/1714/files#diff-58ccb973f92cd2e70e2f56718ab05d59]&amp;lt;br&amp;gt;&lt;br /&gt;
4. &amp;lt;code&amp;gt;app/helpers/review_mapping_helper.rb&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/pull/1714/files#diff-8f6215af8180fd708a629b4094f01c3c]&amp;lt;br&amp;gt;&lt;br /&gt;
5. &amp;lt;code&amp;gt;app/helpers/summary_helper.rb&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/pull/1714/files#diff-7e2a53155464089f13c8462bd81b8116]&amp;lt;br&amp;gt;&lt;br /&gt;
6. &amp;lt;code&amp;gt;app/mailers/mailer.rb&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/pull/1714/files#diff-5354a099931d64748967998ea42d1fc1]&amp;lt;br&amp;gt;&lt;br /&gt;
7. &amp;lt;code&amp;gt;app/models/answer.rb&amp;lt;/code&amp;gt;[https://github.com/expertiza/expertiza/pull/1714/files#diff-a983bfc492e6d1982c673bc208afe459]&amp;lt;br&amp;gt;&lt;br /&gt;
8. &amp;lt;code&amp;gt;app/models/response.rb&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/pull/1714/files#diff-f2caf2e29f94ec94cb27bdb86ec85d40]&amp;lt;br&amp;gt;&lt;br /&gt;
9. &amp;lt;code&amp;gt;app/views/mailer/notify_grade_conflict_message.html.erb&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/pull/1714/files#diff-a847769ab4f73b3b644c52acd4aa6430]&amp;lt;br&amp;gt;&lt;br /&gt;
10. &amp;lt;code&amp;gt;app/views/reports/_review_conflict_metric.html.erb&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/pull/1714/files#diff-7adec512db194a439744ab4d2d8d10ea] &amp;lt;br&amp;gt;&lt;br /&gt;
11. &amp;lt;code&amp;gt;app/views/reports/_review_conflict_report.html.erb&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/pull/1714/files#diff-6d120ad6f7e1d1e4d971f7fd9f0ea434] &amp;lt;br&amp;gt;&lt;br /&gt;
12. &amp;lt;code&amp;gt;app/views/reports/_searchbox.html.erb&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/pull/1714/files#diff-127fb0956fcd466778195f8814733934] &amp;lt;br&amp;gt;&lt;br /&gt;
13. &amp;lt;code&amp;gt;app/views/reports/response_report.html.haml&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/pull/1714/files#diff-b3496c4d4cf7597d2ecfc22b28d78ab6] &amp;lt;br&amp;gt;&lt;br /&gt;
14. &amp;lt;code&amp;gt;spec/controllers/reports_controller_spec.rb&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/pull/1714/files#diff-2f71e4cd74da63b4f65224bbebe44a1c]&amp;lt;br&amp;gt;&lt;br /&gt;
15. &amp;lt;code&amp;gt;spec/features/review_mapping_helper_spec.rb&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/pull/1714/files#diff-d431293fd1daca78b5d63309fe56e031] &amp;lt;br&amp;gt;&lt;br /&gt;
16. &amp;lt;code&amp;gt;spec/helpers/review_mapping_helper_spec.rb&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/pull/1714/files#diff-9252f13f8d7039091ec9afd7d65ee10f] &amp;lt;br&amp;gt;&lt;br /&gt;
17. &amp;lt;code&amp;gt;spec/models/answer_spec.rb &amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/pull/1714/files#diff-a68a7982922073b9602c0fd6097e0bd2] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Useful Links =&lt;br /&gt;
&lt;br /&gt;
'''Github:''' https://github.com/sid189/expertiza/tree/beta &amp;lt;br /&amp;gt;&lt;br /&gt;
'''Pull Request:''' https://github.com/expertiza/expertiza/pull/1714&lt;br /&gt;
&lt;br /&gt;
= Team Information =&lt;br /&gt;
&lt;br /&gt;
'''Project Mentor:'''&lt;br /&gt;
&amp;lt;br&amp;gt;Pratik Abhyankar&lt;br /&gt;
&lt;br /&gt;
'''Project Members:'''&amp;lt;br&amp;gt;&lt;br /&gt;
Sahil Papalkar&amp;lt;br&amp;gt;&lt;br /&gt;
Sahil Mehta&amp;lt;br&amp;gt;&lt;br /&gt;
Siddharth Deshpande&amp;lt;br&amp;gt;&lt;br /&gt;
Carl Klier&amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Shmehta</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2015._Conflict_notification&amp;diff=134055</id>
		<title>CSC/ECE 517 Spring 2020 - E2015. Conflict notification</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2015._Conflict_notification&amp;diff=134055"/>
		<updated>2020-04-25T01:10:13Z</updated>

		<summary type="html">&lt;p&gt;Shmehta: /* Files Changed */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
Expertiza is an open-source project written using the Ruby on Rails framework.  The Expertiza platform aims to improve student learning by using active and cooperative learning, allowing distance education students to participate in active learning, and by discouraging plagiarism through the use of multiple deadlines. Expertiza helps to improve teaching and resource utilization by having students contribute to the creation of course materials and through peer-graded assignments. Expertiza manages objects related to a course such as instructors, TAs, students, and other users. It also manages assignments, teams, signup topics, rubrics, peer grading, and peer evaluations.&lt;br /&gt;
&lt;br /&gt;
== Reports Background ==&lt;br /&gt;
Students can form teams in Expertiza to work on an assignment in a group. Submissions made on Expertiza can be peer-reviewed by students within the course based on a rubric. Results of the peer review can be accessed by instructors and respective student teams in the form of statistical reports. The students have access to view their feedback in the form of a Summary Report. The student Summary Report shows the scores submitted by the reviewers for each question of the rubric for that assignment. If there are more than one round, it shows the scores separated by round number. The instructors have more options to view student submitted feedback in the form of Reviewees Summary Reports which shows the average review scores for an assignment for each round with each reviewer's comments, and Review Reports which shows what teams' assignment were reviewed by each student.&lt;br /&gt;
&lt;br /&gt;
== Review Conflict Background ==&lt;br /&gt;
In the current implementation, during the peer review phase of an assignment, email notifications are sent out to the instructor whenever a submitted review score differs “significantly” from the average score of other submitted reviews for that submission. The threshold to trigger a notification is specified in the “Notification limit” on the Rubrics tab of assignment creation. The email that gets sent to instructors contains three links: a link to the conflicting review, a link to the summary page of grades for the reviewee, and a link to edit the assignment.&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
When a review is submitted that triggers a conflict, an email gets sent to instructors that contains three links: a link to the conflicting review, a link to the summary page of grades for the reviewee, and a link to edit the assignment. Although the links sent in the email are helpful for reference, the process of examining a conflicting review could be made more efficient if we provide an easy to understand report of the conflicts. The information sent in the email should be updated to contain a link to a report page which should contain more details about the newest conflict as well as information on previous review conflicts for the assignment. The conflict report page should have an easy to understand visualization showing the assignment's reviews with scores that cause a conflict.&lt;br /&gt;
&lt;br /&gt;
= Existing Implementation =&lt;br /&gt;
The existing system has the following implementation for conflict notification. On submitting a new review for a particular artifact, the submitted score is compared to the average score of the previously submitted reviews. If the difference between the average score and the newly submitted score is more than the notification threshold specified for the assignment, an email is sent out to the instructor. The email sent to the instructor contains the names of the reviewer and reviewee and a link to the conflicting review, a link to the summary of review responses, and a link to edit the assignment. The flowchart below delineates the entire process:&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
[[File:Conflictflowchart.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
== Problems with Existing Implementation ==&lt;br /&gt;
The existing implementation has the following flaws:&lt;br /&gt;
&lt;br /&gt;
=== No dedicated report for analyzing the conflict ===&lt;br /&gt;
The current implementation does not provide any dedicated view or report containing a detailed analysis of the conflicts that occur during the entire review period. The link to the conflicting review is helpful, but doesn't provide any context for for why that review was in conflict. The link to the summary of review responses provides more insight into how the assignment is being scored overall, but it doesn't provide a clear picture of which reviews are in conflict and have scores that are outliers. &lt;br /&gt;
&lt;br /&gt;
=== Incorrect email URLs ===&lt;br /&gt;
When an review is in conflict and an email gets set to the instructor, the body of the email contains links to the review, review summary page, and a link to edit the assignment. See a copy of the email message below as it is being sent by the current implementation.&lt;br /&gt;
[[File:Conflictemail.png]]&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
The current implementation uses hardcoded URLs mentioned in the &amp;lt;code&amp;gt;notify_instructor_on_difference&amp;lt;/code&amp;gt; method of the &amp;lt;code&amp;gt;models/response.rb&amp;lt;/code&amp;gt; file. See the code:&lt;br /&gt;
&lt;br /&gt;
  conflicting_response_url: 'https://expertiza.ncsu.edu/response/view?id=' + response_id.to_s,&lt;br /&gt;
  summary_url: 'https://expertiza.ncsu.edu/grades/view_team?id=' + reviewee_participant.id.to_s,&lt;br /&gt;
  assignment_edit_url: 'https://expertiza.ncsu.edu/assignments/' + assignment.id.to_s + '/edit'&lt;br /&gt;
&lt;br /&gt;
Being hardcoded, these link would not work in on other servers where Expertiza is running. For example, the links won't be valid if the setup was done on the localhost.&lt;br /&gt;
&lt;br /&gt;
= Previous Work =&lt;br /&gt;
&lt;br /&gt;
The [https://expertiza.csc.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_E1931._Conflict_notification Previous Work] resolved the email related issues and also created a simple UI report page for analyzing the conflict. However, the implementation had quite a few issues that prevented it from being merged. See a screenshot from the previous implementation of a snippet of the information from the conflict report page:&amp;lt;br /&amp;gt; [[File:OldConflictGraph.PNG|center]]&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
==Issues with Previous Work ==&lt;br /&gt;
1. The UI for the conflict report included a bar graph that showed the grades of reviews that were in conflict. The information in the bar graph was showing percentages while the scores shown beside it were in raw points. This is an inconsistency; they should display the data in the same units.&amp;lt;br /&amp;gt;&lt;br /&gt;
2. The bar graph contained too much white space and took up too much area on the screen.&amp;lt;br /&amp;gt;&lt;br /&gt;
3. It was also not obvious from the bar graph which review scores caused a conflict as they were not highlighted or distinguished in any way.&amp;lt;br /&amp;gt;&lt;br /&gt;
4. The bars in the chart were also not sorted in any meaningful way (i.e., ascending or descending) &amp;lt;br /&amp;gt;&lt;br /&gt;
5. The list of students who reviewed an submission extended vertically down the page which contributed to each row of the table taking up considerable screen space, especially for submissions with many reviews.&amp;lt;br /&amp;gt;&lt;br /&gt;
6. The metrics listed in the screenshot above don't specify the threshold for conflict. Therefore, you can't tell what review scores would actually cause a conflict.&amp;lt;br /&amp;gt;&lt;br /&gt;
7. The code for the conflict report view included a lot of logic. &amp;lt;br /&amp;gt;&lt;br /&gt;
8. There was minimal effort spent on refactoring test cases and the test cases added in the pull request were shallow tests, meaning that they simply asserted that the expected value was not empty rather than the correct way of asserting the expected value matched a specific value. &amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Design of New Implementation =&lt;br /&gt;
== Proposed Solution ==&lt;br /&gt;
As the mailing functionality was implemented perfectly in the previous implementation, we plan to use their implementation as our starting point. Building on top of it, we plan to address the highlighted issues with the previous implementation and refactor the conflict report so that it is able to provide better insights into the review conflicts.&lt;br /&gt;
Once the existing code determines that a conflict has occurred, the code will create a report view for the conflict. The report view will contain all the relevant statistics(mean, max, standard deviation, etc.) of all the reviews received for the submission. Next, a URL for the report page will be added to the email body. All URLs in the email will be relative URLs and therefore the URLs will be valid on all servers. Following files need to be updated in order to implement these changes:   &lt;br /&gt;
&lt;br /&gt;
*Related to Email:&lt;br /&gt;
**&amp;lt;code&amp;gt;app/mailers/mailer.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Modify method &amp;lt;code&amp;gt;notify_grade_conflict_message&amp;lt;/code&amp;gt; to add the link to the conflict report in the email body.&lt;br /&gt;
**&amp;lt;code&amp;gt;app/models/response.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Modify method &amp;lt;code&amp;gt;notify_instructor_on_difference&amp;lt;/code&amp;gt; to add a relative links to various pages that get included in the email body.&lt;br /&gt;
**&amp;lt;code&amp;gt;app/views/mailer/notify_grade_conflict_message.html.erb&amp;lt;/code&amp;gt; &lt;br /&gt;
*** Modify the html to add a link to the email message using which the conflict report viewed.&lt;br /&gt;
**&amp;lt;code&amp;gt;app/controllers/response_contrller.rb&amp;lt;/code&amp;gt; &lt;br /&gt;
*** Modify &amp;lt;code&amp;gt;update&amp;lt;/code&amp;gt; method to add &amp;lt;code&amp;gt;request.base_url&amp;lt;/code&amp;gt; as a param sent to &amp;lt;code&amp;gt;notify_instructor_on_difference&amp;lt;/code&amp;gt; method&lt;br /&gt;
*** Modify &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method to add &amp;lt;code&amp;gt;request.base_url&amp;lt;/code&amp;gt; as a param sent to &amp;lt;code&amp;gt;notify_instructor_on_difference&amp;lt;/code&amp;gt; method&lt;br /&gt;
	&lt;br /&gt;
*Related to the conflict report view:&lt;br /&gt;
**&amp;lt;code&amp;gt;app/views/reports/_searchbox.html.erb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Modify the html to add the option to view a conflict report.&lt;br /&gt;
**&amp;lt;code&amp;gt;app/views/reports/response_report.html.haml&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Modify the html to render the conflict report partial if the option to view a conflict report was selected.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
What we need to create:&lt;br /&gt;
*Related to the conflict report view:&lt;br /&gt;
**&amp;lt;code&amp;gt;App/views/reports/_conflict_report.html.erb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Need to create this entire file to make the view for a conflict report&lt;br /&gt;
**&amp;lt;code&amp;gt;app/helpers/report_formatter_helper.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Need to add a method &amp;lt;code&amp;gt;conflict_reponse_map&amp;lt;/code&amp;gt; to make specific instance variables available to our conflict report view. This method will get called from the ReportsController. &lt;br /&gt;
**&amp;lt;code&amp;gt;app/helpers/summary_helper.rb&amp;lt;/code&amp;gt; &lt;br /&gt;
*** Need to add a method to get the maximum possible score of an assignment in each round&lt;br /&gt;
**&amp;lt;code&amp;gt;app/models/answer.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Need to add a method to get the answers from a review for an assignment submitted by a specific reviewer.&lt;br /&gt;
**&amp;lt;code&amp;gt;app/helpers/review_mapping_helper.rb&amp;lt;/code&amp;gt; &lt;br /&gt;
*** Need to add methods to get the review scores for a team in each round, calculate the average review score for a round, calculate the std. deviation of review scores for each round, and get the team members of each team. In addition, the code to create the formatted bar chart will also be placed in a helper method in this file. Apart from these, any other method to find and calculate data to be viewed in the report can be added to this helper file.	&lt;br /&gt;
	&lt;br /&gt;
&lt;br /&gt;
The conflict report view should:&lt;br /&gt;
*For each team that had a submission with a review that was in a conflict:&lt;br /&gt;
**List the team name and team members&lt;br /&gt;
**Provide a graphical view of the statistics displayed in the report&lt;br /&gt;
**For each round of reviews:&lt;br /&gt;
***List the students who reviewed the submission and the score they gave.&lt;br /&gt;
***Plot the review scores on a horizontal bar chart, highlighting those that caused a conflict.&lt;br /&gt;
***List the threshold for conflict review score, max review score, average review score, and standard deviation. &amp;lt;br \&amp;gt;&amp;lt;br \&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order to resolve the issues with the previous team's pull request, we will:&amp;lt;br \&amp;gt;&lt;br /&gt;
1. Modify the bar chart code to show the point values as raw scores instead of percentages.&amp;lt;br \&amp;gt;&lt;br /&gt;
2. Modify the bar chart code to eliminate unnecessary white space.&amp;lt;br \&amp;gt;&lt;br /&gt;
3. Modify the bar chart code to highlight bars representing scores that cause conflict. &amp;lt;br \&amp;gt;&lt;br /&gt;
4. Modify the bar chart code so that the bars are sorted by ascending score. &amp;lt;br \&amp;gt;&lt;br /&gt;
5. List the students who reviewed the submission in multiple columns rather than a single long column. &amp;lt;br \&amp;gt;&lt;br /&gt;
6. Add additional metrics specifying threshold for conflict to the conflict report so you can see what scores would cause a conflict. &amp;lt;br \&amp;gt;&lt;br /&gt;
7. Put the necessary logic into helper methods in helper files to ensure logic stays out of our views.&amp;lt;br \&amp;gt;&lt;br /&gt;
8. Refactor the necessary affected test cases and write new RSpec tests in accordance with our proposed test plan to ensure adequate coverage.&amp;lt;br \&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== UML Diagrams ==&lt;br /&gt;
=== Use Case Diagram ===&lt;br /&gt;
The usecase diagram highlights the simple workflow of the proposed system when trigger by the user.&amp;lt;br /&amp;gt;&lt;br /&gt;
[[File:usecase-1.png]]&lt;br /&gt;
&amp;lt;br /&amp;gt; &amp;lt;br /&amp;gt;&lt;br /&gt;
Actors participating:&lt;br /&gt;
&lt;br /&gt;
* Student: In this use case, fills out the reviews for different projects submitted by the peers.&lt;br /&gt;
* TA/Instructor: In this use case, goes over the conflicting review submitted by the students for the same project.&lt;br /&gt;
&lt;br /&gt;
=== Sequence Diagram ===&lt;br /&gt;
The sequence diagram models the interactions that will take place between various components of the system for the above use-case. &lt;br /&gt;
&amp;lt;br /&amp;gt; &amp;lt;br /&amp;gt;&lt;br /&gt;
[[File:conflictSeq.jpg]]&lt;br /&gt;
&lt;br /&gt;
= New Implementation =&lt;br /&gt;
As stated in our Proposed Design, we made the following changes to address the Problem Statement:&amp;lt;br /&amp;gt;&lt;br /&gt;
As stated in our Proposed Design, we made the following changes to address the Issues with the Previous Implementation.&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Testing =&lt;br /&gt;
Both manual testing and RSpec testing were used to test the new functionalities. &lt;br /&gt;
=== RSpec Testing ===&lt;br /&gt;
In order to test the changes implemented in the model, controller and helper file new RSpec tests have been added. &lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
'''1. Add a new test to &amp;lt;code&amp;gt;spec/controllers/reports_controller_spec.rb&amp;lt;/code&amp;gt;''' &amp;lt;br /&amp;gt;&lt;br /&gt;
The test checks if the new review conflict report is routed and rendered properly by the response controller.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: green&amp;quot;&amp;gt;&lt;br /&gt;
    describe '#review_conflict_response_map' do&lt;br /&gt;
      context 'when type is ReviewConflictResponseMap' do&lt;br /&gt;
        it 'renders response_report page with corresponding data' do&lt;br /&gt;
          allow(TeammateReviewResponseMap).to receive(:teammate_response_report)&lt;br /&gt;
            .with('1')&lt;br /&gt;
            .and_return([participant, participant2])&lt;br /&gt;
          params = {&lt;br /&gt;
              id: 1,&lt;br /&gt;
              report: {type: 'ReviewConflictResponseMap'},&lt;br /&gt;
              user: 'no one'&lt;br /&gt;
          }&lt;br /&gt;
          get :response_report, params&lt;br /&gt;
          expect(response).to render_template(:response_report)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. Add a new test to &amp;lt;code&amp;gt;spec/models/answer_spec.rb&amp;lt;/code&amp;gt;''' &amp;lt;br /&amp;gt;&lt;br /&gt;
This tests if the query in the newly added method 'answers_by_round_for_reviewee' works properly and fetches a valid result.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: green&amp;quot;&amp;gt;&lt;br /&gt;
    it &amp;quot;returns answers by reviewer for reviewee in round from db which is not empty&amp;quot; do&lt;br /&gt;
      expect(Answer.answers_by_round_for_reviewee(@assignment_id, @reviewee_id,@round)).not_to be_empty&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''3. Create and add a new tests to &amp;lt;code&amp;gt;spec/helpers/review_mapping_helper_spec.rb&amp;lt;/code&amp;gt;''' &amp;lt;br /&amp;gt;&lt;br /&gt;
This file tests various calculations performed by the newly added helper methods. The results of these calculations are not only used to display on the report but also used to generate the graph. &lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: green&amp;quot;&amp;gt;&lt;br /&gt;
describe &amp;quot;ReviewMappingHelper&amp;quot; do&lt;br /&gt;
  describe &amp;quot;#review_score_helper_for_team&amp;quot; do&lt;br /&gt;
    before(:each) do&lt;br /&gt;
      @review_answers = [{'reviewer_id': '2', 'answer': 54}, {'reviewer_id': '1', 'answer': 24}, {'reviewer_id': '2', 'answer': 25}]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;The review_score_helper_for_team method calculates the total review scores for each review&amp;quot; do&lt;br /&gt;
      question_answers = helper.review_score_helper_for_team(@review_answers)&lt;br /&gt;
      expect(question_answers).to include('1' =&amp;gt; 24,'2' =&amp;gt; 79)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe &amp;quot;#get_score_metrics&amp;quot; do&lt;br /&gt;
    before(:each) do&lt;br /&gt;
      @review_scores = {'1' =&amp;gt; 50, '2' =&amp;gt; 40, '3' =&amp;gt; 60}&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;The get_score_metrics method calculates various metrics used in the conflict report&amp;quot; do&lt;br /&gt;
      metric = helper.get_score_metrics(@review_scores, 50)&lt;br /&gt;
      expect(metric[:average]).to eq 50.0&lt;br /&gt;
      expect(metric[:std]).to eq 8.16&lt;br /&gt;
      expect(metric[:upper_tolerance_limit]).to eq 50&lt;br /&gt;
      expect(metric[:lower_tolerance_limit]).to eq 33.68&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''4. Add new test in &amp;lt;code&amp;gt;spec/features/review_mapping_helper_spec.rb&amp;lt;/code&amp;gt;''' &amp;lt;br /&amp;gt;&lt;br /&gt;
This UI test navigates to the conflict report page and tests if the report is rendered properly.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: green&amp;quot;&amp;gt;&lt;br /&gt;
describe &amp;quot;Test Review conflict report&amp;quot; do&lt;br /&gt;
  before(:each) do&lt;br /&gt;
    create(:instructor)&lt;br /&gt;
    create(:assignment, course: nil, name: 'Test Assignment')&lt;br /&gt;
    assignment_id = Assignment.where(name: 'Test Assignment')[0].id&lt;br /&gt;
    login_as 'instructor6'&lt;br /&gt;
    visit &amp;quot;/reports/response_report?id=#{assignment_id}&amp;quot;&lt;br /&gt;
    page.select(&amp;quot;Review conflict report&amp;quot;, :from =&amp;gt; &amp;quot;report[type]&amp;quot;)&lt;br /&gt;
    click_button &amp;quot;View&amp;quot;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  # Check if the page renders&lt;br /&gt;
&lt;br /&gt;
  it &amp;quot;has a conflicting review table&amp;quot; do&lt;br /&gt;
    expect(page).to have_css('table')&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it &amp;quot;can display teams&amp;quot; do&lt;br /&gt;
    expect(page).to have_content('Team')&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it &amp;quot;can display author reviewers and metrics&amp;quot; do&lt;br /&gt;
    expect(page).to have_selector(:link_or_button, 'Convert Points to Percents')&lt;br /&gt;
  end&lt;br /&gt;
end &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
All RSpec tests are passing for the current implementation as is evident by the passing Travis CI build.&lt;br /&gt;
&lt;br /&gt;
== Manual Testing ==&lt;br /&gt;
In order to test the functionality manually, we follow the following steps: &amp;lt;br \&amp;gt;&lt;br /&gt;
1. Create a new assignment with 15% as a conflict threshold limit. &amp;lt;br /&amp;gt;&lt;br /&gt;
2. Add 4 students to the assignment and divide them into 2 teams of 2 students in each. &amp;lt;br /&amp;gt;&lt;br /&gt;
3. Add submission for each team. &amp;lt;br /&amp;gt;&lt;br /&gt;
4. In the review phase, login to the first team student accounts and give scores of 100% and 50% to the second team's assignment. &amp;lt;br /&amp;gt;&lt;br /&gt;
5. Since the scores differ by more than 15% the email will be sent to the instructor. &amp;lt;br /&amp;gt;&lt;br /&gt;
6. Access the email and check if the email contains the following details: &amp;lt;br /&amp;gt;&lt;br /&gt;
* Names of the reviewer and reviewee&lt;br /&gt;
* Link to the conflicting review&lt;br /&gt;
* Link to the newly created report view corresponding to the conflict&lt;br /&gt;
* Link to edit the assignment notification limit&lt;br /&gt;
7. View the conflict report and ensure that Team 2 shows up as having a conflicting review submitted by student 2 of Team 1.&lt;br /&gt;
&lt;br /&gt;
= Files Changed =&lt;br /&gt;
1. &amp;lt;code&amp;gt;app/assets/javascripts/conflict_report.js&amp;lt;/code&amp;gt;[https://github.com/expertiza/expertiza/pull/1714/files#diff-0df434e3b51a1cb1604423db5db1ff66] &amp;lt;br&amp;gt;&lt;br /&gt;
2. &amp;lt;code&amp;gt;app/controllers/response_controller.rb&amp;lt;/code&amp;gt;[https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/app/controllers/response_controller.rb] &amp;lt;br&amp;gt;&lt;br /&gt;
3. &amp;lt;code&amp;gt;app/helpers/report_formatter_helper.rb&amp;lt;/code&amp;gt;[https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/app/helpers/report_formatter_helper.rb]&amp;lt;br&amp;gt;&lt;br /&gt;
4. &amp;lt;code&amp;gt;app/helpers/review_mapping_helper.rb&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/app/helpers/review_mapping_helper.rb]&amp;lt;br&amp;gt;&lt;br /&gt;
5. &amp;lt;code&amp;gt;app/helpers/summary_helper.rb&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/app/helpers/summary_helper.rb]&amp;lt;br&amp;gt;&lt;br /&gt;
6. &amp;lt;code&amp;gt;app/mailers/mailer.rb&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/app/mailers/mailer.rb]&amp;lt;br&amp;gt;&lt;br /&gt;
7. &amp;lt;code&amp;gt;app/models/answer.rb&amp;lt;/code&amp;gt;[https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/app/models/answer.rb]&amp;lt;br&amp;gt;&lt;br /&gt;
8. &amp;lt;code&amp;gt;app/models/response.rb&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/app/models/response.rb]&amp;lt;br&amp;gt;&lt;br /&gt;
9. &amp;lt;code&amp;gt;app/views/mailer/notify_grade_conflict_message.html.erb&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/app/views/mailer/notify_grade_conflict_message.html.erb]&amp;lt;br&amp;gt;&lt;br /&gt;
10. &amp;lt;code&amp;gt;app/views/reports/_review_conflict_metric.html.erb&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/app/views/reports/_review_conflict_metric.html.erb] &amp;lt;br&amp;gt;&lt;br /&gt;
11. &amp;lt;code&amp;gt;app/views/reports/_review_conflict_report.html.erb&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/app/views/reports/_review_conflict_report.html.erb] &amp;lt;br&amp;gt;&lt;br /&gt;
12. &amp;lt;code&amp;gt;app/views/reports/_searchbox.html.erb&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/app/views/reports/_searchbox.html.erb] &amp;lt;br&amp;gt;&lt;br /&gt;
13. &amp;lt;code&amp;gt;app/views/reports/response_report.html.haml&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/app/views/reports/response_report.html.haml] &amp;lt;br&amp;gt;&lt;br /&gt;
14. &amp;lt;code&amp;gt;spec/controllers/reports_controller_spec.rb&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/spec/controllers/reports_controller_spec.rb]&amp;lt;br&amp;gt;&lt;br /&gt;
15. &amp;lt;code&amp;gt;spec/features/review_mapping_helper_spec.rb&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/spec/features/review_mapping_helper_spec.rb] &amp;lt;br&amp;gt;&lt;br /&gt;
16. &amp;lt;code&amp;gt;spec/helpers/review_mapping_helper_spec.rb&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/spec/helpers/review_mapping_helper_spec.rb] &amp;lt;br&amp;gt;&lt;br /&gt;
17. &amp;lt;code&amp;gt;spec/models/answer_spec.rb &amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/spec/models/answer_spec.rb] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Useful Links =&lt;br /&gt;
&lt;br /&gt;
'''Github:''' https://github.com/sid189/expertiza/tree/beta &amp;lt;br /&amp;gt;&lt;br /&gt;
'''Pull Request:''' https://github.com/expertiza/expertiza/pull/1714&lt;br /&gt;
&lt;br /&gt;
= Team Information =&lt;br /&gt;
&lt;br /&gt;
'''Project Mentor:'''&lt;br /&gt;
&amp;lt;br&amp;gt;Pratik Abhyankar&lt;br /&gt;
&lt;br /&gt;
'''Project Members:'''&amp;lt;br&amp;gt;&lt;br /&gt;
Sahil Papalkar&amp;lt;br&amp;gt;&lt;br /&gt;
Sahil Mehta&amp;lt;br&amp;gt;&lt;br /&gt;
Siddharth Deshpande&amp;lt;br&amp;gt;&lt;br /&gt;
Carl Klier&amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Shmehta</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2015._Conflict_notification&amp;diff=134042</id>
		<title>CSC/ECE 517 Spring 2020 - E2015. Conflict notification</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2015._Conflict_notification&amp;diff=134042"/>
		<updated>2020-04-25T00:59:42Z</updated>

		<summary type="html">&lt;p&gt;Shmehta: /* Files Changed */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
Expertiza is an open-source project written using the Ruby on Rails framework.  The Expertiza platform aims to improve student learning by using active and cooperative learning, allowing distance education students to participate in active learning, and by discouraging plagiarism through the use of multiple deadlines. Expertiza helps to improve teaching and resource utilization by having students contribute to the creation of course materials and through peer-graded assignments. Expertiza manages objects related to a course such as instructors, TAs, students, and other users. It also manages assignments, teams, signup topics, rubrics, peer grading, and peer evaluations.&lt;br /&gt;
&lt;br /&gt;
== Reports Background ==&lt;br /&gt;
Students can form teams in Expertiza to work on an assignment in a group. Submissions made on Expertiza can be peer-reviewed by students within the course based on a rubric. Results of the peer review can be accessed by instructors and respective student teams in the form of statistical reports. The students have access to view their feedback in the form of a Summary Report. The student Summary Report shows the scores submitted by the reviewers for each question of the rubric for that assignment. If there are more than one round, it shows the scores separated by round number. The instructors have more options to view student submitted feedback in the form of Reviewees Summary Reports which shows the average review scores for an assignment for each round with each reviewer's comments, and Review Reports which shows what teams' assignment were reviewed by each student.&lt;br /&gt;
&lt;br /&gt;
== Review Conflict Background ==&lt;br /&gt;
In the current implementation, during the peer review phase of an assignment, email notifications are sent out to the instructor whenever a submitted review score differs “significantly” from the average score of other submitted reviews for that submission. The threshold to trigger a notification is specified in the “Notification limit” on the Rubrics tab of assignment creation. The email that gets sent to instructors contains three links: a link to the conflicting review, a link to the summary page of grades for the reviewee, and a link to edit the assignment.&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
When a review is submitted that triggers a conflict, an email gets sent to instructors that contains three links: a link to the conflicting review, a link to the summary page of grades for the reviewee, and a link to edit the assignment. Although the links sent in the email are helpful for reference, the process of examining a conflicting review could be made more efficient if we provide an easy to understand report of the conflicts. The information sent in the email should be updated to contain a link to a report page which should contain more details about the newest conflict as well as information on previous review conflicts for the assignment. The conflict report page should have an easy to understand visualization showing the assignment's reviews with scores that cause a conflict.&lt;br /&gt;
&lt;br /&gt;
= Existing Implementation =&lt;br /&gt;
The existing system has the following implementation for conflict notification. On submitting a new review for a particular artifact, the submitted score is compared to the average score of the previously submitted reviews. If the difference between the average score and the newly submitted score is more than the notification threshold specified for the assignment, an email is sent out to the instructor. The email sent to the instructor contains the names of the reviewer and reviewee and a link to the conflicting review, a link to the summary of review responses, and a link to edit the assignment. The flowchart below delineates the entire process:&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
[[File:Conflictflowchart.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
== Problems with Existing Implementation ==&lt;br /&gt;
The existing implementation has the following flaws:&lt;br /&gt;
&lt;br /&gt;
=== No dedicated report for analyzing the conflict ===&lt;br /&gt;
The current implementation does not provide any dedicated view or report containing a detailed analysis of the conflicts that occur during the entire review period. The link to the conflicting review is helpful, but doesn't provide any context for for why that review was in conflict. The link to the summary of review responses provides more insight into how the assignment is being scored overall, but it doesn't provide a clear picture of which reviews are in conflict and have scores that are outliers. &lt;br /&gt;
&lt;br /&gt;
=== Incorrect email URLs ===&lt;br /&gt;
When an review is in conflict and an email gets set to the instructor, the body of the email contains links to the review, review summary page, and a link to edit the assignment. See a copy of the email message below as it is being sent by the current implementation.&lt;br /&gt;
[[File:Conflictemail.png]]&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
The current implementation uses hardcoded URLs mentioned in the &amp;lt;code&amp;gt;notify_instructor_on_difference&amp;lt;/code&amp;gt; method of the &amp;lt;code&amp;gt;models/response.rb&amp;lt;/code&amp;gt; file. See the code:&lt;br /&gt;
&lt;br /&gt;
  conflicting_response_url: 'https://expertiza.ncsu.edu/response/view?id=' + response_id.to_s,&lt;br /&gt;
  summary_url: 'https://expertiza.ncsu.edu/grades/view_team?id=' + reviewee_participant.id.to_s,&lt;br /&gt;
  assignment_edit_url: 'https://expertiza.ncsu.edu/assignments/' + assignment.id.to_s + '/edit'&lt;br /&gt;
&lt;br /&gt;
Being hardcoded, these link would not work in on other servers where Expertiza is running. For example, the links won't be valid if the setup was done on the localhost.&lt;br /&gt;
&lt;br /&gt;
= Previous Work =&lt;br /&gt;
&lt;br /&gt;
The [https://expertiza.csc.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_E1931._Conflict_notification Previous Work] resolved the email related issues and also created a simple UI report page for analyzing the conflict. However, the implementation had quite a few issues that prevented it from being merged. See a screenshot from the previous implementation of a snippet of the information from the conflict report page:&amp;lt;br /&amp;gt; [[File:OldConflictGraph.PNG|center]]&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
==Issues with Previous Work ==&lt;br /&gt;
1. The UI for the conflict report included a bar graph that showed the grades of reviews that were in conflict. The information in the bar graph was showing percentages while the scores shown beside it were in raw points. This is an inconsistency; they should display the data in the same units.&amp;lt;br /&amp;gt;&lt;br /&gt;
2. The bar graph contained too much white space and took up too much area on the screen.&amp;lt;br /&amp;gt;&lt;br /&gt;
3. It was also not obvious from the bar graph which review scores caused a conflict as they were not highlighted or distinguished in any way.&amp;lt;br /&amp;gt;&lt;br /&gt;
4. The bars in the chart were also not sorted in any meaningful way (i.e., ascending or descending) &amp;lt;br /&amp;gt;&lt;br /&gt;
5. The list of students who reviewed an submission extended vertically down the page which contributed to each row of the table taking up considerable screen space, especially for submissions with many reviews.&amp;lt;br /&amp;gt;&lt;br /&gt;
6. The metrics listed in the screenshot above don't specify the threshold for conflict. Therefore, you can't tell what review scores would actually cause a conflict.&amp;lt;br /&amp;gt;&lt;br /&gt;
7. The code for the conflict report view included a lot of logic. &amp;lt;br /&amp;gt;&lt;br /&gt;
8. There was minimal effort spent on refactoring test cases and the test cases added in the pull request were shallow tests, meaning that they simply asserted that the expected value was not empty rather than the correct way of asserting the expected value matched a specific value. &amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Design of New Implementation =&lt;br /&gt;
== Proposed Solution ==&lt;br /&gt;
As the mailing functionality was implemented perfectly in the previous implementation, we plan to use their implementation as our starting point. Building on top of it, we plan to address the highlighted issues with the previous implementation and refactor the conflict report so that it is able to provide better insights into the review conflicts.&lt;br /&gt;
Once the existing code determines that a conflict has occurred, the code will create a report view for the conflict. The report view will contain all the relevant statistics(mean, max, standard deviation, etc.) of all the reviews received for the submission. Next, a URL for the report page will be added to the email body. All URLs in the email will be relative URLs and therefore the URLs will be valid on all servers. Following files need to be updated in order to implement these changes:   &lt;br /&gt;
&lt;br /&gt;
*Related to Email:&lt;br /&gt;
**&amp;lt;code&amp;gt;app/mailers/mailer.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Modify method &amp;lt;code&amp;gt;notify_grade_conflict_message&amp;lt;/code&amp;gt; to add the link to the conflict report in the email body.&lt;br /&gt;
**&amp;lt;code&amp;gt;app/models/response.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Modify method &amp;lt;code&amp;gt;notify_instructor_on_difference&amp;lt;/code&amp;gt; to add a relative links to various pages that get included in the email body.&lt;br /&gt;
**&amp;lt;code&amp;gt;app/views/mailer/notify_grade_conflict_message.html.erb&amp;lt;/code&amp;gt; &lt;br /&gt;
*** Modify the html to add a link to the email message using which the conflict report viewed.&lt;br /&gt;
**&amp;lt;code&amp;gt;app/controllers/response_contrller.rb&amp;lt;/code&amp;gt; &lt;br /&gt;
*** Modify &amp;lt;code&amp;gt;update&amp;lt;/code&amp;gt; method to add &amp;lt;code&amp;gt;request.base_url&amp;lt;/code&amp;gt; as a param sent to &amp;lt;code&amp;gt;notify_instructor_on_difference&amp;lt;/code&amp;gt; method&lt;br /&gt;
*** Modify &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method to add &amp;lt;code&amp;gt;request.base_url&amp;lt;/code&amp;gt; as a param sent to &amp;lt;code&amp;gt;notify_instructor_on_difference&amp;lt;/code&amp;gt; method&lt;br /&gt;
	&lt;br /&gt;
*Related to the conflict report view:&lt;br /&gt;
**&amp;lt;code&amp;gt;app/views/reports/_searchbox.html.erb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Modify the html to add the option to view a conflict report.&lt;br /&gt;
**&amp;lt;code&amp;gt;app/views/reports/response_report.html.haml&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Modify the html to render the conflict report partial if the option to view a conflict report was selected.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
What we need to create:&lt;br /&gt;
*Related to the conflict report view:&lt;br /&gt;
**&amp;lt;code&amp;gt;App/views/reports/_conflict_report.html.erb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Need to create this entire file to make the view for a conflict report&lt;br /&gt;
**&amp;lt;code&amp;gt;app/helpers/report_formatter_helper.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Need to add a method &amp;lt;code&amp;gt;conflict_reponse_map&amp;lt;/code&amp;gt; to make specific instance variables available to our conflict report view. This method will get called from the ReportsController. &lt;br /&gt;
**&amp;lt;code&amp;gt;app/helpers/summary_helper.rb&amp;lt;/code&amp;gt; &lt;br /&gt;
*** Need to add a method to get the maximum possible score of an assignment in each round&lt;br /&gt;
**&amp;lt;code&amp;gt;app/models/answer.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Need to add a method to get the answers from a review for an assignment submitted by a specific reviewer.&lt;br /&gt;
**&amp;lt;code&amp;gt;app/helpers/review_mapping_helper.rb&amp;lt;/code&amp;gt; &lt;br /&gt;
*** Need to add methods to get the review scores for a team in each round, calculate the average review score for a round, calculate the std. deviation of review scores for each round, and get the team members of each team. Apart from these any other method to find and calculate data to be viewed in the report can be added to this helper file.	&lt;br /&gt;
	&lt;br /&gt;
&lt;br /&gt;
The conflict report view should:&lt;br /&gt;
*For each team that had a submission with a review that was in a conflict:&lt;br /&gt;
**List the team name and team members&lt;br /&gt;
**Provide a graphical view of the statistics displayed in the report&lt;br /&gt;
**For each round where there was a review in conflict:&lt;br /&gt;
***List and highlight the students who's review caused a conflict and the score they gave&lt;br /&gt;
***List the threshold for conflict review score, max review score, average review score, and standard deviation. &amp;lt;br \&amp;gt;&amp;lt;br \&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order to resolve the issues with the previous team's pull request, we will:&amp;lt;br \&amp;gt;&lt;br /&gt;
1. Not include any unnecessary bar charts with redundant information in our conflict report view.&amp;lt;br \&amp;gt;&lt;br /&gt;
2. Put the necessary logic into helper methods in helper files to ensure logic stays out of our views.&amp;lt;br \&amp;gt;&lt;br /&gt;
3. Replace the logic used in the review_mapping_helper.rb file to fetch the team member of a specific team. &amp;lt;br \&amp;gt;&lt;br /&gt;
4. Refactor the necessary affected test cases and write new RSpec tests in accordance with our proposed test plan to ensure adequate coverage.&amp;lt;br \&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== UML Diagrams ==&lt;br /&gt;
=== Use Case Diagram ===&lt;br /&gt;
The usecase diagram highlights the simple workflow of the proposed system when trigger by the user.&amp;lt;br /&amp;gt;&lt;br /&gt;
[[File:usecase-1.png]]&lt;br /&gt;
&amp;lt;br /&amp;gt; &amp;lt;br /&amp;gt;&lt;br /&gt;
Actors participating:&lt;br /&gt;
&lt;br /&gt;
* Student: In this use case, fills out the reviews for different projects submitted by the peers.&lt;br /&gt;
* TA/Instructor: In this use case, goes over the conflicting review submitted by the students for the same project.&lt;br /&gt;
&lt;br /&gt;
=== Sequence Diagram ===&lt;br /&gt;
The sequence diagram models the interactions that will take place between various components of the system for the above use-case. &lt;br /&gt;
&amp;lt;br /&amp;gt; &amp;lt;br /&amp;gt;&lt;br /&gt;
[[File:conflictSeq.jpg]]&lt;br /&gt;
&lt;br /&gt;
= New Implementation =&lt;br /&gt;
As per the plan stated in the above section, following changes were implemented:&lt;br /&gt;
&lt;br /&gt;
= Testing =&lt;br /&gt;
Both manual testing and RSpec testing were used to test the new functionalities. &lt;br /&gt;
=== RSpec Testing ===&lt;br /&gt;
In order to test the changes implemented in the model, controller and helper file new RSpec tests have been added. &lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
'''1. Add a new test to &amp;lt;code&amp;gt;spec/controllers/reports_controller_spec.rb&amp;lt;/code&amp;gt;''' &amp;lt;br /&amp;gt;&lt;br /&gt;
The test checks if the new review conflict report is routed and rendered properly by the response controller.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: green&amp;quot;&amp;gt;&lt;br /&gt;
    describe '#review_conflict_response_map' do&lt;br /&gt;
      context 'when type is ReviewConflictResponseMap' do&lt;br /&gt;
        it 'renders response_report page with corresponding data' do&lt;br /&gt;
          allow(TeammateReviewResponseMap).to receive(:teammate_response_report)&lt;br /&gt;
            .with('1')&lt;br /&gt;
            .and_return([participant, participant2])&lt;br /&gt;
          params = {&lt;br /&gt;
              id: 1,&lt;br /&gt;
              report: {type: 'ReviewConflictResponseMap'},&lt;br /&gt;
              user: 'no one'&lt;br /&gt;
          }&lt;br /&gt;
          get :response_report, params&lt;br /&gt;
          expect(response).to render_template(:response_report)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. Add a new test to &amp;lt;code&amp;gt;spec/models/answer_spec.rb&amp;lt;/code&amp;gt;''' &amp;lt;br /&amp;gt;&lt;br /&gt;
This tests if the query in the newly added method 'answers_by_round_for_reviewee' works properly and fetches a valid result.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: green&amp;quot;&amp;gt;&lt;br /&gt;
    it &amp;quot;returns answers by reviewer for reviewee in round from db which is not empty&amp;quot; do&lt;br /&gt;
      expect(Answer.answers_by_round_for_reviewee(@assignment_id, @reviewee_id,@round)).not_to be_empty&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''3. Create and add a new tests to &amp;lt;code&amp;gt;spec/helpers/review_mapping_helper_spec.rb&amp;lt;/code&amp;gt;''' &amp;lt;br /&amp;gt;&lt;br /&gt;
This file tests various calculations performed by the newly added helper methods. The results of these calculations are not only used to display on the report but also used to generate the graph. &lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: green&amp;quot;&amp;gt;&lt;br /&gt;
describe &amp;quot;ReviewMappingHelper&amp;quot; do&lt;br /&gt;
  describe &amp;quot;#review_score_helper_for_team&amp;quot; do&lt;br /&gt;
    before(:each) do&lt;br /&gt;
      @review_answers = [{'reviewer_id': '2', 'answer': 54}, {'reviewer_id': '1', 'answer': 24}, {'reviewer_id': '2', 'answer': 25}]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;The review_score_helper_for_team method calculates the total review scores for each review&amp;quot; do&lt;br /&gt;
      question_answers = helper.review_score_helper_for_team(@review_answers)&lt;br /&gt;
      expect(question_answers).to include('1' =&amp;gt; 24,'2' =&amp;gt; 79)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe &amp;quot;#get_score_metrics&amp;quot; do&lt;br /&gt;
    before(:each) do&lt;br /&gt;
      @review_scores = {'1' =&amp;gt; 50, '2' =&amp;gt; 40, '3' =&amp;gt; 60}&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;The get_score_metrics method calculates various metrics used in the conflict report&amp;quot; do&lt;br /&gt;
      metric = helper.get_score_metrics(@review_scores, 50)&lt;br /&gt;
      expect(metric[:average]).to eq 50.0&lt;br /&gt;
      expect(metric[:std]).to eq 8.16&lt;br /&gt;
      expect(metric[:upper_tolerance_limit]).to eq 50&lt;br /&gt;
      expect(metric[:lower_tolerance_limit]).to eq 33.68&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''4. Add new test in &amp;lt;code&amp;gt;spec/features/review_mapping_helper_spec.rb&amp;lt;/code&amp;gt;''' &amp;lt;br /&amp;gt;&lt;br /&gt;
This UI test navigates to the conflict report page and tests if the report is rendered properly.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: green&amp;quot;&amp;gt;&lt;br /&gt;
describe &amp;quot;Test Review conflict report&amp;quot; do&lt;br /&gt;
  before(:each) do&lt;br /&gt;
    create(:instructor)&lt;br /&gt;
    create(:assignment, course: nil, name: 'Test Assignment')&lt;br /&gt;
    assignment_id = Assignment.where(name: 'Test Assignment')[0].id&lt;br /&gt;
    login_as 'instructor6'&lt;br /&gt;
    visit &amp;quot;/reports/response_report?id=#{assignment_id}&amp;quot;&lt;br /&gt;
    page.select(&amp;quot;Review conflict report&amp;quot;, :from =&amp;gt; &amp;quot;report[type]&amp;quot;)&lt;br /&gt;
    click_button &amp;quot;View&amp;quot;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  # Check if the page renders&lt;br /&gt;
&lt;br /&gt;
  it &amp;quot;has a conflicting review table&amp;quot; do&lt;br /&gt;
    expect(page).to have_css('table')&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it &amp;quot;can display teams&amp;quot; do&lt;br /&gt;
    expect(page).to have_content('Team')&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it &amp;quot;can display author reviewers and metrics&amp;quot; do&lt;br /&gt;
    expect(page).to have_selector(:link_or_button, 'Convert Points to Percents')&lt;br /&gt;
  end&lt;br /&gt;
end &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
All RSpec tests are passing for the current implementation as is evident by the passing Travis CI build.&lt;br /&gt;
&lt;br /&gt;
== Manual Testing ==&lt;br /&gt;
In order to test the functionality manually, we follow the following steps: &amp;lt;br \&amp;gt;&lt;br /&gt;
1. Create a new assignment with 15% as a conflict threshold limit. &amp;lt;br /&amp;gt;&lt;br /&gt;
2. Add 4 students to the assignment and divide them into 2 teams of 2 students in each. &amp;lt;br /&amp;gt;&lt;br /&gt;
3. Add submission for each team. &amp;lt;br /&amp;gt;&lt;br /&gt;
4. In the review phase, login to the first team student accounts and give scores of 100% and 50% to the second team's assignment. &amp;lt;br /&amp;gt;&lt;br /&gt;
5. Since the scores differ by more than 15% the email will be sent to the instructor. &amp;lt;br /&amp;gt;&lt;br /&gt;
6. Access the email and check if the email contains the following details: &amp;lt;br /&amp;gt;&lt;br /&gt;
* Names of the reviewer and reviewee&lt;br /&gt;
* Link to the conflicting review&lt;br /&gt;
* Link to the newly created report view corresponding to the conflict&lt;br /&gt;
* Link to edit the assignment notification limit&lt;br /&gt;
7. View the conflict report and ensure that Team 2 shows up as having a conflicting review submitted by student 2 of Team 1.&lt;br /&gt;
&lt;br /&gt;
= Files Changed =&lt;br /&gt;
1. &amp;lt;code&amp;gt;app/assets/javascripts/conflict_report.js&amp;lt;/code&amp;gt;[https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/app/assets/javascripts/conflict_report.js] &amp;lt;br&amp;gt;&lt;br /&gt;
2. &amp;lt;code&amp;gt;app/controllers/response_controller.rb&amp;lt;/code&amp;gt;[https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/app/controllers/response_controller.rb] &amp;lt;br&amp;gt;&lt;br /&gt;
3. &amp;lt;code&amp;gt;app/helpers/report_formatter_helper.rb&amp;lt;/code&amp;gt;[https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/app/helpers/report_formatter_helper.rb]&amp;lt;br&amp;gt;&lt;br /&gt;
4. &amp;lt;code&amp;gt;app/helpers/review_mapping_helper.rb&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/app/helpers/review_mapping_helper.rb]&amp;lt;br&amp;gt;&lt;br /&gt;
5. &amp;lt;code&amp;gt;app/helpers/summary_helper.rb&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/app/helpers/summary_helper.rb]&amp;lt;br&amp;gt;&lt;br /&gt;
6. &amp;lt;code&amp;gt;app/mailers/mailer.rb&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/app/mailers/mailer.rb]&amp;lt;br&amp;gt;&lt;br /&gt;
7. &amp;lt;code&amp;gt;app/models/answer.rb&amp;lt;/code&amp;gt;[https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/app/models/answer.rb]&amp;lt;br&amp;gt;&lt;br /&gt;
8. &amp;lt;code&amp;gt;app/models/response.rb&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/app/models/response.rb]&amp;lt;br&amp;gt;&lt;br /&gt;
9. &amp;lt;code&amp;gt;app/views/mailer/notify_grade_conflict_message.html.erb&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/app/views/mailer/notify_grade_conflict_message.html.erb]&amp;lt;br&amp;gt;&lt;br /&gt;
10. &amp;lt;code&amp;gt;app/views/reports/_review_conflict_metric.html.erb&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/app/views/reports/_review_conflict_metric.html.erb] &amp;lt;br&amp;gt;&lt;br /&gt;
11. &amp;lt;code&amp;gt;app/views/reports/_review_conflict_report.html.erb&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/app/views/reports/_review_conflict_report.html.erb] &amp;lt;br&amp;gt;&lt;br /&gt;
12. &amp;lt;code&amp;gt;app/views/reports/_searchbox.html.erb&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/app/views/reports/_searchbox.html.erb] &amp;lt;br&amp;gt;&lt;br /&gt;
13. &amp;lt;code&amp;gt;app/views/reports/response_report.html.haml&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/app/views/reports/response_report.html.haml] &amp;lt;br&amp;gt;&lt;br /&gt;
14. &amp;lt;code&amp;gt;spec/controllers/reports_controller_spec.rb&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/spec/controllers/reports_controller_spec.rb]&amp;lt;br&amp;gt;&lt;br /&gt;
15. &amp;lt;code&amp;gt;spec/features/review_mapping_helper_spec.rb&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/spec/features/review_mapping_helper_spec.rb] &amp;lt;br&amp;gt;&lt;br /&gt;
16. &amp;lt;code&amp;gt;spec/helpers/review_mapping_helper_spec.rb&amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/spec/helpers/review_mapping_helper_spec.rb] &amp;lt;br&amp;gt;&lt;br /&gt;
17. &amp;lt;code&amp;gt;spec/models/answer_spec.rb &amp;lt;/code&amp;gt; [https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/spec/models/answer_spec.rb] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Useful Links =&lt;br /&gt;
&lt;br /&gt;
'''Github:''' https://github.com/sid189/expertiza/tree/beta &amp;lt;br /&amp;gt;&lt;br /&gt;
'''Pull Request:''' https://github.com/expertiza/expertiza/pull/1714&lt;br /&gt;
&lt;br /&gt;
= Team Information =&lt;br /&gt;
&lt;br /&gt;
'''Project Mentor:'''&lt;br /&gt;
&amp;lt;br&amp;gt;Pratik Abhyankar&lt;br /&gt;
&lt;br /&gt;
'''Project Members:'''&amp;lt;br&amp;gt;&lt;br /&gt;
Sahil Papalkar&amp;lt;br&amp;gt;&lt;br /&gt;
Sahil Mehta&amp;lt;br&amp;gt;&lt;br /&gt;
Siddharth Deshpande&amp;lt;br&amp;gt;&lt;br /&gt;
Carl Klier&amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Shmehta</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2015._Conflict_notification&amp;diff=134027</id>
		<title>CSC/ECE 517 Spring 2020 - E2015. Conflict notification</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2015._Conflict_notification&amp;diff=134027"/>
		<updated>2020-04-25T00:45:27Z</updated>

		<summary type="html">&lt;p&gt;Shmehta: /* Files Changed */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
Expertiza is an open-source project written using the Ruby on Rails framework.  The Expertiza platform aims to improve student learning by using active and cooperative learning, allowing distance education students to participate in active learning, and by discouraging plagiarism through the use of multiple deadlines. Expertiza helps to improve teaching and resource utilization by having students contribute to the creation of course materials and through peer-graded assignments. Expertiza manages objects related to a course such as instructors, TAs, students, and other users. It also manages assignments, teams, signup topics, rubrics, peer grading, and peer evaluations.&lt;br /&gt;
&lt;br /&gt;
== Reports Background ==&lt;br /&gt;
Students can form teams in Expertiza to work on an assignment in a group. Submissions made on Expertiza can be peer-reviewed by students within the course based on a rubric. Results of the peer review can be accessed by instructors and respective student teams in the form of statistical reports. The students have access to view their feedback in the form of a Summary Report. The student Summary Report shows the scores submitted by the reviewers for each question of the rubric for that assignment. If there are more than one round, it shows the scores separated by round number. The instructors have more options to view student submitted feedback in the form of Reviewees Summary Reports which shows the average review scores for an assignment for each round with each reviewer's comments, and Review Reports which shows what teams' assignment were reviewed by each student.&lt;br /&gt;
&lt;br /&gt;
== Review Conflict Background ==&lt;br /&gt;
In the current implementation, during the peer review phase of an assignment, email notifications are sent out to the instructor whenever a submitted review score differs “significantly” from the average score of other submitted reviews for that submission. The threshold to trigger a notification is specified in the “Notification limit” on the Rubrics tab of assignment creation. The email that gets sent to instructors contains three links: a link to the conflicting review, a link to the summary page of grades for the reviewee, and a link to edit the assignment.&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
When a review is submitted that triggers a conflict, an email gets sent to instructors that contains three links: a link to the conflicting review, a link to the summary page of grades for the reviewee, and a link to edit the assignment. Although the links sent in the email are helpful for reference, the process of examining a conflicting review could be made more efficient if we provide an easy to understand report of the conflicts. The information sent in the email should be updated to contain a link to a report page which should contain more details about the newest conflict as well as information on previous review conflicts for the assignment. The conflict report page should have an easy to understand visualization showing the assignment's reviews with scores that cause a conflict.&lt;br /&gt;
&lt;br /&gt;
= Existing Implementation =&lt;br /&gt;
The existing system has the following implementation for conflict notification. On submitting a new review for a particular artifact, the submitted score is compared to the average score of the previously submitted reviews. If the difference between the average score and the newly submitted score is more than the notification threshold specified for the assignment, an email is sent out to the instructor. The email sent to the instructor contains the names of the reviewer and reviewee and a link to the conflicting review, a link to the summary of review responses, and a link to edit the assignment. The flowchart below delineates the entire process:&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
[[File:Conflictflowchart.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
== Problems with Existing Implementation ==&lt;br /&gt;
The existing implementation has the following flaws:&lt;br /&gt;
&lt;br /&gt;
=== No dedicated report for analyzing the conflict ===&lt;br /&gt;
The current implementation does not provide any dedicated view or report containing a detailed analysis of the conflicts that occur during the entire review period. The link to the conflicting review is helpful, but doesn't provide any context for for why that review was in conflict. The link to the summary of review responses provides more insight into how the assignment is being scored overall, but it doesn't provide a clear picture of which reviews are in conflict and have scores that are outliers. &lt;br /&gt;
&lt;br /&gt;
=== Incorrect email URLs ===&lt;br /&gt;
When an review is in conflict and an email gets set to the instructor, the body of the email contains links to the review, review summary page, and a link to edit the assignment. See a copy of the email message below as it is being sent by the current implementation.&lt;br /&gt;
[[File:Conflictemail.png]]&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
The current implementation uses hardcoded URLs mentioned in the &amp;lt;code&amp;gt;notify_instructor_on_difference&amp;lt;/code&amp;gt; method of the &amp;lt;code&amp;gt;models/response.rb&amp;lt;/code&amp;gt; file. See the code:&lt;br /&gt;
&lt;br /&gt;
  conflicting_response_url: 'https://expertiza.ncsu.edu/response/view?id=' + response_id.to_s,&lt;br /&gt;
  summary_url: 'https://expertiza.ncsu.edu/grades/view_team?id=' + reviewee_participant.id.to_s,&lt;br /&gt;
  assignment_edit_url: 'https://expertiza.ncsu.edu/assignments/' + assignment.id.to_s + '/edit'&lt;br /&gt;
&lt;br /&gt;
Being hardcoded, these link would not work in on other servers where Expertiza is running. For example, the links won't be valid if the setup was done on the localhost.&lt;br /&gt;
&lt;br /&gt;
= Previous Work =&lt;br /&gt;
&lt;br /&gt;
The [https://expertiza.csc.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_E1931._Conflict_notification Previous Work] resolved the email related issues and also created a simple UI report page for analyzing the conflict. However, the implementation had quite a few issues that prevented it from being merged:&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
1. The UI for the conflict report included a bar graph that showed the grades of reviews that were in conflict. The information in the bar graph was showing percentages while the scores shown beside it were in raw points. This is an inconsistency; they should display the data in the same units. Also the bar graph contained too much white space and took up too much area on the screen. It was also not obvious from the bar graph which review scores caused a conflict as they were not highlighted or distinguished in any way. See a screenshot of the previous implementation below: [[File:OldConflictGraph.PNG|center]] &amp;lt;br /&amp;gt;&lt;br /&gt;
2. The code for the conflict report view included a lot of logic. &amp;lt;br /&amp;gt;&lt;br /&gt;
3. There was minimal effort spent on refactoring test cases and the test cases added in the pull request were shallow tests, meaning that they simply asserted that the expected value was not empty rather than the correct way of asserting the expected value matched a specific value. &amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Design of New Implementation =&lt;br /&gt;
== Proposed Solution ==&lt;br /&gt;
As the mailing functionality was implemented perfectly in the previous implementation, we plan to use their implementation as our starting point. Building on top of it, we plan to address the highlighted issues with the previous implementation and refactor the conflict report so that it is able to provide better insights into the review conflicts.&lt;br /&gt;
Once the existing code determines that a conflict has occurred, the code will create a report view for the conflict. The report view will contain all the relevant statistics(mean, max, standard deviation, etc.) of all the reviews received for the submission. Next, a URL for the report page will be added to the email body. All URLs in the email will be relative URLs and therefore the URLs will be valid on all servers. Following files need to be updated in order to implement these changes:   &lt;br /&gt;
&lt;br /&gt;
*Related to Email:&lt;br /&gt;
**&amp;lt;code&amp;gt;app/mailers/mailer.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Modify method &amp;lt;code&amp;gt;notify_grade_conflict_message&amp;lt;/code&amp;gt; to add the link to the conflict report in the email body.&lt;br /&gt;
**&amp;lt;code&amp;gt;app/models/response.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Modify method &amp;lt;code&amp;gt;notify_instructor_on_difference&amp;lt;/code&amp;gt; to add a relative links to various pages that get included in the email body.&lt;br /&gt;
**&amp;lt;code&amp;gt;app/views/mailer/notify_grade_conflict_message.html.erb&amp;lt;/code&amp;gt; &lt;br /&gt;
*** Modify the html to add a link to the email message using which the conflict report viewed.&lt;br /&gt;
**&amp;lt;code&amp;gt;app/controllers/response_contrller.rb&amp;lt;/code&amp;gt; &lt;br /&gt;
*** Modify &amp;lt;code&amp;gt;update&amp;lt;/code&amp;gt; method to add &amp;lt;code&amp;gt;request.base_url&amp;lt;/code&amp;gt; as a param sent to &amp;lt;code&amp;gt;notify_instructor_on_difference&amp;lt;/code&amp;gt; method&lt;br /&gt;
*** Modify &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method to add &amp;lt;code&amp;gt;request.base_url&amp;lt;/code&amp;gt; as a param sent to &amp;lt;code&amp;gt;notify_instructor_on_difference&amp;lt;/code&amp;gt; method&lt;br /&gt;
	&lt;br /&gt;
*Related to the conflict report view:&lt;br /&gt;
**&amp;lt;code&amp;gt;app/views/reports/_searchbox.html.erb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Modify the html to add the option to view a conflict report.&lt;br /&gt;
**&amp;lt;code&amp;gt;app/views/reports/response_report.html.haml&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Modify the html to render the conflict report partial if the option to view a conflict report was selected.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
What we need to create:&lt;br /&gt;
*Related to the conflict report view:&lt;br /&gt;
**&amp;lt;code&amp;gt;App/views/reports/_conflict_report.html.erb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Need to create this entire file to make the view for a conflict report&lt;br /&gt;
**&amp;lt;code&amp;gt;app/helpers/report_formatter_helper.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Need to add a method &amp;lt;code&amp;gt;conflict_reponse_map&amp;lt;/code&amp;gt; to make specific instance variables available to our conflict report view. This method will get called from the ReportsController. &lt;br /&gt;
**&amp;lt;code&amp;gt;app/helpers/summary_helper.rb&amp;lt;/code&amp;gt; &lt;br /&gt;
*** Need to add a method to get the maximum possible score of an assignment in each round&lt;br /&gt;
**&amp;lt;code&amp;gt;app/models/answer.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Need to add a method to get the answers from a review for an assignment submitted by a specific reviewer.&lt;br /&gt;
**&amp;lt;code&amp;gt;app/helpers/review_mapping_helper.rb&amp;lt;/code&amp;gt; &lt;br /&gt;
*** Need to add methods to get the review scores for a team in each round, calculate the average review score for a round, calculate the std. deviation of review scores for each round, and get the team members of each team. Apart from these any other method to find and calculate data to be viewed in the report can be added to this helper file.	&lt;br /&gt;
	&lt;br /&gt;
&lt;br /&gt;
The conflict report view should:&lt;br /&gt;
*For each team that had a submission with a review that was in a conflict:&lt;br /&gt;
**List the team name and team members&lt;br /&gt;
**Provide a graphical view of the statistics displayed in the report&lt;br /&gt;
**For each round where there was a review in conflict:&lt;br /&gt;
***List and highlight the students who's review caused a conflict and the score they gave&lt;br /&gt;
***List the threshold for conflict review score, max review score, average review score, and standard deviation. &amp;lt;br \&amp;gt;&amp;lt;br \&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order to resolve the issues with the previous team's pull request, we will:&amp;lt;br \&amp;gt;&lt;br /&gt;
1. Not include any unnecessary bar charts with redundant information in our conflict report view.&amp;lt;br \&amp;gt;&lt;br /&gt;
2. Put the necessary logic into helper methods in helper files to ensure logic stays out of our views.&amp;lt;br \&amp;gt;&lt;br /&gt;
3. Replace the logic used in the review_mapping_helper.rb file to fetch the team member of a specific team. &amp;lt;br \&amp;gt;&lt;br /&gt;
4. Refactor the necessary affected test cases and write new RSpec tests in accordance with our proposed test plan to ensure adequate coverage.&amp;lt;br \&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== UML Diagrams ==&lt;br /&gt;
=== Use Case Diagram ===&lt;br /&gt;
The usecase diagram highlights the simple workflow of the proposed system when trigger by the user.&amp;lt;br /&amp;gt;&lt;br /&gt;
[[File:usecase-1.png]]&lt;br /&gt;
&amp;lt;br /&amp;gt; &amp;lt;br /&amp;gt;&lt;br /&gt;
Actors participating:&lt;br /&gt;
&lt;br /&gt;
* Student: In this use case, fills out the reviews for different projects submitted by the peers.&lt;br /&gt;
* TA/Instructor: In this use case, goes over the conflicting review submitted by the students for the same project.&lt;br /&gt;
&lt;br /&gt;
=== Sequence Diagram ===&lt;br /&gt;
The sequence diagram models the interactions that will take place between various components of the system for the above use-case. &lt;br /&gt;
&amp;lt;br /&amp;gt; &amp;lt;br /&amp;gt;&lt;br /&gt;
[[File:conflictSeq.jpg]]&lt;br /&gt;
&lt;br /&gt;
= New Implementation =&lt;br /&gt;
As per the plan stated in the above section, following changes were implemented:&lt;br /&gt;
&lt;br /&gt;
= Testing =&lt;br /&gt;
Both manual testing and RSpec testing were used to test the new functionalities. &lt;br /&gt;
=== RSpec Testing ===&lt;br /&gt;
In order to test the changes implemented in the model, controller and helper file new RSpec tests have been added. &lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
'''1. Add a new test to &amp;lt;code&amp;gt;spec/controllers/reports_controller_spec.rb&amp;lt;/code&amp;gt;''' &amp;lt;br /&amp;gt;&lt;br /&gt;
The test checks if the new review conflict report is routed and rendered properly by the response controller.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: green&amp;quot;&amp;gt;&lt;br /&gt;
    describe '#review_conflict_response_map' do&lt;br /&gt;
      context 'when type is ReviewConflictResponseMap' do&lt;br /&gt;
        it 'renders response_report page with corresponding data' do&lt;br /&gt;
          allow(TeammateReviewResponseMap).to receive(:teammate_response_report)&lt;br /&gt;
            .with('1')&lt;br /&gt;
            .and_return([participant, participant2])&lt;br /&gt;
          params = {&lt;br /&gt;
              id: 1,&lt;br /&gt;
              report: {type: 'ReviewConflictResponseMap'},&lt;br /&gt;
              user: 'no one'&lt;br /&gt;
          }&lt;br /&gt;
          get :response_report, params&lt;br /&gt;
          expect(response).to render_template(:response_report)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. Add a new test to &amp;lt;code&amp;gt;spec/models/answer_spec.rb&amp;lt;/code&amp;gt;''' &amp;lt;br /&amp;gt;&lt;br /&gt;
This tests if the query in the newly added method 'answers_by_round_for_reviewee' works properly and fetches a valid result.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: green&amp;quot;&amp;gt;&lt;br /&gt;
    it &amp;quot;returns answers by reviewer for reviewee in round from db which is not empty&amp;quot; do&lt;br /&gt;
      expect(Answer.answers_by_round_for_reviewee(@assignment_id, @reviewee_id,@round)).not_to be_empty&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''3. Create and add a new tests to &amp;lt;code&amp;gt;spec/helpers/review_mapping_helper_spec.rb&amp;lt;/code&amp;gt;''' &amp;lt;br /&amp;gt;&lt;br /&gt;
This file tests various calculations performed by the newly added helper methods. The results of these calculations are not only used to display on the report but also used to generate the graph. &lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: green&amp;quot;&amp;gt;&lt;br /&gt;
describe &amp;quot;ReviewMappingHelper&amp;quot; do&lt;br /&gt;
  describe &amp;quot;#review_score_helper_for_team&amp;quot; do&lt;br /&gt;
    before(:each) do&lt;br /&gt;
      @review_answers = [{'reviewer_id': '2', 'answer': 54}, {'reviewer_id': '1', 'answer': 24}, {'reviewer_id': '2', 'answer': 25}]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;The review_score_helper_for_team method calculates the total review scores for each review&amp;quot; do&lt;br /&gt;
      question_answers = helper.review_score_helper_for_team(@review_answers)&lt;br /&gt;
      expect(question_answers).to include('1' =&amp;gt; 24,'2' =&amp;gt; 79)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe &amp;quot;#get_score_metrics&amp;quot; do&lt;br /&gt;
    before(:each) do&lt;br /&gt;
      @review_scores = {'1' =&amp;gt; 50, '2' =&amp;gt; 40, '3' =&amp;gt; 60}&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;The get_score_metrics method calculates various metrics used in the conflict report&amp;quot; do&lt;br /&gt;
      metric = helper.get_score_metrics(@review_scores, 50)&lt;br /&gt;
      expect(metric[:average]).to eq 50.0&lt;br /&gt;
      expect(metric[:std]).to eq 8.16&lt;br /&gt;
      expect(metric[:upper_tolerance_limit]).to eq 50&lt;br /&gt;
      expect(metric[:lower_tolerance_limit]).to eq 33.68&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''4. Add new test in &amp;lt;code&amp;gt;spec/features/review_mapping_helper_spec.rb&amp;lt;/code&amp;gt;''' &amp;lt;br /&amp;gt;&lt;br /&gt;
This UI test navigates to the conflict report page and tests if the report is rendered properly.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: green&amp;quot;&amp;gt;&lt;br /&gt;
describe &amp;quot;Test Review conflict report&amp;quot; do&lt;br /&gt;
  before(:each) do&lt;br /&gt;
    create(:instructor)&lt;br /&gt;
    create(:assignment, course: nil, name: 'Test Assignment')&lt;br /&gt;
    assignment_id = Assignment.where(name: 'Test Assignment')[0].id&lt;br /&gt;
    login_as 'instructor6'&lt;br /&gt;
    visit &amp;quot;/reports/response_report?id=#{assignment_id}&amp;quot;&lt;br /&gt;
    page.select(&amp;quot;Review conflict report&amp;quot;, :from =&amp;gt; &amp;quot;report[type]&amp;quot;)&lt;br /&gt;
    click_button &amp;quot;View&amp;quot;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  # Check if the page renders&lt;br /&gt;
&lt;br /&gt;
  it &amp;quot;has a conflicting review table&amp;quot; do&lt;br /&gt;
    expect(page).to have_css('table')&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it &amp;quot;can display teams&amp;quot; do&lt;br /&gt;
    expect(page).to have_content('Team')&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it &amp;quot;can display author reviewers and metrics&amp;quot; do&lt;br /&gt;
    expect(page).to have_selector(:link_or_button, 'Convert Points to Percents')&lt;br /&gt;
  end&lt;br /&gt;
end &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
All RSpec tests are passing for the current implementation as is evident by the passing Travis CI build.&lt;br /&gt;
&lt;br /&gt;
== Manual Testing ==&lt;br /&gt;
In order to test the functionality manually, we follow the following steps: &amp;lt;br \&amp;gt;&lt;br /&gt;
1. Create a new assignment with 15% as a conflict threshold limit. &amp;lt;br /&amp;gt;&lt;br /&gt;
2. Add 4 students to the assignment and divide them into 2 teams of 2 students in each. &amp;lt;br /&amp;gt;&lt;br /&gt;
3. Add submission for each team. &amp;lt;br /&amp;gt;&lt;br /&gt;
4. In the review phase, login to the first team student accounts and give scores of 100% and 50% to the second team's assignment. &amp;lt;br /&amp;gt;&lt;br /&gt;
5. Since the scores differ by more than 15% the email will be sent to the instructor. &amp;lt;br /&amp;gt;&lt;br /&gt;
6. Access the email and check if the email contains the following details: &amp;lt;br /&amp;gt;&lt;br /&gt;
* Names of the reviewer and reviewee&lt;br /&gt;
* Link to the conflicting review&lt;br /&gt;
* Link to the newly created report view corresponding to the conflict&lt;br /&gt;
* Link to edit the assignment notification limit&lt;br /&gt;
7. View the conflict report and ensure that Team 2 shows up as having a conflicting review submitted by student 2 of Team 1.&lt;br /&gt;
&lt;br /&gt;
= Files Changed =&lt;br /&gt;
1. app/assets/javascripts/conflict_report.js[https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/app/assets/javascripts/conflict_report.js] &amp;lt;br&amp;gt;&lt;br /&gt;
2. app/controllers/response_controller.rb[https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/app/controllers/response_controller.rb] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Useful Links =&lt;br /&gt;
&lt;br /&gt;
'''Github:''' https://github.com/sid189/expertiza/tree/beta &amp;lt;br /&amp;gt;&lt;br /&gt;
'''Pull Request:''' https://github.com/expertiza/expertiza/pull/1714&lt;br /&gt;
&lt;br /&gt;
= Team Information =&lt;br /&gt;
&lt;br /&gt;
'''Project Mentor:'''&lt;br /&gt;
&amp;lt;br&amp;gt;Pratik Abhyankar&lt;br /&gt;
&lt;br /&gt;
'''Project Members:'''&amp;lt;br&amp;gt;&lt;br /&gt;
Sahil Papalkar&amp;lt;br&amp;gt;&lt;br /&gt;
Sahil Mehta&amp;lt;br&amp;gt;&lt;br /&gt;
Siddharth Deshpande&amp;lt;br&amp;gt;&lt;br /&gt;
Carl Klier&amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Shmehta</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2015._Conflict_notification&amp;diff=134024</id>
		<title>CSC/ECE 517 Spring 2020 - E2015. Conflict notification</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2015._Conflict_notification&amp;diff=134024"/>
		<updated>2020-04-25T00:44:23Z</updated>

		<summary type="html">&lt;p&gt;Shmehta: /* Files Changed */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
Expertiza is an open-source project written using the Ruby on Rails framework.  The Expertiza platform aims to improve student learning by using active and cooperative learning, allowing distance education students to participate in active learning, and by discouraging plagiarism through the use of multiple deadlines. Expertiza helps to improve teaching and resource utilization by having students contribute to the creation of course materials and through peer-graded assignments. Expertiza manages objects related to a course such as instructors, TAs, students, and other users. It also manages assignments, teams, signup topics, rubrics, peer grading, and peer evaluations.&lt;br /&gt;
&lt;br /&gt;
== Reports Background ==&lt;br /&gt;
Students can form teams in Expertiza to work on an assignment in a group. Submissions made on Expertiza can be peer-reviewed by students within the course based on a rubric. Results of the peer review can be accessed by instructors and respective student teams in the form of statistical reports. The students have access to view their feedback in the form of a Summary Report. The student Summary Report shows the scores submitted by the reviewers for each question of the rubric for that assignment. If there are more than one round, it shows the scores separated by round number. The instructors have more options to view student submitted feedback in the form of Reviewees Summary Reports which shows the average review scores for an assignment for each round with each reviewer's comments, and Review Reports which shows what teams' assignment were reviewed by each student.&lt;br /&gt;
&lt;br /&gt;
== Review Conflict Background ==&lt;br /&gt;
In the current implementation, during the peer review phase of an assignment, email notifications are sent out to the instructor whenever a submitted review score differs “significantly” from the average score of other submitted reviews for that submission. The threshold to trigger a notification is specified in the “Notification limit” on the Rubrics tab of assignment creation. The email that gets sent to instructors contains three links: a link to the conflicting review, a link to the summary page of grades for the reviewee, and a link to edit the assignment.&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
When a review is submitted that triggers a conflict, an email gets sent to instructors that contains three links: a link to the conflicting review, a link to the summary page of grades for the reviewee, and a link to edit the assignment. Although the links sent in the email are helpful for reference, the process of examining a conflicting review could be made more efficient if we provide an easy to understand report of the conflicts. The information sent in the email should be updated to contain a link to a report page which should contain more details about the newest conflict as well as information on previous review conflicts for the assignment. The conflict report page should have an easy to understand visualization showing the assignment's reviews with scores that cause a conflict.&lt;br /&gt;
&lt;br /&gt;
= Existing Implementation =&lt;br /&gt;
The existing system has the following implementation for conflict notification. On submitting a new review for a particular artifact, the submitted score is compared to the average score of the previously submitted reviews. If the difference between the average score and the newly submitted score is more than the notification threshold specified for the assignment, an email is sent out to the instructor. The email sent to the instructor contains the names of the reviewer and reviewee and a link to the conflicting review, a link to the summary of review responses, and a link to edit the assignment. The flowchart below delineates the entire process:&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
[[File:Conflictflowchart.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
== Problems with Existing Implementation ==&lt;br /&gt;
The existing implementation has the following flaws:&lt;br /&gt;
&lt;br /&gt;
=== No dedicated report for analyzing the conflict ===&lt;br /&gt;
The current implementation does not provide any dedicated view or report containing a detailed analysis of the conflicts that occur during the entire review period. The link to the conflicting review is helpful, but doesn't provide any context for for why that review was in conflict. The link to the summary of review responses provides more insight into how the assignment is being scored overall, but it doesn't provide a clear picture of which reviews are in conflict and have scores that are outliers. &lt;br /&gt;
&lt;br /&gt;
=== Incorrect email URLs ===&lt;br /&gt;
When an review is in conflict and an email gets set to the instructor, the body of the email contains links to the review, review summary page, and a link to edit the assignment. See a copy of the email message below as it is being sent by the current implementation.&lt;br /&gt;
[[File:Conflictemail.png]]&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
The current implementation uses hardcoded URLs mentioned in the &amp;lt;code&amp;gt;notify_instructor_on_difference&amp;lt;/code&amp;gt; method of the &amp;lt;code&amp;gt;models/response.rb&amp;lt;/code&amp;gt; file. See the code:&lt;br /&gt;
&lt;br /&gt;
  conflicting_response_url: 'https://expertiza.ncsu.edu/response/view?id=' + response_id.to_s,&lt;br /&gt;
  summary_url: 'https://expertiza.ncsu.edu/grades/view_team?id=' + reviewee_participant.id.to_s,&lt;br /&gt;
  assignment_edit_url: 'https://expertiza.ncsu.edu/assignments/' + assignment.id.to_s + '/edit'&lt;br /&gt;
&lt;br /&gt;
Being hardcoded, these link would not work in on other servers where Expertiza is running. For example, the links won't be valid if the setup was done on the localhost.&lt;br /&gt;
&lt;br /&gt;
= Previous Work =&lt;br /&gt;
&lt;br /&gt;
The [https://expertiza.csc.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_E1931._Conflict_notification Previous Work] resolved the email related issues and also created a simple UI report page for analyzing the conflict. However, the implementation had quite a few issues that prevented it from being merged:&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
1. The UI for the conflict report included a bar graph that showed the grades of reviews that were in conflict. The information in the bar graph was showing percentages while the scores shown beside it were in raw points. This is an inconsistency; they should display the data in the same units. Also the bar graph contained too much white space and took up too much area on the screen. It was also not obvious from the bar graph which review scores caused a conflict as they were not highlighted or distinguished in any way. See a screenshot of the previous implementation below: [[File:OldConflictGraph.PNG|center]] &amp;lt;br /&amp;gt;&lt;br /&gt;
2. The code for the conflict report view included a lot of logic. &amp;lt;br /&amp;gt;&lt;br /&gt;
3. There was minimal effort spent on refactoring test cases and the test cases added in the pull request were shallow tests, meaning that they simply asserted that the expected value was not empty rather than the correct way of asserting the expected value matched a specific value. &amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Design of New Implementation =&lt;br /&gt;
== Proposed Solution ==&lt;br /&gt;
As the mailing functionality was implemented perfectly in the previous implementation, we plan to use their implementation as our starting point. Building on top of it, we plan to address the highlighted issues with the previous implementation and refactor the conflict report so that it is able to provide better insights into the review conflicts.&lt;br /&gt;
Once the existing code determines that a conflict has occurred, the code will create a report view for the conflict. The report view will contain all the relevant statistics(mean, max, standard deviation, etc.) of all the reviews received for the submission. Next, a URL for the report page will be added to the email body. All URLs in the email will be relative URLs and therefore the URLs will be valid on all servers. Following files need to be updated in order to implement these changes:   &lt;br /&gt;
&lt;br /&gt;
*Related to Email:&lt;br /&gt;
**&amp;lt;code&amp;gt;app/mailers/mailer.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Modify method &amp;lt;code&amp;gt;notify_grade_conflict_message&amp;lt;/code&amp;gt; to add the link to the conflict report in the email body.&lt;br /&gt;
**&amp;lt;code&amp;gt;app/models/response.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Modify method &amp;lt;code&amp;gt;notify_instructor_on_difference&amp;lt;/code&amp;gt; to add a relative links to various pages that get included in the email body.&lt;br /&gt;
**&amp;lt;code&amp;gt;app/views/mailer/notify_grade_conflict_message.html.erb&amp;lt;/code&amp;gt; &lt;br /&gt;
*** Modify the html to add a link to the email message using which the conflict report viewed.&lt;br /&gt;
**&amp;lt;code&amp;gt;app/controllers/response_contrller.rb&amp;lt;/code&amp;gt; &lt;br /&gt;
*** Modify &amp;lt;code&amp;gt;update&amp;lt;/code&amp;gt; method to add &amp;lt;code&amp;gt;request.base_url&amp;lt;/code&amp;gt; as a param sent to &amp;lt;code&amp;gt;notify_instructor_on_difference&amp;lt;/code&amp;gt; method&lt;br /&gt;
*** Modify &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method to add &amp;lt;code&amp;gt;request.base_url&amp;lt;/code&amp;gt; as a param sent to &amp;lt;code&amp;gt;notify_instructor_on_difference&amp;lt;/code&amp;gt; method&lt;br /&gt;
	&lt;br /&gt;
*Related to the conflict report view:&lt;br /&gt;
**&amp;lt;code&amp;gt;app/views/reports/_searchbox.html.erb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Modify the html to add the option to view a conflict report.&lt;br /&gt;
**&amp;lt;code&amp;gt;app/views/reports/response_report.html.haml&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Modify the html to render the conflict report partial if the option to view a conflict report was selected.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
What we need to create:&lt;br /&gt;
*Related to the conflict report view:&lt;br /&gt;
**&amp;lt;code&amp;gt;App/views/reports/_conflict_report.html.erb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Need to create this entire file to make the view for a conflict report&lt;br /&gt;
**&amp;lt;code&amp;gt;app/helpers/report_formatter_helper.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Need to add a method &amp;lt;code&amp;gt;conflict_reponse_map&amp;lt;/code&amp;gt; to make specific instance variables available to our conflict report view. This method will get called from the ReportsController. &lt;br /&gt;
**&amp;lt;code&amp;gt;app/helpers/summary_helper.rb&amp;lt;/code&amp;gt; &lt;br /&gt;
*** Need to add a method to get the maximum possible score of an assignment in each round&lt;br /&gt;
**&amp;lt;code&amp;gt;app/models/answer.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
*** Need to add a method to get the answers from a review for an assignment submitted by a specific reviewer.&lt;br /&gt;
**&amp;lt;code&amp;gt;app/helpers/review_mapping_helper.rb&amp;lt;/code&amp;gt; &lt;br /&gt;
*** Need to add methods to get the review scores for a team in each round, calculate the average review score for a round, calculate the std. deviation of review scores for each round, and get the team members of each team. Apart from these any other method to find and calculate data to be viewed in the report can be added to this helper file.	&lt;br /&gt;
	&lt;br /&gt;
&lt;br /&gt;
The conflict report view should:&lt;br /&gt;
*For each team that had a submission with a review that was in a conflict:&lt;br /&gt;
**List the team name and team members&lt;br /&gt;
**Provide a graphical view of the statistics displayed in the report&lt;br /&gt;
**For each round where there was a review in conflict:&lt;br /&gt;
***List and highlight the students who's review caused a conflict and the score they gave&lt;br /&gt;
***List the threshold for conflict review score, max review score, average review score, and standard deviation. &amp;lt;br \&amp;gt;&amp;lt;br \&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order to resolve the issues with the previous team's pull request, we will:&amp;lt;br \&amp;gt;&lt;br /&gt;
1. Not include any unnecessary bar charts with redundant information in our conflict report view.&amp;lt;br \&amp;gt;&lt;br /&gt;
2. Put the necessary logic into helper methods in helper files to ensure logic stays out of our views.&amp;lt;br \&amp;gt;&lt;br /&gt;
3. Replace the logic used in the review_mapping_helper.rb file to fetch the team member of a specific team. &amp;lt;br \&amp;gt;&lt;br /&gt;
4. Refactor the necessary affected test cases and write new RSpec tests in accordance with our proposed test plan to ensure adequate coverage.&amp;lt;br \&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== UML Diagrams ==&lt;br /&gt;
=== Use Case Diagram ===&lt;br /&gt;
The usecase diagram highlights the simple workflow of the proposed system when trigger by the user.&amp;lt;br /&amp;gt;&lt;br /&gt;
[[File:usecase-1.png]]&lt;br /&gt;
&amp;lt;br /&amp;gt; &amp;lt;br /&amp;gt;&lt;br /&gt;
Actors participating:&lt;br /&gt;
&lt;br /&gt;
* Student: In this use case, fills out the reviews for different projects submitted by the peers.&lt;br /&gt;
* TA/Instructor: In this use case, goes over the conflicting review submitted by the students for the same project.&lt;br /&gt;
&lt;br /&gt;
=== Sequence Diagram ===&lt;br /&gt;
The sequence diagram models the interactions that will take place between various components of the system for the above use-case. &lt;br /&gt;
&amp;lt;br /&amp;gt; &amp;lt;br /&amp;gt;&lt;br /&gt;
[[File:conflictSeq.jpg]]&lt;br /&gt;
&lt;br /&gt;
= New Implementation =&lt;br /&gt;
As per the plan stated in the above section, following changes were implemented:&lt;br /&gt;
&lt;br /&gt;
= Testing =&lt;br /&gt;
Both manual testing and RSpec testing were used to test the new functionalities. &lt;br /&gt;
=== RSpec Testing ===&lt;br /&gt;
In order to test the changes implemented in the model, controller and helper file new RSpec tests have been added. &lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
'''1. Add a new test to &amp;lt;code&amp;gt;spec/controllers/reports_controller_spec.rb&amp;lt;/code&amp;gt;''' &amp;lt;br /&amp;gt;&lt;br /&gt;
The test checks if the new review conflict report is routed and rendered properly by the response controller.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: green&amp;quot;&amp;gt;&lt;br /&gt;
    describe '#review_conflict_response_map' do&lt;br /&gt;
      context 'when type is ReviewConflictResponseMap' do&lt;br /&gt;
        it 'renders response_report page with corresponding data' do&lt;br /&gt;
          allow(TeammateReviewResponseMap).to receive(:teammate_response_report)&lt;br /&gt;
            .with('1')&lt;br /&gt;
            .and_return([participant, participant2])&lt;br /&gt;
          params = {&lt;br /&gt;
              id: 1,&lt;br /&gt;
              report: {type: 'ReviewConflictResponseMap'},&lt;br /&gt;
              user: 'no one'&lt;br /&gt;
          }&lt;br /&gt;
          get :response_report, params&lt;br /&gt;
          expect(response).to render_template(:response_report)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. Add a new test to &amp;lt;code&amp;gt;spec/models/answer_spec.rb&amp;lt;/code&amp;gt;''' &amp;lt;br /&amp;gt;&lt;br /&gt;
This tests if the query in the newly added method 'answers_by_round_for_reviewee' works properly and fetches a valid result.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: green&amp;quot;&amp;gt;&lt;br /&gt;
    it &amp;quot;returns answers by reviewer for reviewee in round from db which is not empty&amp;quot; do&lt;br /&gt;
      expect(Answer.answers_by_round_for_reviewee(@assignment_id, @reviewee_id,@round)).not_to be_empty&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''3. Create and add a new tests to &amp;lt;code&amp;gt;spec/helpers/review_mapping_helper_spec.rb&amp;lt;/code&amp;gt;''' &amp;lt;br /&amp;gt;&lt;br /&gt;
This file tests various calculations performed by the newly added helper methods. The results of these calculations are not only used to display on the report but also used to generate the graph. &lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: green&amp;quot;&amp;gt;&lt;br /&gt;
describe &amp;quot;ReviewMappingHelper&amp;quot; do&lt;br /&gt;
  describe &amp;quot;#review_score_helper_for_team&amp;quot; do&lt;br /&gt;
    before(:each) do&lt;br /&gt;
      @review_answers = [{'reviewer_id': '2', 'answer': 54}, {'reviewer_id': '1', 'answer': 24}, {'reviewer_id': '2', 'answer': 25}]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;The review_score_helper_for_team method calculates the total review scores for each review&amp;quot; do&lt;br /&gt;
      question_answers = helper.review_score_helper_for_team(@review_answers)&lt;br /&gt;
      expect(question_answers).to include('1' =&amp;gt; 24,'2' =&amp;gt; 79)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe &amp;quot;#get_score_metrics&amp;quot; do&lt;br /&gt;
    before(:each) do&lt;br /&gt;
      @review_scores = {'1' =&amp;gt; 50, '2' =&amp;gt; 40, '3' =&amp;gt; 60}&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;The get_score_metrics method calculates various metrics used in the conflict report&amp;quot; do&lt;br /&gt;
      metric = helper.get_score_metrics(@review_scores, 50)&lt;br /&gt;
      expect(metric[:average]).to eq 50.0&lt;br /&gt;
      expect(metric[:std]).to eq 8.16&lt;br /&gt;
      expect(metric[:upper_tolerance_limit]).to eq 50&lt;br /&gt;
      expect(metric[:lower_tolerance_limit]).to eq 33.68&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''4. Add new test in &amp;lt;code&amp;gt;spec/features/review_mapping_helper_spec.rb&amp;lt;/code&amp;gt;''' &amp;lt;br /&amp;gt;&lt;br /&gt;
This UI test navigates to the conflict report page and tests if the report is rendered properly.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: green&amp;quot;&amp;gt;&lt;br /&gt;
describe &amp;quot;Test Review conflict report&amp;quot; do&lt;br /&gt;
  before(:each) do&lt;br /&gt;
    create(:instructor)&lt;br /&gt;
    create(:assignment, course: nil, name: 'Test Assignment')&lt;br /&gt;
    assignment_id = Assignment.where(name: 'Test Assignment')[0].id&lt;br /&gt;
    login_as 'instructor6'&lt;br /&gt;
    visit &amp;quot;/reports/response_report?id=#{assignment_id}&amp;quot;&lt;br /&gt;
    page.select(&amp;quot;Review conflict report&amp;quot;, :from =&amp;gt; &amp;quot;report[type]&amp;quot;)&lt;br /&gt;
    click_button &amp;quot;View&amp;quot;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  # Check if the page renders&lt;br /&gt;
&lt;br /&gt;
  it &amp;quot;has a conflicting review table&amp;quot; do&lt;br /&gt;
    expect(page).to have_css('table')&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it &amp;quot;can display teams&amp;quot; do&lt;br /&gt;
    expect(page).to have_content('Team')&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it &amp;quot;can display author reviewers and metrics&amp;quot; do&lt;br /&gt;
    expect(page).to have_selector(:link_or_button, 'Convert Points to Percents')&lt;br /&gt;
  end&lt;br /&gt;
end &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
All RSpec tests are passing for the current implementation as is evident by the passing Travis CI build.&lt;br /&gt;
&lt;br /&gt;
== Manual Testing ==&lt;br /&gt;
In order to test the functionality manually, we follow the following steps: &amp;lt;br \&amp;gt;&lt;br /&gt;
1. Create a new assignment with 15% as a conflict threshold limit. &amp;lt;br /&amp;gt;&lt;br /&gt;
2. Add 4 students to the assignment and divide them into 2 teams of 2 students in each. &amp;lt;br /&amp;gt;&lt;br /&gt;
3. Add submission for each team. &amp;lt;br /&amp;gt;&lt;br /&gt;
4. In the review phase, login to the first team student accounts and give scores of 100% and 50% to the second team's assignment. &amp;lt;br /&amp;gt;&lt;br /&gt;
5. Since the scores differ by more than 15% the email will be sent to the instructor. &amp;lt;br /&amp;gt;&lt;br /&gt;
6. Access the email and check if the email contains the following details: &amp;lt;br /&amp;gt;&lt;br /&gt;
* Names of the reviewer and reviewee&lt;br /&gt;
* Link to the conflicting review&lt;br /&gt;
* Link to the newly created report view corresponding to the conflict&lt;br /&gt;
* Link to edit the assignment notification limit&lt;br /&gt;
7. View the conflict report and ensure that Team 2 shows up as having a conflicting review submitted by student 2 of Team 1.&lt;br /&gt;
&lt;br /&gt;
= Files Changed =&lt;br /&gt;
1. app/assets/javascripts/conflict_report.js[https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/app/assets/javascripts/conflict_report.js] &lt;br /&gt;
2. app/controllers/response_controller.rb[https://github.com/expertiza/expertiza/blob/d90830993d97df152d932cee7fd5df6be8df26f9/app/controllers/response_controller.rb]&lt;br /&gt;
&lt;br /&gt;
= Useful Links =&lt;br /&gt;
&lt;br /&gt;
'''Github:''' https://github.com/sid189/expertiza/tree/beta &amp;lt;br /&amp;gt;&lt;br /&gt;
'''Pull Request:''' https://github.com/expertiza/expertiza/pull/1714&lt;br /&gt;
&lt;br /&gt;
= Team Information =&lt;br /&gt;
&lt;br /&gt;
'''Project Mentor:'''&lt;br /&gt;
&amp;lt;br&amp;gt;Pratik Abhyankar&lt;br /&gt;
&lt;br /&gt;
'''Project Members:'''&amp;lt;br&amp;gt;&lt;br /&gt;
Sahil Papalkar&amp;lt;br&amp;gt;&lt;br /&gt;
Sahil Mehta&amp;lt;br&amp;gt;&lt;br /&gt;
Siddharth Deshpande&amp;lt;br&amp;gt;&lt;br /&gt;
Carl Klier&amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Shmehta</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2015._Conflict_notification&amp;diff=133037</id>
		<title>CSC/ECE 517 Spring 2020 - E2015. Conflict notification</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2015._Conflict_notification&amp;diff=133037"/>
		<updated>2020-04-08T20:13:49Z</updated>

		<summary type="html">&lt;p&gt;Shmehta: /* Use Case Diagram */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== '''Abstract''' ==&lt;br /&gt;
Expertiza is an open-source web application implemented using Ruby on Rails. It is used for management of courses and the assignments for respective courses, by the faculties and the students. Students can form teams in Expertiza to work on an assignment in a group. A student team can submit their work through multiple means such as file uploads and embedded links. Submissions made on Expertiza can be peer-reviewed by students within the course based on a rubric. Results of the peer review can be accessed by instructors and respective student teams. During the peer evaluation, Expertiza sends appropriate email notifications to the instructor and also provides a complete statistical report of the evaluation.&lt;br /&gt;
&lt;br /&gt;
== '''Problem Statement''' ==&lt;br /&gt;
In the current implementation, during the peer review phase of an assignment, email notifications are sent out to the instructor whenever a submitted review score differs “significantly” from the average score of other submitted reviews for that submission. The threshold to trigger a notification is specified in the “Notification limit” on the Rubrics tab of assignment creation. The email that gets sent to instructors contains three links: a link the the conflicting review, a link the the summary page of grades for the reviewee, and a link to edit the assignment. Although the links sent in the email are helpful for reference, the process of examining a conflicting review could be made more efficient if we provide an easy to understand report of the conflict. The information sent in the email should be updated to contain a link to a report page which should contain more details about the conflict. In addition to creating a new conflict report page, we also want to change the algorithm to detect and trigger a notification if there is a significant difference between a submitted review and any previous submitted review for that assignment. Rather than compare the review score to the average of all review scores, an email should be sent whenever two review scores differ significantly for the same submission.&lt;br /&gt;
&lt;br /&gt;
== '''Existing Implementation''' ==&lt;br /&gt;
On submitting a new review for a particular artifact, the submitted score is compared to the average score of the previously submitted reviews. If the difference between the average score and the newly submitted score is more than the notification threshold specified for the assignment an email is sent out to the instructor. The flowchart below delineates the entire process:&lt;br /&gt;
&lt;br /&gt;
[[File:Flowwork.PNG|center]]&lt;br /&gt;
&lt;br /&gt;
== '''Design''' ==&lt;br /&gt;
=== Proposed Solution ===&lt;br /&gt;
&lt;br /&gt;
What we need to modify:&lt;br /&gt;
*Related to Email:&lt;br /&gt;
**App/mailers/mailer.rb in method notify_grade_conflict_message to make the link to the conflict report available in the email.&lt;br /&gt;
**App/models/response.rb in method notify_instructor_on_difference to add a link to the conflict report that gets sent to the mailer.&lt;br /&gt;
**App/views/mailer/notify_grade_conflict_message.html.erb to add to the message a link to view the conflict report.&lt;br /&gt;
	&lt;br /&gt;
*Related to the conflict report view:&lt;br /&gt;
**App/views/reports/_searchbox.html.erb to add the option to view a conflict report.&lt;br /&gt;
**App/views/reports/response_report.html.haml to render the conflict report partial if the option to view a conflict report was selected. &lt;br /&gt;
	&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
What we need to create:&lt;br /&gt;
*Related to the conflict report view:&lt;br /&gt;
**App/views/reports/_conflict_report.html.erb to make the view for a conflict report&lt;br /&gt;
	&lt;br /&gt;
&lt;br /&gt;
The conflict report view should:&lt;br /&gt;
*For each team that had a submission with a review that was in conflict:&lt;br /&gt;
**List the team name and team members&lt;br /&gt;
**Provide a graphical view of the statistics displayed in the report&lt;br /&gt;
**For each round where there was a review in conflict:&lt;br /&gt;
***List the students who's review caused a conflict and the score they gave&lt;br /&gt;
***List the threshold for conflict review score, max review score, average review score, and standard deviation.&lt;br /&gt;
&lt;br /&gt;
=== Why we chose this approach? ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Use Case Diagram ===&lt;br /&gt;
[[File:usecase-1.png]]&lt;br /&gt;
&lt;br /&gt;
Actors participating:&lt;br /&gt;
&lt;br /&gt;
* Student: In this use case, fills out the reviews for different projects submitted by the peers.&lt;br /&gt;
* TA/Instructor: In this use case, goes over the conflicting review submitted by the students for the same project.&lt;br /&gt;
&lt;br /&gt;
== '''Testing''' ==&lt;br /&gt;
=== Test Plan ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== '''Useful Links''' ==&lt;br /&gt;
&lt;br /&gt;
'''Github:''' https://github.com/sid189/expertiza/tree/beta &amp;lt;br /&amp;gt;&lt;br /&gt;
'''Pull Request:''' https://github.com/expertiza/expertiza/pull/1714&lt;br /&gt;
&lt;br /&gt;
== '''Team Information''' ==&lt;br /&gt;
&lt;br /&gt;
'''Project Mentor:'''&lt;br /&gt;
&amp;lt;br&amp;gt;Pratik Abhyankar&lt;br /&gt;
&lt;br /&gt;
'''Project Members:'''&amp;lt;br&amp;gt;&lt;br /&gt;
Sahil Papalkar&amp;lt;br&amp;gt;&lt;br /&gt;
Sahil Mehta&amp;lt;br&amp;gt;&lt;br /&gt;
Siddharth Deshpande&amp;lt;br&amp;gt;&lt;br /&gt;
Carl Klier&amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Shmehta</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Usecase-1.png&amp;diff=133030</id>
		<title>File:Usecase-1.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Usecase-1.png&amp;diff=133030"/>
		<updated>2020-04-08T20:01:16Z</updated>

		<summary type="html">&lt;p&gt;Shmehta: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Shmehta</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC517_(Spring_2020)_-_E2010._Refactor_criterion.rb&amp;diff=132325</id>
		<title>CSC517 (Spring 2020) - E2010. Refactor criterion.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC517_(Spring_2020)_-_E2010._Refactor_criterion.rb&amp;diff=132325"/>
		<updated>2020-03-31T08:58:31Z</updated>

		<summary type="html">&lt;p&gt;Shmehta: /* Manual Testing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= E2010 Refactor criterion.rb =&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project.&lt;br /&gt;
&lt;br /&gt;
== About Expertiza ==&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source project based on [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create new assignments and customize new or existing assignments. It also allows the instructor to create a list of topics the students can sign up for. Students can form teams in Expertiza to work on various projects and assignments. Students can also peer review other students' submissions. Expertiza supports submission across various document types, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
The criterion.rb model consists of functions that decide what to display while creating, editing and viewing the questionnaires depending on whether the user is an instructor, a teaching assistant or a student. So, this file consists of a lot of HTML code that is rendered to the final questionnaire view. &lt;br /&gt;
&lt;br /&gt;
The current version of this controller has four methods, but two methods are very long and would require refactoring. The primary problem with these functions is that it consists of many statements of string concatenation. The HTML code which is rendered to the final view is made up of concatenations. &lt;br /&gt;
&lt;br /&gt;
Another issue with the code is that the branch conditions size for the complete and the view_completed_question method is very high. Also, this controller has very few comments. They are specifically needed to differentiate between the purpose of numerous nested branches from each other.&lt;br /&gt;
&lt;br /&gt;
== About criterion.rb ==&lt;br /&gt;
The ''criterion.rb'' model consists of functions that decide what to display while creating, editing and viewing the questionnaires depending on whether the user is an instructor, a teaching assistant or a student. So this file consists of a lot of HTML code that is rendered to the final questionnaire view.&lt;br /&gt;
&lt;br /&gt;
For this project, we have to deal with the following two methods:&lt;br /&gt;
* The '''''complete''''' method, which is 104 lines long. this method returns the display for the students when they are filling the questionnaire. It includes the advice given for different questions, dropdown options to rate a project based on the question, a textarea to enter comments and so on.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def complete(count, answer = nil, questionnaire_min, questionnaire_max, dropdown_or_scale)&lt;br /&gt;
    if self.size.nil?&lt;br /&gt;
      cols = '70'&lt;br /&gt;
      rows = '1'&lt;br /&gt;
    else&lt;br /&gt;
      cols = self.size.split(',')[0]&lt;br /&gt;
      rows = self.size.split(',')[1]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    html = '&amp;lt;div&amp;gt;&amp;lt;label for=&amp;quot;responses_' + count.to_s + '&amp;quot;&amp;gt;' + self.txt + '&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;'&lt;br /&gt;
    # show advice for each criterion question&lt;br /&gt;
    question_advices = QuestionAdvice.where(question_id: self.id).sort_by(&amp;amp;:id)&lt;br /&gt;
    advice_total_length = 0&lt;br /&gt;
&lt;br /&gt;
    question_advices.each do |question_advice|&lt;br /&gt;
      advice_total_length += question_advice.advice.length if question_advice.advice &amp;amp;&amp;amp; question_advice.advice != &amp;quot;&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if !question_advices.empty? and advice_total_length &amp;gt; 0&lt;br /&gt;
      html += '&amp;lt;a id=&amp;quot;showAdivce_' + self.id.to_s + '&amp;quot; onclick=&amp;quot;showAdvice(' + self.id.to_s + ')&amp;quot;&amp;gt;Show advice&amp;lt;/a&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;script&amp;gt;'&lt;br /&gt;
      html += 'function showAdvice(i){'&lt;br /&gt;
      html += 'var element = document.getElementById(&amp;quot;showAdivce_&amp;quot; + i.toString());'&lt;br /&gt;
      html += 'var show = element.innerHTML == &amp;quot;Hide advice&amp;quot;;'&lt;br /&gt;
      html += 'if (show){'&lt;br /&gt;
      html += 'element.innerHTML=&amp;quot;Show advice&amp;quot;;'&lt;br /&gt;
      html += '}else{'&lt;br /&gt;
      html += 'element.innerHTML=&amp;quot;Hide advice&amp;quot;;}'&lt;br /&gt;
      html += 'toggleAdvice(i);}'&lt;br /&gt;
&lt;br /&gt;
      html += 'function toggleAdvice(i) {'&lt;br /&gt;
      html += 'var elem = document.getElementById(i.toString() + &amp;quot;_myDiv&amp;quot;);'&lt;br /&gt;
      html += 'if (elem.style.display == &amp;quot;none&amp;quot;) {'&lt;br /&gt;
      html += 'elem.style.display = &amp;quot;&amp;quot;;'&lt;br /&gt;
      html += '} else {'&lt;br /&gt;
      html += 'elem.style.display = &amp;quot;none&amp;quot;;}}'&lt;br /&gt;
      html += '&amp;lt;/script&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;div id=&amp;quot;' + self.id.to_s + '_myDiv&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;'&lt;br /&gt;
      # [2015-10-26] Zhewei:&lt;br /&gt;
      # best to order advices high to low, e.g., 5 to 1&lt;br /&gt;
      # each level used to be a link;&lt;br /&gt;
      # clicking on the link caused the dropbox to be filled in with the corresponding number&lt;br /&gt;
      question_advices.reverse.each_with_index do |question_advice, index|&lt;br /&gt;
        html += '&amp;lt;a id=&amp;quot;changeScore_&amp;gt;' + self.id.to_s + '&amp;quot; onclick=&amp;quot;changeScore(' + count.to_s + ',' + index.to_s + ')&amp;quot;&amp;gt;'&lt;br /&gt;
        html += (self.questionnaire.max_question_score - index).to_s + ' - ' + question_advice.advice + '&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;'&lt;br /&gt;
        html += '&amp;lt;script&amp;gt;'&lt;br /&gt;
        html += 'function changeScore(i, j) {'&lt;br /&gt;
        html += 'var elem = jQuery(&amp;quot;#responses_&amp;quot; + i.toString() + &amp;quot;_score&amp;quot;);'&lt;br /&gt;
        html += 'var opts = elem.children(&amp;quot;option&amp;quot;).length;'&lt;br /&gt;
        html += 'elem.val((' + self.questionnaire.max_question_score.to_s + ' - j).toString());}'&lt;br /&gt;
        html += '&amp;lt;/script&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;/div&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if dropdown_or_scale == 'dropdown'&lt;br /&gt;
      current_value = &amp;quot;&amp;quot;&lt;br /&gt;
      current_value += 'data-current-rating =' + answer.answer.to_s if !answer.nil?&lt;br /&gt;
      html += '&amp;lt;div&amp;gt;&amp;lt;select id=&amp;quot;responses_' + count.to_s + '_score&amp;quot; name=&amp;quot;responses[' + count.to_s + '][score]&amp;quot; class=&amp;quot;review-rating&amp;quot; ' + current_value + '&amp;gt;'&lt;br /&gt;
      html += &amp;quot;&amp;lt;option value = ''&amp;gt;--&amp;lt;/option&amp;gt;&amp;quot;&lt;br /&gt;
      questionnaire_min.upto(questionnaire_max).each do |j|&lt;br /&gt;
        html += if !answer.nil? and j == answer.answer&lt;br /&gt;
                  '&amp;lt;option value=' + j.to_s + ' selected=&amp;quot;selected&amp;quot;&amp;gt;'&lt;br /&gt;
                else&lt;br /&gt;
                  '&amp;lt;option value=' + j.to_s + '&amp;gt;'&lt;br /&gt;
                end&lt;br /&gt;
&lt;br /&gt;
        html += j.to_s&lt;br /&gt;
        if j == questionnaire_min&lt;br /&gt;
          html += &amp;quot;-&amp;quot; + self.min_label if self.min_label.present?&lt;br /&gt;
        elsif j == questionnaire_max&lt;br /&gt;
          html += &amp;quot;-&amp;quot; + self.max_label if self.max_label.present?&lt;br /&gt;
        end&lt;br /&gt;
        html += &amp;quot;&amp;lt;/option&amp;gt;&amp;quot;&lt;br /&gt;
      end&lt;br /&gt;
      html += &amp;quot;&amp;lt;/select&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;&lt;br /&gt;
      html += '&amp;lt;textarea' + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
       ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
      html += answer.comments unless answer.nil?&lt;br /&gt;
      html += '&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
    elsif dropdown_or_scale == 'scale'&lt;br /&gt;
      html += '&amp;lt;input id=&amp;quot;responses_' + count.to_s + '_score&amp;quot; name=&amp;quot;responses[' + count.to_s + '][score]&amp;quot; type=&amp;quot;hidden&amp;quot;'&lt;br /&gt;
      html += 'value=&amp;quot;' + answer.answer.to_s + '&amp;quot;' unless answer.nil?&lt;br /&gt;
      html += '&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;table&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;tr&amp;gt;&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      (questionnaire_min..questionnaire_max).each do |j|&lt;br /&gt;
        html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;label&amp;gt;' + j.to_s + '&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += if !self.min_label.nil?&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;' + self.min_label + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
              else&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
              end&lt;br /&gt;
      (questionnaire_min..questionnaire_max).each do |j|&lt;br /&gt;
        html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;input type=&amp;quot;radio&amp;quot; id=&amp;quot;' + j.to_s + '&amp;quot; value=&amp;quot;' + j.to_s + '&amp;quot; name=&amp;quot;Radio_' + self.id.to_s + '&amp;quot;'&lt;br /&gt;
        html += 'checked=&amp;quot;checked&amp;quot;' if (!answer.nil? and answer.answer == j) or (answer.nil? and questionnaire_min == j)&lt;br /&gt;
        html += '&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;script&amp;gt;jQuery(&amp;quot;input[name=Radio_' + self.id.to_s + ']:radio&amp;quot;).change(function() {'&lt;br /&gt;
      html += 'var response_score = jQuery(&amp;quot;#responses_' + count.to_s + '_score&amp;quot;);'&lt;br /&gt;
      html += 'var checked_value = jQuery(&amp;quot;input[name=Radio_' + self.id.to_s + ']:checked&amp;quot;).val();'&lt;br /&gt;
      html += 'response_score.val(checked_value);});&amp;lt;/script&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += if !self.max_label.nil?&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;' + self.max_label + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
              else&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
              end&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;textarea cols=' + cols + ' rows=' + rows + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
        ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
      html += answer.comments unless answer.nil?&lt;br /&gt;
      html += '&amp;lt;/textarea&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    end&lt;br /&gt;
    safe_join([&amp;quot;&amp;quot;.html_safe, &amp;quot;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The '''''view_completed_question''''' method, which is 47 lies long. Thismethod is responsible to return the display if a student is viewingan already filled-out questionnaire.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def view_completed_question(count, answer, questionnaire_max, tag_prompt_deployments = nil, current_user = nil)&lt;br /&gt;
    html = '&amp;lt;b&amp;gt;' + count.to_s + &amp;quot;. &amp;quot; + self.txt + ' [Max points: ' + questionnaire_max.to_s + &amp;quot;]&amp;lt;/b&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    score = answer &amp;amp;&amp;amp; !answer.answer.nil? ? answer.answer.to_s : &amp;quot;-&amp;quot;&lt;br /&gt;
    score_percent = if score != &amp;quot;-&amp;quot;&lt;br /&gt;
                      answer.answer * 1.0 / questionnaire_max&lt;br /&gt;
                    else&lt;br /&gt;
                      0&lt;br /&gt;
                    end&lt;br /&gt;
&lt;br /&gt;
    score_color = if score_percent &amp;gt; 0.8&lt;br /&gt;
                    &amp;quot;c5&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.6&lt;br /&gt;
                    &amp;quot;c4&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.4&lt;br /&gt;
                    &amp;quot;c3&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.2&lt;br /&gt;
                    &amp;quot;c2&amp;quot;&lt;br /&gt;
                  else&lt;br /&gt;
                    &amp;quot;c1&amp;quot;&lt;br /&gt;
                  end&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;table cellpadding=&amp;quot;5&amp;quot;&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;tr&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;div class=&amp;quot;' + score_color + '&amp;quot; style=&amp;quot;width:30px; height:30px;' \&lt;br /&gt;
      ' border-radius:50%; font-size:15px; color:black; line-height:30px; text-align:center;&amp;quot;&amp;gt;'&lt;br /&gt;
    html += score&lt;br /&gt;
    html += '&amp;lt;/div&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;/td&amp;gt;'&lt;br /&gt;
    if answer &amp;amp;&amp;amp; !answer.comments.nil?&lt;br /&gt;
      html += '&amp;lt;td style=&amp;quot;padding-left:10px&amp;quot;&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;br&amp;gt;' + answer.comments.html_safe&lt;br /&gt;
      html += '&amp;lt;/td&amp;gt;'&lt;br /&gt;
      #### start code to show tag prompts ####&lt;br /&gt;
      unless tag_prompt_deployments.nil?&lt;br /&gt;
        # show check boxes for answer tagging&lt;br /&gt;
        resp = Response.find(answer.response_id)&lt;br /&gt;
        question = Question.find(answer.question_id)&lt;br /&gt;
        if tag_prompt_deployments.count &amp;gt; 0&lt;br /&gt;
          html += '&amp;lt;tr&amp;gt;&amp;lt;td colspan=&amp;quot;2&amp;quot;&amp;gt;'&lt;br /&gt;
          tag_prompt_deployments.each do |tag_dep|&lt;br /&gt;
            tag_prompt = TagPrompt.find(tag_dep.tag_prompt_id)&lt;br /&gt;
            if tag_dep.question_type == question.type and answer.comments.length &amp;gt; tag_dep.answer_length_threshold.to_i&lt;br /&gt;
              html += tag_prompt.html_control(tag_dep, answer, current_user)&lt;br /&gt;
            end&lt;br /&gt;
          end&lt;br /&gt;
          html += '&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;'&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      #### end code to show tag prompts ####&lt;br /&gt;
    end&lt;br /&gt;
    html += '&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;'&lt;br /&gt;
    safe_join([&amp;quot;&amp;quot;.html_safe, &amp;quot;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Proposed Solution ==&lt;br /&gt;
Our goal is to refactor the complete and view_completed_question method mainly by reducing the number of lines code for each function and also by introducing new methods to make the code more modular. &lt;br /&gt;
We will also try to reduce the branch condition size wherever possible and hence reduce the cyclomatic complexity for these two functions. &lt;br /&gt;
We also plan to introduce comments wherever needed to make the code more understandable. The main aim is to reduce the number of lines and make the code more compact without affecting the readability of the code.&lt;br /&gt;
* High branch condition size problem: extracting three methods from method &amp;quot;'''complete'''&amp;quot;&lt;br /&gt;
** Method &amp;quot;'''dropdown_criterion_question'''&amp;quot; return html when choosing dropdown options&lt;br /&gt;
** Method &amp;quot;'''scale_criterion_question'''&amp;quot; return html when choosing scale options&lt;br /&gt;
** Method &amp;quot;'''advices_criterion_question'''&amp;quot; return html about showing advice for each criterion question&lt;br /&gt;
* Too long code&lt;br /&gt;
** Combining the short HTML strings into longer ones but not too long&lt;br /&gt;
** Using one readable line of code instead of three or more lines of if-else statements&lt;br /&gt;
* Fix incomplete condition problem &lt;br /&gt;
* Change the language to more Ruby friendly&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
&lt;br /&gt;
We tried to tackle the issues mentioned in the problem statement as described below:&lt;br /&gt;
&lt;br /&gt;
=== The ''complete'' method ===&lt;br /&gt;
* We extracted three methods from &amp;quot;complete&amp;quot; method. &lt;br /&gt;
* We combined the short HTML strings into longer ones. &lt;br /&gt;
* We used the shorthand which beautifully consolidates three or more lines of code (read: if-else statements) into one readable line of code. &lt;br /&gt;
&lt;br /&gt;
====''Examples of changes''====&lt;br /&gt;
'''Extracting three methods to reducing the condition branch'''&lt;br /&gt;
* Method &amp;quot;dropdown_criterion_question&amp;quot; return html when choosing dropdown options&lt;br /&gt;
* Method &amp;quot;scale_criterion_question&amp;quot; return html when choosing scale options&lt;br /&gt;
* Method &amp;quot;advices_criterion_question&amp;quot; return html about showing advice for each criterion question&lt;br /&gt;
&lt;br /&gt;
'''Combining the short HTML strings into longer ones'''&lt;br /&gt;
&lt;br /&gt;
We go from:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
html += &amp;quot;&amp;lt;/select&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;&lt;br /&gt;
html += '&amp;lt;textarea' + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;'&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
html += '&amp;lt;/select&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;textarea' + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;'&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Using one readable line of code instead of three or more lines of if-else statements'''&lt;br /&gt;
&lt;br /&gt;
We go from:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
html += if !answer.nil? and j == answer.answer&lt;br /&gt;
           '&amp;lt;option value=' + j.to_s + ' selected=&amp;quot;selected&amp;quot;&amp;gt;'&lt;br /&gt;
        else&lt;br /&gt;
           '&amp;lt;option value=' + j.to_s + '&amp;gt;'&lt;br /&gt;
        end&lt;br /&gt;
html += j.to_s&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
html += '&amp;lt;option value=' + j.to_s&lt;br /&gt;
html += ' selected=&amp;quot;selected&amp;quot;' if !answer.nil? &amp;amp;&amp;amp; j == answer.answer&lt;br /&gt;
html += '&amp;gt;' + j.to_s&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Use unless for negative conditions'''&lt;br /&gt;
&lt;br /&gt;
We go from:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
current_value += 'data-current-rating =' + answer.answer.to_s if !answer.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
current_value += 'data-current-rating =' + answer.answer.to_s unless answer.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Same change for self.min_label and self.max_label. We go from:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
html += if !self.min_label.nil?&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;' + self.min_label + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
              else&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
              end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;'&lt;br /&gt;
html += self.min_label unless self.min_label.nil?&lt;br /&gt;
html += '&amp;lt;/td&amp;gt;'&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Unsafe condition'''&lt;br /&gt;
&lt;br /&gt;
We added condition to make sure when answer.comments is nil. We go from:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
html += answer.comments unless answer.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
html += answer.comments if !answer.nil? &amp;amp;&amp;amp; !answer.comments.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Incomplete condition'''&lt;br /&gt;
&lt;br /&gt;
When create a new criterion, which size is &amp;quot;&amp;quot; that isn't nil. We add condition to make sure &amp;quot;cols&amp;quot; and &amp;quot;rows&amp;quot; will be assign when &amp;quot;self.size&amp;quot; is &amp;quot;&amp;quot;. We go from:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if self.size.nil?&lt;br /&gt;
   cols = '70'&lt;br /&gt;
   rows = '1'&lt;br /&gt;
else&lt;br /&gt;
   cols = self.size.split(',')[0]&lt;br /&gt;
   rows = self.size.split(',')[1]&lt;br /&gt;
end&lt;br /&gt;
html += '&amp;lt;textarea cols=' + cols + ' rows=' + rows + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
        ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if self.size.nil?||self.size.blank?&lt;br /&gt;
   cols = '70'&lt;br /&gt;
   rows = '1'&lt;br /&gt;
else&lt;br /&gt;
   cols = self.size.split(',')[0]&lt;br /&gt;
   rows = self.size.split(',')[1]&lt;br /&gt;
end&lt;br /&gt;
html += '&amp;lt;textarea cols=' + cols + ' rows=' + rows + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
        ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Ruby grammer'''&lt;br /&gt;
&lt;br /&gt;
We change &amp;quot;and&amp;quot; to &amp;amp;&amp;amp;. We changed from:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
html += 'checked=&amp;quot;checked&amp;quot;' if (!answer.nil? and answer.answer == j) or (answer.nil? and questionnaire_min == j)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
html += 'checked=&amp;quot;checked&amp;quot;' if (!answer.nil? &amp;amp;&amp;amp; answer.answer == j) or (answer.nil? &amp;amp;&amp;amp; questionnaire_min == j)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====''The modified ''complete'' method''====&lt;br /&gt;
* '''Method &amp;quot;complete&amp;quot;'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def complete(count, answer = nil, questionnaire_min, questionnaire_max, dropdown_or_scale)&lt;br /&gt;
    html = '&amp;lt;div&amp;gt;&amp;lt;label for=&amp;quot;responses_' + count.to_s + '&amp;quot;&amp;gt;' + self.txt + '&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;'&lt;br /&gt;
    question_advices = QuestionAdvice.where(question_id: self.id).sort_by(&amp;amp;:id)&lt;br /&gt;
    advice_total_length = 0&lt;br /&gt;
    question_advices.each do |question_advice|&lt;br /&gt;
      advice_total_length += question_advice.advice.length if question_advice.advice &amp;amp;&amp;amp; question_advice.advice != &amp;quot;&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
    #show advice given for different questions&lt;br /&gt;
    html += advices_criterion_question(count, question_advices) if !question_advices.empty? and advice_total_length &amp;gt; 0&lt;br /&gt;
&lt;br /&gt;
    #dropdown options to rate a project based on the quetion&lt;br /&gt;
    html += dropdown_criterion_question(count, answer, questionnaire_min, questionnaire_max) if dropdown_or_scale == 'dropdown'&lt;br /&gt;
&lt;br /&gt;
    #scale optioins&lt;br /&gt;
    html += scale_criterion_question(count, answer, questionnaire_min, questionnaire_max) if dropdown_or_scale == 'scale'&lt;br /&gt;
    safe_join([&amp;quot;&amp;quot;.html_safe, &amp;quot;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* '''Method &amp;quot;advices_criterion_question&amp;quot;'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  # show advice for each criterion question&lt;br /&gt;
  def advices_criterion_question(count, question_advices)&lt;br /&gt;
    html = '&amp;lt;a id=&amp;quot;showAdvice_' + self.id.to_s + '&amp;quot; onclick=&amp;quot;showAdvice(' + self.id.to_s + ')&amp;quot;&amp;gt;Show advice&amp;lt;/a&amp;gt;&amp;lt;script&amp;gt;'&lt;br /&gt;
    html += 'function showAdvice(i){var element = document.getElementById(&amp;quot;showAdivce_&amp;quot; + i.toString());'&lt;br /&gt;
    html += 'var show = element.innerHTML == &amp;quot;Hide advice&amp;quot;;'&lt;br /&gt;
    html += 'if (show){element.innerHTML=&amp;quot;Show advice&amp;quot;;} else{element.innerHTML=&amp;quot;Hide advice&amp;quot;;}toggleAdvice(i);}'&lt;br /&gt;
    html += 'function toggleAdvice(i) {var elem = document.getElementById(i.toString() + &amp;quot;_myDiv&amp;quot;);'&lt;br /&gt;
    html += 'if (elem.style.display == &amp;quot;none&amp;quot;) {elem.style.display = &amp;quot;&amp;quot;;} else {elem.style.display = &amp;quot;none&amp;quot;;}}&amp;lt;/script&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;div id=&amp;quot;' + self.id.to_s + '_myDiv&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;'&lt;br /&gt;
    # [2015-10-26] Zhewei:&lt;br /&gt;
    # best to order advices high to low, e.g., 5 to 1&lt;br /&gt;
    # each level used to be a link;&lt;br /&gt;
    # clicking on the link caused the dropbox to be filled in with the corresponding number&lt;br /&gt;
    question_advices.reverse.each_with_index do |question_advice, index|&lt;br /&gt;
      html += '&amp;lt;a id=&amp;quot;changeScore_&amp;gt;' + self.id.to_s + '&amp;quot; onclick=&amp;quot;changeScore(' + count.to_s + ',' + index.to_s + ')&amp;quot;&amp;gt;'&lt;br /&gt;
      html += (self.questionnaire.max_question_score - index).to_s + ' - ' + question_advice.advice + '&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;script&amp;gt;'&lt;br /&gt;
      html += 'function changeScore(i, j) {var elem = jQuery(&amp;quot;#responses_&amp;quot; + i.toString() + &amp;quot;_score&amp;quot;);'&lt;br /&gt;
      html += 'var opts = elem.children(&amp;quot;option&amp;quot;).length;'&lt;br /&gt;
      html += 'elem.val((' + self.questionnaire.max_question_score.to_s + ' - j).toString());}&amp;lt;/script&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
    html += '&amp;lt;/div&amp;gt;'&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* '''Method &amp;quot;dropdown_criterion_question&amp;quot;'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def dropdown_criterion_question(count, answer = nil, questionnaire_min, questionnaire_max)&lt;br /&gt;
    current_value = &amp;quot;&amp;quot; &lt;br /&gt;
    current_value += 'data-current-rating =' + answer.answer.to_s unless answer.nil?&lt;br /&gt;
    html = '&amp;lt;div&amp;gt;&amp;lt;select id=&amp;quot;responses_' + count.to_s + '_score&amp;quot; name=&amp;quot;responses[' + count.to_s + '][score]&amp;quot; class=&amp;quot;review-rating&amp;quot; ' + current_value + '&amp;gt;'&lt;br /&gt;
    html += &amp;quot;&amp;lt;option value = ''&amp;gt;--&amp;lt;/option&amp;gt;&amp;quot;&lt;br /&gt;
    questionnaire_min.upto(questionnaire_max).each do |j|&lt;br /&gt;
      html += '&amp;lt;option value=' + j.to_s&lt;br /&gt;
      html += ' selected=&amp;quot;selected&amp;quot;' if !answer.nil? &amp;amp;&amp;amp; j == answer.answer&lt;br /&gt;
      html += '&amp;gt;'&lt;br /&gt;
      html += j.to_s&lt;br /&gt;
      html += &amp;quot;-&amp;quot; + self.min_label if self.min_label.present? &amp;amp;&amp;amp; j == questionnaire_min&lt;br /&gt;
      html += &amp;quot;-&amp;quot; + self.max_label if self.max_label.present? &amp;amp;&amp;amp; j == questionnaire_max&lt;br /&gt;
      html += &amp;quot;&amp;lt;/option&amp;gt;&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;/select&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;textarea' + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;'&lt;br /&gt;
    html += ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
    html += answer.comments if !answer.nil? &amp;amp;&amp;amp; !answer.comments.nil?&lt;br /&gt;
    html += '&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* '''Method &amp;quot;scale_criterion_question&amp;quot;'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def scale_criterion_question(count, answer = nil, questionnaire_min, questionnaire_max)&lt;br /&gt;
    if self.size.nil? || !self.size.present?&lt;br /&gt;
      cols = '70'&lt;br /&gt;
      rows = '1'&lt;br /&gt;
    else&lt;br /&gt;
     cols = self.size.split(',')[0]&lt;br /&gt;
     rows = self.size.split(',')[1]&lt;br /&gt;
    end&lt;br /&gt;
    html = '&amp;lt;input id=&amp;quot;responses_' + count.to_s + '_score&amp;quot; name=&amp;quot;responses[' + count.to_s + '][score]&amp;quot; type=&amp;quot;hidden&amp;quot;'&lt;br /&gt;
    html += 'value=&amp;quot;' + answer.answer.to_s + '&amp;quot;' unless answer.nil?&lt;br /&gt;
    html += '&amp;gt;&amp;lt;table&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    (questionnaire_min..questionnaire_max).each do |j|&lt;br /&gt;
      html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;label&amp;gt;' + j.to_s + '&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;'&lt;br /&gt;
    html += self.min_label unless self.min_label.nil?&lt;br /&gt;
    html += '&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    (questionnaire_min..questionnaire_max).each do |j|&lt;br /&gt;
      html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;input type=&amp;quot;radio&amp;quot; id=&amp;quot;' + j.to_s + '&amp;quot; value=&amp;quot;' + j.to_s + '&amp;quot; name=&amp;quot;Radio_' + self.id.to_s + '&amp;quot;'&lt;br /&gt;
      html += 'checked=&amp;quot;checked&amp;quot;' if (!answer.nil? &amp;amp;&amp;amp; answer.answer == j) or (answer.nil? &amp;amp;&amp;amp; questionnaire_min == j)&lt;br /&gt;
      html += '&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
    html += '&amp;lt;script&amp;gt;jQuery(&amp;quot;input[name=Radio_' + self.id.to_s + ']:radio&amp;quot;).change(function() {'&lt;br /&gt;
    html += 'var response_score = jQuery(&amp;quot;#responses_' + count.to_s + '_score&amp;quot;);'&lt;br /&gt;
    html += 'var checked_value = jQuery(&amp;quot;input[name=Radio_' + self.id.to_s + ']:checked&amp;quot;).val();'&lt;br /&gt;
    html += 'response_score.val(checked_value);});&amp;lt;/script&amp;gt;&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;'&lt;br /&gt;
    html += self.max_label unless self.max_label.nil?&lt;br /&gt;
    html += '&amp;lt;/td&amp;gt;&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;textarea cols=' + cols + ' rows=' + rows + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
      ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
    html += answer.comments if !answer.nil? &amp;amp;&amp;amp; !answer.comments.nil?&lt;br /&gt;
    html += '&amp;lt;/textarea&amp;gt;'    &lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The ''view_completed_question&amp;quot; method===&lt;br /&gt;
&lt;br /&gt;
The main task here was to reduce the nested if-else branching and reduce the number of arguments for this function. &lt;br /&gt;
* We reduced the nested if-else branching.&lt;br /&gt;
* We concatenated small HTML string&lt;br /&gt;
* We used shorthand for if-else condition statements. &lt;br /&gt;
&lt;br /&gt;
This was a very small method with its major dependent functions present in response.rb file. To refactor this method, we would have had to refactor response.rb and in turn, the other question subclasses which would make it very complex and break the code. According to us, refactoring this method along with the response.rb file would make more sense. &lt;br /&gt;
&lt;br /&gt;
====''Example of changes''====&lt;br /&gt;
'''Combining the short HTML strings into longer ones'''&lt;br /&gt;
&lt;br /&gt;
We concatenated small HTML which was from:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
html += '&amp;lt;table cellpadding=&amp;quot;5&amp;quot;&amp;gt;'&lt;br /&gt;
html += '&amp;lt;tr&amp;gt;'&lt;br /&gt;
html += '&amp;lt;td&amp;gt;'&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
html += '&amp;lt;table cellpadding=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;'&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Using one readable line of code instead of three or more lines of if-else statements'''&lt;br /&gt;
&lt;br /&gt;
We changed from:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
score_percent = if score != &amp;quot;-&amp;quot;&lt;br /&gt;
                     answer.answer * 1.0 / questionnaire_max&lt;br /&gt;
                else&lt;br /&gt;
                     0&lt;br /&gt;
                end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
score_percent = score != &amp;quot;-&amp;quot; ? answer.answer * 1.0 / questionnaire_max : 0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Delete useless variable - 'resp''''&lt;br /&gt;
&lt;br /&gt;
We deleted this code&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
resp = Response.find(answer.response_id)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Change of language to make it more Ruby friendly'''&lt;br /&gt;
&lt;br /&gt;
We changed from:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if tag_dep.question_type == question.type and answer.comments.length &amp;gt; tag_dep.answer_length_threshold.to_i&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if tag_dep.question_type == question.type &amp;amp;&amp;amp; answer.comments.length &amp;gt; tag_dep.answer_length_threshold.to_i&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Reduce the branch condition'''&lt;br /&gt;
&lt;br /&gt;
We combined condition &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
unless tag_prompt_deployments.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
and&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if tag_prompt_deployments.count &amp;gt; 0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if !tag_prompt_deployments.nil? &amp;amp;&amp;amp; tag_prompt_deployments.count &amp;gt; 0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
  [[File:Multiple_2.png]]&lt;br /&gt;
&lt;br /&gt;
==== The modified ''view_completed_question''====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def view_completed_question(count, answer, questionnaire_max, tag_prompt_deployments = nil, current_user = nil)&lt;br /&gt;
    html = '&amp;lt;b&amp;gt;' + count.to_s + &amp;quot;. &amp;quot; + self.txt + ' [Max points: ' + questionnaire_max.to_s + &amp;quot;]&amp;lt;/b&amp;gt;&amp;quot;&lt;br /&gt;
    score = answer &amp;amp;&amp;amp; !answer.answer.nil? ? answer.answer.to_s : &amp;quot;-&amp;quot;&lt;br /&gt;
    score_percent = score != &amp;quot;-&amp;quot; ? answer.answer * 1.0 / questionnaire_max : 0&lt;br /&gt;
    score_color = if score_percent &amp;gt; 0.8&lt;br /&gt;
                    &amp;quot;c5&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.6&lt;br /&gt;
                    &amp;quot;c4&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.4&lt;br /&gt;
                    &amp;quot;c3&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.2&lt;br /&gt;
                    &amp;quot;c2&amp;quot;&lt;br /&gt;
                  else&lt;br /&gt;
                    &amp;quot;c1&amp;quot;&lt;br /&gt;
                  end&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;table cellpadding=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;div class=&amp;quot;' + score_color + '&amp;quot; style=&amp;quot;width:30px; height:30px;' \&lt;br /&gt;
      ' border-radius:50%; font-size:15px; color:black; line-height:30px; text-align:center;&amp;quot;&amp;gt;'&lt;br /&gt;
    html += score + '&amp;lt;/div&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    if answer &amp;amp;&amp;amp; !answer.comments.nil?&lt;br /&gt;
      html += '&amp;lt;td style=&amp;quot;padding-left:10px&amp;quot;&amp;gt;&amp;lt;br&amp;gt;' + answer.comments.html_safe + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
      #### start code to show tag prompts ####&lt;br /&gt;
      if !tag_prompt_deployments.nil? &amp;amp;&amp;amp; tag_prompt_deployments.count &amp;gt; 0&lt;br /&gt;
        # show check boxes for answer tagging&lt;br /&gt;
        question = Question.find(answer.question_id)&lt;br /&gt;
        html += '&amp;lt;tr&amp;gt;&amp;lt;td colspan=&amp;quot;2&amp;quot;&amp;gt;'&lt;br /&gt;
        tag_prompt_deployments.each do |tag_dep|&lt;br /&gt;
          tag_prompt = TagPrompt.find(tag_dep.tag_prompt_id)&lt;br /&gt;
          if tag_dep.question_type == question.type &amp;amp;&amp;amp; answer.comments.length &amp;gt; tag_dep.answer_length_threshold.to_i&lt;br /&gt;
            html += tag_prompt.html_control(tag_dep, answer, current_user)&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
        html += '&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      #### end code to show tag prompts ####&lt;br /&gt;
    end&lt;br /&gt;
    html += '&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;'&lt;br /&gt;
    safe_join([&amp;quot;&amp;quot;.html_safe, &amp;quot;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Test Plan ==&lt;br /&gt;
&lt;br /&gt;
We are running Rspec tests to make sure the coverage is the same and manually checking the pages to make sure there are not any issues and the code is not breaking&lt;br /&gt;
=== RSpec Testing ===&lt;br /&gt;
The origin test about method &amp;quot;complete&amp;quot; didn't include the situation when the parameter &amp;quot;answer&amp;quot; isn't nil and the parameter &amp;quot;dropdown_or_scale&amp;quot; is &amp;quot;dropdown&amp;quot; or &amp;quot;scale&amp;quot;. We added the test examples from 4 to 16 including the multiple for method &amp;quot;complete&amp;quot;, &amp;quot;dropdown_criterion_question&amp;quot;, &amp;quot;scale_criterion_question&amp;quot;.&lt;br /&gt;
* '''Test for method &amp;quot;complete&amp;quot; with or without answer and dorpdown_or_scale'''&lt;br /&gt;
'''Origin test'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 describe &amp;quot;#complete&amp;quot; do&lt;br /&gt;
    it &amp;quot;returns the html &amp;quot; do&lt;br /&gt;
      html = criterion.complete(0, nil, 0, 5).to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;div&amp;gt;&amp;lt;label for=\&amp;quot;responses_0\&amp;quot;&amp;gt;test txt&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''New test'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe &amp;quot;#complete&amp;quot; do&lt;br /&gt;
    it &amp;quot;returns the html without answer and no dropdown or scale&amp;quot; do&lt;br /&gt;
      html = criterion.complete(0, nil, 0, 5).to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;div&amp;gt;&amp;lt;label for=\&amp;quot;responses_0\&amp;quot;&amp;gt;test txt&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;returns the html without answer and dropdown&amp;quot; do&lt;br /&gt;
      html = criterion.complete(0, nil, 0, 5, dropdown_or_scale = 'dropdown').to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;div&amp;gt;&amp;lt;label for=\&amp;quot;responses_0\&amp;quot;&amp;gt;test txt&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div&amp;gt;&amp;lt;select id=\&amp;quot;responses_0_score\&amp;quot; name=\&amp;quot;responses[0][score]\&amp;quot; class=\&amp;quot;review-rating\&amp;quot; &amp;gt;&amp;lt;option value = ''&amp;gt;--&amp;lt;/option&amp;gt;&amp;lt;option value=0&amp;gt;0&amp;lt;/option&amp;gt;&amp;lt;option value=1&amp;gt;1&amp;lt;/option&amp;gt;&amp;lt;option value=2&amp;gt;2&amp;lt;/option&amp;gt;&amp;lt;option value=3&amp;gt;3&amp;lt;/option&amp;gt;&amp;lt;option value=4&amp;gt;4&amp;lt;/option&amp;gt;&amp;lt;option value=5&amp;gt;5&amp;lt;/option&amp;gt;&amp;lt;/select&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;textarea id=\&amp;quot;responses_0_comments\&amp;quot; name=\&amp;quot;responses[0][comment]\&amp;quot; class=\&amp;quot;tinymce\&amp;quot;&amp;gt;&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;returns the html with no comments answer and answer.answer outside questionnaire min and max and dropdown&amp;quot; do&lt;br /&gt;
      html = criterion.complete(0, answer_no_comments, 0, 5, dropdown_or_scale = 'dropdown').to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;div&amp;gt;&amp;lt;label for=\&amp;quot;responses_0\&amp;quot;&amp;gt;test txt&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div&amp;gt;&amp;lt;select id=\&amp;quot;responses_0_score\&amp;quot; name=\&amp;quot;responses[0][score]\&amp;quot; class=\&amp;quot;review-rating\&amp;quot; data-current-rating =8&amp;gt;&amp;lt;option value = ''&amp;gt;--&amp;lt;/option&amp;gt;&amp;lt;option value=0&amp;gt;0&amp;lt;/option&amp;gt;&amp;lt;option value=1&amp;gt;1&amp;lt;/option&amp;gt;&amp;lt;option value=2&amp;gt;2&amp;lt;/option&amp;gt;&amp;lt;option value=3&amp;gt;3&amp;lt;/option&amp;gt;&amp;lt;option value=4&amp;gt;4&amp;lt;/option&amp;gt;&amp;lt;option value=5&amp;gt;5&amp;lt;/option&amp;gt;&amp;lt;/select&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;textarea id=\&amp;quot;responses_0_comments\&amp;quot; name=\&amp;quot;responses[0][comment]\&amp;quot; class=\&amp;quot;tinymce\&amp;quot;&amp;gt;&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;returns the html with comments answer and answer.answer between questionnaire min and max and dropdown&amp;quot; do&lt;br /&gt;
      html = criterion.complete(0, answer_comments, 0, 5, dropdown_or_scale = 'dropdown').to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;div&amp;gt;&amp;lt;label for=\&amp;quot;responses_0\&amp;quot;&amp;gt;test txt&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div&amp;gt;&amp;lt;select id=\&amp;quot;responses_0_score\&amp;quot; name=\&amp;quot;responses[0][score]\&amp;quot; class=\&amp;quot;review-rating\&amp;quot; data-current-rating =3&amp;gt;&amp;lt;option value = ''&amp;gt;--&amp;lt;/option&amp;gt;&amp;lt;option value=0&amp;gt;0&amp;lt;/option&amp;gt;&amp;lt;option value=1&amp;gt;1&amp;lt;/option&amp;gt;&amp;lt;option value=2&amp;gt;2&amp;lt;/option&amp;gt;&amp;lt;option value=3 selected=\&amp;quot;selected\&amp;quot;&amp;gt;3&amp;lt;/option&amp;gt;&amp;lt;option value=4&amp;gt;4&amp;lt;/option&amp;gt;&amp;lt;option value=5&amp;gt;5&amp;lt;/option&amp;gt;&amp;lt;/select&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;textarea id=\&amp;quot;responses_0_comments\&amp;quot; name=\&amp;quot;responses[0][comment]\&amp;quot; class=\&amp;quot;tinymce\&amp;quot;&amp;gt;text comments&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;returns the html without answer and scale&amp;quot; do&lt;br /&gt;
      html = criterion.complete(0, nil, 0, 5, dropdown_or_scale = 'scale').to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;div&amp;gt;&amp;lt;label for=\&amp;quot;responses_0\&amp;quot;&amp;gt;test txt&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;input id=\&amp;quot;responses_0_score\&amp;quot; name=\&amp;quot;responses[0][score]\&amp;quot; type=\&amp;quot;hidden\&amp;quot;&amp;gt;&amp;lt;table&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;0&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;1&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;2&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;3&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;4&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;5&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;0\&amp;quot; value=\&amp;quot;0\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;checked=\&amp;quot;checked\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;1\&amp;quot; value=\&amp;quot;1\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;2\&amp;quot; value=\&amp;quot;2\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;3\&amp;quot; value=\&amp;quot;3\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;4\&amp;quot; value=\&amp;quot;4\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;5\&amp;quot; value=\&amp;quot;5\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;script&amp;gt;jQuery(\&amp;quot;input[name=Radio_1]:radio\&amp;quot;).change(function() {var response_score = jQuery(\&amp;quot;#responses_0_score\&amp;quot;);var checked_value = jQuery(\&amp;quot;input[name=Radio_1]:checked\&amp;quot;).val();response_score.val(checked_value);});&amp;lt;/script&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;&amp;lt;textarea cols=70 rows=1 id=\&amp;quot;responses_0_comments\&amp;quot; name=\&amp;quot;responses[0][comment]\&amp;quot; class=\&amp;quot;tinymce\&amp;quot;&amp;gt;&amp;lt;/textarea&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;returns the html with no comments answer and answer.answer outside questionnaire min and max and scale&amp;quot; do&lt;br /&gt;
      html = criterion.complete(0, answer_no_comments, 0, 5, dropdown_or_scale = 'scale').to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;div&amp;gt;&amp;lt;label for=\&amp;quot;responses_0\&amp;quot;&amp;gt;test txt&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;input id=\&amp;quot;responses_0_score\&amp;quot; name=\&amp;quot;responses[0][score]\&amp;quot; type=\&amp;quot;hidden\&amp;quot;value=\&amp;quot;8\&amp;quot;&amp;gt;&amp;lt;table&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;0&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;1&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;2&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;3&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;4&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;5&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;0\&amp;quot; value=\&amp;quot;0\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;1\&amp;quot; value=\&amp;quot;1\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;2\&amp;quot; value=\&amp;quot;2\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;3\&amp;quot; value=\&amp;quot;3\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;4\&amp;quot; value=\&amp;quot;4\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;5\&amp;quot; value=\&amp;quot;5\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;script&amp;gt;jQuery(\&amp;quot;input[name=Radio_1]:radio\&amp;quot;).change(function() {var response_score = jQuery(\&amp;quot;#responses_0_score\&amp;quot;);var checked_value = jQuery(\&amp;quot;input[name=Radio_1]:checked\&amp;quot;).val();response_score.val(checked_value);});&amp;lt;/script&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;&amp;lt;textarea cols=70 rows=1 id=\&amp;quot;responses_0_comments\&amp;quot; name=\&amp;quot;responses[0][comment]\&amp;quot; class=\&amp;quot;tinymce\&amp;quot;&amp;gt;&amp;lt;/textarea&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;returns the html with comments answer and answer.answer between questionnaire min and max and scale&amp;quot; do&lt;br /&gt;
      html = criterion.complete(0, answer_comments, 0, 5, dropdown_or_scale = 'scale').to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;div&amp;gt;&amp;lt;label for=\&amp;quot;responses_0\&amp;quot;&amp;gt;test txt&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;input id=\&amp;quot;responses_0_score\&amp;quot; name=\&amp;quot;responses[0][score]\&amp;quot; type=\&amp;quot;hidden\&amp;quot;value=\&amp;quot;3\&amp;quot;&amp;gt;&amp;lt;table&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;0&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;1&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;2&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;3&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;4&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;5&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;0\&amp;quot; value=\&amp;quot;0\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;1\&amp;quot; value=\&amp;quot;1\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;2\&amp;quot; value=\&amp;quot;2\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;3\&amp;quot; value=\&amp;quot;3\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;checked=\&amp;quot;checked\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;4\&amp;quot; value=\&amp;quot;4\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;5\&amp;quot; value=\&amp;quot;5\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;script&amp;gt;jQuery(\&amp;quot;input[name=Radio_1]:radio\&amp;quot;).change(function() {var response_score = jQuery(\&amp;quot;#responses_0_score\&amp;quot;);var checked_value = jQuery(\&amp;quot;input[name=Radio_1]:checked\&amp;quot;).val();response_score.val(checked_value);});&amp;lt;/script&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;&amp;lt;textarea cols=70 rows=1 id=\&amp;quot;responses_0_comments\&amp;quot; name=\&amp;quot;responses[0][comment]\&amp;quot; class=\&amp;quot;tinymce\&amp;quot;&amp;gt;text comments&amp;lt;/textarea&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Test for method &amp;quot;dropdown_criterion_question&amp;quot; with or without answer'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe &amp;quot;#dropdown_criterion_question&amp;quot; do&lt;br /&gt;
    it &amp;quot;returns the html without answer&amp;quot; do&lt;br /&gt;
      html = criterion.dropdown_criterion_question(0, nil, 0, 5).to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;div&amp;gt;&amp;lt;select id=\&amp;quot;responses_0_score\&amp;quot; name=\&amp;quot;responses[0][score]\&amp;quot; class=\&amp;quot;review-rating\&amp;quot; &amp;gt;&amp;lt;option value = ''&amp;gt;--&amp;lt;/option&amp;gt;&amp;lt;option value=0&amp;gt;0&amp;lt;/option&amp;gt;&amp;lt;option value=1&amp;gt;1&amp;lt;/option&amp;gt;&amp;lt;option value=2&amp;gt;2&amp;lt;/option&amp;gt;&amp;lt;option value=3&amp;gt;3&amp;lt;/option&amp;gt;&amp;lt;option value=4&amp;gt;4&amp;lt;/option&amp;gt;&amp;lt;option value=5&amp;gt;5&amp;lt;/option&amp;gt;&amp;lt;/select&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;textarea id=\&amp;quot;responses_0_comments\&amp;quot; name=\&amp;quot;responses[0][comment]\&amp;quot; class=\&amp;quot;tinymce\&amp;quot;&amp;gt;&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    it &amp;quot;returns the html with no comments answer and answer.answer outside questionnaire min and max&amp;quot; do&lt;br /&gt;
      html = criterion.dropdown_criterion_question(0, answer_no_comments, 0, 5).to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;div&amp;gt;&amp;lt;select id=\&amp;quot;responses_0_score\&amp;quot; name=\&amp;quot;responses[0][score]\&amp;quot; class=\&amp;quot;review-rating\&amp;quot; data-current-rating =8&amp;gt;&amp;lt;option value = ''&amp;gt;--&amp;lt;/option&amp;gt;&amp;lt;option value=0&amp;gt;0&amp;lt;/option&amp;gt;&amp;lt;option value=1&amp;gt;1&amp;lt;/option&amp;gt;&amp;lt;option value=2&amp;gt;2&amp;lt;/option&amp;gt;&amp;lt;option value=3&amp;gt;3&amp;lt;/option&amp;gt;&amp;lt;option value=4&amp;gt;4&amp;lt;/option&amp;gt;&amp;lt;option value=5&amp;gt;5&amp;lt;/option&amp;gt;&amp;lt;/select&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;textarea id=\&amp;quot;responses_0_comments\&amp;quot; name=\&amp;quot;responses[0][comment]\&amp;quot; class=\&amp;quot;tinymce\&amp;quot;&amp;gt;&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;returns the html with comments in answer and answer.answer between questionnaire min and max&amp;quot; do&lt;br /&gt;
      html = criterion.dropdown_criterion_question(0, answer_comments, 0, 5).to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;div&amp;gt;&amp;lt;select id=\&amp;quot;responses_0_score\&amp;quot; name=\&amp;quot;responses[0][score]\&amp;quot; class=\&amp;quot;review-rating\&amp;quot; data-current-rating =3&amp;gt;&amp;lt;option value = ''&amp;gt;--&amp;lt;/option&amp;gt;&amp;lt;option value=0&amp;gt;0&amp;lt;/option&amp;gt;&amp;lt;option value=1&amp;gt;1&amp;lt;/option&amp;gt;&amp;lt;option value=2&amp;gt;2&amp;lt;/option&amp;gt;&amp;lt;option value=3 selected=\&amp;quot;selected\&amp;quot;&amp;gt;3&amp;lt;/option&amp;gt;&amp;lt;option value=4&amp;gt;4&amp;lt;/option&amp;gt;&amp;lt;option value=5&amp;gt;5&amp;lt;/option&amp;gt;&amp;lt;/select&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;textarea id=\&amp;quot;responses_0_comments\&amp;quot; name=\&amp;quot;responses[0][comment]\&amp;quot; class=\&amp;quot;tinymce\&amp;quot;&amp;gt;text comments&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* '''Test for method &amp;quot;scale_criterion_question&amp;quot; with or without answer'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe &amp;quot;#scale_criterion_question&amp;quot; do&lt;br /&gt;
    it &amp;quot;returns the html without answer&amp;quot; do&lt;br /&gt;
      html = criterion.scale_criterion_question(0, nil, 0, 5).to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;input id=\&amp;quot;responses_0_score\&amp;quot; name=\&amp;quot;responses[0][score]\&amp;quot; type=\&amp;quot;hidden\&amp;quot;&amp;gt;&amp;lt;table&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;0&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;1&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;2&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;3&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;4&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;5&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;0\&amp;quot; value=\&amp;quot;0\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;checked=\&amp;quot;checked\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;1\&amp;quot; value=\&amp;quot;1\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;2\&amp;quot; value=\&amp;quot;2\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;3\&amp;quot; value=\&amp;quot;3\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;4\&amp;quot; value=\&amp;quot;4\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;5\&amp;quot; value=\&amp;quot;5\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;script&amp;gt;jQuery(\&amp;quot;input[name=Radio_1]:radio\&amp;quot;).change(function() {var response_score = jQuery(\&amp;quot;#responses_0_score\&amp;quot;);var checked_value = jQuery(\&amp;quot;input[name=Radio_1]:checked\&amp;quot;).val();response_score.val(checked_value);});&amp;lt;/script&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;&amp;lt;textarea cols=70 rows=1 id=\&amp;quot;responses_0_comments\&amp;quot; name=\&amp;quot;responses[0][comment]\&amp;quot; class=\&amp;quot;tinymce\&amp;quot;&amp;gt;&amp;lt;/textarea&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;returns the html with no comments answer and answer.answer outside questionnaire min and max&amp;quot; do&lt;br /&gt;
      html = criterion.scale_criterion_question(0, answer_no_comments, 0, 5).to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;input id=\&amp;quot;responses_0_score\&amp;quot; name=\&amp;quot;responses[0][score]\&amp;quot; type=\&amp;quot;hidden\&amp;quot;value=\&amp;quot;8\&amp;quot;&amp;gt;&amp;lt;table&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;0&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;1&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;2&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;3&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;4&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;5&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;0\&amp;quot; value=\&amp;quot;0\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;1\&amp;quot; value=\&amp;quot;1\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;2\&amp;quot; value=\&amp;quot;2\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;3\&amp;quot; value=\&amp;quot;3\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;4\&amp;quot; value=\&amp;quot;4\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;5\&amp;quot; value=\&amp;quot;5\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;script&amp;gt;jQuery(\&amp;quot;input[name=Radio_1]:radio\&amp;quot;).change(function() {var response_score = jQuery(\&amp;quot;#responses_0_score\&amp;quot;);var checked_value = jQuery(\&amp;quot;input[name=Radio_1]:checked\&amp;quot;).val();response_score.val(checked_value);});&amp;lt;/script&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;&amp;lt;textarea cols=70 rows=1 id=\&amp;quot;responses_0_comments\&amp;quot; name=\&amp;quot;responses[0][comment]\&amp;quot; class=\&amp;quot;tinymce\&amp;quot;&amp;gt;&amp;lt;/textarea&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;returns the html with comments answer and answer.answer between questionnaire min and max&amp;quot; do&lt;br /&gt;
      html = criterion.scale_criterion_question(0, answer_comments, 0, 5).to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;input id=\&amp;quot;responses_0_score\&amp;quot; name=\&amp;quot;responses[0][score]\&amp;quot; type=\&amp;quot;hidden\&amp;quot;value=\&amp;quot;3\&amp;quot;&amp;gt;&amp;lt;table&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;0&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;1&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;2&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;3&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;4&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;5&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;0\&amp;quot; value=\&amp;quot;0\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;1\&amp;quot; value=\&amp;quot;1\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;2\&amp;quot; value=\&amp;quot;2\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;3\&amp;quot; value=\&amp;quot;3\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;checked=\&amp;quot;checked\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;4\&amp;quot; value=\&amp;quot;4\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;5\&amp;quot; value=\&amp;quot;5\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;script&amp;gt;jQuery(\&amp;quot;input[name=Radio_1]:radio\&amp;quot;).change(function() {var response_score = jQuery(\&amp;quot;#responses_0_score\&amp;quot;);var checked_value = jQuery(\&amp;quot;input[name=Radio_1]:checked\&amp;quot;).val();response_score.val(checked_value);});&amp;lt;/script&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;&amp;lt;textarea cols=70 rows=1 id=\&amp;quot;responses_0_comments\&amp;quot; name=\&amp;quot;responses[0][comment]\&amp;quot; class=\&amp;quot;tinymce\&amp;quot;&amp;gt;text comments&amp;lt;/textarea&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''All existing tests passed'''&lt;br /&gt;
[[File:Test1.png]]&lt;br /&gt;
&lt;br /&gt;
=== Manual Testing ===&lt;br /&gt;
'''Test Log in'''&lt;br /&gt;
Website url: http://152.7.99.41:8080/ &amp;lt;br&amp;gt;&lt;br /&gt;
Log in: instructor6&amp;lt;br&amp;gt;&lt;br /&gt;
Password: password&amp;lt;br&amp;gt;&lt;br /&gt;
Log in: student2064&amp;lt;br&amp;gt;&lt;br /&gt;
Password: password&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Test criterion works well in questionnaire'''&lt;br /&gt;
&lt;br /&gt;
1. After logging in as a student, click the &amp;quot;Assignments&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
2. Choose an assignment, like &amp;quot;Backchannel application review&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
3. You can choose &amp;quot;Your scores&amp;quot; to see the review results&amp;lt;br&amp;gt;&lt;br /&gt;
4. Click Criterion 1, you can see all the reviews for this criterion.&amp;lt;br&amp;gt;&lt;br /&gt;
5. Click &amp;quot;toggle question list&amp;quot;, you can see all criterion questions.&amp;lt;br&amp;gt;&lt;br /&gt;
6. After logging in as an instructor, choose &amp;quot;Questionnaires&amp;quot; tag&amp;lt;br&amp;gt;&lt;br /&gt;
7. Click on the name Review: This should show a drop-down showing different reviews made.&amp;lt;br&amp;gt;&lt;br /&gt;
8. Choose a review, select the edit icon to the right.&amp;lt;br&amp;gt;&lt;br /&gt;
8. Change dropbox of question type to Criterion, select Add &amp;quot;2&amp;quot; more. Press the add button.&amp;lt;br&amp;gt;&lt;br /&gt;
9. Edit question content: &amp;quot;Test question Textarea&amp;quot;, &amp;quot;Test question Criterion1&amp;quot;, and &amp;quot;Test question Criterion2&amp;quot; in that order.&amp;lt;br&amp;gt;&lt;br /&gt;
10. You can also change the question content for exited criterion question&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These manual tests show criterion works well. Feel free to try your own test cases.&lt;/div&gt;</summary>
		<author><name>Shmehta</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC517_(Spring_2020)_-_E2010._Refactor_criterion.rb&amp;diff=132324</id>
		<title>CSC517 (Spring 2020) - E2010. Refactor criterion.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC517_(Spring_2020)_-_E2010._Refactor_criterion.rb&amp;diff=132324"/>
		<updated>2020-03-31T08:56:51Z</updated>

		<summary type="html">&lt;p&gt;Shmehta: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= E2010 Refactor criterion.rb =&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project.&lt;br /&gt;
&lt;br /&gt;
== About Expertiza ==&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source project based on [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create new assignments and customize new or existing assignments. It also allows the instructor to create a list of topics the students can sign up for. Students can form teams in Expertiza to work on various projects and assignments. Students can also peer review other students' submissions. Expertiza supports submission across various document types, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
The criterion.rb model consists of functions that decide what to display while creating, editing and viewing the questionnaires depending on whether the user is an instructor, a teaching assistant or a student. So, this file consists of a lot of HTML code that is rendered to the final questionnaire view. &lt;br /&gt;
&lt;br /&gt;
The current version of this controller has four methods, but two methods are very long and would require refactoring. The primary problem with these functions is that it consists of many statements of string concatenation. The HTML code which is rendered to the final view is made up of concatenations. &lt;br /&gt;
&lt;br /&gt;
Another issue with the code is that the branch conditions size for the complete and the view_completed_question method is very high. Also, this controller has very few comments. They are specifically needed to differentiate between the purpose of numerous nested branches from each other.&lt;br /&gt;
&lt;br /&gt;
== About criterion.rb ==&lt;br /&gt;
The ''criterion.rb'' model consists of functions that decide what to display while creating, editing and viewing the questionnaires depending on whether the user is an instructor, a teaching assistant or a student. So this file consists of a lot of HTML code that is rendered to the final questionnaire view.&lt;br /&gt;
&lt;br /&gt;
For this project, we have to deal with the following two methods:&lt;br /&gt;
* The '''''complete''''' method, which is 104 lines long. this method returns the display for the students when they are filling the questionnaire. It includes the advice given for different questions, dropdown options to rate a project based on the question, a textarea to enter comments and so on.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def complete(count, answer = nil, questionnaire_min, questionnaire_max, dropdown_or_scale)&lt;br /&gt;
    if self.size.nil?&lt;br /&gt;
      cols = '70'&lt;br /&gt;
      rows = '1'&lt;br /&gt;
    else&lt;br /&gt;
      cols = self.size.split(',')[0]&lt;br /&gt;
      rows = self.size.split(',')[1]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    html = '&amp;lt;div&amp;gt;&amp;lt;label for=&amp;quot;responses_' + count.to_s + '&amp;quot;&amp;gt;' + self.txt + '&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;'&lt;br /&gt;
    # show advice for each criterion question&lt;br /&gt;
    question_advices = QuestionAdvice.where(question_id: self.id).sort_by(&amp;amp;:id)&lt;br /&gt;
    advice_total_length = 0&lt;br /&gt;
&lt;br /&gt;
    question_advices.each do |question_advice|&lt;br /&gt;
      advice_total_length += question_advice.advice.length if question_advice.advice &amp;amp;&amp;amp; question_advice.advice != &amp;quot;&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if !question_advices.empty? and advice_total_length &amp;gt; 0&lt;br /&gt;
      html += '&amp;lt;a id=&amp;quot;showAdivce_' + self.id.to_s + '&amp;quot; onclick=&amp;quot;showAdvice(' + self.id.to_s + ')&amp;quot;&amp;gt;Show advice&amp;lt;/a&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;script&amp;gt;'&lt;br /&gt;
      html += 'function showAdvice(i){'&lt;br /&gt;
      html += 'var element = document.getElementById(&amp;quot;showAdivce_&amp;quot; + i.toString());'&lt;br /&gt;
      html += 'var show = element.innerHTML == &amp;quot;Hide advice&amp;quot;;'&lt;br /&gt;
      html += 'if (show){'&lt;br /&gt;
      html += 'element.innerHTML=&amp;quot;Show advice&amp;quot;;'&lt;br /&gt;
      html += '}else{'&lt;br /&gt;
      html += 'element.innerHTML=&amp;quot;Hide advice&amp;quot;;}'&lt;br /&gt;
      html += 'toggleAdvice(i);}'&lt;br /&gt;
&lt;br /&gt;
      html += 'function toggleAdvice(i) {'&lt;br /&gt;
      html += 'var elem = document.getElementById(i.toString() + &amp;quot;_myDiv&amp;quot;);'&lt;br /&gt;
      html += 'if (elem.style.display == &amp;quot;none&amp;quot;) {'&lt;br /&gt;
      html += 'elem.style.display = &amp;quot;&amp;quot;;'&lt;br /&gt;
      html += '} else {'&lt;br /&gt;
      html += 'elem.style.display = &amp;quot;none&amp;quot;;}}'&lt;br /&gt;
      html += '&amp;lt;/script&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;div id=&amp;quot;' + self.id.to_s + '_myDiv&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;'&lt;br /&gt;
      # [2015-10-26] Zhewei:&lt;br /&gt;
      # best to order advices high to low, e.g., 5 to 1&lt;br /&gt;
      # each level used to be a link;&lt;br /&gt;
      # clicking on the link caused the dropbox to be filled in with the corresponding number&lt;br /&gt;
      question_advices.reverse.each_with_index do |question_advice, index|&lt;br /&gt;
        html += '&amp;lt;a id=&amp;quot;changeScore_&amp;gt;' + self.id.to_s + '&amp;quot; onclick=&amp;quot;changeScore(' + count.to_s + ',' + index.to_s + ')&amp;quot;&amp;gt;'&lt;br /&gt;
        html += (self.questionnaire.max_question_score - index).to_s + ' - ' + question_advice.advice + '&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;'&lt;br /&gt;
        html += '&amp;lt;script&amp;gt;'&lt;br /&gt;
        html += 'function changeScore(i, j) {'&lt;br /&gt;
        html += 'var elem = jQuery(&amp;quot;#responses_&amp;quot; + i.toString() + &amp;quot;_score&amp;quot;);'&lt;br /&gt;
        html += 'var opts = elem.children(&amp;quot;option&amp;quot;).length;'&lt;br /&gt;
        html += 'elem.val((' + self.questionnaire.max_question_score.to_s + ' - j).toString());}'&lt;br /&gt;
        html += '&amp;lt;/script&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;/div&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if dropdown_or_scale == 'dropdown'&lt;br /&gt;
      current_value = &amp;quot;&amp;quot;&lt;br /&gt;
      current_value += 'data-current-rating =' + answer.answer.to_s if !answer.nil?&lt;br /&gt;
      html += '&amp;lt;div&amp;gt;&amp;lt;select id=&amp;quot;responses_' + count.to_s + '_score&amp;quot; name=&amp;quot;responses[' + count.to_s + '][score]&amp;quot; class=&amp;quot;review-rating&amp;quot; ' + current_value + '&amp;gt;'&lt;br /&gt;
      html += &amp;quot;&amp;lt;option value = ''&amp;gt;--&amp;lt;/option&amp;gt;&amp;quot;&lt;br /&gt;
      questionnaire_min.upto(questionnaire_max).each do |j|&lt;br /&gt;
        html += if !answer.nil? and j == answer.answer&lt;br /&gt;
                  '&amp;lt;option value=' + j.to_s + ' selected=&amp;quot;selected&amp;quot;&amp;gt;'&lt;br /&gt;
                else&lt;br /&gt;
                  '&amp;lt;option value=' + j.to_s + '&amp;gt;'&lt;br /&gt;
                end&lt;br /&gt;
&lt;br /&gt;
        html += j.to_s&lt;br /&gt;
        if j == questionnaire_min&lt;br /&gt;
          html += &amp;quot;-&amp;quot; + self.min_label if self.min_label.present?&lt;br /&gt;
        elsif j == questionnaire_max&lt;br /&gt;
          html += &amp;quot;-&amp;quot; + self.max_label if self.max_label.present?&lt;br /&gt;
        end&lt;br /&gt;
        html += &amp;quot;&amp;lt;/option&amp;gt;&amp;quot;&lt;br /&gt;
      end&lt;br /&gt;
      html += &amp;quot;&amp;lt;/select&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;&lt;br /&gt;
      html += '&amp;lt;textarea' + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
       ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
      html += answer.comments unless answer.nil?&lt;br /&gt;
      html += '&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
    elsif dropdown_or_scale == 'scale'&lt;br /&gt;
      html += '&amp;lt;input id=&amp;quot;responses_' + count.to_s + '_score&amp;quot; name=&amp;quot;responses[' + count.to_s + '][score]&amp;quot; type=&amp;quot;hidden&amp;quot;'&lt;br /&gt;
      html += 'value=&amp;quot;' + answer.answer.to_s + '&amp;quot;' unless answer.nil?&lt;br /&gt;
      html += '&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;table&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;tr&amp;gt;&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      (questionnaire_min..questionnaire_max).each do |j|&lt;br /&gt;
        html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;label&amp;gt;' + j.to_s + '&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += if !self.min_label.nil?&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;' + self.min_label + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
              else&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
              end&lt;br /&gt;
      (questionnaire_min..questionnaire_max).each do |j|&lt;br /&gt;
        html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;input type=&amp;quot;radio&amp;quot; id=&amp;quot;' + j.to_s + '&amp;quot; value=&amp;quot;' + j.to_s + '&amp;quot; name=&amp;quot;Radio_' + self.id.to_s + '&amp;quot;'&lt;br /&gt;
        html += 'checked=&amp;quot;checked&amp;quot;' if (!answer.nil? and answer.answer == j) or (answer.nil? and questionnaire_min == j)&lt;br /&gt;
        html += '&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;script&amp;gt;jQuery(&amp;quot;input[name=Radio_' + self.id.to_s + ']:radio&amp;quot;).change(function() {'&lt;br /&gt;
      html += 'var response_score = jQuery(&amp;quot;#responses_' + count.to_s + '_score&amp;quot;);'&lt;br /&gt;
      html += 'var checked_value = jQuery(&amp;quot;input[name=Radio_' + self.id.to_s + ']:checked&amp;quot;).val();'&lt;br /&gt;
      html += 'response_score.val(checked_value);});&amp;lt;/script&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += if !self.max_label.nil?&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;' + self.max_label + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
              else&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
              end&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;textarea cols=' + cols + ' rows=' + rows + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
        ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
      html += answer.comments unless answer.nil?&lt;br /&gt;
      html += '&amp;lt;/textarea&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    end&lt;br /&gt;
    safe_join([&amp;quot;&amp;quot;.html_safe, &amp;quot;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The '''''view_completed_question''''' method, which is 47 lies long. Thismethod is responsible to return the display if a student is viewingan already filled-out questionnaire.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def view_completed_question(count, answer, questionnaire_max, tag_prompt_deployments = nil, current_user = nil)&lt;br /&gt;
    html = '&amp;lt;b&amp;gt;' + count.to_s + &amp;quot;. &amp;quot; + self.txt + ' [Max points: ' + questionnaire_max.to_s + &amp;quot;]&amp;lt;/b&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    score = answer &amp;amp;&amp;amp; !answer.answer.nil? ? answer.answer.to_s : &amp;quot;-&amp;quot;&lt;br /&gt;
    score_percent = if score != &amp;quot;-&amp;quot;&lt;br /&gt;
                      answer.answer * 1.0 / questionnaire_max&lt;br /&gt;
                    else&lt;br /&gt;
                      0&lt;br /&gt;
                    end&lt;br /&gt;
&lt;br /&gt;
    score_color = if score_percent &amp;gt; 0.8&lt;br /&gt;
                    &amp;quot;c5&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.6&lt;br /&gt;
                    &amp;quot;c4&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.4&lt;br /&gt;
                    &amp;quot;c3&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.2&lt;br /&gt;
                    &amp;quot;c2&amp;quot;&lt;br /&gt;
                  else&lt;br /&gt;
                    &amp;quot;c1&amp;quot;&lt;br /&gt;
                  end&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;table cellpadding=&amp;quot;5&amp;quot;&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;tr&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;div class=&amp;quot;' + score_color + '&amp;quot; style=&amp;quot;width:30px; height:30px;' \&lt;br /&gt;
      ' border-radius:50%; font-size:15px; color:black; line-height:30px; text-align:center;&amp;quot;&amp;gt;'&lt;br /&gt;
    html += score&lt;br /&gt;
    html += '&amp;lt;/div&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;/td&amp;gt;'&lt;br /&gt;
    if answer &amp;amp;&amp;amp; !answer.comments.nil?&lt;br /&gt;
      html += '&amp;lt;td style=&amp;quot;padding-left:10px&amp;quot;&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;br&amp;gt;' + answer.comments.html_safe&lt;br /&gt;
      html += '&amp;lt;/td&amp;gt;'&lt;br /&gt;
      #### start code to show tag prompts ####&lt;br /&gt;
      unless tag_prompt_deployments.nil?&lt;br /&gt;
        # show check boxes for answer tagging&lt;br /&gt;
        resp = Response.find(answer.response_id)&lt;br /&gt;
        question = Question.find(answer.question_id)&lt;br /&gt;
        if tag_prompt_deployments.count &amp;gt; 0&lt;br /&gt;
          html += '&amp;lt;tr&amp;gt;&amp;lt;td colspan=&amp;quot;2&amp;quot;&amp;gt;'&lt;br /&gt;
          tag_prompt_deployments.each do |tag_dep|&lt;br /&gt;
            tag_prompt = TagPrompt.find(tag_dep.tag_prompt_id)&lt;br /&gt;
            if tag_dep.question_type == question.type and answer.comments.length &amp;gt; tag_dep.answer_length_threshold.to_i&lt;br /&gt;
              html += tag_prompt.html_control(tag_dep, answer, current_user)&lt;br /&gt;
            end&lt;br /&gt;
          end&lt;br /&gt;
          html += '&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;'&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      #### end code to show tag prompts ####&lt;br /&gt;
    end&lt;br /&gt;
    html += '&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;'&lt;br /&gt;
    safe_join([&amp;quot;&amp;quot;.html_safe, &amp;quot;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Proposed Solution ==&lt;br /&gt;
Our goal is to refactor the complete and view_completed_question method mainly by reducing the number of lines code for each function and also by introducing new methods to make the code more modular. &lt;br /&gt;
We will also try to reduce the branch condition size wherever possible and hence reduce the cyclomatic complexity for these two functions. &lt;br /&gt;
We also plan to introduce comments wherever needed to make the code more understandable. The main aim is to reduce the number of lines and make the code more compact without affecting the readability of the code.&lt;br /&gt;
* High branch condition size problem: extracting three methods from method &amp;quot;'''complete'''&amp;quot;&lt;br /&gt;
** Method &amp;quot;'''dropdown_criterion_question'''&amp;quot; return html when choosing dropdown options&lt;br /&gt;
** Method &amp;quot;'''scale_criterion_question'''&amp;quot; return html when choosing scale options&lt;br /&gt;
** Method &amp;quot;'''advices_criterion_question'''&amp;quot; return html about showing advice for each criterion question&lt;br /&gt;
* Too long code&lt;br /&gt;
** Combining the short HTML strings into longer ones but not too long&lt;br /&gt;
** Using one readable line of code instead of three or more lines of if-else statements&lt;br /&gt;
* Fix incomplete condition problem &lt;br /&gt;
* Change the language to more Ruby friendly&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
&lt;br /&gt;
We tried to tackle the issues mentioned in the problem statement as described below:&lt;br /&gt;
&lt;br /&gt;
=== The ''complete'' method ===&lt;br /&gt;
* We extracted three methods from &amp;quot;complete&amp;quot; method. &lt;br /&gt;
* We combined the short HTML strings into longer ones. &lt;br /&gt;
* We used the shorthand which beautifully consolidates three or more lines of code (read: if-else statements) into one readable line of code. &lt;br /&gt;
&lt;br /&gt;
====''Examples of changes''====&lt;br /&gt;
'''Extracting three methods to reducing the condition branch'''&lt;br /&gt;
* Method &amp;quot;dropdown_criterion_question&amp;quot; return html when choosing dropdown options&lt;br /&gt;
* Method &amp;quot;scale_criterion_question&amp;quot; return html when choosing scale options&lt;br /&gt;
* Method &amp;quot;advices_criterion_question&amp;quot; return html about showing advice for each criterion question&lt;br /&gt;
&lt;br /&gt;
'''Combining the short HTML strings into longer ones'''&lt;br /&gt;
&lt;br /&gt;
We go from:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
html += &amp;quot;&amp;lt;/select&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;&lt;br /&gt;
html += '&amp;lt;textarea' + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;'&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
html += '&amp;lt;/select&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;textarea' + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;'&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Using one readable line of code instead of three or more lines of if-else statements'''&lt;br /&gt;
&lt;br /&gt;
We go from:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
html += if !answer.nil? and j == answer.answer&lt;br /&gt;
           '&amp;lt;option value=' + j.to_s + ' selected=&amp;quot;selected&amp;quot;&amp;gt;'&lt;br /&gt;
        else&lt;br /&gt;
           '&amp;lt;option value=' + j.to_s + '&amp;gt;'&lt;br /&gt;
        end&lt;br /&gt;
html += j.to_s&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
html += '&amp;lt;option value=' + j.to_s&lt;br /&gt;
html += ' selected=&amp;quot;selected&amp;quot;' if !answer.nil? &amp;amp;&amp;amp; j == answer.answer&lt;br /&gt;
html += '&amp;gt;' + j.to_s&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Use unless for negative conditions'''&lt;br /&gt;
&lt;br /&gt;
We go from:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
current_value += 'data-current-rating =' + answer.answer.to_s if !answer.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
current_value += 'data-current-rating =' + answer.answer.to_s unless answer.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Same change for self.min_label and self.max_label. We go from:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
html += if !self.min_label.nil?&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;' + self.min_label + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
              else&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
              end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;'&lt;br /&gt;
html += self.min_label unless self.min_label.nil?&lt;br /&gt;
html += '&amp;lt;/td&amp;gt;'&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Unsafe condition'''&lt;br /&gt;
&lt;br /&gt;
We added condition to make sure when answer.comments is nil. We go from:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
html += answer.comments unless answer.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
html += answer.comments if !answer.nil? &amp;amp;&amp;amp; !answer.comments.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Incomplete condition'''&lt;br /&gt;
&lt;br /&gt;
When create a new criterion, which size is &amp;quot;&amp;quot; that isn't nil. We add condition to make sure &amp;quot;cols&amp;quot; and &amp;quot;rows&amp;quot; will be assign when &amp;quot;self.size&amp;quot; is &amp;quot;&amp;quot;. We go from:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if self.size.nil?&lt;br /&gt;
   cols = '70'&lt;br /&gt;
   rows = '1'&lt;br /&gt;
else&lt;br /&gt;
   cols = self.size.split(',')[0]&lt;br /&gt;
   rows = self.size.split(',')[1]&lt;br /&gt;
end&lt;br /&gt;
html += '&amp;lt;textarea cols=' + cols + ' rows=' + rows + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
        ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if self.size.nil?||self.size.blank?&lt;br /&gt;
   cols = '70'&lt;br /&gt;
   rows = '1'&lt;br /&gt;
else&lt;br /&gt;
   cols = self.size.split(',')[0]&lt;br /&gt;
   rows = self.size.split(',')[1]&lt;br /&gt;
end&lt;br /&gt;
html += '&amp;lt;textarea cols=' + cols + ' rows=' + rows + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
        ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Ruby grammer'''&lt;br /&gt;
&lt;br /&gt;
We change &amp;quot;and&amp;quot; to &amp;amp;&amp;amp;. We changed from:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
html += 'checked=&amp;quot;checked&amp;quot;' if (!answer.nil? and answer.answer == j) or (answer.nil? and questionnaire_min == j)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
html += 'checked=&amp;quot;checked&amp;quot;' if (!answer.nil? &amp;amp;&amp;amp; answer.answer == j) or (answer.nil? &amp;amp;&amp;amp; questionnaire_min == j)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====''The modified ''complete'' method''====&lt;br /&gt;
* '''Method &amp;quot;complete&amp;quot;'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def complete(count, answer = nil, questionnaire_min, questionnaire_max, dropdown_or_scale)&lt;br /&gt;
    html = '&amp;lt;div&amp;gt;&amp;lt;label for=&amp;quot;responses_' + count.to_s + '&amp;quot;&amp;gt;' + self.txt + '&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;'&lt;br /&gt;
    question_advices = QuestionAdvice.where(question_id: self.id).sort_by(&amp;amp;:id)&lt;br /&gt;
    advice_total_length = 0&lt;br /&gt;
    question_advices.each do |question_advice|&lt;br /&gt;
      advice_total_length += question_advice.advice.length if question_advice.advice &amp;amp;&amp;amp; question_advice.advice != &amp;quot;&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
    #show advice given for different questions&lt;br /&gt;
    html += advices_criterion_question(count, question_advices) if !question_advices.empty? and advice_total_length &amp;gt; 0&lt;br /&gt;
&lt;br /&gt;
    #dropdown options to rate a project based on the quetion&lt;br /&gt;
    html += dropdown_criterion_question(count, answer, questionnaire_min, questionnaire_max) if dropdown_or_scale == 'dropdown'&lt;br /&gt;
&lt;br /&gt;
    #scale optioins&lt;br /&gt;
    html += scale_criterion_question(count, answer, questionnaire_min, questionnaire_max) if dropdown_or_scale == 'scale'&lt;br /&gt;
    safe_join([&amp;quot;&amp;quot;.html_safe, &amp;quot;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* '''Method &amp;quot;advices_criterion_question&amp;quot;'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  # show advice for each criterion question&lt;br /&gt;
  def advices_criterion_question(count, question_advices)&lt;br /&gt;
    html = '&amp;lt;a id=&amp;quot;showAdvice_' + self.id.to_s + '&amp;quot; onclick=&amp;quot;showAdvice(' + self.id.to_s + ')&amp;quot;&amp;gt;Show advice&amp;lt;/a&amp;gt;&amp;lt;script&amp;gt;'&lt;br /&gt;
    html += 'function showAdvice(i){var element = document.getElementById(&amp;quot;showAdivce_&amp;quot; + i.toString());'&lt;br /&gt;
    html += 'var show = element.innerHTML == &amp;quot;Hide advice&amp;quot;;'&lt;br /&gt;
    html += 'if (show){element.innerHTML=&amp;quot;Show advice&amp;quot;;} else{element.innerHTML=&amp;quot;Hide advice&amp;quot;;}toggleAdvice(i);}'&lt;br /&gt;
    html += 'function toggleAdvice(i) {var elem = document.getElementById(i.toString() + &amp;quot;_myDiv&amp;quot;);'&lt;br /&gt;
    html += 'if (elem.style.display == &amp;quot;none&amp;quot;) {elem.style.display = &amp;quot;&amp;quot;;} else {elem.style.display = &amp;quot;none&amp;quot;;}}&amp;lt;/script&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;div id=&amp;quot;' + self.id.to_s + '_myDiv&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;'&lt;br /&gt;
    # [2015-10-26] Zhewei:&lt;br /&gt;
    # best to order advices high to low, e.g., 5 to 1&lt;br /&gt;
    # each level used to be a link;&lt;br /&gt;
    # clicking on the link caused the dropbox to be filled in with the corresponding number&lt;br /&gt;
    question_advices.reverse.each_with_index do |question_advice, index|&lt;br /&gt;
      html += '&amp;lt;a id=&amp;quot;changeScore_&amp;gt;' + self.id.to_s + '&amp;quot; onclick=&amp;quot;changeScore(' + count.to_s + ',' + index.to_s + ')&amp;quot;&amp;gt;'&lt;br /&gt;
      html += (self.questionnaire.max_question_score - index).to_s + ' - ' + question_advice.advice + '&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;script&amp;gt;'&lt;br /&gt;
      html += 'function changeScore(i, j) {var elem = jQuery(&amp;quot;#responses_&amp;quot; + i.toString() + &amp;quot;_score&amp;quot;);'&lt;br /&gt;
      html += 'var opts = elem.children(&amp;quot;option&amp;quot;).length;'&lt;br /&gt;
      html += 'elem.val((' + self.questionnaire.max_question_score.to_s + ' - j).toString());}&amp;lt;/script&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
    html += '&amp;lt;/div&amp;gt;'&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* '''Method &amp;quot;dropdown_criterion_question&amp;quot;'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def dropdown_criterion_question(count, answer = nil, questionnaire_min, questionnaire_max)&lt;br /&gt;
    current_value = &amp;quot;&amp;quot; &lt;br /&gt;
    current_value += 'data-current-rating =' + answer.answer.to_s unless answer.nil?&lt;br /&gt;
    html = '&amp;lt;div&amp;gt;&amp;lt;select id=&amp;quot;responses_' + count.to_s + '_score&amp;quot; name=&amp;quot;responses[' + count.to_s + '][score]&amp;quot; class=&amp;quot;review-rating&amp;quot; ' + current_value + '&amp;gt;'&lt;br /&gt;
    html += &amp;quot;&amp;lt;option value = ''&amp;gt;--&amp;lt;/option&amp;gt;&amp;quot;&lt;br /&gt;
    questionnaire_min.upto(questionnaire_max).each do |j|&lt;br /&gt;
      html += '&amp;lt;option value=' + j.to_s&lt;br /&gt;
      html += ' selected=&amp;quot;selected&amp;quot;' if !answer.nil? &amp;amp;&amp;amp; j == answer.answer&lt;br /&gt;
      html += '&amp;gt;'&lt;br /&gt;
      html += j.to_s&lt;br /&gt;
      html += &amp;quot;-&amp;quot; + self.min_label if self.min_label.present? &amp;amp;&amp;amp; j == questionnaire_min&lt;br /&gt;
      html += &amp;quot;-&amp;quot; + self.max_label if self.max_label.present? &amp;amp;&amp;amp; j == questionnaire_max&lt;br /&gt;
      html += &amp;quot;&amp;lt;/option&amp;gt;&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;/select&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;textarea' + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;'&lt;br /&gt;
    html += ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
    html += answer.comments if !answer.nil? &amp;amp;&amp;amp; !answer.comments.nil?&lt;br /&gt;
    html += '&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* '''Method &amp;quot;scale_criterion_question&amp;quot;'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def scale_criterion_question(count, answer = nil, questionnaire_min, questionnaire_max)&lt;br /&gt;
    if self.size.nil? || !self.size.present?&lt;br /&gt;
      cols = '70'&lt;br /&gt;
      rows = '1'&lt;br /&gt;
    else&lt;br /&gt;
     cols = self.size.split(',')[0]&lt;br /&gt;
     rows = self.size.split(',')[1]&lt;br /&gt;
    end&lt;br /&gt;
    html = '&amp;lt;input id=&amp;quot;responses_' + count.to_s + '_score&amp;quot; name=&amp;quot;responses[' + count.to_s + '][score]&amp;quot; type=&amp;quot;hidden&amp;quot;'&lt;br /&gt;
    html += 'value=&amp;quot;' + answer.answer.to_s + '&amp;quot;' unless answer.nil?&lt;br /&gt;
    html += '&amp;gt;&amp;lt;table&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    (questionnaire_min..questionnaire_max).each do |j|&lt;br /&gt;
      html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;label&amp;gt;' + j.to_s + '&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;'&lt;br /&gt;
    html += self.min_label unless self.min_label.nil?&lt;br /&gt;
    html += '&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    (questionnaire_min..questionnaire_max).each do |j|&lt;br /&gt;
      html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;input type=&amp;quot;radio&amp;quot; id=&amp;quot;' + j.to_s + '&amp;quot; value=&amp;quot;' + j.to_s + '&amp;quot; name=&amp;quot;Radio_' + self.id.to_s + '&amp;quot;'&lt;br /&gt;
      html += 'checked=&amp;quot;checked&amp;quot;' if (!answer.nil? &amp;amp;&amp;amp; answer.answer == j) or (answer.nil? &amp;amp;&amp;amp; questionnaire_min == j)&lt;br /&gt;
      html += '&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
    html += '&amp;lt;script&amp;gt;jQuery(&amp;quot;input[name=Radio_' + self.id.to_s + ']:radio&amp;quot;).change(function() {'&lt;br /&gt;
    html += 'var response_score = jQuery(&amp;quot;#responses_' + count.to_s + '_score&amp;quot;);'&lt;br /&gt;
    html += 'var checked_value = jQuery(&amp;quot;input[name=Radio_' + self.id.to_s + ']:checked&amp;quot;).val();'&lt;br /&gt;
    html += 'response_score.val(checked_value);});&amp;lt;/script&amp;gt;&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;'&lt;br /&gt;
    html += self.max_label unless self.max_label.nil?&lt;br /&gt;
    html += '&amp;lt;/td&amp;gt;&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;textarea cols=' + cols + ' rows=' + rows + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
      ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
    html += answer.comments if !answer.nil? &amp;amp;&amp;amp; !answer.comments.nil?&lt;br /&gt;
    html += '&amp;lt;/textarea&amp;gt;'    &lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The ''view_completed_question&amp;quot; method===&lt;br /&gt;
&lt;br /&gt;
The main task here was to reduce the nested if-else branching and reduce the number of arguments for this function. &lt;br /&gt;
* We reduced the nested if-else branching.&lt;br /&gt;
* We concatenated small HTML string&lt;br /&gt;
* We used shorthand for if-else condition statements. &lt;br /&gt;
&lt;br /&gt;
This was a very small method with its major dependent functions present in response.rb file. To refactor this method, we would have had to refactor response.rb and in turn, the other question subclasses which would make it very complex and break the code. According to us, refactoring this method along with the response.rb file would make more sense. &lt;br /&gt;
&lt;br /&gt;
====''Example of changes''====&lt;br /&gt;
'''Combining the short HTML strings into longer ones'''&lt;br /&gt;
&lt;br /&gt;
We concatenated small HTML which was from:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
html += '&amp;lt;table cellpadding=&amp;quot;5&amp;quot;&amp;gt;'&lt;br /&gt;
html += '&amp;lt;tr&amp;gt;'&lt;br /&gt;
html += '&amp;lt;td&amp;gt;'&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
html += '&amp;lt;table cellpadding=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;'&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Using one readable line of code instead of three or more lines of if-else statements'''&lt;br /&gt;
&lt;br /&gt;
We changed from:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
score_percent = if score != &amp;quot;-&amp;quot;&lt;br /&gt;
                     answer.answer * 1.0 / questionnaire_max&lt;br /&gt;
                else&lt;br /&gt;
                     0&lt;br /&gt;
                end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
score_percent = score != &amp;quot;-&amp;quot; ? answer.answer * 1.0 / questionnaire_max : 0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Delete useless variable - 'resp''''&lt;br /&gt;
&lt;br /&gt;
We deleted this code&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
resp = Response.find(answer.response_id)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Change of language to make it more Ruby friendly'''&lt;br /&gt;
&lt;br /&gt;
We changed from:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if tag_dep.question_type == question.type and answer.comments.length &amp;gt; tag_dep.answer_length_threshold.to_i&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if tag_dep.question_type == question.type &amp;amp;&amp;amp; answer.comments.length &amp;gt; tag_dep.answer_length_threshold.to_i&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Reduce the branch condition'''&lt;br /&gt;
&lt;br /&gt;
We combined condition &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
unless tag_prompt_deployments.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
and&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if tag_prompt_deployments.count &amp;gt; 0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if !tag_prompt_deployments.nil? &amp;amp;&amp;amp; tag_prompt_deployments.count &amp;gt; 0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
  [[File:Multiple_2.png]]&lt;br /&gt;
&lt;br /&gt;
==== The modified ''view_completed_question''====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def view_completed_question(count, answer, questionnaire_max, tag_prompt_deployments = nil, current_user = nil)&lt;br /&gt;
    html = '&amp;lt;b&amp;gt;' + count.to_s + &amp;quot;. &amp;quot; + self.txt + ' [Max points: ' + questionnaire_max.to_s + &amp;quot;]&amp;lt;/b&amp;gt;&amp;quot;&lt;br /&gt;
    score = answer &amp;amp;&amp;amp; !answer.answer.nil? ? answer.answer.to_s : &amp;quot;-&amp;quot;&lt;br /&gt;
    score_percent = score != &amp;quot;-&amp;quot; ? answer.answer * 1.0 / questionnaire_max : 0&lt;br /&gt;
    score_color = if score_percent &amp;gt; 0.8&lt;br /&gt;
                    &amp;quot;c5&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.6&lt;br /&gt;
                    &amp;quot;c4&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.4&lt;br /&gt;
                    &amp;quot;c3&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.2&lt;br /&gt;
                    &amp;quot;c2&amp;quot;&lt;br /&gt;
                  else&lt;br /&gt;
                    &amp;quot;c1&amp;quot;&lt;br /&gt;
                  end&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;table cellpadding=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;div class=&amp;quot;' + score_color + '&amp;quot; style=&amp;quot;width:30px; height:30px;' \&lt;br /&gt;
      ' border-radius:50%; font-size:15px; color:black; line-height:30px; text-align:center;&amp;quot;&amp;gt;'&lt;br /&gt;
    html += score + '&amp;lt;/div&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    if answer &amp;amp;&amp;amp; !answer.comments.nil?&lt;br /&gt;
      html += '&amp;lt;td style=&amp;quot;padding-left:10px&amp;quot;&amp;gt;&amp;lt;br&amp;gt;' + answer.comments.html_safe + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
      #### start code to show tag prompts ####&lt;br /&gt;
      if !tag_prompt_deployments.nil? &amp;amp;&amp;amp; tag_prompt_deployments.count &amp;gt; 0&lt;br /&gt;
        # show check boxes for answer tagging&lt;br /&gt;
        question = Question.find(answer.question_id)&lt;br /&gt;
        html += '&amp;lt;tr&amp;gt;&amp;lt;td colspan=&amp;quot;2&amp;quot;&amp;gt;'&lt;br /&gt;
        tag_prompt_deployments.each do |tag_dep|&lt;br /&gt;
          tag_prompt = TagPrompt.find(tag_dep.tag_prompt_id)&lt;br /&gt;
          if tag_dep.question_type == question.type &amp;amp;&amp;amp; answer.comments.length &amp;gt; tag_dep.answer_length_threshold.to_i&lt;br /&gt;
            html += tag_prompt.html_control(tag_dep, answer, current_user)&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
        html += '&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      #### end code to show tag prompts ####&lt;br /&gt;
    end&lt;br /&gt;
    html += '&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;'&lt;br /&gt;
    safe_join([&amp;quot;&amp;quot;.html_safe, &amp;quot;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Test Plan ==&lt;br /&gt;
&lt;br /&gt;
We are running Rspec tests to make sure the coverage is the same and manually checking the pages to make sure there are not any issues and the code is not breaking&lt;br /&gt;
=== RSpec Testing ===&lt;br /&gt;
The origin test about method &amp;quot;complete&amp;quot; didn't include the situation when the parameter &amp;quot;answer&amp;quot; isn't nil and the parameter &amp;quot;dropdown_or_scale&amp;quot; is &amp;quot;dropdown&amp;quot; or &amp;quot;scale&amp;quot;. We added the test examples from 4 to 16 including the multiple for method &amp;quot;complete&amp;quot;, &amp;quot;dropdown_criterion_question&amp;quot;, &amp;quot;scale_criterion_question&amp;quot;.&lt;br /&gt;
* '''Test for method &amp;quot;complete&amp;quot; with or without answer and dorpdown_or_scale'''&lt;br /&gt;
'''Origin test'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 describe &amp;quot;#complete&amp;quot; do&lt;br /&gt;
    it &amp;quot;returns the html &amp;quot; do&lt;br /&gt;
      html = criterion.complete(0, nil, 0, 5).to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;div&amp;gt;&amp;lt;label for=\&amp;quot;responses_0\&amp;quot;&amp;gt;test txt&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''New test'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe &amp;quot;#complete&amp;quot; do&lt;br /&gt;
    it &amp;quot;returns the html without answer and no dropdown or scale&amp;quot; do&lt;br /&gt;
      html = criterion.complete(0, nil, 0, 5).to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;div&amp;gt;&amp;lt;label for=\&amp;quot;responses_0\&amp;quot;&amp;gt;test txt&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;returns the html without answer and dropdown&amp;quot; do&lt;br /&gt;
      html = criterion.complete(0, nil, 0, 5, dropdown_or_scale = 'dropdown').to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;div&amp;gt;&amp;lt;label for=\&amp;quot;responses_0\&amp;quot;&amp;gt;test txt&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div&amp;gt;&amp;lt;select id=\&amp;quot;responses_0_score\&amp;quot; name=\&amp;quot;responses[0][score]\&amp;quot; class=\&amp;quot;review-rating\&amp;quot; &amp;gt;&amp;lt;option value = ''&amp;gt;--&amp;lt;/option&amp;gt;&amp;lt;option value=0&amp;gt;0&amp;lt;/option&amp;gt;&amp;lt;option value=1&amp;gt;1&amp;lt;/option&amp;gt;&amp;lt;option value=2&amp;gt;2&amp;lt;/option&amp;gt;&amp;lt;option value=3&amp;gt;3&amp;lt;/option&amp;gt;&amp;lt;option value=4&amp;gt;4&amp;lt;/option&amp;gt;&amp;lt;option value=5&amp;gt;5&amp;lt;/option&amp;gt;&amp;lt;/select&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;textarea id=\&amp;quot;responses_0_comments\&amp;quot; name=\&amp;quot;responses[0][comment]\&amp;quot; class=\&amp;quot;tinymce\&amp;quot;&amp;gt;&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;returns the html with no comments answer and answer.answer outside questionnaire min and max and dropdown&amp;quot; do&lt;br /&gt;
      html = criterion.complete(0, answer_no_comments, 0, 5, dropdown_or_scale = 'dropdown').to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;div&amp;gt;&amp;lt;label for=\&amp;quot;responses_0\&amp;quot;&amp;gt;test txt&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div&amp;gt;&amp;lt;select id=\&amp;quot;responses_0_score\&amp;quot; name=\&amp;quot;responses[0][score]\&amp;quot; class=\&amp;quot;review-rating\&amp;quot; data-current-rating =8&amp;gt;&amp;lt;option value = ''&amp;gt;--&amp;lt;/option&amp;gt;&amp;lt;option value=0&amp;gt;0&amp;lt;/option&amp;gt;&amp;lt;option value=1&amp;gt;1&amp;lt;/option&amp;gt;&amp;lt;option value=2&amp;gt;2&amp;lt;/option&amp;gt;&amp;lt;option value=3&amp;gt;3&amp;lt;/option&amp;gt;&amp;lt;option value=4&amp;gt;4&amp;lt;/option&amp;gt;&amp;lt;option value=5&amp;gt;5&amp;lt;/option&amp;gt;&amp;lt;/select&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;textarea id=\&amp;quot;responses_0_comments\&amp;quot; name=\&amp;quot;responses[0][comment]\&amp;quot; class=\&amp;quot;tinymce\&amp;quot;&amp;gt;&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;returns the html with comments answer and answer.answer between questionnaire min and max and dropdown&amp;quot; do&lt;br /&gt;
      html = criterion.complete(0, answer_comments, 0, 5, dropdown_or_scale = 'dropdown').to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;div&amp;gt;&amp;lt;label for=\&amp;quot;responses_0\&amp;quot;&amp;gt;test txt&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div&amp;gt;&amp;lt;select id=\&amp;quot;responses_0_score\&amp;quot; name=\&amp;quot;responses[0][score]\&amp;quot; class=\&amp;quot;review-rating\&amp;quot; data-current-rating =3&amp;gt;&amp;lt;option value = ''&amp;gt;--&amp;lt;/option&amp;gt;&amp;lt;option value=0&amp;gt;0&amp;lt;/option&amp;gt;&amp;lt;option value=1&amp;gt;1&amp;lt;/option&amp;gt;&amp;lt;option value=2&amp;gt;2&amp;lt;/option&amp;gt;&amp;lt;option value=3 selected=\&amp;quot;selected\&amp;quot;&amp;gt;3&amp;lt;/option&amp;gt;&amp;lt;option value=4&amp;gt;4&amp;lt;/option&amp;gt;&amp;lt;option value=5&amp;gt;5&amp;lt;/option&amp;gt;&amp;lt;/select&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;textarea id=\&amp;quot;responses_0_comments\&amp;quot; name=\&amp;quot;responses[0][comment]\&amp;quot; class=\&amp;quot;tinymce\&amp;quot;&amp;gt;text comments&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;returns the html without answer and scale&amp;quot; do&lt;br /&gt;
      html = criterion.complete(0, nil, 0, 5, dropdown_or_scale = 'scale').to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;div&amp;gt;&amp;lt;label for=\&amp;quot;responses_0\&amp;quot;&amp;gt;test txt&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;input id=\&amp;quot;responses_0_score\&amp;quot; name=\&amp;quot;responses[0][score]\&amp;quot; type=\&amp;quot;hidden\&amp;quot;&amp;gt;&amp;lt;table&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;0&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;1&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;2&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;3&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;4&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;5&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;0\&amp;quot; value=\&amp;quot;0\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;checked=\&amp;quot;checked\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;1\&amp;quot; value=\&amp;quot;1\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;2\&amp;quot; value=\&amp;quot;2\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;3\&amp;quot; value=\&amp;quot;3\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;4\&amp;quot; value=\&amp;quot;4\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;5\&amp;quot; value=\&amp;quot;5\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;script&amp;gt;jQuery(\&amp;quot;input[name=Radio_1]:radio\&amp;quot;).change(function() {var response_score = jQuery(\&amp;quot;#responses_0_score\&amp;quot;);var checked_value = jQuery(\&amp;quot;input[name=Radio_1]:checked\&amp;quot;).val();response_score.val(checked_value);});&amp;lt;/script&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;&amp;lt;textarea cols=70 rows=1 id=\&amp;quot;responses_0_comments\&amp;quot; name=\&amp;quot;responses[0][comment]\&amp;quot; class=\&amp;quot;tinymce\&amp;quot;&amp;gt;&amp;lt;/textarea&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;returns the html with no comments answer and answer.answer outside questionnaire min and max and scale&amp;quot; do&lt;br /&gt;
      html = criterion.complete(0, answer_no_comments, 0, 5, dropdown_or_scale = 'scale').to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;div&amp;gt;&amp;lt;label for=\&amp;quot;responses_0\&amp;quot;&amp;gt;test txt&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;input id=\&amp;quot;responses_0_score\&amp;quot; name=\&amp;quot;responses[0][score]\&amp;quot; type=\&amp;quot;hidden\&amp;quot;value=\&amp;quot;8\&amp;quot;&amp;gt;&amp;lt;table&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;0&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;1&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;2&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;3&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;4&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;5&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;0\&amp;quot; value=\&amp;quot;0\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;1\&amp;quot; value=\&amp;quot;1\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;2\&amp;quot; value=\&amp;quot;2\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;3\&amp;quot; value=\&amp;quot;3\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;4\&amp;quot; value=\&amp;quot;4\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;5\&amp;quot; value=\&amp;quot;5\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;script&amp;gt;jQuery(\&amp;quot;input[name=Radio_1]:radio\&amp;quot;).change(function() {var response_score = jQuery(\&amp;quot;#responses_0_score\&amp;quot;);var checked_value = jQuery(\&amp;quot;input[name=Radio_1]:checked\&amp;quot;).val();response_score.val(checked_value);});&amp;lt;/script&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;&amp;lt;textarea cols=70 rows=1 id=\&amp;quot;responses_0_comments\&amp;quot; name=\&amp;quot;responses[0][comment]\&amp;quot; class=\&amp;quot;tinymce\&amp;quot;&amp;gt;&amp;lt;/textarea&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;returns the html with comments answer and answer.answer between questionnaire min and max and scale&amp;quot; do&lt;br /&gt;
      html = criterion.complete(0, answer_comments, 0, 5, dropdown_or_scale = 'scale').to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;div&amp;gt;&amp;lt;label for=\&amp;quot;responses_0\&amp;quot;&amp;gt;test txt&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;input id=\&amp;quot;responses_0_score\&amp;quot; name=\&amp;quot;responses[0][score]\&amp;quot; type=\&amp;quot;hidden\&amp;quot;value=\&amp;quot;3\&amp;quot;&amp;gt;&amp;lt;table&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;0&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;1&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;2&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;3&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;4&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;5&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;0\&amp;quot; value=\&amp;quot;0\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;1\&amp;quot; value=\&amp;quot;1\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;2\&amp;quot; value=\&amp;quot;2\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;3\&amp;quot; value=\&amp;quot;3\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;checked=\&amp;quot;checked\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;4\&amp;quot; value=\&amp;quot;4\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;5\&amp;quot; value=\&amp;quot;5\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;script&amp;gt;jQuery(\&amp;quot;input[name=Radio_1]:radio\&amp;quot;).change(function() {var response_score = jQuery(\&amp;quot;#responses_0_score\&amp;quot;);var checked_value = jQuery(\&amp;quot;input[name=Radio_1]:checked\&amp;quot;).val();response_score.val(checked_value);});&amp;lt;/script&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;&amp;lt;textarea cols=70 rows=1 id=\&amp;quot;responses_0_comments\&amp;quot; name=\&amp;quot;responses[0][comment]\&amp;quot; class=\&amp;quot;tinymce\&amp;quot;&amp;gt;text comments&amp;lt;/textarea&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Test for method &amp;quot;dropdown_criterion_question&amp;quot; with or without answer'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe &amp;quot;#dropdown_criterion_question&amp;quot; do&lt;br /&gt;
    it &amp;quot;returns the html without answer&amp;quot; do&lt;br /&gt;
      html = criterion.dropdown_criterion_question(0, nil, 0, 5).to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;div&amp;gt;&amp;lt;select id=\&amp;quot;responses_0_score\&amp;quot; name=\&amp;quot;responses[0][score]\&amp;quot; class=\&amp;quot;review-rating\&amp;quot; &amp;gt;&amp;lt;option value = ''&amp;gt;--&amp;lt;/option&amp;gt;&amp;lt;option value=0&amp;gt;0&amp;lt;/option&amp;gt;&amp;lt;option value=1&amp;gt;1&amp;lt;/option&amp;gt;&amp;lt;option value=2&amp;gt;2&amp;lt;/option&amp;gt;&amp;lt;option value=3&amp;gt;3&amp;lt;/option&amp;gt;&amp;lt;option value=4&amp;gt;4&amp;lt;/option&amp;gt;&amp;lt;option value=5&amp;gt;5&amp;lt;/option&amp;gt;&amp;lt;/select&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;textarea id=\&amp;quot;responses_0_comments\&amp;quot; name=\&amp;quot;responses[0][comment]\&amp;quot; class=\&amp;quot;tinymce\&amp;quot;&amp;gt;&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    it &amp;quot;returns the html with no comments answer and answer.answer outside questionnaire min and max&amp;quot; do&lt;br /&gt;
      html = criterion.dropdown_criterion_question(0, answer_no_comments, 0, 5).to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;div&amp;gt;&amp;lt;select id=\&amp;quot;responses_0_score\&amp;quot; name=\&amp;quot;responses[0][score]\&amp;quot; class=\&amp;quot;review-rating\&amp;quot; data-current-rating =8&amp;gt;&amp;lt;option value = ''&amp;gt;--&amp;lt;/option&amp;gt;&amp;lt;option value=0&amp;gt;0&amp;lt;/option&amp;gt;&amp;lt;option value=1&amp;gt;1&amp;lt;/option&amp;gt;&amp;lt;option value=2&amp;gt;2&amp;lt;/option&amp;gt;&amp;lt;option value=3&amp;gt;3&amp;lt;/option&amp;gt;&amp;lt;option value=4&amp;gt;4&amp;lt;/option&amp;gt;&amp;lt;option value=5&amp;gt;5&amp;lt;/option&amp;gt;&amp;lt;/select&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;textarea id=\&amp;quot;responses_0_comments\&amp;quot; name=\&amp;quot;responses[0][comment]\&amp;quot; class=\&amp;quot;tinymce\&amp;quot;&amp;gt;&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;returns the html with comments in answer and answer.answer between questionnaire min and max&amp;quot; do&lt;br /&gt;
      html = criterion.dropdown_criterion_question(0, answer_comments, 0, 5).to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;div&amp;gt;&amp;lt;select id=\&amp;quot;responses_0_score\&amp;quot; name=\&amp;quot;responses[0][score]\&amp;quot; class=\&amp;quot;review-rating\&amp;quot; data-current-rating =3&amp;gt;&amp;lt;option value = ''&amp;gt;--&amp;lt;/option&amp;gt;&amp;lt;option value=0&amp;gt;0&amp;lt;/option&amp;gt;&amp;lt;option value=1&amp;gt;1&amp;lt;/option&amp;gt;&amp;lt;option value=2&amp;gt;2&amp;lt;/option&amp;gt;&amp;lt;option value=3 selected=\&amp;quot;selected\&amp;quot;&amp;gt;3&amp;lt;/option&amp;gt;&amp;lt;option value=4&amp;gt;4&amp;lt;/option&amp;gt;&amp;lt;option value=5&amp;gt;5&amp;lt;/option&amp;gt;&amp;lt;/select&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;textarea id=\&amp;quot;responses_0_comments\&amp;quot; name=\&amp;quot;responses[0][comment]\&amp;quot; class=\&amp;quot;tinymce\&amp;quot;&amp;gt;text comments&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* '''Test for method &amp;quot;scale_criterion_question&amp;quot; with or without answer'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe &amp;quot;#scale_criterion_question&amp;quot; do&lt;br /&gt;
    it &amp;quot;returns the html without answer&amp;quot; do&lt;br /&gt;
      html = criterion.scale_criterion_question(0, nil, 0, 5).to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;input id=\&amp;quot;responses_0_score\&amp;quot; name=\&amp;quot;responses[0][score]\&amp;quot; type=\&amp;quot;hidden\&amp;quot;&amp;gt;&amp;lt;table&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;0&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;1&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;2&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;3&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;4&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;5&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;0\&amp;quot; value=\&amp;quot;0\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;checked=\&amp;quot;checked\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;1\&amp;quot; value=\&amp;quot;1\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;2\&amp;quot; value=\&amp;quot;2\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;3\&amp;quot; value=\&amp;quot;3\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;4\&amp;quot; value=\&amp;quot;4\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;5\&amp;quot; value=\&amp;quot;5\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;script&amp;gt;jQuery(\&amp;quot;input[name=Radio_1]:radio\&amp;quot;).change(function() {var response_score = jQuery(\&amp;quot;#responses_0_score\&amp;quot;);var checked_value = jQuery(\&amp;quot;input[name=Radio_1]:checked\&amp;quot;).val();response_score.val(checked_value);});&amp;lt;/script&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;&amp;lt;textarea cols=70 rows=1 id=\&amp;quot;responses_0_comments\&amp;quot; name=\&amp;quot;responses[0][comment]\&amp;quot; class=\&amp;quot;tinymce\&amp;quot;&amp;gt;&amp;lt;/textarea&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;returns the html with no comments answer and answer.answer outside questionnaire min and max&amp;quot; do&lt;br /&gt;
      html = criterion.scale_criterion_question(0, answer_no_comments, 0, 5).to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;input id=\&amp;quot;responses_0_score\&amp;quot; name=\&amp;quot;responses[0][score]\&amp;quot; type=\&amp;quot;hidden\&amp;quot;value=\&amp;quot;8\&amp;quot;&amp;gt;&amp;lt;table&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;0&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;1&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;2&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;3&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;4&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;5&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;0\&amp;quot; value=\&amp;quot;0\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;1\&amp;quot; value=\&amp;quot;1\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;2\&amp;quot; value=\&amp;quot;2\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;3\&amp;quot; value=\&amp;quot;3\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;4\&amp;quot; value=\&amp;quot;4\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;5\&amp;quot; value=\&amp;quot;5\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;script&amp;gt;jQuery(\&amp;quot;input[name=Radio_1]:radio\&amp;quot;).change(function() {var response_score = jQuery(\&amp;quot;#responses_0_score\&amp;quot;);var checked_value = jQuery(\&amp;quot;input[name=Radio_1]:checked\&amp;quot;).val();response_score.val(checked_value);});&amp;lt;/script&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;&amp;lt;textarea cols=70 rows=1 id=\&amp;quot;responses_0_comments\&amp;quot; name=\&amp;quot;responses[0][comment]\&amp;quot; class=\&amp;quot;tinymce\&amp;quot;&amp;gt;&amp;lt;/textarea&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;returns the html with comments answer and answer.answer between questionnaire min and max&amp;quot; do&lt;br /&gt;
      html = criterion.scale_criterion_question(0, answer_comments, 0, 5).to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;input id=\&amp;quot;responses_0_score\&amp;quot; name=\&amp;quot;responses[0][score]\&amp;quot; type=\&amp;quot;hidden\&amp;quot;value=\&amp;quot;3\&amp;quot;&amp;gt;&amp;lt;table&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;0&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;1&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;2&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;3&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;4&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;label&amp;gt;5&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;0\&amp;quot; value=\&amp;quot;0\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;1\&amp;quot; value=\&amp;quot;1\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;2\&amp;quot; value=\&amp;quot;2\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;3\&amp;quot; value=\&amp;quot;3\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;checked=\&amp;quot;checked\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;4\&amp;quot; value=\&amp;quot;4\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;input type=\&amp;quot;radio\&amp;quot; id=\&amp;quot;5\&amp;quot; value=\&amp;quot;5\&amp;quot; name=\&amp;quot;Radio_1\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;script&amp;gt;jQuery(\&amp;quot;input[name=Radio_1]:radio\&amp;quot;).change(function() {var response_score = jQuery(\&amp;quot;#responses_0_score\&amp;quot;);var checked_value = jQuery(\&amp;quot;input[name=Radio_1]:checked\&amp;quot;).val();response_score.val(checked_value);});&amp;lt;/script&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td width=\&amp;quot;10%\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;&amp;lt;textarea cols=70 rows=1 id=\&amp;quot;responses_0_comments\&amp;quot; name=\&amp;quot;responses[0][comment]\&amp;quot; class=\&amp;quot;tinymce\&amp;quot;&amp;gt;text comments&amp;lt;/textarea&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''All existing tests passed'''&lt;br /&gt;
[[File:Test1.png]]&lt;br /&gt;
&lt;br /&gt;
=== Manual Testing ===&lt;br /&gt;
'''Test Log in'''&lt;br /&gt;
Website url: http://152.7.99.41:8080/&lt;br /&gt;
Log in: instructor6&lt;br /&gt;
Password: password&lt;br /&gt;
Log in: student2064&lt;br /&gt;
Password: password&lt;br /&gt;
&lt;br /&gt;
'''Test criterion works well in questionnaire'''&lt;br /&gt;
&lt;br /&gt;
1. After logging in as a student, click the &amp;quot;Assignments&amp;quot;&lt;br /&gt;
2. Choose an assignment, like &amp;quot;Backchannel application review&amp;quot;&lt;br /&gt;
3. You can choose &amp;quot;Your scores&amp;quot; to see the review results.&lt;br /&gt;
4. Click Criterion 1, you can see all the reviews for this criterion.&lt;br /&gt;
5. Click &amp;quot;toggle question list&amp;quot;, you can see all criterion questions.&lt;br /&gt;
&lt;br /&gt;
6. After logging in as an instructor, choose &amp;quot;Questionnaires&amp;quot; tag&lt;br /&gt;
7. Click on the name Review: This should show a drop-down showing different reviews made.&lt;br /&gt;
8. Choose a review, select the edit icon to the right.&lt;br /&gt;
8. Change dropbox of question type to Criterion, select Add &amp;quot;2&amp;quot; more. Press the add button.&lt;br /&gt;
9. Edit question content: &amp;quot;Test question Textarea&amp;quot;, &amp;quot;Test question Criterion1&amp;quot;, and &amp;quot;Test question Criterion2&amp;quot; in that order.&lt;br /&gt;
10. You can also change the question content for exited criterion question&lt;br /&gt;
&lt;br /&gt;
These manual tests show criterion works well. Feel free to try your own test cases.&lt;/div&gt;</summary>
		<author><name>Shmehta</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC517_(Spring_2020)_-_E2010._Refactor_criterion.rb&amp;diff=131795</id>
		<title>CSC517 (Spring 2020) - E2010. Refactor criterion.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC517_(Spring_2020)_-_E2010._Refactor_criterion.rb&amp;diff=131795"/>
		<updated>2020-03-23T19:44:06Z</updated>

		<summary type="html">&lt;p&gt;Shmehta: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= E2010 Refactor criterion.rb =&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project.&lt;br /&gt;
&lt;br /&gt;
== About Expertiza ==&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create new assignments and customize new or existing assignments. It also allows the instructor to create a list of topics the students can sign up for. Students can form teams in Expertiza to work on various projects and assignments. Students can also peer review other students' submissions. Expertiza supports submission across various document types, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
The criterion.rb model consists of functions that decide what to display while creating, editing and viewing the questionnaires depending on whether the user is an instructor, a teaching assistant or a student. So, this file consists of a lot of HTML code that is rendered to the final questionnaire view. &lt;br /&gt;
&lt;br /&gt;
The current version of this controller has four methods, but two methods are very long and would require refactoring. The primary problem with these functions is that it consists of many statements of string concatenation. The HTML code which is rendered to the final view is made up of concatenations. &lt;br /&gt;
&lt;br /&gt;
Another issue with the code is that the branch conditions size for the complete and the view_completed_question method is very high. Also, this controller has very few comments. They are specifically needed to differentiate between the purpose of numerous nested branches from each other.&lt;br /&gt;
&lt;br /&gt;
== About criterion.rb ==&lt;br /&gt;
The ''criterion.rb'' model consists of functions that decide what to display while creating, editing and viewing the questionnaires depending on whether the user is an instructor, a teaching assistant or a student. So this file consists of a lot of HTML code that is rendered to the final questionnaire view.&lt;br /&gt;
&lt;br /&gt;
For this project, we have to deal with the following two methods:&lt;br /&gt;
* The '''''complete''''' method, which is 104 lines long. this method returns the display for the students when they are filling the questionnaire. It includes the advice given for different questions, dropdown options to rate a project based on the question, a textarea to enter comments and so on.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def complete(count, answer = nil, questionnaire_min, questionnaire_max, dropdown_or_scale)&lt;br /&gt;
    if self.size.nil?&lt;br /&gt;
      cols = '70'&lt;br /&gt;
      rows = '1'&lt;br /&gt;
    else&lt;br /&gt;
      cols = self.size.split(',')[0]&lt;br /&gt;
      rows = self.size.split(',')[1]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    html = '&amp;lt;div&amp;gt;&amp;lt;label for=&amp;quot;responses_' + count.to_s + '&amp;quot;&amp;gt;' + self.txt + '&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;'&lt;br /&gt;
    # show advice for each criterion question&lt;br /&gt;
    question_advices = QuestionAdvice.where(question_id: self.id).sort_by(&amp;amp;:id)&lt;br /&gt;
    advice_total_length = 0&lt;br /&gt;
&lt;br /&gt;
    question_advices.each do |question_advice|&lt;br /&gt;
      advice_total_length += question_advice.advice.length if question_advice.advice &amp;amp;&amp;amp; question_advice.advice != &amp;quot;&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if !question_advices.empty? and advice_total_length &amp;gt; 0&lt;br /&gt;
      html += '&amp;lt;a id=&amp;quot;showAdivce_' + self.id.to_s + '&amp;quot; onclick=&amp;quot;showAdvice(' + self.id.to_s + ')&amp;quot;&amp;gt;Show advice&amp;lt;/a&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;script&amp;gt;'&lt;br /&gt;
      html += 'function showAdvice(i){'&lt;br /&gt;
      html += 'var element = document.getElementById(&amp;quot;showAdivce_&amp;quot; + i.toString());'&lt;br /&gt;
      html += 'var show = element.innerHTML == &amp;quot;Hide advice&amp;quot;;'&lt;br /&gt;
      html += 'if (show){'&lt;br /&gt;
      html += 'element.innerHTML=&amp;quot;Show advice&amp;quot;;'&lt;br /&gt;
      html += '}else{'&lt;br /&gt;
      html += 'element.innerHTML=&amp;quot;Hide advice&amp;quot;;}'&lt;br /&gt;
      html += 'toggleAdvice(i);}'&lt;br /&gt;
&lt;br /&gt;
      html += 'function toggleAdvice(i) {'&lt;br /&gt;
      html += 'var elem = document.getElementById(i.toString() + &amp;quot;_myDiv&amp;quot;);'&lt;br /&gt;
      html += 'if (elem.style.display == &amp;quot;none&amp;quot;) {'&lt;br /&gt;
      html += 'elem.style.display = &amp;quot;&amp;quot;;'&lt;br /&gt;
      html += '} else {'&lt;br /&gt;
      html += 'elem.style.display = &amp;quot;none&amp;quot;;}}'&lt;br /&gt;
      html += '&amp;lt;/script&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;div id=&amp;quot;' + self.id.to_s + '_myDiv&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;'&lt;br /&gt;
      # [2015-10-26] Zhewei:&lt;br /&gt;
      # best to order advices high to low, e.g., 5 to 1&lt;br /&gt;
      # each level used to be a link;&lt;br /&gt;
      # clicking on the link caused the dropbox to be filled in with the corresponding number&lt;br /&gt;
      question_advices.reverse.each_with_index do |question_advice, index|&lt;br /&gt;
        html += '&amp;lt;a id=&amp;quot;changeScore_&amp;gt;' + self.id.to_s + '&amp;quot; onclick=&amp;quot;changeScore(' + count.to_s + ',' + index.to_s + ')&amp;quot;&amp;gt;'&lt;br /&gt;
        html += (self.questionnaire.max_question_score - index).to_s + ' - ' + question_advice.advice + '&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;'&lt;br /&gt;
        html += '&amp;lt;script&amp;gt;'&lt;br /&gt;
        html += 'function changeScore(i, j) {'&lt;br /&gt;
        html += 'var elem = jQuery(&amp;quot;#responses_&amp;quot; + i.toString() + &amp;quot;_score&amp;quot;);'&lt;br /&gt;
        html += 'var opts = elem.children(&amp;quot;option&amp;quot;).length;'&lt;br /&gt;
        html += 'elem.val((' + self.questionnaire.max_question_score.to_s + ' - j).toString());}'&lt;br /&gt;
        html += '&amp;lt;/script&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;/div&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if dropdown_or_scale == 'dropdown'&lt;br /&gt;
      current_value = &amp;quot;&amp;quot;&lt;br /&gt;
      current_value += 'data-current-rating =' + answer.answer.to_s if !answer.nil?&lt;br /&gt;
      html += '&amp;lt;div&amp;gt;&amp;lt;select id=&amp;quot;responses_' + count.to_s + '_score&amp;quot; name=&amp;quot;responses[' + count.to_s + '][score]&amp;quot; class=&amp;quot;review-rating&amp;quot; ' + current_value + '&amp;gt;'&lt;br /&gt;
      html += &amp;quot;&amp;lt;option value = ''&amp;gt;--&amp;lt;/option&amp;gt;&amp;quot;&lt;br /&gt;
      questionnaire_min.upto(questionnaire_max).each do |j|&lt;br /&gt;
        html += if !answer.nil? and j == answer.answer&lt;br /&gt;
                  '&amp;lt;option value=' + j.to_s + ' selected=&amp;quot;selected&amp;quot;&amp;gt;'&lt;br /&gt;
                else&lt;br /&gt;
                  '&amp;lt;option value=' + j.to_s + '&amp;gt;'&lt;br /&gt;
                end&lt;br /&gt;
&lt;br /&gt;
        html += j.to_s&lt;br /&gt;
        if j == questionnaire_min&lt;br /&gt;
          html += &amp;quot;-&amp;quot; + self.min_label if self.min_label.present?&lt;br /&gt;
        elsif j == questionnaire_max&lt;br /&gt;
          html += &amp;quot;-&amp;quot; + self.max_label if self.max_label.present?&lt;br /&gt;
        end&lt;br /&gt;
        html += &amp;quot;&amp;lt;/option&amp;gt;&amp;quot;&lt;br /&gt;
      end&lt;br /&gt;
      html += &amp;quot;&amp;lt;/select&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;&lt;br /&gt;
      html += '&amp;lt;textarea' + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
       ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
      html += answer.comments unless answer.nil?&lt;br /&gt;
      html += '&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
    elsif dropdown_or_scale == 'scale'&lt;br /&gt;
      html += '&amp;lt;input id=&amp;quot;responses_' + count.to_s + '_score&amp;quot; name=&amp;quot;responses[' + count.to_s + '][score]&amp;quot; type=&amp;quot;hidden&amp;quot;'&lt;br /&gt;
      html += 'value=&amp;quot;' + answer.answer.to_s + '&amp;quot;' unless answer.nil?&lt;br /&gt;
      html += '&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;table&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;tr&amp;gt;&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      (questionnaire_min..questionnaire_max).each do |j|&lt;br /&gt;
        html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;label&amp;gt;' + j.to_s + '&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += if !self.min_label.nil?&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;' + self.min_label + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
              else&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
              end&lt;br /&gt;
      (questionnaire_min..questionnaire_max).each do |j|&lt;br /&gt;
        html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;input type=&amp;quot;radio&amp;quot; id=&amp;quot;' + j.to_s + '&amp;quot; value=&amp;quot;' + j.to_s + '&amp;quot; name=&amp;quot;Radio_' + self.id.to_s + '&amp;quot;'&lt;br /&gt;
        html += 'checked=&amp;quot;checked&amp;quot;' if (!answer.nil? and answer.answer == j) or (answer.nil? and questionnaire_min == j)&lt;br /&gt;
        html += '&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;script&amp;gt;jQuery(&amp;quot;input[name=Radio_' + self.id.to_s + ']:radio&amp;quot;).change(function() {'&lt;br /&gt;
      html += 'var response_score = jQuery(&amp;quot;#responses_' + count.to_s + '_score&amp;quot;);'&lt;br /&gt;
      html += 'var checked_value = jQuery(&amp;quot;input[name=Radio_' + self.id.to_s + ']:checked&amp;quot;).val();'&lt;br /&gt;
      html += 'response_score.val(checked_value);});&amp;lt;/script&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += if !self.max_label.nil?&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;' + self.max_label + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
              else&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
              end&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;textarea cols=' + cols + ' rows=' + rows + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
        ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
      html += answer.comments unless answer.nil?&lt;br /&gt;
      html += '&amp;lt;/textarea&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    end&lt;br /&gt;
    safe_join([&amp;quot;&amp;quot;.html_safe, &amp;quot;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The '''''view_completed_question''''' method, which is 47 lies long. Thismethod is responsible to return the display if a student is viewingan already filled-out questionnaire.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def view_completed_question(count, answer, questionnaire_max, tag_prompt_deployments = nil, current_user = nil)&lt;br /&gt;
    html = '&amp;lt;b&amp;gt;' + count.to_s + &amp;quot;. &amp;quot; + self.txt + ' [Max points: ' + questionnaire_max.to_s + &amp;quot;]&amp;lt;/b&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    score = answer &amp;amp;&amp;amp; !answer.answer.nil? ? answer.answer.to_s : &amp;quot;-&amp;quot;&lt;br /&gt;
    score_percent = if score != &amp;quot;-&amp;quot;&lt;br /&gt;
                      answer.answer * 1.0 / questionnaire_max&lt;br /&gt;
                    else&lt;br /&gt;
                      0&lt;br /&gt;
                    end&lt;br /&gt;
&lt;br /&gt;
    score_color = if score_percent &amp;gt; 0.8&lt;br /&gt;
                    &amp;quot;c5&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.6&lt;br /&gt;
                    &amp;quot;c4&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.4&lt;br /&gt;
                    &amp;quot;c3&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.2&lt;br /&gt;
                    &amp;quot;c2&amp;quot;&lt;br /&gt;
                  else&lt;br /&gt;
                    &amp;quot;c1&amp;quot;&lt;br /&gt;
                  end&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;table cellpadding=&amp;quot;5&amp;quot;&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;tr&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;div class=&amp;quot;' + score_color + '&amp;quot; style=&amp;quot;width:30px; height:30px;' \&lt;br /&gt;
      ' border-radius:50%; font-size:15px; color:black; line-height:30px; text-align:center;&amp;quot;&amp;gt;'&lt;br /&gt;
    html += score&lt;br /&gt;
    html += '&amp;lt;/div&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;/td&amp;gt;'&lt;br /&gt;
    if answer &amp;amp;&amp;amp; !answer.comments.nil?&lt;br /&gt;
      html += '&amp;lt;td style=&amp;quot;padding-left:10px&amp;quot;&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;br&amp;gt;' + answer.comments.html_safe&lt;br /&gt;
      html += '&amp;lt;/td&amp;gt;'&lt;br /&gt;
      #### start code to show tag prompts ####&lt;br /&gt;
      unless tag_prompt_deployments.nil?&lt;br /&gt;
        # show check boxes for answer tagging&lt;br /&gt;
        resp = Response.find(answer.response_id)&lt;br /&gt;
        question = Question.find(answer.question_id)&lt;br /&gt;
        if tag_prompt_deployments.count &amp;gt; 0&lt;br /&gt;
          html += '&amp;lt;tr&amp;gt;&amp;lt;td colspan=&amp;quot;2&amp;quot;&amp;gt;'&lt;br /&gt;
          tag_prompt_deployments.each do |tag_dep|&lt;br /&gt;
            tag_prompt = TagPrompt.find(tag_dep.tag_prompt_id)&lt;br /&gt;
            if tag_dep.question_type == question.type and answer.comments.length &amp;gt; tag_dep.answer_length_threshold.to_i&lt;br /&gt;
              html += tag_prompt.html_control(tag_dep, answer, current_user)&lt;br /&gt;
            end&lt;br /&gt;
          end&lt;br /&gt;
          html += '&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;'&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      #### end code to show tag prompts ####&lt;br /&gt;
    end&lt;br /&gt;
    html += '&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;'&lt;br /&gt;
    safe_join([&amp;quot;&amp;quot;.html_safe, &amp;quot;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Proposed Solution ==&lt;br /&gt;
Our goal is to refactor the complete and view_completed_question method mainly by reducing the number of lines code for each function and also by introducing new methods to make the code more modular. We will also try to reduce the branch condition size wherever possible and hence reduce the cyclomatic complexity for these two functions. We also plan to introduce comments wherever needed to make the code more understandable. The main aim is to reduce the number of lines and make the code more compact without affecting the readability of the code.&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
&lt;br /&gt;
We tried to tackle the issues mentioned in the problem statement as described below:&lt;br /&gt;
&lt;br /&gt;
=== The ''complete'' method ===&lt;br /&gt;
&lt;br /&gt;
All the code in the model is just HTML. We thought of removing the code from here and putting it in a .erb file but it didn’t make much sense as the HTML code was heavily branched by the if-else conditions and it would just have been taking it out from this function and putting it in another file. We instead decided to refactor it in the file. We mainly combined the short HTML strings into longer ones but not too long so that the Code Climate cannot throw a “line too long” error. Another thing we did is reduce the number of lines used by condition statements by using the shorthand which beautifully consolidates three or more lines of code (read: if-else statements) into one readable line of code. (We also created another method for the repeated HTML code, so we just have to call the method rather than repeating the code. It increases code re-usability and reduces the number of lines of code.)&lt;br /&gt;
&lt;br /&gt;
====''List of changes''====&lt;br /&gt;
&lt;br /&gt;
* Combining the short HTML strings into longer ones&lt;br /&gt;
[[File:Combine1.png]]&lt;br /&gt;
* Using one readable line of code instead of three or more lines of if-else statements&lt;br /&gt;
[[File:Oneline1.png]]&lt;br /&gt;
&lt;br /&gt;
====''The modified ''complete'' method''====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def complete(count, answer = nil, questionnaire_min, questionnaire_max, dropdown_or_scale)&lt;br /&gt;
    if self.size.nil?&lt;br /&gt;
      cols = '70'&lt;br /&gt;
      rows = '1'&lt;br /&gt;
    else&lt;br /&gt;
      cols = self.size.split(',')[0]&lt;br /&gt;
      rows = self.size.split(',')[1]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    html = '&amp;lt;div&amp;gt;&amp;lt;label for=&amp;quot;responses_' + count.to_s + '&amp;quot;&amp;gt;' + self.txt + '&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;'&lt;br /&gt;
    # show advice for each criterion question&lt;br /&gt;
    question_advices = QuestionAdvice.where(question_id: self.id).sort_by(&amp;amp;:id)&lt;br /&gt;
    advice_total_length = 0&lt;br /&gt;
&lt;br /&gt;
    question_advices.each do |question_advice|&lt;br /&gt;
      advice_total_length += question_advice.advice.length if question_advice.advice &amp;amp;&amp;amp; question_advice.advice != &amp;quot;&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if !question_advices.empty? and advice_total_length &amp;gt; 0&lt;br /&gt;
      html += '&amp;lt;a id=&amp;quot;showAdvice_' + self.id.to_s + '&amp;quot; onclick=&amp;quot;showAdvice(' + self.id.to_s + ')&amp;quot;&amp;gt;Show advice&amp;lt;/a&amp;gt;&amp;lt;script&amp;gt;'&lt;br /&gt;
      html += 'function showAdvice(i){var element = document.getElementById(&amp;quot;showAdivce_&amp;quot; + i.toString());'&lt;br /&gt;
      html += 'var show = element.innerHTML == &amp;quot;Hide advice&amp;quot;;'&lt;br /&gt;
      html += 'if (show){element.innerHTML=&amp;quot;Show advice&amp;quot;;} else{element.innerHTML=&amp;quot;Hide advice&amp;quot;;}toggleAdvice(i);}'&lt;br /&gt;
&lt;br /&gt;
      html += 'function toggleAdvice(i) {var elem = document.getElementById(i.toString() + &amp;quot;_myDiv&amp;quot;);'&lt;br /&gt;
      html += 'if (elem.style.display == &amp;quot;none&amp;quot;) {elem.style.display = &amp;quot;&amp;quot;;} else {elem.style.display = &amp;quot;none&amp;quot;;}}&amp;lt;/script&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;div id=&amp;quot;' + self.id.to_s + '_myDiv&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;'&lt;br /&gt;
      # [2015-10-26] Zhewei:&lt;br /&gt;
      # best to order advices high to low, e.g., 5 to 1&lt;br /&gt;
      # each level used to be a link;&lt;br /&gt;
      # clicking on the link caused the dropbox to be filled in with the corresponding number&lt;br /&gt;
      question_advices.reverse.each_with_index do |question_advice, index|&lt;br /&gt;
        html += '&amp;lt;a id=&amp;quot;changeScore_&amp;gt;' + self.id.to_s + '&amp;quot; onclick=&amp;quot;changeScore(' + count.to_s + ',' + index.to_s + ')&amp;quot;&amp;gt;'&lt;br /&gt;
        html += (self.questionnaire.max_question_score - index).to_s + ' - ' + question_advice.advice + '&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;script&amp;gt;'&lt;br /&gt;
        html += 'function changeScore(i, j) {var elem = jQuery(&amp;quot;#responses_&amp;quot; + i.toString() + &amp;quot;_score&amp;quot;);'&lt;br /&gt;
        html += 'var opts = elem.children(&amp;quot;option&amp;quot;).length;'&lt;br /&gt;
        html += 'elem.val((' + self.questionnaire.max_question_score.to_s + ' - j).toString());}&amp;lt;/script&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;/div&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if dropdown_or_scale == 'dropdown'&lt;br /&gt;
      current_value = &amp;quot;&amp;quot;&lt;br /&gt;
      current_value += 'data-current-rating =' + answer.answer.to_s if !answer.nil?&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;div&amp;gt;&amp;lt;select id=&amp;quot;responses_' + count.to_s + '_score&amp;quot; name=&amp;quot;responses[' + count.to_s + '][score]&amp;quot; class=&amp;quot;review-rating&amp;quot; ' + current_value + '&amp;gt;' + &amp;quot;&amp;lt;option value = ''&amp;gt;--&amp;lt;/option&amp;gt;&amp;quot; + '&amp;lt;option value='&lt;br /&gt;
      questionnaire_min.upto(questionnaire_max).each do |j|&lt;br /&gt;
        html += j.to_s + 'selected=&amp;quot;selected&amp;quot;' if !answer.nil? and j == answer.answer + '&amp;gt;'        &lt;br /&gt;
        html += j.to_s + &amp;quot;-&amp;quot;&lt;br /&gt;
        html += self.min_label if self.min_label.present? and j == questionnaire_min + &amp;quot;&amp;lt;/option&amp;gt;&amp;quot;&lt;br /&gt;
        html += self.max_label if self.max_label.present? and j == questionnaire_max + &amp;quot;&amp;lt;/option&amp;gt;&amp;quot;&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;/select&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;textarea' + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
       ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
      html += answer.comments unless answer.nil? + '&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
    elsif dropdown_or_scale == 'scale'&lt;br /&gt;
      html += '&amp;lt;input id=&amp;quot;responses_' + count.to_s + '_score&amp;quot; name=&amp;quot;responses[' + count.to_s + '][score]&amp;quot; type=&amp;quot;hidden&amp;quot;'&lt;br /&gt;
      html += 'value=&amp;quot;' + answer.answer.to_s + '&amp;quot;' unless answer.nil? + '&amp;gt;&amp;lt;table&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      (questionnaire_min..questionnaire_max).each do |j|&lt;br /&gt;
        html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;label&amp;gt;' + j.to_s + '&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;' + self.min_label if !self.min_label.nil? + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      (questionnaire_min..questionnaire_max).each do |j|&lt;br /&gt;
        html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;input type=&amp;quot;radio&amp;quot; id=&amp;quot;' + j.to_s + '&amp;quot; value=&amp;quot;' + j.to_s + '&amp;quot; name=&amp;quot;Radio_' + self.id.to_s + '&amp;quot;'&lt;br /&gt;
        html += 'checked=&amp;quot;checked&amp;quot;' if (!answer.nil? and answer.answer == j) or (answer.nil? and questionnaire_min == j) + '&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;script&amp;gt;jQuery(&amp;quot;input[name=Radio_' + self.id.to_s + ']:radio&amp;quot;).change(function() {var response_score = jQuery(&amp;quot;#responses_' + count.to_s + '_score&amp;quot;);'&lt;br /&gt;
      html += 'var checked_value = jQuery(&amp;quot;input[name=Radio_' + self.id.to_s + ']:checked&amp;quot;).val();'&lt;br /&gt;
      html += 'response_score.val(checked_value);});&amp;lt;/script&amp;gt;&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += self.max_label if !self.max_label.nil? + '&amp;lt;/td&amp;gt;&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;textarea cols=' + cols + ' rows=' + rows + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
        ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
      html += answer.comments unless answer.nil? + '&amp;lt;/textarea&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
    safe_join([&amp;quot;&amp;quot;.html_safe, &amp;quot;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====The ''view_completed_question&amp;quot; method====&lt;br /&gt;
&lt;br /&gt;
The main task here was to reduce the nested if-else branching and reduce the number of arguments for this function. This was a very small method with its major dependent functions present in response.rb file. To refactor this method, we would have had to refactor response.rb and in turn, the other question subclasses which would make it very complex and break the code. According to us, refactoring this method along with the response.rb file would make more sense. We still made some changes in the file like concatenating small HTML string and using shorthand for if-else condition statements. &lt;br /&gt;
&lt;br /&gt;
The modified ''view_completed_question'' method is as below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def view_completed_question(count, answer, questionnaire_max, tag_prompt_deployments = nil, current_user = nil)&lt;br /&gt;
    html = '&amp;lt;b&amp;gt;' + count.to_s + &amp;quot;. &amp;quot; + self.txt + ' [Max points: ' + questionnaire_max.to_s + &amp;quot;]&amp;lt;/b&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    score = answer &amp;amp;&amp;amp; !answer.answer.nil? ? answer.answer.to_s : &amp;quot;-&amp;quot;&lt;br /&gt;
    score_percent = score != &amp;quot;-&amp;quot; ? answer.answer * 1.0 / questionnaire_max : 0&lt;br /&gt;
    score_color = if score_percent &amp;gt; 0.8&lt;br /&gt;
                    &amp;quot;c5&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.6&lt;br /&gt;
                    &amp;quot;c4&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.4&lt;br /&gt;
                    &amp;quot;c3&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.2&lt;br /&gt;
                    &amp;quot;c2&amp;quot;&lt;br /&gt;
                  else&lt;br /&gt;
                    &amp;quot;c1&amp;quot;&lt;br /&gt;
                  end&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;table cellpadding=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;div class=&amp;quot;' + score_color + '&amp;quot; style=&amp;quot;width:30px; height:30px;' \&lt;br /&gt;
      ' border-radius:50%; font-size:15px; color:black; line-height:30px; text-align:center;&amp;quot;&amp;gt;'&lt;br /&gt;
    html += score + '&amp;lt;/div&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    if answer &amp;amp;&amp;amp; !answer.comments.nil?&lt;br /&gt;
      html += '&amp;lt;td style=&amp;quot;padding-left:10px&amp;quot;&amp;gt;&amp;lt;br&amp;gt;' + answer.comments.html_safe + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
      #### start code to show tag prompts ####&lt;br /&gt;
      unless tag_prompt_deployments.nil?&lt;br /&gt;
        # show check boxes for answer tagging&lt;br /&gt;
        resp = Response.find(answer.response_id)&lt;br /&gt;
        question = Question.find(answer.question_id)&lt;br /&gt;
        if tag_prompt_deployments.count &amp;gt; 0&lt;br /&gt;
          html += '&amp;lt;tr&amp;gt;&amp;lt;td colspan=&amp;quot;2&amp;quot;&amp;gt;'&lt;br /&gt;
          tag_prompt_deployments.each do |tag_dep|&lt;br /&gt;
            tag_prompt = TagPrompt.find(tag_dep.tag_prompt_id)&lt;br /&gt;
            if tag_dep.question_type == question.type and answer.comments.length &amp;gt; tag_dep.answer_length_threshold.to_i&lt;br /&gt;
              html += tag_prompt.html_control(tag_dep, answer, current_user)&lt;br /&gt;
            end&lt;br /&gt;
          end&lt;br /&gt;
          html += '&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;'&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      #### end code to show tag prompts ####&lt;br /&gt;
    end&lt;br /&gt;
    html += '&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;'&lt;br /&gt;
    safe_join([&amp;quot;&amp;quot;.html_safe, &amp;quot;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Testing ==&lt;br /&gt;
&lt;br /&gt;
We are running Rspec tests to make sure the coverage is the same and manually checking the pages to make sure there are not any issues and the code is not breaking&lt;/div&gt;</summary>
		<author><name>Shmehta</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC517_(Spring_2020)_-_E2010._Refactor_criterion.rb&amp;diff=131713</id>
		<title>CSC517 (Spring 2020) - E2010. Refactor criterion.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC517_(Spring_2020)_-_E2010._Refactor_criterion.rb&amp;diff=131713"/>
		<updated>2020-03-23T15:59:26Z</updated>

		<summary type="html">&lt;p&gt;Shmehta: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= E2010 Refactor criterion.rb =&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project.&lt;br /&gt;
&lt;br /&gt;
== About Expertiza ==&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create new assignments and customize new or existing assignments. It also allows the instructor to create a list of topics the students can sign up for. Students can form teams in Expertiza to work on various projects and assignments. Students can also peer review other students' submissions. Expertiza supports submission across various document types, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
The criterion.rb model consists of functions that decide what to display while creating, editing and viewing the questionnaires depending on whether the user is an instructor, a teaching assistant or a student. So, this file consists of a lot of HTML code that is rendered to the final questionnaire view. &lt;br /&gt;
&lt;br /&gt;
The current version of this controller has four methods, but two methods are very long and would require refactoring. The primary problem with these functions is that it consists of many statements of string concatenation. The HTML code which is rendered to the final view is made up of concatenations. &lt;br /&gt;
&lt;br /&gt;
Another issue with the code is that the branch conditions size for the complete and the view_completed_question method is very high. Also, this controller has very few comments. They are specifically needed to differentiate between the purpose of numerous nested branches from each other.&lt;br /&gt;
&lt;br /&gt;
== About criterion.rb ==&lt;br /&gt;
The ''criterion.rb'' model consists of functions that decide what to display while creating, editing and viewing the questionnaires depending on whether the user is an instructor, a teaching assistant or a student. So this file consists of a lot of HTML code that is rendered to the final questionnaire view.&lt;br /&gt;
&lt;br /&gt;
For this project, we have to deal with the following two methods:&lt;br /&gt;
* The '''''complete''''' method, which is 104 lines long. this method returns the display for the students when they are filling the questionnaire. It includes the advice given for different questions, dropdown options to rate a project based on the question, a textarea to enter comments and so on.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def complete(count, answer = nil, questionnaire_min, questionnaire_max, dropdown_or_scale)&lt;br /&gt;
    if self.size.nil?&lt;br /&gt;
      cols = '70'&lt;br /&gt;
      rows = '1'&lt;br /&gt;
    else&lt;br /&gt;
      cols = self.size.split(',')[0]&lt;br /&gt;
      rows = self.size.split(',')[1]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    html = '&amp;lt;div&amp;gt;&amp;lt;label for=&amp;quot;responses_' + count.to_s + '&amp;quot;&amp;gt;' + self.txt + '&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;'&lt;br /&gt;
    # show advice for each criterion question&lt;br /&gt;
    question_advices = QuestionAdvice.where(question_id: self.id).sort_by(&amp;amp;:id)&lt;br /&gt;
    advice_total_length = 0&lt;br /&gt;
&lt;br /&gt;
    question_advices.each do |question_advice|&lt;br /&gt;
      advice_total_length += question_advice.advice.length if question_advice.advice &amp;amp;&amp;amp; question_advice.advice != &amp;quot;&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if !question_advices.empty? and advice_total_length &amp;gt; 0&lt;br /&gt;
      html += '&amp;lt;a id=&amp;quot;showAdivce_' + self.id.to_s + '&amp;quot; onclick=&amp;quot;showAdvice(' + self.id.to_s + ')&amp;quot;&amp;gt;Show advice&amp;lt;/a&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;script&amp;gt;'&lt;br /&gt;
      html += 'function showAdvice(i){'&lt;br /&gt;
      html += 'var element = document.getElementById(&amp;quot;showAdivce_&amp;quot; + i.toString());'&lt;br /&gt;
      html += 'var show = element.innerHTML == &amp;quot;Hide advice&amp;quot;;'&lt;br /&gt;
      html += 'if (show){'&lt;br /&gt;
      html += 'element.innerHTML=&amp;quot;Show advice&amp;quot;;'&lt;br /&gt;
      html += '}else{'&lt;br /&gt;
      html += 'element.innerHTML=&amp;quot;Hide advice&amp;quot;;}'&lt;br /&gt;
      html += 'toggleAdvice(i);}'&lt;br /&gt;
&lt;br /&gt;
      html += 'function toggleAdvice(i) {'&lt;br /&gt;
      html += 'var elem = document.getElementById(i.toString() + &amp;quot;_myDiv&amp;quot;);'&lt;br /&gt;
      html += 'if (elem.style.display == &amp;quot;none&amp;quot;) {'&lt;br /&gt;
      html += 'elem.style.display = &amp;quot;&amp;quot;;'&lt;br /&gt;
      html += '} else {'&lt;br /&gt;
      html += 'elem.style.display = &amp;quot;none&amp;quot;;}}'&lt;br /&gt;
      html += '&amp;lt;/script&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;div id=&amp;quot;' + self.id.to_s + '_myDiv&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;'&lt;br /&gt;
      # [2015-10-26] Zhewei:&lt;br /&gt;
      # best to order advices high to low, e.g., 5 to 1&lt;br /&gt;
      # each level used to be a link;&lt;br /&gt;
      # clicking on the link caused the dropbox to be filled in with the corresponding number&lt;br /&gt;
      question_advices.reverse.each_with_index do |question_advice, index|&lt;br /&gt;
        html += '&amp;lt;a id=&amp;quot;changeScore_&amp;gt;' + self.id.to_s + '&amp;quot; onclick=&amp;quot;changeScore(' + count.to_s + ',' + index.to_s + ')&amp;quot;&amp;gt;'&lt;br /&gt;
        html += (self.questionnaire.max_question_score - index).to_s + ' - ' + question_advice.advice + '&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;'&lt;br /&gt;
        html += '&amp;lt;script&amp;gt;'&lt;br /&gt;
        html += 'function changeScore(i, j) {'&lt;br /&gt;
        html += 'var elem = jQuery(&amp;quot;#responses_&amp;quot; + i.toString() + &amp;quot;_score&amp;quot;);'&lt;br /&gt;
        html += 'var opts = elem.children(&amp;quot;option&amp;quot;).length;'&lt;br /&gt;
        html += 'elem.val((' + self.questionnaire.max_question_score.to_s + ' - j).toString());}'&lt;br /&gt;
        html += '&amp;lt;/script&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;/div&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if dropdown_or_scale == 'dropdown'&lt;br /&gt;
      current_value = &amp;quot;&amp;quot;&lt;br /&gt;
      current_value += 'data-current-rating =' + answer.answer.to_s if !answer.nil?&lt;br /&gt;
      html += '&amp;lt;div&amp;gt;&amp;lt;select id=&amp;quot;responses_' + count.to_s + '_score&amp;quot; name=&amp;quot;responses[' + count.to_s + '][score]&amp;quot; class=&amp;quot;review-rating&amp;quot; ' + current_value + '&amp;gt;'&lt;br /&gt;
      html += &amp;quot;&amp;lt;option value = ''&amp;gt;--&amp;lt;/option&amp;gt;&amp;quot;&lt;br /&gt;
      questionnaire_min.upto(questionnaire_max).each do |j|&lt;br /&gt;
        html += if !answer.nil? and j == answer.answer&lt;br /&gt;
                  '&amp;lt;option value=' + j.to_s + ' selected=&amp;quot;selected&amp;quot;&amp;gt;'&lt;br /&gt;
                else&lt;br /&gt;
                  '&amp;lt;option value=' + j.to_s + '&amp;gt;'&lt;br /&gt;
                end&lt;br /&gt;
&lt;br /&gt;
        html += j.to_s&lt;br /&gt;
        if j == questionnaire_min&lt;br /&gt;
          html += &amp;quot;-&amp;quot; + self.min_label if self.min_label.present?&lt;br /&gt;
        elsif j == questionnaire_max&lt;br /&gt;
          html += &amp;quot;-&amp;quot; + self.max_label if self.max_label.present?&lt;br /&gt;
        end&lt;br /&gt;
        html += &amp;quot;&amp;lt;/option&amp;gt;&amp;quot;&lt;br /&gt;
      end&lt;br /&gt;
      html += &amp;quot;&amp;lt;/select&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;&lt;br /&gt;
      html += '&amp;lt;textarea' + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
       ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
      html += answer.comments unless answer.nil?&lt;br /&gt;
      html += '&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
    elsif dropdown_or_scale == 'scale'&lt;br /&gt;
      html += '&amp;lt;input id=&amp;quot;responses_' + count.to_s + '_score&amp;quot; name=&amp;quot;responses[' + count.to_s + '][score]&amp;quot; type=&amp;quot;hidden&amp;quot;'&lt;br /&gt;
      html += 'value=&amp;quot;' + answer.answer.to_s + '&amp;quot;' unless answer.nil?&lt;br /&gt;
      html += '&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;table&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;tr&amp;gt;&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      (questionnaire_min..questionnaire_max).each do |j|&lt;br /&gt;
        html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;label&amp;gt;' + j.to_s + '&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += if !self.min_label.nil?&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;' + self.min_label + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
              else&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
              end&lt;br /&gt;
      (questionnaire_min..questionnaire_max).each do |j|&lt;br /&gt;
        html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;input type=&amp;quot;radio&amp;quot; id=&amp;quot;' + j.to_s + '&amp;quot; value=&amp;quot;' + j.to_s + '&amp;quot; name=&amp;quot;Radio_' + self.id.to_s + '&amp;quot;'&lt;br /&gt;
        html += 'checked=&amp;quot;checked&amp;quot;' if (!answer.nil? and answer.answer == j) or (answer.nil? and questionnaire_min == j)&lt;br /&gt;
        html += '&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;script&amp;gt;jQuery(&amp;quot;input[name=Radio_' + self.id.to_s + ']:radio&amp;quot;).change(function() {'&lt;br /&gt;
      html += 'var response_score = jQuery(&amp;quot;#responses_' + count.to_s + '_score&amp;quot;);'&lt;br /&gt;
      html += 'var checked_value = jQuery(&amp;quot;input[name=Radio_' + self.id.to_s + ']:checked&amp;quot;).val();'&lt;br /&gt;
      html += 'response_score.val(checked_value);});&amp;lt;/script&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += if !self.max_label.nil?&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;' + self.max_label + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
              else&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
              end&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;textarea cols=' + cols + ' rows=' + rows + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
        ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
      html += answer.comments unless answer.nil?&lt;br /&gt;
      html += '&amp;lt;/textarea&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    end&lt;br /&gt;
    safe_join([&amp;quot;&amp;quot;.html_safe, &amp;quot;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The '''''view_completed_question''''' method, which is 47 lies long. Thismethod is responsible to return the display if a student is viewingan already filled-out questionnaire.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def view_completed_question(count, answer, questionnaire_max, tag_prompt_deployments = nil, current_user = nil)&lt;br /&gt;
    html = '&amp;lt;b&amp;gt;' + count.to_s + &amp;quot;. &amp;quot; + self.txt + ' [Max points: ' + questionnaire_max.to_s + &amp;quot;]&amp;lt;/b&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    score = answer &amp;amp;&amp;amp; !answer.answer.nil? ? answer.answer.to_s : &amp;quot;-&amp;quot;&lt;br /&gt;
    score_percent = if score != &amp;quot;-&amp;quot;&lt;br /&gt;
                      answer.answer * 1.0 / questionnaire_max&lt;br /&gt;
                    else&lt;br /&gt;
                      0&lt;br /&gt;
                    end&lt;br /&gt;
&lt;br /&gt;
    score_color = if score_percent &amp;gt; 0.8&lt;br /&gt;
                    &amp;quot;c5&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.6&lt;br /&gt;
                    &amp;quot;c4&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.4&lt;br /&gt;
                    &amp;quot;c3&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.2&lt;br /&gt;
                    &amp;quot;c2&amp;quot;&lt;br /&gt;
                  else&lt;br /&gt;
                    &amp;quot;c1&amp;quot;&lt;br /&gt;
                  end&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;table cellpadding=&amp;quot;5&amp;quot;&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;tr&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;div class=&amp;quot;' + score_color + '&amp;quot; style=&amp;quot;width:30px; height:30px;' \&lt;br /&gt;
      ' border-radius:50%; font-size:15px; color:black; line-height:30px; text-align:center;&amp;quot;&amp;gt;'&lt;br /&gt;
    html += score&lt;br /&gt;
    html += '&amp;lt;/div&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;/td&amp;gt;'&lt;br /&gt;
    if answer &amp;amp;&amp;amp; !answer.comments.nil?&lt;br /&gt;
      html += '&amp;lt;td style=&amp;quot;padding-left:10px&amp;quot;&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;br&amp;gt;' + answer.comments.html_safe&lt;br /&gt;
      html += '&amp;lt;/td&amp;gt;'&lt;br /&gt;
      #### start code to show tag prompts ####&lt;br /&gt;
      unless tag_prompt_deployments.nil?&lt;br /&gt;
        # show check boxes for answer tagging&lt;br /&gt;
        resp = Response.find(answer.response_id)&lt;br /&gt;
        question = Question.find(answer.question_id)&lt;br /&gt;
        if tag_prompt_deployments.count &amp;gt; 0&lt;br /&gt;
          html += '&amp;lt;tr&amp;gt;&amp;lt;td colspan=&amp;quot;2&amp;quot;&amp;gt;'&lt;br /&gt;
          tag_prompt_deployments.each do |tag_dep|&lt;br /&gt;
            tag_prompt = TagPrompt.find(tag_dep.tag_prompt_id)&lt;br /&gt;
            if tag_dep.question_type == question.type and answer.comments.length &amp;gt; tag_dep.answer_length_threshold.to_i&lt;br /&gt;
              html += tag_prompt.html_control(tag_dep, answer, current_user)&lt;br /&gt;
            end&lt;br /&gt;
          end&lt;br /&gt;
          html += '&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;'&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      #### end code to show tag prompts ####&lt;br /&gt;
    end&lt;br /&gt;
    html += '&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;'&lt;br /&gt;
    safe_join([&amp;quot;&amp;quot;.html_safe, &amp;quot;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Proposed Solution ==&lt;br /&gt;
Our goal is to refactor the complete and view_completed_question method mainly by reducing the number of lines code for each function and also by introducing new methods to make the code more modular. We will also try to reduce the branch condition size wherever possible and hence reduce the cyclomatic complexity for these two functions. We also plan to introduce comments wherever needed to make the code more understandable. The main aim is to reduce the number of lines and make the code more compact without affecting the readability of the code.&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
&lt;br /&gt;
We tried to tackle the issues mentioned in the problem statement as described below:&lt;br /&gt;
&lt;br /&gt;
====The ''complete'' method====&lt;br /&gt;
&lt;br /&gt;
All the code in the model is just HTML. We thought of removing the code from here and putting it in a .erb file but it didn’t make much sense as the HTML code was heavily branched by the if-else conditions and it would just have been taking it out from this function and putting it in another file. We instead decided to refactor it in the file. We mainly combined the short HTML strings into longer ones but not too long so that the Code Climate cannot throw a “line too long” error. Another thing we did is reduce the number of lines used by condition statements by using the shorthand which beautifully consolidates three or more lines of code (read: if-else statements) into one readable line of code. (We also created another method for the repeated HTML code, so we just have to call the method rather than repeating the code. It increases code re-usability and reduces the number of lines of code.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The modified ''complete'' method is as below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def complete(count, answer = nil, questionnaire_min, questionnaire_max, dropdown_or_scale)&lt;br /&gt;
    if self.size.nil?&lt;br /&gt;
      cols = '70'&lt;br /&gt;
      rows = '1'&lt;br /&gt;
    else&lt;br /&gt;
      cols = self.size.split(',')[0]&lt;br /&gt;
      rows = self.size.split(',')[1]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    html = '&amp;lt;div&amp;gt;&amp;lt;label for=&amp;quot;responses_' + count.to_s + '&amp;quot;&amp;gt;' + self.txt + '&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;'&lt;br /&gt;
    # show advice for each criterion question&lt;br /&gt;
    question_advices = QuestionAdvice.where(question_id: self.id).sort_by(&amp;amp;:id)&lt;br /&gt;
    advice_total_length = 0&lt;br /&gt;
&lt;br /&gt;
    question_advices.each do |question_advice|&lt;br /&gt;
      advice_total_length += question_advice.advice.length if question_advice.advice &amp;amp;&amp;amp; question_advice.advice != &amp;quot;&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if !question_advices.empty? and advice_total_length &amp;gt; 0&lt;br /&gt;
      html += '&amp;lt;a id=&amp;quot;showAdvice_' + self.id.to_s + '&amp;quot; onclick=&amp;quot;showAdvice(' + self.id.to_s + ')&amp;quot;&amp;gt;Show advice&amp;lt;/a&amp;gt;&amp;lt;script&amp;gt;'&lt;br /&gt;
      html += 'function showAdvice(i){var element = document.getElementById(&amp;quot;showAdivce_&amp;quot; + i.toString());'&lt;br /&gt;
      html += 'var show = element.innerHTML == &amp;quot;Hide advice&amp;quot;;'&lt;br /&gt;
      html += 'if (show){element.innerHTML=&amp;quot;Show advice&amp;quot;;} else{element.innerHTML=&amp;quot;Hide advice&amp;quot;;}toggleAdvice(i);}'&lt;br /&gt;
&lt;br /&gt;
      html += 'function toggleAdvice(i) {var elem = document.getElementById(i.toString() + &amp;quot;_myDiv&amp;quot;);'&lt;br /&gt;
      html += 'if (elem.style.display == &amp;quot;none&amp;quot;) {elem.style.display = &amp;quot;&amp;quot;;} else {elem.style.display = &amp;quot;none&amp;quot;;}}&amp;lt;/script&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;div id=&amp;quot;' + self.id.to_s + '_myDiv&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;'&lt;br /&gt;
      # [2015-10-26] Zhewei:&lt;br /&gt;
      # best to order advices high to low, e.g., 5 to 1&lt;br /&gt;
      # each level used to be a link;&lt;br /&gt;
      # clicking on the link caused the dropbox to be filled in with the corresponding number&lt;br /&gt;
      question_advices.reverse.each_with_index do |question_advice, index|&lt;br /&gt;
        html += '&amp;lt;a id=&amp;quot;changeScore_&amp;gt;' + self.id.to_s + '&amp;quot; onclick=&amp;quot;changeScore(' + count.to_s + ',' + index.to_s + ')&amp;quot;&amp;gt;'&lt;br /&gt;
        html += (self.questionnaire.max_question_score - index).to_s + ' - ' + question_advice.advice + '&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;script&amp;gt;'&lt;br /&gt;
        html += 'function changeScore(i, j) {var elem = jQuery(&amp;quot;#responses_&amp;quot; + i.toString() + &amp;quot;_score&amp;quot;);'&lt;br /&gt;
        html += 'var opts = elem.children(&amp;quot;option&amp;quot;).length;'&lt;br /&gt;
        html += 'elem.val((' + self.questionnaire.max_question_score.to_s + ' - j).toString());}&amp;lt;/script&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;/div&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if dropdown_or_scale == 'dropdown'&lt;br /&gt;
      current_value = &amp;quot;&amp;quot;&lt;br /&gt;
      current_value += 'data-current-rating =' + answer.answer.to_s if !answer.nil?&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;div&amp;gt;&amp;lt;select id=&amp;quot;responses_' + count.to_s + '_score&amp;quot; name=&amp;quot;responses[' + count.to_s + '][score]&amp;quot; class=&amp;quot;review-rating&amp;quot; ' + current_value + '&amp;gt;' + &amp;quot;&amp;lt;option value = ''&amp;gt;--&amp;lt;/option&amp;gt;&amp;quot; + '&amp;lt;option value='&lt;br /&gt;
      questionnaire_min.upto(questionnaire_max).each do |j|&lt;br /&gt;
        html += j.to_s + 'selected=&amp;quot;selected&amp;quot;' if !answer.nil? and j == answer.answer + '&amp;gt;'        &lt;br /&gt;
        html += j.to_s + &amp;quot;-&amp;quot;&lt;br /&gt;
        html += self.min_label if self.min_label.present? and j == questionnaire_min + &amp;quot;&amp;lt;/option&amp;gt;&amp;quot;&lt;br /&gt;
        html += self.max_label if self.max_label.present? and j == questionnaire_max + &amp;quot;&amp;lt;/option&amp;gt;&amp;quot;&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;/select&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;textarea' + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
       ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
      html += answer.comments unless answer.nil? + '&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
    elsif dropdown_or_scale == 'scale'&lt;br /&gt;
      html += '&amp;lt;input id=&amp;quot;responses_' + count.to_s + '_score&amp;quot; name=&amp;quot;responses[' + count.to_s + '][score]&amp;quot; type=&amp;quot;hidden&amp;quot;'&lt;br /&gt;
      html += 'value=&amp;quot;' + answer.answer.to_s + '&amp;quot;' unless answer.nil? + '&amp;gt;&amp;lt;table&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      (questionnaire_min..questionnaire_max).each do |j|&lt;br /&gt;
        html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;label&amp;gt;' + j.to_s + '&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;' + self.min_label if !self.min_label.nil? + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      (questionnaire_min..questionnaire_max).each do |j|&lt;br /&gt;
        html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;input type=&amp;quot;radio&amp;quot; id=&amp;quot;' + j.to_s + '&amp;quot; value=&amp;quot;' + j.to_s + '&amp;quot; name=&amp;quot;Radio_' + self.id.to_s + '&amp;quot;'&lt;br /&gt;
        html += 'checked=&amp;quot;checked&amp;quot;' if (!answer.nil? and answer.answer == j) or (answer.nil? and questionnaire_min == j) + '&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;script&amp;gt;jQuery(&amp;quot;input[name=Radio_' + self.id.to_s + ']:radio&amp;quot;).change(function() {var response_score = jQuery(&amp;quot;#responses_' + count.to_s + '_score&amp;quot;);'&lt;br /&gt;
      html += 'var checked_value = jQuery(&amp;quot;input[name=Radio_' + self.id.to_s + ']:checked&amp;quot;).val();'&lt;br /&gt;
      html += 'response_score.val(checked_value);});&amp;lt;/script&amp;gt;&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += self.max_label if !self.max_label.nil? + '&amp;lt;/td&amp;gt;&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;textarea cols=' + cols + ' rows=' + rows + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
        ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
      html += answer.comments unless answer.nil? + '&amp;lt;/textarea&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
    safe_join([&amp;quot;&amp;quot;.html_safe, &amp;quot;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====The ''view_completed_question&amp;quot; method====&lt;br /&gt;
&lt;br /&gt;
The main task here was to reduce the nested if-else branching and reduce the number of arguments for this function. This was a very small method with its major dependent functions present in response.rb file. To refactor this method, we would have had to refactor response.rb and in turn, the other question subclasses which would make it very complex and break the code. According to us, refactoring this method along with the response.rb file would make more sense. We still made some changes in the file like concatenating small HTML string and using shorthand for if-else condition statements. &lt;br /&gt;
&lt;br /&gt;
The modified ''view_completed_question'' method is as below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def view_completed_question(count, answer, questionnaire_max, tag_prompt_deployments = nil, current_user = nil)&lt;br /&gt;
    html = '&amp;lt;b&amp;gt;' + count.to_s + &amp;quot;. &amp;quot; + self.txt + ' [Max points: ' + questionnaire_max.to_s + &amp;quot;]&amp;lt;/b&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    score = answer &amp;amp;&amp;amp; !answer.answer.nil? ? answer.answer.to_s : &amp;quot;-&amp;quot;&lt;br /&gt;
    score_percent = score != &amp;quot;-&amp;quot; ? answer.answer * 1.0 / questionnaire_max : 0&lt;br /&gt;
    score_color = if score_percent &amp;gt; 0.8&lt;br /&gt;
                    &amp;quot;c5&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.6&lt;br /&gt;
                    &amp;quot;c4&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.4&lt;br /&gt;
                    &amp;quot;c3&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.2&lt;br /&gt;
                    &amp;quot;c2&amp;quot;&lt;br /&gt;
                  else&lt;br /&gt;
                    &amp;quot;c1&amp;quot;&lt;br /&gt;
                  end&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;table cellpadding=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;div class=&amp;quot;' + score_color + '&amp;quot; style=&amp;quot;width:30px; height:30px;' \&lt;br /&gt;
      ' border-radius:50%; font-size:15px; color:black; line-height:30px; text-align:center;&amp;quot;&amp;gt;'&lt;br /&gt;
    html += score + '&amp;lt;/div&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    if answer &amp;amp;&amp;amp; !answer.comments.nil?&lt;br /&gt;
      html += '&amp;lt;td style=&amp;quot;padding-left:10px&amp;quot;&amp;gt;&amp;lt;br&amp;gt;' + answer.comments.html_safe + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
      #### start code to show tag prompts ####&lt;br /&gt;
      unless tag_prompt_deployments.nil?&lt;br /&gt;
        # show check boxes for answer tagging&lt;br /&gt;
        resp = Response.find(answer.response_id)&lt;br /&gt;
        question = Question.find(answer.question_id)&lt;br /&gt;
        if tag_prompt_deployments.count &amp;gt; 0&lt;br /&gt;
          html += '&amp;lt;tr&amp;gt;&amp;lt;td colspan=&amp;quot;2&amp;quot;&amp;gt;'&lt;br /&gt;
          tag_prompt_deployments.each do |tag_dep|&lt;br /&gt;
            tag_prompt = TagPrompt.find(tag_dep.tag_prompt_id)&lt;br /&gt;
            if tag_dep.question_type == question.type and answer.comments.length &amp;gt; tag_dep.answer_length_threshold.to_i&lt;br /&gt;
              html += tag_prompt.html_control(tag_dep, answer, current_user)&lt;br /&gt;
            end&lt;br /&gt;
          end&lt;br /&gt;
          html += '&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;'&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      #### end code to show tag prompts ####&lt;br /&gt;
    end&lt;br /&gt;
    html += '&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;'&lt;br /&gt;
    safe_join([&amp;quot;&amp;quot;.html_safe, &amp;quot;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Testing ==&lt;/div&gt;</summary>
		<author><name>Shmehta</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC517_(Spring_2020)_-_E2010._Refactor_criterion.rb&amp;diff=131489</id>
		<title>CSC517 (Spring 2020) - E2010. Refactor criterion.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC517_(Spring_2020)_-_E2010._Refactor_criterion.rb&amp;diff=131489"/>
		<updated>2020-03-22T15:40:27Z</updated>

		<summary type="html">&lt;p&gt;Shmehta: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= E2010 Refactor criterion.rb =&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project.&lt;br /&gt;
&lt;br /&gt;
== About Expertiza ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
The criterion.rb model consists of functions that decide what to display while creating, editing and viewing the questionnaires depending on whether the user is an instructor, a teaching assistant or a student. So, this file consists of a lot of HTML code that is rendered to the final questionnaire view. &lt;br /&gt;
&lt;br /&gt;
The current version of this controller has four methods, but two methods are very long and would require refactoring. The primary problem with these functions is that it consists of many statements of string concatenation. The HTML code which is rendered to the final view is made up of concatenations. &lt;br /&gt;
&lt;br /&gt;
Another issue with the code is that the branch conditions size for the complete and the view_completed_question method is very high. Also, this controller has very few comments. They are specifically needed to differentiate between the purpose of numerous nested branches from each other.&lt;br /&gt;
&lt;br /&gt;
== About criterion.rb ==&lt;br /&gt;
The ''criterion.rb'' model consists of functions that decide what to display while creating, editing and viewing the questionnaires depending on whether the user is an instructor, a teaching assistant or a student. So this file consists of a lot of HTML code that is rendered to the final questionnaire view.&lt;br /&gt;
&lt;br /&gt;
For this project, we have to deal with the following two methods:&lt;br /&gt;
* The '''''complete''''' method, which is 104 lines long. this method returns the display for the students when they are filling the questionnaire. It includes the advice given for different questions, dropdown options to rate a project based on the question, a textarea to enter comments and so on.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def complete(count, answer = nil, questionnaire_min, questionnaire_max, dropdown_or_scale)&lt;br /&gt;
    if self.size.nil?&lt;br /&gt;
      cols = '70'&lt;br /&gt;
      rows = '1'&lt;br /&gt;
    else&lt;br /&gt;
      cols = self.size.split(',')[0]&lt;br /&gt;
      rows = self.size.split(',')[1]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    html = '&amp;lt;div&amp;gt;&amp;lt;label for=&amp;quot;responses_' + count.to_s + '&amp;quot;&amp;gt;' + self.txt + '&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;'&lt;br /&gt;
    # show advice for each criterion question&lt;br /&gt;
    question_advices = QuestionAdvice.where(question_id: self.id).sort_by(&amp;amp;:id)&lt;br /&gt;
    advice_total_length = 0&lt;br /&gt;
&lt;br /&gt;
    question_advices.each do |question_advice|&lt;br /&gt;
      advice_total_length += question_advice.advice.length if question_advice.advice &amp;amp;&amp;amp; question_advice.advice != &amp;quot;&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if !question_advices.empty? and advice_total_length &amp;gt; 0&lt;br /&gt;
      html += '&amp;lt;a id=&amp;quot;showAdivce_' + self.id.to_s + '&amp;quot; onclick=&amp;quot;showAdvice(' + self.id.to_s + ')&amp;quot;&amp;gt;Show advice&amp;lt;/a&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;script&amp;gt;'&lt;br /&gt;
      html += 'function showAdvice(i){'&lt;br /&gt;
      html += 'var element = document.getElementById(&amp;quot;showAdivce_&amp;quot; + i.toString());'&lt;br /&gt;
      html += 'var show = element.innerHTML == &amp;quot;Hide advice&amp;quot;;'&lt;br /&gt;
      html += 'if (show){'&lt;br /&gt;
      html += 'element.innerHTML=&amp;quot;Show advice&amp;quot;;'&lt;br /&gt;
      html += '}else{'&lt;br /&gt;
      html += 'element.innerHTML=&amp;quot;Hide advice&amp;quot;;}'&lt;br /&gt;
      html += 'toggleAdvice(i);}'&lt;br /&gt;
&lt;br /&gt;
      html += 'function toggleAdvice(i) {'&lt;br /&gt;
      html += 'var elem = document.getElementById(i.toString() + &amp;quot;_myDiv&amp;quot;);'&lt;br /&gt;
      html += 'if (elem.style.display == &amp;quot;none&amp;quot;) {'&lt;br /&gt;
      html += 'elem.style.display = &amp;quot;&amp;quot;;'&lt;br /&gt;
      html += '} else {'&lt;br /&gt;
      html += 'elem.style.display = &amp;quot;none&amp;quot;;}}'&lt;br /&gt;
      html += '&amp;lt;/script&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;div id=&amp;quot;' + self.id.to_s + '_myDiv&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;'&lt;br /&gt;
      # [2015-10-26] Zhewei:&lt;br /&gt;
      # best to order advices high to low, e.g., 5 to 1&lt;br /&gt;
      # each level used to be a link;&lt;br /&gt;
      # clicking on the link caused the dropbox to be filled in with the corresponding number&lt;br /&gt;
      question_advices.reverse.each_with_index do |question_advice, index|&lt;br /&gt;
        html += '&amp;lt;a id=&amp;quot;changeScore_&amp;gt;' + self.id.to_s + '&amp;quot; onclick=&amp;quot;changeScore(' + count.to_s + ',' + index.to_s + ')&amp;quot;&amp;gt;'&lt;br /&gt;
        html += (self.questionnaire.max_question_score - index).to_s + ' - ' + question_advice.advice + '&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;'&lt;br /&gt;
        html += '&amp;lt;script&amp;gt;'&lt;br /&gt;
        html += 'function changeScore(i, j) {'&lt;br /&gt;
        html += 'var elem = jQuery(&amp;quot;#responses_&amp;quot; + i.toString() + &amp;quot;_score&amp;quot;);'&lt;br /&gt;
        html += 'var opts = elem.children(&amp;quot;option&amp;quot;).length;'&lt;br /&gt;
        html += 'elem.val((' + self.questionnaire.max_question_score.to_s + ' - j).toString());}'&lt;br /&gt;
        html += '&amp;lt;/script&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;/div&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if dropdown_or_scale == 'dropdown'&lt;br /&gt;
      current_value = &amp;quot;&amp;quot;&lt;br /&gt;
      current_value += 'data-current-rating =' + answer.answer.to_s if !answer.nil?&lt;br /&gt;
      html += '&amp;lt;div&amp;gt;&amp;lt;select id=&amp;quot;responses_' + count.to_s + '_score&amp;quot; name=&amp;quot;responses[' + count.to_s + '][score]&amp;quot; class=&amp;quot;review-rating&amp;quot; ' + current_value + '&amp;gt;'&lt;br /&gt;
      html += &amp;quot;&amp;lt;option value = ''&amp;gt;--&amp;lt;/option&amp;gt;&amp;quot;&lt;br /&gt;
      questionnaire_min.upto(questionnaire_max).each do |j|&lt;br /&gt;
        html += if !answer.nil? and j == answer.answer&lt;br /&gt;
                  '&amp;lt;option value=' + j.to_s + ' selected=&amp;quot;selected&amp;quot;&amp;gt;'&lt;br /&gt;
                else&lt;br /&gt;
                  '&amp;lt;option value=' + j.to_s + '&amp;gt;'&lt;br /&gt;
                end&lt;br /&gt;
&lt;br /&gt;
        html += j.to_s&lt;br /&gt;
        if j == questionnaire_min&lt;br /&gt;
          html += &amp;quot;-&amp;quot; + self.min_label if self.min_label.present?&lt;br /&gt;
        elsif j == questionnaire_max&lt;br /&gt;
          html += &amp;quot;-&amp;quot; + self.max_label if self.max_label.present?&lt;br /&gt;
        end&lt;br /&gt;
        html += &amp;quot;&amp;lt;/option&amp;gt;&amp;quot;&lt;br /&gt;
      end&lt;br /&gt;
      html += &amp;quot;&amp;lt;/select&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;&lt;br /&gt;
      html += '&amp;lt;textarea' + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
       ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
      html += answer.comments unless answer.nil?&lt;br /&gt;
      html += '&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
    elsif dropdown_or_scale == 'scale'&lt;br /&gt;
      html += '&amp;lt;input id=&amp;quot;responses_' + count.to_s + '_score&amp;quot; name=&amp;quot;responses[' + count.to_s + '][score]&amp;quot; type=&amp;quot;hidden&amp;quot;'&lt;br /&gt;
      html += 'value=&amp;quot;' + answer.answer.to_s + '&amp;quot;' unless answer.nil?&lt;br /&gt;
      html += '&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;table&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;tr&amp;gt;&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      (questionnaire_min..questionnaire_max).each do |j|&lt;br /&gt;
        html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;label&amp;gt;' + j.to_s + '&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += if !self.min_label.nil?&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;' + self.min_label + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
              else&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
              end&lt;br /&gt;
      (questionnaire_min..questionnaire_max).each do |j|&lt;br /&gt;
        html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;input type=&amp;quot;radio&amp;quot; id=&amp;quot;' + j.to_s + '&amp;quot; value=&amp;quot;' + j.to_s + '&amp;quot; name=&amp;quot;Radio_' + self.id.to_s + '&amp;quot;'&lt;br /&gt;
        html += 'checked=&amp;quot;checked&amp;quot;' if (!answer.nil? and answer.answer == j) or (answer.nil? and questionnaire_min == j)&lt;br /&gt;
        html += '&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;script&amp;gt;jQuery(&amp;quot;input[name=Radio_' + self.id.to_s + ']:radio&amp;quot;).change(function() {'&lt;br /&gt;
      html += 'var response_score = jQuery(&amp;quot;#responses_' + count.to_s + '_score&amp;quot;);'&lt;br /&gt;
      html += 'var checked_value = jQuery(&amp;quot;input[name=Radio_' + self.id.to_s + ']:checked&amp;quot;).val();'&lt;br /&gt;
      html += 'response_score.val(checked_value);});&amp;lt;/script&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += if !self.max_label.nil?&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;' + self.max_label + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
              else&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
              end&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;textarea cols=' + cols + ' rows=' + rows + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
        ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
      html += answer.comments unless answer.nil?&lt;br /&gt;
      html += '&amp;lt;/textarea&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    end&lt;br /&gt;
    safe_join([&amp;quot;&amp;quot;.html_safe, &amp;quot;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The '''''view_completed_question''''' method, which is 47 lies long. Thismethod is responsible to return the display if a student is viewingan already filled-out questionnaire.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def view_completed_question(count, answer, questionnaire_max, tag_prompt_deployments = nil, current_user = nil)&lt;br /&gt;
    html = '&amp;lt;b&amp;gt;' + count.to_s + &amp;quot;. &amp;quot; + self.txt + ' [Max points: ' + questionnaire_max.to_s + &amp;quot;]&amp;lt;/b&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    score = answer &amp;amp;&amp;amp; !answer.answer.nil? ? answer.answer.to_s : &amp;quot;-&amp;quot;&lt;br /&gt;
    score_percent = if score != &amp;quot;-&amp;quot;&lt;br /&gt;
                      answer.answer * 1.0 / questionnaire_max&lt;br /&gt;
                    else&lt;br /&gt;
                      0&lt;br /&gt;
                    end&lt;br /&gt;
&lt;br /&gt;
    score_color = if score_percent &amp;gt; 0.8&lt;br /&gt;
                    &amp;quot;c5&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.6&lt;br /&gt;
                    &amp;quot;c4&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.4&lt;br /&gt;
                    &amp;quot;c3&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.2&lt;br /&gt;
                    &amp;quot;c2&amp;quot;&lt;br /&gt;
                  else&lt;br /&gt;
                    &amp;quot;c1&amp;quot;&lt;br /&gt;
                  end&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;table cellpadding=&amp;quot;5&amp;quot;&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;tr&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;div class=&amp;quot;' + score_color + '&amp;quot; style=&amp;quot;width:30px; height:30px;' \&lt;br /&gt;
      ' border-radius:50%; font-size:15px; color:black; line-height:30px; text-align:center;&amp;quot;&amp;gt;'&lt;br /&gt;
    html += score&lt;br /&gt;
    html += '&amp;lt;/div&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;/td&amp;gt;'&lt;br /&gt;
    if answer &amp;amp;&amp;amp; !answer.comments.nil?&lt;br /&gt;
      html += '&amp;lt;td style=&amp;quot;padding-left:10px&amp;quot;&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;br&amp;gt;' + answer.comments.html_safe&lt;br /&gt;
      html += '&amp;lt;/td&amp;gt;'&lt;br /&gt;
      #### start code to show tag prompts ####&lt;br /&gt;
      unless tag_prompt_deployments.nil?&lt;br /&gt;
        # show check boxes for answer tagging&lt;br /&gt;
        resp = Response.find(answer.response_id)&lt;br /&gt;
        question = Question.find(answer.question_id)&lt;br /&gt;
        if tag_prompt_deployments.count &amp;gt; 0&lt;br /&gt;
          html += '&amp;lt;tr&amp;gt;&amp;lt;td colspan=&amp;quot;2&amp;quot;&amp;gt;'&lt;br /&gt;
          tag_prompt_deployments.each do |tag_dep|&lt;br /&gt;
            tag_prompt = TagPrompt.find(tag_dep.tag_prompt_id)&lt;br /&gt;
            if tag_dep.question_type == question.type and answer.comments.length &amp;gt; tag_dep.answer_length_threshold.to_i&lt;br /&gt;
              html += tag_prompt.html_control(tag_dep, answer, current_user)&lt;br /&gt;
            end&lt;br /&gt;
          end&lt;br /&gt;
          html += '&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;'&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      #### end code to show tag prompts ####&lt;br /&gt;
    end&lt;br /&gt;
    html += '&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;'&lt;br /&gt;
    safe_join([&amp;quot;&amp;quot;.html_safe, &amp;quot;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Proposed Solution ==&lt;br /&gt;
Our goal is to refactor the complete and view_completed_question method mainly by reducing the number of lines code for each function and also by introducing new methods to make the code more modular. We will also try to reduce the branch condition size wherever possible and hence reduce the cyclomatic complexity for these two functions. We also plan to introduce comments wherever needed to make the code more understandable. The main aim is to reduce the number of lines and make the code more compact without affecting the readability of the code.&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
&lt;br /&gt;
We tried to tackle the issues mentioned in the problem statement as described below:&lt;br /&gt;
&lt;br /&gt;
====The ''complete'' method====&lt;br /&gt;
&lt;br /&gt;
All the code in the model is just HTML. We thought of removing the code from here and putting it in a .erb file but it didn’t make much sense as the HTML code was heavily branched by the if-else conditions and it would just have been taking it out from this function and putting it in another file. We instead decided to refactor it in the file. We mainly combined the short HTML strings into longer ones but not too long so that the Code Climate cannot throw a “line too long” error. Another thing we did is reduced the number of lines used by condition statements by using the shorthand which beautifully consolidates three or more lines of code into one readable line of code. (We also created another method for the repeated HTML code, so we just have to call the method rather than repeating the code. It increases code reusability and reduces the number of lines of code.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The modified ''complete'' method is as below:&lt;br /&gt;
&lt;br /&gt;
====The ''view_completed_question&amp;quot; method====&lt;br /&gt;
&lt;br /&gt;
The main task here was to reduce the nested if-else branching and reduce the number of arguments for this function. This was a very small method with its major dependent functions present in response.rb file. To refactor this method, we would have had to refactor response.rb and in turn, the other question subclasses which would make it very complex and break the code. According to us, refactoring this method along with the response.rn file would make more sense. We still made some changes in the file like concatenating small HTML string and using shorthand for if-else condition statements. &lt;br /&gt;
&lt;br /&gt;
The modified ''view_completed_question'' method is as below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def view_completed_question(count, answer, questionnaire_max, tag_prompt_deployments = nil, current_user = nil)&lt;br /&gt;
    html = '&amp;lt;b&amp;gt;' + count.to_s + &amp;quot;. &amp;quot; + self.txt + ' [Max points: ' + questionnaire_max.to_s + &amp;quot;]&amp;lt;/b&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    score = answer &amp;amp;&amp;amp; !answer.answer.nil? ? answer.answer.to_s : &amp;quot;-&amp;quot;&lt;br /&gt;
    score_percent = score != &amp;quot;-&amp;quot; ? answer.answer * 1.0 / questionnaire_max : 0&lt;br /&gt;
&lt;br /&gt;
    score_color = if score_percent &amp;gt; 0.8&lt;br /&gt;
                    &amp;quot;c5&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.6&lt;br /&gt;
                    &amp;quot;c4&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.4&lt;br /&gt;
                    &amp;quot;c3&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.2&lt;br /&gt;
                    &amp;quot;c2&amp;quot;&lt;br /&gt;
                  else&lt;br /&gt;
                    &amp;quot;c1&amp;quot;&lt;br /&gt;
                  end&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;table cellpadding=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;div class=&amp;quot;' + score_color + '&amp;quot; style=&amp;quot;width:30px; height:30px;' \&lt;br /&gt;
      ' border-radius:50%; font-size:15px; color:black; line-height:30px; text-align:center;&amp;quot;&amp;gt;'&lt;br /&gt;
    html += score + '&amp;lt;/div&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
    if answer &amp;amp;&amp;amp; !answer.comments.nil?&lt;br /&gt;
      html += '&amp;lt;td style=&amp;quot;padding-left:10px&amp;quot;&amp;gt;&amp;lt;br&amp;gt;' + answer.comments.html_safe + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
      #### start code to show tag prompts ####&lt;br /&gt;
      unless tag_prompt_deployments.nil?&lt;br /&gt;
        # show check boxes for answer tagging&lt;br /&gt;
        resp = Response.find(answer.response_id)&lt;br /&gt;
        question = Question.find(answer.question_id)&lt;br /&gt;
        if tag_prompt_deployments.count &amp;gt; 0&lt;br /&gt;
          html += '&amp;lt;tr&amp;gt;&amp;lt;td colspan=&amp;quot;2&amp;quot;&amp;gt;'&lt;br /&gt;
          tag_prompt_deployments.each do |tag_dep|&lt;br /&gt;
            tag_prompt = TagPrompt.find(tag_dep.tag_prompt_id)&lt;br /&gt;
            if tag_dep.question_type == question.type and answer.comments.length &amp;gt; tag_dep.answer_length_threshold.to_i&lt;br /&gt;
              html += tag_prompt.html_control(tag_dep, answer, current_user)&lt;br /&gt;
            end&lt;br /&gt;
          end&lt;br /&gt;
          html += '&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;'&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      #### end code to show tag prompts ####&lt;br /&gt;
    end&lt;br /&gt;
    html += '#&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;'&lt;br /&gt;
    safe_join([&amp;quot;&amp;quot;.html_safe, &amp;quot;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Testing ==&lt;/div&gt;</summary>
		<author><name>Shmehta</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC517_(Spring_2020)_-_E2010._Refactor_criterion.rb&amp;diff=131479</id>
		<title>CSC517 (Spring 2020) - E2010. Refactor criterion.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC517_(Spring_2020)_-_E2010._Refactor_criterion.rb&amp;diff=131479"/>
		<updated>2020-03-22T15:25:12Z</updated>

		<summary type="html">&lt;p&gt;Shmehta: Created page with &amp;quot; = E2010 Refactor criterion.rb =  This page provides a description of the Expertiza based OSS project.  == About Expertiza ==   == Problem Statement == The criterion.rb model...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= E2010 Refactor criterion.rb =&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project.&lt;br /&gt;
&lt;br /&gt;
== About Expertiza ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
The criterion.rb model consists of functions that decide what to display while creating, editing and viewing the questionnaires depending on whether the user is an instructor, a teaching assistant or a student. So, this file consists of a lot of HTML code that is rendered to the final questionnaire view. &lt;br /&gt;
&lt;br /&gt;
The current version of this controller has four methods, but two methods are very long and would require refactoring. The primary problem with these functions is that it consists of many statements of string concatenation. The HTML code which is rendered to the final view is made up of concatenations. &lt;br /&gt;
&lt;br /&gt;
Another issue with the code is that the branch conditions size for the complete and the view_completed_question method is very high. Also, this controller has very few comments. They are specifically needed to differentiate between the purpose of numerous nested branches from each other.&lt;br /&gt;
&lt;br /&gt;
== About criterion.rb ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def complete(count, answer = nil, questionnaire_min, questionnaire_max, dropdown_or_scale)&lt;br /&gt;
    if self.size.nil?&lt;br /&gt;
      cols = '70'&lt;br /&gt;
      rows = '1'&lt;br /&gt;
    else&lt;br /&gt;
      cols = self.size.split(',')[0]&lt;br /&gt;
      rows = self.size.split(',')[1]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    html = '&amp;lt;div&amp;gt;&amp;lt;label for=&amp;quot;responses_' + count.to_s + '&amp;quot;&amp;gt;' + self.txt + '&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;'&lt;br /&gt;
    # show advice for each criterion question&lt;br /&gt;
    question_advices = QuestionAdvice.where(question_id: self.id).sort_by(&amp;amp;:id)&lt;br /&gt;
    advice_total_length = 0&lt;br /&gt;
&lt;br /&gt;
    question_advices.each do |question_advice|&lt;br /&gt;
      advice_total_length += question_advice.advice.length if question_advice.advice &amp;amp;&amp;amp; question_advice.advice != &amp;quot;&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if !question_advices.empty? and advice_total_length &amp;gt; 0&lt;br /&gt;
      html += '&amp;lt;a id=&amp;quot;showAdivce_' + self.id.to_s + '&amp;quot; onclick=&amp;quot;showAdvice(' + self.id.to_s + ')&amp;quot;&amp;gt;Show advice&amp;lt;/a&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;script&amp;gt;'&lt;br /&gt;
      html += 'function showAdvice(i){'&lt;br /&gt;
      html += 'var element = document.getElementById(&amp;quot;showAdivce_&amp;quot; + i.toString());'&lt;br /&gt;
      html += 'var show = element.innerHTML == &amp;quot;Hide advice&amp;quot;;'&lt;br /&gt;
      html += 'if (show){'&lt;br /&gt;
      html += 'element.innerHTML=&amp;quot;Show advice&amp;quot;;'&lt;br /&gt;
      html += '}else{'&lt;br /&gt;
      html += 'element.innerHTML=&amp;quot;Hide advice&amp;quot;;}'&lt;br /&gt;
      html += 'toggleAdvice(i);}'&lt;br /&gt;
&lt;br /&gt;
      html += 'function toggleAdvice(i) {'&lt;br /&gt;
      html += 'var elem = document.getElementById(i.toString() + &amp;quot;_myDiv&amp;quot;);'&lt;br /&gt;
      html += 'if (elem.style.display == &amp;quot;none&amp;quot;) {'&lt;br /&gt;
      html += 'elem.style.display = &amp;quot;&amp;quot;;'&lt;br /&gt;
      html += '} else {'&lt;br /&gt;
      html += 'elem.style.display = &amp;quot;none&amp;quot;;}}'&lt;br /&gt;
      html += '&amp;lt;/script&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;div id=&amp;quot;' + self.id.to_s + '_myDiv&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;'&lt;br /&gt;
      # [2015-10-26] Zhewei:&lt;br /&gt;
      # best to order advices high to low, e.g., 5 to 1&lt;br /&gt;
      # each level used to be a link;&lt;br /&gt;
      # clicking on the link caused the dropbox to be filled in with the corresponding number&lt;br /&gt;
      question_advices.reverse.each_with_index do |question_advice, index|&lt;br /&gt;
        html += '&amp;lt;a id=&amp;quot;changeScore_&amp;gt;' + self.id.to_s + '&amp;quot; onclick=&amp;quot;changeScore(' + count.to_s + ',' + index.to_s + ')&amp;quot;&amp;gt;'&lt;br /&gt;
        html += (self.questionnaire.max_question_score - index).to_s + ' - ' + question_advice.advice + '&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;'&lt;br /&gt;
        html += '&amp;lt;script&amp;gt;'&lt;br /&gt;
        html += 'function changeScore(i, j) {'&lt;br /&gt;
        html += 'var elem = jQuery(&amp;quot;#responses_&amp;quot; + i.toString() + &amp;quot;_score&amp;quot;);'&lt;br /&gt;
        html += 'var opts = elem.children(&amp;quot;option&amp;quot;).length;'&lt;br /&gt;
        html += 'elem.val((' + self.questionnaire.max_question_score.to_s + ' - j).toString());}'&lt;br /&gt;
        html += '&amp;lt;/script&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;/div&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if dropdown_or_scale == 'dropdown'&lt;br /&gt;
      current_value = &amp;quot;&amp;quot;&lt;br /&gt;
      current_value += 'data-current-rating =' + answer.answer.to_s if !answer.nil?&lt;br /&gt;
      html += '&amp;lt;div&amp;gt;&amp;lt;select id=&amp;quot;responses_' + count.to_s + '_score&amp;quot; name=&amp;quot;responses[' + count.to_s + '][score]&amp;quot; class=&amp;quot;review-rating&amp;quot; ' + current_value + '&amp;gt;'&lt;br /&gt;
      html += &amp;quot;&amp;lt;option value = ''&amp;gt;--&amp;lt;/option&amp;gt;&amp;quot;&lt;br /&gt;
      questionnaire_min.upto(questionnaire_max).each do |j|&lt;br /&gt;
        html += if !answer.nil? and j == answer.answer&lt;br /&gt;
                  '&amp;lt;option value=' + j.to_s + ' selected=&amp;quot;selected&amp;quot;&amp;gt;'&lt;br /&gt;
                else&lt;br /&gt;
                  '&amp;lt;option value=' + j.to_s + '&amp;gt;'&lt;br /&gt;
                end&lt;br /&gt;
&lt;br /&gt;
        html += j.to_s&lt;br /&gt;
        if j == questionnaire_min&lt;br /&gt;
          html += &amp;quot;-&amp;quot; + self.min_label if self.min_label.present?&lt;br /&gt;
        elsif j == questionnaire_max&lt;br /&gt;
          html += &amp;quot;-&amp;quot; + self.max_label if self.max_label.present?&lt;br /&gt;
        end&lt;br /&gt;
        html += &amp;quot;&amp;lt;/option&amp;gt;&amp;quot;&lt;br /&gt;
      end&lt;br /&gt;
      html += &amp;quot;&amp;lt;/select&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;&lt;br /&gt;
      html += '&amp;lt;textarea' + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
       ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
      html += answer.comments unless answer.nil?&lt;br /&gt;
      html += '&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
    elsif dropdown_or_scale == 'scale'&lt;br /&gt;
      html += '&amp;lt;input id=&amp;quot;responses_' + count.to_s + '_score&amp;quot; name=&amp;quot;responses[' + count.to_s + '][score]&amp;quot; type=&amp;quot;hidden&amp;quot;'&lt;br /&gt;
      html += 'value=&amp;quot;' + answer.answer.to_s + '&amp;quot;' unless answer.nil?&lt;br /&gt;
      html += '&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;table&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;tr&amp;gt;&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      (questionnaire_min..questionnaire_max).each do |j|&lt;br /&gt;
        html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;label&amp;gt;' + j.to_s + '&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += if !self.min_label.nil?&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;' + self.min_label + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
              else&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
              end&lt;br /&gt;
      (questionnaire_min..questionnaire_max).each do |j|&lt;br /&gt;
        html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;input type=&amp;quot;radio&amp;quot; id=&amp;quot;' + j.to_s + '&amp;quot; value=&amp;quot;' + j.to_s + '&amp;quot; name=&amp;quot;Radio_' + self.id.to_s + '&amp;quot;'&lt;br /&gt;
        html += 'checked=&amp;quot;checked&amp;quot;' if (!answer.nil? and answer.answer == j) or (answer.nil? and questionnaire_min == j)&lt;br /&gt;
        html += '&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;script&amp;gt;jQuery(&amp;quot;input[name=Radio_' + self.id.to_s + ']:radio&amp;quot;).change(function() {'&lt;br /&gt;
      html += 'var response_score = jQuery(&amp;quot;#responses_' + count.to_s + '_score&amp;quot;);'&lt;br /&gt;
      html += 'var checked_value = jQuery(&amp;quot;input[name=Radio_' + self.id.to_s + ']:checked&amp;quot;).val();'&lt;br /&gt;
      html += 'response_score.val(checked_value);});&amp;lt;/script&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += if !self.max_label.nil?&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;' + self.max_label + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
              else&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
              end&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;textarea cols=' + cols + ' rows=' + rows + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
        ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
      html += answer.comments unless answer.nil?&lt;br /&gt;
      html += '&amp;lt;/textarea&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    end&lt;br /&gt;
    safe_join([&amp;quot;&amp;quot;.html_safe, &amp;quot;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def view_completed_question(count, answer, questionnaire_max, tag_prompt_deployments = nil, current_user = nil)&lt;br /&gt;
    html = '&amp;lt;b&amp;gt;' + count.to_s + &amp;quot;. &amp;quot; + self.txt + ' [Max points: ' + questionnaire_max.to_s + &amp;quot;]&amp;lt;/b&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    score = answer &amp;amp;&amp;amp; !answer.answer.nil? ? answer.answer.to_s : &amp;quot;-&amp;quot;&lt;br /&gt;
    score_percent = if score != &amp;quot;-&amp;quot;&lt;br /&gt;
                      answer.answer * 1.0 / questionnaire_max&lt;br /&gt;
                    else&lt;br /&gt;
                      0&lt;br /&gt;
                    end&lt;br /&gt;
&lt;br /&gt;
    score_color = if score_percent &amp;gt; 0.8&lt;br /&gt;
                    &amp;quot;c5&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.6&lt;br /&gt;
                    &amp;quot;c4&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.4&lt;br /&gt;
                    &amp;quot;c3&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.2&lt;br /&gt;
                    &amp;quot;c2&amp;quot;&lt;br /&gt;
                  else&lt;br /&gt;
                    &amp;quot;c1&amp;quot;&lt;br /&gt;
                  end&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;table cellpadding=&amp;quot;5&amp;quot;&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;tr&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;div class=&amp;quot;' + score_color + '&amp;quot; style=&amp;quot;width:30px; height:30px;' \&lt;br /&gt;
      ' border-radius:50%; font-size:15px; color:black; line-height:30px; text-align:center;&amp;quot;&amp;gt;'&lt;br /&gt;
    html += score&lt;br /&gt;
    html += '&amp;lt;/div&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;/td&amp;gt;'&lt;br /&gt;
    if answer &amp;amp;&amp;amp; !answer.comments.nil?&lt;br /&gt;
      html += '&amp;lt;td style=&amp;quot;padding-left:10px&amp;quot;&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;br&amp;gt;' + answer.comments.html_safe&lt;br /&gt;
      html += '&amp;lt;/td&amp;gt;'&lt;br /&gt;
      #### start code to show tag prompts ####&lt;br /&gt;
      unless tag_prompt_deployments.nil?&lt;br /&gt;
        # show check boxes for answer tagging&lt;br /&gt;
        resp = Response.find(answer.response_id)&lt;br /&gt;
        question = Question.find(answer.question_id)&lt;br /&gt;
        if tag_prompt_deployments.count &amp;gt; 0&lt;br /&gt;
          html += '&amp;lt;tr&amp;gt;&amp;lt;td colspan=&amp;quot;2&amp;quot;&amp;gt;'&lt;br /&gt;
          tag_prompt_deployments.each do |tag_dep|&lt;br /&gt;
            tag_prompt = TagPrompt.find(tag_dep.tag_prompt_id)&lt;br /&gt;
            if tag_dep.question_type == question.type and answer.comments.length &amp;gt; tag_dep.answer_length_threshold.to_i&lt;br /&gt;
              html += tag_prompt.html_control(tag_dep, answer, current_user)&lt;br /&gt;
            end&lt;br /&gt;
          end&lt;br /&gt;
          html += '&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;'&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      #### end code to show tag prompts ####&lt;br /&gt;
    end&lt;br /&gt;
    html += '&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;'&lt;br /&gt;
    safe_join([&amp;quot;&amp;quot;.html_safe, &amp;quot;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Proposed Solution ==&lt;br /&gt;
Our goal is to refactor the complete and view_completed_question method mainly by reducing the number of lines code for each function and also by introducing new methods to make the code more modular. We will also try to reduce the branch condition size wherever possible and hence reduce the cyclomatic complexity for these two functions. We also plan to introduce comments wherever needed to make the code more understandable. The main aim is to reduce the number of lines and make the code more compact without affecting the readability of the code.&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
&lt;br /&gt;
We tried to tackle the issues mentioned in the problem statement as described below:&lt;br /&gt;
&lt;br /&gt;
====The ''complete'' method====&lt;br /&gt;
&lt;br /&gt;
All the code in the model is just HTML. We thought of removing the code from here and putting it in a .erb file but it didn’t make much sense as the HTML code was heavily branched by the if-else conditions and it would just have been taking it out from this function and putting it in another file. We instead decided to refactor it in the file. We mainly combined the short HTML strings into longer ones but not too long so that the Code Climate cannot throw a “line too long” error. Another thing we did is reduced the number of lines used by condition statements by using the shorthand which beautifully consolidates three or more lines of code into one readable line of code. (We also created another method for the repeated HTML code, so we just have to call the method rather than repeating the code. It increases code reusability and reduces the number of lines of code.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The modified ''complete'' method is as below:&lt;br /&gt;
&lt;br /&gt;
====The ''view_completed_question&amp;quot; method====&lt;br /&gt;
&lt;br /&gt;
The main task here was to reduce the nested if-else branching and reduce the number of arguments for this function. This was a very small method with its major dependent functions present in response.rb file. To refactor this method, we would have had to refactor response.rb and in turn, the other question subclasses which would make it very complex and break the code. According to us, refactoring this method along with the response.rn file would make more sense. We still made some changes in the file like concatenating small HTML string and using shorthand for if-else condition statements. &lt;br /&gt;
&lt;br /&gt;
The modified ''view_completed_question'' method is as below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def view_completed_question(count, answer, questionnaire_max, tag_prompt_deployments = nil, current_user = nil)&lt;br /&gt;
    html = '&amp;lt;b&amp;gt;' + count.to_s + &amp;quot;. &amp;quot; + self.txt + ' [Max points: ' + questionnaire_max.to_s + &amp;quot;]&amp;lt;/b&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    score = answer &amp;amp;&amp;amp; !answer.answer.nil? ? answer.answer.to_s : &amp;quot;-&amp;quot;&lt;br /&gt;
    score_percent = score != &amp;quot;-&amp;quot; ? answer.answer * 1.0 / questionnaire_max : 0&lt;br /&gt;
&lt;br /&gt;
    score_color = if score_percent &amp;gt; 0.8&lt;br /&gt;
                    &amp;quot;c5&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.6&lt;br /&gt;
                    &amp;quot;c4&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.4&lt;br /&gt;
                    &amp;quot;c3&amp;quot;&lt;br /&gt;
                  elsif score_percent &amp;gt; 0.2&lt;br /&gt;
                    &amp;quot;c2&amp;quot;&lt;br /&gt;
                  else&lt;br /&gt;
                    &amp;quot;c1&amp;quot;&lt;br /&gt;
                  end&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;table cellpadding=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;div class=&amp;quot;' + score_color + '&amp;quot; style=&amp;quot;width:30px; height:30px;' \&lt;br /&gt;
      ' border-radius:50%; font-size:15px; color:black; line-height:30px; text-align:center;&amp;quot;&amp;gt;'&lt;br /&gt;
    html += score + '&amp;lt;/div&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
    if answer &amp;amp;&amp;amp; !answer.comments.nil?&lt;br /&gt;
      html += '&amp;lt;td style=&amp;quot;padding-left:10px&amp;quot;&amp;gt;&amp;lt;br&amp;gt;' + answer.comments.html_safe + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
      #### start code to show tag prompts ####&lt;br /&gt;
      unless tag_prompt_deployments.nil?&lt;br /&gt;
        # show check boxes for answer tagging&lt;br /&gt;
        resp = Response.find(answer.response_id)&lt;br /&gt;
        question = Question.find(answer.question_id)&lt;br /&gt;
        if tag_prompt_deployments.count &amp;gt; 0&lt;br /&gt;
          html += '&amp;lt;tr&amp;gt;&amp;lt;td colspan=&amp;quot;2&amp;quot;&amp;gt;'&lt;br /&gt;
          tag_prompt_deployments.each do |tag_dep|&lt;br /&gt;
            tag_prompt = TagPrompt.find(tag_dep.tag_prompt_id)&lt;br /&gt;
            if tag_dep.question_type == question.type and answer.comments.length &amp;gt; tag_dep.answer_length_threshold.to_i&lt;br /&gt;
              html += tag_prompt.html_control(tag_dep, answer, current_user)&lt;br /&gt;
            end&lt;br /&gt;
          end&lt;br /&gt;
          html += '&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;'&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      #### end code to show tag prompts ####&lt;br /&gt;
    end&lt;br /&gt;
    html += '#&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;'&lt;br /&gt;
    safe_join([&amp;quot;&amp;quot;.html_safe, &amp;quot;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Shmehta</name></author>
	</entry>
</feed>