<?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=Rananth2</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=Rananth2"/>
	<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=Special:Contributions/Rananth2"/>
	<updated>2026-05-16T09:09:16Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.41.0</generator>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/CSC_517_Spring_2020/Implement_ImageBitMap_WebAPI&amp;diff=134175</id>
		<title>CSC/CSC 517 Spring 2020/Implement ImageBitMap WebAPI</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/CSC_517_Spring_2020/Implement_ImageBitMap_WebAPI&amp;diff=134175"/>
		<updated>2020-04-25T03:04:19Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: /* Current Implementation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== '''Background Information''' ==&lt;br /&gt;
This project aims to contribute to Mozilla's experimental browser engine called Servo, which is implemented in a language called RUST(useful for implementing features that need concurrency and memory safety).&lt;br /&gt;
&lt;br /&gt;
Many of the components of Servo are still under development and one such feature is the [https://www.techopedia.com/definition/792/bitmap-bmp| ImageBitmap].&lt;br /&gt;
&lt;br /&gt;
Major browsers support the ImageBitmap standard which can be used to create images that are ready to be drawn efficiently to [https://en.wikipedia.org/wiki/Canvas_element| HTML canvas elements]. Servo is a new, experimental browser that supports these canvas APIs. &lt;br /&gt;
&lt;br /&gt;
The goal of and motivation behind this project is to implement support for image bitmaps and improve our canvas automated test coverage as a result.&lt;br /&gt;
&lt;br /&gt;
== '''About ImageBitMap and Motivation behind the project''' ==&lt;br /&gt;
We usually decode images for a use with canvas to allow users to customize an avatar, crop an image, or just zoom in on a picture. The problem with decoding images is that it can be CPU intensive, and that can sometimes mean jank or checkerboarding.&lt;br /&gt;
&lt;br /&gt;
But the createImageBitmap() method allows us to decode the image in the background and get access to a new ImageBitmap primitive, which you can draw into a canvas in the same way you would an &amp;lt;img&amp;gt; element, another canvas, or a video.&lt;br /&gt;
&lt;br /&gt;
The aim of this project is to develop the ImageBitmap for the servo environment. &lt;br /&gt;
&lt;br /&gt;
This can be done in the steps mentioned in the following section.&lt;br /&gt;
&lt;br /&gt;
== '''Steps for implementation''' ==&lt;br /&gt;
&lt;br /&gt;
'''Initial Phase'''&lt;br /&gt;
* '''Step 1: '''Add a ImageBitmap WebIDL interface to ''components/script/dom/webidl''s and Rust implementation in components/script/dom/imagebitmap.rs&lt;br /&gt;
* '''Step 2: ''' Add the ''createImageBitmap'' method that takes no extra x/y/w/h parameters in ''component/script/dom/webidls/WindowOrWorkerGlobalScope.webidl'' and implement the method in ''component/script/dom/window.rs'', handling the HTMLCanvasElement and OffscreenCanvas types from the possible image sources&lt;br /&gt;
&lt;br /&gt;
'''Subsequent phase'''&lt;br /&gt;
* '''Step 1: '''Implement several remaining image source types (HTMLImageElement, ImageData, ImageBitmap)&lt;br /&gt;
* '''Step 2: '''Implement the ''createImageBitmap'' overload that accepts x/y/w/h parameters&lt;br /&gt;
* '''Step 3: '''Implement support for ImageBitmaps as canvas image sources in ''components/script/canvas_state.rs''&lt;br /&gt;
[[File:AllSteps.jpg]]&lt;br /&gt;
&lt;br /&gt;
== '''Details about previous work on implementation''' ==&lt;br /&gt;
The steps that have been implemented so far in this project by the previous batch are:&lt;br /&gt;
&lt;br /&gt;
'''Step 1:''' Added the ImageBitmap interface to ''components/script/dom/webidls'' that represents a bitmap image which can be drawn to a &amp;lt;canvas&amp;gt; without undue latency. The interface contains height and weight as its attributes which are read only unsigned long integers.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//[Exposed=(Window,Worker), Serializable, Transferable]&lt;br /&gt;
[Exposed=(Window,Worker)]&lt;br /&gt;
interface ImageBitmap {&lt;br /&gt;
  readonly attribute unsigned long width;&lt;br /&gt;
  readonly attribute unsigned long height;&lt;br /&gt;
  //void close();&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef (CanvasImageSource or&lt;br /&gt;
         Blob or&lt;br /&gt;
         ImageData) ImageBitmapSource;&lt;br /&gt;
&lt;br /&gt;
enum ImageOrientation { &amp;quot;none&amp;quot;, &amp;quot;flipY&amp;quot; };&lt;br /&gt;
enum PremultiplyAlpha { &amp;quot;none&amp;quot;, &amp;quot;premultiply&amp;quot;, &amp;quot;default&amp;quot; };&lt;br /&gt;
enum ColorSpaceConversion { &amp;quot;none&amp;quot;, &amp;quot;default&amp;quot; };&lt;br /&gt;
enum ResizeQuality { &amp;quot;pixelated&amp;quot;, &amp;quot;low&amp;quot;, &amp;quot;medium&amp;quot;, &amp;quot;high&amp;quot; };&lt;br /&gt;
&lt;br /&gt;
dictionary ImageBitmapOptions {&lt;br /&gt;
  ImageOrientation imageOrientation = &amp;quot;none&amp;quot;;&lt;br /&gt;
  PremultiplyAlpha premultiplyAlpha = &amp;quot;default&amp;quot;;&lt;br /&gt;
  ColorSpaceConversion colorSpaceConversion = &amp;quot;default&amp;quot;;&lt;br /&gt;
  [EnforceRange] unsigned long resizeWidth;&lt;br /&gt;
  [EnforceRange] unsigned long resizeHeight;&lt;br /&gt;
  ResizeQuality resizeQuality = &amp;quot;low&amp;quot;;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ImageBitmap webidl also defines a dictionary for various ImageBitmap Options that can be used to modify the ImageBitmap object.&lt;br /&gt;
&lt;br /&gt;
'''Step 2:''' Implemented the rust code for the webidl interface at ''components/script/dom/imagebitmap.rs''. For more details on the code [https://expertiza.csc.ncsu.edu/index.php/CSC/ECE_517_Spring_2020_-_M2000._Implement_ImageBitMap_web_API#Implementation visit]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
use crate::dom::bindings::cell::DomRefCell;&lt;br /&gt;
&lt;br /&gt;
use crate::dom::bindings::codegen::Bindings::ImageBitmapBinding::ImageBitmapMethods;&lt;br /&gt;
use crate::dom::bindings::root::DomRoot;&lt;br /&gt;
use crate::dom::globalscope::GlobalScope;&lt;br /&gt;
&lt;br /&gt;
use crate::dom::bindings::error::Fallible;&lt;br /&gt;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};&lt;br /&gt;
use dom_struct::dom_struct;&lt;br /&gt;
&lt;br /&gt;
use std::vec::Vec;&lt;br /&gt;
&lt;br /&gt;
#[dom_struct]&lt;br /&gt;
pub struct ImageBitmap {&lt;br /&gt;
    reflector_: Reflector,&lt;br /&gt;
    width: u32,&lt;br /&gt;
    height: u32,&lt;br /&gt;
    bitmap_data: DomRefCell&amp;lt;Vec&amp;lt;u8&amp;gt;&amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
impl ImageBitmap {&lt;br /&gt;
    fn new_inherited(width_arg: u32, height_arg: u32) -&amp;gt; ImageBitmap {&lt;br /&gt;
        ImageBitmap {&lt;br /&gt;
            reflector_: Reflector::new(),&lt;br /&gt;
            width: width_arg,&lt;br /&gt;
            height: height_arg,&lt;br /&gt;
            bitmap_data: DomRefCell::new(vec![]),&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    #[allow(dead_code)]&lt;br /&gt;
    pub fn new(global: &amp;amp;GlobalScope, width: u32, height: u32) -&amp;gt; Fallible&amp;lt;DomRoot&amp;lt;ImageBitmap&amp;gt;&amp;gt; {&lt;br /&gt;
        //assigning to a variable the return object of new_inherited&lt;br /&gt;
        let imagebitmap = Box::new(ImageBitmap::new_inherited(width, height));&lt;br /&gt;
&lt;br /&gt;
        Ok(reflect_dom_object(imagebitmap, global))&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code also implements the getter methods for height and width attribute of an ImageBitmap object.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
impl ImageBitmapMethods for ImageBitmap {&lt;br /&gt;
    // https://html.spec.whatwg.org/multipage/#dom-imagebitmap-height&lt;br /&gt;
    fn Height(&amp;amp;self) -&amp;gt; u32 {&lt;br /&gt;
        //to do: add a condition for checking detached internal slot&lt;br /&gt;
        //and return 0 if set to true&lt;br /&gt;
        self.height&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // https://html.spec.whatwg.org/multipage/#dom-imagebitmap-width&lt;br /&gt;
    fn Width(&amp;amp;self) -&amp;gt; u32 {&lt;br /&gt;
        //to do: add a condition to check detached internal slot&lt;br /&gt;
        ////and return 0 if set to true&lt;br /&gt;
        self.width&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== '''Proposed Implementation''' ==&lt;br /&gt;
Among the remaining steps in the initial and subsequent phases, the focus will be on step 2 of initial phase and once there is progress made on this step, implementation of the subsequent steps will take place. &lt;br /&gt;
&lt;br /&gt;
;Starting with createImageBitmap()&lt;br /&gt;
&lt;br /&gt;
:*The createImageBitmap() method creates a bitmap from a given source, optionally cropped to contain only a portion of that source. The method exists on the global scope in both windows and workers. It accepts a variety of different image sources, and returns a Promise which resolves to an ImageBitmap.&lt;br /&gt;
:*This method is defined in the file ''components/script/dom/webidls/WindowOrWorkerGlobalScope.webidl'' and rust code is implemented at ''components/script/dom/window.rs''.&lt;br /&gt;
:*The syntax of the method looks like&lt;br /&gt;
:::const imageBitmapPromise = createImageBitmap(image[, options]);&lt;br /&gt;
:::const imageBitmapPromise = createImageBitmap(image, sx, sy, sw, sh[, options]);&lt;br /&gt;
::where the parameters indicate:&lt;br /&gt;
:::'''image:''' an image source, which can be an img element, a SVG image element, a video element, a canvas element, a blob object, an ImageData object or another ImageBitmap object.&lt;br /&gt;
:::'''sx, sy, sw, sh:''' if given, source image is cropped to the given pixels.&lt;br /&gt;
:::'''options (Optional):''' the ImageBitmap object's bitmap data is modified according to options. Available options are:&lt;br /&gt;
:::*imageOrientation&lt;br /&gt;
:::*premultiplyAlpha&lt;br /&gt;
:::*colorSpaceConversion&lt;br /&gt;
:::*resizeWidth&lt;br /&gt;
:::*resizeHeight&lt;br /&gt;
:::*resizeQuality&lt;br /&gt;
:::: You can read more about these options [https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/createImageBitmap here]&lt;br /&gt;
::The return value is a Promise that is resolved when a new ImageBitmap is created.&lt;br /&gt;
:* As a first step, we will be implementing the method to handle canvas elements. Subsequently, we will be enhancing the method to handle other image sources and the x/y/w/h parameters.&lt;br /&gt;
&lt;br /&gt;
;Implementing close() method from previous work&lt;br /&gt;
&lt;br /&gt;
:* close() is a method in the ImageBitmap interface. It is implemented in ''components/script/dom/imagebitmap.rs'' file.&lt;br /&gt;
:* This method disposes of all graphical resources associated with an ImageBitmap.&lt;br /&gt;
&lt;br /&gt;
== '''Current Implementation''' ==&lt;br /&gt;
&lt;br /&gt;
* Implemented createImageBitmap method for canvas image source(HTMLCanvasElement and OffscreenCanvas) using RUST programming language.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// https://html.spec.whatwg.org/multipage/#dom-createimagebitmap&lt;br /&gt;
fn CreateImageBitmap(&lt;br /&gt;
    &amp;amp;self,&lt;br /&gt;
    image: ImageBitmapSource,&lt;br /&gt;
    options: &amp;amp;ImageBitmapOptions,&lt;br /&gt;
) -&amp;gt; Rc&amp;lt;Promise&amp;gt; {&lt;br /&gt;
    let global = self.global();&lt;br /&gt;
    let in_realm_proof = AlreadyInRealm::assert(&amp;amp;global);&lt;br /&gt;
    let p = Promise::new_in_current_realm(&amp;amp;global, InRealm::Already(&amp;amp;in_realm_proof));&lt;br /&gt;
    if options.resizeWidth.unwrap() == 0 {&lt;br /&gt;
        p.reject_error(Error::InvalidState)&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if options.resizeHeight.unwrap() == 0 {&lt;br /&gt;
        p.reject_error(Error::InvalidState)&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    let image_bitmap = ImageBitmap::new(&amp;amp;global, 0, 0).unwrap();&lt;br /&gt;
&lt;br /&gt;
    let promise = match image {&lt;br /&gt;
        ImageBitmapSource::HTMLCanvasElement(ref canvas) =&amp;gt; {&lt;br /&gt;
            // https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument&lt;br /&gt;
            if !canvas.is_valid() {&lt;br /&gt;
                p.reject_error(Error::InvalidState)&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if let Some((data, size)) = canvas.fetch_all_data() {&lt;br /&gt;
                let data = DomRefCell::new(&lt;br /&gt;
                    data.map(|data| data.to_vec())&lt;br /&gt;
                        .unwrap_or_else(|| vec![0; size.area() as usize * 4]),&lt;br /&gt;
                );&lt;br /&gt;
&lt;br /&gt;
                image_bitmap.set_bitmap_data(data);&lt;br /&gt;
                image_bitmap.set_origin_clean(canvas.origin_is_clean());&lt;br /&gt;
                p.resolve_native(&amp;amp;(image_bitmap));&lt;br /&gt;
            }&lt;br /&gt;
            p&lt;br /&gt;
        },&lt;br /&gt;
        ImageBitmapSource::OffscreenCanvas(ref canvas) =&amp;gt; {&lt;br /&gt;
            // https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument&lt;br /&gt;
            if !canvas.is_valid() {&lt;br /&gt;
                p.reject_error(Error::InvalidState)&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if let Some((data, size)) = canvas.fetch_all_data() {&lt;br /&gt;
                let data = DomRefCell::new(&lt;br /&gt;
                    data.map(|data| data.to_vec())&lt;br /&gt;
                        .unwrap_or_else(|| vec![0; size.area() as usize * 4]),&lt;br /&gt;
                );&lt;br /&gt;
&lt;br /&gt;
                image_bitmap.set_bitmap_data(data);&lt;br /&gt;
                image_bitmap.set_origin_clean(canvas.origin_is_clean());&lt;br /&gt;
                p.resolve_native(&amp;amp;(image_bitmap));&lt;br /&gt;
            }&lt;br /&gt;
            p&lt;br /&gt;
        },&lt;br /&gt;
        _ =&amp;gt; p,&lt;br /&gt;
    };&lt;br /&gt;
    promise&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Tested the build using ‘mach’ commands&lt;br /&gt;
&lt;br /&gt;
== '''Algorithm to design the createImageBitmap() method''' ==&lt;br /&gt;
&lt;br /&gt;
On invoking the createImageBitmap(image, options) or the createImageBitmap(image sx, sy, sw, sh, options) the following in the sequence of actions&lt;br /&gt;
&lt;br /&gt;
[[File:fig1.png|border]] &lt;br /&gt;
&lt;br /&gt;
Switching on the &amp;quot;image&amp;quot; argument the following is the sequence of actions &lt;br /&gt;
&lt;br /&gt;
=== If the image is an SVGImage===&lt;br /&gt;
[[File:fig2.png|border]]&lt;br /&gt;
&lt;br /&gt;
=== If the image is a video===&lt;br /&gt;
[[File:ReFigure3.png|border]] &lt;br /&gt;
&lt;br /&gt;
=== If the image is a canvas===&lt;br /&gt;
[[File:ReFigure4.png|border]]&lt;br /&gt;
 &lt;br /&gt;
=== If the image is an ImageBitmap===&lt;br /&gt;
[[File:ImageBitmap.jpg|border]]&lt;br /&gt;
&lt;br /&gt;
=== If the image is an ImageData===&lt;br /&gt;
[[File:ImageData.jpg|border]]&lt;br /&gt;
&lt;br /&gt;
=='''Test Plan'''==&lt;br /&gt;
The following are the respective steps in testing:&lt;br /&gt;
* &amp;lt;b&amp;gt;Servo check should be successful.&amp;lt;/b&amp;gt;&lt;br /&gt;
The compiling time for servo build takes a lot of time. In order to make sure that our changes didn't break any of the existing features, we run &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Linux or macOS:&lt;br /&gt;
    ./mach check&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Windows:&lt;br /&gt;
    mach.bat check&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:machCheck.png]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt;Servo building test should be successful.&amp;lt;/b&amp;gt;&lt;br /&gt;
The compiling time is based on the CPU clock speed and the OS of the system where the file is being run. For a 64-bit Linux OS, it takes from about 1 hour to 2 hours for the entire build. It takes 2.5 hours on Windows OS.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Linux or macOS:&lt;br /&gt;
    ./mach build --dev&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Windows:&lt;br /&gt;
    mach.bat build --dev&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
[[File:machBuild.png]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt;Check for the file tidiness (following standards of servo) using the command:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Linux or macOS:&lt;br /&gt;
    ./mach test-tidy&lt;br /&gt;
    ./mach fmt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Windows:&lt;br /&gt;
    mach.bat test-tidy&lt;br /&gt;
    mach.bat fmt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:machTestTidy.png]]&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Servo automated Unit-testing should be successful.&amp;lt;/b&amp;gt;&lt;br /&gt;
Running the following commands will run all the unit-tests&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Linux or macOS:&lt;br /&gt;
    ./mach test-unit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Windows:&lt;br /&gt;
    mach.bat test-unit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note: A log file can be maintained to make keep a check on the tests that are passing.&lt;br /&gt;
* &amp;lt;b&amp;gt;Update the automated servo Web Platform tests(wpt):&amp;lt;/b&amp;gt;&lt;br /&gt;
For a DOM feature, extensive tests already exist under tests/wpt. Any change in DOM would require updating the expected results in the automated tests.&lt;br /&gt;
&lt;br /&gt;
This first requires storing the log in raw format from a test run, for example by running&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach test-wpt --log-raw /path/for/storing/log/file/&amp;lt;filename&amp;gt;.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once log is saved, then run to update test expectations&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach update-wpt /path/to/logfile/&amp;lt;filename&amp;gt;.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt; Finally, to run the servo with a webpage (Google.com) :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Linux or macOS:&lt;br /&gt;
    ./mach run https://www.google.com&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Windows:&lt;br /&gt;
    mach.bat run https://www.google.com&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:machRun.png]]&lt;br /&gt;
&lt;br /&gt;
== '''Team Details''' ==&lt;br /&gt;
 &lt;br /&gt;
Jayalakshmi Vishwanathan (jviswan@ncsu.edu) &lt;br /&gt;
 &lt;br /&gt;
Nita Radhakrishnan (nradhak2@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
Ramya Ananth (rananth2@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
Sandeep Kundala (skundal@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== '''Mentor Details''' ==&lt;br /&gt;
Jay Modi &lt;br /&gt;
&lt;br /&gt;
== '''References''' ==&lt;br /&gt;
 &lt;br /&gt;
* [https://en.wikipedia.org/wiki/Servo_(software)| What is servo?]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Rust_(programming_language)| what is RUST programming?]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/CSC_517_Spring_2020/Implement_ImageBitMap_WebAPI&amp;diff=134166</id>
		<title>CSC/CSC 517 Spring 2020/Implement ImageBitMap WebAPI</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/CSC_517_Spring_2020/Implement_ImageBitMap_WebAPI&amp;diff=134166"/>
		<updated>2020-04-25T03:00:38Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: /* Current Implementation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== '''Background Information''' ==&lt;br /&gt;
This project aims to contribute to Mozilla's experimental browser engine called Servo, which is implemented in a language called RUST(useful for implementing features that need concurrency and memory safety).&lt;br /&gt;
&lt;br /&gt;
Many of the components of Servo are still under development and one such feature is the [https://www.techopedia.com/definition/792/bitmap-bmp| ImageBitmap].&lt;br /&gt;
&lt;br /&gt;
Major browsers support the ImageBitmap standard which can be used to create images that are ready to be drawn efficiently to [https://en.wikipedia.org/wiki/Canvas_element| HTML canvas elements]. Servo is a new, experimental browser that supports these canvas APIs. &lt;br /&gt;
&lt;br /&gt;
The goal of and motivation behind this project is to implement support for image bitmaps and improve our canvas automated test coverage as a result.&lt;br /&gt;
&lt;br /&gt;
== '''About ImageBitMap and Motivation behind the project''' ==&lt;br /&gt;
We usually decode images for a use with canvas to allow users to customize an avatar, crop an image, or just zoom in on a picture. The problem with decoding images is that it can be CPU intensive, and that can sometimes mean jank or checkerboarding.&lt;br /&gt;
&lt;br /&gt;
But the createImageBitmap() method allows us to decode the image in the background and get access to a new ImageBitmap primitive, which you can draw into a canvas in the same way you would an &amp;lt;img&amp;gt; element, another canvas, or a video.&lt;br /&gt;
&lt;br /&gt;
The aim of this project is to develop the ImageBitmap for the servo environment. &lt;br /&gt;
&lt;br /&gt;
This can be done in the steps mentioned in the following section.&lt;br /&gt;
&lt;br /&gt;
== '''Steps for implementation''' ==&lt;br /&gt;
&lt;br /&gt;
'''Initial Phase'''&lt;br /&gt;
* '''Step 1: '''Add a ImageBitmap WebIDL interface to ''components/script/dom/webidl''s and Rust implementation in components/script/dom/imagebitmap.rs&lt;br /&gt;
* '''Step 2: ''' Add the ''createImageBitmap'' method that takes no extra x/y/w/h parameters in ''component/script/dom/webidls/WindowOrWorkerGlobalScope.webidl'' and implement the method in ''component/script/dom/window.rs'', handling the HTMLCanvasElement and OffscreenCanvas types from the possible image sources&lt;br /&gt;
&lt;br /&gt;
'''Subsequent phase'''&lt;br /&gt;
* '''Step 1: '''Implement several remaining image source types (HTMLImageElement, ImageData, ImageBitmap)&lt;br /&gt;
* '''Step 2: '''Implement the ''createImageBitmap'' overload that accepts x/y/w/h parameters&lt;br /&gt;
* '''Step 3: '''Implement support for ImageBitmaps as canvas image sources in ''components/script/canvas_state.rs''&lt;br /&gt;
[[File:AllSteps.jpg]]&lt;br /&gt;
&lt;br /&gt;
== '''Details about previous work on implementation''' ==&lt;br /&gt;
The steps that have been implemented so far in this project by the previous batch are:&lt;br /&gt;
&lt;br /&gt;
'''Step 1:''' Added the ImageBitmap interface to ''components/script/dom/webidls'' that represents a bitmap image which can be drawn to a &amp;lt;canvas&amp;gt; without undue latency. The interface contains height and weight as its attributes which are read only unsigned long integers.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//[Exposed=(Window,Worker), Serializable, Transferable]&lt;br /&gt;
[Exposed=(Window,Worker)]&lt;br /&gt;
interface ImageBitmap {&lt;br /&gt;
  readonly attribute unsigned long width;&lt;br /&gt;
  readonly attribute unsigned long height;&lt;br /&gt;
  //void close();&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef (CanvasImageSource or&lt;br /&gt;
         Blob or&lt;br /&gt;
         ImageData) ImageBitmapSource;&lt;br /&gt;
&lt;br /&gt;
enum ImageOrientation { &amp;quot;none&amp;quot;, &amp;quot;flipY&amp;quot; };&lt;br /&gt;
enum PremultiplyAlpha { &amp;quot;none&amp;quot;, &amp;quot;premultiply&amp;quot;, &amp;quot;default&amp;quot; };&lt;br /&gt;
enum ColorSpaceConversion { &amp;quot;none&amp;quot;, &amp;quot;default&amp;quot; };&lt;br /&gt;
enum ResizeQuality { &amp;quot;pixelated&amp;quot;, &amp;quot;low&amp;quot;, &amp;quot;medium&amp;quot;, &amp;quot;high&amp;quot; };&lt;br /&gt;
&lt;br /&gt;
dictionary ImageBitmapOptions {&lt;br /&gt;
  ImageOrientation imageOrientation = &amp;quot;none&amp;quot;;&lt;br /&gt;
  PremultiplyAlpha premultiplyAlpha = &amp;quot;default&amp;quot;;&lt;br /&gt;
  ColorSpaceConversion colorSpaceConversion = &amp;quot;default&amp;quot;;&lt;br /&gt;
  [EnforceRange] unsigned long resizeWidth;&lt;br /&gt;
  [EnforceRange] unsigned long resizeHeight;&lt;br /&gt;
  ResizeQuality resizeQuality = &amp;quot;low&amp;quot;;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ImageBitmap webidl also defines a dictionary for various ImageBitmap Options that can be used to modify the ImageBitmap object.&lt;br /&gt;
&lt;br /&gt;
'''Step 2:''' Implemented the rust code for the webidl interface at ''components/script/dom/imagebitmap.rs''. For more details on the code [https://expertiza.csc.ncsu.edu/index.php/CSC/ECE_517_Spring_2020_-_M2000._Implement_ImageBitMap_web_API#Implementation visit]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
use crate::dom::bindings::cell::DomRefCell;&lt;br /&gt;
&lt;br /&gt;
use crate::dom::bindings::codegen::Bindings::ImageBitmapBinding::ImageBitmapMethods;&lt;br /&gt;
use crate::dom::bindings::root::DomRoot;&lt;br /&gt;
use crate::dom::globalscope::GlobalScope;&lt;br /&gt;
&lt;br /&gt;
use crate::dom::bindings::error::Fallible;&lt;br /&gt;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};&lt;br /&gt;
use dom_struct::dom_struct;&lt;br /&gt;
&lt;br /&gt;
use std::vec::Vec;&lt;br /&gt;
&lt;br /&gt;
#[dom_struct]&lt;br /&gt;
pub struct ImageBitmap {&lt;br /&gt;
    reflector_: Reflector,&lt;br /&gt;
    width: u32,&lt;br /&gt;
    height: u32,&lt;br /&gt;
    bitmap_data: DomRefCell&amp;lt;Vec&amp;lt;u8&amp;gt;&amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
impl ImageBitmap {&lt;br /&gt;
    fn new_inherited(width_arg: u32, height_arg: u32) -&amp;gt; ImageBitmap {&lt;br /&gt;
        ImageBitmap {&lt;br /&gt;
            reflector_: Reflector::new(),&lt;br /&gt;
            width: width_arg,&lt;br /&gt;
            height: height_arg,&lt;br /&gt;
            bitmap_data: DomRefCell::new(vec![]),&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    #[allow(dead_code)]&lt;br /&gt;
    pub fn new(global: &amp;amp;GlobalScope, width: u32, height: u32) -&amp;gt; Fallible&amp;lt;DomRoot&amp;lt;ImageBitmap&amp;gt;&amp;gt; {&lt;br /&gt;
        //assigning to a variable the return object of new_inherited&lt;br /&gt;
        let imagebitmap = Box::new(ImageBitmap::new_inherited(width, height));&lt;br /&gt;
&lt;br /&gt;
        Ok(reflect_dom_object(imagebitmap, global))&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code also implements the getter methods for height and width attribute of an ImageBitmap object.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
impl ImageBitmapMethods for ImageBitmap {&lt;br /&gt;
    // https://html.spec.whatwg.org/multipage/#dom-imagebitmap-height&lt;br /&gt;
    fn Height(&amp;amp;self) -&amp;gt; u32 {&lt;br /&gt;
        //to do: add a condition for checking detached internal slot&lt;br /&gt;
        //and return 0 if set to true&lt;br /&gt;
        self.height&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // https://html.spec.whatwg.org/multipage/#dom-imagebitmap-width&lt;br /&gt;
    fn Width(&amp;amp;self) -&amp;gt; u32 {&lt;br /&gt;
        //to do: add a condition to check detached internal slot&lt;br /&gt;
        ////and return 0 if set to true&lt;br /&gt;
        self.width&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== '''Proposed Implementation''' ==&lt;br /&gt;
Among the remaining steps in the initial and subsequent phases, the focus will be on step 2 of initial phase and once there is progress made on this step, implementation of the subsequent steps will take place. &lt;br /&gt;
&lt;br /&gt;
;Starting with createImageBitmap()&lt;br /&gt;
&lt;br /&gt;
:*The createImageBitmap() method creates a bitmap from a given source, optionally cropped to contain only a portion of that source. The method exists on the global scope in both windows and workers. It accepts a variety of different image sources, and returns a Promise which resolves to an ImageBitmap.&lt;br /&gt;
:*This method is defined in the file ''components/script/dom/webidls/WindowOrWorkerGlobalScope.webidl'' and rust code is implemented at ''components/script/dom/window.rs''.&lt;br /&gt;
:*The syntax of the method looks like&lt;br /&gt;
:::const imageBitmapPromise = createImageBitmap(image[, options]);&lt;br /&gt;
:::const imageBitmapPromise = createImageBitmap(image, sx, sy, sw, sh[, options]);&lt;br /&gt;
::where the parameters indicate:&lt;br /&gt;
:::'''image:''' an image source, which can be an img element, a SVG image element, a video element, a canvas element, a blob object, an ImageData object or another ImageBitmap object.&lt;br /&gt;
:::'''sx, sy, sw, sh:''' if given, source image is cropped to the given pixels.&lt;br /&gt;
:::'''options (Optional):''' the ImageBitmap object's bitmap data is modified according to options. Available options are:&lt;br /&gt;
:::*imageOrientation&lt;br /&gt;
:::*premultiplyAlpha&lt;br /&gt;
:::*colorSpaceConversion&lt;br /&gt;
:::*resizeWidth&lt;br /&gt;
:::*resizeHeight&lt;br /&gt;
:::*resizeQuality&lt;br /&gt;
:::: You can read more about these options [https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/createImageBitmap here]&lt;br /&gt;
::The return value is a Promise that is resolved when a new ImageBitmap is created.&lt;br /&gt;
:* As a first step, we will be implementing the method to handle canvas elements. Subsequently, we will be enhancing the method to handle other image sources and the x/y/w/h parameters.&lt;br /&gt;
&lt;br /&gt;
;Implementing close() method from previous work&lt;br /&gt;
&lt;br /&gt;
:* close() is a method in the ImageBitmap interface. It is implemented in ''components/script/dom/imagebitmap.rs'' file.&lt;br /&gt;
:* This method disposes of all graphical resources associated with an ImageBitmap.&lt;br /&gt;
&lt;br /&gt;
== '''Current Implementation''' ==&lt;br /&gt;
&lt;br /&gt;
* Implemented createImageBitmap method for canvas image source(HTMLCanvasElement and OffscreenCanvas) using RUST programming language.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // https://html.spec.whatwg.org/multipage/#dom-createimagebitmap&lt;br /&gt;
    fn CreateImageBitmap(&lt;br /&gt;
        &amp;amp;self,&lt;br /&gt;
        image: ImageBitmapSource,&lt;br /&gt;
        options: &amp;amp;ImageBitmapOptions,&lt;br /&gt;
    ) -&amp;gt; Rc&amp;lt;Promise&amp;gt; {&lt;br /&gt;
        let global = self.global();&lt;br /&gt;
        let in_realm_proof = AlreadyInRealm::assert(&amp;amp;global);&lt;br /&gt;
        let p = Promise::new_in_current_realm(&amp;amp;global, InRealm::Already(&amp;amp;in_realm_proof));&lt;br /&gt;
        if options.resizeWidth.unwrap() == 0 {&lt;br /&gt;
            p.reject_error(Error::InvalidState)&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if options.resizeHeight.unwrap() == 0 {&lt;br /&gt;
            p.reject_error(Error::InvalidState)&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        let image_bitmap = ImageBitmap::new(&amp;amp;global, 0, 0).unwrap();&lt;br /&gt;
&lt;br /&gt;
        let promise = match image {&lt;br /&gt;
            ImageBitmapSource::HTMLCanvasElement(ref canvas) =&amp;gt; {&lt;br /&gt;
                // https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument&lt;br /&gt;
                if !canvas.is_valid() {&lt;br /&gt;
                    p.reject_error(Error::InvalidState)&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if let Some((data, size)) = canvas.fetch_all_data() {&lt;br /&gt;
                    let data = DomRefCell::new(&lt;br /&gt;
                        data.map(|data| data.to_vec())&lt;br /&gt;
                            .unwrap_or_else(|| vec![0; size.area() as usize * 4]),&lt;br /&gt;
                    );&lt;br /&gt;
&lt;br /&gt;
                    image_bitmap.set_bitmap_data(data);&lt;br /&gt;
                    image_bitmap.set_origin_clean(canvas.origin_is_clean());&lt;br /&gt;
                    p.resolve_native(&amp;amp;(image_bitmap));&lt;br /&gt;
                }&lt;br /&gt;
                p&lt;br /&gt;
            },&lt;br /&gt;
            ImageBitmapSource::OffscreenCanvas(ref canvas) =&amp;gt; {&lt;br /&gt;
                // https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument&lt;br /&gt;
                if !canvas.is_valid() {&lt;br /&gt;
                    p.reject_error(Error::InvalidState)&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if let Some((data, size)) = canvas.fetch_all_data() {&lt;br /&gt;
                    let data = DomRefCell::new(&lt;br /&gt;
                        data.map(|data| data.to_vec())&lt;br /&gt;
                            .unwrap_or_else(|| vec![0; size.area() as usize * 4]),&lt;br /&gt;
                    );&lt;br /&gt;
&lt;br /&gt;
                    image_bitmap.set_bitmap_data(data);&lt;br /&gt;
                    image_bitmap.set_origin_clean(canvas.origin_is_clean());&lt;br /&gt;
                    p.resolve_native(&amp;amp;(image_bitmap));&lt;br /&gt;
                }&lt;br /&gt;
                p&lt;br /&gt;
            },&lt;br /&gt;
            _ =&amp;gt; p,&lt;br /&gt;
        };&lt;br /&gt;
        promise&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Tested the build using ‘mach’ commands&lt;br /&gt;
&lt;br /&gt;
== '''Algorithm to design the createImageBitmap() method''' ==&lt;br /&gt;
&lt;br /&gt;
On invoking the createImageBitmap(image, options) or the createImageBitmap(image sx, sy, sw, sh, options) the following in the sequence of actions&lt;br /&gt;
&lt;br /&gt;
[[File:fig1.png|border]] &lt;br /&gt;
&lt;br /&gt;
Switching on the &amp;quot;image&amp;quot; argument the following is the sequence of actions &lt;br /&gt;
&lt;br /&gt;
=== If the image is an SVGImage===&lt;br /&gt;
[[File:fig2.png|border]]&lt;br /&gt;
&lt;br /&gt;
=== If the image is a video===&lt;br /&gt;
[[File:ReFigure3.png|border]] &lt;br /&gt;
&lt;br /&gt;
=== If the image is a canvas===&lt;br /&gt;
[[File:ReFigure4.png|border]]&lt;br /&gt;
 &lt;br /&gt;
=== If the image is an ImageBitmap===&lt;br /&gt;
[[File:ImageBitmap.jpg|border]]&lt;br /&gt;
&lt;br /&gt;
=== If the image is an ImageData===&lt;br /&gt;
[[File:ImageData.jpg|border]]&lt;br /&gt;
&lt;br /&gt;
=='''Test Plan'''==&lt;br /&gt;
The following are the respective steps in testing:&lt;br /&gt;
* &amp;lt;b&amp;gt;Servo check should be successful.&amp;lt;/b&amp;gt;&lt;br /&gt;
The compiling time for servo build takes a lot of time. In order to make sure that our changes didn't break any of the existing features, we run &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Linux or macOS:&lt;br /&gt;
    ./mach check&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Windows:&lt;br /&gt;
    mach.bat check&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:machCheck.png]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt;Servo building test should be successful.&amp;lt;/b&amp;gt;&lt;br /&gt;
The compiling time is based on the CPU clock speed and the OS of the system where the file is being run. For a 64-bit Linux OS, it takes from about 1 hour to 2 hours for the entire build. It takes 2.5 hours on Windows OS.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Linux or macOS:&lt;br /&gt;
    ./mach build --dev&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Windows:&lt;br /&gt;
    mach.bat build --dev&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
[[File:machBuild.png]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt;Check for the file tidiness (following standards of servo) using the command:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Linux or macOS:&lt;br /&gt;
    ./mach test-tidy&lt;br /&gt;
    ./mach fmt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Windows:&lt;br /&gt;
    mach.bat test-tidy&lt;br /&gt;
    mach.bat fmt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:machTestTidy.png]]&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;Servo automated Unit-testing should be successful.&amp;lt;/b&amp;gt;&lt;br /&gt;
Running the following commands will run all the unit-tests&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Linux or macOS:&lt;br /&gt;
    ./mach test-unit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Windows:&lt;br /&gt;
    mach.bat test-unit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note: A log file can be maintained to make keep a check on the tests that are passing.&lt;br /&gt;
* &amp;lt;b&amp;gt;Update the automated servo Web Platform tests(wpt):&amp;lt;/b&amp;gt;&lt;br /&gt;
For a DOM feature, extensive tests already exist under tests/wpt. Any change in DOM would require updating the expected results in the automated tests.&lt;br /&gt;
&lt;br /&gt;
This first requires storing the log in raw format from a test run, for example by running&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach test-wpt --log-raw /path/for/storing/log/file/&amp;lt;filename&amp;gt;.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once log is saved, then run to update test expectations&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach update-wpt /path/to/logfile/&amp;lt;filename&amp;gt;.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt; Finally, to run the servo with a webpage (Google.com) :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Linux or macOS:&lt;br /&gt;
    ./mach run https://www.google.com&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Windows:&lt;br /&gt;
    mach.bat run https://www.google.com&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:machRun.png]]&lt;br /&gt;
&lt;br /&gt;
== '''Team Details''' ==&lt;br /&gt;
 &lt;br /&gt;
Jayalakshmi Vishwanathan (jviswan@ncsu.edu) &lt;br /&gt;
 &lt;br /&gt;
Nita Radhakrishnan (nradhak2@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
Ramya Ananth (rananth2@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
Sandeep Kundala (skundal@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== '''Mentor Details''' ==&lt;br /&gt;
Jay Modi &lt;br /&gt;
&lt;br /&gt;
== '''References''' ==&lt;br /&gt;
 &lt;br /&gt;
* [https://en.wikipedia.org/wiki/Servo_(software)| What is servo?]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Rust_(programming_language)| what is RUST programming?]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:MachBuild.png&amp;diff=134000</id>
		<title>File:MachBuild.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:MachBuild.png&amp;diff=134000"/>
		<updated>2020-04-25T00:09:11Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:MachCheck.png&amp;diff=133999</id>
		<title>File:MachCheck.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:MachCheck.png&amp;diff=133999"/>
		<updated>2020-04-25T00:08:17Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:MachRun.png&amp;diff=133997</id>
		<title>File:MachRun.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:MachRun.png&amp;diff=133997"/>
		<updated>2020-04-25T00:08:00Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:MachTestTidy.png&amp;diff=133992</id>
		<title>File:MachTestTidy.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:MachTestTidy.png&amp;diff=133992"/>
		<updated>2020-04-25T00:05:33Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/CSC_517_Spring_2020/Implement_ImageBitMap_WebAPI&amp;diff=133632</id>
		<title>CSC/CSC 517 Spring 2020/Implement ImageBitMap WebAPI</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/CSC_517_Spring_2020/Implement_ImageBitMap_WebAPI&amp;diff=133632"/>
		<updated>2020-04-14T03:49:32Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: /* Steps for implementation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== '''Background Information''' ==&lt;br /&gt;
This project aims to contribute to Mozilla's experimental browser engine called Servo, which is implemented in a language called RUST(useful for implementing features that need concurrency and memory safety).&lt;br /&gt;
&lt;br /&gt;
Many of the components of Servo are still under development and one such feature is the [https://www.techopedia.com/definition/792/bitmap-bmp| ImageBitmap].&lt;br /&gt;
&lt;br /&gt;
Major browsers support the ImageBitmap standard which can be used to create images that are ready to be drawn efficiently to [https://en.wikipedia.org/wiki/Canvas_element| HTML canvas elements]. Servo is a new, experimental browser that supports these canvas APIs. &lt;br /&gt;
&lt;br /&gt;
The goal of and motivation behind this project is to implement support for image bitmaps and improve our canvas automated test coverage as a result.&lt;br /&gt;
&lt;br /&gt;
== '''About ImageBitMap and Motivation behind the project''' ==&lt;br /&gt;
We usually decode images for a use with canvas to allow users to customize an avatar, crop an image, or just zoom in on a picture. The problem with decoding images is that it can be CPU intensive, and that can sometimes mean jank or checkerboarding.&lt;br /&gt;
&lt;br /&gt;
But the createImageBitmap() method allows us to decode the image in the background and get access to a new ImageBitmap primitive, which you can draw into a canvas in the same way you would an &amp;lt;img&amp;gt; element, another canvas, or a video.&lt;br /&gt;
&lt;br /&gt;
The aim of this project is to develop the ImageBitmap for the servo environment. &lt;br /&gt;
&lt;br /&gt;
This can be done in the steps mentioned in the following section.&lt;br /&gt;
&lt;br /&gt;
== '''Steps for implementation''' ==&lt;br /&gt;
&lt;br /&gt;
'''Initial Phase'''&lt;br /&gt;
* '''Step 1: '''Add a ImageBitmap WebIDL interface to ''components/script/dom/webidl''s and Rust implementation in components/script/dom/imagebitmap.rs&lt;br /&gt;
* '''Step 2: ''' Add the ''createImageBitmap'' method that takes no extra x/y/w/h parameters in ''component/script/dom/webidls/WindowOrWorkerGlobalScope.webidl'' and implement the method in ''component/script/dom/window.rs'', handling the HTMLCanvasElement and OffscreenCanvas types from the possible image sources&lt;br /&gt;
&lt;br /&gt;
'''Subsequent phase'''&lt;br /&gt;
* '''Step 1: '''Implement several remaining image source types (HTMLImageElement, ImageData, ImageBitmap)&lt;br /&gt;
* '''Step 2: '''Implement the ''createImageBitmap'' overload that accepts x/y/w/h parameters&lt;br /&gt;
* '''Step 3: '''Implement support for ImageBitmaps as canvas image sources in ''components/script/canvas_state.rs''&lt;br /&gt;
[[File:AllSteps.jpg]]&lt;br /&gt;
&lt;br /&gt;
== '''Details about previous work on implementation''' ==&lt;br /&gt;
The steps that have been implemented so far in this project by the previous batch are:&lt;br /&gt;
&lt;br /&gt;
'''Step 1:''' Added the ImageBitmap interface to ''components/script/dom/webidls'' that represents a bitmap image which can be drawn to a &amp;lt;canvas&amp;gt; without undue latency. The interface contains height and weight as its attributes which are read only unsigned long integers.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//[Exposed=(Window,Worker), Serializable, Transferable]&lt;br /&gt;
[Exposed=(Window,Worker)]&lt;br /&gt;
interface ImageBitmap {&lt;br /&gt;
  readonly attribute unsigned long width;&lt;br /&gt;
  readonly attribute unsigned long height;&lt;br /&gt;
  //void close();&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef (CanvasImageSource or&lt;br /&gt;
         Blob or&lt;br /&gt;
         ImageData) ImageBitmapSource;&lt;br /&gt;
&lt;br /&gt;
enum ImageOrientation { &amp;quot;none&amp;quot;, &amp;quot;flipY&amp;quot; };&lt;br /&gt;
enum PremultiplyAlpha { &amp;quot;none&amp;quot;, &amp;quot;premultiply&amp;quot;, &amp;quot;default&amp;quot; };&lt;br /&gt;
enum ColorSpaceConversion { &amp;quot;none&amp;quot;, &amp;quot;default&amp;quot; };&lt;br /&gt;
enum ResizeQuality { &amp;quot;pixelated&amp;quot;, &amp;quot;low&amp;quot;, &amp;quot;medium&amp;quot;, &amp;quot;high&amp;quot; };&lt;br /&gt;
&lt;br /&gt;
dictionary ImageBitmapOptions {&lt;br /&gt;
  ImageOrientation imageOrientation = &amp;quot;none&amp;quot;;&lt;br /&gt;
  PremultiplyAlpha premultiplyAlpha = &amp;quot;default&amp;quot;;&lt;br /&gt;
  ColorSpaceConversion colorSpaceConversion = &amp;quot;default&amp;quot;;&lt;br /&gt;
  [EnforceRange] unsigned long resizeWidth;&lt;br /&gt;
  [EnforceRange] unsigned long resizeHeight;&lt;br /&gt;
  ResizeQuality resizeQuality = &amp;quot;low&amp;quot;;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ImageBitmap webidl also defines a dictionary for various ImageBitmap Options that can be used to modify the ImageBitmap object.&lt;br /&gt;
&lt;br /&gt;
'''Step 2:''' Implemented the rust code for the webidl interface at ''components/script/dom/imagebitmap.rs''. For more details on the code [https://expertiza.csc.ncsu.edu/index.php/CSC/ECE_517_Spring_2020_-_M2000._Implement_ImageBitMap_web_API#Implementation visit]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
use crate::dom::bindings::cell::DomRefCell;&lt;br /&gt;
&lt;br /&gt;
use crate::dom::bindings::codegen::Bindings::ImageBitmapBinding::ImageBitmapMethods;&lt;br /&gt;
use crate::dom::bindings::root::DomRoot;&lt;br /&gt;
use crate::dom::globalscope::GlobalScope;&lt;br /&gt;
&lt;br /&gt;
use crate::dom::bindings::error::Fallible;&lt;br /&gt;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};&lt;br /&gt;
use dom_struct::dom_struct;&lt;br /&gt;
&lt;br /&gt;
use std::vec::Vec;&lt;br /&gt;
&lt;br /&gt;
#[dom_struct]&lt;br /&gt;
pub struct ImageBitmap {&lt;br /&gt;
    reflector_: Reflector,&lt;br /&gt;
    width: u32,&lt;br /&gt;
    height: u32,&lt;br /&gt;
    bitmap_data: DomRefCell&amp;lt;Vec&amp;lt;u8&amp;gt;&amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
impl ImageBitmap {&lt;br /&gt;
    fn new_inherited(width_arg: u32, height_arg: u32) -&amp;gt; ImageBitmap {&lt;br /&gt;
        ImageBitmap {&lt;br /&gt;
            reflector_: Reflector::new(),&lt;br /&gt;
            width: width_arg,&lt;br /&gt;
            height: height_arg,&lt;br /&gt;
            bitmap_data: DomRefCell::new(vec![]),&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    #[allow(dead_code)]&lt;br /&gt;
    pub fn new(global: &amp;amp;GlobalScope, width: u32, height: u32) -&amp;gt; Fallible&amp;lt;DomRoot&amp;lt;ImageBitmap&amp;gt;&amp;gt; {&lt;br /&gt;
        //assigning to a variable the return object of new_inherited&lt;br /&gt;
        let imagebitmap = Box::new(ImageBitmap::new_inherited(width, height));&lt;br /&gt;
&lt;br /&gt;
        Ok(reflect_dom_object(imagebitmap, global))&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code also implements the getter methods for height and width attribute of an ImageBitmap object.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
impl ImageBitmapMethods for ImageBitmap {&lt;br /&gt;
    // https://html.spec.whatwg.org/multipage/#dom-imagebitmap-height&lt;br /&gt;
    fn Height(&amp;amp;self) -&amp;gt; u32 {&lt;br /&gt;
        //to do: add a condition for checking detached internal slot&lt;br /&gt;
        //and return 0 if set to true&lt;br /&gt;
        self.height&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // https://html.spec.whatwg.org/multipage/#dom-imagebitmap-width&lt;br /&gt;
    fn Width(&amp;amp;self) -&amp;gt; u32 {&lt;br /&gt;
        //to do: add a condition to check detached internal slot&lt;br /&gt;
        ////and return 0 if set to true&lt;br /&gt;
        self.width&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== '''Details about current work on implementation''' ==&lt;br /&gt;
Among the remaining steps in the initial and subsequent phases, the focus will be on step 2 of initial phase and once there is progress made on this step, implementation of the subsequent steps will take place. &lt;br /&gt;
&lt;br /&gt;
;Starting with createImageBitmap()&lt;br /&gt;
&lt;br /&gt;
:*The createImageBitmap() method creates a bitmap from a given source, optionally cropped to contain only a portion of that source. The method exists on the global scope in both windows and workers. It accepts a variety of different image sources, and returns a Promise which resolves to an ImageBitmap.&lt;br /&gt;
:*This method is defined in the file ''components/script/dom/webidls/WindowOrWorkerGlobalScope.webidl'' and rust code is implemented at ''components/script/dom/window.rs''.&lt;br /&gt;
:*The syntax of the method looks like&lt;br /&gt;
:::const imageBitmapPromise = createImageBitmap(image[, options]);&lt;br /&gt;
:::const imageBitmapPromise = createImageBitmap(image, sx, sy, sw, sh[, options]);&lt;br /&gt;
::where the parameters indicate:&lt;br /&gt;
:::'''image:''' an image source, which can be an img element, a SVG image element, a video element, a canvas element, a blob object, an ImageData object or another ImageBitmap object.&lt;br /&gt;
:::'''sx, sy, sw, sh:''' if given, source image is cropped to the given pixels.&lt;br /&gt;
:::'''options (Optional):''' the ImageBitmap object's bitmap data is modified according to options. Available options are:&lt;br /&gt;
:::*imageOrientation&lt;br /&gt;
:::*premultiplyAlpha&lt;br /&gt;
:::*colorSpaceConversion&lt;br /&gt;
:::*resizeWidth&lt;br /&gt;
:::*resizeHeight&lt;br /&gt;
:::*resizeQuality&lt;br /&gt;
:::: You can read more about these options [https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/createImageBitmap here]&lt;br /&gt;
::The return value is a Promise that is resolved when a new ImageBitmap is created.&lt;br /&gt;
:* As a first step, we will be implementing the method to handle canvas elements. Subsequently, we will be enhancing the method to handle other image sources and the x/y/w/h parameters.&lt;br /&gt;
&lt;br /&gt;
;Implementing close() method from previous work&lt;br /&gt;
&lt;br /&gt;
:* close() is a method in the ImageBitmap interface. It is implemented in ''components/script/dom/imagebitmap.rs'' file.&lt;br /&gt;
:* This method disposes of all graphical resources associated with an ImageBitmap.&lt;br /&gt;
&lt;br /&gt;
== '''Algorithm to design the createImageBitmap() method''' ==&lt;br /&gt;
&lt;br /&gt;
On invoking the createImageBitmap(image, options) or the createImageBitmap(image sx, sy, sw, sh, options) the following in the sequence of actions&lt;br /&gt;
&lt;br /&gt;
[[File:fig1.png|border]] &lt;br /&gt;
&lt;br /&gt;
Switching on the &amp;quot;image&amp;quot; argument the following is the sequence of actions &lt;br /&gt;
&lt;br /&gt;
=== If the image is an SVGImage===&lt;br /&gt;
[[File:fig2.png|border]]&lt;br /&gt;
&lt;br /&gt;
=== If the image is a video===&lt;br /&gt;
[[File:ReFigure3.png|border]] &lt;br /&gt;
&lt;br /&gt;
=== If the image is a canvas===&lt;br /&gt;
[[File:ReFigure4.png|border]]&lt;br /&gt;
 &lt;br /&gt;
=== If the image is an ImageBitmap===&lt;br /&gt;
[[File:ImageBitmap.jpg|border]]&lt;br /&gt;
&lt;br /&gt;
=== If the image is an ImageData===&lt;br /&gt;
[[File:ImageData.jpg|border]]&lt;br /&gt;
&lt;br /&gt;
=='''Test Plan'''==&lt;br /&gt;
The following are the respective steps in testing:&lt;br /&gt;
* &amp;lt;b&amp;gt;Servo building test should be successful.&amp;lt;/b&amp;gt;&lt;br /&gt;
The compiling time is based on the CPU clock speed and the OS of the system where the file is being run. For a 64-bit Linux OS, it takes from about 1 hour to 2 hours for the entire build. It takes 2.5 hours on Windows OS.&lt;br /&gt;
* &amp;lt;b&amp;gt;Check for the file tidiness (following standards of servo) using the command:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Linux or macOS:&lt;br /&gt;
    ./mach test-tidy&lt;br /&gt;
    ./mach fmt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Windows:&lt;br /&gt;
    mach.bat test-tidy&lt;br /&gt;
    mach.bat fmt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
*&amp;lt;b&amp;gt;Servo automated Unit-testing should be successful.&amp;lt;/b&amp;gt;&lt;br /&gt;
Running the following commands will run all the unit-tests&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Linux or macOS:&lt;br /&gt;
    ./mach test-unit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Windows:&lt;br /&gt;
    mach.bat test-unit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note: A log file can be maintained to make keep a check on the tests that are passing.&lt;br /&gt;
* &amp;lt;b&amp;gt;Update the automated servo Web Platform tests(wpt):&amp;lt;/b&amp;gt;&lt;br /&gt;
For a DOM feature, extensive tests already exist under tests/wpt. Any change in DOM would require updating the expected results in the automated tests.&lt;br /&gt;
&lt;br /&gt;
This first requires storing the log in raw format from a test run, for example by running&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach test-wpt --log-raw /path/for/storing/log/file/&amp;lt;filename&amp;gt;.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once log is saved, then run to update test expectations&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach update-wpt /path/to/logfile/&amp;lt;filename&amp;gt;.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== '''Team Details''' ==&lt;br /&gt;
 &lt;br /&gt;
Jayalakshmi Vishwanathan (jviswan@ncsu.edu) &lt;br /&gt;
 &lt;br /&gt;
Nita Radhakrishnan (nradhak2@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
Ramya Ananth (rananth2@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
Sandeep Kundala (skundal@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
== '''Mentor Details''' ==&lt;br /&gt;
Jay Modi &lt;br /&gt;
&lt;br /&gt;
== '''References''' ==&lt;br /&gt;
 &lt;br /&gt;
* [https://en.wikipedia.org/wiki/Servo_(software)| What is servo?]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Rust_(programming_language)| what is RUST programming?]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/CSC_517_Spring_2020/Implement_ImageBitMap_WebAPI&amp;diff=133631</id>
		<title>CSC/CSC 517 Spring 2020/Implement ImageBitMap WebAPI</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/CSC_517_Spring_2020/Implement_ImageBitMap_WebAPI&amp;diff=133631"/>
		<updated>2020-04-14T03:49:21Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: /* Steps for implementation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== '''Background Information''' ==&lt;br /&gt;
This project aims to contribute to Mozilla's experimental browser engine called Servo, which is implemented in a language called RUST(useful for implementing features that need concurrency and memory safety).&lt;br /&gt;
&lt;br /&gt;
Many of the components of Servo are still under development and one such feature is the [https://www.techopedia.com/definition/792/bitmap-bmp| ImageBitmap].&lt;br /&gt;
&lt;br /&gt;
Major browsers support the ImageBitmap standard which can be used to create images that are ready to be drawn efficiently to [https://en.wikipedia.org/wiki/Canvas_element| HTML canvas elements]. Servo is a new, experimental browser that supports these canvas APIs. &lt;br /&gt;
&lt;br /&gt;
The goal of and motivation behind this project is to implement support for image bitmaps and improve our canvas automated test coverage as a result.&lt;br /&gt;
&lt;br /&gt;
== '''About ImageBitMap and Motivation behind the project''' ==&lt;br /&gt;
We usually decode images for a use with canvas to allow users to customize an avatar, crop an image, or just zoom in on a picture. The problem with decoding images is that it can be CPU intensive, and that can sometimes mean jank or checkerboarding.&lt;br /&gt;
&lt;br /&gt;
But the createImageBitmap() method allows us to decode the image in the background and get access to a new ImageBitmap primitive, which you can draw into a canvas in the same way you would an &amp;lt;img&amp;gt; element, another canvas, or a video.&lt;br /&gt;
&lt;br /&gt;
The aim of this project is to develop the ImageBitmap for the servo environment. &lt;br /&gt;
&lt;br /&gt;
This can be done in the steps mentioned in the following section.&lt;br /&gt;
&lt;br /&gt;
== '''Steps for implementation''' ==&lt;br /&gt;
&lt;br /&gt;
'''Initial Phase'''&lt;br /&gt;
* '''Step 1: '''Add a ImageBitmap WebIDL interface to ''components/script/dom/webidl''s and Rust implementation in components/script/dom/imagebitmap.rs&lt;br /&gt;
* '''Step 2: ''' Add the ''createImageBitmap'' method that takes no extra x/y/w/h parameters in ''component/script/dom/webidls/WindowOrWorkerGlobalScope.webidl'' and implement the method in ''component/script/dom/window.rs'', handling the HTMLCanvasElement and OffscreenCanvas types from the possible image sources&lt;br /&gt;
&lt;br /&gt;
'''Subsequent phase'''&lt;br /&gt;
* '''Step 1: '''Implement several remaining image source types (HTMLImageElement, ImageData, ImageBitmap)&lt;br /&gt;
* '''Step 2: '''Implement the ''createImageBitmap'' overload that accepts x/y/w/h parameters&lt;br /&gt;
* '''Step 3: '''Implement support for ImageBitmaps as canvas image sources in ''components/script/canvas_state.rs''&lt;br /&gt;
[[File:AllSteps.jpg|600px]]&lt;br /&gt;
&lt;br /&gt;
== '''Details about previous work on implementation''' ==&lt;br /&gt;
The steps that have been implemented so far in this project by the previous batch are:&lt;br /&gt;
&lt;br /&gt;
'''Step 1:''' Added the ImageBitmap interface to ''components/script/dom/webidls'' that represents a bitmap image which can be drawn to a &amp;lt;canvas&amp;gt; without undue latency. The interface contains height and weight as its attributes which are read only unsigned long integers.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//[Exposed=(Window,Worker), Serializable, Transferable]&lt;br /&gt;
[Exposed=(Window,Worker)]&lt;br /&gt;
interface ImageBitmap {&lt;br /&gt;
  readonly attribute unsigned long width;&lt;br /&gt;
  readonly attribute unsigned long height;&lt;br /&gt;
  //void close();&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef (CanvasImageSource or&lt;br /&gt;
         Blob or&lt;br /&gt;
         ImageData) ImageBitmapSource;&lt;br /&gt;
&lt;br /&gt;
enum ImageOrientation { &amp;quot;none&amp;quot;, &amp;quot;flipY&amp;quot; };&lt;br /&gt;
enum PremultiplyAlpha { &amp;quot;none&amp;quot;, &amp;quot;premultiply&amp;quot;, &amp;quot;default&amp;quot; };&lt;br /&gt;
enum ColorSpaceConversion { &amp;quot;none&amp;quot;, &amp;quot;default&amp;quot; };&lt;br /&gt;
enum ResizeQuality { &amp;quot;pixelated&amp;quot;, &amp;quot;low&amp;quot;, &amp;quot;medium&amp;quot;, &amp;quot;high&amp;quot; };&lt;br /&gt;
&lt;br /&gt;
dictionary ImageBitmapOptions {&lt;br /&gt;
  ImageOrientation imageOrientation = &amp;quot;none&amp;quot;;&lt;br /&gt;
  PremultiplyAlpha premultiplyAlpha = &amp;quot;default&amp;quot;;&lt;br /&gt;
  ColorSpaceConversion colorSpaceConversion = &amp;quot;default&amp;quot;;&lt;br /&gt;
  [EnforceRange] unsigned long resizeWidth;&lt;br /&gt;
  [EnforceRange] unsigned long resizeHeight;&lt;br /&gt;
  ResizeQuality resizeQuality = &amp;quot;low&amp;quot;;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ImageBitmap webidl also defines a dictionary for various ImageBitmap Options that can be used to modify the ImageBitmap object.&lt;br /&gt;
&lt;br /&gt;
'''Step 2:''' Implemented the rust code for the webidl interface at ''components/script/dom/imagebitmap.rs''. For more details on the code [https://expertiza.csc.ncsu.edu/index.php/CSC/ECE_517_Spring_2020_-_M2000._Implement_ImageBitMap_web_API#Implementation visit]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
use crate::dom::bindings::cell::DomRefCell;&lt;br /&gt;
&lt;br /&gt;
use crate::dom::bindings::codegen::Bindings::ImageBitmapBinding::ImageBitmapMethods;&lt;br /&gt;
use crate::dom::bindings::root::DomRoot;&lt;br /&gt;
use crate::dom::globalscope::GlobalScope;&lt;br /&gt;
&lt;br /&gt;
use crate::dom::bindings::error::Fallible;&lt;br /&gt;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};&lt;br /&gt;
use dom_struct::dom_struct;&lt;br /&gt;
&lt;br /&gt;
use std::vec::Vec;&lt;br /&gt;
&lt;br /&gt;
#[dom_struct]&lt;br /&gt;
pub struct ImageBitmap {&lt;br /&gt;
    reflector_: Reflector,&lt;br /&gt;
    width: u32,&lt;br /&gt;
    height: u32,&lt;br /&gt;
    bitmap_data: DomRefCell&amp;lt;Vec&amp;lt;u8&amp;gt;&amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
impl ImageBitmap {&lt;br /&gt;
    fn new_inherited(width_arg: u32, height_arg: u32) -&amp;gt; ImageBitmap {&lt;br /&gt;
        ImageBitmap {&lt;br /&gt;
            reflector_: Reflector::new(),&lt;br /&gt;
            width: width_arg,&lt;br /&gt;
            height: height_arg,&lt;br /&gt;
            bitmap_data: DomRefCell::new(vec![]),&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    #[allow(dead_code)]&lt;br /&gt;
    pub fn new(global: &amp;amp;GlobalScope, width: u32, height: u32) -&amp;gt; Fallible&amp;lt;DomRoot&amp;lt;ImageBitmap&amp;gt;&amp;gt; {&lt;br /&gt;
        //assigning to a variable the return object of new_inherited&lt;br /&gt;
        let imagebitmap = Box::new(ImageBitmap::new_inherited(width, height));&lt;br /&gt;
&lt;br /&gt;
        Ok(reflect_dom_object(imagebitmap, global))&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code also implements the getter methods for height and width attribute of an ImageBitmap object.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
impl ImageBitmapMethods for ImageBitmap {&lt;br /&gt;
    // https://html.spec.whatwg.org/multipage/#dom-imagebitmap-height&lt;br /&gt;
    fn Height(&amp;amp;self) -&amp;gt; u32 {&lt;br /&gt;
        //to do: add a condition for checking detached internal slot&lt;br /&gt;
        //and return 0 if set to true&lt;br /&gt;
        self.height&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // https://html.spec.whatwg.org/multipage/#dom-imagebitmap-width&lt;br /&gt;
    fn Width(&amp;amp;self) -&amp;gt; u32 {&lt;br /&gt;
        //to do: add a condition to check detached internal slot&lt;br /&gt;
        ////and return 0 if set to true&lt;br /&gt;
        self.width&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== '''Details about current work on implementation''' ==&lt;br /&gt;
Among the remaining steps in the initial and subsequent phases, the focus will be on step 2 of initial phase and once there is progress made on this step, implementation of the subsequent steps will take place. &lt;br /&gt;
&lt;br /&gt;
;Starting with createImageBitmap()&lt;br /&gt;
&lt;br /&gt;
:*The createImageBitmap() method creates a bitmap from a given source, optionally cropped to contain only a portion of that source. The method exists on the global scope in both windows and workers. It accepts a variety of different image sources, and returns a Promise which resolves to an ImageBitmap.&lt;br /&gt;
:*This method is defined in the file ''components/script/dom/webidls/WindowOrWorkerGlobalScope.webidl'' and rust code is implemented at ''components/script/dom/window.rs''.&lt;br /&gt;
:*The syntax of the method looks like&lt;br /&gt;
:::const imageBitmapPromise = createImageBitmap(image[, options]);&lt;br /&gt;
:::const imageBitmapPromise = createImageBitmap(image, sx, sy, sw, sh[, options]);&lt;br /&gt;
::where the parameters indicate:&lt;br /&gt;
:::'''image:''' an image source, which can be an img element, a SVG image element, a video element, a canvas element, a blob object, an ImageData object or another ImageBitmap object.&lt;br /&gt;
:::'''sx, sy, sw, sh:''' if given, source image is cropped to the given pixels.&lt;br /&gt;
:::'''options (Optional):''' the ImageBitmap object's bitmap data is modified according to options. Available options are:&lt;br /&gt;
:::*imageOrientation&lt;br /&gt;
:::*premultiplyAlpha&lt;br /&gt;
:::*colorSpaceConversion&lt;br /&gt;
:::*resizeWidth&lt;br /&gt;
:::*resizeHeight&lt;br /&gt;
:::*resizeQuality&lt;br /&gt;
:::: You can read more about these options [https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/createImageBitmap here]&lt;br /&gt;
::The return value is a Promise that is resolved when a new ImageBitmap is created.&lt;br /&gt;
:* As a first step, we will be implementing the method to handle canvas elements. Subsequently, we will be enhancing the method to handle other image sources and the x/y/w/h parameters.&lt;br /&gt;
&lt;br /&gt;
;Implementing close() method from previous work&lt;br /&gt;
&lt;br /&gt;
:* close() is a method in the ImageBitmap interface. It is implemented in ''components/script/dom/imagebitmap.rs'' file.&lt;br /&gt;
:* This method disposes of all graphical resources associated with an ImageBitmap.&lt;br /&gt;
&lt;br /&gt;
== '''Algorithm to design the createImageBitmap() method''' ==&lt;br /&gt;
&lt;br /&gt;
On invoking the createImageBitmap(image, options) or the createImageBitmap(image sx, sy, sw, sh, options) the following in the sequence of actions&lt;br /&gt;
&lt;br /&gt;
[[File:fig1.png|border]] &lt;br /&gt;
&lt;br /&gt;
Switching on the &amp;quot;image&amp;quot; argument the following is the sequence of actions &lt;br /&gt;
&lt;br /&gt;
=== If the image is an SVGImage===&lt;br /&gt;
[[File:fig2.png|border]]&lt;br /&gt;
&lt;br /&gt;
=== If the image is a video===&lt;br /&gt;
[[File:ReFigure3.png|border]] &lt;br /&gt;
&lt;br /&gt;
=== If the image is a canvas===&lt;br /&gt;
[[File:ReFigure4.png|border]]&lt;br /&gt;
 &lt;br /&gt;
=== If the image is an ImageBitmap===&lt;br /&gt;
[[File:ImageBitmap.jpg|border]]&lt;br /&gt;
&lt;br /&gt;
=== If the image is an ImageData===&lt;br /&gt;
[[File:ImageData.jpg|border]]&lt;br /&gt;
&lt;br /&gt;
=='''Test Plan'''==&lt;br /&gt;
The following are the respective steps in testing:&lt;br /&gt;
* &amp;lt;b&amp;gt;Servo building test should be successful.&amp;lt;/b&amp;gt;&lt;br /&gt;
The compiling time is based on the CPU clock speed and the OS of the system where the file is being run. For a 64-bit Linux OS, it takes from about 1 hour to 2 hours for the entire build. It takes 2.5 hours on Windows OS.&lt;br /&gt;
* &amp;lt;b&amp;gt;Check for the file tidiness (following standards of servo) using the command:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Linux or macOS:&lt;br /&gt;
    ./mach test-tidy&lt;br /&gt;
    ./mach fmt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Windows:&lt;br /&gt;
    mach.bat test-tidy&lt;br /&gt;
    mach.bat fmt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
*&amp;lt;b&amp;gt;Servo automated Unit-testing should be successful.&amp;lt;/b&amp;gt;&lt;br /&gt;
Running the following commands will run all the unit-tests&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Linux or macOS:&lt;br /&gt;
    ./mach test-unit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Windows:&lt;br /&gt;
    mach.bat test-unit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note: A log file can be maintained to make keep a check on the tests that are passing.&lt;br /&gt;
* &amp;lt;b&amp;gt;Update the automated servo Web Platform tests(wpt):&amp;lt;/b&amp;gt;&lt;br /&gt;
For a DOM feature, extensive tests already exist under tests/wpt. Any change in DOM would require updating the expected results in the automated tests.&lt;br /&gt;
&lt;br /&gt;
This first requires storing the log in raw format from a test run, for example by running&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach test-wpt --log-raw /path/for/storing/log/file/&amp;lt;filename&amp;gt;.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once log is saved, then run to update test expectations&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach update-wpt /path/to/logfile/&amp;lt;filename&amp;gt;.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== '''Team Details''' ==&lt;br /&gt;
 &lt;br /&gt;
Jayalakshmi Vishwanathan (jviswan@ncsu.edu) &lt;br /&gt;
 &lt;br /&gt;
Nita Radhakrishnan (nradhak2@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
Ramya Ananth (rananth2@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
Sandeep Kundala (skundal@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
== '''Mentor Details''' ==&lt;br /&gt;
Jay Modi &lt;br /&gt;
&lt;br /&gt;
== '''References''' ==&lt;br /&gt;
 &lt;br /&gt;
* [https://en.wikipedia.org/wiki/Servo_(software)| What is servo?]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Rust_(programming_language)| what is RUST programming?]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/CSC_517_Spring_2020/Implement_ImageBitMap_WebAPI&amp;diff=133630</id>
		<title>CSC/CSC 517 Spring 2020/Implement ImageBitMap WebAPI</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/CSC_517_Spring_2020/Implement_ImageBitMap_WebAPI&amp;diff=133630"/>
		<updated>2020-04-14T03:47:35Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: /* Test Plan */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== '''Background Information''' ==&lt;br /&gt;
This project aims to contribute to Mozilla's experimental browser engine called Servo, which is implemented in a language called RUST(useful for implementing features that need concurrency and memory safety).&lt;br /&gt;
&lt;br /&gt;
Many of the components of Servo are still under development and one such feature is the [https://www.techopedia.com/definition/792/bitmap-bmp| ImageBitmap].&lt;br /&gt;
&lt;br /&gt;
Major browsers support the ImageBitmap standard which can be used to create images that are ready to be drawn efficiently to [https://en.wikipedia.org/wiki/Canvas_element| HTML canvas elements]. Servo is a new, experimental browser that supports these canvas APIs. &lt;br /&gt;
&lt;br /&gt;
The goal of and motivation behind this project is to implement support for image bitmaps and improve our canvas automated test coverage as a result.&lt;br /&gt;
&lt;br /&gt;
== '''About ImageBitMap and Motivation behind the project''' ==&lt;br /&gt;
We usually decode images for a use with canvas to allow users to customize an avatar, crop an image, or just zoom in on a picture. The problem with decoding images is that it can be CPU intensive, and that can sometimes mean jank or checkerboarding.&lt;br /&gt;
&lt;br /&gt;
But the createImageBitmap() method allows us to decode the image in the background and get access to a new ImageBitmap primitive, which you can draw into a canvas in the same way you would an &amp;lt;img&amp;gt; element, another canvas, or a video.&lt;br /&gt;
&lt;br /&gt;
The aim of this project is to develop the ImageBitmap for the servo environment. &lt;br /&gt;
&lt;br /&gt;
This can be done in the steps mentioned in the following section.&lt;br /&gt;
&lt;br /&gt;
== '''Steps for implementation''' ==&lt;br /&gt;
&lt;br /&gt;
'''Initial Phase'''&lt;br /&gt;
* '''Step 1: '''Add a ImageBitmap WebIDL interface to ''components/script/dom/webidl''s and Rust implementation in components/script/dom/imagebitmap.rs&lt;br /&gt;
* '''Step 2: ''' Add the ''createImageBitmap'' method that takes no extra x/y/w/h parameters in ''component/script/dom/webidls/WindowOrWorkerGlobalScope.webidl'' and implement the method in ''component/script/dom/window.rs'', handling the HTMLCanvasElement and OffscreenCanvas types from the possible image sources&lt;br /&gt;
&lt;br /&gt;
'''Subsequent phase'''&lt;br /&gt;
* '''Step 1: '''Implement several remaining image source types (HTMLImageElement, ImageData, ImageBitmap)&lt;br /&gt;
* '''Step 2: '''Implement the ''createImageBitmap'' overload that accepts x/y/w/h parameters&lt;br /&gt;
* '''Step 3: '''Implement support for ImageBitmaps as canvas image sources in ''components/script/canvas_state.rs''&lt;br /&gt;
[[File:AllSteps.jpg]]&lt;br /&gt;
&lt;br /&gt;
== '''Details about previous work on implementation''' ==&lt;br /&gt;
The steps that have been implemented so far in this project by the previous batch are:&lt;br /&gt;
&lt;br /&gt;
'''Step 1:''' Added the ImageBitmap interface to ''components/script/dom/webidls'' that represents a bitmap image which can be drawn to a &amp;lt;canvas&amp;gt; without undue latency. The interface contains height and weight as its attributes which are read only unsigned long integers.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//[Exposed=(Window,Worker), Serializable, Transferable]&lt;br /&gt;
[Exposed=(Window,Worker)]&lt;br /&gt;
interface ImageBitmap {&lt;br /&gt;
  readonly attribute unsigned long width;&lt;br /&gt;
  readonly attribute unsigned long height;&lt;br /&gt;
  //void close();&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef (CanvasImageSource or&lt;br /&gt;
         Blob or&lt;br /&gt;
         ImageData) ImageBitmapSource;&lt;br /&gt;
&lt;br /&gt;
enum ImageOrientation { &amp;quot;none&amp;quot;, &amp;quot;flipY&amp;quot; };&lt;br /&gt;
enum PremultiplyAlpha { &amp;quot;none&amp;quot;, &amp;quot;premultiply&amp;quot;, &amp;quot;default&amp;quot; };&lt;br /&gt;
enum ColorSpaceConversion { &amp;quot;none&amp;quot;, &amp;quot;default&amp;quot; };&lt;br /&gt;
enum ResizeQuality { &amp;quot;pixelated&amp;quot;, &amp;quot;low&amp;quot;, &amp;quot;medium&amp;quot;, &amp;quot;high&amp;quot; };&lt;br /&gt;
&lt;br /&gt;
dictionary ImageBitmapOptions {&lt;br /&gt;
  ImageOrientation imageOrientation = &amp;quot;none&amp;quot;;&lt;br /&gt;
  PremultiplyAlpha premultiplyAlpha = &amp;quot;default&amp;quot;;&lt;br /&gt;
  ColorSpaceConversion colorSpaceConversion = &amp;quot;default&amp;quot;;&lt;br /&gt;
  [EnforceRange] unsigned long resizeWidth;&lt;br /&gt;
  [EnforceRange] unsigned long resizeHeight;&lt;br /&gt;
  ResizeQuality resizeQuality = &amp;quot;low&amp;quot;;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ImageBitmap webidl also defines a dictionary for various ImageBitmap Options that can be used to modify the ImageBitmap object.&lt;br /&gt;
&lt;br /&gt;
'''Step 2:''' Implemented the rust code for the webidl interface at ''components/script/dom/imagebitmap.rs''. For more details on the code [https://expertiza.csc.ncsu.edu/index.php/CSC/ECE_517_Spring_2020_-_M2000._Implement_ImageBitMap_web_API#Implementation visit]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
use crate::dom::bindings::cell::DomRefCell;&lt;br /&gt;
&lt;br /&gt;
use crate::dom::bindings::codegen::Bindings::ImageBitmapBinding::ImageBitmapMethods;&lt;br /&gt;
use crate::dom::bindings::root::DomRoot;&lt;br /&gt;
use crate::dom::globalscope::GlobalScope;&lt;br /&gt;
&lt;br /&gt;
use crate::dom::bindings::error::Fallible;&lt;br /&gt;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};&lt;br /&gt;
use dom_struct::dom_struct;&lt;br /&gt;
&lt;br /&gt;
use std::vec::Vec;&lt;br /&gt;
&lt;br /&gt;
#[dom_struct]&lt;br /&gt;
pub struct ImageBitmap {&lt;br /&gt;
    reflector_: Reflector,&lt;br /&gt;
    width: u32,&lt;br /&gt;
    height: u32,&lt;br /&gt;
    bitmap_data: DomRefCell&amp;lt;Vec&amp;lt;u8&amp;gt;&amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
impl ImageBitmap {&lt;br /&gt;
    fn new_inherited(width_arg: u32, height_arg: u32) -&amp;gt; ImageBitmap {&lt;br /&gt;
        ImageBitmap {&lt;br /&gt;
            reflector_: Reflector::new(),&lt;br /&gt;
            width: width_arg,&lt;br /&gt;
            height: height_arg,&lt;br /&gt;
            bitmap_data: DomRefCell::new(vec![]),&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    #[allow(dead_code)]&lt;br /&gt;
    pub fn new(global: &amp;amp;GlobalScope, width: u32, height: u32) -&amp;gt; Fallible&amp;lt;DomRoot&amp;lt;ImageBitmap&amp;gt;&amp;gt; {&lt;br /&gt;
        //assigning to a variable the return object of new_inherited&lt;br /&gt;
        let imagebitmap = Box::new(ImageBitmap::new_inherited(width, height));&lt;br /&gt;
&lt;br /&gt;
        Ok(reflect_dom_object(imagebitmap, global))&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code also implements the getter methods for height and width attribute of an ImageBitmap object.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
impl ImageBitmapMethods for ImageBitmap {&lt;br /&gt;
    // https://html.spec.whatwg.org/multipage/#dom-imagebitmap-height&lt;br /&gt;
    fn Height(&amp;amp;self) -&amp;gt; u32 {&lt;br /&gt;
        //to do: add a condition for checking detached internal slot&lt;br /&gt;
        //and return 0 if set to true&lt;br /&gt;
        self.height&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // https://html.spec.whatwg.org/multipage/#dom-imagebitmap-width&lt;br /&gt;
    fn Width(&amp;amp;self) -&amp;gt; u32 {&lt;br /&gt;
        //to do: add a condition to check detached internal slot&lt;br /&gt;
        ////and return 0 if set to true&lt;br /&gt;
        self.width&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== '''Details about current work on implementation''' ==&lt;br /&gt;
Among the remaining steps in the initial and subsequent phases, the focus will be on step 2 of initial phase and once there is progress made on this step, implementation of the subsequent steps will take place. &lt;br /&gt;
&lt;br /&gt;
;Starting with createImageBitmap()&lt;br /&gt;
&lt;br /&gt;
:*The createImageBitmap() method creates a bitmap from a given source, optionally cropped to contain only a portion of that source. The method exists on the global scope in both windows and workers. It accepts a variety of different image sources, and returns a Promise which resolves to an ImageBitmap.&lt;br /&gt;
:*This method is defined in the file ''components/script/dom/webidls/WindowOrWorkerGlobalScope.webidl'' and rust code is implemented at ''components/script/dom/window.rs''.&lt;br /&gt;
:*The syntax of the method looks like&lt;br /&gt;
:::const imageBitmapPromise = createImageBitmap(image[, options]);&lt;br /&gt;
:::const imageBitmapPromise = createImageBitmap(image, sx, sy, sw, sh[, options]);&lt;br /&gt;
::where the parameters indicate:&lt;br /&gt;
:::'''image:''' an image source, which can be an img element, a SVG image element, a video element, a canvas element, a blob object, an ImageData object or another ImageBitmap object.&lt;br /&gt;
:::'''sx, sy, sw, sh:''' if given, source image is cropped to the given pixels.&lt;br /&gt;
:::'''options (Optional):''' the ImageBitmap object's bitmap data is modified according to options. Available options are:&lt;br /&gt;
:::*imageOrientation&lt;br /&gt;
:::*premultiplyAlpha&lt;br /&gt;
:::*colorSpaceConversion&lt;br /&gt;
:::*resizeWidth&lt;br /&gt;
:::*resizeHeight&lt;br /&gt;
:::*resizeQuality&lt;br /&gt;
:::: You can read more about these options [https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/createImageBitmap here]&lt;br /&gt;
::The return value is a Promise that is resolved when a new ImageBitmap is created.&lt;br /&gt;
:* As a first step, we will be implementing the method to handle canvas elements. Subsequently, we will be enhancing the method to handle other image sources and the x/y/w/h parameters.&lt;br /&gt;
&lt;br /&gt;
;Implementing close() method from previous work&lt;br /&gt;
&lt;br /&gt;
:* close() is a method in the ImageBitmap interface. It is implemented in ''components/script/dom/imagebitmap.rs'' file.&lt;br /&gt;
:* This method disposes of all graphical resources associated with an ImageBitmap.&lt;br /&gt;
&lt;br /&gt;
== '''Algorithm to design the createImageBitmap() method''' ==&lt;br /&gt;
&lt;br /&gt;
On invoking the createImageBitmap(image, options) or the createImageBitmap(image sx, sy, sw, sh, options) the following in the sequence of actions&lt;br /&gt;
&lt;br /&gt;
[[File:fig1.png|border]] &lt;br /&gt;
&lt;br /&gt;
Switching on the &amp;quot;image&amp;quot; argument the following is the sequence of actions &lt;br /&gt;
&lt;br /&gt;
=== If the image is an SVGImage===&lt;br /&gt;
[[File:fig2.png|border]]&lt;br /&gt;
&lt;br /&gt;
=== If the image is a video===&lt;br /&gt;
[[File:ReFigure3.png|border]] &lt;br /&gt;
&lt;br /&gt;
=== If the image is a canvas===&lt;br /&gt;
[[File:ReFigure4.png|border]]&lt;br /&gt;
 &lt;br /&gt;
=== If the image is an ImageBitmap===&lt;br /&gt;
[[File:ImageBitmap.jpg|border]]&lt;br /&gt;
&lt;br /&gt;
=== If the image is an ImageData===&lt;br /&gt;
[[File:ImageData.jpg|border]]&lt;br /&gt;
&lt;br /&gt;
=='''Test Plan'''==&lt;br /&gt;
The following are the respective steps in testing:&lt;br /&gt;
* &amp;lt;b&amp;gt;Servo building test should be successful.&amp;lt;/b&amp;gt;&lt;br /&gt;
The compiling time is based on the CPU clock speed and the OS of the system where the file is being run. For a 64-bit Linux OS, it takes from about 1 hour to 2 hours for the entire build. It takes 2.5 hours on Windows OS.&lt;br /&gt;
* &amp;lt;b&amp;gt;Check for the file tidiness (following standards of servo) using the command:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Linux or macOS:&lt;br /&gt;
    ./mach test-tidy&lt;br /&gt;
    ./mach fmt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Windows:&lt;br /&gt;
    mach.bat test-tidy&lt;br /&gt;
    mach.bat fmt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
*&amp;lt;b&amp;gt;Servo automated Unit-testing should be successful.&amp;lt;/b&amp;gt;&lt;br /&gt;
Running the following commands will run all the unit-tests&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Linux or macOS:&lt;br /&gt;
    ./mach test-unit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Windows:&lt;br /&gt;
    mach.bat test-unit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note: A log file can be maintained to make keep a check on the tests that are passing.&lt;br /&gt;
* &amp;lt;b&amp;gt;Update the automated servo Web Platform tests(wpt):&amp;lt;/b&amp;gt;&lt;br /&gt;
For a DOM feature, extensive tests already exist under tests/wpt. Any change in DOM would require updating the expected results in the automated tests.&lt;br /&gt;
&lt;br /&gt;
This first requires storing the log in raw format from a test run, for example by running&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach test-wpt --log-raw /path/for/storing/log/file/&amp;lt;filename&amp;gt;.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once log is saved, then run to update test expectations&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach update-wpt /path/to/logfile/&amp;lt;filename&amp;gt;.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== '''Team Details''' ==&lt;br /&gt;
 &lt;br /&gt;
Jayalakshmi Vishwanathan (jviswan@ncsu.edu) &lt;br /&gt;
 &lt;br /&gt;
Nita Radhakrishnan (nradhak2@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
Ramya Ananth (rananth2@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
Sandeep Kundala (skundal@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
== '''Mentor Details''' ==&lt;br /&gt;
Jay Modi &lt;br /&gt;
&lt;br /&gt;
== '''References''' ==&lt;br /&gt;
 &lt;br /&gt;
* [https://en.wikipedia.org/wiki/Servo_(software)| What is servo?]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Rust_(programming_language)| what is RUST programming?]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/CSC_517_Spring_2020/Implement_ImageBitMap_WebAPI&amp;diff=133629</id>
		<title>CSC/CSC 517 Spring 2020/Implement ImageBitMap WebAPI</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/CSC_517_Spring_2020/Implement_ImageBitMap_WebAPI&amp;diff=133629"/>
		<updated>2020-04-14T03:47:13Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: /* Team Details */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== '''Background Information''' ==&lt;br /&gt;
This project aims to contribute to Mozilla's experimental browser engine called Servo, which is implemented in a language called RUST(useful for implementing features that need concurrency and memory safety).&lt;br /&gt;
&lt;br /&gt;
Many of the components of Servo are still under development and one such feature is the [https://www.techopedia.com/definition/792/bitmap-bmp| ImageBitmap].&lt;br /&gt;
&lt;br /&gt;
Major browsers support the ImageBitmap standard which can be used to create images that are ready to be drawn efficiently to [https://en.wikipedia.org/wiki/Canvas_element| HTML canvas elements]. Servo is a new, experimental browser that supports these canvas APIs. &lt;br /&gt;
&lt;br /&gt;
The goal of and motivation behind this project is to implement support for image bitmaps and improve our canvas automated test coverage as a result.&lt;br /&gt;
&lt;br /&gt;
== '''About ImageBitMap and Motivation behind the project''' ==&lt;br /&gt;
We usually decode images for a use with canvas to allow users to customize an avatar, crop an image, or just zoom in on a picture. The problem with decoding images is that it can be CPU intensive, and that can sometimes mean jank or checkerboarding.&lt;br /&gt;
&lt;br /&gt;
But the createImageBitmap() method allows us to decode the image in the background and get access to a new ImageBitmap primitive, which you can draw into a canvas in the same way you would an &amp;lt;img&amp;gt; element, another canvas, or a video.&lt;br /&gt;
&lt;br /&gt;
The aim of this project is to develop the ImageBitmap for the servo environment. &lt;br /&gt;
&lt;br /&gt;
This can be done in the steps mentioned in the following section.&lt;br /&gt;
&lt;br /&gt;
== '''Steps for implementation''' ==&lt;br /&gt;
&lt;br /&gt;
'''Initial Phase'''&lt;br /&gt;
* '''Step 1: '''Add a ImageBitmap WebIDL interface to ''components/script/dom/webidl''s and Rust implementation in components/script/dom/imagebitmap.rs&lt;br /&gt;
* '''Step 2: ''' Add the ''createImageBitmap'' method that takes no extra x/y/w/h parameters in ''component/script/dom/webidls/WindowOrWorkerGlobalScope.webidl'' and implement the method in ''component/script/dom/window.rs'', handling the HTMLCanvasElement and OffscreenCanvas types from the possible image sources&lt;br /&gt;
&lt;br /&gt;
'''Subsequent phase'''&lt;br /&gt;
* '''Step 1: '''Implement several remaining image source types (HTMLImageElement, ImageData, ImageBitmap)&lt;br /&gt;
* '''Step 2: '''Implement the ''createImageBitmap'' overload that accepts x/y/w/h parameters&lt;br /&gt;
* '''Step 3: '''Implement support for ImageBitmaps as canvas image sources in ''components/script/canvas_state.rs''&lt;br /&gt;
[[File:AllSteps.jpg]]&lt;br /&gt;
&lt;br /&gt;
== '''Details about previous work on implementation''' ==&lt;br /&gt;
The steps that have been implemented so far in this project by the previous batch are:&lt;br /&gt;
&lt;br /&gt;
'''Step 1:''' Added the ImageBitmap interface to ''components/script/dom/webidls'' that represents a bitmap image which can be drawn to a &amp;lt;canvas&amp;gt; without undue latency. The interface contains height and weight as its attributes which are read only unsigned long integers.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//[Exposed=(Window,Worker), Serializable, Transferable]&lt;br /&gt;
[Exposed=(Window,Worker)]&lt;br /&gt;
interface ImageBitmap {&lt;br /&gt;
  readonly attribute unsigned long width;&lt;br /&gt;
  readonly attribute unsigned long height;&lt;br /&gt;
  //void close();&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef (CanvasImageSource or&lt;br /&gt;
         Blob or&lt;br /&gt;
         ImageData) ImageBitmapSource;&lt;br /&gt;
&lt;br /&gt;
enum ImageOrientation { &amp;quot;none&amp;quot;, &amp;quot;flipY&amp;quot; };&lt;br /&gt;
enum PremultiplyAlpha { &amp;quot;none&amp;quot;, &amp;quot;premultiply&amp;quot;, &amp;quot;default&amp;quot; };&lt;br /&gt;
enum ColorSpaceConversion { &amp;quot;none&amp;quot;, &amp;quot;default&amp;quot; };&lt;br /&gt;
enum ResizeQuality { &amp;quot;pixelated&amp;quot;, &amp;quot;low&amp;quot;, &amp;quot;medium&amp;quot;, &amp;quot;high&amp;quot; };&lt;br /&gt;
&lt;br /&gt;
dictionary ImageBitmapOptions {&lt;br /&gt;
  ImageOrientation imageOrientation = &amp;quot;none&amp;quot;;&lt;br /&gt;
  PremultiplyAlpha premultiplyAlpha = &amp;quot;default&amp;quot;;&lt;br /&gt;
  ColorSpaceConversion colorSpaceConversion = &amp;quot;default&amp;quot;;&lt;br /&gt;
  [EnforceRange] unsigned long resizeWidth;&lt;br /&gt;
  [EnforceRange] unsigned long resizeHeight;&lt;br /&gt;
  ResizeQuality resizeQuality = &amp;quot;low&amp;quot;;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ImageBitmap webidl also defines a dictionary for various ImageBitmap Options that can be used to modify the ImageBitmap object.&lt;br /&gt;
&lt;br /&gt;
'''Step 2:''' Implemented the rust code for the webidl interface at ''components/script/dom/imagebitmap.rs''. For more details on the code [https://expertiza.csc.ncsu.edu/index.php/CSC/ECE_517_Spring_2020_-_M2000._Implement_ImageBitMap_web_API#Implementation visit]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
use crate::dom::bindings::cell::DomRefCell;&lt;br /&gt;
&lt;br /&gt;
use crate::dom::bindings::codegen::Bindings::ImageBitmapBinding::ImageBitmapMethods;&lt;br /&gt;
use crate::dom::bindings::root::DomRoot;&lt;br /&gt;
use crate::dom::globalscope::GlobalScope;&lt;br /&gt;
&lt;br /&gt;
use crate::dom::bindings::error::Fallible;&lt;br /&gt;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};&lt;br /&gt;
use dom_struct::dom_struct;&lt;br /&gt;
&lt;br /&gt;
use std::vec::Vec;&lt;br /&gt;
&lt;br /&gt;
#[dom_struct]&lt;br /&gt;
pub struct ImageBitmap {&lt;br /&gt;
    reflector_: Reflector,&lt;br /&gt;
    width: u32,&lt;br /&gt;
    height: u32,&lt;br /&gt;
    bitmap_data: DomRefCell&amp;lt;Vec&amp;lt;u8&amp;gt;&amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
impl ImageBitmap {&lt;br /&gt;
    fn new_inherited(width_arg: u32, height_arg: u32) -&amp;gt; ImageBitmap {&lt;br /&gt;
        ImageBitmap {&lt;br /&gt;
            reflector_: Reflector::new(),&lt;br /&gt;
            width: width_arg,&lt;br /&gt;
            height: height_arg,&lt;br /&gt;
            bitmap_data: DomRefCell::new(vec![]),&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    #[allow(dead_code)]&lt;br /&gt;
    pub fn new(global: &amp;amp;GlobalScope, width: u32, height: u32) -&amp;gt; Fallible&amp;lt;DomRoot&amp;lt;ImageBitmap&amp;gt;&amp;gt; {&lt;br /&gt;
        //assigning to a variable the return object of new_inherited&lt;br /&gt;
        let imagebitmap = Box::new(ImageBitmap::new_inherited(width, height));&lt;br /&gt;
&lt;br /&gt;
        Ok(reflect_dom_object(imagebitmap, global))&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code also implements the getter methods for height and width attribute of an ImageBitmap object.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
impl ImageBitmapMethods for ImageBitmap {&lt;br /&gt;
    // https://html.spec.whatwg.org/multipage/#dom-imagebitmap-height&lt;br /&gt;
    fn Height(&amp;amp;self) -&amp;gt; u32 {&lt;br /&gt;
        //to do: add a condition for checking detached internal slot&lt;br /&gt;
        //and return 0 if set to true&lt;br /&gt;
        self.height&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // https://html.spec.whatwg.org/multipage/#dom-imagebitmap-width&lt;br /&gt;
    fn Width(&amp;amp;self) -&amp;gt; u32 {&lt;br /&gt;
        //to do: add a condition to check detached internal slot&lt;br /&gt;
        ////and return 0 if set to true&lt;br /&gt;
        self.width&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== '''Details about current work on implementation''' ==&lt;br /&gt;
Among the remaining steps in the initial and subsequent phases, the focus will be on step 2 of initial phase and once there is progress made on this step, implementation of the subsequent steps will take place. &lt;br /&gt;
&lt;br /&gt;
;Starting with createImageBitmap()&lt;br /&gt;
&lt;br /&gt;
:*The createImageBitmap() method creates a bitmap from a given source, optionally cropped to contain only a portion of that source. The method exists on the global scope in both windows and workers. It accepts a variety of different image sources, and returns a Promise which resolves to an ImageBitmap.&lt;br /&gt;
:*This method is defined in the file ''components/script/dom/webidls/WindowOrWorkerGlobalScope.webidl'' and rust code is implemented at ''components/script/dom/window.rs''.&lt;br /&gt;
:*The syntax of the method looks like&lt;br /&gt;
:::const imageBitmapPromise = createImageBitmap(image[, options]);&lt;br /&gt;
:::const imageBitmapPromise = createImageBitmap(image, sx, sy, sw, sh[, options]);&lt;br /&gt;
::where the parameters indicate:&lt;br /&gt;
:::'''image:''' an image source, which can be an img element, a SVG image element, a video element, a canvas element, a blob object, an ImageData object or another ImageBitmap object.&lt;br /&gt;
:::'''sx, sy, sw, sh:''' if given, source image is cropped to the given pixels.&lt;br /&gt;
:::'''options (Optional):''' the ImageBitmap object's bitmap data is modified according to options. Available options are:&lt;br /&gt;
:::*imageOrientation&lt;br /&gt;
:::*premultiplyAlpha&lt;br /&gt;
:::*colorSpaceConversion&lt;br /&gt;
:::*resizeWidth&lt;br /&gt;
:::*resizeHeight&lt;br /&gt;
:::*resizeQuality&lt;br /&gt;
:::: You can read more about these options [https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/createImageBitmap here]&lt;br /&gt;
::The return value is a Promise that is resolved when a new ImageBitmap is created.&lt;br /&gt;
:* As a first step, we will be implementing the method to handle canvas elements. Subsequently, we will be enhancing the method to handle other image sources and the x/y/w/h parameters.&lt;br /&gt;
&lt;br /&gt;
;Implementing close() method from previous work&lt;br /&gt;
&lt;br /&gt;
:* close() is a method in the ImageBitmap interface. It is implemented in ''components/script/dom/imagebitmap.rs'' file.&lt;br /&gt;
:* This method disposes of all graphical resources associated with an ImageBitmap.&lt;br /&gt;
&lt;br /&gt;
== '''Algorithm to design the createImageBitmap() method''' ==&lt;br /&gt;
&lt;br /&gt;
On invoking the createImageBitmap(image, options) or the createImageBitmap(image sx, sy, sw, sh, options) the following in the sequence of actions&lt;br /&gt;
&lt;br /&gt;
[[File:fig1.png|border]] &lt;br /&gt;
&lt;br /&gt;
Switching on the &amp;quot;image&amp;quot; argument the following is the sequence of actions &lt;br /&gt;
&lt;br /&gt;
=== If the image is an SVGImage===&lt;br /&gt;
[[File:fig2.png|border]]&lt;br /&gt;
&lt;br /&gt;
=== If the image is a video===&lt;br /&gt;
[[File:ReFigure3.png|border]] &lt;br /&gt;
&lt;br /&gt;
=== If the image is a canvas===&lt;br /&gt;
[[File:ReFigure4.png|border]]&lt;br /&gt;
 &lt;br /&gt;
=== If the image is an ImageBitmap===&lt;br /&gt;
[[File:ImageBitmap.jpg|border]]&lt;br /&gt;
&lt;br /&gt;
=== If the image is an ImageData===&lt;br /&gt;
[[File:ImageData.jpg|border]]&lt;br /&gt;
&lt;br /&gt;
=='''Test Plan'''==&lt;br /&gt;
The following are the respective steps in testing:&lt;br /&gt;
* &amp;lt;b&amp;gt;Servo building test should be successful.&amp;lt;/b&amp;gt;&lt;br /&gt;
The compiling time is based on the CPU clock speed and the OS of the system where the file is being run. For a 64-bit Linux OS, it takes from about 1 hour to 2 hours for the entire build. It takes 2.5 hours on Windows OS.&lt;br /&gt;
* &amp;lt;b&amp;gt;Check for the file tidiness (following standards of servo) using the command:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Linux or macOS:&lt;br /&gt;
    ./mach test-tidy&lt;br /&gt;
    ./mach fmt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Windows:&lt;br /&gt;
    mach.bat test-tidy&lt;br /&gt;
    mach.bat fmt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
*&amp;lt;b&amp;gt;Servo automated Unit-testing should be successful.&amp;lt;/b&amp;gt;&lt;br /&gt;
Running the following commands will run all the unit-tests&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Linux or macOS:&lt;br /&gt;
    ./mach test-unit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Windows:&lt;br /&gt;
    mach.bat test-unit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note: A log file can be maintained to make keep a check on the tests that are passing.&lt;br /&gt;
* &amp;lt;b&amp;gt;Update the automated servo Web Platform tests(wpt):&amp;lt;/b&amp;gt;&lt;br /&gt;
For a DOM feature, extensive tests already exist under tests/wpt. Any change in DOM would require updating the expected results in the automated tests.&lt;br /&gt;
&lt;br /&gt;
This first requires storing the log in raw format from a test run, for example by running&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach test-wpt --log-raw /path/for/storing/log/file/&amp;lt;filename&amp;gt;.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once log is saved, then run to update test expectations&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach update-wpt /path/to/logfile/&amp;lt;filename&amp;gt;.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* &amp;lt;b&amp;gt;&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== '''Team Details''' ==&lt;br /&gt;
 &lt;br /&gt;
Jayalakshmi Vishwanathan (jviswan@ncsu.edu) &lt;br /&gt;
 &lt;br /&gt;
Nita Radhakrishnan (nradhak2@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
Ramya Ananth (rananth2@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
Sandeep Kundala (skundal@ncsu.edu)&lt;br /&gt;
&lt;br /&gt;
== '''Mentor Details''' ==&lt;br /&gt;
Jay Modi &lt;br /&gt;
&lt;br /&gt;
== '''References''' ==&lt;br /&gt;
 &lt;br /&gt;
* [https://en.wikipedia.org/wiki/Servo_(software)| What is servo?]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Rust_(programming_language)| what is RUST programming?]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/CSC_517_Spring_2020/Implement_ImageBitMap_WebAPI&amp;diff=133627</id>
		<title>CSC/CSC 517 Spring 2020/Implement ImageBitMap WebAPI</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/CSC_517_Spring_2020/Implement_ImageBitMap_WebAPI&amp;diff=133627"/>
		<updated>2020-04-14T03:46:38Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: /* Test Plan */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== '''Background Information''' ==&lt;br /&gt;
This project aims to contribute to Mozilla's experimental browser engine called Servo, which is implemented in a language called RUST(useful for implementing features that need concurrency and memory safety).&lt;br /&gt;
&lt;br /&gt;
Many of the components of Servo are still under development and one such feature is the [https://www.techopedia.com/definition/792/bitmap-bmp| ImageBitmap].&lt;br /&gt;
&lt;br /&gt;
Major browsers support the ImageBitmap standard which can be used to create images that are ready to be drawn efficiently to [https://en.wikipedia.org/wiki/Canvas_element| HTML canvas elements]. Servo is a new, experimental browser that supports these canvas APIs. &lt;br /&gt;
&lt;br /&gt;
The goal of and motivation behind this project is to implement support for image bitmaps and improve our canvas automated test coverage as a result.&lt;br /&gt;
&lt;br /&gt;
== '''About ImageBitMap and Motivation behind the project''' ==&lt;br /&gt;
We usually decode images for a use with canvas to allow users to customize an avatar, crop an image, or just zoom in on a picture. The problem with decoding images is that it can be CPU intensive, and that can sometimes mean jank or checkerboarding.&lt;br /&gt;
&lt;br /&gt;
But the createImageBitmap() method allows us to decode the image in the background and get access to a new ImageBitmap primitive, which you can draw into a canvas in the same way you would an &amp;lt;img&amp;gt; element, another canvas, or a video.&lt;br /&gt;
&lt;br /&gt;
The aim of this project is to develop the ImageBitmap for the servo environment. &lt;br /&gt;
&lt;br /&gt;
This can be done in the steps mentioned in the following section.&lt;br /&gt;
&lt;br /&gt;
== '''Steps for implementation''' ==&lt;br /&gt;
&lt;br /&gt;
'''Initial Phase'''&lt;br /&gt;
* '''Step 1: '''Add a ImageBitmap WebIDL interface to ''components/script/dom/webidl''s and Rust implementation in components/script/dom/imagebitmap.rs&lt;br /&gt;
* '''Step 2: ''' Add the ''createImageBitmap'' method that takes no extra x/y/w/h parameters in ''component/script/dom/webidls/WindowOrWorkerGlobalScope.webidl'' and implement the method in ''component/script/dom/window.rs'', handling the HTMLCanvasElement and OffscreenCanvas types from the possible image sources&lt;br /&gt;
&lt;br /&gt;
'''Subsequent phase'''&lt;br /&gt;
* '''Step 1: '''Implement several remaining image source types (HTMLImageElement, ImageData, ImageBitmap)&lt;br /&gt;
* '''Step 2: '''Implement the ''createImageBitmap'' overload that accepts x/y/w/h parameters&lt;br /&gt;
* '''Step 3: '''Implement support for ImageBitmaps as canvas image sources in ''components/script/canvas_state.rs''&lt;br /&gt;
[[File:AllSteps.jpg]]&lt;br /&gt;
&lt;br /&gt;
== '''Details about previous work on implementation''' ==&lt;br /&gt;
The steps that have been implemented so far in this project by the previous batch are:&lt;br /&gt;
&lt;br /&gt;
'''Step 1:''' Added the ImageBitmap interface to ''components/script/dom/webidls'' that represents a bitmap image which can be drawn to a &amp;lt;canvas&amp;gt; without undue latency. The interface contains height and weight as its attributes which are read only unsigned long integers.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//[Exposed=(Window,Worker), Serializable, Transferable]&lt;br /&gt;
[Exposed=(Window,Worker)]&lt;br /&gt;
interface ImageBitmap {&lt;br /&gt;
  readonly attribute unsigned long width;&lt;br /&gt;
  readonly attribute unsigned long height;&lt;br /&gt;
  //void close();&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef (CanvasImageSource or&lt;br /&gt;
         Blob or&lt;br /&gt;
         ImageData) ImageBitmapSource;&lt;br /&gt;
&lt;br /&gt;
enum ImageOrientation { &amp;quot;none&amp;quot;, &amp;quot;flipY&amp;quot; };&lt;br /&gt;
enum PremultiplyAlpha { &amp;quot;none&amp;quot;, &amp;quot;premultiply&amp;quot;, &amp;quot;default&amp;quot; };&lt;br /&gt;
enum ColorSpaceConversion { &amp;quot;none&amp;quot;, &amp;quot;default&amp;quot; };&lt;br /&gt;
enum ResizeQuality { &amp;quot;pixelated&amp;quot;, &amp;quot;low&amp;quot;, &amp;quot;medium&amp;quot;, &amp;quot;high&amp;quot; };&lt;br /&gt;
&lt;br /&gt;
dictionary ImageBitmapOptions {&lt;br /&gt;
  ImageOrientation imageOrientation = &amp;quot;none&amp;quot;;&lt;br /&gt;
  PremultiplyAlpha premultiplyAlpha = &amp;quot;default&amp;quot;;&lt;br /&gt;
  ColorSpaceConversion colorSpaceConversion = &amp;quot;default&amp;quot;;&lt;br /&gt;
  [EnforceRange] unsigned long resizeWidth;&lt;br /&gt;
  [EnforceRange] unsigned long resizeHeight;&lt;br /&gt;
  ResizeQuality resizeQuality = &amp;quot;low&amp;quot;;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ImageBitmap webidl also defines a dictionary for various ImageBitmap Options that can be used to modify the ImageBitmap object.&lt;br /&gt;
&lt;br /&gt;
'''Step 2:''' Implemented the rust code for the webidl interface at ''components/script/dom/imagebitmap.rs''. For more details on the code [https://expertiza.csc.ncsu.edu/index.php/CSC/ECE_517_Spring_2020_-_M2000._Implement_ImageBitMap_web_API#Implementation visit]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
use crate::dom::bindings::cell::DomRefCell;&lt;br /&gt;
&lt;br /&gt;
use crate::dom::bindings::codegen::Bindings::ImageBitmapBinding::ImageBitmapMethods;&lt;br /&gt;
use crate::dom::bindings::root::DomRoot;&lt;br /&gt;
use crate::dom::globalscope::GlobalScope;&lt;br /&gt;
&lt;br /&gt;
use crate::dom::bindings::error::Fallible;&lt;br /&gt;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};&lt;br /&gt;
use dom_struct::dom_struct;&lt;br /&gt;
&lt;br /&gt;
use std::vec::Vec;&lt;br /&gt;
&lt;br /&gt;
#[dom_struct]&lt;br /&gt;
pub struct ImageBitmap {&lt;br /&gt;
    reflector_: Reflector,&lt;br /&gt;
    width: u32,&lt;br /&gt;
    height: u32,&lt;br /&gt;
    bitmap_data: DomRefCell&amp;lt;Vec&amp;lt;u8&amp;gt;&amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
impl ImageBitmap {&lt;br /&gt;
    fn new_inherited(width_arg: u32, height_arg: u32) -&amp;gt; ImageBitmap {&lt;br /&gt;
        ImageBitmap {&lt;br /&gt;
            reflector_: Reflector::new(),&lt;br /&gt;
            width: width_arg,&lt;br /&gt;
            height: height_arg,&lt;br /&gt;
            bitmap_data: DomRefCell::new(vec![]),&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    #[allow(dead_code)]&lt;br /&gt;
    pub fn new(global: &amp;amp;GlobalScope, width: u32, height: u32) -&amp;gt; Fallible&amp;lt;DomRoot&amp;lt;ImageBitmap&amp;gt;&amp;gt; {&lt;br /&gt;
        //assigning to a variable the return object of new_inherited&lt;br /&gt;
        let imagebitmap = Box::new(ImageBitmap::new_inherited(width, height));&lt;br /&gt;
&lt;br /&gt;
        Ok(reflect_dom_object(imagebitmap, global))&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code also implements the getter methods for height and width attribute of an ImageBitmap object.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
impl ImageBitmapMethods for ImageBitmap {&lt;br /&gt;
    // https://html.spec.whatwg.org/multipage/#dom-imagebitmap-height&lt;br /&gt;
    fn Height(&amp;amp;self) -&amp;gt; u32 {&lt;br /&gt;
        //to do: add a condition for checking detached internal slot&lt;br /&gt;
        //and return 0 if set to true&lt;br /&gt;
        self.height&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // https://html.spec.whatwg.org/multipage/#dom-imagebitmap-width&lt;br /&gt;
    fn Width(&amp;amp;self) -&amp;gt; u32 {&lt;br /&gt;
        //to do: add a condition to check detached internal slot&lt;br /&gt;
        ////and return 0 if set to true&lt;br /&gt;
        self.width&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== '''Details about current work on implementation''' ==&lt;br /&gt;
Among the remaining steps in the initial and subsequent phases, the focus will be on step 2 of initial phase and once there is progress made on this step, implementation of the subsequent steps will take place. &lt;br /&gt;
&lt;br /&gt;
;Starting with createImageBitmap()&lt;br /&gt;
&lt;br /&gt;
:*The createImageBitmap() method creates a bitmap from a given source, optionally cropped to contain only a portion of that source. The method exists on the global scope in both windows and workers. It accepts a variety of different image sources, and returns a Promise which resolves to an ImageBitmap.&lt;br /&gt;
:*This method is defined in the file ''components/script/dom/webidls/WindowOrWorkerGlobalScope.webidl'' and rust code is implemented at ''components/script/dom/window.rs''.&lt;br /&gt;
:*The syntax of the method looks like&lt;br /&gt;
:::const imageBitmapPromise = createImageBitmap(image[, options]);&lt;br /&gt;
:::const imageBitmapPromise = createImageBitmap(image, sx, sy, sw, sh[, options]);&lt;br /&gt;
::where the parameters indicate:&lt;br /&gt;
:::'''image:''' an image source, which can be an img element, a SVG image element, a video element, a canvas element, a blob object, an ImageData object or another ImageBitmap object.&lt;br /&gt;
:::'''sx, sy, sw, sh:''' if given, source image is cropped to the given pixels.&lt;br /&gt;
:::'''options (Optional):''' the ImageBitmap object's bitmap data is modified according to options. Available options are:&lt;br /&gt;
:::*imageOrientation&lt;br /&gt;
:::*premultiplyAlpha&lt;br /&gt;
:::*colorSpaceConversion&lt;br /&gt;
:::*resizeWidth&lt;br /&gt;
:::*resizeHeight&lt;br /&gt;
:::*resizeQuality&lt;br /&gt;
:::: You can read more about these options [https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/createImageBitmap here]&lt;br /&gt;
::The return value is a Promise that is resolved when a new ImageBitmap is created.&lt;br /&gt;
:* As a first step, we will be implementing the method to handle canvas elements. Subsequently, we will be enhancing the method to handle other image sources and the x/y/w/h parameters.&lt;br /&gt;
&lt;br /&gt;
;Implementing close() method from previous work&lt;br /&gt;
&lt;br /&gt;
:* close() is a method in the ImageBitmap interface. It is implemented in ''components/script/dom/imagebitmap.rs'' file.&lt;br /&gt;
:* This method disposes of all graphical resources associated with an ImageBitmap.&lt;br /&gt;
&lt;br /&gt;
== '''Algorithm to design the createImageBitmap() method''' ==&lt;br /&gt;
&lt;br /&gt;
On invoking the createImageBitmap(image, options) or the createImageBitmap(image sx, sy, sw, sh, options) the following in the sequence of actions&lt;br /&gt;
&lt;br /&gt;
[[File:fig1.png|border]] &lt;br /&gt;
&lt;br /&gt;
Switching on the &amp;quot;image&amp;quot; argument the following is the sequence of actions &lt;br /&gt;
&lt;br /&gt;
=== If the image is an SVGImage===&lt;br /&gt;
[[File:fig2.png|border]]&lt;br /&gt;
&lt;br /&gt;
=== If the image is a video===&lt;br /&gt;
[[File:ReFigure3.png|border]] &lt;br /&gt;
&lt;br /&gt;
=== If the image is a canvas===&lt;br /&gt;
[[File:ReFigure4.png|border]]&lt;br /&gt;
 &lt;br /&gt;
=== If the image is an ImageBitmap===&lt;br /&gt;
[[File:ImageBitmap.jpg|border]]&lt;br /&gt;
&lt;br /&gt;
=== If the image is an ImageData===&lt;br /&gt;
[[File:ImageData.jpg|border]]&lt;br /&gt;
&lt;br /&gt;
=='''Test Plan'''==&lt;br /&gt;
The following are the respective steps in testing:&lt;br /&gt;
* &amp;lt;b&amp;gt;Servo building test should be successful.&amp;lt;/b&amp;gt;&lt;br /&gt;
The compiling time is based on the CPU clock speed and the OS of the system where the file is being run. For a 64-bit Linux OS, it takes from about 1 hour to 2 hours for the entire build. It takes 2.5 hours on Windows OS.&lt;br /&gt;
* &amp;lt;b&amp;gt;Check for the file tidiness (following standards of servo) using the command:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Linux or macOS:&lt;br /&gt;
    ./mach test-tidy&lt;br /&gt;
    ./mach fmt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Windows:&lt;br /&gt;
    mach.bat test-tidy&lt;br /&gt;
    mach.bat fmt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
*&amp;lt;b&amp;gt;Servo automated Unit-testing should be successful.&amp;lt;/b&amp;gt;&lt;br /&gt;
Running the following commands will run all the unit-tests&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Linux or macOS:&lt;br /&gt;
    ./mach test-unit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Windows:&lt;br /&gt;
    mach.bat test-unit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note: A log file can be maintained to make keep a check on the tests that are passing.&lt;br /&gt;
* &amp;lt;b&amp;gt;Update the automated servo Web Platform tests(wpt):&amp;lt;/b&amp;gt;&lt;br /&gt;
For a DOM feature, extensive tests already exist under tests/wpt. Any change in DOM would require updating the expected results in the automated tests.&lt;br /&gt;
&lt;br /&gt;
This first requires storing the log in raw format from a test run, for example by running&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach test-wpt --log-raw /path/for/storing/log/file/&amp;lt;filename&amp;gt;.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once log is saved, then run to update test expectations&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach update-wpt /path/to/logfile/&amp;lt;filename&amp;gt;.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* &amp;lt;b&amp;gt;&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== '''Team Details''' ==&lt;br /&gt;
Sandeep Kundala (skundal@ncsu.edu)&lt;br /&gt;
 &lt;br /&gt;
Nita Radhakrishnan (nradhak2@ncsu.edu)&lt;br /&gt;
 &lt;br /&gt;
Jayalakshmi Vishwanathan (jviswan@ncsu.edu) &lt;br /&gt;
&lt;br /&gt;
Ramya Ananth (rananth2@ncsu.edu) &lt;br /&gt;
&lt;br /&gt;
== '''Mentor Details''' ==&lt;br /&gt;
Jay Modi &lt;br /&gt;
&lt;br /&gt;
== '''References''' ==&lt;br /&gt;
 &lt;br /&gt;
* [https://en.wikipedia.org/wiki/Servo_(software)| What is servo?]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Rust_(programming_language)| what is RUST programming?]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/CSC_517_Spring_2020/Implement_ImageBitMap_WebAPI&amp;diff=133625</id>
		<title>CSC/CSC 517 Spring 2020/Implement ImageBitMap WebAPI</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/CSC_517_Spring_2020/Implement_ImageBitMap_WebAPI&amp;diff=133625"/>
		<updated>2020-04-14T03:42:53Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: /* Test Plan */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== '''Background Information''' ==&lt;br /&gt;
This project aims to contribute to Mozilla's experimental browser engine called Servo, which is implemented in a language called RUST(useful for implementing features that need concurrency and memory safety).&lt;br /&gt;
&lt;br /&gt;
Many of the components of Servo are still under development and one such feature is the [https://www.techopedia.com/definition/792/bitmap-bmp| ImageBitmap].&lt;br /&gt;
&lt;br /&gt;
Major browsers support the ImageBitmap standard which can be used to create images that are ready to be drawn efficiently to [https://en.wikipedia.org/wiki/Canvas_element| HTML canvas elements]. Servo is a new, experimental browser that supports these canvas APIs. &lt;br /&gt;
&lt;br /&gt;
The goal of and motivation behind this project is to implement support for image bitmaps and improve our canvas automated test coverage as a result.&lt;br /&gt;
&lt;br /&gt;
== '''About ImageBitMap and Motivation behind the project''' ==&lt;br /&gt;
We usually decode images for a use with canvas to allow users to customize an avatar, crop an image, or just zoom in on a picture. The problem with decoding images is that it can be CPU intensive, and that can sometimes mean jank or checkerboarding.&lt;br /&gt;
&lt;br /&gt;
But the createImageBitmap() method allows us to decode the image in the background and get access to a new ImageBitmap primitive, which you can draw into a canvas in the same way you would an &amp;lt;img&amp;gt; element, another canvas, or a video.&lt;br /&gt;
&lt;br /&gt;
The aim of this project is to develop the ImageBitmap for the servo environment. &lt;br /&gt;
&lt;br /&gt;
This can be done in the steps mentioned in the following section.&lt;br /&gt;
&lt;br /&gt;
== '''Steps for implementation''' ==&lt;br /&gt;
&lt;br /&gt;
'''Initial Phase'''&lt;br /&gt;
* '''Step 1: '''Add a ImageBitmap WebIDL interface to ''components/script/dom/webidl''s and Rust implementation in components/script/dom/imagebitmap.rs&lt;br /&gt;
* '''Step 2: ''' Add the ''createImageBitmap'' method that takes no extra x/y/w/h parameters in ''component/script/dom/webidls/WindowOrWorkerGlobalScope.webidl'' and implement the method in ''component/script/dom/window.rs'', handling the HTMLCanvasElement and OffscreenCanvas types from the possible image sources&lt;br /&gt;
&lt;br /&gt;
'''Subsequent phase'''&lt;br /&gt;
* '''Step 1: '''Implement several remaining image source types (HTMLImageElement, ImageData, ImageBitmap)&lt;br /&gt;
* '''Step 2: '''Implement the ''createImageBitmap'' overload that accepts x/y/w/h parameters&lt;br /&gt;
* '''Step 3: '''Implement support for ImageBitmaps as canvas image sources in ''components/script/canvas_state.rs''&lt;br /&gt;
[[File:AllSteps.jpg]]&lt;br /&gt;
&lt;br /&gt;
== '''Details about previous work on implementation''' ==&lt;br /&gt;
The steps that have been implemented so far in this project by the previous batch are:&lt;br /&gt;
&lt;br /&gt;
'''Step 1:''' Added the ImageBitmap interface to ''components/script/dom/webidls'' that represents a bitmap image which can be drawn to a &amp;lt;canvas&amp;gt; without undue latency. The interface contains height and weight as its attributes which are read only unsigned long integers.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//[Exposed=(Window,Worker), Serializable, Transferable]&lt;br /&gt;
[Exposed=(Window,Worker)]&lt;br /&gt;
interface ImageBitmap {&lt;br /&gt;
  readonly attribute unsigned long width;&lt;br /&gt;
  readonly attribute unsigned long height;&lt;br /&gt;
  //void close();&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef (CanvasImageSource or&lt;br /&gt;
         Blob or&lt;br /&gt;
         ImageData) ImageBitmapSource;&lt;br /&gt;
&lt;br /&gt;
enum ImageOrientation { &amp;quot;none&amp;quot;, &amp;quot;flipY&amp;quot; };&lt;br /&gt;
enum PremultiplyAlpha { &amp;quot;none&amp;quot;, &amp;quot;premultiply&amp;quot;, &amp;quot;default&amp;quot; };&lt;br /&gt;
enum ColorSpaceConversion { &amp;quot;none&amp;quot;, &amp;quot;default&amp;quot; };&lt;br /&gt;
enum ResizeQuality { &amp;quot;pixelated&amp;quot;, &amp;quot;low&amp;quot;, &amp;quot;medium&amp;quot;, &amp;quot;high&amp;quot; };&lt;br /&gt;
&lt;br /&gt;
dictionary ImageBitmapOptions {&lt;br /&gt;
  ImageOrientation imageOrientation = &amp;quot;none&amp;quot;;&lt;br /&gt;
  PremultiplyAlpha premultiplyAlpha = &amp;quot;default&amp;quot;;&lt;br /&gt;
  ColorSpaceConversion colorSpaceConversion = &amp;quot;default&amp;quot;;&lt;br /&gt;
  [EnforceRange] unsigned long resizeWidth;&lt;br /&gt;
  [EnforceRange] unsigned long resizeHeight;&lt;br /&gt;
  ResizeQuality resizeQuality = &amp;quot;low&amp;quot;;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ImageBitmap webidl also defines a dictionary for various ImageBitmap Options that can be used to modify the ImageBitmap object.&lt;br /&gt;
&lt;br /&gt;
'''Step 2:''' Implemented the rust code for the webidl interface at ''components/script/dom/imagebitmap.rs''. For more details on the code [https://expertiza.csc.ncsu.edu/index.php/CSC/ECE_517_Spring_2020_-_M2000._Implement_ImageBitMap_web_API#Implementation visit]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
use crate::dom::bindings::cell::DomRefCell;&lt;br /&gt;
&lt;br /&gt;
use crate::dom::bindings::codegen::Bindings::ImageBitmapBinding::ImageBitmapMethods;&lt;br /&gt;
use crate::dom::bindings::root::DomRoot;&lt;br /&gt;
use crate::dom::globalscope::GlobalScope;&lt;br /&gt;
&lt;br /&gt;
use crate::dom::bindings::error::Fallible;&lt;br /&gt;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};&lt;br /&gt;
use dom_struct::dom_struct;&lt;br /&gt;
&lt;br /&gt;
use std::vec::Vec;&lt;br /&gt;
&lt;br /&gt;
#[dom_struct]&lt;br /&gt;
pub struct ImageBitmap {&lt;br /&gt;
    reflector_: Reflector,&lt;br /&gt;
    width: u32,&lt;br /&gt;
    height: u32,&lt;br /&gt;
    bitmap_data: DomRefCell&amp;lt;Vec&amp;lt;u8&amp;gt;&amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
impl ImageBitmap {&lt;br /&gt;
    fn new_inherited(width_arg: u32, height_arg: u32) -&amp;gt; ImageBitmap {&lt;br /&gt;
        ImageBitmap {&lt;br /&gt;
            reflector_: Reflector::new(),&lt;br /&gt;
            width: width_arg,&lt;br /&gt;
            height: height_arg,&lt;br /&gt;
            bitmap_data: DomRefCell::new(vec![]),&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    #[allow(dead_code)]&lt;br /&gt;
    pub fn new(global: &amp;amp;GlobalScope, width: u32, height: u32) -&amp;gt; Fallible&amp;lt;DomRoot&amp;lt;ImageBitmap&amp;gt;&amp;gt; {&lt;br /&gt;
        //assigning to a variable the return object of new_inherited&lt;br /&gt;
        let imagebitmap = Box::new(ImageBitmap::new_inherited(width, height));&lt;br /&gt;
&lt;br /&gt;
        Ok(reflect_dom_object(imagebitmap, global))&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code also implements the getter methods for height and width attribute of an ImageBitmap object.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
impl ImageBitmapMethods for ImageBitmap {&lt;br /&gt;
    // https://html.spec.whatwg.org/multipage/#dom-imagebitmap-height&lt;br /&gt;
    fn Height(&amp;amp;self) -&amp;gt; u32 {&lt;br /&gt;
        //to do: add a condition for checking detached internal slot&lt;br /&gt;
        //and return 0 if set to true&lt;br /&gt;
        self.height&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // https://html.spec.whatwg.org/multipage/#dom-imagebitmap-width&lt;br /&gt;
    fn Width(&amp;amp;self) -&amp;gt; u32 {&lt;br /&gt;
        //to do: add a condition to check detached internal slot&lt;br /&gt;
        ////and return 0 if set to true&lt;br /&gt;
        self.width&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== '''Details about current work on implementation''' ==&lt;br /&gt;
Among the remaining steps in the initial and subsequent phases, the focus will be on step 2 of initial phase and once there is progress made on this step, implementation of the subsequent steps will take place. &lt;br /&gt;
&lt;br /&gt;
;Starting with createImageBitmap()&lt;br /&gt;
&lt;br /&gt;
:*The createImageBitmap() method creates a bitmap from a given source, optionally cropped to contain only a portion of that source. The method exists on the global scope in both windows and workers. It accepts a variety of different image sources, and returns a Promise which resolves to an ImageBitmap.&lt;br /&gt;
:*This method is defined in the file ''components/script/dom/webidls/WindowOrWorkerGlobalScope.webidl'' and rust code is implemented at ''components/script/dom/window.rs''.&lt;br /&gt;
:*The syntax of the method looks like&lt;br /&gt;
:::const imageBitmapPromise = createImageBitmap(image[, options]);&lt;br /&gt;
:::const imageBitmapPromise = createImageBitmap(image, sx, sy, sw, sh[, options]);&lt;br /&gt;
::where the parameters indicate:&lt;br /&gt;
:::'''image:''' an image source, which can be an img element, a SVG image element, a video element, a canvas element, a blob object, an ImageData object or another ImageBitmap object.&lt;br /&gt;
:::'''sx, sy, sw, sh:''' if given, source image is cropped to the given pixels.&lt;br /&gt;
:::'''options (Optional):''' the ImageBitmap object's bitmap data is modified according to options. Available options are:&lt;br /&gt;
:::*imageOrientation&lt;br /&gt;
:::*premultiplyAlpha&lt;br /&gt;
:::*colorSpaceConversion&lt;br /&gt;
:::*resizeWidth&lt;br /&gt;
:::*resizeHeight&lt;br /&gt;
:::*resizeQuality&lt;br /&gt;
:::: You can read more about these options [https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/createImageBitmap here]&lt;br /&gt;
::The return value is a Promise that is resolved when a new ImageBitmap is created.&lt;br /&gt;
:* As a first step, we will be implementing the method to handle canvas elements. Subsequently, we will be enhancing the method to handle other image sources and the x/y/w/h parameters.&lt;br /&gt;
&lt;br /&gt;
;Implementing close() method from previous work&lt;br /&gt;
&lt;br /&gt;
:* close() is a method in the ImageBitmap interface. It is implemented in ''components/script/dom/imagebitmap.rs'' file.&lt;br /&gt;
:* This method disposes of all graphical resources associated with an ImageBitmap.&lt;br /&gt;
&lt;br /&gt;
== '''Algorithm to design the createImageBitmap() method''' ==&lt;br /&gt;
&lt;br /&gt;
On invoking the createImageBitmap(image, options) or the createImageBitmap(image sx, sy, sw, sh, options) the following in the sequence of actions&lt;br /&gt;
&lt;br /&gt;
[[File:fig1.png|border]] &lt;br /&gt;
&lt;br /&gt;
Switching on the &amp;quot;image&amp;quot; argument the following is the sequence of actions &lt;br /&gt;
&lt;br /&gt;
=== If the image is an SVGImage===&lt;br /&gt;
[[File:fig2.png|border]]&lt;br /&gt;
&lt;br /&gt;
=== If the image is a video===&lt;br /&gt;
[[File:ReFigure3.png|border]] &lt;br /&gt;
&lt;br /&gt;
=== If the image is a canvas===&lt;br /&gt;
[[File:ReFigure4.png|border]]&lt;br /&gt;
 &lt;br /&gt;
=== If the image is an ImageBitmap===&lt;br /&gt;
[[File:ImageBitmap.jpg|border]]&lt;br /&gt;
&lt;br /&gt;
=== If the image is an ImageData===&lt;br /&gt;
[[File:ImageData.jpg|border]]&lt;br /&gt;
&lt;br /&gt;
=='''Test Plan'''==&lt;br /&gt;
The following are the respective steps in testing:&lt;br /&gt;
* &amp;lt;b&amp;gt;Servo building test should be successful.&amp;lt;/b&amp;gt;&lt;br /&gt;
The compiling time is based on the CPU clock speed and the OS of the system where the file is being run. For a 64-bit Linux OS, it takes from about 1 hour to 2 hours for the entire build. It takes 2.5 hours on Windows OS.&lt;br /&gt;
* &amp;lt;b&amp;gt;Check for the file tidiness (following standards of servo) using the command:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Linux or macOS:&lt;br /&gt;
    ./mach test-tidy&lt;br /&gt;
    ./mach fmt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Windows:&lt;br /&gt;
    mach.bat test-tidy&lt;br /&gt;
    mach.bat fmt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
*&amp;lt;b&amp;gt;Servo automated Unit-testing should be successful.&amp;lt;/b&amp;gt;&lt;br /&gt;
Running the following commands will run all the unit-tests&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Linux or macOS:&lt;br /&gt;
    ./mach test-unit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Windows:&lt;br /&gt;
    mach.bat test-unit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note: A log file can be maintained to make keep a check on the tests that are passing.&lt;br /&gt;
* &amp;lt;b&amp;gt;Update the automated servo Web Platform tests(wpt):&amp;lt;/b&amp;gt;&lt;br /&gt;
For a DOM feature, extensive tests already exist under tests/wpt. Any change in DOM would require updating the expected results in the automated tests.&lt;br /&gt;
&lt;br /&gt;
This first requires storing the log in raw format from a test run, for example by running&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach test-wpt --log-raw /path/for/storing/log/file/&amp;lt;filename&amp;gt;.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once log is saved, then run to update test expectations&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach update-wpt /path/to/logfile/&amp;lt;filename&amp;gt;.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== '''Team Details''' ==&lt;br /&gt;
Sandeep Kundala (skundal@ncsu.edu)&lt;br /&gt;
 &lt;br /&gt;
Nita Radhakrishnan (nradhak2@ncsu.edu)&lt;br /&gt;
 &lt;br /&gt;
Jayalakshmi Vishwanathan (jviswan@ncsu.edu) &lt;br /&gt;
&lt;br /&gt;
Ramya Ananth (rananth2@ncsu.edu) &lt;br /&gt;
&lt;br /&gt;
== '''Mentor Details''' ==&lt;br /&gt;
Jay Modi &lt;br /&gt;
&lt;br /&gt;
== '''References''' ==&lt;br /&gt;
 &lt;br /&gt;
* [https://en.wikipedia.org/wiki/Servo_(software)| What is servo?]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Rust_(programming_language)| what is RUST programming?]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/CSC_517_Spring_2020/Implement_ImageBitMap_WebAPI&amp;diff=133616</id>
		<title>CSC/CSC 517 Spring 2020/Implement ImageBitMap WebAPI</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/CSC_517_Spring_2020/Implement_ImageBitMap_WebAPI&amp;diff=133616"/>
		<updated>2020-04-14T03:32:14Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: /* Algorithm to design the createImageBitmap() method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== '''Background Information''' ==&lt;br /&gt;
This project aims to contribute to Mozilla's experimental browser engine called Servo, which is implemented in a language called RUST(useful for implementing features that need concurrency and memory safety).&lt;br /&gt;
&lt;br /&gt;
Many of the components of Servo are still under development and one such feature is the [https://www.techopedia.com/definition/792/bitmap-bmp| ImageBitmap].&lt;br /&gt;
&lt;br /&gt;
Major browsers support the ImageBitmap standard which can be used to create images that are ready to be drawn efficiently to [https://en.wikipedia.org/wiki/Canvas_element| HTML canvas elements]. Servo is a new, experimental browser that supports these canvas APIs. &lt;br /&gt;
&lt;br /&gt;
The goal of and motivation behind this project is to implement support for image bitmaps and improve our canvas automated test coverage as a result.&lt;br /&gt;
&lt;br /&gt;
== '''About ImageBitMap and Motivation behind the project''' ==&lt;br /&gt;
We usually decode images for a use with canvas to allow users to customize an avatar, crop an image, or just zoom in on a picture. The problem with decoding images is that it can be CPU intensive, and that can sometimes mean jank or checkerboarding.&lt;br /&gt;
&lt;br /&gt;
But the createImageBitmap() method allows us to decode the image in the background and get access to a new ImageBitmap primitive, which you can draw into a canvas in the same way you would an &amp;lt;img&amp;gt; element, another canvas, or a video.&lt;br /&gt;
&lt;br /&gt;
The aim of this project is to develop the ImageBitmap for the servo environment. &lt;br /&gt;
&lt;br /&gt;
This can be done in the steps mentioned in the following section.&lt;br /&gt;
&lt;br /&gt;
== '''Steps for implementation''' ==&lt;br /&gt;
&lt;br /&gt;
'''Initial Phase'''&lt;br /&gt;
* '''Step 1: '''Add a ImageBitmap WebIDL interface to ''components/script/dom/webidl''s and Rust implementation in components/script/dom/imagebitmap.rs&lt;br /&gt;
* '''Step 2: ''' Add the ''createImageBitmap'' method that takes no extra x/y/w/h parameters in ''component/script/dom/webidls/WindowOrWorkerGlobalScope.webidl'' and implement the method in ''component/script/dom/window.rs'', handling the HTMLCanvasElement and OffscreenCanvas types from the possible image sources&lt;br /&gt;
&lt;br /&gt;
'''Subsequent phase'''&lt;br /&gt;
* '''Step 1: '''Implement several remaining image source types (HTMLImageElement, ImageData, ImageBitmap)&lt;br /&gt;
* '''Step 2: '''Implement the ''createImageBitmap'' overload that accepts x/y/w/h parameters&lt;br /&gt;
* '''Step 3: '''Implement support for ImageBitmaps as canvas image sources in ''components/script/canvas_state.rs''&lt;br /&gt;
[[File:AllSteps.jpg]]&lt;br /&gt;
&lt;br /&gt;
== '''Details about previous work on implementation''' ==&lt;br /&gt;
The steps that have been implemented so far in this project by the previous batch are:&lt;br /&gt;
&lt;br /&gt;
'''Step 1:''' Added the ImageBitmap interface to ''components/script/dom/webidls'' that represents a bitmap image which can be drawn to a &amp;lt;canvas&amp;gt; without undue latency. The interface contains height and weight as its attributes which are read only unsigned long integers.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//[Exposed=(Window,Worker), Serializable, Transferable]&lt;br /&gt;
[Exposed=(Window,Worker)]&lt;br /&gt;
interface ImageBitmap {&lt;br /&gt;
  readonly attribute unsigned long width;&lt;br /&gt;
  readonly attribute unsigned long height;&lt;br /&gt;
  //void close();&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef (CanvasImageSource or&lt;br /&gt;
         Blob or&lt;br /&gt;
         ImageData) ImageBitmapSource;&lt;br /&gt;
&lt;br /&gt;
enum ImageOrientation { &amp;quot;none&amp;quot;, &amp;quot;flipY&amp;quot; };&lt;br /&gt;
enum PremultiplyAlpha { &amp;quot;none&amp;quot;, &amp;quot;premultiply&amp;quot;, &amp;quot;default&amp;quot; };&lt;br /&gt;
enum ColorSpaceConversion { &amp;quot;none&amp;quot;, &amp;quot;default&amp;quot; };&lt;br /&gt;
enum ResizeQuality { &amp;quot;pixelated&amp;quot;, &amp;quot;low&amp;quot;, &amp;quot;medium&amp;quot;, &amp;quot;high&amp;quot; };&lt;br /&gt;
&lt;br /&gt;
dictionary ImageBitmapOptions {&lt;br /&gt;
  ImageOrientation imageOrientation = &amp;quot;none&amp;quot;;&lt;br /&gt;
  PremultiplyAlpha premultiplyAlpha = &amp;quot;default&amp;quot;;&lt;br /&gt;
  ColorSpaceConversion colorSpaceConversion = &amp;quot;default&amp;quot;;&lt;br /&gt;
  [EnforceRange] unsigned long resizeWidth;&lt;br /&gt;
  [EnforceRange] unsigned long resizeHeight;&lt;br /&gt;
  ResizeQuality resizeQuality = &amp;quot;low&amp;quot;;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ImageBitmap webidl also defines a dictionary for various ImageBitmap Options that can be used to modify the ImageBitmap object.&lt;br /&gt;
&lt;br /&gt;
'''Step 2:''' Implemented the rust code for the webidl interface at ''components/script/dom/imagebitmap.rs''. For more details on the code [https://expertiza.csc.ncsu.edu/index.php/CSC/ECE_517_Spring_2020_-_M2000._Implement_ImageBitMap_web_API#Implementation visit]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
use crate::dom::bindings::cell::DomRefCell;&lt;br /&gt;
&lt;br /&gt;
use crate::dom::bindings::codegen::Bindings::ImageBitmapBinding::ImageBitmapMethods;&lt;br /&gt;
use crate::dom::bindings::root::DomRoot;&lt;br /&gt;
use crate::dom::globalscope::GlobalScope;&lt;br /&gt;
&lt;br /&gt;
use crate::dom::bindings::error::Fallible;&lt;br /&gt;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};&lt;br /&gt;
use dom_struct::dom_struct;&lt;br /&gt;
&lt;br /&gt;
use std::vec::Vec;&lt;br /&gt;
&lt;br /&gt;
#[dom_struct]&lt;br /&gt;
pub struct ImageBitmap {&lt;br /&gt;
    reflector_: Reflector,&lt;br /&gt;
    width: u32,&lt;br /&gt;
    height: u32,&lt;br /&gt;
    bitmap_data: DomRefCell&amp;lt;Vec&amp;lt;u8&amp;gt;&amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
impl ImageBitmap {&lt;br /&gt;
    fn new_inherited(width_arg: u32, height_arg: u32) -&amp;gt; ImageBitmap {&lt;br /&gt;
        ImageBitmap {&lt;br /&gt;
            reflector_: Reflector::new(),&lt;br /&gt;
            width: width_arg,&lt;br /&gt;
            height: height_arg,&lt;br /&gt;
            bitmap_data: DomRefCell::new(vec![]),&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    #[allow(dead_code)]&lt;br /&gt;
    pub fn new(global: &amp;amp;GlobalScope, width: u32, height: u32) -&amp;gt; Fallible&amp;lt;DomRoot&amp;lt;ImageBitmap&amp;gt;&amp;gt; {&lt;br /&gt;
        //assigning to a variable the return object of new_inherited&lt;br /&gt;
        let imagebitmap = Box::new(ImageBitmap::new_inherited(width, height));&lt;br /&gt;
&lt;br /&gt;
        Ok(reflect_dom_object(imagebitmap, global))&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code also implements the getter methods for height and width attribute of an ImageBitmap object.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
impl ImageBitmapMethods for ImageBitmap {&lt;br /&gt;
    // https://html.spec.whatwg.org/multipage/#dom-imagebitmap-height&lt;br /&gt;
    fn Height(&amp;amp;self) -&amp;gt; u32 {&lt;br /&gt;
        //to do: add a condition for checking detached internal slot&lt;br /&gt;
        //and return 0 if set to true&lt;br /&gt;
        self.height&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // https://html.spec.whatwg.org/multipage/#dom-imagebitmap-width&lt;br /&gt;
    fn Width(&amp;amp;self) -&amp;gt; u32 {&lt;br /&gt;
        //to do: add a condition to check detached internal slot&lt;br /&gt;
        ////and return 0 if set to true&lt;br /&gt;
        self.width&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== '''Details about current work on implementation''' ==&lt;br /&gt;
Among the remaining steps in the initial and subsequent phases, the focus will be on step 2 of initial phase and once there is progress made on this step, implementation of the subsequent steps will take place. &lt;br /&gt;
&lt;br /&gt;
;Starting with createImageBitmap()&lt;br /&gt;
&lt;br /&gt;
:*The createImageBitmap() method creates a bitmap from a given source, optionally cropped to contain only a portion of that source. The method exists on the global scope in both windows and workers. It accepts a variety of different image sources, and returns a Promise which resolves to an ImageBitmap.&lt;br /&gt;
:*The syntax of the method looks like&lt;br /&gt;
:::const imageBitmapPromise = createImageBitmap(image[, options]);&lt;br /&gt;
:::const imageBitmapPromise = createImageBitmap(image, sx, sy, sw, sh[, options]);&lt;br /&gt;
::where the parameters indicate:&lt;br /&gt;
:::'''image:''' an image source, which can be an img element, a SVG image element, a video element, a canvas element, a blob object, an ImageData object or another ImageBitmap object.&lt;br /&gt;
:::'''sx, sy, sw, sh:''' if given, source image is cropped to the given pixels.&lt;br /&gt;
:::'''options (Optional):''' the ImageBitmap object's bitmap data is modified according to options. Available options are:&lt;br /&gt;
:::*imageOrientation&lt;br /&gt;
:::*premultiplyAlpha&lt;br /&gt;
:::*colorSpaceConversion&lt;br /&gt;
:::*resizeWidth&lt;br /&gt;
:::*resizeHeight&lt;br /&gt;
:::*resizeQuality&lt;br /&gt;
:::: You can read more about these options [https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/createImageBitmap here]&lt;br /&gt;
::The return value is a Promise that is resolved when a new ImageBitmap is created.&lt;br /&gt;
:* As a first step, we will be implementing the method to handle canvas elements. Subsequently, we will be enhancing the method to handle other image sources and the x/y/w/h parameters.&lt;br /&gt;
&lt;br /&gt;
;Implementing close() method from previous work&lt;br /&gt;
&lt;br /&gt;
:* close() is a method in the ImageBitmap interface. It is implemented in ''components/script/dom/imagebitmap.rs'' file.&lt;br /&gt;
:* This method disposes of all graphical resources associated with an ImageBitmap.&lt;br /&gt;
&lt;br /&gt;
== '''Algorithm to design the createImageBitmap() method''' ==&lt;br /&gt;
&lt;br /&gt;
On invoking the createImageBitmap(image, options) or the createImageBitmap(image sx, sy, sw, sh, options) the following in the sequence of actions&lt;br /&gt;
&lt;br /&gt;
[[File:fig1.png|border]] &lt;br /&gt;
&lt;br /&gt;
Switching on the &amp;quot;image&amp;quot; argument the following is the sequence of actions &lt;br /&gt;
&lt;br /&gt;
=== If the image is an SVGImage===&lt;br /&gt;
[[File:fig2.png|border]]&lt;br /&gt;
&lt;br /&gt;
=== If the image is a video===&lt;br /&gt;
[[File:ReFigure3.png|border]] &lt;br /&gt;
&lt;br /&gt;
=== If the image is a canvas===&lt;br /&gt;
[[File:ReFigure4.png|border]]&lt;br /&gt;
 &lt;br /&gt;
=== If the image is an ImageBitmap===&lt;br /&gt;
[[File:ImageBitmap.jpg|border]]&lt;br /&gt;
&lt;br /&gt;
=== If the image is an ImageData===&lt;br /&gt;
[[File:ImageData.jpg|border]]&lt;br /&gt;
&lt;br /&gt;
=='''Test Plan'''==&lt;br /&gt;
The following are the respective steps in testing:&lt;br /&gt;
* Servo building test should be successful.&lt;br /&gt;
* Check for the file tidiness (following standards of servo) using the command:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Linux or macOS:&lt;br /&gt;
    ./mach test-tidy&lt;br /&gt;
    ./mach fmt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
For Windows:&lt;br /&gt;
    mach.bat test-tidy&lt;br /&gt;
    mach.bat fmt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Update the automated servo Web Platform tests(wpt):&lt;br /&gt;
For a DOM feature, extensive tests already exist under tests/wpt. Any change in DOM would require updating the expected results in the automated tests.&lt;br /&gt;
&lt;br /&gt;
This first requires storing the log in raw format from a test run, for example by running&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach test-wpt --log-raw /path/for/storing/log/file/&amp;lt;filename&amp;gt;.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once log is saved, then run to update test expectations&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach update-wpt /path/to/logfile/&amp;lt;filename&amp;gt;.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== '''Team Details''' ==&lt;br /&gt;
Sandeep Kundala (skundal@ncsu.edu)&lt;br /&gt;
 &lt;br /&gt;
Nita Radhakrishnan (nradhak2@ncsu.edu)&lt;br /&gt;
 &lt;br /&gt;
Jayalakshmi Vishwanathan (jviswan@ncsu.edu) &lt;br /&gt;
&lt;br /&gt;
Ramya Ananth (rananth2@ncsu.edu) &lt;br /&gt;
&lt;br /&gt;
== '''Mentor Details''' ==&lt;br /&gt;
Jay Modi &lt;br /&gt;
&lt;br /&gt;
== '''References''' ==&lt;br /&gt;
 &lt;br /&gt;
* [https://en.wikipedia.org/wiki/Servo_(software)| What is servo?]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Rust_(programming_language)| what is RUST programming?]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Location_screenshot.jpg&amp;diff=132645</id>
		<title>File:Location screenshot.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Location_screenshot.jpg&amp;diff=132645"/>
		<updated>2020-04-01T04:31:52Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Location_screenshot.PNG&amp;diff=132644</id>
		<title>File:Location screenshot.PNG</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Location_screenshot.PNG&amp;diff=132644"/>
		<updated>2020-04-01T04:25:41Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: Rananth2 uploaded a new version of File:Location screenshot.PNG&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Location_screenshot.PNG&amp;diff=132643</id>
		<title>File:Location screenshot.PNG</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Location_screenshot.PNG&amp;diff=132643"/>
		<updated>2020-04-01T04:24:52Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: Rananth2 uploaded a new version of File:Location screenshot.PNG&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Location_screenshot.PNG&amp;diff=132642</id>
		<title>File:Location screenshot.PNG</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Location_screenshot.PNG&amp;diff=132642"/>
		<updated>2020-04-01T04:23:55Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132641</id>
		<title>CSC/ECE 517 Spring 2020 - E2003. Refactor and improve assessment360 controller</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132641"/>
		<updated>2020-04-01T03:53:37Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: /* Test Plan */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source project based on [http://rubyonrails.org/ Ruby on Rails] framework. The software allows the instructor and students with the following privileges,&lt;br /&gt;
&lt;br /&gt;
===Instructors===&lt;br /&gt;
* Create new assignments&lt;br /&gt;
* Customize new or existing assignments&lt;br /&gt;
* Create a list of topics that students can sign up for&lt;br /&gt;
* Give grades/reviews for the students' submissions&lt;br /&gt;
&lt;br /&gt;
===Students===&lt;br /&gt;
* Form teams with other students to work on various projects and assignments&lt;br /&gt;
* Peer review other students' submissions&lt;br /&gt;
&lt;br /&gt;
Note: Expertiza supports submissions across various document types, including URL and wiki pages&lt;br /&gt;
&lt;br /&gt;
==Project Description==&lt;br /&gt;
&lt;br /&gt;
===About assessment_360 Controller===&lt;br /&gt;
The assessment_360 controller is designed to gather data from all stakeholders about the performance of a student in a course. Thus, its purpose is to provide course-level statistics. At present, the controller provides only two top-level functions where each of them gives a list of students in the class. &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; contains teammate and meta-review scores received by students for all assignments in the course&lt;br /&gt;
* &amp;lt;b&amp;gt;course_student_grade_summary &amp;lt;/b&amp;gt; gives a listing of students and what topic they worked on and what grade they received on each assignment during the semester&lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The assessment360 controller had three major issues. This project is aimed to address some of them, including:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 1:&amp;lt;/b&amp;gt; Methods &amp;lt;i&amp;gt;all_students_all_reviews&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;course_student_grade_summary&amp;lt;/i&amp;gt; were too long. Common initialization and looping had to factored out by moving them into smaller methods with mnemonic names&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 2:&amp;lt;/b&amp;gt; Method populate_hash_for_all_students_all_reviews is not easy to understand. It uses a special data structure to do a very simple task. That had to be refactored&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 3:&amp;lt;/b&amp;gt; Method course_student_grade_summary stopped working and has to be fixed&lt;br /&gt;
&lt;br /&gt;
===Motivation===&lt;br /&gt;
This project aims at encouraging students to collaborate and contribute to open-source project in turn helping them understand what goes on in a full-fledged software deployment process. It also paves a way to understand how one can use Rails, RSpec to develop a system that does justice to the DRY code practicing principles.&lt;br /&gt;
&lt;br /&gt;
==Approach==&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 1: Refactoring all_students_all_reviews and course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(a) The common elements in these files i.e., checking if the course participant list is empty or not is moved to a different function called &amp;lt;i&amp;gt;inspect_course_participants&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(b) Adding on to this, all_student_all_review was broken down to two more functions, &amp;lt;i&amp;gt;avg_review_calc_per_student&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;overall_review_count&amp;lt;/i&amp;gt; &lt;br /&gt;
&lt;br /&gt;
(c) The method course_student_grade_summary is broken down to one more function &amp;lt;i&amp;gt;assignment_grade_summary&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 2: Refactoring populate_hash_for_all_students_all_reviews&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The approach in this function is pretty straight forward when we try to break it down. It calculates,&lt;br /&gt;
&lt;br /&gt;
(a) The average score for each assignment for each course&lt;br /&gt;
&lt;br /&gt;
(b) The overall review grade for each assignment for all the students who have taken the course&lt;br /&gt;
&lt;br /&gt;
Passing the average score calculated from (a) checks if the student has teammates which could result in not having an average teammate_review_score. If we calculate (b) in our main function (this can be done) we would be repeating the checks that we are already doing for (a). Hence, this function is not changed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 3: Fix course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The current implementation ran into an issue when it was comparing the Key-Value pair passed in '''peer_review_score'''. It was hard to check if each of the keys were present or not. The proposed solution makes use of a basic hash value presence check that retrieves a value from the array/hash, given a set of keys. If no value is found, it'll return nil.&lt;br /&gt;
&lt;br /&gt;
==Proposed Implementation==&lt;br /&gt;
====Fixing the bug on course_student_grade_summary====&lt;br /&gt;
The current implementation of the method throws a nil error at the moment on the following line,&lt;br /&gt;
&amp;lt;pre&amp;gt;unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is rectified by introducing,&lt;br /&gt;
&amp;lt;pre&amp;gt;next if (peer_review_score[:review] &amp;amp;&amp;amp; peer_review_score[:review][:scores] &amp;amp;&amp;amp; peer_review_score[:review][:scores][:avg]).nil?&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Common refactoring of all_students_all_reviews and course_student_grade_summary method====&lt;br /&gt;
The functionality that the methods shared was that, both of them checked if there were course participants who had taken a particular course. This occupied 4 lines of code in both the functions. So, this is defined in a separate function called insure_existence_of and called from the two functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def insure_existence_of(course_participants)&lt;br /&gt;
    if course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Refactor all_students_all_reviews method====&lt;br /&gt;
The all_students_all_reviews method is one of the biggest methods in assessment360_controller.rb file. It finds the list of all students and assignments pertaining to the course. This data is then used to compute the metareview and teammate review scores for each student.&lt;br /&gt;
&lt;br /&gt;
The code before refactoring had 64 lines of code as shown below,&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   teammate_reviews,&lt;br /&gt;
                                                   @teammate_review,&lt;br /&gt;
                                                   @overall_teammate_review_grades,&lt;br /&gt;
                                                   @overall_teammate_review_count,&lt;br /&gt;
                                                   @teammate_review_info_per_stu)&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   meta_reviews,&lt;br /&gt;
                                                   @meta_review,&lt;br /&gt;
                                                   @overall_meta_review_grades,&lt;br /&gt;
                                                   @overall_meta_review_count,&lt;br /&gt;
                                                   @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      if @teammate_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @teammate_review_info_per_stu[0] * 1.0 / @teammate_review_info_per_stu[1]&lt;br /&gt;
        @teammate_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
      if @meta_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @meta_review_info_per_stu[0] * 1.0 / @meta_review_info_per_stu[1]&lt;br /&gt;
        @meta_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    @assignments.each do |assignment|&lt;br /&gt;
      temp_count = @overall_teammate_review_count[assignment.id]&lt;br /&gt;
      @overall_teammate_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = @overall_meta_review_count[assignment.id]&lt;br /&gt;
      @overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To calculate the average grade for each student on all assignments in this course that a student has taken in this course is refactoring in the base code by adding the avg_review_calc_per_student method. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def avg_review_calc_per_student(cp, review_info_per_stu, review)&lt;br /&gt;
    # check to see if the student has been given a review&lt;br /&gt;
    if review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
      temp_avg_grade = review_info_per_stu[0] * 1.0 / review_info_per_stu[1]&lt;br /&gt;
      review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To avoid a &amp;lt;i&amp;gt;divide by zero error&amp;lt;/i&amp;gt; that is thrown when we try to calculate the average grade when a student has no teammate is handled by the overall_review_count method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def overall_review_count(assignments, overall_teammate_review_count, overall_meta_review_count)&lt;br /&gt;
    assignments.each do |assignment|&lt;br /&gt;
      temp_count = overall_teammate_review_count[assignment.id]&lt;br /&gt;
      overall_review_count_hash[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = overall_meta_review_count[assignment.id]&lt;br /&gt;
      overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''After refactoring'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 teammate_reviews,&lt;br /&gt;
                                 @teammate_review,&lt;br /&gt;
                                 @overall_teammate_review_grades,&lt;br /&gt;
                                 @overall_teammate_review_count,&lt;br /&gt;
                                 @teammate_review_info_per_stu)&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 meta_reviews,&lt;br /&gt;
                                 @meta_review,&lt;br /&gt;
                                 @overall_meta_review_grades,&lt;br /&gt;
                                 @overall_meta_review_count,&lt;br /&gt;
                                 @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      avg_review_calc_per_student(cp, @teammate_review_info_per_stu, @teammate_review)&lt;br /&gt;
      avg_review_calc_per_student(cp, @meta_review_info_per_stu, @meta_review)&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    overall_review_count(@assignments, @overall_teammate_review_count, @overall_meta_review_count)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Refactor course_student_grade_summary method====&lt;br /&gt;
This method finds the list of all students and assignments pertaining to the course. The data obtained is then used to compute the instructor assigned grade and peer review scores. It was the secong biggest method in the assessment360_controller.rb controller file. The code before refactoring is shown below,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
&lt;br /&gt;
        # A topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
        topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
        @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
&lt;br /&gt;
        # Instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
        team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
        next if team_id.nil?&lt;br /&gt;
&lt;br /&gt;
        team = Team.find(team_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
&lt;br /&gt;
        # Set the assignment grade, peer review score, and sum for the final student summary&lt;br /&gt;
        @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
        unless @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
          @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&lt;br /&gt;
          @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&lt;br /&gt;
        end&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;
In this function, all the functionalities pertaining to a course participant - student in this case, in a given assignment is invoked by introducing a new method called assignment_grade_summary. This method checks if a topic exists and if it does, it passes the final grade that is calculated for that student in that course.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
    user_id = cp.user_id&lt;br /&gt;
    # topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
    topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
    @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
    # instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
    team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
    team = Team.find(team_id)&lt;br /&gt;
    @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
    return if @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
    @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
  end  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''After refactoring'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        # break out of the loop if there are no participants in the assignment&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
        # break out of the loop if the participant has no team&lt;br /&gt;
        next if TeamsUser.team_id(assignment_id, user_id).nil?&lt;br /&gt;
        # pull information about the student's grades for particular assignment&lt;br /&gt;
        assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
        #Skip if there are no peers&lt;br /&gt;
        next if peer_review_score.nil? &lt;br /&gt;
        #Skip if there are no reviews done by peers&lt;br /&gt;
        next if peer_review_score[:review].nil? &lt;br /&gt;
        #Skip if there are no reviews scores assigned by peers&lt;br /&gt;
        next if peer_review_score[:review][:scores].nil?&lt;br /&gt;
        #Skip if there are is no peer review average score&lt;br /&gt;
        next if peer_review_score[:review][:scores][:avg].nil?&lt;br /&gt;
        @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&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;
==Method name explanations==&lt;br /&gt;
One of the methods devised in this project is use nouns instead of verbs. Ideally the name of a variable or method should be enough to identify it's function in the class. This is because assessment_360 controller, of course is an exception and does explain what each of the functions do on their function names,&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; - Find the list of all students and assignments pertaining to the course. This data is used to compute the metareview and teammate review scores.&lt;br /&gt;
*&amp;lt;b&amp;gt;avg_review_calc_per_student&amp;lt;/b&amp;gt; - Calculate the overall average review grade that a student has gotten from their teammate(s) and instructor(s)&lt;br /&gt;
*&amp;lt;b&amp;gt;overall_review_count&amp;lt;/b&amp;gt; - To avoid divide by zero error&lt;br /&gt;
*&amp;lt;b&amp;gt;course_student_grade_summary&amp;lt;/b&amp;gt; - Find the list of all students and assignments pertaining to the course. This data is used to compute the instructor assigned grade and peer review scores.&lt;br /&gt;
*&amp;lt;b&amp;gt;assignment_grade_summary&amp;lt;/b&amp;gt; - To pull information about the student's grades for particular assignment&lt;br /&gt;
*&amp;lt;b&amp;gt;insure_existence_of&amp;lt;/b&amp;gt; - To make sure there are participants for the course&lt;br /&gt;
*&amp;lt;b&amp;gt;calc_overall_review_info&amp;lt;/b&amp;gt; - The function populates the hash value for all students for all the reviews that they have gotten. I.e., Teammate and Meta for each of the assignments that they have taken. This value is then used to display the overall teammate_review and meta_review grade in the view&lt;br /&gt;
*&amp;lt;b&amp;gt;find_peer_review_score&amp;lt;/b&amp;gt; - The peer review score is taken from the questions for the assignment&lt;br /&gt;
&lt;br /&gt;
==Testing==&lt;br /&gt;
===Test Plan===&lt;br /&gt;
&lt;br /&gt;
The main objective of improving the current Assessment 360 Controller testing is to make sure each of the functionalities are being looked into regardless of the test coverage because of the number of calculations that are actually being taken place inside the controller. In order to achieve this, tests were written for two main newly added methods in the controller. The first few tests have assumed to expect a normal condition i.e., a person exists and all other information do exist.&lt;br /&gt;
&lt;br /&gt;
===Test Cases===&lt;br /&gt;
The following test cases were made for the major methods added to the Assessment 360 Controller:&lt;br /&gt;
*&amp;lt;b&amp;gt;insure_existence_of&amp;lt;/b&amp;gt; &lt;br /&gt;
- Checking if the course participants are empty&amp;lt;br&amp;gt;&lt;br /&gt;
- Check if function redirects to back&amp;lt;br&amp;gt;&lt;br /&gt;
- Check if function flashes an error if it's not present&amp;lt;br&amp;gt;&lt;br /&gt;
- When method is called, it should check if there are course participants and redirects to back and flashes error if there are no participants&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;assignment_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
- Checking if the course participants are empty&amp;lt;br&amp;gt;&lt;br /&gt;
- Check if function redirects to back&amp;lt;br&amp;gt;&lt;br /&gt;
- Check if function flashes an error if it's not present&amp;lt;br&amp;gt;&lt;br /&gt;
- When method is called, it should check if there are course participants. When this passes, and when there are participants with team id, the total value returned for final grade should be valid&lt;br /&gt;
&lt;br /&gt;
===UI Testing===&lt;br /&gt;
By following the below steps, a reviewer can manually test the changes made to the Assessment 360 Controller.&lt;br /&gt;
&lt;br /&gt;
1. Visit [http://152.46.16.125:8080/ http://152.46.16.125:8080/] and enter the following credentials,&amp;lt;br&amp;gt;&lt;br /&gt;
   &amp;lt;b&amp;gt;Username:&amp;lt;/b&amp;gt; instructor6 &amp;lt;br&amp;gt;&lt;br /&gt;
   &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password&lt;br /&gt;
&lt;br /&gt;
2. From the menu bar, select Manage &amp;gt; Courses&lt;br /&gt;
&lt;br /&gt;
3. Scroll down to find the respective course, and select the blue globe icon. The page should load.&lt;br /&gt;
&lt;br /&gt;
4. Scroll down to find the respective course, and select the brown menu icon. The page should load.&lt;br /&gt;
&lt;br /&gt;
==Submission==&lt;br /&gt;
===Github Link===&lt;br /&gt;
&lt;br /&gt;
The changes made to the code is present on this [https://github.com/ramyananth/expertiza link]. Multiple comments and refactoring have been addressed in detail here.&lt;br /&gt;
&lt;br /&gt;
===Pull Request===&lt;br /&gt;
&lt;br /&gt;
The initial build made out of pull request [https://github.com/expertiza/expertiza/pull/1691 1691], kept failing continuously since it was made to the master branch of expertiza. It changed the Gemfile.lock and also the database schema. This push was actually made because the beta branch and master branch of expertiza were not different at all. The new pull request [https://github.com/expertiza/expertiza/pull/1713 1713] was made to the beta branch from our beta branch and it worked completely fine.&lt;br /&gt;
&lt;br /&gt;
==Team Information==&lt;br /&gt;
[mailto:rananth2@ncsu.edu Ramya Ananth] - [https://www.linkedin.com/in/ramyananth/ LinkedIn]&lt;br /&gt;
&lt;br /&gt;
[mailto:suppala@ncsu.edu Sri Harsha Varma Uppalapati] - [https://www.linkedin.com/in/sri-harsha-varma-uppalapati LinkedIn]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;[mailto:efg@ncsu.edu Mentor: Dr. Edward F Gehringer]&amp;lt;/b&amp;gt; - [https://www.ece.ncsu.edu/people/efg/ Website]&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
1.[https://github.com/expertiza/expertiza/ Expertiza on GitHub]&lt;br /&gt;
&lt;br /&gt;
2.[https://github.com/ramyananth/expertiza GitHub Project Repository Fork]&lt;br /&gt;
&lt;br /&gt;
3.[http://expertiza.ncsu.edu/ Live Expertiza website]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132640</id>
		<title>CSC/ECE 517 Spring 2020 - E2003. Refactor and improve assessment360 controller</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132640"/>
		<updated>2020-04-01T03:53:02Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: /* Test Cases */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source project based on [http://rubyonrails.org/ Ruby on Rails] framework. The software allows the instructor and students with the following privileges,&lt;br /&gt;
&lt;br /&gt;
===Instructors===&lt;br /&gt;
* Create new assignments&lt;br /&gt;
* Customize new or existing assignments&lt;br /&gt;
* Create a list of topics that students can sign up for&lt;br /&gt;
* Give grades/reviews for the students' submissions&lt;br /&gt;
&lt;br /&gt;
===Students===&lt;br /&gt;
* Form teams with other students to work on various projects and assignments&lt;br /&gt;
* Peer review other students' submissions&lt;br /&gt;
&lt;br /&gt;
Note: Expertiza supports submissions across various document types, including URL and wiki pages&lt;br /&gt;
&lt;br /&gt;
==Project Description==&lt;br /&gt;
&lt;br /&gt;
===About assessment_360 Controller===&lt;br /&gt;
The assessment_360 controller is designed to gather data from all stakeholders about the performance of a student in a course. Thus, its purpose is to provide course-level statistics. At present, the controller provides only two top-level functions where each of them gives a list of students in the class. &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; contains teammate and meta-review scores received by students for all assignments in the course&lt;br /&gt;
* &amp;lt;b&amp;gt;course_student_grade_summary &amp;lt;/b&amp;gt; gives a listing of students and what topic they worked on and what grade they received on each assignment during the semester&lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The assessment360 controller had three major issues. This project is aimed to address some of them, including:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 1:&amp;lt;/b&amp;gt; Methods &amp;lt;i&amp;gt;all_students_all_reviews&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;course_student_grade_summary&amp;lt;/i&amp;gt; were too long. Common initialization and looping had to factored out by moving them into smaller methods with mnemonic names&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 2:&amp;lt;/b&amp;gt; Method populate_hash_for_all_students_all_reviews is not easy to understand. It uses a special data structure to do a very simple task. That had to be refactored&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 3:&amp;lt;/b&amp;gt; Method course_student_grade_summary stopped working and has to be fixed&lt;br /&gt;
&lt;br /&gt;
===Motivation===&lt;br /&gt;
This project aims at encouraging students to collaborate and contribute to open-source project in turn helping them understand what goes on in a full-fledged software deployment process. It also paves a way to understand how one can use Rails, RSpec to develop a system that does justice to the DRY code practicing principles.&lt;br /&gt;
&lt;br /&gt;
==Approach==&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 1: Refactoring all_students_all_reviews and course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(a) The common elements in these files i.e., checking if the course participant list is empty or not is moved to a different function called &amp;lt;i&amp;gt;inspect_course_participants&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(b) Adding on to this, all_student_all_review was broken down to two more functions, &amp;lt;i&amp;gt;avg_review_calc_per_student&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;overall_review_count&amp;lt;/i&amp;gt; &lt;br /&gt;
&lt;br /&gt;
(c) The method course_student_grade_summary is broken down to one more function &amp;lt;i&amp;gt;assignment_grade_summary&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 2: Refactoring populate_hash_for_all_students_all_reviews&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The approach in this function is pretty straight forward when we try to break it down. It calculates,&lt;br /&gt;
&lt;br /&gt;
(a) The average score for each assignment for each course&lt;br /&gt;
&lt;br /&gt;
(b) The overall review grade for each assignment for all the students who have taken the course&lt;br /&gt;
&lt;br /&gt;
Passing the average score calculated from (a) checks if the student has teammates which could result in not having an average teammate_review_score. If we calculate (b) in our main function (this can be done) we would be repeating the checks that we are already doing for (a). Hence, this function is not changed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 3: Fix course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The current implementation ran into an issue when it was comparing the Key-Value pair passed in '''peer_review_score'''. It was hard to check if each of the keys were present or not. The proposed solution makes use of a basic hash value presence check that retrieves a value from the array/hash, given a set of keys. If no value is found, it'll return nil.&lt;br /&gt;
&lt;br /&gt;
==Proposed Implementation==&lt;br /&gt;
====Fixing the bug on course_student_grade_summary====&lt;br /&gt;
The current implementation of the method throws a nil error at the moment on the following line,&lt;br /&gt;
&amp;lt;pre&amp;gt;unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is rectified by introducing,&lt;br /&gt;
&amp;lt;pre&amp;gt;next if (peer_review_score[:review] &amp;amp;&amp;amp; peer_review_score[:review][:scores] &amp;amp;&amp;amp; peer_review_score[:review][:scores][:avg]).nil?&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Common refactoring of all_students_all_reviews and course_student_grade_summary method====&lt;br /&gt;
The functionality that the methods shared was that, both of them checked if there were course participants who had taken a particular course. This occupied 4 lines of code in both the functions. So, this is defined in a separate function called insure_existence_of and called from the two functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def insure_existence_of(course_participants)&lt;br /&gt;
    if course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Refactor all_students_all_reviews method====&lt;br /&gt;
The all_students_all_reviews method is one of the biggest methods in assessment360_controller.rb file. It finds the list of all students and assignments pertaining to the course. This data is then used to compute the metareview and teammate review scores for each student.&lt;br /&gt;
&lt;br /&gt;
The code before refactoring had 64 lines of code as shown below,&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   teammate_reviews,&lt;br /&gt;
                                                   @teammate_review,&lt;br /&gt;
                                                   @overall_teammate_review_grades,&lt;br /&gt;
                                                   @overall_teammate_review_count,&lt;br /&gt;
                                                   @teammate_review_info_per_stu)&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   meta_reviews,&lt;br /&gt;
                                                   @meta_review,&lt;br /&gt;
                                                   @overall_meta_review_grades,&lt;br /&gt;
                                                   @overall_meta_review_count,&lt;br /&gt;
                                                   @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      if @teammate_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @teammate_review_info_per_stu[0] * 1.0 / @teammate_review_info_per_stu[1]&lt;br /&gt;
        @teammate_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
      if @meta_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @meta_review_info_per_stu[0] * 1.0 / @meta_review_info_per_stu[1]&lt;br /&gt;
        @meta_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    @assignments.each do |assignment|&lt;br /&gt;
      temp_count = @overall_teammate_review_count[assignment.id]&lt;br /&gt;
      @overall_teammate_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = @overall_meta_review_count[assignment.id]&lt;br /&gt;
      @overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To calculate the average grade for each student on all assignments in this course that a student has taken in this course is refactoring in the base code by adding the avg_review_calc_per_student method. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def avg_review_calc_per_student(cp, review_info_per_stu, review)&lt;br /&gt;
    # check to see if the student has been given a review&lt;br /&gt;
    if review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
      temp_avg_grade = review_info_per_stu[0] * 1.0 / review_info_per_stu[1]&lt;br /&gt;
      review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To avoid a &amp;lt;i&amp;gt;divide by zero error&amp;lt;/i&amp;gt; that is thrown when we try to calculate the average grade when a student has no teammate is handled by the overall_review_count method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def overall_review_count(assignments, overall_teammate_review_count, overall_meta_review_count)&lt;br /&gt;
    assignments.each do |assignment|&lt;br /&gt;
      temp_count = overall_teammate_review_count[assignment.id]&lt;br /&gt;
      overall_review_count_hash[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = overall_meta_review_count[assignment.id]&lt;br /&gt;
      overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''After refactoring'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 teammate_reviews,&lt;br /&gt;
                                 @teammate_review,&lt;br /&gt;
                                 @overall_teammate_review_grades,&lt;br /&gt;
                                 @overall_teammate_review_count,&lt;br /&gt;
                                 @teammate_review_info_per_stu)&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 meta_reviews,&lt;br /&gt;
                                 @meta_review,&lt;br /&gt;
                                 @overall_meta_review_grades,&lt;br /&gt;
                                 @overall_meta_review_count,&lt;br /&gt;
                                 @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      avg_review_calc_per_student(cp, @teammate_review_info_per_stu, @teammate_review)&lt;br /&gt;
      avg_review_calc_per_student(cp, @meta_review_info_per_stu, @meta_review)&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    overall_review_count(@assignments, @overall_teammate_review_count, @overall_meta_review_count)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Refactor course_student_grade_summary method====&lt;br /&gt;
This method finds the list of all students and assignments pertaining to the course. The data obtained is then used to compute the instructor assigned grade and peer review scores. It was the secong biggest method in the assessment360_controller.rb controller file. The code before refactoring is shown below,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
&lt;br /&gt;
        # A topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
        topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
        @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
&lt;br /&gt;
        # Instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
        team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
        next if team_id.nil?&lt;br /&gt;
&lt;br /&gt;
        team = Team.find(team_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
&lt;br /&gt;
        # Set the assignment grade, peer review score, and sum for the final student summary&lt;br /&gt;
        @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
        unless @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
          @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&lt;br /&gt;
          @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&lt;br /&gt;
        end&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;
In this function, all the functionalities pertaining to a course participant - student in this case, in a given assignment is invoked by introducing a new method called assignment_grade_summary. This method checks if a topic exists and if it does, it passes the final grade that is calculated for that student in that course.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
    user_id = cp.user_id&lt;br /&gt;
    # topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
    topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
    @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
    # instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
    team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
    team = Team.find(team_id)&lt;br /&gt;
    @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
    return if @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
    @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
  end  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''After refactoring'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        # break out of the loop if there are no participants in the assignment&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
        # break out of the loop if the participant has no team&lt;br /&gt;
        next if TeamsUser.team_id(assignment_id, user_id).nil?&lt;br /&gt;
        # pull information about the student's grades for particular assignment&lt;br /&gt;
        assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
        #Skip if there are no peers&lt;br /&gt;
        next if peer_review_score.nil? &lt;br /&gt;
        #Skip if there are no reviews done by peers&lt;br /&gt;
        next if peer_review_score[:review].nil? &lt;br /&gt;
        #Skip if there are no reviews scores assigned by peers&lt;br /&gt;
        next if peer_review_score[:review][:scores].nil?&lt;br /&gt;
        #Skip if there are is no peer review average score&lt;br /&gt;
        next if peer_review_score[:review][:scores][:avg].nil?&lt;br /&gt;
        @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&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;
==Method name explanations==&lt;br /&gt;
One of the methods devised in this project is use nouns instead of verbs. Ideally the name of a variable or method should be enough to identify it's function in the class. This is because assessment_360 controller, of course is an exception and does explain what each of the functions do on their function names,&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; - Find the list of all students and assignments pertaining to the course. This data is used to compute the metareview and teammate review scores.&lt;br /&gt;
*&amp;lt;b&amp;gt;avg_review_calc_per_student&amp;lt;/b&amp;gt; - Calculate the overall average review grade that a student has gotten from their teammate(s) and instructor(s)&lt;br /&gt;
*&amp;lt;b&amp;gt;overall_review_count&amp;lt;/b&amp;gt; - To avoid divide by zero error&lt;br /&gt;
*&amp;lt;b&amp;gt;course_student_grade_summary&amp;lt;/b&amp;gt; - Find the list of all students and assignments pertaining to the course. This data is used to compute the instructor assigned grade and peer review scores.&lt;br /&gt;
*&amp;lt;b&amp;gt;assignment_grade_summary&amp;lt;/b&amp;gt; - To pull information about the student's grades for particular assignment&lt;br /&gt;
*&amp;lt;b&amp;gt;insure_existence_of&amp;lt;/b&amp;gt; - To make sure there are participants for the course&lt;br /&gt;
*&amp;lt;b&amp;gt;calc_overall_review_info&amp;lt;/b&amp;gt; - The function populates the hash value for all students for all the reviews that they have gotten. I.e., Teammate and Meta for each of the assignments that they have taken. This value is then used to display the overall teammate_review and meta_review grade in the view&lt;br /&gt;
*&amp;lt;b&amp;gt;find_peer_review_score&amp;lt;/b&amp;gt; - The peer review score is taken from the questions for the assignment&lt;br /&gt;
&lt;br /&gt;
==Testing==&lt;br /&gt;
===Test Plan===&lt;br /&gt;
&lt;br /&gt;
The main objective of improving the current Assessment 360 Controller testing is to make sure each of the functionalities are being looked into regardless of the test coverage because of the number of calculations that are actually being taken place inside the controller. In order to achieve this, tests were written for each newly added method in the controller. The first few tests have assumed to expect a normal condition i.e., a person exists and all other information do exist.&lt;br /&gt;
&lt;br /&gt;
===Test Cases===&lt;br /&gt;
The following test cases were made for the major methods added to the Assessment 360 Controller:&lt;br /&gt;
*&amp;lt;b&amp;gt;insure_existence_of&amp;lt;/b&amp;gt; &lt;br /&gt;
- Checking if the course participants are empty&amp;lt;br&amp;gt;&lt;br /&gt;
- Check if function redirects to back&amp;lt;br&amp;gt;&lt;br /&gt;
- Check if function flashes an error if it's not present&amp;lt;br&amp;gt;&lt;br /&gt;
- When method is called, it should check if there are course participants and redirects to back and flashes error if there are no participants&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;assignment_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
- Checking if the course participants are empty&amp;lt;br&amp;gt;&lt;br /&gt;
- Check if function redirects to back&amp;lt;br&amp;gt;&lt;br /&gt;
- Check if function flashes an error if it's not present&amp;lt;br&amp;gt;&lt;br /&gt;
- When method is called, it should check if there are course participants. When this passes, and when there are participants with team id, the total value returned for final grade should be valid&lt;br /&gt;
&lt;br /&gt;
===UI Testing===&lt;br /&gt;
By following the below steps, a reviewer can manually test the changes made to the Assessment 360 Controller.&lt;br /&gt;
&lt;br /&gt;
1. Visit [http://152.46.16.125:8080/ http://152.46.16.125:8080/] and enter the following credentials,&amp;lt;br&amp;gt;&lt;br /&gt;
   &amp;lt;b&amp;gt;Username:&amp;lt;/b&amp;gt; instructor6 &amp;lt;br&amp;gt;&lt;br /&gt;
   &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password&lt;br /&gt;
&lt;br /&gt;
2. From the menu bar, select Manage &amp;gt; Courses&lt;br /&gt;
&lt;br /&gt;
3. Scroll down to find the respective course, and select the blue globe icon. The page should load.&lt;br /&gt;
&lt;br /&gt;
4. Scroll down to find the respective course, and select the brown menu icon. The page should load.&lt;br /&gt;
&lt;br /&gt;
==Submission==&lt;br /&gt;
===Github Link===&lt;br /&gt;
&lt;br /&gt;
The changes made to the code is present on this [https://github.com/ramyananth/expertiza link]. Multiple comments and refactoring have been addressed in detail here.&lt;br /&gt;
&lt;br /&gt;
===Pull Request===&lt;br /&gt;
&lt;br /&gt;
The initial build made out of pull request [https://github.com/expertiza/expertiza/pull/1691 1691], kept failing continuously since it was made to the master branch of expertiza. It changed the Gemfile.lock and also the database schema. This push was actually made because the beta branch and master branch of expertiza were not different at all. The new pull request [https://github.com/expertiza/expertiza/pull/1713 1713] was made to the beta branch from our beta branch and it worked completely fine.&lt;br /&gt;
&lt;br /&gt;
==Team Information==&lt;br /&gt;
[mailto:rananth2@ncsu.edu Ramya Ananth] - [https://www.linkedin.com/in/ramyananth/ LinkedIn]&lt;br /&gt;
&lt;br /&gt;
[mailto:suppala@ncsu.edu Sri Harsha Varma Uppalapati] - [https://www.linkedin.com/in/sri-harsha-varma-uppalapati LinkedIn]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;[mailto:efg@ncsu.edu Mentor: Dr. Edward F Gehringer]&amp;lt;/b&amp;gt; - [https://www.ece.ncsu.edu/people/efg/ Website]&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
1.[https://github.com/expertiza/expertiza/ Expertiza on GitHub]&lt;br /&gt;
&lt;br /&gt;
2.[https://github.com/ramyananth/expertiza GitHub Project Repository Fork]&lt;br /&gt;
&lt;br /&gt;
3.[http://expertiza.ncsu.edu/ Live Expertiza website]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132639</id>
		<title>CSC/ECE 517 Spring 2020 - E2003. Refactor and improve assessment360 controller</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132639"/>
		<updated>2020-04-01T03:47:44Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: /* UI Testing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source project based on [http://rubyonrails.org/ Ruby on Rails] framework. The software allows the instructor and students with the following privileges,&lt;br /&gt;
&lt;br /&gt;
===Instructors===&lt;br /&gt;
* Create new assignments&lt;br /&gt;
* Customize new or existing assignments&lt;br /&gt;
* Create a list of topics that students can sign up for&lt;br /&gt;
* Give grades/reviews for the students' submissions&lt;br /&gt;
&lt;br /&gt;
===Students===&lt;br /&gt;
* Form teams with other students to work on various projects and assignments&lt;br /&gt;
* Peer review other students' submissions&lt;br /&gt;
&lt;br /&gt;
Note: Expertiza supports submissions across various document types, including URL and wiki pages&lt;br /&gt;
&lt;br /&gt;
==Project Description==&lt;br /&gt;
&lt;br /&gt;
===About assessment_360 Controller===&lt;br /&gt;
The assessment_360 controller is designed to gather data from all stakeholders about the performance of a student in a course. Thus, its purpose is to provide course-level statistics. At present, the controller provides only two top-level functions where each of them gives a list of students in the class. &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; contains teammate and meta-review scores received by students for all assignments in the course&lt;br /&gt;
* &amp;lt;b&amp;gt;course_student_grade_summary &amp;lt;/b&amp;gt; gives a listing of students and what topic they worked on and what grade they received on each assignment during the semester&lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The assessment360 controller had three major issues. This project is aimed to address some of them, including:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 1:&amp;lt;/b&amp;gt; Methods &amp;lt;i&amp;gt;all_students_all_reviews&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;course_student_grade_summary&amp;lt;/i&amp;gt; were too long. Common initialization and looping had to factored out by moving them into smaller methods with mnemonic names&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 2:&amp;lt;/b&amp;gt; Method populate_hash_for_all_students_all_reviews is not easy to understand. It uses a special data structure to do a very simple task. That had to be refactored&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 3:&amp;lt;/b&amp;gt; Method course_student_grade_summary stopped working and has to be fixed&lt;br /&gt;
&lt;br /&gt;
===Motivation===&lt;br /&gt;
This project aims at encouraging students to collaborate and contribute to open-source project in turn helping them understand what goes on in a full-fledged software deployment process. It also paves a way to understand how one can use Rails, RSpec to develop a system that does justice to the DRY code practicing principles.&lt;br /&gt;
&lt;br /&gt;
==Approach==&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 1: Refactoring all_students_all_reviews and course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(a) The common elements in these files i.e., checking if the course participant list is empty or not is moved to a different function called &amp;lt;i&amp;gt;inspect_course_participants&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(b) Adding on to this, all_student_all_review was broken down to two more functions, &amp;lt;i&amp;gt;avg_review_calc_per_student&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;overall_review_count&amp;lt;/i&amp;gt; &lt;br /&gt;
&lt;br /&gt;
(c) The method course_student_grade_summary is broken down to one more function &amp;lt;i&amp;gt;assignment_grade_summary&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 2: Refactoring populate_hash_for_all_students_all_reviews&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The approach in this function is pretty straight forward when we try to break it down. It calculates,&lt;br /&gt;
&lt;br /&gt;
(a) The average score for each assignment for each course&lt;br /&gt;
&lt;br /&gt;
(b) The overall review grade for each assignment for all the students who have taken the course&lt;br /&gt;
&lt;br /&gt;
Passing the average score calculated from (a) checks if the student has teammates which could result in not having an average teammate_review_score. If we calculate (b) in our main function (this can be done) we would be repeating the checks that we are already doing for (a). Hence, this function is not changed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 3: Fix course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The current implementation ran into an issue when it was comparing the Key-Value pair passed in '''peer_review_score'''. It was hard to check if each of the keys were present or not. The proposed solution makes use of a basic hash value presence check that retrieves a value from the array/hash, given a set of keys. If no value is found, it'll return nil.&lt;br /&gt;
&lt;br /&gt;
==Proposed Implementation==&lt;br /&gt;
====Fixing the bug on course_student_grade_summary====&lt;br /&gt;
The current implementation of the method throws a nil error at the moment on the following line,&lt;br /&gt;
&amp;lt;pre&amp;gt;unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is rectified by introducing,&lt;br /&gt;
&amp;lt;pre&amp;gt;next if (peer_review_score[:review] &amp;amp;&amp;amp; peer_review_score[:review][:scores] &amp;amp;&amp;amp; peer_review_score[:review][:scores][:avg]).nil?&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Common refactoring of all_students_all_reviews and course_student_grade_summary method====&lt;br /&gt;
The functionality that the methods shared was that, both of them checked if there were course participants who had taken a particular course. This occupied 4 lines of code in both the functions. So, this is defined in a separate function called insure_existence_of and called from the two functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def insure_existence_of(course_participants)&lt;br /&gt;
    if course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Refactor all_students_all_reviews method====&lt;br /&gt;
The all_students_all_reviews method is one of the biggest methods in assessment360_controller.rb file. It finds the list of all students and assignments pertaining to the course. This data is then used to compute the metareview and teammate review scores for each student.&lt;br /&gt;
&lt;br /&gt;
The code before refactoring had 64 lines of code as shown below,&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   teammate_reviews,&lt;br /&gt;
                                                   @teammate_review,&lt;br /&gt;
                                                   @overall_teammate_review_grades,&lt;br /&gt;
                                                   @overall_teammate_review_count,&lt;br /&gt;
                                                   @teammate_review_info_per_stu)&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   meta_reviews,&lt;br /&gt;
                                                   @meta_review,&lt;br /&gt;
                                                   @overall_meta_review_grades,&lt;br /&gt;
                                                   @overall_meta_review_count,&lt;br /&gt;
                                                   @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      if @teammate_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @teammate_review_info_per_stu[0] * 1.0 / @teammate_review_info_per_stu[1]&lt;br /&gt;
        @teammate_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
      if @meta_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @meta_review_info_per_stu[0] * 1.0 / @meta_review_info_per_stu[1]&lt;br /&gt;
        @meta_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    @assignments.each do |assignment|&lt;br /&gt;
      temp_count = @overall_teammate_review_count[assignment.id]&lt;br /&gt;
      @overall_teammate_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = @overall_meta_review_count[assignment.id]&lt;br /&gt;
      @overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To calculate the average grade for each student on all assignments in this course that a student has taken in this course is refactoring in the base code by adding the avg_review_calc_per_student method. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def avg_review_calc_per_student(cp, review_info_per_stu, review)&lt;br /&gt;
    # check to see if the student has been given a review&lt;br /&gt;
    if review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
      temp_avg_grade = review_info_per_stu[0] * 1.0 / review_info_per_stu[1]&lt;br /&gt;
      review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To avoid a &amp;lt;i&amp;gt;divide by zero error&amp;lt;/i&amp;gt; that is thrown when we try to calculate the average grade when a student has no teammate is handled by the overall_review_count method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def overall_review_count(assignments, overall_teammate_review_count, overall_meta_review_count)&lt;br /&gt;
    assignments.each do |assignment|&lt;br /&gt;
      temp_count = overall_teammate_review_count[assignment.id]&lt;br /&gt;
      overall_review_count_hash[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = overall_meta_review_count[assignment.id]&lt;br /&gt;
      overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''After refactoring'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 teammate_reviews,&lt;br /&gt;
                                 @teammate_review,&lt;br /&gt;
                                 @overall_teammate_review_grades,&lt;br /&gt;
                                 @overall_teammate_review_count,&lt;br /&gt;
                                 @teammate_review_info_per_stu)&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 meta_reviews,&lt;br /&gt;
                                 @meta_review,&lt;br /&gt;
                                 @overall_meta_review_grades,&lt;br /&gt;
                                 @overall_meta_review_count,&lt;br /&gt;
                                 @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      avg_review_calc_per_student(cp, @teammate_review_info_per_stu, @teammate_review)&lt;br /&gt;
      avg_review_calc_per_student(cp, @meta_review_info_per_stu, @meta_review)&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    overall_review_count(@assignments, @overall_teammate_review_count, @overall_meta_review_count)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Refactor course_student_grade_summary method====&lt;br /&gt;
This method finds the list of all students and assignments pertaining to the course. The data obtained is then used to compute the instructor assigned grade and peer review scores. It was the secong biggest method in the assessment360_controller.rb controller file. The code before refactoring is shown below,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
&lt;br /&gt;
        # A topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
        topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
        @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
&lt;br /&gt;
        # Instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
        team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
        next if team_id.nil?&lt;br /&gt;
&lt;br /&gt;
        team = Team.find(team_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
&lt;br /&gt;
        # Set the assignment grade, peer review score, and sum for the final student summary&lt;br /&gt;
        @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
        unless @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
          @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&lt;br /&gt;
          @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&lt;br /&gt;
        end&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;
In this function, all the functionalities pertaining to a course participant - student in this case, in a given assignment is invoked by introducing a new method called assignment_grade_summary. This method checks if a topic exists and if it does, it passes the final grade that is calculated for that student in that course.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
    user_id = cp.user_id&lt;br /&gt;
    # topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
    topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
    @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
    # instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
    team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
    team = Team.find(team_id)&lt;br /&gt;
    @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
    return if @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
    @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
  end  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''After refactoring'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        # break out of the loop if there are no participants in the assignment&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
        # break out of the loop if the participant has no team&lt;br /&gt;
        next if TeamsUser.team_id(assignment_id, user_id).nil?&lt;br /&gt;
        # pull information about the student's grades for particular assignment&lt;br /&gt;
        assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
        #Skip if there are no peers&lt;br /&gt;
        next if peer_review_score.nil? &lt;br /&gt;
        #Skip if there are no reviews done by peers&lt;br /&gt;
        next if peer_review_score[:review].nil? &lt;br /&gt;
        #Skip if there are no reviews scores assigned by peers&lt;br /&gt;
        next if peer_review_score[:review][:scores].nil?&lt;br /&gt;
        #Skip if there are is no peer review average score&lt;br /&gt;
        next if peer_review_score[:review][:scores][:avg].nil?&lt;br /&gt;
        @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&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;
==Method name explanations==&lt;br /&gt;
One of the methods devised in this project is use nouns instead of verbs. Ideally the name of a variable or method should be enough to identify it's function in the class. This is because assessment_360 controller, of course is an exception and does explain what each of the functions do on their function names,&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; - Find the list of all students and assignments pertaining to the course. This data is used to compute the metareview and teammate review scores.&lt;br /&gt;
*&amp;lt;b&amp;gt;avg_review_calc_per_student&amp;lt;/b&amp;gt; - Calculate the overall average review grade that a student has gotten from their teammate(s) and instructor(s)&lt;br /&gt;
*&amp;lt;b&amp;gt;overall_review_count&amp;lt;/b&amp;gt; - To avoid divide by zero error&lt;br /&gt;
*&amp;lt;b&amp;gt;course_student_grade_summary&amp;lt;/b&amp;gt; - Find the list of all students and assignments pertaining to the course. This data is used to compute the instructor assigned grade and peer review scores.&lt;br /&gt;
*&amp;lt;b&amp;gt;assignment_grade_summary&amp;lt;/b&amp;gt; - To pull information about the student's grades for particular assignment&lt;br /&gt;
*&amp;lt;b&amp;gt;insure_existence_of&amp;lt;/b&amp;gt; - To make sure there are participants for the course&lt;br /&gt;
*&amp;lt;b&amp;gt;calc_overall_review_info&amp;lt;/b&amp;gt; - The function populates the hash value for all students for all the reviews that they have gotten. I.e., Teammate and Meta for each of the assignments that they have taken. This value is then used to display the overall teammate_review and meta_review grade in the view&lt;br /&gt;
*&amp;lt;b&amp;gt;find_peer_review_score&amp;lt;/b&amp;gt; - The peer review score is taken from the questions for the assignment&lt;br /&gt;
&lt;br /&gt;
==Testing==&lt;br /&gt;
===Test Plan===&lt;br /&gt;
&lt;br /&gt;
The main objective of improving the current Assessment 360 Controller testing is to make sure each of the functionalities are being looked into regardless of the test coverage because of the number of calculations that are actually being taken place inside the controller. In order to achieve this, tests were written for each newly added method in the controller. The first few tests have assumed to expect a normal condition i.e., a person exists and all other information do exist.&lt;br /&gt;
&lt;br /&gt;
===Test Cases===&lt;br /&gt;
The following test cases were made for each respective methods added to the Assessment 360 Controller:&lt;br /&gt;
&lt;br /&gt;
===UI Testing===&lt;br /&gt;
By following the below steps, a reviewer can manually test the changes made to the Assessment 360 Controller.&lt;br /&gt;
&lt;br /&gt;
1. Visit [http://152.46.16.125:8080/ http://152.46.16.125:8080/] and enter the following credentials,&amp;lt;br&amp;gt;&lt;br /&gt;
   &amp;lt;b&amp;gt;Username:&amp;lt;/b&amp;gt; instructor6 &amp;lt;br&amp;gt;&lt;br /&gt;
   &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password&lt;br /&gt;
&lt;br /&gt;
2. From the menu bar, select Manage &amp;gt; Courses&lt;br /&gt;
&lt;br /&gt;
3. Scroll down to find the respective course, and select the blue globe icon. The page should load.&lt;br /&gt;
&lt;br /&gt;
4. Scroll down to find the respective course, and select the brown menu icon. The page should load.&lt;br /&gt;
&lt;br /&gt;
==Submission==&lt;br /&gt;
===Github Link===&lt;br /&gt;
&lt;br /&gt;
The changes made to the code is present on this [https://github.com/ramyananth/expertiza link]. Multiple comments and refactoring have been addressed in detail here.&lt;br /&gt;
&lt;br /&gt;
===Pull Request===&lt;br /&gt;
&lt;br /&gt;
The initial build made out of pull request [https://github.com/expertiza/expertiza/pull/1691 1691], kept failing continuously since it was made to the master branch of expertiza. It changed the Gemfile.lock and also the database schema. This push was actually made because the beta branch and master branch of expertiza were not different at all. The new pull request [https://github.com/expertiza/expertiza/pull/1713 1713] was made to the beta branch from our beta branch and it worked completely fine.&lt;br /&gt;
&lt;br /&gt;
==Team Information==&lt;br /&gt;
[mailto:rananth2@ncsu.edu Ramya Ananth] - [https://www.linkedin.com/in/ramyananth/ LinkedIn]&lt;br /&gt;
&lt;br /&gt;
[mailto:suppala@ncsu.edu Sri Harsha Varma Uppalapati] - [https://www.linkedin.com/in/sri-harsha-varma-uppalapati LinkedIn]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;[mailto:efg@ncsu.edu Mentor: Dr. Edward F Gehringer]&amp;lt;/b&amp;gt; - [https://www.ece.ncsu.edu/people/efg/ Website]&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
1.[https://github.com/expertiza/expertiza/ Expertiza on GitHub]&lt;br /&gt;
&lt;br /&gt;
2.[https://github.com/ramyananth/expertiza GitHub Project Repository Fork]&lt;br /&gt;
&lt;br /&gt;
3.[http://expertiza.ncsu.edu/ Live Expertiza website]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132638</id>
		<title>CSC/ECE 517 Spring 2020 - E2003. Refactor and improve assessment360 controller</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132638"/>
		<updated>2020-04-01T03:46:50Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: /* UI Testing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source project based on [http://rubyonrails.org/ Ruby on Rails] framework. The software allows the instructor and students with the following privileges,&lt;br /&gt;
&lt;br /&gt;
===Instructors===&lt;br /&gt;
* Create new assignments&lt;br /&gt;
* Customize new or existing assignments&lt;br /&gt;
* Create a list of topics that students can sign up for&lt;br /&gt;
* Give grades/reviews for the students' submissions&lt;br /&gt;
&lt;br /&gt;
===Students===&lt;br /&gt;
* Form teams with other students to work on various projects and assignments&lt;br /&gt;
* Peer review other students' submissions&lt;br /&gt;
&lt;br /&gt;
Note: Expertiza supports submissions across various document types, including URL and wiki pages&lt;br /&gt;
&lt;br /&gt;
==Project Description==&lt;br /&gt;
&lt;br /&gt;
===About assessment_360 Controller===&lt;br /&gt;
The assessment_360 controller is designed to gather data from all stakeholders about the performance of a student in a course. Thus, its purpose is to provide course-level statistics. At present, the controller provides only two top-level functions where each of them gives a list of students in the class. &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; contains teammate and meta-review scores received by students for all assignments in the course&lt;br /&gt;
* &amp;lt;b&amp;gt;course_student_grade_summary &amp;lt;/b&amp;gt; gives a listing of students and what topic they worked on and what grade they received on each assignment during the semester&lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The assessment360 controller had three major issues. This project is aimed to address some of them, including:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 1:&amp;lt;/b&amp;gt; Methods &amp;lt;i&amp;gt;all_students_all_reviews&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;course_student_grade_summary&amp;lt;/i&amp;gt; were too long. Common initialization and looping had to factored out by moving them into smaller methods with mnemonic names&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 2:&amp;lt;/b&amp;gt; Method populate_hash_for_all_students_all_reviews is not easy to understand. It uses a special data structure to do a very simple task. That had to be refactored&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 3:&amp;lt;/b&amp;gt; Method course_student_grade_summary stopped working and has to be fixed&lt;br /&gt;
&lt;br /&gt;
===Motivation===&lt;br /&gt;
This project aims at encouraging students to collaborate and contribute to open-source project in turn helping them understand what goes on in a full-fledged software deployment process. It also paves a way to understand how one can use Rails, RSpec to develop a system that does justice to the DRY code practicing principles.&lt;br /&gt;
&lt;br /&gt;
==Approach==&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 1: Refactoring all_students_all_reviews and course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(a) The common elements in these files i.e., checking if the course participant list is empty or not is moved to a different function called &amp;lt;i&amp;gt;inspect_course_participants&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(b) Adding on to this, all_student_all_review was broken down to two more functions, &amp;lt;i&amp;gt;avg_review_calc_per_student&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;overall_review_count&amp;lt;/i&amp;gt; &lt;br /&gt;
&lt;br /&gt;
(c) The method course_student_grade_summary is broken down to one more function &amp;lt;i&amp;gt;assignment_grade_summary&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 2: Refactoring populate_hash_for_all_students_all_reviews&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The approach in this function is pretty straight forward when we try to break it down. It calculates,&lt;br /&gt;
&lt;br /&gt;
(a) The average score for each assignment for each course&lt;br /&gt;
&lt;br /&gt;
(b) The overall review grade for each assignment for all the students who have taken the course&lt;br /&gt;
&lt;br /&gt;
Passing the average score calculated from (a) checks if the student has teammates which could result in not having an average teammate_review_score. If we calculate (b) in our main function (this can be done) we would be repeating the checks that we are already doing for (a). Hence, this function is not changed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 3: Fix course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The current implementation ran into an issue when it was comparing the Key-Value pair passed in '''peer_review_score'''. It was hard to check if each of the keys were present or not. The proposed solution makes use of a basic hash value presence check that retrieves a value from the array/hash, given a set of keys. If no value is found, it'll return nil.&lt;br /&gt;
&lt;br /&gt;
==Proposed Implementation==&lt;br /&gt;
====Fixing the bug on course_student_grade_summary====&lt;br /&gt;
The current implementation of the method throws a nil error at the moment on the following line,&lt;br /&gt;
&amp;lt;pre&amp;gt;unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is rectified by introducing,&lt;br /&gt;
&amp;lt;pre&amp;gt;next if (peer_review_score[:review] &amp;amp;&amp;amp; peer_review_score[:review][:scores] &amp;amp;&amp;amp; peer_review_score[:review][:scores][:avg]).nil?&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Common refactoring of all_students_all_reviews and course_student_grade_summary method====&lt;br /&gt;
The functionality that the methods shared was that, both of them checked if there were course participants who had taken a particular course. This occupied 4 lines of code in both the functions. So, this is defined in a separate function called insure_existence_of and called from the two functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def insure_existence_of(course_participants)&lt;br /&gt;
    if course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Refactor all_students_all_reviews method====&lt;br /&gt;
The all_students_all_reviews method is one of the biggest methods in assessment360_controller.rb file. It finds the list of all students and assignments pertaining to the course. This data is then used to compute the metareview and teammate review scores for each student.&lt;br /&gt;
&lt;br /&gt;
The code before refactoring had 64 lines of code as shown below,&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   teammate_reviews,&lt;br /&gt;
                                                   @teammate_review,&lt;br /&gt;
                                                   @overall_teammate_review_grades,&lt;br /&gt;
                                                   @overall_teammate_review_count,&lt;br /&gt;
                                                   @teammate_review_info_per_stu)&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   meta_reviews,&lt;br /&gt;
                                                   @meta_review,&lt;br /&gt;
                                                   @overall_meta_review_grades,&lt;br /&gt;
                                                   @overall_meta_review_count,&lt;br /&gt;
                                                   @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      if @teammate_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @teammate_review_info_per_stu[0] * 1.0 / @teammate_review_info_per_stu[1]&lt;br /&gt;
        @teammate_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
      if @meta_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @meta_review_info_per_stu[0] * 1.0 / @meta_review_info_per_stu[1]&lt;br /&gt;
        @meta_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    @assignments.each do |assignment|&lt;br /&gt;
      temp_count = @overall_teammate_review_count[assignment.id]&lt;br /&gt;
      @overall_teammate_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = @overall_meta_review_count[assignment.id]&lt;br /&gt;
      @overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To calculate the average grade for each student on all assignments in this course that a student has taken in this course is refactoring in the base code by adding the avg_review_calc_per_student method. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def avg_review_calc_per_student(cp, review_info_per_stu, review)&lt;br /&gt;
    # check to see if the student has been given a review&lt;br /&gt;
    if review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
      temp_avg_grade = review_info_per_stu[0] * 1.0 / review_info_per_stu[1]&lt;br /&gt;
      review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To avoid a &amp;lt;i&amp;gt;divide by zero error&amp;lt;/i&amp;gt; that is thrown when we try to calculate the average grade when a student has no teammate is handled by the overall_review_count method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def overall_review_count(assignments, overall_teammate_review_count, overall_meta_review_count)&lt;br /&gt;
    assignments.each do |assignment|&lt;br /&gt;
      temp_count = overall_teammate_review_count[assignment.id]&lt;br /&gt;
      overall_review_count_hash[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = overall_meta_review_count[assignment.id]&lt;br /&gt;
      overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''After refactoring'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 teammate_reviews,&lt;br /&gt;
                                 @teammate_review,&lt;br /&gt;
                                 @overall_teammate_review_grades,&lt;br /&gt;
                                 @overall_teammate_review_count,&lt;br /&gt;
                                 @teammate_review_info_per_stu)&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 meta_reviews,&lt;br /&gt;
                                 @meta_review,&lt;br /&gt;
                                 @overall_meta_review_grades,&lt;br /&gt;
                                 @overall_meta_review_count,&lt;br /&gt;
                                 @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      avg_review_calc_per_student(cp, @teammate_review_info_per_stu, @teammate_review)&lt;br /&gt;
      avg_review_calc_per_student(cp, @meta_review_info_per_stu, @meta_review)&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    overall_review_count(@assignments, @overall_teammate_review_count, @overall_meta_review_count)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Refactor course_student_grade_summary method====&lt;br /&gt;
This method finds the list of all students and assignments pertaining to the course. The data obtained is then used to compute the instructor assigned grade and peer review scores. It was the secong biggest method in the assessment360_controller.rb controller file. The code before refactoring is shown below,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
&lt;br /&gt;
        # A topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
        topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
        @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
&lt;br /&gt;
        # Instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
        team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
        next if team_id.nil?&lt;br /&gt;
&lt;br /&gt;
        team = Team.find(team_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
&lt;br /&gt;
        # Set the assignment grade, peer review score, and sum for the final student summary&lt;br /&gt;
        @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
        unless @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
          @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&lt;br /&gt;
          @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&lt;br /&gt;
        end&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;
In this function, all the functionalities pertaining to a course participant - student in this case, in a given assignment is invoked by introducing a new method called assignment_grade_summary. This method checks if a topic exists and if it does, it passes the final grade that is calculated for that student in that course.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
    user_id = cp.user_id&lt;br /&gt;
    # topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
    topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
    @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
    # instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
    team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
    team = Team.find(team_id)&lt;br /&gt;
    @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
    return if @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
    @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
  end  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''After refactoring'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        # break out of the loop if there are no participants in the assignment&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
        # break out of the loop if the participant has no team&lt;br /&gt;
        next if TeamsUser.team_id(assignment_id, user_id).nil?&lt;br /&gt;
        # pull information about the student's grades for particular assignment&lt;br /&gt;
        assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
        #Skip if there are no peers&lt;br /&gt;
        next if peer_review_score.nil? &lt;br /&gt;
        #Skip if there are no reviews done by peers&lt;br /&gt;
        next if peer_review_score[:review].nil? &lt;br /&gt;
        #Skip if there are no reviews scores assigned by peers&lt;br /&gt;
        next if peer_review_score[:review][:scores].nil?&lt;br /&gt;
        #Skip if there are is no peer review average score&lt;br /&gt;
        next if peer_review_score[:review][:scores][:avg].nil?&lt;br /&gt;
        @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&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;
==Method name explanations==&lt;br /&gt;
One of the methods devised in this project is use nouns instead of verbs. Ideally the name of a variable or method should be enough to identify it's function in the class. This is because assessment_360 controller, of course is an exception and does explain what each of the functions do on their function names,&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; - Find the list of all students and assignments pertaining to the course. This data is used to compute the metareview and teammate review scores.&lt;br /&gt;
*&amp;lt;b&amp;gt;avg_review_calc_per_student&amp;lt;/b&amp;gt; - Calculate the overall average review grade that a student has gotten from their teammate(s) and instructor(s)&lt;br /&gt;
*&amp;lt;b&amp;gt;overall_review_count&amp;lt;/b&amp;gt; - To avoid divide by zero error&lt;br /&gt;
*&amp;lt;b&amp;gt;course_student_grade_summary&amp;lt;/b&amp;gt; - Find the list of all students and assignments pertaining to the course. This data is used to compute the instructor assigned grade and peer review scores.&lt;br /&gt;
*&amp;lt;b&amp;gt;assignment_grade_summary&amp;lt;/b&amp;gt; - To pull information about the student's grades for particular assignment&lt;br /&gt;
*&amp;lt;b&amp;gt;insure_existence_of&amp;lt;/b&amp;gt; - To make sure there are participants for the course&lt;br /&gt;
*&amp;lt;b&amp;gt;calc_overall_review_info&amp;lt;/b&amp;gt; - The function populates the hash value for all students for all the reviews that they have gotten. I.e., Teammate and Meta for each of the assignments that they have taken. This value is then used to display the overall teammate_review and meta_review grade in the view&lt;br /&gt;
*&amp;lt;b&amp;gt;find_peer_review_score&amp;lt;/b&amp;gt; - The peer review score is taken from the questions for the assignment&lt;br /&gt;
&lt;br /&gt;
==Testing==&lt;br /&gt;
===Test Plan===&lt;br /&gt;
&lt;br /&gt;
The main objective of improving the current Assessment 360 Controller testing is to make sure each of the functionalities are being looked into regardless of the test coverage because of the number of calculations that are actually being taken place inside the controller. In order to achieve this, tests were written for each newly added method in the controller. The first few tests have assumed to expect a normal condition i.e., a person exists and all other information do exist.&lt;br /&gt;
&lt;br /&gt;
===Test Cases===&lt;br /&gt;
The following test cases were made for each respective methods added to the Assessment 360 Controller:&lt;br /&gt;
&lt;br /&gt;
===UI Testing===&lt;br /&gt;
By following the below steps, a reviewer can manually test the changes made to the Assessment 360 Controller.&lt;br /&gt;
&lt;br /&gt;
1. Visit [http://152.46.16.125:8080/ http://152.46.16.125:8080/] and enter the following credentials,&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;Username:&amp;lt;/b&amp;gt;instructor6 &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt;password&lt;br /&gt;
&lt;br /&gt;
2. From the menu bar, select Manage &amp;gt; Courses&lt;br /&gt;
&lt;br /&gt;
3. Scroll down to find the respective course, and select the blue globe icon. The page should load.&lt;br /&gt;
&lt;br /&gt;
4. Scroll down to find the respective course, and select the brown menu icon. The page should load.&lt;br /&gt;
&lt;br /&gt;
==Submission==&lt;br /&gt;
===Github Link===&lt;br /&gt;
&lt;br /&gt;
The changes made to the code is present on this [https://github.com/ramyananth/expertiza link]. Multiple comments and refactoring have been addressed in detail here.&lt;br /&gt;
&lt;br /&gt;
===Pull Request===&lt;br /&gt;
&lt;br /&gt;
The initial build made out of pull request [https://github.com/expertiza/expertiza/pull/1691 1691], kept failing continuously since it was made to the master branch of expertiza. It changed the Gemfile.lock and also the database schema. This push was actually made because the beta branch and master branch of expertiza were not different at all. The new pull request [https://github.com/expertiza/expertiza/pull/1713 1713] was made to the beta branch from our beta branch and it worked completely fine.&lt;br /&gt;
&lt;br /&gt;
==Team Information==&lt;br /&gt;
[mailto:rananth2@ncsu.edu Ramya Ananth] - [https://www.linkedin.com/in/ramyananth/ LinkedIn]&lt;br /&gt;
&lt;br /&gt;
[mailto:suppala@ncsu.edu Sri Harsha Varma Uppalapati] - [https://www.linkedin.com/in/sri-harsha-varma-uppalapati LinkedIn]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;[mailto:efg@ncsu.edu Mentor: Dr. Edward F Gehringer]&amp;lt;/b&amp;gt; - [https://www.ece.ncsu.edu/people/efg/ Website]&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
1.[https://github.com/expertiza/expertiza/ Expertiza on GitHub]&lt;br /&gt;
&lt;br /&gt;
2.[https://github.com/ramyananth/expertiza GitHub Project Repository Fork]&lt;br /&gt;
&lt;br /&gt;
3.[http://expertiza.ncsu.edu/ Live Expertiza website]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Menu.PNG&amp;diff=132637</id>
		<title>File:Menu.PNG</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Menu.PNG&amp;diff=132637"/>
		<updated>2020-04-01T03:44:51Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Globe.PNG&amp;diff=132636</id>
		<title>File:Globe.PNG</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Globe.PNG&amp;diff=132636"/>
		<updated>2020-04-01T03:44:06Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132635</id>
		<title>CSC/ECE 517 Spring 2020 - E2003. Refactor and improve assessment360 controller</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132635"/>
		<updated>2020-04-01T03:43:29Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: /* Submission */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source project based on [http://rubyonrails.org/ Ruby on Rails] framework. The software allows the instructor and students with the following privileges,&lt;br /&gt;
&lt;br /&gt;
===Instructors===&lt;br /&gt;
* Create new assignments&lt;br /&gt;
* Customize new or existing assignments&lt;br /&gt;
* Create a list of topics that students can sign up for&lt;br /&gt;
* Give grades/reviews for the students' submissions&lt;br /&gt;
&lt;br /&gt;
===Students===&lt;br /&gt;
* Form teams with other students to work on various projects and assignments&lt;br /&gt;
* Peer review other students' submissions&lt;br /&gt;
&lt;br /&gt;
Note: Expertiza supports submissions across various document types, including URL and wiki pages&lt;br /&gt;
&lt;br /&gt;
==Project Description==&lt;br /&gt;
&lt;br /&gt;
===About assessment_360 Controller===&lt;br /&gt;
The assessment_360 controller is designed to gather data from all stakeholders about the performance of a student in a course. Thus, its purpose is to provide course-level statistics. At present, the controller provides only two top-level functions where each of them gives a list of students in the class. &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; contains teammate and meta-review scores received by students for all assignments in the course&lt;br /&gt;
* &amp;lt;b&amp;gt;course_student_grade_summary &amp;lt;/b&amp;gt; gives a listing of students and what topic they worked on and what grade they received on each assignment during the semester&lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The assessment360 controller had three major issues. This project is aimed to address some of them, including:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 1:&amp;lt;/b&amp;gt; Methods &amp;lt;i&amp;gt;all_students_all_reviews&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;course_student_grade_summary&amp;lt;/i&amp;gt; were too long. Common initialization and looping had to factored out by moving them into smaller methods with mnemonic names&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 2:&amp;lt;/b&amp;gt; Method populate_hash_for_all_students_all_reviews is not easy to understand. It uses a special data structure to do a very simple task. That had to be refactored&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 3:&amp;lt;/b&amp;gt; Method course_student_grade_summary stopped working and has to be fixed&lt;br /&gt;
&lt;br /&gt;
===Motivation===&lt;br /&gt;
This project aims at encouraging students to collaborate and contribute to open-source project in turn helping them understand what goes on in a full-fledged software deployment process. It also paves a way to understand how one can use Rails, RSpec to develop a system that does justice to the DRY code practicing principles.&lt;br /&gt;
&lt;br /&gt;
==Approach==&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 1: Refactoring all_students_all_reviews and course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(a) The common elements in these files i.e., checking if the course participant list is empty or not is moved to a different function called &amp;lt;i&amp;gt;inspect_course_participants&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(b) Adding on to this, all_student_all_review was broken down to two more functions, &amp;lt;i&amp;gt;avg_review_calc_per_student&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;overall_review_count&amp;lt;/i&amp;gt; &lt;br /&gt;
&lt;br /&gt;
(c) The method course_student_grade_summary is broken down to one more function &amp;lt;i&amp;gt;assignment_grade_summary&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 2: Refactoring populate_hash_for_all_students_all_reviews&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The approach in this function is pretty straight forward when we try to break it down. It calculates,&lt;br /&gt;
&lt;br /&gt;
(a) The average score for each assignment for each course&lt;br /&gt;
&lt;br /&gt;
(b) The overall review grade for each assignment for all the students who have taken the course&lt;br /&gt;
&lt;br /&gt;
Passing the average score calculated from (a) checks if the student has teammates which could result in not having an average teammate_review_score. If we calculate (b) in our main function (this can be done) we would be repeating the checks that we are already doing for (a). Hence, this function is not changed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 3: Fix course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The current implementation ran into an issue when it was comparing the Key-Value pair passed in '''peer_review_score'''. It was hard to check if each of the keys were present or not. The proposed solution makes use of a basic hash value presence check that retrieves a value from the array/hash, given a set of keys. If no value is found, it'll return nil.&lt;br /&gt;
&lt;br /&gt;
==Proposed Implementation==&lt;br /&gt;
====Fixing the bug on course_student_grade_summary====&lt;br /&gt;
The current implementation of the method throws a nil error at the moment on the following line,&lt;br /&gt;
&amp;lt;pre&amp;gt;unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is rectified by introducing,&lt;br /&gt;
&amp;lt;pre&amp;gt;next if (peer_review_score[:review] &amp;amp;&amp;amp; peer_review_score[:review][:scores] &amp;amp;&amp;amp; peer_review_score[:review][:scores][:avg]).nil?&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Common refactoring of all_students_all_reviews and course_student_grade_summary method====&lt;br /&gt;
The functionality that the methods shared was that, both of them checked if there were course participants who had taken a particular course. This occupied 4 lines of code in both the functions. So, this is defined in a separate function called insure_existence_of and called from the two functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def insure_existence_of(course_participants)&lt;br /&gt;
    if course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Refactor all_students_all_reviews method====&lt;br /&gt;
The all_students_all_reviews method is one of the biggest methods in assessment360_controller.rb file. It finds the list of all students and assignments pertaining to the course. This data is then used to compute the metareview and teammate review scores for each student.&lt;br /&gt;
&lt;br /&gt;
The code before refactoring had 64 lines of code as shown below,&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   teammate_reviews,&lt;br /&gt;
                                                   @teammate_review,&lt;br /&gt;
                                                   @overall_teammate_review_grades,&lt;br /&gt;
                                                   @overall_teammate_review_count,&lt;br /&gt;
                                                   @teammate_review_info_per_stu)&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   meta_reviews,&lt;br /&gt;
                                                   @meta_review,&lt;br /&gt;
                                                   @overall_meta_review_grades,&lt;br /&gt;
                                                   @overall_meta_review_count,&lt;br /&gt;
                                                   @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      if @teammate_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @teammate_review_info_per_stu[0] * 1.0 / @teammate_review_info_per_stu[1]&lt;br /&gt;
        @teammate_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
      if @meta_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @meta_review_info_per_stu[0] * 1.0 / @meta_review_info_per_stu[1]&lt;br /&gt;
        @meta_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    @assignments.each do |assignment|&lt;br /&gt;
      temp_count = @overall_teammate_review_count[assignment.id]&lt;br /&gt;
      @overall_teammate_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = @overall_meta_review_count[assignment.id]&lt;br /&gt;
      @overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To calculate the average grade for each student on all assignments in this course that a student has taken in this course is refactoring in the base code by adding the avg_review_calc_per_student method. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def avg_review_calc_per_student(cp, review_info_per_stu, review)&lt;br /&gt;
    # check to see if the student has been given a review&lt;br /&gt;
    if review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
      temp_avg_grade = review_info_per_stu[0] * 1.0 / review_info_per_stu[1]&lt;br /&gt;
      review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To avoid a &amp;lt;i&amp;gt;divide by zero error&amp;lt;/i&amp;gt; that is thrown when we try to calculate the average grade when a student has no teammate is handled by the overall_review_count method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def overall_review_count(assignments, overall_teammate_review_count, overall_meta_review_count)&lt;br /&gt;
    assignments.each do |assignment|&lt;br /&gt;
      temp_count = overall_teammate_review_count[assignment.id]&lt;br /&gt;
      overall_review_count_hash[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = overall_meta_review_count[assignment.id]&lt;br /&gt;
      overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''After refactoring'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 teammate_reviews,&lt;br /&gt;
                                 @teammate_review,&lt;br /&gt;
                                 @overall_teammate_review_grades,&lt;br /&gt;
                                 @overall_teammate_review_count,&lt;br /&gt;
                                 @teammate_review_info_per_stu)&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 meta_reviews,&lt;br /&gt;
                                 @meta_review,&lt;br /&gt;
                                 @overall_meta_review_grades,&lt;br /&gt;
                                 @overall_meta_review_count,&lt;br /&gt;
                                 @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      avg_review_calc_per_student(cp, @teammate_review_info_per_stu, @teammate_review)&lt;br /&gt;
      avg_review_calc_per_student(cp, @meta_review_info_per_stu, @meta_review)&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    overall_review_count(@assignments, @overall_teammate_review_count, @overall_meta_review_count)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Refactor course_student_grade_summary method====&lt;br /&gt;
This method finds the list of all students and assignments pertaining to the course. The data obtained is then used to compute the instructor assigned grade and peer review scores. It was the secong biggest method in the assessment360_controller.rb controller file. The code before refactoring is shown below,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
&lt;br /&gt;
        # A topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
        topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
        @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
&lt;br /&gt;
        # Instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
        team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
        next if team_id.nil?&lt;br /&gt;
&lt;br /&gt;
        team = Team.find(team_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
&lt;br /&gt;
        # Set the assignment grade, peer review score, and sum for the final student summary&lt;br /&gt;
        @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
        unless @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
          @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&lt;br /&gt;
          @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&lt;br /&gt;
        end&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;
In this function, all the functionalities pertaining to a course participant - student in this case, in a given assignment is invoked by introducing a new method called assignment_grade_summary. This method checks if a topic exists and if it does, it passes the final grade that is calculated for that student in that course.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
    user_id = cp.user_id&lt;br /&gt;
    # topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
    topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
    @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
    # instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
    team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
    team = Team.find(team_id)&lt;br /&gt;
    @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
    return if @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
    @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
  end  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''After refactoring'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        # break out of the loop if there are no participants in the assignment&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
        # break out of the loop if the participant has no team&lt;br /&gt;
        next if TeamsUser.team_id(assignment_id, user_id).nil?&lt;br /&gt;
        # pull information about the student's grades for particular assignment&lt;br /&gt;
        assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
        #Skip if there are no peers&lt;br /&gt;
        next if peer_review_score.nil? &lt;br /&gt;
        #Skip if there are no reviews done by peers&lt;br /&gt;
        next if peer_review_score[:review].nil? &lt;br /&gt;
        #Skip if there are no reviews scores assigned by peers&lt;br /&gt;
        next if peer_review_score[:review][:scores].nil?&lt;br /&gt;
        #Skip if there are is no peer review average score&lt;br /&gt;
        next if peer_review_score[:review][:scores][:avg].nil?&lt;br /&gt;
        @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&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;
==Method name explanations==&lt;br /&gt;
One of the methods devised in this project is use nouns instead of verbs. Ideally the name of a variable or method should be enough to identify it's function in the class. This is because assessment_360 controller, of course is an exception and does explain what each of the functions do on their function names,&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; - Find the list of all students and assignments pertaining to the course. This data is used to compute the metareview and teammate review scores.&lt;br /&gt;
*&amp;lt;b&amp;gt;avg_review_calc_per_student&amp;lt;/b&amp;gt; - Calculate the overall average review grade that a student has gotten from their teammate(s) and instructor(s)&lt;br /&gt;
*&amp;lt;b&amp;gt;overall_review_count&amp;lt;/b&amp;gt; - To avoid divide by zero error&lt;br /&gt;
*&amp;lt;b&amp;gt;course_student_grade_summary&amp;lt;/b&amp;gt; - Find the list of all students and assignments pertaining to the course. This data is used to compute the instructor assigned grade and peer review scores.&lt;br /&gt;
*&amp;lt;b&amp;gt;assignment_grade_summary&amp;lt;/b&amp;gt; - To pull information about the student's grades for particular assignment&lt;br /&gt;
*&amp;lt;b&amp;gt;insure_existence_of&amp;lt;/b&amp;gt; - To make sure there are participants for the course&lt;br /&gt;
*&amp;lt;b&amp;gt;calc_overall_review_info&amp;lt;/b&amp;gt; - The function populates the hash value for all students for all the reviews that they have gotten. I.e., Teammate and Meta for each of the assignments that they have taken. This value is then used to display the overall teammate_review and meta_review grade in the view&lt;br /&gt;
*&amp;lt;b&amp;gt;find_peer_review_score&amp;lt;/b&amp;gt; - The peer review score is taken from the questions for the assignment&lt;br /&gt;
&lt;br /&gt;
==Testing==&lt;br /&gt;
===Test Plan===&lt;br /&gt;
&lt;br /&gt;
The main objective of improving the current Assessment 360 Controller testing is to make sure each of the functionalities are being looked into regardless of the test coverage because of the number of calculations that are actually being taken place inside the controller. In order to achieve this, tests were written for each newly added method in the controller. The first few tests have assumed to expect a normal condition i.e., a person exists and all other information do exist.&lt;br /&gt;
&lt;br /&gt;
===Test Cases===&lt;br /&gt;
The following test cases were made for each respective methods added to the Assessment 360 Controller:&lt;br /&gt;
&lt;br /&gt;
===UI Testing===&lt;br /&gt;
By following the below steps, a reviewer can manually test the changes made to the Assessment 360 Controller.&lt;br /&gt;
&lt;br /&gt;
1. Visit [http://152.46.16.125:8080/ http://152.46.16.125:8080/] and enter the following credentials,&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;Username:&amp;lt;/b&amp;gt;instructor6 &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt;password&lt;br /&gt;
&lt;br /&gt;
2. From the menu bar, select Manage &amp;gt; Courses&lt;br /&gt;
&lt;br /&gt;
3. Scroll down to find the respective course, and select the&lt;br /&gt;
&lt;br /&gt;
==Submission==&lt;br /&gt;
===Github Link===&lt;br /&gt;
&lt;br /&gt;
The changes made to the code is present on this [https://github.com/ramyananth/expertiza link]. Multiple comments and refactoring have been addressed in detail here.&lt;br /&gt;
&lt;br /&gt;
===Pull Request===&lt;br /&gt;
&lt;br /&gt;
The initial build made out of pull request [https://github.com/expertiza/expertiza/pull/1691 1691], kept failing continuously since it was made to the master branch of expertiza. It changed the Gemfile.lock and also the database schema. This push was actually made because the beta branch and master branch of expertiza were not different at all. The new pull request [https://github.com/expertiza/expertiza/pull/1713 1713] was made to the beta branch from our beta branch and it worked completely fine.&lt;br /&gt;
&lt;br /&gt;
==Team Information==&lt;br /&gt;
[mailto:rananth2@ncsu.edu Ramya Ananth] - [https://www.linkedin.com/in/ramyananth/ LinkedIn]&lt;br /&gt;
&lt;br /&gt;
[mailto:suppala@ncsu.edu Sri Harsha Varma Uppalapati] - [https://www.linkedin.com/in/sri-harsha-varma-uppalapati LinkedIn]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;[mailto:efg@ncsu.edu Mentor: Dr. Edward F Gehringer]&amp;lt;/b&amp;gt; - [https://www.ece.ncsu.edu/people/efg/ Website]&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
1.[https://github.com/expertiza/expertiza/ Expertiza on GitHub]&lt;br /&gt;
&lt;br /&gt;
2.[https://github.com/ramyananth/expertiza GitHub Project Repository Fork]&lt;br /&gt;
&lt;br /&gt;
3.[http://expertiza.ncsu.edu/ Live Expertiza website]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132634</id>
		<title>CSC/ECE 517 Spring 2020 - E2003. Refactor and improve assessment360 controller</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132634"/>
		<updated>2020-04-01T03:43:14Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: /* UI Testing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source project based on [http://rubyonrails.org/ Ruby on Rails] framework. The software allows the instructor and students with the following privileges,&lt;br /&gt;
&lt;br /&gt;
===Instructors===&lt;br /&gt;
* Create new assignments&lt;br /&gt;
* Customize new or existing assignments&lt;br /&gt;
* Create a list of topics that students can sign up for&lt;br /&gt;
* Give grades/reviews for the students' submissions&lt;br /&gt;
&lt;br /&gt;
===Students===&lt;br /&gt;
* Form teams with other students to work on various projects and assignments&lt;br /&gt;
* Peer review other students' submissions&lt;br /&gt;
&lt;br /&gt;
Note: Expertiza supports submissions across various document types, including URL and wiki pages&lt;br /&gt;
&lt;br /&gt;
==Project Description==&lt;br /&gt;
&lt;br /&gt;
===About assessment_360 Controller===&lt;br /&gt;
The assessment_360 controller is designed to gather data from all stakeholders about the performance of a student in a course. Thus, its purpose is to provide course-level statistics. At present, the controller provides only two top-level functions where each of them gives a list of students in the class. &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; contains teammate and meta-review scores received by students for all assignments in the course&lt;br /&gt;
* &amp;lt;b&amp;gt;course_student_grade_summary &amp;lt;/b&amp;gt; gives a listing of students and what topic they worked on and what grade they received on each assignment during the semester&lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The assessment360 controller had three major issues. This project is aimed to address some of them, including:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 1:&amp;lt;/b&amp;gt; Methods &amp;lt;i&amp;gt;all_students_all_reviews&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;course_student_grade_summary&amp;lt;/i&amp;gt; were too long. Common initialization and looping had to factored out by moving them into smaller methods with mnemonic names&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 2:&amp;lt;/b&amp;gt; Method populate_hash_for_all_students_all_reviews is not easy to understand. It uses a special data structure to do a very simple task. That had to be refactored&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 3:&amp;lt;/b&amp;gt; Method course_student_grade_summary stopped working and has to be fixed&lt;br /&gt;
&lt;br /&gt;
===Motivation===&lt;br /&gt;
This project aims at encouraging students to collaborate and contribute to open-source project in turn helping them understand what goes on in a full-fledged software deployment process. It also paves a way to understand how one can use Rails, RSpec to develop a system that does justice to the DRY code practicing principles.&lt;br /&gt;
&lt;br /&gt;
==Approach==&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 1: Refactoring all_students_all_reviews and course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(a) The common elements in these files i.e., checking if the course participant list is empty or not is moved to a different function called &amp;lt;i&amp;gt;inspect_course_participants&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(b) Adding on to this, all_student_all_review was broken down to two more functions, &amp;lt;i&amp;gt;avg_review_calc_per_student&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;overall_review_count&amp;lt;/i&amp;gt; &lt;br /&gt;
&lt;br /&gt;
(c) The method course_student_grade_summary is broken down to one more function &amp;lt;i&amp;gt;assignment_grade_summary&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 2: Refactoring populate_hash_for_all_students_all_reviews&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The approach in this function is pretty straight forward when we try to break it down. It calculates,&lt;br /&gt;
&lt;br /&gt;
(a) The average score for each assignment for each course&lt;br /&gt;
&lt;br /&gt;
(b) The overall review grade for each assignment for all the students who have taken the course&lt;br /&gt;
&lt;br /&gt;
Passing the average score calculated from (a) checks if the student has teammates which could result in not having an average teammate_review_score. If we calculate (b) in our main function (this can be done) we would be repeating the checks that we are already doing for (a). Hence, this function is not changed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 3: Fix course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The current implementation ran into an issue when it was comparing the Key-Value pair passed in '''peer_review_score'''. It was hard to check if each of the keys were present or not. The proposed solution makes use of a basic hash value presence check that retrieves a value from the array/hash, given a set of keys. If no value is found, it'll return nil.&lt;br /&gt;
&lt;br /&gt;
==Proposed Implementation==&lt;br /&gt;
====Fixing the bug on course_student_grade_summary====&lt;br /&gt;
The current implementation of the method throws a nil error at the moment on the following line,&lt;br /&gt;
&amp;lt;pre&amp;gt;unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is rectified by introducing,&lt;br /&gt;
&amp;lt;pre&amp;gt;next if (peer_review_score[:review] &amp;amp;&amp;amp; peer_review_score[:review][:scores] &amp;amp;&amp;amp; peer_review_score[:review][:scores][:avg]).nil?&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Common refactoring of all_students_all_reviews and course_student_grade_summary method====&lt;br /&gt;
The functionality that the methods shared was that, both of them checked if there were course participants who had taken a particular course. This occupied 4 lines of code in both the functions. So, this is defined in a separate function called insure_existence_of and called from the two functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def insure_existence_of(course_participants)&lt;br /&gt;
    if course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Refactor all_students_all_reviews method====&lt;br /&gt;
The all_students_all_reviews method is one of the biggest methods in assessment360_controller.rb file. It finds the list of all students and assignments pertaining to the course. This data is then used to compute the metareview and teammate review scores for each student.&lt;br /&gt;
&lt;br /&gt;
The code before refactoring had 64 lines of code as shown below,&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   teammate_reviews,&lt;br /&gt;
                                                   @teammate_review,&lt;br /&gt;
                                                   @overall_teammate_review_grades,&lt;br /&gt;
                                                   @overall_teammate_review_count,&lt;br /&gt;
                                                   @teammate_review_info_per_stu)&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   meta_reviews,&lt;br /&gt;
                                                   @meta_review,&lt;br /&gt;
                                                   @overall_meta_review_grades,&lt;br /&gt;
                                                   @overall_meta_review_count,&lt;br /&gt;
                                                   @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      if @teammate_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @teammate_review_info_per_stu[0] * 1.0 / @teammate_review_info_per_stu[1]&lt;br /&gt;
        @teammate_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
      if @meta_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @meta_review_info_per_stu[0] * 1.0 / @meta_review_info_per_stu[1]&lt;br /&gt;
        @meta_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    @assignments.each do |assignment|&lt;br /&gt;
      temp_count = @overall_teammate_review_count[assignment.id]&lt;br /&gt;
      @overall_teammate_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = @overall_meta_review_count[assignment.id]&lt;br /&gt;
      @overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To calculate the average grade for each student on all assignments in this course that a student has taken in this course is refactoring in the base code by adding the avg_review_calc_per_student method. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def avg_review_calc_per_student(cp, review_info_per_stu, review)&lt;br /&gt;
    # check to see if the student has been given a review&lt;br /&gt;
    if review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
      temp_avg_grade = review_info_per_stu[0] * 1.0 / review_info_per_stu[1]&lt;br /&gt;
      review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To avoid a &amp;lt;i&amp;gt;divide by zero error&amp;lt;/i&amp;gt; that is thrown when we try to calculate the average grade when a student has no teammate is handled by the overall_review_count method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def overall_review_count(assignments, overall_teammate_review_count, overall_meta_review_count)&lt;br /&gt;
    assignments.each do |assignment|&lt;br /&gt;
      temp_count = overall_teammate_review_count[assignment.id]&lt;br /&gt;
      overall_review_count_hash[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = overall_meta_review_count[assignment.id]&lt;br /&gt;
      overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''After refactoring'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 teammate_reviews,&lt;br /&gt;
                                 @teammate_review,&lt;br /&gt;
                                 @overall_teammate_review_grades,&lt;br /&gt;
                                 @overall_teammate_review_count,&lt;br /&gt;
                                 @teammate_review_info_per_stu)&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 meta_reviews,&lt;br /&gt;
                                 @meta_review,&lt;br /&gt;
                                 @overall_meta_review_grades,&lt;br /&gt;
                                 @overall_meta_review_count,&lt;br /&gt;
                                 @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      avg_review_calc_per_student(cp, @teammate_review_info_per_stu, @teammate_review)&lt;br /&gt;
      avg_review_calc_per_student(cp, @meta_review_info_per_stu, @meta_review)&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    overall_review_count(@assignments, @overall_teammate_review_count, @overall_meta_review_count)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Refactor course_student_grade_summary method====&lt;br /&gt;
This method finds the list of all students and assignments pertaining to the course. The data obtained is then used to compute the instructor assigned grade and peer review scores. It was the secong biggest method in the assessment360_controller.rb controller file. The code before refactoring is shown below,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
&lt;br /&gt;
        # A topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
        topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
        @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
&lt;br /&gt;
        # Instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
        team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
        next if team_id.nil?&lt;br /&gt;
&lt;br /&gt;
        team = Team.find(team_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
&lt;br /&gt;
        # Set the assignment grade, peer review score, and sum for the final student summary&lt;br /&gt;
        @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
        unless @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
          @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&lt;br /&gt;
          @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&lt;br /&gt;
        end&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;
In this function, all the functionalities pertaining to a course participant - student in this case, in a given assignment is invoked by introducing a new method called assignment_grade_summary. This method checks if a topic exists and if it does, it passes the final grade that is calculated for that student in that course.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
    user_id = cp.user_id&lt;br /&gt;
    # topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
    topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
    @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
    # instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
    team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
    team = Team.find(team_id)&lt;br /&gt;
    @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
    return if @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
    @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
  end  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''After refactoring'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        # break out of the loop if there are no participants in the assignment&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
        # break out of the loop if the participant has no team&lt;br /&gt;
        next if TeamsUser.team_id(assignment_id, user_id).nil?&lt;br /&gt;
        # pull information about the student's grades for particular assignment&lt;br /&gt;
        assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
        #Skip if there are no peers&lt;br /&gt;
        next if peer_review_score.nil? &lt;br /&gt;
        #Skip if there are no reviews done by peers&lt;br /&gt;
        next if peer_review_score[:review].nil? &lt;br /&gt;
        #Skip if there are no reviews scores assigned by peers&lt;br /&gt;
        next if peer_review_score[:review][:scores].nil?&lt;br /&gt;
        #Skip if there are is no peer review average score&lt;br /&gt;
        next if peer_review_score[:review][:scores][:avg].nil?&lt;br /&gt;
        @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&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;
==Method name explanations==&lt;br /&gt;
One of the methods devised in this project is use nouns instead of verbs. Ideally the name of a variable or method should be enough to identify it's function in the class. This is because assessment_360 controller, of course is an exception and does explain what each of the functions do on their function names,&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; - Find the list of all students and assignments pertaining to the course. This data is used to compute the metareview and teammate review scores.&lt;br /&gt;
*&amp;lt;b&amp;gt;avg_review_calc_per_student&amp;lt;/b&amp;gt; - Calculate the overall average review grade that a student has gotten from their teammate(s) and instructor(s)&lt;br /&gt;
*&amp;lt;b&amp;gt;overall_review_count&amp;lt;/b&amp;gt; - To avoid divide by zero error&lt;br /&gt;
*&amp;lt;b&amp;gt;course_student_grade_summary&amp;lt;/b&amp;gt; - Find the list of all students and assignments pertaining to the course. This data is used to compute the instructor assigned grade and peer review scores.&lt;br /&gt;
*&amp;lt;b&amp;gt;assignment_grade_summary&amp;lt;/b&amp;gt; - To pull information about the student's grades for particular assignment&lt;br /&gt;
*&amp;lt;b&amp;gt;insure_existence_of&amp;lt;/b&amp;gt; - To make sure there are participants for the course&lt;br /&gt;
*&amp;lt;b&amp;gt;calc_overall_review_info&amp;lt;/b&amp;gt; - The function populates the hash value for all students for all the reviews that they have gotten. I.e., Teammate and Meta for each of the assignments that they have taken. This value is then used to display the overall teammate_review and meta_review grade in the view&lt;br /&gt;
*&amp;lt;b&amp;gt;find_peer_review_score&amp;lt;/b&amp;gt; - The peer review score is taken from the questions for the assignment&lt;br /&gt;
&lt;br /&gt;
==Testing==&lt;br /&gt;
===Test Plan===&lt;br /&gt;
&lt;br /&gt;
The main objective of improving the current Assessment 360 Controller testing is to make sure each of the functionalities are being looked into regardless of the test coverage because of the number of calculations that are actually being taken place inside the controller. In order to achieve this, tests were written for each newly added method in the controller. The first few tests have assumed to expect a normal condition i.e., a person exists and all other information do exist.&lt;br /&gt;
&lt;br /&gt;
===Test Cases===&lt;br /&gt;
The following test cases were made for each respective methods added to the Assessment 360 Controller:&lt;br /&gt;
&lt;br /&gt;
===UI Testing===&lt;br /&gt;
By following the below steps, a reviewer can manually test the changes made to the Assessment 360 Controller.&lt;br /&gt;
&lt;br /&gt;
1. Visit [http://152.46.16.125:8080/ http://152.46.16.125:8080/] and enter the following credentials,&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;Username:&amp;lt;/b&amp;gt;instructor6 &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt;password&lt;br /&gt;
&lt;br /&gt;
2. From the menu bar, select Manage &amp;gt; Courses&lt;br /&gt;
&lt;br /&gt;
3. Scroll down to find the respective course, and select the&lt;br /&gt;
&lt;br /&gt;
==Submission==&lt;br /&gt;
'''Github Link'''&lt;br /&gt;
&lt;br /&gt;
The changes made to the code is present on this [https://github.com/ramyananth/expertiza link]. Multiple comments and refactoring have been addressed in detail here.&lt;br /&gt;
&lt;br /&gt;
===Pull Request===&lt;br /&gt;
&lt;br /&gt;
The initial build made out of pull request [https://github.com/expertiza/expertiza/pull/1691 1691], kept failing continuously since it was made to the master branch of expertiza. It changed the Gemfile.lock and also the database schema. This push was actually made because the beta branch and master branch of expertiza were not different at all. The new pull request [https://github.com/expertiza/expertiza/pull/1713 1713] was made to the beta branch from our beta branch and it worked completely fine.&lt;br /&gt;
&lt;br /&gt;
==Team Information==&lt;br /&gt;
[mailto:rananth2@ncsu.edu Ramya Ananth] - [https://www.linkedin.com/in/ramyananth/ LinkedIn]&lt;br /&gt;
&lt;br /&gt;
[mailto:suppala@ncsu.edu Sri Harsha Varma Uppalapati] - [https://www.linkedin.com/in/sri-harsha-varma-uppalapati LinkedIn]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;[mailto:efg@ncsu.edu Mentor: Dr. Edward F Gehringer]&amp;lt;/b&amp;gt; - [https://www.ece.ncsu.edu/people/efg/ Website]&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
1.[https://github.com/expertiza/expertiza/ Expertiza on GitHub]&lt;br /&gt;
&lt;br /&gt;
2.[https://github.com/ramyananth/expertiza GitHub Project Repository Fork]&lt;br /&gt;
&lt;br /&gt;
3.[http://expertiza.ncsu.edu/ Live Expertiza website]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132633</id>
		<title>CSC/ECE 517 Spring 2020 - E2003. Refactor and improve assessment360 controller</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132633"/>
		<updated>2020-04-01T03:42:38Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: /* Github Link */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source project based on [http://rubyonrails.org/ Ruby on Rails] framework. The software allows the instructor and students with the following privileges,&lt;br /&gt;
&lt;br /&gt;
===Instructors===&lt;br /&gt;
* Create new assignments&lt;br /&gt;
* Customize new or existing assignments&lt;br /&gt;
* Create a list of topics that students can sign up for&lt;br /&gt;
* Give grades/reviews for the students' submissions&lt;br /&gt;
&lt;br /&gt;
===Students===&lt;br /&gt;
* Form teams with other students to work on various projects and assignments&lt;br /&gt;
* Peer review other students' submissions&lt;br /&gt;
&lt;br /&gt;
Note: Expertiza supports submissions across various document types, including URL and wiki pages&lt;br /&gt;
&lt;br /&gt;
==Project Description==&lt;br /&gt;
&lt;br /&gt;
===About assessment_360 Controller===&lt;br /&gt;
The assessment_360 controller is designed to gather data from all stakeholders about the performance of a student in a course. Thus, its purpose is to provide course-level statistics. At present, the controller provides only two top-level functions where each of them gives a list of students in the class. &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; contains teammate and meta-review scores received by students for all assignments in the course&lt;br /&gt;
* &amp;lt;b&amp;gt;course_student_grade_summary &amp;lt;/b&amp;gt; gives a listing of students and what topic they worked on and what grade they received on each assignment during the semester&lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The assessment360 controller had three major issues. This project is aimed to address some of them, including:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 1:&amp;lt;/b&amp;gt; Methods &amp;lt;i&amp;gt;all_students_all_reviews&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;course_student_grade_summary&amp;lt;/i&amp;gt; were too long. Common initialization and looping had to factored out by moving them into smaller methods with mnemonic names&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 2:&amp;lt;/b&amp;gt; Method populate_hash_for_all_students_all_reviews is not easy to understand. It uses a special data structure to do a very simple task. That had to be refactored&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 3:&amp;lt;/b&amp;gt; Method course_student_grade_summary stopped working and has to be fixed&lt;br /&gt;
&lt;br /&gt;
===Motivation===&lt;br /&gt;
This project aims at encouraging students to collaborate and contribute to open-source project in turn helping them understand what goes on in a full-fledged software deployment process. It also paves a way to understand how one can use Rails, RSpec to develop a system that does justice to the DRY code practicing principles.&lt;br /&gt;
&lt;br /&gt;
==Approach==&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 1: Refactoring all_students_all_reviews and course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(a) The common elements in these files i.e., checking if the course participant list is empty or not is moved to a different function called &amp;lt;i&amp;gt;inspect_course_participants&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(b) Adding on to this, all_student_all_review was broken down to two more functions, &amp;lt;i&amp;gt;avg_review_calc_per_student&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;overall_review_count&amp;lt;/i&amp;gt; &lt;br /&gt;
&lt;br /&gt;
(c) The method course_student_grade_summary is broken down to one more function &amp;lt;i&amp;gt;assignment_grade_summary&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 2: Refactoring populate_hash_for_all_students_all_reviews&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The approach in this function is pretty straight forward when we try to break it down. It calculates,&lt;br /&gt;
&lt;br /&gt;
(a) The average score for each assignment for each course&lt;br /&gt;
&lt;br /&gt;
(b) The overall review grade for each assignment for all the students who have taken the course&lt;br /&gt;
&lt;br /&gt;
Passing the average score calculated from (a) checks if the student has teammates which could result in not having an average teammate_review_score. If we calculate (b) in our main function (this can be done) we would be repeating the checks that we are already doing for (a). Hence, this function is not changed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 3: Fix course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The current implementation ran into an issue when it was comparing the Key-Value pair passed in '''peer_review_score'''. It was hard to check if each of the keys were present or not. The proposed solution makes use of a basic hash value presence check that retrieves a value from the array/hash, given a set of keys. If no value is found, it'll return nil.&lt;br /&gt;
&lt;br /&gt;
==Proposed Implementation==&lt;br /&gt;
====Fixing the bug on course_student_grade_summary====&lt;br /&gt;
The current implementation of the method throws a nil error at the moment on the following line,&lt;br /&gt;
&amp;lt;pre&amp;gt;unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is rectified by introducing,&lt;br /&gt;
&amp;lt;pre&amp;gt;next if (peer_review_score[:review] &amp;amp;&amp;amp; peer_review_score[:review][:scores] &amp;amp;&amp;amp; peer_review_score[:review][:scores][:avg]).nil?&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Common refactoring of all_students_all_reviews and course_student_grade_summary method====&lt;br /&gt;
The functionality that the methods shared was that, both of them checked if there were course participants who had taken a particular course. This occupied 4 lines of code in both the functions. So, this is defined in a separate function called insure_existence_of and called from the two functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def insure_existence_of(course_participants)&lt;br /&gt;
    if course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Refactor all_students_all_reviews method====&lt;br /&gt;
The all_students_all_reviews method is one of the biggest methods in assessment360_controller.rb file. It finds the list of all students and assignments pertaining to the course. This data is then used to compute the metareview and teammate review scores for each student.&lt;br /&gt;
&lt;br /&gt;
The code before refactoring had 64 lines of code as shown below,&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   teammate_reviews,&lt;br /&gt;
                                                   @teammate_review,&lt;br /&gt;
                                                   @overall_teammate_review_grades,&lt;br /&gt;
                                                   @overall_teammate_review_count,&lt;br /&gt;
                                                   @teammate_review_info_per_stu)&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   meta_reviews,&lt;br /&gt;
                                                   @meta_review,&lt;br /&gt;
                                                   @overall_meta_review_grades,&lt;br /&gt;
                                                   @overall_meta_review_count,&lt;br /&gt;
                                                   @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      if @teammate_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @teammate_review_info_per_stu[0] * 1.0 / @teammate_review_info_per_stu[1]&lt;br /&gt;
        @teammate_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
      if @meta_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @meta_review_info_per_stu[0] * 1.0 / @meta_review_info_per_stu[1]&lt;br /&gt;
        @meta_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    @assignments.each do |assignment|&lt;br /&gt;
      temp_count = @overall_teammate_review_count[assignment.id]&lt;br /&gt;
      @overall_teammate_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = @overall_meta_review_count[assignment.id]&lt;br /&gt;
      @overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To calculate the average grade for each student on all assignments in this course that a student has taken in this course is refactoring in the base code by adding the avg_review_calc_per_student method. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def avg_review_calc_per_student(cp, review_info_per_stu, review)&lt;br /&gt;
    # check to see if the student has been given a review&lt;br /&gt;
    if review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
      temp_avg_grade = review_info_per_stu[0] * 1.0 / review_info_per_stu[1]&lt;br /&gt;
      review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To avoid a &amp;lt;i&amp;gt;divide by zero error&amp;lt;/i&amp;gt; that is thrown when we try to calculate the average grade when a student has no teammate is handled by the overall_review_count method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def overall_review_count(assignments, overall_teammate_review_count, overall_meta_review_count)&lt;br /&gt;
    assignments.each do |assignment|&lt;br /&gt;
      temp_count = overall_teammate_review_count[assignment.id]&lt;br /&gt;
      overall_review_count_hash[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = overall_meta_review_count[assignment.id]&lt;br /&gt;
      overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''After refactoring'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 teammate_reviews,&lt;br /&gt;
                                 @teammate_review,&lt;br /&gt;
                                 @overall_teammate_review_grades,&lt;br /&gt;
                                 @overall_teammate_review_count,&lt;br /&gt;
                                 @teammate_review_info_per_stu)&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 meta_reviews,&lt;br /&gt;
                                 @meta_review,&lt;br /&gt;
                                 @overall_meta_review_grades,&lt;br /&gt;
                                 @overall_meta_review_count,&lt;br /&gt;
                                 @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      avg_review_calc_per_student(cp, @teammate_review_info_per_stu, @teammate_review)&lt;br /&gt;
      avg_review_calc_per_student(cp, @meta_review_info_per_stu, @meta_review)&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    overall_review_count(@assignments, @overall_teammate_review_count, @overall_meta_review_count)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Refactor course_student_grade_summary method====&lt;br /&gt;
This method finds the list of all students and assignments pertaining to the course. The data obtained is then used to compute the instructor assigned grade and peer review scores. It was the secong biggest method in the assessment360_controller.rb controller file. The code before refactoring is shown below,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
&lt;br /&gt;
        # A topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
        topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
        @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
&lt;br /&gt;
        # Instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
        team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
        next if team_id.nil?&lt;br /&gt;
&lt;br /&gt;
        team = Team.find(team_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
&lt;br /&gt;
        # Set the assignment grade, peer review score, and sum for the final student summary&lt;br /&gt;
        @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
        unless @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
          @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&lt;br /&gt;
          @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&lt;br /&gt;
        end&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;
In this function, all the functionalities pertaining to a course participant - student in this case, in a given assignment is invoked by introducing a new method called assignment_grade_summary. This method checks if a topic exists and if it does, it passes the final grade that is calculated for that student in that course.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
    user_id = cp.user_id&lt;br /&gt;
    # topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
    topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
    @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
    # instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
    team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
    team = Team.find(team_id)&lt;br /&gt;
    @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
    return if @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
    @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
  end  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''After refactoring'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        # break out of the loop if there are no participants in the assignment&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
        # break out of the loop if the participant has no team&lt;br /&gt;
        next if TeamsUser.team_id(assignment_id, user_id).nil?&lt;br /&gt;
        # pull information about the student's grades for particular assignment&lt;br /&gt;
        assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
        #Skip if there are no peers&lt;br /&gt;
        next if peer_review_score.nil? &lt;br /&gt;
        #Skip if there are no reviews done by peers&lt;br /&gt;
        next if peer_review_score[:review].nil? &lt;br /&gt;
        #Skip if there are no reviews scores assigned by peers&lt;br /&gt;
        next if peer_review_score[:review][:scores].nil?&lt;br /&gt;
        #Skip if there are is no peer review average score&lt;br /&gt;
        next if peer_review_score[:review][:scores][:avg].nil?&lt;br /&gt;
        @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&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;
==Method name explanations==&lt;br /&gt;
One of the methods devised in this project is use nouns instead of verbs. Ideally the name of a variable or method should be enough to identify it's function in the class. This is because assessment_360 controller, of course is an exception and does explain what each of the functions do on their function names,&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; - Find the list of all students and assignments pertaining to the course. This data is used to compute the metareview and teammate review scores.&lt;br /&gt;
*&amp;lt;b&amp;gt;avg_review_calc_per_student&amp;lt;/b&amp;gt; - Calculate the overall average review grade that a student has gotten from their teammate(s) and instructor(s)&lt;br /&gt;
*&amp;lt;b&amp;gt;overall_review_count&amp;lt;/b&amp;gt; - To avoid divide by zero error&lt;br /&gt;
*&amp;lt;b&amp;gt;course_student_grade_summary&amp;lt;/b&amp;gt; - Find the list of all students and assignments pertaining to the course. This data is used to compute the instructor assigned grade and peer review scores.&lt;br /&gt;
*&amp;lt;b&amp;gt;assignment_grade_summary&amp;lt;/b&amp;gt; - To pull information about the student's grades for particular assignment&lt;br /&gt;
*&amp;lt;b&amp;gt;insure_existence_of&amp;lt;/b&amp;gt; - To make sure there are participants for the course&lt;br /&gt;
*&amp;lt;b&amp;gt;calc_overall_review_info&amp;lt;/b&amp;gt; - The function populates the hash value for all students for all the reviews that they have gotten. I.e., Teammate and Meta for each of the assignments that they have taken. This value is then used to display the overall teammate_review and meta_review grade in the view&lt;br /&gt;
*&amp;lt;b&amp;gt;find_peer_review_score&amp;lt;/b&amp;gt; - The peer review score is taken from the questions for the assignment&lt;br /&gt;
&lt;br /&gt;
==Testing==&lt;br /&gt;
===Test Plan===&lt;br /&gt;
&lt;br /&gt;
The main objective of improving the current Assessment 360 Controller testing is to make sure each of the functionalities are being looked into regardless of the test coverage because of the number of calculations that are actually being taken place inside the controller. In order to achieve this, tests were written for each newly added method in the controller. The first few tests have assumed to expect a normal condition i.e., a person exists and all other information do exist.&lt;br /&gt;
&lt;br /&gt;
===Test Cases===&lt;br /&gt;
The following test cases were made for each respective methods added to the Assessment 360 Controller:&lt;br /&gt;
&lt;br /&gt;
===UI Testing===&lt;br /&gt;
By following the below steps, a reviewer can manually test the changes made to the Assessment 360 Controller.&lt;br /&gt;
&lt;br /&gt;
1. Visit [http://152.46.16.125:8080/ http://152.46.16.125:8080/] and enter the following credentials,&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;Username:&amp;lt;/br&amp;gt;instructor6 &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;Password:&amp;lt;/br&amp;gt;password&lt;br /&gt;
&lt;br /&gt;
2. From the menu bar, select Manage &amp;gt; Courses&lt;br /&gt;
&lt;br /&gt;
3. Scroll down to find the respective course, and select the &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Submission==&lt;br /&gt;
'''Github Link'''&lt;br /&gt;
&lt;br /&gt;
The changes made to the code is present on this [https://github.com/ramyananth/expertiza link]. Multiple comments and refactoring have been addressed in detail here.&lt;br /&gt;
&lt;br /&gt;
===Pull Request===&lt;br /&gt;
&lt;br /&gt;
The initial build made out of pull request [https://github.com/expertiza/expertiza/pull/1691 1691], kept failing continuously since it was made to the master branch of expertiza. It changed the Gemfile.lock and also the database schema. This push was actually made because the beta branch and master branch of expertiza were not different at all. The new pull request [https://github.com/expertiza/expertiza/pull/1713 1713] was made to the beta branch from our beta branch and it worked completely fine.&lt;br /&gt;
&lt;br /&gt;
==Team Information==&lt;br /&gt;
[mailto:rananth2@ncsu.edu Ramya Ananth] - [https://www.linkedin.com/in/ramyananth/ LinkedIn]&lt;br /&gt;
&lt;br /&gt;
[mailto:suppala@ncsu.edu Sri Harsha Varma Uppalapati] - [https://www.linkedin.com/in/sri-harsha-varma-uppalapati LinkedIn]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;[mailto:efg@ncsu.edu Mentor: Dr. Edward F Gehringer]&amp;lt;/b&amp;gt; - [https://www.ece.ncsu.edu/people/efg/ Website]&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
1.[https://github.com/expertiza/expertiza/ Expertiza on GitHub]&lt;br /&gt;
&lt;br /&gt;
2.[https://github.com/ramyananth/expertiza GitHub Project Repository Fork]&lt;br /&gt;
&lt;br /&gt;
3.[http://expertiza.ncsu.edu/ Live Expertiza website]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Test_pass.PNG&amp;diff=132632</id>
		<title>File:Test pass.PNG</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Test_pass.PNG&amp;diff=132632"/>
		<updated>2020-04-01T03:41:41Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: Rananth2 uploaded a new version of File:Test pass.PNG&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Test_pass.PNG&amp;diff=132631</id>
		<title>File:Test pass.PNG</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Test_pass.PNG&amp;diff=132631"/>
		<updated>2020-04-01T03:41:09Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: Rananth2 uploaded a new version of File:Test pass.PNG&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Test_pass.PNG&amp;diff=132630</id>
		<title>File:Test pass.PNG</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Test_pass.PNG&amp;diff=132630"/>
		<updated>2020-04-01T03:40:48Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132627</id>
		<title>CSC/ECE 517 Spring 2020 - E2003. Refactor and improve assessment360 controller</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132627"/>
		<updated>2020-04-01T03:39:44Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source project based on [http://rubyonrails.org/ Ruby on Rails] framework. The software allows the instructor and students with the following privileges,&lt;br /&gt;
&lt;br /&gt;
===Instructors===&lt;br /&gt;
* Create new assignments&lt;br /&gt;
* Customize new or existing assignments&lt;br /&gt;
* Create a list of topics that students can sign up for&lt;br /&gt;
* Give grades/reviews for the students' submissions&lt;br /&gt;
&lt;br /&gt;
===Students===&lt;br /&gt;
* Form teams with other students to work on various projects and assignments&lt;br /&gt;
* Peer review other students' submissions&lt;br /&gt;
&lt;br /&gt;
Note: Expertiza supports submissions across various document types, including URL and wiki pages&lt;br /&gt;
&lt;br /&gt;
==Project Description==&lt;br /&gt;
&lt;br /&gt;
===About assessment_360 Controller===&lt;br /&gt;
The assessment_360 controller is designed to gather data from all stakeholders about the performance of a student in a course. Thus, its purpose is to provide course-level statistics. At present, the controller provides only two top-level functions where each of them gives a list of students in the class. &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; contains teammate and meta-review scores received by students for all assignments in the course&lt;br /&gt;
* &amp;lt;b&amp;gt;course_student_grade_summary &amp;lt;/b&amp;gt; gives a listing of students and what topic they worked on and what grade they received on each assignment during the semester&lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The assessment360 controller had three major issues. This project is aimed to address some of them, including:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 1:&amp;lt;/b&amp;gt; Methods &amp;lt;i&amp;gt;all_students_all_reviews&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;course_student_grade_summary&amp;lt;/i&amp;gt; were too long. Common initialization and looping had to factored out by moving them into smaller methods with mnemonic names&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 2:&amp;lt;/b&amp;gt; Method populate_hash_for_all_students_all_reviews is not easy to understand. It uses a special data structure to do a very simple task. That had to be refactored&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 3:&amp;lt;/b&amp;gt; Method course_student_grade_summary stopped working and has to be fixed&lt;br /&gt;
&lt;br /&gt;
===Motivation===&lt;br /&gt;
This project aims at encouraging students to collaborate and contribute to open-source project in turn helping them understand what goes on in a full-fledged software deployment process. It also paves a way to understand how one can use Rails, RSpec to develop a system that does justice to the DRY code practicing principles.&lt;br /&gt;
&lt;br /&gt;
==Approach==&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 1: Refactoring all_students_all_reviews and course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(a) The common elements in these files i.e., checking if the course participant list is empty or not is moved to a different function called &amp;lt;i&amp;gt;inspect_course_participants&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(b) Adding on to this, all_student_all_review was broken down to two more functions, &amp;lt;i&amp;gt;avg_review_calc_per_student&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;overall_review_count&amp;lt;/i&amp;gt; &lt;br /&gt;
&lt;br /&gt;
(c) The method course_student_grade_summary is broken down to one more function &amp;lt;i&amp;gt;assignment_grade_summary&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 2: Refactoring populate_hash_for_all_students_all_reviews&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The approach in this function is pretty straight forward when we try to break it down. It calculates,&lt;br /&gt;
&lt;br /&gt;
(a) The average score for each assignment for each course&lt;br /&gt;
&lt;br /&gt;
(b) The overall review grade for each assignment for all the students who have taken the course&lt;br /&gt;
&lt;br /&gt;
Passing the average score calculated from (a) checks if the student has teammates which could result in not having an average teammate_review_score. If we calculate (b) in our main function (this can be done) we would be repeating the checks that we are already doing for (a). Hence, this function is not changed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 3: Fix course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The current implementation ran into an issue when it was comparing the Key-Value pair passed in '''peer_review_score'''. It was hard to check if each of the keys were present or not. The proposed solution makes use of a basic hash value presence check that retrieves a value from the array/hash, given a set of keys. If no value is found, it'll return nil.&lt;br /&gt;
&lt;br /&gt;
==Proposed Implementation==&lt;br /&gt;
====Fixing the bug on course_student_grade_summary====&lt;br /&gt;
The current implementation of the method throws a nil error at the moment on the following line,&lt;br /&gt;
&amp;lt;pre&amp;gt;unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is rectified by introducing,&lt;br /&gt;
&amp;lt;pre&amp;gt;next if (peer_review_score[:review] &amp;amp;&amp;amp; peer_review_score[:review][:scores] &amp;amp;&amp;amp; peer_review_score[:review][:scores][:avg]).nil?&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Common refactoring of all_students_all_reviews and course_student_grade_summary method====&lt;br /&gt;
The functionality that the methods shared was that, both of them checked if there were course participants who had taken a particular course. This occupied 4 lines of code in both the functions. So, this is defined in a separate function called insure_existence_of and called from the two functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def insure_existence_of(course_participants)&lt;br /&gt;
    if course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Refactor all_students_all_reviews method====&lt;br /&gt;
The all_students_all_reviews method is one of the biggest methods in assessment360_controller.rb file. It finds the list of all students and assignments pertaining to the course. This data is then used to compute the metareview and teammate review scores for each student.&lt;br /&gt;
&lt;br /&gt;
The code before refactoring had 64 lines of code as shown below,&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   teammate_reviews,&lt;br /&gt;
                                                   @teammate_review,&lt;br /&gt;
                                                   @overall_teammate_review_grades,&lt;br /&gt;
                                                   @overall_teammate_review_count,&lt;br /&gt;
                                                   @teammate_review_info_per_stu)&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   meta_reviews,&lt;br /&gt;
                                                   @meta_review,&lt;br /&gt;
                                                   @overall_meta_review_grades,&lt;br /&gt;
                                                   @overall_meta_review_count,&lt;br /&gt;
                                                   @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      if @teammate_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @teammate_review_info_per_stu[0] * 1.0 / @teammate_review_info_per_stu[1]&lt;br /&gt;
        @teammate_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
      if @meta_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @meta_review_info_per_stu[0] * 1.0 / @meta_review_info_per_stu[1]&lt;br /&gt;
        @meta_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    @assignments.each do |assignment|&lt;br /&gt;
      temp_count = @overall_teammate_review_count[assignment.id]&lt;br /&gt;
      @overall_teammate_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = @overall_meta_review_count[assignment.id]&lt;br /&gt;
      @overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To calculate the average grade for each student on all assignments in this course that a student has taken in this course is refactoring in the base code by adding the avg_review_calc_per_student method. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def avg_review_calc_per_student(cp, review_info_per_stu, review)&lt;br /&gt;
    # check to see if the student has been given a review&lt;br /&gt;
    if review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
      temp_avg_grade = review_info_per_stu[0] * 1.0 / review_info_per_stu[1]&lt;br /&gt;
      review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To avoid a &amp;lt;i&amp;gt;divide by zero error&amp;lt;/i&amp;gt; that is thrown when we try to calculate the average grade when a student has no teammate is handled by the overall_review_count method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def overall_review_count(assignments, overall_teammate_review_count, overall_meta_review_count)&lt;br /&gt;
    assignments.each do |assignment|&lt;br /&gt;
      temp_count = overall_teammate_review_count[assignment.id]&lt;br /&gt;
      overall_review_count_hash[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = overall_meta_review_count[assignment.id]&lt;br /&gt;
      overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''After refactoring'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 teammate_reviews,&lt;br /&gt;
                                 @teammate_review,&lt;br /&gt;
                                 @overall_teammate_review_grades,&lt;br /&gt;
                                 @overall_teammate_review_count,&lt;br /&gt;
                                 @teammate_review_info_per_stu)&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 meta_reviews,&lt;br /&gt;
                                 @meta_review,&lt;br /&gt;
                                 @overall_meta_review_grades,&lt;br /&gt;
                                 @overall_meta_review_count,&lt;br /&gt;
                                 @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      avg_review_calc_per_student(cp, @teammate_review_info_per_stu, @teammate_review)&lt;br /&gt;
      avg_review_calc_per_student(cp, @meta_review_info_per_stu, @meta_review)&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    overall_review_count(@assignments, @overall_teammate_review_count, @overall_meta_review_count)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Refactor course_student_grade_summary method====&lt;br /&gt;
This method finds the list of all students and assignments pertaining to the course. The data obtained is then used to compute the instructor assigned grade and peer review scores. It was the secong biggest method in the assessment360_controller.rb controller file. The code before refactoring is shown below,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
&lt;br /&gt;
        # A topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
        topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
        @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
&lt;br /&gt;
        # Instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
        team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
        next if team_id.nil?&lt;br /&gt;
&lt;br /&gt;
        team = Team.find(team_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
&lt;br /&gt;
        # Set the assignment grade, peer review score, and sum for the final student summary&lt;br /&gt;
        @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
        unless @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
          @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&lt;br /&gt;
          @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&lt;br /&gt;
        end&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;
In this function, all the functionalities pertaining to a course participant - student in this case, in a given assignment is invoked by introducing a new method called assignment_grade_summary. This method checks if a topic exists and if it does, it passes the final grade that is calculated for that student in that course.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
    user_id = cp.user_id&lt;br /&gt;
    # topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
    topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
    @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
    # instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
    team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
    team = Team.find(team_id)&lt;br /&gt;
    @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
    return if @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
    @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
  end  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''After refactoring'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        # break out of the loop if there are no participants in the assignment&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
        # break out of the loop if the participant has no team&lt;br /&gt;
        next if TeamsUser.team_id(assignment_id, user_id).nil?&lt;br /&gt;
        # pull information about the student's grades for particular assignment&lt;br /&gt;
        assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
        #Skip if there are no peers&lt;br /&gt;
        next if peer_review_score.nil? &lt;br /&gt;
        #Skip if there are no reviews done by peers&lt;br /&gt;
        next if peer_review_score[:review].nil? &lt;br /&gt;
        #Skip if there are no reviews scores assigned by peers&lt;br /&gt;
        next if peer_review_score[:review][:scores].nil?&lt;br /&gt;
        #Skip if there are is no peer review average score&lt;br /&gt;
        next if peer_review_score[:review][:scores][:avg].nil?&lt;br /&gt;
        @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&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;
==Method name explanations==&lt;br /&gt;
One of the methods devised in this project is use nouns instead of verbs. Ideally the name of a variable or method should be enough to identify it's function in the class. This is because assessment_360 controller, of course is an exception and does explain what each of the functions do on their function names,&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; - Find the list of all students and assignments pertaining to the course. This data is used to compute the metareview and teammate review scores.&lt;br /&gt;
*&amp;lt;b&amp;gt;avg_review_calc_per_student&amp;lt;/b&amp;gt; - Calculate the overall average review grade that a student has gotten from their teammate(s) and instructor(s)&lt;br /&gt;
*&amp;lt;b&amp;gt;overall_review_count&amp;lt;/b&amp;gt; - To avoid divide by zero error&lt;br /&gt;
*&amp;lt;b&amp;gt;course_student_grade_summary&amp;lt;/b&amp;gt; - Find the list of all students and assignments pertaining to the course. This data is used to compute the instructor assigned grade and peer review scores.&lt;br /&gt;
*&amp;lt;b&amp;gt;assignment_grade_summary&amp;lt;/b&amp;gt; - To pull information about the student's grades for particular assignment&lt;br /&gt;
*&amp;lt;b&amp;gt;insure_existence_of&amp;lt;/b&amp;gt; - To make sure there are participants for the course&lt;br /&gt;
*&amp;lt;b&amp;gt;calc_overall_review_info&amp;lt;/b&amp;gt; - The function populates the hash value for all students for all the reviews that they have gotten. I.e., Teammate and Meta for each of the assignments that they have taken. This value is then used to display the overall teammate_review and meta_review grade in the view&lt;br /&gt;
*&amp;lt;b&amp;gt;find_peer_review_score&amp;lt;/b&amp;gt; - The peer review score is taken from the questions for the assignment&lt;br /&gt;
&lt;br /&gt;
==Testing==&lt;br /&gt;
===Test Plan===&lt;br /&gt;
&lt;br /&gt;
The main objective of improving the current Assessment 360 Controller testing is to make sure each of the functionalities are being looked into regardless of the test coverage because of the number of calculations that are actually being taken place inside the controller. In order to achieve this, tests were written for each newly added method in the controller. The first few tests have assumed to expect a normal condition i.e., a person exists and all other information do exist.&lt;br /&gt;
&lt;br /&gt;
===Test Cases===&lt;br /&gt;
The following test cases were made for each respective methods added to the Assessment 360 Controller:&lt;br /&gt;
&lt;br /&gt;
===UI Testing===&lt;br /&gt;
By following the below steps, a reviewer can manually test the changes made to the Assessment 360 Controller.&lt;br /&gt;
&lt;br /&gt;
1. Visit [http://152.46.16.125:8080/ http://152.46.16.125:8080/] and enter the following credentials,&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;Username:&amp;lt;/br&amp;gt;instructor6 &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;Password:&amp;lt;/br&amp;gt;password&lt;br /&gt;
&lt;br /&gt;
2. From the menu bar, select Manage &amp;gt; Courses&lt;br /&gt;
&lt;br /&gt;
3. Scroll down to find the respective course, and select the &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Submission==&lt;br /&gt;
===Github Link===&lt;br /&gt;
&lt;br /&gt;
The changes made to the code is present on this [https://github.com/ramyananth/expertiza link]. Multiple comments and refactoring have been addressed in detail here.&lt;br /&gt;
&lt;br /&gt;
===Pull Request===&lt;br /&gt;
&lt;br /&gt;
The initial build made out of pull request [https://github.com/expertiza/expertiza/pull/1691 1691], kept failing continuously since it was made to the master branch of expertiza. It changed the Gemfile.lock and also the database schema. This push was actually made because the beta branch and master branch of expertiza were not different at all. The new pull request [https://github.com/expertiza/expertiza/pull/1713 1713] was made to the beta branch from our beta branch and it worked completely fine.&lt;br /&gt;
&lt;br /&gt;
==Team Information==&lt;br /&gt;
[mailto:rananth2@ncsu.edu Ramya Ananth] - [https://www.linkedin.com/in/ramyananth/ LinkedIn]&lt;br /&gt;
&lt;br /&gt;
[mailto:suppala@ncsu.edu Sri Harsha Varma Uppalapati] - [https://www.linkedin.com/in/sri-harsha-varma-uppalapati LinkedIn]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;[mailto:efg@ncsu.edu Mentor: Dr. Edward F Gehringer]&amp;lt;/b&amp;gt; - [https://www.ece.ncsu.edu/people/efg/ Website]&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
1.[https://github.com/expertiza/expertiza/ Expertiza on GitHub]&lt;br /&gt;
&lt;br /&gt;
2.[https://github.com/ramyananth/expertiza GitHub Project Repository Fork]&lt;br /&gt;
&lt;br /&gt;
3.[http://expertiza.ncsu.edu/ Live Expertiza website]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132624</id>
		<title>CSC/ECE 517 Spring 2020 - E2003. Refactor and improve assessment360 controller</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132624"/>
		<updated>2020-04-01T03:21:26Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: /* Pull Request */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source project based on [http://rubyonrails.org/ Ruby on Rails] framework. The software allows the instructor and students with the following privileges,&lt;br /&gt;
&lt;br /&gt;
===Instructors===&lt;br /&gt;
* Create new assignments&lt;br /&gt;
* Customize new or existing assignments&lt;br /&gt;
* Create a list of topics that students can sign up for&lt;br /&gt;
* Give grades/reviews for the students' submissions&lt;br /&gt;
&lt;br /&gt;
===Students===&lt;br /&gt;
* Form teams with other students to work on various projects and assignments&lt;br /&gt;
* Peer review other students' submissions&lt;br /&gt;
&lt;br /&gt;
Note: Expertiza supports submissions across various document types, including URL and wiki pages&lt;br /&gt;
&lt;br /&gt;
==Project Description==&lt;br /&gt;
&lt;br /&gt;
===About assessment_360 Controller===&lt;br /&gt;
The assessment_360 controller is designed to gather data from all stakeholders about the performance of a student in a course. Thus, its purpose is to provide course-level statistics. At present, the controller provides only two top-level functions where each of them gives a list of students in the class. &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; contains teammate and meta-review scores received by students for all assignments in the course&lt;br /&gt;
* &amp;lt;b&amp;gt;course_student_grade_summary &amp;lt;/b&amp;gt; gives a listing of students and what topic they worked on and what grade they received on each assignment during the semester&lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The assessment360 controller had three major issues. This project is aimed to address some of them, including:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 1:&amp;lt;/b&amp;gt; Methods &amp;lt;i&amp;gt;all_students_all_reviews&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;course_student_grade_summary&amp;lt;/i&amp;gt; were too long. Common initialization and looping had to factored out by moving them into smaller methods with mnemonic names&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 2:&amp;lt;/b&amp;gt; Method populate_hash_for_all_students_all_reviews is not easy to understand. It uses a special data structure to do a very simple task. That had to be refactored&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 3:&amp;lt;/b&amp;gt; Method course_student_grade_summary stopped working and has to be fixed&lt;br /&gt;
&lt;br /&gt;
===Motivation===&lt;br /&gt;
This project aims at encouraging students to collaborate and contribute to open-source project in turn helping them understand what goes on in a full-fledged software deployment process. It also paves a way to understand how one can use Rails, RSpec to develop a system that does justice to the DRY code practicing principles.&lt;br /&gt;
&lt;br /&gt;
==Approach==&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 1: Refactoring all_students_all_reviews and course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(a) The common elements in these files i.e., checking if the course participant list is empty or not is moved to a different function called &amp;lt;i&amp;gt;inspect_course_participants&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(b) Adding on to this, all_student_all_review was broken down to two more functions, &amp;lt;i&amp;gt;avg_review_calc_per_student&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;overall_review_count&amp;lt;/i&amp;gt; &lt;br /&gt;
&lt;br /&gt;
(c) The method course_student_grade_summary is broken down to one more function &amp;lt;i&amp;gt;assignment_grade_summary&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 2: Refactoring populate_hash_for_all_students_all_reviews&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The approach in this function is pretty straight forward when we try to break it down. It calculates,&lt;br /&gt;
&lt;br /&gt;
(a) The average score for each assignment for each course&lt;br /&gt;
&lt;br /&gt;
(b) The overall review grade for each assignment for all the students who have taken the course&lt;br /&gt;
&lt;br /&gt;
Passing the average score calculated from (a) checks if the student has teammates which could result in not having an average teammate_review_score. If we calculate (b) in our main function (this can be done) we would be repeating the checks that we are already doing for (a). Hence, this function is not changed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 3: Fix course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The current implementation ran into an issue when it was comparing the Key-Value pair passed in '''peer_review_score'''. It was hard to check if each of the keys were present or not. The proposed solution makes use of a basic hash value presence check that retrieves a value from the array/hash, given a set of keys. If no value is found, it'll return nil.&lt;br /&gt;
&lt;br /&gt;
==Proposed Implementation==&lt;br /&gt;
====Fixing the bug on course_student_grade_summary====&lt;br /&gt;
The current implementation of the method throws a nil error at the moment on the following line,&lt;br /&gt;
&amp;lt;pre&amp;gt;unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is rectified by introducing,&lt;br /&gt;
&amp;lt;pre&amp;gt;next if (peer_review_score[:review] &amp;amp;&amp;amp; peer_review_score[:review][:scores] &amp;amp;&amp;amp; peer_review_score[:review][:scores][:avg]).nil?&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Common refactoring of all_students_all_reviews and course_student_grade_summary method====&lt;br /&gt;
The functionality that the methods shared was that, both of them checked if there were course participants who had taken a particular course. This occupied 4 lines of code in both the functions. So, this is defined in a separate function called insure_existence_of and called from the two functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def insure_existence_of(course_participants)&lt;br /&gt;
    if course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Refactor all_students_all_reviews method====&lt;br /&gt;
The all_students_all_reviews method is one of the biggest methods in assessment360_controller.rb file. It finds the list of all students and assignments pertaining to the course. This data is then used to compute the metareview and teammate review scores for each student.&lt;br /&gt;
&lt;br /&gt;
The code before refactoring had 64 lines of code as shown below,&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   teammate_reviews,&lt;br /&gt;
                                                   @teammate_review,&lt;br /&gt;
                                                   @overall_teammate_review_grades,&lt;br /&gt;
                                                   @overall_teammate_review_count,&lt;br /&gt;
                                                   @teammate_review_info_per_stu)&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   meta_reviews,&lt;br /&gt;
                                                   @meta_review,&lt;br /&gt;
                                                   @overall_meta_review_grades,&lt;br /&gt;
                                                   @overall_meta_review_count,&lt;br /&gt;
                                                   @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      if @teammate_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @teammate_review_info_per_stu[0] * 1.0 / @teammate_review_info_per_stu[1]&lt;br /&gt;
        @teammate_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
      if @meta_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @meta_review_info_per_stu[0] * 1.0 / @meta_review_info_per_stu[1]&lt;br /&gt;
        @meta_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    @assignments.each do |assignment|&lt;br /&gt;
      temp_count = @overall_teammate_review_count[assignment.id]&lt;br /&gt;
      @overall_teammate_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = @overall_meta_review_count[assignment.id]&lt;br /&gt;
      @overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To calculate the average grade for each student on all assignments in this course that a student has taken in this course is refactoring in the base code by adding the avg_review_calc_per_student method. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def avg_review_calc_per_student(cp, review_info_per_stu, review)&lt;br /&gt;
    # check to see if the student has been given a review&lt;br /&gt;
    if review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
      temp_avg_grade = review_info_per_stu[0] * 1.0 / review_info_per_stu[1]&lt;br /&gt;
      review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To avoid a &amp;lt;i&amp;gt;divide by zero error&amp;lt;/i&amp;gt; that is thrown when we try to calculate the average grade when a student has no teammate is handled by the overall_review_count method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def overall_review_count(assignments, overall_teammate_review_count, overall_meta_review_count)&lt;br /&gt;
    assignments.each do |assignment|&lt;br /&gt;
      temp_count = overall_teammate_review_count[assignment.id]&lt;br /&gt;
      overall_review_count_hash[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = overall_meta_review_count[assignment.id]&lt;br /&gt;
      overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''After refactoring'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 teammate_reviews,&lt;br /&gt;
                                 @teammate_review,&lt;br /&gt;
                                 @overall_teammate_review_grades,&lt;br /&gt;
                                 @overall_teammate_review_count,&lt;br /&gt;
                                 @teammate_review_info_per_stu)&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 meta_reviews,&lt;br /&gt;
                                 @meta_review,&lt;br /&gt;
                                 @overall_meta_review_grades,&lt;br /&gt;
                                 @overall_meta_review_count,&lt;br /&gt;
                                 @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      avg_review_calc_per_student(cp, @teammate_review_info_per_stu, @teammate_review)&lt;br /&gt;
      avg_review_calc_per_student(cp, @meta_review_info_per_stu, @meta_review)&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    overall_review_count(@assignments, @overall_teammate_review_count, @overall_meta_review_count)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Refactor course_student_grade_summary method====&lt;br /&gt;
This method finds the list of all students and assignments pertaining to the course. The data obtained is then used to compute the instructor assigned grade and peer review scores. It was the secong biggest method in the assessment360_controller.rb controller file. The code before refactoring is shown below,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
&lt;br /&gt;
        # A topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
        topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
        @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
&lt;br /&gt;
        # Instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
        team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
        next if team_id.nil?&lt;br /&gt;
&lt;br /&gt;
        team = Team.find(team_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
&lt;br /&gt;
        # Set the assignment grade, peer review score, and sum for the final student summary&lt;br /&gt;
        @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
        unless @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
          @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&lt;br /&gt;
          @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&lt;br /&gt;
        end&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;
In this function, all the functionalities pertaining to a course participant - student in this case, in a given assignment is invoked by introducing a new method called assignment_grade_summary. This method checks if a topic exists and if it does, it passes the final grade that is calculated for that student in that course.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
    user_id = cp.user_id&lt;br /&gt;
    # topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
    topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
    @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
    # instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
    team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
    team = Team.find(team_id)&lt;br /&gt;
    @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
    return if @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
    @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
  end  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''After refactoring'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        # break out of the loop if there are no participants in the assignment&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
        # break out of the loop if the participant has no team&lt;br /&gt;
        next if TeamsUser.team_id(assignment_id, user_id).nil?&lt;br /&gt;
        # pull information about the student's grades for particular assignment&lt;br /&gt;
        assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
        #Skip if there are no peers&lt;br /&gt;
        next if peer_review_score.nil? &lt;br /&gt;
        #Skip if there are no reviews done by peers&lt;br /&gt;
        next if peer_review_score[:review].nil? &lt;br /&gt;
        #Skip if there are no reviews scores assigned by peers&lt;br /&gt;
        next if peer_review_score[:review][:scores].nil?&lt;br /&gt;
        #Skip if there are is no peer review average score&lt;br /&gt;
        next if peer_review_score[:review][:scores][:avg].nil?&lt;br /&gt;
        @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&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;
==Method name explanations==&lt;br /&gt;
One of the methods devised in this project is use nouns instead of verbs. Ideally the name of a variable or method should be enough to identify it's function in the class. This is because assessment_360 controller, of course is an exception and does explain what each of the functions do on their function names,&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; - Find the list of all students and assignments pertaining to the course. This data is used to compute the metareview and teammate review scores.&lt;br /&gt;
*&amp;lt;b&amp;gt;avg_review_calc_per_student&amp;lt;/b&amp;gt; - Calculate the overall average review grade that a student has gotten from their teammate(s) and instructor(s)&lt;br /&gt;
*&amp;lt;b&amp;gt;overall_review_count&amp;lt;/b&amp;gt; - To avoid divide by zero error&lt;br /&gt;
*&amp;lt;b&amp;gt;course_student_grade_summary&amp;lt;/b&amp;gt; - Find the list of all students and assignments pertaining to the course. This data is used to compute the instructor assigned grade and peer review scores.&lt;br /&gt;
*&amp;lt;b&amp;gt;assignment_grade_summary&amp;lt;/b&amp;gt; - To pull information about the student's grades for particular assignment&lt;br /&gt;
*&amp;lt;b&amp;gt;insure_existence_of&amp;lt;/b&amp;gt; - To make sure there are participants for the course&lt;br /&gt;
*&amp;lt;b&amp;gt;calc_overall_review_info&amp;lt;/b&amp;gt; - The function populates the hash value for all students for all the reviews that they have gotten. I.e., Teammate and Meta for each of the assignments that they have taken. This value is then used to display the overall teammate_review and meta_review grade in the view&lt;br /&gt;
*&amp;lt;b&amp;gt;find_peer_review_score&amp;lt;/b&amp;gt; - The peer review score is taken from the questions for the assignment&lt;br /&gt;
&lt;br /&gt;
==Submission==&lt;br /&gt;
===Github Link===&lt;br /&gt;
The changes made to the code is present on this [https://github.com/ramyananth/expertiza link]. Multiple comments and refactoring have been addressed in detail here.&lt;br /&gt;
===Pull Request===&lt;br /&gt;
The initial build made out of pull request [https://github.com/expertiza/expertiza/pull/1691 1691], kept failing continuously since it was made to the master branch of expertiza. It changed the Gemfile.lock and also the database schema. This push was actually made because the beta branch and master branch of expertiza were not different at all. The new pull request [https://github.com/expertiza/expertiza/pull/1713 1713] was made to the beta branch from our beta branch and it worked completely fine.&lt;br /&gt;
&lt;br /&gt;
==Team Information==&lt;br /&gt;
[mailto:rananth2@ncsu.edu Ramya Ananth] - [https://www.linkedin.com/in/ramyananth/ LinkedIn]&lt;br /&gt;
&lt;br /&gt;
[mailto:suppala@ncsu.edu Sri Harsha Varma Uppalapati] - [https://www.linkedin.com/in/sri-harsha-varma-uppalapati LinkedIn]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;[mailto:efg@ncsu.edu Mentor: Dr. Edward F Gehringer]&amp;lt;/b&amp;gt; - [https://www.ece.ncsu.edu/people/efg/ Website]&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
1.[https://github.com/expertiza/expertiza/ Expertiza on GitHub]&lt;br /&gt;
&lt;br /&gt;
2.[https://github.com/ramyananth/expertiza GitHub Project Repository Fork]&lt;br /&gt;
&lt;br /&gt;
3.[http://expertiza.ncsu.edu/ Live Expertiza website]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132622</id>
		<title>CSC/ECE 517 Spring 2020 - E2003. Refactor and improve assessment360 controller</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132622"/>
		<updated>2020-04-01T03:16:50Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: /* Method name explanations */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source project based on [http://rubyonrails.org/ Ruby on Rails] framework. The software allows the instructor and students with the following privileges,&lt;br /&gt;
&lt;br /&gt;
===Instructors===&lt;br /&gt;
* Create new assignments&lt;br /&gt;
* Customize new or existing assignments&lt;br /&gt;
* Create a list of topics that students can sign up for&lt;br /&gt;
* Give grades/reviews for the students' submissions&lt;br /&gt;
&lt;br /&gt;
===Students===&lt;br /&gt;
* Form teams with other students to work on various projects and assignments&lt;br /&gt;
* Peer review other students' submissions&lt;br /&gt;
&lt;br /&gt;
Note: Expertiza supports submissions across various document types, including URL and wiki pages&lt;br /&gt;
&lt;br /&gt;
==Project Description==&lt;br /&gt;
&lt;br /&gt;
===About assessment_360 Controller===&lt;br /&gt;
The assessment_360 controller is designed to gather data from all stakeholders about the performance of a student in a course. Thus, its purpose is to provide course-level statistics. At present, the controller provides only two top-level functions where each of them gives a list of students in the class. &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; contains teammate and meta-review scores received by students for all assignments in the course&lt;br /&gt;
* &amp;lt;b&amp;gt;course_student_grade_summary &amp;lt;/b&amp;gt; gives a listing of students and what topic they worked on and what grade they received on each assignment during the semester&lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The assessment360 controller had three major issues. This project is aimed to address some of them, including:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 1:&amp;lt;/b&amp;gt; Methods &amp;lt;i&amp;gt;all_students_all_reviews&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;course_student_grade_summary&amp;lt;/i&amp;gt; were too long. Common initialization and looping had to factored out by moving them into smaller methods with mnemonic names&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 2:&amp;lt;/b&amp;gt; Method populate_hash_for_all_students_all_reviews is not easy to understand. It uses a special data structure to do a very simple task. That had to be refactored&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 3:&amp;lt;/b&amp;gt; Method course_student_grade_summary stopped working and has to be fixed&lt;br /&gt;
&lt;br /&gt;
===Motivation===&lt;br /&gt;
This project aims at encouraging students to collaborate and contribute to open-source project in turn helping them understand what goes on in a full-fledged software deployment process. It also paves a way to understand how one can use Rails, RSpec to develop a system that does justice to the DRY code practicing principles.&lt;br /&gt;
&lt;br /&gt;
==Approach==&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 1: Refactoring all_students_all_reviews and course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(a) The common elements in these files i.e., checking if the course participant list is empty or not is moved to a different function called &amp;lt;i&amp;gt;inspect_course_participants&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(b) Adding on to this, all_student_all_review was broken down to two more functions, &amp;lt;i&amp;gt;avg_review_calc_per_student&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;overall_review_count&amp;lt;/i&amp;gt; &lt;br /&gt;
&lt;br /&gt;
(c) The method course_student_grade_summary is broken down to one more function &amp;lt;i&amp;gt;assignment_grade_summary&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 2: Refactoring populate_hash_for_all_students_all_reviews&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The approach in this function is pretty straight forward when we try to break it down. It calculates,&lt;br /&gt;
&lt;br /&gt;
(a) The average score for each assignment for each course&lt;br /&gt;
&lt;br /&gt;
(b) The overall review grade for each assignment for all the students who have taken the course&lt;br /&gt;
&lt;br /&gt;
Passing the average score calculated from (a) checks if the student has teammates which could result in not having an average teammate_review_score. If we calculate (b) in our main function (this can be done) we would be repeating the checks that we are already doing for (a). Hence, this function is not changed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 3: Fix course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The current implementation ran into an issue when it was comparing the Key-Value pair passed in '''peer_review_score'''. It was hard to check if each of the keys were present or not. The proposed solution makes use of a basic hash value presence check that retrieves a value from the array/hash, given a set of keys. If no value is found, it'll return nil.&lt;br /&gt;
&lt;br /&gt;
==Proposed Implementation==&lt;br /&gt;
====Fixing the bug on course_student_grade_summary====&lt;br /&gt;
The current implementation of the method throws a nil error at the moment on the following line,&lt;br /&gt;
&amp;lt;pre&amp;gt;unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is rectified by introducing,&lt;br /&gt;
&amp;lt;pre&amp;gt;next if (peer_review_score[:review] &amp;amp;&amp;amp; peer_review_score[:review][:scores] &amp;amp;&amp;amp; peer_review_score[:review][:scores][:avg]).nil?&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Common refactoring of all_students_all_reviews and course_student_grade_summary method====&lt;br /&gt;
The functionality that the methods shared was that, both of them checked if there were course participants who had taken a particular course. This occupied 4 lines of code in both the functions. So, this is defined in a separate function called insure_existence_of and called from the two functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def insure_existence_of(course_participants)&lt;br /&gt;
    if course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Refactor all_students_all_reviews method====&lt;br /&gt;
The all_students_all_reviews method is one of the biggest methods in assessment360_controller.rb file. It finds the list of all students and assignments pertaining to the course. This data is then used to compute the metareview and teammate review scores for each student.&lt;br /&gt;
&lt;br /&gt;
The code before refactoring had 64 lines of code as shown below,&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   teammate_reviews,&lt;br /&gt;
                                                   @teammate_review,&lt;br /&gt;
                                                   @overall_teammate_review_grades,&lt;br /&gt;
                                                   @overall_teammate_review_count,&lt;br /&gt;
                                                   @teammate_review_info_per_stu)&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   meta_reviews,&lt;br /&gt;
                                                   @meta_review,&lt;br /&gt;
                                                   @overall_meta_review_grades,&lt;br /&gt;
                                                   @overall_meta_review_count,&lt;br /&gt;
                                                   @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      if @teammate_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @teammate_review_info_per_stu[0] * 1.0 / @teammate_review_info_per_stu[1]&lt;br /&gt;
        @teammate_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
      if @meta_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @meta_review_info_per_stu[0] * 1.0 / @meta_review_info_per_stu[1]&lt;br /&gt;
        @meta_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    @assignments.each do |assignment|&lt;br /&gt;
      temp_count = @overall_teammate_review_count[assignment.id]&lt;br /&gt;
      @overall_teammate_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = @overall_meta_review_count[assignment.id]&lt;br /&gt;
      @overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To calculate the average grade for each student on all assignments in this course that a student has taken in this course is refactoring in the base code by adding the avg_review_calc_per_student method. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def avg_review_calc_per_student(cp, review_info_per_stu, review)&lt;br /&gt;
    # check to see if the student has been given a review&lt;br /&gt;
    if review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
      temp_avg_grade = review_info_per_stu[0] * 1.0 / review_info_per_stu[1]&lt;br /&gt;
      review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To avoid a &amp;lt;i&amp;gt;divide by zero error&amp;lt;/i&amp;gt; that is thrown when we try to calculate the average grade when a student has no teammate is handled by the overall_review_count method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def overall_review_count(assignments, overall_teammate_review_count, overall_meta_review_count)&lt;br /&gt;
    assignments.each do |assignment|&lt;br /&gt;
      temp_count = overall_teammate_review_count[assignment.id]&lt;br /&gt;
      overall_review_count_hash[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = overall_meta_review_count[assignment.id]&lt;br /&gt;
      overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''After refactoring'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 teammate_reviews,&lt;br /&gt;
                                 @teammate_review,&lt;br /&gt;
                                 @overall_teammate_review_grades,&lt;br /&gt;
                                 @overall_teammate_review_count,&lt;br /&gt;
                                 @teammate_review_info_per_stu)&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 meta_reviews,&lt;br /&gt;
                                 @meta_review,&lt;br /&gt;
                                 @overall_meta_review_grades,&lt;br /&gt;
                                 @overall_meta_review_count,&lt;br /&gt;
                                 @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      avg_review_calc_per_student(cp, @teammate_review_info_per_stu, @teammate_review)&lt;br /&gt;
      avg_review_calc_per_student(cp, @meta_review_info_per_stu, @meta_review)&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    overall_review_count(@assignments, @overall_teammate_review_count, @overall_meta_review_count)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Refactor course_student_grade_summary method====&lt;br /&gt;
This method finds the list of all students and assignments pertaining to the course. The data obtained is then used to compute the instructor assigned grade and peer review scores. It was the secong biggest method in the assessment360_controller.rb controller file. The code before refactoring is shown below,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
&lt;br /&gt;
        # A topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
        topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
        @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
&lt;br /&gt;
        # Instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
        team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
        next if team_id.nil?&lt;br /&gt;
&lt;br /&gt;
        team = Team.find(team_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
&lt;br /&gt;
        # Set the assignment grade, peer review score, and sum for the final student summary&lt;br /&gt;
        @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
        unless @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
          @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&lt;br /&gt;
          @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&lt;br /&gt;
        end&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;
In this function, all the functionalities pertaining to a course participant - student in this case, in a given assignment is invoked by introducing a new method called assignment_grade_summary. This method checks if a topic exists and if it does, it passes the final grade that is calculated for that student in that course.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
    user_id = cp.user_id&lt;br /&gt;
    # topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
    topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
    @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
    # instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
    team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
    team = Team.find(team_id)&lt;br /&gt;
    @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
    return if @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
    @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
  end  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''After refactoring'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        # break out of the loop if there are no participants in the assignment&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
        # break out of the loop if the participant has no team&lt;br /&gt;
        next if TeamsUser.team_id(assignment_id, user_id).nil?&lt;br /&gt;
        # pull information about the student's grades for particular assignment&lt;br /&gt;
        assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
        #Skip if there are no peers&lt;br /&gt;
        next if peer_review_score.nil? &lt;br /&gt;
        #Skip if there are no reviews done by peers&lt;br /&gt;
        next if peer_review_score[:review].nil? &lt;br /&gt;
        #Skip if there are no reviews scores assigned by peers&lt;br /&gt;
        next if peer_review_score[:review][:scores].nil?&lt;br /&gt;
        #Skip if there are is no peer review average score&lt;br /&gt;
        next if peer_review_score[:review][:scores][:avg].nil?&lt;br /&gt;
        @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&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;
==Method name explanations==&lt;br /&gt;
One of the methods devised in this project is use nouns instead of verbs. Ideally the name of a variable or method should be enough to identify it's function in the class. This is because assessment_360 controller, of course is an exception and does explain what each of the functions do on their function names,&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; - Find the list of all students and assignments pertaining to the course. This data is used to compute the metareview and teammate review scores.&lt;br /&gt;
*&amp;lt;b&amp;gt;avg_review_calc_per_student&amp;lt;/b&amp;gt; - Calculate the overall average review grade that a student has gotten from their teammate(s) and instructor(s)&lt;br /&gt;
*&amp;lt;b&amp;gt;overall_review_count&amp;lt;/b&amp;gt; - To avoid divide by zero error&lt;br /&gt;
*&amp;lt;b&amp;gt;course_student_grade_summary&amp;lt;/b&amp;gt; - Find the list of all students and assignments pertaining to the course. This data is used to compute the instructor assigned grade and peer review scores.&lt;br /&gt;
*&amp;lt;b&amp;gt;assignment_grade_summary&amp;lt;/b&amp;gt; - To pull information about the student's grades for particular assignment&lt;br /&gt;
*&amp;lt;b&amp;gt;insure_existence_of&amp;lt;/b&amp;gt; - To make sure there are participants for the course&lt;br /&gt;
*&amp;lt;b&amp;gt;calc_overall_review_info&amp;lt;/b&amp;gt; - The function populates the hash value for all students for all the reviews that they have gotten. I.e., Teammate and Meta for each of the assignments that they have taken. This value is then used to display the overall teammate_review and meta_review grade in the view&lt;br /&gt;
*&amp;lt;b&amp;gt;find_peer_review_score&amp;lt;/b&amp;gt; - The peer review score is taken from the questions for the assignment&lt;br /&gt;
&lt;br /&gt;
==Pull Request==&lt;br /&gt;
The initial pull request&lt;br /&gt;
&lt;br /&gt;
==Team Information==&lt;br /&gt;
[mailto:rananth2@ncsu.edu Ramya Ananth] - [https://www.linkedin.com/in/ramyananth/ LinkedIn]&lt;br /&gt;
&lt;br /&gt;
[mailto:suppala@ncsu.edu Sri Harsha Varma Uppalapati] - [https://www.linkedin.com/in/sri-harsha-varma-uppalapati LinkedIn]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;[mailto:efg@ncsu.edu Mentor: Dr. Edward F Gehringer]&amp;lt;/b&amp;gt; - [https://www.ece.ncsu.edu/people/efg/ Website]&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
1.[https://github.com/expertiza/expertiza/ Expertiza on GitHub]&lt;br /&gt;
&lt;br /&gt;
2.[https://github.com/ramyananth/expertiza GitHub Project Repository Fork]&lt;br /&gt;
&lt;br /&gt;
3.[http://expertiza.ncsu.edu/ Live Expertiza website]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132621</id>
		<title>CSC/ECE 517 Spring 2020 - E2003. Refactor and improve assessment360 controller</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132621"/>
		<updated>2020-04-01T03:16:31Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source project based on [http://rubyonrails.org/ Ruby on Rails] framework. The software allows the instructor and students with the following privileges,&lt;br /&gt;
&lt;br /&gt;
===Instructors===&lt;br /&gt;
* Create new assignments&lt;br /&gt;
* Customize new or existing assignments&lt;br /&gt;
* Create a list of topics that students can sign up for&lt;br /&gt;
* Give grades/reviews for the students' submissions&lt;br /&gt;
&lt;br /&gt;
===Students===&lt;br /&gt;
* Form teams with other students to work on various projects and assignments&lt;br /&gt;
* Peer review other students' submissions&lt;br /&gt;
&lt;br /&gt;
Note: Expertiza supports submissions across various document types, including URL and wiki pages&lt;br /&gt;
&lt;br /&gt;
==Project Description==&lt;br /&gt;
&lt;br /&gt;
===About assessment_360 Controller===&lt;br /&gt;
The assessment_360 controller is designed to gather data from all stakeholders about the performance of a student in a course. Thus, its purpose is to provide course-level statistics. At present, the controller provides only two top-level functions where each of them gives a list of students in the class. &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; contains teammate and meta-review scores received by students for all assignments in the course&lt;br /&gt;
* &amp;lt;b&amp;gt;course_student_grade_summary &amp;lt;/b&amp;gt; gives a listing of students and what topic they worked on and what grade they received on each assignment during the semester&lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The assessment360 controller had three major issues. This project is aimed to address some of them, including:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 1:&amp;lt;/b&amp;gt; Methods &amp;lt;i&amp;gt;all_students_all_reviews&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;course_student_grade_summary&amp;lt;/i&amp;gt; were too long. Common initialization and looping had to factored out by moving them into smaller methods with mnemonic names&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 2:&amp;lt;/b&amp;gt; Method populate_hash_for_all_students_all_reviews is not easy to understand. It uses a special data structure to do a very simple task. That had to be refactored&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 3:&amp;lt;/b&amp;gt; Method course_student_grade_summary stopped working and has to be fixed&lt;br /&gt;
&lt;br /&gt;
===Motivation===&lt;br /&gt;
This project aims at encouraging students to collaborate and contribute to open-source project in turn helping them understand what goes on in a full-fledged software deployment process. It also paves a way to understand how one can use Rails, RSpec to develop a system that does justice to the DRY code practicing principles.&lt;br /&gt;
&lt;br /&gt;
==Approach==&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 1: Refactoring all_students_all_reviews and course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(a) The common elements in these files i.e., checking if the course participant list is empty or not is moved to a different function called &amp;lt;i&amp;gt;inspect_course_participants&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(b) Adding on to this, all_student_all_review was broken down to two more functions, &amp;lt;i&amp;gt;avg_review_calc_per_student&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;overall_review_count&amp;lt;/i&amp;gt; &lt;br /&gt;
&lt;br /&gt;
(c) The method course_student_grade_summary is broken down to one more function &amp;lt;i&amp;gt;assignment_grade_summary&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 2: Refactoring populate_hash_for_all_students_all_reviews&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The approach in this function is pretty straight forward when we try to break it down. It calculates,&lt;br /&gt;
&lt;br /&gt;
(a) The average score for each assignment for each course&lt;br /&gt;
&lt;br /&gt;
(b) The overall review grade for each assignment for all the students who have taken the course&lt;br /&gt;
&lt;br /&gt;
Passing the average score calculated from (a) checks if the student has teammates which could result in not having an average teammate_review_score. If we calculate (b) in our main function (this can be done) we would be repeating the checks that we are already doing for (a). Hence, this function is not changed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 3: Fix course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The current implementation ran into an issue when it was comparing the Key-Value pair passed in '''peer_review_score'''. It was hard to check if each of the keys were present or not. The proposed solution makes use of a basic hash value presence check that retrieves a value from the array/hash, given a set of keys. If no value is found, it'll return nil.&lt;br /&gt;
&lt;br /&gt;
==Proposed Implementation==&lt;br /&gt;
====Fixing the bug on course_student_grade_summary====&lt;br /&gt;
The current implementation of the method throws a nil error at the moment on the following line,&lt;br /&gt;
&amp;lt;pre&amp;gt;unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is rectified by introducing,&lt;br /&gt;
&amp;lt;pre&amp;gt;next if (peer_review_score[:review] &amp;amp;&amp;amp; peer_review_score[:review][:scores] &amp;amp;&amp;amp; peer_review_score[:review][:scores][:avg]).nil?&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Common refactoring of all_students_all_reviews and course_student_grade_summary method====&lt;br /&gt;
The functionality that the methods shared was that, both of them checked if there were course participants who had taken a particular course. This occupied 4 lines of code in both the functions. So, this is defined in a separate function called insure_existence_of and called from the two functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def insure_existence_of(course_participants)&lt;br /&gt;
    if course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Refactor all_students_all_reviews method====&lt;br /&gt;
The all_students_all_reviews method is one of the biggest methods in assessment360_controller.rb file. It finds the list of all students and assignments pertaining to the course. This data is then used to compute the metareview and teammate review scores for each student.&lt;br /&gt;
&lt;br /&gt;
The code before refactoring had 64 lines of code as shown below,&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   teammate_reviews,&lt;br /&gt;
                                                   @teammate_review,&lt;br /&gt;
                                                   @overall_teammate_review_grades,&lt;br /&gt;
                                                   @overall_teammate_review_count,&lt;br /&gt;
                                                   @teammate_review_info_per_stu)&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   meta_reviews,&lt;br /&gt;
                                                   @meta_review,&lt;br /&gt;
                                                   @overall_meta_review_grades,&lt;br /&gt;
                                                   @overall_meta_review_count,&lt;br /&gt;
                                                   @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      if @teammate_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @teammate_review_info_per_stu[0] * 1.0 / @teammate_review_info_per_stu[1]&lt;br /&gt;
        @teammate_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
      if @meta_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @meta_review_info_per_stu[0] * 1.0 / @meta_review_info_per_stu[1]&lt;br /&gt;
        @meta_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    @assignments.each do |assignment|&lt;br /&gt;
      temp_count = @overall_teammate_review_count[assignment.id]&lt;br /&gt;
      @overall_teammate_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = @overall_meta_review_count[assignment.id]&lt;br /&gt;
      @overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To calculate the average grade for each student on all assignments in this course that a student has taken in this course is refactoring in the base code by adding the avg_review_calc_per_student method. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def avg_review_calc_per_student(cp, review_info_per_stu, review)&lt;br /&gt;
    # check to see if the student has been given a review&lt;br /&gt;
    if review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
      temp_avg_grade = review_info_per_stu[0] * 1.0 / review_info_per_stu[1]&lt;br /&gt;
      review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To avoid a &amp;lt;i&amp;gt;divide by zero error&amp;lt;/i&amp;gt; that is thrown when we try to calculate the average grade when a student has no teammate is handled by the overall_review_count method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def overall_review_count(assignments, overall_teammate_review_count, overall_meta_review_count)&lt;br /&gt;
    assignments.each do |assignment|&lt;br /&gt;
      temp_count = overall_teammate_review_count[assignment.id]&lt;br /&gt;
      overall_review_count_hash[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = overall_meta_review_count[assignment.id]&lt;br /&gt;
      overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''After refactoring'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 teammate_reviews,&lt;br /&gt;
                                 @teammate_review,&lt;br /&gt;
                                 @overall_teammate_review_grades,&lt;br /&gt;
                                 @overall_teammate_review_count,&lt;br /&gt;
                                 @teammate_review_info_per_stu)&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 meta_reviews,&lt;br /&gt;
                                 @meta_review,&lt;br /&gt;
                                 @overall_meta_review_grades,&lt;br /&gt;
                                 @overall_meta_review_count,&lt;br /&gt;
                                 @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      avg_review_calc_per_student(cp, @teammate_review_info_per_stu, @teammate_review)&lt;br /&gt;
      avg_review_calc_per_student(cp, @meta_review_info_per_stu, @meta_review)&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    overall_review_count(@assignments, @overall_teammate_review_count, @overall_meta_review_count)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Refactor course_student_grade_summary method====&lt;br /&gt;
This method finds the list of all students and assignments pertaining to the course. The data obtained is then used to compute the instructor assigned grade and peer review scores. It was the secong biggest method in the assessment360_controller.rb controller file. The code before refactoring is shown below,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
&lt;br /&gt;
        # A topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
        topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
        @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
&lt;br /&gt;
        # Instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
        team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
        next if team_id.nil?&lt;br /&gt;
&lt;br /&gt;
        team = Team.find(team_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
&lt;br /&gt;
        # Set the assignment grade, peer review score, and sum for the final student summary&lt;br /&gt;
        @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
        unless @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
          @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&lt;br /&gt;
          @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&lt;br /&gt;
        end&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;
In this function, all the functionalities pertaining to a course participant - student in this case, in a given assignment is invoked by introducing a new method called assignment_grade_summary. This method checks if a topic exists and if it does, it passes the final grade that is calculated for that student in that course.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
    user_id = cp.user_id&lt;br /&gt;
    # topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
    topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
    @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
    # instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
    team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
    team = Team.find(team_id)&lt;br /&gt;
    @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
    return if @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
    @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
  end  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''After refactoring'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        # break out of the loop if there are no participants in the assignment&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
        # break out of the loop if the participant has no team&lt;br /&gt;
        next if TeamsUser.team_id(assignment_id, user_id).nil?&lt;br /&gt;
        # pull information about the student's grades for particular assignment&lt;br /&gt;
        assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
        #Skip if there are no peers&lt;br /&gt;
        next if peer_review_score.nil? &lt;br /&gt;
        #Skip if there are no reviews done by peers&lt;br /&gt;
        next if peer_review_score[:review].nil? &lt;br /&gt;
        #Skip if there are no reviews scores assigned by peers&lt;br /&gt;
        next if peer_review_score[:review][:scores].nil?&lt;br /&gt;
        #Skip if there are is no peer review average score&lt;br /&gt;
        next if peer_review_score[:review][:scores][:avg].nil?&lt;br /&gt;
        @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&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;
====Method name explanations====&lt;br /&gt;
One of the methods devised in this project is use nouns instead of verbs. Ideally the name of a variable or method should be enough to identify it's function in the class. This is because assessment_360 controller, of course is an exception and does explain what each of the functions do on their function names,&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; - Find the list of all students and assignments pertaining to the course. This data is used to compute the metareview and teammate review scores.&lt;br /&gt;
*&amp;lt;b&amp;gt;avg_review_calc_per_student&amp;lt;/b&amp;gt; - Calculate the overall average review grade that a student has gotten from their teammate(s) and instructor(s)&lt;br /&gt;
*&amp;lt;b&amp;gt;overall_review_count&amp;lt;/b&amp;gt; - To avoid divide by zero error&lt;br /&gt;
*&amp;lt;b&amp;gt;course_student_grade_summary&amp;lt;/b&amp;gt; - Find the list of all students and assignments pertaining to the course. This data is used to compute the instructor assigned grade and peer review scores.&lt;br /&gt;
*&amp;lt;b&amp;gt;assignment_grade_summary&amp;lt;/b&amp;gt; - To pull information about the student's grades for particular assignment&lt;br /&gt;
*&amp;lt;b&amp;gt;insure_existence_of&amp;lt;/b&amp;gt; - To make sure there are participants for the course&lt;br /&gt;
*&amp;lt;b&amp;gt;calc_overall_review_info&amp;lt;/b&amp;gt; - The function populates the hash value for all students for all the reviews that they have gotten. I.e., Teammate and Meta for each of the assignments that they have taken. This value is then used to display the overall teammate_review and meta_review grade in the view&lt;br /&gt;
*&amp;lt;b&amp;gt;find_peer_review_score&amp;lt;/b&amp;gt; - The peer review score is taken from the questions for the assignment&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Pull Request==&lt;br /&gt;
The initial pull request&lt;br /&gt;
&lt;br /&gt;
==Team Information==&lt;br /&gt;
[mailto:rananth2@ncsu.edu Ramya Ananth] - [https://www.linkedin.com/in/ramyananth/ LinkedIn]&lt;br /&gt;
&lt;br /&gt;
[mailto:suppala@ncsu.edu Sri Harsha Varma Uppalapati] - [https://www.linkedin.com/in/sri-harsha-varma-uppalapati LinkedIn]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;[mailto:efg@ncsu.edu Mentor: Dr. Edward F Gehringer]&amp;lt;/b&amp;gt; - [https://www.ece.ncsu.edu/people/efg/ Website]&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
1.[https://github.com/expertiza/expertiza/ Expertiza on GitHub]&lt;br /&gt;
&lt;br /&gt;
2.[https://github.com/ramyananth/expertiza GitHub Project Repository Fork]&lt;br /&gt;
&lt;br /&gt;
3.[http://expertiza.ncsu.edu/ Live Expertiza website]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132604</id>
		<title>CSC/ECE 517 Spring 2020 - E2003. Refactor and improve assessment360 controller</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132604"/>
		<updated>2020-04-01T02:41:30Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: /* Refactor course_student_grade_summary method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source project based on [http://rubyonrails.org/ Ruby on Rails] framework. The software allows the instructor and students with the following privileges,&lt;br /&gt;
&lt;br /&gt;
===Instructors===&lt;br /&gt;
* Create new assignments&lt;br /&gt;
* Customize new or existing assignments&lt;br /&gt;
* Create a list of topics that students can sign up for&lt;br /&gt;
* Give grades/reviews for the students' submissions&lt;br /&gt;
&lt;br /&gt;
===Students===&lt;br /&gt;
* Form teams with other students to work on various projects and assignments&lt;br /&gt;
* Peer review other students' submissions&lt;br /&gt;
&lt;br /&gt;
Note: Expertiza supports submissions across various document types, including URL and wiki pages&lt;br /&gt;
&lt;br /&gt;
==Project Description==&lt;br /&gt;
&lt;br /&gt;
===About assessment_360 Controller===&lt;br /&gt;
The assessment_360 controller is designed to gather data from all stakeholders about the performance of a student in a course. Thus, its purpose is to provide course-level statistics. At present, the controller provides only two top-level functions where each of them gives a list of students in the class. &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; contains teammate and meta-review scores received by students for all assignments in the course&lt;br /&gt;
* &amp;lt;b&amp;gt;course_student_grade_summary &amp;lt;/b&amp;gt; gives a listing of students and what topic they worked on and what grade they received on each assignment during the semester&lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The assessment360 controller had three major issues. This project is aimed to address some of them, including:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 1:&amp;lt;/b&amp;gt; Methods &amp;lt;i&amp;gt;all_students_all_reviews&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;course_student_grade_summary&amp;lt;/i&amp;gt; were too long. Common initialization and looping had to factored out by moving them into smaller methods with mnemonic names&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 2:&amp;lt;/b&amp;gt; Method populate_hash_for_all_students_all_reviews is not easy to understand. It uses a special data structure to do a very simple task. That had to be refactored&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 3:&amp;lt;/b&amp;gt; Method course_student_grade_summary stopped working and has to be fixed&lt;br /&gt;
&lt;br /&gt;
===Motivation===&lt;br /&gt;
This project aims at encouraging students to collaborate and contribute to open-source project in turn helping them understand what goes on in a full-fledged software deployment process. It also paves a way to understand how one can use Rails, RSpec to develop a system that does justice to the DRY code practicing principles.&lt;br /&gt;
&lt;br /&gt;
==Approach==&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 1: Refactoring all_students_all_reviews and course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(a) The common elements in these files i.e., checking if the course participant list is empty or not is moved to a different function called &amp;lt;i&amp;gt;inspect_course_participants&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(b) Adding on to this, all_student_all_review was broken down to two more functions, &amp;lt;i&amp;gt;avg_review_calc_per_student&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;overall_review_count&amp;lt;/i&amp;gt; &lt;br /&gt;
&lt;br /&gt;
(c) The method course_student_grade_summary is broken down to one more function &amp;lt;i&amp;gt;assignment_grade_summary&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 2: Refactoring populate_hash_for_all_students_all_reviews&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The approach in this function is pretty straight forward when we try to break it down. It calculates,&lt;br /&gt;
&lt;br /&gt;
(a) The average score for each assignment for each course&lt;br /&gt;
&lt;br /&gt;
(b) The overall review grade for each assignment for all the students who have taken the course&lt;br /&gt;
&lt;br /&gt;
Passing the average score calculated from (a) checks if the student has teammates which could result in not having an average teammate_review_score. If we calculate (b) in our main function (this can be done) we would be repeating the checks that we are already doing for (a). Hence, this function is not changed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 3: Fix course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The current implementation ran into an issue when it was comparing the Key-Value pair passed in '''peer_review_score'''. It was hard to check if each of the keys were present or not. The proposed solution makes use of a basic hash value presence check that retrieves a value from the array/hash, given a set of keys. If no value is found, it'll return nil.&lt;br /&gt;
&lt;br /&gt;
==Proposed Implementation==&lt;br /&gt;
====Fixing the bug on course_student_grade_summary====&lt;br /&gt;
The current implementation of the method throws a nil error at the moment on the following line,&lt;br /&gt;
&amp;lt;pre&amp;gt;unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is rectified by introducing,&lt;br /&gt;
&amp;lt;pre&amp;gt;next if (peer_review_score[:review] &amp;amp;&amp;amp; peer_review_score[:review][:scores] &amp;amp;&amp;amp; peer_review_score[:review][:scores][:avg]).nil?&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Common refactoring of all_students_all_reviews and course_student_grade_summary method====&lt;br /&gt;
The functionality that the methods shared was that, both of them checked if there were course participants who had taken a particular course. This occupied 4 lines of code in both the functions. So, this is defined in a separate function called insure_existence_of and called from the two functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def insure_existence_of(course_participants)&lt;br /&gt;
    if course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Refactor all_students_all_reviews method====&lt;br /&gt;
The all_students_all_reviews method is one of the biggest methods in assessment360_controller.rb file. It finds the list of all students and assignments pertaining to the course. This data is then used to compute the metareview and teammate review scores for each student.&lt;br /&gt;
&lt;br /&gt;
The code before refactoring had 64 lines of code as shown below,&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   teammate_reviews,&lt;br /&gt;
                                                   @teammate_review,&lt;br /&gt;
                                                   @overall_teammate_review_grades,&lt;br /&gt;
                                                   @overall_teammate_review_count,&lt;br /&gt;
                                                   @teammate_review_info_per_stu)&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   meta_reviews,&lt;br /&gt;
                                                   @meta_review,&lt;br /&gt;
                                                   @overall_meta_review_grades,&lt;br /&gt;
                                                   @overall_meta_review_count,&lt;br /&gt;
                                                   @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      if @teammate_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @teammate_review_info_per_stu[0] * 1.0 / @teammate_review_info_per_stu[1]&lt;br /&gt;
        @teammate_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
      if @meta_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @meta_review_info_per_stu[0] * 1.0 / @meta_review_info_per_stu[1]&lt;br /&gt;
        @meta_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    @assignments.each do |assignment|&lt;br /&gt;
      temp_count = @overall_teammate_review_count[assignment.id]&lt;br /&gt;
      @overall_teammate_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = @overall_meta_review_count[assignment.id]&lt;br /&gt;
      @overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To calculate the average grade for each student on all assignments in this course that a student has taken in this course is refactoring in the base code by adding the avg_review_calc_per_student method. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def avg_review_calc_per_student(cp, review_info_per_stu, review)&lt;br /&gt;
    # check to see if the student has been given a review&lt;br /&gt;
    if review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
      temp_avg_grade = review_info_per_stu[0] * 1.0 / review_info_per_stu[1]&lt;br /&gt;
      review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To avoid a &amp;lt;i&amp;gt;divide by zero error&amp;lt;/i&amp;gt; that is thrown when we try to calculate the average grade when a student has no teammate is handled by the overall_review_count method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def overall_review_count(assignments, overall_teammate_review_count, overall_meta_review_count)&lt;br /&gt;
    assignments.each do |assignment|&lt;br /&gt;
      temp_count = overall_teammate_review_count[assignment.id]&lt;br /&gt;
      overall_review_count_hash[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = overall_meta_review_count[assignment.id]&lt;br /&gt;
      overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''After refactoring'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 teammate_reviews,&lt;br /&gt;
                                 @teammate_review,&lt;br /&gt;
                                 @overall_teammate_review_grades,&lt;br /&gt;
                                 @overall_teammate_review_count,&lt;br /&gt;
                                 @teammate_review_info_per_stu)&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 meta_reviews,&lt;br /&gt;
                                 @meta_review,&lt;br /&gt;
                                 @overall_meta_review_grades,&lt;br /&gt;
                                 @overall_meta_review_count,&lt;br /&gt;
                                 @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      avg_review_calc_per_student(cp, @teammate_review_info_per_stu, @teammate_review)&lt;br /&gt;
      avg_review_calc_per_student(cp, @meta_review_info_per_stu, @meta_review)&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    overall_review_count(@assignments, @overall_teammate_review_count, @overall_meta_review_count)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Refactor course_student_grade_summary method====&lt;br /&gt;
This method finds the list of all students and assignments pertaining to the course. The data obtained is then used to compute the instructor assigned grade and peer review scores. It was the secong biggest method in the assessment360_controller.rb controller file. The code before refactoring is shown below,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
&lt;br /&gt;
        # A topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
        topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
        @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
&lt;br /&gt;
        # Instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
        team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
        next if team_id.nil?&lt;br /&gt;
&lt;br /&gt;
        team = Team.find(team_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
&lt;br /&gt;
        # Set the assignment grade, peer review score, and sum for the final student summary&lt;br /&gt;
        @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
        unless @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
          @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&lt;br /&gt;
          @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&lt;br /&gt;
        end&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;
In this function, all the functionalities pertaining to a course participant - student in this case, in a given assignment is invoked by introducing a new method called assignment_grade_summary. This method checks if a topic exists and if it does, it passes the final grade that is calculated for that student in that course.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
    user_id = cp.user_id&lt;br /&gt;
    # topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
    topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
    @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
    # instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
    team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
    team = Team.find(team_id)&lt;br /&gt;
    @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
    return if @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
    @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
  end  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''After refactoring'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        # break out of the loop if there are no participants in the assignment&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
        # break out of the loop if the participant has no team&lt;br /&gt;
        next if TeamsUser.team_id(assignment_id, user_id).nil?&lt;br /&gt;
        # pull information about the student's grades for particular assignment&lt;br /&gt;
        assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
        #Skip if there are no peers&lt;br /&gt;
        next if peer_review_score.nil? &lt;br /&gt;
        #Skip if there are no reviews done by peers&lt;br /&gt;
        next if peer_review_score[:review].nil? &lt;br /&gt;
        #Skip if there are no reviews scores assigned by peers&lt;br /&gt;
        next if peer_review_score[:review][:scores].nil?&lt;br /&gt;
        #Skip if there are is no peer review average score&lt;br /&gt;
        next if peer_review_score[:review][:scores][:avg].nil?&lt;br /&gt;
        @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&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;
==Team Information==&lt;br /&gt;
[mailto:rananth2@ncsu.edu Ramya Ananth] - [https://www.linkedin.com/in/ramyananth/ LinkedIn]&lt;br /&gt;
&lt;br /&gt;
[mailto:suppala@ncsu.edu Sri Harsha Varma Uppalapati] - [https://www.linkedin.com/in/sri-harsha-varma-uppalapati LinkedIn]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;[mailto:efg@ncsu.edu Mentor: Dr. Edward F Gehringer]&amp;lt;/b&amp;gt; - [https://www.ece.ncsu.edu/people/efg/ Website]&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
1.[https://github.com/expertiza/expertiza/ Expertiza on GitHub]&lt;br /&gt;
&lt;br /&gt;
2.[https://github.com/ramyananth/expertiza GitHub Project Repository Fork]&lt;br /&gt;
&lt;br /&gt;
3.[http://expertiza.ncsu.edu/ Live Expertiza website]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132119</id>
		<title>CSC/ECE 517 Spring 2020 - E2003. Refactor and improve assessment360 controller</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132119"/>
		<updated>2020-03-24T04:00:48Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: /* Refactor course_student_grade_summary method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source project based on [http://rubyonrails.org/ Ruby on Rails] framework. The software allows the instructor and students with the following privileges,&lt;br /&gt;
&lt;br /&gt;
===Instructors===&lt;br /&gt;
* Create new assignments&lt;br /&gt;
* Customize new or existing assignments&lt;br /&gt;
* Create a list of topics that students can sign up for&lt;br /&gt;
* Give grades/reviews for the students' submissions&lt;br /&gt;
&lt;br /&gt;
===Students===&lt;br /&gt;
* Form teams with other students to work on various projects and assignments&lt;br /&gt;
* Peer review other students' submissions&lt;br /&gt;
&lt;br /&gt;
Note: Expertiza supports submissions across various document types, including URL and wiki pages&lt;br /&gt;
&lt;br /&gt;
==Project Description==&lt;br /&gt;
&lt;br /&gt;
===About assessment_360 Controller===&lt;br /&gt;
The assessment_360 controller is designed to gather data from all stakeholders about the performance of a student in a course. Thus, its purpose is to provide course-level statistics. At present, the controller provides only two top-level functions where each of them gives a list of students in the class. &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; contains teammate and meta-review scores received by students for all assignments in the course&lt;br /&gt;
* &amp;lt;b&amp;gt;course_student_grade_summary &amp;lt;/b&amp;gt; gives a listing of students and what topic they worked on and what grade they received on each assignment during the semester&lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The assessment360 controller had three major issues. This project is aimed to address some of them, including:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 1:&amp;lt;/b&amp;gt; Methods &amp;lt;i&amp;gt;all_students_all_reviews&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;course_student_grade_summary&amp;lt;/i&amp;gt; were too long. Common initialization and looping had to factored out by moving them into smaller methods with mnemonic names&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 2:&amp;lt;/b&amp;gt; Method populate_hash_for_all_students_all_reviews is not easy to understand. It uses a special data structure to do a very simple task. That had to be refactored&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 3:&amp;lt;/b&amp;gt; Method course_student_grade_summary stopped working and has to be fixed&lt;br /&gt;
&lt;br /&gt;
===Motivation===&lt;br /&gt;
This project aims at encouraging students to collaborate and contribute to open-source project in turn helping them understand what goes on in a full-fledged software deployment process. It also paves a way to understand how one can use Rails, RSpec to develop a system that does justice to the DRY code practicing principles.&lt;br /&gt;
&lt;br /&gt;
==Approach==&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 1: Refactoring all_students_all_reviews and course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(a) The common elements in these files i.e., checking if the course participant list is empty or not is moved to a different function called &amp;lt;i&amp;gt;inspect_course_participants&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(b) Adding on to this, all_student_all_review was broken down to two more functions, &amp;lt;i&amp;gt;avg_review_calc_per_student&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;overall_review_count&amp;lt;/i&amp;gt; &lt;br /&gt;
&lt;br /&gt;
(c) The method course_student_grade_summary is broken down to one more function &amp;lt;i&amp;gt;assignment_grade_summary&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 2: Refactoring populate_hash_for_all_students_all_reviews&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The approach in this function is pretty straight forward when we try to break it down. It calculates,&lt;br /&gt;
&lt;br /&gt;
(a) The average score for each assignment for each course&lt;br /&gt;
&lt;br /&gt;
(b) The overall review grade for each assignment for all the students who have taken the course&lt;br /&gt;
&lt;br /&gt;
Passing the average score calculated from (a) checks if the student has teammates which could result in not having an average teammate_review_score. If we calculate (b) in our main function (this can be done) we would be repeating the checks that we are already doing for (a). Hence, this function is not changed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 3: Fix course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The current implementation ran into an issue when it was comparing the Key-Value pair passed in '''peer_review_score'''. It was hard to check if each of the keys were present or not. The proposed solution makes use of a basic hash value presence check that retrieves a value from the array/hash, given a set of keys. If no value is found, it'll return nil.&lt;br /&gt;
&lt;br /&gt;
==Proposed Implementation==&lt;br /&gt;
====Fixing the bug on course_student_grade_summary====&lt;br /&gt;
The current implementation of the method throws a nil error at the moment on the following line,&lt;br /&gt;
&amp;lt;pre&amp;gt;unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is rectified by introducing,&lt;br /&gt;
&amp;lt;pre&amp;gt;next if (peer_review_score[:review] &amp;amp;&amp;amp; peer_review_score[:review][:scores] &amp;amp;&amp;amp; peer_review_score[:review][:scores][:avg]).nil?&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Common refactoring of all_students_all_reviews and course_student_grade_summary method====&lt;br /&gt;
The functionality that the methods shared was that, both of them checked if there were course participants who had taken a particular course. This occupied 4 lines of code in both the functions. So, this is defined in a separate function called insure_existence_of and called from the two functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def insure_existence_of(course_participants)&lt;br /&gt;
    if course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Refactor all_students_all_reviews method====&lt;br /&gt;
The all_students_all_reviews method is one of the biggest methods in assessment360_controller.rb file. It finds the list of all students and assignments pertaining to the course. This data is then used to compute the metareview and teammate review scores for each student.&lt;br /&gt;
&lt;br /&gt;
The code before refactoring had 64 lines of code as shown below,&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   teammate_reviews,&lt;br /&gt;
                                                   @teammate_review,&lt;br /&gt;
                                                   @overall_teammate_review_grades,&lt;br /&gt;
                                                   @overall_teammate_review_count,&lt;br /&gt;
                                                   @teammate_review_info_per_stu)&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   meta_reviews,&lt;br /&gt;
                                                   @meta_review,&lt;br /&gt;
                                                   @overall_meta_review_grades,&lt;br /&gt;
                                                   @overall_meta_review_count,&lt;br /&gt;
                                                   @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      if @teammate_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @teammate_review_info_per_stu[0] * 1.0 / @teammate_review_info_per_stu[1]&lt;br /&gt;
        @teammate_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
      if @meta_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @meta_review_info_per_stu[0] * 1.0 / @meta_review_info_per_stu[1]&lt;br /&gt;
        @meta_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    @assignments.each do |assignment|&lt;br /&gt;
      temp_count = @overall_teammate_review_count[assignment.id]&lt;br /&gt;
      @overall_teammate_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = @overall_meta_review_count[assignment.id]&lt;br /&gt;
      @overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To calculate the average grade for each student on all assignments in this course that a student has taken in this course is refactoring in the base code by adding the avg_review_calc_per_student method. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def avg_review_calc_per_student(cp, review_info_per_stu, review)&lt;br /&gt;
    # check to see if the student has been given a review&lt;br /&gt;
    if review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
      temp_avg_grade = review_info_per_stu[0] * 1.0 / review_info_per_stu[1]&lt;br /&gt;
      review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To avoid a &amp;lt;i&amp;gt;divide by zero error&amp;lt;/i&amp;gt; that is thrown when we try to calculate the average grade when a student has no teammate is handled by the overall_review_count method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def overall_review_count(assignments, overall_teammate_review_count, overall_meta_review_count)&lt;br /&gt;
    assignments.each do |assignment|&lt;br /&gt;
      temp_count = overall_teammate_review_count[assignment.id]&lt;br /&gt;
      overall_review_count_hash[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = overall_meta_review_count[assignment.id]&lt;br /&gt;
      overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''After refactoring'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 teammate_reviews,&lt;br /&gt;
                                 @teammate_review,&lt;br /&gt;
                                 @overall_teammate_review_grades,&lt;br /&gt;
                                 @overall_teammate_review_count,&lt;br /&gt;
                                 @teammate_review_info_per_stu)&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 meta_reviews,&lt;br /&gt;
                                 @meta_review,&lt;br /&gt;
                                 @overall_meta_review_grades,&lt;br /&gt;
                                 @overall_meta_review_count,&lt;br /&gt;
                                 @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      avg_review_calc_per_student(cp, @teammate_review_info_per_stu, @teammate_review)&lt;br /&gt;
      avg_review_calc_per_student(cp, @meta_review_info_per_stu, @meta_review)&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    overall_review_count(@assignments, @overall_teammate_review_count, @overall_meta_review_count)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Refactor course_student_grade_summary method====&lt;br /&gt;
This method finds the list of all students and assignments pertaining to the course. The data obtained is then used to compute the instructor assigned grade and peer review scores. It was the secong biggest method in the assessment360_controller.rb controller file. The code before refactoring is shown below,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
&lt;br /&gt;
        # A topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
        topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
        @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
&lt;br /&gt;
        # Instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
        team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
        next if team_id.nil?&lt;br /&gt;
&lt;br /&gt;
        team = Team.find(team_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
&lt;br /&gt;
        # Set the assignment grade, peer review score, and sum for the final student summary&lt;br /&gt;
        @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
        unless @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
          @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&lt;br /&gt;
          @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&lt;br /&gt;
        end&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;
In this function, all the functionalities pertaining to a course participant - student in this case, in a given assignment is invoked by introducing a new method called assignment_grade_summary. This method checks if a topic exists and if it does, it passes the final grade that is calculated for that student in that course.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
    user_id = cp.user_id&lt;br /&gt;
    # topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
    topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
    @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
    # instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
    team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
    team = Team.find(team_id)&lt;br /&gt;
    @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
    return if @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
    @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
  end  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''After refactoring'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        # break out of the loop if there are no participants in the assignment&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
        # break out of the loop if the participant has no team&lt;br /&gt;
        next if TeamsUser.team_id(assignment_id, user_id).nil?&lt;br /&gt;
        # pull information about the student's grades for particular assignment&lt;br /&gt;
        assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
        next if (peer_review_score[:review] &amp;amp;&amp;amp; peer_review_score[:review][:scores] &amp;amp;&amp;amp; peer_review_score[:review][:scores][:avg]).nil?&lt;br /&gt;
        @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&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;
==Team Information==&lt;br /&gt;
[mailto:rananth2@ncsu.edu Ramya Ananth] - [https://www.linkedin.com/in/ramyananth/ LinkedIn]&lt;br /&gt;
&lt;br /&gt;
[mailto:suppala@ncsu.edu Sri Harsha Varma Uppalapati] - [https://www.linkedin.com/in/sri-harsha-varma-uppalapati LinkedIn]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;[mailto:efg@ncsu.edu Mentor: Dr. Edward F Gehringer]&amp;lt;/b&amp;gt; - [https://www.ece.ncsu.edu/people/efg/ Website]&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
1.[https://github.com/expertiza/expertiza/ Expertiza on GitHub]&lt;br /&gt;
&lt;br /&gt;
2.[https://github.com/ramyananth/expertiza GitHub Project Repository Fork]&lt;br /&gt;
&lt;br /&gt;
3.[http://expertiza.ncsu.edu/ Live Expertiza website]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132118</id>
		<title>CSC/ECE 517 Spring 2020 - E2003. Refactor and improve assessment360 controller</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132118"/>
		<updated>2020-03-24T04:00:31Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: /* Refactor all_students_all_reviews method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source project based on [http://rubyonrails.org/ Ruby on Rails] framework. The software allows the instructor and students with the following privileges,&lt;br /&gt;
&lt;br /&gt;
===Instructors===&lt;br /&gt;
* Create new assignments&lt;br /&gt;
* Customize new or existing assignments&lt;br /&gt;
* Create a list of topics that students can sign up for&lt;br /&gt;
* Give grades/reviews for the students' submissions&lt;br /&gt;
&lt;br /&gt;
===Students===&lt;br /&gt;
* Form teams with other students to work on various projects and assignments&lt;br /&gt;
* Peer review other students' submissions&lt;br /&gt;
&lt;br /&gt;
Note: Expertiza supports submissions across various document types, including URL and wiki pages&lt;br /&gt;
&lt;br /&gt;
==Project Description==&lt;br /&gt;
&lt;br /&gt;
===About assessment_360 Controller===&lt;br /&gt;
The assessment_360 controller is designed to gather data from all stakeholders about the performance of a student in a course. Thus, its purpose is to provide course-level statistics. At present, the controller provides only two top-level functions where each of them gives a list of students in the class. &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; contains teammate and meta-review scores received by students for all assignments in the course&lt;br /&gt;
* &amp;lt;b&amp;gt;course_student_grade_summary &amp;lt;/b&amp;gt; gives a listing of students and what topic they worked on and what grade they received on each assignment during the semester&lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The assessment360 controller had three major issues. This project is aimed to address some of them, including:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 1:&amp;lt;/b&amp;gt; Methods &amp;lt;i&amp;gt;all_students_all_reviews&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;course_student_grade_summary&amp;lt;/i&amp;gt; were too long. Common initialization and looping had to factored out by moving them into smaller methods with mnemonic names&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 2:&amp;lt;/b&amp;gt; Method populate_hash_for_all_students_all_reviews is not easy to understand. It uses a special data structure to do a very simple task. That had to be refactored&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 3:&amp;lt;/b&amp;gt; Method course_student_grade_summary stopped working and has to be fixed&lt;br /&gt;
&lt;br /&gt;
===Motivation===&lt;br /&gt;
This project aims at encouraging students to collaborate and contribute to open-source project in turn helping them understand what goes on in a full-fledged software deployment process. It also paves a way to understand how one can use Rails, RSpec to develop a system that does justice to the DRY code practicing principles.&lt;br /&gt;
&lt;br /&gt;
==Approach==&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 1: Refactoring all_students_all_reviews and course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(a) The common elements in these files i.e., checking if the course participant list is empty or not is moved to a different function called &amp;lt;i&amp;gt;inspect_course_participants&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(b) Adding on to this, all_student_all_review was broken down to two more functions, &amp;lt;i&amp;gt;avg_review_calc_per_student&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;overall_review_count&amp;lt;/i&amp;gt; &lt;br /&gt;
&lt;br /&gt;
(c) The method course_student_grade_summary is broken down to one more function &amp;lt;i&amp;gt;assignment_grade_summary&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 2: Refactoring populate_hash_for_all_students_all_reviews&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The approach in this function is pretty straight forward when we try to break it down. It calculates,&lt;br /&gt;
&lt;br /&gt;
(a) The average score for each assignment for each course&lt;br /&gt;
&lt;br /&gt;
(b) The overall review grade for each assignment for all the students who have taken the course&lt;br /&gt;
&lt;br /&gt;
Passing the average score calculated from (a) checks if the student has teammates which could result in not having an average teammate_review_score. If we calculate (b) in our main function (this can be done) we would be repeating the checks that we are already doing for (a). Hence, this function is not changed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 3: Fix course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The current implementation ran into an issue when it was comparing the Key-Value pair passed in '''peer_review_score'''. It was hard to check if each of the keys were present or not. The proposed solution makes use of a basic hash value presence check that retrieves a value from the array/hash, given a set of keys. If no value is found, it'll return nil.&lt;br /&gt;
&lt;br /&gt;
==Proposed Implementation==&lt;br /&gt;
====Fixing the bug on course_student_grade_summary====&lt;br /&gt;
The current implementation of the method throws a nil error at the moment on the following line,&lt;br /&gt;
&amp;lt;pre&amp;gt;unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is rectified by introducing,&lt;br /&gt;
&amp;lt;pre&amp;gt;next if (peer_review_score[:review] &amp;amp;&amp;amp; peer_review_score[:review][:scores] &amp;amp;&amp;amp; peer_review_score[:review][:scores][:avg]).nil?&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Common refactoring of all_students_all_reviews and course_student_grade_summary method====&lt;br /&gt;
The functionality that the methods shared was that, both of them checked if there were course participants who had taken a particular course. This occupied 4 lines of code in both the functions. So, this is defined in a separate function called insure_existence_of and called from the two functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def insure_existence_of(course_participants)&lt;br /&gt;
    if course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Refactor all_students_all_reviews method====&lt;br /&gt;
The all_students_all_reviews method is one of the biggest methods in assessment360_controller.rb file. It finds the list of all students and assignments pertaining to the course. This data is then used to compute the metareview and teammate review scores for each student.&lt;br /&gt;
&lt;br /&gt;
The code before refactoring had 64 lines of code as shown below,&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   teammate_reviews,&lt;br /&gt;
                                                   @teammate_review,&lt;br /&gt;
                                                   @overall_teammate_review_grades,&lt;br /&gt;
                                                   @overall_teammate_review_count,&lt;br /&gt;
                                                   @teammate_review_info_per_stu)&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   meta_reviews,&lt;br /&gt;
                                                   @meta_review,&lt;br /&gt;
                                                   @overall_meta_review_grades,&lt;br /&gt;
                                                   @overall_meta_review_count,&lt;br /&gt;
                                                   @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      if @teammate_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @teammate_review_info_per_stu[0] * 1.0 / @teammate_review_info_per_stu[1]&lt;br /&gt;
        @teammate_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
      if @meta_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @meta_review_info_per_stu[0] * 1.0 / @meta_review_info_per_stu[1]&lt;br /&gt;
        @meta_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    @assignments.each do |assignment|&lt;br /&gt;
      temp_count = @overall_teammate_review_count[assignment.id]&lt;br /&gt;
      @overall_teammate_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = @overall_meta_review_count[assignment.id]&lt;br /&gt;
      @overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To calculate the average grade for each student on all assignments in this course that a student has taken in this course is refactoring in the base code by adding the avg_review_calc_per_student method. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def avg_review_calc_per_student(cp, review_info_per_stu, review)&lt;br /&gt;
    # check to see if the student has been given a review&lt;br /&gt;
    if review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
      temp_avg_grade = review_info_per_stu[0] * 1.0 / review_info_per_stu[1]&lt;br /&gt;
      review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To avoid a &amp;lt;i&amp;gt;divide by zero error&amp;lt;/i&amp;gt; that is thrown when we try to calculate the average grade when a student has no teammate is handled by the overall_review_count method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def overall_review_count(assignments, overall_teammate_review_count, overall_meta_review_count)&lt;br /&gt;
    assignments.each do |assignment|&lt;br /&gt;
      temp_count = overall_teammate_review_count[assignment.id]&lt;br /&gt;
      overall_review_count_hash[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = overall_meta_review_count[assignment.id]&lt;br /&gt;
      overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''After refactoring'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 teammate_reviews,&lt;br /&gt;
                                 @teammate_review,&lt;br /&gt;
                                 @overall_teammate_review_grades,&lt;br /&gt;
                                 @overall_teammate_review_count,&lt;br /&gt;
                                 @teammate_review_info_per_stu)&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 meta_reviews,&lt;br /&gt;
                                 @meta_review,&lt;br /&gt;
                                 @overall_meta_review_grades,&lt;br /&gt;
                                 @overall_meta_review_count,&lt;br /&gt;
                                 @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      avg_review_calc_per_student(cp, @teammate_review_info_per_stu, @teammate_review)&lt;br /&gt;
      avg_review_calc_per_student(cp, @meta_review_info_per_stu, @meta_review)&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    overall_review_count(@assignments, @overall_teammate_review_count, @overall_meta_review_count)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Refactor course_student_grade_summary method=====&lt;br /&gt;
This method finds the list of all students and assignments pertaining to the course. The data obtained is then used to compute the instructor assigned grade and peer review scores. It was the secong biggest method in the assessment360_controller.rb controller file. The code before refactoring is shown below,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
&lt;br /&gt;
        # A topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
        topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
        @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
&lt;br /&gt;
        # Instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
        team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
        next if team_id.nil?&lt;br /&gt;
&lt;br /&gt;
        team = Team.find(team_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
&lt;br /&gt;
        # Set the assignment grade, peer review score, and sum for the final student summary&lt;br /&gt;
        @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
        unless @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
          @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&lt;br /&gt;
          @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&lt;br /&gt;
        end&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;
In this function, all the functionalities pertaining to a course participant - student in this case, in a given assignment is invoked by introducing a new method called assignment_grade_summary. This method checks if a topic exists and if it does, it passes the final grade that is calculated for that student in that course.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
    user_id = cp.user_id&lt;br /&gt;
    # topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
    topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
    @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
    # instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
    team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
    team = Team.find(team_id)&lt;br /&gt;
    @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
    return if @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
    @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
  end  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''After refactoring'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        # break out of the loop if there are no participants in the assignment&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
        # break out of the loop if the participant has no team&lt;br /&gt;
        next if TeamsUser.team_id(assignment_id, user_id).nil?&lt;br /&gt;
        # pull information about the student's grades for particular assignment&lt;br /&gt;
        assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
        next if (peer_review_score[:review] &amp;amp;&amp;amp; peer_review_score[:review][:scores] &amp;amp;&amp;amp; peer_review_score[:review][:scores][:avg]).nil?&lt;br /&gt;
        @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&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;
==Team Information==&lt;br /&gt;
[mailto:rananth2@ncsu.edu Ramya Ananth] - [https://www.linkedin.com/in/ramyananth/ LinkedIn]&lt;br /&gt;
&lt;br /&gt;
[mailto:suppala@ncsu.edu Sri Harsha Varma Uppalapati] - [https://www.linkedin.com/in/sri-harsha-varma-uppalapati LinkedIn]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;[mailto:efg@ncsu.edu Mentor: Dr. Edward F Gehringer]&amp;lt;/b&amp;gt; - [https://www.ece.ncsu.edu/people/efg/ Website]&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
1.[https://github.com/expertiza/expertiza/ Expertiza on GitHub]&lt;br /&gt;
&lt;br /&gt;
2.[https://github.com/ramyananth/expertiza GitHub Project Repository Fork]&lt;br /&gt;
&lt;br /&gt;
3.[http://expertiza.ncsu.edu/ Live Expertiza website]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132117</id>
		<title>CSC/ECE 517 Spring 2020 - E2003. Refactor and improve assessment360 controller</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132117"/>
		<updated>2020-03-24T03:59:45Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: /* Proposed Implementation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source project based on [http://rubyonrails.org/ Ruby on Rails] framework. The software allows the instructor and students with the following privileges,&lt;br /&gt;
&lt;br /&gt;
===Instructors===&lt;br /&gt;
* Create new assignments&lt;br /&gt;
* Customize new or existing assignments&lt;br /&gt;
* Create a list of topics that students can sign up for&lt;br /&gt;
* Give grades/reviews for the students' submissions&lt;br /&gt;
&lt;br /&gt;
===Students===&lt;br /&gt;
* Form teams with other students to work on various projects and assignments&lt;br /&gt;
* Peer review other students' submissions&lt;br /&gt;
&lt;br /&gt;
Note: Expertiza supports submissions across various document types, including URL and wiki pages&lt;br /&gt;
&lt;br /&gt;
==Project Description==&lt;br /&gt;
&lt;br /&gt;
===About assessment_360 Controller===&lt;br /&gt;
The assessment_360 controller is designed to gather data from all stakeholders about the performance of a student in a course. Thus, its purpose is to provide course-level statistics. At present, the controller provides only two top-level functions where each of them gives a list of students in the class. &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; contains teammate and meta-review scores received by students for all assignments in the course&lt;br /&gt;
* &amp;lt;b&amp;gt;course_student_grade_summary &amp;lt;/b&amp;gt; gives a listing of students and what topic they worked on and what grade they received on each assignment during the semester&lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The assessment360 controller had three major issues. This project is aimed to address some of them, including:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 1:&amp;lt;/b&amp;gt; Methods &amp;lt;i&amp;gt;all_students_all_reviews&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;course_student_grade_summary&amp;lt;/i&amp;gt; were too long. Common initialization and looping had to factored out by moving them into smaller methods with mnemonic names&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 2:&amp;lt;/b&amp;gt; Method populate_hash_for_all_students_all_reviews is not easy to understand. It uses a special data structure to do a very simple task. That had to be refactored&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 3:&amp;lt;/b&amp;gt; Method course_student_grade_summary stopped working and has to be fixed&lt;br /&gt;
&lt;br /&gt;
===Motivation===&lt;br /&gt;
This project aims at encouraging students to collaborate and contribute to open-source project in turn helping them understand what goes on in a full-fledged software deployment process. It also paves a way to understand how one can use Rails, RSpec to develop a system that does justice to the DRY code practicing principles.&lt;br /&gt;
&lt;br /&gt;
==Approach==&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 1: Refactoring all_students_all_reviews and course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(a) The common elements in these files i.e., checking if the course participant list is empty or not is moved to a different function called &amp;lt;i&amp;gt;inspect_course_participants&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(b) Adding on to this, all_student_all_review was broken down to two more functions, &amp;lt;i&amp;gt;avg_review_calc_per_student&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;overall_review_count&amp;lt;/i&amp;gt; &lt;br /&gt;
&lt;br /&gt;
(c) The method course_student_grade_summary is broken down to one more function &amp;lt;i&amp;gt;assignment_grade_summary&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 2: Refactoring populate_hash_for_all_students_all_reviews&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The approach in this function is pretty straight forward when we try to break it down. It calculates,&lt;br /&gt;
&lt;br /&gt;
(a) The average score for each assignment for each course&lt;br /&gt;
&lt;br /&gt;
(b) The overall review grade for each assignment for all the students who have taken the course&lt;br /&gt;
&lt;br /&gt;
Passing the average score calculated from (a) checks if the student has teammates which could result in not having an average teammate_review_score. If we calculate (b) in our main function (this can be done) we would be repeating the checks that we are already doing for (a). Hence, this function is not changed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 3: Fix course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The current implementation ran into an issue when it was comparing the Key-Value pair passed in '''peer_review_score'''. It was hard to check if each of the keys were present or not. The proposed solution makes use of a basic hash value presence check that retrieves a value from the array/hash, given a set of keys. If no value is found, it'll return nil.&lt;br /&gt;
&lt;br /&gt;
==Proposed Implementation==&lt;br /&gt;
====Fixing the bug on course_student_grade_summary====&lt;br /&gt;
The current implementation of the method throws a nil error at the moment on the following line,&lt;br /&gt;
&amp;lt;pre&amp;gt;unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is rectified by introducing,&lt;br /&gt;
&amp;lt;pre&amp;gt;next if (peer_review_score[:review] &amp;amp;&amp;amp; peer_review_score[:review][:scores] &amp;amp;&amp;amp; peer_review_score[:review][:scores][:avg]).nil?&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Common refactoring of all_students_all_reviews and course_student_grade_summary method====&lt;br /&gt;
The functionality that the methods shared was that, both of them checked if there were course participants who had taken a particular course. This occupied 4 lines of code in both the functions. So, this is defined in a separate function called insure_existence_of and called from the two functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def insure_existence_of(course_participants)&lt;br /&gt;
    if course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Refactor all_students_all_reviews method=====&lt;br /&gt;
The all_students_all_reviews method is one of the biggest methods in assessment360_controller.rb file. It finds the list of all students and assignments pertaining to the course. This data is then used to compute the metareview and teammate review scores for each student.&lt;br /&gt;
&lt;br /&gt;
The code before refactoring had 64 lines of code as shown below,&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   teammate_reviews,&lt;br /&gt;
                                                   @teammate_review,&lt;br /&gt;
                                                   @overall_teammate_review_grades,&lt;br /&gt;
                                                   @overall_teammate_review_count,&lt;br /&gt;
                                                   @teammate_review_info_per_stu)&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   meta_reviews,&lt;br /&gt;
                                                   @meta_review,&lt;br /&gt;
                                                   @overall_meta_review_grades,&lt;br /&gt;
                                                   @overall_meta_review_count,&lt;br /&gt;
                                                   @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      if @teammate_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @teammate_review_info_per_stu[0] * 1.0 / @teammate_review_info_per_stu[1]&lt;br /&gt;
        @teammate_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
      if @meta_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @meta_review_info_per_stu[0] * 1.0 / @meta_review_info_per_stu[1]&lt;br /&gt;
        @meta_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    @assignments.each do |assignment|&lt;br /&gt;
      temp_count = @overall_teammate_review_count[assignment.id]&lt;br /&gt;
      @overall_teammate_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = @overall_meta_review_count[assignment.id]&lt;br /&gt;
      @overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To calculate the average grade for each student on all assignments in this course that a student has taken in this course is refactoring in the base code by adding the avg_review_calc_per_student method. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def avg_review_calc_per_student(cp, review_info_per_stu, review)&lt;br /&gt;
    # check to see if the student has been given a review&lt;br /&gt;
    if review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
      temp_avg_grade = review_info_per_stu[0] * 1.0 / review_info_per_stu[1]&lt;br /&gt;
      review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To avoid a &amp;lt;i&amp;gt;divide by zero error&amp;lt;/i&amp;gt; that is thrown when we try to calculate the average grade when a student has no teammate is handled by the overall_review_count method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def overall_review_count(assignments, overall_teammate_review_count, overall_meta_review_count)&lt;br /&gt;
    assignments.each do |assignment|&lt;br /&gt;
      temp_count = overall_teammate_review_count[assignment.id]&lt;br /&gt;
      overall_review_count_hash[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = overall_meta_review_count[assignment.id]&lt;br /&gt;
      overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''After refactoring'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 teammate_reviews,&lt;br /&gt;
                                 @teammate_review,&lt;br /&gt;
                                 @overall_teammate_review_grades,&lt;br /&gt;
                                 @overall_teammate_review_count,&lt;br /&gt;
                                 @teammate_review_info_per_stu)&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 meta_reviews,&lt;br /&gt;
                                 @meta_review,&lt;br /&gt;
                                 @overall_meta_review_grades,&lt;br /&gt;
                                 @overall_meta_review_count,&lt;br /&gt;
                                 @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      avg_review_calc_per_student(cp, @teammate_review_info_per_stu, @teammate_review)&lt;br /&gt;
      avg_review_calc_per_student(cp, @meta_review_info_per_stu, @meta_review)&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    overall_review_count(@assignments, @overall_teammate_review_count, @overall_meta_review_count)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Refactor course_student_grade_summary method=====&lt;br /&gt;
This method finds the list of all students and assignments pertaining to the course. The data obtained is then used to compute the instructor assigned grade and peer review scores. It was the secong biggest method in the assessment360_controller.rb controller file. The code before refactoring is shown below,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
&lt;br /&gt;
        # A topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
        topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
        @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
&lt;br /&gt;
        # Instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
        team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
        next if team_id.nil?&lt;br /&gt;
&lt;br /&gt;
        team = Team.find(team_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
&lt;br /&gt;
        # Set the assignment grade, peer review score, and sum for the final student summary&lt;br /&gt;
        @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
        unless @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
          @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&lt;br /&gt;
          @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&lt;br /&gt;
        end&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;
In this function, all the functionalities pertaining to a course participant - student in this case, in a given assignment is invoked by introducing a new method called assignment_grade_summary. This method checks if a topic exists and if it does, it passes the final grade that is calculated for that student in that course.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
    user_id = cp.user_id&lt;br /&gt;
    # topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
    topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
    @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
    # instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
    team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
    team = Team.find(team_id)&lt;br /&gt;
    @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
    return if @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
    @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
  end  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''After refactoring'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        # break out of the loop if there are no participants in the assignment&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
        # break out of the loop if the participant has no team&lt;br /&gt;
        next if TeamsUser.team_id(assignment_id, user_id).nil?&lt;br /&gt;
        # pull information about the student's grades for particular assignment&lt;br /&gt;
        assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
        next if (peer_review_score[:review] &amp;amp;&amp;amp; peer_review_score[:review][:scores] &amp;amp;&amp;amp; peer_review_score[:review][:scores][:avg]).nil?&lt;br /&gt;
        @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&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;
==Team Information==&lt;br /&gt;
[mailto:rananth2@ncsu.edu Ramya Ananth] - [https://www.linkedin.com/in/ramyananth/ LinkedIn]&lt;br /&gt;
&lt;br /&gt;
[mailto:suppala@ncsu.edu Sri Harsha Varma Uppalapati] - [https://www.linkedin.com/in/sri-harsha-varma-uppalapati LinkedIn]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;[mailto:efg@ncsu.edu Mentor: Dr. Edward F Gehringer]&amp;lt;/b&amp;gt; - [https://www.ece.ncsu.edu/people/efg/ Website]&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
1.[https://github.com/expertiza/expertiza/ Expertiza on GitHub]&lt;br /&gt;
&lt;br /&gt;
2.[https://github.com/ramyananth/expertiza GitHub Project Repository Fork]&lt;br /&gt;
&lt;br /&gt;
3.[http://expertiza.ncsu.edu/ Live Expertiza website]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132114</id>
		<title>CSC/ECE 517 Spring 2020 - E2003. Refactor and improve assessment360 controller</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132114"/>
		<updated>2020-03-24T03:55:39Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: /* Refactor course_student_grade_summary method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source project based on [http://rubyonrails.org/ Ruby on Rails] framework. The software allows the instructor and students with the following privileges,&lt;br /&gt;
&lt;br /&gt;
===Instructors===&lt;br /&gt;
* Create new assignments&lt;br /&gt;
* Customize new or existing assignments&lt;br /&gt;
* Create a list of topics that students can sign up for&lt;br /&gt;
* Give grades/reviews for the students' submissions&lt;br /&gt;
&lt;br /&gt;
===Students===&lt;br /&gt;
* Form teams with other students to work on various projects and assignments&lt;br /&gt;
* Peer review other students' submissions&lt;br /&gt;
&lt;br /&gt;
Note: Expertiza supports submissions across various document types, including URL and wiki pages&lt;br /&gt;
&lt;br /&gt;
==Project Description==&lt;br /&gt;
&lt;br /&gt;
===About assessment_360 Controller===&lt;br /&gt;
The assessment_360 controller is designed to gather data from all stakeholders about the performance of a student in a course. Thus, its purpose is to provide course-level statistics. At present, the controller provides only two top-level functions where each of them gives a list of students in the class. &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; contains teammate and meta-review scores received by students for all assignments in the course&lt;br /&gt;
* &amp;lt;b&amp;gt;course_student_grade_summary &amp;lt;/b&amp;gt; gives a listing of students and what topic they worked on and what grade they received on each assignment during the semester&lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The assessment360 controller had three major issues. This project is aimed to address some of them, including:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 1:&amp;lt;/b&amp;gt; Methods &amp;lt;i&amp;gt;all_students_all_reviews&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;course_student_grade_summary&amp;lt;/i&amp;gt; were too long. Common initialization and looping had to factored out by moving them into smaller methods with mnemonic names&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 2:&amp;lt;/b&amp;gt; Method populate_hash_for_all_students_all_reviews is not easy to understand. It uses a special data structure to do a very simple task. That had to be refactored&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 3:&amp;lt;/b&amp;gt; Method course_student_grade_summary stopped working and has to be fixed&lt;br /&gt;
&lt;br /&gt;
===Motivation===&lt;br /&gt;
This project aims at encouraging students to collaborate and contribute to open-source project in turn helping them understand what goes on in a full-fledged software deployment process. It also paves a way to understand how one can use Rails, RSpec to develop a system that does justice to the DRY code practicing principles.&lt;br /&gt;
&lt;br /&gt;
==Approach==&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 1: Refactoring all_students_all_reviews and course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(a) The common elements in these files i.e., checking if the course participant list is empty or not is moved to a different function called &amp;lt;i&amp;gt;inspect_course_participants&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(b) Adding on to this, all_student_all_review was broken down to two more functions, &amp;lt;i&amp;gt;avg_review_calc_per_student&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;overall_review_count&amp;lt;/i&amp;gt; &lt;br /&gt;
&lt;br /&gt;
(c) The method course_student_grade_summary is broken down to one more function &amp;lt;i&amp;gt;assignment_grade_summary&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 2: Refactoring populate_hash_for_all_students_all_reviews&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The approach in this function is pretty straight forward when we try to break it down. It calculates,&lt;br /&gt;
&lt;br /&gt;
(a) The average score for each assignment for each course&lt;br /&gt;
&lt;br /&gt;
(b) The overall review grade for each assignment for all the students who have taken the course&lt;br /&gt;
&lt;br /&gt;
Passing the average score calculated from (a) checks if the student has teammates which could result in not having an average teammate_review_score. If we calculate (b) in our main function (this can be done) we would be repeating the checks that we are already doing for (a). Hence, this function is not changed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 3: Fix course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The current implementation ran into an issue when it was comparing the Key-Value pair passed in '''peer_review_score'''. It was hard to check if each of the keys were present or not. The proposed solution makes use of a basic hash value presence check that retrieves a value from the array/hash, given a set of keys. If no value is found, it'll return nil.&lt;br /&gt;
&lt;br /&gt;
==Proposed Implementation==&lt;br /&gt;
====Common refactoring of all_students_all_reviews and course_student_grade_summary method====&lt;br /&gt;
The functionality that the methods shared was that, both of them checked if there were course participants who had taken a particular course. This occupied 4 lines of code in both the functions. So, this is defined in a separate function called insure_existence_of and called from the two functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def insure_existence_of(course_participants)&lt;br /&gt;
    if course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Refactor all_students_all_reviews method=====&lt;br /&gt;
The all_students_all_reviews method is one of the biggest methods in assessment360_controller.rb file. It finds the list of all students and assignments pertaining to the course. This data is then used to compute the metareview and teammate review scores for each student.&lt;br /&gt;
&lt;br /&gt;
The code before refactoring had 64 lines of code as shown below,&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   teammate_reviews,&lt;br /&gt;
                                                   @teammate_review,&lt;br /&gt;
                                                   @overall_teammate_review_grades,&lt;br /&gt;
                                                   @overall_teammate_review_count,&lt;br /&gt;
                                                   @teammate_review_info_per_stu)&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   meta_reviews,&lt;br /&gt;
                                                   @meta_review,&lt;br /&gt;
                                                   @overall_meta_review_grades,&lt;br /&gt;
                                                   @overall_meta_review_count,&lt;br /&gt;
                                                   @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      if @teammate_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @teammate_review_info_per_stu[0] * 1.0 / @teammate_review_info_per_stu[1]&lt;br /&gt;
        @teammate_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
      if @meta_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @meta_review_info_per_stu[0] * 1.0 / @meta_review_info_per_stu[1]&lt;br /&gt;
        @meta_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    @assignments.each do |assignment|&lt;br /&gt;
      temp_count = @overall_teammate_review_count[assignment.id]&lt;br /&gt;
      @overall_teammate_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = @overall_meta_review_count[assignment.id]&lt;br /&gt;
      @overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To calculate the average grade for each student on all assignments in this course that a student has taken in this course is refactoring in the base code by adding the avg_review_calc_per_student method. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def avg_review_calc_per_student(cp, review_info_per_stu, review)&lt;br /&gt;
    # check to see if the student has been given a review&lt;br /&gt;
    if review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
      temp_avg_grade = review_info_per_stu[0] * 1.0 / review_info_per_stu[1]&lt;br /&gt;
      review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To avoid a &amp;lt;i&amp;gt;divide by zero error&amp;lt;/i&amp;gt; that is thrown when we try to calculate the average grade when a student has no teammate is handled by the overall_review_count method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def overall_review_count(assignments, overall_teammate_review_count, overall_meta_review_count)&lt;br /&gt;
    assignments.each do |assignment|&lt;br /&gt;
      temp_count = overall_teammate_review_count[assignment.id]&lt;br /&gt;
      overall_review_count_hash[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = overall_meta_review_count[assignment.id]&lt;br /&gt;
      overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''After refactoring'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 teammate_reviews,&lt;br /&gt;
                                 @teammate_review,&lt;br /&gt;
                                 @overall_teammate_review_grades,&lt;br /&gt;
                                 @overall_teammate_review_count,&lt;br /&gt;
                                 @teammate_review_info_per_stu)&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 meta_reviews,&lt;br /&gt;
                                 @meta_review,&lt;br /&gt;
                                 @overall_meta_review_grades,&lt;br /&gt;
                                 @overall_meta_review_count,&lt;br /&gt;
                                 @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      avg_review_calc_per_student(cp, @teammate_review_info_per_stu, @teammate_review)&lt;br /&gt;
      avg_review_calc_per_student(cp, @meta_review_info_per_stu, @meta_review)&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    overall_review_count(@assignments, @overall_teammate_review_count, @overall_meta_review_count)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Refactor course_student_grade_summary method=====&lt;br /&gt;
This method finds the list of all students and assignments pertaining to the course. The data obtained is then used to compute the instructor assigned grade and peer review scores. It was the secong biggest method in the assessment360_controller.rb controller file. The code before refactoring is shown below,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
&lt;br /&gt;
        # A topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
        topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
        @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
&lt;br /&gt;
        # Instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
        team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
        next if team_id.nil?&lt;br /&gt;
&lt;br /&gt;
        team = Team.find(team_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
&lt;br /&gt;
        # Set the assignment grade, peer review score, and sum for the final student summary&lt;br /&gt;
        @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
        unless @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
          @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&lt;br /&gt;
          @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&lt;br /&gt;
        end&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;
In this function, all the functionalities pertaining to a course participant - student in this case, in a given assignment is invoked by introducing a new method called assignment_grade_summary. This method checks if a topic exists and if it does, it passes the final grade that is calculated for that student in that course.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
    user_id = cp.user_id&lt;br /&gt;
    # topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
    topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
    @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
    # instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
    team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
    team = Team.find(team_id)&lt;br /&gt;
    @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
    return if @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
    @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
  end  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''After refactoring'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        # break out of the loop if there are no participants in the assignment&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
        # break out of the loop if the participant has no team&lt;br /&gt;
        next if TeamsUser.team_id(assignment_id, user_id).nil?&lt;br /&gt;
        # pull information about the student's grades for particular assignment&lt;br /&gt;
        assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
        next if (peer_review_score[:review] &amp;amp;&amp;amp; peer_review_score[:review][:scores] &amp;amp;&amp;amp; peer_review_score[:review][:scores][:avg]).nil?&lt;br /&gt;
        @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&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;
==Team Information==&lt;br /&gt;
[mailto:rananth2@ncsu.edu Ramya Ananth] - [https://www.linkedin.com/in/ramyananth/ LinkedIn]&lt;br /&gt;
&lt;br /&gt;
[mailto:suppala@ncsu.edu Sri Harsha Varma Uppalapati] - [https://www.linkedin.com/in/sri-harsha-varma-uppalapati LinkedIn]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;[mailto:efg@ncsu.edu Mentor: Dr. Edward F Gehringer]&amp;lt;/b&amp;gt; - [https://www.ece.ncsu.edu/people/efg/ Website]&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
1.[https://github.com/expertiza/expertiza/ Expertiza on GitHub]&lt;br /&gt;
&lt;br /&gt;
2.[https://github.com/ramyananth/expertiza GitHub Project Repository Fork]&lt;br /&gt;
&lt;br /&gt;
3.[http://expertiza.ncsu.edu/ Live Expertiza website]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132110</id>
		<title>CSC/ECE 517 Spring 2020 - E2003. Refactor and improve assessment360 controller</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132110"/>
		<updated>2020-03-24T03:55:02Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: /* Refactor all_students_all_reviews method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source project based on [http://rubyonrails.org/ Ruby on Rails] framework. The software allows the instructor and students with the following privileges,&lt;br /&gt;
&lt;br /&gt;
===Instructors===&lt;br /&gt;
* Create new assignments&lt;br /&gt;
* Customize new or existing assignments&lt;br /&gt;
* Create a list of topics that students can sign up for&lt;br /&gt;
* Give grades/reviews for the students' submissions&lt;br /&gt;
&lt;br /&gt;
===Students===&lt;br /&gt;
* Form teams with other students to work on various projects and assignments&lt;br /&gt;
* Peer review other students' submissions&lt;br /&gt;
&lt;br /&gt;
Note: Expertiza supports submissions across various document types, including URL and wiki pages&lt;br /&gt;
&lt;br /&gt;
==Project Description==&lt;br /&gt;
&lt;br /&gt;
===About assessment_360 Controller===&lt;br /&gt;
The assessment_360 controller is designed to gather data from all stakeholders about the performance of a student in a course. Thus, its purpose is to provide course-level statistics. At present, the controller provides only two top-level functions where each of them gives a list of students in the class. &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; contains teammate and meta-review scores received by students for all assignments in the course&lt;br /&gt;
* &amp;lt;b&amp;gt;course_student_grade_summary &amp;lt;/b&amp;gt; gives a listing of students and what topic they worked on and what grade they received on each assignment during the semester&lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The assessment360 controller had three major issues. This project is aimed to address some of them, including:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 1:&amp;lt;/b&amp;gt; Methods &amp;lt;i&amp;gt;all_students_all_reviews&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;course_student_grade_summary&amp;lt;/i&amp;gt; were too long. Common initialization and looping had to factored out by moving them into smaller methods with mnemonic names&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 2:&amp;lt;/b&amp;gt; Method populate_hash_for_all_students_all_reviews is not easy to understand. It uses a special data structure to do a very simple task. That had to be refactored&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 3:&amp;lt;/b&amp;gt; Method course_student_grade_summary stopped working and has to be fixed&lt;br /&gt;
&lt;br /&gt;
===Motivation===&lt;br /&gt;
This project aims at encouraging students to collaborate and contribute to open-source project in turn helping them understand what goes on in a full-fledged software deployment process. It also paves a way to understand how one can use Rails, RSpec to develop a system that does justice to the DRY code practicing principles.&lt;br /&gt;
&lt;br /&gt;
==Approach==&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 1: Refactoring all_students_all_reviews and course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(a) The common elements in these files i.e., checking if the course participant list is empty or not is moved to a different function called &amp;lt;i&amp;gt;inspect_course_participants&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(b) Adding on to this, all_student_all_review was broken down to two more functions, &amp;lt;i&amp;gt;avg_review_calc_per_student&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;overall_review_count&amp;lt;/i&amp;gt; &lt;br /&gt;
&lt;br /&gt;
(c) The method course_student_grade_summary is broken down to one more function &amp;lt;i&amp;gt;assignment_grade_summary&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 2: Refactoring populate_hash_for_all_students_all_reviews&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The approach in this function is pretty straight forward when we try to break it down. It calculates,&lt;br /&gt;
&lt;br /&gt;
(a) The average score for each assignment for each course&lt;br /&gt;
&lt;br /&gt;
(b) The overall review grade for each assignment for all the students who have taken the course&lt;br /&gt;
&lt;br /&gt;
Passing the average score calculated from (a) checks if the student has teammates which could result in not having an average teammate_review_score. If we calculate (b) in our main function (this can be done) we would be repeating the checks that we are already doing for (a). Hence, this function is not changed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 3: Fix course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The current implementation ran into an issue when it was comparing the Key-Value pair passed in '''peer_review_score'''. It was hard to check if each of the keys were present or not. The proposed solution makes use of a basic hash value presence check that retrieves a value from the array/hash, given a set of keys. If no value is found, it'll return nil.&lt;br /&gt;
&lt;br /&gt;
==Proposed Implementation==&lt;br /&gt;
====Common refactoring of all_students_all_reviews and course_student_grade_summary method====&lt;br /&gt;
The functionality that the methods shared was that, both of them checked if there were course participants who had taken a particular course. This occupied 4 lines of code in both the functions. So, this is defined in a separate function called insure_existence_of and called from the two functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def insure_existence_of(course_participants)&lt;br /&gt;
    if course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Refactor all_students_all_reviews method=====&lt;br /&gt;
The all_students_all_reviews method is one of the biggest methods in assessment360_controller.rb file. It finds the list of all students and assignments pertaining to the course. This data is then used to compute the metareview and teammate review scores for each student.&lt;br /&gt;
&lt;br /&gt;
The code before refactoring had 64 lines of code as shown below,&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   teammate_reviews,&lt;br /&gt;
                                                   @teammate_review,&lt;br /&gt;
                                                   @overall_teammate_review_grades,&lt;br /&gt;
                                                   @overall_teammate_review_count,&lt;br /&gt;
                                                   @teammate_review_info_per_stu)&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   meta_reviews,&lt;br /&gt;
                                                   @meta_review,&lt;br /&gt;
                                                   @overall_meta_review_grades,&lt;br /&gt;
                                                   @overall_meta_review_count,&lt;br /&gt;
                                                   @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      if @teammate_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @teammate_review_info_per_stu[0] * 1.0 / @teammate_review_info_per_stu[1]&lt;br /&gt;
        @teammate_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
      if @meta_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @meta_review_info_per_stu[0] * 1.0 / @meta_review_info_per_stu[1]&lt;br /&gt;
        @meta_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    @assignments.each do |assignment|&lt;br /&gt;
      temp_count = @overall_teammate_review_count[assignment.id]&lt;br /&gt;
      @overall_teammate_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = @overall_meta_review_count[assignment.id]&lt;br /&gt;
      @overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To calculate the average grade for each student on all assignments in this course that a student has taken in this course is refactoring in the base code by adding the avg_review_calc_per_student method. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def avg_review_calc_per_student(cp, review_info_per_stu, review)&lt;br /&gt;
    # check to see if the student has been given a review&lt;br /&gt;
    if review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
      temp_avg_grade = review_info_per_stu[0] * 1.0 / review_info_per_stu[1]&lt;br /&gt;
      review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To avoid a &amp;lt;i&amp;gt;divide by zero error&amp;lt;/i&amp;gt; that is thrown when we try to calculate the average grade when a student has no teammate is handled by the overall_review_count method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def overall_review_count(assignments, overall_teammate_review_count, overall_meta_review_count)&lt;br /&gt;
    assignments.each do |assignment|&lt;br /&gt;
      temp_count = overall_teammate_review_count[assignment.id]&lt;br /&gt;
      overall_review_count_hash[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = overall_meta_review_count[assignment.id]&lt;br /&gt;
      overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''After refactoring'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 teammate_reviews,&lt;br /&gt;
                                 @teammate_review,&lt;br /&gt;
                                 @overall_teammate_review_grades,&lt;br /&gt;
                                 @overall_teammate_review_count,&lt;br /&gt;
                                 @teammate_review_info_per_stu)&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 meta_reviews,&lt;br /&gt;
                                 @meta_review,&lt;br /&gt;
                                 @overall_meta_review_grades,&lt;br /&gt;
                                 @overall_meta_review_count,&lt;br /&gt;
                                 @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      avg_review_calc_per_student(cp, @teammate_review_info_per_stu, @teammate_review)&lt;br /&gt;
      avg_review_calc_per_student(cp, @meta_review_info_per_stu, @meta_review)&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    overall_review_count(@assignments, @overall_teammate_review_count, @overall_meta_review_count)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Refactor course_student_grade_summary method=====&lt;br /&gt;
This method finds the list of all students and assignments pertaining to the course. The data obtained is then used to compute the instructor assigned grade and peer review scores. It was the secong biggest method in the assessment360_controller.rb controller file. The code before refactoring is shown below,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
&lt;br /&gt;
        # A topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
        topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
        @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
&lt;br /&gt;
        # Instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
        team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
        next if team_id.nil?&lt;br /&gt;
&lt;br /&gt;
        team = Team.find(team_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
&lt;br /&gt;
        # Set the assignment grade, peer review score, and sum for the final student summary&lt;br /&gt;
        @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
        unless @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
          @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&lt;br /&gt;
          @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&lt;br /&gt;
        end&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;
In this function, all the functionalities pertaining to a course participant - student in this case, in a given assignment is invoked by introducing a new method called assignment_grade_summary. This method checks if a topic exists and if it does, it passes the final grade that is calculated for that student in that course.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
    user_id = cp.user_id&lt;br /&gt;
    # topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
    topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
    @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
    # instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
    team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
    team = Team.find(team_id)&lt;br /&gt;
    @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
    return if @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
    @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
  end  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Team Information==&lt;br /&gt;
[mailto:rananth2@ncsu.edu Ramya Ananth] - [https://www.linkedin.com/in/ramyananth/ LinkedIn]&lt;br /&gt;
&lt;br /&gt;
[mailto:suppala@ncsu.edu Sri Harsha Varma Uppalapati] - [https://www.linkedin.com/in/sri-harsha-varma-uppalapati LinkedIn]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;[mailto:efg@ncsu.edu Mentor: Dr. Edward F Gehringer]&amp;lt;/b&amp;gt; - [https://www.ece.ncsu.edu/people/efg/ Website]&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
1.[https://github.com/expertiza/expertiza/ Expertiza on GitHub]&lt;br /&gt;
&lt;br /&gt;
2.[https://github.com/ramyananth/expertiza GitHub Project Repository Fork]&lt;br /&gt;
&lt;br /&gt;
3.[http://expertiza.ncsu.edu/ Live Expertiza website]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132108</id>
		<title>CSC/ECE 517 Spring 2020 - E2003. Refactor and improve assessment360 controller</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132108"/>
		<updated>2020-03-24T03:54:31Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: /* Refactor course_student_grade_summary method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source project based on [http://rubyonrails.org/ Ruby on Rails] framework. The software allows the instructor and students with the following privileges,&lt;br /&gt;
&lt;br /&gt;
===Instructors===&lt;br /&gt;
* Create new assignments&lt;br /&gt;
* Customize new or existing assignments&lt;br /&gt;
* Create a list of topics that students can sign up for&lt;br /&gt;
* Give grades/reviews for the students' submissions&lt;br /&gt;
&lt;br /&gt;
===Students===&lt;br /&gt;
* Form teams with other students to work on various projects and assignments&lt;br /&gt;
* Peer review other students' submissions&lt;br /&gt;
&lt;br /&gt;
Note: Expertiza supports submissions across various document types, including URL and wiki pages&lt;br /&gt;
&lt;br /&gt;
==Project Description==&lt;br /&gt;
&lt;br /&gt;
===About assessment_360 Controller===&lt;br /&gt;
The assessment_360 controller is designed to gather data from all stakeholders about the performance of a student in a course. Thus, its purpose is to provide course-level statistics. At present, the controller provides only two top-level functions where each of them gives a list of students in the class. &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; contains teammate and meta-review scores received by students for all assignments in the course&lt;br /&gt;
* &amp;lt;b&amp;gt;course_student_grade_summary &amp;lt;/b&amp;gt; gives a listing of students and what topic they worked on and what grade they received on each assignment during the semester&lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The assessment360 controller had three major issues. This project is aimed to address some of them, including:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 1:&amp;lt;/b&amp;gt; Methods &amp;lt;i&amp;gt;all_students_all_reviews&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;course_student_grade_summary&amp;lt;/i&amp;gt; were too long. Common initialization and looping had to factored out by moving them into smaller methods with mnemonic names&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 2:&amp;lt;/b&amp;gt; Method populate_hash_for_all_students_all_reviews is not easy to understand. It uses a special data structure to do a very simple task. That had to be refactored&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 3:&amp;lt;/b&amp;gt; Method course_student_grade_summary stopped working and has to be fixed&lt;br /&gt;
&lt;br /&gt;
===Motivation===&lt;br /&gt;
This project aims at encouraging students to collaborate and contribute to open-source project in turn helping them understand what goes on in a full-fledged software deployment process. It also paves a way to understand how one can use Rails, RSpec to develop a system that does justice to the DRY code practicing principles.&lt;br /&gt;
&lt;br /&gt;
==Approach==&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 1: Refactoring all_students_all_reviews and course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(a) The common elements in these files i.e., checking if the course participant list is empty or not is moved to a different function called &amp;lt;i&amp;gt;inspect_course_participants&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(b) Adding on to this, all_student_all_review was broken down to two more functions, &amp;lt;i&amp;gt;avg_review_calc_per_student&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;overall_review_count&amp;lt;/i&amp;gt; &lt;br /&gt;
&lt;br /&gt;
(c) The method course_student_grade_summary is broken down to one more function &amp;lt;i&amp;gt;assignment_grade_summary&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 2: Refactoring populate_hash_for_all_students_all_reviews&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The approach in this function is pretty straight forward when we try to break it down. It calculates,&lt;br /&gt;
&lt;br /&gt;
(a) The average score for each assignment for each course&lt;br /&gt;
&lt;br /&gt;
(b) The overall review grade for each assignment for all the students who have taken the course&lt;br /&gt;
&lt;br /&gt;
Passing the average score calculated from (a) checks if the student has teammates which could result in not having an average teammate_review_score. If we calculate (b) in our main function (this can be done) we would be repeating the checks that we are already doing for (a). Hence, this function is not changed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 3: Fix course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The current implementation ran into an issue when it was comparing the Key-Value pair passed in '''peer_review_score'''. It was hard to check if each of the keys were present or not. The proposed solution makes use of a basic hash value presence check that retrieves a value from the array/hash, given a set of keys. If no value is found, it'll return nil.&lt;br /&gt;
&lt;br /&gt;
==Proposed Implementation==&lt;br /&gt;
====Common refactoring of all_students_all_reviews and course_student_grade_summary method====&lt;br /&gt;
The functionality that the methods shared was that, both of them checked if there were course participants who had taken a particular course. This occupied 4 lines of code in both the functions. So, this is defined in a separate function called insure_existence_of and called from the two functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def insure_existence_of(course_participants)&lt;br /&gt;
    if course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Refactor all_students_all_reviews method=====&lt;br /&gt;
The all_students_all_reviews method is one of the biggest methods in assessment360_controller.rb file. It finds the list of all students and assignments pertaining to the course. This data is then used to compute the metareview and teammate review scores for each student.&lt;br /&gt;
&lt;br /&gt;
The code before refactoring had 64 lines of code as shown below,&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   teammate_reviews,&lt;br /&gt;
                                                   @teammate_review,&lt;br /&gt;
                                                   @overall_teammate_review_grades,&lt;br /&gt;
                                                   @overall_teammate_review_count,&lt;br /&gt;
                                                   @teammate_review_info_per_stu)&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   meta_reviews,&lt;br /&gt;
                                                   @meta_review,&lt;br /&gt;
                                                   @overall_meta_review_grades,&lt;br /&gt;
                                                   @overall_meta_review_count,&lt;br /&gt;
                                                   @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      if @teammate_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @teammate_review_info_per_stu[0] * 1.0 / @teammate_review_info_per_stu[1]&lt;br /&gt;
        @teammate_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
      if @meta_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @meta_review_info_per_stu[0] * 1.0 / @meta_review_info_per_stu[1]&lt;br /&gt;
        @meta_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    @assignments.each do |assignment|&lt;br /&gt;
      temp_count = @overall_teammate_review_count[assignment.id]&lt;br /&gt;
      @overall_teammate_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = @overall_meta_review_count[assignment.id]&lt;br /&gt;
      @overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To calculate the average grade for each student on all assignments in this course that a student has taken in this course is refactoring in the base code by adding the avg_review_calc_per_student method. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def avg_review_calc_per_student(cp, review_info_per_stu, review)&lt;br /&gt;
    # check to see if the student has been given a review&lt;br /&gt;
    if review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
      temp_avg_grade = review_info_per_stu[0] * 1.0 / review_info_per_stu[1]&lt;br /&gt;
      review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To avoid a &amp;lt;i&amp;gt;divide by zero error&amp;lt;/i&amp;gt; that is thrown when we try to calculate the average grade when a student has no teammate is handled by the overall_review_count method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def overall_review_count(assignments, overall_teammate_review_count, overall_meta_review_count)&lt;br /&gt;
    assignments.each do |assignment|&lt;br /&gt;
      temp_count = overall_teammate_review_count[assignment.id]&lt;br /&gt;
      overall_review_count_hash[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = overall_meta_review_count[assignment.id]&lt;br /&gt;
      overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&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;
'''After refactoring'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 teammate_reviews,&lt;br /&gt;
                                 @teammate_review,&lt;br /&gt;
                                 @overall_teammate_review_grades,&lt;br /&gt;
                                 @overall_teammate_review_count,&lt;br /&gt;
                                 @teammate_review_info_per_stu)&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 meta_reviews,&lt;br /&gt;
                                 @meta_review,&lt;br /&gt;
                                 @overall_meta_review_grades,&lt;br /&gt;
                                 @overall_meta_review_count,&lt;br /&gt;
                                 @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      avg_review_calc_per_student(cp, @teammate_review_info_per_stu, @teammate_review)&lt;br /&gt;
      avg_review_calc_per_student(cp, @meta_review_info_per_stu, @meta_review)&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    overall_review_count(@assignments, @overall_teammate_review_count, @overall_meta_review_count)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Refactor course_student_grade_summary method=====&lt;br /&gt;
This method finds the list of all students and assignments pertaining to the course. The data obtained is then used to compute the instructor assigned grade and peer review scores. It was the secong biggest method in the assessment360_controller.rb controller file. The code before refactoring is shown below,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
&lt;br /&gt;
        # A topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
        topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
        @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
&lt;br /&gt;
        # Instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
        team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
        next if team_id.nil?&lt;br /&gt;
&lt;br /&gt;
        team = Team.find(team_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
&lt;br /&gt;
        # Set the assignment grade, peer review score, and sum for the final student summary&lt;br /&gt;
        @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
        unless @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
          @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&lt;br /&gt;
          @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&lt;br /&gt;
        end&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;
In this function, all the functionalities pertaining to a course participant - student in this case, in a given assignment is invoked by introducing a new method called assignment_grade_summary. This method checks if a topic exists and if it does, it passes the final grade that is calculated for that student in that course.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def assignment_grade_summary(cp, assignment_id)&lt;br /&gt;
    user_id = cp.user_id&lt;br /&gt;
    # topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
    topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
    @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
    # instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
    team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
    team = Team.find(team_id)&lt;br /&gt;
    @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
    return if @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
    @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
  end  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Team Information==&lt;br /&gt;
[mailto:rananth2@ncsu.edu Ramya Ananth] - [https://www.linkedin.com/in/ramyananth/ LinkedIn]&lt;br /&gt;
&lt;br /&gt;
[mailto:suppala@ncsu.edu Sri Harsha Varma Uppalapati] - [https://www.linkedin.com/in/sri-harsha-varma-uppalapati LinkedIn]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;[mailto:efg@ncsu.edu Mentor: Dr. Edward F Gehringer]&amp;lt;/b&amp;gt; - [https://www.ece.ncsu.edu/people/efg/ Website]&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
1.[https://github.com/expertiza/expertiza/ Expertiza on GitHub]&lt;br /&gt;
&lt;br /&gt;
2.[https://github.com/ramyananth/expertiza GitHub Project Repository Fork]&lt;br /&gt;
&lt;br /&gt;
3.[http://expertiza.ncsu.edu/ Live Expertiza website]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132105</id>
		<title>CSC/ECE 517 Spring 2020 - E2003. Refactor and improve assessment360 controller</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132105"/>
		<updated>2020-03-24T03:48:43Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source project based on [http://rubyonrails.org/ Ruby on Rails] framework. The software allows the instructor and students with the following privileges,&lt;br /&gt;
&lt;br /&gt;
===Instructors===&lt;br /&gt;
* Create new assignments&lt;br /&gt;
* Customize new or existing assignments&lt;br /&gt;
* Create a list of topics that students can sign up for&lt;br /&gt;
* Give grades/reviews for the students' submissions&lt;br /&gt;
&lt;br /&gt;
===Students===&lt;br /&gt;
* Form teams with other students to work on various projects and assignments&lt;br /&gt;
* Peer review other students' submissions&lt;br /&gt;
&lt;br /&gt;
Note: Expertiza supports submissions across various document types, including URL and wiki pages&lt;br /&gt;
&lt;br /&gt;
==Project Description==&lt;br /&gt;
&lt;br /&gt;
===About assessment_360 Controller===&lt;br /&gt;
The assessment_360 controller is designed to gather data from all stakeholders about the performance of a student in a course. Thus, its purpose is to provide course-level statistics. At present, the controller provides only two top-level functions where each of them gives a list of students in the class. &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; contains teammate and meta-review scores received by students for all assignments in the course&lt;br /&gt;
* &amp;lt;b&amp;gt;course_student_grade_summary &amp;lt;/b&amp;gt; gives a listing of students and what topic they worked on and what grade they received on each assignment during the semester&lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The assessment360 controller had three major issues. This project is aimed to address some of them, including:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 1:&amp;lt;/b&amp;gt; Methods &amp;lt;i&amp;gt;all_students_all_reviews&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;course_student_grade_summary&amp;lt;/i&amp;gt; were too long. Common initialization and looping had to factored out by moving them into smaller methods with mnemonic names&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 2:&amp;lt;/b&amp;gt; Method populate_hash_for_all_students_all_reviews is not easy to understand. It uses a special data structure to do a very simple task. That had to be refactored&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 3:&amp;lt;/b&amp;gt; Method course_student_grade_summary stopped working and has to be fixed&lt;br /&gt;
&lt;br /&gt;
===Motivation===&lt;br /&gt;
This project aims at encouraging students to collaborate and contribute to open-source project in turn helping them understand what goes on in a full-fledged software deployment process. It also paves a way to understand how one can use Rails, RSpec to develop a system that does justice to the DRY code practicing principles.&lt;br /&gt;
&lt;br /&gt;
==Approach==&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 1: Refactoring all_students_all_reviews and course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(a) The common elements in these files i.e., checking if the course participant list is empty or not is moved to a different function called &amp;lt;i&amp;gt;inspect_course_participants&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(b) Adding on to this, all_student_all_review was broken down to two more functions, &amp;lt;i&amp;gt;avg_review_calc_per_student&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;overall_review_count&amp;lt;/i&amp;gt; &lt;br /&gt;
&lt;br /&gt;
(c) The method course_student_grade_summary is broken down to one more function &amp;lt;i&amp;gt;assignment_grade_summary&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 2: Refactoring populate_hash_for_all_students_all_reviews&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The approach in this function is pretty straight forward when we try to break it down. It calculates,&lt;br /&gt;
&lt;br /&gt;
(a) The average score for each assignment for each course&lt;br /&gt;
&lt;br /&gt;
(b) The overall review grade for each assignment for all the students who have taken the course&lt;br /&gt;
&lt;br /&gt;
Passing the average score calculated from (a) checks if the student has teammates which could result in not having an average teammate_review_score. If we calculate (b) in our main function (this can be done) we would be repeating the checks that we are already doing for (a). Hence, this function is not changed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 3: Fix course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The current implementation ran into an issue when it was comparing the Key-Value pair passed in '''peer_review_score'''. It was hard to check if each of the keys were present or not. The proposed solution makes use of a basic hash value presence check that retrieves a value from the array/hash, given a set of keys. If no value is found, it'll return nil.&lt;br /&gt;
&lt;br /&gt;
==Proposed Implementation==&lt;br /&gt;
====Common refactoring of all_students_all_reviews and course_student_grade_summary method====&lt;br /&gt;
The functionality that the methods shared was that, both of them checked if there were course participants who had taken a particular course. This occupied 4 lines of code in both the functions. So, this is defined in a separate function called insure_existence_of and called from the two functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def insure_existence_of(course_participants)&lt;br /&gt;
    if course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Refactor all_students_all_reviews method=====&lt;br /&gt;
The all_students_all_reviews method is one of the biggest methods in assessment360_controller.rb file. It finds the list of all students and assignments pertaining to the course. This data is then used to compute the metareview and teammate review scores for each student.&lt;br /&gt;
&lt;br /&gt;
The code before refactoring had 64 lines of code as shown below,&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   teammate_reviews,&lt;br /&gt;
                                                   @teammate_review,&lt;br /&gt;
                                                   @overall_teammate_review_grades,&lt;br /&gt;
                                                   @overall_teammate_review_count,&lt;br /&gt;
                                                   @teammate_review_info_per_stu)&lt;br /&gt;
        populate_hash_for_all_students_all_reviews(assignment,&lt;br /&gt;
                                                   cp,&lt;br /&gt;
                                                   meta_reviews,&lt;br /&gt;
                                                   @meta_review,&lt;br /&gt;
                                                   @overall_meta_review_grades,&lt;br /&gt;
                                                   @overall_meta_review_count,&lt;br /&gt;
                                                   @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      if @teammate_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @teammate_review_info_per_stu[0] * 1.0 / @teammate_review_info_per_stu[1]&lt;br /&gt;
        @teammate_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
      if @meta_review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
        temp_avg_grade = @meta_review_info_per_stu[0] * 1.0 / @meta_review_info_per_stu[1]&lt;br /&gt;
        @meta_review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    @assignments.each do |assignment|&lt;br /&gt;
      temp_count = @overall_teammate_review_count[assignment.id]&lt;br /&gt;
      @overall_teammate_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = @overall_meta_review_count[assignment.id]&lt;br /&gt;
      @overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To calculate the average grade for each student on all assignments in this course that a student has taken in this course is refactoring in the base code by adding the avg_review_calc_per_student method. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def avg_review_calc_per_student(cp, review_info_per_stu, review)&lt;br /&gt;
    # check to see if the student has been given a review&lt;br /&gt;
    if review_info_per_stu[1] &amp;gt; 0&lt;br /&gt;
      temp_avg_grade = review_info_per_stu[0] * 1.0 / review_info_per_stu[1]&lt;br /&gt;
      review[cp.id][:avg_grade_for_assgt] = temp_avg_grade.round.to_s + '%'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To avoid a &amp;lt;i&amp;gt;divide by zero error&amp;lt;/i&amp;gt; that is thrown when we try to calculate the average grade when a student has no teammate is handled by the overall_review_count method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def overall_review_count(assignments, overall_teammate_review_count, overall_meta_review_count)&lt;br /&gt;
    assignments.each do |assignment|&lt;br /&gt;
      temp_count = overall_teammate_review_count[assignment.id]&lt;br /&gt;
      overall_review_count_hash[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&lt;br /&gt;
      temp_count = overall_meta_review_count[assignment.id]&lt;br /&gt;
      overall_meta_review_count[assignment.id] = 1 if temp_count.nil? or temp_count.zero?&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;
'''After refactoring'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def all_students_all_reviews&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    insure_existence_of(@course_participants)&lt;br /&gt;
    # hashes for view&lt;br /&gt;
    @meta_review = {}&lt;br /&gt;
    @teammate_review = {}&lt;br /&gt;
    @teamed_count = {}&lt;br /&gt;
    # for course&lt;br /&gt;
    # eg. @overall_teammate_review_grades = {assgt_id1: 100, assgt_id2: 178, ...}&lt;br /&gt;
    # @overall_teammate_review_count = {assgt_id1: 1, assgt_id2: 2, ...}&lt;br /&gt;
    %w[teammate meta].each do |type|&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_grades&amp;quot;, {})&lt;br /&gt;
      instance_variable_set(&amp;quot;@overall_#{type}_review_count&amp;quot;, {})&lt;br /&gt;
    end&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      # for each assignment&lt;br /&gt;
      # [aggregrate_review_grades_per_stu, review_count_per_stu] --&amp;gt; [0, 0]&lt;br /&gt;
      %w[teammate meta].each {|type| instance_variable_set(&amp;quot;@#{type}_review_info_per_stu&amp;quot;, [0, 0]) }&lt;br /&gt;
      students_teamed = StudentTask.teamed_students(cp.user)&lt;br /&gt;
      @teamed_count[cp.id] = students_teamed[course.id].try(:size).to_i&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        @meta_review[cp.id] = {} unless @meta_review.key?(cp.id)&lt;br /&gt;
        @teammate_review[cp.id] = {} unless @teammate_review.key?(cp.id)&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: cp.user_id)&lt;br /&gt;
        next if assignment_participant.nil?&lt;br /&gt;
        teammate_reviews = assignment_participant.teammate_reviews&lt;br /&gt;
        meta_reviews = assignment_participant.metareviews&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 teammate_reviews,&lt;br /&gt;
                                 @teammate_review,&lt;br /&gt;
                                 @overall_teammate_review_grades,&lt;br /&gt;
                                 @overall_teammate_review_count,&lt;br /&gt;
                                 @teammate_review_info_per_stu)&lt;br /&gt;
        calc_overall_review_info(assignment,&lt;br /&gt;
                                 cp,&lt;br /&gt;
                                 meta_reviews,&lt;br /&gt;
                                 @meta_review,&lt;br /&gt;
                                 @overall_meta_review_grades,&lt;br /&gt;
                                 @overall_meta_review_count,&lt;br /&gt;
                                 @meta_review_info_per_stu)&lt;br /&gt;
      end&lt;br /&gt;
      # calculate average grade for each student on all assignments in this course&lt;br /&gt;
      avg_review_calc_per_student(cp, @teammate_review_info_per_stu, @teammate_review)&lt;br /&gt;
      avg_review_calc_per_student(cp, @meta_review_info_per_stu, @meta_review)&lt;br /&gt;
    end&lt;br /&gt;
    # avoid divide by zero error&lt;br /&gt;
    overall_review_count(@assignments, @overall_teammate_review_count, @overall_meta_review_count)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Refactor course_student_grade_summary method=====&lt;br /&gt;
This method finds the list of all students and assignments pertaining to the course. The data obtained is then used to compute the instructor assigned grade and peer review scores. It was the secong biggest method in the assessment360_controller.rb controller file. The code before refactoring is shown below,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def course_student_grade_summary&lt;br /&gt;
    @topics = {}&lt;br /&gt;
    @assignment_grades = {}&lt;br /&gt;
    @peer_review_scores = {}&lt;br /&gt;
    @final_grades = {}&lt;br /&gt;
&lt;br /&gt;
    course = Course.find(params[:course_id])&lt;br /&gt;
    @assignments = course.assignments.reject(&amp;amp;:is_calibrated).reject {|a| a.participants.empty? }&lt;br /&gt;
    @course_participants = course.get_participants&lt;br /&gt;
    if @course_participants.empty?&lt;br /&gt;
      flash[:error] = &amp;quot;There is no course participant in course #{course.name}&amp;quot;&lt;br /&gt;
      redirect_to(:back)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    @course_participants.each do |cp|&lt;br /&gt;
      @topics[cp.id] = {}&lt;br /&gt;
      @assignment_grades[cp.id] = {}&lt;br /&gt;
      @peer_review_scores[cp.id] = {}&lt;br /&gt;
      @final_grades[cp.id] = 0&lt;br /&gt;
&lt;br /&gt;
      @assignments.each do |assignment|&lt;br /&gt;
        user_id = cp.user_id&lt;br /&gt;
        assignment_id = assignment.id&lt;br /&gt;
&lt;br /&gt;
        assignment_participant = assignment.participants.find_by(user_id: user_id)&lt;br /&gt;
        next if assignment.participants.find_by(user_id: user_id).nil?&lt;br /&gt;
&lt;br /&gt;
        # A topic exists if a team signed up for a topic, which can be found via the user and the assignment&lt;br /&gt;
        topic_id = SignedUpTeam.topic_id(assignment_id, user_id)&lt;br /&gt;
        @topics[cp.id][assignment_id] = SignUpTopic.find_by(id: topic_id)&lt;br /&gt;
&lt;br /&gt;
        # Instructor grade is stored in the team model, which is found by finding the user's team for the assignment&lt;br /&gt;
        team_id = TeamsUser.team_id(assignment_id, user_id)&lt;br /&gt;
        next if team_id.nil?&lt;br /&gt;
&lt;br /&gt;
        team = Team.find(team_id)&lt;br /&gt;
        peer_review_score = find_peer_review_score(user_id, assignment_id)&lt;br /&gt;
&lt;br /&gt;
        # Set the assignment grade, peer review score, and sum for the final student summary&lt;br /&gt;
        @assignment_grades[cp.id][assignment_id] = team[:grade_for_submission]&lt;br /&gt;
        unless @assignment_grades[cp.id][assignment_id].nil?&lt;br /&gt;
          @final_grades[cp.id] += @assignment_grades[cp.id][assignment_id]&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        unless (peer_review_score.nil? || peer_review_score[:review][:scores][:avg].nil?)&lt;br /&gt;
          @peer_review_scores[cp.id][assignment_id] = peer_review_score[:review][:scores][:avg].round(2)&lt;br /&gt;
        end&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;
==Team Information==&lt;br /&gt;
[mailto:rananth2@ncsu.edu Ramya Ananth] - [https://www.linkedin.com/in/ramyananth/ LinkedIn]&lt;br /&gt;
&lt;br /&gt;
[mailto:suppala@ncsu.edu Sri Harsha Varma Uppalapati] - [https://www.linkedin.com/in/sri-harsha-varma-uppalapati LinkedIn]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;[mailto:efg@ncsu.edu Mentor: Dr. Edward F Gehringer]&amp;lt;/b&amp;gt; - [https://www.ece.ncsu.edu/people/efg/ Website]&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
1.[https://github.com/expertiza/expertiza/ Expertiza on GitHub]&lt;br /&gt;
&lt;br /&gt;
2.[https://github.com/ramyananth/expertiza GitHub Project Repository Fork]&lt;br /&gt;
&lt;br /&gt;
3.[http://expertiza.ncsu.edu/ Live Expertiza website]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132082</id>
		<title>CSC/ECE 517 Spring 2020 - E2003. Refactor and improve assessment360 controller</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=132082"/>
		<updated>2020-03-24T03:21:39Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source project based on [http://rubyonrails.org/ Ruby on Rails] framework. The software allows the instructor and students with the following privileges,&lt;br /&gt;
&lt;br /&gt;
===Instructors===&lt;br /&gt;
* Create new assignments&lt;br /&gt;
* Customize new or existing assignments&lt;br /&gt;
* Create a list of topics that students can sign up for&lt;br /&gt;
* Give grades/reviews for the students' submissions&lt;br /&gt;
&lt;br /&gt;
===Students===&lt;br /&gt;
* Form teams with other students to work on various projects and assignments&lt;br /&gt;
* Peer review other students' submissions&lt;br /&gt;
&lt;br /&gt;
Note: Expertiza supports submissions across various document types, including URL and wiki pages&lt;br /&gt;
&lt;br /&gt;
==Project Description==&lt;br /&gt;
&lt;br /&gt;
===About assessment_360 Controller===&lt;br /&gt;
The assessment_360 controller is designed to gather data from all stakeholders about the performance of a student in a course. Thus, its purpose is to provide course-level statistics. At present, the controller provides only two top-level functions where each of them gives a list of students in the class. &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; contains teammate and meta-review scores received by students for all assignments in the course&lt;br /&gt;
* &amp;lt;b&amp;gt;course_student_grade_summary &amp;lt;/b&amp;gt; gives a listing of students and what topic they worked on and what grade they received on each assignment during the semester&lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The assessment360 controller had three major issues. This project is aimed to address some of them, including:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 1:&amp;lt;/b&amp;gt; Methods &amp;lt;i&amp;gt;all_students_all_reviews&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;course_student_grade_summary&amp;lt;/i&amp;gt; were too long. Common initialization and looping had to factored out by moving them into smaller methods with mnemonic names&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 2:&amp;lt;/b&amp;gt; Method populate_hash_for_all_students_all_reviews is not easy to understand. It uses a special data structure to do a very simple task. That had to be refactored&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 3:&amp;lt;/b&amp;gt; Method course_student_grade_summary stopped working and has to be fixed&lt;br /&gt;
&lt;br /&gt;
===Motivation===&lt;br /&gt;
This project aims at encouraging students to collaborate and contribute to open-source project in turn helping them understand what goes on in a full-fledged software deployment process. It also paves a way to understand how one can use Rails, RSpec to develop a system that does justice to the DRY code practicing principles.&lt;br /&gt;
&lt;br /&gt;
==Proposed Implementation==&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 1: Refactoring all_students_all_reviews and course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(a) The common elements in these files i.e., checking if the course participant list is empty or not is moved to a different function called &amp;lt;i&amp;gt;inspect_course_participants&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(b) Adding on to this, all_student_all_review was broken down to two more functions, &amp;lt;i&amp;gt;review_info_per_student&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;avoid_divide_by_zero_error&amp;lt;/i&amp;gt; &lt;br /&gt;
&lt;br /&gt;
(c) The method course_student_grade_summary is broken down to one more function &amp;lt;i&amp;gt;assignment_grade_summary&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 2: Refactoring populate_hash_for_all_students_all_reviews&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The approach in this function is pretty straight forward when we try to break it down. It calculates,&lt;br /&gt;
&lt;br /&gt;
(a) The average score for each assignment for each course&lt;br /&gt;
&lt;br /&gt;
(b) The overall review grade for each assignment for all the students who have taken the course&lt;br /&gt;
&lt;br /&gt;
Passing the average score calculated from (a) checks if the student has teammates which could result in not having an average teammate_review_score. If we calculate (b) in our main function (this can be done) we would be repeating the checks that we are already doing for (a). Hence, this function is not changed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 3: Fix course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The current implementation ran into an issue when it was comparing the Key-Value pair passed in '''peer_review_score'''. It was hard to check if each of the keys were present or not. The proposed solution makes use of a basic hash value presence check that retrieves a value from the array/hash, given a set of keys. If no value is found, it'll return nil.&lt;br /&gt;
&lt;br /&gt;
==Team Information==&lt;br /&gt;
[mailto:rananth2@ncsu.edu Ramya Ananth] - [https://www.linkedin.com/in/ramyananth/ LinkedIn]&lt;br /&gt;
&lt;br /&gt;
[mailto:suppala@ncsu.edu Sri Harsha Varma Uppalapati] - [https://www.linkedin.com/in/sri-harsha-varma-uppalapati LinkedIn]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;[mailto:efg@ncsu.edu Mentor: Dr. Edward F Gehringer]&amp;lt;/b&amp;gt; - [https://www.ece.ncsu.edu/people/efg/ Website]&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
1.[https://github.com/expertiza/expertiza/ Expertiza on GitHub]&lt;br /&gt;
&lt;br /&gt;
2.[https://github.com/ramyananth/expertiza GitHub Project Repository Fork]&lt;br /&gt;
&lt;br /&gt;
3.[http://expertiza.ncsu.edu/ Live Expertiza website]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=131550</id>
		<title>CSC/ECE 517 Spring 2020 - E2003. Refactor and improve assessment360 controller</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=131550"/>
		<updated>2020-03-22T20:45:39Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source project based on [http://rubyonrails.org/ Ruby on Rails] framework. The software allows the instructor and students with the following privileges,&lt;br /&gt;
&lt;br /&gt;
===Instructors===&lt;br /&gt;
* Create new assignments&lt;br /&gt;
* Customize new or existing assignments&lt;br /&gt;
* Create a list of topics that students can sign up for&lt;br /&gt;
* Give grades/reviews for the students' submissions&lt;br /&gt;
&lt;br /&gt;
===Students===&lt;br /&gt;
* Form teams with other students to work on various projects and assignments&lt;br /&gt;
* Peer review other students' submissions&lt;br /&gt;
&lt;br /&gt;
Note: Expertiza supports submissions across various document types, including URL and wiki pages&lt;br /&gt;
&lt;br /&gt;
==Project Description==&lt;br /&gt;
&lt;br /&gt;
===About assessment_360 Controller===&lt;br /&gt;
The assessment_360 controller is designed to gather data from all stakeholders about the performance of a student in a course. Thus, its purpose is to provide course-level statistics. At present, the controller provides only two top-level functions where each of them gives a list of students in the class. &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; contains teammate and meta-review scores received by students for all assignments in the course&lt;br /&gt;
* &amp;lt;b&amp;gt;course_student_grade_summary &amp;lt;/b&amp;gt; gives a listing of students and what topic they worked on and what grade they received on each assignment during the semester&lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The assessment360 controller had three major issues. This project is aimed to address some of them, including:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 1:&amp;lt;/b&amp;gt; Methods &amp;lt;i&amp;gt;all_students_all_reviews&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;course_student_grade_summary&amp;lt;/i&amp;gt; were too long. Common initialization and looping had to factored out by moving them into smaller methods with mnemonic names&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 2:&amp;lt;/b&amp;gt; Method populate_hash_for_all_students_all_reviews is not easy to understand. It uses a special data structure to do a very simple task. That had to be refactored&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 3:&amp;lt;/b&amp;gt; Method course_student_grade_summary stopped working and has to be fixed&lt;br /&gt;
&lt;br /&gt;
===Motivation===&lt;br /&gt;
This project aims at encouraging students to collaborate and contribute to open-source project in turn helping them understand what goes on in a full-fledged software deployment process. It also paves a way to understand how one can use Rails, RSpec to develop a system that does justice to the DRY code practicing principles.&lt;br /&gt;
&lt;br /&gt;
==Proposed Implementation==&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 1: Refactoring all_students_all_reviews and course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(a) The common elements in these files i.e., checking if the course participant list is empty or not is moved to a different function called &amp;lt;i&amp;gt;inspect_course_participants&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(b) Adding on to this, all_student_all_review was broken down to two more functions, &amp;lt;i&amp;gt;review_info_per_student&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;avoid_divide_by_zero_error&amp;lt;/i&amp;gt; &lt;br /&gt;
&lt;br /&gt;
(c) The method course_student_grade_summary is broken down to one more function &amp;lt;i&amp;gt;assignment_grade_summary&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 2: Refactoring populate_hash_for_all_students_all_reviews&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The approach in this function is pretty straight forward when we try to break it down. It calculates,&lt;br /&gt;
&lt;br /&gt;
(a) The average score for each assignment for each course&lt;br /&gt;
&lt;br /&gt;
(b) The overall review grade for each assignment for all the students who have taken the course&lt;br /&gt;
&lt;br /&gt;
Passing the average score calculated from (a) checks if the student has teammates which could result in not having an average teammate_review_score. If we calculate (b) in our main function (this can be done) we would be repeating the checks that we are already doing for (a). Hence, this function is not changed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 3: Fix course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The current implementation ran into an issue when it was comparing the Key-Value pair passed in '''peer_review_score'''. It was hard to check if each of the keys were present or not. The proposed solution makes use of the &amp;lt;b&amp;gt;[https://ruby-doc.org/core-2.3.0_preview1/Hash.html#method-i-dig dig]&amp;lt;/b&amp;gt; function in Ruby that retrieves a value from the array/hash, given a set of keys. If no value is found, it'll return nil.&lt;br /&gt;
&lt;br /&gt;
==Team Information==&lt;br /&gt;
[mailto:rananth2@ncsu.edu Ramya Ananth] - [https://www.linkedin.com/in/ramyananth/ LinkedIn]&lt;br /&gt;
&lt;br /&gt;
[mailto:suppala@ncsu.edu Sri Harsha Varma Uppalapati] - [https://www.linkedin.com/in/sri-harsha-varma-uppalapati LinkedIn]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;[mailto:efg@ncsu.edu Mentor: Dr. Edward F Gehringer]&amp;lt;/b&amp;gt; - [https://www.ece.ncsu.edu/people/efg/ Website]&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
1.[https://github.com/expertiza/expertiza/ Expertiza on GitHub]&lt;br /&gt;
&lt;br /&gt;
2.[https://github.com/ramyananth/expertiza GitHub Project Repository Fork]&lt;br /&gt;
&lt;br /&gt;
3.[http://expertiza.ncsu.edu/ Live Expertiza website]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2019_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=131549</id>
		<title>CSC/ECE 517 Fall 2019 - E2003. Refactor and improve assessment360 controller</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2019_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=131549"/>
		<updated>2020-03-22T20:30:32Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: Rananth2 moved page CSC/ECE 517 Fall 2019 - E2003. Refactor and improve assessment360 controller to CSC/ECE 517 Spring 2020 - E2003. Refactor and improve assessment360 controller&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[CSC/ECE 517 Spring 2020 - E2003. Refactor and improve assessment360 controller]]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=131548</id>
		<title>CSC/ECE 517 Spring 2020 - E2003. Refactor and improve assessment360 controller</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=131548"/>
		<updated>2020-03-22T20:30:32Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: Rananth2 moved page CSC/ECE 517 Fall 2019 - E2003. Refactor and improve assessment360 controller to CSC/ECE 517 Spring 2020 - E2003. Refactor and improve assessment360 controller&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source project based on [http://rubyonrails.org/ Ruby on Rails] framework. The software allows the instructor and students with the following privileges,&lt;br /&gt;
&lt;br /&gt;
===Instructors===&lt;br /&gt;
* Create new assignments&lt;br /&gt;
* Customize new or existing assignments&lt;br /&gt;
* Create a list of topics that students can sign up for&lt;br /&gt;
* Give grades/reviews for the students' submissions&lt;br /&gt;
&lt;br /&gt;
===Students===&lt;br /&gt;
* Form teams with other students to work on various projects and assignments&lt;br /&gt;
* Peer review other students' submissions&lt;br /&gt;
&lt;br /&gt;
Note: Expertiza supports submissions across various document types, including URL and wiki pages&lt;br /&gt;
&lt;br /&gt;
==Project Description==&lt;br /&gt;
&lt;br /&gt;
===About assessment_360 Controller===&lt;br /&gt;
The assessment_360 controller is designed to gather data from all stakeholders about the performance of a student in a course. Thus, its purpose is to provide course-level statistics. At present, the controller provides only two top-level functions where each of them gives a list of students in the class. &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; contains teammate and meta-review scores received by students for all assignments in the course&lt;br /&gt;
* &amp;lt;b&amp;gt;course_student_grade_summary &amp;lt;/b&amp;gt; gives a listing of students and what topic they worked on and what grade they received on each assignment during the semester&lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The assessment360 controller had three major issues. This project is aimed to address some of them, including:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 1:&amp;lt;/b&amp;gt; Methods &amp;lt;i&amp;gt;all_students_all_reviews&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;course_student_grade_summary&amp;lt;/i&amp;gt; were too long. Common initialization and looping had to factored out by moving them into smaller methods with mnemonic names&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 2:&amp;lt;/b&amp;gt; Method populate_hash_for_all_students_all_reviews is not easy to understand. It uses a special data structure to do a very simple task. That had to be refactored&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 3:&amp;lt;/b&amp;gt; Method course_student_grade_summary stopped working and has to be fixed&lt;br /&gt;
&lt;br /&gt;
===Motivation===&lt;br /&gt;
This project aims at encouraging students to collaborate and contribute to open-source project in turn helping them understand what goes on in a full-fledged software deployment process. It also paves a way to understand how one can use Rails, RSpec to develop a system that does justice to the DRY code practicing principles.&lt;br /&gt;
&lt;br /&gt;
==Proposed Implementation==&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 1: Refactoring all_students_all_reviews and course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(a) The common elements in these files i.e., checking if the course participant list is empty or not is moved to a different function called &amp;lt;i&amp;gt;inspect_course_participants&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(b) Adding on to this, all_student_all_review was broken down to two more functions, &amp;lt;i&amp;gt;review_info_per_student&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;avoid_divide_by_zero_error&amp;lt;/i&amp;gt; &lt;br /&gt;
&lt;br /&gt;
(c) The method course_student_grade_summary is broken down to one more function &amp;lt;i&amp;gt;assignment_grade_summary&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 2: Refactoring populate_hash_for_all_students_all_reviews&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The approach in this function is pretty straight forward when we try to break it down. It calculates,&lt;br /&gt;
&lt;br /&gt;
(a) The average score for each assignment for each course&lt;br /&gt;
&lt;br /&gt;
(b) The overall review grade for each assignment for all the students who have taken the course&lt;br /&gt;
&lt;br /&gt;
Passing the average score calculated from (a) checks if the student has teammates which could result in not having an average teammate_review_score. If we calculate (b) in our main function (this can be done) we would be repeating the checks that we are already doing for (a). Hence, this function is not changed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 3: Fix course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The current implementation ran into an issue when it was comparing the Key-Value pair passed in '''peer_review_score'''. It was hard to check if each of the keys were present or not. The proposed solution makes use of the &amp;lt;b&amp;gt;[https://ruby-doc.org/core-2.3.0_preview1/Hash.html#method-i-dig dig]&amp;lt;/b&amp;gt; function in Ruby that retrieves a value from the array/hash, given a set of keys. If no value is found, it'll return nil.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Team Information==&lt;br /&gt;
Ramya Ananth&lt;br /&gt;
&lt;br /&gt;
Sri Harsha Varma Uppalapati&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Mentor: Dr. Edward Gehringer&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
1.[https://github.com/expertiza/expertiza/ Expertiza on GitHub]&lt;br /&gt;
&lt;br /&gt;
2.[https://github.com/ramyananth/expertiza GitHub Project Repository Fork]&lt;br /&gt;
&lt;br /&gt;
3.[http://expertiza.ncsu.edu/ Live Expertiza website]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=131547</id>
		<title>CSC/ECE 517 Spring 2020 - E2003. Refactor and improve assessment360 controller</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=131547"/>
		<updated>2020-03-22T20:29:20Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source project based on [http://rubyonrails.org/ Ruby on Rails] framework. The software allows the instructor and students with the following privileges,&lt;br /&gt;
&lt;br /&gt;
===Instructors===&lt;br /&gt;
* Create new assignments&lt;br /&gt;
* Customize new or existing assignments&lt;br /&gt;
* Create a list of topics that students can sign up for&lt;br /&gt;
* Give grades/reviews for the students' submissions&lt;br /&gt;
&lt;br /&gt;
===Students===&lt;br /&gt;
* Form teams with other students to work on various projects and assignments&lt;br /&gt;
* Peer review other students' submissions&lt;br /&gt;
&lt;br /&gt;
Note: Expertiza supports submissions across various document types, including URL and wiki pages&lt;br /&gt;
&lt;br /&gt;
==Project Description==&lt;br /&gt;
&lt;br /&gt;
===About assessment_360 Controller===&lt;br /&gt;
The assessment_360 controller is designed to gather data from all stakeholders about the performance of a student in a course. Thus, its purpose is to provide course-level statistics. At present, the controller provides only two top-level functions where each of them gives a list of students in the class. &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; contains teammate and meta-review scores received by students for all assignments in the course&lt;br /&gt;
* &amp;lt;b&amp;gt;course_student_grade_summary &amp;lt;/b&amp;gt; gives a listing of students and what topic they worked on and what grade they received on each assignment during the semester&lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The assessment360 controller had three major issues. This project is aimed to address some of them, including:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 1:&amp;lt;/b&amp;gt; Methods &amp;lt;i&amp;gt;all_students_all_reviews&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;course_student_grade_summary&amp;lt;/i&amp;gt; were too long. Common initialization and looping had to factored out by moving them into smaller methods with mnemonic names&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 2:&amp;lt;/b&amp;gt; Method populate_hash_for_all_students_all_reviews is not easy to understand. It uses a special data structure to do a very simple task. That had to be refactored&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 3:&amp;lt;/b&amp;gt; Method course_student_grade_summary stopped working and has to be fixed&lt;br /&gt;
&lt;br /&gt;
===Motivation===&lt;br /&gt;
This project aims at encouraging students to collaborate and contribute to open-source project in turn helping them understand what goes on in a full-fledged software deployment process. It also paves a way to understand how one can use Rails, RSpec to develop a system that does justice to the DRY code practicing principles.&lt;br /&gt;
&lt;br /&gt;
==Proposed Implementation==&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 1: Refactoring all_students_all_reviews and course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(a) The common elements in these files i.e., checking if the course participant list is empty or not is moved to a different function called &amp;lt;i&amp;gt;inspect_course_participants&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(b) Adding on to this, all_student_all_review was broken down to two more functions, &amp;lt;i&amp;gt;review_info_per_student&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;avoid_divide_by_zero_error&amp;lt;/i&amp;gt; &lt;br /&gt;
&lt;br /&gt;
(c) The method course_student_grade_summary is broken down to one more function &amp;lt;i&amp;gt;assignment_grade_summary&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 2: Refactoring populate_hash_for_all_students_all_reviews&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The approach in this function is pretty straight forward when we try to break it down. It calculates,&lt;br /&gt;
&lt;br /&gt;
(a) The average score for each assignment for each course&lt;br /&gt;
&lt;br /&gt;
(b) The overall review grade for each assignment for all the students who have taken the course&lt;br /&gt;
&lt;br /&gt;
Passing the average score calculated from (a) checks if the student has teammates which could result in not having an average teammate_review_score. If we calculate (b) in our main function (this can be done) we would be repeating the checks that we are already doing for (a). Hence, this function is not changed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Problem 3: Fix course_student_grade_summary&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The current implementation ran into an issue when it was comparing the Key-Value pair passed in '''peer_review_score'''. It was hard to check if each of the keys were present or not. The proposed solution makes use of the &amp;lt;b&amp;gt;[https://ruby-doc.org/core-2.3.0_preview1/Hash.html#method-i-dig dig]&amp;lt;/b&amp;gt; function in Ruby that retrieves a value from the array/hash, given a set of keys. If no value is found, it'll return nil.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Team Information==&lt;br /&gt;
Ramya Ananth&lt;br /&gt;
&lt;br /&gt;
Sri Harsha Varma Uppalapati&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Mentor: Dr. Edward Gehringer&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
1.[https://github.com/expertiza/expertiza/ Expertiza on GitHub]&lt;br /&gt;
&lt;br /&gt;
2.[https://github.com/ramyananth/expertiza GitHub Project Repository Fork]&lt;br /&gt;
&lt;br /&gt;
3.[http://expertiza.ncsu.edu/ Live Expertiza website]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=131545</id>
		<title>CSC/ECE 517 Spring 2020 - E2003. Refactor and improve assessment360 controller</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_E2003._Refactor_and_improve_assessment360_controller&amp;diff=131545"/>
		<updated>2020-03-22T18:54:19Z</updated>

		<summary type="html">&lt;p&gt;Rananth2: Created page with &amp;quot;==About Expertiza== [http://expertiza.ncsu.edu/ Expertiza] is an open-source project based on [http://rubyonrails.org/ Ruby on Rails] framework. The software allows the instru...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open-source project based on [http://rubyonrails.org/ Ruby on Rails] framework. The software allows the instructor and students with the following privileges,&lt;br /&gt;
&lt;br /&gt;
===Instructors===&lt;br /&gt;
* Create new assignments&lt;br /&gt;
* Customize new or existing assignments&lt;br /&gt;
* Create a list of topics that students can sign up for&lt;br /&gt;
* Give grades/reviews for the students' submissions&lt;br /&gt;
&lt;br /&gt;
===Students===&lt;br /&gt;
* Form teams with other students to work on various projects and assignments&lt;br /&gt;
* Peer review other students' submissions&lt;br /&gt;
&lt;br /&gt;
Note: Expertiza supports submissions across various document types, including URL and wiki pages&lt;br /&gt;
&lt;br /&gt;
==Project Description==&lt;br /&gt;
&lt;br /&gt;
===About assessment_360 Controller===&lt;br /&gt;
The assessment_360 controller is designed to gather data from all stakeholders about the performance of a student in a course. Thus, its purpose is to provide course-level statistics. At present, the controller provides only two top-level functions where each of them gives a list of students in the class. &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt;all_students_all_reviews&amp;lt;/b&amp;gt; contains teammate and meta-review scores received by students for all assignments in the course&lt;br /&gt;
* &amp;lt;b&amp;gt;course_student_grade_summary &amp;lt;/b&amp;gt; gives a listing of students and what topic they worked on and what grade they received on each assignment during the semester&lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The assessment360 controller had three major issues. This project is aimed to address some of them, including:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 1:&amp;lt;/b&amp;gt; Methods &amp;lt;i&amp;gt;all_students_all_reviews&amp;lt;/i&amp;gt; and &amp;lt;i&amp;gt;course_student_grade_summary&amp;lt;/i&amp;gt; were too long. Common initialization and looping had to factored out by moving them into smaller methods with mnemonic names&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 2:&amp;lt;/b&amp;gt; Method populate_hash_for_all_students_all_reviews is not easy to understand. It uses a special data structure to do a very simple task. That had to be refactored&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Issue 3:&amp;lt;/b&amp;gt; Method course_student_grade_summary () stopped working and has to be fixed&lt;br /&gt;
&lt;br /&gt;
===Motivation===&lt;br /&gt;
This project aims at encouraging students to collaborate and contribute to open-source project in turn helping them understand what goes on in a full-fledged software deployment process. It also paves a way to understand how one can use Rails, RSpec to develop a system that does justice to the DRY code practicing principles.&lt;br /&gt;
&lt;br /&gt;
==Current Implementation==&lt;br /&gt;
&lt;br /&gt;
==Team Information==&lt;br /&gt;
Ramya Ananth&lt;br /&gt;
&lt;br /&gt;
Sri Harsha Varma Uppalapati&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Mentor: Dr. Edward Gehringer&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
1.[https://github.com/expertiza/expertiza/ Expertiza on GitHub]&lt;br /&gt;
&lt;br /&gt;
2.[https://github.com/ramyananth/expertiza GitHub Project Repository Fork]&lt;br /&gt;
&lt;br /&gt;
3.[http://expertiza.ncsu.edu/ Live Expertiza website]&lt;/div&gt;</summary>
		<author><name>Rananth2</name></author>
	</entry>
</feed>