<?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=Skundal</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=Skundal"/>
	<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=Special:Contributions/Skundal"/>
	<updated>2026-06-15T07:31:22Z</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=134252</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=134252"/>
		<updated>2020-04-25T03:41:01Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* 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;
== '''Current 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 Progress''' ==&lt;br /&gt;
&lt;br /&gt;
* Implemented createImageBitmap method for canvas image source(HTMLCanvasElement and OffscreenCanvas) using RUST programming language in the '''components/script/dom/workerglobalscope.rs''' and '''components/script/dom/window.rs''' files. The comments in the following code will explain the functionality that it carries out.&lt;br /&gt;
&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;
    // The following line creates promise element which is to be returned&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;
    // match the image type to promise element&lt;br /&gt;
    let promise = match image {&lt;br /&gt;
        // Check if the imageBitmapSource is of HTMLCanvasElement type&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;
            // Use fetch_all_data() from canvas_state.rs to return the image data and its size and assign it to a DomRefCell as a vector&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;
                // Set imageBitmap's bitmap data to a copy of image's bitmap data&lt;br /&gt;
                image_bitmap.set_bitmap_data(data);&lt;br /&gt;
                // Set the origin-clean flag of the imageBitmap's bitmap to the same value as the origin-clean flag of image's bitmap&lt;br /&gt;
                image_bitmap.set_origin_clean(canvas.origin_is_clean());&lt;br /&gt;
                // Resolve p with imageBitmap&lt;br /&gt;
                p.resolve_native(&amp;amp;(image_bitmap));&lt;br /&gt;
            }&lt;br /&gt;
            p&lt;br /&gt;
        },&lt;br /&gt;
        // Check if the imageBitmapSource is of OffscreenCanvas type&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;
            // Use fetch_all_data() from canvas_state.rs to return the image data and its size and assign it to a DomRefCell as a vector&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]), // set value as 0 if image data is null&lt;br /&gt;
                );&lt;br /&gt;
                // Set imageBitmap's bitmap data to a copy of image's bitmap data&lt;br /&gt;
                image_bitmap.set_bitmap_data(data);  &lt;br /&gt;
                // Set the origin-clean flag of the imageBitmap's bitmap to the same value as the origin-clean flag of image's bitmap&lt;br /&gt;
                image_bitmap.set_origin_clean(canvas.origin_is_clean());&lt;br /&gt;
                // Resolve p with imageBitmap&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;
== '''Design of 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 quickly, 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. This is done to make sure that the end-to-end implementation can be successfully run in a system.&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) to visually confirm that servo is working:&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;
=='''Code submission and Pull request'''==&lt;br /&gt;
&lt;br /&gt;
'''Code: '''[https://github.com/ramyananth/servo] &amp;lt;br/&amp;gt;&lt;br /&gt;
'''Pull Request: '''[https://github.com/servo/servo/pull/26296]&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>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/CSC_517_Spring_2020/Implement_ImageBitMap_WebAPI&amp;diff=134247</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=134247"/>
		<updated>2020-04-25T03:40:34Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* 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;
== '''Current 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 Progress''' ==&lt;br /&gt;
&lt;br /&gt;
* Implemented createImageBitmap method for canvas image source(HTMLCanvasElement and OffscreenCanvas) using RUST programming language in the '''components/script/dom/workerglobalscope.rs''' and '''components/script/dom/window.rs''' files. The comments in the following code will explain the functionality that it carries out.&lt;br /&gt;
&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;
    // The following line creates promise element which is to be returned&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;
    // match the image type to promise element&lt;br /&gt;
    let promise = match image {&lt;br /&gt;
        // Check if the imageBitmapSource is of HTMLCanvasElement type&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;
            // Use fetch_all_data() from canvas_state.rs to return the image data and its size and assign it to a DomRefCell as a vector&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;
                // Set imageBitmap's bitmap data to a copy of image's bitmap data&lt;br /&gt;
                image_bitmap.set_bitmap_data(data);&lt;br /&gt;
                // Set the origin-clean flag of the imageBitmap's bitmap to the same value as the origin-clean flag of image's bitmap&lt;br /&gt;
                image_bitmap.set_origin_clean(canvas.origin_is_clean());&lt;br /&gt;
                // Resolve p with imageBitmap&lt;br /&gt;
                p.resolve_native(&amp;amp;(image_bitmap));&lt;br /&gt;
            }&lt;br /&gt;
            p&lt;br /&gt;
        },&lt;br /&gt;
        // Check if the imageBitmapSource is of OffscreenCanvas type&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;
            // Use fetch_all_data() from canvas_state.rs to return the image data and its size and assign it to a DomRefCell as a vector&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]), // set value as 0 if image data is null&lt;br /&gt;
                );&lt;br /&gt;
                // Set imageBitmap's bitmap data to a copy of image's bitmap data&lt;br /&gt;
                image_bitmap.set_bitmap_data(data);  &lt;br /&gt;
                // Set the origin-clean flag of the imageBitmap's bitmap to the same value as the origin-clean flag of image's bitmap&lt;br /&gt;
                image_bitmap.set_origin_clean(canvas.origin_is_clean());&lt;br /&gt;
                // Resolve p with imageBitmap&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;
== '''Design of 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 quickly, 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. This is done to make sure that the end-to-end implementation can be successfully run in a system.&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) to visually confirm that servo is working :&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;
=='''Code submission and Pull request'''==&lt;br /&gt;
&lt;br /&gt;
'''Code: '''[https://github.com/ramyananth/servo] &amp;lt;br/&amp;gt;&lt;br /&gt;
'''Pull Request: '''[https://github.com/servo/servo/pull/26296]&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>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/CSC_517_Spring_2020/Implement_ImageBitMap_WebAPI&amp;diff=134243</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=134243"/>
		<updated>2020-04-25T03:36:49Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* 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;
== '''Current 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 Progress''' ==&lt;br /&gt;
&lt;br /&gt;
* Implemented createImageBitmap method for canvas image source(HTMLCanvasElement and OffscreenCanvas) using RUST programming language in the '''components/script/dom/workerglobalscope.rs''' and '''components/script/dom/window.rs''' files. The comments in the following code will explain the functionality that it carries out.&lt;br /&gt;
&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;
    // The following line creates promise element which is to be returned&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;
    // match the image type to promise element&lt;br /&gt;
    let promise = match image {&lt;br /&gt;
        // Check if the imageBitmapSource is of HTMLCanvasElement type&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;
            // Use fetch_all_data() from canvas_state.rs to return the image data and its size and assign it to a DomRefCell as a vector&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;
                // Set imageBitmap's bitmap data to a copy of image's bitmap data&lt;br /&gt;
                image_bitmap.set_bitmap_data(data);&lt;br /&gt;
                // Set the origin-clean flag of the imageBitmap's bitmap to the same value as the origin-clean flag of image's bitmap&lt;br /&gt;
                image_bitmap.set_origin_clean(canvas.origin_is_clean());&lt;br /&gt;
                // Resolve p with imageBitmap&lt;br /&gt;
                p.resolve_native(&amp;amp;(image_bitmap));&lt;br /&gt;
            }&lt;br /&gt;
            p&lt;br /&gt;
        },&lt;br /&gt;
        // Check if the imageBitmapSource is of OffscreenCanvas type&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;
            // Use fetch_all_data() from canvas_state.rs to return the image data and its size and assign it to a DomRefCell as a vector&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]), // set value as 0 if image data is null&lt;br /&gt;
                );&lt;br /&gt;
                // Set imageBitmap's bitmap data to a copy of image's bitmap data&lt;br /&gt;
                image_bitmap.set_bitmap_data(data);  &lt;br /&gt;
                // Set the origin-clean flag of the imageBitmap's bitmap to the same value as the origin-clean flag of image's bitmap&lt;br /&gt;
                image_bitmap.set_origin_clean(canvas.origin_is_clean());&lt;br /&gt;
                // Resolve p with imageBitmap&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;
== '''Design of 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;
=='''Code submission and Pull request'''==&lt;br /&gt;
&lt;br /&gt;
'''Code: '''[https://github.com/ramyananth/servo] &amp;lt;br/&amp;gt;&lt;br /&gt;
'''Pull Request: '''[https://github.com/servo/servo/pull/26296]&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>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/CSC_517_Spring_2020/Implement_ImageBitMap_WebAPI&amp;diff=134238</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=134238"/>
		<updated>2020-04-25T03:35:31Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* Proposed 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;
== '''Current 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 Progress''' ==&lt;br /&gt;
&lt;br /&gt;
* Implemented createImageBitmap method for canvas image source(HTMLCanvasElement and OffscreenCanvas) using RUST programming language in the '''components/script/dom/workerglobalscope.rs''' and '''components/script/dom/window.rs''' files. The comments in the following code will explain the functionality that it carries out.&lt;br /&gt;
&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;
    // The following line creates promise element which is to be returned&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;
    // match the image type to promise element&lt;br /&gt;
    let promise = match image {&lt;br /&gt;
        // Check if the imageBitmapSource is of HTMLCanvasElement type&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;
            // Use fetch_all_data() from canvas_state.rs to return the image data and its size and assign it to a DomRefCell as a vector&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;
                // Set imageBitmap's bitmap data to a copy of image's bitmap data&lt;br /&gt;
                image_bitmap.set_bitmap_data(data);&lt;br /&gt;
                // Set the origin-clean flag of the imageBitmap's bitmap to the same value as the origin-clean flag of image's bitmap&lt;br /&gt;
                image_bitmap.set_origin_clean(canvas.origin_is_clean());&lt;br /&gt;
                // Resolve p with imageBitmap&lt;br /&gt;
                p.resolve_native(&amp;amp;(image_bitmap));&lt;br /&gt;
            }&lt;br /&gt;
            p&lt;br /&gt;
        },&lt;br /&gt;
        // Check if the imageBitmapSource is of OffscreenCanvas type&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;
            // Use fetch_all_data() from canvas_state.rs to return the image data and its size and assign it to a DomRefCell as a vector&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]), // set value as 0 if image data is null&lt;br /&gt;
                );&lt;br /&gt;
                // Set imageBitmap's bitmap data to a copy of image's bitmap data&lt;br /&gt;
                image_bitmap.set_bitmap_data(data);  &lt;br /&gt;
                // Set the origin-clean flag of the imageBitmap's bitmap to the same value as the origin-clean flag of image's bitmap&lt;br /&gt;
                image_bitmap.set_origin_clean(canvas.origin_is_clean());&lt;br /&gt;
                // Resolve p with imageBitmap&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;
=='''Code submission and Pull request'''==&lt;br /&gt;
&lt;br /&gt;
'''Code: '''[https://github.com/ramyananth/servo] &amp;lt;br/&amp;gt;&lt;br /&gt;
'''Pull Request: '''[https://github.com/servo/servo/pull/26296]&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>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/CSC_517_Spring_2020/Implement_ImageBitMap_WebAPI&amp;diff=134237</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=134237"/>
		<updated>2020-04-25T03:35:09Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* 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;
== '''Proposed 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 Progress''' ==&lt;br /&gt;
&lt;br /&gt;
* Implemented createImageBitmap method for canvas image source(HTMLCanvasElement and OffscreenCanvas) using RUST programming language in the '''components/script/dom/workerglobalscope.rs''' and '''components/script/dom/window.rs''' files. The comments in the following code will explain the functionality that it carries out.&lt;br /&gt;
&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;
    // The following line creates promise element which is to be returned&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;
    // match the image type to promise element&lt;br /&gt;
    let promise = match image {&lt;br /&gt;
        // Check if the imageBitmapSource is of HTMLCanvasElement type&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;
            // Use fetch_all_data() from canvas_state.rs to return the image data and its size and assign it to a DomRefCell as a vector&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;
                // Set imageBitmap's bitmap data to a copy of image's bitmap data&lt;br /&gt;
                image_bitmap.set_bitmap_data(data);&lt;br /&gt;
                // Set the origin-clean flag of the imageBitmap's bitmap to the same value as the origin-clean flag of image's bitmap&lt;br /&gt;
                image_bitmap.set_origin_clean(canvas.origin_is_clean());&lt;br /&gt;
                // Resolve p with imageBitmap&lt;br /&gt;
                p.resolve_native(&amp;amp;(image_bitmap));&lt;br /&gt;
            }&lt;br /&gt;
            p&lt;br /&gt;
        },&lt;br /&gt;
        // Check if the imageBitmapSource is of OffscreenCanvas type&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;
            // Use fetch_all_data() from canvas_state.rs to return the image data and its size and assign it to a DomRefCell as a vector&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]), // set value as 0 if image data is null&lt;br /&gt;
                );&lt;br /&gt;
                // Set imageBitmap's bitmap data to a copy of image's bitmap data&lt;br /&gt;
                image_bitmap.set_bitmap_data(data);  &lt;br /&gt;
                // Set the origin-clean flag of the imageBitmap's bitmap to the same value as the origin-clean flag of image's bitmap&lt;br /&gt;
                image_bitmap.set_origin_clean(canvas.origin_is_clean());&lt;br /&gt;
                // Resolve p with imageBitmap&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;
=='''Code submission and Pull request'''==&lt;br /&gt;
&lt;br /&gt;
'''Code: '''[https://github.com/ramyananth/servo] &amp;lt;br/&amp;gt;&lt;br /&gt;
'''Pull Request: '''[https://github.com/servo/servo/pull/26296]&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>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/CSC_517_Spring_2020/Implement_ImageBitMap_WebAPI&amp;diff=134234</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=134234"/>
		<updated>2020-04-25T03:34:27Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* Details about previous work on 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;
== '''Proposed 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 in the '''components/script/dom/workerglobalscope.rs''' and '''components/script/dom/window.rs''' files. The comments in the following code will explain the functionality that it carries out.&lt;br /&gt;
&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;
    // The following line creates promise element which is to be returned&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;
    // match the image type to promise element&lt;br /&gt;
    let promise = match image {&lt;br /&gt;
        // Check if the imageBitmapSource is of HTMLCanvasElement type&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;
            // Use fetch_all_data() from canvas_state.rs to return the image data and its size and assign it to a DomRefCell as a vector&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;
                // Set imageBitmap's bitmap data to a copy of image's bitmap data&lt;br /&gt;
                image_bitmap.set_bitmap_data(data);&lt;br /&gt;
                // Set the origin-clean flag of the imageBitmap's bitmap to the same value as the origin-clean flag of image's bitmap&lt;br /&gt;
                image_bitmap.set_origin_clean(canvas.origin_is_clean());&lt;br /&gt;
                // Resolve p with imageBitmap&lt;br /&gt;
                p.resolve_native(&amp;amp;(image_bitmap));&lt;br /&gt;
            }&lt;br /&gt;
            p&lt;br /&gt;
        },&lt;br /&gt;
        // Check if the imageBitmapSource is of OffscreenCanvas type&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;
            // Use fetch_all_data() from canvas_state.rs to return the image data and its size and assign it to a DomRefCell as a vector&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]), // set value as 0 if image data is null&lt;br /&gt;
                );&lt;br /&gt;
                // Set imageBitmap's bitmap data to a copy of image's bitmap data&lt;br /&gt;
                image_bitmap.set_bitmap_data(data);  &lt;br /&gt;
                // Set the origin-clean flag of the imageBitmap's bitmap to the same value as the origin-clean flag of image's bitmap&lt;br /&gt;
                image_bitmap.set_origin_clean(canvas.origin_is_clean());&lt;br /&gt;
                // Resolve p with imageBitmap&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;
=='''Code submission and Pull request'''==&lt;br /&gt;
&lt;br /&gt;
'''Code: '''[https://github.com/ramyananth/servo] &amp;lt;br/&amp;gt;&lt;br /&gt;
'''Pull Request: '''[https://github.com/servo/servo/pull/26296]&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>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/CSC_517_Spring_2020/Implement_ImageBitMap_WebAPI&amp;diff=134223</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=134223"/>
		<updated>2020-04-25T03:31:35Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* Code submission and Pull request */&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 in the '''components/script/dom/workerglobalscope.rs''' and '''components/script/dom/window.rs''' files. The comments in the following code will explain the functionality that it carries out.&lt;br /&gt;
&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;
    // The following line creates promise element which is to be returned&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;
    // match the image type to promise element&lt;br /&gt;
    let promise = match image {&lt;br /&gt;
        // Check if the imageBitmapSource is of HTMLCanvasElement type&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;
            // Use fetch_all_data() from canvas_state.rs to return the image data and its size and assign it to a DomRefCell as a vector&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;
                // Set imageBitmap's bitmap data to a copy of image's bitmap data&lt;br /&gt;
                image_bitmap.set_bitmap_data(data);&lt;br /&gt;
                // Set the origin-clean flag of the imageBitmap's bitmap to the same value as the origin-clean flag of image's bitmap&lt;br /&gt;
                image_bitmap.set_origin_clean(canvas.origin_is_clean());&lt;br /&gt;
                // Resolve p with imageBitmap&lt;br /&gt;
                p.resolve_native(&amp;amp;(image_bitmap));&lt;br /&gt;
            }&lt;br /&gt;
            p&lt;br /&gt;
        },&lt;br /&gt;
        // Check if the imageBitmapSource is of OffscreenCanvas type&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;
            // Use fetch_all_data() from canvas_state.rs to return the image data and its size and assign it to a DomRefCell as a vector&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]), // set value as 0 if image data is null&lt;br /&gt;
                );&lt;br /&gt;
                // Set imageBitmap's bitmap data to a copy of image's bitmap data&lt;br /&gt;
                image_bitmap.set_bitmap_data(data);  &lt;br /&gt;
                // Set the origin-clean flag of the imageBitmap's bitmap to the same value as the origin-clean flag of image's bitmap&lt;br /&gt;
                image_bitmap.set_origin_clean(canvas.origin_is_clean());&lt;br /&gt;
                // Resolve p with imageBitmap&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;
=='''Code submission and Pull request'''==&lt;br /&gt;
&lt;br /&gt;
'''Code: '''[https://github.com/ramyananth/servo] &amp;lt;br/&amp;gt;&lt;br /&gt;
'''Pull Request: '''[https://github.com/servo/servo/pull/26296]&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>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/CSC_517_Spring_2020/Implement_ImageBitMap_WebAPI&amp;diff=134221</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=134221"/>
		<updated>2020-04-25T03:31:19Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* Code submission and Pull request */&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 in the '''components/script/dom/workerglobalscope.rs''' and '''components/script/dom/window.rs''' files. The comments in the following code will explain the functionality that it carries out.&lt;br /&gt;
&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;
    // The following line creates promise element which is to be returned&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;
    // match the image type to promise element&lt;br /&gt;
    let promise = match image {&lt;br /&gt;
        // Check if the imageBitmapSource is of HTMLCanvasElement type&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;
            // Use fetch_all_data() from canvas_state.rs to return the image data and its size and assign it to a DomRefCell as a vector&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;
                // Set imageBitmap's bitmap data to a copy of image's bitmap data&lt;br /&gt;
                image_bitmap.set_bitmap_data(data);&lt;br /&gt;
                // Set the origin-clean flag of the imageBitmap's bitmap to the same value as the origin-clean flag of image's bitmap&lt;br /&gt;
                image_bitmap.set_origin_clean(canvas.origin_is_clean());&lt;br /&gt;
                // Resolve p with imageBitmap&lt;br /&gt;
                p.resolve_native(&amp;amp;(image_bitmap));&lt;br /&gt;
            }&lt;br /&gt;
            p&lt;br /&gt;
        },&lt;br /&gt;
        // Check if the imageBitmapSource is of OffscreenCanvas type&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;
            // Use fetch_all_data() from canvas_state.rs to return the image data and its size and assign it to a DomRefCell as a vector&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]), // set value as 0 if image data is null&lt;br /&gt;
                );&lt;br /&gt;
                // Set imageBitmap's bitmap data to a copy of image's bitmap data&lt;br /&gt;
                image_bitmap.set_bitmap_data(data);  &lt;br /&gt;
                // Set the origin-clean flag of the imageBitmap's bitmap to the same value as the origin-clean flag of image's bitmap&lt;br /&gt;
                image_bitmap.set_origin_clean(canvas.origin_is_clean());&lt;br /&gt;
                // Resolve p with imageBitmap&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;
=='''Code submission and Pull request'''==&lt;br /&gt;
&lt;br /&gt;
'''Code: '''[https://github.com/ramyananth/servo] &amp;lt;/br&amp;gt;&lt;br /&gt;
'''Pull Request: '''[https://github.com/servo/servo/pull/26296]&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>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/CSC_517_Spring_2020/Implement_ImageBitMap_WebAPI&amp;diff=134217</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=134217"/>
		<updated>2020-04-25T03:30:44Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* 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;
== '''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 in the '''components/script/dom/workerglobalscope.rs''' and '''components/script/dom/window.rs''' files. The comments in the following code will explain the functionality that it carries out.&lt;br /&gt;
&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;
    // The following line creates promise element which is to be returned&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;
    // match the image type to promise element&lt;br /&gt;
    let promise = match image {&lt;br /&gt;
        // Check if the imageBitmapSource is of HTMLCanvasElement type&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;
            // Use fetch_all_data() from canvas_state.rs to return the image data and its size and assign it to a DomRefCell as a vector&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;
                // Set imageBitmap's bitmap data to a copy of image's bitmap data&lt;br /&gt;
                image_bitmap.set_bitmap_data(data);&lt;br /&gt;
                // Set the origin-clean flag of the imageBitmap's bitmap to the same value as the origin-clean flag of image's bitmap&lt;br /&gt;
                image_bitmap.set_origin_clean(canvas.origin_is_clean());&lt;br /&gt;
                // Resolve p with imageBitmap&lt;br /&gt;
                p.resolve_native(&amp;amp;(image_bitmap));&lt;br /&gt;
            }&lt;br /&gt;
            p&lt;br /&gt;
        },&lt;br /&gt;
        // Check if the imageBitmapSource is of OffscreenCanvas type&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;
            // Use fetch_all_data() from canvas_state.rs to return the image data and its size and assign it to a DomRefCell as a vector&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]), // set value as 0 if image data is null&lt;br /&gt;
                );&lt;br /&gt;
                // Set imageBitmap's bitmap data to a copy of image's bitmap data&lt;br /&gt;
                image_bitmap.set_bitmap_data(data);  &lt;br /&gt;
                // Set the origin-clean flag of the imageBitmap's bitmap to the same value as the origin-clean flag of image's bitmap&lt;br /&gt;
                image_bitmap.set_origin_clean(canvas.origin_is_clean());&lt;br /&gt;
                // Resolve p with imageBitmap&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;
=='''Code submission and Pull request'''==&lt;br /&gt;
&lt;br /&gt;
'''Code: '''[https://github.com/ramyananth/servo]&lt;br /&gt;
'''Pull Request: '''[https://github.com/servo/servo/pull/26296]&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>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/CSC_517_Spring_2020/Implement_ImageBitMap_WebAPI&amp;diff=134208</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=134208"/>
		<updated>2020-04-25T03:27:29Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* 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 in the '''components/script/dom/workerglobalscope.rs''' and '''components/script/dom/window.rs''' files. The comments in the following code will explain the functionality that it carries out.&lt;br /&gt;
&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;
    // The following line creates promise element which is to be returned&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;
    // match the image type to promise element&lt;br /&gt;
    let promise = match image {&lt;br /&gt;
        // Check if the imageBitmapSource is of HTMLCanvasElement type&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;
            // Use fetch_all_data() from canvas_state.rs to return the image data and its size and assign it to a DomRefCell as a vector&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;
                // Set imageBitmap's bitmap data to a copy of image's bitmap data&lt;br /&gt;
                image_bitmap.set_bitmap_data(data);&lt;br /&gt;
                // Set the origin-clean flag of the imageBitmap's bitmap to the same value as the origin-clean flag of image's bitmap&lt;br /&gt;
                image_bitmap.set_origin_clean(canvas.origin_is_clean());&lt;br /&gt;
                // Resolve p with imageBitmap&lt;br /&gt;
                p.resolve_native(&amp;amp;(image_bitmap));&lt;br /&gt;
            }&lt;br /&gt;
            p&lt;br /&gt;
        },&lt;br /&gt;
        // Check if the imageBitmapSource is of OffscreenCanvas type&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;
            // Use fetch_all_data() from canvas_state.rs to return the image data and its size and assign it to a DomRefCell as a vector&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]), // set value as 0 if image data is null&lt;br /&gt;
                );&lt;br /&gt;
                // Set imageBitmap's bitmap data to a copy of image's bitmap data&lt;br /&gt;
                image_bitmap.set_bitmap_data(data);  &lt;br /&gt;
                // Set the origin-clean flag of the imageBitmap's bitmap to the same value as the origin-clean flag of image's bitmap&lt;br /&gt;
                image_bitmap.set_origin_clean(canvas.origin_is_clean());&lt;br /&gt;
                // Resolve p with imageBitmap&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>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/CSC_517_Spring_2020/Implement_ImageBitMap_WebAPI&amp;diff=134164</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=134164"/>
		<updated>2020-04-25T02:59:43Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* Details about current work on 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;
```&lt;br /&gt;
&lt;br /&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>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/CSC_517_Spring_2020/Implement_ImageBitMap_WebAPI&amp;diff=134130</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=134130"/>
		<updated>2020-04-25T02:48:06Z</updated>

		<summary type="html">&lt;p&gt;Skundal: &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 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>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/CSC_517_Spring_2020/Implement_ImageBitMap_WebAPI&amp;diff=134048</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=134048"/>
		<updated>2020-04-25T01:06:03Z</updated>

		<summary type="html">&lt;p&gt;Skundal: &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 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;
== '''Output''' ==&lt;br /&gt;
To run the servo with a webpage (Google.com)&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>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/CSC_517_Spring_2020/Implement_ImageBitMap_WebAPI&amp;diff=134040</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=134040"/>
		<updated>2020-04-25T00:54:54Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* 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 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;
== '''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>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/CSC_517_Spring_2020/Implement_ImageBitMap_WebAPI&amp;diff=134017</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=134017"/>
		<updated>2020-04-25T00:34:28Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* 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 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;
&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;
== '''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>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/CSC_517_Spring_2020/Implement_ImageBitMap_WebAPI&amp;diff=134005</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=134005"/>
		<updated>2020-04-25T00:24:04Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* 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;
&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;
== '''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>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132629</id>
		<title>CSC/ECE 517 Spring 2020 - Project E2008. Refactor summary helper.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132629"/>
		<updated>2020-04-01T03:40:19Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* Refactor - summarize_reviews_by_criterion */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''About Expertiza'''==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed using Ruby on Rails Framework whose creation and maintenance are taken care of by students as well as the faculty of NCSU. Its code is available on Github [https://github.com/expertiza/expertiza Expertiza on GitHub]. Expertiza allows the instructor to create and edit new as well as existing assignments. This also includes creating a wide range of topics under each assignment that students can sign up for. They can also publish surveys and reviews, view statistical results, set deadlines for assignments and make announcements. It provides a platform for students to signup for topics, form teams, view and submit assignments and give peer reviews and feedback.&lt;br /&gt;
&lt;br /&gt;
=='''Problem Statement'''==&lt;br /&gt;
'''Background:''' In Expertiza students can review each other’s projects and even each other as teammates. Students can view their project scores and instructors can view student's teammate review scores on the view scores page. This Summary helper aids in calculating these scores and rendering the results on the view scores section of an assignment. Summary helper is a helper module that consists of methods used to calculate scores for these reviews. This is for the use of instructors.&lt;br /&gt;
&lt;br /&gt;
'''Requirement:'''&lt;br /&gt;
E2008 is an Expertiza OSS project which deals basically with refactoring app/helpers/summary_helper.rb to reduce the code climate issues such as&lt;br /&gt;
&lt;br /&gt;
* [http://wiki.c2.com/?AbcMetric Assignment Branch Condition]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Cognitive_complexity Cognitive Complexity]&lt;br /&gt;
* Method/line too long&lt;br /&gt;
* Unused variables / access modifiers&lt;br /&gt;
&lt;br /&gt;
'''A good method should have:'''&lt;br /&gt;
* Assignment Branch Condition size &amp;lt;= 15&lt;br /&gt;
* Cognitive Complexity &amp;lt;= 6&lt;br /&gt;
* No. of lines in a method &amp;lt;= 25&lt;br /&gt;
&lt;br /&gt;
=='''Issues found'''==&lt;br /&gt;
The following are issues which were found in the code:&lt;br /&gt;
&lt;br /&gt;
==='''Assignment Branch Condition'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! ABC Size&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewee&lt;br /&gt;
| 44.61&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 42.34&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 89.93&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 16.43&lt;br /&gt;
|-&lt;br /&gt;
| calculate_avg_score_by_round&lt;br /&gt;
| 18.57&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
==='''Cognitive Complexity'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! Cognitive Complexity&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 16&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 17&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 11&lt;br /&gt;
|-&lt;br /&gt;
| break_up_comments_to_sentences&lt;br /&gt;
| 6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Method/line too long'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method/Line too long&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewees&lt;br /&gt;
|'''Lines of Code:'''39&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_criterion  &lt;br /&gt;
|'''Lines of Code:'''27&lt;br /&gt;
|-&lt;br /&gt;
|'''Line:''' 145&lt;br /&gt;
|self.avg_scores_by_round[reviewee.name][round] too long (162/160)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==='''Unused variables / access modifiers'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Vaiable/Access Modifier&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' summary  &lt;br /&gt;
|'''Method:''' summarize_sentences&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' included_question_counter  &lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewee&lt;br /&gt;
|-&lt;br /&gt;
|'''Access Modifier:''' module_function  &lt;br /&gt;
|'''Class:''' Summary&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=='''Solution Implemented'''==&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewee'''===&lt;br /&gt;
:This method is used to summarize reviews by a reviewer for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:''' &lt;br /&gt;
:This method could be refactored into smaller methods namely ''summarize_reviews_by_reviewee'' and ''summarize_reviews_by_reviewee_assign'' where ''summarize_reviews_by_reviewee'' calls ''summarize_reviews_by_reviewee_assign'' to get average scores and summary for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def summarize_reviews_by_reviewee(questions, assignment, r_id, summary_ws_url)&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
&lt;br /&gt;
      # get all answers for each question and send them to summarization WS&lt;br /&gt;
      questions.keys.each do |round|&lt;br /&gt;
        self.summary[round.to_s] = {}&lt;br /&gt;
        self.avg_scores_by_criterion[round.to_s] = {}&lt;br /&gt;
        self.avg_scores_by_round[round.to_s] = 0.0&lt;br /&gt;
        included_question_counter = 0&lt;br /&gt;
&lt;br /&gt;
        questions[round].each do |q|&lt;br /&gt;
          next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
          self.summary[round.to_s][q.txt] = &amp;quot;&amp;quot;&lt;br /&gt;
          self.avg_scores_by_criterion[round.to_s][q.txt] = 0.0&lt;br /&gt;
&lt;br /&gt;
          question_answers = Answer.answers_by_question_for_reviewee(assignment.id, r_id, q.id)&lt;br /&gt;
&lt;br /&gt;
          max_score = get_max_score_for_question(q)&lt;br /&gt;
&lt;br /&gt;
          comments = break_up_comments_to_sentences(question_answers)&lt;br /&gt;
&lt;br /&gt;
          # get the avg scores for this question&lt;br /&gt;
          self.avg_scores_by_criterion[round.to_s][q.txt] = calculate_avg_score_by_criterion(question_answers, max_score)&lt;br /&gt;
          # get the summary of answers to this question&lt;br /&gt;
          self.summary[round.to_s][q.txt] = summarize_sentences(comments, summary_ws_url)&lt;br /&gt;
        end&lt;br /&gt;
        self.avg_scores_by_round[round.to_s] = calculate_avg_score_by_round(self.avg_scores_by_criterion[round.to_s], questions[round])&lt;br /&gt;
      end&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    # produce average score and summary of comments for reviews by a reviewer for each question&lt;br /&gt;
    def summarize_reviews_by_reviewee(questions, assignment, reviewee_id, summary_ws_url)&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.summary_ws_url = summary_ws_url&lt;br /&gt;
&lt;br /&gt;
      # get all answers for each question and send them to summarization WS&lt;br /&gt;
      questions.each_key do |round|&lt;br /&gt;
        self.summary[round.to_s] = {}&lt;br /&gt;
        self.avg_scores_by_criterion[round.to_s] = {}&lt;br /&gt;
        self.avg_scores_by_round[round.to_s] = 0.0&lt;br /&gt;
        questions[round].each do |question|&lt;br /&gt;
          next if question.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
          summarize_reviews_by_reviewee_question(assignment, reviewee_id, question, round)&lt;br /&gt;
        end&lt;br /&gt;
        self.avg_scores_by_round[round.to_s] = calculate_avg_score_by_round(self.avg_scores_by_criterion[round.to_s], questions[round])&lt;br /&gt;
      end&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # get average scores and summary for each question in a review by a reviewer&lt;br /&gt;
    def summarize_reviews_by_reviewee_question(assignment, reviewee_id, question, round)&lt;br /&gt;
      question_answers = Answer.answers_by_question_for_reviewee(assignment.id, reviewee_id, question.id)&lt;br /&gt;
&lt;br /&gt;
      self.avg_scores_by_criterion[round.to_s][question.txt] = calculate_avg_score_by_criterion(question_answers, get_max_score_for_question(question))&lt;br /&gt;
&lt;br /&gt;
      self.summary[round.to_s][question.txt] = summarize_sentences(break_up_comments_to_sentences(question_answers), self.summary_ws_url)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewee is reduced from 44.61 to 20.64.&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_criterion'''===&lt;br /&gt;
:This method is used to summarize the review for each questions&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:*This method was refactored into 3 smaller methods namely ''summarize_reviews_by_criterion'', ''summarize_reviews_by_criterion_questions'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:*The method ''summarize_reviews_by_criterion'' calls ''summarize_reviews_by_criterion_questions'' to get answers of each question in the rubric.&lt;br /&gt;
&lt;br /&gt;
:*The method ''summarize_reviews_by_criterion_questions'' starts many threads to process each question and closes it by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    # produce summaries for instructor. it merges all feedback given to all reviewees, and summarize them by criterion&lt;br /&gt;
    def summarize_reviews_by_criterion(assignment, summary_ws_url)&lt;br /&gt;
      # @summary[reviewee][round][question]&lt;br /&gt;
      # @avg_score_round[reviewee][round]&lt;br /&gt;
      # @avg_scores_by_criterion[reviewee][round][criterion]&lt;br /&gt;
      nround = assignment.rounds_of_reviews&lt;br /&gt;
      self.summary = Array.new(nround)&lt;br /&gt;
      self.avg_scores_by_criterion = Array.new(nround)&lt;br /&gt;
      self.avg_scores_by_round = Array.new(nround)&lt;br /&gt;
      threads = []&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      (0..nround - 1).each do |round|&lt;br /&gt;
        self.avg_scores_by_round[round] = 0.0&lt;br /&gt;
        self.summary[round] = {}&lt;br /&gt;
        self.avg_scores_by_criterion[round] = {}&lt;br /&gt;
&lt;br /&gt;
        questions_used_in_round = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
        # get answers of each question in the rubric&lt;br /&gt;
        questions_used_in_round.each do |question|&lt;br /&gt;
          next if question.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
          answers_questions = Answer.answers_by_question(assignment.id, question.id)&lt;br /&gt;
&lt;br /&gt;
          max_score = get_max_score_for_question(question)&lt;br /&gt;
          # process each question in a seperate thread&lt;br /&gt;
          threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
            comments = break_up_comments_to_sentences(answers_questions)&lt;br /&gt;
            # store each avg in a hashmap and use the question as the key&lt;br /&gt;
            self.avg_scores_by_criterion[round][question.txt] = calculate_avg_score_by_criterion(answers_questions, max_score)&lt;br /&gt;
            self.summary[round][question.txt] = summarize_sentences(comments, summary_ws_url) unless comments.empty?&lt;br /&gt;
          end&lt;br /&gt;
          # Wait for all threads to end&lt;br /&gt;
          threads.each do |t|&lt;br /&gt;
            # Wait for the thread to finish if it isn't this thread (i.e. the main thread).&lt;br /&gt;
            t.join if t != Thread.current&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
        self.avg_scores_by_round[round] = calculate_avg_score_by_round(avg_scores_by_criterion[round], questions_used_in_round)&lt;br /&gt;
      end&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    # produce summaries for instructor. it merges all feedback given to all reviewees, and summarize them by criterion&lt;br /&gt;
    def summarize_reviews_by_criterion(assignment, summary_ws_url)&lt;br /&gt;
      self.summary = self.avg_scores_by_criterion = self.avg_scores_by_round = Array.new(assignment.rounds_of_reviews)&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get question in each round and summarize them all&lt;br /&gt;
      (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
        questions_used_in_round = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
        questions_used_in_round.each do |question|&lt;br /&gt;
          next if question.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
          summarize_reviews_by_criterion_question(assignment, summary_ws_url, round, question)&lt;br /&gt;
        end&lt;br /&gt;
        self.avg_scores_by_round[round] = calculate_avg_score_by_round(avg_scores_by_criterion[round], questions_used_in_round)&lt;br /&gt;
      end&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # get summary of answers of each question in the rubric&lt;br /&gt;
    def summarize_reviews_by_criterion_question(assignment, summary_ws_url, round, question)&lt;br /&gt;
      threads = []&lt;br /&gt;
      answers_questions = Answer.answers_by_question(assignment.id, question.id)&lt;br /&gt;
&lt;br /&gt;
      threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
        self.avg_scores_by_criterion[round][question.txt] = calculate_avg_score_by_criterion(answers_questions, get_max_score_for_question(question))&lt;br /&gt;
        self.summary[round][question.txt] = summarize_sentences(break_up_comments_to_sentences(answers_questions), summary_ws_url)&lt;br /&gt;
      end&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      end_threads(threads)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Wait for threads to end&lt;br /&gt;
    def end_threads(threads)&lt;br /&gt;
      threads.each do |t|&lt;br /&gt;
        # Wait for the thread to finish if it isn't this thread (i.e. the main thread).&lt;br /&gt;
        t.join if t != Thread.current&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_criterion is reduced from 42.34 to 17.2&lt;br /&gt;
:* Cognitive complexity is reduced from 16 to 7&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewees'''===&lt;br /&gt;
:This method is used to produce summaries for instructor and students. It sums up the feedback by criterion for each reviewer&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:*This method was refactored into 4 smaller methods namely ''summarize_reviews_by_reviewees'', ''summarize_reviews_by_teams'', ''summarize_by_reviewee_round'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:*The method ''summarize_reviews_by_reviewees'' calls ''summarize_reviews_by_teams''  which inturn calls ''summarize_by_reviewee_round'' to get answers of each reviewer by rubric.&lt;br /&gt;
&lt;br /&gt;
:*The method ''summarize_by_reviewee_round'' starts many threads to create requests to summarize the comments and closes the threads by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def summarize_reviews_by_reviewees(assignment, summary_ws_url)&lt;br /&gt;
      # @summary[reviewee][round][question]&lt;br /&gt;
      # @reviewers[team][reviewer]&lt;br /&gt;
      # @avg_scores_by_reviewee[team]&lt;br /&gt;
      # @avg_score_round[reviewee][round]&lt;br /&gt;
      # @avg_scores_by_criterion[reviewee][round][criterion]&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_reviewee = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.reviewers = ({})&lt;br /&gt;
      threads = []&lt;br /&gt;
&lt;br /&gt;
      # get all criteria used in each round&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get all teams in this assignment&lt;br /&gt;
      teams = Team.select(:id, :name).where(parent_id: assignment.id).order(:name)&lt;br /&gt;
&lt;br /&gt;
      teams.each do |reviewee|&lt;br /&gt;
        self.summary[reviewee.name] = []&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = 0.0&lt;br /&gt;
        self.avg_scores_by_round[reviewee.name] = []&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name] = []&lt;br /&gt;
&lt;br /&gt;
        # get the name of reviewers for display only&lt;br /&gt;
        self.reviewers[reviewee.name] = get_reviewers_by_reviewee_and_assignment(reviewee, assignment.id)&lt;br /&gt;
&lt;br /&gt;
        # get answers of each reviewer by rubric&lt;br /&gt;
        (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
          self.summary[reviewee.name][round] = {}&lt;br /&gt;
          self.avg_scores_by_round[reviewee.name][round] = 0.0&lt;br /&gt;
          self.avg_scores_by_criterion[reviewee.name][round] = {}&lt;br /&gt;
&lt;br /&gt;
          # iterate each round and get answers&lt;br /&gt;
          # if use the same rubric, only use rubric[0]&lt;br /&gt;
          rubric_questions_used = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
          rubric_questions_used.each do |q|&lt;br /&gt;
            next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
            summary[reviewee.name][round][q.txt] = &amp;quot;&amp;quot;&lt;br /&gt;
            self.avg_scores_by_criterion[reviewee.name][round][q.txt] = 0.0&lt;br /&gt;
&lt;br /&gt;
            # get all answers to this question&lt;br /&gt;
            question_answers = Answer.answers_by_question_for_reviewee_in_round(assignment.id, reviewee.id, q.id, round + 1)&lt;br /&gt;
            # get max score of this rubric&lt;br /&gt;
            q_max_score = get_max_score_for_question(q)&lt;br /&gt;
&lt;br /&gt;
            comments = break_up_comments_to_sentences(question_answers)&lt;br /&gt;
            # get score and summary of answers for each question&lt;br /&gt;
            self.avg_scores_by_criterion[reviewee.name][round][q.txt] = calculate_avg_score_by_criterion(question_answers, q_max_score)&lt;br /&gt;
&lt;br /&gt;
            # summarize the comments by calling the summarization Web Service&lt;br /&gt;
&lt;br /&gt;
            # since it'll do a lot of request, do this in seperate threads&lt;br /&gt;
            threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
              summary[reviewee.name][round][q.txt] = summarize_sentences(comments, summary_ws_url) unless comments.empty?&lt;br /&gt;
            end&lt;br /&gt;
          end&lt;br /&gt;
          self.avg_scores_by_round[reviewee.name][round] = calculate_avg_score_by_round(self.avg_scores_by_criterion[reviewee.name][round], rubric_questions_used)&lt;br /&gt;
        end&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = calculate_avg_score_by_reviewee(self.avg_scores_by_round[reviewee.name], assignment.rounds_of_reviews)&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      threads.each do |t|&lt;br /&gt;
        t.join if t != Thread.current&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    # produce summaries for instructor and students. It sum up the feedback by criterion for each reviewee&lt;br /&gt;
    def summarize_reviews_by_reviewees(assignment, summary_ws_url)&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_reviewee = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.reviewers = ({})&lt;br /&gt;
      self.summary_ws_url = summary_ws_url&lt;br /&gt;
&lt;br /&gt;
      # get all criteria used in each round&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get all teams in this assignment&lt;br /&gt;
      teams = Team.select(:id, :name).where(parent_id: assignment.id).order(:name)&lt;br /&gt;
&lt;br /&gt;
      teams.each do |reviewee|&lt;br /&gt;
        summarize_reviews_by_team_reviewee(assignment, reviewee, rubric)&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = calculate_avg_score_by_reviewee(self.avg_scores_by_round[reviewee.name], assignment.rounds_of_reviews)&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # get answers and average scores for each team&lt;br /&gt;
    def summarize_reviews_by_team_reviewee(assignment, reviewee, rubric)&lt;br /&gt;
      self.summary[reviewee.name] = []&lt;br /&gt;
      self.avg_scores_by_reviewee[reviewee.name] = 0.0&lt;br /&gt;
      self.avg_scores_by_round[reviewee.name] = self.avg_scores_by_criterion[reviewee.name] = []&lt;br /&gt;
&lt;br /&gt;
      # get the name of reviewers for display only&lt;br /&gt;
      self.reviewers[reviewee.name] = get_reviewers_by_reviewee_and_assignment(reviewee, assignment.id)&lt;br /&gt;
&lt;br /&gt;
      # get answers and average scores of each round by rubric&lt;br /&gt;
      (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
        self.summary[reviewee.name][round] = {}&lt;br /&gt;
        self.avg_scores_by_round[reviewee.name][round] = 0.0&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name][round] = {}&lt;br /&gt;
        summarize_by_reviewee_round(assignment, reviewee, round, rubric)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # get answers and averge score for each question in a round&lt;br /&gt;
    def summarize_by_reviewee_round(assignment, reviewee, round, rubric)&lt;br /&gt;
      threads = []&lt;br /&gt;
      # if use the same rubric, only use rubric[0]&lt;br /&gt;
      rubric_questions_used = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
      rubric_questions_used.each do |q|&lt;br /&gt;
        next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # get all answers to this question&lt;br /&gt;
        question_answers = Answer.answers_by_question_for_reviewee_in_round(assignment.id, reviewee.id, q.id, round + 1)&lt;br /&gt;
&lt;br /&gt;
        # get score and summary of answers for each question&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name][round][q.txt] = calculate_avg_score_by_criterion(question_answers, get_max_score_for_question(q))&lt;br /&gt;
&lt;br /&gt;
        threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
          self.summary[reviewee.name][round][q.txt] = summarize_sentences(break_up_comments_to_sentences(question_answers), self.summary_ws_url)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      avg_scores_by_round = calculate_avg_score_by_round(self.avg_scores_by_criterion[reviewee.name][round], rubric_questions_used)&lt;br /&gt;
      self.avg_scores_by_round[reviewee.name][round] = avg_scores_by_round&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      end_threads(threads)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewees is reduced from 89.93 to 16.64&lt;br /&gt;
:* Cognitive Complexity is reduced from 17 to 7&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_sentence'''===&lt;br /&gt;
:This method calls web service to store each summary in a hashmap and use the question as the key.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Removed variable ''summary''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_8.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - break_up_comments_to_sentences'''===&lt;br /&gt;
: This method adds the comment to an array to be converted as a json request.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:The method is broken down into 2 smaller methods namely ''break_up_comments_to_sentences'' and ''get_sentences'' where ''get_sentences'' is called by ''break_up_comments_to_sentences'' to  get sentences in desired format.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_9.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact''':&lt;br /&gt;
:*The Cognitive complexity of break_up_comments_to_sentences reduced from 6 to &amp;lt;5&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - get_questions_by_assignment'''===&lt;br /&gt;
:This method returns the rubric for given assignment&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
:*In IF CONDITION: Removed unnecessary use of variable which was being used only once (questionaire_id) and replaced the variable with its assignment (assignment.review_questionnaire_id(round + 1)&lt;br /&gt;
:*In ELSE CONDITION: Removed unnecessary ternary operation for variable ''questionaire_id'' and replaced the variable with its assignment (assignment.review_questionnaire_id) &lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_10.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - calculate_avg_score_by_round'''===&lt;br /&gt;
:This method is used to calculate average round score for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Refactored the method into 2 smaller methods namely ''calculate_avg_score_by_round'' and ''calculate_round_score'' where ''calculate_avg_score_by_round'' calls ''calculate_round_score'' to calculate average round score and ''calculate_avg_score_by_round'' rounds the round_score upto 2 decimal places.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = 0.0&lt;br /&gt;
      sum_weight = 0&lt;br /&gt;
&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = sum_weight = 0.0&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
      round_score&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:*Assignment Branch Condition size for calculate_avg_score_by_round is reduced from 18.57 to &amp;lt;15.&lt;br /&gt;
&lt;br /&gt;
==='''Coverage'''===&lt;br /&gt;
Coverage increased (+17.1%) to 41.407%&lt;br /&gt;
&lt;br /&gt;
==='''Pull request'''===&lt;br /&gt;
https://github.com/expertiza/expertiza/pull/1685&lt;br /&gt;
&lt;br /&gt;
=='''Test Plan'''==&lt;br /&gt;
==='''Manual Testing'''===&lt;br /&gt;
:'''Login Details:''' '''USERNAME:''' instructor6 '''PASSWORD:''' password&lt;br /&gt;
:Click '''Assignment''' &amp;gt;&amp;gt; Click the '''View Submissions''' of '''Madeup problem''' &amp;gt;&amp;gt; Click on any student &amp;gt;&amp;gt; Click on '''Madeup problem''' &amp;gt;&amp;gt; Click on '''Your Scores'''&lt;br /&gt;
:[[File:expertiza2008-1.png]]&lt;br /&gt;
:[[File:expertiza2008-2.png]]&lt;br /&gt;
:[[File:expertiza2008-3.png]]&lt;br /&gt;
:[[File:expertiza2008-4.png]]&lt;br /&gt;
:The 3 main functions of the Summary helper are summarize review by reviewees, summarize review by reviewee and summarize reviews by criterion.&lt;br /&gt;
:To check ''summarize reviews by reviewees'' is working we should get the output similar to the one shown below. This function summarizes all the reviews and displays average score.&lt;br /&gt;
:[[File:expertiza2008-5.png]]&lt;br /&gt;
&lt;br /&gt;
:To check ''summarize reviews by reviewee'' is working, click on any review.&lt;br /&gt;
:[[File:expertiza2008-6a.png]]&lt;br /&gt;
:A new webpage pops up with all the reviews and scores given by an individual.&lt;br /&gt;
:[[File:expertiza2008-6b.png]]&lt;br /&gt;
&lt;br /&gt;
: To check ''summarize reviews by criterion'' is working, click on any criterion. This should display summarized reviews and scores for a particular question in the questionnaire.&lt;br /&gt;
:[[File:expertiza2008-7.png]]&lt;br /&gt;
&lt;br /&gt;
=='''Future improvement'''==&lt;br /&gt;
* Modularize ''summarize_by_rounds'' to even smaller modules so that Assignment Branch Condition size is reduced from 36.73 to 15.00.&lt;br /&gt;
* Create more test cases for the new modularized methods.&lt;br /&gt;
&lt;br /&gt;
=='''Contributors'''==&lt;br /&gt;
* [mailto:jviswan@ncsu.edu Jayalakshmi Viswanathan]&lt;br /&gt;
* [mailto:skundal@ncsu.edu Sandeep Kundala]&lt;br /&gt;
* [mailto:spal3@ncsu.edu Sumitosh Pal]&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132628</id>
		<title>CSC/ECE 517 Spring 2020 - Project E2008. Refactor summary helper.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132628"/>
		<updated>2020-04-01T03:39:56Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* Refactor - summarize_reviews_by_reviewees */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''About Expertiza'''==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed using Ruby on Rails Framework whose creation and maintenance are taken care of by students as well as the faculty of NCSU. Its code is available on Github [https://github.com/expertiza/expertiza Expertiza on GitHub]. Expertiza allows the instructor to create and edit new as well as existing assignments. This also includes creating a wide range of topics under each assignment that students can sign up for. They can also publish surveys and reviews, view statistical results, set deadlines for assignments and make announcements. It provides a platform for students to signup for topics, form teams, view and submit assignments and give peer reviews and feedback.&lt;br /&gt;
&lt;br /&gt;
=='''Problem Statement'''==&lt;br /&gt;
'''Background:''' In Expertiza students can review each other’s projects and even each other as teammates. Students can view their project scores and instructors can view student's teammate review scores on the view scores page. This Summary helper aids in calculating these scores and rendering the results on the view scores section of an assignment. Summary helper is a helper module that consists of methods used to calculate scores for these reviews. This is for the use of instructors.&lt;br /&gt;
&lt;br /&gt;
'''Requirement:'''&lt;br /&gt;
E2008 is an Expertiza OSS project which deals basically with refactoring app/helpers/summary_helper.rb to reduce the code climate issues such as&lt;br /&gt;
&lt;br /&gt;
* [http://wiki.c2.com/?AbcMetric Assignment Branch Condition]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Cognitive_complexity Cognitive Complexity]&lt;br /&gt;
* Method/line too long&lt;br /&gt;
* Unused variables / access modifiers&lt;br /&gt;
&lt;br /&gt;
'''A good method should have:'''&lt;br /&gt;
* Assignment Branch Condition size &amp;lt;= 15&lt;br /&gt;
* Cognitive Complexity &amp;lt;= 6&lt;br /&gt;
* No. of lines in a method &amp;lt;= 25&lt;br /&gt;
&lt;br /&gt;
=='''Issues found'''==&lt;br /&gt;
The following are issues which were found in the code:&lt;br /&gt;
&lt;br /&gt;
==='''Assignment Branch Condition'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! ABC Size&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewee&lt;br /&gt;
| 44.61&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 42.34&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 89.93&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 16.43&lt;br /&gt;
|-&lt;br /&gt;
| calculate_avg_score_by_round&lt;br /&gt;
| 18.57&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
==='''Cognitive Complexity'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! Cognitive Complexity&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 16&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 17&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 11&lt;br /&gt;
|-&lt;br /&gt;
| break_up_comments_to_sentences&lt;br /&gt;
| 6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Method/line too long'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method/Line too long&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewees&lt;br /&gt;
|'''Lines of Code:'''39&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_criterion  &lt;br /&gt;
|'''Lines of Code:'''27&lt;br /&gt;
|-&lt;br /&gt;
|'''Line:''' 145&lt;br /&gt;
|self.avg_scores_by_round[reviewee.name][round] too long (162/160)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==='''Unused variables / access modifiers'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Vaiable/Access Modifier&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' summary  &lt;br /&gt;
|'''Method:''' summarize_sentences&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' included_question_counter  &lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewee&lt;br /&gt;
|-&lt;br /&gt;
|'''Access Modifier:''' module_function  &lt;br /&gt;
|'''Class:''' Summary&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=='''Solution Implemented'''==&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewee'''===&lt;br /&gt;
:This method is used to summarize reviews by a reviewer for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:''' &lt;br /&gt;
:This method could be refactored into smaller methods namely ''summarize_reviews_by_reviewee'' and ''summarize_reviews_by_reviewee_assign'' where ''summarize_reviews_by_reviewee'' calls ''summarize_reviews_by_reviewee_assign'' to get average scores and summary for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def summarize_reviews_by_reviewee(questions, assignment, r_id, summary_ws_url)&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
&lt;br /&gt;
      # get all answers for each question and send them to summarization WS&lt;br /&gt;
      questions.keys.each do |round|&lt;br /&gt;
        self.summary[round.to_s] = {}&lt;br /&gt;
        self.avg_scores_by_criterion[round.to_s] = {}&lt;br /&gt;
        self.avg_scores_by_round[round.to_s] = 0.0&lt;br /&gt;
        included_question_counter = 0&lt;br /&gt;
&lt;br /&gt;
        questions[round].each do |q|&lt;br /&gt;
          next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
          self.summary[round.to_s][q.txt] = &amp;quot;&amp;quot;&lt;br /&gt;
          self.avg_scores_by_criterion[round.to_s][q.txt] = 0.0&lt;br /&gt;
&lt;br /&gt;
          question_answers = Answer.answers_by_question_for_reviewee(assignment.id, r_id, q.id)&lt;br /&gt;
&lt;br /&gt;
          max_score = get_max_score_for_question(q)&lt;br /&gt;
&lt;br /&gt;
          comments = break_up_comments_to_sentences(question_answers)&lt;br /&gt;
&lt;br /&gt;
          # get the avg scores for this question&lt;br /&gt;
          self.avg_scores_by_criterion[round.to_s][q.txt] = calculate_avg_score_by_criterion(question_answers, max_score)&lt;br /&gt;
          # get the summary of answers to this question&lt;br /&gt;
          self.summary[round.to_s][q.txt] = summarize_sentences(comments, summary_ws_url)&lt;br /&gt;
        end&lt;br /&gt;
        self.avg_scores_by_round[round.to_s] = calculate_avg_score_by_round(self.avg_scores_by_criterion[round.to_s], questions[round])&lt;br /&gt;
      end&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    # produce average score and summary of comments for reviews by a reviewer for each question&lt;br /&gt;
    def summarize_reviews_by_reviewee(questions, assignment, reviewee_id, summary_ws_url)&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.summary_ws_url = summary_ws_url&lt;br /&gt;
&lt;br /&gt;
      # get all answers for each question and send them to summarization WS&lt;br /&gt;
      questions.each_key do |round|&lt;br /&gt;
        self.summary[round.to_s] = {}&lt;br /&gt;
        self.avg_scores_by_criterion[round.to_s] = {}&lt;br /&gt;
        self.avg_scores_by_round[round.to_s] = 0.0&lt;br /&gt;
        questions[round].each do |question|&lt;br /&gt;
          next if question.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
          summarize_reviews_by_reviewee_question(assignment, reviewee_id, question, round)&lt;br /&gt;
        end&lt;br /&gt;
        self.avg_scores_by_round[round.to_s] = calculate_avg_score_by_round(self.avg_scores_by_criterion[round.to_s], questions[round])&lt;br /&gt;
      end&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # get average scores and summary for each question in a review by a reviewer&lt;br /&gt;
    def summarize_reviews_by_reviewee_question(assignment, reviewee_id, question, round)&lt;br /&gt;
      question_answers = Answer.answers_by_question_for_reviewee(assignment.id, reviewee_id, question.id)&lt;br /&gt;
&lt;br /&gt;
      self.avg_scores_by_criterion[round.to_s][question.txt] = calculate_avg_score_by_criterion(question_answers, get_max_score_for_question(question))&lt;br /&gt;
&lt;br /&gt;
      self.summary[round.to_s][question.txt] = summarize_sentences(break_up_comments_to_sentences(question_answers), self.summary_ws_url)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewee is reduced from 44.61 to 20.64.&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_criterion'''===&lt;br /&gt;
:This method is used to summarize the review for each questions&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 3 smaller methods namely ''summarize_reviews_by_criterion'', ''summarize_reviews_by_criterion_questions'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion'' calls ''summarize_reviews_by_criterion_questions'' to get answers of each question in the rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion_questions'' starts many threads to process each question and closes it by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    # produce summaries for instructor. it merges all feedback given to all reviewees, and summarize them by criterion&lt;br /&gt;
    def summarize_reviews_by_criterion(assignment, summary_ws_url)&lt;br /&gt;
      # @summary[reviewee][round][question]&lt;br /&gt;
      # @avg_score_round[reviewee][round]&lt;br /&gt;
      # @avg_scores_by_criterion[reviewee][round][criterion]&lt;br /&gt;
      nround = assignment.rounds_of_reviews&lt;br /&gt;
      self.summary = Array.new(nround)&lt;br /&gt;
      self.avg_scores_by_criterion = Array.new(nround)&lt;br /&gt;
      self.avg_scores_by_round = Array.new(nround)&lt;br /&gt;
      threads = []&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      (0..nround - 1).each do |round|&lt;br /&gt;
        self.avg_scores_by_round[round] = 0.0&lt;br /&gt;
        self.summary[round] = {}&lt;br /&gt;
        self.avg_scores_by_criterion[round] = {}&lt;br /&gt;
&lt;br /&gt;
        questions_used_in_round = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
        # get answers of each question in the rubric&lt;br /&gt;
        questions_used_in_round.each do |question|&lt;br /&gt;
          next if question.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
          answers_questions = Answer.answers_by_question(assignment.id, question.id)&lt;br /&gt;
&lt;br /&gt;
          max_score = get_max_score_for_question(question)&lt;br /&gt;
          # process each question in a seperate thread&lt;br /&gt;
          threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
            comments = break_up_comments_to_sentences(answers_questions)&lt;br /&gt;
            # store each avg in a hashmap and use the question as the key&lt;br /&gt;
            self.avg_scores_by_criterion[round][question.txt] = calculate_avg_score_by_criterion(answers_questions, max_score)&lt;br /&gt;
            self.summary[round][question.txt] = summarize_sentences(comments, summary_ws_url) unless comments.empty?&lt;br /&gt;
          end&lt;br /&gt;
          # Wait for all threads to end&lt;br /&gt;
          threads.each do |t|&lt;br /&gt;
            # Wait for the thread to finish if it isn't this thread (i.e. the main thread).&lt;br /&gt;
            t.join if t != Thread.current&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
        self.avg_scores_by_round[round] = calculate_avg_score_by_round(avg_scores_by_criterion[round], questions_used_in_round)&lt;br /&gt;
      end&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    # produce summaries for instructor. it merges all feedback given to all reviewees, and summarize them by criterion&lt;br /&gt;
    def summarize_reviews_by_criterion(assignment, summary_ws_url)&lt;br /&gt;
      self.summary = self.avg_scores_by_criterion = self.avg_scores_by_round = Array.new(assignment.rounds_of_reviews)&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get question in each round and summarize them all&lt;br /&gt;
      (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
        questions_used_in_round = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
        questions_used_in_round.each do |question|&lt;br /&gt;
          next if question.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
          summarize_reviews_by_criterion_question(assignment, summary_ws_url, round, question)&lt;br /&gt;
        end&lt;br /&gt;
        self.avg_scores_by_round[round] = calculate_avg_score_by_round(avg_scores_by_criterion[round], questions_used_in_round)&lt;br /&gt;
      end&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # get summary of answers of each question in the rubric&lt;br /&gt;
    def summarize_reviews_by_criterion_question(assignment, summary_ws_url, round, question)&lt;br /&gt;
      threads = []&lt;br /&gt;
      answers_questions = Answer.answers_by_question(assignment.id, question.id)&lt;br /&gt;
&lt;br /&gt;
      threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
        self.avg_scores_by_criterion[round][question.txt] = calculate_avg_score_by_criterion(answers_questions, get_max_score_for_question(question))&lt;br /&gt;
        self.summary[round][question.txt] = summarize_sentences(break_up_comments_to_sentences(answers_questions), summary_ws_url)&lt;br /&gt;
      end&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      end_threads(threads)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Wait for threads to end&lt;br /&gt;
    def end_threads(threads)&lt;br /&gt;
      threads.each do |t|&lt;br /&gt;
        # Wait for the thread to finish if it isn't this thread (i.e. the main thread).&lt;br /&gt;
        t.join if t != Thread.current&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_criterion is reduced from 42.34 to 17.2&lt;br /&gt;
:* Cognitive complexity is reduced from 16 to 7&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewees'''===&lt;br /&gt;
:This method is used to produce summaries for instructor and students. It sums up the feedback by criterion for each reviewer&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:*This method was refactored into 4 smaller methods namely ''summarize_reviews_by_reviewees'', ''summarize_reviews_by_teams'', ''summarize_by_reviewee_round'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:*The method ''summarize_reviews_by_reviewees'' calls ''summarize_reviews_by_teams''  which inturn calls ''summarize_by_reviewee_round'' to get answers of each reviewer by rubric.&lt;br /&gt;
&lt;br /&gt;
:*The method ''summarize_by_reviewee_round'' starts many threads to create requests to summarize the comments and closes the threads by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def summarize_reviews_by_reviewees(assignment, summary_ws_url)&lt;br /&gt;
      # @summary[reviewee][round][question]&lt;br /&gt;
      # @reviewers[team][reviewer]&lt;br /&gt;
      # @avg_scores_by_reviewee[team]&lt;br /&gt;
      # @avg_score_round[reviewee][round]&lt;br /&gt;
      # @avg_scores_by_criterion[reviewee][round][criterion]&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_reviewee = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.reviewers = ({})&lt;br /&gt;
      threads = []&lt;br /&gt;
&lt;br /&gt;
      # get all criteria used in each round&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get all teams in this assignment&lt;br /&gt;
      teams = Team.select(:id, :name).where(parent_id: assignment.id).order(:name)&lt;br /&gt;
&lt;br /&gt;
      teams.each do |reviewee|&lt;br /&gt;
        self.summary[reviewee.name] = []&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = 0.0&lt;br /&gt;
        self.avg_scores_by_round[reviewee.name] = []&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name] = []&lt;br /&gt;
&lt;br /&gt;
        # get the name of reviewers for display only&lt;br /&gt;
        self.reviewers[reviewee.name] = get_reviewers_by_reviewee_and_assignment(reviewee, assignment.id)&lt;br /&gt;
&lt;br /&gt;
        # get answers of each reviewer by rubric&lt;br /&gt;
        (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
          self.summary[reviewee.name][round] = {}&lt;br /&gt;
          self.avg_scores_by_round[reviewee.name][round] = 0.0&lt;br /&gt;
          self.avg_scores_by_criterion[reviewee.name][round] = {}&lt;br /&gt;
&lt;br /&gt;
          # iterate each round and get answers&lt;br /&gt;
          # if use the same rubric, only use rubric[0]&lt;br /&gt;
          rubric_questions_used = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
          rubric_questions_used.each do |q|&lt;br /&gt;
            next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
            summary[reviewee.name][round][q.txt] = &amp;quot;&amp;quot;&lt;br /&gt;
            self.avg_scores_by_criterion[reviewee.name][round][q.txt] = 0.0&lt;br /&gt;
&lt;br /&gt;
            # get all answers to this question&lt;br /&gt;
            question_answers = Answer.answers_by_question_for_reviewee_in_round(assignment.id, reviewee.id, q.id, round + 1)&lt;br /&gt;
            # get max score of this rubric&lt;br /&gt;
            q_max_score = get_max_score_for_question(q)&lt;br /&gt;
&lt;br /&gt;
            comments = break_up_comments_to_sentences(question_answers)&lt;br /&gt;
            # get score and summary of answers for each question&lt;br /&gt;
            self.avg_scores_by_criterion[reviewee.name][round][q.txt] = calculate_avg_score_by_criterion(question_answers, q_max_score)&lt;br /&gt;
&lt;br /&gt;
            # summarize the comments by calling the summarization Web Service&lt;br /&gt;
&lt;br /&gt;
            # since it'll do a lot of request, do this in seperate threads&lt;br /&gt;
            threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
              summary[reviewee.name][round][q.txt] = summarize_sentences(comments, summary_ws_url) unless comments.empty?&lt;br /&gt;
            end&lt;br /&gt;
          end&lt;br /&gt;
          self.avg_scores_by_round[reviewee.name][round] = calculate_avg_score_by_round(self.avg_scores_by_criterion[reviewee.name][round], rubric_questions_used)&lt;br /&gt;
        end&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = calculate_avg_score_by_reviewee(self.avg_scores_by_round[reviewee.name], assignment.rounds_of_reviews)&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      threads.each do |t|&lt;br /&gt;
        t.join if t != Thread.current&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    # produce summaries for instructor and students. It sum up the feedback by criterion for each reviewee&lt;br /&gt;
    def summarize_reviews_by_reviewees(assignment, summary_ws_url)&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_reviewee = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.reviewers = ({})&lt;br /&gt;
      self.summary_ws_url = summary_ws_url&lt;br /&gt;
&lt;br /&gt;
      # get all criteria used in each round&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get all teams in this assignment&lt;br /&gt;
      teams = Team.select(:id, :name).where(parent_id: assignment.id).order(:name)&lt;br /&gt;
&lt;br /&gt;
      teams.each do |reviewee|&lt;br /&gt;
        summarize_reviews_by_team_reviewee(assignment, reviewee, rubric)&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = calculate_avg_score_by_reviewee(self.avg_scores_by_round[reviewee.name], assignment.rounds_of_reviews)&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # get answers and average scores for each team&lt;br /&gt;
    def summarize_reviews_by_team_reviewee(assignment, reviewee, rubric)&lt;br /&gt;
      self.summary[reviewee.name] = []&lt;br /&gt;
      self.avg_scores_by_reviewee[reviewee.name] = 0.0&lt;br /&gt;
      self.avg_scores_by_round[reviewee.name] = self.avg_scores_by_criterion[reviewee.name] = []&lt;br /&gt;
&lt;br /&gt;
      # get the name of reviewers for display only&lt;br /&gt;
      self.reviewers[reviewee.name] = get_reviewers_by_reviewee_and_assignment(reviewee, assignment.id)&lt;br /&gt;
&lt;br /&gt;
      # get answers and average scores of each round by rubric&lt;br /&gt;
      (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
        self.summary[reviewee.name][round] = {}&lt;br /&gt;
        self.avg_scores_by_round[reviewee.name][round] = 0.0&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name][round] = {}&lt;br /&gt;
        summarize_by_reviewee_round(assignment, reviewee, round, rubric)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # get answers and averge score for each question in a round&lt;br /&gt;
    def summarize_by_reviewee_round(assignment, reviewee, round, rubric)&lt;br /&gt;
      threads = []&lt;br /&gt;
      # if use the same rubric, only use rubric[0]&lt;br /&gt;
      rubric_questions_used = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
      rubric_questions_used.each do |q|&lt;br /&gt;
        next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # get all answers to this question&lt;br /&gt;
        question_answers = Answer.answers_by_question_for_reviewee_in_round(assignment.id, reviewee.id, q.id, round + 1)&lt;br /&gt;
&lt;br /&gt;
        # get score and summary of answers for each question&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name][round][q.txt] = calculate_avg_score_by_criterion(question_answers, get_max_score_for_question(q))&lt;br /&gt;
&lt;br /&gt;
        threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
          self.summary[reviewee.name][round][q.txt] = summarize_sentences(break_up_comments_to_sentences(question_answers), self.summary_ws_url)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      avg_scores_by_round = calculate_avg_score_by_round(self.avg_scores_by_criterion[reviewee.name][round], rubric_questions_used)&lt;br /&gt;
      self.avg_scores_by_round[reviewee.name][round] = avg_scores_by_round&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      end_threads(threads)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewees is reduced from 89.93 to 16.64&lt;br /&gt;
:* Cognitive Complexity is reduced from 17 to 7&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_sentence'''===&lt;br /&gt;
:This method calls web service to store each summary in a hashmap and use the question as the key.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Removed variable ''summary''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_8.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - break_up_comments_to_sentences'''===&lt;br /&gt;
: This method adds the comment to an array to be converted as a json request.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:The method is broken down into 2 smaller methods namely ''break_up_comments_to_sentences'' and ''get_sentences'' where ''get_sentences'' is called by ''break_up_comments_to_sentences'' to  get sentences in desired format.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_9.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact''':&lt;br /&gt;
:*The Cognitive complexity of break_up_comments_to_sentences reduced from 6 to &amp;lt;5&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - get_questions_by_assignment'''===&lt;br /&gt;
:This method returns the rubric for given assignment&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
:*In IF CONDITION: Removed unnecessary use of variable which was being used only once (questionaire_id) and replaced the variable with its assignment (assignment.review_questionnaire_id(round + 1)&lt;br /&gt;
:*In ELSE CONDITION: Removed unnecessary ternary operation for variable ''questionaire_id'' and replaced the variable with its assignment (assignment.review_questionnaire_id) &lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_10.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - calculate_avg_score_by_round'''===&lt;br /&gt;
:This method is used to calculate average round score for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Refactored the method into 2 smaller methods namely ''calculate_avg_score_by_round'' and ''calculate_round_score'' where ''calculate_avg_score_by_round'' calls ''calculate_round_score'' to calculate average round score and ''calculate_avg_score_by_round'' rounds the round_score upto 2 decimal places.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = 0.0&lt;br /&gt;
      sum_weight = 0&lt;br /&gt;
&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = sum_weight = 0.0&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
      round_score&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:*Assignment Branch Condition size for calculate_avg_score_by_round is reduced from 18.57 to &amp;lt;15.&lt;br /&gt;
&lt;br /&gt;
==='''Coverage'''===&lt;br /&gt;
Coverage increased (+17.1%) to 41.407%&lt;br /&gt;
&lt;br /&gt;
==='''Pull request'''===&lt;br /&gt;
https://github.com/expertiza/expertiza/pull/1685&lt;br /&gt;
&lt;br /&gt;
=='''Test Plan'''==&lt;br /&gt;
==='''Manual Testing'''===&lt;br /&gt;
:'''Login Details:''' '''USERNAME:''' instructor6 '''PASSWORD:''' password&lt;br /&gt;
:Click '''Assignment''' &amp;gt;&amp;gt; Click the '''View Submissions''' of '''Madeup problem''' &amp;gt;&amp;gt; Click on any student &amp;gt;&amp;gt; Click on '''Madeup problem''' &amp;gt;&amp;gt; Click on '''Your Scores'''&lt;br /&gt;
:[[File:expertiza2008-1.png]]&lt;br /&gt;
:[[File:expertiza2008-2.png]]&lt;br /&gt;
:[[File:expertiza2008-3.png]]&lt;br /&gt;
:[[File:expertiza2008-4.png]]&lt;br /&gt;
:The 3 main functions of the Summary helper are summarize review by reviewees, summarize review by reviewee and summarize reviews by criterion.&lt;br /&gt;
:To check ''summarize reviews by reviewees'' is working we should get the output similar to the one shown below. This function summarizes all the reviews and displays average score.&lt;br /&gt;
:[[File:expertiza2008-5.png]]&lt;br /&gt;
&lt;br /&gt;
:To check ''summarize reviews by reviewee'' is working, click on any review.&lt;br /&gt;
:[[File:expertiza2008-6a.png]]&lt;br /&gt;
:A new webpage pops up with all the reviews and scores given by an individual.&lt;br /&gt;
:[[File:expertiza2008-6b.png]]&lt;br /&gt;
&lt;br /&gt;
: To check ''summarize reviews by criterion'' is working, click on any criterion. This should display summarized reviews and scores for a particular question in the questionnaire.&lt;br /&gt;
:[[File:expertiza2008-7.png]]&lt;br /&gt;
&lt;br /&gt;
=='''Future improvement'''==&lt;br /&gt;
* Modularize ''summarize_by_rounds'' to even smaller modules so that Assignment Branch Condition size is reduced from 36.73 to 15.00.&lt;br /&gt;
* Create more test cases for the new modularized methods.&lt;br /&gt;
&lt;br /&gt;
=='''Contributors'''==&lt;br /&gt;
* [mailto:jviswan@ncsu.edu Jayalakshmi Viswanathan]&lt;br /&gt;
* [mailto:skundal@ncsu.edu Sandeep Kundala]&lt;br /&gt;
* [mailto:spal3@ncsu.edu Sumitosh Pal]&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132626</id>
		<title>CSC/ECE 517 Spring 2020 - Project E2008. Refactor summary helper.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132626"/>
		<updated>2020-04-01T03:39:15Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* Refactor - summarize_reviews_by_reviewees */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''About Expertiza'''==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed using Ruby on Rails Framework whose creation and maintenance are taken care of by students as well as the faculty of NCSU. Its code is available on Github [https://github.com/expertiza/expertiza Expertiza on GitHub]. Expertiza allows the instructor to create and edit new as well as existing assignments. This also includes creating a wide range of topics under each assignment that students can sign up for. They can also publish surveys and reviews, view statistical results, set deadlines for assignments and make announcements. It provides a platform for students to signup for topics, form teams, view and submit assignments and give peer reviews and feedback.&lt;br /&gt;
&lt;br /&gt;
=='''Problem Statement'''==&lt;br /&gt;
'''Background:''' In Expertiza students can review each other’s projects and even each other as teammates. Students can view their project scores and instructors can view student's teammate review scores on the view scores page. This Summary helper aids in calculating these scores and rendering the results on the view scores section of an assignment. Summary helper is a helper module that consists of methods used to calculate scores for these reviews. This is for the use of instructors.&lt;br /&gt;
&lt;br /&gt;
'''Requirement:'''&lt;br /&gt;
E2008 is an Expertiza OSS project which deals basically with refactoring app/helpers/summary_helper.rb to reduce the code climate issues such as&lt;br /&gt;
&lt;br /&gt;
* [http://wiki.c2.com/?AbcMetric Assignment Branch Condition]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Cognitive_complexity Cognitive Complexity]&lt;br /&gt;
* Method/line too long&lt;br /&gt;
* Unused variables / access modifiers&lt;br /&gt;
&lt;br /&gt;
'''A good method should have:'''&lt;br /&gt;
* Assignment Branch Condition size &amp;lt;= 15&lt;br /&gt;
* Cognitive Complexity &amp;lt;= 6&lt;br /&gt;
* No. of lines in a method &amp;lt;= 25&lt;br /&gt;
&lt;br /&gt;
=='''Issues found'''==&lt;br /&gt;
The following are issues which were found in the code:&lt;br /&gt;
&lt;br /&gt;
==='''Assignment Branch Condition'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! ABC Size&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewee&lt;br /&gt;
| 44.61&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 42.34&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 89.93&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 16.43&lt;br /&gt;
|-&lt;br /&gt;
| calculate_avg_score_by_round&lt;br /&gt;
| 18.57&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
==='''Cognitive Complexity'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! Cognitive Complexity&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 16&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 17&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 11&lt;br /&gt;
|-&lt;br /&gt;
| break_up_comments_to_sentences&lt;br /&gt;
| 6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Method/line too long'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method/Line too long&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewees&lt;br /&gt;
|'''Lines of Code:'''39&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_criterion  &lt;br /&gt;
|'''Lines of Code:'''27&lt;br /&gt;
|-&lt;br /&gt;
|'''Line:''' 145&lt;br /&gt;
|self.avg_scores_by_round[reviewee.name][round] too long (162/160)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==='''Unused variables / access modifiers'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Vaiable/Access Modifier&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' summary  &lt;br /&gt;
|'''Method:''' summarize_sentences&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' included_question_counter  &lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewee&lt;br /&gt;
|-&lt;br /&gt;
|'''Access Modifier:''' module_function  &lt;br /&gt;
|'''Class:''' Summary&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=='''Solution Implemented'''==&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewee'''===&lt;br /&gt;
:This method is used to summarize reviews by a reviewer for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:''' &lt;br /&gt;
:This method could be refactored into smaller methods namely ''summarize_reviews_by_reviewee'' and ''summarize_reviews_by_reviewee_assign'' where ''summarize_reviews_by_reviewee'' calls ''summarize_reviews_by_reviewee_assign'' to get average scores and summary for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def summarize_reviews_by_reviewee(questions, assignment, r_id, summary_ws_url)&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
&lt;br /&gt;
      # get all answers for each question and send them to summarization WS&lt;br /&gt;
      questions.keys.each do |round|&lt;br /&gt;
        self.summary[round.to_s] = {}&lt;br /&gt;
        self.avg_scores_by_criterion[round.to_s] = {}&lt;br /&gt;
        self.avg_scores_by_round[round.to_s] = 0.0&lt;br /&gt;
        included_question_counter = 0&lt;br /&gt;
&lt;br /&gt;
        questions[round].each do |q|&lt;br /&gt;
          next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
          self.summary[round.to_s][q.txt] = &amp;quot;&amp;quot;&lt;br /&gt;
          self.avg_scores_by_criterion[round.to_s][q.txt] = 0.0&lt;br /&gt;
&lt;br /&gt;
          question_answers = Answer.answers_by_question_for_reviewee(assignment.id, r_id, q.id)&lt;br /&gt;
&lt;br /&gt;
          max_score = get_max_score_for_question(q)&lt;br /&gt;
&lt;br /&gt;
          comments = break_up_comments_to_sentences(question_answers)&lt;br /&gt;
&lt;br /&gt;
          # get the avg scores for this question&lt;br /&gt;
          self.avg_scores_by_criterion[round.to_s][q.txt] = calculate_avg_score_by_criterion(question_answers, max_score)&lt;br /&gt;
          # get the summary of answers to this question&lt;br /&gt;
          self.summary[round.to_s][q.txt] = summarize_sentences(comments, summary_ws_url)&lt;br /&gt;
        end&lt;br /&gt;
        self.avg_scores_by_round[round.to_s] = calculate_avg_score_by_round(self.avg_scores_by_criterion[round.to_s], questions[round])&lt;br /&gt;
      end&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    # produce average score and summary of comments for reviews by a reviewer for each question&lt;br /&gt;
    def summarize_reviews_by_reviewee(questions, assignment, reviewee_id, summary_ws_url)&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.summary_ws_url = summary_ws_url&lt;br /&gt;
&lt;br /&gt;
      # get all answers for each question and send them to summarization WS&lt;br /&gt;
      questions.each_key do |round|&lt;br /&gt;
        self.summary[round.to_s] = {}&lt;br /&gt;
        self.avg_scores_by_criterion[round.to_s] = {}&lt;br /&gt;
        self.avg_scores_by_round[round.to_s] = 0.0&lt;br /&gt;
        questions[round].each do |question|&lt;br /&gt;
          next if question.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
          summarize_reviews_by_reviewee_question(assignment, reviewee_id, question, round)&lt;br /&gt;
        end&lt;br /&gt;
        self.avg_scores_by_round[round.to_s] = calculate_avg_score_by_round(self.avg_scores_by_criterion[round.to_s], questions[round])&lt;br /&gt;
      end&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # get average scores and summary for each question in a review by a reviewer&lt;br /&gt;
    def summarize_reviews_by_reviewee_question(assignment, reviewee_id, question, round)&lt;br /&gt;
      question_answers = Answer.answers_by_question_for_reviewee(assignment.id, reviewee_id, question.id)&lt;br /&gt;
&lt;br /&gt;
      self.avg_scores_by_criterion[round.to_s][question.txt] = calculate_avg_score_by_criterion(question_answers, get_max_score_for_question(question))&lt;br /&gt;
&lt;br /&gt;
      self.summary[round.to_s][question.txt] = summarize_sentences(break_up_comments_to_sentences(question_answers), self.summary_ws_url)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewee is reduced from 44.61 to 20.64.&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_criterion'''===&lt;br /&gt;
:This method is used to summarize the review for each questions&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 3 smaller methods namely ''summarize_reviews_by_criterion'', ''summarize_reviews_by_criterion_questions'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion'' calls ''summarize_reviews_by_criterion_questions'' to get answers of each question in the rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion_questions'' starts many threads to process each question and closes it by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    # produce summaries for instructor. it merges all feedback given to all reviewees, and summarize them by criterion&lt;br /&gt;
    def summarize_reviews_by_criterion(assignment, summary_ws_url)&lt;br /&gt;
      # @summary[reviewee][round][question]&lt;br /&gt;
      # @avg_score_round[reviewee][round]&lt;br /&gt;
      # @avg_scores_by_criterion[reviewee][round][criterion]&lt;br /&gt;
      nround = assignment.rounds_of_reviews&lt;br /&gt;
      self.summary = Array.new(nround)&lt;br /&gt;
      self.avg_scores_by_criterion = Array.new(nround)&lt;br /&gt;
      self.avg_scores_by_round = Array.new(nround)&lt;br /&gt;
      threads = []&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      (0..nround - 1).each do |round|&lt;br /&gt;
        self.avg_scores_by_round[round] = 0.0&lt;br /&gt;
        self.summary[round] = {}&lt;br /&gt;
        self.avg_scores_by_criterion[round] = {}&lt;br /&gt;
&lt;br /&gt;
        questions_used_in_round = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
        # get answers of each question in the rubric&lt;br /&gt;
        questions_used_in_round.each do |question|&lt;br /&gt;
          next if question.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
          answers_questions = Answer.answers_by_question(assignment.id, question.id)&lt;br /&gt;
&lt;br /&gt;
          max_score = get_max_score_for_question(question)&lt;br /&gt;
          # process each question in a seperate thread&lt;br /&gt;
          threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
            comments = break_up_comments_to_sentences(answers_questions)&lt;br /&gt;
            # store each avg in a hashmap and use the question as the key&lt;br /&gt;
            self.avg_scores_by_criterion[round][question.txt] = calculate_avg_score_by_criterion(answers_questions, max_score)&lt;br /&gt;
            self.summary[round][question.txt] = summarize_sentences(comments, summary_ws_url) unless comments.empty?&lt;br /&gt;
          end&lt;br /&gt;
          # Wait for all threads to end&lt;br /&gt;
          threads.each do |t|&lt;br /&gt;
            # Wait for the thread to finish if it isn't this thread (i.e. the main thread).&lt;br /&gt;
            t.join if t != Thread.current&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
        self.avg_scores_by_round[round] = calculate_avg_score_by_round(avg_scores_by_criterion[round], questions_used_in_round)&lt;br /&gt;
      end&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    # produce summaries for instructor. it merges all feedback given to all reviewees, and summarize them by criterion&lt;br /&gt;
    def summarize_reviews_by_criterion(assignment, summary_ws_url)&lt;br /&gt;
      self.summary = self.avg_scores_by_criterion = self.avg_scores_by_round = Array.new(assignment.rounds_of_reviews)&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get question in each round and summarize them all&lt;br /&gt;
      (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
        questions_used_in_round = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
        questions_used_in_round.each do |question|&lt;br /&gt;
          next if question.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
          summarize_reviews_by_criterion_question(assignment, summary_ws_url, round, question)&lt;br /&gt;
        end&lt;br /&gt;
        self.avg_scores_by_round[round] = calculate_avg_score_by_round(avg_scores_by_criterion[round], questions_used_in_round)&lt;br /&gt;
      end&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # get summary of answers of each question in the rubric&lt;br /&gt;
    def summarize_reviews_by_criterion_question(assignment, summary_ws_url, round, question)&lt;br /&gt;
      threads = []&lt;br /&gt;
      answers_questions = Answer.answers_by_question(assignment.id, question.id)&lt;br /&gt;
&lt;br /&gt;
      threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
        self.avg_scores_by_criterion[round][question.txt] = calculate_avg_score_by_criterion(answers_questions, get_max_score_for_question(question))&lt;br /&gt;
        self.summary[round][question.txt] = summarize_sentences(break_up_comments_to_sentences(answers_questions), summary_ws_url)&lt;br /&gt;
      end&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      end_threads(threads)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Wait for threads to end&lt;br /&gt;
    def end_threads(threads)&lt;br /&gt;
      threads.each do |t|&lt;br /&gt;
        # Wait for the thread to finish if it isn't this thread (i.e. the main thread).&lt;br /&gt;
        t.join if t != Thread.current&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_criterion is reduced from 42.34 to 17.2&lt;br /&gt;
:* Cognitive complexity is reduced from 16 to 7&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewees'''===&lt;br /&gt;
:This method is used to produce summaries for instructor and students. It sums up the feedback by criterion for each reviewer&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 4 smaller methods namely ''summarize_reviews_by_reviewees'', ''summarize_reviews_by_teams'', ''summarize_by_reviewee_round'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_reviewees'' calls ''summarize_reviews_by_teams''  which inturn calls ''summarize_by_reviewee_round'' to get answers of each reviewer by rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_by_reviewee_round'' starts many threads to create requests to summarize the comments and closes the threads by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def summarize_reviews_by_reviewees(assignment, summary_ws_url)&lt;br /&gt;
      # @summary[reviewee][round][question]&lt;br /&gt;
      # @reviewers[team][reviewer]&lt;br /&gt;
      # @avg_scores_by_reviewee[team]&lt;br /&gt;
      # @avg_score_round[reviewee][round]&lt;br /&gt;
      # @avg_scores_by_criterion[reviewee][round][criterion]&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_reviewee = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.reviewers = ({})&lt;br /&gt;
      threads = []&lt;br /&gt;
&lt;br /&gt;
      # get all criteria used in each round&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get all teams in this assignment&lt;br /&gt;
      teams = Team.select(:id, :name).where(parent_id: assignment.id).order(:name)&lt;br /&gt;
&lt;br /&gt;
      teams.each do |reviewee|&lt;br /&gt;
        self.summary[reviewee.name] = []&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = 0.0&lt;br /&gt;
        self.avg_scores_by_round[reviewee.name] = []&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name] = []&lt;br /&gt;
&lt;br /&gt;
        # get the name of reviewers for display only&lt;br /&gt;
        self.reviewers[reviewee.name] = get_reviewers_by_reviewee_and_assignment(reviewee, assignment.id)&lt;br /&gt;
&lt;br /&gt;
        # get answers of each reviewer by rubric&lt;br /&gt;
        (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
          self.summary[reviewee.name][round] = {}&lt;br /&gt;
          self.avg_scores_by_round[reviewee.name][round] = 0.0&lt;br /&gt;
          self.avg_scores_by_criterion[reviewee.name][round] = {}&lt;br /&gt;
&lt;br /&gt;
          # iterate each round and get answers&lt;br /&gt;
          # if use the same rubric, only use rubric[0]&lt;br /&gt;
          rubric_questions_used = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
          rubric_questions_used.each do |q|&lt;br /&gt;
            next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
            summary[reviewee.name][round][q.txt] = &amp;quot;&amp;quot;&lt;br /&gt;
            self.avg_scores_by_criterion[reviewee.name][round][q.txt] = 0.0&lt;br /&gt;
&lt;br /&gt;
            # get all answers to this question&lt;br /&gt;
            question_answers = Answer.answers_by_question_for_reviewee_in_round(assignment.id, reviewee.id, q.id, round + 1)&lt;br /&gt;
            # get max score of this rubric&lt;br /&gt;
            q_max_score = get_max_score_for_question(q)&lt;br /&gt;
&lt;br /&gt;
            comments = break_up_comments_to_sentences(question_answers)&lt;br /&gt;
            # get score and summary of answers for each question&lt;br /&gt;
            self.avg_scores_by_criterion[reviewee.name][round][q.txt] = calculate_avg_score_by_criterion(question_answers, q_max_score)&lt;br /&gt;
&lt;br /&gt;
            # summarize the comments by calling the summarization Web Service&lt;br /&gt;
&lt;br /&gt;
            # since it'll do a lot of request, do this in seperate threads&lt;br /&gt;
            threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
              summary[reviewee.name][round][q.txt] = summarize_sentences(comments, summary_ws_url) unless comments.empty?&lt;br /&gt;
            end&lt;br /&gt;
          end&lt;br /&gt;
          self.avg_scores_by_round[reviewee.name][round] = calculate_avg_score_by_round(self.avg_scores_by_criterion[reviewee.name][round], rubric_questions_used)&lt;br /&gt;
        end&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = calculate_avg_score_by_reviewee(self.avg_scores_by_round[reviewee.name], assignment.rounds_of_reviews)&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      threads.each do |t|&lt;br /&gt;
        t.join if t != Thread.current&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    # produce summaries for instructor and students. It sum up the feedback by criterion for each reviewee&lt;br /&gt;
    def summarize_reviews_by_reviewees(assignment, summary_ws_url)&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_reviewee = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.reviewers = ({})&lt;br /&gt;
      self.summary_ws_url = summary_ws_url&lt;br /&gt;
&lt;br /&gt;
      # get all criteria used in each round&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get all teams in this assignment&lt;br /&gt;
      teams = Team.select(:id, :name).where(parent_id: assignment.id).order(:name)&lt;br /&gt;
&lt;br /&gt;
      teams.each do |reviewee|&lt;br /&gt;
        summarize_reviews_by_team_reviewee(assignment, reviewee, rubric)&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = calculate_avg_score_by_reviewee(self.avg_scores_by_round[reviewee.name], assignment.rounds_of_reviews)&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # get answers and average scores for each team&lt;br /&gt;
    def summarize_reviews_by_team_reviewee(assignment, reviewee, rubric)&lt;br /&gt;
      self.summary[reviewee.name] = []&lt;br /&gt;
      self.avg_scores_by_reviewee[reviewee.name] = 0.0&lt;br /&gt;
      self.avg_scores_by_round[reviewee.name] = self.avg_scores_by_criterion[reviewee.name] = []&lt;br /&gt;
&lt;br /&gt;
      # get the name of reviewers for display only&lt;br /&gt;
      self.reviewers[reviewee.name] = get_reviewers_by_reviewee_and_assignment(reviewee, assignment.id)&lt;br /&gt;
&lt;br /&gt;
      # get answers and average scores of each round by rubric&lt;br /&gt;
      (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
        self.summary[reviewee.name][round] = {}&lt;br /&gt;
        self.avg_scores_by_round[reviewee.name][round] = 0.0&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name][round] = {}&lt;br /&gt;
        summarize_by_reviewee_round(assignment, reviewee, round, rubric)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # get answers and averge score for each question in a round&lt;br /&gt;
    def summarize_by_reviewee_round(assignment, reviewee, round, rubric)&lt;br /&gt;
      threads = []&lt;br /&gt;
      # if use the same rubric, only use rubric[0]&lt;br /&gt;
      rubric_questions_used = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
      rubric_questions_used.each do |q|&lt;br /&gt;
        next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # get all answers to this question&lt;br /&gt;
        question_answers = Answer.answers_by_question_for_reviewee_in_round(assignment.id, reviewee.id, q.id, round + 1)&lt;br /&gt;
&lt;br /&gt;
        # get score and summary of answers for each question&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name][round][q.txt] = calculate_avg_score_by_criterion(question_answers, get_max_score_for_question(q))&lt;br /&gt;
&lt;br /&gt;
        threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
          self.summary[reviewee.name][round][q.txt] = summarize_sentences(break_up_comments_to_sentences(question_answers), self.summary_ws_url)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      avg_scores_by_round = calculate_avg_score_by_round(self.avg_scores_by_criterion[reviewee.name][round], rubric_questions_used)&lt;br /&gt;
      self.avg_scores_by_round[reviewee.name][round] = avg_scores_by_round&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      end_threads(threads)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewees is reduced from 89.93 to 16.64&lt;br /&gt;
:* Cognitive Complexity is reduced from 17 to 7&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_sentence'''===&lt;br /&gt;
:This method calls web service to store each summary in a hashmap and use the question as the key.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Removed variable ''summary''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_8.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - break_up_comments_to_sentences'''===&lt;br /&gt;
: This method adds the comment to an array to be converted as a json request.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:The method is broken down into 2 smaller methods namely ''break_up_comments_to_sentences'' and ''get_sentences'' where ''get_sentences'' is called by ''break_up_comments_to_sentences'' to  get sentences in desired format.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_9.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact''':&lt;br /&gt;
:*The Cognitive complexity of break_up_comments_to_sentences reduced from 6 to &amp;lt;5&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - get_questions_by_assignment'''===&lt;br /&gt;
:This method returns the rubric for given assignment&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
:*In IF CONDITION: Removed unnecessary use of variable which was being used only once (questionaire_id) and replaced the variable with its assignment (assignment.review_questionnaire_id(round + 1)&lt;br /&gt;
:*In ELSE CONDITION: Removed unnecessary ternary operation for variable ''questionaire_id'' and replaced the variable with its assignment (assignment.review_questionnaire_id) &lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_10.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - calculate_avg_score_by_round'''===&lt;br /&gt;
:This method is used to calculate average round score for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Refactored the method into 2 smaller methods namely ''calculate_avg_score_by_round'' and ''calculate_round_score'' where ''calculate_avg_score_by_round'' calls ''calculate_round_score'' to calculate average round score and ''calculate_avg_score_by_round'' rounds the round_score upto 2 decimal places.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = 0.0&lt;br /&gt;
      sum_weight = 0&lt;br /&gt;
&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = sum_weight = 0.0&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
      round_score&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:*Assignment Branch Condition size for calculate_avg_score_by_round is reduced from 18.57 to &amp;lt;15.&lt;br /&gt;
&lt;br /&gt;
==='''Coverage'''===&lt;br /&gt;
Coverage increased (+17.1%) to 41.407%&lt;br /&gt;
&lt;br /&gt;
==='''Pull request'''===&lt;br /&gt;
https://github.com/expertiza/expertiza/pull/1685&lt;br /&gt;
&lt;br /&gt;
=='''Test Plan'''==&lt;br /&gt;
==='''Manual Testing'''===&lt;br /&gt;
:'''Login Details:''' '''USERNAME:''' instructor6 '''PASSWORD:''' password&lt;br /&gt;
:Click '''Assignment''' &amp;gt;&amp;gt; Click the '''View Submissions''' of '''Madeup problem''' &amp;gt;&amp;gt; Click on any student &amp;gt;&amp;gt; Click on '''Madeup problem''' &amp;gt;&amp;gt; Click on '''Your Scores'''&lt;br /&gt;
:[[File:expertiza2008-1.png]]&lt;br /&gt;
:[[File:expertiza2008-2.png]]&lt;br /&gt;
:[[File:expertiza2008-3.png]]&lt;br /&gt;
:[[File:expertiza2008-4.png]]&lt;br /&gt;
:The 3 main functions of the Summary helper are summarize review by reviewees, summarize review by reviewee and summarize reviews by criterion.&lt;br /&gt;
:To check ''summarize reviews by reviewees'' is working we should get the output similar to the one shown below. This function summarizes all the reviews and displays average score.&lt;br /&gt;
:[[File:expertiza2008-5.png]]&lt;br /&gt;
&lt;br /&gt;
:To check ''summarize reviews by reviewee'' is working, click on any review.&lt;br /&gt;
:[[File:expertiza2008-6a.png]]&lt;br /&gt;
:A new webpage pops up with all the reviews and scores given by an individual.&lt;br /&gt;
:[[File:expertiza2008-6b.png]]&lt;br /&gt;
&lt;br /&gt;
: To check ''summarize reviews by criterion'' is working, click on any criterion. This should display summarized reviews and scores for a particular question in the questionnaire.&lt;br /&gt;
:[[File:expertiza2008-7.png]]&lt;br /&gt;
&lt;br /&gt;
=='''Future improvement'''==&lt;br /&gt;
* Modularize ''summarize_by_rounds'' to even smaller modules so that Assignment Branch Condition size is reduced from 36.73 to 15.00.&lt;br /&gt;
* Create more test cases for the new modularized methods.&lt;br /&gt;
&lt;br /&gt;
=='''Contributors'''==&lt;br /&gt;
* [mailto:jviswan@ncsu.edu Jayalakshmi Viswanathan]&lt;br /&gt;
* [mailto:skundal@ncsu.edu Sandeep Kundala]&lt;br /&gt;
* [mailto:spal3@ncsu.edu Sumitosh Pal]&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132228</id>
		<title>CSC/ECE 517 Spring 2020 - Project E2008. Refactor summary helper.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132228"/>
		<updated>2020-03-30T17:24:15Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* Problem Statement */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''About Expertiza'''==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed using Ruby on Rails Framework whose creation and maintenance are taken care of by students as well as the faculty of NCSU. Its code is available on Github [https://github.com/expertiza/expertiza Expertiza on GitHub]. Expertiza allows the instructor to create and edit new as well as existing assignments. This also includes creating a wide range of topics under each assignment that students can sign up for. They can also publish surveys and reviews, view statistical results, set deadlines for assignments and make announcements. It provides a platform for students to signup for topics, form teams, view and submit assignments and give peer reviews and feedback.&lt;br /&gt;
&lt;br /&gt;
=='''Problem Statement'''==&lt;br /&gt;
'''Background:''' In Expertiza students can review each other’s projects and even each other as teammates. Students can view their project scores and instructors can view student's teammate review scores on the view scores page. This Summary helper aids in calculating these scores and rendering the results on the view scores section of an assignment. Summary helper is a helper module that consists of methods used to calculate scores for these reviews. This is for the use of instructors.&lt;br /&gt;
&lt;br /&gt;
'''Requirement:'''&lt;br /&gt;
E2008 is an Expertiza OSS project which deals basically with refactoring app/helpers/summary_helper.rb to reduce the code climate issues such as&lt;br /&gt;
&lt;br /&gt;
* [http://wiki.c2.com/?AbcMetric Assignment Branch Condition]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Cognitive_complexity Cognitive Complexity]&lt;br /&gt;
* Method/line too long&lt;br /&gt;
* Unused variables / access modifiers&lt;br /&gt;
&lt;br /&gt;
'''A good method should have:'''&lt;br /&gt;
* Assignment Branch Condition size &amp;lt;= 15&lt;br /&gt;
* Cognitive Complexity &amp;lt;= 6&lt;br /&gt;
* No. of lines in a method &amp;lt;= 25&lt;br /&gt;
&lt;br /&gt;
=='''Issues found'''==&lt;br /&gt;
The following are issues which were found in the code:&lt;br /&gt;
&lt;br /&gt;
==='''Assignment Branch Condition'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! ABC Size&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewee&lt;br /&gt;
| 44.61&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 42.34&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 89.93&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 16.43&lt;br /&gt;
|-&lt;br /&gt;
| calculate_avg_score_by_round&lt;br /&gt;
| 18.57&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
==='''Cognitive Complexity'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! Cognitive Complexity&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 16&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 17&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 11&lt;br /&gt;
|-&lt;br /&gt;
| break_up_comments_to_sentences&lt;br /&gt;
| 6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Method/line too long'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method/Line too long&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewees&lt;br /&gt;
|'''Lines of Code:'''39&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_criterion  &lt;br /&gt;
|'''Lines of Code:'''27&lt;br /&gt;
|-&lt;br /&gt;
|'''Line:''' 145&lt;br /&gt;
|self.avg_scores_by_round[reviewee.name][round] too long (162/160)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==='''Unused variables / access modifiers'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Vaiable/Access Modifier&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' summary  &lt;br /&gt;
|'''Method:''' summarize_sentences&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' included_question_counter  &lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewee&lt;br /&gt;
|-&lt;br /&gt;
|'''Access Modifier:''' module_function  &lt;br /&gt;
|'''Class:''' Summary&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=='''Solution Implemented'''==&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewee'''===&lt;br /&gt;
:This method is used to summarize reviews by a reviewer for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:''' &lt;br /&gt;
:This method could be refactored into smaller methods namely ''summarize_reviews_by_reviewee'' and ''summarize_reviews_by_reviewee_assign'' where ''summarize_reviews_by_reviewee'' calls ''summarize_reviews_by_reviewee_assign'' to get average scores and summary for each question.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewee is reduced from 44.61 to 20.64.&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_criterion'''===&lt;br /&gt;
:This method is used to summarize the review for each questions&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 3 smaller methods namely ''summarize_reviews_by_criterion'', ''summarize_reviews_by_criterion_questions'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion'' calls ''summarize_reviews_by_criterion_questions'' to get answers of each question in the rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion_questions'' starts many threads to process each question and closes it by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_3.jpg]]&lt;br /&gt;
:[[File:e2008_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_criterion is reduced from 42.34 to 17.2&lt;br /&gt;
:* Cognitive complexity is reduced from 16 to 7&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewees'''===&lt;br /&gt;
:This method is used to produce summaries for instructor and students. It sums up the feedback by criterion for each reviewer&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 4 smaller methods namely ''summarize_reviews_by_reviewees'', ''summarize_reviews_by_teams'', ''summarize_by_rounds'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_reviewees'' calls ''summarize_reviews_by_teams''  which inturn calls ''summarize_by_rounds'' to get answers of each reviewer by rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_by_rounds'' starts many threads to create requests to summarize the comments and closes the threads by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def summarize_reviews_by_reviewees(assignment, summary_ws_url)&lt;br /&gt;
      # @summary[reviewee][round][question]&lt;br /&gt;
      # @reviewers[team][reviewer]&lt;br /&gt;
      # @avg_scores_by_reviewee[team]&lt;br /&gt;
      # @avg_score_round[reviewee][round]&lt;br /&gt;
      # @avg_scores_by_criterion[reviewee][round][criterion]&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_reviewee = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.reviewers = ({})&lt;br /&gt;
      threads = []&lt;br /&gt;
&lt;br /&gt;
      # get all criteria used in each round&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get all teams in this assignment&lt;br /&gt;
      teams = Team.select(:id, :name).where(parent_id: assignment.id).order(:name)&lt;br /&gt;
&lt;br /&gt;
      teams.each do |reviewee|&lt;br /&gt;
        self.summary[reviewee.name] = []&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = 0.0&lt;br /&gt;
        self.avg_scores_by_round[reviewee.name] = []&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name] = []&lt;br /&gt;
&lt;br /&gt;
        # get the name of reviewers for display only&lt;br /&gt;
        self.reviewers[reviewee.name] = get_reviewers_by_reviewee_and_assignment(reviewee, assignment.id)&lt;br /&gt;
&lt;br /&gt;
        # get answers of each reviewer by rubric&lt;br /&gt;
        (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
          self.summary[reviewee.name][round] = {}&lt;br /&gt;
          self.avg_scores_by_round[reviewee.name][round] = 0.0&lt;br /&gt;
          self.avg_scores_by_criterion[reviewee.name][round] = {}&lt;br /&gt;
&lt;br /&gt;
          # iterate each round and get answers&lt;br /&gt;
          # if use the same rubric, only use rubric[0]&lt;br /&gt;
          rubric_questions_used = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
          rubric_questions_used.each do |q|&lt;br /&gt;
            next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
            summary[reviewee.name][round][q.txt] = &amp;quot;&amp;quot;&lt;br /&gt;
            self.avg_scores_by_criterion[reviewee.name][round][q.txt] = 0.0&lt;br /&gt;
&lt;br /&gt;
            # get all answers to this question&lt;br /&gt;
            question_answers = Answer.answers_by_question_for_reviewee_in_round(assignment.id, reviewee.id, q.id, round + 1)&lt;br /&gt;
            # get max score of this rubric&lt;br /&gt;
            q_max_score = get_max_score_for_question(q)&lt;br /&gt;
&lt;br /&gt;
            comments = break_up_comments_to_sentences(question_answers)&lt;br /&gt;
            # get score and summary of answers for each question&lt;br /&gt;
            self.avg_scores_by_criterion[reviewee.name][round][q.txt] = calculate_avg_score_by_criterion(question_answers, q_max_score)&lt;br /&gt;
&lt;br /&gt;
            # summarize the comments by calling the summarization Web Service&lt;br /&gt;
&lt;br /&gt;
            # since it'll do a lot of request, do this in seperate threads&lt;br /&gt;
            threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
              summary[reviewee.name][round][q.txt] = summarize_sentences(comments, summary_ws_url) unless comments.empty?&lt;br /&gt;
            end&lt;br /&gt;
          end&lt;br /&gt;
          self.avg_scores_by_round[reviewee.name][round] = calculate_avg_score_by_round(self.avg_scores_by_criterion[reviewee.name][round], rubric_questions_used)&lt;br /&gt;
        end&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = calculate_avg_score_by_reviewee(self.avg_scores_by_round[reviewee.name], assignment.rounds_of_reviews)&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      threads.each do |t|&lt;br /&gt;
        t.join if t != Thread.current&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def summarize_reviews_by_reviewees(assignment, summary_ws_url)&lt;br /&gt;
      # @summary[reviewee][round][question]&lt;br /&gt;
      # @reviewers[team][reviewer]&lt;br /&gt;
      # @avg_scores_by_reviewee[team]&lt;br /&gt;
      # @avg_score_round[reviewee][round]&lt;br /&gt;
      # @avg_scores_by_criterion[reviewee][round][criterion]&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_reviewee = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.reviewers = ({})&lt;br /&gt;
      self.summary_ws_url = summary_ws_url&lt;br /&gt;
&lt;br /&gt;
      # get all criteria used in each round&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get all teams in this assignment&lt;br /&gt;
      teams = Team.select(:id, :name).where(parent_id: assignment.id).order(:name)&lt;br /&gt;
&lt;br /&gt;
      teams.each do |reviewee|&lt;br /&gt;
        summarize_reviews_by_team_reviewee(assignment, reviewee, rubric)&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = calculate_avg_score_by_reviewee(self.avg_scores_by_round[reviewee.name], assignment.rounds_of_reviews)&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def summarize_reviews_by_team_reviewee(assignment, reviewee, rubric)&lt;br /&gt;
      self.summary[reviewee.name] = []&lt;br /&gt;
      self.avg_scores_by_reviewee[reviewee.name] = 0.0&lt;br /&gt;
      self.avg_scores_by_round[reviewee.name] = self.avg_scores_by_criterion[reviewee.name] = []&lt;br /&gt;
&lt;br /&gt;
      # get the name of reviewers for display only&lt;br /&gt;
      self.reviewers[reviewee.name] = get_reviewers_by_reviewee_and_assignment(reviewee, assignment.id)&lt;br /&gt;
&lt;br /&gt;
      # get answers of each reviewer by rubric&lt;br /&gt;
      (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
        self.summary[reviewee.name][round] = {}&lt;br /&gt;
        self.avg_scores_by_round[reviewee.name][round] = 0.0&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name][round] = {}&lt;br /&gt;
        summarize_by_reviewee_round(assignment, reviewee, round, rubric)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def summarize_by_reviewee_round(assignment, reviewee, round, rubric)&lt;br /&gt;
      threads = []&lt;br /&gt;
      # iterate each round and get answers&lt;br /&gt;
      # if use the same rubric, only use rubric[0]&lt;br /&gt;
      rubric_questions_used = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
      rubric_questions_used.each do |q|&lt;br /&gt;
        next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # get all answers to this question&lt;br /&gt;
        question_answers = Answer.answers_by_question_for_reviewee_in_round(assignment.id, reviewee.id, q.id, round + 1)&lt;br /&gt;
&lt;br /&gt;
        # get score and summary of answers for each question&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name][round][q.txt] = calculate_avg_score_by_criterion(question_answers, get_max_score_for_question(q))&lt;br /&gt;
&lt;br /&gt;
        # summarize the comments by calling the summarization Web Service&lt;br /&gt;
        # since it'll do a lot of request, do this in seperate threads&lt;br /&gt;
        threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
          self.summary[reviewee.name][round][q.txt] = summarize_sentences(break_up_comments_to_sentences(question_answers), self.summary_ws_url)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      avg_scores_by_round = calculate_avg_score_by_round(self.avg_scores_by_criterion[reviewee.name][round], rubric_questions_used)&lt;br /&gt;
      self.avg_scores_by_round[reviewee.name][round] = avg_scores_by_round&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      end_threads(threads)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    def end_threads(threads)&lt;br /&gt;
      threads.each do |t|&lt;br /&gt;
        # Wait for the thread to finish if it isn't this thread (i.e. the main thread).&lt;br /&gt;
        t.join if t != Thread.current&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewees is reduced from 89.93 to 16.64&lt;br /&gt;
:* Cognitive Complexity is reduced from 17 to 7&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_sentence'''===&lt;br /&gt;
:This method calls web service to store each summary in a hashmap and use the question as the key.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Removed variable ''summary''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_8.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - break_up_comments_to_sentences'''===&lt;br /&gt;
: This method adds the comment to an array to be converted as a json request.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:The method is broken down into 2 smaller methods namely ''break_up_comments_to_sentences'' and ''get_sentences'' where ''get_sentences'' is called by ''break_up_comments_to_sentences'' to  get sentences in desired format.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_9.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact''':&lt;br /&gt;
:*The Cognitive complexity of break_up_comments_to_sentences reduced from 6 to &amp;lt;5&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - get_questions_by_assignment'''===&lt;br /&gt;
:This method returns the rubric for given assignment&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
:*In IF CONDITION: Removed unnecessary use of variable which was being used only once (questionaire_id) and replaced the variable with its assignment (assignment.review_questionnaire_id(round + 1)&lt;br /&gt;
:*In ELSE CONDITION: Removed unnecessary ternary operation for variable ''questionaire_id'' and replaced the variable with its assignment (assignment.review_questionnaire_id) &lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_10.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - calculate_avg_score_by_round'''===&lt;br /&gt;
:This method is used to calculate average round score for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Refactored the method into 2 smaller methods namely ''calculate_avg_score_by_round'' and ''calculate_round_score'' where ''calculate_avg_score_by_round'' calls ''calculate_round_score'' to calculate average round score and ''calculate_avg_score_by_round'' rounds the round_score upto 2 decimal places.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = 0.0&lt;br /&gt;
      sum_weight = 0&lt;br /&gt;
&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = sum_weight = 0.0&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
      round_score&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:*Assignment Branch Condition size for calculate_avg_score_by_round is reduced from 18.57 to &amp;lt;15.&lt;br /&gt;
&lt;br /&gt;
==='''Coverage'''===&lt;br /&gt;
Coverage increased (+17.1%) to 41.407%&lt;br /&gt;
&lt;br /&gt;
==='''Pull request'''===&lt;br /&gt;
https://github.com/expertiza/expertiza/pull/1685&lt;br /&gt;
&lt;br /&gt;
=='''Test Plan'''==&lt;br /&gt;
==='''Manual Testing'''===&lt;br /&gt;
:'''Login Details:''' '''USERNAME:''' instructor6 '''PASSWORD:''' password&lt;br /&gt;
:Click '''Assignment''' &amp;gt;&amp;gt; Click the '''View Submissions''' of '''Madeup problem''' &amp;gt;&amp;gt; Click on any student &amp;gt;&amp;gt; Click on '''Madeup problem''' &amp;gt;&amp;gt; Click on '''Your Scores'''&lt;br /&gt;
:[[File:expertiza2008-1.png]]&lt;br /&gt;
:[[File:expertiza2008-2.png]]&lt;br /&gt;
:[[File:expertiza2008-3.png]]&lt;br /&gt;
:[[File:expertiza2008-4.png]]&lt;br /&gt;
:The 3 main functions of the Summary helper are summarize review by reviewees, summarize review by reviewee and summarize reviews by criterion.&lt;br /&gt;
:To check ''summarize reviews by reviewees'' is working we should get the output similar to the one shown below. This function summarizes all the reviews and displays average score.&lt;br /&gt;
:[[File:expertiza2008-5.png]]&lt;br /&gt;
&lt;br /&gt;
:To check ''summarize reviews by reviewee'' is working, click on any review.&lt;br /&gt;
:[[File:expertiza2008-6a.png]]&lt;br /&gt;
:A new webpage pops up with all the reviews and scores given by an individual.&lt;br /&gt;
:[[File:expertiza2008-6b.png]]&lt;br /&gt;
&lt;br /&gt;
: To check ''summarize reviews by criterion'' is working, click on any criterion. This should display summarized reviews and scores for a particular question in the questionnaire.&lt;br /&gt;
:[[File:expertiza2008-7.png]]&lt;br /&gt;
&lt;br /&gt;
=='''Future improvement'''==&lt;br /&gt;
* Modularize ''summarize_by_rounds'' to even smaller modules so that Assignment Branch Condition size is reduced from 36.73 to 15.00.&lt;br /&gt;
* Create more test cases for the new modularized methods.&lt;br /&gt;
&lt;br /&gt;
=='''Contributors'''==&lt;br /&gt;
* [mailto:jviswan@ncsu.edu Jayalakshmi Viswanathan]&lt;br /&gt;
* [mailto:skundal@ncsu.edu Sandeep Kundala]&lt;br /&gt;
* [mailto:spal3@ncsu.edu Sumitosh Pal]&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132227</id>
		<title>CSC/ECE 517 Spring 2020 - Project E2008. Refactor summary helper.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132227"/>
		<updated>2020-03-30T17:23:44Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* Pull request: */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''About Expertiza'''==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed using Ruby on Rails Framework whose creation and maintenance are taken care of by students as well as the faculty of NCSU. Its code is available on Github [https://github.com/expertiza/expertiza Expertiza on GitHub]. Expertiza allows the instructor to create and edit new as well as existing assignments. This also includes creating a wide range of topics under each assignment that students can sign up for. They can also publish surveys and reviews, view statistical results, set deadlines for assignments and make announcements. It provides a platform for students to signup for topics, form teams, view and submit assignments and give peer reviews and feedback.&lt;br /&gt;
&lt;br /&gt;
=='''Problem Statement'''==&lt;br /&gt;
'''Background:''' In Expertiza students can review each other’s projects and even each other as teammates. Students can view their project scores and instructors can view student's teammate review scores on the view scores page. This Summary helper aids in calculating these scores and rendering the results on the view scores section of an assignment. Summary helper is a helper module that consists of methods used to calculate scores for these reviews. This is for the use of instructors.&lt;br /&gt;
&lt;br /&gt;
'''Requirement:'''&lt;br /&gt;
E2008 is an Expertiza OSS project which deals basically with refactoring app/helpers/summary_helper.rb to reduce the code climate issues such as&lt;br /&gt;
&lt;br /&gt;
* [http://wiki.c2.com/?AbcMetric Assignment Branch Condition]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Cognitive_complexity Cognitive Complexity]&lt;br /&gt;
* Method/line too long&lt;br /&gt;
* Unused variables / access modifiers&lt;br /&gt;
&lt;br /&gt;
'''A good method should have:'''&lt;br /&gt;
* Assignment Branch Condition size &amp;lt; 15&lt;br /&gt;
* Cognitive Complexity &amp;lt; 6&lt;br /&gt;
* No. of lines in a method &amp;lt; 25&lt;br /&gt;
&lt;br /&gt;
=='''Issues found'''==&lt;br /&gt;
The following are issues which were found in the code:&lt;br /&gt;
&lt;br /&gt;
==='''Assignment Branch Condition'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! ABC Size&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewee&lt;br /&gt;
| 44.61&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 42.34&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 89.93&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 16.43&lt;br /&gt;
|-&lt;br /&gt;
| calculate_avg_score_by_round&lt;br /&gt;
| 18.57&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
==='''Cognitive Complexity'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! Cognitive Complexity&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 16&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 17&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 11&lt;br /&gt;
|-&lt;br /&gt;
| break_up_comments_to_sentences&lt;br /&gt;
| 6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Method/line too long'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method/Line too long&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewees&lt;br /&gt;
|'''Lines of Code:'''39&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_criterion  &lt;br /&gt;
|'''Lines of Code:'''27&lt;br /&gt;
|-&lt;br /&gt;
|'''Line:''' 145&lt;br /&gt;
|self.avg_scores_by_round[reviewee.name][round] too long (162/160)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==='''Unused variables / access modifiers'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Vaiable/Access Modifier&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' summary  &lt;br /&gt;
|'''Method:''' summarize_sentences&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' included_question_counter  &lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewee&lt;br /&gt;
|-&lt;br /&gt;
|'''Access Modifier:''' module_function  &lt;br /&gt;
|'''Class:''' Summary&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=='''Solution Implemented'''==&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewee'''===&lt;br /&gt;
:This method is used to summarize reviews by a reviewer for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:''' &lt;br /&gt;
:This method could be refactored into smaller methods namely ''summarize_reviews_by_reviewee'' and ''summarize_reviews_by_reviewee_assign'' where ''summarize_reviews_by_reviewee'' calls ''summarize_reviews_by_reviewee_assign'' to get average scores and summary for each question.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewee is reduced from 44.61 to 20.64.&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_criterion'''===&lt;br /&gt;
:This method is used to summarize the review for each questions&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 3 smaller methods namely ''summarize_reviews_by_criterion'', ''summarize_reviews_by_criterion_questions'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion'' calls ''summarize_reviews_by_criterion_questions'' to get answers of each question in the rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion_questions'' starts many threads to process each question and closes it by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_3.jpg]]&lt;br /&gt;
:[[File:e2008_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_criterion is reduced from 42.34 to 17.2&lt;br /&gt;
:* Cognitive complexity is reduced from 16 to 7&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewees'''===&lt;br /&gt;
:This method is used to produce summaries for instructor and students. It sums up the feedback by criterion for each reviewer&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 4 smaller methods namely ''summarize_reviews_by_reviewees'', ''summarize_reviews_by_teams'', ''summarize_by_rounds'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_reviewees'' calls ''summarize_reviews_by_teams''  which inturn calls ''summarize_by_rounds'' to get answers of each reviewer by rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_by_rounds'' starts many threads to create requests to summarize the comments and closes the threads by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def summarize_reviews_by_reviewees(assignment, summary_ws_url)&lt;br /&gt;
      # @summary[reviewee][round][question]&lt;br /&gt;
      # @reviewers[team][reviewer]&lt;br /&gt;
      # @avg_scores_by_reviewee[team]&lt;br /&gt;
      # @avg_score_round[reviewee][round]&lt;br /&gt;
      # @avg_scores_by_criterion[reviewee][round][criterion]&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_reviewee = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.reviewers = ({})&lt;br /&gt;
      threads = []&lt;br /&gt;
&lt;br /&gt;
      # get all criteria used in each round&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get all teams in this assignment&lt;br /&gt;
      teams = Team.select(:id, :name).where(parent_id: assignment.id).order(:name)&lt;br /&gt;
&lt;br /&gt;
      teams.each do |reviewee|&lt;br /&gt;
        self.summary[reviewee.name] = []&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = 0.0&lt;br /&gt;
        self.avg_scores_by_round[reviewee.name] = []&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name] = []&lt;br /&gt;
&lt;br /&gt;
        # get the name of reviewers for display only&lt;br /&gt;
        self.reviewers[reviewee.name] = get_reviewers_by_reviewee_and_assignment(reviewee, assignment.id)&lt;br /&gt;
&lt;br /&gt;
        # get answers of each reviewer by rubric&lt;br /&gt;
        (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
          self.summary[reviewee.name][round] = {}&lt;br /&gt;
          self.avg_scores_by_round[reviewee.name][round] = 0.0&lt;br /&gt;
          self.avg_scores_by_criterion[reviewee.name][round] = {}&lt;br /&gt;
&lt;br /&gt;
          # iterate each round and get answers&lt;br /&gt;
          # if use the same rubric, only use rubric[0]&lt;br /&gt;
          rubric_questions_used = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
          rubric_questions_used.each do |q|&lt;br /&gt;
            next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
            summary[reviewee.name][round][q.txt] = &amp;quot;&amp;quot;&lt;br /&gt;
            self.avg_scores_by_criterion[reviewee.name][round][q.txt] = 0.0&lt;br /&gt;
&lt;br /&gt;
            # get all answers to this question&lt;br /&gt;
            question_answers = Answer.answers_by_question_for_reviewee_in_round(assignment.id, reviewee.id, q.id, round + 1)&lt;br /&gt;
            # get max score of this rubric&lt;br /&gt;
            q_max_score = get_max_score_for_question(q)&lt;br /&gt;
&lt;br /&gt;
            comments = break_up_comments_to_sentences(question_answers)&lt;br /&gt;
            # get score and summary of answers for each question&lt;br /&gt;
            self.avg_scores_by_criterion[reviewee.name][round][q.txt] = calculate_avg_score_by_criterion(question_answers, q_max_score)&lt;br /&gt;
&lt;br /&gt;
            # summarize the comments by calling the summarization Web Service&lt;br /&gt;
&lt;br /&gt;
            # since it'll do a lot of request, do this in seperate threads&lt;br /&gt;
            threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
              summary[reviewee.name][round][q.txt] = summarize_sentences(comments, summary_ws_url) unless comments.empty?&lt;br /&gt;
            end&lt;br /&gt;
          end&lt;br /&gt;
          self.avg_scores_by_round[reviewee.name][round] = calculate_avg_score_by_round(self.avg_scores_by_criterion[reviewee.name][round], rubric_questions_used)&lt;br /&gt;
        end&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = calculate_avg_score_by_reviewee(self.avg_scores_by_round[reviewee.name], assignment.rounds_of_reviews)&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      threads.each do |t|&lt;br /&gt;
        t.join if t != Thread.current&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def summarize_reviews_by_reviewees(assignment, summary_ws_url)&lt;br /&gt;
      # @summary[reviewee][round][question]&lt;br /&gt;
      # @reviewers[team][reviewer]&lt;br /&gt;
      # @avg_scores_by_reviewee[team]&lt;br /&gt;
      # @avg_score_round[reviewee][round]&lt;br /&gt;
      # @avg_scores_by_criterion[reviewee][round][criterion]&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_reviewee = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.reviewers = ({})&lt;br /&gt;
      self.summary_ws_url = summary_ws_url&lt;br /&gt;
&lt;br /&gt;
      # get all criteria used in each round&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get all teams in this assignment&lt;br /&gt;
      teams = Team.select(:id, :name).where(parent_id: assignment.id).order(:name)&lt;br /&gt;
&lt;br /&gt;
      teams.each do |reviewee|&lt;br /&gt;
        summarize_reviews_by_team_reviewee(assignment, reviewee, rubric)&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = calculate_avg_score_by_reviewee(self.avg_scores_by_round[reviewee.name], assignment.rounds_of_reviews)&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def summarize_reviews_by_team_reviewee(assignment, reviewee, rubric)&lt;br /&gt;
      self.summary[reviewee.name] = []&lt;br /&gt;
      self.avg_scores_by_reviewee[reviewee.name] = 0.0&lt;br /&gt;
      self.avg_scores_by_round[reviewee.name] = self.avg_scores_by_criterion[reviewee.name] = []&lt;br /&gt;
&lt;br /&gt;
      # get the name of reviewers for display only&lt;br /&gt;
      self.reviewers[reviewee.name] = get_reviewers_by_reviewee_and_assignment(reviewee, assignment.id)&lt;br /&gt;
&lt;br /&gt;
      # get answers of each reviewer by rubric&lt;br /&gt;
      (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
        self.summary[reviewee.name][round] = {}&lt;br /&gt;
        self.avg_scores_by_round[reviewee.name][round] = 0.0&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name][round] = {}&lt;br /&gt;
        summarize_by_reviewee_round(assignment, reviewee, round, rubric)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def summarize_by_reviewee_round(assignment, reviewee, round, rubric)&lt;br /&gt;
      threads = []&lt;br /&gt;
      # iterate each round and get answers&lt;br /&gt;
      # if use the same rubric, only use rubric[0]&lt;br /&gt;
      rubric_questions_used = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
      rubric_questions_used.each do |q|&lt;br /&gt;
        next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # get all answers to this question&lt;br /&gt;
        question_answers = Answer.answers_by_question_for_reviewee_in_round(assignment.id, reviewee.id, q.id, round + 1)&lt;br /&gt;
&lt;br /&gt;
        # get score and summary of answers for each question&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name][round][q.txt] = calculate_avg_score_by_criterion(question_answers, get_max_score_for_question(q))&lt;br /&gt;
&lt;br /&gt;
        # summarize the comments by calling the summarization Web Service&lt;br /&gt;
        # since it'll do a lot of request, do this in seperate threads&lt;br /&gt;
        threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
          self.summary[reviewee.name][round][q.txt] = summarize_sentences(break_up_comments_to_sentences(question_answers), self.summary_ws_url)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      avg_scores_by_round = calculate_avg_score_by_round(self.avg_scores_by_criterion[reviewee.name][round], rubric_questions_used)&lt;br /&gt;
      self.avg_scores_by_round[reviewee.name][round] = avg_scores_by_round&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      end_threads(threads)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    def end_threads(threads)&lt;br /&gt;
      threads.each do |t|&lt;br /&gt;
        # Wait for the thread to finish if it isn't this thread (i.e. the main thread).&lt;br /&gt;
        t.join if t != Thread.current&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewees is reduced from 89.93 to 16.64&lt;br /&gt;
:* Cognitive Complexity is reduced from 17 to 7&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_sentence'''===&lt;br /&gt;
:This method calls web service to store each summary in a hashmap and use the question as the key.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Removed variable ''summary''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_8.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - break_up_comments_to_sentences'''===&lt;br /&gt;
: This method adds the comment to an array to be converted as a json request.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:The method is broken down into 2 smaller methods namely ''break_up_comments_to_sentences'' and ''get_sentences'' where ''get_sentences'' is called by ''break_up_comments_to_sentences'' to  get sentences in desired format.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_9.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact''':&lt;br /&gt;
:*The Cognitive complexity of break_up_comments_to_sentences reduced from 6 to &amp;lt;5&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - get_questions_by_assignment'''===&lt;br /&gt;
:This method returns the rubric for given assignment&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
:*In IF CONDITION: Removed unnecessary use of variable which was being used only once (questionaire_id) and replaced the variable with its assignment (assignment.review_questionnaire_id(round + 1)&lt;br /&gt;
:*In ELSE CONDITION: Removed unnecessary ternary operation for variable ''questionaire_id'' and replaced the variable with its assignment (assignment.review_questionnaire_id) &lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_10.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - calculate_avg_score_by_round'''===&lt;br /&gt;
:This method is used to calculate average round score for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Refactored the method into 2 smaller methods namely ''calculate_avg_score_by_round'' and ''calculate_round_score'' where ''calculate_avg_score_by_round'' calls ''calculate_round_score'' to calculate average round score and ''calculate_avg_score_by_round'' rounds the round_score upto 2 decimal places.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = 0.0&lt;br /&gt;
      sum_weight = 0&lt;br /&gt;
&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = sum_weight = 0.0&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
      round_score&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:*Assignment Branch Condition size for calculate_avg_score_by_round is reduced from 18.57 to &amp;lt;15.&lt;br /&gt;
&lt;br /&gt;
==='''Coverage'''===&lt;br /&gt;
Coverage increased (+17.1%) to 41.407%&lt;br /&gt;
&lt;br /&gt;
==='''Pull request'''===&lt;br /&gt;
https://github.com/expertiza/expertiza/pull/1685&lt;br /&gt;
&lt;br /&gt;
=='''Test Plan'''==&lt;br /&gt;
==='''Manual Testing'''===&lt;br /&gt;
:'''Login Details:''' '''USERNAME:''' instructor6 '''PASSWORD:''' password&lt;br /&gt;
:Click '''Assignment''' &amp;gt;&amp;gt; Click the '''View Submissions''' of '''Madeup problem''' &amp;gt;&amp;gt; Click on any student &amp;gt;&amp;gt; Click on '''Madeup problem''' &amp;gt;&amp;gt; Click on '''Your Scores'''&lt;br /&gt;
:[[File:expertiza2008-1.png]]&lt;br /&gt;
:[[File:expertiza2008-2.png]]&lt;br /&gt;
:[[File:expertiza2008-3.png]]&lt;br /&gt;
:[[File:expertiza2008-4.png]]&lt;br /&gt;
:The 3 main functions of the Summary helper are summarize review by reviewees, summarize review by reviewee and summarize reviews by criterion.&lt;br /&gt;
:To check ''summarize reviews by reviewees'' is working we should get the output similar to the one shown below. This function summarizes all the reviews and displays average score.&lt;br /&gt;
:[[File:expertiza2008-5.png]]&lt;br /&gt;
&lt;br /&gt;
:To check ''summarize reviews by reviewee'' is working, click on any review.&lt;br /&gt;
:[[File:expertiza2008-6a.png]]&lt;br /&gt;
:A new webpage pops up with all the reviews and scores given by an individual.&lt;br /&gt;
:[[File:expertiza2008-6b.png]]&lt;br /&gt;
&lt;br /&gt;
: To check ''summarize reviews by criterion'' is working, click on any criterion. This should display summarized reviews and scores for a particular question in the questionnaire.&lt;br /&gt;
:[[File:expertiza2008-7.png]]&lt;br /&gt;
&lt;br /&gt;
=='''Future improvement'''==&lt;br /&gt;
* Modularize ''summarize_by_rounds'' to even smaller modules so that Assignment Branch Condition size is reduced from 36.73 to 15.00.&lt;br /&gt;
* Create more test cases for the new modularized methods.&lt;br /&gt;
&lt;br /&gt;
=='''Contributors'''==&lt;br /&gt;
* [mailto:jviswan@ncsu.edu Jayalakshmi Viswanathan]&lt;br /&gt;
* [mailto:skundal@ncsu.edu Sandeep Kundala]&lt;br /&gt;
* [mailto:spal3@ncsu.edu Sumitosh Pal]&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132226</id>
		<title>CSC/ECE 517 Spring 2020 - Project E2008. Refactor summary helper.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132226"/>
		<updated>2020-03-30T17:23:22Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* Coverage: */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''About Expertiza'''==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed using Ruby on Rails Framework whose creation and maintenance are taken care of by students as well as the faculty of NCSU. Its code is available on Github [https://github.com/expertiza/expertiza Expertiza on GitHub]. Expertiza allows the instructor to create and edit new as well as existing assignments. This also includes creating a wide range of topics under each assignment that students can sign up for. They can also publish surveys and reviews, view statistical results, set deadlines for assignments and make announcements. It provides a platform for students to signup for topics, form teams, view and submit assignments and give peer reviews and feedback.&lt;br /&gt;
&lt;br /&gt;
=='''Problem Statement'''==&lt;br /&gt;
'''Background:''' In Expertiza students can review each other’s projects and even each other as teammates. Students can view their project scores and instructors can view student's teammate review scores on the view scores page. This Summary helper aids in calculating these scores and rendering the results on the view scores section of an assignment. Summary helper is a helper module that consists of methods used to calculate scores for these reviews. This is for the use of instructors.&lt;br /&gt;
&lt;br /&gt;
'''Requirement:'''&lt;br /&gt;
E2008 is an Expertiza OSS project which deals basically with refactoring app/helpers/summary_helper.rb to reduce the code climate issues such as&lt;br /&gt;
&lt;br /&gt;
* [http://wiki.c2.com/?AbcMetric Assignment Branch Condition]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Cognitive_complexity Cognitive Complexity]&lt;br /&gt;
* Method/line too long&lt;br /&gt;
* Unused variables / access modifiers&lt;br /&gt;
&lt;br /&gt;
'''A good method should have:'''&lt;br /&gt;
* Assignment Branch Condition size &amp;lt; 15&lt;br /&gt;
* Cognitive Complexity &amp;lt; 6&lt;br /&gt;
* No. of lines in a method &amp;lt; 25&lt;br /&gt;
&lt;br /&gt;
=='''Issues found'''==&lt;br /&gt;
The following are issues which were found in the code:&lt;br /&gt;
&lt;br /&gt;
==='''Assignment Branch Condition'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! ABC Size&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewee&lt;br /&gt;
| 44.61&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 42.34&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 89.93&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 16.43&lt;br /&gt;
|-&lt;br /&gt;
| calculate_avg_score_by_round&lt;br /&gt;
| 18.57&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
==='''Cognitive Complexity'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! Cognitive Complexity&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 16&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 17&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 11&lt;br /&gt;
|-&lt;br /&gt;
| break_up_comments_to_sentences&lt;br /&gt;
| 6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Method/line too long'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method/Line too long&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewees&lt;br /&gt;
|'''Lines of Code:'''39&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_criterion  &lt;br /&gt;
|'''Lines of Code:'''27&lt;br /&gt;
|-&lt;br /&gt;
|'''Line:''' 145&lt;br /&gt;
|self.avg_scores_by_round[reviewee.name][round] too long (162/160)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==='''Unused variables / access modifiers'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Vaiable/Access Modifier&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' summary  &lt;br /&gt;
|'''Method:''' summarize_sentences&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' included_question_counter  &lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewee&lt;br /&gt;
|-&lt;br /&gt;
|'''Access Modifier:''' module_function  &lt;br /&gt;
|'''Class:''' Summary&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=='''Solution Implemented'''==&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewee'''===&lt;br /&gt;
:This method is used to summarize reviews by a reviewer for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:''' &lt;br /&gt;
:This method could be refactored into smaller methods namely ''summarize_reviews_by_reviewee'' and ''summarize_reviews_by_reviewee_assign'' where ''summarize_reviews_by_reviewee'' calls ''summarize_reviews_by_reviewee_assign'' to get average scores and summary for each question.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewee is reduced from 44.61 to 20.64.&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_criterion'''===&lt;br /&gt;
:This method is used to summarize the review for each questions&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 3 smaller methods namely ''summarize_reviews_by_criterion'', ''summarize_reviews_by_criterion_questions'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion'' calls ''summarize_reviews_by_criterion_questions'' to get answers of each question in the rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion_questions'' starts many threads to process each question and closes it by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_3.jpg]]&lt;br /&gt;
:[[File:e2008_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_criterion is reduced from 42.34 to 17.2&lt;br /&gt;
:* Cognitive complexity is reduced from 16 to 7&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewees'''===&lt;br /&gt;
:This method is used to produce summaries for instructor and students. It sums up the feedback by criterion for each reviewer&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 4 smaller methods namely ''summarize_reviews_by_reviewees'', ''summarize_reviews_by_teams'', ''summarize_by_rounds'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_reviewees'' calls ''summarize_reviews_by_teams''  which inturn calls ''summarize_by_rounds'' to get answers of each reviewer by rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_by_rounds'' starts many threads to create requests to summarize the comments and closes the threads by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def summarize_reviews_by_reviewees(assignment, summary_ws_url)&lt;br /&gt;
      # @summary[reviewee][round][question]&lt;br /&gt;
      # @reviewers[team][reviewer]&lt;br /&gt;
      # @avg_scores_by_reviewee[team]&lt;br /&gt;
      # @avg_score_round[reviewee][round]&lt;br /&gt;
      # @avg_scores_by_criterion[reviewee][round][criterion]&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_reviewee = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.reviewers = ({})&lt;br /&gt;
      threads = []&lt;br /&gt;
&lt;br /&gt;
      # get all criteria used in each round&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get all teams in this assignment&lt;br /&gt;
      teams = Team.select(:id, :name).where(parent_id: assignment.id).order(:name)&lt;br /&gt;
&lt;br /&gt;
      teams.each do |reviewee|&lt;br /&gt;
        self.summary[reviewee.name] = []&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = 0.0&lt;br /&gt;
        self.avg_scores_by_round[reviewee.name] = []&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name] = []&lt;br /&gt;
&lt;br /&gt;
        # get the name of reviewers for display only&lt;br /&gt;
        self.reviewers[reviewee.name] = get_reviewers_by_reviewee_and_assignment(reviewee, assignment.id)&lt;br /&gt;
&lt;br /&gt;
        # get answers of each reviewer by rubric&lt;br /&gt;
        (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
          self.summary[reviewee.name][round] = {}&lt;br /&gt;
          self.avg_scores_by_round[reviewee.name][round] = 0.0&lt;br /&gt;
          self.avg_scores_by_criterion[reviewee.name][round] = {}&lt;br /&gt;
&lt;br /&gt;
          # iterate each round and get answers&lt;br /&gt;
          # if use the same rubric, only use rubric[0]&lt;br /&gt;
          rubric_questions_used = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
          rubric_questions_used.each do |q|&lt;br /&gt;
            next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
            summary[reviewee.name][round][q.txt] = &amp;quot;&amp;quot;&lt;br /&gt;
            self.avg_scores_by_criterion[reviewee.name][round][q.txt] = 0.0&lt;br /&gt;
&lt;br /&gt;
            # get all answers to this question&lt;br /&gt;
            question_answers = Answer.answers_by_question_for_reviewee_in_round(assignment.id, reviewee.id, q.id, round + 1)&lt;br /&gt;
            # get max score of this rubric&lt;br /&gt;
            q_max_score = get_max_score_for_question(q)&lt;br /&gt;
&lt;br /&gt;
            comments = break_up_comments_to_sentences(question_answers)&lt;br /&gt;
            # get score and summary of answers for each question&lt;br /&gt;
            self.avg_scores_by_criterion[reviewee.name][round][q.txt] = calculate_avg_score_by_criterion(question_answers, q_max_score)&lt;br /&gt;
&lt;br /&gt;
            # summarize the comments by calling the summarization Web Service&lt;br /&gt;
&lt;br /&gt;
            # since it'll do a lot of request, do this in seperate threads&lt;br /&gt;
            threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
              summary[reviewee.name][round][q.txt] = summarize_sentences(comments, summary_ws_url) unless comments.empty?&lt;br /&gt;
            end&lt;br /&gt;
          end&lt;br /&gt;
          self.avg_scores_by_round[reviewee.name][round] = calculate_avg_score_by_round(self.avg_scores_by_criterion[reviewee.name][round], rubric_questions_used)&lt;br /&gt;
        end&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = calculate_avg_score_by_reviewee(self.avg_scores_by_round[reviewee.name], assignment.rounds_of_reviews)&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      threads.each do |t|&lt;br /&gt;
        t.join if t != Thread.current&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def summarize_reviews_by_reviewees(assignment, summary_ws_url)&lt;br /&gt;
      # @summary[reviewee][round][question]&lt;br /&gt;
      # @reviewers[team][reviewer]&lt;br /&gt;
      # @avg_scores_by_reviewee[team]&lt;br /&gt;
      # @avg_score_round[reviewee][round]&lt;br /&gt;
      # @avg_scores_by_criterion[reviewee][round][criterion]&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_reviewee = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.reviewers = ({})&lt;br /&gt;
      self.summary_ws_url = summary_ws_url&lt;br /&gt;
&lt;br /&gt;
      # get all criteria used in each round&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get all teams in this assignment&lt;br /&gt;
      teams = Team.select(:id, :name).where(parent_id: assignment.id).order(:name)&lt;br /&gt;
&lt;br /&gt;
      teams.each do |reviewee|&lt;br /&gt;
        summarize_reviews_by_team_reviewee(assignment, reviewee, rubric)&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = calculate_avg_score_by_reviewee(self.avg_scores_by_round[reviewee.name], assignment.rounds_of_reviews)&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def summarize_reviews_by_team_reviewee(assignment, reviewee, rubric)&lt;br /&gt;
      self.summary[reviewee.name] = []&lt;br /&gt;
      self.avg_scores_by_reviewee[reviewee.name] = 0.0&lt;br /&gt;
      self.avg_scores_by_round[reviewee.name] = self.avg_scores_by_criterion[reviewee.name] = []&lt;br /&gt;
&lt;br /&gt;
      # get the name of reviewers for display only&lt;br /&gt;
      self.reviewers[reviewee.name] = get_reviewers_by_reviewee_and_assignment(reviewee, assignment.id)&lt;br /&gt;
&lt;br /&gt;
      # get answers of each reviewer by rubric&lt;br /&gt;
      (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
        self.summary[reviewee.name][round] = {}&lt;br /&gt;
        self.avg_scores_by_round[reviewee.name][round] = 0.0&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name][round] = {}&lt;br /&gt;
        summarize_by_reviewee_round(assignment, reviewee, round, rubric)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def summarize_by_reviewee_round(assignment, reviewee, round, rubric)&lt;br /&gt;
      threads = []&lt;br /&gt;
      # iterate each round and get answers&lt;br /&gt;
      # if use the same rubric, only use rubric[0]&lt;br /&gt;
      rubric_questions_used = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
      rubric_questions_used.each do |q|&lt;br /&gt;
        next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # get all answers to this question&lt;br /&gt;
        question_answers = Answer.answers_by_question_for_reviewee_in_round(assignment.id, reviewee.id, q.id, round + 1)&lt;br /&gt;
&lt;br /&gt;
        # get score and summary of answers for each question&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name][round][q.txt] = calculate_avg_score_by_criterion(question_answers, get_max_score_for_question(q))&lt;br /&gt;
&lt;br /&gt;
        # summarize the comments by calling the summarization Web Service&lt;br /&gt;
        # since it'll do a lot of request, do this in seperate threads&lt;br /&gt;
        threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
          self.summary[reviewee.name][round][q.txt] = summarize_sentences(break_up_comments_to_sentences(question_answers), self.summary_ws_url)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      avg_scores_by_round = calculate_avg_score_by_round(self.avg_scores_by_criterion[reviewee.name][round], rubric_questions_used)&lt;br /&gt;
      self.avg_scores_by_round[reviewee.name][round] = avg_scores_by_round&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      end_threads(threads)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    def end_threads(threads)&lt;br /&gt;
      threads.each do |t|&lt;br /&gt;
        # Wait for the thread to finish if it isn't this thread (i.e. the main thread).&lt;br /&gt;
        t.join if t != Thread.current&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewees is reduced from 89.93 to 16.64&lt;br /&gt;
:* Cognitive Complexity is reduced from 17 to 7&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_sentence'''===&lt;br /&gt;
:This method calls web service to store each summary in a hashmap and use the question as the key.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Removed variable ''summary''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_8.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - break_up_comments_to_sentences'''===&lt;br /&gt;
: This method adds the comment to an array to be converted as a json request.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:The method is broken down into 2 smaller methods namely ''break_up_comments_to_sentences'' and ''get_sentences'' where ''get_sentences'' is called by ''break_up_comments_to_sentences'' to  get sentences in desired format.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_9.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact''':&lt;br /&gt;
:*The Cognitive complexity of break_up_comments_to_sentences reduced from 6 to &amp;lt;5&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - get_questions_by_assignment'''===&lt;br /&gt;
:This method returns the rubric for given assignment&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
:*In IF CONDITION: Removed unnecessary use of variable which was being used only once (questionaire_id) and replaced the variable with its assignment (assignment.review_questionnaire_id(round + 1)&lt;br /&gt;
:*In ELSE CONDITION: Removed unnecessary ternary operation for variable ''questionaire_id'' and replaced the variable with its assignment (assignment.review_questionnaire_id) &lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_10.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - calculate_avg_score_by_round'''===&lt;br /&gt;
:This method is used to calculate average round score for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Refactored the method into 2 smaller methods namely ''calculate_avg_score_by_round'' and ''calculate_round_score'' where ''calculate_avg_score_by_round'' calls ''calculate_round_score'' to calculate average round score and ''calculate_avg_score_by_round'' rounds the round_score upto 2 decimal places.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = 0.0&lt;br /&gt;
      sum_weight = 0&lt;br /&gt;
&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = sum_weight = 0.0&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
      round_score&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:*Assignment Branch Condition size for calculate_avg_score_by_round is reduced from 18.57 to &amp;lt;15.&lt;br /&gt;
&lt;br /&gt;
==='''Coverage'''===&lt;br /&gt;
Coverage increased (+17.1%) to 41.407%&lt;br /&gt;
&lt;br /&gt;
==='''Pull request:'''===&lt;br /&gt;
https://github.com/expertiza/expertiza/pull/1685&lt;br /&gt;
&lt;br /&gt;
=='''Test Plan'''==&lt;br /&gt;
==='''Manual Testing'''===&lt;br /&gt;
:'''Login Details:''' '''USERNAME:''' instructor6 '''PASSWORD:''' password&lt;br /&gt;
:Click '''Assignment''' &amp;gt;&amp;gt; Click the '''View Submissions''' of '''Madeup problem''' &amp;gt;&amp;gt; Click on any student &amp;gt;&amp;gt; Click on '''Madeup problem''' &amp;gt;&amp;gt; Click on '''Your Scores'''&lt;br /&gt;
:[[File:expertiza2008-1.png]]&lt;br /&gt;
:[[File:expertiza2008-2.png]]&lt;br /&gt;
:[[File:expertiza2008-3.png]]&lt;br /&gt;
:[[File:expertiza2008-4.png]]&lt;br /&gt;
:The 3 main functions of the Summary helper are summarize review by reviewees, summarize review by reviewee and summarize reviews by criterion.&lt;br /&gt;
:To check ''summarize reviews by reviewees'' is working we should get the output similar to the one shown below. This function summarizes all the reviews and displays average score.&lt;br /&gt;
:[[File:expertiza2008-5.png]]&lt;br /&gt;
&lt;br /&gt;
:To check ''summarize reviews by reviewee'' is working, click on any review.&lt;br /&gt;
:[[File:expertiza2008-6a.png]]&lt;br /&gt;
:A new webpage pops up with all the reviews and scores given by an individual.&lt;br /&gt;
:[[File:expertiza2008-6b.png]]&lt;br /&gt;
&lt;br /&gt;
: To check ''summarize reviews by criterion'' is working, click on any criterion. This should display summarized reviews and scores for a particular question in the questionnaire.&lt;br /&gt;
:[[File:expertiza2008-7.png]]&lt;br /&gt;
&lt;br /&gt;
=='''Future improvement'''==&lt;br /&gt;
* Modularize ''summarize_by_rounds'' to even smaller modules so that Assignment Branch Condition size is reduced from 36.73 to 15.00.&lt;br /&gt;
* Create more test cases for the new modularized methods.&lt;br /&gt;
&lt;br /&gt;
=='''Contributors'''==&lt;br /&gt;
* [mailto:jviswan@ncsu.edu Jayalakshmi Viswanathan]&lt;br /&gt;
* [mailto:skundal@ncsu.edu Sandeep Kundala]&lt;br /&gt;
* [mailto:spal3@ncsu.edu Sumitosh Pal]&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132225</id>
		<title>CSC/ECE 517 Spring 2020 - Project E2008. Refactor summary helper.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132225"/>
		<updated>2020-03-30T17:22:45Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* Refactor - get_questions_by_assignment */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''About Expertiza'''==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed using Ruby on Rails Framework whose creation and maintenance are taken care of by students as well as the faculty of NCSU. Its code is available on Github [https://github.com/expertiza/expertiza Expertiza on GitHub]. Expertiza allows the instructor to create and edit new as well as existing assignments. This also includes creating a wide range of topics under each assignment that students can sign up for. They can also publish surveys and reviews, view statistical results, set deadlines for assignments and make announcements. It provides a platform for students to signup for topics, form teams, view and submit assignments and give peer reviews and feedback.&lt;br /&gt;
&lt;br /&gt;
=='''Problem Statement'''==&lt;br /&gt;
'''Background:''' In Expertiza students can review each other’s projects and even each other as teammates. Students can view their project scores and instructors can view student's teammate review scores on the view scores page. This Summary helper aids in calculating these scores and rendering the results on the view scores section of an assignment. Summary helper is a helper module that consists of methods used to calculate scores for these reviews. This is for the use of instructors.&lt;br /&gt;
&lt;br /&gt;
'''Requirement:'''&lt;br /&gt;
E2008 is an Expertiza OSS project which deals basically with refactoring app/helpers/summary_helper.rb to reduce the code climate issues such as&lt;br /&gt;
&lt;br /&gt;
* [http://wiki.c2.com/?AbcMetric Assignment Branch Condition]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Cognitive_complexity Cognitive Complexity]&lt;br /&gt;
* Method/line too long&lt;br /&gt;
* Unused variables / access modifiers&lt;br /&gt;
&lt;br /&gt;
'''A good method should have:'''&lt;br /&gt;
* Assignment Branch Condition size &amp;lt; 15&lt;br /&gt;
* Cognitive Complexity &amp;lt; 6&lt;br /&gt;
* No. of lines in a method &amp;lt; 25&lt;br /&gt;
&lt;br /&gt;
=='''Issues found'''==&lt;br /&gt;
The following are issues which were found in the code:&lt;br /&gt;
&lt;br /&gt;
==='''Assignment Branch Condition'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! ABC Size&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewee&lt;br /&gt;
| 44.61&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 42.34&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 89.93&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 16.43&lt;br /&gt;
|-&lt;br /&gt;
| calculate_avg_score_by_round&lt;br /&gt;
| 18.57&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
==='''Cognitive Complexity'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! Cognitive Complexity&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 16&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 17&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 11&lt;br /&gt;
|-&lt;br /&gt;
| break_up_comments_to_sentences&lt;br /&gt;
| 6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Method/line too long'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method/Line too long&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewees&lt;br /&gt;
|'''Lines of Code:'''39&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_criterion  &lt;br /&gt;
|'''Lines of Code:'''27&lt;br /&gt;
|-&lt;br /&gt;
|'''Line:''' 145&lt;br /&gt;
|self.avg_scores_by_round[reviewee.name][round] too long (162/160)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==='''Unused variables / access modifiers'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Vaiable/Access Modifier&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' summary  &lt;br /&gt;
|'''Method:''' summarize_sentences&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' included_question_counter  &lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewee&lt;br /&gt;
|-&lt;br /&gt;
|'''Access Modifier:''' module_function  &lt;br /&gt;
|'''Class:''' Summary&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=='''Solution Implemented'''==&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewee'''===&lt;br /&gt;
:This method is used to summarize reviews by a reviewer for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:''' &lt;br /&gt;
:This method could be refactored into smaller methods namely ''summarize_reviews_by_reviewee'' and ''summarize_reviews_by_reviewee_assign'' where ''summarize_reviews_by_reviewee'' calls ''summarize_reviews_by_reviewee_assign'' to get average scores and summary for each question.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewee is reduced from 44.61 to 20.64.&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_criterion'''===&lt;br /&gt;
:This method is used to summarize the review for each questions&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 3 smaller methods namely ''summarize_reviews_by_criterion'', ''summarize_reviews_by_criterion_questions'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion'' calls ''summarize_reviews_by_criterion_questions'' to get answers of each question in the rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion_questions'' starts many threads to process each question and closes it by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_3.jpg]]&lt;br /&gt;
:[[File:e2008_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_criterion is reduced from 42.34 to 17.2&lt;br /&gt;
:* Cognitive complexity is reduced from 16 to 7&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewees'''===&lt;br /&gt;
:This method is used to produce summaries for instructor and students. It sums up the feedback by criterion for each reviewer&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 4 smaller methods namely ''summarize_reviews_by_reviewees'', ''summarize_reviews_by_teams'', ''summarize_by_rounds'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_reviewees'' calls ''summarize_reviews_by_teams''  which inturn calls ''summarize_by_rounds'' to get answers of each reviewer by rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_by_rounds'' starts many threads to create requests to summarize the comments and closes the threads by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def summarize_reviews_by_reviewees(assignment, summary_ws_url)&lt;br /&gt;
      # @summary[reviewee][round][question]&lt;br /&gt;
      # @reviewers[team][reviewer]&lt;br /&gt;
      # @avg_scores_by_reviewee[team]&lt;br /&gt;
      # @avg_score_round[reviewee][round]&lt;br /&gt;
      # @avg_scores_by_criterion[reviewee][round][criterion]&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_reviewee = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.reviewers = ({})&lt;br /&gt;
      threads = []&lt;br /&gt;
&lt;br /&gt;
      # get all criteria used in each round&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get all teams in this assignment&lt;br /&gt;
      teams = Team.select(:id, :name).where(parent_id: assignment.id).order(:name)&lt;br /&gt;
&lt;br /&gt;
      teams.each do |reviewee|&lt;br /&gt;
        self.summary[reviewee.name] = []&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = 0.0&lt;br /&gt;
        self.avg_scores_by_round[reviewee.name] = []&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name] = []&lt;br /&gt;
&lt;br /&gt;
        # get the name of reviewers for display only&lt;br /&gt;
        self.reviewers[reviewee.name] = get_reviewers_by_reviewee_and_assignment(reviewee, assignment.id)&lt;br /&gt;
&lt;br /&gt;
        # get answers of each reviewer by rubric&lt;br /&gt;
        (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
          self.summary[reviewee.name][round] = {}&lt;br /&gt;
          self.avg_scores_by_round[reviewee.name][round] = 0.0&lt;br /&gt;
          self.avg_scores_by_criterion[reviewee.name][round] = {}&lt;br /&gt;
&lt;br /&gt;
          # iterate each round and get answers&lt;br /&gt;
          # if use the same rubric, only use rubric[0]&lt;br /&gt;
          rubric_questions_used = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
          rubric_questions_used.each do |q|&lt;br /&gt;
            next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
            summary[reviewee.name][round][q.txt] = &amp;quot;&amp;quot;&lt;br /&gt;
            self.avg_scores_by_criterion[reviewee.name][round][q.txt] = 0.0&lt;br /&gt;
&lt;br /&gt;
            # get all answers to this question&lt;br /&gt;
            question_answers = Answer.answers_by_question_for_reviewee_in_round(assignment.id, reviewee.id, q.id, round + 1)&lt;br /&gt;
            # get max score of this rubric&lt;br /&gt;
            q_max_score = get_max_score_for_question(q)&lt;br /&gt;
&lt;br /&gt;
            comments = break_up_comments_to_sentences(question_answers)&lt;br /&gt;
            # get score and summary of answers for each question&lt;br /&gt;
            self.avg_scores_by_criterion[reviewee.name][round][q.txt] = calculate_avg_score_by_criterion(question_answers, q_max_score)&lt;br /&gt;
&lt;br /&gt;
            # summarize the comments by calling the summarization Web Service&lt;br /&gt;
&lt;br /&gt;
            # since it'll do a lot of request, do this in seperate threads&lt;br /&gt;
            threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
              summary[reviewee.name][round][q.txt] = summarize_sentences(comments, summary_ws_url) unless comments.empty?&lt;br /&gt;
            end&lt;br /&gt;
          end&lt;br /&gt;
          self.avg_scores_by_round[reviewee.name][round] = calculate_avg_score_by_round(self.avg_scores_by_criterion[reviewee.name][round], rubric_questions_used)&lt;br /&gt;
        end&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = calculate_avg_score_by_reviewee(self.avg_scores_by_round[reviewee.name], assignment.rounds_of_reviews)&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      threads.each do |t|&lt;br /&gt;
        t.join if t != Thread.current&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def summarize_reviews_by_reviewees(assignment, summary_ws_url)&lt;br /&gt;
      # @summary[reviewee][round][question]&lt;br /&gt;
      # @reviewers[team][reviewer]&lt;br /&gt;
      # @avg_scores_by_reviewee[team]&lt;br /&gt;
      # @avg_score_round[reviewee][round]&lt;br /&gt;
      # @avg_scores_by_criterion[reviewee][round][criterion]&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_reviewee = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.reviewers = ({})&lt;br /&gt;
      self.summary_ws_url = summary_ws_url&lt;br /&gt;
&lt;br /&gt;
      # get all criteria used in each round&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get all teams in this assignment&lt;br /&gt;
      teams = Team.select(:id, :name).where(parent_id: assignment.id).order(:name)&lt;br /&gt;
&lt;br /&gt;
      teams.each do |reviewee|&lt;br /&gt;
        summarize_reviews_by_team_reviewee(assignment, reviewee, rubric)&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = calculate_avg_score_by_reviewee(self.avg_scores_by_round[reviewee.name], assignment.rounds_of_reviews)&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def summarize_reviews_by_team_reviewee(assignment, reviewee, rubric)&lt;br /&gt;
      self.summary[reviewee.name] = []&lt;br /&gt;
      self.avg_scores_by_reviewee[reviewee.name] = 0.0&lt;br /&gt;
      self.avg_scores_by_round[reviewee.name] = self.avg_scores_by_criterion[reviewee.name] = []&lt;br /&gt;
&lt;br /&gt;
      # get the name of reviewers for display only&lt;br /&gt;
      self.reviewers[reviewee.name] = get_reviewers_by_reviewee_and_assignment(reviewee, assignment.id)&lt;br /&gt;
&lt;br /&gt;
      # get answers of each reviewer by rubric&lt;br /&gt;
      (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
        self.summary[reviewee.name][round] = {}&lt;br /&gt;
        self.avg_scores_by_round[reviewee.name][round] = 0.0&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name][round] = {}&lt;br /&gt;
        summarize_by_reviewee_round(assignment, reviewee, round, rubric)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def summarize_by_reviewee_round(assignment, reviewee, round, rubric)&lt;br /&gt;
      threads = []&lt;br /&gt;
      # iterate each round and get answers&lt;br /&gt;
      # if use the same rubric, only use rubric[0]&lt;br /&gt;
      rubric_questions_used = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
      rubric_questions_used.each do |q|&lt;br /&gt;
        next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # get all answers to this question&lt;br /&gt;
        question_answers = Answer.answers_by_question_for_reviewee_in_round(assignment.id, reviewee.id, q.id, round + 1)&lt;br /&gt;
&lt;br /&gt;
        # get score and summary of answers for each question&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name][round][q.txt] = calculate_avg_score_by_criterion(question_answers, get_max_score_for_question(q))&lt;br /&gt;
&lt;br /&gt;
        # summarize the comments by calling the summarization Web Service&lt;br /&gt;
        # since it'll do a lot of request, do this in seperate threads&lt;br /&gt;
        threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
          self.summary[reviewee.name][round][q.txt] = summarize_sentences(break_up_comments_to_sentences(question_answers), self.summary_ws_url)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      avg_scores_by_round = calculate_avg_score_by_round(self.avg_scores_by_criterion[reviewee.name][round], rubric_questions_used)&lt;br /&gt;
      self.avg_scores_by_round[reviewee.name][round] = avg_scores_by_round&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      end_threads(threads)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    def end_threads(threads)&lt;br /&gt;
      threads.each do |t|&lt;br /&gt;
        # Wait for the thread to finish if it isn't this thread (i.e. the main thread).&lt;br /&gt;
        t.join if t != Thread.current&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewees is reduced from 89.93 to 16.64&lt;br /&gt;
:* Cognitive Complexity is reduced from 17 to 7&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_sentence'''===&lt;br /&gt;
:This method calls web service to store each summary in a hashmap and use the question as the key.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Removed variable ''summary''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_8.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - break_up_comments_to_sentences'''===&lt;br /&gt;
: This method adds the comment to an array to be converted as a json request.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:The method is broken down into 2 smaller methods namely ''break_up_comments_to_sentences'' and ''get_sentences'' where ''get_sentences'' is called by ''break_up_comments_to_sentences'' to  get sentences in desired format.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_9.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact''':&lt;br /&gt;
:*The Cognitive complexity of break_up_comments_to_sentences reduced from 6 to &amp;lt;5&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - get_questions_by_assignment'''===&lt;br /&gt;
:This method returns the rubric for given assignment&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
:*In IF CONDITION: Removed unnecessary use of variable which was being used only once (questionaire_id) and replaced the variable with its assignment (assignment.review_questionnaire_id(round + 1)&lt;br /&gt;
:*In ELSE CONDITION: Removed unnecessary ternary operation for variable ''questionaire_id'' and replaced the variable with its assignment (assignment.review_questionnaire_id) &lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_10.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - calculate_avg_score_by_round'''===&lt;br /&gt;
:This method is used to calculate average round score for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Refactored the method into 2 smaller methods namely ''calculate_avg_score_by_round'' and ''calculate_round_score'' where ''calculate_avg_score_by_round'' calls ''calculate_round_score'' to calculate average round score and ''calculate_avg_score_by_round'' rounds the round_score upto 2 decimal places.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = 0.0&lt;br /&gt;
      sum_weight = 0&lt;br /&gt;
&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = sum_weight = 0.0&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
      round_score&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:*Assignment Branch Condition size for calculate_avg_score_by_round is reduced from 18.57 to &amp;lt;15.&lt;br /&gt;
&lt;br /&gt;
==='''Coverage:'''===&lt;br /&gt;
Coverage increased (+17.1%) to 41.407%&lt;br /&gt;
&lt;br /&gt;
==='''Pull request:'''===&lt;br /&gt;
https://github.com/expertiza/expertiza/pull/1685&lt;br /&gt;
&lt;br /&gt;
=='''Test Plan'''==&lt;br /&gt;
==='''Manual Testing'''===&lt;br /&gt;
:'''Login Details:''' '''USERNAME:''' instructor6 '''PASSWORD:''' password&lt;br /&gt;
:Click '''Assignment''' &amp;gt;&amp;gt; Click the '''View Submissions''' of '''Madeup problem''' &amp;gt;&amp;gt; Click on any student &amp;gt;&amp;gt; Click on '''Madeup problem''' &amp;gt;&amp;gt; Click on '''Your Scores'''&lt;br /&gt;
:[[File:expertiza2008-1.png]]&lt;br /&gt;
:[[File:expertiza2008-2.png]]&lt;br /&gt;
:[[File:expertiza2008-3.png]]&lt;br /&gt;
:[[File:expertiza2008-4.png]]&lt;br /&gt;
:The 3 main functions of the Summary helper are summarize review by reviewees, summarize review by reviewee and summarize reviews by criterion.&lt;br /&gt;
:To check ''summarize reviews by reviewees'' is working we should get the output similar to the one shown below. This function summarizes all the reviews and displays average score.&lt;br /&gt;
:[[File:expertiza2008-5.png]]&lt;br /&gt;
&lt;br /&gt;
:To check ''summarize reviews by reviewee'' is working, click on any review.&lt;br /&gt;
:[[File:expertiza2008-6a.png]]&lt;br /&gt;
:A new webpage pops up with all the reviews and scores given by an individual.&lt;br /&gt;
:[[File:expertiza2008-6b.png]]&lt;br /&gt;
&lt;br /&gt;
: To check ''summarize reviews by criterion'' is working, click on any criterion. This should display summarized reviews and scores for a particular question in the questionnaire.&lt;br /&gt;
:[[File:expertiza2008-7.png]]&lt;br /&gt;
&lt;br /&gt;
=='''Future improvement'''==&lt;br /&gt;
* Modularize ''summarize_by_rounds'' to even smaller modules so that Assignment Branch Condition size is reduced from 36.73 to 15.00.&lt;br /&gt;
* Create more test cases for the new modularized methods.&lt;br /&gt;
&lt;br /&gt;
=='''Contributors'''==&lt;br /&gt;
* [mailto:jviswan@ncsu.edu Jayalakshmi Viswanathan]&lt;br /&gt;
* [mailto:skundal@ncsu.edu Sandeep Kundala]&lt;br /&gt;
* [mailto:spal3@ncsu.edu Sumitosh Pal]&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132208</id>
		<title>CSC/ECE 517 Spring 2020 - Project E2008. Refactor summary helper.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132208"/>
		<updated>2020-03-30T07:32:08Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* Solution Implemented */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''About Expertiza'''==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed using Ruby on Rails Framework whose creation and maintenance are taken care of by students as well as the faculty of NCSU. Its code is available on Github [https://github.com/expertiza/expertiza Expertiza on GitHub]. Expertiza allows the instructor to create and edit new as well as existing assignments. This also includes creating a wide range of topics under each assignment that students can sign up for. They can also publish surveys and reviews, view statistical results, set deadlines for assignments and make announcements. It provides a platform for students to signup for topics, form teams, view and submit assignments and give peer reviews and feedback.&lt;br /&gt;
&lt;br /&gt;
=='''Problem Statement'''==&lt;br /&gt;
'''Background:''' In Expertiza students can review each other’s projects and even each other as teammates. Students can view their project scores and instructors can view student's teammate review scores on the view scores page. This Summary helper aids in calculating these scores and rendering the results on the view scores section of an assignment. Summary helper is a helper module that consists of methods used to calculate scores for these reviews. This is for the use of instructors.&lt;br /&gt;
&lt;br /&gt;
'''Requirement:'''&lt;br /&gt;
E2008 is an Expertiza OSS project which deals basically with refactoring app/helpers/summary_helper.rb to reduce the code climate issues such as&lt;br /&gt;
&lt;br /&gt;
* [http://wiki.c2.com/?AbcMetric Assignment Branch Condition]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Cognitive_complexity Cognitive Complexity]&lt;br /&gt;
* Method/line too long&lt;br /&gt;
* Unused variables / access modifiers&lt;br /&gt;
&lt;br /&gt;
'''A good method should have:'''&lt;br /&gt;
* Assignment Branch Condition size &amp;lt; 15&lt;br /&gt;
* Cognitive Complexity &amp;lt; 6&lt;br /&gt;
* No. of lines in a method &amp;lt; 25&lt;br /&gt;
&lt;br /&gt;
=='''Issues found'''==&lt;br /&gt;
The following are issues which were found in the code:&lt;br /&gt;
&lt;br /&gt;
==='''Assignment Branch Condition'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! ABC Size&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewee&lt;br /&gt;
| 44.61&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 42.34&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 89.93&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 16.43&lt;br /&gt;
|-&lt;br /&gt;
| calculate_avg_score_by_round&lt;br /&gt;
| 18.57&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
==='''Cognitive Complexity'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! Cognitive Complexity&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 16&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 17&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 11&lt;br /&gt;
|-&lt;br /&gt;
| break_up_comments_to_sentences&lt;br /&gt;
| 6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Method/line too long'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method/Line too long&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewees&lt;br /&gt;
|'''Lines of Code:'''39&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_criterion  &lt;br /&gt;
|'''Lines of Code:'''27&lt;br /&gt;
|-&lt;br /&gt;
|'''Line:''' 145&lt;br /&gt;
|self.avg_scores_by_round[reviewee.name][round] too long (162/160)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==='''Unused variables / access modifiers'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Vaiable/Access Modifier&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' summary  &lt;br /&gt;
|'''Method:''' summarize_sentences&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' included_question_counter  &lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewee&lt;br /&gt;
|-&lt;br /&gt;
|'''Access Modifier:''' module_function  &lt;br /&gt;
|'''Class:''' Summary&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=='''Solution Implemented'''==&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewee'''===&lt;br /&gt;
:This method is used to summarize reviews by a reviewer for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:''' &lt;br /&gt;
:This method could be refactored into smaller methods namely ''summarize_reviews_by_reviewee'' and ''summarize_reviews_by_reviewee_assign'' where ''summarize_reviews_by_reviewee'' calls ''summarize_reviews_by_reviewee_assign'' to get average scores and summary for each question.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewee is reduced from 44.61 to 20.64.&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_criterion'''===&lt;br /&gt;
:This method is used to summarize the review for each questions&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 3 smaller methods namely ''summarize_reviews_by_criterion'', ''summarize_reviews_by_criterion_questions'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion'' calls ''summarize_reviews_by_criterion_questions'' to get answers of each question in the rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion_questions'' starts many threads to process each question and closes it by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_3.jpg]]&lt;br /&gt;
:[[File:e2008_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_criterion is reduced from 42.34 to 17.2&lt;br /&gt;
:* Cognitive complexity is reduced from 16 to 7&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewees'''===&lt;br /&gt;
:This method is used to produce summaries for instructor and students. It sums up the feedback by criterion for each reviewer&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 4 smaller methods namely ''summarize_reviews_by_reviewees'', ''summarize_reviews_by_teams'', ''summarize_by_rounds'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_reviewees'' calls ''summarize_reviews_by_teams''  which inturn calls ''summarize_by_rounds'' to get answers of each reviewer by rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_by_rounds'' starts many threads to create requests to summarize the comments and closes the threads by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def summarize_reviews_by_reviewees(assignment, summary_ws_url)&lt;br /&gt;
      # @summary[reviewee][round][question]&lt;br /&gt;
      # @reviewers[team][reviewer]&lt;br /&gt;
      # @avg_scores_by_reviewee[team]&lt;br /&gt;
      # @avg_score_round[reviewee][round]&lt;br /&gt;
      # @avg_scores_by_criterion[reviewee][round][criterion]&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_reviewee = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.reviewers = ({})&lt;br /&gt;
      threads = []&lt;br /&gt;
&lt;br /&gt;
      # get all criteria used in each round&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get all teams in this assignment&lt;br /&gt;
      teams = Team.select(:id, :name).where(parent_id: assignment.id).order(:name)&lt;br /&gt;
&lt;br /&gt;
      teams.each do |reviewee|&lt;br /&gt;
        self.summary[reviewee.name] = []&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = 0.0&lt;br /&gt;
        self.avg_scores_by_round[reviewee.name] = []&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name] = []&lt;br /&gt;
&lt;br /&gt;
        # get the name of reviewers for display only&lt;br /&gt;
        self.reviewers[reviewee.name] = get_reviewers_by_reviewee_and_assignment(reviewee, assignment.id)&lt;br /&gt;
&lt;br /&gt;
        # get answers of each reviewer by rubric&lt;br /&gt;
        (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
          self.summary[reviewee.name][round] = {}&lt;br /&gt;
          self.avg_scores_by_round[reviewee.name][round] = 0.0&lt;br /&gt;
          self.avg_scores_by_criterion[reviewee.name][round] = {}&lt;br /&gt;
&lt;br /&gt;
          # iterate each round and get answers&lt;br /&gt;
          # if use the same rubric, only use rubric[0]&lt;br /&gt;
          rubric_questions_used = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
          rubric_questions_used.each do |q|&lt;br /&gt;
            next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
            summary[reviewee.name][round][q.txt] = &amp;quot;&amp;quot;&lt;br /&gt;
            self.avg_scores_by_criterion[reviewee.name][round][q.txt] = 0.0&lt;br /&gt;
&lt;br /&gt;
            # get all answers to this question&lt;br /&gt;
            question_answers = Answer.answers_by_question_for_reviewee_in_round(assignment.id, reviewee.id, q.id, round + 1)&lt;br /&gt;
            # get max score of this rubric&lt;br /&gt;
            q_max_score = get_max_score_for_question(q)&lt;br /&gt;
&lt;br /&gt;
            comments = break_up_comments_to_sentences(question_answers)&lt;br /&gt;
            # get score and summary of answers for each question&lt;br /&gt;
            self.avg_scores_by_criterion[reviewee.name][round][q.txt] = calculate_avg_score_by_criterion(question_answers, q_max_score)&lt;br /&gt;
&lt;br /&gt;
            # summarize the comments by calling the summarization Web Service&lt;br /&gt;
&lt;br /&gt;
            # since it'll do a lot of request, do this in seperate threads&lt;br /&gt;
            threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
              summary[reviewee.name][round][q.txt] = summarize_sentences(comments, summary_ws_url) unless comments.empty?&lt;br /&gt;
            end&lt;br /&gt;
          end&lt;br /&gt;
          self.avg_scores_by_round[reviewee.name][round] = calculate_avg_score_by_round(self.avg_scores_by_criterion[reviewee.name][round], rubric_questions_used)&lt;br /&gt;
        end&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = calculate_avg_score_by_reviewee(self.avg_scores_by_round[reviewee.name], assignment.rounds_of_reviews)&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      threads.each do |t|&lt;br /&gt;
        t.join if t != Thread.current&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def summarize_reviews_by_reviewees(assignment, summary_ws_url)&lt;br /&gt;
      # @summary[reviewee][round][question]&lt;br /&gt;
      # @reviewers[team][reviewer]&lt;br /&gt;
      # @avg_scores_by_reviewee[team]&lt;br /&gt;
      # @avg_score_round[reviewee][round]&lt;br /&gt;
      # @avg_scores_by_criterion[reviewee][round][criterion]&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_reviewee = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.reviewers = ({})&lt;br /&gt;
      self.summary_ws_url = summary_ws_url&lt;br /&gt;
&lt;br /&gt;
      # get all criteria used in each round&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get all teams in this assignment&lt;br /&gt;
      teams = Team.select(:id, :name).where(parent_id: assignment.id).order(:name)&lt;br /&gt;
&lt;br /&gt;
      teams.each do |reviewee|&lt;br /&gt;
        summarize_reviews_by_team_reviewee(assignment, reviewee, rubric)&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = calculate_avg_score_by_reviewee(self.avg_scores_by_round[reviewee.name], assignment.rounds_of_reviews)&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def summarize_reviews_by_team_reviewee(assignment, reviewee, rubric)&lt;br /&gt;
      self.summary[reviewee.name] = []&lt;br /&gt;
      self.avg_scores_by_reviewee[reviewee.name] = 0.0&lt;br /&gt;
      self.avg_scores_by_round[reviewee.name] = self.avg_scores_by_criterion[reviewee.name] = []&lt;br /&gt;
&lt;br /&gt;
      # get the name of reviewers for display only&lt;br /&gt;
      self.reviewers[reviewee.name] = get_reviewers_by_reviewee_and_assignment(reviewee, assignment.id)&lt;br /&gt;
&lt;br /&gt;
      # get answers of each reviewer by rubric&lt;br /&gt;
      (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
        self.summary[reviewee.name][round] = {}&lt;br /&gt;
        self.avg_scores_by_round[reviewee.name][round] = 0.0&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name][round] = {}&lt;br /&gt;
        summarize_by_reviewee_round(assignment, reviewee, round, rubric)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def summarize_by_reviewee_round(assignment, reviewee, round, rubric)&lt;br /&gt;
      threads = []&lt;br /&gt;
      # iterate each round and get answers&lt;br /&gt;
      # if use the same rubric, only use rubric[0]&lt;br /&gt;
      rubric_questions_used = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
      rubric_questions_used.each do |q|&lt;br /&gt;
        next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # get all answers to this question&lt;br /&gt;
        question_answers = Answer.answers_by_question_for_reviewee_in_round(assignment.id, reviewee.id, q.id, round + 1)&lt;br /&gt;
&lt;br /&gt;
        # get score and summary of answers for each question&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name][round][q.txt] = calculate_avg_score_by_criterion(question_answers, get_max_score_for_question(q))&lt;br /&gt;
&lt;br /&gt;
        # summarize the comments by calling the summarization Web Service&lt;br /&gt;
        # since it'll do a lot of request, do this in seperate threads&lt;br /&gt;
        threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
          self.summary[reviewee.name][round][q.txt] = summarize_sentences(break_up_comments_to_sentences(question_answers), self.summary_ws_url)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      avg_scores_by_round = calculate_avg_score_by_round(self.avg_scores_by_criterion[reviewee.name][round], rubric_questions_used)&lt;br /&gt;
      self.avg_scores_by_round[reviewee.name][round] = avg_scores_by_round&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      end_threads(threads)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    def end_threads(threads)&lt;br /&gt;
      threads.each do |t|&lt;br /&gt;
        # Wait for the thread to finish if it isn't this thread (i.e. the main thread).&lt;br /&gt;
        t.join if t != Thread.current&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewees is reduced from 89.93 to 16.64&lt;br /&gt;
:* Cognitive Complexity is reduced from 17 to 7&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_sentence'''===&lt;br /&gt;
:This method calls web service to store each summary in a hashmap and use the question as the key.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Removed variable ''summary''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_8.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - break_up_comments_to_sentences'''===&lt;br /&gt;
: This method adds the comment to an array to be converted as a json request.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:The method is broken down into 2 smaller methods namely ''break_up_comments_to_sentences'' and ''get_sentences'' where ''get_sentences'' is called by ''break_up_comments_to_sentences'' to  get sentences in desired format.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_9.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact''':&lt;br /&gt;
:*The Cognitive complexity of break_up_comments_to_sentences reduced from 6 to &amp;lt;5&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - get_questions_by_assignment'''===&lt;br /&gt;
:This method returns the rubric for given assignment&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_10.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - calculate_avg_score_by_round'''===&lt;br /&gt;
:This method is used to calculate average round score for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Refactored the method into 2 smaller methods namely ''calculate_avg_score_by_round'' and ''calculate_round_score'' where ''calculate_avg_score_by_round'' calls ''calculate_round_score'' to calculate average round score and ''calculate_avg_score_by_round'' rounds the round_score upto 2 decimal places.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = 0.0&lt;br /&gt;
      sum_weight = 0&lt;br /&gt;
&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = sum_weight = 0.0&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
      round_score&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:*Assignment Branch Condition size for calculate_avg_score_by_round is reduced from 18.57 to &amp;lt;15.&lt;br /&gt;
&lt;br /&gt;
==='''Coverage:'''===&lt;br /&gt;
Coverage increased (+17.1%) to 41.407%&lt;br /&gt;
&lt;br /&gt;
==='''Pull request:'''===&lt;br /&gt;
https://github.com/expertiza/expertiza/pull/1685&lt;br /&gt;
&lt;br /&gt;
=='''Test Plan'''==&lt;br /&gt;
==='''Manual Testing'''===&lt;br /&gt;
:'''Login Details:''' '''USERNAME:''' instructor6 '''PASSWORD:''' password&lt;br /&gt;
:Click '''Assignment''' &amp;gt;&amp;gt; Click the '''View Submissions''' of '''Madeup problem''' &amp;gt;&amp;gt; Click on any student &amp;gt;&amp;gt; Click on '''Madeup problem''' &amp;gt;&amp;gt; Click on '''Your Scores'''&lt;br /&gt;
:[[File:expertiza2008-1.png]]&lt;br /&gt;
:[[File:expertiza2008-2.png]]&lt;br /&gt;
:[[File:expertiza2008-3.png]]&lt;br /&gt;
:[[File:expertiza2008-4.png]]&lt;br /&gt;
:The 3 main functions of the Summary helper are summarize review by reviewees, summarize review by reviewee and summarize reviews by criterion.&lt;br /&gt;
:To check ''summarize reviews by reviewees'' is working we should get the output similar to the one shown below. This function summarizes all the reviews and displays average score.&lt;br /&gt;
:[[File:expertiza2008-5.png]]&lt;br /&gt;
&lt;br /&gt;
:To check ''summarize reviews by reviewee'' is working, click on any review.&lt;br /&gt;
:[[File:expertiza2008-6a.png]]&lt;br /&gt;
:A new webpage pops up with all the reviews and scores given by an individual.&lt;br /&gt;
:[[File:expertiza2008-6b.png]]&lt;br /&gt;
&lt;br /&gt;
: To check ''summarize reviews by criterion'' is working, click on any criterion. This should display summarized reviews and scores for a particular question in the questionnaire.&lt;br /&gt;
:[[File:expertiza2008-7.png]]&lt;br /&gt;
&lt;br /&gt;
=='''Future improvement'''==&lt;br /&gt;
* Modularize ''summarize_by_rounds'' to even smaller modules so that Assignment Branch Condition size is reduced from 36.73 to 15.00.&lt;br /&gt;
* Create more test cases for the new modularized methods.&lt;br /&gt;
&lt;br /&gt;
=='''Contributors'''==&lt;br /&gt;
* [mailto:jviswan@ncsu.edu Jayalakshmi Viswanathan]&lt;br /&gt;
* [mailto:skundal@ncsu.edu Sandeep Kundala]&lt;br /&gt;
* [mailto:spal3@ncsu.edu Sumitosh Pal]&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132207</id>
		<title>CSC/ECE 517 Spring 2020 - Project E2008. Refactor summary helper.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132207"/>
		<updated>2020-03-30T07:22:06Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* Problem Statement */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''About Expertiza'''==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed using Ruby on Rails Framework whose creation and maintenance are taken care of by students as well as the faculty of NCSU. Its code is available on Github [https://github.com/expertiza/expertiza Expertiza on GitHub]. Expertiza allows the instructor to create and edit new as well as existing assignments. This also includes creating a wide range of topics under each assignment that students can sign up for. They can also publish surveys and reviews, view statistical results, set deadlines for assignments and make announcements. It provides a platform for students to signup for topics, form teams, view and submit assignments and give peer reviews and feedback.&lt;br /&gt;
&lt;br /&gt;
=='''Problem Statement'''==&lt;br /&gt;
'''Background:''' In Expertiza students can review each other’s projects and even each other as teammates. Students can view their project scores and instructors can view student's teammate review scores on the view scores page. This Summary helper aids in calculating these scores and rendering the results on the view scores section of an assignment. Summary helper is a helper module that consists of methods used to calculate scores for these reviews. This is for the use of instructors.&lt;br /&gt;
&lt;br /&gt;
'''Requirement:'''&lt;br /&gt;
E2008 is an Expertiza OSS project which deals basically with refactoring app/helpers/summary_helper.rb to reduce the code climate issues such as&lt;br /&gt;
&lt;br /&gt;
* [http://wiki.c2.com/?AbcMetric Assignment Branch Condition]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Cognitive_complexity Cognitive Complexity]&lt;br /&gt;
* Method/line too long&lt;br /&gt;
* Unused variables / access modifiers&lt;br /&gt;
&lt;br /&gt;
'''A good method should have:'''&lt;br /&gt;
* Assignment Branch Condition size &amp;lt; 15&lt;br /&gt;
* Cognitive Complexity &amp;lt; 6&lt;br /&gt;
* No. of lines in a method &amp;lt; 25&lt;br /&gt;
&lt;br /&gt;
=='''Issues found'''==&lt;br /&gt;
The following are issues which were found in the code:&lt;br /&gt;
&lt;br /&gt;
==='''Assignment Branch Condition'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! ABC Size&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewee&lt;br /&gt;
| 44.61&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 42.34&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 89.93&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 16.43&lt;br /&gt;
|-&lt;br /&gt;
| calculate_avg_score_by_round&lt;br /&gt;
| 18.57&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
==='''Cognitive Complexity'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! Cognitive Complexity&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 16&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 17&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 11&lt;br /&gt;
|-&lt;br /&gt;
| break_up_comments_to_sentences&lt;br /&gt;
| 6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Method/line too long'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method/Line too long&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewees&lt;br /&gt;
|'''Lines of Code:'''39&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_criterion  &lt;br /&gt;
|'''Lines of Code:'''27&lt;br /&gt;
|-&lt;br /&gt;
|'''Line:''' 145&lt;br /&gt;
|self.avg_scores_by_round[reviewee.name][round] too long (162/160)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==='''Unused variables / access modifiers'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Vaiable/Access Modifier&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' summary  &lt;br /&gt;
|'''Method:''' summarize_sentences&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' included_question_counter  &lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewee&lt;br /&gt;
|-&lt;br /&gt;
|'''Access Modifier:''' module_function  &lt;br /&gt;
|'''Class:''' Summary&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=='''Solution Implemented'''==&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewee'''===&lt;br /&gt;
:This method is used to summarize reviews by a reviewer for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:''' &lt;br /&gt;
:This method could be refactored into smaller methods namely ''summarize_reviews_by_reviewee'' and ''summarize_reviews_by_reviewee_assign'' where ''summarize_reviews_by_reviewee'' calls ''summarize_reviews_by_reviewee_assign'' to get average scores and summary for each question.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewee is reduced from 44.61 to 20.64.&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_criterion'''===&lt;br /&gt;
:This method is used to summarize the review for each questions&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 3 smaller methods namely ''summarize_reviews_by_criterion'', ''summarize_reviews_by_criterion_questions'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion'' calls ''summarize_reviews_by_criterion_questions'' to get answers of each question in the rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion_questions'' starts many threads to process each question and closes it by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_3.jpg]]&lt;br /&gt;
:[[File:e2008_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_criterion is reduced from 42.34 to 17.2&lt;br /&gt;
:* Cognitive complexity is reduced from 16 to 7&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewees'''===&lt;br /&gt;
:This method is used to produce summaries for instructor and students. It sums up the feedback by criterion for each reviewer&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 4 smaller methods namely ''summarize_reviews_by_reviewees'', ''summarize_reviews_by_teams'', ''summarize_by_rounds'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_reviewees'' calls ''summarize_reviews_by_teams''  which inturn calls ''summarize_by_rounds'' to get answers of each reviewer by rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_by_rounds'' starts many threads to create requests to summarize the comments and closes the threads by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def summarize_reviews_by_reviewees(assignment, summary_ws_url)&lt;br /&gt;
      # @summary[reviewee][round][question]&lt;br /&gt;
      # @reviewers[team][reviewer]&lt;br /&gt;
      # @avg_scores_by_reviewee[team]&lt;br /&gt;
      # @avg_score_round[reviewee][round]&lt;br /&gt;
      # @avg_scores_by_criterion[reviewee][round][criterion]&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_reviewee = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.reviewers = ({})&lt;br /&gt;
      threads = []&lt;br /&gt;
&lt;br /&gt;
      # get all criteria used in each round&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get all teams in this assignment&lt;br /&gt;
      teams = Team.select(:id, :name).where(parent_id: assignment.id).order(:name)&lt;br /&gt;
&lt;br /&gt;
      teams.each do |reviewee|&lt;br /&gt;
        self.summary[reviewee.name] = []&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = 0.0&lt;br /&gt;
        self.avg_scores_by_round[reviewee.name] = []&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name] = []&lt;br /&gt;
&lt;br /&gt;
        # get the name of reviewers for display only&lt;br /&gt;
        self.reviewers[reviewee.name] = get_reviewers_by_reviewee_and_assignment(reviewee, assignment.id)&lt;br /&gt;
&lt;br /&gt;
        # get answers of each reviewer by rubric&lt;br /&gt;
        (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
          self.summary[reviewee.name][round] = {}&lt;br /&gt;
          self.avg_scores_by_round[reviewee.name][round] = 0.0&lt;br /&gt;
          self.avg_scores_by_criterion[reviewee.name][round] = {}&lt;br /&gt;
&lt;br /&gt;
          # iterate each round and get answers&lt;br /&gt;
          # if use the same rubric, only use rubric[0]&lt;br /&gt;
          rubric_questions_used = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
          rubric_questions_used.each do |q|&lt;br /&gt;
            next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
            summary[reviewee.name][round][q.txt] = &amp;quot;&amp;quot;&lt;br /&gt;
            self.avg_scores_by_criterion[reviewee.name][round][q.txt] = 0.0&lt;br /&gt;
&lt;br /&gt;
            # get all answers to this question&lt;br /&gt;
            question_answers = Answer.answers_by_question_for_reviewee_in_round(assignment.id, reviewee.id, q.id, round + 1)&lt;br /&gt;
            # get max score of this rubric&lt;br /&gt;
            q_max_score = get_max_score_for_question(q)&lt;br /&gt;
&lt;br /&gt;
            comments = break_up_comments_to_sentences(question_answers)&lt;br /&gt;
            # get score and summary of answers for each question&lt;br /&gt;
            self.avg_scores_by_criterion[reviewee.name][round][q.txt] = calculate_avg_score_by_criterion(question_answers, q_max_score)&lt;br /&gt;
&lt;br /&gt;
            # summarize the comments by calling the summarization Web Service&lt;br /&gt;
&lt;br /&gt;
            # since it'll do a lot of request, do this in seperate threads&lt;br /&gt;
            threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
              summary[reviewee.name][round][q.txt] = summarize_sentences(comments, summary_ws_url) unless comments.empty?&lt;br /&gt;
            end&lt;br /&gt;
          end&lt;br /&gt;
          self.avg_scores_by_round[reviewee.name][round] = calculate_avg_score_by_round(self.avg_scores_by_criterion[reviewee.name][round], rubric_questions_used)&lt;br /&gt;
        end&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = calculate_avg_score_by_reviewee(self.avg_scores_by_round[reviewee.name], assignment.rounds_of_reviews)&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      threads.each do |t|&lt;br /&gt;
        t.join if t != Thread.current&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def summarize_reviews_by_reviewees(assignment, summary_ws_url)&lt;br /&gt;
      # @summary[reviewee][round][question]&lt;br /&gt;
      # @reviewers[team][reviewer]&lt;br /&gt;
      # @avg_scores_by_reviewee[team]&lt;br /&gt;
      # @avg_score_round[reviewee][round]&lt;br /&gt;
      # @avg_scores_by_criterion[reviewee][round][criterion]&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_reviewee = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.reviewers = ({})&lt;br /&gt;
      self.summary_ws_url = summary_ws_url&lt;br /&gt;
&lt;br /&gt;
      # get all criteria used in each round&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get all teams in this assignment&lt;br /&gt;
      teams = Team.select(:id, :name).where(parent_id: assignment.id).order(:name)&lt;br /&gt;
&lt;br /&gt;
      teams.each do |reviewee|&lt;br /&gt;
        summarize_reviews_by_team_reviewee(assignment, reviewee, rubric)&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = calculate_avg_score_by_reviewee(self.avg_scores_by_round[reviewee.name], assignment.rounds_of_reviews)&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def summarize_reviews_by_team_reviewee(assignment, reviewee, rubric)&lt;br /&gt;
      self.summary[reviewee.name] = []&lt;br /&gt;
      self.avg_scores_by_reviewee[reviewee.name] = 0.0&lt;br /&gt;
      self.avg_scores_by_round[reviewee.name] = self.avg_scores_by_criterion[reviewee.name] = []&lt;br /&gt;
&lt;br /&gt;
      # get the name of reviewers for display only&lt;br /&gt;
      self.reviewers[reviewee.name] = get_reviewers_by_reviewee_and_assignment(reviewee, assignment.id)&lt;br /&gt;
&lt;br /&gt;
      # get answers of each reviewer by rubric&lt;br /&gt;
      (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
        self.summary[reviewee.name][round] = {}&lt;br /&gt;
        self.avg_scores_by_round[reviewee.name][round] = 0.0&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name][round] = {}&lt;br /&gt;
        summarize_by_reviewee_round(assignment, reviewee, round, rubric)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def summarize_by_reviewee_round(assignment, reviewee, round, rubric)&lt;br /&gt;
      threads = []&lt;br /&gt;
      # iterate each round and get answers&lt;br /&gt;
      # if use the same rubric, only use rubric[0]&lt;br /&gt;
      rubric_questions_used = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
      rubric_questions_used.each do |q|&lt;br /&gt;
        next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # get all answers to this question&lt;br /&gt;
        question_answers = Answer.answers_by_question_for_reviewee_in_round(assignment.id, reviewee.id, q.id, round + 1)&lt;br /&gt;
&lt;br /&gt;
        # get score and summary of answers for each question&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name][round][q.txt] = calculate_avg_score_by_criterion(question_answers, get_max_score_for_question(q))&lt;br /&gt;
&lt;br /&gt;
        # summarize the comments by calling the summarization Web Service&lt;br /&gt;
        # since it'll do a lot of request, do this in seperate threads&lt;br /&gt;
        threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
          self.summary[reviewee.name][round][q.txt] = summarize_sentences(break_up_comments_to_sentences(question_answers), self.summary_ws_url)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      avg_scores_by_round = calculate_avg_score_by_round(self.avg_scores_by_criterion[reviewee.name][round], rubric_questions_used)&lt;br /&gt;
      self.avg_scores_by_round[reviewee.name][round] = avg_scores_by_round&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      end_threads(threads)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    def end_threads(threads)&lt;br /&gt;
      threads.each do |t|&lt;br /&gt;
        # Wait for the thread to finish if it isn't this thread (i.e. the main thread).&lt;br /&gt;
        t.join if t != Thread.current&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewees is reduced from 89.93 to 16.64&lt;br /&gt;
:* Cognitive Complexity is reduced from 17 to 7&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_sentence'''===&lt;br /&gt;
:This method calls web service to store each summary in a hashmap and use the question as the key.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Removed variable ''summary''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_8.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - break_up_comments_to_sentences'''===&lt;br /&gt;
: This method adds the comment to an array to be converted as a json request.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:The method is broken down into 2 smaller methods namely ''break_up_comments_to_sentences'' and ''get_sentences'' where ''get_sentences'' is called by ''break_up_comments_to_sentences'' to  get sentences in desired format.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_9.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact''':&lt;br /&gt;
:*The Cognitive complexity of break_up_comments_to_sentences reduced from 6 to &amp;lt;5&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - get_questions_by_assignment'''===&lt;br /&gt;
:This method returns the rubric for given assignment&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_10.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - calculate_avg_score_by_round'''===&lt;br /&gt;
:This method is used to calculate average round score for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Refactored the method into 2 smaller methods namely ''calculate_avg_score_by_round'' and ''calculate_round_score'' where ''calculate_avg_score_by_round'' calls ''calculate_round_score'' to calculate average round score and ''calculate_avg_score_by_round'' rounds the round_score upto 2 decimal places.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = 0.0&lt;br /&gt;
      sum_weight = 0&lt;br /&gt;
&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = sum_weight = 0.0&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
      round_score&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:*Assignment Branch Condition size for calculate_avg_score_by_round is reduced from 18.57 to &amp;lt;15.&lt;br /&gt;
&lt;br /&gt;
=='''Test Plan'''==&lt;br /&gt;
==='''Manual Testing'''===&lt;br /&gt;
:'''Login Details:''' '''USERNAME:''' instructor6 '''PASSWORD:''' password&lt;br /&gt;
:Click '''Assignment''' &amp;gt;&amp;gt; Click the '''View Submissions''' of '''Madeup problem''' &amp;gt;&amp;gt; Click on any student &amp;gt;&amp;gt; Click on '''Madeup problem''' &amp;gt;&amp;gt; Click on '''Your Scores'''&lt;br /&gt;
:[[File:expertiza2008-1.png]]&lt;br /&gt;
:[[File:expertiza2008-2.png]]&lt;br /&gt;
:[[File:expertiza2008-3.png]]&lt;br /&gt;
:[[File:expertiza2008-4.png]]&lt;br /&gt;
:The 3 main functions of the Summary helper are summarize review by reviewees, summarize review by reviewee and summarize reviews by criterion.&lt;br /&gt;
:To check ''summarize reviews by reviewees'' is working we should get the output similar to the one shown below. This function summarizes all the reviews and displays average score.&lt;br /&gt;
:[[File:expertiza2008-5.png]]&lt;br /&gt;
&lt;br /&gt;
:To check ''summarize reviews by reviewee'' is working, click on any review.&lt;br /&gt;
:[[File:expertiza2008-6a.png]]&lt;br /&gt;
:A new webpage pops up with all the reviews and scores given by an individual.&lt;br /&gt;
:[[File:expertiza2008-6b.png]]&lt;br /&gt;
&lt;br /&gt;
: To check ''summarize reviews by criterion'' is working, click on any criterion. This should display summarized reviews and scores for a particular question in the questionnaire.&lt;br /&gt;
:[[File:expertiza2008-7.png]]&lt;br /&gt;
&lt;br /&gt;
=='''Future improvement'''==&lt;br /&gt;
* Modularize ''summarize_by_rounds'' to even smaller modules so that Assignment Branch Condition size is reduced from 36.73 to 15.00.&lt;br /&gt;
* Create more test cases for the new modularized methods.&lt;br /&gt;
&lt;br /&gt;
=='''Contributors'''==&lt;br /&gt;
* [mailto:jviswan@ncsu.edu Jayalakshmi Viswanathan]&lt;br /&gt;
* [mailto:skundal@ncsu.edu Sandeep Kundala]&lt;br /&gt;
* [mailto:spal3@ncsu.edu Sumitosh Pal]&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132206</id>
		<title>CSC/ECE 517 Spring 2020 - Project E2008. Refactor summary helper.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132206"/>
		<updated>2020-03-30T07:19:26Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* Manual Testing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''About Expertiza'''==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed using Ruby on Rails Framework whose creation and maintenance are taken care of by students as well as the faculty of NCSU. Its code is available on Github [https://github.com/expertiza/expertiza Expertiza on GitHub]. Expertiza allows the instructor to create and edit new as well as existing assignments. This also includes creating a wide range of topics under each assignment that students can sign up for. They can also publish surveys and reviews, view statistical results, set deadlines for assignments and make announcements. It provides a platform for students to signup for topics, form teams, view and submit assignments and give peer reviews and feedback.&lt;br /&gt;
&lt;br /&gt;
=='''Problem Statement'''==&lt;br /&gt;
'''Background:''' In Expertiza students can review each other’s projects and even each other as teammates. Students can view their project scores and instructors can view student's teammate review scores on the view scores page. This helper file aids in calculating these scores and rendering the results on the view scores section of an assignment. Summary helper is a helper module that consists of methods used to calculate scores for these reviews. This is for the use of instructors.&lt;br /&gt;
&lt;br /&gt;
'''Requirement:'''&lt;br /&gt;
E2008 is an Expertiza OSS project which deals basically with refactoring app/helpers/summary_helper.rb to reduce the code climate issues such as&lt;br /&gt;
&lt;br /&gt;
* [http://wiki.c2.com/?AbcMetric Assignment Branch Condition]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Cognitive_complexity Cognitive Complexity]&lt;br /&gt;
* Method/line too long&lt;br /&gt;
* Unused variables / access modifiers&lt;br /&gt;
&lt;br /&gt;
'''A good method should have:'''&lt;br /&gt;
* Assignment Branch Condition size &amp;lt; 15&lt;br /&gt;
* Cognitive Complexity &amp;lt; 6&lt;br /&gt;
* No. of lines in a method &amp;lt; 25&lt;br /&gt;
&lt;br /&gt;
=='''Issues found'''==&lt;br /&gt;
The following are issues which were found in the code:&lt;br /&gt;
&lt;br /&gt;
==='''Assignment Branch Condition'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! ABC Size&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewee&lt;br /&gt;
| 44.61&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 42.34&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 89.93&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 16.43&lt;br /&gt;
|-&lt;br /&gt;
| calculate_avg_score_by_round&lt;br /&gt;
| 18.57&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
==='''Cognitive Complexity'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! Cognitive Complexity&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 16&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 17&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 11&lt;br /&gt;
|-&lt;br /&gt;
| break_up_comments_to_sentences&lt;br /&gt;
| 6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Method/line too long'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method/Line too long&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewees&lt;br /&gt;
|'''Lines of Code:'''39&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_criterion  &lt;br /&gt;
|'''Lines of Code:'''27&lt;br /&gt;
|-&lt;br /&gt;
|'''Line:''' 145&lt;br /&gt;
|self.avg_scores_by_round[reviewee.name][round] too long (162/160)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==='''Unused variables / access modifiers'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Vaiable/Access Modifier&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' summary  &lt;br /&gt;
|'''Method:''' summarize_sentences&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' included_question_counter  &lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewee&lt;br /&gt;
|-&lt;br /&gt;
|'''Access Modifier:''' module_function  &lt;br /&gt;
|'''Class:''' Summary&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=='''Solution Implemented'''==&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewee'''===&lt;br /&gt;
:This method is used to summarize reviews by a reviewer for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:''' &lt;br /&gt;
:This method could be refactored into smaller methods namely ''summarize_reviews_by_reviewee'' and ''summarize_reviews_by_reviewee_assign'' where ''summarize_reviews_by_reviewee'' calls ''summarize_reviews_by_reviewee_assign'' to get average scores and summary for each question.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewee is reduced from 44.61 to 20.64.&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_criterion'''===&lt;br /&gt;
:This method is used to summarize the review for each questions&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 3 smaller methods namely ''summarize_reviews_by_criterion'', ''summarize_reviews_by_criterion_questions'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion'' calls ''summarize_reviews_by_criterion_questions'' to get answers of each question in the rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion_questions'' starts many threads to process each question and closes it by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_3.jpg]]&lt;br /&gt;
:[[File:e2008_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_criterion is reduced from 42.34 to 17.2&lt;br /&gt;
:* Cognitive complexity is reduced from 16 to 7&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewees'''===&lt;br /&gt;
:This method is used to produce summaries for instructor and students. It sums up the feedback by criterion for each reviewer&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 4 smaller methods namely ''summarize_reviews_by_reviewees'', ''summarize_reviews_by_teams'', ''summarize_by_rounds'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_reviewees'' calls ''summarize_reviews_by_teams''  which inturn calls ''summarize_by_rounds'' to get answers of each reviewer by rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_by_rounds'' starts many threads to create requests to summarize the comments and closes the threads by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def summarize_reviews_by_reviewees(assignment, summary_ws_url)&lt;br /&gt;
      # @summary[reviewee][round][question]&lt;br /&gt;
      # @reviewers[team][reviewer]&lt;br /&gt;
      # @avg_scores_by_reviewee[team]&lt;br /&gt;
      # @avg_score_round[reviewee][round]&lt;br /&gt;
      # @avg_scores_by_criterion[reviewee][round][criterion]&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_reviewee = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.reviewers = ({})&lt;br /&gt;
      threads = []&lt;br /&gt;
&lt;br /&gt;
      # get all criteria used in each round&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get all teams in this assignment&lt;br /&gt;
      teams = Team.select(:id, :name).where(parent_id: assignment.id).order(:name)&lt;br /&gt;
&lt;br /&gt;
      teams.each do |reviewee|&lt;br /&gt;
        self.summary[reviewee.name] = []&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = 0.0&lt;br /&gt;
        self.avg_scores_by_round[reviewee.name] = []&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name] = []&lt;br /&gt;
&lt;br /&gt;
        # get the name of reviewers for display only&lt;br /&gt;
        self.reviewers[reviewee.name] = get_reviewers_by_reviewee_and_assignment(reviewee, assignment.id)&lt;br /&gt;
&lt;br /&gt;
        # get answers of each reviewer by rubric&lt;br /&gt;
        (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
          self.summary[reviewee.name][round] = {}&lt;br /&gt;
          self.avg_scores_by_round[reviewee.name][round] = 0.0&lt;br /&gt;
          self.avg_scores_by_criterion[reviewee.name][round] = {}&lt;br /&gt;
&lt;br /&gt;
          # iterate each round and get answers&lt;br /&gt;
          # if use the same rubric, only use rubric[0]&lt;br /&gt;
          rubric_questions_used = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
          rubric_questions_used.each do |q|&lt;br /&gt;
            next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
            summary[reviewee.name][round][q.txt] = &amp;quot;&amp;quot;&lt;br /&gt;
            self.avg_scores_by_criterion[reviewee.name][round][q.txt] = 0.0&lt;br /&gt;
&lt;br /&gt;
            # get all answers to this question&lt;br /&gt;
            question_answers = Answer.answers_by_question_for_reviewee_in_round(assignment.id, reviewee.id, q.id, round + 1)&lt;br /&gt;
            # get max score of this rubric&lt;br /&gt;
            q_max_score = get_max_score_for_question(q)&lt;br /&gt;
&lt;br /&gt;
            comments = break_up_comments_to_sentences(question_answers)&lt;br /&gt;
            # get score and summary of answers for each question&lt;br /&gt;
            self.avg_scores_by_criterion[reviewee.name][round][q.txt] = calculate_avg_score_by_criterion(question_answers, q_max_score)&lt;br /&gt;
&lt;br /&gt;
            # summarize the comments by calling the summarization Web Service&lt;br /&gt;
&lt;br /&gt;
            # since it'll do a lot of request, do this in seperate threads&lt;br /&gt;
            threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
              summary[reviewee.name][round][q.txt] = summarize_sentences(comments, summary_ws_url) unless comments.empty?&lt;br /&gt;
            end&lt;br /&gt;
          end&lt;br /&gt;
          self.avg_scores_by_round[reviewee.name][round] = calculate_avg_score_by_round(self.avg_scores_by_criterion[reviewee.name][round], rubric_questions_used)&lt;br /&gt;
        end&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = calculate_avg_score_by_reviewee(self.avg_scores_by_round[reviewee.name], assignment.rounds_of_reviews)&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      threads.each do |t|&lt;br /&gt;
        t.join if t != Thread.current&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def summarize_reviews_by_reviewees(assignment, summary_ws_url)&lt;br /&gt;
      # @summary[reviewee][round][question]&lt;br /&gt;
      # @reviewers[team][reviewer]&lt;br /&gt;
      # @avg_scores_by_reviewee[team]&lt;br /&gt;
      # @avg_score_round[reviewee][round]&lt;br /&gt;
      # @avg_scores_by_criterion[reviewee][round][criterion]&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_reviewee = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.reviewers = ({})&lt;br /&gt;
      self.summary_ws_url = summary_ws_url&lt;br /&gt;
&lt;br /&gt;
      # get all criteria used in each round&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get all teams in this assignment&lt;br /&gt;
      teams = Team.select(:id, :name).where(parent_id: assignment.id).order(:name)&lt;br /&gt;
&lt;br /&gt;
      teams.each do |reviewee|&lt;br /&gt;
        summarize_reviews_by_team_reviewee(assignment, reviewee, rubric)&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = calculate_avg_score_by_reviewee(self.avg_scores_by_round[reviewee.name], assignment.rounds_of_reviews)&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def summarize_reviews_by_team_reviewee(assignment, reviewee, rubric)&lt;br /&gt;
      self.summary[reviewee.name] = []&lt;br /&gt;
      self.avg_scores_by_reviewee[reviewee.name] = 0.0&lt;br /&gt;
      self.avg_scores_by_round[reviewee.name] = self.avg_scores_by_criterion[reviewee.name] = []&lt;br /&gt;
&lt;br /&gt;
      # get the name of reviewers for display only&lt;br /&gt;
      self.reviewers[reviewee.name] = get_reviewers_by_reviewee_and_assignment(reviewee, assignment.id)&lt;br /&gt;
&lt;br /&gt;
      # get answers of each reviewer by rubric&lt;br /&gt;
      (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
        self.summary[reviewee.name][round] = {}&lt;br /&gt;
        self.avg_scores_by_round[reviewee.name][round] = 0.0&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name][round] = {}&lt;br /&gt;
        summarize_by_reviewee_round(assignment, reviewee, round, rubric)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def summarize_by_reviewee_round(assignment, reviewee, round, rubric)&lt;br /&gt;
      threads = []&lt;br /&gt;
      # iterate each round and get answers&lt;br /&gt;
      # if use the same rubric, only use rubric[0]&lt;br /&gt;
      rubric_questions_used = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
      rubric_questions_used.each do |q|&lt;br /&gt;
        next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # get all answers to this question&lt;br /&gt;
        question_answers = Answer.answers_by_question_for_reviewee_in_round(assignment.id, reviewee.id, q.id, round + 1)&lt;br /&gt;
&lt;br /&gt;
        # get score and summary of answers for each question&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name][round][q.txt] = calculate_avg_score_by_criterion(question_answers, get_max_score_for_question(q))&lt;br /&gt;
&lt;br /&gt;
        # summarize the comments by calling the summarization Web Service&lt;br /&gt;
        # since it'll do a lot of request, do this in seperate threads&lt;br /&gt;
        threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
          self.summary[reviewee.name][round][q.txt] = summarize_sentences(break_up_comments_to_sentences(question_answers), self.summary_ws_url)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      avg_scores_by_round = calculate_avg_score_by_round(self.avg_scores_by_criterion[reviewee.name][round], rubric_questions_used)&lt;br /&gt;
      self.avg_scores_by_round[reviewee.name][round] = avg_scores_by_round&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      end_threads(threads)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    def end_threads(threads)&lt;br /&gt;
      threads.each do |t|&lt;br /&gt;
        # Wait for the thread to finish if it isn't this thread (i.e. the main thread).&lt;br /&gt;
        t.join if t != Thread.current&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewees is reduced from 89.93 to 16.64&lt;br /&gt;
:* Cognitive Complexity is reduced from 17 to 7&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_sentence'''===&lt;br /&gt;
:This method calls web service to store each summary in a hashmap and use the question as the key.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Removed variable ''summary''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_8.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - break_up_comments_to_sentences'''===&lt;br /&gt;
: This method adds the comment to an array to be converted as a json request.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:The method is broken down into 2 smaller methods namely ''break_up_comments_to_sentences'' and ''get_sentences'' where ''get_sentences'' is called by ''break_up_comments_to_sentences'' to  get sentences in desired format.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_9.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact''':&lt;br /&gt;
:*The Cognitive complexity of break_up_comments_to_sentences reduced from 6 to &amp;lt;5&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - get_questions_by_assignment'''===&lt;br /&gt;
:This method returns the rubric for given assignment&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_10.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - calculate_avg_score_by_round'''===&lt;br /&gt;
:This method is used to calculate average round score for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Refactored the method into 2 smaller methods namely ''calculate_avg_score_by_round'' and ''calculate_round_score'' where ''calculate_avg_score_by_round'' calls ''calculate_round_score'' to calculate average round score and ''calculate_avg_score_by_round'' rounds the round_score upto 2 decimal places.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = 0.0&lt;br /&gt;
      sum_weight = 0&lt;br /&gt;
&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = sum_weight = 0.0&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
      round_score&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:*Assignment Branch Condition size for calculate_avg_score_by_round is reduced from 18.57 to &amp;lt;15.&lt;br /&gt;
&lt;br /&gt;
=='''Test Plan'''==&lt;br /&gt;
==='''Manual Testing'''===&lt;br /&gt;
:'''Login Details:''' '''USERNAME:''' instructor6 '''PASSWORD:''' password&lt;br /&gt;
:Click '''Assignment''' &amp;gt;&amp;gt; Click the '''View Submissions''' of '''Madeup problem''' &amp;gt;&amp;gt; Click on any student &amp;gt;&amp;gt; Click on '''Madeup problem''' &amp;gt;&amp;gt; Click on '''Your Scores'''&lt;br /&gt;
:[[File:expertiza2008-1.png]]&lt;br /&gt;
:[[File:expertiza2008-2.png]]&lt;br /&gt;
:[[File:expertiza2008-3.png]]&lt;br /&gt;
:[[File:expertiza2008-4.png]]&lt;br /&gt;
:The 3 main functions of the Summary helper are summarize review by reviewees, summarize review by reviewee and summarize reviews by criterion.&lt;br /&gt;
:To check ''summarize reviews by reviewees'' is working we should get the output similar to the one shown below. This function summarizes all the reviews and displays average score.&lt;br /&gt;
:[[File:expertiza2008-5.png]]&lt;br /&gt;
&lt;br /&gt;
:To check ''summarize reviews by reviewee'' is working, click on any review.&lt;br /&gt;
:[[File:expertiza2008-6a.png]]&lt;br /&gt;
:A new webpage pops up with all the reviews and scores given by an individual.&lt;br /&gt;
:[[File:expertiza2008-6b.png]]&lt;br /&gt;
&lt;br /&gt;
: To check ''summarize reviews by criterion'' is working, click on any criterion. This should display summarized reviews and scores for a particular question in the questionnaire.&lt;br /&gt;
:[[File:expertiza2008-7.png]]&lt;br /&gt;
&lt;br /&gt;
=='''Future improvement'''==&lt;br /&gt;
* Modularize ''summarize_by_rounds'' to even smaller modules so that Assignment Branch Condition size is reduced from 36.73 to 15.00.&lt;br /&gt;
* Create more test cases for the new modularized methods.&lt;br /&gt;
&lt;br /&gt;
=='''Contributors'''==&lt;br /&gt;
* [mailto:jviswan@ncsu.edu Jayalakshmi Viswanathan]&lt;br /&gt;
* [mailto:skundal@ncsu.edu Sandeep Kundala]&lt;br /&gt;
* [mailto:spal3@ncsu.edu Sumitosh Pal]&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132205</id>
		<title>CSC/ECE 517 Spring 2020 - Project E2008. Refactor summary helper.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132205"/>
		<updated>2020-03-30T07:18:57Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* Manual Testing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''About Expertiza'''==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed using Ruby on Rails Framework whose creation and maintenance are taken care of by students as well as the faculty of NCSU. Its code is available on Github [https://github.com/expertiza/expertiza Expertiza on GitHub]. Expertiza allows the instructor to create and edit new as well as existing assignments. This also includes creating a wide range of topics under each assignment that students can sign up for. They can also publish surveys and reviews, view statistical results, set deadlines for assignments and make announcements. It provides a platform for students to signup for topics, form teams, view and submit assignments and give peer reviews and feedback.&lt;br /&gt;
&lt;br /&gt;
=='''Problem Statement'''==&lt;br /&gt;
'''Background:''' In Expertiza students can review each other’s projects and even each other as teammates. Students can view their project scores and instructors can view student's teammate review scores on the view scores page. This helper file aids in calculating these scores and rendering the results on the view scores section of an assignment. Summary helper is a helper module that consists of methods used to calculate scores for these reviews. This is for the use of instructors.&lt;br /&gt;
&lt;br /&gt;
'''Requirement:'''&lt;br /&gt;
E2008 is an Expertiza OSS project which deals basically with refactoring app/helpers/summary_helper.rb to reduce the code climate issues such as&lt;br /&gt;
&lt;br /&gt;
* [http://wiki.c2.com/?AbcMetric Assignment Branch Condition]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Cognitive_complexity Cognitive Complexity]&lt;br /&gt;
* Method/line too long&lt;br /&gt;
* Unused variables / access modifiers&lt;br /&gt;
&lt;br /&gt;
'''A good method should have:'''&lt;br /&gt;
* Assignment Branch Condition size &amp;lt; 15&lt;br /&gt;
* Cognitive Complexity &amp;lt; 6&lt;br /&gt;
* No. of lines in a method &amp;lt; 25&lt;br /&gt;
&lt;br /&gt;
=='''Issues found'''==&lt;br /&gt;
The following are issues which were found in the code:&lt;br /&gt;
&lt;br /&gt;
==='''Assignment Branch Condition'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! ABC Size&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewee&lt;br /&gt;
| 44.61&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 42.34&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 89.93&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 16.43&lt;br /&gt;
|-&lt;br /&gt;
| calculate_avg_score_by_round&lt;br /&gt;
| 18.57&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
==='''Cognitive Complexity'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! Cognitive Complexity&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 16&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 17&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 11&lt;br /&gt;
|-&lt;br /&gt;
| break_up_comments_to_sentences&lt;br /&gt;
| 6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Method/line too long'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method/Line too long&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewees&lt;br /&gt;
|'''Lines of Code:'''39&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_criterion  &lt;br /&gt;
|'''Lines of Code:'''27&lt;br /&gt;
|-&lt;br /&gt;
|'''Line:''' 145&lt;br /&gt;
|self.avg_scores_by_round[reviewee.name][round] too long (162/160)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==='''Unused variables / access modifiers'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Vaiable/Access Modifier&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' summary  &lt;br /&gt;
|'''Method:''' summarize_sentences&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' included_question_counter  &lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewee&lt;br /&gt;
|-&lt;br /&gt;
|'''Access Modifier:''' module_function  &lt;br /&gt;
|'''Class:''' Summary&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=='''Solution Implemented'''==&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewee'''===&lt;br /&gt;
:This method is used to summarize reviews by a reviewer for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:''' &lt;br /&gt;
:This method could be refactored into smaller methods namely ''summarize_reviews_by_reviewee'' and ''summarize_reviews_by_reviewee_assign'' where ''summarize_reviews_by_reviewee'' calls ''summarize_reviews_by_reviewee_assign'' to get average scores and summary for each question.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewee is reduced from 44.61 to 20.64.&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_criterion'''===&lt;br /&gt;
:This method is used to summarize the review for each questions&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 3 smaller methods namely ''summarize_reviews_by_criterion'', ''summarize_reviews_by_criterion_questions'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion'' calls ''summarize_reviews_by_criterion_questions'' to get answers of each question in the rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion_questions'' starts many threads to process each question and closes it by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_3.jpg]]&lt;br /&gt;
:[[File:e2008_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_criterion is reduced from 42.34 to 17.2&lt;br /&gt;
:* Cognitive complexity is reduced from 16 to 7&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewees'''===&lt;br /&gt;
:This method is used to produce summaries for instructor and students. It sums up the feedback by criterion for each reviewer&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 4 smaller methods namely ''summarize_reviews_by_reviewees'', ''summarize_reviews_by_teams'', ''summarize_by_rounds'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_reviewees'' calls ''summarize_reviews_by_teams''  which inturn calls ''summarize_by_rounds'' to get answers of each reviewer by rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_by_rounds'' starts many threads to create requests to summarize the comments and closes the threads by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def summarize_reviews_by_reviewees(assignment, summary_ws_url)&lt;br /&gt;
      # @summary[reviewee][round][question]&lt;br /&gt;
      # @reviewers[team][reviewer]&lt;br /&gt;
      # @avg_scores_by_reviewee[team]&lt;br /&gt;
      # @avg_score_round[reviewee][round]&lt;br /&gt;
      # @avg_scores_by_criterion[reviewee][round][criterion]&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_reviewee = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.reviewers = ({})&lt;br /&gt;
      threads = []&lt;br /&gt;
&lt;br /&gt;
      # get all criteria used in each round&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get all teams in this assignment&lt;br /&gt;
      teams = Team.select(:id, :name).where(parent_id: assignment.id).order(:name)&lt;br /&gt;
&lt;br /&gt;
      teams.each do |reviewee|&lt;br /&gt;
        self.summary[reviewee.name] = []&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = 0.0&lt;br /&gt;
        self.avg_scores_by_round[reviewee.name] = []&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name] = []&lt;br /&gt;
&lt;br /&gt;
        # get the name of reviewers for display only&lt;br /&gt;
        self.reviewers[reviewee.name] = get_reviewers_by_reviewee_and_assignment(reviewee, assignment.id)&lt;br /&gt;
&lt;br /&gt;
        # get answers of each reviewer by rubric&lt;br /&gt;
        (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
          self.summary[reviewee.name][round] = {}&lt;br /&gt;
          self.avg_scores_by_round[reviewee.name][round] = 0.0&lt;br /&gt;
          self.avg_scores_by_criterion[reviewee.name][round] = {}&lt;br /&gt;
&lt;br /&gt;
          # iterate each round and get answers&lt;br /&gt;
          # if use the same rubric, only use rubric[0]&lt;br /&gt;
          rubric_questions_used = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
          rubric_questions_used.each do |q|&lt;br /&gt;
            next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
            summary[reviewee.name][round][q.txt] = &amp;quot;&amp;quot;&lt;br /&gt;
            self.avg_scores_by_criterion[reviewee.name][round][q.txt] = 0.0&lt;br /&gt;
&lt;br /&gt;
            # get all answers to this question&lt;br /&gt;
            question_answers = Answer.answers_by_question_for_reviewee_in_round(assignment.id, reviewee.id, q.id, round + 1)&lt;br /&gt;
            # get max score of this rubric&lt;br /&gt;
            q_max_score = get_max_score_for_question(q)&lt;br /&gt;
&lt;br /&gt;
            comments = break_up_comments_to_sentences(question_answers)&lt;br /&gt;
            # get score and summary of answers for each question&lt;br /&gt;
            self.avg_scores_by_criterion[reviewee.name][round][q.txt] = calculate_avg_score_by_criterion(question_answers, q_max_score)&lt;br /&gt;
&lt;br /&gt;
            # summarize the comments by calling the summarization Web Service&lt;br /&gt;
&lt;br /&gt;
            # since it'll do a lot of request, do this in seperate threads&lt;br /&gt;
            threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
              summary[reviewee.name][round][q.txt] = summarize_sentences(comments, summary_ws_url) unless comments.empty?&lt;br /&gt;
            end&lt;br /&gt;
          end&lt;br /&gt;
          self.avg_scores_by_round[reviewee.name][round] = calculate_avg_score_by_round(self.avg_scores_by_criterion[reviewee.name][round], rubric_questions_used)&lt;br /&gt;
        end&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = calculate_avg_score_by_reviewee(self.avg_scores_by_round[reviewee.name], assignment.rounds_of_reviews)&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      threads.each do |t|&lt;br /&gt;
        t.join if t != Thread.current&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def summarize_reviews_by_reviewees(assignment, summary_ws_url)&lt;br /&gt;
      # @summary[reviewee][round][question]&lt;br /&gt;
      # @reviewers[team][reviewer]&lt;br /&gt;
      # @avg_scores_by_reviewee[team]&lt;br /&gt;
      # @avg_score_round[reviewee][round]&lt;br /&gt;
      # @avg_scores_by_criterion[reviewee][round][criterion]&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_reviewee = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.reviewers = ({})&lt;br /&gt;
      self.summary_ws_url = summary_ws_url&lt;br /&gt;
&lt;br /&gt;
      # get all criteria used in each round&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get all teams in this assignment&lt;br /&gt;
      teams = Team.select(:id, :name).where(parent_id: assignment.id).order(:name)&lt;br /&gt;
&lt;br /&gt;
      teams.each do |reviewee|&lt;br /&gt;
        summarize_reviews_by_team_reviewee(assignment, reviewee, rubric)&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = calculate_avg_score_by_reviewee(self.avg_scores_by_round[reviewee.name], assignment.rounds_of_reviews)&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def summarize_reviews_by_team_reviewee(assignment, reviewee, rubric)&lt;br /&gt;
      self.summary[reviewee.name] = []&lt;br /&gt;
      self.avg_scores_by_reviewee[reviewee.name] = 0.0&lt;br /&gt;
      self.avg_scores_by_round[reviewee.name] = self.avg_scores_by_criterion[reviewee.name] = []&lt;br /&gt;
&lt;br /&gt;
      # get the name of reviewers for display only&lt;br /&gt;
      self.reviewers[reviewee.name] = get_reviewers_by_reviewee_and_assignment(reviewee, assignment.id)&lt;br /&gt;
&lt;br /&gt;
      # get answers of each reviewer by rubric&lt;br /&gt;
      (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
        self.summary[reviewee.name][round] = {}&lt;br /&gt;
        self.avg_scores_by_round[reviewee.name][round] = 0.0&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name][round] = {}&lt;br /&gt;
        summarize_by_reviewee_round(assignment, reviewee, round, rubric)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def summarize_by_reviewee_round(assignment, reviewee, round, rubric)&lt;br /&gt;
      threads = []&lt;br /&gt;
      # iterate each round and get answers&lt;br /&gt;
      # if use the same rubric, only use rubric[0]&lt;br /&gt;
      rubric_questions_used = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
      rubric_questions_used.each do |q|&lt;br /&gt;
        next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # get all answers to this question&lt;br /&gt;
        question_answers = Answer.answers_by_question_for_reviewee_in_round(assignment.id, reviewee.id, q.id, round + 1)&lt;br /&gt;
&lt;br /&gt;
        # get score and summary of answers for each question&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name][round][q.txt] = calculate_avg_score_by_criterion(question_answers, get_max_score_for_question(q))&lt;br /&gt;
&lt;br /&gt;
        # summarize the comments by calling the summarization Web Service&lt;br /&gt;
        # since it'll do a lot of request, do this in seperate threads&lt;br /&gt;
        threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
          self.summary[reviewee.name][round][q.txt] = summarize_sentences(break_up_comments_to_sentences(question_answers), self.summary_ws_url)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      avg_scores_by_round = calculate_avg_score_by_round(self.avg_scores_by_criterion[reviewee.name][round], rubric_questions_used)&lt;br /&gt;
      self.avg_scores_by_round[reviewee.name][round] = avg_scores_by_round&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      end_threads(threads)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    def end_threads(threads)&lt;br /&gt;
      threads.each do |t|&lt;br /&gt;
        # Wait for the thread to finish if it isn't this thread (i.e. the main thread).&lt;br /&gt;
        t.join if t != Thread.current&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewees is reduced from 89.93 to 16.64&lt;br /&gt;
:* Cognitive Complexity is reduced from 17 to 7&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_sentence'''===&lt;br /&gt;
:This method calls web service to store each summary in a hashmap and use the question as the key.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Removed variable ''summary''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_8.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - break_up_comments_to_sentences'''===&lt;br /&gt;
: This method adds the comment to an array to be converted as a json request.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:The method is broken down into 2 smaller methods namely ''break_up_comments_to_sentences'' and ''get_sentences'' where ''get_sentences'' is called by ''break_up_comments_to_sentences'' to  get sentences in desired format.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_9.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact''':&lt;br /&gt;
:*The Cognitive complexity of break_up_comments_to_sentences reduced from 6 to &amp;lt;5&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - get_questions_by_assignment'''===&lt;br /&gt;
:This method returns the rubric for given assignment&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_10.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - calculate_avg_score_by_round'''===&lt;br /&gt;
:This method is used to calculate average round score for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Refactored the method into 2 smaller methods namely ''calculate_avg_score_by_round'' and ''calculate_round_score'' where ''calculate_avg_score_by_round'' calls ''calculate_round_score'' to calculate average round score and ''calculate_avg_score_by_round'' rounds the round_score upto 2 decimal places.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = 0.0&lt;br /&gt;
      sum_weight = 0&lt;br /&gt;
&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = sum_weight = 0.0&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
      round_score&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:*Assignment Branch Condition size for calculate_avg_score_by_round is reduced from 18.57 to &amp;lt;15.&lt;br /&gt;
&lt;br /&gt;
=='''Test Plan'''==&lt;br /&gt;
==='''Manual Testing'''===&lt;br /&gt;
:'''Login Details:''' '''USERNAME:''' instructor6 '''PASSWORD:''' password&lt;br /&gt;
:Click '''Assignment''' &amp;gt;&amp;gt; Click the '''View Submissions''' of '''Madeup problem''' &amp;gt;&amp;gt; Click on any student &amp;gt;&amp;gt; Click on '''Madeup problem''' &amp;gt;&amp;gt; Click on '''Your Scores'''&lt;br /&gt;
:[[File:expertiza2008-1.png]]&lt;br /&gt;
:[[File:expertiza2008-2.png]]&lt;br /&gt;
:[[File:expertiza2008-3.png]]&lt;br /&gt;
:[[File:expertiza2008-4.png]]&lt;br /&gt;
:The 3 main functions of the Summary helper are summarize review by reviewees, summarize review by reviewee and summarize reviews by criterion.&lt;br /&gt;
:To check ''summarize reviews by reviewees'' is working we should get the output similar to the one shown below. This function summarizes all the reviews and displays average score.&lt;br /&gt;
:[[File:expertiza2008-5.png]]&lt;br /&gt;
&lt;br /&gt;
:To check ''summarize reviews by reviewee'' is working, click on any review.&lt;br /&gt;
:[[File:expertiza2008-6a.png]]&lt;br /&gt;
:A new webpage pops up with all the reviews and scores given by an individual.&lt;br /&gt;
:[[File:expertiza2008-6b.jpg]]&lt;br /&gt;
&lt;br /&gt;
: To check ''summarize reviews by criterion'' is working, click on any criterion. This should display summarized reviews and scores for a particular question in the questionnaire.&lt;br /&gt;
:[[File:expertiza2008-7.png]]&lt;br /&gt;
&lt;br /&gt;
=='''Future improvement'''==&lt;br /&gt;
* Modularize ''summarize_by_rounds'' to even smaller modules so that Assignment Branch Condition size is reduced from 36.73 to 15.00.&lt;br /&gt;
* Create more test cases for the new modularized methods.&lt;br /&gt;
&lt;br /&gt;
=='''Contributors'''==&lt;br /&gt;
* [mailto:jviswan@ncsu.edu Jayalakshmi Viswanathan]&lt;br /&gt;
* [mailto:skundal@ncsu.edu Sandeep Kundala]&lt;br /&gt;
* [mailto:spal3@ncsu.edu Sumitosh Pal]&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Expertiza2008-1.png&amp;diff=132204</id>
		<title>File:Expertiza2008-1.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Expertiza2008-1.png&amp;diff=132204"/>
		<updated>2020-03-30T07:00:37Z</updated>

		<summary type="html">&lt;p&gt;Skundal: Skundal uploaded a new version of File:Expertiza2008-1.png&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Expertiza2008-7.png&amp;diff=132203</id>
		<title>File:Expertiza2008-7.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Expertiza2008-7.png&amp;diff=132203"/>
		<updated>2020-03-30T06:59:41Z</updated>

		<summary type="html">&lt;p&gt;Skundal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Expertiza2008-6b.png&amp;diff=132202</id>
		<title>File:Expertiza2008-6b.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Expertiza2008-6b.png&amp;diff=132202"/>
		<updated>2020-03-30T06:59:33Z</updated>

		<summary type="html">&lt;p&gt;Skundal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Expertiza2008-6a.png&amp;diff=132201</id>
		<title>File:Expertiza2008-6a.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Expertiza2008-6a.png&amp;diff=132201"/>
		<updated>2020-03-30T06:59:25Z</updated>

		<summary type="html">&lt;p&gt;Skundal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Expertiza2008-5.png&amp;diff=132200</id>
		<title>File:Expertiza2008-5.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Expertiza2008-5.png&amp;diff=132200"/>
		<updated>2020-03-30T06:59:19Z</updated>

		<summary type="html">&lt;p&gt;Skundal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Expertiza2008-4.png&amp;diff=132199</id>
		<title>File:Expertiza2008-4.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Expertiza2008-4.png&amp;diff=132199"/>
		<updated>2020-03-30T06:59:09Z</updated>

		<summary type="html">&lt;p&gt;Skundal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Expertiza2008-3.png&amp;diff=132198</id>
		<title>File:Expertiza2008-3.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Expertiza2008-3.png&amp;diff=132198"/>
		<updated>2020-03-30T06:58:58Z</updated>

		<summary type="html">&lt;p&gt;Skundal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Expertiza2008-2.png&amp;diff=132197</id>
		<title>File:Expertiza2008-2.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Expertiza2008-2.png&amp;diff=132197"/>
		<updated>2020-03-30T06:58:51Z</updated>

		<summary type="html">&lt;p&gt;Skundal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Expertiza2008-1.png&amp;diff=132196</id>
		<title>File:Expertiza2008-1.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Expertiza2008-1.png&amp;diff=132196"/>
		<updated>2020-03-30T06:58:06Z</updated>

		<summary type="html">&lt;p&gt;Skundal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132195</id>
		<title>CSC/ECE 517 Spring 2020 - Project E2008. Refactor summary helper.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132195"/>
		<updated>2020-03-30T06:57:32Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* Manual Testing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''About Expertiza'''==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed using Ruby on Rails Framework whose creation and maintenance are taken care of by students as well as the faculty of NCSU. Its code is available on Github [https://github.com/expertiza/expertiza Expertiza on GitHub]. Expertiza allows the instructor to create and edit new as well as existing assignments. This also includes creating a wide range of topics under each assignment that students can sign up for. They can also publish surveys and reviews, view statistical results, set deadlines for assignments and make announcements. It provides a platform for students to signup for topics, form teams, view and submit assignments and give peer reviews and feedback.&lt;br /&gt;
&lt;br /&gt;
=='''Problem Statement'''==&lt;br /&gt;
'''Background:''' In Expertiza students can review each other’s projects and even each other as teammates. Students can view their project scores and instructors can view student's teammate review scores on the view scores page. This helper file aids in calculating these scores and rendering the results on the view scores section of an assignment. Summary helper is a helper module that consists of methods used to calculate scores for these reviews. This is for the use of instructors.&lt;br /&gt;
&lt;br /&gt;
'''Requirement:'''&lt;br /&gt;
E2008 is an Expertiza OSS project which deals basically with refactoring app/helpers/summary_helper.rb to reduce the code climate issues such as&lt;br /&gt;
&lt;br /&gt;
* [http://wiki.c2.com/?AbcMetric Assignment Branch Condition]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Cognitive_complexity Cognitive Complexity]&lt;br /&gt;
* Method/line too long&lt;br /&gt;
* Unused variables / access modifiers&lt;br /&gt;
&lt;br /&gt;
'''A good method should have:'''&lt;br /&gt;
* Assignment Branch Condition size &amp;lt; 15&lt;br /&gt;
* Cognitive Complexity &amp;lt; 6&lt;br /&gt;
* No. of lines in a method &amp;lt; 25&lt;br /&gt;
&lt;br /&gt;
=='''Issues found'''==&lt;br /&gt;
The following are issues which were found in the code:&lt;br /&gt;
&lt;br /&gt;
==='''Assignment Branch Condition'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! ABC Size&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewee&lt;br /&gt;
| 44.61&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 42.34&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 89.93&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 16.43&lt;br /&gt;
|-&lt;br /&gt;
| calculate_avg_score_by_round&lt;br /&gt;
| 18.57&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
==='''Cognitive Complexity'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! Cognitive Complexity&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 16&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 17&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 11&lt;br /&gt;
|-&lt;br /&gt;
| break_up_comments_to_sentences&lt;br /&gt;
| 6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Method/line too long'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method/Line too long&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewees&lt;br /&gt;
|'''Lines of Code:'''39&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_criterion  &lt;br /&gt;
|'''Lines of Code:'''27&lt;br /&gt;
|-&lt;br /&gt;
|'''Line:''' 145&lt;br /&gt;
|self.avg_scores_by_round[reviewee.name][round] too long (162/160)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==='''Unused variables / access modifiers'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Vaiable/Access Modifier&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' summary  &lt;br /&gt;
|'''Method:''' summarize_sentences&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' included_question_counter  &lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewee&lt;br /&gt;
|-&lt;br /&gt;
|'''Access Modifier:''' module_function  &lt;br /&gt;
|'''Class:''' Summary&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=='''Solution Implemented'''==&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewee'''===&lt;br /&gt;
:This method is used to summarize reviews by a reviewer for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:''' &lt;br /&gt;
:This method could be refactored into smaller methods namely ''summarize_reviews_by_reviewee'' and ''summarize_reviews_by_reviewee_assign'' where ''summarize_reviews_by_reviewee'' calls ''summarize_reviews_by_reviewee_assign'' to get average scores and summary for each question.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewee is reduced from 44.61 to 20.64.&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_criterion'''===&lt;br /&gt;
:This method is used to summarize the review for each questions&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 3 smaller methods namely ''summarize_reviews_by_criterion'', ''summarize_reviews_by_criterion_questions'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion'' calls ''summarize_reviews_by_criterion_questions'' to get answers of each question in the rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion_questions'' starts many threads to process each question and closes it by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_3.jpg]]&lt;br /&gt;
:[[File:e2008_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_criterion is reduced from 42.34 to 17.2&lt;br /&gt;
:* Cognitive complexity is reduced from 16 to 7&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewees'''===&lt;br /&gt;
:This method is used to produce summaries for instructor and students. It sums up the feedback by criterion for each reviewer&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 4 smaller methods namely ''summarize_reviews_by_reviewees'', ''summarize_reviews_by_teams'', ''summarize_by_rounds'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_reviewees'' calls ''summarize_reviews_by_teams''  which inturn calls ''summarize_by_rounds'' to get answers of each reviewer by rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_by_rounds'' starts many threads to create requests to summarize the comments and closes the threads by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def summarize_reviews_by_reviewees(assignment, summary_ws_url)&lt;br /&gt;
      # @summary[reviewee][round][question]&lt;br /&gt;
      # @reviewers[team][reviewer]&lt;br /&gt;
      # @avg_scores_by_reviewee[team]&lt;br /&gt;
      # @avg_score_round[reviewee][round]&lt;br /&gt;
      # @avg_scores_by_criterion[reviewee][round][criterion]&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_reviewee = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.reviewers = ({})&lt;br /&gt;
      threads = []&lt;br /&gt;
&lt;br /&gt;
      # get all criteria used in each round&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get all teams in this assignment&lt;br /&gt;
      teams = Team.select(:id, :name).where(parent_id: assignment.id).order(:name)&lt;br /&gt;
&lt;br /&gt;
      teams.each do |reviewee|&lt;br /&gt;
        self.summary[reviewee.name] = []&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = 0.0&lt;br /&gt;
        self.avg_scores_by_round[reviewee.name] = []&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name] = []&lt;br /&gt;
&lt;br /&gt;
        # get the name of reviewers for display only&lt;br /&gt;
        self.reviewers[reviewee.name] = get_reviewers_by_reviewee_and_assignment(reviewee, assignment.id)&lt;br /&gt;
&lt;br /&gt;
        # get answers of each reviewer by rubric&lt;br /&gt;
        (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
          self.summary[reviewee.name][round] = {}&lt;br /&gt;
          self.avg_scores_by_round[reviewee.name][round] = 0.0&lt;br /&gt;
          self.avg_scores_by_criterion[reviewee.name][round] = {}&lt;br /&gt;
&lt;br /&gt;
          # iterate each round and get answers&lt;br /&gt;
          # if use the same rubric, only use rubric[0]&lt;br /&gt;
          rubric_questions_used = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
          rubric_questions_used.each do |q|&lt;br /&gt;
            next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
            summary[reviewee.name][round][q.txt] = &amp;quot;&amp;quot;&lt;br /&gt;
            self.avg_scores_by_criterion[reviewee.name][round][q.txt] = 0.0&lt;br /&gt;
&lt;br /&gt;
            # get all answers to this question&lt;br /&gt;
            question_answers = Answer.answers_by_question_for_reviewee_in_round(assignment.id, reviewee.id, q.id, round + 1)&lt;br /&gt;
            # get max score of this rubric&lt;br /&gt;
            q_max_score = get_max_score_for_question(q)&lt;br /&gt;
&lt;br /&gt;
            comments = break_up_comments_to_sentences(question_answers)&lt;br /&gt;
            # get score and summary of answers for each question&lt;br /&gt;
            self.avg_scores_by_criterion[reviewee.name][round][q.txt] = calculate_avg_score_by_criterion(question_answers, q_max_score)&lt;br /&gt;
&lt;br /&gt;
            # summarize the comments by calling the summarization Web Service&lt;br /&gt;
&lt;br /&gt;
            # since it'll do a lot of request, do this in seperate threads&lt;br /&gt;
            threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
              summary[reviewee.name][round][q.txt] = summarize_sentences(comments, summary_ws_url) unless comments.empty?&lt;br /&gt;
            end&lt;br /&gt;
          end&lt;br /&gt;
          self.avg_scores_by_round[reviewee.name][round] = calculate_avg_score_by_round(self.avg_scores_by_criterion[reviewee.name][round], rubric_questions_used)&lt;br /&gt;
        end&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = calculate_avg_score_by_reviewee(self.avg_scores_by_round[reviewee.name], assignment.rounds_of_reviews)&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      threads.each do |t|&lt;br /&gt;
        t.join if t != Thread.current&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def summarize_reviews_by_reviewees(assignment, summary_ws_url)&lt;br /&gt;
      # @summary[reviewee][round][question]&lt;br /&gt;
      # @reviewers[team][reviewer]&lt;br /&gt;
      # @avg_scores_by_reviewee[team]&lt;br /&gt;
      # @avg_score_round[reviewee][round]&lt;br /&gt;
      # @avg_scores_by_criterion[reviewee][round][criterion]&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_reviewee = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.reviewers = ({})&lt;br /&gt;
      self.summary_ws_url = summary_ws_url&lt;br /&gt;
&lt;br /&gt;
      # get all criteria used in each round&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get all teams in this assignment&lt;br /&gt;
      teams = Team.select(:id, :name).where(parent_id: assignment.id).order(:name)&lt;br /&gt;
&lt;br /&gt;
      teams.each do |reviewee|&lt;br /&gt;
        summarize_reviews_by_team_reviewee(assignment, reviewee, rubric)&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = calculate_avg_score_by_reviewee(self.avg_scores_by_round[reviewee.name], assignment.rounds_of_reviews)&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def summarize_reviews_by_team_reviewee(assignment, reviewee, rubric)&lt;br /&gt;
      self.summary[reviewee.name] = []&lt;br /&gt;
      self.avg_scores_by_reviewee[reviewee.name] = 0.0&lt;br /&gt;
      self.avg_scores_by_round[reviewee.name] = self.avg_scores_by_criterion[reviewee.name] = []&lt;br /&gt;
&lt;br /&gt;
      # get the name of reviewers for display only&lt;br /&gt;
      self.reviewers[reviewee.name] = get_reviewers_by_reviewee_and_assignment(reviewee, assignment.id)&lt;br /&gt;
&lt;br /&gt;
      # get answers of each reviewer by rubric&lt;br /&gt;
      (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
        self.summary[reviewee.name][round] = {}&lt;br /&gt;
        self.avg_scores_by_round[reviewee.name][round] = 0.0&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name][round] = {}&lt;br /&gt;
        summarize_by_reviewee_round(assignment, reviewee, round, rubric)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def summarize_by_reviewee_round(assignment, reviewee, round, rubric)&lt;br /&gt;
      threads = []&lt;br /&gt;
      # iterate each round and get answers&lt;br /&gt;
      # if use the same rubric, only use rubric[0]&lt;br /&gt;
      rubric_questions_used = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
      rubric_questions_used.each do |q|&lt;br /&gt;
        next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # get all answers to this question&lt;br /&gt;
        question_answers = Answer.answers_by_question_for_reviewee_in_round(assignment.id, reviewee.id, q.id, round + 1)&lt;br /&gt;
&lt;br /&gt;
        # get score and summary of answers for each question&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name][round][q.txt] = calculate_avg_score_by_criterion(question_answers, get_max_score_for_question(q))&lt;br /&gt;
&lt;br /&gt;
        # summarize the comments by calling the summarization Web Service&lt;br /&gt;
        # since it'll do a lot of request, do this in seperate threads&lt;br /&gt;
        threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
          self.summary[reviewee.name][round][q.txt] = summarize_sentences(break_up_comments_to_sentences(question_answers), self.summary_ws_url)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      avg_scores_by_round = calculate_avg_score_by_round(self.avg_scores_by_criterion[reviewee.name][round], rubric_questions_used)&lt;br /&gt;
      self.avg_scores_by_round[reviewee.name][round] = avg_scores_by_round&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      end_threads(threads)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    def end_threads(threads)&lt;br /&gt;
      threads.each do |t|&lt;br /&gt;
        # Wait for the thread to finish if it isn't this thread (i.e. the main thread).&lt;br /&gt;
        t.join if t != Thread.current&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewees is reduced from 89.93 to 16.64&lt;br /&gt;
:* Cognitive Complexity is reduced from 17 to 7&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_sentence'''===&lt;br /&gt;
:This method calls web service to store each summary in a hashmap and use the question as the key.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Removed variable ''summary''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_8.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - break_up_comments_to_sentences'''===&lt;br /&gt;
: This method adds the comment to an array to be converted as a json request.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:The method is broken down into 2 smaller methods namely ''break_up_comments_to_sentences'' and ''get_sentences'' where ''get_sentences'' is called by ''break_up_comments_to_sentences'' to  get sentences in desired format.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_9.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact''':&lt;br /&gt;
:*The Cognitive complexity of break_up_comments_to_sentences reduced from 6 to &amp;lt;5&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - get_questions_by_assignment'''===&lt;br /&gt;
:This method returns the rubric for given assignment&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_10.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - calculate_avg_score_by_round'''===&lt;br /&gt;
:This method is used to calculate average round score for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Refactored the method into 2 smaller methods namely ''calculate_avg_score_by_round'' and ''calculate_round_score'' where ''calculate_avg_score_by_round'' calls ''calculate_round_score'' to calculate average round score and ''calculate_avg_score_by_round'' rounds the round_score upto 2 decimal places.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = 0.0&lt;br /&gt;
      sum_weight = 0&lt;br /&gt;
&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = sum_weight = 0.0&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
      round_score&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:*Assignment Branch Condition size for calculate_avg_score_by_round is reduced from 18.57 to &amp;lt;15.&lt;br /&gt;
&lt;br /&gt;
=='''Test Plan'''==&lt;br /&gt;
==='''Manual Testing'''===&lt;br /&gt;
:'''Login Details:''' '''USERNAME:''' instructor6 '''PASSWORD:''' password&lt;br /&gt;
:Click '''Assignment''' &amp;gt;&amp;gt; Click the '''View Submissions''' of '''Madeup problem''' &amp;gt;&amp;gt; Click on any student &amp;gt;&amp;gt; Click on '''Madeup problem''' &amp;gt;&amp;gt; Click on '''Your Scores'''&lt;br /&gt;
:[[File:expertiza2008-1.png]]&lt;br /&gt;
:[[File:expertiza2008-2.png]]&lt;br /&gt;
:[[File:expertiza2008-3.png]]&lt;br /&gt;
:[[File:expertiza2008-4.png]]&lt;br /&gt;
:The 3 main functions of the Summary helper are summarize review by reviewees, summarize review by reviewee and summarize reviews by criterion.&lt;br /&gt;
:To check ''summarize reviews by reviewees'' is working we should get the output similar to the one shown below. This function summarizes all the reviews and displays average score.&lt;br /&gt;
:[[File:expertiza2008-5.png]]&lt;br /&gt;
&lt;br /&gt;
:To check ''summarize reviews by reviewee'' is working, click on any review.&lt;br /&gt;
:[[File:expertiza2008-6a.png]]&lt;br /&gt;
:A new webpage pops up with all the reviews and scores given by an individual.&lt;br /&gt;
:[[File:expertiza2008-6b.png]]&lt;br /&gt;
&lt;br /&gt;
: To check ''summarize reviews by criterion'' is working, click on any criterion. This should display summarized reviews and scores for a particular question in the questionnaire.&lt;br /&gt;
:[[File:expertiza2008-7.png]]&lt;br /&gt;
&lt;br /&gt;
=='''Future improvement'''==&lt;br /&gt;
* Modularize ''summarize_by_rounds'' to even smaller modules so that Assignment Branch Condition size is reduced from 36.73 to 15.00.&lt;br /&gt;
* Create more test cases for the new modularized methods.&lt;br /&gt;
&lt;br /&gt;
=='''Contributors'''==&lt;br /&gt;
* [mailto:jviswan@ncsu.edu Jayalakshmi Viswanathan]&lt;br /&gt;
* [mailto:skundal@ncsu.edu Sandeep Kundala]&lt;br /&gt;
* [mailto:spal3@ncsu.edu Sumitosh Pal]&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132194</id>
		<title>CSC/ECE 517 Spring 2020 - Project E2008. Refactor summary helper.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132194"/>
		<updated>2020-03-30T06:56:25Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* Manual Testing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''About Expertiza'''==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed using Ruby on Rails Framework whose creation and maintenance are taken care of by students as well as the faculty of NCSU. Its code is available on Github [https://github.com/expertiza/expertiza Expertiza on GitHub]. Expertiza allows the instructor to create and edit new as well as existing assignments. This also includes creating a wide range of topics under each assignment that students can sign up for. They can also publish surveys and reviews, view statistical results, set deadlines for assignments and make announcements. It provides a platform for students to signup for topics, form teams, view and submit assignments and give peer reviews and feedback.&lt;br /&gt;
&lt;br /&gt;
=='''Problem Statement'''==&lt;br /&gt;
'''Background:''' In Expertiza students can review each other’s projects and even each other as teammates. Students can view their project scores and instructors can view student's teammate review scores on the view scores page. This helper file aids in calculating these scores and rendering the results on the view scores section of an assignment. Summary helper is a helper module that consists of methods used to calculate scores for these reviews. This is for the use of instructors.&lt;br /&gt;
&lt;br /&gt;
'''Requirement:'''&lt;br /&gt;
E2008 is an Expertiza OSS project which deals basically with refactoring app/helpers/summary_helper.rb to reduce the code climate issues such as&lt;br /&gt;
&lt;br /&gt;
* [http://wiki.c2.com/?AbcMetric Assignment Branch Condition]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Cognitive_complexity Cognitive Complexity]&lt;br /&gt;
* Method/line too long&lt;br /&gt;
* Unused variables / access modifiers&lt;br /&gt;
&lt;br /&gt;
'''A good method should have:'''&lt;br /&gt;
* Assignment Branch Condition size &amp;lt; 15&lt;br /&gt;
* Cognitive Complexity &amp;lt; 6&lt;br /&gt;
* No. of lines in a method &amp;lt; 25&lt;br /&gt;
&lt;br /&gt;
=='''Issues found'''==&lt;br /&gt;
The following are issues which were found in the code:&lt;br /&gt;
&lt;br /&gt;
==='''Assignment Branch Condition'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! ABC Size&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewee&lt;br /&gt;
| 44.61&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 42.34&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 89.93&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 16.43&lt;br /&gt;
|-&lt;br /&gt;
| calculate_avg_score_by_round&lt;br /&gt;
| 18.57&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
==='''Cognitive Complexity'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! Cognitive Complexity&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 16&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 17&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 11&lt;br /&gt;
|-&lt;br /&gt;
| break_up_comments_to_sentences&lt;br /&gt;
| 6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Method/line too long'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method/Line too long&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewees&lt;br /&gt;
|'''Lines of Code:'''39&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_criterion  &lt;br /&gt;
|'''Lines of Code:'''27&lt;br /&gt;
|-&lt;br /&gt;
|'''Line:''' 145&lt;br /&gt;
|self.avg_scores_by_round[reviewee.name][round] too long (162/160)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==='''Unused variables / access modifiers'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Vaiable/Access Modifier&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' summary  &lt;br /&gt;
|'''Method:''' summarize_sentences&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' included_question_counter  &lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewee&lt;br /&gt;
|-&lt;br /&gt;
|'''Access Modifier:''' module_function  &lt;br /&gt;
|'''Class:''' Summary&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=='''Solution Implemented'''==&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewee'''===&lt;br /&gt;
:This method is used to summarize reviews by a reviewer for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:''' &lt;br /&gt;
:This method could be refactored into smaller methods namely ''summarize_reviews_by_reviewee'' and ''summarize_reviews_by_reviewee_assign'' where ''summarize_reviews_by_reviewee'' calls ''summarize_reviews_by_reviewee_assign'' to get average scores and summary for each question.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewee is reduced from 44.61 to 20.64.&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_criterion'''===&lt;br /&gt;
:This method is used to summarize the review for each questions&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 3 smaller methods namely ''summarize_reviews_by_criterion'', ''summarize_reviews_by_criterion_questions'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion'' calls ''summarize_reviews_by_criterion_questions'' to get answers of each question in the rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion_questions'' starts many threads to process each question and closes it by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_3.jpg]]&lt;br /&gt;
:[[File:e2008_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_criterion is reduced from 42.34 to 17.2&lt;br /&gt;
:* Cognitive complexity is reduced from 16 to 7&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewees'''===&lt;br /&gt;
:This method is used to produce summaries for instructor and students. It sums up the feedback by criterion for each reviewer&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 4 smaller methods namely ''summarize_reviews_by_reviewees'', ''summarize_reviews_by_teams'', ''summarize_by_rounds'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_reviewees'' calls ''summarize_reviews_by_teams''  which inturn calls ''summarize_by_rounds'' to get answers of each reviewer by rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_by_rounds'' starts many threads to create requests to summarize the comments and closes the threads by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def summarize_reviews_by_reviewees(assignment, summary_ws_url)&lt;br /&gt;
      # @summary[reviewee][round][question]&lt;br /&gt;
      # @reviewers[team][reviewer]&lt;br /&gt;
      # @avg_scores_by_reviewee[team]&lt;br /&gt;
      # @avg_score_round[reviewee][round]&lt;br /&gt;
      # @avg_scores_by_criterion[reviewee][round][criterion]&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_reviewee = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.reviewers = ({})&lt;br /&gt;
      threads = []&lt;br /&gt;
&lt;br /&gt;
      # get all criteria used in each round&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get all teams in this assignment&lt;br /&gt;
      teams = Team.select(:id, :name).where(parent_id: assignment.id).order(:name)&lt;br /&gt;
&lt;br /&gt;
      teams.each do |reviewee|&lt;br /&gt;
        self.summary[reviewee.name] = []&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = 0.0&lt;br /&gt;
        self.avg_scores_by_round[reviewee.name] = []&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name] = []&lt;br /&gt;
&lt;br /&gt;
        # get the name of reviewers for display only&lt;br /&gt;
        self.reviewers[reviewee.name] = get_reviewers_by_reviewee_and_assignment(reviewee, assignment.id)&lt;br /&gt;
&lt;br /&gt;
        # get answers of each reviewer by rubric&lt;br /&gt;
        (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
          self.summary[reviewee.name][round] = {}&lt;br /&gt;
          self.avg_scores_by_round[reviewee.name][round] = 0.0&lt;br /&gt;
          self.avg_scores_by_criterion[reviewee.name][round] = {}&lt;br /&gt;
&lt;br /&gt;
          # iterate each round and get answers&lt;br /&gt;
          # if use the same rubric, only use rubric[0]&lt;br /&gt;
          rubric_questions_used = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
          rubric_questions_used.each do |q|&lt;br /&gt;
            next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
            summary[reviewee.name][round][q.txt] = &amp;quot;&amp;quot;&lt;br /&gt;
            self.avg_scores_by_criterion[reviewee.name][round][q.txt] = 0.0&lt;br /&gt;
&lt;br /&gt;
            # get all answers to this question&lt;br /&gt;
            question_answers = Answer.answers_by_question_for_reviewee_in_round(assignment.id, reviewee.id, q.id, round + 1)&lt;br /&gt;
            # get max score of this rubric&lt;br /&gt;
            q_max_score = get_max_score_for_question(q)&lt;br /&gt;
&lt;br /&gt;
            comments = break_up_comments_to_sentences(question_answers)&lt;br /&gt;
            # get score and summary of answers for each question&lt;br /&gt;
            self.avg_scores_by_criterion[reviewee.name][round][q.txt] = calculate_avg_score_by_criterion(question_answers, q_max_score)&lt;br /&gt;
&lt;br /&gt;
            # summarize the comments by calling the summarization Web Service&lt;br /&gt;
&lt;br /&gt;
            # since it'll do a lot of request, do this in seperate threads&lt;br /&gt;
            threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
              summary[reviewee.name][round][q.txt] = summarize_sentences(comments, summary_ws_url) unless comments.empty?&lt;br /&gt;
            end&lt;br /&gt;
          end&lt;br /&gt;
          self.avg_scores_by_round[reviewee.name][round] = calculate_avg_score_by_round(self.avg_scores_by_criterion[reviewee.name][round], rubric_questions_used)&lt;br /&gt;
        end&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = calculate_avg_score_by_reviewee(self.avg_scores_by_round[reviewee.name], assignment.rounds_of_reviews)&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      threads.each do |t|&lt;br /&gt;
        t.join if t != Thread.current&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def summarize_reviews_by_reviewees(assignment, summary_ws_url)&lt;br /&gt;
      # @summary[reviewee][round][question]&lt;br /&gt;
      # @reviewers[team][reviewer]&lt;br /&gt;
      # @avg_scores_by_reviewee[team]&lt;br /&gt;
      # @avg_score_round[reviewee][round]&lt;br /&gt;
      # @avg_scores_by_criterion[reviewee][round][criterion]&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_reviewee = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.reviewers = ({})&lt;br /&gt;
      self.summary_ws_url = summary_ws_url&lt;br /&gt;
&lt;br /&gt;
      # get all criteria used in each round&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get all teams in this assignment&lt;br /&gt;
      teams = Team.select(:id, :name).where(parent_id: assignment.id).order(:name)&lt;br /&gt;
&lt;br /&gt;
      teams.each do |reviewee|&lt;br /&gt;
        summarize_reviews_by_team_reviewee(assignment, reviewee, rubric)&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = calculate_avg_score_by_reviewee(self.avg_scores_by_round[reviewee.name], assignment.rounds_of_reviews)&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def summarize_reviews_by_team_reviewee(assignment, reviewee, rubric)&lt;br /&gt;
      self.summary[reviewee.name] = []&lt;br /&gt;
      self.avg_scores_by_reviewee[reviewee.name] = 0.0&lt;br /&gt;
      self.avg_scores_by_round[reviewee.name] = self.avg_scores_by_criterion[reviewee.name] = []&lt;br /&gt;
&lt;br /&gt;
      # get the name of reviewers for display only&lt;br /&gt;
      self.reviewers[reviewee.name] = get_reviewers_by_reviewee_and_assignment(reviewee, assignment.id)&lt;br /&gt;
&lt;br /&gt;
      # get answers of each reviewer by rubric&lt;br /&gt;
      (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
        self.summary[reviewee.name][round] = {}&lt;br /&gt;
        self.avg_scores_by_round[reviewee.name][round] = 0.0&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name][round] = {}&lt;br /&gt;
        summarize_by_reviewee_round(assignment, reviewee, round, rubric)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def summarize_by_reviewee_round(assignment, reviewee, round, rubric)&lt;br /&gt;
      threads = []&lt;br /&gt;
      # iterate each round and get answers&lt;br /&gt;
      # if use the same rubric, only use rubric[0]&lt;br /&gt;
      rubric_questions_used = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
      rubric_questions_used.each do |q|&lt;br /&gt;
        next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # get all answers to this question&lt;br /&gt;
        question_answers = Answer.answers_by_question_for_reviewee_in_round(assignment.id, reviewee.id, q.id, round + 1)&lt;br /&gt;
&lt;br /&gt;
        # get score and summary of answers for each question&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name][round][q.txt] = calculate_avg_score_by_criterion(question_answers, get_max_score_for_question(q))&lt;br /&gt;
&lt;br /&gt;
        # summarize the comments by calling the summarization Web Service&lt;br /&gt;
        # since it'll do a lot of request, do this in seperate threads&lt;br /&gt;
        threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
          self.summary[reviewee.name][round][q.txt] = summarize_sentences(break_up_comments_to_sentences(question_answers), self.summary_ws_url)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      avg_scores_by_round = calculate_avg_score_by_round(self.avg_scores_by_criterion[reviewee.name][round], rubric_questions_used)&lt;br /&gt;
      self.avg_scores_by_round[reviewee.name][round] = avg_scores_by_round&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      end_threads(threads)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    def end_threads(threads)&lt;br /&gt;
      threads.each do |t|&lt;br /&gt;
        # Wait for the thread to finish if it isn't this thread (i.e. the main thread).&lt;br /&gt;
        t.join if t != Thread.current&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewees is reduced from 89.93 to 16.64&lt;br /&gt;
:* Cognitive Complexity is reduced from 17 to 7&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_sentence'''===&lt;br /&gt;
:This method calls web service to store each summary in a hashmap and use the question as the key.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Removed variable ''summary''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_8.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - break_up_comments_to_sentences'''===&lt;br /&gt;
: This method adds the comment to an array to be converted as a json request.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:The method is broken down into 2 smaller methods namely ''break_up_comments_to_sentences'' and ''get_sentences'' where ''get_sentences'' is called by ''break_up_comments_to_sentences'' to  get sentences in desired format.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_9.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact''':&lt;br /&gt;
:*The Cognitive complexity of break_up_comments_to_sentences reduced from 6 to &amp;lt;5&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - get_questions_by_assignment'''===&lt;br /&gt;
:This method returns the rubric for given assignment&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_10.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - calculate_avg_score_by_round'''===&lt;br /&gt;
:This method is used to calculate average round score for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Refactored the method into 2 smaller methods namely ''calculate_avg_score_by_round'' and ''calculate_round_score'' where ''calculate_avg_score_by_round'' calls ''calculate_round_score'' to calculate average round score and ''calculate_avg_score_by_round'' rounds the round_score upto 2 decimal places.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = 0.0&lt;br /&gt;
      sum_weight = 0&lt;br /&gt;
&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = sum_weight = 0.0&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
      round_score&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:*Assignment Branch Condition size for calculate_avg_score_by_round is reduced from 18.57 to &amp;lt;15.&lt;br /&gt;
&lt;br /&gt;
=='''Test Plan'''==&lt;br /&gt;
==='''Manual Testing'''===&lt;br /&gt;
:'''Login Details:''' '''USERNAME:''' instructor6 '''PASSWORD:''' password&lt;br /&gt;
:Click '''Assignment''' &amp;gt;&amp;gt; Click the '''View Submissions''' of '''Madeup problem''' &amp;gt;&amp;gt; Click on any student &amp;gt;&amp;gt; Click on '''Madeup problem''' &amp;gt;&amp;gt; Click on '''Your Scores'''&lt;br /&gt;
:[[File:expertiza2008-1.jpg]]&lt;br /&gt;
:[[File:expertiza2008-2.jpg]]&lt;br /&gt;
:[[File:expertiza2008-3.jpg]]&lt;br /&gt;
:[[File:expertiza2008-4.jpg]]&lt;br /&gt;
:The 3 main functions of the Summary helper are summarize review by reviewees, summarize review by reviewee and summarize reviews by criterion.&lt;br /&gt;
:To check ''summarize reviews by reviewees'' is working we should get the output similar to the one shown below. This function summarizes all the reviews and displays average score.&lt;br /&gt;
:[[File:expertiza2008-5.jpg]]&lt;br /&gt;
&lt;br /&gt;
:To check ''summarize reviews by reviewee'' is working, click on any review.&lt;br /&gt;
:[[File:expertiza2008-6a.jpg]]&lt;br /&gt;
:A new webpage pops up with all the reviews and scores given by an individual.&lt;br /&gt;
:[[File:expertiza2008-6b.jpg]]&lt;br /&gt;
&lt;br /&gt;
: To check ''summarize reviews by criterion'' is working, click on any criterion. This should display summarized reviews and scores for a particular question in the questionnaire.&lt;br /&gt;
:[[File:expertiza2008-7.jpg]]&lt;br /&gt;
&lt;br /&gt;
=='''Future improvement'''==&lt;br /&gt;
* Modularize ''summarize_by_rounds'' to even smaller modules so that Assignment Branch Condition size is reduced from 36.73 to 15.00.&lt;br /&gt;
* Create more test cases for the new modularized methods.&lt;br /&gt;
&lt;br /&gt;
=='''Contributors'''==&lt;br /&gt;
* [mailto:jviswan@ncsu.edu Jayalakshmi Viswanathan]&lt;br /&gt;
* [mailto:skundal@ncsu.edu Sandeep Kundala]&lt;br /&gt;
* [mailto:spal3@ncsu.edu Sumitosh Pal]&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132193</id>
		<title>CSC/ECE 517 Spring 2020 - Project E2008. Refactor summary helper.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132193"/>
		<updated>2020-03-30T06:55:41Z</updated>

		<summary type="html">&lt;p&gt;Skundal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''About Expertiza'''==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed using Ruby on Rails Framework whose creation and maintenance are taken care of by students as well as the faculty of NCSU. Its code is available on Github [https://github.com/expertiza/expertiza Expertiza on GitHub]. Expertiza allows the instructor to create and edit new as well as existing assignments. This also includes creating a wide range of topics under each assignment that students can sign up for. They can also publish surveys and reviews, view statistical results, set deadlines for assignments and make announcements. It provides a platform for students to signup for topics, form teams, view and submit assignments and give peer reviews and feedback.&lt;br /&gt;
&lt;br /&gt;
=='''Problem Statement'''==&lt;br /&gt;
'''Background:''' In Expertiza students can review each other’s projects and even each other as teammates. Students can view their project scores and instructors can view student's teammate review scores on the view scores page. This helper file aids in calculating these scores and rendering the results on the view scores section of an assignment. Summary helper is a helper module that consists of methods used to calculate scores for these reviews. This is for the use of instructors.&lt;br /&gt;
&lt;br /&gt;
'''Requirement:'''&lt;br /&gt;
E2008 is an Expertiza OSS project which deals basically with refactoring app/helpers/summary_helper.rb to reduce the code climate issues such as&lt;br /&gt;
&lt;br /&gt;
* [http://wiki.c2.com/?AbcMetric Assignment Branch Condition]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Cognitive_complexity Cognitive Complexity]&lt;br /&gt;
* Method/line too long&lt;br /&gt;
* Unused variables / access modifiers&lt;br /&gt;
&lt;br /&gt;
'''A good method should have:'''&lt;br /&gt;
* Assignment Branch Condition size &amp;lt; 15&lt;br /&gt;
* Cognitive Complexity &amp;lt; 6&lt;br /&gt;
* No. of lines in a method &amp;lt; 25&lt;br /&gt;
&lt;br /&gt;
=='''Issues found'''==&lt;br /&gt;
The following are issues which were found in the code:&lt;br /&gt;
&lt;br /&gt;
==='''Assignment Branch Condition'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! ABC Size&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewee&lt;br /&gt;
| 44.61&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 42.34&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 89.93&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 16.43&lt;br /&gt;
|-&lt;br /&gt;
| calculate_avg_score_by_round&lt;br /&gt;
| 18.57&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
==='''Cognitive Complexity'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! Cognitive Complexity&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 16&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 17&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 11&lt;br /&gt;
|-&lt;br /&gt;
| break_up_comments_to_sentences&lt;br /&gt;
| 6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Method/line too long'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method/Line too long&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewees&lt;br /&gt;
|'''Lines of Code:'''39&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_criterion  &lt;br /&gt;
|'''Lines of Code:'''27&lt;br /&gt;
|-&lt;br /&gt;
|'''Line:''' 145&lt;br /&gt;
|self.avg_scores_by_round[reviewee.name][round] too long (162/160)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==='''Unused variables / access modifiers'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Vaiable/Access Modifier&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' summary  &lt;br /&gt;
|'''Method:''' summarize_sentences&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' included_question_counter  &lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewee&lt;br /&gt;
|-&lt;br /&gt;
|'''Access Modifier:''' module_function  &lt;br /&gt;
|'''Class:''' Summary&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=='''Solution Implemented'''==&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewee'''===&lt;br /&gt;
:This method is used to summarize reviews by a reviewer for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:''' &lt;br /&gt;
:This method could be refactored into smaller methods namely ''summarize_reviews_by_reviewee'' and ''summarize_reviews_by_reviewee_assign'' where ''summarize_reviews_by_reviewee'' calls ''summarize_reviews_by_reviewee_assign'' to get average scores and summary for each question.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewee is reduced from 44.61 to 20.64.&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_criterion'''===&lt;br /&gt;
:This method is used to summarize the review for each questions&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 3 smaller methods namely ''summarize_reviews_by_criterion'', ''summarize_reviews_by_criterion_questions'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion'' calls ''summarize_reviews_by_criterion_questions'' to get answers of each question in the rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion_questions'' starts many threads to process each question and closes it by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_3.jpg]]&lt;br /&gt;
:[[File:e2008_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_criterion is reduced from 42.34 to 17.2&lt;br /&gt;
:* Cognitive complexity is reduced from 16 to 7&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewees'''===&lt;br /&gt;
:This method is used to produce summaries for instructor and students. It sums up the feedback by criterion for each reviewer&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 4 smaller methods namely ''summarize_reviews_by_reviewees'', ''summarize_reviews_by_teams'', ''summarize_by_rounds'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_reviewees'' calls ''summarize_reviews_by_teams''  which inturn calls ''summarize_by_rounds'' to get answers of each reviewer by rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_by_rounds'' starts many threads to create requests to summarize the comments and closes the threads by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def summarize_reviews_by_reviewees(assignment, summary_ws_url)&lt;br /&gt;
      # @summary[reviewee][round][question]&lt;br /&gt;
      # @reviewers[team][reviewer]&lt;br /&gt;
      # @avg_scores_by_reviewee[team]&lt;br /&gt;
      # @avg_score_round[reviewee][round]&lt;br /&gt;
      # @avg_scores_by_criterion[reviewee][round][criterion]&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_reviewee = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.reviewers = ({})&lt;br /&gt;
      threads = []&lt;br /&gt;
&lt;br /&gt;
      # get all criteria used in each round&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get all teams in this assignment&lt;br /&gt;
      teams = Team.select(:id, :name).where(parent_id: assignment.id).order(:name)&lt;br /&gt;
&lt;br /&gt;
      teams.each do |reviewee|&lt;br /&gt;
        self.summary[reviewee.name] = []&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = 0.0&lt;br /&gt;
        self.avg_scores_by_round[reviewee.name] = []&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name] = []&lt;br /&gt;
&lt;br /&gt;
        # get the name of reviewers for display only&lt;br /&gt;
        self.reviewers[reviewee.name] = get_reviewers_by_reviewee_and_assignment(reviewee, assignment.id)&lt;br /&gt;
&lt;br /&gt;
        # get answers of each reviewer by rubric&lt;br /&gt;
        (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
          self.summary[reviewee.name][round] = {}&lt;br /&gt;
          self.avg_scores_by_round[reviewee.name][round] = 0.0&lt;br /&gt;
          self.avg_scores_by_criterion[reviewee.name][round] = {}&lt;br /&gt;
&lt;br /&gt;
          # iterate each round and get answers&lt;br /&gt;
          # if use the same rubric, only use rubric[0]&lt;br /&gt;
          rubric_questions_used = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
          rubric_questions_used.each do |q|&lt;br /&gt;
            next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
            summary[reviewee.name][round][q.txt] = &amp;quot;&amp;quot;&lt;br /&gt;
            self.avg_scores_by_criterion[reviewee.name][round][q.txt] = 0.0&lt;br /&gt;
&lt;br /&gt;
            # get all answers to this question&lt;br /&gt;
            question_answers = Answer.answers_by_question_for_reviewee_in_round(assignment.id, reviewee.id, q.id, round + 1)&lt;br /&gt;
            # get max score of this rubric&lt;br /&gt;
            q_max_score = get_max_score_for_question(q)&lt;br /&gt;
&lt;br /&gt;
            comments = break_up_comments_to_sentences(question_answers)&lt;br /&gt;
            # get score and summary of answers for each question&lt;br /&gt;
            self.avg_scores_by_criterion[reviewee.name][round][q.txt] = calculate_avg_score_by_criterion(question_answers, q_max_score)&lt;br /&gt;
&lt;br /&gt;
            # summarize the comments by calling the summarization Web Service&lt;br /&gt;
&lt;br /&gt;
            # since it'll do a lot of request, do this in seperate threads&lt;br /&gt;
            threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
              summary[reviewee.name][round][q.txt] = summarize_sentences(comments, summary_ws_url) unless comments.empty?&lt;br /&gt;
            end&lt;br /&gt;
          end&lt;br /&gt;
          self.avg_scores_by_round[reviewee.name][round] = calculate_avg_score_by_round(self.avg_scores_by_criterion[reviewee.name][round], rubric_questions_used)&lt;br /&gt;
        end&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = calculate_avg_score_by_reviewee(self.avg_scores_by_round[reviewee.name], assignment.rounds_of_reviews)&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      threads.each do |t|&lt;br /&gt;
        t.join if t != Thread.current&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def summarize_reviews_by_reviewees(assignment, summary_ws_url)&lt;br /&gt;
      # @summary[reviewee][round][question]&lt;br /&gt;
      # @reviewers[team][reviewer]&lt;br /&gt;
      # @avg_scores_by_reviewee[team]&lt;br /&gt;
      # @avg_score_round[reviewee][round]&lt;br /&gt;
      # @avg_scores_by_criterion[reviewee][round][criterion]&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_reviewee = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.reviewers = ({})&lt;br /&gt;
      self.summary_ws_url = summary_ws_url&lt;br /&gt;
&lt;br /&gt;
      # get all criteria used in each round&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get all teams in this assignment&lt;br /&gt;
      teams = Team.select(:id, :name).where(parent_id: assignment.id).order(:name)&lt;br /&gt;
&lt;br /&gt;
      teams.each do |reviewee|&lt;br /&gt;
        summarize_reviews_by_team_reviewee(assignment, reviewee, rubric)&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = calculate_avg_score_by_reviewee(self.avg_scores_by_round[reviewee.name], assignment.rounds_of_reviews)&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def summarize_reviews_by_team_reviewee(assignment, reviewee, rubric)&lt;br /&gt;
      self.summary[reviewee.name] = []&lt;br /&gt;
      self.avg_scores_by_reviewee[reviewee.name] = 0.0&lt;br /&gt;
      self.avg_scores_by_round[reviewee.name] = self.avg_scores_by_criterion[reviewee.name] = []&lt;br /&gt;
&lt;br /&gt;
      # get the name of reviewers for display only&lt;br /&gt;
      self.reviewers[reviewee.name] = get_reviewers_by_reviewee_and_assignment(reviewee, assignment.id)&lt;br /&gt;
&lt;br /&gt;
      # get answers of each reviewer by rubric&lt;br /&gt;
      (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
        self.summary[reviewee.name][round] = {}&lt;br /&gt;
        self.avg_scores_by_round[reviewee.name][round] = 0.0&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name][round] = {}&lt;br /&gt;
        summarize_by_reviewee_round(assignment, reviewee, round, rubric)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def summarize_by_reviewee_round(assignment, reviewee, round, rubric)&lt;br /&gt;
      threads = []&lt;br /&gt;
      # iterate each round and get answers&lt;br /&gt;
      # if use the same rubric, only use rubric[0]&lt;br /&gt;
      rubric_questions_used = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
      rubric_questions_used.each do |q|&lt;br /&gt;
        next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # get all answers to this question&lt;br /&gt;
        question_answers = Answer.answers_by_question_for_reviewee_in_round(assignment.id, reviewee.id, q.id, round + 1)&lt;br /&gt;
&lt;br /&gt;
        # get score and summary of answers for each question&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name][round][q.txt] = calculate_avg_score_by_criterion(question_answers, get_max_score_for_question(q))&lt;br /&gt;
&lt;br /&gt;
        # summarize the comments by calling the summarization Web Service&lt;br /&gt;
        # since it'll do a lot of request, do this in seperate threads&lt;br /&gt;
        threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
          self.summary[reviewee.name][round][q.txt] = summarize_sentences(break_up_comments_to_sentences(question_answers), self.summary_ws_url)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      avg_scores_by_round = calculate_avg_score_by_round(self.avg_scores_by_criterion[reviewee.name][round], rubric_questions_used)&lt;br /&gt;
      self.avg_scores_by_round[reviewee.name][round] = avg_scores_by_round&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      end_threads(threads)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    def end_threads(threads)&lt;br /&gt;
      threads.each do |t|&lt;br /&gt;
        # Wait for the thread to finish if it isn't this thread (i.e. the main thread).&lt;br /&gt;
        t.join if t != Thread.current&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewees is reduced from 89.93 to 16.64&lt;br /&gt;
:* Cognitive Complexity is reduced from 17 to 7&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_sentence'''===&lt;br /&gt;
:This method calls web service to store each summary in a hashmap and use the question as the key.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Removed variable ''summary''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_8.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - break_up_comments_to_sentences'''===&lt;br /&gt;
: This method adds the comment to an array to be converted as a json request.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:The method is broken down into 2 smaller methods namely ''break_up_comments_to_sentences'' and ''get_sentences'' where ''get_sentences'' is called by ''break_up_comments_to_sentences'' to  get sentences in desired format.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_9.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact''':&lt;br /&gt;
:*The Cognitive complexity of break_up_comments_to_sentences reduced from 6 to &amp;lt;5&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - get_questions_by_assignment'''===&lt;br /&gt;
:This method returns the rubric for given assignment&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_10.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - calculate_avg_score_by_round'''===&lt;br /&gt;
:This method is used to calculate average round score for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Refactored the method into 2 smaller methods namely ''calculate_avg_score_by_round'' and ''calculate_round_score'' where ''calculate_avg_score_by_round'' calls ''calculate_round_score'' to calculate average round score and ''calculate_avg_score_by_round'' rounds the round_score upto 2 decimal places.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = 0.0&lt;br /&gt;
      sum_weight = 0&lt;br /&gt;
&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = sum_weight = 0.0&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
      round_score&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:*Assignment Branch Condition size for calculate_avg_score_by_round is reduced from 18.57 to &amp;lt;15.&lt;br /&gt;
&lt;br /&gt;
=='''Test Plan'''==&lt;br /&gt;
==='''Manual Testing'''===&lt;br /&gt;
:'''Login Details:''' '''USERNAME:''' instructor6 '''PASSWORD:''' password&lt;br /&gt;
:Click '''Assignment''' &amp;gt;&amp;gt; Click the '''View Submissions''' of '''Madeup problem''' &amp;gt;&amp;gt; Click on any student &amp;gt;&amp;gt; Click on '''Madeup problem''' &amp;gt;&amp;gt; Click on '''Your Scores'''&lt;br /&gt;
:[[File:expertiza2008-1.jpg]]&lt;br /&gt;
:[[File:expertiza2008-2.jpg]]&lt;br /&gt;
:[[File:expertiza2008-3.jpg]]&lt;br /&gt;
:[[File:expertiza2008-4.jpg]]&lt;br /&gt;
:The 3 main functions of the Summary helper are summarize review by reviewees, summarize review by reviewee and summarize reviews by criterion.&lt;br /&gt;
:To check ''summarize reviews by reviewees'' is working we should get the output similar to the one shown below. This function summarizes all the reviews and displays average score.&lt;br /&gt;
:[[File:expertiza2008-5.jpg]]&lt;br /&gt;
&lt;br /&gt;
:To check ''summarize reviews by reviewee'' is working, click on any review.&lt;br /&gt;
:[[File:expertiza2008-6a.jpg]]&lt;br /&gt;
:A new webpage pops up with all the reviews and scores given by an individual.&lt;br /&gt;
:[[File:expertiza2008-6b.jpg]]&lt;br /&gt;
&lt;br /&gt;
: To check ''summarize reviews by criterion'' is working, click on any criterion. This should display summarized reviews and scores for a particular question in the questionnaire.&lt;br /&gt;
[[File:expertiza2008-7.jpg]]&lt;br /&gt;
&lt;br /&gt;
=='''Future improvement'''==&lt;br /&gt;
* Modularize ''summarize_by_rounds'' to even smaller modules so that Assignment Branch Condition size is reduced from 36.73 to 15.00.&lt;br /&gt;
* Create more test cases for the new modularized methods.&lt;br /&gt;
&lt;br /&gt;
=='''Contributors'''==&lt;br /&gt;
* [mailto:jviswan@ncsu.edu Jayalakshmi Viswanathan]&lt;br /&gt;
* [mailto:skundal@ncsu.edu Sandeep Kundala]&lt;br /&gt;
* [mailto:spal3@ncsu.edu Sumitosh Pal]&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132163</id>
		<title>CSC/ECE 517 Spring 2020 - Project E2008. Refactor summary helper.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132163"/>
		<updated>2020-03-29T13:53:03Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* Refactor - summarize_reviews_by_reviewees */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''About Expertiza'''==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed using Ruby on Rails Framework whose creation and maintenance are taken care of by students as well as the faculty of NCSU. Its code is available on Github [https://github.com/expertiza/expertiza Expertiza on GitHub]. Expertiza allows the instructor to create and edit new as well as existing assignments. This also includes creating a wide range of topics under each assignment that students can sign up for. They can also publish surveys and reviews, view statistical results, set deadlines for assignments and make announcements. It provides a platform for students to signup for topics, form teams, view and submit assignments and give peer reviews and feedback.&lt;br /&gt;
&lt;br /&gt;
=='''Problem Statement'''==&lt;br /&gt;
'''Background:''' In Expertiza students can review each other’s projects and even each other as teammates. Students can view their project scores and instructors can view student's teammate review scores on the view scores page. This helper file aids in calculating these scores and rendering the results on the view scores section of an assignment. Summary helper is a helper module that consists of methods used to calculate scores for these reviews. This is for the use of instructors.&lt;br /&gt;
&lt;br /&gt;
'''Requirement:'''&lt;br /&gt;
E2008 is an Expertiza OSS project which deals basically with refactoring app/helpers/summary_helper.rb to reduce the code climate issues such as&lt;br /&gt;
&lt;br /&gt;
* [http://wiki.c2.com/?AbcMetric Assignment Branch Condition]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Cognitive_complexity Cognitive Complexity]&lt;br /&gt;
* Method/line too long&lt;br /&gt;
* Unused variables / access modifiers&lt;br /&gt;
&lt;br /&gt;
'''A good method should have:'''&lt;br /&gt;
* Assignment Branch Condition size &amp;lt; 15&lt;br /&gt;
* Cognitive Complexity &amp;lt; 6&lt;br /&gt;
* No. of lines in a method &amp;lt; 25&lt;br /&gt;
&lt;br /&gt;
=='''Issues found'''==&lt;br /&gt;
The following are issues which were found in the code:&lt;br /&gt;
&lt;br /&gt;
==='''Assignment Branch Condition'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! ABC Size&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewee&lt;br /&gt;
| 44.61&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 42.34&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 89.93&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 16.43&lt;br /&gt;
|-&lt;br /&gt;
| calculate_avg_score_by_round&lt;br /&gt;
| 18.57&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
==='''Cognitive Complexity'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! Cognitive Complexity&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 16&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 17&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 11&lt;br /&gt;
|-&lt;br /&gt;
| break_up_comments_to_sentences&lt;br /&gt;
| 6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Method/line too long'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method/Line too long&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewees&lt;br /&gt;
|'''Lines of Code:'''39&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_criterion  &lt;br /&gt;
|'''Lines of Code:'''27&lt;br /&gt;
|-&lt;br /&gt;
|'''Line:''' 145&lt;br /&gt;
|self.avg_scores_by_round[reviewee.name][round] too long (162/160)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==='''Unused variables / access modifiers'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Vaiable/Access Modifier&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' summary  &lt;br /&gt;
|'''Method:''' summarize_sentences&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' included_question_counter  &lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewee&lt;br /&gt;
|-&lt;br /&gt;
|'''Access Modifier:''' module_function  &lt;br /&gt;
|'''Class:''' Summary&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=='''Solution Implemented'''==&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewee'''===&lt;br /&gt;
:This method is used to summarize reviews by a reviewer for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:''' &lt;br /&gt;
:This method could be refactored into smaller methods namely ''summarize_reviews_by_reviewee'' and ''summarize_reviews_by_reviewee_assign'' where ''summarize_reviews_by_reviewee'' calls ''summarize_reviews_by_reviewee_assign'' to get average scores and summary for each question.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewee is reduced from 44.61 to 20.64.&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_criterion'''===&lt;br /&gt;
:This method is used to summarize the review for each questions&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 3 smaller methods namely ''summarize_reviews_by_criterion'', ''summarize_reviews_by_criterion_questions'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion'' calls ''summarize_reviews_by_criterion_questions'' to get answers of each question in the rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion_questions'' starts many threads to process each question and closes it by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_3.jpg]]&lt;br /&gt;
:[[File:e2008_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_criterion is reduced from 42.34 to 17.2&lt;br /&gt;
:* Cognitive complexity is reduced from 16 to 7&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewees'''===&lt;br /&gt;
:This method is used to produce summaries for instructor and students. It sums up the feedback by criterion for each reviewer&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 4 smaller methods namely ''summarize_reviews_by_reviewees'', ''summarize_reviews_by_teams'', ''summarize_by_rounds'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_reviewees'' calls ''summarize_reviews_by_teams''  which inturn calls ''summarize_by_rounds'' to get answers of each reviewer by rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_by_rounds'' starts many threads to create requests to summarize the comments and closes the threads by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def summarize_reviews_by_reviewees(assignment, summary_ws_url)&lt;br /&gt;
      # @summary[reviewee][round][question]&lt;br /&gt;
      # @reviewers[team][reviewer]&lt;br /&gt;
      # @avg_scores_by_reviewee[team]&lt;br /&gt;
      # @avg_score_round[reviewee][round]&lt;br /&gt;
      # @avg_scores_by_criterion[reviewee][round][criterion]&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_reviewee = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.reviewers = ({})&lt;br /&gt;
      threads = []&lt;br /&gt;
&lt;br /&gt;
      # get all criteria used in each round&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get all teams in this assignment&lt;br /&gt;
      teams = Team.select(:id, :name).where(parent_id: assignment.id).order(:name)&lt;br /&gt;
&lt;br /&gt;
      teams.each do |reviewee|&lt;br /&gt;
        self.summary[reviewee.name] = []&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = 0.0&lt;br /&gt;
        self.avg_scores_by_round[reviewee.name] = []&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name] = []&lt;br /&gt;
&lt;br /&gt;
        # get the name of reviewers for display only&lt;br /&gt;
        self.reviewers[reviewee.name] = get_reviewers_by_reviewee_and_assignment(reviewee, assignment.id)&lt;br /&gt;
&lt;br /&gt;
        # get answers of each reviewer by rubric&lt;br /&gt;
        (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
          self.summary[reviewee.name][round] = {}&lt;br /&gt;
          self.avg_scores_by_round[reviewee.name][round] = 0.0&lt;br /&gt;
          self.avg_scores_by_criterion[reviewee.name][round] = {}&lt;br /&gt;
&lt;br /&gt;
          # iterate each round and get answers&lt;br /&gt;
          # if use the same rubric, only use rubric[0]&lt;br /&gt;
          rubric_questions_used = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
          rubric_questions_used.each do |q|&lt;br /&gt;
            next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
            summary[reviewee.name][round][q.txt] = &amp;quot;&amp;quot;&lt;br /&gt;
            self.avg_scores_by_criterion[reviewee.name][round][q.txt] = 0.0&lt;br /&gt;
&lt;br /&gt;
            # get all answers to this question&lt;br /&gt;
            question_answers = Answer.answers_by_question_for_reviewee_in_round(assignment.id, reviewee.id, q.id, round + 1)&lt;br /&gt;
            # get max score of this rubric&lt;br /&gt;
            q_max_score = get_max_score_for_question(q)&lt;br /&gt;
&lt;br /&gt;
            comments = break_up_comments_to_sentences(question_answers)&lt;br /&gt;
            # get score and summary of answers for each question&lt;br /&gt;
            self.avg_scores_by_criterion[reviewee.name][round][q.txt] = calculate_avg_score_by_criterion(question_answers, q_max_score)&lt;br /&gt;
&lt;br /&gt;
            # summarize the comments by calling the summarization Web Service&lt;br /&gt;
&lt;br /&gt;
            # since it'll do a lot of request, do this in seperate threads&lt;br /&gt;
            threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
              summary[reviewee.name][round][q.txt] = summarize_sentences(comments, summary_ws_url) unless comments.empty?&lt;br /&gt;
            end&lt;br /&gt;
          end&lt;br /&gt;
          self.avg_scores_by_round[reviewee.name][round] = calculate_avg_score_by_round(self.avg_scores_by_criterion[reviewee.name][round], rubric_questions_used)&lt;br /&gt;
        end&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = calculate_avg_score_by_reviewee(self.avg_scores_by_round[reviewee.name], assignment.rounds_of_reviews)&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      threads.each do |t|&lt;br /&gt;
        t.join if t != Thread.current&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def summarize_reviews_by_reviewees(assignment, summary_ws_url)&lt;br /&gt;
      # @summary[reviewee][round][question]&lt;br /&gt;
      # @reviewers[team][reviewer]&lt;br /&gt;
      # @avg_scores_by_reviewee[team]&lt;br /&gt;
      # @avg_score_round[reviewee][round]&lt;br /&gt;
      # @avg_scores_by_criterion[reviewee][round][criterion]&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_reviewee = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.reviewers = ({})&lt;br /&gt;
      self.summary_ws_url = summary_ws_url&lt;br /&gt;
&lt;br /&gt;
      # get all criteria used in each round&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get all teams in this assignment&lt;br /&gt;
      teams = Team.select(:id, :name).where(parent_id: assignment.id).order(:name)&lt;br /&gt;
&lt;br /&gt;
      teams.each do |reviewee|&lt;br /&gt;
        summarize_reviews_by_team_reviewee(assignment, reviewee, rubric)&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = calculate_avg_score_by_reviewee(self.avg_scores_by_round[reviewee.name], assignment.rounds_of_reviews)&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def summarize_reviews_by_team_reviewee(assignment, reviewee, rubric)&lt;br /&gt;
      self.summary[reviewee.name] = []&lt;br /&gt;
      self.avg_scores_by_reviewee[reviewee.name] = 0.0&lt;br /&gt;
      self.avg_scores_by_round[reviewee.name] = self.avg_scores_by_criterion[reviewee.name] = []&lt;br /&gt;
&lt;br /&gt;
      # get the name of reviewers for display only&lt;br /&gt;
      self.reviewers[reviewee.name] = get_reviewers_by_reviewee_and_assignment(reviewee, assignment.id)&lt;br /&gt;
&lt;br /&gt;
      # get answers of each reviewer by rubric&lt;br /&gt;
      (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
        self.summary[reviewee.name][round] = {}&lt;br /&gt;
        self.avg_scores_by_round[reviewee.name][round] = 0.0&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name][round] = {}&lt;br /&gt;
        summarize_by_reviewee_round(assignment, reviewee, round, rubric)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def summarize_by_reviewee_round(assignment, reviewee, round, rubric)&lt;br /&gt;
      threads = []&lt;br /&gt;
      # iterate each round and get answers&lt;br /&gt;
      # if use the same rubric, only use rubric[0]&lt;br /&gt;
      rubric_questions_used = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
      rubric_questions_used.each do |q|&lt;br /&gt;
        next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # get all answers to this question&lt;br /&gt;
        question_answers = Answer.answers_by_question_for_reviewee_in_round(assignment.id, reviewee.id, q.id, round + 1)&lt;br /&gt;
&lt;br /&gt;
        # get score and summary of answers for each question&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name][round][q.txt] = calculate_avg_score_by_criterion(question_answers, get_max_score_for_question(q))&lt;br /&gt;
&lt;br /&gt;
        # summarize the comments by calling the summarization Web Service&lt;br /&gt;
        # since it'll do a lot of request, do this in seperate threads&lt;br /&gt;
        threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
          self.summary[reviewee.name][round][q.txt] = summarize_sentences(break_up_comments_to_sentences(question_answers), self.summary_ws_url)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      avg_scores_by_round = calculate_avg_score_by_round(self.avg_scores_by_criterion[reviewee.name][round], rubric_questions_used)&lt;br /&gt;
      self.avg_scores_by_round[reviewee.name][round] = avg_scores_by_round&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      end_threads(threads)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    def end_threads(threads)&lt;br /&gt;
      threads.each do |t|&lt;br /&gt;
        # Wait for the thread to finish if it isn't this thread (i.e. the main thread).&lt;br /&gt;
        t.join if t != Thread.current&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewees is reduced from 89.93 to 16.64&lt;br /&gt;
:* Cognitive Complexity is reduced from 17 to 7&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_sentence'''===&lt;br /&gt;
:This method calls web service to store each summary in a hashmap and use the question as the key.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Removed variable ''summary''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_8.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - break_up_comments_to_sentences'''===&lt;br /&gt;
: This method adds the comment to an array to be converted as a json request.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:The method is broken down into 2 smaller methods namely ''break_up_comments_to_sentences'' and ''get_sentences'' where ''get_sentences'' is called by ''break_up_comments_to_sentences'' to  get sentences in desired format.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_9.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact''':&lt;br /&gt;
:*The Cognitive complexity of break_up_comments_to_sentences reduced from 6 to &amp;lt;5&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - get_questions_by_assignment'''===&lt;br /&gt;
:This method returns the rubric for given assignment&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_10.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - calculate_avg_score_by_round'''===&lt;br /&gt;
:This method is used to calculate average round score for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Refactored the method into 2 smaller methods namely ''calculate_avg_score_by_round'' and ''calculate_round_score'' where ''calculate_avg_score_by_round'' calls ''calculate_round_score'' to calculate average round score and ''calculate_avg_score_by_round'' rounds the round_score upto 2 decimal places.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = 0.0&lt;br /&gt;
      sum_weight = 0&lt;br /&gt;
&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = sum_weight = 0.0&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
      round_score&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:*Assignment Branch Condition size for calculate_avg_score_by_round is reduced from 18.57 to &amp;lt;15.&lt;br /&gt;
&lt;br /&gt;
=='''Future improvement'''==&lt;br /&gt;
* Modularize ''summarize_by_rounds'' to even smaller modules so that Assignment Branch Condition size is reduced from 36.73 to 15.00.&lt;br /&gt;
* Create more test cases for the new modularized methods.&lt;br /&gt;
&lt;br /&gt;
=='''Contributors'''==&lt;br /&gt;
* [mailto:jviswan@ncsu.edu Jayalakshmi Viswanathan]&lt;br /&gt;
* [mailto:skundal@ncsu.edu Sandeep Kundala]&lt;br /&gt;
* [mailto:spal3@ncsu.edu Sumitosh Pal]&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132162</id>
		<title>CSC/ECE 517 Spring 2020 - Project E2008. Refactor summary helper.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132162"/>
		<updated>2020-03-29T13:52:07Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* Refactor - summarize_reviews_by_reviewees */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''About Expertiza'''==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed using Ruby on Rails Framework whose creation and maintenance are taken care of by students as well as the faculty of NCSU. Its code is available on Github [https://github.com/expertiza/expertiza Expertiza on GitHub]. Expertiza allows the instructor to create and edit new as well as existing assignments. This also includes creating a wide range of topics under each assignment that students can sign up for. They can also publish surveys and reviews, view statistical results, set deadlines for assignments and make announcements. It provides a platform for students to signup for topics, form teams, view and submit assignments and give peer reviews and feedback.&lt;br /&gt;
&lt;br /&gt;
=='''Problem Statement'''==&lt;br /&gt;
'''Background:''' In Expertiza students can review each other’s projects and even each other as teammates. Students can view their project scores and instructors can view student's teammate review scores on the view scores page. This helper file aids in calculating these scores and rendering the results on the view scores section of an assignment. Summary helper is a helper module that consists of methods used to calculate scores for these reviews. This is for the use of instructors.&lt;br /&gt;
&lt;br /&gt;
'''Requirement:'''&lt;br /&gt;
E2008 is an Expertiza OSS project which deals basically with refactoring app/helpers/summary_helper.rb to reduce the code climate issues such as&lt;br /&gt;
&lt;br /&gt;
* [http://wiki.c2.com/?AbcMetric Assignment Branch Condition]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Cognitive_complexity Cognitive Complexity]&lt;br /&gt;
* Method/line too long&lt;br /&gt;
* Unused variables / access modifiers&lt;br /&gt;
&lt;br /&gt;
'''A good method should have:'''&lt;br /&gt;
* Assignment Branch Condition size &amp;lt; 15&lt;br /&gt;
* Cognitive Complexity &amp;lt; 6&lt;br /&gt;
* No. of lines in a method &amp;lt; 25&lt;br /&gt;
&lt;br /&gt;
=='''Issues found'''==&lt;br /&gt;
The following are issues which were found in the code:&lt;br /&gt;
&lt;br /&gt;
==='''Assignment Branch Condition'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! ABC Size&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewee&lt;br /&gt;
| 44.61&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 42.34&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 89.93&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 16.43&lt;br /&gt;
|-&lt;br /&gt;
| calculate_avg_score_by_round&lt;br /&gt;
| 18.57&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
==='''Cognitive Complexity'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! Cognitive Complexity&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 16&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 17&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 11&lt;br /&gt;
|-&lt;br /&gt;
| break_up_comments_to_sentences&lt;br /&gt;
| 6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Method/line too long'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method/Line too long&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewees&lt;br /&gt;
|'''Lines of Code:'''39&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_criterion  &lt;br /&gt;
|'''Lines of Code:'''27&lt;br /&gt;
|-&lt;br /&gt;
|'''Line:''' 145&lt;br /&gt;
|self.avg_scores_by_round[reviewee.name][round] too long (162/160)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==='''Unused variables / access modifiers'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Vaiable/Access Modifier&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' summary  &lt;br /&gt;
|'''Method:''' summarize_sentences&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' included_question_counter  &lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewee&lt;br /&gt;
|-&lt;br /&gt;
|'''Access Modifier:''' module_function  &lt;br /&gt;
|'''Class:''' Summary&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=='''Solution Implemented'''==&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewee'''===&lt;br /&gt;
:This method is used to summarize reviews by a reviewer for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:''' &lt;br /&gt;
:This method could be refactored into smaller methods namely ''summarize_reviews_by_reviewee'' and ''summarize_reviews_by_reviewee_assign'' where ''summarize_reviews_by_reviewee'' calls ''summarize_reviews_by_reviewee_assign'' to get average scores and summary for each question.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewee is reduced from 44.61 to 20.64.&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_criterion'''===&lt;br /&gt;
:This method is used to summarize the review for each questions&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 3 smaller methods namely ''summarize_reviews_by_criterion'', ''summarize_reviews_by_criterion_questions'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion'' calls ''summarize_reviews_by_criterion_questions'' to get answers of each question in the rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion_questions'' starts many threads to process each question and closes it by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_3.jpg]]&lt;br /&gt;
:[[File:e2008_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_criterion is reduced from 42.34 to 17.2&lt;br /&gt;
:* Cognitive complexity is reduced from 16 to 7&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewees'''===&lt;br /&gt;
:This method is used to produce summaries for instructor and students. It sums up the feedback by criterion for each reviewer&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 4 smaller methods namely ''summarize_reviews_by_reviewees'', ''summarize_reviews_by_teams'', ''summarize_by_rounds'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_reviewees'' calls ''summarize_reviews_by_teams''  which inturn calls ''summarize_by_rounds'' to get answers of each reviewer by rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_by_rounds'' starts many threads to create requests to summarize the comments and closes the threads by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def summarize_reviews_by_reviewees(assignment, summary_ws_url)&lt;br /&gt;
      # @summary[reviewee][round][question]&lt;br /&gt;
      # @reviewers[team][reviewer]&lt;br /&gt;
      # @avg_scores_by_reviewee[team]&lt;br /&gt;
      # @avg_score_round[reviewee][round]&lt;br /&gt;
      # @avg_scores_by_criterion[reviewee][round][criterion]&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_reviewee = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.reviewers = ({})&lt;br /&gt;
      threads = []&lt;br /&gt;
&lt;br /&gt;
      # get all criteria used in each round&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get all teams in this assignment&lt;br /&gt;
      teams = Team.select(:id, :name).where(parent_id: assignment.id).order(:name)&lt;br /&gt;
&lt;br /&gt;
      teams.each do |reviewee|&lt;br /&gt;
        self.summary[reviewee.name] = []&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = 0.0&lt;br /&gt;
        self.avg_scores_by_round[reviewee.name] = []&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name] = []&lt;br /&gt;
&lt;br /&gt;
        # get the name of reviewers for display only&lt;br /&gt;
        self.reviewers[reviewee.name] = get_reviewers_by_reviewee_and_assignment(reviewee, assignment.id)&lt;br /&gt;
&lt;br /&gt;
        # get answers of each reviewer by rubric&lt;br /&gt;
        (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
          self.summary[reviewee.name][round] = {}&lt;br /&gt;
          self.avg_scores_by_round[reviewee.name][round] = 0.0&lt;br /&gt;
          self.avg_scores_by_criterion[reviewee.name][round] = {}&lt;br /&gt;
&lt;br /&gt;
          # iterate each round and get answers&lt;br /&gt;
          # if use the same rubric, only use rubric[0]&lt;br /&gt;
          rubric_questions_used = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
          rubric_questions_used.each do |q|&lt;br /&gt;
            next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
            summary[reviewee.name][round][q.txt] = &amp;quot;&amp;quot;&lt;br /&gt;
            self.avg_scores_by_criterion[reviewee.name][round][q.txt] = 0.0&lt;br /&gt;
&lt;br /&gt;
            # get all answers to this question&lt;br /&gt;
            question_answers = Answer.answers_by_question_for_reviewee_in_round(assignment.id, reviewee.id, q.id, round + 1)&lt;br /&gt;
            # get max score of this rubric&lt;br /&gt;
            q_max_score = get_max_score_for_question(q)&lt;br /&gt;
&lt;br /&gt;
            comments = break_up_comments_to_sentences(question_answers)&lt;br /&gt;
            # get score and summary of answers for each question&lt;br /&gt;
            self.avg_scores_by_criterion[reviewee.name][round][q.txt] = calculate_avg_score_by_criterion(question_answers, q_max_score)&lt;br /&gt;
&lt;br /&gt;
            # summarize the comments by calling the summarization Web Service&lt;br /&gt;
&lt;br /&gt;
            # since it'll do a lot of request, do this in seperate threads&lt;br /&gt;
            threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
              summary[reviewee.name][round][q.txt] = summarize_sentences(comments, summary_ws_url) unless comments.empty?&lt;br /&gt;
            end&lt;br /&gt;
          end&lt;br /&gt;
          self.avg_scores_by_round[reviewee.name][round] = calculate_avg_score_by_round(self.avg_scores_by_criterion[reviewee.name][round], rubric_questions_used)&lt;br /&gt;
        end&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = calculate_avg_score_by_reviewee(self.avg_scores_by_round[reviewee.name], assignment.rounds_of_reviews)&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      threads.each do |t|&lt;br /&gt;
        t.join if t != Thread.current&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def summarize_reviews_by_reviewees(assignment, summary_ws_url)&lt;br /&gt;
      # @summary[reviewee][round][question]&lt;br /&gt;
      # @reviewers[team][reviewer]&lt;br /&gt;
      # @avg_scores_by_reviewee[team]&lt;br /&gt;
      # @avg_score_round[reviewee][round]&lt;br /&gt;
      # @avg_scores_by_criterion[reviewee][round][criterion]&lt;br /&gt;
      self.summary = ({})&lt;br /&gt;
      self.avg_scores_by_reviewee = ({})&lt;br /&gt;
      self.avg_scores_by_round = ({})&lt;br /&gt;
      self.avg_scores_by_criterion = ({})&lt;br /&gt;
      self.reviewers = ({})&lt;br /&gt;
      self.summary_ws_url = summary_ws_url&lt;br /&gt;
&lt;br /&gt;
      # get all criteria used in each round&lt;br /&gt;
      rubric = get_questions_by_assignment(assignment)&lt;br /&gt;
&lt;br /&gt;
      # get all teams in this assignment&lt;br /&gt;
      teams = Team.select(:id, :name).where(parent_id: assignment.id).order(:name)&lt;br /&gt;
&lt;br /&gt;
      teams.each do |reviewee|&lt;br /&gt;
        summarize_reviews_by_team_reviewee(assignment, reviewee, rubric)&lt;br /&gt;
        self.avg_scores_by_reviewee[reviewee.name] = calculate_avg_score_by_reviewee(self.avg_scores_by_round[reviewee.name], assignment.rounds_of_reviews)&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      self&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def summarize_reviews_by_team_reviewee(assignment, reviewee, rubric)&lt;br /&gt;
      self.summary[reviewee.name] = []&lt;br /&gt;
      self.avg_scores_by_reviewee[reviewee.name] = 0.0&lt;br /&gt;
      self.avg_scores_by_round[reviewee.name] = self.avg_scores_by_criterion[reviewee.name] = []&lt;br /&gt;
&lt;br /&gt;
      # get the name of reviewers for display only&lt;br /&gt;
      self.reviewers[reviewee.name] = get_reviewers_by_reviewee_and_assignment(reviewee, assignment.id)&lt;br /&gt;
&lt;br /&gt;
      # get answers of each reviewer by rubric&lt;br /&gt;
      (0..assignment.rounds_of_reviews - 1).each do |round|&lt;br /&gt;
        self.summary[reviewee.name][round] = {}&lt;br /&gt;
        self.avg_scores_by_round[reviewee.name][round] = 0.0&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name][round] = {}&lt;br /&gt;
        summarize_by_reviewee_round(assignment, reviewee, round, rubric)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def summarize_by_reviewee_round(assignment, reviewee, round, rubric)&lt;br /&gt;
      threads = []&lt;br /&gt;
      # iterate each round and get answers&lt;br /&gt;
      # if use the same rubric, only use rubric[0]&lt;br /&gt;
      rubric_questions_used = rubric[assignment.varying_rubrics_by_round? ? round : 0]&lt;br /&gt;
      rubric_questions_used.each do |q|&lt;br /&gt;
        next if q.type.eql?(&amp;quot;SectionHeader&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # get all answers to this question&lt;br /&gt;
        question_answers = Answer.answers_by_question_for_reviewee_in_round(assignment.id, reviewee.id, q.id, round + 1)&lt;br /&gt;
&lt;br /&gt;
        # get score and summary of answers for each question&lt;br /&gt;
        self.avg_scores_by_criterion[reviewee.name][round][q.txt] = calculate_avg_score_by_criterion(question_answers, get_max_score_for_question(q))&lt;br /&gt;
&lt;br /&gt;
        # summarize the comments by calling the summarization Web Service&lt;br /&gt;
        # since it'll do a lot of request, do this in seperate threads&lt;br /&gt;
        threads &amp;lt;&amp;lt; Thread.new do&lt;br /&gt;
          self.summary[reviewee.name][round][q.txt] = summarize_sentences(break_up_comments_to_sentences(question_answers), self.summary_ws_url)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      avg_scores_by_round = calculate_avg_score_by_round(self.avg_scores_by_criterion[reviewee.name][round], rubric_questions_used)&lt;br /&gt;
      self.avg_scores_by_round[reviewee.name][round] = avg_scores_by_round&lt;br /&gt;
      # Wait for all threads to end&lt;br /&gt;
      end_threads(threads)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    def end_threads(threads)&lt;br /&gt;
      threads.each do |t|&lt;br /&gt;
        # Wait for the thread to finish if it isn't this thread (i.e. the main thread).&lt;br /&gt;
        t.join if t != Thread.current&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewees is reduced from 89.93 to 16.64&lt;br /&gt;
:* Cognitive Complexity is reduced from 17 to 7&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_sentence'''===&lt;br /&gt;
:This method calls web service to store each summary in a hashmap and use the question as the key.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Removed variable ''summary''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_8.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - break_up_comments_to_sentences'''===&lt;br /&gt;
: This method adds the comment to an array to be converted as a json request.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:The method is broken down into 2 smaller methods namely ''break_up_comments_to_sentences'' and ''get_sentences'' where ''get_sentences'' is called by ''break_up_comments_to_sentences'' to  get sentences in desired format.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_9.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact''':&lt;br /&gt;
:*The Cognitive complexity of break_up_comments_to_sentences reduced from 6 to &amp;lt;5&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - get_questions_by_assignment'''===&lt;br /&gt;
:This method returns the rubric for given assignment&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_10.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - calculate_avg_score_by_round'''===&lt;br /&gt;
:This method is used to calculate average round score for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Refactored the method into 2 smaller methods namely ''calculate_avg_score_by_round'' and ''calculate_round_score'' where ''calculate_avg_score_by_round'' calls ''calculate_round_score'' to calculate average round score and ''calculate_avg_score_by_round'' rounds the round_score upto 2 decimal places.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = 0.0&lt;br /&gt;
      sum_weight = 0&lt;br /&gt;
&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = sum_weight = 0.0&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
      round_score&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:*Assignment Branch Condition size for calculate_avg_score_by_round is reduced from 18.57 to &amp;lt;15.&lt;br /&gt;
&lt;br /&gt;
=='''Future improvement'''==&lt;br /&gt;
* Modularize ''summarize_by_rounds'' to even smaller modules so that Assignment Branch Condition size is reduced from 36.73 to 15.00.&lt;br /&gt;
* Create more test cases for the new modularized methods.&lt;br /&gt;
&lt;br /&gt;
=='''Contributors'''==&lt;br /&gt;
* [mailto:jviswan@ncsu.edu Jayalakshmi Viswanathan]&lt;br /&gt;
* [mailto:skundal@ncsu.edu Sandeep Kundala]&lt;br /&gt;
* [mailto:spal3@ncsu.edu Sumitosh Pal]&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132161</id>
		<title>CSC/ECE 517 Spring 2020 - Project E2008. Refactor summary helper.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132161"/>
		<updated>2020-03-29T13:41:58Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* Refactor - calculate_avg_score_by_round */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''About Expertiza'''==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed using Ruby on Rails Framework whose creation and maintenance are taken care of by students as well as the faculty of NCSU. Its code is available on Github [https://github.com/expertiza/expertiza Expertiza on GitHub]. Expertiza allows the instructor to create and edit new as well as existing assignments. This also includes creating a wide range of topics under each assignment that students can sign up for. They can also publish surveys and reviews, view statistical results, set deadlines for assignments and make announcements. It provides a platform for students to signup for topics, form teams, view and submit assignments and give peer reviews and feedback.&lt;br /&gt;
&lt;br /&gt;
=='''Problem Statement'''==&lt;br /&gt;
'''Background:''' In Expertiza students can review each other’s projects and even each other as teammates. Students can view their project scores and instructors can view student's teammate review scores on the view scores page. This helper file aids in calculating these scores and rendering the results on the view scores section of an assignment. Summary helper is a helper module that consists of methods used to calculate scores for these reviews. This is for the use of instructors.&lt;br /&gt;
&lt;br /&gt;
'''Requirement:'''&lt;br /&gt;
E2008 is an Expertiza OSS project which deals basically with refactoring app/helpers/summary_helper.rb to reduce the code climate issues such as&lt;br /&gt;
&lt;br /&gt;
* [http://wiki.c2.com/?AbcMetric Assignment Branch Condition]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Cognitive_complexity Cognitive Complexity]&lt;br /&gt;
* Method/line too long&lt;br /&gt;
* Unused variables / access modifiers&lt;br /&gt;
&lt;br /&gt;
'''A good method should have:'''&lt;br /&gt;
* Assignment Branch Condition size &amp;lt; 15&lt;br /&gt;
* Cognitive Complexity &amp;lt; 6&lt;br /&gt;
* No. of lines in a method &amp;lt; 25&lt;br /&gt;
&lt;br /&gt;
=='''Issues found'''==&lt;br /&gt;
The following are issues which were found in the code:&lt;br /&gt;
&lt;br /&gt;
==='''Assignment Branch Condition'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! ABC Size&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewee&lt;br /&gt;
| 44.61&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 42.34&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 89.93&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 16.43&lt;br /&gt;
|-&lt;br /&gt;
| calculate_avg_score_by_round&lt;br /&gt;
| 18.57&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
==='''Cognitive Complexity'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! Cognitive Complexity&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 16&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 17&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 11&lt;br /&gt;
|-&lt;br /&gt;
| break_up_comments_to_sentences&lt;br /&gt;
| 6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Method/line too long'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method/Line too long&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewees&lt;br /&gt;
|'''Lines of Code:'''39&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_criterion  &lt;br /&gt;
|'''Lines of Code:'''27&lt;br /&gt;
|-&lt;br /&gt;
|'''Line:''' 145&lt;br /&gt;
|self.avg_scores_by_round[reviewee.name][round] too long (162/160)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==='''Unused variables / access modifiers'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Vaiable/Access Modifier&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' summary  &lt;br /&gt;
|'''Method:''' summarize_sentences&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' included_question_counter  &lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewee&lt;br /&gt;
|-&lt;br /&gt;
|'''Access Modifier:''' module_function  &lt;br /&gt;
|'''Class:''' Summary&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=='''Solution Implemented'''==&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewee'''===&lt;br /&gt;
:This method is used to summarize reviews by a reviewer for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:''' &lt;br /&gt;
:This method could be refactored into smaller methods namely ''summarize_reviews_by_reviewee'' and ''summarize_reviews_by_reviewee_assign'' where ''summarize_reviews_by_reviewee'' calls ''summarize_reviews_by_reviewee_assign'' to get average scores and summary for each question.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewee is reduced from 44.61 to 20.64.&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_criterion'''===&lt;br /&gt;
:This method is used to summarize the review for each questions&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 3 smaller methods namely ''summarize_reviews_by_criterion'', ''summarize_reviews_by_criterion_questions'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion'' calls ''summarize_reviews_by_criterion_questions'' to get answers of each question in the rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion_questions'' starts many threads to process each question and closes it by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_3.jpg]]&lt;br /&gt;
:[[File:e2008_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_criterion is reduced from 42.34 to 17.2&lt;br /&gt;
:* Cognitive complexity is reduced from 16 to 7&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewees'''===&lt;br /&gt;
:This method is used to produce summaries for instructor and students. It sums up the feedback by criterion for each reviewer&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 4 smaller methods namely ''summarize_reviews_by_reviewees'', ''summarize_reviews_by_teams'', ''summarize_by_rounds'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_reviewees'' calls ''summarize_reviews_by_teams''  which inturn calls ''summarize_by_rounds'' to get answers of each reviewer by rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_by_rounds'' starts many threads to create requests to summarize the comments and closes the threads by calling the function ''end_threads''.&lt;br /&gt;
:[[File:e2008_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_6.jpg]]&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_7.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewees is reduced from 89.93 to 16.64&lt;br /&gt;
:* Cognitive Complexity is reduced from 17 to 7&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_sentence'''===&lt;br /&gt;
:This method calls web service to store each summary in a hashmap and use the question as the key.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Removed variable ''summary''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_8.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - break_up_comments_to_sentences'''===&lt;br /&gt;
: This method adds the comment to an array to be converted as a json request.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:The method is broken down into 2 smaller methods namely ''break_up_comments_to_sentences'' and ''get_sentences'' where ''get_sentences'' is called by ''break_up_comments_to_sentences'' to  get sentences in desired format.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_9.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact''':&lt;br /&gt;
:*The Cognitive complexity of break_up_comments_to_sentences reduced from 6 to &amp;lt;5&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - get_questions_by_assignment'''===&lt;br /&gt;
:This method returns the rubric for given assignment&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_10.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - calculate_avg_score_by_round'''===&lt;br /&gt;
:This method is used to calculate average round score for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Refactored the method into 2 smaller methods namely ''calculate_avg_score_by_round'' and ''calculate_round_score'' where ''calculate_avg_score_by_round'' calls ''calculate_round_score'' to calculate average round score and ''calculate_avg_score_by_round'' rounds the round_score upto 2 decimal places.&lt;br /&gt;
&lt;br /&gt;
:'''Before:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = 0.0&lt;br /&gt;
      sum_weight = 0&lt;br /&gt;
&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''After:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = sum_weight = 0.0&lt;br /&gt;
      criteria.each do |q|&lt;br /&gt;
        # include this score in the average round score if the weight is valid &amp;amp; q is criterion&lt;br /&gt;
        if !q.weight.nil? and q.weight &amp;gt; 0 and q.type.eql?(&amp;quot;Criterion&amp;quot;)&lt;br /&gt;
          round_score += avg_scores_by_criterion[q.txt] * q.weight&lt;br /&gt;
          sum_weight += q.weight&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      round_score /= sum_weight if sum_weight &amp;gt; 0 and round_score &amp;gt; 0&lt;br /&gt;
      round_score&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    def calculate_avg_score_by_round(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score = calculate_round_score(avg_scores_by_criterion, criteria)&lt;br /&gt;
      round_score.round(2)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:*Assignment Branch Condition size for calculate_avg_score_by_round is reduced from 18.57 to &amp;lt;15.&lt;br /&gt;
&lt;br /&gt;
=='''Future improvement'''==&lt;br /&gt;
* Modularize ''summarize_by_rounds'' to even smaller modules so that Assignment Branch Condition size is reduced from 36.73 to 15.00.&lt;br /&gt;
* Create more test cases for the new modularized methods.&lt;br /&gt;
&lt;br /&gt;
=='''Contributors'''==&lt;br /&gt;
* [mailto:jviswan@ncsu.edu Jayalakshmi Viswanathan]&lt;br /&gt;
* [mailto:skundal@ncsu.edu Sandeep Kundala]&lt;br /&gt;
* [mailto:spal3@ncsu.edu Sumitosh Pal]&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132160</id>
		<title>CSC/ECE 517 Spring 2020 - Project E2008. Refactor summary helper.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132160"/>
		<updated>2020-03-29T13:35:39Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* Problem Statement */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''About Expertiza'''==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed using Ruby on Rails Framework whose creation and maintenance are taken care of by students as well as the faculty of NCSU. Its code is available on Github [https://github.com/expertiza/expertiza Expertiza on GitHub]. Expertiza allows the instructor to create and edit new as well as existing assignments. This also includes creating a wide range of topics under each assignment that students can sign up for. They can also publish surveys and reviews, view statistical results, set deadlines for assignments and make announcements. It provides a platform for students to signup for topics, form teams, view and submit assignments and give peer reviews and feedback.&lt;br /&gt;
&lt;br /&gt;
=='''Problem Statement'''==&lt;br /&gt;
'''Background:''' In Expertiza students can review each other’s projects and even each other as teammates. Students can view their project scores and instructors can view student's teammate review scores on the view scores page. This helper file aids in calculating these scores and rendering the results on the view scores section of an assignment. Summary helper is a helper module that consists of methods used to calculate scores for these reviews. This is for the use of instructors.&lt;br /&gt;
&lt;br /&gt;
'''Requirement:'''&lt;br /&gt;
E2008 is an Expertiza OSS project which deals basically with refactoring app/helpers/summary_helper.rb to reduce the code climate issues such as&lt;br /&gt;
&lt;br /&gt;
* [http://wiki.c2.com/?AbcMetric Assignment Branch Condition]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Cognitive_complexity Cognitive Complexity]&lt;br /&gt;
* Method/line too long&lt;br /&gt;
* Unused variables / access modifiers&lt;br /&gt;
&lt;br /&gt;
'''A good method should have:'''&lt;br /&gt;
* Assignment Branch Condition size &amp;lt; 15&lt;br /&gt;
* Cognitive Complexity &amp;lt; 6&lt;br /&gt;
* No. of lines in a method &amp;lt; 25&lt;br /&gt;
&lt;br /&gt;
=='''Issues found'''==&lt;br /&gt;
The following are issues which were found in the code:&lt;br /&gt;
&lt;br /&gt;
==='''Assignment Branch Condition'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! ABC Size&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewee&lt;br /&gt;
| 44.61&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 42.34&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 89.93&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 16.43&lt;br /&gt;
|-&lt;br /&gt;
| calculate_avg_score_by_round&lt;br /&gt;
| 18.57&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
==='''Cognitive Complexity'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! Cognitive Complexity&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 16&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 17&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 11&lt;br /&gt;
|-&lt;br /&gt;
| break_up_comments_to_sentences&lt;br /&gt;
| 6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Method/line too long'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method/Line too long&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewees&lt;br /&gt;
|'''Lines of Code:'''39&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_criterion  &lt;br /&gt;
|'''Lines of Code:'''27&lt;br /&gt;
|-&lt;br /&gt;
|'''Line:''' 145&lt;br /&gt;
|self.avg_scores_by_round[reviewee.name][round] too long (162/160)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==='''Unused variables / access modifiers'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Vaiable/Access Modifier&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' summary  &lt;br /&gt;
|'''Method:''' summarize_sentences&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' included_question_counter  &lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewee&lt;br /&gt;
|-&lt;br /&gt;
|'''Access Modifier:''' module_function  &lt;br /&gt;
|'''Class:''' Summary&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=='''Solution Implemented'''==&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewee'''===&lt;br /&gt;
:This method is used to summarize reviews by a reviewer for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:''' &lt;br /&gt;
:This method could be refactored into smaller methods namely ''summarize_reviews_by_reviewee'' and ''summarize_reviews_by_reviewee_assign'' where ''summarize_reviews_by_reviewee'' calls ''summarize_reviews_by_reviewee_assign'' to get average scores and summary for each question.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewee is reduced from 44.61 to 20.64.&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_criterion'''===&lt;br /&gt;
:This method is used to summarize the review for each questions&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 3 smaller methods namely ''summarize_reviews_by_criterion'', ''summarize_reviews_by_criterion_questions'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion'' calls ''summarize_reviews_by_criterion_questions'' to get answers of each question in the rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion_questions'' starts many threads to process each question and closes it by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_3.jpg]]&lt;br /&gt;
:[[File:e2008_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_criterion is reduced from 42.34 to 17.2&lt;br /&gt;
:* Cognitive complexity is reduced from 16 to 7&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewees'''===&lt;br /&gt;
:This method is used to produce summaries for instructor and students. It sums up the feedback by criterion for each reviewer&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 4 smaller methods namely ''summarize_reviews_by_reviewees'', ''summarize_reviews_by_teams'', ''summarize_by_rounds'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_reviewees'' calls ''summarize_reviews_by_teams''  which inturn calls ''summarize_by_rounds'' to get answers of each reviewer by rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_by_rounds'' starts many threads to create requests to summarize the comments and closes the threads by calling the function ''end_threads''.&lt;br /&gt;
:[[File:e2008_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_6.jpg]]&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_7.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewees is reduced from 89.93 to 16.64&lt;br /&gt;
:* Cognitive Complexity is reduced from 17 to 7&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_sentence'''===&lt;br /&gt;
:This method calls web service to store each summary in a hashmap and use the question as the key.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Removed variable ''summary''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_8.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - break_up_comments_to_sentences'''===&lt;br /&gt;
: This method adds the comment to an array to be converted as a json request.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:The method is broken down into 2 smaller methods namely ''break_up_comments_to_sentences'' and ''get_sentences'' where ''get_sentences'' is called by ''break_up_comments_to_sentences'' to  get sentences in desired format.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_9.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact''':&lt;br /&gt;
:*The Cognitive complexity of break_up_comments_to_sentences reduced from 6 to &amp;lt;5&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - get_questions_by_assignment'''===&lt;br /&gt;
:This method returns the rubric for given assignment&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_10.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - calculate_avg_score_by_round'''===&lt;br /&gt;
:This method is used to calculate average round score for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Refactored the method into 2 smaller methods namely ''calculate_avg_score_by_round'' and ''calculate_round_score'' where ''calculate_avg_score_by_round'' calls ''calculate_round_score'' to calculate average round score and ''calculate_avg_score_by_round'' rounds the round_score upto 2 decimal places.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_11.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:*Assignment Branch Condition size for calculate_avg_score_by_round is reduced from 18.57 to &amp;lt;15.&lt;br /&gt;
&lt;br /&gt;
=='''Future improvement'''==&lt;br /&gt;
* Modularize ''summarize_by_rounds'' to even smaller modules so that Assignment Branch Condition size is reduced from 36.73 to 15.00.&lt;br /&gt;
* Create more test cases for the new modularized methods.&lt;br /&gt;
&lt;br /&gt;
=='''Contributors'''==&lt;br /&gt;
* [mailto:jviswan@ncsu.edu Jayalakshmi Viswanathan]&lt;br /&gt;
* [mailto:skundal@ncsu.edu Sandeep Kundala]&lt;br /&gt;
* [mailto:spal3@ncsu.edu Sumitosh Pal]&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132159</id>
		<title>CSC/ECE 517 Spring 2020 - Project E2008. Refactor summary helper.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132159"/>
		<updated>2020-03-29T13:35:16Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* Problem Statement */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''About Expertiza'''==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed using Ruby on Rails Framework whose creation and maintenance are taken care of by students as well as the faculty of NCSU. Its code is available on Github [https://github.com/expertiza/expertiza Expertiza on GitHub]. Expertiza allows the instructor to create and edit new as well as existing assignments. This also includes creating a wide range of topics under each assignment that students can sign up for. They can also publish surveys and reviews, view statistical results, set deadlines for assignments and make announcements. It provides a platform for students to signup for topics, form teams, view and submit assignments and give peer reviews and feedback.&lt;br /&gt;
&lt;br /&gt;
=='''Problem Statement'''==&lt;br /&gt;
'''Background:''' In Expertiza students can review each other’s projects and even each other as teammates. Students can view their project scores and instructors can view student's teammate review scores on the view scores page. This helper file aids in calculating these scores and rendering the results on the view scores section of an assignment. Summary helper is a helper module that consists of methods used to calculate scores for these reviews. This is for the use of instructors.&lt;br /&gt;
&lt;br /&gt;
'''Requirement:'''&lt;br /&gt;
E2008 is an Expertiza OSS project which deals basically with refactoring app/helpers/summary_helper.rb to reduce the code climate issues such as&lt;br /&gt;
&lt;br /&gt;
* [http://wiki.c2.com/?AbcMetric Assignment Branch Condition]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Cognitive_complexity Cognitive Complexity]&lt;br /&gt;
* Method/line too long&lt;br /&gt;
* Unused variables / access modifiers&lt;br /&gt;
&lt;br /&gt;
A good method should have:&lt;br /&gt;
* Assignment Branch Condition size &amp;lt; 15&lt;br /&gt;
* Cognitive Complexity &amp;lt; 6&lt;br /&gt;
* No. of lines in a method &amp;lt; 25&lt;br /&gt;
&lt;br /&gt;
=='''Issues found'''==&lt;br /&gt;
The following are issues which were found in the code:&lt;br /&gt;
&lt;br /&gt;
==='''Assignment Branch Condition'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! ABC Size&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewee&lt;br /&gt;
| 44.61&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 42.34&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 89.93&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 16.43&lt;br /&gt;
|-&lt;br /&gt;
| calculate_avg_score_by_round&lt;br /&gt;
| 18.57&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
==='''Cognitive Complexity'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! Cognitive Complexity&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 16&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 17&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 11&lt;br /&gt;
|-&lt;br /&gt;
| break_up_comments_to_sentences&lt;br /&gt;
| 6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Method/line too long'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method/Line too long&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewees&lt;br /&gt;
|'''Lines of Code:'''39&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_criterion  &lt;br /&gt;
|'''Lines of Code:'''27&lt;br /&gt;
|-&lt;br /&gt;
|'''Line:''' 145&lt;br /&gt;
|self.avg_scores_by_round[reviewee.name][round] too long (162/160)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==='''Unused variables / access modifiers'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Vaiable/Access Modifier&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' summary  &lt;br /&gt;
|'''Method:''' summarize_sentences&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' included_question_counter  &lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewee&lt;br /&gt;
|-&lt;br /&gt;
|'''Access Modifier:''' module_function  &lt;br /&gt;
|'''Class:''' Summary&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=='''Solution Implemented'''==&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewee'''===&lt;br /&gt;
:This method is used to summarize reviews by a reviewer for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:''' &lt;br /&gt;
:This method could be refactored into smaller methods namely ''summarize_reviews_by_reviewee'' and ''summarize_reviews_by_reviewee_assign'' where ''summarize_reviews_by_reviewee'' calls ''summarize_reviews_by_reviewee_assign'' to get average scores and summary for each question.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewee is reduced from 44.61 to 20.64.&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_criterion'''===&lt;br /&gt;
:This method is used to summarize the review for each questions&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 3 smaller methods namely ''summarize_reviews_by_criterion'', ''summarize_reviews_by_criterion_questions'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion'' calls ''summarize_reviews_by_criterion_questions'' to get answers of each question in the rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion_questions'' starts many threads to process each question and closes it by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_3.jpg]]&lt;br /&gt;
:[[File:e2008_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_criterion is reduced from 42.34 to 17.2&lt;br /&gt;
:* Cognitive complexity is reduced from 16 to 7&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewees'''===&lt;br /&gt;
:This method is used to produce summaries for instructor and students. It sums up the feedback by criterion for each reviewer&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 4 smaller methods namely ''summarize_reviews_by_reviewees'', ''summarize_reviews_by_teams'', ''summarize_by_rounds'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_reviewees'' calls ''summarize_reviews_by_teams''  which inturn calls ''summarize_by_rounds'' to get answers of each reviewer by rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_by_rounds'' starts many threads to create requests to summarize the comments and closes the threads by calling the function ''end_threads''.&lt;br /&gt;
:[[File:e2008_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_6.jpg]]&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_7.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewees is reduced from 89.93 to 16.64&lt;br /&gt;
:* Cognitive Complexity is reduced from 17 to 7&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_sentence'''===&lt;br /&gt;
:This method calls web service to store each summary in a hashmap and use the question as the key.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Removed variable ''summary''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_8.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - break_up_comments_to_sentences'''===&lt;br /&gt;
: This method adds the comment to an array to be converted as a json request.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:The method is broken down into 2 smaller methods namely ''break_up_comments_to_sentences'' and ''get_sentences'' where ''get_sentences'' is called by ''break_up_comments_to_sentences'' to  get sentences in desired format.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_9.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact''':&lt;br /&gt;
:*The Cognitive complexity of break_up_comments_to_sentences reduced from 6 to &amp;lt;5&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - get_questions_by_assignment'''===&lt;br /&gt;
:This method returns the rubric for given assignment&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_10.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - calculate_avg_score_by_round'''===&lt;br /&gt;
:This method is used to calculate average round score for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Refactored the method into 2 smaller methods namely ''calculate_avg_score_by_round'' and ''calculate_round_score'' where ''calculate_avg_score_by_round'' calls ''calculate_round_score'' to calculate average round score and ''calculate_avg_score_by_round'' rounds the round_score upto 2 decimal places.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_11.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:*Assignment Branch Condition size for calculate_avg_score_by_round is reduced from 18.57 to &amp;lt;15.&lt;br /&gt;
&lt;br /&gt;
=='''Future improvement'''==&lt;br /&gt;
* Modularize ''summarize_by_rounds'' to even smaller modules so that Assignment Branch Condition size is reduced from 36.73 to 15.00.&lt;br /&gt;
* Create more test cases for the new modularized methods.&lt;br /&gt;
&lt;br /&gt;
=='''Contributors'''==&lt;br /&gt;
* [mailto:jviswan@ncsu.edu Jayalakshmi Viswanathan]&lt;br /&gt;
* [mailto:skundal@ncsu.edu Sandeep Kundala]&lt;br /&gt;
* [mailto:spal3@ncsu.edu Sumitosh Pal]&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132158</id>
		<title>CSC/ECE 517 Spring 2020 - Project E2008. Refactor summary helper.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=132158"/>
		<updated>2020-03-29T13:33:43Z</updated>

		<summary type="html">&lt;p&gt;Skundal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''About Expertiza'''==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed using Ruby on Rails Framework whose creation and maintenance are taken care of by students as well as the faculty of NCSU. Its code is available on Github [https://github.com/expertiza/expertiza Expertiza on GitHub]. Expertiza allows the instructor to create and edit new as well as existing assignments. This also includes creating a wide range of topics under each assignment that students can sign up for. They can also publish surveys and reviews, view statistical results, set deadlines for assignments and make announcements. It provides a platform for students to signup for topics, form teams, view and submit assignments and give peer reviews and feedback.&lt;br /&gt;
&lt;br /&gt;
=='''Problem Statement'''==&lt;br /&gt;
'''Background:''' In Expertiza students can review each other’s projects and even each other as teammates. Students can view their project scores and instructors can view student's teammate review scores on the view scores page. This helper file aids in calculating these scores and rendering the results on the view scores section of an assignment. Summary helper is a helper module that consists of methods used to calculate scores for these reviews. This is for the use of instructors.&lt;br /&gt;
&lt;br /&gt;
'''Requirement:'''&lt;br /&gt;
E2008 is an Expertiza OSS project which deals basically with refactoring app/helpers/summary_helper.rb to reduce the code climate issues such as&lt;br /&gt;
&lt;br /&gt;
* [http://wiki.c2.com/?AbcMetric Assignment Branch Condition]&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Cyclomatic_complexity Cognitive Complexity]&lt;br /&gt;
* Method/line too long&lt;br /&gt;
* Unused variables / access modifiers&lt;br /&gt;
&lt;br /&gt;
A good method should have:&lt;br /&gt;
* Assignment Branch Condition size &amp;lt; 15&lt;br /&gt;
* Cognitive Complexity &amp;lt; 6&lt;br /&gt;
* No. of lines in a method &amp;lt; 25&lt;br /&gt;
&lt;br /&gt;
=='''Issues found'''==&lt;br /&gt;
The following are issues which were found in the code:&lt;br /&gt;
&lt;br /&gt;
==='''Assignment Branch Condition'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! ABC Size&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewee&lt;br /&gt;
| 44.61&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 42.34&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 89.93&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 16.43&lt;br /&gt;
|-&lt;br /&gt;
| calculate_avg_score_by_round&lt;br /&gt;
| 18.57&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
==='''Cognitive Complexity'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! Cognitive Complexity&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 16&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 17&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 11&lt;br /&gt;
|-&lt;br /&gt;
| break_up_comments_to_sentences&lt;br /&gt;
| 6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Method/line too long'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method/Line too long&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewees&lt;br /&gt;
|'''Lines of Code:'''39&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_criterion  &lt;br /&gt;
|'''Lines of Code:'''27&lt;br /&gt;
|-&lt;br /&gt;
|'''Line:''' 145&lt;br /&gt;
|self.avg_scores_by_round[reviewee.name][round] too long (162/160)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==='''Unused variables / access modifiers'''===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Vaiable/Access Modifier&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' summary  &lt;br /&gt;
|'''Method:''' summarize_sentences&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' included_question_counter  &lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewee&lt;br /&gt;
|-&lt;br /&gt;
|'''Access Modifier:''' module_function  &lt;br /&gt;
|'''Class:''' Summary&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=='''Solution Implemented'''==&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewee'''===&lt;br /&gt;
:This method is used to summarize reviews by a reviewer for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:''' &lt;br /&gt;
:This method could be refactored into smaller methods namely ''summarize_reviews_by_reviewee'' and ''summarize_reviews_by_reviewee_assign'' where ''summarize_reviews_by_reviewee'' calls ''summarize_reviews_by_reviewee_assign'' to get average scores and summary for each question.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewee is reduced from 44.61 to 20.64.&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_criterion'''===&lt;br /&gt;
:This method is used to summarize the review for each questions&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 3 smaller methods namely ''summarize_reviews_by_criterion'', ''summarize_reviews_by_criterion_questions'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion'' calls ''summarize_reviews_by_criterion_questions'' to get answers of each question in the rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion_questions'' starts many threads to process each question and closes it by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_3.jpg]]&lt;br /&gt;
:[[File:e2008_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_criterion is reduced from 42.34 to 17.2&lt;br /&gt;
:* Cognitive complexity is reduced from 16 to 7&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_reviews_by_reviewees'''===&lt;br /&gt;
:This method is used to produce summaries for instructor and students. It sums up the feedback by criterion for each reviewer&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 4 smaller methods namely ''summarize_reviews_by_reviewees'', ''summarize_reviews_by_teams'', ''summarize_by_rounds'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_reviewees'' calls ''summarize_reviews_by_teams''  which inturn calls ''summarize_by_rounds'' to get answers of each reviewer by rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_by_rounds'' starts many threads to create requests to summarize the comments and closes the threads by calling the function ''end_threads''.&lt;br /&gt;
:[[File:e2008_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_6.jpg]]&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_7.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewees is reduced from 89.93 to 16.64&lt;br /&gt;
:* Cognitive Complexity is reduced from 17 to 7&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - summarize_sentence'''===&lt;br /&gt;
:This method calls web service to store each summary in a hashmap and use the question as the key.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Removed variable ''summary''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_8.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - break_up_comments_to_sentences'''===&lt;br /&gt;
: This method adds the comment to an array to be converted as a json request.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:The method is broken down into 2 smaller methods namely ''break_up_comments_to_sentences'' and ''get_sentences'' where ''get_sentences'' is called by ''break_up_comments_to_sentences'' to  get sentences in desired format.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_9.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact''':&lt;br /&gt;
:*The Cognitive complexity of break_up_comments_to_sentences reduced from 6 to &amp;lt;5&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - get_questions_by_assignment'''===&lt;br /&gt;
:This method returns the rubric for given assignment&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_10.jpg]]&lt;br /&gt;
&lt;br /&gt;
==='''Refactor - calculate_avg_score_by_round'''===&lt;br /&gt;
:This method is used to calculate average round score for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Refactored the method into 2 smaller methods namely ''calculate_avg_score_by_round'' and ''calculate_round_score'' where ''calculate_avg_score_by_round'' calls ''calculate_round_score'' to calculate average round score and ''calculate_avg_score_by_round'' rounds the round_score upto 2 decimal places.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_11.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:*Assignment Branch Condition size for calculate_avg_score_by_round is reduced from 18.57 to &amp;lt;15.&lt;br /&gt;
&lt;br /&gt;
=='''Future improvement'''==&lt;br /&gt;
* Modularize ''summarize_by_rounds'' to even smaller modules so that Assignment Branch Condition size is reduced from 36.73 to 15.00.&lt;br /&gt;
* Create more test cases for the new modularized methods.&lt;br /&gt;
&lt;br /&gt;
=='''Contributors'''==&lt;br /&gt;
* [mailto:jviswan@ncsu.edu Jayalakshmi Viswanathan]&lt;br /&gt;
* [mailto:skundal@ncsu.edu Sandeep Kundala]&lt;br /&gt;
* [mailto:spal3@ncsu.edu Sumitosh Pal]&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:E2008_5.jpg&amp;diff=131706</id>
		<title>File:E2008 5.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:E2008_5.jpg&amp;diff=131706"/>
		<updated>2020-03-23T07:44:49Z</updated>

		<summary type="html">&lt;p&gt;Skundal: Skundal uploaded a new version of File:E2008 5.jpg&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:E2008_5.jpg&amp;diff=131705</id>
		<title>File:E2008 5.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:E2008_5.jpg&amp;diff=131705"/>
		<updated>2020-03-23T07:42:36Z</updated>

		<summary type="html">&lt;p&gt;Skundal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=131704</id>
		<title>CSC/ECE 517 Spring 2020 - Project E2008. Refactor summary helper.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=131704"/>
		<updated>2020-03-23T07:42:12Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* Solution Implemented */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page provides a description of the Expertiza based OSS project. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=='''About Expertiza'''==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed using Ruby on Rails Framework whose creation and maintenance are taken care of by students as well as the faculty of NCSU. Its code is available on Github [https://github.com/expertiza/expertiza Expertiza on GitHub]. Expertiza allows the instructor to create and edit new as well as existing assignments. This also includes creating a wide range of topics under each assignment that students can sign up for. They can also publish surveys and reviews, view statistical results, set deadlines for assignments and make announcements. It provides a platform for students to signup for topics, form teams, view and submit assignments and give peer reviews and feedback.&lt;br /&gt;
&lt;br /&gt;
=='''Problem Statement'''==&lt;br /&gt;
'''Background:''' In Expertiza students can review each other’s projects and even each other as teammates. Students can view their project scores and instructors can view student's teammate review scores on the view scores page. This helper file aids in calculating these scores and rendering the results on the view scores section of an assignment. Summary helper is a helper module that consists of methods used to calculate scores for these reviews. This is for the use of instructors.&lt;br /&gt;
&lt;br /&gt;
'''Requirement:'''&lt;br /&gt;
E2008 is an Expertiza OSS project which deals basically with refactoring app/helpers/summary_helper.rb to reduce the code climate issues such as&lt;br /&gt;
&lt;br /&gt;
* [http://wiki.c2.com/?AbcMetric Assignment Branch Condition]&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Cyclomatic_complexity Cognitive Complexity]&lt;br /&gt;
* Method/line too long&lt;br /&gt;
* Unused variables / access modifiers&lt;br /&gt;
&lt;br /&gt;
=='''Issues found'''==&lt;br /&gt;
The following are issues which were found in the code:&lt;br /&gt;
&lt;br /&gt;
* Assignment Branch Condition&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! ABC Size&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewee&lt;br /&gt;
| 44.61&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 42.34&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 89.93&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 16.43&lt;br /&gt;
|-&lt;br /&gt;
| calculate_avg_score_by_round&lt;br /&gt;
| 18.57&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
* Cognitive Complexity&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! Cognitive Complexity&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 16&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 17&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 11&lt;br /&gt;
|-&lt;br /&gt;
| break_up_comments_to_sentences&lt;br /&gt;
| 6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Method/line too long&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method/Line too long&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewees&lt;br /&gt;
|'''Lines of Code:'''39&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_criterion  &lt;br /&gt;
|'''Lines of Code:'''27&lt;br /&gt;
|-&lt;br /&gt;
|'''Line:''' 145&lt;br /&gt;
|self.avg_scores_by_round[reviewee.name][round] too long (162/160)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* Unused variables / access modifiers:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Vaiable/Access Modifier&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' summary  &lt;br /&gt;
|'''Method:''' summarize_sentences&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' included_question_counter  &lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewee&lt;br /&gt;
|-&lt;br /&gt;
|'''Access Modifier:''' module_function  &lt;br /&gt;
|'''Class:''' Summary&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=='''Solution Implemented'''==&lt;br /&gt;
* '''Refactor ''summarize_reviews_by_reviewee'':'''&lt;br /&gt;
:This method is used to summarize reviews by a reviewer for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:''' &lt;br /&gt;
:This method could be refactored into smaller methods namely ''summarize_reviews_by_reviewee'' and ''summarize_reviews_by_reviewee_assign'' where ''summarize_reviews_by_reviewee'' calls ''summarize_reviews_by_reviewee_assign'' to get average scores and summary for each question.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewee is reduced from 44.61 to 20.64.&lt;br /&gt;
&lt;br /&gt;
* '''Refactor ''summarize_reviews_by_criterion'':'''&lt;br /&gt;
:This method is used to summarize the review for each questions&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 3 smaller methods namely ''summarize_reviews_by_criterion'', ''summarize_reviews_by_criterion_questions'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion'' calls ''summarize_reviews_by_criterion_questions'' to get answers of each question in the rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion_questions'' starts many threads to process each question and closes it by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_3.jpg]]&lt;br /&gt;
:[[File:e2008_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_criterion is reduced from 42.34 to 17.2&lt;br /&gt;
:* Cognitive complexity is reduced from 16 to 7&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* '''Refactor ''summarize_reviews_by_reviewees'':'''&lt;br /&gt;
:This method is used to produce summaries for instructor and students. It sums up the feedback by criterion for each reviewer&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 4 smaller methods namely ''summarize_reviews_by_reviewees'', ''summarize_reviews_by_teams'', ''summarize_by_rounds'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_reviewees'' calls ''summarize_reviews_by_teams''  which inturn calls ''summarize_by_rounds'' to get answers of each reviewer by rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_by_rounds'' starts many threads to create requests to summarize the comments and closes the threads by calling the function ''end_threads''.&lt;br /&gt;
:[[File:e2008_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_6.jpg]]&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_7.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewees is reduced from 89.93 to 16.64&lt;br /&gt;
:* Cognitive Complexity is reduced from 17 to 7&lt;br /&gt;
&lt;br /&gt;
* '''Refactor ''summarize_sentence'':'''&lt;br /&gt;
:This method calls web service to store each summary in a hashmap and use the question as the key.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Removed variable ''summary''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_8.jpg]]&lt;br /&gt;
&lt;br /&gt;
* '''Refactor ''break_up_comments_to_sentences'':'''&lt;br /&gt;
: This method adds the comment to an array to be converted as a json request.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:The method is broken down into 2 smaller methods namely ''break_up_comments_to_sentences'' and ''get_sentences'' where ''get_sentences'' is called by ''break_up_comments_to_sentences'' to  get sentences in desired format.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_9.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact''':&lt;br /&gt;
:*The Cognitive complexity of break_up_comments_to_sentences reduced from 6 to &amp;lt;5&lt;br /&gt;
&lt;br /&gt;
* '''Refactor ''get_questions_by_assignment'':'''&lt;br /&gt;
:This method returns the rubric for given assignment&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_10.jpg]]&lt;br /&gt;
&lt;br /&gt;
* '''Refactor ''calculate_avg_score_by_round'':'''&lt;br /&gt;
:This method is used to calculate average round score for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Refactored the method into 2 smaller methods namely ''calculate_avg_score_by_round'' and ''calculate_round_score'' where ''calculate_avg_score_by_round'' calls ''calculate_round_score'' to calculate average round score and ''calculate_avg_score_by_round'' rounds the round_score upto 2 decimal places.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_11.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:*Assignment Branch Condition size for calculate_avg_score_by_round is reduced from 18.57 to &amp;lt;15.&lt;br /&gt;
&lt;br /&gt;
=='''Future improvement'''==&lt;br /&gt;
* Modularize ''summarize_by_rounds'' to even smaller modules so that Assignment Branch Condition size is reduced from 36.73 to 15.00.&lt;br /&gt;
* Create more test cases for the new modularized methods.&lt;br /&gt;
&lt;br /&gt;
=='''Contributors'''==&lt;br /&gt;
* [mailto:jviswan@ncsu.edu Jayalakshmi Viswanathan]&lt;br /&gt;
* [mailto:skundal@ncsu.edu Sandeep Kundala]&lt;br /&gt;
* [mailto:spal3@ncsu.edu Sumitosh Pal]&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:E2008_6.jpg&amp;diff=131703</id>
		<title>File:E2008 6.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:E2008_6.jpg&amp;diff=131703"/>
		<updated>2020-03-23T07:42:05Z</updated>

		<summary type="html">&lt;p&gt;Skundal: Skundal uploaded a new version of File:E2008 6.jpg&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=131702</id>
		<title>CSC/ECE 517 Spring 2020 - Project E2008. Refactor summary helper.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020_-_Project_E2008._Refactor_summary_helper.rb&amp;diff=131702"/>
		<updated>2020-03-23T07:39:22Z</updated>

		<summary type="html">&lt;p&gt;Skundal: /* Solution Implemented */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page provides a description of the Expertiza based OSS project. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=='''About Expertiza'''==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed using Ruby on Rails Framework whose creation and maintenance are taken care of by students as well as the faculty of NCSU. Its code is available on Github [https://github.com/expertiza/expertiza Expertiza on GitHub]. Expertiza allows the instructor to create and edit new as well as existing assignments. This also includes creating a wide range of topics under each assignment that students can sign up for. They can also publish surveys and reviews, view statistical results, set deadlines for assignments and make announcements. It provides a platform for students to signup for topics, form teams, view and submit assignments and give peer reviews and feedback.&lt;br /&gt;
&lt;br /&gt;
=='''Problem Statement'''==&lt;br /&gt;
'''Background:''' In Expertiza students can review each other’s projects and even each other as teammates. Students can view their project scores and instructors can view student's teammate review scores on the view scores page. This helper file aids in calculating these scores and rendering the results on the view scores section of an assignment. Summary helper is a helper module that consists of methods used to calculate scores for these reviews. This is for the use of instructors.&lt;br /&gt;
&lt;br /&gt;
'''Requirement:'''&lt;br /&gt;
E2008 is an Expertiza OSS project which deals basically with refactoring app/helpers/summary_helper.rb to reduce the code climate issues such as&lt;br /&gt;
&lt;br /&gt;
* [http://wiki.c2.com/?AbcMetric Assignment Branch Condition]&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Cyclomatic_complexity Cognitive Complexity]&lt;br /&gt;
* Method/line too long&lt;br /&gt;
* Unused variables / access modifiers&lt;br /&gt;
&lt;br /&gt;
=='''Issues found'''==&lt;br /&gt;
The following are issues which were found in the code:&lt;br /&gt;
&lt;br /&gt;
* Assignment Branch Condition&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! ABC Size&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewee&lt;br /&gt;
| 44.61&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 42.34&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 89.93&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 16.43&lt;br /&gt;
|-&lt;br /&gt;
| calculate_avg_score_by_round&lt;br /&gt;
| 18.57&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
* Cognitive Complexity&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! Cognitive Complexity&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_criterion&lt;br /&gt;
| 16&lt;br /&gt;
|-&lt;br /&gt;
| summarize_reviews_by_reviewees&lt;br /&gt;
| 17&lt;br /&gt;
|-&lt;br /&gt;
| get_questions_by_assignment&lt;br /&gt;
| 11&lt;br /&gt;
|-&lt;br /&gt;
| break_up_comments_to_sentences&lt;br /&gt;
| 6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Method/line too long&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method/Line too long&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewees&lt;br /&gt;
|'''Lines of Code:'''39&lt;br /&gt;
|-&lt;br /&gt;
|'''Method:''' summarize_reviews_by_criterion  &lt;br /&gt;
|'''Lines of Code:'''27&lt;br /&gt;
|-&lt;br /&gt;
|'''Line:''' 145&lt;br /&gt;
|self.avg_scores_by_round[reviewee.name][round] too long (162/160)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* Unused variables / access modifiers:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Vaiable/Access Modifier&lt;br /&gt;
! Comments&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' summary  &lt;br /&gt;
|'''Method:''' summarize_sentences&lt;br /&gt;
|-&lt;br /&gt;
|'''Variable:''' included_question_counter  &lt;br /&gt;
|'''Method:''' summarize_reviews_by_reviewee&lt;br /&gt;
|-&lt;br /&gt;
|'''Access Modifier:''' module_function  &lt;br /&gt;
|'''Class:''' Summary&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=='''Solution Implemented'''==&lt;br /&gt;
* '''Refactor ''summarize_reviews_by_reviewee'':'''&lt;br /&gt;
:This method is used to summarize reviews by a reviewer for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:''' &lt;br /&gt;
:This method could be refactored into smaller methods namely ''summarize_reviews_by_reviewee'' and ''summarize_reviews_by_reviewee_assign'' where ''summarize_reviews_by_reviewee'' calls ''summarize_reviews_by_reviewee_assign'' to get average scores and summary for each question.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewee is reduced from 44.61 to 20.64.&lt;br /&gt;
&lt;br /&gt;
* '''Refactor ''summarize_reviews_by_criterion'':'''&lt;br /&gt;
:This method is used to summarize the review for each questions&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 3 smaller methods namely ''summarize_reviews_by_criterion'', ''summarize_reviews_by_criterion_questions'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion'' calls ''summarize_reviews_by_criterion_questions'' to get answers of each question in the rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_criterion_questions'' starts many threads to process each question and closes it by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_3.jpg]]&lt;br /&gt;
:[[File:e2008_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_criterion is reduced from 42.34 to 17.2&lt;br /&gt;
:* Cognitive complexity is reduced from 16 to 7&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* '''Refactor ''summarize_reviews_by_reviewees'':'''&lt;br /&gt;
:This method is used to produce summaries for instructor and students. It sums up the feedback by criterion for each reviewer&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:This method was refactored into 4 smaller methods namely ''summarize_reviews_by_reviewees'', ''summarize_reviews_by_teams'', ''summarize_by_rounds'' and ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_reviews_by_reviewees'' calls ''summarize_reviews_by_teams''  which inturn calls ''summarize_by_rounds'' to get answers of each reviewer by rubric.&lt;br /&gt;
&lt;br /&gt;
:The method ''summarize_by_rounds'' starts many threads to create requests to summarize the comments and closes the threads by calling the function ''end_threads''.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_6.jpg]]&lt;br /&gt;
:[[File:e2008_7.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
&lt;br /&gt;
:* Assignment Branch Condition size for summarize_reviews_by_reviewees is reduced from 89.93 to 16.64&lt;br /&gt;
:* Cognitive Complexity is reduced from 17 to 7&lt;br /&gt;
&lt;br /&gt;
* '''Refactor ''summarize_sentence'':'''&lt;br /&gt;
:This method calls web service to store each summary in a hashmap and use the question as the key.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Removed variable ''summary''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_8.jpg]]&lt;br /&gt;
&lt;br /&gt;
* '''Refactor ''break_up_comments_to_sentences'':'''&lt;br /&gt;
: This method adds the comment to an array to be converted as a json request.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:The method is broken down into 2 smaller methods namely ''break_up_comments_to_sentences'' and ''get_sentences'' where ''get_sentences'' is called by ''break_up_comments_to_sentences'' to  get sentences in desired format.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_9.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact''':&lt;br /&gt;
:*The Cognitive complexity of break_up_comments_to_sentences reduced from 6 to &amp;lt;5&lt;br /&gt;
&lt;br /&gt;
* '''Refactor ''get_questions_by_assignment'':'''&lt;br /&gt;
:This method returns the rubric for given assignment&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_10.jpg]]&lt;br /&gt;
&lt;br /&gt;
* '''Refactor ''calculate_avg_score_by_round'':'''&lt;br /&gt;
:This method is used to calculate average round score for each question.&lt;br /&gt;
&lt;br /&gt;
:'''Changes Made:'''&lt;br /&gt;
&lt;br /&gt;
:Refactored the method into 2 smaller methods namely ''calculate_avg_score_by_round'' and ''calculate_round_score'' where ''calculate_avg_score_by_round'' calls ''calculate_round_score'' to calculate average round score and ''calculate_avg_score_by_round'' rounds the round_score upto 2 decimal places.&lt;br /&gt;
&lt;br /&gt;
:[[File:e2008_11.jpg]]&lt;br /&gt;
&lt;br /&gt;
:'''Impact:'''&lt;br /&gt;
:*Assignment Branch Condition size for calculate_avg_score_by_round is reduced from 18.57 to &amp;lt;15.&lt;br /&gt;
&lt;br /&gt;
=='''Future improvement'''==&lt;br /&gt;
* Modularize ''summarize_by_rounds'' to even smaller modules so that Assignment Branch Condition size is reduced from 36.73 to 15.00.&lt;br /&gt;
* Create more test cases for the new modularized methods.&lt;br /&gt;
&lt;br /&gt;
=='''Contributors'''==&lt;br /&gt;
* [mailto:jviswan@ncsu.edu Jayalakshmi Viswanathan]&lt;br /&gt;
* [mailto:skundal@ncsu.edu Sandeep Kundala]&lt;br /&gt;
* [mailto:spal3@ncsu.edu Sumitosh Pal]&lt;/div&gt;</summary>
		<author><name>Skundal</name></author>
	</entry>
</feed>