<?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=Amadhus2</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=Amadhus2"/>
	<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=Special:Contributions/Amadhus2"/>
	<updated>2026-06-03T18:16:23Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.41.0</generator>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support&amp;diff=124050</id>
		<title>CSC/ECE 517 Spring 2019 - Project M1901 Implement missing WebAudio automation support</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support&amp;diff=124050"/>
		<updated>2019-04-13T03:12:26Z</updated>

		<summary type="html">&lt;p&gt;Amadhus2: /* List of issues */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''Introduction'''== &lt;br /&gt;
&lt;br /&gt;
==='''Servo'''===&lt;br /&gt;
Servo is an developmental browser engine designed to make use of the memory safety properties and concurrency features of the Rust programming language. The project was initiated by Mozilla Research with effort from Samsung to port it to Android and ARM processors&lt;br /&gt;
&lt;br /&gt;
More information about Servo is available [https://servo.org here]&lt;br /&gt;
&lt;br /&gt;
==='''Rust'''===&lt;br /&gt;
Rust is a systems programming language which focuses on memory safety and concurrency. It is similar to C++ but ensures memory safety and provides high performance. Rust is brain child of Mozilla and simple as this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
fn main() {&lt;br /&gt;
    println!(&amp;quot;Hello World&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More information about Rust can be found [https://www.rust-lang.org/en-US/ here] and here is why we love [https://thenewstack.io/safer-future-rust/ Rust], [https://insights.stackoverflow.com/survey/2018/#most-loved-dreaded-and-wanted SF Loved]&lt;br /&gt;
&lt;br /&gt;
==='''Web Audio API'''===&lt;br /&gt;
The Web Audio API involves handling audio operations inside an audio context, and has been designed to allow modular routing. An audio routing graph has been created by linking together the Basic Audio operations performed with audio nodes. Several sources — with different types of channel layout — are supported even within a single context. This modular design provides the flexibility to create complex audio functions with dynamic effects.&lt;br /&gt;
&lt;br /&gt;
Audio nodes are linked into chains and simple webs by their inputs and outputs. They typically start with one or more sources. Sources provide arrays of sound intensities (samples) at very small timeslices, often tens of thousands of them per second. These could be either computed mathematically (such as OscillatorNode), or they can be recordings from sound/video files (like AudioBufferSourceNode and MediaElementAudioSourceNode) and audio streams (MediaStreamAudioSourceNode). In fact, sound files are just recordings of sound intensities themselves, which come in from microphones or electric instruments, and get mixed down into a single, complicated wave.&lt;br /&gt;
&lt;br /&gt;
Outputs of these nodes could be linked to inputs of others, which mix or modify these streams of sound samples into different streams. A common modification is multiplying the samples by a value to make them louder or quieter (as is the case with GainNode). Once the sound has been sufficiently processed for the intended effect, it can be linked to the input of a destination (AudioContext.destination), which sends the sound to the speakers or headphones. This last connection is only necessary if the user is supposed to hear the audio.&lt;br /&gt;
&lt;br /&gt;
A simple, typical workflow for web audio would look something like this:&lt;br /&gt;
&lt;br /&gt;
1. Create audio context&amp;lt;br&amp;gt;&lt;br /&gt;
2. Inside the context, create sources — such as &amp;lt;audio&amp;gt;, oscillator, stream&amp;lt;br&amp;gt;&lt;br /&gt;
3. Create effects nodes, such as reverb, biquad filter, panner, compressor&amp;lt;br&amp;gt;&lt;br /&gt;
4. Choose final destination of audio, for example your system speakers&amp;lt;br&amp;gt;&lt;br /&gt;
5. Connect the sources up to the effects, and the effects to the destination.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Problem Statement: Web Audio Automation'''===&lt;br /&gt;
&lt;br /&gt;
AudioParam is used to control the AudioNode functioning, say, Volume (a Gain parameter). These values can either be scheduled to be changed at precise times or set to particular value immediately following an event or at an event. The schedule to change when used with AudioContext.currentTime can helps in volume fades, filter sweeps etc. This would work aims to implement [https://github.com/servo/media/issues/204 SetValueCurveAtTime()].&lt;br /&gt;
&lt;br /&gt;
[https://webaudio.github.io/web-audio-api/#dom-audioparam-setvaluecurveattime setValueCurveAtTime()] is one such method in AudioParam that takes an array as input and schedules a change. The array is usually a curve in wedAudio and achieved my linear interpolation between the values from the floating-point values array and for the duration, d from the startTime, s&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;v(t) = values[N * (t - s) / d]&amp;lt;/code&amp;gt;, where N is the length of the values in the array.&lt;br /&gt;
And after the end of the curve time interval &amp;lt;code&amp;gt;(t &amp;gt;= s + d)&amp;lt;/code&amp;gt;, the value will remain constant at the final curve value. This would persist to happen until the next automation event.&lt;br /&gt;
&lt;br /&gt;
One of the application of setValueCurveAtTime() it to create tremolo effect. Suppose linear nor an exponential curve satisfy the needs then user can create curve based on values to setValueCurveAtTime() with an array of timing values. Its a much loved approached against multiple calls to setValueAtTime().&lt;br /&gt;
&lt;br /&gt;
==='''Build'''===&lt;br /&gt;
Servo is built with Cargo, the Rust package manager. We also use Mozilla's Mach tools to orchestrate the build and other tasks.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=='''Implementation of the Project'''== &lt;br /&gt;
&lt;br /&gt;
==='''Code'''===&lt;br /&gt;
The code is implemented as in [https://github.com/JHBalaji/media/blob/master/audio/src/param.rs#L418-L436 here]. The code below is the main code snippet for the SetValueCurveAtTime function. The values and function behavior is define in the param.rs file. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            AutomationEvent::SetValueCurveAtTime(ref values, start, duration) =&amp;gt; {&lt;br /&gt;
                let time_diff = ((duration.0 as f32) - (start.0 as f32)) as f32;&lt;br /&gt;
                let mut progress = ((((current_tick.0 as f32) - (start.0 as f32)) as f32) / time_diff) as f32;&lt;br /&gt;
                if progress &amp;lt; 0.0 {&lt;br /&gt;
                    progress = 0.0 as f32;&lt;br /&gt;
                }&lt;br /&gt;
                let n = values.len() as f32;&lt;br /&gt;
	            let k = (((n - 1.) * progress) as f32).floor();&lt;br /&gt;
                let next = k + 1. as f32;&lt;br /&gt;
                let step = time_diff / (n - 1.);&lt;br /&gt;
                if next &amp;lt; n {&lt;br /&gt;
                    let time_k = (k * step) as f32;&lt;br /&gt;
                    let time_k_next = (next * step) as f32;&lt;br /&gt;
                    let v_k = values[k as usize];&lt;br /&gt;
    				let v_k_next = values[next as usize];&lt;br /&gt;
                    *value = v_k + (v_k_next - v_k) * (((current_tick.0 as f32) - time_k) / (time_k_next - time_k));&lt;br /&gt;
                }&lt;br /&gt;
                true&lt;br /&gt;
            }&lt;br /&gt;
            AutomationEvent::CancelAndHoldAtTime(..) =&amp;gt; false,&lt;br /&gt;
            AutomationEvent::CancelScheduledValues(..) | AutomationEvent::SetValue(..) =&amp;gt; {&lt;br /&gt;
                unreachable!(&amp;quot;CancelScheduledValues/SetValue should never appear in the timeline&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Let's walk through the code. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;AutomationEvent::SetValueCurveAtTime()&amp;lt;/code&amp;gt; is a fn and takes three arguments: values, start, duration.&lt;br /&gt;
&lt;br /&gt;
progress, computes the difference between the first value in start_time and [https://github.com/JHBalaji/media/blob/5a981dff94f4dfaf2ebf0f0e09f599fab9d1a13b/audio/src/param.rs#L384 time] and makes explicit conversion to f32. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                let time_diff = ((duration.0 as f32) - (start.0 as f32)) as f32;&lt;br /&gt;
                let mut progress = ((((current_tick.0 as f32) - (start.0 as f32)) as f32) / time_diff) as f32;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
time_diff computes the total difference between duration and start_time, this is required when the values that needs to be computed goes beyond time_diff from start_time to set a constant value later.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                if progress &amp;lt; 0.0 {&lt;br /&gt;
                    progress = 0.0 as f32;&lt;br /&gt;
                }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Sets 0 if the progress from values array and present time being negative.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                let n = values.len() as f32;&lt;br /&gt;
	            let k = (((n - 1.) * progress) as f32).floor();&lt;br /&gt;
                let next = k + 1. as f32;&lt;br /&gt;
                let step = time_diff / (n - 1.);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
n, total length of values array. k, compute as k as in [[https://webaudio.github.io/web-audio-api/#dom-audioparam-setvaluecurveattime here] and &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; is k+1, the delta or step is computed that would be added to generate the sound wave from the values array. Say, the frequency start at 44KHz and the &amp;lt;code&amp;gt;step&amp;lt;/code&amp;gt; would be used to change the frequency of the curve.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                if next &amp;lt; n {&lt;br /&gt;
                    let time_k = (k * step) as f32;&lt;br /&gt;
                    let time_k_next = (next * step) as f32;&lt;br /&gt;
                    let v_k = values[k as usize];&lt;br /&gt;
    				let v_k_next = values[next as usize];&lt;br /&gt;
                    *value = v_k + (v_k_next - v_k) * (((current_tick.0 as f32) - time_k) / (time_k_next - time_k));&lt;br /&gt;
                }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code block generates sequences of values from &amp;lt;code&amp;gt;values&amp;lt;/code array and using &amp;lt;code&amp;gt;step&amp;lt;/code&amp;gt; value we computed. And does that till it reaches the total length of the array.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                true&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media/blob/f32a71c51f05f44d1e8ca217fbaa4dfb0b55d11e/audio/src/param.rs#L435 Used] to loop the function call made from [https://github.com/JHBalaji/media/blob/f32a71c51f05f44d1e8ca217fbaa4dfb0b55d11e/audio/src/param.rs#L117 here].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            AutomationEvent::CancelAndHoldAtTime(..) =&amp;gt; false,&lt;br /&gt;
            AutomationEvent::CancelScheduledValues(..) | AutomationEvent::SetValue(..) =&amp;gt; {&lt;br /&gt;
                unreachable!(&amp;quot;CancelScheduledValues/SetValue should never appear in the timeline&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media/blob/5a981dff94f4dfaf2ebf0f0e09f599fab9d1a13b/audio/src/param.rs#L466 Code] instructs to cancel this event or end of this function and proceed to next instructions. In Audio API unless you explicitly say the block to end, the block would end and hardware device would be stopped from consumption.&lt;br /&gt;
&lt;br /&gt;
==='''Examples'''===&lt;br /&gt;
&lt;br /&gt;
Examples are unique aspect to Rust. This instructs that code to make use of the function we just wrote and generates a sound output. Refer our example [https://github.com/JHBalaji/media-1/blob/master/examples/set_value_curve.rs here] for the SetValueCurveAtTime()&lt;br /&gt;
&lt;br /&gt;
And example is usually called by using cargo build in rust or cargo run.&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media-1/blob/master/examples/Cargo.toml Cargo.toml] dictates the naming and the file to be called as.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cargo run --example set_value_curve&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above code instructs to run the example [https://github.com/JHBalaji/media-1/blob/master/examples/set_value_curve.rs set_value_curve] to generate a sound output through our terminal.&lt;br /&gt;
&lt;br /&gt;
==='''Compile'''===&lt;br /&gt;
[https://github.com/JHBalaji/media-1/blob/master/Cargo.lock Cargo.lock] instructs the dependencies that would be required to build this project.&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media-1/blob/master/Cargo.toml Cargo.toml] calls all the folders or members to be complied. Usually the compilation would be at /media&lt;br /&gt;
&lt;br /&gt;
Cargo.lock installs number of packages called crates that would be used by the project to access the modules. Each of the member in [https://github.com/JHBalaji/media-1/blob/master/Cargo.toml Cargo.toml] would have [https://github.com/JHBalaji/media-1/blob/master/examples/Cargo.toml Cargo.toml] in them that would instruct [https://github.com/JHBalaji/media-1/blob/master/examples/Cargo.toml#L6 dependencies] during the build. build-dependencies would be used if you have dependencies before the build.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media-1/blob/master/.cargo/config .cargo config] is similar to a dotenv file for Rust&lt;br /&gt;
&lt;br /&gt;
==='''Test'''===&lt;br /&gt;
&lt;br /&gt;
If you would like to test our build please look into [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#Issues_and_Fixes Fixes] before proceeding. We would suggest MacOS or Linux 16.04 LTS for any development and testing. Virtual Machine or VirtualBox could be another option. We spent countless days in frustration with libraries and never ending apt installs so avoid Linux 18.04 for this build test.&lt;br /&gt;
&lt;br /&gt;
Once &amp;lt;code&amp;gt;cargo build&amp;lt;/code&amp;gt; is completed. Open /target/debug to view the examples that are generated.&lt;br /&gt;
&lt;br /&gt;
[[File:Servo-initial-build.PNG]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To run all examples after the cargo build is complete, use &amp;lt;code&amp;gt;cargo run --example &amp;lt;bin_name&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Examples.PNG]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Status of the Project'''===&lt;br /&gt;
&lt;br /&gt;
The [https://github.com/JHBalaji/media-1 build] is ready and the Pull request is [https://github.com/servo/media/pull/230 merged] with Servo/media.&lt;br /&gt;
&lt;br /&gt;
[[File:Pr.PNG]]&lt;br /&gt;
&lt;br /&gt;
=='''Normal build from Master Repo '''==&lt;br /&gt;
To build Servo in development mode. This is useful for development, but the resulting binary is very slow.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git clone https://github.com/servo/servo&lt;br /&gt;
cd servo&lt;br /&gt;
./mach build --dev&lt;br /&gt;
./mach run tests/html/about-mozilla.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
For benchmarking, performance testing, or real-world use, add the --release flag to create an optimized build:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach build --release&lt;br /&gt;
./mach run --release tests/html/about-mozilla.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==='''Compiling and Running the code'''===&lt;br /&gt;
&lt;br /&gt;
====Mac OS====&lt;br /&gt;
&lt;br /&gt;
Follow the instructions posted in this [https://github.com/JHBalaji/media-1 URL] and install GStreamer and Rust. After that follow the following lines for compiling on MacOS. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1. brew install gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-libav gst-rtsp-server gst-editing-services&lt;br /&gt;
&lt;br /&gt;
2. export PKG_CONFIG_PATH=/usr/local/Cellar/libffi/3.2.1/lib/pkgconfig/&lt;br /&gt;
&lt;br /&gt;
3. rustup override set nightly&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After this run the following command to compile servo/media &lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
cargo build &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After compiling you will be able to test our example that is places in the examples folder.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Windows and Linux====&lt;br /&gt;
&lt;br /&gt;
Head over here to install [https://rustup.rs/ Rust ToolChain]. If you need any additional details we would suggest reading the [https://github.com/rust-lang/rustup.rs/blob/master/README.md ReadMe on Rust]. Some Servo media specific build issues are [https://github.com/servo/media/blob/master/README.md advised]. &lt;br /&gt;
&lt;br /&gt;
We would suggest Ubuntu 18.04 LTS with updates [https://github.com/servo/media/blob/master/README.md gstreamer package].&lt;br /&gt;
&lt;br /&gt;
==='''Servo Media'''===&lt;br /&gt;
&amp;lt;b&amp;gt;Requirements&amp;lt;/b&amp;gt;&lt;br /&gt;
In order to build this crate you need to install gstreamer which can be found here [https://github.com/sdroege/gstreamer-rs]&lt;br /&gt;
==='''Test Case'''===&lt;br /&gt;
After you run cargo build, you should be able to see the executable of the example inside the target/debug folder. Following is the test we have written  file to check the functioning of the [https://github.com/JHBalaji/media-1/blob/master/examples/set_value_curve.rs SetValueCurveAtTIme].&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
extern crate servo_media;&lt;br /&gt;
extern crate servo_media_auto;&lt;br /&gt;
&lt;br /&gt;
use servo_media::audio::constant_source_node::ConstantSourceNodeOptions;&lt;br /&gt;
use servo_media::audio::gain_node::GainNodeOptions;&lt;br /&gt;
use servo_media::audio::node::{AudioNodeInit, AudioNodeMessage, AudioScheduledSourceNodeMessage};&lt;br /&gt;
use servo_media::audio::param::{ParamType, UserAutomationEvent};&lt;br /&gt;
use servo_media::ServoMedia;&lt;br /&gt;
use std::sync::Arc;&lt;br /&gt;
use std::{thread, time};&lt;br /&gt;
&lt;br /&gt;
fn run_example(servo_media: Arc&amp;lt;ServoMedia&amp;gt;) {&lt;br /&gt;
    let context = servo_media.create_audio_context(Default::default());&lt;br /&gt;
    let dest = context.dest_node();&lt;br /&gt;
&lt;br /&gt;
    //Initializing the values vector for SetValueCurve function&lt;br /&gt;
    let mut values: Vec&amp;lt;f32&amp;gt; = Vec::new();&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(1.0);&lt;br /&gt;
    values.push(1.0);&lt;br /&gt;
    values.push(1.0);&lt;br /&gt;
    values.push(1.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.5);&lt;br /&gt;
    values.push(0.5);&lt;br /&gt;
    values.push(0.5);&lt;br /&gt;
    values.push(0.5);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    let start_time = 0.;&lt;br /&gt;
    let end_time = 5.;&lt;br /&gt;
    let n = values.len() as f32;&lt;br /&gt;
    let value_next = values[(n - 1.) as usize];&lt;br /&gt;
&lt;br /&gt;
    let cs = context.create_node(&lt;br /&gt;
        AudioNodeInit::ConstantSourceNode(ConstantSourceNodeOptions::default()),&lt;br /&gt;
        Default::default(),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    let mut gain_options = GainNodeOptions::default();&lt;br /&gt;
    gain_options.gain = 0.0;&lt;br /&gt;
    let gain = context.create_node(&lt;br /&gt;
        AudioNodeInit::GainNode(gain_options.clone()),&lt;br /&gt;
        Default::default(),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    let osc = context.create_node(&lt;br /&gt;
        AudioNodeInit::OscillatorNode(Default::default()),&lt;br /&gt;
        Default::default(),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.connect_ports(osc.output(0), gain.input(0));&lt;br /&gt;
    context.connect_ports(cs.output(0), gain.param(ParamType::Gain));&lt;br /&gt;
    context.connect_ports(gain.output(0), dest.input(0));&lt;br /&gt;
&lt;br /&gt;
    let _ = context.resume();&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        osc,&lt;br /&gt;
        AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(0.)),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        gain,&lt;br /&gt;
        AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(0.)),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        cs,&lt;br /&gt;
        AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(0.)),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        cs,&lt;br /&gt;
        AudioNodeMessage::SetParam(&lt;br /&gt;
            ParamType::Offset,&lt;br /&gt;
            UserAutomationEvent::SetValueCurveAtTime(values, start_time, end_time),&lt;br /&gt;
        ),&lt;br /&gt;
&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        osc,&lt;br /&gt;
        AudioNodeMessage::SetParam(&lt;br /&gt;
            ParamType::Frequency,&lt;br /&gt;
            UserAutomationEvent::SetValueAtTime(value_next, end_time),&lt;br /&gt;
        ),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    thread::sleep(time::Duration::from_millis(7000));&lt;br /&gt;
    let _ = context.close();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
fn main() {&lt;br /&gt;
    ServoMedia::init::&amp;lt;servo_media_auto::Backend&amp;gt;();&lt;br /&gt;
    if let Ok(servo_media) = ServoMedia::get() {&lt;br /&gt;
        run_example(servo_media);&lt;br /&gt;
    } else {&lt;br /&gt;
        unreachable!();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above program, the values vector is passed into the SetValueCurveAtTime function to modulate the output. The output of the same can also be checked in the test-case video at the end of this page. &lt;br /&gt;
We can modify the values function as we want and observe the output. One more modification that we used was by using a sine curve. It is implemented as follows. Change the values vector in the set-value-curve function with the following: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 use std::f64::consts::PI;&lt;br /&gt;
    let mut values: Vec&amp;lt;f32&amp;gt; = Vec::new();&lt;br /&gt;
    let curvelength = 44100;&lt;br /&gt;
    let mut i = 0;&lt;br /&gt;
    while i &amp;lt; curvelength {&lt;br /&gt;
    values.push(f32::sin((PI *i as f64/curvelength as f64) as f32));&lt;br /&gt;
    i += 1;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The output of this function can be seen in the test video attached to at the end of this page. &lt;br /&gt;
&amp;lt;references&amp;gt;&amp;lt;/references&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=='''Video of Testing Audio Output'''==&lt;br /&gt;
[https://drive.google.com/file/d/1jzEZwAZE-7mi6N5N_JcEE6ISM-wc9910/view?usp=sharing Test-1]&lt;br /&gt;
[https://drive.google.com/file/d/1UsPgyv29Zf29d6pEDgLpYX86DI6hzOqp/view?usp=sharing Test-2]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=='''Issues and Fixes'''==&lt;br /&gt;
&lt;br /&gt;
Windows Specific during build&lt;br /&gt;
&lt;br /&gt;
https://github.com/holochain/holochain-cmd/issues/29&lt;br /&gt;
&lt;br /&gt;
https://stackoverflow.com/questions/53136717/errore0554-feature-may-not-be-used-on-the-stable-release-channel-couldnt&lt;br /&gt;
&lt;br /&gt;
https://github.com/servo/servo/issues/21429&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=='''Final Project'''==&lt;br /&gt;
If you are a peer reviewer please look into this [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#For_Peer_Reviewers_Note section]&lt;br /&gt;
&lt;br /&gt;
The final [https://github.com/servo/servo/wiki/Implement-missing-WebAudio-automation-student-project project] rely on our previous [https://github.com/servo/media/pull/230 work]. The next part would focus on implementing the code [https://github.com/servo/media/issues/204 written] to be accessible by Servo browser [https://github.com/servo/servo/issues/22897 engine]. &lt;br /&gt;
This would require interfacing the DOM [https://github.com/servo/servo/blob/master/components/script/dom/webidls/AudioParam.webidl file] reference the Param.rs [https://github.com/JHBalaji/media/blob/master/audio/src/param.rs#L259 setValueCurveAtTime] to be interfaced with [https://github.com/servo/servo/blob/master/components/script/dom/audioparam.rs AudioParam.rs]. The audioparam.rs would call the UserAutomationEvent in the param.rs setValueCurveAtTime.&lt;br /&gt;
&lt;br /&gt;
Once the initial function call with arguments  are updated, then the [https://github.com/servo/servo/blob/master/tests/wpt/README.md#updating-test-expectations testing] would be performed on ''./mach test-wpt tests/wpt/web-platform-tests/webaudio/the-audio-api/[https://github.com/servo/servo/tree/master/tests/wpt/web-platform-tests/webaudio/the-audio-api/the-audioparam-interface the-audioparam-interface]''. The [https://github.com/servo/servo/tree/master/tests/wpt/web-platform-tests/webaudio/the-audio-api/the-audioparam-interface the-audioparam-interface] is a folder of series of test cases that emulate the behavior of a function call, here the setValueCurveAtTime would need to be necessitated to mock the values as tested in previous [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#Test_Case example] but would require to be performed over a .html webpage with DOM elements to test the complete functionality.&lt;br /&gt;
&lt;br /&gt;
Servo webAudio tests are performed using [https://github.com/web-platform-tests/wpt/blob/master/resources/readme.md testharness.js]. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach create-wpt tests/wpt/path/to/new/test.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
would create a test.html using the WPT template for javascript tests. Once the skeleton code is completed with necessary function call, them the WPT tests would be executed using &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach test-wpt tests/wpt/path/to/new/test.html&lt;br /&gt;
./mach test-wpt tests/wpt/path/to/new/reftest.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[https://web-platform-tests.org/writing-tests/reftests.html reftest] are used in Servo to test behavior related to rendering; that are related to interaction made up of several webpages [think passing or referencing values to another webpage] with assertions to test cases that are expected from the interaction. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach create-wpt --reftest tests/wpt/path/to/new/reftest.html --reference tests/wpt/path/to/reference.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
reference.html and reftest.html will be created using WPT reftest template. Once the reftest is run the upstream test would need to be updated using &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach update-wpt --sync&lt;br /&gt;
./mach test-wpt --log-raw=update.log&lt;br /&gt;
./mach update-wpt update.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When reftest fails to diagnose the behavior reftest raw log is required which is generate using the below command. The .log is fed into  [https://github.com/Gankro/live-reftest-analyzer  reftest analyzer] to find those failing test. The reftest is also capable of pixel level comparison of the test and reference screenshots (incase of rendering)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach test-wpt --log-raw wpt.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==='''List of issues'''===&lt;br /&gt;
This project has listed 4 known issues under the  WebAudio title, each solving a different issue.&lt;br /&gt;
&lt;br /&gt;
1. [https://github.com/servo/media/issues/204 Implement ValueCurveAtTime automation]&lt;br /&gt;
&lt;br /&gt;
This is the first issue, which has been addressed and successfully closed during the initial parts of this project. The steps followed are shown in the following diagram.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:WebAudio-Issue1.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. [https://github.com/servo/servo/issues/22897 Implement AudioParam.setValueCurveAtTime]&lt;br /&gt;
&lt;br /&gt;
This second issue builds up on the first one, and focuses on implementing yet another method called [https://webaudio.github.io/web-audio-api/#dom-audioparam-setvaluecurveattime setValueCurveAtTime]. The next focus of this project will likely be to work on this issue. This deals with the javascript API values for the curves.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:WebAudio-Issue2.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3. [https://github.com/servo/servo/issues/22898 Implement deprecated setPosition and setOrientation methods for AudioListener]&lt;br /&gt;
&lt;br /&gt;
The third issue deals with a few missing APIs for AudioListener. We need to accordingly add the new methods, i.e. [https://webaudio.github.io/web-audio-api/#dom-pannernode-setposition setPosition] and [https://webaudio.github.io/web-audio-api/#dom-pannernode-setorientation setOrientation] to the audiolistener.rs file so that they properly update the values of the relevant AudioParam members of AudioListener along with the passed arguments.This should help stopping an endless list of javascript errors which would occur when these deprecated methods weren't implemented.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:WebAudio-Issue3.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
4. [https://github.com/servo/media/issues/205 Implement WaveShaper node]&lt;br /&gt;
&lt;br /&gt;
This final issue listed tries to implement a new node called the [https://webaudio.github.io/web-audio-api/#waveshapernode WaveShaper node]. This is an independant issue and may be done before or after the other issues have been solved.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:WebAudio-Issue4.png]]&lt;br /&gt;
&lt;br /&gt;
=='''For Peer Reviewers Note'''==&lt;br /&gt;
&lt;br /&gt;
''Common peer review question clarifications are below,''&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Does the design incorporate all of the functionality required?&amp;quot; or &amp;quot;Check the changes that the authors proposed. Rate the overall quality of the explanations. Give comments if you find the explanation hard to follow or inadequate.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
:The [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#Final_Project section] clarifies your question.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Check the designs proposed by the authors.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
:There is no explicit design is involved as going by [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#Final_Project proposal], there are three files to be added with new functionality in addition to test cases and files.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Check the use of visual aids&amp;quot;&lt;br /&gt;
:Visual aids not applicable &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Give comments on the completeness of the design doc.&amp;quot;&lt;br /&gt;
: Let us know what you think about them!&lt;/div&gt;</summary>
		<author><name>Amadhus2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support&amp;diff=124048</id>
		<title>CSC/ECE 517 Spring 2019 - Project M1901 Implement missing WebAudio automation support</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support&amp;diff=124048"/>
		<updated>2019-04-13T03:10:03Z</updated>

		<summary type="html">&lt;p&gt;Amadhus2: /* List of issues */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''Introduction'''== &lt;br /&gt;
&lt;br /&gt;
==='''Servo'''===&lt;br /&gt;
Servo is an developmental browser engine designed to make use of the memory safety properties and concurrency features of the Rust programming language. The project was initiated by Mozilla Research with effort from Samsung to port it to Android and ARM processors&lt;br /&gt;
&lt;br /&gt;
More information about Servo is available [https://servo.org here]&lt;br /&gt;
&lt;br /&gt;
==='''Rust'''===&lt;br /&gt;
Rust is a systems programming language which focuses on memory safety and concurrency. It is similar to C++ but ensures memory safety and provides high performance. Rust is brain child of Mozilla and simple as this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
fn main() {&lt;br /&gt;
    println!(&amp;quot;Hello World&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More information about Rust can be found [https://www.rust-lang.org/en-US/ here] and here is why we love [https://thenewstack.io/safer-future-rust/ Rust], [https://insights.stackoverflow.com/survey/2018/#most-loved-dreaded-and-wanted SF Loved]&lt;br /&gt;
&lt;br /&gt;
==='''Web Audio API'''===&lt;br /&gt;
The Web Audio API involves handling audio operations inside an audio context, and has been designed to allow modular routing. An audio routing graph has been created by linking together the Basic Audio operations performed with audio nodes. Several sources — with different types of channel layout — are supported even within a single context. This modular design provides the flexibility to create complex audio functions with dynamic effects.&lt;br /&gt;
&lt;br /&gt;
Audio nodes are linked into chains and simple webs by their inputs and outputs. They typically start with one or more sources. Sources provide arrays of sound intensities (samples) at very small timeslices, often tens of thousands of them per second. These could be either computed mathematically (such as OscillatorNode), or they can be recordings from sound/video files (like AudioBufferSourceNode and MediaElementAudioSourceNode) and audio streams (MediaStreamAudioSourceNode). In fact, sound files are just recordings of sound intensities themselves, which come in from microphones or electric instruments, and get mixed down into a single, complicated wave.&lt;br /&gt;
&lt;br /&gt;
Outputs of these nodes could be linked to inputs of others, which mix or modify these streams of sound samples into different streams. A common modification is multiplying the samples by a value to make them louder or quieter (as is the case with GainNode). Once the sound has been sufficiently processed for the intended effect, it can be linked to the input of a destination (AudioContext.destination), which sends the sound to the speakers or headphones. This last connection is only necessary if the user is supposed to hear the audio.&lt;br /&gt;
&lt;br /&gt;
A simple, typical workflow for web audio would look something like this:&lt;br /&gt;
&lt;br /&gt;
1. Create audio context&amp;lt;br&amp;gt;&lt;br /&gt;
2. Inside the context, create sources — such as &amp;lt;audio&amp;gt;, oscillator, stream&amp;lt;br&amp;gt;&lt;br /&gt;
3. Create effects nodes, such as reverb, biquad filter, panner, compressor&amp;lt;br&amp;gt;&lt;br /&gt;
4. Choose final destination of audio, for example your system speakers&amp;lt;br&amp;gt;&lt;br /&gt;
5. Connect the sources up to the effects, and the effects to the destination.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Problem Statement: Web Audio Automation'''===&lt;br /&gt;
&lt;br /&gt;
AudioParam is used to control the AudioNode functioning, say, Volume (a Gain parameter). These values can either be scheduled to be changed at precise times or set to particular value immediately following an event or at an event. The schedule to change when used with AudioContext.currentTime can helps in volume fades, filter sweeps etc. This would work aims to implement [https://github.com/servo/media/issues/204 SetValueCurveAtTime()].&lt;br /&gt;
&lt;br /&gt;
[https://webaudio.github.io/web-audio-api/#dom-audioparam-setvaluecurveattime setValueCurveAtTime()] is one such method in AudioParam that takes an array as input and schedules a change. The array is usually a curve in wedAudio and achieved my linear interpolation between the values from the floating-point values array and for the duration, d from the startTime, s&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;v(t) = values[N * (t - s) / d]&amp;lt;/code&amp;gt;, where N is the length of the values in the array.&lt;br /&gt;
And after the end of the curve time interval &amp;lt;code&amp;gt;(t &amp;gt;= s + d)&amp;lt;/code&amp;gt;, the value will remain constant at the final curve value. This would persist to happen until the next automation event.&lt;br /&gt;
&lt;br /&gt;
One of the application of setValueCurveAtTime() it to create tremolo effect. Suppose linear nor an exponential curve satisfy the needs then user can create curve based on values to setValueCurveAtTime() with an array of timing values. Its a much loved approached against multiple calls to setValueAtTime().&lt;br /&gt;
&lt;br /&gt;
==='''Build'''===&lt;br /&gt;
Servo is built with Cargo, the Rust package manager. We also use Mozilla's Mach tools to orchestrate the build and other tasks.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=='''Implementation of the Project'''== &lt;br /&gt;
&lt;br /&gt;
==='''Code'''===&lt;br /&gt;
The code is implemented as in [https://github.com/JHBalaji/media/blob/master/audio/src/param.rs#L418-L436 here]. The code below is the main code snippet for the SetValueCurveAtTime function. The values and function behavior is define in the param.rs file. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            AutomationEvent::SetValueCurveAtTime(ref values, start, duration) =&amp;gt; {&lt;br /&gt;
                let time_diff = ((duration.0 as f32) - (start.0 as f32)) as f32;&lt;br /&gt;
                let mut progress = ((((current_tick.0 as f32) - (start.0 as f32)) as f32) / time_diff) as f32;&lt;br /&gt;
                if progress &amp;lt; 0.0 {&lt;br /&gt;
                    progress = 0.0 as f32;&lt;br /&gt;
                }&lt;br /&gt;
                let n = values.len() as f32;&lt;br /&gt;
	            let k = (((n - 1.) * progress) as f32).floor();&lt;br /&gt;
                let next = k + 1. as f32;&lt;br /&gt;
                let step = time_diff / (n - 1.);&lt;br /&gt;
                if next &amp;lt; n {&lt;br /&gt;
                    let time_k = (k * step) as f32;&lt;br /&gt;
                    let time_k_next = (next * step) as f32;&lt;br /&gt;
                    let v_k = values[k as usize];&lt;br /&gt;
    				let v_k_next = values[next as usize];&lt;br /&gt;
                    *value = v_k + (v_k_next - v_k) * (((current_tick.0 as f32) - time_k) / (time_k_next - time_k));&lt;br /&gt;
                }&lt;br /&gt;
                true&lt;br /&gt;
            }&lt;br /&gt;
            AutomationEvent::CancelAndHoldAtTime(..) =&amp;gt; false,&lt;br /&gt;
            AutomationEvent::CancelScheduledValues(..) | AutomationEvent::SetValue(..) =&amp;gt; {&lt;br /&gt;
                unreachable!(&amp;quot;CancelScheduledValues/SetValue should never appear in the timeline&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Let's walk through the code. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;AutomationEvent::SetValueCurveAtTime()&amp;lt;/code&amp;gt; is a fn and takes three arguments: values, start, duration.&lt;br /&gt;
&lt;br /&gt;
progress, computes the difference between the first value in start_time and [https://github.com/JHBalaji/media/blob/5a981dff94f4dfaf2ebf0f0e09f599fab9d1a13b/audio/src/param.rs#L384 time] and makes explicit conversion to f32. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                let time_diff = ((duration.0 as f32) - (start.0 as f32)) as f32;&lt;br /&gt;
                let mut progress = ((((current_tick.0 as f32) - (start.0 as f32)) as f32) / time_diff) as f32;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
time_diff computes the total difference between duration and start_time, this is required when the values that needs to be computed goes beyond time_diff from start_time to set a constant value later.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                if progress &amp;lt; 0.0 {&lt;br /&gt;
                    progress = 0.0 as f32;&lt;br /&gt;
                }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Sets 0 if the progress from values array and present time being negative.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                let n = values.len() as f32;&lt;br /&gt;
	            let k = (((n - 1.) * progress) as f32).floor();&lt;br /&gt;
                let next = k + 1. as f32;&lt;br /&gt;
                let step = time_diff / (n - 1.);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
n, total length of values array. k, compute as k as in [[https://webaudio.github.io/web-audio-api/#dom-audioparam-setvaluecurveattime here] and &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; is k+1, the delta or step is computed that would be added to generate the sound wave from the values array. Say, the frequency start at 44KHz and the &amp;lt;code&amp;gt;step&amp;lt;/code&amp;gt; would be used to change the frequency of the curve.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                if next &amp;lt; n {&lt;br /&gt;
                    let time_k = (k * step) as f32;&lt;br /&gt;
                    let time_k_next = (next * step) as f32;&lt;br /&gt;
                    let v_k = values[k as usize];&lt;br /&gt;
    				let v_k_next = values[next as usize];&lt;br /&gt;
                    *value = v_k + (v_k_next - v_k) * (((current_tick.0 as f32) - time_k) / (time_k_next - time_k));&lt;br /&gt;
                }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code block generates sequences of values from &amp;lt;code&amp;gt;values&amp;lt;/code array and using &amp;lt;code&amp;gt;step&amp;lt;/code&amp;gt; value we computed. And does that till it reaches the total length of the array.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                true&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media/blob/f32a71c51f05f44d1e8ca217fbaa4dfb0b55d11e/audio/src/param.rs#L435 Used] to loop the function call made from [https://github.com/JHBalaji/media/blob/f32a71c51f05f44d1e8ca217fbaa4dfb0b55d11e/audio/src/param.rs#L117 here].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            AutomationEvent::CancelAndHoldAtTime(..) =&amp;gt; false,&lt;br /&gt;
            AutomationEvent::CancelScheduledValues(..) | AutomationEvent::SetValue(..) =&amp;gt; {&lt;br /&gt;
                unreachable!(&amp;quot;CancelScheduledValues/SetValue should never appear in the timeline&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media/blob/5a981dff94f4dfaf2ebf0f0e09f599fab9d1a13b/audio/src/param.rs#L466 Code] instructs to cancel this event or end of this function and proceed to next instructions. In Audio API unless you explicitly say the block to end, the block would end and hardware device would be stopped from consumption.&lt;br /&gt;
&lt;br /&gt;
==='''Examples'''===&lt;br /&gt;
&lt;br /&gt;
Examples are unique aspect to Rust. This instructs that code to make use of the function we just wrote and generates a sound output. Refer our example [https://github.com/JHBalaji/media-1/blob/master/examples/set_value_curve.rs here] for the SetValueCurveAtTime()&lt;br /&gt;
&lt;br /&gt;
And example is usually called by using cargo build in rust or cargo run.&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media-1/blob/master/examples/Cargo.toml Cargo.toml] dictates the naming and the file to be called as.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cargo run --example set_value_curve&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above code instructs to run the example [https://github.com/JHBalaji/media-1/blob/master/examples/set_value_curve.rs set_value_curve] to generate a sound output through our terminal.&lt;br /&gt;
&lt;br /&gt;
==='''Compile'''===&lt;br /&gt;
[https://github.com/JHBalaji/media-1/blob/master/Cargo.lock Cargo.lock] instructs the dependencies that would be required to build this project.&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media-1/blob/master/Cargo.toml Cargo.toml] calls all the folders or members to be complied. Usually the compilation would be at /media&lt;br /&gt;
&lt;br /&gt;
Cargo.lock installs number of packages called crates that would be used by the project to access the modules. Each of the member in [https://github.com/JHBalaji/media-1/blob/master/Cargo.toml Cargo.toml] would have [https://github.com/JHBalaji/media-1/blob/master/examples/Cargo.toml Cargo.toml] in them that would instruct [https://github.com/JHBalaji/media-1/blob/master/examples/Cargo.toml#L6 dependencies] during the build. build-dependencies would be used if you have dependencies before the build.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media-1/blob/master/.cargo/config .cargo config] is similar to a dotenv file for Rust&lt;br /&gt;
&lt;br /&gt;
==='''Test'''===&lt;br /&gt;
&lt;br /&gt;
If you would like to test our build please look into [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#Issues_and_Fixes Fixes] before proceeding. We would suggest MacOS or Linux 16.04 LTS for any development and testing. Virtual Machine or VirtualBox could be another option. We spent countless days in frustration with libraries and never ending apt installs so avoid Linux 18.04 for this build test.&lt;br /&gt;
&lt;br /&gt;
Once &amp;lt;code&amp;gt;cargo build&amp;lt;/code&amp;gt; is completed. Open /target/debug to view the examples that are generated.&lt;br /&gt;
&lt;br /&gt;
[[File:Servo-initial-build.PNG]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To run all examples after the cargo build is complete, use &amp;lt;code&amp;gt;cargo run --example &amp;lt;bin_name&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Examples.PNG]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Status of the Project'''===&lt;br /&gt;
&lt;br /&gt;
The [https://github.com/JHBalaji/media-1 build] is ready and the Pull request is [https://github.com/servo/media/pull/230 merged] with Servo/media.&lt;br /&gt;
&lt;br /&gt;
[[File:Pr.PNG]]&lt;br /&gt;
&lt;br /&gt;
=='''Normal build from Master Repo '''==&lt;br /&gt;
To build Servo in development mode. This is useful for development, but the resulting binary is very slow.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git clone https://github.com/servo/servo&lt;br /&gt;
cd servo&lt;br /&gt;
./mach build --dev&lt;br /&gt;
./mach run tests/html/about-mozilla.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
For benchmarking, performance testing, or real-world use, add the --release flag to create an optimized build:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach build --release&lt;br /&gt;
./mach run --release tests/html/about-mozilla.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==='''Compiling and Running the code'''===&lt;br /&gt;
&lt;br /&gt;
====Mac OS====&lt;br /&gt;
&lt;br /&gt;
Follow the instructions posted in this [https://github.com/JHBalaji/media-1 URL] and install GStreamer and Rust. After that follow the following lines for compiling on MacOS. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1. brew install gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-libav gst-rtsp-server gst-editing-services&lt;br /&gt;
&lt;br /&gt;
2. export PKG_CONFIG_PATH=/usr/local/Cellar/libffi/3.2.1/lib/pkgconfig/&lt;br /&gt;
&lt;br /&gt;
3. rustup override set nightly&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After this run the following command to compile servo/media &lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
cargo build &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After compiling you will be able to test our example that is places in the examples folder.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Windows and Linux====&lt;br /&gt;
&lt;br /&gt;
Head over here to install [https://rustup.rs/ Rust ToolChain]. If you need any additional details we would suggest reading the [https://github.com/rust-lang/rustup.rs/blob/master/README.md ReadMe on Rust]. Some Servo media specific build issues are [https://github.com/servo/media/blob/master/README.md advised]. &lt;br /&gt;
&lt;br /&gt;
We would suggest Ubuntu 18.04 LTS with updates [https://github.com/servo/media/blob/master/README.md gstreamer package].&lt;br /&gt;
&lt;br /&gt;
==='''Servo Media'''===&lt;br /&gt;
&amp;lt;b&amp;gt;Requirements&amp;lt;/b&amp;gt;&lt;br /&gt;
In order to build this crate you need to install gstreamer which can be found here [https://github.com/sdroege/gstreamer-rs]&lt;br /&gt;
==='''Test Case'''===&lt;br /&gt;
After you run cargo build, you should be able to see the executable of the example inside the target/debug folder. Following is the test we have written  file to check the functioning of the [https://github.com/JHBalaji/media-1/blob/master/examples/set_value_curve.rs SetValueCurveAtTIme].&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
extern crate servo_media;&lt;br /&gt;
extern crate servo_media_auto;&lt;br /&gt;
&lt;br /&gt;
use servo_media::audio::constant_source_node::ConstantSourceNodeOptions;&lt;br /&gt;
use servo_media::audio::gain_node::GainNodeOptions;&lt;br /&gt;
use servo_media::audio::node::{AudioNodeInit, AudioNodeMessage, AudioScheduledSourceNodeMessage};&lt;br /&gt;
use servo_media::audio::param::{ParamType, UserAutomationEvent};&lt;br /&gt;
use servo_media::ServoMedia;&lt;br /&gt;
use std::sync::Arc;&lt;br /&gt;
use std::{thread, time};&lt;br /&gt;
&lt;br /&gt;
fn run_example(servo_media: Arc&amp;lt;ServoMedia&amp;gt;) {&lt;br /&gt;
    let context = servo_media.create_audio_context(Default::default());&lt;br /&gt;
    let dest = context.dest_node();&lt;br /&gt;
&lt;br /&gt;
    //Initializing the values vector for SetValueCurve function&lt;br /&gt;
    let mut values: Vec&amp;lt;f32&amp;gt; = Vec::new();&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(1.0);&lt;br /&gt;
    values.push(1.0);&lt;br /&gt;
    values.push(1.0);&lt;br /&gt;
    values.push(1.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.5);&lt;br /&gt;
    values.push(0.5);&lt;br /&gt;
    values.push(0.5);&lt;br /&gt;
    values.push(0.5);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    let start_time = 0.;&lt;br /&gt;
    let end_time = 5.;&lt;br /&gt;
    let n = values.len() as f32;&lt;br /&gt;
    let value_next = values[(n - 1.) as usize];&lt;br /&gt;
&lt;br /&gt;
    let cs = context.create_node(&lt;br /&gt;
        AudioNodeInit::ConstantSourceNode(ConstantSourceNodeOptions::default()),&lt;br /&gt;
        Default::default(),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    let mut gain_options = GainNodeOptions::default();&lt;br /&gt;
    gain_options.gain = 0.0;&lt;br /&gt;
    let gain = context.create_node(&lt;br /&gt;
        AudioNodeInit::GainNode(gain_options.clone()),&lt;br /&gt;
        Default::default(),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    let osc = context.create_node(&lt;br /&gt;
        AudioNodeInit::OscillatorNode(Default::default()),&lt;br /&gt;
        Default::default(),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.connect_ports(osc.output(0), gain.input(0));&lt;br /&gt;
    context.connect_ports(cs.output(0), gain.param(ParamType::Gain));&lt;br /&gt;
    context.connect_ports(gain.output(0), dest.input(0));&lt;br /&gt;
&lt;br /&gt;
    let _ = context.resume();&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        osc,&lt;br /&gt;
        AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(0.)),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        gain,&lt;br /&gt;
        AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(0.)),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        cs,&lt;br /&gt;
        AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(0.)),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        cs,&lt;br /&gt;
        AudioNodeMessage::SetParam(&lt;br /&gt;
            ParamType::Offset,&lt;br /&gt;
            UserAutomationEvent::SetValueCurveAtTime(values, start_time, end_time),&lt;br /&gt;
        ),&lt;br /&gt;
&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        osc,&lt;br /&gt;
        AudioNodeMessage::SetParam(&lt;br /&gt;
            ParamType::Frequency,&lt;br /&gt;
            UserAutomationEvent::SetValueAtTime(value_next, end_time),&lt;br /&gt;
        ),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    thread::sleep(time::Duration::from_millis(7000));&lt;br /&gt;
    let _ = context.close();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
fn main() {&lt;br /&gt;
    ServoMedia::init::&amp;lt;servo_media_auto::Backend&amp;gt;();&lt;br /&gt;
    if let Ok(servo_media) = ServoMedia::get() {&lt;br /&gt;
        run_example(servo_media);&lt;br /&gt;
    } else {&lt;br /&gt;
        unreachable!();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above program, the values vector is passed into the SetValueCurveAtTime function to modulate the output. The output of the same can also be checked in the test-case video at the end of this page. &lt;br /&gt;
We can modify the values function as we want and observe the output. One more modification that we used was by using a sine curve. It is implemented as follows. Change the values vector in the set-value-curve function with the following: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 use std::f64::consts::PI;&lt;br /&gt;
    let mut values: Vec&amp;lt;f32&amp;gt; = Vec::new();&lt;br /&gt;
    let curvelength = 44100;&lt;br /&gt;
    let mut i = 0;&lt;br /&gt;
    while i &amp;lt; curvelength {&lt;br /&gt;
    values.push(f32::sin((PI *i as f64/curvelength as f64) as f32));&lt;br /&gt;
    i += 1;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The output of this function can be seen in the test video attached to at the end of this page. &lt;br /&gt;
&amp;lt;references&amp;gt;&amp;lt;/references&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=='''Video of Testing Audio Output'''==&lt;br /&gt;
[https://drive.google.com/file/d/1jzEZwAZE-7mi6N5N_JcEE6ISM-wc9910/view?usp=sharing Test-1]&lt;br /&gt;
[https://drive.google.com/file/d/1UsPgyv29Zf29d6pEDgLpYX86DI6hzOqp/view?usp=sharing Test-2]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=='''Issues and Fixes'''==&lt;br /&gt;
&lt;br /&gt;
Windows Specific during build&lt;br /&gt;
&lt;br /&gt;
https://github.com/holochain/holochain-cmd/issues/29&lt;br /&gt;
&lt;br /&gt;
https://stackoverflow.com/questions/53136717/errore0554-feature-may-not-be-used-on-the-stable-release-channel-couldnt&lt;br /&gt;
&lt;br /&gt;
https://github.com/servo/servo/issues/21429&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=='''Final Project'''==&lt;br /&gt;
If you are a peer reviewer please look into this [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#For_Peer_Reviewers_Note section]&lt;br /&gt;
&lt;br /&gt;
The final [https://github.com/servo/servo/wiki/Implement-missing-WebAudio-automation-student-project project] rely on our previous [https://github.com/servo/media/pull/230 work]. The next part would focus on implementing the code [https://github.com/servo/media/issues/204 written] to be accessible by Servo browser [https://github.com/servo/servo/issues/22897 engine]. &lt;br /&gt;
This would require interfacing the DOM [https://github.com/servo/servo/blob/master/components/script/dom/webidls/AudioParam.webidl file] reference the Param.rs [https://github.com/JHBalaji/media/blob/master/audio/src/param.rs#L259 setValueCurveAtTime] to be interfaced with [https://github.com/servo/servo/blob/master/components/script/dom/audioparam.rs AudioParam.rs]. The audioparam.rs would call the UserAutomationEvent in the param.rs setValueCurveAtTime.&lt;br /&gt;
&lt;br /&gt;
Once the initial function call with arguments  are updated, then the [https://github.com/servo/servo/blob/master/tests/wpt/README.md#updating-test-expectations testing] would be performed on ''./mach test-wpt tests/wpt/web-platform-tests/webaudio/the-audio-api/[https://github.com/servo/servo/tree/master/tests/wpt/web-platform-tests/webaudio/the-audio-api/the-audioparam-interface the-audioparam-interface]''. The [https://github.com/servo/servo/tree/master/tests/wpt/web-platform-tests/webaudio/the-audio-api/the-audioparam-interface the-audioparam-interface] is a folder of series of test cases that emulate the behavior of a function call, here the setValueCurveAtTime would need to be necessitated to mock the values as tested in previous [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#Test_Case example] but would require to be performed over a .html webpage with DOM elements to test the complete functionality.&lt;br /&gt;
&lt;br /&gt;
Servo webAudio tests are performed using [https://github.com/web-platform-tests/wpt/blob/master/resources/readme.md testharness.js]. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach create-wpt tests/wpt/path/to/new/test.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
would create a test.html using the WPT template for javascript tests. Once the skeleton code is completed with necessary function call, them the WPT tests would be executed using &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach test-wpt tests/wpt/path/to/new/test.html&lt;br /&gt;
./mach test-wpt tests/wpt/path/to/new/reftest.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[https://web-platform-tests.org/writing-tests/reftests.html reftest] are used in Servo to test behavior related to rendering; that are related to interaction made up of several webpages [think passing or referencing values to another webpage] with assertions to test cases that are expected from the interaction. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach create-wpt --reftest tests/wpt/path/to/new/reftest.html --reference tests/wpt/path/to/reference.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
reference.html and reftest.html will be created using WPT reftest template. Once the reftest is run the upstream test would need to be updated using &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach update-wpt --sync&lt;br /&gt;
./mach test-wpt --log-raw=update.log&lt;br /&gt;
./mach update-wpt update.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When reftest fails to diagnose the behavior reftest raw log is required which is generate using the below command. The .log is fed into  [https://github.com/Gankro/live-reftest-analyzer  reftest analyzer] to find those failing test. The reftest is also capable of pixel level comparison of the test and reference screenshots (incase of rendering)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach test-wpt --log-raw wpt.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==='''List of issues'''===&lt;br /&gt;
This project has listed 4 known issues under the  WebAudio title, each solving a different issue.&lt;br /&gt;
&lt;br /&gt;
1. [https://github.com/servo/media/issues/204 Implement ValueCurveAtTime automation]&lt;br /&gt;
&lt;br /&gt;
This is the first issue, which has been addressed and successfully closed during the initial parts of this project. The steps followed are shown in the following diagram.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:WebAudio-Issue1.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. [https://github.com/servo/servo/issues/22897 Implement AudioParam.setValueCurveAtTime]&lt;br /&gt;
&lt;br /&gt;
This second issue builds up on the first one, and focuses on implementing yet another method called [https://webaudio.github.io/web-audio-api/#dom-audioparam-setvaluecurveattime setValueCurveAtTime]. The next focus of this project will likely be to work on this issue. This deals with the javascript API values for the curves.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:WebAudio-Issue2.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3. [https://github.com/servo/servo/issues/22898 Implement deprecated setPosition and setOrientation methods for AudioListener]&lt;br /&gt;
&lt;br /&gt;
The third issue deals with a few missing APIs for AudioListener. We need to accordingly add the new methods, i.e. [https://webaudio.github.io/web-audio-api/#dom-pannernode-setposition setPosition] and [https://webaudio.github.io/web-audio-api/#dom-pannernode-setorientation setOrientation] to the audiolistener.rs file so that they properly update the values of the relevant AudioParam members of AudioListener along with the passed arguments.This should help stopping an endless list of javascript errors when these deprecated methods weren't implemented.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:WebAudio-Issue3.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
4. [https://github.com/servo/media/issues/205 Implement WaveShaper node]&lt;br /&gt;
&lt;br /&gt;
This final issue listed tries to implement a new node called the [https://webaudio.github.io/web-audio-api/#waveshapernode WaveShaper node]. This is an independant issue and may be done before or after the other issues have been solved.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:WebAudio-Issue4.png]]&lt;br /&gt;
&lt;br /&gt;
=='''For Peer Reviewers Note'''==&lt;br /&gt;
&lt;br /&gt;
''Common peer review question clarifications are below,''&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Does the design incorporate all of the functionality required?&amp;quot; or &amp;quot;Check the changes that the authors proposed. Rate the overall quality of the explanations. Give comments if you find the explanation hard to follow or inadequate.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
:The [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#Final_Project section] clarifies your question.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Check the designs proposed by the authors.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
:There is no explicit design is involved as going by [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#Final_Project proposal], there are three files to be added with new functionality in addition to test cases and files.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Check the use of visual aids&amp;quot;&lt;br /&gt;
:Visual aids not applicable &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Give comments on the completeness of the design doc.&amp;quot;&lt;br /&gt;
: Let us know what you think about them!&lt;/div&gt;</summary>
		<author><name>Amadhus2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:WebAudio-Issue4.png&amp;diff=124047</id>
		<title>File:WebAudio-Issue4.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:WebAudio-Issue4.png&amp;diff=124047"/>
		<updated>2019-04-13T03:09:47Z</updated>

		<summary type="html">&lt;p&gt;Amadhus2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Amadhus2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support&amp;diff=124045</id>
		<title>CSC/ECE 517 Spring 2019 - Project M1901 Implement missing WebAudio automation support</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support&amp;diff=124045"/>
		<updated>2019-04-13T03:01:24Z</updated>

		<summary type="html">&lt;p&gt;Amadhus2: /* List of issues */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''Introduction'''== &lt;br /&gt;
&lt;br /&gt;
==='''Servo'''===&lt;br /&gt;
Servo is an developmental browser engine designed to make use of the memory safety properties and concurrency features of the Rust programming language. The project was initiated by Mozilla Research with effort from Samsung to port it to Android and ARM processors&lt;br /&gt;
&lt;br /&gt;
More information about Servo is available [https://servo.org here]&lt;br /&gt;
&lt;br /&gt;
==='''Rust'''===&lt;br /&gt;
Rust is a systems programming language which focuses on memory safety and concurrency. It is similar to C++ but ensures memory safety and provides high performance. Rust is brain child of Mozilla and simple as this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
fn main() {&lt;br /&gt;
    println!(&amp;quot;Hello World&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More information about Rust can be found [https://www.rust-lang.org/en-US/ here] and here is why we love [https://thenewstack.io/safer-future-rust/ Rust], [https://insights.stackoverflow.com/survey/2018/#most-loved-dreaded-and-wanted SF Loved]&lt;br /&gt;
&lt;br /&gt;
==='''Web Audio API'''===&lt;br /&gt;
The Web Audio API involves handling audio operations inside an audio context, and has been designed to allow modular routing. An audio routing graph has been created by linking together the Basic Audio operations performed with audio nodes. Several sources — with different types of channel layout — are supported even within a single context. This modular design provides the flexibility to create complex audio functions with dynamic effects.&lt;br /&gt;
&lt;br /&gt;
Audio nodes are linked into chains and simple webs by their inputs and outputs. They typically start with one or more sources. Sources provide arrays of sound intensities (samples) at very small timeslices, often tens of thousands of them per second. These could be either computed mathematically (such as OscillatorNode), or they can be recordings from sound/video files (like AudioBufferSourceNode and MediaElementAudioSourceNode) and audio streams (MediaStreamAudioSourceNode). In fact, sound files are just recordings of sound intensities themselves, which come in from microphones or electric instruments, and get mixed down into a single, complicated wave.&lt;br /&gt;
&lt;br /&gt;
Outputs of these nodes could be linked to inputs of others, which mix or modify these streams of sound samples into different streams. A common modification is multiplying the samples by a value to make them louder or quieter (as is the case with GainNode). Once the sound has been sufficiently processed for the intended effect, it can be linked to the input of a destination (AudioContext.destination), which sends the sound to the speakers or headphones. This last connection is only necessary if the user is supposed to hear the audio.&lt;br /&gt;
&lt;br /&gt;
A simple, typical workflow for web audio would look something like this:&lt;br /&gt;
&lt;br /&gt;
1. Create audio context&amp;lt;br&amp;gt;&lt;br /&gt;
2. Inside the context, create sources — such as &amp;lt;audio&amp;gt;, oscillator, stream&amp;lt;br&amp;gt;&lt;br /&gt;
3. Create effects nodes, such as reverb, biquad filter, panner, compressor&amp;lt;br&amp;gt;&lt;br /&gt;
4. Choose final destination of audio, for example your system speakers&amp;lt;br&amp;gt;&lt;br /&gt;
5. Connect the sources up to the effects, and the effects to the destination.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Problem Statement: Web Audio Automation'''===&lt;br /&gt;
&lt;br /&gt;
AudioParam is used to control the AudioNode functioning, say, Volume (a Gain parameter). These values can either be scheduled to be changed at precise times or set to particular value immediately following an event or at an event. The schedule to change when used with AudioContext.currentTime can helps in volume fades, filter sweeps etc. This would work aims to implement [https://github.com/servo/media/issues/204 SetValueCurveAtTime()].&lt;br /&gt;
&lt;br /&gt;
[https://webaudio.github.io/web-audio-api/#dom-audioparam-setvaluecurveattime setValueCurveAtTime()] is one such method in AudioParam that takes an array as input and schedules a change. The array is usually a curve in wedAudio and achieved my linear interpolation between the values from the floating-point values array and for the duration, d from the startTime, s&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;v(t) = values[N * (t - s) / d]&amp;lt;/code&amp;gt;, where N is the length of the values in the array.&lt;br /&gt;
And after the end of the curve time interval &amp;lt;code&amp;gt;(t &amp;gt;= s + d)&amp;lt;/code&amp;gt;, the value will remain constant at the final curve value. This would persist to happen until the next automation event.&lt;br /&gt;
&lt;br /&gt;
One of the application of setValueCurveAtTime() it to create tremolo effect. Suppose linear nor an exponential curve satisfy the needs then user can create curve based on values to setValueCurveAtTime() with an array of timing values. Its a much loved approached against multiple calls to setValueAtTime().&lt;br /&gt;
&lt;br /&gt;
==='''Build'''===&lt;br /&gt;
Servo is built with Cargo, the Rust package manager. We also use Mozilla's Mach tools to orchestrate the build and other tasks.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=='''Implementation of the Project'''== &lt;br /&gt;
&lt;br /&gt;
==='''Code'''===&lt;br /&gt;
The code is implemented as in [https://github.com/JHBalaji/media/blob/master/audio/src/param.rs#L418-L436 here]. The code below is the main code snippet for the SetValueCurveAtTime function. The values and function behavior is define in the param.rs file. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            AutomationEvent::SetValueCurveAtTime(ref values, start, duration) =&amp;gt; {&lt;br /&gt;
                let time_diff = ((duration.0 as f32) - (start.0 as f32)) as f32;&lt;br /&gt;
                let mut progress = ((((current_tick.0 as f32) - (start.0 as f32)) as f32) / time_diff) as f32;&lt;br /&gt;
                if progress &amp;lt; 0.0 {&lt;br /&gt;
                    progress = 0.0 as f32;&lt;br /&gt;
                }&lt;br /&gt;
                let n = values.len() as f32;&lt;br /&gt;
	            let k = (((n - 1.) * progress) as f32).floor();&lt;br /&gt;
                let next = k + 1. as f32;&lt;br /&gt;
                let step = time_diff / (n - 1.);&lt;br /&gt;
                if next &amp;lt; n {&lt;br /&gt;
                    let time_k = (k * step) as f32;&lt;br /&gt;
                    let time_k_next = (next * step) as f32;&lt;br /&gt;
                    let v_k = values[k as usize];&lt;br /&gt;
    				let v_k_next = values[next as usize];&lt;br /&gt;
                    *value = v_k + (v_k_next - v_k) * (((current_tick.0 as f32) - time_k) / (time_k_next - time_k));&lt;br /&gt;
                }&lt;br /&gt;
                true&lt;br /&gt;
            }&lt;br /&gt;
            AutomationEvent::CancelAndHoldAtTime(..) =&amp;gt; false,&lt;br /&gt;
            AutomationEvent::CancelScheduledValues(..) | AutomationEvent::SetValue(..) =&amp;gt; {&lt;br /&gt;
                unreachable!(&amp;quot;CancelScheduledValues/SetValue should never appear in the timeline&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Let's walk through the code. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;AutomationEvent::SetValueCurveAtTime()&amp;lt;/code&amp;gt; is a fn and takes three arguments: values, start, duration.&lt;br /&gt;
&lt;br /&gt;
progress, computes the difference between the first value in start_time and [https://github.com/JHBalaji/media/blob/5a981dff94f4dfaf2ebf0f0e09f599fab9d1a13b/audio/src/param.rs#L384 time] and makes explicit conversion to f32. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                let time_diff = ((duration.0 as f32) - (start.0 as f32)) as f32;&lt;br /&gt;
                let mut progress = ((((current_tick.0 as f32) - (start.0 as f32)) as f32) / time_diff) as f32;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
time_diff computes the total difference between duration and start_time, this is required when the values that needs to be computed goes beyond time_diff from start_time to set a constant value later.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                if progress &amp;lt; 0.0 {&lt;br /&gt;
                    progress = 0.0 as f32;&lt;br /&gt;
                }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Sets 0 if the progress from values array and present time being negative.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                let n = values.len() as f32;&lt;br /&gt;
	            let k = (((n - 1.) * progress) as f32).floor();&lt;br /&gt;
                let next = k + 1. as f32;&lt;br /&gt;
                let step = time_diff / (n - 1.);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
n, total length of values array. k, compute as k as in [[https://webaudio.github.io/web-audio-api/#dom-audioparam-setvaluecurveattime here] and &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; is k+1, the delta or step is computed that would be added to generate the sound wave from the values array. Say, the frequency start at 44KHz and the &amp;lt;code&amp;gt;step&amp;lt;/code&amp;gt; would be used to change the frequency of the curve.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                if next &amp;lt; n {&lt;br /&gt;
                    let time_k = (k * step) as f32;&lt;br /&gt;
                    let time_k_next = (next * step) as f32;&lt;br /&gt;
                    let v_k = values[k as usize];&lt;br /&gt;
    				let v_k_next = values[next as usize];&lt;br /&gt;
                    *value = v_k + (v_k_next - v_k) * (((current_tick.0 as f32) - time_k) / (time_k_next - time_k));&lt;br /&gt;
                }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code block generates sequences of values from &amp;lt;code&amp;gt;values&amp;lt;/code array and using &amp;lt;code&amp;gt;step&amp;lt;/code&amp;gt; value we computed. And does that till it reaches the total length of the array.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                true&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media/blob/f32a71c51f05f44d1e8ca217fbaa4dfb0b55d11e/audio/src/param.rs#L435 Used] to loop the function call made from [https://github.com/JHBalaji/media/blob/f32a71c51f05f44d1e8ca217fbaa4dfb0b55d11e/audio/src/param.rs#L117 here].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            AutomationEvent::CancelAndHoldAtTime(..) =&amp;gt; false,&lt;br /&gt;
            AutomationEvent::CancelScheduledValues(..) | AutomationEvent::SetValue(..) =&amp;gt; {&lt;br /&gt;
                unreachable!(&amp;quot;CancelScheduledValues/SetValue should never appear in the timeline&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media/blob/5a981dff94f4dfaf2ebf0f0e09f599fab9d1a13b/audio/src/param.rs#L466 Code] instructs to cancel this event or end of this function and proceed to next instructions. In Audio API unless you explicitly say the block to end, the block would end and hardware device would be stopped from consumption.&lt;br /&gt;
&lt;br /&gt;
==='''Examples'''===&lt;br /&gt;
&lt;br /&gt;
Examples are unique aspect to Rust. This instructs that code to make use of the function we just wrote and generates a sound output. Refer our example [https://github.com/JHBalaji/media-1/blob/master/examples/set_value_curve.rs here] for the SetValueCurveAtTime()&lt;br /&gt;
&lt;br /&gt;
And example is usually called by using cargo build in rust or cargo run.&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media-1/blob/master/examples/Cargo.toml Cargo.toml] dictates the naming and the file to be called as.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cargo run --example set_value_curve&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above code instructs to run the example [https://github.com/JHBalaji/media-1/blob/master/examples/set_value_curve.rs set_value_curve] to generate a sound output through our terminal.&lt;br /&gt;
&lt;br /&gt;
==='''Compile'''===&lt;br /&gt;
[https://github.com/JHBalaji/media-1/blob/master/Cargo.lock Cargo.lock] instructs the dependencies that would be required to build this project.&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media-1/blob/master/Cargo.toml Cargo.toml] calls all the folders or members to be complied. Usually the compilation would be at /media&lt;br /&gt;
&lt;br /&gt;
Cargo.lock installs number of packages called crates that would be used by the project to access the modules. Each of the member in [https://github.com/JHBalaji/media-1/blob/master/Cargo.toml Cargo.toml] would have [https://github.com/JHBalaji/media-1/blob/master/examples/Cargo.toml Cargo.toml] in them that would instruct [https://github.com/JHBalaji/media-1/blob/master/examples/Cargo.toml#L6 dependencies] during the build. build-dependencies would be used if you have dependencies before the build.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media-1/blob/master/.cargo/config .cargo config] is similar to a dotenv file for Rust&lt;br /&gt;
&lt;br /&gt;
==='''Test'''===&lt;br /&gt;
&lt;br /&gt;
If you would like to test our build please look into [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#Issues_and_Fixes Fixes] before proceeding. We would suggest MacOS or Linux 16.04 LTS for any development and testing. Virtual Machine or VirtualBox could be another option. We spent countless days in frustration with libraries and never ending apt installs so avoid Linux 18.04 for this build test.&lt;br /&gt;
&lt;br /&gt;
Once &amp;lt;code&amp;gt;cargo build&amp;lt;/code&amp;gt; is completed. Open /target/debug to view the examples that are generated.&lt;br /&gt;
&lt;br /&gt;
[[File:Servo-initial-build.PNG]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To run all examples after the cargo build is complete, use &amp;lt;code&amp;gt;cargo run --example &amp;lt;bin_name&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Examples.PNG]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Status of the Project'''===&lt;br /&gt;
&lt;br /&gt;
The [https://github.com/JHBalaji/media-1 build] is ready and the Pull request is [https://github.com/servo/media/pull/230 merged] with Servo/media.&lt;br /&gt;
&lt;br /&gt;
[[File:Pr.PNG]]&lt;br /&gt;
&lt;br /&gt;
=='''Normal build from Master Repo '''==&lt;br /&gt;
To build Servo in development mode. This is useful for development, but the resulting binary is very slow.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git clone https://github.com/servo/servo&lt;br /&gt;
cd servo&lt;br /&gt;
./mach build --dev&lt;br /&gt;
./mach run tests/html/about-mozilla.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
For benchmarking, performance testing, or real-world use, add the --release flag to create an optimized build:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach build --release&lt;br /&gt;
./mach run --release tests/html/about-mozilla.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==='''Compiling and Running the code'''===&lt;br /&gt;
&lt;br /&gt;
====Mac OS====&lt;br /&gt;
&lt;br /&gt;
Follow the instructions posted in this [https://github.com/JHBalaji/media-1 URL] and install GStreamer and Rust. After that follow the following lines for compiling on MacOS. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1. brew install gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-libav gst-rtsp-server gst-editing-services&lt;br /&gt;
&lt;br /&gt;
2. export PKG_CONFIG_PATH=/usr/local/Cellar/libffi/3.2.1/lib/pkgconfig/&lt;br /&gt;
&lt;br /&gt;
3. rustup override set nightly&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After this run the following command to compile servo/media &lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
cargo build &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After compiling you will be able to test our example that is places in the examples folder.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Windows and Linux====&lt;br /&gt;
&lt;br /&gt;
Head over here to install [https://rustup.rs/ Rust ToolChain]. If you need any additional details we would suggest reading the [https://github.com/rust-lang/rustup.rs/blob/master/README.md ReadMe on Rust]. Some Servo media specific build issues are [https://github.com/servo/media/blob/master/README.md advised]. &lt;br /&gt;
&lt;br /&gt;
We would suggest Ubuntu 18.04 LTS with updates [https://github.com/servo/media/blob/master/README.md gstreamer package].&lt;br /&gt;
&lt;br /&gt;
==='''Servo Media'''===&lt;br /&gt;
&amp;lt;b&amp;gt;Requirements&amp;lt;/b&amp;gt;&lt;br /&gt;
In order to build this crate you need to install gstreamer which can be found here [https://github.com/sdroege/gstreamer-rs]&lt;br /&gt;
==='''Test Case'''===&lt;br /&gt;
After you run cargo build, you should be able to see the executable of the example inside the target/debug folder. Following is the test we have written  file to check the functioning of the [https://github.com/JHBalaji/media-1/blob/master/examples/set_value_curve.rs SetValueCurveAtTIme].&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
extern crate servo_media;&lt;br /&gt;
extern crate servo_media_auto;&lt;br /&gt;
&lt;br /&gt;
use servo_media::audio::constant_source_node::ConstantSourceNodeOptions;&lt;br /&gt;
use servo_media::audio::gain_node::GainNodeOptions;&lt;br /&gt;
use servo_media::audio::node::{AudioNodeInit, AudioNodeMessage, AudioScheduledSourceNodeMessage};&lt;br /&gt;
use servo_media::audio::param::{ParamType, UserAutomationEvent};&lt;br /&gt;
use servo_media::ServoMedia;&lt;br /&gt;
use std::sync::Arc;&lt;br /&gt;
use std::{thread, time};&lt;br /&gt;
&lt;br /&gt;
fn run_example(servo_media: Arc&amp;lt;ServoMedia&amp;gt;) {&lt;br /&gt;
    let context = servo_media.create_audio_context(Default::default());&lt;br /&gt;
    let dest = context.dest_node();&lt;br /&gt;
&lt;br /&gt;
    //Initializing the values vector for SetValueCurve function&lt;br /&gt;
    let mut values: Vec&amp;lt;f32&amp;gt; = Vec::new();&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(1.0);&lt;br /&gt;
    values.push(1.0);&lt;br /&gt;
    values.push(1.0);&lt;br /&gt;
    values.push(1.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.5);&lt;br /&gt;
    values.push(0.5);&lt;br /&gt;
    values.push(0.5);&lt;br /&gt;
    values.push(0.5);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    let start_time = 0.;&lt;br /&gt;
    let end_time = 5.;&lt;br /&gt;
    let n = values.len() as f32;&lt;br /&gt;
    let value_next = values[(n - 1.) as usize];&lt;br /&gt;
&lt;br /&gt;
    let cs = context.create_node(&lt;br /&gt;
        AudioNodeInit::ConstantSourceNode(ConstantSourceNodeOptions::default()),&lt;br /&gt;
        Default::default(),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    let mut gain_options = GainNodeOptions::default();&lt;br /&gt;
    gain_options.gain = 0.0;&lt;br /&gt;
    let gain = context.create_node(&lt;br /&gt;
        AudioNodeInit::GainNode(gain_options.clone()),&lt;br /&gt;
        Default::default(),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    let osc = context.create_node(&lt;br /&gt;
        AudioNodeInit::OscillatorNode(Default::default()),&lt;br /&gt;
        Default::default(),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.connect_ports(osc.output(0), gain.input(0));&lt;br /&gt;
    context.connect_ports(cs.output(0), gain.param(ParamType::Gain));&lt;br /&gt;
    context.connect_ports(gain.output(0), dest.input(0));&lt;br /&gt;
&lt;br /&gt;
    let _ = context.resume();&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        osc,&lt;br /&gt;
        AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(0.)),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        gain,&lt;br /&gt;
        AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(0.)),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        cs,&lt;br /&gt;
        AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(0.)),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        cs,&lt;br /&gt;
        AudioNodeMessage::SetParam(&lt;br /&gt;
            ParamType::Offset,&lt;br /&gt;
            UserAutomationEvent::SetValueCurveAtTime(values, start_time, end_time),&lt;br /&gt;
        ),&lt;br /&gt;
&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        osc,&lt;br /&gt;
        AudioNodeMessage::SetParam(&lt;br /&gt;
            ParamType::Frequency,&lt;br /&gt;
            UserAutomationEvent::SetValueAtTime(value_next, end_time),&lt;br /&gt;
        ),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    thread::sleep(time::Duration::from_millis(7000));&lt;br /&gt;
    let _ = context.close();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
fn main() {&lt;br /&gt;
    ServoMedia::init::&amp;lt;servo_media_auto::Backend&amp;gt;();&lt;br /&gt;
    if let Ok(servo_media) = ServoMedia::get() {&lt;br /&gt;
        run_example(servo_media);&lt;br /&gt;
    } else {&lt;br /&gt;
        unreachable!();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above program, the values vector is passed into the SetValueCurveAtTime function to modulate the output. The output of the same can also be checked in the test-case video at the end of this page. &lt;br /&gt;
We can modify the values function as we want and observe the output. One more modification that we used was by using a sine curve. It is implemented as follows. Change the values vector in the set-value-curve function with the following: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 use std::f64::consts::PI;&lt;br /&gt;
    let mut values: Vec&amp;lt;f32&amp;gt; = Vec::new();&lt;br /&gt;
    let curvelength = 44100;&lt;br /&gt;
    let mut i = 0;&lt;br /&gt;
    while i &amp;lt; curvelength {&lt;br /&gt;
    values.push(f32::sin((PI *i as f64/curvelength as f64) as f32));&lt;br /&gt;
    i += 1;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The output of this function can be seen in the test video attached to at the end of this page. &lt;br /&gt;
&amp;lt;references&amp;gt;&amp;lt;/references&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=='''Video of Testing Audio Output'''==&lt;br /&gt;
[https://drive.google.com/file/d/1jzEZwAZE-7mi6N5N_JcEE6ISM-wc9910/view?usp=sharing Test-1]&lt;br /&gt;
[https://drive.google.com/file/d/1UsPgyv29Zf29d6pEDgLpYX86DI6hzOqp/view?usp=sharing Test-2]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=='''Issues and Fixes'''==&lt;br /&gt;
&lt;br /&gt;
Windows Specific during build&lt;br /&gt;
&lt;br /&gt;
https://github.com/holochain/holochain-cmd/issues/29&lt;br /&gt;
&lt;br /&gt;
https://stackoverflow.com/questions/53136717/errore0554-feature-may-not-be-used-on-the-stable-release-channel-couldnt&lt;br /&gt;
&lt;br /&gt;
https://github.com/servo/servo/issues/21429&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=='''Final Project'''==&lt;br /&gt;
If you are a peer reviewer please look into this [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#For_Peer_Reviewers_Note section]&lt;br /&gt;
&lt;br /&gt;
The final [https://github.com/servo/servo/wiki/Implement-missing-WebAudio-automation-student-project project] rely on our previous [https://github.com/servo/media/pull/230 work]. The next part would focus on implementing the code [https://github.com/servo/media/issues/204 written] to be accessible by Servo browser [https://github.com/servo/servo/issues/22897 engine]. &lt;br /&gt;
This would require interfacing the DOM [https://github.com/servo/servo/blob/master/components/script/dom/webidls/AudioParam.webidl file] reference the Param.rs [https://github.com/JHBalaji/media/blob/master/audio/src/param.rs#L259 setValueCurveAtTime] to be interfaced with [https://github.com/servo/servo/blob/master/components/script/dom/audioparam.rs AudioParam.rs]. The audioparam.rs would call the UserAutomationEvent in the param.rs setValueCurveAtTime.&lt;br /&gt;
&lt;br /&gt;
Once the initial function call with arguments  are updated, then the [https://github.com/servo/servo/blob/master/tests/wpt/README.md#updating-test-expectations testing] would be performed on ''./mach test-wpt tests/wpt/web-platform-tests/webaudio/the-audio-api/[https://github.com/servo/servo/tree/master/tests/wpt/web-platform-tests/webaudio/the-audio-api/the-audioparam-interface the-audioparam-interface]''. The [https://github.com/servo/servo/tree/master/tests/wpt/web-platform-tests/webaudio/the-audio-api/the-audioparam-interface the-audioparam-interface] is a folder of series of test cases that emulate the behavior of a function call, here the setValueCurveAtTime would need to be necessitated to mock the values as tested in previous [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#Test_Case example] but would require to be performed over a .html webpage with DOM elements to test the complete functionality.&lt;br /&gt;
&lt;br /&gt;
Servo webAudio tests are performed using [https://github.com/web-platform-tests/wpt/blob/master/resources/readme.md testharness.js]. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach create-wpt tests/wpt/path/to/new/test.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
would create a test.html using the WPT template for javascript tests. Once the skeleton code is completed with necessary function call, them the WPT tests would be executed using &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach test-wpt tests/wpt/path/to/new/test.html&lt;br /&gt;
./mach test-wpt tests/wpt/path/to/new/reftest.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[https://web-platform-tests.org/writing-tests/reftests.html reftest] are used in Servo to test behavior related to rendering; that are related to interaction made up of several webpages [think passing or referencing values to another webpage] with assertions to test cases that are expected from the interaction. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach create-wpt --reftest tests/wpt/path/to/new/reftest.html --reference tests/wpt/path/to/reference.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
reference.html and reftest.html will be created using WPT reftest template. Once the reftest is run the upstream test would need to be updated using &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach update-wpt --sync&lt;br /&gt;
./mach test-wpt --log-raw=update.log&lt;br /&gt;
./mach update-wpt update.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When reftest fails to diagnose the behavior reftest raw log is required which is generate using the below command. The .log is fed into  [https://github.com/Gankro/live-reftest-analyzer  reftest analyzer] to find those failing test. The reftest is also capable of pixel level comparison of the test and reference screenshots (incase of rendering)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach test-wpt --log-raw wpt.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==='''List of issues'''===&lt;br /&gt;
This project has listed 4 known issues under the  WebAudio title, each solving a different issue.&lt;br /&gt;
&lt;br /&gt;
1. [https://github.com/servo/media/issues/204 Implement ValueCurveAtTime automation]&lt;br /&gt;
&lt;br /&gt;
This is the first issue, which has been addressed and successfully closed during the initial parts of this project. The steps followed are shown in the following diagram.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:WebAudio-Issue1.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. [https://github.com/servo/servo/issues/22897 Implement AudioParam.setValueCurveAtTime]&lt;br /&gt;
&lt;br /&gt;
This second issue builds up on the first one, and focuses on implementing yet another method called [https://webaudio.github.io/web-audio-api/#dom-audioparam-setvaluecurveattime setValueCurveAtTime]. The next focus of this project will likely be to work on this issue. This deals with the javascript API values for the curves.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:WebAudio-Issue2.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3. [https://github.com/servo/servo/issues/22898 Implement deprecated setPosition and setOrientation methods for AudioListener]&lt;br /&gt;
&lt;br /&gt;
The third issue deals with a few missing APIs for AudioListener. We need to accordingly add the new methods, i.e. setPosition and setOrientation to the audiolistener.rs file so that they properly update the values of the relevant AudioParam members of AudioListener along with the passed arguments.This should help stopping an endless list of javascript errors when these deprecated methods weren't implemented.&lt;br /&gt;
&lt;br /&gt;
[[File:WebAudio-Issue3.png]]&lt;br /&gt;
&lt;br /&gt;
=='''For Peer Reviewers Note'''==&lt;br /&gt;
&lt;br /&gt;
''Common peer review question clarifications are below,''&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Does the design incorporate all of the functionality required?&amp;quot; or &amp;quot;Check the changes that the authors proposed. Rate the overall quality of the explanations. Give comments if you find the explanation hard to follow or inadequate.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
:The [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#Final_Project section] clarifies your question.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Check the designs proposed by the authors.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
:There is no explicit design is involved as going by [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#Final_Project proposal], there are three files to be added with new functionality in addition to test cases and files.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Check the use of visual aids&amp;quot;&lt;br /&gt;
:Visual aids not applicable &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Give comments on the completeness of the design doc.&amp;quot;&lt;br /&gt;
: Let us know what you think about them!&lt;/div&gt;</summary>
		<author><name>Amadhus2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:WebAudio-Issue3.png&amp;diff=124044</id>
		<title>File:WebAudio-Issue3.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:WebAudio-Issue3.png&amp;diff=124044"/>
		<updated>2019-04-13T03:01:04Z</updated>

		<summary type="html">&lt;p&gt;Amadhus2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Amadhus2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support&amp;diff=124040</id>
		<title>CSC/ECE 517 Spring 2019 - Project M1901 Implement missing WebAudio automation support</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support&amp;diff=124040"/>
		<updated>2019-04-13T02:52:52Z</updated>

		<summary type="html">&lt;p&gt;Amadhus2: /* Final Project */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''Introduction'''== &lt;br /&gt;
&lt;br /&gt;
==='''Servo'''===&lt;br /&gt;
Servo is an developmental browser engine designed to make use of the memory safety properties and concurrency features of the Rust programming language. The project was initiated by Mozilla Research with effort from Samsung to port it to Android and ARM processors&lt;br /&gt;
&lt;br /&gt;
More information about Servo is available [https://servo.org here]&lt;br /&gt;
&lt;br /&gt;
==='''Rust'''===&lt;br /&gt;
Rust is a systems programming language which focuses on memory safety and concurrency. It is similar to C++ but ensures memory safety and provides high performance. Rust is brain child of Mozilla and simple as this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
fn main() {&lt;br /&gt;
    println!(&amp;quot;Hello World&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More information about Rust can be found [https://www.rust-lang.org/en-US/ here] and here is why we love [https://thenewstack.io/safer-future-rust/ Rust], [https://insights.stackoverflow.com/survey/2018/#most-loved-dreaded-and-wanted SF Loved]&lt;br /&gt;
&lt;br /&gt;
==='''Web Audio API'''===&lt;br /&gt;
The Web Audio API involves handling audio operations inside an audio context, and has been designed to allow modular routing. An audio routing graph has been created by linking together the Basic Audio operations performed with audio nodes. Several sources — with different types of channel layout — are supported even within a single context. This modular design provides the flexibility to create complex audio functions with dynamic effects.&lt;br /&gt;
&lt;br /&gt;
Audio nodes are linked into chains and simple webs by their inputs and outputs. They typically start with one or more sources. Sources provide arrays of sound intensities (samples) at very small timeslices, often tens of thousands of them per second. These could be either computed mathematically (such as OscillatorNode), or they can be recordings from sound/video files (like AudioBufferSourceNode and MediaElementAudioSourceNode) and audio streams (MediaStreamAudioSourceNode). In fact, sound files are just recordings of sound intensities themselves, which come in from microphones or electric instruments, and get mixed down into a single, complicated wave.&lt;br /&gt;
&lt;br /&gt;
Outputs of these nodes could be linked to inputs of others, which mix or modify these streams of sound samples into different streams. A common modification is multiplying the samples by a value to make them louder or quieter (as is the case with GainNode). Once the sound has been sufficiently processed for the intended effect, it can be linked to the input of a destination (AudioContext.destination), which sends the sound to the speakers or headphones. This last connection is only necessary if the user is supposed to hear the audio.&lt;br /&gt;
&lt;br /&gt;
A simple, typical workflow for web audio would look something like this:&lt;br /&gt;
&lt;br /&gt;
1. Create audio context&amp;lt;br&amp;gt;&lt;br /&gt;
2. Inside the context, create sources — such as &amp;lt;audio&amp;gt;, oscillator, stream&amp;lt;br&amp;gt;&lt;br /&gt;
3. Create effects nodes, such as reverb, biquad filter, panner, compressor&amp;lt;br&amp;gt;&lt;br /&gt;
4. Choose final destination of audio, for example your system speakers&amp;lt;br&amp;gt;&lt;br /&gt;
5. Connect the sources up to the effects, and the effects to the destination.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Problem Statement: Web Audio Automation'''===&lt;br /&gt;
&lt;br /&gt;
AudioParam is used to control the AudioNode functioning, say, Volume (a Gain parameter). These values can either be scheduled to be changed at precise times or set to particular value immediately following an event or at an event. The schedule to change when used with AudioContext.currentTime can helps in volume fades, filter sweeps etc. This would work aims to implement [https://github.com/servo/media/issues/204 SetValueCurveAtTime()].&lt;br /&gt;
&lt;br /&gt;
[https://webaudio.github.io/web-audio-api/#dom-audioparam-setvaluecurveattime setValueCurveAtTime()] is one such method in AudioParam that takes an array as input and schedules a change. The array is usually a curve in wedAudio and achieved my linear interpolation between the values from the floating-point values array and for the duration, d from the startTime, s&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;v(t) = values[N * (t - s) / d]&amp;lt;/code&amp;gt;, where N is the length of the values in the array.&lt;br /&gt;
And after the end of the curve time interval &amp;lt;code&amp;gt;(t &amp;gt;= s + d)&amp;lt;/code&amp;gt;, the value will remain constant at the final curve value. This would persist to happen until the next automation event.&lt;br /&gt;
&lt;br /&gt;
One of the application of setValueCurveAtTime() it to create tremolo effect. Suppose linear nor an exponential curve satisfy the needs then user can create curve based on values to setValueCurveAtTime() with an array of timing values. Its a much loved approached against multiple calls to setValueAtTime().&lt;br /&gt;
&lt;br /&gt;
==='''Build'''===&lt;br /&gt;
Servo is built with Cargo, the Rust package manager. We also use Mozilla's Mach tools to orchestrate the build and other tasks.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=='''Implementation of the Project'''== &lt;br /&gt;
&lt;br /&gt;
==='''Code'''===&lt;br /&gt;
The code is implemented as in [https://github.com/JHBalaji/media/blob/master/audio/src/param.rs#L418-L436 here]. The code below is the main code snippet for the SetValueCurveAtTime function. The values and function behavior is define in the param.rs file. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            AutomationEvent::SetValueCurveAtTime(ref values, start, duration) =&amp;gt; {&lt;br /&gt;
                let time_diff = ((duration.0 as f32) - (start.0 as f32)) as f32;&lt;br /&gt;
                let mut progress = ((((current_tick.0 as f32) - (start.0 as f32)) as f32) / time_diff) as f32;&lt;br /&gt;
                if progress &amp;lt; 0.0 {&lt;br /&gt;
                    progress = 0.0 as f32;&lt;br /&gt;
                }&lt;br /&gt;
                let n = values.len() as f32;&lt;br /&gt;
	            let k = (((n - 1.) * progress) as f32).floor();&lt;br /&gt;
                let next = k + 1. as f32;&lt;br /&gt;
                let step = time_diff / (n - 1.);&lt;br /&gt;
                if next &amp;lt; n {&lt;br /&gt;
                    let time_k = (k * step) as f32;&lt;br /&gt;
                    let time_k_next = (next * step) as f32;&lt;br /&gt;
                    let v_k = values[k as usize];&lt;br /&gt;
    				let v_k_next = values[next as usize];&lt;br /&gt;
                    *value = v_k + (v_k_next - v_k) * (((current_tick.0 as f32) - time_k) / (time_k_next - time_k));&lt;br /&gt;
                }&lt;br /&gt;
                true&lt;br /&gt;
            }&lt;br /&gt;
            AutomationEvent::CancelAndHoldAtTime(..) =&amp;gt; false,&lt;br /&gt;
            AutomationEvent::CancelScheduledValues(..) | AutomationEvent::SetValue(..) =&amp;gt; {&lt;br /&gt;
                unreachable!(&amp;quot;CancelScheduledValues/SetValue should never appear in the timeline&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Let's walk through the code. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;AutomationEvent::SetValueCurveAtTime()&amp;lt;/code&amp;gt; is a fn and takes three arguments: values, start, duration.&lt;br /&gt;
&lt;br /&gt;
progress, computes the difference between the first value in start_time and [https://github.com/JHBalaji/media/blob/5a981dff94f4dfaf2ebf0f0e09f599fab9d1a13b/audio/src/param.rs#L384 time] and makes explicit conversion to f32. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                let time_diff = ((duration.0 as f32) - (start.0 as f32)) as f32;&lt;br /&gt;
                let mut progress = ((((current_tick.0 as f32) - (start.0 as f32)) as f32) / time_diff) as f32;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
time_diff computes the total difference between duration and start_time, this is required when the values that needs to be computed goes beyond time_diff from start_time to set a constant value later.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                if progress &amp;lt; 0.0 {&lt;br /&gt;
                    progress = 0.0 as f32;&lt;br /&gt;
                }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Sets 0 if the progress from values array and present time being negative.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                let n = values.len() as f32;&lt;br /&gt;
	            let k = (((n - 1.) * progress) as f32).floor();&lt;br /&gt;
                let next = k + 1. as f32;&lt;br /&gt;
                let step = time_diff / (n - 1.);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
n, total length of values array. k, compute as k as in [[https://webaudio.github.io/web-audio-api/#dom-audioparam-setvaluecurveattime here] and &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; is k+1, the delta or step is computed that would be added to generate the sound wave from the values array. Say, the frequency start at 44KHz and the &amp;lt;code&amp;gt;step&amp;lt;/code&amp;gt; would be used to change the frequency of the curve.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                if next &amp;lt; n {&lt;br /&gt;
                    let time_k = (k * step) as f32;&lt;br /&gt;
                    let time_k_next = (next * step) as f32;&lt;br /&gt;
                    let v_k = values[k as usize];&lt;br /&gt;
    				let v_k_next = values[next as usize];&lt;br /&gt;
                    *value = v_k + (v_k_next - v_k) * (((current_tick.0 as f32) - time_k) / (time_k_next - time_k));&lt;br /&gt;
                }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code block generates sequences of values from &amp;lt;code&amp;gt;values&amp;lt;/code array and using &amp;lt;code&amp;gt;step&amp;lt;/code&amp;gt; value we computed. And does that till it reaches the total length of the array.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                true&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media/blob/f32a71c51f05f44d1e8ca217fbaa4dfb0b55d11e/audio/src/param.rs#L435 Used] to loop the function call made from [https://github.com/JHBalaji/media/blob/f32a71c51f05f44d1e8ca217fbaa4dfb0b55d11e/audio/src/param.rs#L117 here].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            AutomationEvent::CancelAndHoldAtTime(..) =&amp;gt; false,&lt;br /&gt;
            AutomationEvent::CancelScheduledValues(..) | AutomationEvent::SetValue(..) =&amp;gt; {&lt;br /&gt;
                unreachable!(&amp;quot;CancelScheduledValues/SetValue should never appear in the timeline&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media/blob/5a981dff94f4dfaf2ebf0f0e09f599fab9d1a13b/audio/src/param.rs#L466 Code] instructs to cancel this event or end of this function and proceed to next instructions. In Audio API unless you explicitly say the block to end, the block would end and hardware device would be stopped from consumption.&lt;br /&gt;
&lt;br /&gt;
==='''Examples'''===&lt;br /&gt;
&lt;br /&gt;
Examples are unique aspect to Rust. This instructs that code to make use of the function we just wrote and generates a sound output. Refer our example [https://github.com/JHBalaji/media-1/blob/master/examples/set_value_curve.rs here] for the SetValueCurveAtTime()&lt;br /&gt;
&lt;br /&gt;
And example is usually called by using cargo build in rust or cargo run.&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media-1/blob/master/examples/Cargo.toml Cargo.toml] dictates the naming and the file to be called as.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cargo run --example set_value_curve&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above code instructs to run the example [https://github.com/JHBalaji/media-1/blob/master/examples/set_value_curve.rs set_value_curve] to generate a sound output through our terminal.&lt;br /&gt;
&lt;br /&gt;
==='''Compile'''===&lt;br /&gt;
[https://github.com/JHBalaji/media-1/blob/master/Cargo.lock Cargo.lock] instructs the dependencies that would be required to build this project.&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media-1/blob/master/Cargo.toml Cargo.toml] calls all the folders or members to be complied. Usually the compilation would be at /media&lt;br /&gt;
&lt;br /&gt;
Cargo.lock installs number of packages called crates that would be used by the project to access the modules. Each of the member in [https://github.com/JHBalaji/media-1/blob/master/Cargo.toml Cargo.toml] would have [https://github.com/JHBalaji/media-1/blob/master/examples/Cargo.toml Cargo.toml] in them that would instruct [https://github.com/JHBalaji/media-1/blob/master/examples/Cargo.toml#L6 dependencies] during the build. build-dependencies would be used if you have dependencies before the build.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media-1/blob/master/.cargo/config .cargo config] is similar to a dotenv file for Rust&lt;br /&gt;
&lt;br /&gt;
==='''Test'''===&lt;br /&gt;
&lt;br /&gt;
If you would like to test our build please look into [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#Issues_and_Fixes Fixes] before proceeding. We would suggest MacOS or Linux 16.04 LTS for any development and testing. Virtual Machine or VirtualBox could be another option. We spent countless days in frustration with libraries and never ending apt installs so avoid Linux 18.04 for this build test.&lt;br /&gt;
&lt;br /&gt;
Once &amp;lt;code&amp;gt;cargo build&amp;lt;/code&amp;gt; is completed. Open /target/debug to view the examples that are generated.&lt;br /&gt;
&lt;br /&gt;
[[File:Servo-initial-build.PNG]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To run all examples after the cargo build is complete, use &amp;lt;code&amp;gt;cargo run --example &amp;lt;bin_name&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Examples.PNG]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Status of the Project'''===&lt;br /&gt;
&lt;br /&gt;
The [https://github.com/JHBalaji/media-1 build] is ready and the Pull request is [https://github.com/servo/media/pull/230 merged] with Servo/media.&lt;br /&gt;
&lt;br /&gt;
[[File:Pr.PNG]]&lt;br /&gt;
&lt;br /&gt;
=='''Normal build from Master Repo '''==&lt;br /&gt;
To build Servo in development mode. This is useful for development, but the resulting binary is very slow.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git clone https://github.com/servo/servo&lt;br /&gt;
cd servo&lt;br /&gt;
./mach build --dev&lt;br /&gt;
./mach run tests/html/about-mozilla.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
For benchmarking, performance testing, or real-world use, add the --release flag to create an optimized build:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach build --release&lt;br /&gt;
./mach run --release tests/html/about-mozilla.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==='''Compiling and Running the code'''===&lt;br /&gt;
&lt;br /&gt;
====Mac OS====&lt;br /&gt;
&lt;br /&gt;
Follow the instructions posted in this [https://github.com/JHBalaji/media-1 URL] and install GStreamer and Rust. After that follow the following lines for compiling on MacOS. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1. brew install gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-libav gst-rtsp-server gst-editing-services&lt;br /&gt;
&lt;br /&gt;
2. export PKG_CONFIG_PATH=/usr/local/Cellar/libffi/3.2.1/lib/pkgconfig/&lt;br /&gt;
&lt;br /&gt;
3. rustup override set nightly&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After this run the following command to compile servo/media &lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
cargo build &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After compiling you will be able to test our example that is places in the examples folder.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Windows and Linux====&lt;br /&gt;
&lt;br /&gt;
Head over here to install [https://rustup.rs/ Rust ToolChain]. If you need any additional details we would suggest reading the [https://github.com/rust-lang/rustup.rs/blob/master/README.md ReadMe on Rust]. Some Servo media specific build issues are [https://github.com/servo/media/blob/master/README.md advised]. &lt;br /&gt;
&lt;br /&gt;
We would suggest Ubuntu 18.04 LTS with updates [https://github.com/servo/media/blob/master/README.md gstreamer package].&lt;br /&gt;
&lt;br /&gt;
==='''Servo Media'''===&lt;br /&gt;
&amp;lt;b&amp;gt;Requirements&amp;lt;/b&amp;gt;&lt;br /&gt;
In order to build this crate you need to install gstreamer which can be found here [https://github.com/sdroege/gstreamer-rs]&lt;br /&gt;
==='''Test Case'''===&lt;br /&gt;
After you run cargo build, you should be able to see the executable of the example inside the target/debug folder. Following is the test we have written  file to check the functioning of the [https://github.com/JHBalaji/media-1/blob/master/examples/set_value_curve.rs SetValueCurveAtTIme].&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
extern crate servo_media;&lt;br /&gt;
extern crate servo_media_auto;&lt;br /&gt;
&lt;br /&gt;
use servo_media::audio::constant_source_node::ConstantSourceNodeOptions;&lt;br /&gt;
use servo_media::audio::gain_node::GainNodeOptions;&lt;br /&gt;
use servo_media::audio::node::{AudioNodeInit, AudioNodeMessage, AudioScheduledSourceNodeMessage};&lt;br /&gt;
use servo_media::audio::param::{ParamType, UserAutomationEvent};&lt;br /&gt;
use servo_media::ServoMedia;&lt;br /&gt;
use std::sync::Arc;&lt;br /&gt;
use std::{thread, time};&lt;br /&gt;
&lt;br /&gt;
fn run_example(servo_media: Arc&amp;lt;ServoMedia&amp;gt;) {&lt;br /&gt;
    let context = servo_media.create_audio_context(Default::default());&lt;br /&gt;
    let dest = context.dest_node();&lt;br /&gt;
&lt;br /&gt;
    //Initializing the values vector for SetValueCurve function&lt;br /&gt;
    let mut values: Vec&amp;lt;f32&amp;gt; = Vec::new();&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(1.0);&lt;br /&gt;
    values.push(1.0);&lt;br /&gt;
    values.push(1.0);&lt;br /&gt;
    values.push(1.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.5);&lt;br /&gt;
    values.push(0.5);&lt;br /&gt;
    values.push(0.5);&lt;br /&gt;
    values.push(0.5);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    let start_time = 0.;&lt;br /&gt;
    let end_time = 5.;&lt;br /&gt;
    let n = values.len() as f32;&lt;br /&gt;
    let value_next = values[(n - 1.) as usize];&lt;br /&gt;
&lt;br /&gt;
    let cs = context.create_node(&lt;br /&gt;
        AudioNodeInit::ConstantSourceNode(ConstantSourceNodeOptions::default()),&lt;br /&gt;
        Default::default(),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    let mut gain_options = GainNodeOptions::default();&lt;br /&gt;
    gain_options.gain = 0.0;&lt;br /&gt;
    let gain = context.create_node(&lt;br /&gt;
        AudioNodeInit::GainNode(gain_options.clone()),&lt;br /&gt;
        Default::default(),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    let osc = context.create_node(&lt;br /&gt;
        AudioNodeInit::OscillatorNode(Default::default()),&lt;br /&gt;
        Default::default(),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.connect_ports(osc.output(0), gain.input(0));&lt;br /&gt;
    context.connect_ports(cs.output(0), gain.param(ParamType::Gain));&lt;br /&gt;
    context.connect_ports(gain.output(0), dest.input(0));&lt;br /&gt;
&lt;br /&gt;
    let _ = context.resume();&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        osc,&lt;br /&gt;
        AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(0.)),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        gain,&lt;br /&gt;
        AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(0.)),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        cs,&lt;br /&gt;
        AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(0.)),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        cs,&lt;br /&gt;
        AudioNodeMessage::SetParam(&lt;br /&gt;
            ParamType::Offset,&lt;br /&gt;
            UserAutomationEvent::SetValueCurveAtTime(values, start_time, end_time),&lt;br /&gt;
        ),&lt;br /&gt;
&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        osc,&lt;br /&gt;
        AudioNodeMessage::SetParam(&lt;br /&gt;
            ParamType::Frequency,&lt;br /&gt;
            UserAutomationEvent::SetValueAtTime(value_next, end_time),&lt;br /&gt;
        ),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    thread::sleep(time::Duration::from_millis(7000));&lt;br /&gt;
    let _ = context.close();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
fn main() {&lt;br /&gt;
    ServoMedia::init::&amp;lt;servo_media_auto::Backend&amp;gt;();&lt;br /&gt;
    if let Ok(servo_media) = ServoMedia::get() {&lt;br /&gt;
        run_example(servo_media);&lt;br /&gt;
    } else {&lt;br /&gt;
        unreachable!();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above program, the values vector is passed into the SetValueCurveAtTime function to modulate the output. The output of the same can also be checked in the test-case video at the end of this page. &lt;br /&gt;
We can modify the values function as we want and observe the output. One more modification that we used was by using a sine curve. It is implemented as follows. Change the values vector in the set-value-curve function with the following: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 use std::f64::consts::PI;&lt;br /&gt;
    let mut values: Vec&amp;lt;f32&amp;gt; = Vec::new();&lt;br /&gt;
    let curvelength = 44100;&lt;br /&gt;
    let mut i = 0;&lt;br /&gt;
    while i &amp;lt; curvelength {&lt;br /&gt;
    values.push(f32::sin((PI *i as f64/curvelength as f64) as f32));&lt;br /&gt;
    i += 1;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The output of this function can be seen in the test video attached to at the end of this page. &lt;br /&gt;
&amp;lt;references&amp;gt;&amp;lt;/references&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=='''Video of Testing Audio Output'''==&lt;br /&gt;
[https://drive.google.com/file/d/1jzEZwAZE-7mi6N5N_JcEE6ISM-wc9910/view?usp=sharing Test-1]&lt;br /&gt;
[https://drive.google.com/file/d/1UsPgyv29Zf29d6pEDgLpYX86DI6hzOqp/view?usp=sharing Test-2]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=='''Issues and Fixes'''==&lt;br /&gt;
&lt;br /&gt;
Windows Specific during build&lt;br /&gt;
&lt;br /&gt;
https://github.com/holochain/holochain-cmd/issues/29&lt;br /&gt;
&lt;br /&gt;
https://stackoverflow.com/questions/53136717/errore0554-feature-may-not-be-used-on-the-stable-release-channel-couldnt&lt;br /&gt;
&lt;br /&gt;
https://github.com/servo/servo/issues/21429&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=='''Final Project'''==&lt;br /&gt;
If you are a peer reviewer please look into this [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#For_Peer_Reviewers_Note section]&lt;br /&gt;
&lt;br /&gt;
The final [https://github.com/servo/servo/wiki/Implement-missing-WebAudio-automation-student-project project] rely on our previous [https://github.com/servo/media/pull/230 work]. The next part would focus on implementing the code [https://github.com/servo/media/issues/204 written] to be accessible by Servo browser [https://github.com/servo/servo/issues/22897 engine]. &lt;br /&gt;
This would require interfacing the DOM [https://github.com/servo/servo/blob/master/components/script/dom/webidls/AudioParam.webidl file] reference the Param.rs [https://github.com/JHBalaji/media/blob/master/audio/src/param.rs#L259 setValueCurveAtTime] to be interfaced with [https://github.com/servo/servo/blob/master/components/script/dom/audioparam.rs AudioParam.rs]. The audioparam.rs would call the UserAutomationEvent in the param.rs setValueCurveAtTime.&lt;br /&gt;
&lt;br /&gt;
Once the initial function call with arguments  are updated, then the [https://github.com/servo/servo/blob/master/tests/wpt/README.md#updating-test-expectations testing] would be performed on ''./mach test-wpt tests/wpt/web-platform-tests/webaudio/the-audio-api/[https://github.com/servo/servo/tree/master/tests/wpt/web-platform-tests/webaudio/the-audio-api/the-audioparam-interface the-audioparam-interface]''. The [https://github.com/servo/servo/tree/master/tests/wpt/web-platform-tests/webaudio/the-audio-api/the-audioparam-interface the-audioparam-interface] is a folder of series of test cases that emulate the behavior of a function call, here the setValueCurveAtTime would need to be necessitated to mock the values as tested in previous [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#Test_Case example] but would require to be performed over a .html webpage with DOM elements to test the complete functionality.&lt;br /&gt;
&lt;br /&gt;
Servo webAudio tests are performed using [https://github.com/web-platform-tests/wpt/blob/master/resources/readme.md testharness.js]. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach create-wpt tests/wpt/path/to/new/test.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
would create a test.html using the WPT template for javascript tests. Once the skeleton code is completed with necessary function call, them the WPT tests would be executed using &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach test-wpt tests/wpt/path/to/new/test.html&lt;br /&gt;
./mach test-wpt tests/wpt/path/to/new/reftest.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[https://web-platform-tests.org/writing-tests/reftests.html reftest] are used in Servo to test behavior related to rendering; that are related to interaction made up of several webpages [think passing or referencing values to another webpage] with assertions to test cases that are expected from the interaction. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach create-wpt --reftest tests/wpt/path/to/new/reftest.html --reference tests/wpt/path/to/reference.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
reference.html and reftest.html will be created using WPT reftest template. Once the reftest is run the upstream test would need to be updated using &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach update-wpt --sync&lt;br /&gt;
./mach test-wpt --log-raw=update.log&lt;br /&gt;
./mach update-wpt update.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When reftest fails to diagnose the behavior reftest raw log is required which is generate using the below command. The .log is fed into  [https://github.com/Gankro/live-reftest-analyzer  reftest analyzer] to find those failing test. The reftest is also capable of pixel level comparison of the test and reference screenshots (incase of rendering)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach test-wpt --log-raw wpt.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==='''List of issues'''===&lt;br /&gt;
This project has listed 4 known issues under the  WebAudio title, each solving a different issue.&lt;br /&gt;
&lt;br /&gt;
1. [https://github.com/servo/media/issues/204 Implement ValueCurveAtTime automation]&lt;br /&gt;
&lt;br /&gt;
This is the first issue, which has been addressed and successfully closed during the initial parts of this project. The steps followed are shown in the following diagram.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:WebAudio-Issue1.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. [https://github.com/servo/servo/issues/22897 Implement AudioParam.setValueCurveAtTime]&lt;br /&gt;
&lt;br /&gt;
This second issue builds up on the first one, and focuses on implementing yet another method called [https://webaudio.github.io/web-audio-api/#dom-audioparam-setvaluecurveattime setValueCurveAtTime]. The next focus of this project will likely be to work on this issue.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:WebAudio-Issue2.png]]&lt;br /&gt;
&lt;br /&gt;
=='''For Peer Reviewers Note'''==&lt;br /&gt;
&lt;br /&gt;
''Common peer review question clarifications are below,''&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Does the design incorporate all of the functionality required?&amp;quot; or &amp;quot;Check the changes that the authors proposed. Rate the overall quality of the explanations. Give comments if you find the explanation hard to follow or inadequate.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
:The [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#Final_Project section] clarifies your question.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Check the designs proposed by the authors.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
:There is no explicit design is involved as going by [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#Final_Project proposal], there are three files to be added with new functionality in addition to test cases and files.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Check the use of visual aids&amp;quot;&lt;br /&gt;
:Visual aids not applicable &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Give comments on the completeness of the design doc.&amp;quot;&lt;br /&gt;
: Let us know what you think about them!&lt;/div&gt;</summary>
		<author><name>Amadhus2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support&amp;diff=124038</id>
		<title>CSC/ECE 517 Spring 2019 - Project M1901 Implement missing WebAudio automation support</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support&amp;diff=124038"/>
		<updated>2019-04-13T02:52:02Z</updated>

		<summary type="html">&lt;p&gt;Amadhus2: /* List of issues */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''Introduction'''== &lt;br /&gt;
&lt;br /&gt;
==='''Servo'''===&lt;br /&gt;
Servo is an developmental browser engine designed to make use of the memory safety properties and concurrency features of the Rust programming language. The project was initiated by Mozilla Research with effort from Samsung to port it to Android and ARM processors&lt;br /&gt;
&lt;br /&gt;
More information about Servo is available [https://servo.org here]&lt;br /&gt;
&lt;br /&gt;
==='''Rust'''===&lt;br /&gt;
Rust is a systems programming language which focuses on memory safety and concurrency. It is similar to C++ but ensures memory safety and provides high performance. Rust is brain child of Mozilla and simple as this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
fn main() {&lt;br /&gt;
    println!(&amp;quot;Hello World&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More information about Rust can be found [https://www.rust-lang.org/en-US/ here] and here is why we love [https://thenewstack.io/safer-future-rust/ Rust], [https://insights.stackoverflow.com/survey/2018/#most-loved-dreaded-and-wanted SF Loved]&lt;br /&gt;
&lt;br /&gt;
==='''Web Audio API'''===&lt;br /&gt;
The Web Audio API involves handling audio operations inside an audio context, and has been designed to allow modular routing. An audio routing graph has been created by linking together the Basic Audio operations performed with audio nodes. Several sources — with different types of channel layout — are supported even within a single context. This modular design provides the flexibility to create complex audio functions with dynamic effects.&lt;br /&gt;
&lt;br /&gt;
Audio nodes are linked into chains and simple webs by their inputs and outputs. They typically start with one or more sources. Sources provide arrays of sound intensities (samples) at very small timeslices, often tens of thousands of them per second. These could be either computed mathematically (such as OscillatorNode), or they can be recordings from sound/video files (like AudioBufferSourceNode and MediaElementAudioSourceNode) and audio streams (MediaStreamAudioSourceNode). In fact, sound files are just recordings of sound intensities themselves, which come in from microphones or electric instruments, and get mixed down into a single, complicated wave.&lt;br /&gt;
&lt;br /&gt;
Outputs of these nodes could be linked to inputs of others, which mix or modify these streams of sound samples into different streams. A common modification is multiplying the samples by a value to make them louder or quieter (as is the case with GainNode). Once the sound has been sufficiently processed for the intended effect, it can be linked to the input of a destination (AudioContext.destination), which sends the sound to the speakers or headphones. This last connection is only necessary if the user is supposed to hear the audio.&lt;br /&gt;
&lt;br /&gt;
A simple, typical workflow for web audio would look something like this:&lt;br /&gt;
&lt;br /&gt;
1. Create audio context&amp;lt;br&amp;gt;&lt;br /&gt;
2. Inside the context, create sources — such as &amp;lt;audio&amp;gt;, oscillator, stream&amp;lt;br&amp;gt;&lt;br /&gt;
3. Create effects nodes, such as reverb, biquad filter, panner, compressor&amp;lt;br&amp;gt;&lt;br /&gt;
4. Choose final destination of audio, for example your system speakers&amp;lt;br&amp;gt;&lt;br /&gt;
5. Connect the sources up to the effects, and the effects to the destination.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Problem Statement: Web Audio Automation'''===&lt;br /&gt;
&lt;br /&gt;
AudioParam is used to control the AudioNode functioning, say, Volume (a Gain parameter). These values can either be scheduled to be changed at precise times or set to particular value immediately following an event or at an event. The schedule to change when used with AudioContext.currentTime can helps in volume fades, filter sweeps etc. This would work aims to implement [https://github.com/servo/media/issues/204 SetValueCurveAtTime()].&lt;br /&gt;
&lt;br /&gt;
[https://webaudio.github.io/web-audio-api/#dom-audioparam-setvaluecurveattime setValueCurveAtTime()] is one such method in AudioParam that takes an array as input and schedules a change. The array is usually a curve in wedAudio and achieved my linear interpolation between the values from the floating-point values array and for the duration, d from the startTime, s&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;v(t) = values[N * (t - s) / d]&amp;lt;/code&amp;gt;, where N is the length of the values in the array.&lt;br /&gt;
And after the end of the curve time interval &amp;lt;code&amp;gt;(t &amp;gt;= s + d)&amp;lt;/code&amp;gt;, the value will remain constant at the final curve value. This would persist to happen until the next automation event.&lt;br /&gt;
&lt;br /&gt;
One of the application of setValueCurveAtTime() it to create tremolo effect. Suppose linear nor an exponential curve satisfy the needs then user can create curve based on values to setValueCurveAtTime() with an array of timing values. Its a much loved approached against multiple calls to setValueAtTime().&lt;br /&gt;
&lt;br /&gt;
==='''Build'''===&lt;br /&gt;
Servo is built with Cargo, the Rust package manager. We also use Mozilla's Mach tools to orchestrate the build and other tasks.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=='''Implementation of the Project'''== &lt;br /&gt;
&lt;br /&gt;
==='''Code'''===&lt;br /&gt;
The code is implemented as in [https://github.com/JHBalaji/media/blob/master/audio/src/param.rs#L418-L436 here]. The code below is the main code snippet for the SetValueCurveAtTime function. The values and function behavior is define in the param.rs file. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            AutomationEvent::SetValueCurveAtTime(ref values, start, duration) =&amp;gt; {&lt;br /&gt;
                let time_diff = ((duration.0 as f32) - (start.0 as f32)) as f32;&lt;br /&gt;
                let mut progress = ((((current_tick.0 as f32) - (start.0 as f32)) as f32) / time_diff) as f32;&lt;br /&gt;
                if progress &amp;lt; 0.0 {&lt;br /&gt;
                    progress = 0.0 as f32;&lt;br /&gt;
                }&lt;br /&gt;
                let n = values.len() as f32;&lt;br /&gt;
	            let k = (((n - 1.) * progress) as f32).floor();&lt;br /&gt;
                let next = k + 1. as f32;&lt;br /&gt;
                let step = time_diff / (n - 1.);&lt;br /&gt;
                if next &amp;lt; n {&lt;br /&gt;
                    let time_k = (k * step) as f32;&lt;br /&gt;
                    let time_k_next = (next * step) as f32;&lt;br /&gt;
                    let v_k = values[k as usize];&lt;br /&gt;
    				let v_k_next = values[next as usize];&lt;br /&gt;
                    *value = v_k + (v_k_next - v_k) * (((current_tick.0 as f32) - time_k) / (time_k_next - time_k));&lt;br /&gt;
                }&lt;br /&gt;
                true&lt;br /&gt;
            }&lt;br /&gt;
            AutomationEvent::CancelAndHoldAtTime(..) =&amp;gt; false,&lt;br /&gt;
            AutomationEvent::CancelScheduledValues(..) | AutomationEvent::SetValue(..) =&amp;gt; {&lt;br /&gt;
                unreachable!(&amp;quot;CancelScheduledValues/SetValue should never appear in the timeline&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Let's walk through the code. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;AutomationEvent::SetValueCurveAtTime()&amp;lt;/code&amp;gt; is a fn and takes three arguments: values, start, duration.&lt;br /&gt;
&lt;br /&gt;
progress, computes the difference between the first value in start_time and [https://github.com/JHBalaji/media/blob/5a981dff94f4dfaf2ebf0f0e09f599fab9d1a13b/audio/src/param.rs#L384 time] and makes explicit conversion to f32. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                let time_diff = ((duration.0 as f32) - (start.0 as f32)) as f32;&lt;br /&gt;
                let mut progress = ((((current_tick.0 as f32) - (start.0 as f32)) as f32) / time_diff) as f32;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
time_diff computes the total difference between duration and start_time, this is required when the values that needs to be computed goes beyond time_diff from start_time to set a constant value later.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                if progress &amp;lt; 0.0 {&lt;br /&gt;
                    progress = 0.0 as f32;&lt;br /&gt;
                }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Sets 0 if the progress from values array and present time being negative.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                let n = values.len() as f32;&lt;br /&gt;
	            let k = (((n - 1.) * progress) as f32).floor();&lt;br /&gt;
                let next = k + 1. as f32;&lt;br /&gt;
                let step = time_diff / (n - 1.);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
n, total length of values array. k, compute as k as in [[https://webaudio.github.io/web-audio-api/#dom-audioparam-setvaluecurveattime here] and &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; is k+1, the delta or step is computed that would be added to generate the sound wave from the values array. Say, the frequency start at 44KHz and the &amp;lt;code&amp;gt;step&amp;lt;/code&amp;gt; would be used to change the frequency of the curve.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                if next &amp;lt; n {&lt;br /&gt;
                    let time_k = (k * step) as f32;&lt;br /&gt;
                    let time_k_next = (next * step) as f32;&lt;br /&gt;
                    let v_k = values[k as usize];&lt;br /&gt;
    				let v_k_next = values[next as usize];&lt;br /&gt;
                    *value = v_k + (v_k_next - v_k) * (((current_tick.0 as f32) - time_k) / (time_k_next - time_k));&lt;br /&gt;
                }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code block generates sequences of values from &amp;lt;code&amp;gt;values&amp;lt;/code array and using &amp;lt;code&amp;gt;step&amp;lt;/code&amp;gt; value we computed. And does that till it reaches the total length of the array.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                true&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media/blob/f32a71c51f05f44d1e8ca217fbaa4dfb0b55d11e/audio/src/param.rs#L435 Used] to loop the function call made from [https://github.com/JHBalaji/media/blob/f32a71c51f05f44d1e8ca217fbaa4dfb0b55d11e/audio/src/param.rs#L117 here].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            AutomationEvent::CancelAndHoldAtTime(..) =&amp;gt; false,&lt;br /&gt;
            AutomationEvent::CancelScheduledValues(..) | AutomationEvent::SetValue(..) =&amp;gt; {&lt;br /&gt;
                unreachable!(&amp;quot;CancelScheduledValues/SetValue should never appear in the timeline&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media/blob/5a981dff94f4dfaf2ebf0f0e09f599fab9d1a13b/audio/src/param.rs#L466 Code] instructs to cancel this event or end of this function and proceed to next instructions. In Audio API unless you explicitly say the block to end, the block would end and hardware device would be stopped from consumption.&lt;br /&gt;
&lt;br /&gt;
==='''Examples'''===&lt;br /&gt;
&lt;br /&gt;
Examples are unique aspect to Rust. This instructs that code to make use of the function we just wrote and generates a sound output. Refer our example [https://github.com/JHBalaji/media-1/blob/master/examples/set_value_curve.rs here] for the SetValueCurveAtTime()&lt;br /&gt;
&lt;br /&gt;
And example is usually called by using cargo build in rust or cargo run.&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media-1/blob/master/examples/Cargo.toml Cargo.toml] dictates the naming and the file to be called as.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cargo run --example set_value_curve&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above code instructs to run the example [https://github.com/JHBalaji/media-1/blob/master/examples/set_value_curve.rs set_value_curve] to generate a sound output through our terminal.&lt;br /&gt;
&lt;br /&gt;
==='''Compile'''===&lt;br /&gt;
[https://github.com/JHBalaji/media-1/blob/master/Cargo.lock Cargo.lock] instructs the dependencies that would be required to build this project.&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media-1/blob/master/Cargo.toml Cargo.toml] calls all the folders or members to be complied. Usually the compilation would be at /media&lt;br /&gt;
&lt;br /&gt;
Cargo.lock installs number of packages called crates that would be used by the project to access the modules. Each of the member in [https://github.com/JHBalaji/media-1/blob/master/Cargo.toml Cargo.toml] would have [https://github.com/JHBalaji/media-1/blob/master/examples/Cargo.toml Cargo.toml] in them that would instruct [https://github.com/JHBalaji/media-1/blob/master/examples/Cargo.toml#L6 dependencies] during the build. build-dependencies would be used if you have dependencies before the build.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media-1/blob/master/.cargo/config .cargo config] is similar to a dotenv file for Rust&lt;br /&gt;
&lt;br /&gt;
==='''Test'''===&lt;br /&gt;
&lt;br /&gt;
If you would like to test our build please look into [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#Issues_and_Fixes Fixes] before proceeding. We would suggest MacOS or Linux 16.04 LTS for any development and testing. Virtual Machine or VirtualBox could be another option. We spent countless days in frustration with libraries and never ending apt installs so avoid Linux 18.04 for this build test.&lt;br /&gt;
&lt;br /&gt;
Once &amp;lt;code&amp;gt;cargo build&amp;lt;/code&amp;gt; is completed. Open /target/debug to view the examples that are generated.&lt;br /&gt;
&lt;br /&gt;
[[File:Servo-initial-build.PNG]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To run all examples after the cargo build is complete, use &amp;lt;code&amp;gt;cargo run --example &amp;lt;bin_name&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Examples.PNG]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''''''Bold text''''''==='''Status of the Project'''===&lt;br /&gt;
&lt;br /&gt;
The [https://github.com/JHBalaji/media-1 build] is ready and the Pull request is [https://github.com/servo/media/pull/230 merged] with Servo/media.&lt;br /&gt;
&lt;br /&gt;
[[File:Pr.PNG]]&lt;br /&gt;
[[File:Example.jpg]]&lt;br /&gt;
&lt;br /&gt;
=='''Normal build from Master Repo '''==&lt;br /&gt;
To build Servo in development mode. This is useful for development, but the resulting binary is very slow.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git clone https://github.com/servo/servo&lt;br /&gt;
cd servo&lt;br /&gt;
./mach build --dev&lt;br /&gt;
./mach run tests/html/about-mozilla.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
For benchmarking, performance testing, or real-world use, add the --release flag to create an optimized build:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach build --release&lt;br /&gt;
./mach run --release tests/html/about-mozilla.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==='''Compiling and Running the code'''===&lt;br /&gt;
&lt;br /&gt;
====Mac OS====&lt;br /&gt;
&lt;br /&gt;
Follow the instructions posted in this [https://github.com/JHBalaji/media-1 URL] and install GStreamer and Rust. After that follow the following lines for compiling on MacOS. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1. brew install gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-libav gst-rtsp-server gst-editing-services&lt;br /&gt;
&lt;br /&gt;
2. export PKG_CONFIG_PATH=/usr/local/Cellar/libffi/3.2.1/lib/pkgconfig/&lt;br /&gt;
&lt;br /&gt;
3. rustup override set nightly&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After this run the following command to compile servo/media &lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
cargo build &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After compiling you will be able to test our example that is places in the examples folder.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Windows and Linux====&lt;br /&gt;
&lt;br /&gt;
Head over here to install [https://rustup.rs/ Rust ToolChain]. If you need any additional details we would suggest reading the [https://github.com/rust-lang/rustup.rs/blob/master/README.md ReadMe on Rust]. Some Servo media specific build issues are [https://github.com/servo/media/blob/master/README.md advised]. &lt;br /&gt;
&lt;br /&gt;
We would suggest Ubuntu 18.04 LTS with updates [https://github.com/servo/media/blob/master/README.md gstreamer package].&lt;br /&gt;
&lt;br /&gt;
==='''Servo Media'''===&lt;br /&gt;
&amp;lt;b&amp;gt;Requirements&amp;lt;/b&amp;gt;&lt;br /&gt;
In order to build this crate you need to install gstreamer which can be found here [https://github.com/sdroege/gstreamer-rs]&lt;br /&gt;
==='''Test Case'''===&lt;br /&gt;
After you run cargo build, you should be able to see the executable of the example inside the target/debug folder. Following is the test we have written  file to check the functioning of the [https://github.com/JHBalaji/media-1/blob/master/examples/set_value_curve.rs SetValueCurveAtTIme].&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
extern crate servo_media;&lt;br /&gt;
extern crate servo_media_auto;&lt;br /&gt;
&lt;br /&gt;
use servo_media::audio::constant_source_node::ConstantSourceNodeOptions;&lt;br /&gt;
use servo_media::audio::gain_node::GainNodeOptions;&lt;br /&gt;
use servo_media::audio::node::{AudioNodeInit, AudioNodeMessage, AudioScheduledSourceNodeMessage};&lt;br /&gt;
use servo_media::audio::param::{ParamType, UserAutomationEvent};&lt;br /&gt;
use servo_media::ServoMedia;&lt;br /&gt;
use std::sync::Arc;&lt;br /&gt;
use std::{thread, time};&lt;br /&gt;
&lt;br /&gt;
fn run_example(servo_media: Arc&amp;lt;ServoMedia&amp;gt;) {&lt;br /&gt;
    let context = servo_media.create_audio_context(Default::default());&lt;br /&gt;
    let dest = context.dest_node();&lt;br /&gt;
&lt;br /&gt;
    //Initializing the values vector for SetValueCurve function&lt;br /&gt;
    let mut values: Vec&amp;lt;f32&amp;gt; = Vec::new();&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(1.0);&lt;br /&gt;
    values.push(1.0);&lt;br /&gt;
    values.push(1.0);&lt;br /&gt;
    values.push(1.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.5);&lt;br /&gt;
    values.push(0.5);&lt;br /&gt;
    values.push(0.5);&lt;br /&gt;
    values.push(0.5);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    let start_time = 0.;&lt;br /&gt;
    let end_time = 5.;&lt;br /&gt;
    let n = values.len() as f32;&lt;br /&gt;
    let value_next = values[(n - 1.) as usize];&lt;br /&gt;
&lt;br /&gt;
    let cs = context.create_node(&lt;br /&gt;
        AudioNodeInit::ConstantSourceNode(ConstantSourceNodeOptions::default()),&lt;br /&gt;
        Default::default(),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    let mut gain_options = GainNodeOptions::default();&lt;br /&gt;
    gain_options.gain = 0.0;&lt;br /&gt;
    let gain = context.create_node(&lt;br /&gt;
        AudioNodeInit::GainNode(gain_options.clone()),&lt;br /&gt;
        Default::default(),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    let osc = context.create_node(&lt;br /&gt;
        AudioNodeInit::OscillatorNode(Default::default()),&lt;br /&gt;
        Default::default(),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.connect_ports(osc.output(0), gain.input(0));&lt;br /&gt;
    context.connect_ports(cs.output(0), gain.param(ParamType::Gain));&lt;br /&gt;
    context.connect_ports(gain.output(0), dest.input(0));&lt;br /&gt;
&lt;br /&gt;
    let _ = context.resume();&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        osc,&lt;br /&gt;
        AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(0.)),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        gain,&lt;br /&gt;
        AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(0.)),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        cs,&lt;br /&gt;
        AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(0.)),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        cs,&lt;br /&gt;
        AudioNodeMessage::SetParam(&lt;br /&gt;
            ParamType::Offset,&lt;br /&gt;
            UserAutomationEvent::SetValueCurveAtTime(values, start_time, end_time),&lt;br /&gt;
        ),&lt;br /&gt;
&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        osc,&lt;br /&gt;
        AudioNodeMessage::SetParam(&lt;br /&gt;
            ParamType::Frequency,&lt;br /&gt;
            UserAutomationEvent::SetValueAtTime(value_next, end_time),&lt;br /&gt;
        ),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    thread::sleep(time::Duration::from_millis(7000));&lt;br /&gt;
    let _ = context.close();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
fn main() {&lt;br /&gt;
    ServoMedia::init::&amp;lt;servo_media_auto::Backend&amp;gt;();&lt;br /&gt;
    if let Ok(servo_media) = ServoMedia::get() {&lt;br /&gt;
        run_example(servo_media);&lt;br /&gt;
    } else {&lt;br /&gt;
        unreachable!();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above program, the values vector is passed into the SetValueCurveAtTime function to modulate the output. The output of the same can also be checked in the test-case video at the end of this page. &lt;br /&gt;
We can modify the values function as we want and observe the output. One more modification that we used was by using a sine curve. It is implemented as follows. Change the values vector in the set-value-curve function with the following: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 use std::f64::consts::PI;&lt;br /&gt;
    let mut values: Vec&amp;lt;f32&amp;gt; = Vec::new();&lt;br /&gt;
    let curvelength = 44100;&lt;br /&gt;
    let mut i = 0;&lt;br /&gt;
    while i &amp;lt; curvelength {&lt;br /&gt;
    values.push(f32::sin((PI *i as f64/curvelength as f64) as f32));&lt;br /&gt;
    i += 1;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The output of this function can be seen in the test video attached to at the end of this page. &lt;br /&gt;
&amp;lt;references&amp;gt;&amp;lt;/references&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=='''Video of Testing Audio Output'''==&lt;br /&gt;
[https://drive.google.com/file/d/1jzEZwAZE-7mi6N5N_JcEE6ISM-wc9910/view?usp=sharing Test-1]&lt;br /&gt;
[https://drive.google.com/file/d/1UsPgyv29Zf29d6pEDgLpYX86DI6hzOqp/view?usp=sharing Test-2]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=='''Issues and Fixes'''==&lt;br /&gt;
&lt;br /&gt;
Windows Specific during build&lt;br /&gt;
&lt;br /&gt;
https://github.com/holochain/holochain-cmd/issues/29&lt;br /&gt;
&lt;br /&gt;
https://stackoverflow.com/questions/53136717/errore0554-feature-may-not-be-used-on-the-stable-release-channel-couldnt&lt;br /&gt;
&lt;br /&gt;
https://github.com/servo/servo/issues/21429&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=='''Final Project'''==&lt;br /&gt;
If you are a peer reviewer please look into this [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#For_Peer_Reviewers_Note section]&lt;br /&gt;
&lt;br /&gt;
The final [https://github.com/servo/servo/wiki/Implement-missing-WebAudio-automation-student-project project] rely on our previous [https://github.com/servo/media/pull/230 work]. The next part would focus on implementing the code [https://github.com/servo/media/issues/204 written] to be accessible by Servo browser [https://github.com/servo/servo/issues/22897 engine]. &lt;br /&gt;
This would require interfacing the DOM [https://github.com/servo/servo/blob/master/components/script/dom/webidls/AudioParam.webidl file] reference the Param.rs [https://github.com/JHBalaji/media/blob/master/audio/src/param.rs#L259 setValueCurveAtTime] to be interfaced with [https://github.com/servo/servo/blob/master/components/script/dom/audioparam.rs AudioParam.rs]. The audioparam.rs would call the UserAutomationEvent in the param.rs setValueCurveAtTime.&lt;br /&gt;
&lt;br /&gt;
Once the initial function call with arguments  are updated, then the [https://github.com/servo/servo/blob/master/tests/wpt/README.md#updating-test-expectations testing] would be performed on ''./mach test-wpt tests/wpt/web-platform-tests/webaudio/the-audio-api/[https://github.com/servo/servo/tree/master/tests/wpt/web-platform-tests/webaudio/the-audio-api/the-audioparam-interface the-audioparam-interface]''. The [https://github.com/servo/servo/tree/master/tests/wpt/web-platform-tests/webaudio/the-audio-api/the-audioparam-interface the-audioparam-interface] is a folder of series of test cases that emulate the behavior of a function call, here the setValueCurveAtTime would need to be necessitated to mock the values as tested in previous [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#Test_Case example] but would require to be performed over a .html webpage with DOM elements to test the complete functionality.&lt;br /&gt;
&lt;br /&gt;
Servo webAudio tests are performed using [https://github.com/web-platform-tests/wpt/blob/master/resources/readme.md testharness.js]. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach create-wpt tests/wpt/path/to/new/test.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
would create a test.html using the WPT template for javascript tests. Once the skeleton code is completed with necessary function call, them the WPT tests would be executed using &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach test-wpt tests/wpt/path/to/new/test.html&lt;br /&gt;
./mach test-wpt tests/wpt/path/to/new/reftest.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[https://web-platform-tests.org/writing-tests/reftests.html reftest] are used in Servo to test behavior related to rendering; that are related to interaction made up of several webpages [think passing or referencing values to another webpage] with assertions to test cases that are expected from the interaction. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach create-wpt --reftest tests/wpt/path/to/new/reftest.html --reference tests/wpt/path/to/reference.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
reference.html and reftest.html will be created using WPT reftest template. Once the reftest is run the upstream test would need to be updated using &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach update-wpt --sync&lt;br /&gt;
./mach test-wpt --log-raw=update.log&lt;br /&gt;
./mach update-wpt update.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When reftest fails to diagnose the behavior reftest raw log is required which is generate using the below command. The .log is fed into  [https://github.com/Gankro/live-reftest-analyzer  reftest analyzer] to find those failing test. The reftest is also capable of pixel level comparison of the test and reference screenshots (incase of rendering)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach test-wpt --log-raw wpt.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==='''List of issues'''===&lt;br /&gt;
This project has listed 4 known issues under the  WebAudio title, each solving a different issue.&lt;br /&gt;
&lt;br /&gt;
1. [https://github.com/servo/media/issues/204 Implement ValueCurveAtTime automation]&lt;br /&gt;
This is the first issue, which has been addressed and successfully closed during the initial parts of this project. The steps followed are shown in the following diagram.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:WebAudio-Issue1.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. [https://github.com/servo/servo/issues/22897 Implement AudioParam.setValueCurveAtTime]&lt;br /&gt;
This second issue builds up on the first one, and focuses on implementing yet another method called [https://webaudio.github.io/web-audio-api/#dom-audioparam-setvaluecurveattime setValueCurveAtTime]. The next focus of this project will likely be to work on this issue.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:WebAudio-Issue2.png]]&lt;br /&gt;
&lt;br /&gt;
=='''For Peer Reviewers Note'''==&lt;br /&gt;
&lt;br /&gt;
''Common peer review question clarifications are below,''&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Does the design incorporate all of the functionality required?&amp;quot; or &amp;quot;Check the changes that the authors proposed. Rate the overall quality of the explanations. Give comments if you find the explanation hard to follow or inadequate.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
:The [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#Final_Project section] clarifies your question.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Check the designs proposed by the authors.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
:There is no explicit design is involved as going by [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#Final_Project proposal], there are three files to be added with new functionality in addition to test cases and files.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Check the use of visual aids&amp;quot;&lt;br /&gt;
:Visual aids not applicable &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Give comments on the completeness of the design doc.&amp;quot;&lt;br /&gt;
: Let us know what you think about them!&lt;/div&gt;</summary>
		<author><name>Amadhus2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support&amp;diff=124037</id>
		<title>CSC/ECE 517 Spring 2019 - Project M1901 Implement missing WebAudio automation support</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support&amp;diff=124037"/>
		<updated>2019-04-13T02:51:34Z</updated>

		<summary type="html">&lt;p&gt;Amadhus2: /* List of issues */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''Introduction'''== &lt;br /&gt;
&lt;br /&gt;
==='''Servo'''===&lt;br /&gt;
Servo is an developmental browser engine designed to make use of the memory safety properties and concurrency features of the Rust programming language. The project was initiated by Mozilla Research with effort from Samsung to port it to Android and ARM processors&lt;br /&gt;
&lt;br /&gt;
More information about Servo is available [https://servo.org here]&lt;br /&gt;
&lt;br /&gt;
==='''Rust'''===&lt;br /&gt;
Rust is a systems programming language which focuses on memory safety and concurrency. It is similar to C++ but ensures memory safety and provides high performance. Rust is brain child of Mozilla and simple as this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
fn main() {&lt;br /&gt;
    println!(&amp;quot;Hello World&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More information about Rust can be found [https://www.rust-lang.org/en-US/ here] and here is why we love [https://thenewstack.io/safer-future-rust/ Rust], [https://insights.stackoverflow.com/survey/2018/#most-loved-dreaded-and-wanted SF Loved]&lt;br /&gt;
&lt;br /&gt;
==='''Web Audio API'''===&lt;br /&gt;
The Web Audio API involves handling audio operations inside an audio context, and has been designed to allow modular routing. An audio routing graph has been created by linking together the Basic Audio operations performed with audio nodes. Several sources — with different types of channel layout — are supported even within a single context. This modular design provides the flexibility to create complex audio functions with dynamic effects.&lt;br /&gt;
&lt;br /&gt;
Audio nodes are linked into chains and simple webs by their inputs and outputs. They typically start with one or more sources. Sources provide arrays of sound intensities (samples) at very small timeslices, often tens of thousands of them per second. These could be either computed mathematically (such as OscillatorNode), or they can be recordings from sound/video files (like AudioBufferSourceNode and MediaElementAudioSourceNode) and audio streams (MediaStreamAudioSourceNode). In fact, sound files are just recordings of sound intensities themselves, which come in from microphones or electric instruments, and get mixed down into a single, complicated wave.&lt;br /&gt;
&lt;br /&gt;
Outputs of these nodes could be linked to inputs of others, which mix or modify these streams of sound samples into different streams. A common modification is multiplying the samples by a value to make them louder or quieter (as is the case with GainNode). Once the sound has been sufficiently processed for the intended effect, it can be linked to the input of a destination (AudioContext.destination), which sends the sound to the speakers or headphones. This last connection is only necessary if the user is supposed to hear the audio.&lt;br /&gt;
&lt;br /&gt;
A simple, typical workflow for web audio would look something like this:&lt;br /&gt;
&lt;br /&gt;
1. Create audio context&amp;lt;br&amp;gt;&lt;br /&gt;
2. Inside the context, create sources — such as &amp;lt;audio&amp;gt;, oscillator, stream&amp;lt;br&amp;gt;&lt;br /&gt;
3. Create effects nodes, such as reverb, biquad filter, panner, compressor&amp;lt;br&amp;gt;&lt;br /&gt;
4. Choose final destination of audio, for example your system speakers&amp;lt;br&amp;gt;&lt;br /&gt;
5. Connect the sources up to the effects, and the effects to the destination.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Problem Statement: Web Audio Automation'''===&lt;br /&gt;
&lt;br /&gt;
AudioParam is used to control the AudioNode functioning, say, Volume (a Gain parameter). These values can either be scheduled to be changed at precise times or set to particular value immediately following an event or at an event. The schedule to change when used with AudioContext.currentTime can helps in volume fades, filter sweeps etc. This would work aims to implement [https://github.com/servo/media/issues/204 SetValueCurveAtTime()].&lt;br /&gt;
&lt;br /&gt;
[https://webaudio.github.io/web-audio-api/#dom-audioparam-setvaluecurveattime setValueCurveAtTime()] is one such method in AudioParam that takes an array as input and schedules a change. The array is usually a curve in wedAudio and achieved my linear interpolation between the values from the floating-point values array and for the duration, d from the startTime, s&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;v(t) = values[N * (t - s) / d]&amp;lt;/code&amp;gt;, where N is the length of the values in the array.&lt;br /&gt;
And after the end of the curve time interval &amp;lt;code&amp;gt;(t &amp;gt;= s + d)&amp;lt;/code&amp;gt;, the value will remain constant at the final curve value. This would persist to happen until the next automation event.&lt;br /&gt;
&lt;br /&gt;
One of the application of setValueCurveAtTime() it to create tremolo effect. Suppose linear nor an exponential curve satisfy the needs then user can create curve based on values to setValueCurveAtTime() with an array of timing values. Its a much loved approached against multiple calls to setValueAtTime().&lt;br /&gt;
&lt;br /&gt;
==='''Build'''===&lt;br /&gt;
Servo is built with Cargo, the Rust package manager. We also use Mozilla's Mach tools to orchestrate the build and other tasks.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=='''Implementation of the Project'''== &lt;br /&gt;
&lt;br /&gt;
==='''Code'''===&lt;br /&gt;
The code is implemented as in [https://github.com/JHBalaji/media/blob/master/audio/src/param.rs#L418-L436 here]. The code below is the main code snippet for the SetValueCurveAtTime function. The values and function behavior is define in the param.rs file. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            AutomationEvent::SetValueCurveAtTime(ref values, start, duration) =&amp;gt; {&lt;br /&gt;
                let time_diff = ((duration.0 as f32) - (start.0 as f32)) as f32;&lt;br /&gt;
                let mut progress = ((((current_tick.0 as f32) - (start.0 as f32)) as f32) / time_diff) as f32;&lt;br /&gt;
                if progress &amp;lt; 0.0 {&lt;br /&gt;
                    progress = 0.0 as f32;&lt;br /&gt;
                }&lt;br /&gt;
                let n = values.len() as f32;&lt;br /&gt;
	            let k = (((n - 1.) * progress) as f32).floor();&lt;br /&gt;
                let next = k + 1. as f32;&lt;br /&gt;
                let step = time_diff / (n - 1.);&lt;br /&gt;
                if next &amp;lt; n {&lt;br /&gt;
                    let time_k = (k * step) as f32;&lt;br /&gt;
                    let time_k_next = (next * step) as f32;&lt;br /&gt;
                    let v_k = values[k as usize];&lt;br /&gt;
    				let v_k_next = values[next as usize];&lt;br /&gt;
                    *value = v_k + (v_k_next - v_k) * (((current_tick.0 as f32) - time_k) / (time_k_next - time_k));&lt;br /&gt;
                }&lt;br /&gt;
                true&lt;br /&gt;
            }&lt;br /&gt;
            AutomationEvent::CancelAndHoldAtTime(..) =&amp;gt; false,&lt;br /&gt;
            AutomationEvent::CancelScheduledValues(..) | AutomationEvent::SetValue(..) =&amp;gt; {&lt;br /&gt;
                unreachable!(&amp;quot;CancelScheduledValues/SetValue should never appear in the timeline&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Let's walk through the code. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;AutomationEvent::SetValueCurveAtTime()&amp;lt;/code&amp;gt; is a fn and takes three arguments: values, start, duration.&lt;br /&gt;
&lt;br /&gt;
progress, computes the difference between the first value in start_time and [https://github.com/JHBalaji/media/blob/5a981dff94f4dfaf2ebf0f0e09f599fab9d1a13b/audio/src/param.rs#L384 time] and makes explicit conversion to f32. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                let time_diff = ((duration.0 as f32) - (start.0 as f32)) as f32;&lt;br /&gt;
                let mut progress = ((((current_tick.0 as f32) - (start.0 as f32)) as f32) / time_diff) as f32;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
time_diff computes the total difference between duration and start_time, this is required when the values that needs to be computed goes beyond time_diff from start_time to set a constant value later.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                if progress &amp;lt; 0.0 {&lt;br /&gt;
                    progress = 0.0 as f32;&lt;br /&gt;
                }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Sets 0 if the progress from values array and present time being negative.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                let n = values.len() as f32;&lt;br /&gt;
	            let k = (((n - 1.) * progress) as f32).floor();&lt;br /&gt;
                let next = k + 1. as f32;&lt;br /&gt;
                let step = time_diff / (n - 1.);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
n, total length of values array. k, compute as k as in [[https://webaudio.github.io/web-audio-api/#dom-audioparam-setvaluecurveattime here] and &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; is k+1, the delta or step is computed that would be added to generate the sound wave from the values array. Say, the frequency start at 44KHz and the &amp;lt;code&amp;gt;step&amp;lt;/code&amp;gt; would be used to change the frequency of the curve.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                if next &amp;lt; n {&lt;br /&gt;
                    let time_k = (k * step) as f32;&lt;br /&gt;
                    let time_k_next = (next * step) as f32;&lt;br /&gt;
                    let v_k = values[k as usize];&lt;br /&gt;
    				let v_k_next = values[next as usize];&lt;br /&gt;
                    *value = v_k + (v_k_next - v_k) * (((current_tick.0 as f32) - time_k) / (time_k_next - time_k));&lt;br /&gt;
                }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code block generates sequences of values from &amp;lt;code&amp;gt;values&amp;lt;/code array and using &amp;lt;code&amp;gt;step&amp;lt;/code&amp;gt; value we computed. And does that till it reaches the total length of the array.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                true&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media/blob/f32a71c51f05f44d1e8ca217fbaa4dfb0b55d11e/audio/src/param.rs#L435 Used] to loop the function call made from [https://github.com/JHBalaji/media/blob/f32a71c51f05f44d1e8ca217fbaa4dfb0b55d11e/audio/src/param.rs#L117 here].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            AutomationEvent::CancelAndHoldAtTime(..) =&amp;gt; false,&lt;br /&gt;
            AutomationEvent::CancelScheduledValues(..) | AutomationEvent::SetValue(..) =&amp;gt; {&lt;br /&gt;
                unreachable!(&amp;quot;CancelScheduledValues/SetValue should never appear in the timeline&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media/blob/5a981dff94f4dfaf2ebf0f0e09f599fab9d1a13b/audio/src/param.rs#L466 Code] instructs to cancel this event or end of this function and proceed to next instructions. In Audio API unless you explicitly say the block to end, the block would end and hardware device would be stopped from consumption.&lt;br /&gt;
&lt;br /&gt;
==='''Examples'''===&lt;br /&gt;
&lt;br /&gt;
Examples are unique aspect to Rust. This instructs that code to make use of the function we just wrote and generates a sound output. Refer our example [https://github.com/JHBalaji/media-1/blob/master/examples/set_value_curve.rs here] for the SetValueCurveAtTime()&lt;br /&gt;
&lt;br /&gt;
And example is usually called by using cargo build in rust or cargo run.&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media-1/blob/master/examples/Cargo.toml Cargo.toml] dictates the naming and the file to be called as.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cargo run --example set_value_curve&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above code instructs to run the example [https://github.com/JHBalaji/media-1/blob/master/examples/set_value_curve.rs set_value_curve] to generate a sound output through our terminal.&lt;br /&gt;
&lt;br /&gt;
==='''Compile'''===&lt;br /&gt;
[https://github.com/JHBalaji/media-1/blob/master/Cargo.lock Cargo.lock] instructs the dependencies that would be required to build this project.&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media-1/blob/master/Cargo.toml Cargo.toml] calls all the folders or members to be complied. Usually the compilation would be at /media&lt;br /&gt;
&lt;br /&gt;
Cargo.lock installs number of packages called crates that would be used by the project to access the modules. Each of the member in [https://github.com/JHBalaji/media-1/blob/master/Cargo.toml Cargo.toml] would have [https://github.com/JHBalaji/media-1/blob/master/examples/Cargo.toml Cargo.toml] in them that would instruct [https://github.com/JHBalaji/media-1/blob/master/examples/Cargo.toml#L6 dependencies] during the build. build-dependencies would be used if you have dependencies before the build.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media-1/blob/master/.cargo/config .cargo config] is similar to a dotenv file for Rust&lt;br /&gt;
&lt;br /&gt;
==='''Test'''===&lt;br /&gt;
&lt;br /&gt;
If you would like to test our build please look into [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#Issues_and_Fixes Fixes] before proceeding. We would suggest MacOS or Linux 16.04 LTS for any development and testing. Virtual Machine or VirtualBox could be another option. We spent countless days in frustration with libraries and never ending apt installs so avoid Linux 18.04 for this build test.&lt;br /&gt;
&lt;br /&gt;
Once &amp;lt;code&amp;gt;cargo build&amp;lt;/code&amp;gt; is completed. Open /target/debug to view the examples that are generated.&lt;br /&gt;
&lt;br /&gt;
[[File:Servo-initial-build.PNG]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To run all examples after the cargo build is complete, use &amp;lt;code&amp;gt;cargo run --example &amp;lt;bin_name&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Examples.PNG]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''''''Bold text''''''==='''Status of the Project'''===&lt;br /&gt;
&lt;br /&gt;
The [https://github.com/JHBalaji/media-1 build] is ready and the Pull request is [https://github.com/servo/media/pull/230 merged] with Servo/media.&lt;br /&gt;
&lt;br /&gt;
[[File:Pr.PNG]]&lt;br /&gt;
[[File:Example.jpg]]&lt;br /&gt;
&lt;br /&gt;
=='''Normal build from Master Repo '''==&lt;br /&gt;
To build Servo in development mode. This is useful for development, but the resulting binary is very slow.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git clone https://github.com/servo/servo&lt;br /&gt;
cd servo&lt;br /&gt;
./mach build --dev&lt;br /&gt;
./mach run tests/html/about-mozilla.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
For benchmarking, performance testing, or real-world use, add the --release flag to create an optimized build:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach build --release&lt;br /&gt;
./mach run --release tests/html/about-mozilla.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==='''Compiling and Running the code'''===&lt;br /&gt;
&lt;br /&gt;
====Mac OS====&lt;br /&gt;
&lt;br /&gt;
Follow the instructions posted in this [https://github.com/JHBalaji/media-1 URL] and install GStreamer and Rust. After that follow the following lines for compiling on MacOS. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1. brew install gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-libav gst-rtsp-server gst-editing-services&lt;br /&gt;
&lt;br /&gt;
2. export PKG_CONFIG_PATH=/usr/local/Cellar/libffi/3.2.1/lib/pkgconfig/&lt;br /&gt;
&lt;br /&gt;
3. rustup override set nightly&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After this run the following command to compile servo/media &lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
cargo build &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After compiling you will be able to test our example that is places in the examples folder.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Windows and Linux====&lt;br /&gt;
&lt;br /&gt;
Head over here to install [https://rustup.rs/ Rust ToolChain]. If you need any additional details we would suggest reading the [https://github.com/rust-lang/rustup.rs/blob/master/README.md ReadMe on Rust]. Some Servo media specific build issues are [https://github.com/servo/media/blob/master/README.md advised]. &lt;br /&gt;
&lt;br /&gt;
We would suggest Ubuntu 18.04 LTS with updates [https://github.com/servo/media/blob/master/README.md gstreamer package].&lt;br /&gt;
&lt;br /&gt;
==='''Servo Media'''===&lt;br /&gt;
&amp;lt;b&amp;gt;Requirements&amp;lt;/b&amp;gt;&lt;br /&gt;
In order to build this crate you need to install gstreamer which can be found here [https://github.com/sdroege/gstreamer-rs]&lt;br /&gt;
==='''Test Case'''===&lt;br /&gt;
After you run cargo build, you should be able to see the executable of the example inside the target/debug folder. Following is the test we have written  file to check the functioning of the [https://github.com/JHBalaji/media-1/blob/master/examples/set_value_curve.rs SetValueCurveAtTIme].&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
extern crate servo_media;&lt;br /&gt;
extern crate servo_media_auto;&lt;br /&gt;
&lt;br /&gt;
use servo_media::audio::constant_source_node::ConstantSourceNodeOptions;&lt;br /&gt;
use servo_media::audio::gain_node::GainNodeOptions;&lt;br /&gt;
use servo_media::audio::node::{AudioNodeInit, AudioNodeMessage, AudioScheduledSourceNodeMessage};&lt;br /&gt;
use servo_media::audio::param::{ParamType, UserAutomationEvent};&lt;br /&gt;
use servo_media::ServoMedia;&lt;br /&gt;
use std::sync::Arc;&lt;br /&gt;
use std::{thread, time};&lt;br /&gt;
&lt;br /&gt;
fn run_example(servo_media: Arc&amp;lt;ServoMedia&amp;gt;) {&lt;br /&gt;
    let context = servo_media.create_audio_context(Default::default());&lt;br /&gt;
    let dest = context.dest_node();&lt;br /&gt;
&lt;br /&gt;
    //Initializing the values vector for SetValueCurve function&lt;br /&gt;
    let mut values: Vec&amp;lt;f32&amp;gt; = Vec::new();&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(1.0);&lt;br /&gt;
    values.push(1.0);&lt;br /&gt;
    values.push(1.0);&lt;br /&gt;
    values.push(1.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.5);&lt;br /&gt;
    values.push(0.5);&lt;br /&gt;
    values.push(0.5);&lt;br /&gt;
    values.push(0.5);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    let start_time = 0.;&lt;br /&gt;
    let end_time = 5.;&lt;br /&gt;
    let n = values.len() as f32;&lt;br /&gt;
    let value_next = values[(n - 1.) as usize];&lt;br /&gt;
&lt;br /&gt;
    let cs = context.create_node(&lt;br /&gt;
        AudioNodeInit::ConstantSourceNode(ConstantSourceNodeOptions::default()),&lt;br /&gt;
        Default::default(),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    let mut gain_options = GainNodeOptions::default();&lt;br /&gt;
    gain_options.gain = 0.0;&lt;br /&gt;
    let gain = context.create_node(&lt;br /&gt;
        AudioNodeInit::GainNode(gain_options.clone()),&lt;br /&gt;
        Default::default(),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    let osc = context.create_node(&lt;br /&gt;
        AudioNodeInit::OscillatorNode(Default::default()),&lt;br /&gt;
        Default::default(),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.connect_ports(osc.output(0), gain.input(0));&lt;br /&gt;
    context.connect_ports(cs.output(0), gain.param(ParamType::Gain));&lt;br /&gt;
    context.connect_ports(gain.output(0), dest.input(0));&lt;br /&gt;
&lt;br /&gt;
    let _ = context.resume();&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        osc,&lt;br /&gt;
        AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(0.)),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        gain,&lt;br /&gt;
        AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(0.)),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        cs,&lt;br /&gt;
        AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(0.)),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        cs,&lt;br /&gt;
        AudioNodeMessage::SetParam(&lt;br /&gt;
            ParamType::Offset,&lt;br /&gt;
            UserAutomationEvent::SetValueCurveAtTime(values, start_time, end_time),&lt;br /&gt;
        ),&lt;br /&gt;
&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        osc,&lt;br /&gt;
        AudioNodeMessage::SetParam(&lt;br /&gt;
            ParamType::Frequency,&lt;br /&gt;
            UserAutomationEvent::SetValueAtTime(value_next, end_time),&lt;br /&gt;
        ),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    thread::sleep(time::Duration::from_millis(7000));&lt;br /&gt;
    let _ = context.close();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
fn main() {&lt;br /&gt;
    ServoMedia::init::&amp;lt;servo_media_auto::Backend&amp;gt;();&lt;br /&gt;
    if let Ok(servo_media) = ServoMedia::get() {&lt;br /&gt;
        run_example(servo_media);&lt;br /&gt;
    } else {&lt;br /&gt;
        unreachable!();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above program, the values vector is passed into the SetValueCurveAtTime function to modulate the output. The output of the same can also be checked in the test-case video at the end of this page. &lt;br /&gt;
We can modify the values function as we want and observe the output. One more modification that we used was by using a sine curve. It is implemented as follows. Change the values vector in the set-value-curve function with the following: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 use std::f64::consts::PI;&lt;br /&gt;
    let mut values: Vec&amp;lt;f32&amp;gt; = Vec::new();&lt;br /&gt;
    let curvelength = 44100;&lt;br /&gt;
    let mut i = 0;&lt;br /&gt;
    while i &amp;lt; curvelength {&lt;br /&gt;
    values.push(f32::sin((PI *i as f64/curvelength as f64) as f32));&lt;br /&gt;
    i += 1;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The output of this function can be seen in the test video attached to at the end of this page. &lt;br /&gt;
&amp;lt;references&amp;gt;&amp;lt;/references&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=='''Video of Testing Audio Output'''==&lt;br /&gt;
[https://drive.google.com/file/d/1jzEZwAZE-7mi6N5N_JcEE6ISM-wc9910/view?usp=sharing Test-1]&lt;br /&gt;
[https://drive.google.com/file/d/1UsPgyv29Zf29d6pEDgLpYX86DI6hzOqp/view?usp=sharing Test-2]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=='''Issues and Fixes'''==&lt;br /&gt;
&lt;br /&gt;
Windows Specific during build&lt;br /&gt;
&lt;br /&gt;
https://github.com/holochain/holochain-cmd/issues/29&lt;br /&gt;
&lt;br /&gt;
https://stackoverflow.com/questions/53136717/errore0554-feature-may-not-be-used-on-the-stable-release-channel-couldnt&lt;br /&gt;
&lt;br /&gt;
https://github.com/servo/servo/issues/21429&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=='''Final Project'''==&lt;br /&gt;
If you are a peer reviewer please look into this [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#For_Peer_Reviewers_Note section]&lt;br /&gt;
&lt;br /&gt;
The final [https://github.com/servo/servo/wiki/Implement-missing-WebAudio-automation-student-project project] rely on our previous [https://github.com/servo/media/pull/230 work]. The next part would focus on implementing the code [https://github.com/servo/media/issues/204 written] to be accessible by Servo browser [https://github.com/servo/servo/issues/22897 engine]. &lt;br /&gt;
This would require interfacing the DOM [https://github.com/servo/servo/blob/master/components/script/dom/webidls/AudioParam.webidl file] reference the Param.rs [https://github.com/JHBalaji/media/blob/master/audio/src/param.rs#L259 setValueCurveAtTime] to be interfaced with [https://github.com/servo/servo/blob/master/components/script/dom/audioparam.rs AudioParam.rs]. The audioparam.rs would call the UserAutomationEvent in the param.rs setValueCurveAtTime.&lt;br /&gt;
&lt;br /&gt;
Once the initial function call with arguments  are updated, then the [https://github.com/servo/servo/blob/master/tests/wpt/README.md#updating-test-expectations testing] would be performed on ''./mach test-wpt tests/wpt/web-platform-tests/webaudio/the-audio-api/[https://github.com/servo/servo/tree/master/tests/wpt/web-platform-tests/webaudio/the-audio-api/the-audioparam-interface the-audioparam-interface]''. The [https://github.com/servo/servo/tree/master/tests/wpt/web-platform-tests/webaudio/the-audio-api/the-audioparam-interface the-audioparam-interface] is a folder of series of test cases that emulate the behavior of a function call, here the setValueCurveAtTime would need to be necessitated to mock the values as tested in previous [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#Test_Case example] but would require to be performed over a .html webpage with DOM elements to test the complete functionality.&lt;br /&gt;
&lt;br /&gt;
Servo webAudio tests are performed using [https://github.com/web-platform-tests/wpt/blob/master/resources/readme.md testharness.js]. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach create-wpt tests/wpt/path/to/new/test.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
would create a test.html using the WPT template for javascript tests. Once the skeleton code is completed with necessary function call, them the WPT tests would be executed using &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach test-wpt tests/wpt/path/to/new/test.html&lt;br /&gt;
./mach test-wpt tests/wpt/path/to/new/reftest.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[https://web-platform-tests.org/writing-tests/reftests.html reftest] are used in Servo to test behavior related to rendering; that are related to interaction made up of several webpages [think passing or referencing values to another webpage] with assertions to test cases that are expected from the interaction. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach create-wpt --reftest tests/wpt/path/to/new/reftest.html --reference tests/wpt/path/to/reference.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
reference.html and reftest.html will be created using WPT reftest template. Once the reftest is run the upstream test would need to be updated using &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach update-wpt --sync&lt;br /&gt;
./mach test-wpt --log-raw=update.log&lt;br /&gt;
./mach update-wpt update.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When reftest fails to diagnose the behavior reftest raw log is required which is generate using the below command. The .log is fed into  [https://github.com/Gankro/live-reftest-analyzer  reftest analyzer] to find those failing test. The reftest is also capable of pixel level comparison of the test and reference screenshots (incase of rendering)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach test-wpt --log-raw wpt.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==='''List of issues'''===&lt;br /&gt;
This project has listed 4 known issues under the  WebAudio title, each solving a different issue.&lt;br /&gt;
&lt;br /&gt;
1. [https://github.com/servo/media/issues/204 Implement ValueCurveAtTime automation]&lt;br /&gt;
This is the first issue, which has been addressed and successfully closed during the initial parts of this project. The steps followed are shown in the following diagram.&lt;br /&gt;
&lt;br /&gt;
[[File:WebAudio-Issue1.png]]&lt;br /&gt;
&lt;br /&gt;
2. [https://github.com/servo/servo/issues/22897 Implement AudioParam.setValueCurveAtTime]&lt;br /&gt;
This second issue builds up on the first one, and focuses on implementing yet another method called [https://webaudio.github.io/web-audio-api/#dom-audioparam-setvaluecurveattime setValueCurveAtTime]. The next focus of this project will likely be to work on this issue.&lt;br /&gt;
&lt;br /&gt;
[[File:WebAudio-Issue2.png]]&lt;br /&gt;
&lt;br /&gt;
=='''For Peer Reviewers Note'''==&lt;br /&gt;
&lt;br /&gt;
''Common peer review question clarifications are below,''&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Does the design incorporate all of the functionality required?&amp;quot; or &amp;quot;Check the changes that the authors proposed. Rate the overall quality of the explanations. Give comments if you find the explanation hard to follow or inadequate.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
:The [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#Final_Project section] clarifies your question.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Check the designs proposed by the authors.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
:There is no explicit design is involved as going by [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#Final_Project proposal], there are three files to be added with new functionality in addition to test cases and files.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Check the use of visual aids&amp;quot;&lt;br /&gt;
:Visual aids not applicable &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Give comments on the completeness of the design doc.&amp;quot;&lt;br /&gt;
: Let us know what you think about them!&lt;/div&gt;</summary>
		<author><name>Amadhus2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:WebAudio-Issue2.png&amp;diff=124035</id>
		<title>File:WebAudio-Issue2.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:WebAudio-Issue2.png&amp;diff=124035"/>
		<updated>2019-04-13T02:48:18Z</updated>

		<summary type="html">&lt;p&gt;Amadhus2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Amadhus2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support&amp;diff=124034</id>
		<title>CSC/ECE 517 Spring 2019 - Project M1901 Implement missing WebAudio automation support</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support&amp;diff=124034"/>
		<updated>2019-04-13T02:46:28Z</updated>

		<summary type="html">&lt;p&gt;Amadhus2: /* List of issues */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''Introduction'''== &lt;br /&gt;
&lt;br /&gt;
==='''Servo'''===&lt;br /&gt;
Servo is an developmental browser engine designed to make use of the memory safety properties and concurrency features of the Rust programming language. The project was initiated by Mozilla Research with effort from Samsung to port it to Android and ARM processors&lt;br /&gt;
&lt;br /&gt;
More information about Servo is available [https://servo.org here]&lt;br /&gt;
&lt;br /&gt;
==='''Rust'''===&lt;br /&gt;
Rust is a systems programming language which focuses on memory safety and concurrency. It is similar to C++ but ensures memory safety and provides high performance. Rust is brain child of Mozilla and simple as this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
fn main() {&lt;br /&gt;
    println!(&amp;quot;Hello World&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More information about Rust can be found [https://www.rust-lang.org/en-US/ here] and here is why we love [https://thenewstack.io/safer-future-rust/ Rust], [https://insights.stackoverflow.com/survey/2018/#most-loved-dreaded-and-wanted SF Loved]&lt;br /&gt;
&lt;br /&gt;
==='''Web Audio API'''===&lt;br /&gt;
The Web Audio API involves handling audio operations inside an audio context, and has been designed to allow modular routing. An audio routing graph has been created by linking together the Basic Audio operations performed with audio nodes. Several sources — with different types of channel layout — are supported even within a single context. This modular design provides the flexibility to create complex audio functions with dynamic effects.&lt;br /&gt;
&lt;br /&gt;
Audio nodes are linked into chains and simple webs by their inputs and outputs. They typically start with one or more sources. Sources provide arrays of sound intensities (samples) at very small timeslices, often tens of thousands of them per second. These could be either computed mathematically (such as OscillatorNode), or they can be recordings from sound/video files (like AudioBufferSourceNode and MediaElementAudioSourceNode) and audio streams (MediaStreamAudioSourceNode). In fact, sound files are just recordings of sound intensities themselves, which come in from microphones or electric instruments, and get mixed down into a single, complicated wave.&lt;br /&gt;
&lt;br /&gt;
Outputs of these nodes could be linked to inputs of others, which mix or modify these streams of sound samples into different streams. A common modification is multiplying the samples by a value to make them louder or quieter (as is the case with GainNode). Once the sound has been sufficiently processed for the intended effect, it can be linked to the input of a destination (AudioContext.destination), which sends the sound to the speakers or headphones. This last connection is only necessary if the user is supposed to hear the audio.&lt;br /&gt;
&lt;br /&gt;
A simple, typical workflow for web audio would look something like this:&lt;br /&gt;
&lt;br /&gt;
1. Create audio context&amp;lt;br&amp;gt;&lt;br /&gt;
2. Inside the context, create sources — such as &amp;lt;audio&amp;gt;, oscillator, stream&amp;lt;br&amp;gt;&lt;br /&gt;
3. Create effects nodes, such as reverb, biquad filter, panner, compressor&amp;lt;br&amp;gt;&lt;br /&gt;
4. Choose final destination of audio, for example your system speakers&amp;lt;br&amp;gt;&lt;br /&gt;
5. Connect the sources up to the effects, and the effects to the destination.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Problem Statement: Web Audio Automation'''===&lt;br /&gt;
&lt;br /&gt;
AudioParam is used to control the AudioNode functioning, say, Volume (a Gain parameter). These values can either be scheduled to be changed at precise times or set to particular value immediately following an event or at an event. The schedule to change when used with AudioContext.currentTime can helps in volume fades, filter sweeps etc. This would work aims to implement [https://github.com/servo/media/issues/204 SetValueCurveAtTime()].&lt;br /&gt;
&lt;br /&gt;
[https://webaudio.github.io/web-audio-api/#dom-audioparam-setvaluecurveattime setValueCurveAtTime()] is one such method in AudioParam that takes an array as input and schedules a change. The array is usually a curve in wedAudio and achieved my linear interpolation between the values from the floating-point values array and for the duration, d from the startTime, s&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;v(t) = values[N * (t - s) / d]&amp;lt;/code&amp;gt;, where N is the length of the values in the array.&lt;br /&gt;
And after the end of the curve time interval &amp;lt;code&amp;gt;(t &amp;gt;= s + d)&amp;lt;/code&amp;gt;, the value will remain constant at the final curve value. This would persist to happen until the next automation event.&lt;br /&gt;
&lt;br /&gt;
One of the application of setValueCurveAtTime() it to create tremolo effect. Suppose linear nor an exponential curve satisfy the needs then user can create curve based on values to setValueCurveAtTime() with an array of timing values. Its a much loved approached against multiple calls to setValueAtTime().&lt;br /&gt;
&lt;br /&gt;
==='''Build'''===&lt;br /&gt;
Servo is built with Cargo, the Rust package manager. We also use Mozilla's Mach tools to orchestrate the build and other tasks.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=='''Implementation of the Project'''== &lt;br /&gt;
&lt;br /&gt;
==='''Code'''===&lt;br /&gt;
The code is implemented as in [https://github.com/JHBalaji/media/blob/master/audio/src/param.rs#L418-L436 here]. The code below is the main code snippet for the SetValueCurveAtTime function. The values and function behavior is define in the param.rs file. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            AutomationEvent::SetValueCurveAtTime(ref values, start, duration) =&amp;gt; {&lt;br /&gt;
                let time_diff = ((duration.0 as f32) - (start.0 as f32)) as f32;&lt;br /&gt;
                let mut progress = ((((current_tick.0 as f32) - (start.0 as f32)) as f32) / time_diff) as f32;&lt;br /&gt;
                if progress &amp;lt; 0.0 {&lt;br /&gt;
                    progress = 0.0 as f32;&lt;br /&gt;
                }&lt;br /&gt;
                let n = values.len() as f32;&lt;br /&gt;
	            let k = (((n - 1.) * progress) as f32).floor();&lt;br /&gt;
                let next = k + 1. as f32;&lt;br /&gt;
                let step = time_diff / (n - 1.);&lt;br /&gt;
                if next &amp;lt; n {&lt;br /&gt;
                    let time_k = (k * step) as f32;&lt;br /&gt;
                    let time_k_next = (next * step) as f32;&lt;br /&gt;
                    let v_k = values[k as usize];&lt;br /&gt;
    				let v_k_next = values[next as usize];&lt;br /&gt;
                    *value = v_k + (v_k_next - v_k) * (((current_tick.0 as f32) - time_k) / (time_k_next - time_k));&lt;br /&gt;
                }&lt;br /&gt;
                true&lt;br /&gt;
            }&lt;br /&gt;
            AutomationEvent::CancelAndHoldAtTime(..) =&amp;gt; false,&lt;br /&gt;
            AutomationEvent::CancelScheduledValues(..) | AutomationEvent::SetValue(..) =&amp;gt; {&lt;br /&gt;
                unreachable!(&amp;quot;CancelScheduledValues/SetValue should never appear in the timeline&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Let's walk through the code. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;AutomationEvent::SetValueCurveAtTime()&amp;lt;/code&amp;gt; is a fn and takes three arguments: values, start, duration.&lt;br /&gt;
&lt;br /&gt;
progress, computes the difference between the first value in start_time and [https://github.com/JHBalaji/media/blob/5a981dff94f4dfaf2ebf0f0e09f599fab9d1a13b/audio/src/param.rs#L384 time] and makes explicit conversion to f32. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                let time_diff = ((duration.0 as f32) - (start.0 as f32)) as f32;&lt;br /&gt;
                let mut progress = ((((current_tick.0 as f32) - (start.0 as f32)) as f32) / time_diff) as f32;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
time_diff computes the total difference between duration and start_time, this is required when the values that needs to be computed goes beyond time_diff from start_time to set a constant value later.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                if progress &amp;lt; 0.0 {&lt;br /&gt;
                    progress = 0.0 as f32;&lt;br /&gt;
                }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Sets 0 if the progress from values array and present time being negative.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                let n = values.len() as f32;&lt;br /&gt;
	            let k = (((n - 1.) * progress) as f32).floor();&lt;br /&gt;
                let next = k + 1. as f32;&lt;br /&gt;
                let step = time_diff / (n - 1.);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
n, total length of values array. k, compute as k as in [[https://webaudio.github.io/web-audio-api/#dom-audioparam-setvaluecurveattime here] and &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; is k+1, the delta or step is computed that would be added to generate the sound wave from the values array. Say, the frequency start at 44KHz and the &amp;lt;code&amp;gt;step&amp;lt;/code&amp;gt; would be used to change the frequency of the curve.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                if next &amp;lt; n {&lt;br /&gt;
                    let time_k = (k * step) as f32;&lt;br /&gt;
                    let time_k_next = (next * step) as f32;&lt;br /&gt;
                    let v_k = values[k as usize];&lt;br /&gt;
    				let v_k_next = values[next as usize];&lt;br /&gt;
                    *value = v_k + (v_k_next - v_k) * (((current_tick.0 as f32) - time_k) / (time_k_next - time_k));&lt;br /&gt;
                }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code block generates sequences of values from &amp;lt;code&amp;gt;values&amp;lt;/code array and using &amp;lt;code&amp;gt;step&amp;lt;/code&amp;gt; value we computed. And does that till it reaches the total length of the array.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                true&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media/blob/f32a71c51f05f44d1e8ca217fbaa4dfb0b55d11e/audio/src/param.rs#L435 Used] to loop the function call made from [https://github.com/JHBalaji/media/blob/f32a71c51f05f44d1e8ca217fbaa4dfb0b55d11e/audio/src/param.rs#L117 here].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            AutomationEvent::CancelAndHoldAtTime(..) =&amp;gt; false,&lt;br /&gt;
            AutomationEvent::CancelScheduledValues(..) | AutomationEvent::SetValue(..) =&amp;gt; {&lt;br /&gt;
                unreachable!(&amp;quot;CancelScheduledValues/SetValue should never appear in the timeline&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media/blob/5a981dff94f4dfaf2ebf0f0e09f599fab9d1a13b/audio/src/param.rs#L466 Code] instructs to cancel this event or end of this function and proceed to next instructions. In Audio API unless you explicitly say the block to end, the block would end and hardware device would be stopped from consumption.&lt;br /&gt;
&lt;br /&gt;
==='''Examples'''===&lt;br /&gt;
&lt;br /&gt;
Examples are unique aspect to Rust. This instructs that code to make use of the function we just wrote and generates a sound output. Refer our example [https://github.com/JHBalaji/media-1/blob/master/examples/set_value_curve.rs here] for the SetValueCurveAtTime()&lt;br /&gt;
&lt;br /&gt;
And example is usually called by using cargo build in rust or cargo run.&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media-1/blob/master/examples/Cargo.toml Cargo.toml] dictates the naming and the file to be called as.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cargo run --example set_value_curve&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above code instructs to run the example [https://github.com/JHBalaji/media-1/blob/master/examples/set_value_curve.rs set_value_curve] to generate a sound output through our terminal.&lt;br /&gt;
&lt;br /&gt;
==='''Compile'''===&lt;br /&gt;
[https://github.com/JHBalaji/media-1/blob/master/Cargo.lock Cargo.lock] instructs the dependencies that would be required to build this project.&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media-1/blob/master/Cargo.toml Cargo.toml] calls all the folders or members to be complied. Usually the compilation would be at /media&lt;br /&gt;
&lt;br /&gt;
Cargo.lock installs number of packages called crates that would be used by the project to access the modules. Each of the member in [https://github.com/JHBalaji/media-1/blob/master/Cargo.toml Cargo.toml] would have [https://github.com/JHBalaji/media-1/blob/master/examples/Cargo.toml Cargo.toml] in them that would instruct [https://github.com/JHBalaji/media-1/blob/master/examples/Cargo.toml#L6 dependencies] during the build. build-dependencies would be used if you have dependencies before the build.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media-1/blob/master/.cargo/config .cargo config] is similar to a dotenv file for Rust&lt;br /&gt;
&lt;br /&gt;
==='''Test'''===&lt;br /&gt;
&lt;br /&gt;
If you would like to test our build please look into [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#Issues_and_Fixes Fixes] before proceeding. We would suggest MacOS or Linux 16.04 LTS for any development and testing. Virtual Machine or VirtualBox could be another option. We spent countless days in frustration with libraries and never ending apt installs so avoid Linux 18.04 for this build test.&lt;br /&gt;
&lt;br /&gt;
Once &amp;lt;code&amp;gt;cargo build&amp;lt;/code&amp;gt; is completed. Open /target/debug to view the examples that are generated.&lt;br /&gt;
&lt;br /&gt;
[[File:Servo-initial-build.PNG]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To run all examples after the cargo build is complete, use &amp;lt;code&amp;gt;cargo run --example &amp;lt;bin_name&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Examples.PNG]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Status of the Project'''===&lt;br /&gt;
&lt;br /&gt;
The [https://github.com/JHBalaji/media-1 build] is ready and the Pull request is [https://github.com/servo/media/pull/230 merged] with Servo/media.&lt;br /&gt;
&lt;br /&gt;
[[File:Pr.PNG]]&lt;br /&gt;
&lt;br /&gt;
=='''Normal build from Master Repo '''==&lt;br /&gt;
To build Servo in development mode. This is useful for development, but the resulting binary is very slow.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git clone https://github.com/servo/servo&lt;br /&gt;
cd servo&lt;br /&gt;
./mach build --dev&lt;br /&gt;
./mach run tests/html/about-mozilla.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
For benchmarking, performance testing, or real-world use, add the --release flag to create an optimized build:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach build --release&lt;br /&gt;
./mach run --release tests/html/about-mozilla.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==='''Compiling and Running the code'''===&lt;br /&gt;
&lt;br /&gt;
====Mac OS====&lt;br /&gt;
&lt;br /&gt;
Follow the instructions posted in this [https://github.com/JHBalaji/media-1 URL] and install GStreamer and Rust. After that follow the following lines for compiling on MacOS. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1. brew install gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-libav gst-rtsp-server gst-editing-services&lt;br /&gt;
&lt;br /&gt;
2. export PKG_CONFIG_PATH=/usr/local/Cellar/libffi/3.2.1/lib/pkgconfig/&lt;br /&gt;
&lt;br /&gt;
3. rustup override set nightly&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After this run the following command to compile servo/media &lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
cargo build &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After compiling you will be able to test our example that is places in the examples folder.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Windows and Linux====&lt;br /&gt;
&lt;br /&gt;
Head over here to install [https://rustup.rs/ Rust ToolChain]. If you need any additional details we would suggest reading the [https://github.com/rust-lang/rustup.rs/blob/master/README.md ReadMe on Rust]. Some Servo media specific build issues are [https://github.com/servo/media/blob/master/README.md advised]. &lt;br /&gt;
&lt;br /&gt;
We would suggest Ubuntu 18.04 LTS with updates [https://github.com/servo/media/blob/master/README.md gstreamer package].&lt;br /&gt;
&lt;br /&gt;
==='''Servo Media'''===&lt;br /&gt;
&amp;lt;b&amp;gt;Requirements&amp;lt;/b&amp;gt;&lt;br /&gt;
In order to build this crate you need to install gstreamer which can be found here [https://github.com/sdroege/gstreamer-rs]&lt;br /&gt;
==='''Test Case'''===&lt;br /&gt;
After you run cargo build, you should be able to see the executable of the example inside the target/debug folder. Following is the test we have written  file to check the functioning of the [https://github.com/JHBalaji/media-1/blob/master/examples/set_value_curve.rs SetValueCurveAtTIme].&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
extern crate servo_media;&lt;br /&gt;
extern crate servo_media_auto;&lt;br /&gt;
&lt;br /&gt;
use servo_media::audio::constant_source_node::ConstantSourceNodeOptions;&lt;br /&gt;
use servo_media::audio::gain_node::GainNodeOptions;&lt;br /&gt;
use servo_media::audio::node::{AudioNodeInit, AudioNodeMessage, AudioScheduledSourceNodeMessage};&lt;br /&gt;
use servo_media::audio::param::{ParamType, UserAutomationEvent};&lt;br /&gt;
use servo_media::ServoMedia;&lt;br /&gt;
use std::sync::Arc;&lt;br /&gt;
use std::{thread, time};&lt;br /&gt;
&lt;br /&gt;
fn run_example(servo_media: Arc&amp;lt;ServoMedia&amp;gt;) {&lt;br /&gt;
    let context = servo_media.create_audio_context(Default::default());&lt;br /&gt;
    let dest = context.dest_node();&lt;br /&gt;
&lt;br /&gt;
    //Initializing the values vector for SetValueCurve function&lt;br /&gt;
    let mut values: Vec&amp;lt;f32&amp;gt; = Vec::new();&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(1.0);&lt;br /&gt;
    values.push(1.0);&lt;br /&gt;
    values.push(1.0);&lt;br /&gt;
    values.push(1.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.5);&lt;br /&gt;
    values.push(0.5);&lt;br /&gt;
    values.push(0.5);&lt;br /&gt;
    values.push(0.5);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    let start_time = 0.;&lt;br /&gt;
    let end_time = 5.;&lt;br /&gt;
    let n = values.len() as f32;&lt;br /&gt;
    let value_next = values[(n - 1.) as usize];&lt;br /&gt;
&lt;br /&gt;
    let cs = context.create_node(&lt;br /&gt;
        AudioNodeInit::ConstantSourceNode(ConstantSourceNodeOptions::default()),&lt;br /&gt;
        Default::default(),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    let mut gain_options = GainNodeOptions::default();&lt;br /&gt;
    gain_options.gain = 0.0;&lt;br /&gt;
    let gain = context.create_node(&lt;br /&gt;
        AudioNodeInit::GainNode(gain_options.clone()),&lt;br /&gt;
        Default::default(),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    let osc = context.create_node(&lt;br /&gt;
        AudioNodeInit::OscillatorNode(Default::default()),&lt;br /&gt;
        Default::default(),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.connect_ports(osc.output(0), gain.input(0));&lt;br /&gt;
    context.connect_ports(cs.output(0), gain.param(ParamType::Gain));&lt;br /&gt;
    context.connect_ports(gain.output(0), dest.input(0));&lt;br /&gt;
&lt;br /&gt;
    let _ = context.resume();&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        osc,&lt;br /&gt;
        AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(0.)),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        gain,&lt;br /&gt;
        AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(0.)),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        cs,&lt;br /&gt;
        AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(0.)),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        cs,&lt;br /&gt;
        AudioNodeMessage::SetParam(&lt;br /&gt;
            ParamType::Offset,&lt;br /&gt;
            UserAutomationEvent::SetValueCurveAtTime(values, start_time, end_time),&lt;br /&gt;
        ),&lt;br /&gt;
&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        osc,&lt;br /&gt;
        AudioNodeMessage::SetParam(&lt;br /&gt;
            ParamType::Frequency,&lt;br /&gt;
            UserAutomationEvent::SetValueAtTime(value_next, end_time),&lt;br /&gt;
        ),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    thread::sleep(time::Duration::from_millis(7000));&lt;br /&gt;
    let _ = context.close();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
fn main() {&lt;br /&gt;
    ServoMedia::init::&amp;lt;servo_media_auto::Backend&amp;gt;();&lt;br /&gt;
    if let Ok(servo_media) = ServoMedia::get() {&lt;br /&gt;
        run_example(servo_media);&lt;br /&gt;
    } else {&lt;br /&gt;
        unreachable!();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above program, the values vector is passed into the SetValueCurveAtTime function to modulate the output. The output of the same can also be checked in the test-case video at the end of this page. &lt;br /&gt;
We can modify the values function as we want and observe the output. One more modification that we used was by using a sine curve. It is implemented as follows. Change the values vector in the set-value-curve function with the following: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 use std::f64::consts::PI;&lt;br /&gt;
    let mut values: Vec&amp;lt;f32&amp;gt; = Vec::new();&lt;br /&gt;
    let curvelength = 44100;&lt;br /&gt;
    let mut i = 0;&lt;br /&gt;
    while i &amp;lt; curvelength {&lt;br /&gt;
    values.push(f32::sin((PI *i as f64/curvelength as f64) as f32));&lt;br /&gt;
    i += 1;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The output of this function can be seen in the test video attached to at the end of this page. &lt;br /&gt;
&amp;lt;references&amp;gt;&amp;lt;/references&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=='''Video of Testing Audio Output'''==&lt;br /&gt;
[https://drive.google.com/file/d/1jzEZwAZE-7mi6N5N_JcEE6ISM-wc9910/view?usp=sharing Test-1]&lt;br /&gt;
[https://drive.google.com/file/d/1UsPgyv29Zf29d6pEDgLpYX86DI6hzOqp/view?usp=sharing Test-2]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=='''Issues and Fixes'''==&lt;br /&gt;
&lt;br /&gt;
Windows Specific during build&lt;br /&gt;
&lt;br /&gt;
https://github.com/holochain/holochain-cmd/issues/29&lt;br /&gt;
&lt;br /&gt;
https://stackoverflow.com/questions/53136717/errore0554-feature-may-not-be-used-on-the-stable-release-channel-couldnt&lt;br /&gt;
&lt;br /&gt;
https://github.com/servo/servo/issues/21429&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=='''Final Project'''==&lt;br /&gt;
If you are a peer reviewer please look into this [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#For_Peer_Reviewers_Note section]&lt;br /&gt;
&lt;br /&gt;
The final [https://github.com/servo/servo/wiki/Implement-missing-WebAudio-automation-student-project project] rely on our previous [https://github.com/servo/media/pull/230 work]. The next part would focus on implementing the code [https://github.com/servo/media/issues/204 written] to be accessible by Servo browser [https://github.com/servo/servo/issues/22897 engine]. &lt;br /&gt;
This would require interfacing the DOM [https://github.com/servo/servo/blob/master/components/script/dom/webidls/AudioParam.webidl file] reference the Param.rs [https://github.com/JHBalaji/media/blob/master/audio/src/param.rs#L259 setValueCurveAtTime] to be interfaced with [https://github.com/servo/servo/blob/master/components/script/dom/audioparam.rs AudioParam.rs]. The audioparam.rs would call the UserAutomationEvent in the param.rs setValueCurveAtTime.&lt;br /&gt;
&lt;br /&gt;
Once the initial function call with arguments  are updated, then the [https://github.com/servo/servo/blob/master/tests/wpt/README.md#updating-test-expectations testing] would be performed on ''./mach test-wpt tests/wpt/web-platform-tests/webaudio/the-audio-api/[https://github.com/servo/servo/tree/master/tests/wpt/web-platform-tests/webaudio/the-audio-api/the-audioparam-interface the-audioparam-interface]''. The [https://github.com/servo/servo/tree/master/tests/wpt/web-platform-tests/webaudio/the-audio-api/the-audioparam-interface the-audioparam-interface] is a folder of series of test cases that emulate the behavior of a function call, here the setValueCurveAtTime would need to be necessitated to mock the values as tested in previous [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#Test_Case example] but would require to be performed over a .html webpage with DOM elements to test the complete functionality.&lt;br /&gt;
&lt;br /&gt;
Servo webAudio tests are performed using [https://github.com/web-platform-tests/wpt/blob/master/resources/readme.md testharness.js]. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach create-wpt tests/wpt/path/to/new/test.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
would create a test.html using the WPT template for javascript tests. Once the skeleton code is completed with necessary function call, them the WPT tests would be executed using &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach test-wpt tests/wpt/path/to/new/test.html&lt;br /&gt;
./mach test-wpt tests/wpt/path/to/new/reftest.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[https://web-platform-tests.org/writing-tests/reftests.html reftest] are used in Servo to test behavior related to rendering; that are related to interaction made up of several webpages [think passing or referencing values to another webpage] with assertions to test cases that are expected from the interaction. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach create-wpt --reftest tests/wpt/path/to/new/reftest.html --reference tests/wpt/path/to/reference.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
reference.html and reftest.html will be created using WPT reftest template. Once the reftest is run the upstream test would need to be updated using &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach update-wpt --sync&lt;br /&gt;
./mach test-wpt --log-raw=update.log&lt;br /&gt;
./mach update-wpt update.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When reftest fails to diagnose the behavior reftest raw log is required which is generate using the below command. The .log is fed into  [https://github.com/Gankro/live-reftest-analyzer  reftest analyzer] to find those failing test. The reftest is also capable of pixel level comparison of the test and reference screenshots (incase of rendering)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach test-wpt --log-raw wpt.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==='''List of issues'''===&lt;br /&gt;
This project has listed 4 known issues under the  WebAudio title, each solving a different issue.&lt;br /&gt;
&lt;br /&gt;
1. [https://github.com/servo/media/issues/204 Implement ValueCurveAtTime automation]&lt;br /&gt;
This is the first issue, which has been addressed and successfully closed during the initial parts of this project. The steps followed are shown in the following diagram.&lt;br /&gt;
[[File:WebAudio-Issue1.png]]&lt;br /&gt;
&lt;br /&gt;
=='''For Peer Reviewers Note'''==&lt;br /&gt;
&lt;br /&gt;
''Common peer review question clarifications are below,''&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Does the design incorporate all of the functionality required?&amp;quot; or &amp;quot;Check the changes that the authors proposed. Rate the overall quality of the explanations. Give comments if you find the explanation hard to follow or inadequate.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
:The [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#Final_Project section] clarifies your question.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Check the designs proposed by the authors.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
:There is no explicit design is involved as going by [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#Final_Project proposal], there are three files to be added with new functionality in addition to test cases and files.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Check the use of visual aids&amp;quot;&lt;br /&gt;
:Visual aids not applicable &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Give comments on the completeness of the design doc.&amp;quot;&lt;br /&gt;
: Let us know what you think about them!&lt;/div&gt;</summary>
		<author><name>Amadhus2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:WebAudio-Issue1.png&amp;diff=124033</id>
		<title>File:WebAudio-Issue1.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:WebAudio-Issue1.png&amp;diff=124033"/>
		<updated>2019-04-13T02:45:14Z</updated>

		<summary type="html">&lt;p&gt;Amadhus2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Amadhus2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support&amp;diff=124030</id>
		<title>CSC/ECE 517 Spring 2019 - Project M1901 Implement missing WebAudio automation support</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support&amp;diff=124030"/>
		<updated>2019-04-13T02:38:14Z</updated>

		<summary type="html">&lt;p&gt;Amadhus2: /* Final Project */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''Introduction'''== &lt;br /&gt;
&lt;br /&gt;
==='''Servo'''===&lt;br /&gt;
Servo is an developmental browser engine designed to make use of the memory safety properties and concurrency features of the Rust programming language. The project was initiated by Mozilla Research with effort from Samsung to port it to Android and ARM processors&lt;br /&gt;
&lt;br /&gt;
More information about Servo is available [https://servo.org here]&lt;br /&gt;
&lt;br /&gt;
==='''Rust'''===&lt;br /&gt;
Rust is a systems programming language which focuses on memory safety and concurrency. It is similar to C++ but ensures memory safety and provides high performance. Rust is brain child of Mozilla and simple as this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
fn main() {&lt;br /&gt;
    println!(&amp;quot;Hello World&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More information about Rust can be found [https://www.rust-lang.org/en-US/ here] and here is why we love [https://thenewstack.io/safer-future-rust/ Rust], [https://insights.stackoverflow.com/survey/2018/#most-loved-dreaded-and-wanted SF Loved]&lt;br /&gt;
&lt;br /&gt;
==='''Web Audio API'''===&lt;br /&gt;
The Web Audio API involves handling audio operations inside an audio context, and has been designed to allow modular routing. An audio routing graph has been created by linking together the Basic Audio operations performed with audio nodes. Several sources — with different types of channel layout — are supported even within a single context. This modular design provides the flexibility to create complex audio functions with dynamic effects.&lt;br /&gt;
&lt;br /&gt;
Audio nodes are linked into chains and simple webs by their inputs and outputs. They typically start with one or more sources. Sources provide arrays of sound intensities (samples) at very small timeslices, often tens of thousands of them per second. These could be either computed mathematically (such as OscillatorNode), or they can be recordings from sound/video files (like AudioBufferSourceNode and MediaElementAudioSourceNode) and audio streams (MediaStreamAudioSourceNode). In fact, sound files are just recordings of sound intensities themselves, which come in from microphones or electric instruments, and get mixed down into a single, complicated wave.&lt;br /&gt;
&lt;br /&gt;
Outputs of these nodes could be linked to inputs of others, which mix or modify these streams of sound samples into different streams. A common modification is multiplying the samples by a value to make them louder or quieter (as is the case with GainNode). Once the sound has been sufficiently processed for the intended effect, it can be linked to the input of a destination (AudioContext.destination), which sends the sound to the speakers or headphones. This last connection is only necessary if the user is supposed to hear the audio.&lt;br /&gt;
&lt;br /&gt;
A simple, typical workflow for web audio would look something like this:&lt;br /&gt;
&lt;br /&gt;
1. Create audio context&amp;lt;br&amp;gt;&lt;br /&gt;
2. Inside the context, create sources — such as &amp;lt;audio&amp;gt;, oscillator, stream&amp;lt;br&amp;gt;&lt;br /&gt;
3. Create effects nodes, such as reverb, biquad filter, panner, compressor&amp;lt;br&amp;gt;&lt;br /&gt;
4. Choose final destination of audio, for example your system speakers&amp;lt;br&amp;gt;&lt;br /&gt;
5. Connect the sources up to the effects, and the effects to the destination.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Problem Statement: Web Audio Automation'''===&lt;br /&gt;
&lt;br /&gt;
AudioParam is used to control the AudioNode functioning, say, Volume (a Gain parameter). These values can either be scheduled to be changed at precise times or set to particular value immediately following an event or at an event. The schedule to change when used with AudioContext.currentTime can helps in volume fades, filter sweeps etc. This would work aims to implement [https://github.com/servo/media/issues/204 SetValueCurveAtTime()].&lt;br /&gt;
&lt;br /&gt;
[https://webaudio.github.io/web-audio-api/#dom-audioparam-setvaluecurveattime setValueCurveAtTime()] is one such method in AudioParam that takes an array as input and schedules a change. The array is usually a curve in wedAudio and achieved my linear interpolation between the values from the floating-point values array and for the duration, d from the startTime, s&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;v(t) = values[N * (t - s) / d]&amp;lt;/code&amp;gt;, where N is the length of the values in the array.&lt;br /&gt;
And after the end of the curve time interval &amp;lt;code&amp;gt;(t &amp;gt;= s + d)&amp;lt;/code&amp;gt;, the value will remain constant at the final curve value. This would persist to happen until the next automation event.&lt;br /&gt;
&lt;br /&gt;
One of the application of setValueCurveAtTime() it to create tremolo effect. Suppose linear nor an exponential curve satisfy the needs then user can create curve based on values to setValueCurveAtTime() with an array of timing values. Its a much loved approached against multiple calls to setValueAtTime().&lt;br /&gt;
&lt;br /&gt;
==='''Build'''===&lt;br /&gt;
Servo is built with Cargo, the Rust package manager. We also use Mozilla's Mach tools to orchestrate the build and other tasks.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=='''Implementation of the Project'''== &lt;br /&gt;
&lt;br /&gt;
==='''Code'''===&lt;br /&gt;
The code is implemented as in [https://github.com/JHBalaji/media/blob/master/audio/src/param.rs#L418-L436 here]. The code below is the main code snippet for the SetValueCurveAtTime function. The values and function behavior is define in the param.rs file. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            AutomationEvent::SetValueCurveAtTime(ref values, start, duration) =&amp;gt; {&lt;br /&gt;
                let time_diff = ((duration.0 as f32) - (start.0 as f32)) as f32;&lt;br /&gt;
                let mut progress = ((((current_tick.0 as f32) - (start.0 as f32)) as f32) / time_diff) as f32;&lt;br /&gt;
                if progress &amp;lt; 0.0 {&lt;br /&gt;
                    progress = 0.0 as f32;&lt;br /&gt;
                }&lt;br /&gt;
                let n = values.len() as f32;&lt;br /&gt;
	            let k = (((n - 1.) * progress) as f32).floor();&lt;br /&gt;
                let next = k + 1. as f32;&lt;br /&gt;
                let step = time_diff / (n - 1.);&lt;br /&gt;
                if next &amp;lt; n {&lt;br /&gt;
                    let time_k = (k * step) as f32;&lt;br /&gt;
                    let time_k_next = (next * step) as f32;&lt;br /&gt;
                    let v_k = values[k as usize];&lt;br /&gt;
    				let v_k_next = values[next as usize];&lt;br /&gt;
                    *value = v_k + (v_k_next - v_k) * (((current_tick.0 as f32) - time_k) / (time_k_next - time_k));&lt;br /&gt;
                }&lt;br /&gt;
                true&lt;br /&gt;
            }&lt;br /&gt;
            AutomationEvent::CancelAndHoldAtTime(..) =&amp;gt; false,&lt;br /&gt;
            AutomationEvent::CancelScheduledValues(..) | AutomationEvent::SetValue(..) =&amp;gt; {&lt;br /&gt;
                unreachable!(&amp;quot;CancelScheduledValues/SetValue should never appear in the timeline&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Let's walk through the code. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;AutomationEvent::SetValueCurveAtTime()&amp;lt;/code&amp;gt; is a fn and takes three arguments: values, start, duration.&lt;br /&gt;
&lt;br /&gt;
progress, computes the difference between the first value in start_time and [https://github.com/JHBalaji/media/blob/5a981dff94f4dfaf2ebf0f0e09f599fab9d1a13b/audio/src/param.rs#L384 time] and makes explicit conversion to f32. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                let time_diff = ((duration.0 as f32) - (start.0 as f32)) as f32;&lt;br /&gt;
                let mut progress = ((((current_tick.0 as f32) - (start.0 as f32)) as f32) / time_diff) as f32;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
time_diff computes the total difference between duration and start_time, this is required when the values that needs to be computed goes beyond time_diff from start_time to set a constant value later.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                if progress &amp;lt; 0.0 {&lt;br /&gt;
                    progress = 0.0 as f32;&lt;br /&gt;
                }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Sets 0 if the progress from values array and present time being negative.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                let n = values.len() as f32;&lt;br /&gt;
	            let k = (((n - 1.) * progress) as f32).floor();&lt;br /&gt;
                let next = k + 1. as f32;&lt;br /&gt;
                let step = time_diff / (n - 1.);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
n, total length of values array. k, compute as k as in [[https://webaudio.github.io/web-audio-api/#dom-audioparam-setvaluecurveattime here] and &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; is k+1, the delta or step is computed that would be added to generate the sound wave from the values array. Say, the frequency start at 44KHz and the &amp;lt;code&amp;gt;step&amp;lt;/code&amp;gt; would be used to change the frequency of the curve.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                if next &amp;lt; n {&lt;br /&gt;
                    let time_k = (k * step) as f32;&lt;br /&gt;
                    let time_k_next = (next * step) as f32;&lt;br /&gt;
                    let v_k = values[k as usize];&lt;br /&gt;
    				let v_k_next = values[next as usize];&lt;br /&gt;
                    *value = v_k + (v_k_next - v_k) * (((current_tick.0 as f32) - time_k) / (time_k_next - time_k));&lt;br /&gt;
                }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code block generates sequences of values from &amp;lt;code&amp;gt;values&amp;lt;/code array and using &amp;lt;code&amp;gt;step&amp;lt;/code&amp;gt; value we computed. And does that till it reaches the total length of the array.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                true&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media/blob/f32a71c51f05f44d1e8ca217fbaa4dfb0b55d11e/audio/src/param.rs#L435 Used] to loop the function call made from [https://github.com/JHBalaji/media/blob/f32a71c51f05f44d1e8ca217fbaa4dfb0b55d11e/audio/src/param.rs#L117 here].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            AutomationEvent::CancelAndHoldAtTime(..) =&amp;gt; false,&lt;br /&gt;
            AutomationEvent::CancelScheduledValues(..) | AutomationEvent::SetValue(..) =&amp;gt; {&lt;br /&gt;
                unreachable!(&amp;quot;CancelScheduledValues/SetValue should never appear in the timeline&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media/blob/5a981dff94f4dfaf2ebf0f0e09f599fab9d1a13b/audio/src/param.rs#L466 Code] instructs to cancel this event or end of this function and proceed to next instructions. In Audio API unless you explicitly say the block to end, the block would end and hardware device would be stopped from consumption.&lt;br /&gt;
&lt;br /&gt;
==='''Examples'''===&lt;br /&gt;
&lt;br /&gt;
Examples are unique aspect to Rust. This instructs that code to make use of the function we just wrote and generates a sound output. Refer our example [https://github.com/JHBalaji/media-1/blob/master/examples/set_value_curve.rs here] for the SetValueCurveAtTime()&lt;br /&gt;
&lt;br /&gt;
And example is usually called by using cargo build in rust or cargo run.&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media-1/blob/master/examples/Cargo.toml Cargo.toml] dictates the naming and the file to be called as.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cargo run --example set_value_curve&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above code instructs to run the example [https://github.com/JHBalaji/media-1/blob/master/examples/set_value_curve.rs set_value_curve] to generate a sound output through our terminal.&lt;br /&gt;
&lt;br /&gt;
==='''Compile'''===&lt;br /&gt;
[https://github.com/JHBalaji/media-1/blob/master/Cargo.lock Cargo.lock] instructs the dependencies that would be required to build this project.&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media-1/blob/master/Cargo.toml Cargo.toml] calls all the folders or members to be complied. Usually the compilation would be at /media&lt;br /&gt;
&lt;br /&gt;
Cargo.lock installs number of packages called crates that would be used by the project to access the modules. Each of the member in [https://github.com/JHBalaji/media-1/blob/master/Cargo.toml Cargo.toml] would have [https://github.com/JHBalaji/media-1/blob/master/examples/Cargo.toml Cargo.toml] in them that would instruct [https://github.com/JHBalaji/media-1/blob/master/examples/Cargo.toml#L6 dependencies] during the build. build-dependencies would be used if you have dependencies before the build.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[https://github.com/JHBalaji/media-1/blob/master/.cargo/config .cargo config] is similar to a dotenv file for Rust&lt;br /&gt;
&lt;br /&gt;
==='''Test'''===&lt;br /&gt;
&lt;br /&gt;
If you would like to test our build please look into [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#Issues_and_Fixes Fixes] before proceeding. We would suggest MacOS or Linux 16.04 LTS for any development and testing. Virtual Machine or VirtualBox could be another option. We spent countless days in frustration with libraries and never ending apt installs so avoid Linux 18.04 for this build test.&lt;br /&gt;
&lt;br /&gt;
Once &amp;lt;code&amp;gt;cargo build&amp;lt;/code&amp;gt; is completed. Open /target/debug to view the examples that are generated.&lt;br /&gt;
&lt;br /&gt;
[[File:Servo-initial-build.PNG]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To run all examples after the cargo build is complete, use &amp;lt;code&amp;gt;cargo run --example &amp;lt;bin_name&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Examples.PNG]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Status of the Project'''===&lt;br /&gt;
&lt;br /&gt;
The [https://github.com/JHBalaji/media-1 build] is ready and the Pull request is [https://github.com/servo/media/pull/230 merged] with Servo/media.&lt;br /&gt;
&lt;br /&gt;
[[File:Pr.PNG]]&lt;br /&gt;
&lt;br /&gt;
=='''Normal build from Master Repo '''==&lt;br /&gt;
To build Servo in development mode. This is useful for development, but the resulting binary is very slow.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git clone https://github.com/servo/servo&lt;br /&gt;
cd servo&lt;br /&gt;
./mach build --dev&lt;br /&gt;
./mach run tests/html/about-mozilla.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
For benchmarking, performance testing, or real-world use, add the --release flag to create an optimized build:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach build --release&lt;br /&gt;
./mach run --release tests/html/about-mozilla.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==='''Compiling and Running the code'''===&lt;br /&gt;
&lt;br /&gt;
====Mac OS====&lt;br /&gt;
&lt;br /&gt;
Follow the instructions posted in this [https://github.com/JHBalaji/media-1 URL] and install GStreamer and Rust. After that follow the following lines for compiling on MacOS. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1. brew install gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-libav gst-rtsp-server gst-editing-services&lt;br /&gt;
&lt;br /&gt;
2. export PKG_CONFIG_PATH=/usr/local/Cellar/libffi/3.2.1/lib/pkgconfig/&lt;br /&gt;
&lt;br /&gt;
3. rustup override set nightly&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After this run the following command to compile servo/media &lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
cargo build &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After compiling you will be able to test our example that is places in the examples folder.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Windows and Linux====&lt;br /&gt;
&lt;br /&gt;
Head over here to install [https://rustup.rs/ Rust ToolChain]. If you need any additional details we would suggest reading the [https://github.com/rust-lang/rustup.rs/blob/master/README.md ReadMe on Rust]. Some Servo media specific build issues are [https://github.com/servo/media/blob/master/README.md advised]. &lt;br /&gt;
&lt;br /&gt;
We would suggest Ubuntu 18.04 LTS with updates [https://github.com/servo/media/blob/master/README.md gstreamer package].&lt;br /&gt;
&lt;br /&gt;
==='''Servo Media'''===&lt;br /&gt;
&amp;lt;b&amp;gt;Requirements&amp;lt;/b&amp;gt;&lt;br /&gt;
In order to build this crate you need to install gstreamer which can be found here [https://github.com/sdroege/gstreamer-rs]&lt;br /&gt;
==='''Test Case'''===&lt;br /&gt;
After you run cargo build, you should be able to see the executable of the example inside the target/debug folder. Following is the test we have written  file to check the functioning of the [https://github.com/JHBalaji/media-1/blob/master/examples/set_value_curve.rs SetValueCurveAtTIme].&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
extern crate servo_media;&lt;br /&gt;
extern crate servo_media_auto;&lt;br /&gt;
&lt;br /&gt;
use servo_media::audio::constant_source_node::ConstantSourceNodeOptions;&lt;br /&gt;
use servo_media::audio::gain_node::GainNodeOptions;&lt;br /&gt;
use servo_media::audio::node::{AudioNodeInit, AudioNodeMessage, AudioScheduledSourceNodeMessage};&lt;br /&gt;
use servo_media::audio::param::{ParamType, UserAutomationEvent};&lt;br /&gt;
use servo_media::ServoMedia;&lt;br /&gt;
use std::sync::Arc;&lt;br /&gt;
use std::{thread, time};&lt;br /&gt;
&lt;br /&gt;
fn run_example(servo_media: Arc&amp;lt;ServoMedia&amp;gt;) {&lt;br /&gt;
    let context = servo_media.create_audio_context(Default::default());&lt;br /&gt;
    let dest = context.dest_node();&lt;br /&gt;
&lt;br /&gt;
    //Initializing the values vector for SetValueCurve function&lt;br /&gt;
    let mut values: Vec&amp;lt;f32&amp;gt; = Vec::new();&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(1.0);&lt;br /&gt;
    values.push(1.0);&lt;br /&gt;
    values.push(1.0);&lt;br /&gt;
    values.push(1.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.5);&lt;br /&gt;
    values.push(0.5);&lt;br /&gt;
    values.push(0.5);&lt;br /&gt;
    values.push(0.5);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    values.push(0.0);&lt;br /&gt;
    let start_time = 0.;&lt;br /&gt;
    let end_time = 5.;&lt;br /&gt;
    let n = values.len() as f32;&lt;br /&gt;
    let value_next = values[(n - 1.) as usize];&lt;br /&gt;
&lt;br /&gt;
    let cs = context.create_node(&lt;br /&gt;
        AudioNodeInit::ConstantSourceNode(ConstantSourceNodeOptions::default()),&lt;br /&gt;
        Default::default(),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    let mut gain_options = GainNodeOptions::default();&lt;br /&gt;
    gain_options.gain = 0.0;&lt;br /&gt;
    let gain = context.create_node(&lt;br /&gt;
        AudioNodeInit::GainNode(gain_options.clone()),&lt;br /&gt;
        Default::default(),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    let osc = context.create_node(&lt;br /&gt;
        AudioNodeInit::OscillatorNode(Default::default()),&lt;br /&gt;
        Default::default(),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.connect_ports(osc.output(0), gain.input(0));&lt;br /&gt;
    context.connect_ports(cs.output(0), gain.param(ParamType::Gain));&lt;br /&gt;
    context.connect_ports(gain.output(0), dest.input(0));&lt;br /&gt;
&lt;br /&gt;
    let _ = context.resume();&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        osc,&lt;br /&gt;
        AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(0.)),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        gain,&lt;br /&gt;
        AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(0.)),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        cs,&lt;br /&gt;
        AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(0.)),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        cs,&lt;br /&gt;
        AudioNodeMessage::SetParam(&lt;br /&gt;
            ParamType::Offset,&lt;br /&gt;
            UserAutomationEvent::SetValueCurveAtTime(values, start_time, end_time),&lt;br /&gt;
        ),&lt;br /&gt;
&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    context.message_node(&lt;br /&gt;
        osc,&lt;br /&gt;
        AudioNodeMessage::SetParam(&lt;br /&gt;
            ParamType::Frequency,&lt;br /&gt;
            UserAutomationEvent::SetValueAtTime(value_next, end_time),&lt;br /&gt;
        ),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    thread::sleep(time::Duration::from_millis(7000));&lt;br /&gt;
    let _ = context.close();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
fn main() {&lt;br /&gt;
    ServoMedia::init::&amp;lt;servo_media_auto::Backend&amp;gt;();&lt;br /&gt;
    if let Ok(servo_media) = ServoMedia::get() {&lt;br /&gt;
        run_example(servo_media);&lt;br /&gt;
    } else {&lt;br /&gt;
        unreachable!();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the above program, the values vector is passed into the SetValueCurveAtTime function to modulate the output. The output of the same can also be checked in the test-case video at the end of this page. &lt;br /&gt;
We can modify the values function as we want and observe the output. One more modification that we used was by using a sine curve. It is implemented as follows. Change the values vector in the set-value-curve function with the following: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 use std::f64::consts::PI;&lt;br /&gt;
    let mut values: Vec&amp;lt;f32&amp;gt; = Vec::new();&lt;br /&gt;
    let curvelength = 44100;&lt;br /&gt;
    let mut i = 0;&lt;br /&gt;
    while i &amp;lt; curvelength {&lt;br /&gt;
    values.push(f32::sin((PI *i as f64/curvelength as f64) as f32));&lt;br /&gt;
    i += 1;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The output of this function can be seen in the test video attached to at the end of this page. &lt;br /&gt;
&amp;lt;references&amp;gt;&amp;lt;/references&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=='''Video of Testing Audio Output'''==&lt;br /&gt;
[https://drive.google.com/file/d/1jzEZwAZE-7mi6N5N_JcEE6ISM-wc9910/view?usp=sharing Test-1]&lt;br /&gt;
[https://drive.google.com/file/d/1UsPgyv29Zf29d6pEDgLpYX86DI6hzOqp/view?usp=sharing Test-2]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=='''Issues and Fixes'''==&lt;br /&gt;
&lt;br /&gt;
Windows Specific during build&lt;br /&gt;
&lt;br /&gt;
https://github.com/holochain/holochain-cmd/issues/29&lt;br /&gt;
&lt;br /&gt;
https://stackoverflow.com/questions/53136717/errore0554-feature-may-not-be-used-on-the-stable-release-channel-couldnt&lt;br /&gt;
&lt;br /&gt;
https://github.com/servo/servo/issues/21429&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=='''Final Project'''==&lt;br /&gt;
If you are a peer reviewer please look into this [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#For_Peer_Reviewers_Note section]&lt;br /&gt;
&lt;br /&gt;
The final [https://github.com/servo/servo/wiki/Implement-missing-WebAudio-automation-student-project project] rely on our previous [https://github.com/servo/media/pull/230 work]. The next part would focus on implementing the code [https://github.com/servo/media/issues/204 written] to be accessible by Servo browser [https://github.com/servo/servo/issues/22897 engine]. &lt;br /&gt;
This would require interfacing the DOM [https://github.com/servo/servo/blob/master/components/script/dom/webidls/AudioParam.webidl file] reference the Param.rs [https://github.com/JHBalaji/media/blob/master/audio/src/param.rs#L259 setValueCurveAtTime] to be interfaced with [https://github.com/servo/servo/blob/master/components/script/dom/audioparam.rs AudioParam.rs]. The audioparam.rs would call the UserAutomationEvent in the param.rs setValueCurveAtTime.&lt;br /&gt;
&lt;br /&gt;
Once the initial function call with arguments  are updated, then the [https://github.com/servo/servo/blob/master/tests/wpt/README.md#updating-test-expectations testing] would be performed on ''./mach test-wpt tests/wpt/web-platform-tests/webaudio/the-audio-api/[https://github.com/servo/servo/tree/master/tests/wpt/web-platform-tests/webaudio/the-audio-api/the-audioparam-interface the-audioparam-interface]''. The [https://github.com/servo/servo/tree/master/tests/wpt/web-platform-tests/webaudio/the-audio-api/the-audioparam-interface the-audioparam-interface] is a folder of series of test cases that emulate the behavior of a function call, here the setValueCurveAtTime would need to be necessitated to mock the values as tested in previous [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#Test_Case example] but would require to be performed over a .html webpage with DOM elements to test the complete functionality.&lt;br /&gt;
&lt;br /&gt;
Servo webAudio tests are performed using [https://github.com/web-platform-tests/wpt/blob/master/resources/readme.md testharness.js]. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach create-wpt tests/wpt/path/to/new/test.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
would create a test.html using the WPT template for javascript tests. Once the skeleton code is completed with necessary function call, them the WPT tests would be executed using &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach test-wpt tests/wpt/path/to/new/test.html&lt;br /&gt;
./mach test-wpt tests/wpt/path/to/new/reftest.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[https://web-platform-tests.org/writing-tests/reftests.html reftest] are used in Servo to test behavior related to rendering; that are related to interaction made up of several webpages [think passing or referencing values to another webpage] with assertions to test cases that are expected from the interaction. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach create-wpt --reftest tests/wpt/path/to/new/reftest.html --reference tests/wpt/path/to/reference.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
reference.html and reftest.html will be created using WPT reftest template. Once the reftest is run the upstream test would need to be updated using &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach update-wpt --sync&lt;br /&gt;
./mach test-wpt --log-raw=update.log&lt;br /&gt;
./mach update-wpt update.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When reftest fails to diagnose the behavior reftest raw log is required which is generate using the below command. The .log is fed into  [https://github.com/Gankro/live-reftest-analyzer  reftest analyzer] to find those failing test. The reftest is also capable of pixel level comparison of the test and reference screenshots (incase of rendering)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mach test-wpt --log-raw wpt.log&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==='''List of issues'''===&lt;br /&gt;
This project has listed 4 known issues under the  WebAudio title, each solving a different issue.&lt;br /&gt;
&lt;br /&gt;
1. [https://github.com/servo/media/issues/204 Implement ValueCurveAtTime automation]&lt;br /&gt;
&lt;br /&gt;
=='''For Peer Reviewers Note'''==&lt;br /&gt;
&lt;br /&gt;
''Common peer review question clarifications are below,''&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Does the design incorporate all of the functionality required?&amp;quot; or &amp;quot;Check the changes that the authors proposed. Rate the overall quality of the explanations. Give comments if you find the explanation hard to follow or inadequate.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
:The [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#Final_Project section] clarifies your question.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Check the designs proposed by the authors.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
:There is no explicit design is involved as going by [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2019_-_Project_M1901_Implement_missing_WebAudio_automation_support#Final_Project proposal], there are three files to be added with new functionality in addition to test cases and files.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Check the use of visual aids&amp;quot;&lt;br /&gt;
:Visual aids not applicable &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Give comments on the completeness of the design doc.&amp;quot;&lt;br /&gt;
: Let us know what you think about them!&lt;/div&gt;</summary>
		<author><name>Amadhus2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=E1911_Refactor_Criterion&amp;diff=122957</id>
		<title>E1911 Refactor Criterion</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=E1911_Refactor_Criterion&amp;diff=122957"/>
		<updated>2019-04-02T00:49:31Z</updated>

		<summary type="html">&lt;p&gt;Amadhus2: /* Testing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=E1911 Refactoring criterion.rb=&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create new assignments and customize new or existing assignments. It also allows the instructor to create a list of topics the students can sign up for. Students can form teams in Expertiza to work on various projects and assignments. Students can also peer review other students' submissions. Expertiza supports submission across various document types, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The bulk of the code in criterion is HTML. It is the violation of MVC architecture - Model should not concern itself with how the data is displayed. This code needs to be moved to a partial file, and the partial file needs to be called in all appropriate places which call the criterion’s model methods. Once the logic for the view is moved out of the model, the model should only be left with business logic. This business logic code can also be refactored. Plus there are virtually no comments, properly comment the code.&lt;br /&gt;
&lt;br /&gt;
==About Criterion.rb==&lt;br /&gt;
Criterion is one of the types of questions that can be added to a questionnaire. There are many other types of question objects like dropdown that have the implementation of similar methods. As of now, the criterion model holds 4 methods that are called from different places in the application. Each of these methods is storing a string value which contains the necessary HTML lines to display the required functionalities to the user. This string value is then returned to the calling methods from the respective views. This HTML string is then entered wherever necessary. This is ideally the exact function of a partial, and this page needs to be heavily reformatted to use partials instead of returning a string containing html code.&lt;br /&gt;
&lt;br /&gt;
===The pull request===&lt;br /&gt;
https://github.com/expertiza/expertiza/pull/1407&lt;br /&gt;
&lt;br /&gt;
===The edit method===&lt;br /&gt;
This method is one of the several other methods in other files like criterion.rb which gets called when the type of the question being created in the respective model. In the case of this problem, which deals with criterion type questions, the edit method defined in criterion.rb is called when the question.type is equal to &amp;quot;Criterion&amp;quot;. This method allows for a user to create the criterion question and enter the necessary details. This method is called only from two view files - one for creating (_questionnaire.html.erb partial file) and another for editing (edit.html.erb). Both these files are in questionnaires view. Verified this using both RubyMine and the grep command. Another interesting thing to note is the use of &amp;quot;self.&amp;quot; to get the attributes associated with question object. When we move this code to a partial, we need to change this in the erb file. The outcome of this method's refactoring will completely remove this method from the model file criterion.rb as there is no business logic involved here.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def edit(_count)&lt;br /&gt;
    html = '&amp;lt;td align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;a rel=&amp;quot;nofollow&amp;quot; data-method=&amp;quot;delete&amp;quot; href=&amp;quot;/questions/' + self.id.to_s + '&amp;quot;&amp;gt;Remove&amp;lt;/a&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;6&amp;quot; value=&amp;quot;' + self.seq.to_s + '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][seq]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_seq&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;textarea cols=&amp;quot;50&amp;quot; rows=&amp;quot;1&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][txt]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_txt&amp;quot; placeholder=&amp;quot;Edit question content here&amp;quot;&amp;gt;' + self.txt + '&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;10&amp;quot; disabled=&amp;quot;disabled&amp;quot; value=&amp;quot;' + self.type + '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][type]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_type&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;2&amp;quot; value=&amp;quot;' + self.weight.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][weight]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_weight&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;text area size &amp;lt;input size=&amp;quot;3&amp;quot; value=&amp;quot;' + self.size.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][size]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_size&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt; max_label &amp;lt;input size=&amp;quot;10&amp;quot; value=&amp;quot;' + self.max_label.to_s + '&amp;quot; name=&amp;quot;question[' + self.id.to_s&lt;br /&gt;
    html += '][max_label]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_max_label&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;  min_label &amp;lt;input size=&amp;quot;12&amp;quot; value=&amp;quot;' + self.min_label.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][min_label]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_min_label&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    safe_join([&amp;quot;&amp;lt;tr&amp;gt;&amp;quot;.html_safe, &amp;quot;&amp;lt;/tr&amp;gt;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The safe_join is later used to return the HTML string to the calling view.&lt;br /&gt;
&lt;br /&gt;
===The view_question_text method===&lt;br /&gt;
This method has the same explanation as the edit method except the fact that this method is called only during viewing of questionnaires by an instructor. We observed that this method is also called by in student_quiz view. On further analysis, we found that the student_quiz does not use criterion object and has only three options: TrueFalse, MultipleChoiceRadio and MultipleChoiceCheckbox. So no refactoring is required here. Verified this method isn't called anywhere else using RubyMine and grep command. The outcome of this method's refactoring will completely remove this method from the model file criterion.rb as there is no business logic in this method and is completely html code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def view_question_text&lt;br /&gt;
    html = '&amp;lt;TD align=&amp;quot;left&amp;quot;&amp;gt; ' + self.txt + ' &amp;lt;/TD&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;TD align=&amp;quot;left&amp;quot;&amp;gt;' + self.type + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;td align=&amp;quot;center&amp;quot;&amp;gt;' + self.weight.to_s + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    questionnaire = self.questionnaire&lt;br /&gt;
    if !self.max_label.nil? &amp;amp;&amp;amp; !self.min_label.nil?&lt;br /&gt;
      html += '&amp;lt;TD align=&amp;quot;center&amp;quot;&amp;gt; (' + self.min_label + ') ' + questionnaire.min_question_score.to_s&lt;br /&gt;
      html += ' to ' + questionnaire.max_question_score.to_s + ' (' + self.max_label + ')&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    else&lt;br /&gt;
      html += '&amp;lt;TD align=&amp;quot;center&amp;quot;&amp;gt;' + questionnaire.min_question_score.to_s + ' to ' + questionnaire.max_question_score.to_s + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    safe_join([&amp;quot;&amp;lt;TR&amp;gt;&amp;quot;.html_safe, &amp;quot;&amp;lt;/TR&amp;gt;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===The complete method===&lt;br /&gt;
&lt;br /&gt;
This method is one of the several other methods in other files like criterion.rb which gets called when the user responds to the question being created in the respective model. In the case of this problem, which deals with criterion type question responses, the complete method defined in criterion.rb is called when the question.type is equal to &amp;quot;Criterion&amp;quot;. This method allows for a user to respond to the criterion question and enter the necessary details. This method is called only from one view file i.e. response.html.erb. This file is in response view. Verified this using both RubyMine and the grep command. Unlike edit or view_question_text the self object does not refer to a global object instead it refers to a copy of the local object. So, we had passed the required object as locals to the partial, along with the parameters required by the method namely question, count, answer, questionnaire_min, questionnaire_max, dropdown_or_scale. When we move this code to a partial, we need to change this in the erb file. The outcome of this method's refactoring will completely remove this method from the model file criterion.rb as there is no business logic involved here.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def complete(count, answer = nil, questionnaire_min, questionnaire_max, dropdown_or_scale)&lt;br /&gt;
    if self.size.nil?&lt;br /&gt;
      cols = '70'&lt;br /&gt;
      rows = '1'&lt;br /&gt;
    else&lt;br /&gt;
      cols = self.size.split(',')[0]&lt;br /&gt;
      rows = self.size.split(',')[1]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    html = '&amp;lt;div&amp;gt;&amp;lt;label for=&amp;quot;responses_' + count.to_s + '&amp;quot;&amp;gt;' + self.txt + '&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;'&lt;br /&gt;
    # show advice for each criterion question&lt;br /&gt;
    question_advices = QuestionAdvice.where(question_id: self.id).sort_by(&amp;amp;:id)&lt;br /&gt;
    advice_total_length = 0&lt;br /&gt;
&lt;br /&gt;
    question_advices.each do |question_advice|&lt;br /&gt;
      advice_total_length += question_advice.advice.length if question_advice.advice &amp;amp;&amp;amp; question_advice.advice != &amp;quot;&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if !question_advices.empty? and advice_total_length &amp;gt; 0&lt;br /&gt;
      html += '&amp;lt;a id=&amp;quot;showAdivce_' + self.id.to_s + '&amp;quot; onclick=&amp;quot;showAdvice(' + self.id.to_s + ')&amp;quot;&amp;gt;Show advice&amp;lt;/a&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;script&amp;gt;'&lt;br /&gt;
      html += 'function showAdvice(i){'&lt;br /&gt;
      html += 'var element = document.getElementById(&amp;quot;showAdivce_&amp;quot; + i.toString());'&lt;br /&gt;
      html += 'var show = element.innerHTML == &amp;quot;Hide advice&amp;quot;;'&lt;br /&gt;
      html += 'if (show){'&lt;br /&gt;
      html += 'element.innerHTML=&amp;quot;Show advice&amp;quot;;'&lt;br /&gt;
      html += '}else{'&lt;br /&gt;
      html += 'element.innerHTML=&amp;quot;Hide advice&amp;quot;;}'&lt;br /&gt;
      html += 'toggleAdvice(i);}'&lt;br /&gt;
&lt;br /&gt;
      html += 'function toggleAdvice(i) {'&lt;br /&gt;
      html += 'var elem = document.getElementById(i.toString() + &amp;quot;_myDiv&amp;quot;);'&lt;br /&gt;
      html += 'if (elem.style.display == &amp;quot;none&amp;quot;) {'&lt;br /&gt;
      html += 'elem.style.display = &amp;quot;&amp;quot;;'&lt;br /&gt;
      html += '} else {'&lt;br /&gt;
      html += 'elem.style.display = &amp;quot;none&amp;quot;;}}'&lt;br /&gt;
      html += '&amp;lt;/script&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;div id=&amp;quot;' + self.id.to_s + '_myDiv&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;'&lt;br /&gt;
      # [2015-10-26] Zhewei:&lt;br /&gt;
      # best to order advices high to low, e.g., 5 to 1&lt;br /&gt;
      # each level used to be a link;&lt;br /&gt;
      # clicking on the link caused the dropbox to be filled in with the corresponding number&lt;br /&gt;
      question_advices.reverse.each_with_index do |question_advice, index|&lt;br /&gt;
        html += '&amp;lt;a id=&amp;quot;changeScore_&amp;gt;' + self.id.to_s + '&amp;quot; onclick=&amp;quot;changeScore(' + count.to_s + ',' + index.to_s + ')&amp;quot;&amp;gt;'&lt;br /&gt;
        html += (self.questionnaire.max_question_score - index).to_s + ' - ' + question_advice.advice + '&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;'&lt;br /&gt;
        html += '&amp;lt;script&amp;gt;'&lt;br /&gt;
        html += 'function changeScore(i, j) {'&lt;br /&gt;
        html += 'var elem = jQuery(&amp;quot;#responses_&amp;quot; + i.toString() + &amp;quot;_score&amp;quot;);'&lt;br /&gt;
        html += 'var opts = elem.children(&amp;quot;option&amp;quot;).length;'&lt;br /&gt;
        html += 'elem.val((' + self.questionnaire.max_question_score.to_s + ' - j).toString());}'&lt;br /&gt;
        html += '&amp;lt;/script&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;/div&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if dropdown_or_scale == 'dropdown'&lt;br /&gt;
      current_value = &amp;quot;&amp;quot;&lt;br /&gt;
      current_value += 'data-current-rating =' + answer.answer.to_s if !answer.nil?&lt;br /&gt;
      html += '&amp;lt;div&amp;gt;&amp;lt;select id=&amp;quot;responses_' + count.to_s + '_score&amp;quot; name=&amp;quot;responses[' + count.to_s + '][score]&amp;quot; class=&amp;quot;review-rating&amp;quot; ' + current_value + '&amp;gt;'&lt;br /&gt;
      html += &amp;quot;&amp;lt;option value = ''&amp;gt;--&amp;lt;/option&amp;gt;&amp;quot;&lt;br /&gt;
      questionnaire_min.upto(questionnaire_max).each do |j|&lt;br /&gt;
        html += if !answer.nil? and j == answer.answer&lt;br /&gt;
                  '&amp;lt;option value=' + j.to_s + ' selected=&amp;quot;selected&amp;quot;&amp;gt;'&lt;br /&gt;
                else&lt;br /&gt;
                  '&amp;lt;option value=' + j.to_s + '&amp;gt;'&lt;br /&gt;
                end&lt;br /&gt;
&lt;br /&gt;
        html += j.to_s&lt;br /&gt;
        if j == questionnaire_min&lt;br /&gt;
          html += &amp;quot;-&amp;quot; + self.min_label if self.min_label.present?&lt;br /&gt;
        elsif j == questionnaire_max&lt;br /&gt;
          html += &amp;quot;-&amp;quot; + self.max_label if self.max_label.present?&lt;br /&gt;
        end&lt;br /&gt;
        html += &amp;quot;&amp;lt;/option&amp;gt;&amp;quot;&lt;br /&gt;
      end&lt;br /&gt;
      html += &amp;quot;&amp;lt;/select&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;&lt;br /&gt;
      html += '&amp;lt;textarea' + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
       ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
      html += answer.comments unless answer.nil?&lt;br /&gt;
      html += '&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
    elsif dropdown_or_scale == 'scale'&lt;br /&gt;
      html += '&amp;lt;input id=&amp;quot;responses_' + count.to_s + '_score&amp;quot; name=&amp;quot;responses[' + count.to_s + '][score]&amp;quot; type=&amp;quot;hidden&amp;quot;'&lt;br /&gt;
      html += 'value=&amp;quot;' + answer.answer.to_s + '&amp;quot;' unless answer.nil?&lt;br /&gt;
      html += '&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;table&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;tr&amp;gt;&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      (questionnaire_min..questionnaire_max).each do |j|&lt;br /&gt;
        html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;label&amp;gt;' + j.to_s + '&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += if !self.min_label.nil?&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;' + self.min_label + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
              else&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
              end&lt;br /&gt;
      (questionnaire_min..questionnaire_max).each do |j|&lt;br /&gt;
        html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;input type=&amp;quot;radio&amp;quot; id=&amp;quot;' + j.to_s + '&amp;quot; value=&amp;quot;' + j.to_s + '&amp;quot; name=&amp;quot;Radio_' + self.id.to_s + '&amp;quot;'&lt;br /&gt;
        html += 'checked=&amp;quot;checked&amp;quot;' if (!answer.nil? and answer.answer == j) or (answer.nil? and questionnaire_min == j)&lt;br /&gt;
        html += '&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;script&amp;gt;jQuery(&amp;quot;input[name=Radio_' + self.id.to_s + ']:radio&amp;quot;).change(function() {'&lt;br /&gt;
      html += 'var response_score = jQuery(&amp;quot;#responses_' + count.to_s + '_score&amp;quot;);'&lt;br /&gt;
      html += 'var checked_value = jQuery(&amp;quot;input[name=Radio_' + self.id.to_s + ']:checked&amp;quot;).val();'&lt;br /&gt;
      html += 'response_score.val(checked_value);});&amp;lt;/script&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += if !self.max_label.nil?&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;' + self.max_label + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
              else&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
              end&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;textarea cols=' + cols + ' rows=' + rows + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
        ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
      html += answer.comments unless answer.nil?&lt;br /&gt;
      html += '&amp;lt;/textarea&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    end&lt;br /&gt;
    safe_join([&amp;quot;&amp;quot;.html_safe, &amp;quot;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===The view_completed_question method===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Proposed Solution==&lt;br /&gt;
All these methods contain HTML text. What we propose to do is to pick these lines of code and move them into an appropriate partial, in the required format. The next task is to find out where in the entire application do these methods get called. The multiple overriding of the method calls in this poorly structured application makes it a challenging task. These method-calls then have to be replaced with the appropriate rendering of a partial in the views. This would make the structure more MVC oriented, and help keep it clean and understandable for the next developer who accesses this file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Implementation==&lt;br /&gt;
The changes proposed above were implemented as described below.&lt;br /&gt;
&lt;br /&gt;
===The Edit Method===&lt;br /&gt;
All the code in the model was just html and thus was completely removed from there. It was moved to the partial file (views/questionnaires/_criterion_edit.html.rb) and the necessary changes were made. Since it was all HTML code, no comments were actually required. However, we still added comments describing the partial file itself. Other comments were added whenever changes were made.&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/questionnaires/edit.html.erb -''' This file calls the edit method for all types of question objects and the object type takes care of invoking the right overridden method. We modified this file to call the partial instead of edit method only for Criterion type of question objects. This view is invoked during edit on the questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% for @question in @questionnaire.questions %&amp;gt;&lt;br /&gt;
-   &amp;lt;%-# The following line call certain method of the object, which returns html string-%&amp;gt;&lt;br /&gt;
+   &amp;lt;%# E1911: Call the criterion_edit partial if question is of type Criterion -%&amp;gt;&lt;br /&gt;
+   &amp;lt;% if @question.is_a? Criterion %&amp;gt;&lt;br /&gt;
+     &amp;lt;%= render :partial =&amp;gt; 'criterion_edit' %&amp;gt;&lt;br /&gt;
+   &amp;lt;% else %&amp;gt;&lt;br /&gt;
      &amp;lt;%=@question.edit%&amp;gt;&lt;br /&gt;
+ &amp;lt;% end %&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/questionnaires/_questionnaire.html.erb -''' This partial file is called by new.html.erb when anew question is created. Same logic and changes as above.&lt;br /&gt;
&lt;br /&gt;
'''3. views/questionnaires/_criterion_edit.html.erb -''' This file has all the html code that was earlier in the edit method of the criterion model. We changed the variables from &amp;quot;self.xxx&amp;quot; to &amp;quot;@question.xxx&amp;quot; because self was referring to question object in this context. Apart from this we changed the code to erb format. No more changes were deemed necessary. Please refer to the pull request to refer to the changes in this file as they are pure html and really long to be put in this wiki.&lt;br /&gt;
&lt;br /&gt;
===The view_question_text Method===&lt;br /&gt;
This method did not contain any business logic and thus all code was formatted and moved to a new partial file (views/questionnaires/_criterion_view.html.erb). Again, no comments were required due to complete html code and a comment describing the partial was added in addition to other necessary comments in other files.&lt;br /&gt;
&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/questionnaires/view.html.erb -''' Modified to invoke the partial if question is of type Criterion only. Also changed the question variable to a instance variable (question =&amp;gt; @question) to extend it's scope to the partial. This view is invoked during the view of questions in a questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- &amp;lt;%questions.each do |question| %&amp;gt;&lt;br /&gt;
-   &amp;lt;%if question.is_a? Question%&amp;gt;&lt;br /&gt;
-     &amp;lt;%=question.view_question_text.html_safe%&amp;gt;&lt;br /&gt;
+ &amp;lt;% for @question in questions %&amp;gt;&lt;br /&gt;
+   &amp;lt;%# E1911: Call the criterion_view partial if question is of type Criterion %&amp;gt;&lt;br /&gt;
+   &amp;lt;%if @question.is_a? Criterion %&amp;gt;&lt;br /&gt;
+         &amp;lt;%= render :partial =&amp;gt; 'criterion_view' %&amp;gt;&lt;br /&gt;
+     &amp;lt;%elsif @question.is_a? Question%&amp;gt;&lt;br /&gt;
+         &amp;lt;%= @question.view_question_text.html_safe %&amp;gt;&lt;br /&gt;
    &amp;lt;%end%&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/questionnaires/_criterion_view.html.erb -''' This partial file has the moved html code from view_question_text. Note that the &amp;quot;self.xxx&amp;quot; have been updated to &amp;quot;@question.xxx&amp;quot; as self referred to question object discussed in 1. Comment added to describe the partial file. Refer the pull request to look at the code.&lt;br /&gt;
&lt;br /&gt;
===The complete Method===&lt;br /&gt;
All the code in the model included html thus was completely removed from there. It was moved to the partial file (app/views/response/_criterion_complete.html.erb) and the necessary changes were made. Since it was all HTML code, no comments were actually required. However, we still added comments describing the partial file itself. Other comments were added whenever changes were made.&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/repsonse/response.html.erb -''' This file calls the complete method for all types of question objects and the object type takes care of invoking the right overridden method. We modified this file to call the partial instead of the complete method only for Criterion type of question objects. This view is invoked during user responds to the questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% elsif question.instance_of? Scale %&amp;gt;&lt;br /&gt;
&amp;lt;!--E1911: Replaced the call to criterion.complete method with the newly refactored partial--&amp;gt;&lt;br /&gt;
&amp;lt;%= render partial: 'criterion_complete', :locals =&amp;gt; {:question =&amp;gt; question, :count =&amp;gt; i, :answer =&amp;gt; answer, :questionnaire_min =&amp;gt; @questionnaire.min_question_score, :questionnaire_max =&amp;gt; @questionnaire.max_question_score, &lt;br /&gt;
:dropdown_or_scale =&amp;gt; @dropdown_or_scale} %&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;% elsif question.instance_of? Scale %&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/response/_criterion_complete.html.erb -''' This file has all the html code that was earlier in the complete method of the criterion model. We changed the variables from &amp;quot;self.xxx&amp;quot; to &amp;quot;question.xxx&amp;quot; because self was referring to copy of question object in this context. Apart from this we changed the code to erb format. No more changes were deemed necessary. Please refer to the pull request to refer to the changes in this file as they are pure html and really long to be put in this wiki.&lt;br /&gt;
&lt;br /&gt;
===The view_completed_question Method===&lt;br /&gt;
This method returns a constructed html string that is used to display a particular criterion question. Although this is similar to the other 3 methods, the html variable returned from this function is not directly called into a view. If that was the case, this could be simply moved into a partial as well.&lt;br /&gt;
&lt;br /&gt;
Instead, this html string is appended to another larger string variable named code in the response model, which builds the entire webpage by iterative appending. The html code for a criterion question being completed is a mere &amp;quot;part&amp;quot; of this entire string, which also includes other things such as the navbar of the page, links to the buttons, other questions, the header and the footer and such. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def add_table_rows questionnaire_max, questions, answers, code, tag_prompt_deployments = nil, current_user = nil&lt;br /&gt;
    count = 0&lt;br /&gt;
    # loop through questions so the the questions are displayed in order based on seq (sequence number)&lt;br /&gt;
    questions.each do |question|&lt;br /&gt;
      count += 1 if !question.is_a? QuestionnaireHeader and question.break_before == true&lt;br /&gt;
      answer = answers.find {|a| a.question_id == question.id }&lt;br /&gt;
      row_class = count.even? ? &amp;quot;info&amp;quot; : &amp;quot;warning&amp;quot;&lt;br /&gt;
      row_class = &amp;quot;&amp;quot; if question.is_a? QuestionnaireHeader&lt;br /&gt;
      code += '&amp;lt;tr class=&amp;quot;' + row_class + '&amp;quot;&amp;gt;&amp;lt;td&amp;gt;'&lt;br /&gt;
      if !answer.nil? or question.is_a? QuestionnaireHeader&lt;br /&gt;
        code += if question.instance_of? Criterion&lt;br /&gt;
                  #Answer Tags are enabled only for Criterion questions at the moment.&lt;br /&gt;
                  question.view_completed_question(count, answer, questionnaire_max, tag_prompt_deployments, current_user) || ''&lt;br /&gt;
                elsif question.instance_of? Scale&lt;br /&gt;
                  question.view_completed_question(count, answer, questionnaire_max) || ''&lt;br /&gt;
                else&lt;br /&gt;
                  question.view_completed_question(count, answer) || ''&lt;br /&gt;
                end&lt;br /&gt;
      end&lt;br /&gt;
      code += '&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
    code&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This &amp;quot;code&amp;quot; variable is then used to display the entire page through the view method under response.rb.&lt;br /&gt;
&lt;br /&gt;
A partial cannot be rendered halfway through the computation of &amp;quot;code&amp;quot;, neither can it be called from a model. Since code is containing the html string, and not erb, we cannot append the render partial line to the code variable as well.&lt;br /&gt;
&lt;br /&gt;
To refactor this method, we need to first refactor the entire response.rb to not append the html string for an entire webpage in a single variable, but rather use appropriate views to render the webpage.&lt;br /&gt;
&lt;br /&gt;
Refactoring an entire model would be beyond the scope of this project as the scale of the task is that of an entire project by itself.&lt;br /&gt;
&lt;br /&gt;
Thus, this method has been left untouched and still remains in criterion.rb itself.&lt;br /&gt;
&lt;br /&gt;
==Testing==&lt;br /&gt;
&lt;br /&gt;
Since our project only dealt with refactoring existing code, there was no particular need to test any specific components of the application. That being said, there were previous tests that were testing if the html variable returned by those methods was in the expected format or not.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  describe &amp;quot;#edit&amp;quot; do&lt;br /&gt;
    it &amp;quot;returns the html &amp;quot; do&lt;br /&gt;
      html = criterion.edit(0).to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;tr&amp;gt;&amp;lt;td align=\&amp;quot;center\&amp;quot;&amp;gt;&amp;lt;a rel=\&amp;quot;nofollow\&amp;quot; data-method=\&amp;quot;delete\&amp;quot; href=\&amp;quot;/questions/1\&amp;quot;&amp;gt;Remove&amp;lt;/a&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&lt;br /&gt;
&amp;lt;input size=\&amp;quot;6\&amp;quot; value=\&amp;quot;1.0\&amp;quot; name=\&amp;quot;question[1][seq]\&amp;quot; id=\&amp;quot;question_1_seq\&amp;quot; type=\&amp;quot;text\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&amp;lt;textarea cols=\&amp;quot;50\&amp;quot; rows=\&amp;quot;1\&amp;quot; &lt;br /&gt;
name=\&amp;quot;question[1][txt]\&amp;quot; id=\&amp;quot;question_1_txt\&amp;quot; placeholder=\&amp;quot;Edit question content here\&amp;quot;&amp;gt;test txt&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&amp;lt;input size=\&amp;quot;10\&amp;quot;&lt;br /&gt;
 disabled=\&amp;quot;disabled\&amp;quot; value=\&amp;quot;Criterion\&amp;quot; name=\&amp;quot;question[1][type]\&amp;quot; id=\&amp;quot;question_1_type\&amp;quot; type=\&amp;quot;text\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&amp;lt;input size=\&amp;quot;2\&amp;quot; &lt;br /&gt;
value=\&amp;quot;1\&amp;quot; name=\&amp;quot;question[1][weight]\&amp;quot; id=\&amp;quot;question_1_weight\&amp;quot; type=\&amp;quot;text\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;text area size &amp;lt;input size=\&amp;quot;3\&amp;quot; value=\&amp;quot;\&amp;quot; &lt;br /&gt;
name=\&amp;quot;question[1][size]\&amp;quot; id=\&amp;quot;question_1_size\&amp;quot; type=\&amp;quot;text\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt; max_label &amp;lt;input size=\&amp;quot;10\&amp;quot; value=\&amp;quot;\&amp;quot; name=\&amp;quot;question[1]&lt;br /&gt;
[max_label]\&amp;quot; id=\&amp;quot;question_1_max_label\&amp;quot; type=\&amp;quot;text\&amp;quot;&amp;gt;  min_label &amp;lt;input size=\&amp;quot;12\&amp;quot; value=\&amp;quot;\&amp;quot; name=\&amp;quot;question[1][min_label]\&amp;quot; &lt;br /&gt;
id=\&amp;quot;question_1_min_label\&amp;quot; type=\&amp;quot;text\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  describe &amp;quot;#view_question_text&amp;quot; do&lt;br /&gt;
    it &amp;quot;returns the html &amp;quot; do&lt;br /&gt;
      html = criterion.view_question_text.to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD align=\&amp;quot;left\&amp;quot;&amp;gt; test txt &amp;lt;/TD&amp;gt;&amp;lt;TD align=\&amp;quot;left\&amp;quot;&amp;gt;Criterion&amp;lt;/TD&amp;gt;&amp;lt;td align=\&amp;quot;center\&amp;quot;&amp;gt;1&amp;lt;/TD&amp;gt;&amp;lt;TD align=\&amp;quot;center\&amp;quot;&amp;gt; () 0 to 5 ()&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  describe &amp;quot;#complete&amp;quot; do&lt;br /&gt;
    it &amp;quot;returns the html &amp;quot; do&lt;br /&gt;
      html = criterion.complete(0, nil, 0, 5).to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;div&amp;gt;&amp;lt;label for=\&amp;quot;responses_0\&amp;quot;&amp;gt;test txt&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that these methods do not exist, there is no need to keep these test files as there is no html variable being returned or parsed. Therefore, we have removed these redundant test cases.&lt;/div&gt;</summary>
		<author><name>Amadhus2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=E1911_Refactor_Criterion&amp;diff=122956</id>
		<title>E1911 Refactor Criterion</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=E1911_Refactor_Criterion&amp;diff=122956"/>
		<updated>2019-04-02T00:46:54Z</updated>

		<summary type="html">&lt;p&gt;Amadhus2: /* Testing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=E1911 Refactoring criterion.rb=&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create new assignments and customize new or existing assignments. It also allows the instructor to create a list of topics the students can sign up for. Students can form teams in Expertiza to work on various projects and assignments. Students can also peer review other students' submissions. Expertiza supports submission across various document types, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The bulk of the code in criterion is HTML. It is the violation of MVC architecture - Model should not concern itself with how the data is displayed. This code needs to be moved to a partial file, and the partial file needs to be called in all appropriate places which call the criterion’s model methods. Once the logic for the view is moved out of the model, the model should only be left with business logic. This business logic code can also be refactored. Plus there are virtually no comments, properly comment the code.&lt;br /&gt;
&lt;br /&gt;
==About Criterion.rb==&lt;br /&gt;
Criterion is one of the types of questions that can be added to a questionnaire. There are many other types of question objects like dropdown that have the implementation of similar methods. As of now, the criterion model holds 4 methods that are called from different places in the application. Each of these methods is storing a string value which contains the necessary HTML lines to display the required functionalities to the user. This string value is then returned to the calling methods from the respective views. This HTML string is then entered wherever necessary. This is ideally the exact function of a partial, and this page needs to be heavily reformatted to use partials instead of returning a string containing html code.&lt;br /&gt;
&lt;br /&gt;
===The pull request===&lt;br /&gt;
https://github.com/expertiza/expertiza/pull/1407&lt;br /&gt;
&lt;br /&gt;
===The edit method===&lt;br /&gt;
This method is one of the several other methods in other files like criterion.rb which gets called when the type of the question being created in the respective model. In the case of this problem, which deals with criterion type questions, the edit method defined in criterion.rb is called when the question.type is equal to &amp;quot;Criterion&amp;quot;. This method allows for a user to create the criterion question and enter the necessary details. This method is called only from two view files - one for creating (_questionnaire.html.erb partial file) and another for editing (edit.html.erb). Both these files are in questionnaires view. Verified this using both RubyMine and the grep command. Another interesting thing to note is the use of &amp;quot;self.&amp;quot; to get the attributes associated with question object. When we move this code to a partial, we need to change this in the erb file. The outcome of this method's refactoring will completely remove this method from the model file criterion.rb as there is no business logic involved here.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def edit(_count)&lt;br /&gt;
    html = '&amp;lt;td align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;a rel=&amp;quot;nofollow&amp;quot; data-method=&amp;quot;delete&amp;quot; href=&amp;quot;/questions/' + self.id.to_s + '&amp;quot;&amp;gt;Remove&amp;lt;/a&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;6&amp;quot; value=&amp;quot;' + self.seq.to_s + '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][seq]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_seq&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;textarea cols=&amp;quot;50&amp;quot; rows=&amp;quot;1&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][txt]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_txt&amp;quot; placeholder=&amp;quot;Edit question content here&amp;quot;&amp;gt;' + self.txt + '&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;10&amp;quot; disabled=&amp;quot;disabled&amp;quot; value=&amp;quot;' + self.type + '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][type]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_type&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;2&amp;quot; value=&amp;quot;' + self.weight.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][weight]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_weight&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;text area size &amp;lt;input size=&amp;quot;3&amp;quot; value=&amp;quot;' + self.size.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][size]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_size&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt; max_label &amp;lt;input size=&amp;quot;10&amp;quot; value=&amp;quot;' + self.max_label.to_s + '&amp;quot; name=&amp;quot;question[' + self.id.to_s&lt;br /&gt;
    html += '][max_label]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_max_label&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;  min_label &amp;lt;input size=&amp;quot;12&amp;quot; value=&amp;quot;' + self.min_label.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][min_label]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_min_label&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    safe_join([&amp;quot;&amp;lt;tr&amp;gt;&amp;quot;.html_safe, &amp;quot;&amp;lt;/tr&amp;gt;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The safe_join is later used to return the HTML string to the calling view.&lt;br /&gt;
&lt;br /&gt;
===The view_question_text method===&lt;br /&gt;
This method has the same explanation as the edit method except the fact that this method is called only during viewing of questionnaires by an instructor. We observed that this method is also called by in student_quiz view. On further analysis, we found that the student_quiz does not use criterion object and has only three options: TrueFalse, MultipleChoiceRadio and MultipleChoiceCheckbox. So no refactoring is required here. Verified this method isn't called anywhere else using RubyMine and grep command. The outcome of this method's refactoring will completely remove this method from the model file criterion.rb as there is no business logic in this method and is completely html code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def view_question_text&lt;br /&gt;
    html = '&amp;lt;TD align=&amp;quot;left&amp;quot;&amp;gt; ' + self.txt + ' &amp;lt;/TD&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;TD align=&amp;quot;left&amp;quot;&amp;gt;' + self.type + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;td align=&amp;quot;center&amp;quot;&amp;gt;' + self.weight.to_s + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    questionnaire = self.questionnaire&lt;br /&gt;
    if !self.max_label.nil? &amp;amp;&amp;amp; !self.min_label.nil?&lt;br /&gt;
      html += '&amp;lt;TD align=&amp;quot;center&amp;quot;&amp;gt; (' + self.min_label + ') ' + questionnaire.min_question_score.to_s&lt;br /&gt;
      html += ' to ' + questionnaire.max_question_score.to_s + ' (' + self.max_label + ')&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    else&lt;br /&gt;
      html += '&amp;lt;TD align=&amp;quot;center&amp;quot;&amp;gt;' + questionnaire.min_question_score.to_s + ' to ' + questionnaire.max_question_score.to_s + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    safe_join([&amp;quot;&amp;lt;TR&amp;gt;&amp;quot;.html_safe, &amp;quot;&amp;lt;/TR&amp;gt;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===The complete method===&lt;br /&gt;
&lt;br /&gt;
This method is one of the several other methods in other files like criterion.rb which gets called when the user responds to the question being created in the respective model. In the case of this problem, which deals with criterion type question responses, the complete method defined in criterion.rb is called when the question.type is equal to &amp;quot;Criterion&amp;quot;. This method allows for a user to respond to the criterion question and enter the necessary details. This method is called only from one view file i.e. response.html.erb. This file is in response view. Verified this using both RubyMine and the grep command. Unlike edit or view_question_text the self object does not refer to a global object instead it refers to a copy of the local object. So, we had passed the required object as locals to the partial, along with the parameters required by the method namely question, count, answer, questionnaire_min, questionnaire_max, dropdown_or_scale. When we move this code to a partial, we need to change this in the erb file. The outcome of this method's refactoring will completely remove this method from the model file criterion.rb as there is no business logic involved here.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def complete(count, answer = nil, questionnaire_min, questionnaire_max, dropdown_or_scale)&lt;br /&gt;
    if self.size.nil?&lt;br /&gt;
      cols = '70'&lt;br /&gt;
      rows = '1'&lt;br /&gt;
    else&lt;br /&gt;
      cols = self.size.split(',')[0]&lt;br /&gt;
      rows = self.size.split(',')[1]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    html = '&amp;lt;div&amp;gt;&amp;lt;label for=&amp;quot;responses_' + count.to_s + '&amp;quot;&amp;gt;' + self.txt + '&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;'&lt;br /&gt;
    # show advice for each criterion question&lt;br /&gt;
    question_advices = QuestionAdvice.where(question_id: self.id).sort_by(&amp;amp;:id)&lt;br /&gt;
    advice_total_length = 0&lt;br /&gt;
&lt;br /&gt;
    question_advices.each do |question_advice|&lt;br /&gt;
      advice_total_length += question_advice.advice.length if question_advice.advice &amp;amp;&amp;amp; question_advice.advice != &amp;quot;&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if !question_advices.empty? and advice_total_length &amp;gt; 0&lt;br /&gt;
      html += '&amp;lt;a id=&amp;quot;showAdivce_' + self.id.to_s + '&amp;quot; onclick=&amp;quot;showAdvice(' + self.id.to_s + ')&amp;quot;&amp;gt;Show advice&amp;lt;/a&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;script&amp;gt;'&lt;br /&gt;
      html += 'function showAdvice(i){'&lt;br /&gt;
      html += 'var element = document.getElementById(&amp;quot;showAdivce_&amp;quot; + i.toString());'&lt;br /&gt;
      html += 'var show = element.innerHTML == &amp;quot;Hide advice&amp;quot;;'&lt;br /&gt;
      html += 'if (show){'&lt;br /&gt;
      html += 'element.innerHTML=&amp;quot;Show advice&amp;quot;;'&lt;br /&gt;
      html += '}else{'&lt;br /&gt;
      html += 'element.innerHTML=&amp;quot;Hide advice&amp;quot;;}'&lt;br /&gt;
      html += 'toggleAdvice(i);}'&lt;br /&gt;
&lt;br /&gt;
      html += 'function toggleAdvice(i) {'&lt;br /&gt;
      html += 'var elem = document.getElementById(i.toString() + &amp;quot;_myDiv&amp;quot;);'&lt;br /&gt;
      html += 'if (elem.style.display == &amp;quot;none&amp;quot;) {'&lt;br /&gt;
      html += 'elem.style.display = &amp;quot;&amp;quot;;'&lt;br /&gt;
      html += '} else {'&lt;br /&gt;
      html += 'elem.style.display = &amp;quot;none&amp;quot;;}}'&lt;br /&gt;
      html += '&amp;lt;/script&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;div id=&amp;quot;' + self.id.to_s + '_myDiv&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;'&lt;br /&gt;
      # [2015-10-26] Zhewei:&lt;br /&gt;
      # best to order advices high to low, e.g., 5 to 1&lt;br /&gt;
      # each level used to be a link;&lt;br /&gt;
      # clicking on the link caused the dropbox to be filled in with the corresponding number&lt;br /&gt;
      question_advices.reverse.each_with_index do |question_advice, index|&lt;br /&gt;
        html += '&amp;lt;a id=&amp;quot;changeScore_&amp;gt;' + self.id.to_s + '&amp;quot; onclick=&amp;quot;changeScore(' + count.to_s + ',' + index.to_s + ')&amp;quot;&amp;gt;'&lt;br /&gt;
        html += (self.questionnaire.max_question_score - index).to_s + ' - ' + question_advice.advice + '&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;'&lt;br /&gt;
        html += '&amp;lt;script&amp;gt;'&lt;br /&gt;
        html += 'function changeScore(i, j) {'&lt;br /&gt;
        html += 'var elem = jQuery(&amp;quot;#responses_&amp;quot; + i.toString() + &amp;quot;_score&amp;quot;);'&lt;br /&gt;
        html += 'var opts = elem.children(&amp;quot;option&amp;quot;).length;'&lt;br /&gt;
        html += 'elem.val((' + self.questionnaire.max_question_score.to_s + ' - j).toString());}'&lt;br /&gt;
        html += '&amp;lt;/script&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;/div&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if dropdown_or_scale == 'dropdown'&lt;br /&gt;
      current_value = &amp;quot;&amp;quot;&lt;br /&gt;
      current_value += 'data-current-rating =' + answer.answer.to_s if !answer.nil?&lt;br /&gt;
      html += '&amp;lt;div&amp;gt;&amp;lt;select id=&amp;quot;responses_' + count.to_s + '_score&amp;quot; name=&amp;quot;responses[' + count.to_s + '][score]&amp;quot; class=&amp;quot;review-rating&amp;quot; ' + current_value + '&amp;gt;'&lt;br /&gt;
      html += &amp;quot;&amp;lt;option value = ''&amp;gt;--&amp;lt;/option&amp;gt;&amp;quot;&lt;br /&gt;
      questionnaire_min.upto(questionnaire_max).each do |j|&lt;br /&gt;
        html += if !answer.nil? and j == answer.answer&lt;br /&gt;
                  '&amp;lt;option value=' + j.to_s + ' selected=&amp;quot;selected&amp;quot;&amp;gt;'&lt;br /&gt;
                else&lt;br /&gt;
                  '&amp;lt;option value=' + j.to_s + '&amp;gt;'&lt;br /&gt;
                end&lt;br /&gt;
&lt;br /&gt;
        html += j.to_s&lt;br /&gt;
        if j == questionnaire_min&lt;br /&gt;
          html += &amp;quot;-&amp;quot; + self.min_label if self.min_label.present?&lt;br /&gt;
        elsif j == questionnaire_max&lt;br /&gt;
          html += &amp;quot;-&amp;quot; + self.max_label if self.max_label.present?&lt;br /&gt;
        end&lt;br /&gt;
        html += &amp;quot;&amp;lt;/option&amp;gt;&amp;quot;&lt;br /&gt;
      end&lt;br /&gt;
      html += &amp;quot;&amp;lt;/select&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;&lt;br /&gt;
      html += '&amp;lt;textarea' + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
       ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
      html += answer.comments unless answer.nil?&lt;br /&gt;
      html += '&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
    elsif dropdown_or_scale == 'scale'&lt;br /&gt;
      html += '&amp;lt;input id=&amp;quot;responses_' + count.to_s + '_score&amp;quot; name=&amp;quot;responses[' + count.to_s + '][score]&amp;quot; type=&amp;quot;hidden&amp;quot;'&lt;br /&gt;
      html += 'value=&amp;quot;' + answer.answer.to_s + '&amp;quot;' unless answer.nil?&lt;br /&gt;
      html += '&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;table&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;tr&amp;gt;&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      (questionnaire_min..questionnaire_max).each do |j|&lt;br /&gt;
        html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;label&amp;gt;' + j.to_s + '&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += if !self.min_label.nil?&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;' + self.min_label + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
              else&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
              end&lt;br /&gt;
      (questionnaire_min..questionnaire_max).each do |j|&lt;br /&gt;
        html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;input type=&amp;quot;radio&amp;quot; id=&amp;quot;' + j.to_s + '&amp;quot; value=&amp;quot;' + j.to_s + '&amp;quot; name=&amp;quot;Radio_' + self.id.to_s + '&amp;quot;'&lt;br /&gt;
        html += 'checked=&amp;quot;checked&amp;quot;' if (!answer.nil? and answer.answer == j) or (answer.nil? and questionnaire_min == j)&lt;br /&gt;
        html += '&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;script&amp;gt;jQuery(&amp;quot;input[name=Radio_' + self.id.to_s + ']:radio&amp;quot;).change(function() {'&lt;br /&gt;
      html += 'var response_score = jQuery(&amp;quot;#responses_' + count.to_s + '_score&amp;quot;);'&lt;br /&gt;
      html += 'var checked_value = jQuery(&amp;quot;input[name=Radio_' + self.id.to_s + ']:checked&amp;quot;).val();'&lt;br /&gt;
      html += 'response_score.val(checked_value);});&amp;lt;/script&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += if !self.max_label.nil?&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;' + self.max_label + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
              else&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
              end&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;textarea cols=' + cols + ' rows=' + rows + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
        ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
      html += answer.comments unless answer.nil?&lt;br /&gt;
      html += '&amp;lt;/textarea&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    end&lt;br /&gt;
    safe_join([&amp;quot;&amp;quot;.html_safe, &amp;quot;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===The view_completed_question method===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Proposed Solution==&lt;br /&gt;
All these methods contain HTML text. What we propose to do is to pick these lines of code and move them into an appropriate partial, in the required format. The next task is to find out where in the entire application do these methods get called. The multiple overriding of the method calls in this poorly structured application makes it a challenging task. These method-calls then have to be replaced with the appropriate rendering of a partial in the views. This would make the structure more MVC oriented, and help keep it clean and understandable for the next developer who accesses this file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Implementation==&lt;br /&gt;
The changes proposed above were implemented as described below.&lt;br /&gt;
&lt;br /&gt;
===The Edit Method===&lt;br /&gt;
All the code in the model was just html and thus was completely removed from there. It was moved to the partial file (views/questionnaires/_criterion_edit.html.rb) and the necessary changes were made. Since it was all HTML code, no comments were actually required. However, we still added comments describing the partial file itself. Other comments were added whenever changes were made.&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/questionnaires/edit.html.erb -''' This file calls the edit method for all types of question objects and the object type takes care of invoking the right overridden method. We modified this file to call the partial instead of edit method only for Criterion type of question objects. This view is invoked during edit on the questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% for @question in @questionnaire.questions %&amp;gt;&lt;br /&gt;
-   &amp;lt;%-# The following line call certain method of the object, which returns html string-%&amp;gt;&lt;br /&gt;
+   &amp;lt;%# E1911: Call the criterion_edit partial if question is of type Criterion -%&amp;gt;&lt;br /&gt;
+   &amp;lt;% if @question.is_a? Criterion %&amp;gt;&lt;br /&gt;
+     &amp;lt;%= render :partial =&amp;gt; 'criterion_edit' %&amp;gt;&lt;br /&gt;
+   &amp;lt;% else %&amp;gt;&lt;br /&gt;
      &amp;lt;%=@question.edit%&amp;gt;&lt;br /&gt;
+ &amp;lt;% end %&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/questionnaires/_questionnaire.html.erb -''' This partial file is called by new.html.erb when anew question is created. Same logic and changes as above.&lt;br /&gt;
&lt;br /&gt;
'''3. views/questionnaires/_criterion_edit.html.erb -''' This file has all the html code that was earlier in the edit method of the criterion model. We changed the variables from &amp;quot;self.xxx&amp;quot; to &amp;quot;@question.xxx&amp;quot; because self was referring to question object in this context. Apart from this we changed the code to erb format. No more changes were deemed necessary. Please refer to the pull request to refer to the changes in this file as they are pure html and really long to be put in this wiki.&lt;br /&gt;
&lt;br /&gt;
===The view_question_text Method===&lt;br /&gt;
This method did not contain any business logic and thus all code was formatted and moved to a new partial file (views/questionnaires/_criterion_view.html.erb). Again, no comments were required due to complete html code and a comment describing the partial was added in addition to other necessary comments in other files.&lt;br /&gt;
&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/questionnaires/view.html.erb -''' Modified to invoke the partial if question is of type Criterion only. Also changed the question variable to a instance variable (question =&amp;gt; @question) to extend it's scope to the partial. This view is invoked during the view of questions in a questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- &amp;lt;%questions.each do |question| %&amp;gt;&lt;br /&gt;
-   &amp;lt;%if question.is_a? Question%&amp;gt;&lt;br /&gt;
-     &amp;lt;%=question.view_question_text.html_safe%&amp;gt;&lt;br /&gt;
+ &amp;lt;% for @question in questions %&amp;gt;&lt;br /&gt;
+   &amp;lt;%# E1911: Call the criterion_view partial if question is of type Criterion %&amp;gt;&lt;br /&gt;
+   &amp;lt;%if @question.is_a? Criterion %&amp;gt;&lt;br /&gt;
+         &amp;lt;%= render :partial =&amp;gt; 'criterion_view' %&amp;gt;&lt;br /&gt;
+     &amp;lt;%elsif @question.is_a? Question%&amp;gt;&lt;br /&gt;
+         &amp;lt;%= @question.view_question_text.html_safe %&amp;gt;&lt;br /&gt;
    &amp;lt;%end%&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/questionnaires/_criterion_view.html.erb -''' This partial file has the moved html code from view_question_text. Note that the &amp;quot;self.xxx&amp;quot; have been updated to &amp;quot;@question.xxx&amp;quot; as self referred to question object discussed in 1. Comment added to describe the partial file. Refer the pull request to look at the code.&lt;br /&gt;
&lt;br /&gt;
===The complete Method===&lt;br /&gt;
All the code in the model included html thus was completely removed from there. It was moved to the partial file (app/views/response/_criterion_complete.html.erb) and the necessary changes were made. Since it was all HTML code, no comments were actually required. However, we still added comments describing the partial file itself. Other comments were added whenever changes were made.&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/repsonse/response.html.erb -''' This file calls the complete method for all types of question objects and the object type takes care of invoking the right overridden method. We modified this file to call the partial instead of the complete method only for Criterion type of question objects. This view is invoked during user responds to the questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% elsif question.instance_of? Scale %&amp;gt;&lt;br /&gt;
&amp;lt;!--E1911: Replaced the call to criterion.complete method with the newly refactored partial--&amp;gt;&lt;br /&gt;
&amp;lt;%= render partial: 'criterion_complete', :locals =&amp;gt; {:question =&amp;gt; question, :count =&amp;gt; i, :answer =&amp;gt; answer, :questionnaire_min =&amp;gt; @questionnaire.min_question_score, :questionnaire_max =&amp;gt; @questionnaire.max_question_score, &lt;br /&gt;
:dropdown_or_scale =&amp;gt; @dropdown_or_scale} %&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;% elsif question.instance_of? Scale %&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/response/_criterion_complete.html.erb -''' This file has all the html code that was earlier in the complete method of the criterion model. We changed the variables from &amp;quot;self.xxx&amp;quot; to &amp;quot;question.xxx&amp;quot; because self was referring to copy of question object in this context. Apart from this we changed the code to erb format. No more changes were deemed necessary. Please refer to the pull request to refer to the changes in this file as they are pure html and really long to be put in this wiki.&lt;br /&gt;
&lt;br /&gt;
===The view_completed_question Method===&lt;br /&gt;
This method returns a constructed html string that is used to display a particular criterion question. Although this is similar to the other 3 methods, the html variable returned from this function is not directly called into a view. If that was the case, this could be simply moved into a partial as well.&lt;br /&gt;
&lt;br /&gt;
Instead, this html string is appended to another larger string variable named code in the response model, which builds the entire webpage by iterative appending. The html code for a criterion question being completed is a mere &amp;quot;part&amp;quot; of this entire string, which also includes other things such as the navbar of the page, links to the buttons, other questions, the header and the footer and such. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def add_table_rows questionnaire_max, questions, answers, code, tag_prompt_deployments = nil, current_user = nil&lt;br /&gt;
    count = 0&lt;br /&gt;
    # loop through questions so the the questions are displayed in order based on seq (sequence number)&lt;br /&gt;
    questions.each do |question|&lt;br /&gt;
      count += 1 if !question.is_a? QuestionnaireHeader and question.break_before == true&lt;br /&gt;
      answer = answers.find {|a| a.question_id == question.id }&lt;br /&gt;
      row_class = count.even? ? &amp;quot;info&amp;quot; : &amp;quot;warning&amp;quot;&lt;br /&gt;
      row_class = &amp;quot;&amp;quot; if question.is_a? QuestionnaireHeader&lt;br /&gt;
      code += '&amp;lt;tr class=&amp;quot;' + row_class + '&amp;quot;&amp;gt;&amp;lt;td&amp;gt;'&lt;br /&gt;
      if !answer.nil? or question.is_a? QuestionnaireHeader&lt;br /&gt;
        code += if question.instance_of? Criterion&lt;br /&gt;
                  #Answer Tags are enabled only for Criterion questions at the moment.&lt;br /&gt;
                  question.view_completed_question(count, answer, questionnaire_max, tag_prompt_deployments, current_user) || ''&lt;br /&gt;
                elsif question.instance_of? Scale&lt;br /&gt;
                  question.view_completed_question(count, answer, questionnaire_max) || ''&lt;br /&gt;
                else&lt;br /&gt;
                  question.view_completed_question(count, answer) || ''&lt;br /&gt;
                end&lt;br /&gt;
      end&lt;br /&gt;
      code += '&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
    code&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This &amp;quot;code&amp;quot; variable is then used to display the entire page through the view method under response.rb.&lt;br /&gt;
&lt;br /&gt;
A partial cannot be rendered halfway through the computation of &amp;quot;code&amp;quot;, neither can it be called from a model. Since code is containing the html string, and not erb, we cannot append the render partial line to the code variable as well.&lt;br /&gt;
&lt;br /&gt;
To refactor this method, we need to first refactor the entire response.rb to not append the html string for an entire webpage in a single variable, but rather use appropriate views to render the webpage.&lt;br /&gt;
&lt;br /&gt;
Refactoring an entire model would be beyond the scope of this project as the scale of the task is that of an entire project by itself.&lt;br /&gt;
&lt;br /&gt;
Thus, this method has been left untouched and still remains in criterion.rb itself.&lt;br /&gt;
&lt;br /&gt;
==Testing==&lt;br /&gt;
&lt;br /&gt;
Since our project only dealt with refactoring existing code, there was no particular need to test any specific components of the application. That being said, there were previous tests that were testing if the html variable returned by those methods was in the expected format or not.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  describe &amp;quot;#edit&amp;quot; do&lt;br /&gt;
    it &amp;quot;returns the html &amp;quot; do&lt;br /&gt;
      html = criterion.edit(0).to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;tr&amp;gt;&amp;lt;td align=\&amp;quot;center\&amp;quot;&amp;gt;&amp;lt;a rel=\&amp;quot;nofollow\&amp;quot; data-method=\&amp;quot;delete\&amp;quot; href=\&amp;quot;/questions/1\&amp;quot;&amp;gt;Remove&amp;lt;/a&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&lt;br /&gt;
&amp;lt;input size=\&amp;quot;6\&amp;quot; value=\&amp;quot;1.0\&amp;quot; name=\&amp;quot;question[1][seq]\&amp;quot; id=\&amp;quot;question_1_seq\&amp;quot; type=\&amp;quot;text\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&amp;lt;textarea cols=\&amp;quot;50\&amp;quot; rows=\&amp;quot;1\&amp;quot; &lt;br /&gt;
name=\&amp;quot;question[1][txt]\&amp;quot; id=\&amp;quot;question_1_txt\&amp;quot; placeholder=\&amp;quot;Edit question content here\&amp;quot;&amp;gt;test txt&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&amp;lt;input size=\&amp;quot;10\&amp;quot;&lt;br /&gt;
 disabled=\&amp;quot;disabled\&amp;quot; value=\&amp;quot;Criterion\&amp;quot; name=\&amp;quot;question[1][type]\&amp;quot; id=\&amp;quot;question_1_type\&amp;quot; type=\&amp;quot;text\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&amp;lt;input size=\&amp;quot;2\&amp;quot; &lt;br /&gt;
value=\&amp;quot;1\&amp;quot; name=\&amp;quot;question[1][weight]\&amp;quot; id=\&amp;quot;question_1_weight\&amp;quot; type=\&amp;quot;text\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;text area size &amp;lt;input size=\&amp;quot;3\&amp;quot; value=\&amp;quot;\&amp;quot; &lt;br /&gt;
name=\&amp;quot;question[1][size]\&amp;quot; id=\&amp;quot;question_1_size\&amp;quot; type=\&amp;quot;text\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt; max_label &amp;lt;input size=\&amp;quot;10\&amp;quot; value=\&amp;quot;\&amp;quot; name=\&amp;quot;question[1]&lt;br /&gt;
[max_label]\&amp;quot; id=\&amp;quot;question_1_max_label\&amp;quot; type=\&amp;quot;text\&amp;quot;&amp;gt;  min_label &amp;lt;input size=\&amp;quot;12\&amp;quot; value=\&amp;quot;\&amp;quot; name=\&amp;quot;question[1][min_label]\&amp;quot; &lt;br /&gt;
id=\&amp;quot;question_1_min_label\&amp;quot; type=\&amp;quot;text\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  describe &amp;quot;#view_question_text&amp;quot; do&lt;br /&gt;
    it &amp;quot;returns the html &amp;quot; do&lt;br /&gt;
      html = criterion.view_question_text.to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD align=\&amp;quot;left\&amp;quot;&amp;gt; test txt &amp;lt;/TD&amp;gt;&amp;lt;TD align=\&amp;quot;left\&amp;quot;&amp;gt;Criterion&amp;lt;/TD&amp;gt;&amp;lt;td align=\&amp;quot;center\&amp;quot;&amp;gt;1&amp;lt;/TD&amp;gt;&amp;lt;TD align=\&amp;quot;center\&amp;quot;&amp;gt; () 0 to 5 ()&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  describe &amp;quot;#complete&amp;quot; do&lt;br /&gt;
    it &amp;quot;returns the html &amp;quot; do&lt;br /&gt;
      html = criterion.complete(0, nil, 0, 5).to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;div&amp;gt;&amp;lt;label for=\&amp;quot;responses_0\&amp;quot;&amp;gt;test txt&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Amadhus2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=E1911_Refactor_Criterion&amp;diff=122955</id>
		<title>E1911 Refactor Criterion</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=E1911_Refactor_Criterion&amp;diff=122955"/>
		<updated>2019-04-02T00:46:35Z</updated>

		<summary type="html">&lt;p&gt;Amadhus2: /* Testing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=E1911 Refactoring criterion.rb=&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create new assignments and customize new or existing assignments. It also allows the instructor to create a list of topics the students can sign up for. Students can form teams in Expertiza to work on various projects and assignments. Students can also peer review other students' submissions. Expertiza supports submission across various document types, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The bulk of the code in criterion is HTML. It is the violation of MVC architecture - Model should not concern itself with how the data is displayed. This code needs to be moved to a partial file, and the partial file needs to be called in all appropriate places which call the criterion’s model methods. Once the logic for the view is moved out of the model, the model should only be left with business logic. This business logic code can also be refactored. Plus there are virtually no comments, properly comment the code.&lt;br /&gt;
&lt;br /&gt;
==About Criterion.rb==&lt;br /&gt;
Criterion is one of the types of questions that can be added to a questionnaire. There are many other types of question objects like dropdown that have the implementation of similar methods. As of now, the criterion model holds 4 methods that are called from different places in the application. Each of these methods is storing a string value which contains the necessary HTML lines to display the required functionalities to the user. This string value is then returned to the calling methods from the respective views. This HTML string is then entered wherever necessary. This is ideally the exact function of a partial, and this page needs to be heavily reformatted to use partials instead of returning a string containing html code.&lt;br /&gt;
&lt;br /&gt;
===The pull request===&lt;br /&gt;
https://github.com/expertiza/expertiza/pull/1407&lt;br /&gt;
&lt;br /&gt;
===The edit method===&lt;br /&gt;
This method is one of the several other methods in other files like criterion.rb which gets called when the type of the question being created in the respective model. In the case of this problem, which deals with criterion type questions, the edit method defined in criterion.rb is called when the question.type is equal to &amp;quot;Criterion&amp;quot;. This method allows for a user to create the criterion question and enter the necessary details. This method is called only from two view files - one for creating (_questionnaire.html.erb partial file) and another for editing (edit.html.erb). Both these files are in questionnaires view. Verified this using both RubyMine and the grep command. Another interesting thing to note is the use of &amp;quot;self.&amp;quot; to get the attributes associated with question object. When we move this code to a partial, we need to change this in the erb file. The outcome of this method's refactoring will completely remove this method from the model file criterion.rb as there is no business logic involved here.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def edit(_count)&lt;br /&gt;
    html = '&amp;lt;td align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;a rel=&amp;quot;nofollow&amp;quot; data-method=&amp;quot;delete&amp;quot; href=&amp;quot;/questions/' + self.id.to_s + '&amp;quot;&amp;gt;Remove&amp;lt;/a&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;6&amp;quot; value=&amp;quot;' + self.seq.to_s + '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][seq]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_seq&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;textarea cols=&amp;quot;50&amp;quot; rows=&amp;quot;1&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][txt]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_txt&amp;quot; placeholder=&amp;quot;Edit question content here&amp;quot;&amp;gt;' + self.txt + '&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;10&amp;quot; disabled=&amp;quot;disabled&amp;quot; value=&amp;quot;' + self.type + '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][type]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_type&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;2&amp;quot; value=&amp;quot;' + self.weight.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][weight]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_weight&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;text area size &amp;lt;input size=&amp;quot;3&amp;quot; value=&amp;quot;' + self.size.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][size]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_size&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt; max_label &amp;lt;input size=&amp;quot;10&amp;quot; value=&amp;quot;' + self.max_label.to_s + '&amp;quot; name=&amp;quot;question[' + self.id.to_s&lt;br /&gt;
    html += '][max_label]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_max_label&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;  min_label &amp;lt;input size=&amp;quot;12&amp;quot; value=&amp;quot;' + self.min_label.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][min_label]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_min_label&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    safe_join([&amp;quot;&amp;lt;tr&amp;gt;&amp;quot;.html_safe, &amp;quot;&amp;lt;/tr&amp;gt;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The safe_join is later used to return the HTML string to the calling view.&lt;br /&gt;
&lt;br /&gt;
===The view_question_text method===&lt;br /&gt;
This method has the same explanation as the edit method except the fact that this method is called only during viewing of questionnaires by an instructor. We observed that this method is also called by in student_quiz view. On further analysis, we found that the student_quiz does not use criterion object and has only three options: TrueFalse, MultipleChoiceRadio and MultipleChoiceCheckbox. So no refactoring is required here. Verified this method isn't called anywhere else using RubyMine and grep command. The outcome of this method's refactoring will completely remove this method from the model file criterion.rb as there is no business logic in this method and is completely html code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def view_question_text&lt;br /&gt;
    html = '&amp;lt;TD align=&amp;quot;left&amp;quot;&amp;gt; ' + self.txt + ' &amp;lt;/TD&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;TD align=&amp;quot;left&amp;quot;&amp;gt;' + self.type + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;td align=&amp;quot;center&amp;quot;&amp;gt;' + self.weight.to_s + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    questionnaire = self.questionnaire&lt;br /&gt;
    if !self.max_label.nil? &amp;amp;&amp;amp; !self.min_label.nil?&lt;br /&gt;
      html += '&amp;lt;TD align=&amp;quot;center&amp;quot;&amp;gt; (' + self.min_label + ') ' + questionnaire.min_question_score.to_s&lt;br /&gt;
      html += ' to ' + questionnaire.max_question_score.to_s + ' (' + self.max_label + ')&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    else&lt;br /&gt;
      html += '&amp;lt;TD align=&amp;quot;center&amp;quot;&amp;gt;' + questionnaire.min_question_score.to_s + ' to ' + questionnaire.max_question_score.to_s + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    safe_join([&amp;quot;&amp;lt;TR&amp;gt;&amp;quot;.html_safe, &amp;quot;&amp;lt;/TR&amp;gt;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===The complete method===&lt;br /&gt;
&lt;br /&gt;
This method is one of the several other methods in other files like criterion.rb which gets called when the user responds to the question being created in the respective model. In the case of this problem, which deals with criterion type question responses, the complete method defined in criterion.rb is called when the question.type is equal to &amp;quot;Criterion&amp;quot;. This method allows for a user to respond to the criterion question and enter the necessary details. This method is called only from one view file i.e. response.html.erb. This file is in response view. Verified this using both RubyMine and the grep command. Unlike edit or view_question_text the self object does not refer to a global object instead it refers to a copy of the local object. So, we had passed the required object as locals to the partial, along with the parameters required by the method namely question, count, answer, questionnaire_min, questionnaire_max, dropdown_or_scale. When we move this code to a partial, we need to change this in the erb file. The outcome of this method's refactoring will completely remove this method from the model file criterion.rb as there is no business logic involved here.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def complete(count, answer = nil, questionnaire_min, questionnaire_max, dropdown_or_scale)&lt;br /&gt;
    if self.size.nil?&lt;br /&gt;
      cols = '70'&lt;br /&gt;
      rows = '1'&lt;br /&gt;
    else&lt;br /&gt;
      cols = self.size.split(',')[0]&lt;br /&gt;
      rows = self.size.split(',')[1]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    html = '&amp;lt;div&amp;gt;&amp;lt;label for=&amp;quot;responses_' + count.to_s + '&amp;quot;&amp;gt;' + self.txt + '&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;'&lt;br /&gt;
    # show advice for each criterion question&lt;br /&gt;
    question_advices = QuestionAdvice.where(question_id: self.id).sort_by(&amp;amp;:id)&lt;br /&gt;
    advice_total_length = 0&lt;br /&gt;
&lt;br /&gt;
    question_advices.each do |question_advice|&lt;br /&gt;
      advice_total_length += question_advice.advice.length if question_advice.advice &amp;amp;&amp;amp; question_advice.advice != &amp;quot;&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if !question_advices.empty? and advice_total_length &amp;gt; 0&lt;br /&gt;
      html += '&amp;lt;a id=&amp;quot;showAdivce_' + self.id.to_s + '&amp;quot; onclick=&amp;quot;showAdvice(' + self.id.to_s + ')&amp;quot;&amp;gt;Show advice&amp;lt;/a&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;script&amp;gt;'&lt;br /&gt;
      html += 'function showAdvice(i){'&lt;br /&gt;
      html += 'var element = document.getElementById(&amp;quot;showAdivce_&amp;quot; + i.toString());'&lt;br /&gt;
      html += 'var show = element.innerHTML == &amp;quot;Hide advice&amp;quot;;'&lt;br /&gt;
      html += 'if (show){'&lt;br /&gt;
      html += 'element.innerHTML=&amp;quot;Show advice&amp;quot;;'&lt;br /&gt;
      html += '}else{'&lt;br /&gt;
      html += 'element.innerHTML=&amp;quot;Hide advice&amp;quot;;}'&lt;br /&gt;
      html += 'toggleAdvice(i);}'&lt;br /&gt;
&lt;br /&gt;
      html += 'function toggleAdvice(i) {'&lt;br /&gt;
      html += 'var elem = document.getElementById(i.toString() + &amp;quot;_myDiv&amp;quot;);'&lt;br /&gt;
      html += 'if (elem.style.display == &amp;quot;none&amp;quot;) {'&lt;br /&gt;
      html += 'elem.style.display = &amp;quot;&amp;quot;;'&lt;br /&gt;
      html += '} else {'&lt;br /&gt;
      html += 'elem.style.display = &amp;quot;none&amp;quot;;}}'&lt;br /&gt;
      html += '&amp;lt;/script&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;div id=&amp;quot;' + self.id.to_s + '_myDiv&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;'&lt;br /&gt;
      # [2015-10-26] Zhewei:&lt;br /&gt;
      # best to order advices high to low, e.g., 5 to 1&lt;br /&gt;
      # each level used to be a link;&lt;br /&gt;
      # clicking on the link caused the dropbox to be filled in with the corresponding number&lt;br /&gt;
      question_advices.reverse.each_with_index do |question_advice, index|&lt;br /&gt;
        html += '&amp;lt;a id=&amp;quot;changeScore_&amp;gt;' + self.id.to_s + '&amp;quot; onclick=&amp;quot;changeScore(' + count.to_s + ',' + index.to_s + ')&amp;quot;&amp;gt;'&lt;br /&gt;
        html += (self.questionnaire.max_question_score - index).to_s + ' - ' + question_advice.advice + '&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;'&lt;br /&gt;
        html += '&amp;lt;script&amp;gt;'&lt;br /&gt;
        html += 'function changeScore(i, j) {'&lt;br /&gt;
        html += 'var elem = jQuery(&amp;quot;#responses_&amp;quot; + i.toString() + &amp;quot;_score&amp;quot;);'&lt;br /&gt;
        html += 'var opts = elem.children(&amp;quot;option&amp;quot;).length;'&lt;br /&gt;
        html += 'elem.val((' + self.questionnaire.max_question_score.to_s + ' - j).toString());}'&lt;br /&gt;
        html += '&amp;lt;/script&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;/div&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if dropdown_or_scale == 'dropdown'&lt;br /&gt;
      current_value = &amp;quot;&amp;quot;&lt;br /&gt;
      current_value += 'data-current-rating =' + answer.answer.to_s if !answer.nil?&lt;br /&gt;
      html += '&amp;lt;div&amp;gt;&amp;lt;select id=&amp;quot;responses_' + count.to_s + '_score&amp;quot; name=&amp;quot;responses[' + count.to_s + '][score]&amp;quot; class=&amp;quot;review-rating&amp;quot; ' + current_value + '&amp;gt;'&lt;br /&gt;
      html += &amp;quot;&amp;lt;option value = ''&amp;gt;--&amp;lt;/option&amp;gt;&amp;quot;&lt;br /&gt;
      questionnaire_min.upto(questionnaire_max).each do |j|&lt;br /&gt;
        html += if !answer.nil? and j == answer.answer&lt;br /&gt;
                  '&amp;lt;option value=' + j.to_s + ' selected=&amp;quot;selected&amp;quot;&amp;gt;'&lt;br /&gt;
                else&lt;br /&gt;
                  '&amp;lt;option value=' + j.to_s + '&amp;gt;'&lt;br /&gt;
                end&lt;br /&gt;
&lt;br /&gt;
        html += j.to_s&lt;br /&gt;
        if j == questionnaire_min&lt;br /&gt;
          html += &amp;quot;-&amp;quot; + self.min_label if self.min_label.present?&lt;br /&gt;
        elsif j == questionnaire_max&lt;br /&gt;
          html += &amp;quot;-&amp;quot; + self.max_label if self.max_label.present?&lt;br /&gt;
        end&lt;br /&gt;
        html += &amp;quot;&amp;lt;/option&amp;gt;&amp;quot;&lt;br /&gt;
      end&lt;br /&gt;
      html += &amp;quot;&amp;lt;/select&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;&lt;br /&gt;
      html += '&amp;lt;textarea' + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
       ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
      html += answer.comments unless answer.nil?&lt;br /&gt;
      html += '&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
    elsif dropdown_or_scale == 'scale'&lt;br /&gt;
      html += '&amp;lt;input id=&amp;quot;responses_' + count.to_s + '_score&amp;quot; name=&amp;quot;responses[' + count.to_s + '][score]&amp;quot; type=&amp;quot;hidden&amp;quot;'&lt;br /&gt;
      html += 'value=&amp;quot;' + answer.answer.to_s + '&amp;quot;' unless answer.nil?&lt;br /&gt;
      html += '&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;table&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;tr&amp;gt;&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      (questionnaire_min..questionnaire_max).each do |j|&lt;br /&gt;
        html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;label&amp;gt;' + j.to_s + '&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += if !self.min_label.nil?&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;' + self.min_label + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
              else&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
              end&lt;br /&gt;
      (questionnaire_min..questionnaire_max).each do |j|&lt;br /&gt;
        html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;input type=&amp;quot;radio&amp;quot; id=&amp;quot;' + j.to_s + '&amp;quot; value=&amp;quot;' + j.to_s + '&amp;quot; name=&amp;quot;Radio_' + self.id.to_s + '&amp;quot;'&lt;br /&gt;
        html += 'checked=&amp;quot;checked&amp;quot;' if (!answer.nil? and answer.answer == j) or (answer.nil? and questionnaire_min == j)&lt;br /&gt;
        html += '&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;script&amp;gt;jQuery(&amp;quot;input[name=Radio_' + self.id.to_s + ']:radio&amp;quot;).change(function() {'&lt;br /&gt;
      html += 'var response_score = jQuery(&amp;quot;#responses_' + count.to_s + '_score&amp;quot;);'&lt;br /&gt;
      html += 'var checked_value = jQuery(&amp;quot;input[name=Radio_' + self.id.to_s + ']:checked&amp;quot;).val();'&lt;br /&gt;
      html += 'response_score.val(checked_value);});&amp;lt;/script&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += if !self.max_label.nil?&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;' + self.max_label + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
              else&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
              end&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;textarea cols=' + cols + ' rows=' + rows + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
        ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
      html += answer.comments unless answer.nil?&lt;br /&gt;
      html += '&amp;lt;/textarea&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    end&lt;br /&gt;
    safe_join([&amp;quot;&amp;quot;.html_safe, &amp;quot;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===The view_completed_question method===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Proposed Solution==&lt;br /&gt;
All these methods contain HTML text. What we propose to do is to pick these lines of code and move them into an appropriate partial, in the required format. The next task is to find out where in the entire application do these methods get called. The multiple overriding of the method calls in this poorly structured application makes it a challenging task. These method-calls then have to be replaced with the appropriate rendering of a partial in the views. This would make the structure more MVC oriented, and help keep it clean and understandable for the next developer who accesses this file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Implementation==&lt;br /&gt;
The changes proposed above were implemented as described below.&lt;br /&gt;
&lt;br /&gt;
===The Edit Method===&lt;br /&gt;
All the code in the model was just html and thus was completely removed from there. It was moved to the partial file (views/questionnaires/_criterion_edit.html.rb) and the necessary changes were made. Since it was all HTML code, no comments were actually required. However, we still added comments describing the partial file itself. Other comments were added whenever changes were made.&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/questionnaires/edit.html.erb -''' This file calls the edit method for all types of question objects and the object type takes care of invoking the right overridden method. We modified this file to call the partial instead of edit method only for Criterion type of question objects. This view is invoked during edit on the questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% for @question in @questionnaire.questions %&amp;gt;&lt;br /&gt;
-   &amp;lt;%-# The following line call certain method of the object, which returns html string-%&amp;gt;&lt;br /&gt;
+   &amp;lt;%# E1911: Call the criterion_edit partial if question is of type Criterion -%&amp;gt;&lt;br /&gt;
+   &amp;lt;% if @question.is_a? Criterion %&amp;gt;&lt;br /&gt;
+     &amp;lt;%= render :partial =&amp;gt; 'criterion_edit' %&amp;gt;&lt;br /&gt;
+   &amp;lt;% else %&amp;gt;&lt;br /&gt;
      &amp;lt;%=@question.edit%&amp;gt;&lt;br /&gt;
+ &amp;lt;% end %&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/questionnaires/_questionnaire.html.erb -''' This partial file is called by new.html.erb when anew question is created. Same logic and changes as above.&lt;br /&gt;
&lt;br /&gt;
'''3. views/questionnaires/_criterion_edit.html.erb -''' This file has all the html code that was earlier in the edit method of the criterion model. We changed the variables from &amp;quot;self.xxx&amp;quot; to &amp;quot;@question.xxx&amp;quot; because self was referring to question object in this context. Apart from this we changed the code to erb format. No more changes were deemed necessary. Please refer to the pull request to refer to the changes in this file as they are pure html and really long to be put in this wiki.&lt;br /&gt;
&lt;br /&gt;
===The view_question_text Method===&lt;br /&gt;
This method did not contain any business logic and thus all code was formatted and moved to a new partial file (views/questionnaires/_criterion_view.html.erb). Again, no comments were required due to complete html code and a comment describing the partial was added in addition to other necessary comments in other files.&lt;br /&gt;
&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/questionnaires/view.html.erb -''' Modified to invoke the partial if question is of type Criterion only. Also changed the question variable to a instance variable (question =&amp;gt; @question) to extend it's scope to the partial. This view is invoked during the view of questions in a questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- &amp;lt;%questions.each do |question| %&amp;gt;&lt;br /&gt;
-   &amp;lt;%if question.is_a? Question%&amp;gt;&lt;br /&gt;
-     &amp;lt;%=question.view_question_text.html_safe%&amp;gt;&lt;br /&gt;
+ &amp;lt;% for @question in questions %&amp;gt;&lt;br /&gt;
+   &amp;lt;%# E1911: Call the criterion_view partial if question is of type Criterion %&amp;gt;&lt;br /&gt;
+   &amp;lt;%if @question.is_a? Criterion %&amp;gt;&lt;br /&gt;
+         &amp;lt;%= render :partial =&amp;gt; 'criterion_view' %&amp;gt;&lt;br /&gt;
+     &amp;lt;%elsif @question.is_a? Question%&amp;gt;&lt;br /&gt;
+         &amp;lt;%= @question.view_question_text.html_safe %&amp;gt;&lt;br /&gt;
    &amp;lt;%end%&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/questionnaires/_criterion_view.html.erb -''' This partial file has the moved html code from view_question_text. Note that the &amp;quot;self.xxx&amp;quot; have been updated to &amp;quot;@question.xxx&amp;quot; as self referred to question object discussed in 1. Comment added to describe the partial file. Refer the pull request to look at the code.&lt;br /&gt;
&lt;br /&gt;
===The complete Method===&lt;br /&gt;
All the code in the model included html thus was completely removed from there. It was moved to the partial file (app/views/response/_criterion_complete.html.erb) and the necessary changes were made. Since it was all HTML code, no comments were actually required. However, we still added comments describing the partial file itself. Other comments were added whenever changes were made.&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/repsonse/response.html.erb -''' This file calls the complete method for all types of question objects and the object type takes care of invoking the right overridden method. We modified this file to call the partial instead of the complete method only for Criterion type of question objects. This view is invoked during user responds to the questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% elsif question.instance_of? Scale %&amp;gt;&lt;br /&gt;
&amp;lt;!--E1911: Replaced the call to criterion.complete method with the newly refactored partial--&amp;gt;&lt;br /&gt;
&amp;lt;%= render partial: 'criterion_complete', :locals =&amp;gt; {:question =&amp;gt; question, :count =&amp;gt; i, :answer =&amp;gt; answer, :questionnaire_min =&amp;gt; @questionnaire.min_question_score, :questionnaire_max =&amp;gt; @questionnaire.max_question_score, &lt;br /&gt;
:dropdown_or_scale =&amp;gt; @dropdown_or_scale} %&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;% elsif question.instance_of? Scale %&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/response/_criterion_complete.html.erb -''' This file has all the html code that was earlier in the complete method of the criterion model. We changed the variables from &amp;quot;self.xxx&amp;quot; to &amp;quot;question.xxx&amp;quot; because self was referring to copy of question object in this context. Apart from this we changed the code to erb format. No more changes were deemed necessary. Please refer to the pull request to refer to the changes in this file as they are pure html and really long to be put in this wiki.&lt;br /&gt;
&lt;br /&gt;
===The view_completed_question Method===&lt;br /&gt;
This method returns a constructed html string that is used to display a particular criterion question. Although this is similar to the other 3 methods, the html variable returned from this function is not directly called into a view. If that was the case, this could be simply moved into a partial as well.&lt;br /&gt;
&lt;br /&gt;
Instead, this html string is appended to another larger string variable named code in the response model, which builds the entire webpage by iterative appending. The html code for a criterion question being completed is a mere &amp;quot;part&amp;quot; of this entire string, which also includes other things such as the navbar of the page, links to the buttons, other questions, the header and the footer and such. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def add_table_rows questionnaire_max, questions, answers, code, tag_prompt_deployments = nil, current_user = nil&lt;br /&gt;
    count = 0&lt;br /&gt;
    # loop through questions so the the questions are displayed in order based on seq (sequence number)&lt;br /&gt;
    questions.each do |question|&lt;br /&gt;
      count += 1 if !question.is_a? QuestionnaireHeader and question.break_before == true&lt;br /&gt;
      answer = answers.find {|a| a.question_id == question.id }&lt;br /&gt;
      row_class = count.even? ? &amp;quot;info&amp;quot; : &amp;quot;warning&amp;quot;&lt;br /&gt;
      row_class = &amp;quot;&amp;quot; if question.is_a? QuestionnaireHeader&lt;br /&gt;
      code += '&amp;lt;tr class=&amp;quot;' + row_class + '&amp;quot;&amp;gt;&amp;lt;td&amp;gt;'&lt;br /&gt;
      if !answer.nil? or question.is_a? QuestionnaireHeader&lt;br /&gt;
        code += if question.instance_of? Criterion&lt;br /&gt;
                  #Answer Tags are enabled only for Criterion questions at the moment.&lt;br /&gt;
                  question.view_completed_question(count, answer, questionnaire_max, tag_prompt_deployments, current_user) || ''&lt;br /&gt;
                elsif question.instance_of? Scale&lt;br /&gt;
                  question.view_completed_question(count, answer, questionnaire_max) || ''&lt;br /&gt;
                else&lt;br /&gt;
                  question.view_completed_question(count, answer) || ''&lt;br /&gt;
                end&lt;br /&gt;
      end&lt;br /&gt;
      code += '&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
    code&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This &amp;quot;code&amp;quot; variable is then used to display the entire page through the view method under response.rb.&lt;br /&gt;
&lt;br /&gt;
A partial cannot be rendered halfway through the computation of &amp;quot;code&amp;quot;, neither can it be called from a model. Since code is containing the html string, and not erb, we cannot append the render partial line to the code variable as well.&lt;br /&gt;
&lt;br /&gt;
To refactor this method, we need to first refactor the entire response.rb to not append the html string for an entire webpage in a single variable, but rather use appropriate views to render the webpage.&lt;br /&gt;
&lt;br /&gt;
Refactoring an entire model would be beyond the scope of this project as the scale of the task is that of an entire project by itself.&lt;br /&gt;
&lt;br /&gt;
Thus, this method has been left untouched and still remains in criterion.rb itself.&lt;br /&gt;
&lt;br /&gt;
==Testing==&lt;br /&gt;
&lt;br /&gt;
Since our project only dealt with refactoring existing code, there was no particular need to test any specific components of the application. That being said, there were previous tests that were testing if the html variable returned by those methods was in the expected format or not.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  describe &amp;quot;#edit&amp;quot; do&lt;br /&gt;
    it &amp;quot;returns the html &amp;quot; do&lt;br /&gt;
      html = criterion.edit(0).to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;tr&amp;gt;&amp;lt;td align=\&amp;quot;center\&amp;quot;&amp;gt;&amp;lt;a rel=\&amp;quot;nofollow\&amp;quot; data-method=\&amp;quot;delete\&amp;quot; href=\&amp;quot;/questions/1\&amp;quot;&amp;gt;Remove&amp;lt;/a&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&amp;lt;input size=\&amp;quot;6\&amp;quot; value=\&amp;quot;1.0\&amp;quot; name=\&amp;quot;question[1][seq]\&amp;quot; id=\&amp;quot;question_1_seq\&amp;quot; type=\&amp;quot;text\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&amp;lt;textarea cols=\&amp;quot;50\&amp;quot; rows=\&amp;quot;1\&amp;quot; name=\&amp;quot;question[1][txt]\&amp;quot; id=\&amp;quot;question_1_txt\&amp;quot; placeholder=\&amp;quot;Edit question content here\&amp;quot;&amp;gt;test txt&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&amp;lt;input size=\&amp;quot;10\&amp;quot; disabled=\&amp;quot;disabled\&amp;quot; value=\&amp;quot;Criterion\&amp;quot; name=\&amp;quot;question[1][type]\&amp;quot; id=\&amp;quot;question_1_type\&amp;quot; type=\&amp;quot;text\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&amp;lt;input size=\&amp;quot;2\&amp;quot; value=\&amp;quot;1\&amp;quot; name=\&amp;quot;question[1][weight]\&amp;quot; id=\&amp;quot;question_1_weight\&amp;quot; type=\&amp;quot;text\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;text area size &amp;lt;input size=\&amp;quot;3\&amp;quot; value=\&amp;quot;\&amp;quot; name=\&amp;quot;question[1][size]\&amp;quot; id=\&amp;quot;question_1_size\&amp;quot; type=\&amp;quot;text\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt; max_label &amp;lt;input size=\&amp;quot;10\&amp;quot; value=\&amp;quot;\&amp;quot; name=\&amp;quot;question[1][max_label]\&amp;quot; id=\&amp;quot;question_1_max_label\&amp;quot; type=\&amp;quot;text\&amp;quot;&amp;gt;  min_label &amp;lt;input size=\&amp;quot;12\&amp;quot; value=\&amp;quot;\&amp;quot; name=\&amp;quot;question[1][min_label]\&amp;quot; id=\&amp;quot;question_1_min_label\&amp;quot; type=\&amp;quot;text\&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  describe &amp;quot;#view_question_text&amp;quot; do&lt;br /&gt;
    it &amp;quot;returns the html &amp;quot; do&lt;br /&gt;
      html = criterion.view_question_text.to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD align=\&amp;quot;left\&amp;quot;&amp;gt; test txt &amp;lt;/TD&amp;gt;&amp;lt;TD align=\&amp;quot;left\&amp;quot;&amp;gt;Criterion&amp;lt;/TD&amp;gt;&amp;lt;td align=\&amp;quot;center\&amp;quot;&amp;gt;1&amp;lt;/TD&amp;gt;&amp;lt;TD align=\&amp;quot;center\&amp;quot;&amp;gt; () 0 to 5 ()&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  describe &amp;quot;#complete&amp;quot; do&lt;br /&gt;
    it &amp;quot;returns the html &amp;quot; do&lt;br /&gt;
      html = criterion.complete(0, nil, 0, 5).to_s&lt;br /&gt;
      expect(html).to eq(&amp;quot;&amp;lt;div&amp;gt;&amp;lt;label for=\&amp;quot;responses_0\&amp;quot;&amp;gt;test txt&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Amadhus2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=E1911_Refactor_Criterion&amp;diff=122949</id>
		<title>E1911 Refactor Criterion</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=E1911_Refactor_Criterion&amp;diff=122949"/>
		<updated>2019-04-02T00:28:43Z</updated>

		<summary type="html">&lt;p&gt;Amadhus2: /* The view_completed_question Method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=E1911 Refactoring criterion.rb=&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create new assignments and customize new or existing assignments. It also allows the instructor to create a list of topics the students can sign up for. Students can form teams in Expertiza to work on various projects and assignments. Students can also peer review other students' submissions. Expertiza supports submission across various document types, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The bulk of the code in criterion is HTML. It is the violation of MVC architecture - Model should not concern itself with how the data is displayed. This code needs to be moved to a partial file, and the partial file needs to be called in all appropriate places which call the criterion’s model methods. Once the logic for the view is moved out of the model, the model should only be left with business logic. This business logic code can also be refactored. Plus there are virtually no comments, properly comment the code.&lt;br /&gt;
&lt;br /&gt;
==About Criterion.rb==&lt;br /&gt;
Criterion is one of the types of questions that can be added to a questionnaire. There are many other types of question objects like dropdown that have the implementation of similar methods. As of now, the criterion model holds 4 methods that are called from different places in the application. Each of these methods is storing a string value which contains the necessary HTML lines to display the required functionalities to the user. This string value is then returned to the calling methods from the respective views. This HTML string is then entered wherever necessary. This is ideally the exact function of a partial, and this page needs to be heavily reformatted to use partials instead of returning a string containing html code.&lt;br /&gt;
&lt;br /&gt;
===The pull request===&lt;br /&gt;
https://github.com/expertiza/expertiza/pull/1407&lt;br /&gt;
&lt;br /&gt;
===The edit method===&lt;br /&gt;
This method is one of the several other methods in other files like criterion.rb which gets called when the type of the question being created in the respective model. In the case of this problem, which deals with criterion type questions, the edit method defined in criterion.rb is called when the question.type is equal to &amp;quot;Criterion&amp;quot;. This method allows for a user to create the criterion question and enter the necessary details. This method is called only from two view files - one for creating (_questionnaire.html.erb partial file) and another for editing (edit.html.erb). Both these files are in questionnaires view. Verified this using both RubyMine and the grep command. Another interesting thing to note is the use of &amp;quot;self.&amp;quot; to get the attributes associated with question object. When we move this code to a partial, we need to change this in the erb file. The outcome of this method's refactoring will completely remove this method from the model file criterion.rb as there is no business logic involved here.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def edit(_count)&lt;br /&gt;
    html = '&amp;lt;td align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;a rel=&amp;quot;nofollow&amp;quot; data-method=&amp;quot;delete&amp;quot; href=&amp;quot;/questions/' + self.id.to_s + '&amp;quot;&amp;gt;Remove&amp;lt;/a&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;6&amp;quot; value=&amp;quot;' + self.seq.to_s + '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][seq]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_seq&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;textarea cols=&amp;quot;50&amp;quot; rows=&amp;quot;1&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][txt]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_txt&amp;quot; placeholder=&amp;quot;Edit question content here&amp;quot;&amp;gt;' + self.txt + '&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;10&amp;quot; disabled=&amp;quot;disabled&amp;quot; value=&amp;quot;' + self.type + '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][type]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_type&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;2&amp;quot; value=&amp;quot;' + self.weight.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][weight]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_weight&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;text area size &amp;lt;input size=&amp;quot;3&amp;quot; value=&amp;quot;' + self.size.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][size]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_size&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt; max_label &amp;lt;input size=&amp;quot;10&amp;quot; value=&amp;quot;' + self.max_label.to_s + '&amp;quot; name=&amp;quot;question[' + self.id.to_s&lt;br /&gt;
    html += '][max_label]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_max_label&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;  min_label &amp;lt;input size=&amp;quot;12&amp;quot; value=&amp;quot;' + self.min_label.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][min_label]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_min_label&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    safe_join([&amp;quot;&amp;lt;tr&amp;gt;&amp;quot;.html_safe, &amp;quot;&amp;lt;/tr&amp;gt;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The safe_join is later used to return the HTML string to the calling view.&lt;br /&gt;
&lt;br /&gt;
===The view_question_text method===&lt;br /&gt;
This method has the same explanation as the edit method except the fact that this method is called only during viewing of questionnaires by an instructor. We observed that this method is also called by in student_quiz view. On further analysis, we found that the student_quiz does not use criterion object and has only three options: TrueFalse, MultipleChoiceRadio and MultipleChoiceCheckbox. So no refactoring is required here. Verified this method isn't called anywhere else using RubyMine and grep command. The outcome of this method's refactoring will completely remove this method from the model file criterion.rb as there is no business logic in this method and is completely html code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def view_question_text&lt;br /&gt;
    html = '&amp;lt;TD align=&amp;quot;left&amp;quot;&amp;gt; ' + self.txt + ' &amp;lt;/TD&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;TD align=&amp;quot;left&amp;quot;&amp;gt;' + self.type + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;td align=&amp;quot;center&amp;quot;&amp;gt;' + self.weight.to_s + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    questionnaire = self.questionnaire&lt;br /&gt;
    if !self.max_label.nil? &amp;amp;&amp;amp; !self.min_label.nil?&lt;br /&gt;
      html += '&amp;lt;TD align=&amp;quot;center&amp;quot;&amp;gt; (' + self.min_label + ') ' + questionnaire.min_question_score.to_s&lt;br /&gt;
      html += ' to ' + questionnaire.max_question_score.to_s + ' (' + self.max_label + ')&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    else&lt;br /&gt;
      html += '&amp;lt;TD align=&amp;quot;center&amp;quot;&amp;gt;' + questionnaire.min_question_score.to_s + ' to ' + questionnaire.max_question_score.to_s + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    safe_join([&amp;quot;&amp;lt;TR&amp;gt;&amp;quot;.html_safe, &amp;quot;&amp;lt;/TR&amp;gt;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===The complete method===&lt;br /&gt;
&lt;br /&gt;
This method is one of the several other methods in other files like criterion.rb which gets called when the user responds to the question being created in the respective model. In the case of this problem, which deals with criterion type question responses, the complete method defined in criterion.rb is called when the question.type is equal to &amp;quot;Criterion&amp;quot;. This method allows for a user to respond to the criterion question and enter the necessary details. This method is called only from one view file i.e. response.html.erb. This file is in response view. Verified this using both RubyMine and the grep command. Unlike edit or view_question_text the self object does not refer to a global object instead it refers to a copy of the local object. So, we had passed the required object as locals to the partial, along with the parameters required by the method namely question, count, answer, questionnaire_min, questionnaire_max, dropdown_or_scale. When we move this code to a partial, we need to change this in the erb file. The outcome of this method's refactoring will completely remove this method from the model file criterion.rb as there is no business logic involved here.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def complete(count, answer = nil, questionnaire_min, questionnaire_max, dropdown_or_scale)&lt;br /&gt;
    if self.size.nil?&lt;br /&gt;
      cols = '70'&lt;br /&gt;
      rows = '1'&lt;br /&gt;
    else&lt;br /&gt;
      cols = self.size.split(',')[0]&lt;br /&gt;
      rows = self.size.split(',')[1]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    html = '&amp;lt;div&amp;gt;&amp;lt;label for=&amp;quot;responses_' + count.to_s + '&amp;quot;&amp;gt;' + self.txt + '&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;'&lt;br /&gt;
    # show advice for each criterion question&lt;br /&gt;
    question_advices = QuestionAdvice.where(question_id: self.id).sort_by(&amp;amp;:id)&lt;br /&gt;
    advice_total_length = 0&lt;br /&gt;
&lt;br /&gt;
    question_advices.each do |question_advice|&lt;br /&gt;
      advice_total_length += question_advice.advice.length if question_advice.advice &amp;amp;&amp;amp; question_advice.advice != &amp;quot;&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if !question_advices.empty? and advice_total_length &amp;gt; 0&lt;br /&gt;
      html += '&amp;lt;a id=&amp;quot;showAdivce_' + self.id.to_s + '&amp;quot; onclick=&amp;quot;showAdvice(' + self.id.to_s + ')&amp;quot;&amp;gt;Show advice&amp;lt;/a&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;script&amp;gt;'&lt;br /&gt;
      html += 'function showAdvice(i){'&lt;br /&gt;
      html += 'var element = document.getElementById(&amp;quot;showAdivce_&amp;quot; + i.toString());'&lt;br /&gt;
      html += 'var show = element.innerHTML == &amp;quot;Hide advice&amp;quot;;'&lt;br /&gt;
      html += 'if (show){'&lt;br /&gt;
      html += 'element.innerHTML=&amp;quot;Show advice&amp;quot;;'&lt;br /&gt;
      html += '}else{'&lt;br /&gt;
      html += 'element.innerHTML=&amp;quot;Hide advice&amp;quot;;}'&lt;br /&gt;
      html += 'toggleAdvice(i);}'&lt;br /&gt;
&lt;br /&gt;
      html += 'function toggleAdvice(i) {'&lt;br /&gt;
      html += 'var elem = document.getElementById(i.toString() + &amp;quot;_myDiv&amp;quot;);'&lt;br /&gt;
      html += 'if (elem.style.display == &amp;quot;none&amp;quot;) {'&lt;br /&gt;
      html += 'elem.style.display = &amp;quot;&amp;quot;;'&lt;br /&gt;
      html += '} else {'&lt;br /&gt;
      html += 'elem.style.display = &amp;quot;none&amp;quot;;}}'&lt;br /&gt;
      html += '&amp;lt;/script&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;div id=&amp;quot;' + self.id.to_s + '_myDiv&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;'&lt;br /&gt;
      # [2015-10-26] Zhewei:&lt;br /&gt;
      # best to order advices high to low, e.g., 5 to 1&lt;br /&gt;
      # each level used to be a link;&lt;br /&gt;
      # clicking on the link caused the dropbox to be filled in with the corresponding number&lt;br /&gt;
      question_advices.reverse.each_with_index do |question_advice, index|&lt;br /&gt;
        html += '&amp;lt;a id=&amp;quot;changeScore_&amp;gt;' + self.id.to_s + '&amp;quot; onclick=&amp;quot;changeScore(' + count.to_s + ',' + index.to_s + ')&amp;quot;&amp;gt;'&lt;br /&gt;
        html += (self.questionnaire.max_question_score - index).to_s + ' - ' + question_advice.advice + '&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;'&lt;br /&gt;
        html += '&amp;lt;script&amp;gt;'&lt;br /&gt;
        html += 'function changeScore(i, j) {'&lt;br /&gt;
        html += 'var elem = jQuery(&amp;quot;#responses_&amp;quot; + i.toString() + &amp;quot;_score&amp;quot;);'&lt;br /&gt;
        html += 'var opts = elem.children(&amp;quot;option&amp;quot;).length;'&lt;br /&gt;
        html += 'elem.val((' + self.questionnaire.max_question_score.to_s + ' - j).toString());}'&lt;br /&gt;
        html += '&amp;lt;/script&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;/div&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if dropdown_or_scale == 'dropdown'&lt;br /&gt;
      current_value = &amp;quot;&amp;quot;&lt;br /&gt;
      current_value += 'data-current-rating =' + answer.answer.to_s if !answer.nil?&lt;br /&gt;
      html += '&amp;lt;div&amp;gt;&amp;lt;select id=&amp;quot;responses_' + count.to_s + '_score&amp;quot; name=&amp;quot;responses[' + count.to_s + '][score]&amp;quot; class=&amp;quot;review-rating&amp;quot; ' + current_value + '&amp;gt;'&lt;br /&gt;
      html += &amp;quot;&amp;lt;option value = ''&amp;gt;--&amp;lt;/option&amp;gt;&amp;quot;&lt;br /&gt;
      questionnaire_min.upto(questionnaire_max).each do |j|&lt;br /&gt;
        html += if !answer.nil? and j == answer.answer&lt;br /&gt;
                  '&amp;lt;option value=' + j.to_s + ' selected=&amp;quot;selected&amp;quot;&amp;gt;'&lt;br /&gt;
                else&lt;br /&gt;
                  '&amp;lt;option value=' + j.to_s + '&amp;gt;'&lt;br /&gt;
                end&lt;br /&gt;
&lt;br /&gt;
        html += j.to_s&lt;br /&gt;
        if j == questionnaire_min&lt;br /&gt;
          html += &amp;quot;-&amp;quot; + self.min_label if self.min_label.present?&lt;br /&gt;
        elsif j == questionnaire_max&lt;br /&gt;
          html += &amp;quot;-&amp;quot; + self.max_label if self.max_label.present?&lt;br /&gt;
        end&lt;br /&gt;
        html += &amp;quot;&amp;lt;/option&amp;gt;&amp;quot;&lt;br /&gt;
      end&lt;br /&gt;
      html += &amp;quot;&amp;lt;/select&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;&lt;br /&gt;
      html += '&amp;lt;textarea' + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
       ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
      html += answer.comments unless answer.nil?&lt;br /&gt;
      html += '&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
    elsif dropdown_or_scale == 'scale'&lt;br /&gt;
      html += '&amp;lt;input id=&amp;quot;responses_' + count.to_s + '_score&amp;quot; name=&amp;quot;responses[' + count.to_s + '][score]&amp;quot; type=&amp;quot;hidden&amp;quot;'&lt;br /&gt;
      html += 'value=&amp;quot;' + answer.answer.to_s + '&amp;quot;' unless answer.nil?&lt;br /&gt;
      html += '&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;table&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;tr&amp;gt;&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      (questionnaire_min..questionnaire_max).each do |j|&lt;br /&gt;
        html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;label&amp;gt;' + j.to_s + '&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += if !self.min_label.nil?&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;' + self.min_label + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
              else&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
              end&lt;br /&gt;
      (questionnaire_min..questionnaire_max).each do |j|&lt;br /&gt;
        html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;input type=&amp;quot;radio&amp;quot; id=&amp;quot;' + j.to_s + '&amp;quot; value=&amp;quot;' + j.to_s + '&amp;quot; name=&amp;quot;Radio_' + self.id.to_s + '&amp;quot;'&lt;br /&gt;
        html += 'checked=&amp;quot;checked&amp;quot;' if (!answer.nil? and answer.answer == j) or (answer.nil? and questionnaire_min == j)&lt;br /&gt;
        html += '&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;script&amp;gt;jQuery(&amp;quot;input[name=Radio_' + self.id.to_s + ']:radio&amp;quot;).change(function() {'&lt;br /&gt;
      html += 'var response_score = jQuery(&amp;quot;#responses_' + count.to_s + '_score&amp;quot;);'&lt;br /&gt;
      html += 'var checked_value = jQuery(&amp;quot;input[name=Radio_' + self.id.to_s + ']:checked&amp;quot;).val();'&lt;br /&gt;
      html += 'response_score.val(checked_value);});&amp;lt;/script&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += if !self.max_label.nil?&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;' + self.max_label + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
              else&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
              end&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;textarea cols=' + cols + ' rows=' + rows + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
        ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
      html += answer.comments unless answer.nil?&lt;br /&gt;
      html += '&amp;lt;/textarea&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    end&lt;br /&gt;
    safe_join([&amp;quot;&amp;quot;.html_safe, &amp;quot;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===The view_completed_question method===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Proposed Solution==&lt;br /&gt;
All these methods contain HTML text. What we propose to do is to pick these lines of code and move them into an appropriate partial, in the required format. The next task is to find out where in the entire application do these methods get called. The multiple overriding of the method calls in this poorly structured application makes it a challenging task. These method-calls then have to be replaced with the appropriate rendering of a partial in the views. This would make the structure more MVC oriented, and help keep it clean and understandable for the next developer who accesses this file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Implementation==&lt;br /&gt;
The changes proposed above were implemented as described below.&lt;br /&gt;
&lt;br /&gt;
===The Edit Method===&lt;br /&gt;
All the code in the model was just html and thus was completely removed from there. It was moved to the partial file (views/questionnaires/_criterion_edit.html.rb) and the necessary changes were made. Since it was all HTML code, no comments were actually required. However, we still added comments describing the partial file itself. Other comments were added whenever changes were made.&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/questionnaires/edit.html.erb -''' This file calls the edit method for all types of question objects and the object type takes care of invoking the right overridden method. We modified this file to call the partial instead of edit method only for Criterion type of question objects. This view is invoked during edit on the questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% for @question in @questionnaire.questions %&amp;gt;&lt;br /&gt;
-   &amp;lt;%-# The following line call certain method of the object, which returns html string-%&amp;gt;&lt;br /&gt;
+   &amp;lt;%# E1911: Call the criterion_edit partial if question is of type Criterion -%&amp;gt;&lt;br /&gt;
+   &amp;lt;% if @question.is_a? Criterion %&amp;gt;&lt;br /&gt;
+     &amp;lt;%= render :partial =&amp;gt; 'criterion_edit' %&amp;gt;&lt;br /&gt;
+   &amp;lt;% else %&amp;gt;&lt;br /&gt;
      &amp;lt;%=@question.edit%&amp;gt;&lt;br /&gt;
+ &amp;lt;% end %&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/questionnaires/_questionnaire.html.erb -''' This partial file is called by new.html.erb when anew question is created. Same logic and changes as above.&lt;br /&gt;
&lt;br /&gt;
'''3. views/questionnaires/_criterion_edit.html.erb -''' This file has all the html code that was earlier in the edit method of the criterion model. We changed the variables from &amp;quot;self.xxx&amp;quot; to &amp;quot;@question.xxx&amp;quot; because self was referring to question object in this context. Apart from this we changed the code to erb format. No more changes were deemed necessary. Please refer to the pull request to refer to the changes in this file as they are pure html and really long to be put in this wiki.&lt;br /&gt;
&lt;br /&gt;
===The view_question_text Method===&lt;br /&gt;
This method did not contain any business logic and thus all code was formatted and moved to a new partial file (views/questionnaires/_criterion_view.html.erb). Again, no comments were required due to complete html code and a comment describing the partial was added in addition to other necessary comments in other files.&lt;br /&gt;
&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/questionnaires/view.html.erb -''' Modified to invoke the partial if question is of type Criterion only. Also changed the question variable to a instance variable (question =&amp;gt; @question) to extend it's scope to the partial. This view is invoked during the view of questions in a questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- &amp;lt;%questions.each do |question| %&amp;gt;&lt;br /&gt;
-   &amp;lt;%if question.is_a? Question%&amp;gt;&lt;br /&gt;
-     &amp;lt;%=question.view_question_text.html_safe%&amp;gt;&lt;br /&gt;
+ &amp;lt;% for @question in questions %&amp;gt;&lt;br /&gt;
+   &amp;lt;%# E1911: Call the criterion_view partial if question is of type Criterion %&amp;gt;&lt;br /&gt;
+   &amp;lt;%if @question.is_a? Criterion %&amp;gt;&lt;br /&gt;
+         &amp;lt;%= render :partial =&amp;gt; 'criterion_view' %&amp;gt;&lt;br /&gt;
+     &amp;lt;%elsif @question.is_a? Question%&amp;gt;&lt;br /&gt;
+         &amp;lt;%= @question.view_question_text.html_safe %&amp;gt;&lt;br /&gt;
    &amp;lt;%end%&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/questionnaires/_criterion_view.html.erb -''' This partial file has the moved html code from view_question_text. Note that the &amp;quot;self.xxx&amp;quot; have been updated to &amp;quot;@question.xxx&amp;quot; as self referred to question object discussed in 1. Comment added to describe the partial file. Refer the pull request to look at the code.&lt;br /&gt;
&lt;br /&gt;
===The complete Method===&lt;br /&gt;
All the code in the model included html thus was completely removed from there. It was moved to the partial file (app/views/response/_criterion_complete.html.erb) and the necessary changes were made. Since it was all HTML code, no comments were actually required. However, we still added comments describing the partial file itself. Other comments were added whenever changes were made.&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/repsonse/response.html.erb -''' This file calls the complete method for all types of question objects and the object type takes care of invoking the right overridden method. We modified this file to call the partial instead of the complete method only for Criterion type of question objects. This view is invoked during user responds to the questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% elsif question.instance_of? Scale %&amp;gt;&lt;br /&gt;
&amp;lt;!--E1911: Replaced the call to criterion.complete method with the newly refactored partial--&amp;gt;&lt;br /&gt;
&amp;lt;%= render partial: 'criterion_complete', :locals =&amp;gt; {:question =&amp;gt; question, :count =&amp;gt; i, :answer =&amp;gt; answer, :questionnaire_min =&amp;gt; @questionnaire.min_question_score, :questionnaire_max =&amp;gt; @questionnaire.max_question_score, &lt;br /&gt;
:dropdown_or_scale =&amp;gt; @dropdown_or_scale} %&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;% elsif question.instance_of? Scale %&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/response/_criterion_complete.html.erb -''' This file has all the html code that was earlier in the complete method of the criterion model. We changed the variables from &amp;quot;self.xxx&amp;quot; to &amp;quot;question.xxx&amp;quot; because self was referring to copy of question object in this context. Apart from this we changed the code to erb format. No more changes were deemed necessary. Please refer to the pull request to refer to the changes in this file as they are pure html and really long to be put in this wiki.&lt;br /&gt;
&lt;br /&gt;
===The view_completed_question Method===&lt;br /&gt;
This method returns a constructed html string that is used to display a particular criterion question. Although this is similar to the other 3 methods, the html variable returned from this function is not directly called into a view. If that was the case, this could be simply moved into a partial as well.&lt;br /&gt;
&lt;br /&gt;
Instead, this html string is appended to another larger string variable named code in the response model, which builds the entire webpage by iterative appending. The html code for a criterion question being completed is a mere &amp;quot;part&amp;quot; of this entire string, which also includes other things such as the navbar of the page, links to the buttons, other questions, the header and the footer and such. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def add_table_rows questionnaire_max, questions, answers, code, tag_prompt_deployments = nil, current_user = nil&lt;br /&gt;
    count = 0&lt;br /&gt;
    # loop through questions so the the questions are displayed in order based on seq (sequence number)&lt;br /&gt;
    questions.each do |question|&lt;br /&gt;
      count += 1 if !question.is_a? QuestionnaireHeader and question.break_before == true&lt;br /&gt;
      answer = answers.find {|a| a.question_id == question.id }&lt;br /&gt;
      row_class = count.even? ? &amp;quot;info&amp;quot; : &amp;quot;warning&amp;quot;&lt;br /&gt;
      row_class = &amp;quot;&amp;quot; if question.is_a? QuestionnaireHeader&lt;br /&gt;
      code += '&amp;lt;tr class=&amp;quot;' + row_class + '&amp;quot;&amp;gt;&amp;lt;td&amp;gt;'&lt;br /&gt;
      if !answer.nil? or question.is_a? QuestionnaireHeader&lt;br /&gt;
        code += if question.instance_of? Criterion&lt;br /&gt;
                  #Answer Tags are enabled only for Criterion questions at the moment.&lt;br /&gt;
                  question.view_completed_question(count, answer, questionnaire_max, tag_prompt_deployments, current_user) || ''&lt;br /&gt;
                elsif question.instance_of? Scale&lt;br /&gt;
                  question.view_completed_question(count, answer, questionnaire_max) || ''&lt;br /&gt;
                else&lt;br /&gt;
                  question.view_completed_question(count, answer) || ''&lt;br /&gt;
                end&lt;br /&gt;
      end&lt;br /&gt;
      code += '&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
    code&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This &amp;quot;code&amp;quot; variable is then used to display the entire page through the view method under response.rb.&lt;br /&gt;
&lt;br /&gt;
A partial cannot be rendered halfway through the computation of &amp;quot;code&amp;quot;, neither can it be called from a model. Since code is containing the html string, and not erb, we cannot append the render partial line to the code variable as well.&lt;br /&gt;
&lt;br /&gt;
To refactor this method, we need to first refactor the entire response.rb to not append the html string for an entire webpage in a single variable, but rather use appropriate views to render the webpage.&lt;br /&gt;
&lt;br /&gt;
Refactoring an entire model would be beyond the scope of this project as the scale of the task is that of an entire project by itself.&lt;br /&gt;
&lt;br /&gt;
Thus, this method has been left untouched and still remains in criterion.rb itself.&lt;br /&gt;
&lt;br /&gt;
==Testing==&lt;/div&gt;</summary>
		<author><name>Amadhus2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=E1911_Refactor_Criterion&amp;diff=122948</id>
		<title>E1911 Refactor Criterion</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=E1911_Refactor_Criterion&amp;diff=122948"/>
		<updated>2019-04-02T00:28:04Z</updated>

		<summary type="html">&lt;p&gt;Amadhus2: /* The view_completed_question Method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=E1911 Refactoring criterion.rb=&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create new assignments and customize new or existing assignments. It also allows the instructor to create a list of topics the students can sign up for. Students can form teams in Expertiza to work on various projects and assignments. Students can also peer review other students' submissions. Expertiza supports submission across various document types, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The bulk of the code in criterion is HTML. It is the violation of MVC architecture - Model should not concern itself with how the data is displayed. This code needs to be moved to a partial file, and the partial file needs to be called in all appropriate places which call the criterion’s model methods. Once the logic for the view is moved out of the model, the model should only be left with business logic. This business logic code can also be refactored. Plus there are virtually no comments, properly comment the code.&lt;br /&gt;
&lt;br /&gt;
==About Criterion.rb==&lt;br /&gt;
Criterion is one of the types of questions that can be added to a questionnaire. There are many other types of question objects like dropdown that have the implementation of similar methods. As of now, the criterion model holds 4 methods that are called from different places in the application. Each of these methods is storing a string value which contains the necessary HTML lines to display the required functionalities to the user. This string value is then returned to the calling methods from the respective views. This HTML string is then entered wherever necessary. This is ideally the exact function of a partial, and this page needs to be heavily reformatted to use partials instead of returning a string containing html code.&lt;br /&gt;
&lt;br /&gt;
===The pull request===&lt;br /&gt;
https://github.com/expertiza/expertiza/pull/1407&lt;br /&gt;
&lt;br /&gt;
===The edit method===&lt;br /&gt;
This method is one of the several other methods in other files like criterion.rb which gets called when the type of the question being created in the respective model. In the case of this problem, which deals with criterion type questions, the edit method defined in criterion.rb is called when the question.type is equal to &amp;quot;Criterion&amp;quot;. This method allows for a user to create the criterion question and enter the necessary details. This method is called only from two view files - one for creating (_questionnaire.html.erb partial file) and another for editing (edit.html.erb). Both these files are in questionnaires view. Verified this using both RubyMine and the grep command. Another interesting thing to note is the use of &amp;quot;self.&amp;quot; to get the attributes associated with question object. When we move this code to a partial, we need to change this in the erb file. The outcome of this method's refactoring will completely remove this method from the model file criterion.rb as there is no business logic involved here.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def edit(_count)&lt;br /&gt;
    html = '&amp;lt;td align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;a rel=&amp;quot;nofollow&amp;quot; data-method=&amp;quot;delete&amp;quot; href=&amp;quot;/questions/' + self.id.to_s + '&amp;quot;&amp;gt;Remove&amp;lt;/a&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;6&amp;quot; value=&amp;quot;' + self.seq.to_s + '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][seq]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_seq&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;textarea cols=&amp;quot;50&amp;quot; rows=&amp;quot;1&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][txt]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_txt&amp;quot; placeholder=&amp;quot;Edit question content here&amp;quot;&amp;gt;' + self.txt + '&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;10&amp;quot; disabled=&amp;quot;disabled&amp;quot; value=&amp;quot;' + self.type + '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][type]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_type&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;2&amp;quot; value=&amp;quot;' + self.weight.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][weight]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_weight&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;text area size &amp;lt;input size=&amp;quot;3&amp;quot; value=&amp;quot;' + self.size.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][size]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_size&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt; max_label &amp;lt;input size=&amp;quot;10&amp;quot; value=&amp;quot;' + self.max_label.to_s + '&amp;quot; name=&amp;quot;question[' + self.id.to_s&lt;br /&gt;
    html += '][max_label]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_max_label&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;  min_label &amp;lt;input size=&amp;quot;12&amp;quot; value=&amp;quot;' + self.min_label.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][min_label]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_min_label&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    safe_join([&amp;quot;&amp;lt;tr&amp;gt;&amp;quot;.html_safe, &amp;quot;&amp;lt;/tr&amp;gt;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The safe_join is later used to return the HTML string to the calling view.&lt;br /&gt;
&lt;br /&gt;
===The view_question_text method===&lt;br /&gt;
This method has the same explanation as the edit method except the fact that this method is called only during viewing of questionnaires by an instructor. We observed that this method is also called by in student_quiz view. On further analysis, we found that the student_quiz does not use criterion object and has only three options: TrueFalse, MultipleChoiceRadio and MultipleChoiceCheckbox. So no refactoring is required here. Verified this method isn't called anywhere else using RubyMine and grep command. The outcome of this method's refactoring will completely remove this method from the model file criterion.rb as there is no business logic in this method and is completely html code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def view_question_text&lt;br /&gt;
    html = '&amp;lt;TD align=&amp;quot;left&amp;quot;&amp;gt; ' + self.txt + ' &amp;lt;/TD&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;TD align=&amp;quot;left&amp;quot;&amp;gt;' + self.type + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;td align=&amp;quot;center&amp;quot;&amp;gt;' + self.weight.to_s + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    questionnaire = self.questionnaire&lt;br /&gt;
    if !self.max_label.nil? &amp;amp;&amp;amp; !self.min_label.nil?&lt;br /&gt;
      html += '&amp;lt;TD align=&amp;quot;center&amp;quot;&amp;gt; (' + self.min_label + ') ' + questionnaire.min_question_score.to_s&lt;br /&gt;
      html += ' to ' + questionnaire.max_question_score.to_s + ' (' + self.max_label + ')&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    else&lt;br /&gt;
      html += '&amp;lt;TD align=&amp;quot;center&amp;quot;&amp;gt;' + questionnaire.min_question_score.to_s + ' to ' + questionnaire.max_question_score.to_s + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    safe_join([&amp;quot;&amp;lt;TR&amp;gt;&amp;quot;.html_safe, &amp;quot;&amp;lt;/TR&amp;gt;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===The complete method===&lt;br /&gt;
&lt;br /&gt;
This method is one of the several other methods in other files like criterion.rb which gets called when the user responds to the question being created in the respective model. In the case of this problem, which deals with criterion type question responses, the complete method defined in criterion.rb is called when the question.type is equal to &amp;quot;Criterion&amp;quot;. This method allows for a user to respond to the criterion question and enter the necessary details. This method is called only from one view file i.e. response.html.erb. This file is in response view. Verified this using both RubyMine and the grep command. Unlike edit or view_question_text the self object does not refer to a global object instead it refers to a copy of the local object. So, we had passed the required object as locals to the partial, along with the parameters required by the method namely question, count, answer, questionnaire_min, questionnaire_max, dropdown_or_scale. When we move this code to a partial, we need to change this in the erb file. The outcome of this method's refactoring will completely remove this method from the model file criterion.rb as there is no business logic involved here.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def complete(count, answer = nil, questionnaire_min, questionnaire_max, dropdown_or_scale)&lt;br /&gt;
    if self.size.nil?&lt;br /&gt;
      cols = '70'&lt;br /&gt;
      rows = '1'&lt;br /&gt;
    else&lt;br /&gt;
      cols = self.size.split(',')[0]&lt;br /&gt;
      rows = self.size.split(',')[1]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    html = '&amp;lt;div&amp;gt;&amp;lt;label for=&amp;quot;responses_' + count.to_s + '&amp;quot;&amp;gt;' + self.txt + '&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;'&lt;br /&gt;
    # show advice for each criterion question&lt;br /&gt;
    question_advices = QuestionAdvice.where(question_id: self.id).sort_by(&amp;amp;:id)&lt;br /&gt;
    advice_total_length = 0&lt;br /&gt;
&lt;br /&gt;
    question_advices.each do |question_advice|&lt;br /&gt;
      advice_total_length += question_advice.advice.length if question_advice.advice &amp;amp;&amp;amp; question_advice.advice != &amp;quot;&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if !question_advices.empty? and advice_total_length &amp;gt; 0&lt;br /&gt;
      html += '&amp;lt;a id=&amp;quot;showAdivce_' + self.id.to_s + '&amp;quot; onclick=&amp;quot;showAdvice(' + self.id.to_s + ')&amp;quot;&amp;gt;Show advice&amp;lt;/a&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;script&amp;gt;'&lt;br /&gt;
      html += 'function showAdvice(i){'&lt;br /&gt;
      html += 'var element = document.getElementById(&amp;quot;showAdivce_&amp;quot; + i.toString());'&lt;br /&gt;
      html += 'var show = element.innerHTML == &amp;quot;Hide advice&amp;quot;;'&lt;br /&gt;
      html += 'if (show){'&lt;br /&gt;
      html += 'element.innerHTML=&amp;quot;Show advice&amp;quot;;'&lt;br /&gt;
      html += '}else{'&lt;br /&gt;
      html += 'element.innerHTML=&amp;quot;Hide advice&amp;quot;;}'&lt;br /&gt;
      html += 'toggleAdvice(i);}'&lt;br /&gt;
&lt;br /&gt;
      html += 'function toggleAdvice(i) {'&lt;br /&gt;
      html += 'var elem = document.getElementById(i.toString() + &amp;quot;_myDiv&amp;quot;);'&lt;br /&gt;
      html += 'if (elem.style.display == &amp;quot;none&amp;quot;) {'&lt;br /&gt;
      html += 'elem.style.display = &amp;quot;&amp;quot;;'&lt;br /&gt;
      html += '} else {'&lt;br /&gt;
      html += 'elem.style.display = &amp;quot;none&amp;quot;;}}'&lt;br /&gt;
      html += '&amp;lt;/script&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;div id=&amp;quot;' + self.id.to_s + '_myDiv&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;'&lt;br /&gt;
      # [2015-10-26] Zhewei:&lt;br /&gt;
      # best to order advices high to low, e.g., 5 to 1&lt;br /&gt;
      # each level used to be a link;&lt;br /&gt;
      # clicking on the link caused the dropbox to be filled in with the corresponding number&lt;br /&gt;
      question_advices.reverse.each_with_index do |question_advice, index|&lt;br /&gt;
        html += '&amp;lt;a id=&amp;quot;changeScore_&amp;gt;' + self.id.to_s + '&amp;quot; onclick=&amp;quot;changeScore(' + count.to_s + ',' + index.to_s + ')&amp;quot;&amp;gt;'&lt;br /&gt;
        html += (self.questionnaire.max_question_score - index).to_s + ' - ' + question_advice.advice + '&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;'&lt;br /&gt;
        html += '&amp;lt;script&amp;gt;'&lt;br /&gt;
        html += 'function changeScore(i, j) {'&lt;br /&gt;
        html += 'var elem = jQuery(&amp;quot;#responses_&amp;quot; + i.toString() + &amp;quot;_score&amp;quot;);'&lt;br /&gt;
        html += 'var opts = elem.children(&amp;quot;option&amp;quot;).length;'&lt;br /&gt;
        html += 'elem.val((' + self.questionnaire.max_question_score.to_s + ' - j).toString());}'&lt;br /&gt;
        html += '&amp;lt;/script&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;/div&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if dropdown_or_scale == 'dropdown'&lt;br /&gt;
      current_value = &amp;quot;&amp;quot;&lt;br /&gt;
      current_value += 'data-current-rating =' + answer.answer.to_s if !answer.nil?&lt;br /&gt;
      html += '&amp;lt;div&amp;gt;&amp;lt;select id=&amp;quot;responses_' + count.to_s + '_score&amp;quot; name=&amp;quot;responses[' + count.to_s + '][score]&amp;quot; class=&amp;quot;review-rating&amp;quot; ' + current_value + '&amp;gt;'&lt;br /&gt;
      html += &amp;quot;&amp;lt;option value = ''&amp;gt;--&amp;lt;/option&amp;gt;&amp;quot;&lt;br /&gt;
      questionnaire_min.upto(questionnaire_max).each do |j|&lt;br /&gt;
        html += if !answer.nil? and j == answer.answer&lt;br /&gt;
                  '&amp;lt;option value=' + j.to_s + ' selected=&amp;quot;selected&amp;quot;&amp;gt;'&lt;br /&gt;
                else&lt;br /&gt;
                  '&amp;lt;option value=' + j.to_s + '&amp;gt;'&lt;br /&gt;
                end&lt;br /&gt;
&lt;br /&gt;
        html += j.to_s&lt;br /&gt;
        if j == questionnaire_min&lt;br /&gt;
          html += &amp;quot;-&amp;quot; + self.min_label if self.min_label.present?&lt;br /&gt;
        elsif j == questionnaire_max&lt;br /&gt;
          html += &amp;quot;-&amp;quot; + self.max_label if self.max_label.present?&lt;br /&gt;
        end&lt;br /&gt;
        html += &amp;quot;&amp;lt;/option&amp;gt;&amp;quot;&lt;br /&gt;
      end&lt;br /&gt;
      html += &amp;quot;&amp;lt;/select&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;&lt;br /&gt;
      html += '&amp;lt;textarea' + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
       ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
      html += answer.comments unless answer.nil?&lt;br /&gt;
      html += '&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
    elsif dropdown_or_scale == 'scale'&lt;br /&gt;
      html += '&amp;lt;input id=&amp;quot;responses_' + count.to_s + '_score&amp;quot; name=&amp;quot;responses[' + count.to_s + '][score]&amp;quot; type=&amp;quot;hidden&amp;quot;'&lt;br /&gt;
      html += 'value=&amp;quot;' + answer.answer.to_s + '&amp;quot;' unless answer.nil?&lt;br /&gt;
      html += '&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;table&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;tr&amp;gt;&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      (questionnaire_min..questionnaire_max).each do |j|&lt;br /&gt;
        html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;label&amp;gt;' + j.to_s + '&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += if !self.min_label.nil?&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;' + self.min_label + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
              else&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
              end&lt;br /&gt;
      (questionnaire_min..questionnaire_max).each do |j|&lt;br /&gt;
        html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;input type=&amp;quot;radio&amp;quot; id=&amp;quot;' + j.to_s + '&amp;quot; value=&amp;quot;' + j.to_s + '&amp;quot; name=&amp;quot;Radio_' + self.id.to_s + '&amp;quot;'&lt;br /&gt;
        html += 'checked=&amp;quot;checked&amp;quot;' if (!answer.nil? and answer.answer == j) or (answer.nil? and questionnaire_min == j)&lt;br /&gt;
        html += '&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;script&amp;gt;jQuery(&amp;quot;input[name=Radio_' + self.id.to_s + ']:radio&amp;quot;).change(function() {'&lt;br /&gt;
      html += 'var response_score = jQuery(&amp;quot;#responses_' + count.to_s + '_score&amp;quot;);'&lt;br /&gt;
      html += 'var checked_value = jQuery(&amp;quot;input[name=Radio_' + self.id.to_s + ']:checked&amp;quot;).val();'&lt;br /&gt;
      html += 'response_score.val(checked_value);});&amp;lt;/script&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += if !self.max_label.nil?&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;' + self.max_label + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
              else&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
              end&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;textarea cols=' + cols + ' rows=' + rows + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
        ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
      html += answer.comments unless answer.nil?&lt;br /&gt;
      html += '&amp;lt;/textarea&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    end&lt;br /&gt;
    safe_join([&amp;quot;&amp;quot;.html_safe, &amp;quot;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===The view_completed_question method===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Proposed Solution==&lt;br /&gt;
All these methods contain HTML text. What we propose to do is to pick these lines of code and move them into an appropriate partial, in the required format. The next task is to find out where in the entire application do these methods get called. The multiple overriding of the method calls in this poorly structured application makes it a challenging task. These method-calls then have to be replaced with the appropriate rendering of a partial in the views. This would make the structure more MVC oriented, and help keep it clean and understandable for the next developer who accesses this file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Implementation==&lt;br /&gt;
The changes proposed above were implemented as described below.&lt;br /&gt;
&lt;br /&gt;
===The Edit Method===&lt;br /&gt;
All the code in the model was just html and thus was completely removed from there. It was moved to the partial file (views/questionnaires/_criterion_edit.html.rb) and the necessary changes were made. Since it was all HTML code, no comments were actually required. However, we still added comments describing the partial file itself. Other comments were added whenever changes were made.&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/questionnaires/edit.html.erb -''' This file calls the edit method for all types of question objects and the object type takes care of invoking the right overridden method. We modified this file to call the partial instead of edit method only for Criterion type of question objects. This view is invoked during edit on the questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% for @question in @questionnaire.questions %&amp;gt;&lt;br /&gt;
-   &amp;lt;%-# The following line call certain method of the object, which returns html string-%&amp;gt;&lt;br /&gt;
+   &amp;lt;%# E1911: Call the criterion_edit partial if question is of type Criterion -%&amp;gt;&lt;br /&gt;
+   &amp;lt;% if @question.is_a? Criterion %&amp;gt;&lt;br /&gt;
+     &amp;lt;%= render :partial =&amp;gt; 'criterion_edit' %&amp;gt;&lt;br /&gt;
+   &amp;lt;% else %&amp;gt;&lt;br /&gt;
      &amp;lt;%=@question.edit%&amp;gt;&lt;br /&gt;
+ &amp;lt;% end %&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/questionnaires/_questionnaire.html.erb -''' This partial file is called by new.html.erb when anew question is created. Same logic and changes as above.&lt;br /&gt;
&lt;br /&gt;
'''3. views/questionnaires/_criterion_edit.html.erb -''' This file has all the html code that was earlier in the edit method of the criterion model. We changed the variables from &amp;quot;self.xxx&amp;quot; to &amp;quot;@question.xxx&amp;quot; because self was referring to question object in this context. Apart from this we changed the code to erb format. No more changes were deemed necessary. Please refer to the pull request to refer to the changes in this file as they are pure html and really long to be put in this wiki.&lt;br /&gt;
&lt;br /&gt;
===The view_question_text Method===&lt;br /&gt;
This method did not contain any business logic and thus all code was formatted and moved to a new partial file (views/questionnaires/_criterion_view.html.erb). Again, no comments were required due to complete html code and a comment describing the partial was added in addition to other necessary comments in other files.&lt;br /&gt;
&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/questionnaires/view.html.erb -''' Modified to invoke the partial if question is of type Criterion only. Also changed the question variable to a instance variable (question =&amp;gt; @question) to extend it's scope to the partial. This view is invoked during the view of questions in a questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- &amp;lt;%questions.each do |question| %&amp;gt;&lt;br /&gt;
-   &amp;lt;%if question.is_a? Question%&amp;gt;&lt;br /&gt;
-     &amp;lt;%=question.view_question_text.html_safe%&amp;gt;&lt;br /&gt;
+ &amp;lt;% for @question in questions %&amp;gt;&lt;br /&gt;
+   &amp;lt;%# E1911: Call the criterion_view partial if question is of type Criterion %&amp;gt;&lt;br /&gt;
+   &amp;lt;%if @question.is_a? Criterion %&amp;gt;&lt;br /&gt;
+         &amp;lt;%= render :partial =&amp;gt; 'criterion_view' %&amp;gt;&lt;br /&gt;
+     &amp;lt;%elsif @question.is_a? Question%&amp;gt;&lt;br /&gt;
+         &amp;lt;%= @question.view_question_text.html_safe %&amp;gt;&lt;br /&gt;
    &amp;lt;%end%&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/questionnaires/_criterion_view.html.erb -''' This partial file has the moved html code from view_question_text. Note that the &amp;quot;self.xxx&amp;quot; have been updated to &amp;quot;@question.xxx&amp;quot; as self referred to question object discussed in 1. Comment added to describe the partial file. Refer the pull request to look at the code.&lt;br /&gt;
&lt;br /&gt;
===The complete Method===&lt;br /&gt;
All the code in the model included html thus was completely removed from there. It was moved to the partial file (app/views/response/_criterion_complete.html.erb) and the necessary changes were made. Since it was all HTML code, no comments were actually required. However, we still added comments describing the partial file itself. Other comments were added whenever changes were made.&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/repsonse/response.html.erb -''' This file calls the complete method for all types of question objects and the object type takes care of invoking the right overridden method. We modified this file to call the partial instead of the complete method only for Criterion type of question objects. This view is invoked during user responds to the questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% elsif question.instance_of? Scale %&amp;gt;&lt;br /&gt;
&amp;lt;!--E1911: Replaced the call to criterion.complete method with the newly refactored partial--&amp;gt;&lt;br /&gt;
&amp;lt;%= render partial: 'criterion_complete', :locals =&amp;gt; {:question =&amp;gt; question, :count =&amp;gt; i, :answer =&amp;gt; answer, :questionnaire_min =&amp;gt; @questionnaire.min_question_score, :questionnaire_max =&amp;gt; @questionnaire.max_question_score, &lt;br /&gt;
:dropdown_or_scale =&amp;gt; @dropdown_or_scale} %&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;% elsif question.instance_of? Scale %&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/response/_criterion_complete.html.erb -''' This file has all the html code that was earlier in the complete method of the criterion model. We changed the variables from &amp;quot;self.xxx&amp;quot; to &amp;quot;question.xxx&amp;quot; because self was referring to copy of question object in this context. Apart from this we changed the code to erb format. No more changes were deemed necessary. Please refer to the pull request to refer to the changes in this file as they are pure html and really long to be put in this wiki.&lt;br /&gt;
&lt;br /&gt;
===The view_completed_question Method===&lt;br /&gt;
This method returns a constructed html string that is used to display a particular criterion question. Although this is similar to the other 3 methods, the html variable returned from this function is not directly called into a view. If that was the case, this could be simply moved into a partial as well.&lt;br /&gt;
&lt;br /&gt;
Instead, this html string is appended to another larger string variable named code in the response model, which builds the entire webpage by iterative appending. The html code for a criterion question being completed is a mere &amp;quot;part&amp;quot; of this entire string, which also includes other things such as the navbar of the page, links to the buttons, other questions, the header and the footer and such. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def add_table_rows questionnaire_max, questions, answers, code, tag_prompt_deployments = nil, current_user = nil&lt;br /&gt;
    count = 0&lt;br /&gt;
    # loop through questions so the the questions are displayed in order based on seq (sequence number)&lt;br /&gt;
    questions.each do |question|&lt;br /&gt;
      count += 1 if !question.is_a? QuestionnaireHeader and question.break_before == true&lt;br /&gt;
      answer = answers.find {|a| a.question_id == question.id }&lt;br /&gt;
      row_class = count.even? ? &amp;quot;info&amp;quot; : &amp;quot;warning&amp;quot;&lt;br /&gt;
      row_class = &amp;quot;&amp;quot; if question.is_a? QuestionnaireHeader&lt;br /&gt;
      code += '&amp;lt;tr class=&amp;quot;' + row_class + '&amp;quot;&amp;gt;&amp;lt;td&amp;gt;'&lt;br /&gt;
      if !answer.nil? or question.is_a? QuestionnaireHeader&lt;br /&gt;
        code += if question.instance_of? Criterion&lt;br /&gt;
                  #Answer Tags are enabled only for Criterion questions at the moment.&lt;br /&gt;
                  &amp;lt;b&amp;gt;question.view_completed_question(count, answer, questionnaire_max, tag_prompt_deployments, current_user) || ''&amp;lt;/b&amp;gt;&lt;br /&gt;
                elsif question.instance_of? Scale&lt;br /&gt;
                  question.view_completed_question(count, answer, questionnaire_max) || ''&lt;br /&gt;
                else&lt;br /&gt;
                  question.view_completed_question(count, answer) || ''&lt;br /&gt;
                end&lt;br /&gt;
      end&lt;br /&gt;
      code += '&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
    code&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This &amp;quot;code&amp;quot; variable is then used to display the entire page through the view method under response.rb.&lt;br /&gt;
&lt;br /&gt;
A partial cannot be rendered halfway through the computation of &amp;quot;code&amp;quot;, neither can it be called from a model. Since code is containing the html string, and not erb, we cannot append the render partial line to the code variable as well.&lt;br /&gt;
&lt;br /&gt;
To refactor this method, we need to first refactor the entire response.rb to not append the html string for an entire webpage in a single variable, but rather use appropriate views to render the webpage.&lt;br /&gt;
&lt;br /&gt;
Refactoring an entire model would be beyond the scope of this project as the scale of the task is that of an entire project by itself.&lt;br /&gt;
&lt;br /&gt;
Thus, this method has been left untouched and still remains in criterion.rb itself.&lt;br /&gt;
&lt;br /&gt;
==Testing==&lt;/div&gt;</summary>
		<author><name>Amadhus2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=E1911_Refactor_Criterion&amp;diff=122947</id>
		<title>E1911 Refactor Criterion</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=E1911_Refactor_Criterion&amp;diff=122947"/>
		<updated>2019-04-02T00:27:26Z</updated>

		<summary type="html">&lt;p&gt;Amadhus2: /* E1911 Refactoring criterion.rb */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=E1911 Refactoring criterion.rb=&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create new assignments and customize new or existing assignments. It also allows the instructor to create a list of topics the students can sign up for. Students can form teams in Expertiza to work on various projects and assignments. Students can also peer review other students' submissions. Expertiza supports submission across various document types, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The bulk of the code in criterion is HTML. It is the violation of MVC architecture - Model should not concern itself with how the data is displayed. This code needs to be moved to a partial file, and the partial file needs to be called in all appropriate places which call the criterion’s model methods. Once the logic for the view is moved out of the model, the model should only be left with business logic. This business logic code can also be refactored. Plus there are virtually no comments, properly comment the code.&lt;br /&gt;
&lt;br /&gt;
==About Criterion.rb==&lt;br /&gt;
Criterion is one of the types of questions that can be added to a questionnaire. There are many other types of question objects like dropdown that have the implementation of similar methods. As of now, the criterion model holds 4 methods that are called from different places in the application. Each of these methods is storing a string value which contains the necessary HTML lines to display the required functionalities to the user. This string value is then returned to the calling methods from the respective views. This HTML string is then entered wherever necessary. This is ideally the exact function of a partial, and this page needs to be heavily reformatted to use partials instead of returning a string containing html code.&lt;br /&gt;
&lt;br /&gt;
===The pull request===&lt;br /&gt;
https://github.com/expertiza/expertiza/pull/1407&lt;br /&gt;
&lt;br /&gt;
===The edit method===&lt;br /&gt;
This method is one of the several other methods in other files like criterion.rb which gets called when the type of the question being created in the respective model. In the case of this problem, which deals with criterion type questions, the edit method defined in criterion.rb is called when the question.type is equal to &amp;quot;Criterion&amp;quot;. This method allows for a user to create the criterion question and enter the necessary details. This method is called only from two view files - one for creating (_questionnaire.html.erb partial file) and another for editing (edit.html.erb). Both these files are in questionnaires view. Verified this using both RubyMine and the grep command. Another interesting thing to note is the use of &amp;quot;self.&amp;quot; to get the attributes associated with question object. When we move this code to a partial, we need to change this in the erb file. The outcome of this method's refactoring will completely remove this method from the model file criterion.rb as there is no business logic involved here.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def edit(_count)&lt;br /&gt;
    html = '&amp;lt;td align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;a rel=&amp;quot;nofollow&amp;quot; data-method=&amp;quot;delete&amp;quot; href=&amp;quot;/questions/' + self.id.to_s + '&amp;quot;&amp;gt;Remove&amp;lt;/a&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;6&amp;quot; value=&amp;quot;' + self.seq.to_s + '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][seq]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_seq&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;textarea cols=&amp;quot;50&amp;quot; rows=&amp;quot;1&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][txt]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_txt&amp;quot; placeholder=&amp;quot;Edit question content here&amp;quot;&amp;gt;' + self.txt + '&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;10&amp;quot; disabled=&amp;quot;disabled&amp;quot; value=&amp;quot;' + self.type + '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][type]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_type&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;2&amp;quot; value=&amp;quot;' + self.weight.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][weight]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_weight&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;text area size &amp;lt;input size=&amp;quot;3&amp;quot; value=&amp;quot;' + self.size.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][size]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_size&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt; max_label &amp;lt;input size=&amp;quot;10&amp;quot; value=&amp;quot;' + self.max_label.to_s + '&amp;quot; name=&amp;quot;question[' + self.id.to_s&lt;br /&gt;
    html += '][max_label]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_max_label&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;  min_label &amp;lt;input size=&amp;quot;12&amp;quot; value=&amp;quot;' + self.min_label.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][min_label]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_min_label&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    safe_join([&amp;quot;&amp;lt;tr&amp;gt;&amp;quot;.html_safe, &amp;quot;&amp;lt;/tr&amp;gt;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The safe_join is later used to return the HTML string to the calling view.&lt;br /&gt;
&lt;br /&gt;
===The view_question_text method===&lt;br /&gt;
This method has the same explanation as the edit method except the fact that this method is called only during viewing of questionnaires by an instructor. We observed that this method is also called by in student_quiz view. On further analysis, we found that the student_quiz does not use criterion object and has only three options: TrueFalse, MultipleChoiceRadio and MultipleChoiceCheckbox. So no refactoring is required here. Verified this method isn't called anywhere else using RubyMine and grep command. The outcome of this method's refactoring will completely remove this method from the model file criterion.rb as there is no business logic in this method and is completely html code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def view_question_text&lt;br /&gt;
    html = '&amp;lt;TD align=&amp;quot;left&amp;quot;&amp;gt; ' + self.txt + ' &amp;lt;/TD&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;TD align=&amp;quot;left&amp;quot;&amp;gt;' + self.type + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;td align=&amp;quot;center&amp;quot;&amp;gt;' + self.weight.to_s + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    questionnaire = self.questionnaire&lt;br /&gt;
    if !self.max_label.nil? &amp;amp;&amp;amp; !self.min_label.nil?&lt;br /&gt;
      html += '&amp;lt;TD align=&amp;quot;center&amp;quot;&amp;gt; (' + self.min_label + ') ' + questionnaire.min_question_score.to_s&lt;br /&gt;
      html += ' to ' + questionnaire.max_question_score.to_s + ' (' + self.max_label + ')&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    else&lt;br /&gt;
      html += '&amp;lt;TD align=&amp;quot;center&amp;quot;&amp;gt;' + questionnaire.min_question_score.to_s + ' to ' + questionnaire.max_question_score.to_s + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    safe_join([&amp;quot;&amp;lt;TR&amp;gt;&amp;quot;.html_safe, &amp;quot;&amp;lt;/TR&amp;gt;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===The complete method===&lt;br /&gt;
&lt;br /&gt;
This method is one of the several other methods in other files like criterion.rb which gets called when the user responds to the question being created in the respective model. In the case of this problem, which deals with criterion type question responses, the complete method defined in criterion.rb is called when the question.type is equal to &amp;quot;Criterion&amp;quot;. This method allows for a user to respond to the criterion question and enter the necessary details. This method is called only from one view file i.e. response.html.erb. This file is in response view. Verified this using both RubyMine and the grep command. Unlike edit or view_question_text the self object does not refer to a global object instead it refers to a copy of the local object. So, we had passed the required object as locals to the partial, along with the parameters required by the method namely question, count, answer, questionnaire_min, questionnaire_max, dropdown_or_scale. When we move this code to a partial, we need to change this in the erb file. The outcome of this method's refactoring will completely remove this method from the model file criterion.rb as there is no business logic involved here.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def complete(count, answer = nil, questionnaire_min, questionnaire_max, dropdown_or_scale)&lt;br /&gt;
    if self.size.nil?&lt;br /&gt;
      cols = '70'&lt;br /&gt;
      rows = '1'&lt;br /&gt;
    else&lt;br /&gt;
      cols = self.size.split(',')[0]&lt;br /&gt;
      rows = self.size.split(',')[1]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    html = '&amp;lt;div&amp;gt;&amp;lt;label for=&amp;quot;responses_' + count.to_s + '&amp;quot;&amp;gt;' + self.txt + '&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;'&lt;br /&gt;
    # show advice for each criterion question&lt;br /&gt;
    question_advices = QuestionAdvice.where(question_id: self.id).sort_by(&amp;amp;:id)&lt;br /&gt;
    advice_total_length = 0&lt;br /&gt;
&lt;br /&gt;
    question_advices.each do |question_advice|&lt;br /&gt;
      advice_total_length += question_advice.advice.length if question_advice.advice &amp;amp;&amp;amp; question_advice.advice != &amp;quot;&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if !question_advices.empty? and advice_total_length &amp;gt; 0&lt;br /&gt;
      html += '&amp;lt;a id=&amp;quot;showAdivce_' + self.id.to_s + '&amp;quot; onclick=&amp;quot;showAdvice(' + self.id.to_s + ')&amp;quot;&amp;gt;Show advice&amp;lt;/a&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;script&amp;gt;'&lt;br /&gt;
      html += 'function showAdvice(i){'&lt;br /&gt;
      html += 'var element = document.getElementById(&amp;quot;showAdivce_&amp;quot; + i.toString());'&lt;br /&gt;
      html += 'var show = element.innerHTML == &amp;quot;Hide advice&amp;quot;;'&lt;br /&gt;
      html += 'if (show){'&lt;br /&gt;
      html += 'element.innerHTML=&amp;quot;Show advice&amp;quot;;'&lt;br /&gt;
      html += '}else{'&lt;br /&gt;
      html += 'element.innerHTML=&amp;quot;Hide advice&amp;quot;;}'&lt;br /&gt;
      html += 'toggleAdvice(i);}'&lt;br /&gt;
&lt;br /&gt;
      html += 'function toggleAdvice(i) {'&lt;br /&gt;
      html += 'var elem = document.getElementById(i.toString() + &amp;quot;_myDiv&amp;quot;);'&lt;br /&gt;
      html += 'if (elem.style.display == &amp;quot;none&amp;quot;) {'&lt;br /&gt;
      html += 'elem.style.display = &amp;quot;&amp;quot;;'&lt;br /&gt;
      html += '} else {'&lt;br /&gt;
      html += 'elem.style.display = &amp;quot;none&amp;quot;;}}'&lt;br /&gt;
      html += '&amp;lt;/script&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;div id=&amp;quot;' + self.id.to_s + '_myDiv&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;'&lt;br /&gt;
      # [2015-10-26] Zhewei:&lt;br /&gt;
      # best to order advices high to low, e.g., 5 to 1&lt;br /&gt;
      # each level used to be a link;&lt;br /&gt;
      # clicking on the link caused the dropbox to be filled in with the corresponding number&lt;br /&gt;
      question_advices.reverse.each_with_index do |question_advice, index|&lt;br /&gt;
        html += '&amp;lt;a id=&amp;quot;changeScore_&amp;gt;' + self.id.to_s + '&amp;quot; onclick=&amp;quot;changeScore(' + count.to_s + ',' + index.to_s + ')&amp;quot;&amp;gt;'&lt;br /&gt;
        html += (self.questionnaire.max_question_score - index).to_s + ' - ' + question_advice.advice + '&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;'&lt;br /&gt;
        html += '&amp;lt;script&amp;gt;'&lt;br /&gt;
        html += 'function changeScore(i, j) {'&lt;br /&gt;
        html += 'var elem = jQuery(&amp;quot;#responses_&amp;quot; + i.toString() + &amp;quot;_score&amp;quot;);'&lt;br /&gt;
        html += 'var opts = elem.children(&amp;quot;option&amp;quot;).length;'&lt;br /&gt;
        html += 'elem.val((' + self.questionnaire.max_question_score.to_s + ' - j).toString());}'&lt;br /&gt;
        html += '&amp;lt;/script&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;/div&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if dropdown_or_scale == 'dropdown'&lt;br /&gt;
      current_value = &amp;quot;&amp;quot;&lt;br /&gt;
      current_value += 'data-current-rating =' + answer.answer.to_s if !answer.nil?&lt;br /&gt;
      html += '&amp;lt;div&amp;gt;&amp;lt;select id=&amp;quot;responses_' + count.to_s + '_score&amp;quot; name=&amp;quot;responses[' + count.to_s + '][score]&amp;quot; class=&amp;quot;review-rating&amp;quot; ' + current_value + '&amp;gt;'&lt;br /&gt;
      html += &amp;quot;&amp;lt;option value = ''&amp;gt;--&amp;lt;/option&amp;gt;&amp;quot;&lt;br /&gt;
      questionnaire_min.upto(questionnaire_max).each do |j|&lt;br /&gt;
        html += if !answer.nil? and j == answer.answer&lt;br /&gt;
                  '&amp;lt;option value=' + j.to_s + ' selected=&amp;quot;selected&amp;quot;&amp;gt;'&lt;br /&gt;
                else&lt;br /&gt;
                  '&amp;lt;option value=' + j.to_s + '&amp;gt;'&lt;br /&gt;
                end&lt;br /&gt;
&lt;br /&gt;
        html += j.to_s&lt;br /&gt;
        if j == questionnaire_min&lt;br /&gt;
          html += &amp;quot;-&amp;quot; + self.min_label if self.min_label.present?&lt;br /&gt;
        elsif j == questionnaire_max&lt;br /&gt;
          html += &amp;quot;-&amp;quot; + self.max_label if self.max_label.present?&lt;br /&gt;
        end&lt;br /&gt;
        html += &amp;quot;&amp;lt;/option&amp;gt;&amp;quot;&lt;br /&gt;
      end&lt;br /&gt;
      html += &amp;quot;&amp;lt;/select&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;quot;&lt;br /&gt;
      html += '&amp;lt;textarea' + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
       ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
      html += answer.comments unless answer.nil?&lt;br /&gt;
      html += '&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
    elsif dropdown_or_scale == 'scale'&lt;br /&gt;
      html += '&amp;lt;input id=&amp;quot;responses_' + count.to_s + '_score&amp;quot; name=&amp;quot;responses[' + count.to_s + '][score]&amp;quot; type=&amp;quot;hidden&amp;quot;'&lt;br /&gt;
      html += 'value=&amp;quot;' + answer.answer.to_s + '&amp;quot;' unless answer.nil?&lt;br /&gt;
      html += '&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;table&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;tr&amp;gt;&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      (questionnaire_min..questionnaire_max).each do |j|&lt;br /&gt;
        html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;label&amp;gt;' + j.to_s + '&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += if !self.min_label.nil?&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;' + self.min_label + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
              else&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
              end&lt;br /&gt;
      (questionnaire_min..questionnaire_max).each do |j|&lt;br /&gt;
        html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;input type=&amp;quot;radio&amp;quot; id=&amp;quot;' + j.to_s + '&amp;quot; value=&amp;quot;' + j.to_s + '&amp;quot; name=&amp;quot;Radio_' + self.id.to_s + '&amp;quot;'&lt;br /&gt;
        html += 'checked=&amp;quot;checked&amp;quot;' if (!answer.nil? and answer.answer == j) or (answer.nil? and questionnaire_min == j)&lt;br /&gt;
        html += '&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
      end&lt;br /&gt;
      html += '&amp;lt;script&amp;gt;jQuery(&amp;quot;input[name=Radio_' + self.id.to_s + ']:radio&amp;quot;).change(function() {'&lt;br /&gt;
      html += 'var response_score = jQuery(&amp;quot;#responses_' + count.to_s + '_score&amp;quot;);'&lt;br /&gt;
      html += 'var checked_value = jQuery(&amp;quot;input[name=Radio_' + self.id.to_s + ']:checked&amp;quot;).val();'&lt;br /&gt;
      html += 'response_score.val(checked_value);});&amp;lt;/script&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
      html += if !self.max_label.nil?&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;' + self.max_label + '&amp;lt;/td&amp;gt;'&lt;br /&gt;
              else&lt;br /&gt;
                '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
              end&lt;br /&gt;
&lt;br /&gt;
      html += '&amp;lt;td width=&amp;quot;10%&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;'&lt;br /&gt;
      html += '&amp;lt;textarea cols=' + cols + ' rows=' + rows + ' id=&amp;quot;responses_' + count.to_s + '_comments&amp;quot;' \&lt;br /&gt;
        ' name=&amp;quot;responses[' + count.to_s + '][comment]&amp;quot; class=&amp;quot;tinymce&amp;quot;&amp;gt;'&lt;br /&gt;
      html += answer.comments unless answer.nil?&lt;br /&gt;
      html += '&amp;lt;/textarea&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    end&lt;br /&gt;
    safe_join([&amp;quot;&amp;quot;.html_safe, &amp;quot;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===The view_completed_question method===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Proposed Solution==&lt;br /&gt;
All these methods contain HTML text. What we propose to do is to pick these lines of code and move them into an appropriate partial, in the required format. The next task is to find out where in the entire application do these methods get called. The multiple overriding of the method calls in this poorly structured application makes it a challenging task. These method-calls then have to be replaced with the appropriate rendering of a partial in the views. This would make the structure more MVC oriented, and help keep it clean and understandable for the next developer who accesses this file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Implementation==&lt;br /&gt;
The changes proposed above were implemented as described below.&lt;br /&gt;
&lt;br /&gt;
===The Edit Method===&lt;br /&gt;
All the code in the model was just html and thus was completely removed from there. It was moved to the partial file (views/questionnaires/_criterion_edit.html.rb) and the necessary changes were made. Since it was all HTML code, no comments were actually required. However, we still added comments describing the partial file itself. Other comments were added whenever changes were made.&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/questionnaires/edit.html.erb -''' This file calls the edit method for all types of question objects and the object type takes care of invoking the right overridden method. We modified this file to call the partial instead of edit method only for Criterion type of question objects. This view is invoked during edit on the questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% for @question in @questionnaire.questions %&amp;gt;&lt;br /&gt;
-   &amp;lt;%-# The following line call certain method of the object, which returns html string-%&amp;gt;&lt;br /&gt;
+   &amp;lt;%# E1911: Call the criterion_edit partial if question is of type Criterion -%&amp;gt;&lt;br /&gt;
+   &amp;lt;% if @question.is_a? Criterion %&amp;gt;&lt;br /&gt;
+     &amp;lt;%= render :partial =&amp;gt; 'criterion_edit' %&amp;gt;&lt;br /&gt;
+   &amp;lt;% else %&amp;gt;&lt;br /&gt;
      &amp;lt;%=@question.edit%&amp;gt;&lt;br /&gt;
+ &amp;lt;% end %&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/questionnaires/_questionnaire.html.erb -''' This partial file is called by new.html.erb when anew question is created. Same logic and changes as above.&lt;br /&gt;
&lt;br /&gt;
'''3. views/questionnaires/_criterion_edit.html.erb -''' This file has all the html code that was earlier in the edit method of the criterion model. We changed the variables from &amp;quot;self.xxx&amp;quot; to &amp;quot;@question.xxx&amp;quot; because self was referring to question object in this context. Apart from this we changed the code to erb format. No more changes were deemed necessary. Please refer to the pull request to refer to the changes in this file as they are pure html and really long to be put in this wiki.&lt;br /&gt;
&lt;br /&gt;
===The view_question_text Method===&lt;br /&gt;
This method did not contain any business logic and thus all code was formatted and moved to a new partial file (views/questionnaires/_criterion_view.html.erb). Again, no comments were required due to complete html code and a comment describing the partial was added in addition to other necessary comments in other files.&lt;br /&gt;
&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/questionnaires/view.html.erb -''' Modified to invoke the partial if question is of type Criterion only. Also changed the question variable to a instance variable (question =&amp;gt; @question) to extend it's scope to the partial. This view is invoked during the view of questions in a questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- &amp;lt;%questions.each do |question| %&amp;gt;&lt;br /&gt;
-   &amp;lt;%if question.is_a? Question%&amp;gt;&lt;br /&gt;
-     &amp;lt;%=question.view_question_text.html_safe%&amp;gt;&lt;br /&gt;
+ &amp;lt;% for @question in questions %&amp;gt;&lt;br /&gt;
+   &amp;lt;%# E1911: Call the criterion_view partial if question is of type Criterion %&amp;gt;&lt;br /&gt;
+   &amp;lt;%if @question.is_a? Criterion %&amp;gt;&lt;br /&gt;
+         &amp;lt;%= render :partial =&amp;gt; 'criterion_view' %&amp;gt;&lt;br /&gt;
+     &amp;lt;%elsif @question.is_a? Question%&amp;gt;&lt;br /&gt;
+         &amp;lt;%= @question.view_question_text.html_safe %&amp;gt;&lt;br /&gt;
    &amp;lt;%end%&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/questionnaires/_criterion_view.html.erb -''' This partial file has the moved html code from view_question_text. Note that the &amp;quot;self.xxx&amp;quot; have been updated to &amp;quot;@question.xxx&amp;quot; as self referred to question object discussed in 1. Comment added to describe the partial file. Refer the pull request to look at the code.&lt;br /&gt;
&lt;br /&gt;
===The complete Method===&lt;br /&gt;
All the code in the model included html thus was completely removed from there. It was moved to the partial file (app/views/response/_criterion_complete.html.erb) and the necessary changes were made. Since it was all HTML code, no comments were actually required. However, we still added comments describing the partial file itself. Other comments were added whenever changes were made.&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/repsonse/response.html.erb -''' This file calls the complete method for all types of question objects and the object type takes care of invoking the right overridden method. We modified this file to call the partial instead of the complete method only for Criterion type of question objects. This view is invoked during user responds to the questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% elsif question.instance_of? Scale %&amp;gt;&lt;br /&gt;
&amp;lt;!--E1911: Replaced the call to criterion.complete method with the newly refactored partial--&amp;gt;&lt;br /&gt;
&amp;lt;%= render partial: 'criterion_complete', :locals =&amp;gt; {:question =&amp;gt; question, :count =&amp;gt; i, :answer =&amp;gt; answer, :questionnaire_min =&amp;gt; @questionnaire.min_question_score, :questionnaire_max =&amp;gt; @questionnaire.max_question_score, &lt;br /&gt;
:dropdown_or_scale =&amp;gt; @dropdown_or_scale} %&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;% elsif question.instance_of? Scale %&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/response/_criterion_complete.html.erb -''' This file has all the html code that was earlier in the complete method of the criterion model. We changed the variables from &amp;quot;self.xxx&amp;quot; to &amp;quot;question.xxx&amp;quot; because self was referring to copy of question object in this context. Apart from this we changed the code to erb format. No more changes were deemed necessary. Please refer to the pull request to refer to the changes in this file as they are pure html and really long to be put in this wiki.&lt;br /&gt;
&lt;br /&gt;
===The view_completed_question Method===&lt;br /&gt;
This method returns a constructed html string that is used to display a particular criterion question. Although this is similar to the other 3 methods, the html variable returned from this function is not directly called into a view. If that was the case, this could be simply moved into a partial as well.&lt;br /&gt;
&lt;br /&gt;
Instead, this html string is appended to another larger string variable named code in the response model, which builds the entire webpage by iterative appending. The html code for a criterion question being completed is a mere &amp;quot;part&amp;quot; of this entire string, which also includes other things such as the navbar of the page, links to the buttons, other questions, the header and the footer and such. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def add_table_rows questionnaire_max, questions, answers, code, tag_prompt_deployments = nil, current_user = nil&lt;br /&gt;
    count = 0&lt;br /&gt;
    # loop through questions so the the questions are displayed in order based on seq (sequence number)&lt;br /&gt;
    questions.each do |question|&lt;br /&gt;
      count += 1 if !question.is_a? QuestionnaireHeader and question.break_before == true&lt;br /&gt;
      answer = answers.find {|a| a.question_id == question.id }&lt;br /&gt;
      row_class = count.even? ? &amp;quot;info&amp;quot; : &amp;quot;warning&amp;quot;&lt;br /&gt;
      row_class = &amp;quot;&amp;quot; if question.is_a? QuestionnaireHeader&lt;br /&gt;
      code += '&amp;lt;tr class=&amp;quot;' + row_class + '&amp;quot;&amp;gt;&amp;lt;td&amp;gt;'&lt;br /&gt;
      if !answer.nil? or question.is_a? QuestionnaireHeader&lt;br /&gt;
        code += if question.instance_of? Criterion&lt;br /&gt;
                  #Answer Tags are enabled only for Criterion questions at the moment.&lt;br /&gt;
                  question.view_completed_question(count, answer, questionnaire_max, tag_prompt_deployments, current_user) || ''&lt;br /&gt;
                elsif question.instance_of? Scale&lt;br /&gt;
                  question.view_completed_question(count, answer, questionnaire_max) || ''&lt;br /&gt;
                else&lt;br /&gt;
                  question.view_completed_question(count, answer) || ''&lt;br /&gt;
                end&lt;br /&gt;
      end&lt;br /&gt;
      code += '&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
    code&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This &amp;quot;code&amp;quot; variable is then used to display the entire page through the view method under response.rb.&lt;br /&gt;
&lt;br /&gt;
A partial cannot be rendered halfway through the computation of &amp;quot;code&amp;quot;, neither can it be called from a model. Since code is containing the html string, and not erb, we cannot append the render partial line to the code variable as well.&lt;br /&gt;
&lt;br /&gt;
To refactor this method, we need to first refactor the entire response.rb to not append the html string for an entire webpage in a single variable, but rather use appropriate views to render the webpage.&lt;br /&gt;
&lt;br /&gt;
Refactoring an entire model would be beyond the scope of this project as the scale of the task is that of an entire project by itself.&lt;br /&gt;
&lt;br /&gt;
Thus, this method has been left untouched and still remains in criterion.rb itself.&lt;br /&gt;
==Testing==&lt;/div&gt;</summary>
		<author><name>Amadhus2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=E1911_Refactor_Criterion&amp;diff=122903</id>
		<title>E1911 Refactor Criterion</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=E1911_Refactor_Criterion&amp;diff=122903"/>
		<updated>2019-04-01T22:29:05Z</updated>

		<summary type="html">&lt;p&gt;Amadhus2: /* Affected View Files */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=E1911 Refactoring criterion.rb=&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create new assignments and customize new or existing assignments. It also allows the instructor to create a list of topics the students can sign up for. Students can form teams in Expertiza to work on various projects and assignments. Students can also peer review other students' submissions. Expertiza supports submission across various document types, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The bulk of the code in criterion is HTML. It is the violation of MVC architecture - Model should not concern itself with how the data is displayed. This code needs to be moved to a partial file, and the partial file needs to be called in all appropriate places which call the criterion’s model methods. Once the logic for the view is moved out of the model, the model should only be left with business logic. This business logic code can also be refactored. Plus there are virtually no comments, properly comment the code.&lt;br /&gt;
&lt;br /&gt;
==About Criterion.rb==&lt;br /&gt;
Criterion is one of the types of questions that can be added to a questionnaire. There are many other types of question objects like dropdown that have the implementation of similar methods. As of now, the criterion model holds 4 methods that are called from different places in the application. Each of these methods is storing a string value which contains the necessary HTML lines to display the required functionalities to the user. This string value is then returned to the calling methods from the respective views. This HTML string is then entered wherever necessary. This is ideally the exact function of a partial, and this page needs to be heavily reformatted to use partials instead of returning a string containing html code.&lt;br /&gt;
&lt;br /&gt;
===The pull request===&lt;br /&gt;
https://github.com/expertiza/expertiza/pull/1407&lt;br /&gt;
&lt;br /&gt;
===The edit method===&lt;br /&gt;
This method is one of the several other methods in other files like criterion.rb which gets called when the type of the question being created in the respective model. In the case of this problem, which deals with criterion type questions, the edit method defined in criterion.rb is called when the question.type is equal to &amp;quot;Criterion&amp;quot;. This method allows for a user to create the criterion question and enter the necessary details. This method is called only from two view files - one for creating (_questionnaire.html.erb partial file) and another for editing (edit.html.erb). Both these files are in questionnaires view. Verified this using both RubyMine and the grep command. Another interesting thing to note is the use of &amp;quot;self.&amp;quot; to get the attributes associated with question object. When we move this code to a partial, we need to change this in the erb file. The outcome of this method's refactoring will completely remove this method from the model file criterion.rb as there is no business logic involved here.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def edit(_count)&lt;br /&gt;
    html = '&amp;lt;td align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;a rel=&amp;quot;nofollow&amp;quot; data-method=&amp;quot;delete&amp;quot; href=&amp;quot;/questions/' + self.id.to_s + '&amp;quot;&amp;gt;Remove&amp;lt;/a&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;6&amp;quot; value=&amp;quot;' + self.seq.to_s + '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][seq]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_seq&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;textarea cols=&amp;quot;50&amp;quot; rows=&amp;quot;1&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][txt]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_txt&amp;quot; placeholder=&amp;quot;Edit question content here&amp;quot;&amp;gt;' + self.txt + '&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;10&amp;quot; disabled=&amp;quot;disabled&amp;quot; value=&amp;quot;' + self.type + '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][type]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_type&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;2&amp;quot; value=&amp;quot;' + self.weight.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][weight]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_weight&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;text area size &amp;lt;input size=&amp;quot;3&amp;quot; value=&amp;quot;' + self.size.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][size]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_size&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt; max_label &amp;lt;input size=&amp;quot;10&amp;quot; value=&amp;quot;' + self.max_label.to_s + '&amp;quot; name=&amp;quot;question[' + self.id.to_s&lt;br /&gt;
    html += '][max_label]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_max_label&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;  min_label &amp;lt;input size=&amp;quot;12&amp;quot; value=&amp;quot;' + self.min_label.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][min_label]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_min_label&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    safe_join([&amp;quot;&amp;lt;tr&amp;gt;&amp;quot;.html_safe, &amp;quot;&amp;lt;/tr&amp;gt;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The safe_join is later used to return the HTML string to the calling view.&lt;br /&gt;
&lt;br /&gt;
===The view_question_text method===&lt;br /&gt;
This method has the same explanation as the edit method except the fact that this method is called only during viewing of questionnaires by an instructor. We observed that this method is also called by in student_quiz view. On further analysis, we found that the student_quiz does not use criterion object and has only three options: TrueFalse, MultipleChoiceRadio and MultipleChoiceCheckbox. So no refactoring is required here. Verified this method isn't called anywhere else using RubyMine and grep command. The outcome of this method's refactoring will completely remove this method from the model file criterion.rb as there is no business logic in this method and is completely html code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def view_question_text&lt;br /&gt;
    html = '&amp;lt;TD align=&amp;quot;left&amp;quot;&amp;gt; ' + self.txt + ' &amp;lt;/TD&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;TD align=&amp;quot;left&amp;quot;&amp;gt;' + self.type + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;td align=&amp;quot;center&amp;quot;&amp;gt;' + self.weight.to_s + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    questionnaire = self.questionnaire&lt;br /&gt;
    if !self.max_label.nil? &amp;amp;&amp;amp; !self.min_label.nil?&lt;br /&gt;
      html += '&amp;lt;TD align=&amp;quot;center&amp;quot;&amp;gt; (' + self.min_label + ') ' + questionnaire.min_question_score.to_s&lt;br /&gt;
      html += ' to ' + questionnaire.max_question_score.to_s + ' (' + self.max_label + ')&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    else&lt;br /&gt;
      html += '&amp;lt;TD align=&amp;quot;center&amp;quot;&amp;gt;' + questionnaire.min_question_score.to_s + ' to ' + questionnaire.max_question_score.to_s + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    safe_join([&amp;quot;&amp;lt;TR&amp;gt;&amp;quot;.html_safe, &amp;quot;&amp;lt;/TR&amp;gt;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===The complete method===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===The view_completed_question method===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Proposed Solution==&lt;br /&gt;
All these methods contain HTML text. What we propose to do is to pick these lines of code and move them into an appropriate partial, in the required format. The next task is to find out where in the entire application do these methods get called. The multiple overriding of the method calls in this poorly structured application makes it a challenging task. These method-calls then have to be replaced with the appropriate rendering of a partial in the views. This would make the structure more MVC oriented, and help keep it clean and understandable for the next developer who accesses this file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Implementation==&lt;br /&gt;
The changes proposed above were implemented as described below.&lt;br /&gt;
&lt;br /&gt;
===The Edit Method===&lt;br /&gt;
All the code in the model was just html and thus was completely removed from there. It was moved to the partial file (views/questionnaires/_criterion_edit.html.rb) and the necessary changes were made. Since it was all HTML code, no comments were actually required. However, we still added comments describing the partial file itself. Other comments were added whenever changes were made.&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/questionnaires/edit.html.erb -''' This file calls the edit method for all types of question objects and the object type takes care of invoking the right overridden method. We modified this file to call the partial instead of edit method only for Criterion type of question objects. This view is invoked during edit on the questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% for @question in @questionnaire.questions %&amp;gt;&lt;br /&gt;
-   &amp;lt;%-# The following line call certain method of the object, which returns html string-%&amp;gt;&lt;br /&gt;
+   &amp;lt;%# E1911: Call the criterion_edit partial if question is of type Criterion -%&amp;gt;&lt;br /&gt;
+   &amp;lt;% if @question.is_a? Criterion %&amp;gt;&lt;br /&gt;
+     &amp;lt;%= render :partial =&amp;gt; 'criterion_edit' %&amp;gt;&lt;br /&gt;
+   &amp;lt;% else %&amp;gt;&lt;br /&gt;
      &amp;lt;%=@question.edit%&amp;gt;&lt;br /&gt;
+ &amp;lt;% end %&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/questionnaires/_questionnaire.html.erb -''' This partial file is called by new.html.erb when anew question is created. Same logic and changes as above.&lt;br /&gt;
'''3. views/questionnaires/_criterion_edit.html.erb -''' This file has all the html code that was earlier in the edit method of the criterion model. We changed the variables from &amp;quot;self.xxx&amp;quot; to &amp;quot;@question.xxx&amp;quot; because self was referring to question object in this context. Apart from this we changed the code to erb format. No more changes were deemed necessary. Please refer to the pull request to refer to the changes in this file as they are pure html and really long to be put in this wiki.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===The view_question_text Method===&lt;br /&gt;
This method did not contain any business logic and thus all code was formatted and moved to a new partial file (views/questionnaires/_criterion_view.html.erb). Again, no comments were required due to complete html code and a comment describing the partial was added in addition to other necessary comments in other files.&lt;br /&gt;
&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/questionnaires/view.html.erb -''' Modified to invoke the partial if question is of type Criterion only. Also changed the question variable to a instance variable (question =&amp;gt; @question) to extend it's scope to the partial. This view is invoked during the view of questions in a questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- &amp;lt;%questions.each do |question| %&amp;gt;&lt;br /&gt;
-   &amp;lt;%if question.is_a? Question%&amp;gt;&lt;br /&gt;
-     &amp;lt;%=question.view_question_text.html_safe%&amp;gt;&lt;br /&gt;
+ &amp;lt;% for @question in questions %&amp;gt;&lt;br /&gt;
+   &amp;lt;%# E1911: Call the criterion_view partial if question is of type Criterion %&amp;gt;&lt;br /&gt;
+   &amp;lt;%if @question.is_a? Criterion %&amp;gt;&lt;br /&gt;
+         &amp;lt;%= render :partial =&amp;gt; 'criterion_view' %&amp;gt;&lt;br /&gt;
+     &amp;lt;%elsif @question.is_a? Question%&amp;gt;&lt;br /&gt;
+         &amp;lt;%= @question.view_question_text.html_safe %&amp;gt;&lt;br /&gt;
    &amp;lt;%end%&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/questionnaires/_criterion_view.html.erb -''' This partial file has the moved html code from view_question_text. Note that the &amp;quot;self.xxx&amp;quot; have been updated to &amp;quot;@question.xxx&amp;quot; as self referred to question object discussed in 1. Comment added to describe the partial file. Refer the pull request to look at the code.&lt;br /&gt;
&lt;br /&gt;
===The complete Method===&lt;br /&gt;
All the code in the model included html thus was completely removed from there. It was moved to the partial file (app/views/questionnaires/_criterion_edit.html.erb) and the necessary changes were made. Since it was all HTML code, no comments were actually required. However, we still added comments describing the partial file itself. Other comments were added whenever changes were made.&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/questionnaires/edit.html.erb -''' This file calls the edit method for all types of question objects and the object type takes care of invoking the right overridden method. We modified this file to call the partial instead of edit method only for Criterion type of question objects. This view is invoked during edit on the questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% for @question in @questionnaire.questions %&amp;gt;&lt;br /&gt;
-   &amp;lt;%-# The following line call certain method of the object, which returns html string-%&amp;gt;&lt;br /&gt;
+   &amp;lt;%# E1911: Call the criterion_edit partial if question is of type Criterion -%&amp;gt;&lt;br /&gt;
+   &amp;lt;% if @question.is_a? Criterion %&amp;gt;&lt;br /&gt;
+     &amp;lt;%= render :partial =&amp;gt; 'criterion_edit' %&amp;gt;&lt;br /&gt;
+   &amp;lt;% else %&amp;gt;&lt;br /&gt;
      &amp;lt;%=@question.edit%&amp;gt;&lt;br /&gt;
+ &amp;lt;% end %&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/questionnaires/_questionnaire.html.erb -''' This partial file is called by new.html.erb when anew question is created. Same logic and changes as above.&lt;br /&gt;
'''3. views/questionnaires/_criterion_edit.html.erb -''' This file has all the html code that was earlier in the edit method of the criterion model. We changed the variables from &amp;quot;self.xxx&amp;quot; to &amp;quot;@question.xxx&amp;quot; because self was referring to question object in this context. Apart from this we changed the code to erb format. No more changes were deemed necessary. Please refer to the pull request to refer to the changes in this file as they are pure html and really long to be put in this wiki.&lt;br /&gt;
&lt;br /&gt;
===The view_completed_question Method===&lt;br /&gt;
&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1.&lt;/div&gt;</summary>
		<author><name>Amadhus2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=E1911_Refactor_Criterion&amp;diff=122902</id>
		<title>E1911 Refactor Criterion</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=E1911_Refactor_Criterion&amp;diff=122902"/>
		<updated>2019-04-01T22:27:46Z</updated>

		<summary type="html">&lt;p&gt;Amadhus2: /* Affected View Files */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=E1911 Refactoring criterion.rb=&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create new assignments and customize new or existing assignments. It also allows the instructor to create a list of topics the students can sign up for. Students can form teams in Expertiza to work on various projects and assignments. Students can also peer review other students' submissions. Expertiza supports submission across various document types, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The bulk of the code in criterion is HTML. It is the violation of MVC architecture - Model should not concern itself with how the data is displayed. This code needs to be moved to a partial file, and the partial file needs to be called in all appropriate places which call the criterion’s model methods. Once the logic for the view is moved out of the model, the model should only be left with business logic. This business logic code can also be refactored. Plus there are virtually no comments, properly comment the code.&lt;br /&gt;
&lt;br /&gt;
==About Criterion.rb==&lt;br /&gt;
Criterion is one of the types of questions that can be added to a questionnaire. There are many other types of question objects like dropdown that have the implementation of similar methods. As of now, the criterion model holds 4 methods that are called from different places in the application. Each of these methods is storing a string value which contains the necessary HTML lines to display the required functionalities to the user. This string value is then returned to the calling methods from the respective views. This HTML string is then entered wherever necessary. This is ideally the exact function of a partial, and this page needs to be heavily reformatted to use partials instead of returning a string containing html code.&lt;br /&gt;
&lt;br /&gt;
===The pull request===&lt;br /&gt;
https://github.com/expertiza/expertiza/pull/1407&lt;br /&gt;
&lt;br /&gt;
===The edit method===&lt;br /&gt;
This method is one of the several other methods in other files like criterion.rb which gets called when the type of the question being created in the respective model. In the case of this problem, which deals with criterion type questions, the edit method defined in criterion.rb is called when the question.type is equal to &amp;quot;Criterion&amp;quot;. This method allows for a user to create the criterion question and enter the necessary details. This method is called only from two view files - one for creating (_questionnaire.html.erb partial file) and another for editing (edit.html.erb). Both these files are in questionnaires view. Verified this using both RubyMine and the grep command. Another interesting thing to note is the use of &amp;quot;self.&amp;quot; to get the attributes associated with question object. When we move this code to a partial, we need to change this in the erb file. The outcome of this method's refactoring will completely remove this method from the model file criterion.rb as there is no business logic involved here.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def edit(_count)&lt;br /&gt;
    html = '&amp;lt;td align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;a rel=&amp;quot;nofollow&amp;quot; data-method=&amp;quot;delete&amp;quot; href=&amp;quot;/questions/' + self.id.to_s + '&amp;quot;&amp;gt;Remove&amp;lt;/a&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;6&amp;quot; value=&amp;quot;' + self.seq.to_s + '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][seq]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_seq&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;textarea cols=&amp;quot;50&amp;quot; rows=&amp;quot;1&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][txt]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_txt&amp;quot; placeholder=&amp;quot;Edit question content here&amp;quot;&amp;gt;' + self.txt + '&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;10&amp;quot; disabled=&amp;quot;disabled&amp;quot; value=&amp;quot;' + self.type + '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][type]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_type&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;2&amp;quot; value=&amp;quot;' + self.weight.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][weight]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_weight&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;text area size &amp;lt;input size=&amp;quot;3&amp;quot; value=&amp;quot;' + self.size.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][size]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_size&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt; max_label &amp;lt;input size=&amp;quot;10&amp;quot; value=&amp;quot;' + self.max_label.to_s + '&amp;quot; name=&amp;quot;question[' + self.id.to_s&lt;br /&gt;
    html += '][max_label]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_max_label&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;  min_label &amp;lt;input size=&amp;quot;12&amp;quot; value=&amp;quot;' + self.min_label.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][min_label]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_min_label&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    safe_join([&amp;quot;&amp;lt;tr&amp;gt;&amp;quot;.html_safe, &amp;quot;&amp;lt;/tr&amp;gt;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The safe_join is later used to return the HTML string to the calling view.&lt;br /&gt;
&lt;br /&gt;
===The view_question_text method===&lt;br /&gt;
This method has the same explanation as the edit method except the fact that this method is called only during viewing of questionnaires by an instructor. We observed that this method is also called by in student_quiz view. On further analysis, we found that the student_quiz does not use criterion object and has only three options: TrueFalse, MultipleChoiceRadio and MultipleChoiceCheckbox. So no refactoring is required here. Verified this method isn't called anywhere else using RubyMine and grep command. The outcome of this method's refactoring will completely remove this method from the model file criterion.rb as there is no business logic in this method and is completely html code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def view_question_text&lt;br /&gt;
    html = '&amp;lt;TD align=&amp;quot;left&amp;quot;&amp;gt; ' + self.txt + ' &amp;lt;/TD&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;TD align=&amp;quot;left&amp;quot;&amp;gt;' + self.type + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;td align=&amp;quot;center&amp;quot;&amp;gt;' + self.weight.to_s + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    questionnaire = self.questionnaire&lt;br /&gt;
    if !self.max_label.nil? &amp;amp;&amp;amp; !self.min_label.nil?&lt;br /&gt;
      html += '&amp;lt;TD align=&amp;quot;center&amp;quot;&amp;gt; (' + self.min_label + ') ' + questionnaire.min_question_score.to_s&lt;br /&gt;
      html += ' to ' + questionnaire.max_question_score.to_s + ' (' + self.max_label + ')&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    else&lt;br /&gt;
      html += '&amp;lt;TD align=&amp;quot;center&amp;quot;&amp;gt;' + questionnaire.min_question_score.to_s + ' to ' + questionnaire.max_question_score.to_s + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    safe_join([&amp;quot;&amp;lt;TR&amp;gt;&amp;quot;.html_safe, &amp;quot;&amp;lt;/TR&amp;gt;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===The complete method===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===The view_completed_question method===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Proposed Solution==&lt;br /&gt;
All these methods contain HTML text. What we propose to do is to pick these lines of code and move them into an appropriate partial, in the required format. The next task is to find out where in the entire application do these methods get called. The multiple overriding of the method calls in this poorly structured application makes it a challenging task. These method-calls then have to be replaced with the appropriate rendering of a partial in the views. This would make the structure more MVC oriented, and help keep it clean and understandable for the next developer who accesses this file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Implementation==&lt;br /&gt;
The changes proposed above were implemented as described below.&lt;br /&gt;
&lt;br /&gt;
===The Edit Method===&lt;br /&gt;
All the code in the model was just html and thus was completely removed from there. It was moved to the partial file (views/questionnaires/_criterion_edit.html.rb) and the necessary changes were made. Since it was all HTML code, no comments were actually required. However, we still added comments describing the partial file itself. Other comments were added whenever changes were made.&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/questionnaires/edit.html.erb -''' This file calls the edit method for all types of question objects and the object type takes care of invoking the right overridden method. We modified this file to call the partial instead of edit method only for Criterion type of question objects. This view is invoked during edit on the questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% for @question in @questionnaire.questions %&amp;gt;&lt;br /&gt;
-   &amp;lt;%-# The following line call certain method of the object, which returns html string-%&amp;gt;&lt;br /&gt;
+   &amp;lt;%# E1911: Call the criterion_edit partial if question is of type Criterion -%&amp;gt;&lt;br /&gt;
+   &amp;lt;% if @question.is_a? Criterion %&amp;gt;&lt;br /&gt;
+     &amp;lt;%= render :partial =&amp;gt; 'criterion_edit' %&amp;gt;&lt;br /&gt;
+   &amp;lt;% else %&amp;gt;&lt;br /&gt;
      &amp;lt;%=@question.edit%&amp;gt;&lt;br /&gt;
+ &amp;lt;% end %&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/questionnaires/_questionnaire.html.erb -''' This partial file is called by new.html.erb when anew question is created. Same logic and changes as above.&lt;br /&gt;
'''3. views/questionnaires/_criterion_edit.html.erb -''' This file has all the html code that was earlier in the edit method of the criterion model. We changed the variables from &amp;quot;self.xxx&amp;quot; to &amp;quot;@question.xxx&amp;quot; because self was referring to question object in this context. Apart from this we changed the code to erb format. No more changes were deemed necessary. Please refer to the pull request to refer to the changes in this file as they are pure html and really long to be put in this wiki.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===The view_question_text Method===&lt;br /&gt;
This method did not contain any business logic and thus all code was formatted and moved to a new partial file (views/questionnaires/_criterion_view.html.erb). Again, no comments were required due to complete html code and a comment describing the partial was added in addition to other necessary comments in other files.&lt;br /&gt;
&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/questionnaires/view.html.erb -''' Modified to invoke the partial if question is of type Criterion only. Also changed the question variable to a instance variable (question =&amp;gt; @question) to extend it's scope to the partial. This view is invoked during the view of questions in a questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- &amp;lt;%questions.each do |question| %&amp;gt;&lt;br /&gt;
-   &amp;lt;%if question.is_a? Question%&amp;gt;&lt;br /&gt;
-     &amp;lt;%=question.view_question_text.html_safe%&amp;gt;&lt;br /&gt;
+ &amp;lt;% for @question in questions %&amp;gt;&lt;br /&gt;
+   &amp;lt;%# E1911: Call the criterion_view partial if question is of type Criterion %&amp;gt;&lt;br /&gt;
+   &amp;lt;%if @question.is_a? Criterion %&amp;gt;&lt;br /&gt;
+         &amp;lt;%= render :partial =&amp;gt; 'criterion_view' %&amp;gt;&lt;br /&gt;
+     &amp;lt;%elsif @question.is_a? Question%&amp;gt;&lt;br /&gt;
+         &amp;lt;%= @question.view_question_text.html_safe %&amp;gt;&lt;br /&gt;
    &amp;lt;%end%&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/questionnaires/_criterion_view.html.erb -''' This partial file has the moved html code from view_question_text. Note that the &amp;quot;self.xxx&amp;quot; have been updated to &amp;quot;@question.xxx&amp;quot; as self referred to question object discussed in 1. Comment added to describe the partial file. Refer the pull request to look at the code.&lt;br /&gt;
&lt;br /&gt;
===The complete Method===&lt;br /&gt;
All the code in the model included html thus was completely removed from there. It was moved to the partial file (app/views/questionnaires/_criterion_edit.html.erb) and the necessary changes were made. Since it was all HTML code, no comments were actually required. However, we still added comments describing the partial file itself. Other comments were added whenever changes were made.&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/questionnaires/edit.html.erb -''' This file calls the edit method for all types of question objects and the object type takes care of invoking the right overridden method. We modified this file to call the partial instead of edit method only for Criterion type of question objects. This view is invoked during edit on the questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% for @question in @questionnaire.questions %&amp;gt;&lt;br /&gt;
-   &amp;lt;%-# The following line call certain method of the object, which returns html string-%&amp;gt;&lt;br /&gt;
+   &amp;lt;%# E1911: Call the criterion_edit partial if question is of type Criterion -%&amp;gt;&lt;br /&gt;
+   &amp;lt;% if @question.is_a? Criterion %&amp;gt;&lt;br /&gt;
+     &amp;lt;%= render :partial =&amp;gt; 'criterion_edit' %&amp;gt;&lt;br /&gt;
+   &amp;lt;% else %&amp;gt;&lt;br /&gt;
      &amp;lt;%=@question.edit%&amp;gt;&lt;br /&gt;
+ &amp;lt;% end %&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/questionnaires/_questionnaire.html.erb -''' This partial file is called by new.html.erb when anew question is created. Same logic and changes as above.&lt;br /&gt;
'''3. views/questionnaires/_criterion_edit.html.erb -''' This file has all the html code that was earlier in the edit method of the criterion model. We changed the variables from &amp;quot;self.xxx&amp;quot; to &amp;quot;@question.xxx&amp;quot; because self was referring to question object in this context. Apart from this we changed the code to erb format. No more changes were deemed necessary. Please refer to the pull request to refer to the changes in this file as they are pure html and really long to be put in this wiki.&lt;br /&gt;
&lt;br /&gt;
{| role=&amp;quot;presentation&amp;quot; class=&amp;quot;mw-collapsible&amp;quot;&lt;br /&gt;
| &amp;lt;strong&amp;gt;Lorem ipsum&amp;lt;/strong&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Lorem ipsum dolor sit amet&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===The view_completed_question Method===&lt;br /&gt;
&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1.&lt;/div&gt;</summary>
		<author><name>Amadhus2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=E1911_Refactor_Criterion&amp;diff=122901</id>
		<title>E1911 Refactor Criterion</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=E1911_Refactor_Criterion&amp;diff=122901"/>
		<updated>2019-04-01T22:26:20Z</updated>

		<summary type="html">&lt;p&gt;Amadhus2: /* Affected View Files */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=E1911 Refactoring criterion.rb=&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create new assignments and customize new or existing assignments. It also allows the instructor to create a list of topics the students can sign up for. Students can form teams in Expertiza to work on various projects and assignments. Students can also peer review other students' submissions. Expertiza supports submission across various document types, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The bulk of the code in criterion is HTML. It is the violation of MVC architecture - Model should not concern itself with how the data is displayed. This code needs to be moved to a partial file, and the partial file needs to be called in all appropriate places which call the criterion’s model methods. Once the logic for the view is moved out of the model, the model should only be left with business logic. This business logic code can also be refactored. Plus there are virtually no comments, properly comment the code.&lt;br /&gt;
&lt;br /&gt;
==About Criterion.rb==&lt;br /&gt;
Criterion is one of the types of questions that can be added to a questionnaire. There are many other types of question objects like dropdown that have the implementation of similar methods. As of now, the criterion model holds 4 methods that are called from different places in the application. Each of these methods is storing a string value which contains the necessary HTML lines to display the required functionalities to the user. This string value is then returned to the calling methods from the respective views. This HTML string is then entered wherever necessary. This is ideally the exact function of a partial, and this page needs to be heavily reformatted to use partials instead of returning a string containing html code.&lt;br /&gt;
&lt;br /&gt;
===The pull request===&lt;br /&gt;
https://github.com/expertiza/expertiza/pull/1407&lt;br /&gt;
&lt;br /&gt;
===The edit method===&lt;br /&gt;
This method is one of the several other methods in other files like criterion.rb which gets called when the type of the question being created in the respective model. In the case of this problem, which deals with criterion type questions, the edit method defined in criterion.rb is called when the question.type is equal to &amp;quot;Criterion&amp;quot;. This method allows for a user to create the criterion question and enter the necessary details. This method is called only from two view files - one for creating (_questionnaire.html.erb partial file) and another for editing (edit.html.erb). Both these files are in questionnaires view. Verified this using both RubyMine and the grep command. Another interesting thing to note is the use of &amp;quot;self.&amp;quot; to get the attributes associated with question object. When we move this code to a partial, we need to change this in the erb file. The outcome of this method's refactoring will completely remove this method from the model file criterion.rb as there is no business logic involved here.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def edit(_count)&lt;br /&gt;
    html = '&amp;lt;td align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;a rel=&amp;quot;nofollow&amp;quot; data-method=&amp;quot;delete&amp;quot; href=&amp;quot;/questions/' + self.id.to_s + '&amp;quot;&amp;gt;Remove&amp;lt;/a&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;6&amp;quot; value=&amp;quot;' + self.seq.to_s + '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][seq]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_seq&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;textarea cols=&amp;quot;50&amp;quot; rows=&amp;quot;1&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][txt]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_txt&amp;quot; placeholder=&amp;quot;Edit question content here&amp;quot;&amp;gt;' + self.txt + '&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;10&amp;quot; disabled=&amp;quot;disabled&amp;quot; value=&amp;quot;' + self.type + '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][type]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_type&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;2&amp;quot; value=&amp;quot;' + self.weight.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][weight]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_weight&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;text area size &amp;lt;input size=&amp;quot;3&amp;quot; value=&amp;quot;' + self.size.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][size]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_size&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt; max_label &amp;lt;input size=&amp;quot;10&amp;quot; value=&amp;quot;' + self.max_label.to_s + '&amp;quot; name=&amp;quot;question[' + self.id.to_s&lt;br /&gt;
    html += '][max_label]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_max_label&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;  min_label &amp;lt;input size=&amp;quot;12&amp;quot; value=&amp;quot;' + self.min_label.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][min_label]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_min_label&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    safe_join([&amp;quot;&amp;lt;tr&amp;gt;&amp;quot;.html_safe, &amp;quot;&amp;lt;/tr&amp;gt;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The safe_join is later used to return the HTML string to the calling view.&lt;br /&gt;
&lt;br /&gt;
===The view_question_text method===&lt;br /&gt;
This method has the same explanation as the edit method except the fact that this method is called only during viewing of questionnaires by an instructor. We observed that this method is also called by in student_quiz view. On further analysis, we found that the student_quiz does not use criterion object and has only three options: TrueFalse, MultipleChoiceRadio and MultipleChoiceCheckbox. So no refactoring is required here. Verified this method isn't called anywhere else using RubyMine and grep command. The outcome of this method's refactoring will completely remove this method from the model file criterion.rb as there is no business logic in this method and is completely html code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def view_question_text&lt;br /&gt;
    html = '&amp;lt;TD align=&amp;quot;left&amp;quot;&amp;gt; ' + self.txt + ' &amp;lt;/TD&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;TD align=&amp;quot;left&amp;quot;&amp;gt;' + self.type + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;td align=&amp;quot;center&amp;quot;&amp;gt;' + self.weight.to_s + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    questionnaire = self.questionnaire&lt;br /&gt;
    if !self.max_label.nil? &amp;amp;&amp;amp; !self.min_label.nil?&lt;br /&gt;
      html += '&amp;lt;TD align=&amp;quot;center&amp;quot;&amp;gt; (' + self.min_label + ') ' + questionnaire.min_question_score.to_s&lt;br /&gt;
      html += ' to ' + questionnaire.max_question_score.to_s + ' (' + self.max_label + ')&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    else&lt;br /&gt;
      html += '&amp;lt;TD align=&amp;quot;center&amp;quot;&amp;gt;' + questionnaire.min_question_score.to_s + ' to ' + questionnaire.max_question_score.to_s + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    safe_join([&amp;quot;&amp;lt;TR&amp;gt;&amp;quot;.html_safe, &amp;quot;&amp;lt;/TR&amp;gt;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===The complete method===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===The view_completed_question method===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Proposed Solution==&lt;br /&gt;
All these methods contain HTML text. What we propose to do is to pick these lines of code and move them into an appropriate partial, in the required format. The next task is to find out where in the entire application do these methods get called. The multiple overriding of the method calls in this poorly structured application makes it a challenging task. These method-calls then have to be replaced with the appropriate rendering of a partial in the views. This would make the structure more MVC oriented, and help keep it clean and understandable for the next developer who accesses this file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Implementation==&lt;br /&gt;
The changes proposed above were implemented as described below.&lt;br /&gt;
&lt;br /&gt;
===The Edit Method===&lt;br /&gt;
All the code in the model was just html and thus was completely removed from there. It was moved to the partial file (views/questionnaires/_criterion_edit.html.rb) and the necessary changes were made. Since it was all HTML code, no comments were actually required. However, we still added comments describing the partial file itself. Other comments were added whenever changes were made.&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/questionnaires/edit.html.erb -''' This file calls the edit method for all types of question objects and the object type takes care of invoking the right overridden method. We modified this file to call the partial instead of edit method only for Criterion type of question objects. This view is invoked during edit on the questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% for @question in @questionnaire.questions %&amp;gt;&lt;br /&gt;
-   &amp;lt;%-# The following line call certain method of the object, which returns html string-%&amp;gt;&lt;br /&gt;
+   &amp;lt;%# E1911: Call the criterion_edit partial if question is of type Criterion -%&amp;gt;&lt;br /&gt;
+   &amp;lt;% if @question.is_a? Criterion %&amp;gt;&lt;br /&gt;
+     &amp;lt;%= render :partial =&amp;gt; 'criterion_edit' %&amp;gt;&lt;br /&gt;
+   &amp;lt;% else %&amp;gt;&lt;br /&gt;
      &amp;lt;%=@question.edit%&amp;gt;&lt;br /&gt;
+ &amp;lt;% end %&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/questionnaires/_questionnaire.html.erb -''' This partial file is called by new.html.erb when anew question is created. Same logic and changes as above.&lt;br /&gt;
'''3. views/questionnaires/_criterion_edit.html.erb -''' This file has all the html code that was earlier in the edit method of the criterion model. We changed the variables from &amp;quot;self.xxx&amp;quot; to &amp;quot;@question.xxx&amp;quot; because self was referring to question object in this context. Apart from this we changed the code to erb format. No more changes were deemed necessary. Please refer to the pull request to refer to the changes in this file as they are pure html and really long to be put in this wiki.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===The view_question_text Method===&lt;br /&gt;
This method did not contain any business logic and thus all code was formatted and moved to a new partial file (views/questionnaires/_criterion_view.html.erb). Again, no comments were required due to complete html code and a comment describing the partial was added in addition to other necessary comments in other files.&lt;br /&gt;
&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/questionnaires/view.html.erb -''' Modified to invoke the partial if question is of type Criterion only. Also changed the question variable to a instance variable (question =&amp;gt; @question) to extend it's scope to the partial. This view is invoked during the view of questions in a questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- &amp;lt;%questions.each do |question| %&amp;gt;&lt;br /&gt;
-   &amp;lt;%if question.is_a? Question%&amp;gt;&lt;br /&gt;
-     &amp;lt;%=question.view_question_text.html_safe%&amp;gt;&lt;br /&gt;
+ &amp;lt;% for @question in questions %&amp;gt;&lt;br /&gt;
+   &amp;lt;%# E1911: Call the criterion_view partial if question is of type Criterion %&amp;gt;&lt;br /&gt;
+   &amp;lt;%if @question.is_a? Criterion %&amp;gt;&lt;br /&gt;
+         &amp;lt;%= render :partial =&amp;gt; 'criterion_view' %&amp;gt;&lt;br /&gt;
+     &amp;lt;%elsif @question.is_a? Question%&amp;gt;&lt;br /&gt;
+         &amp;lt;%= @question.view_question_text.html_safe %&amp;gt;&lt;br /&gt;
    &amp;lt;%end%&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/questionnaires/_criterion_view.html.erb -''' This partial file has the moved html code from view_question_text. Note that the &amp;quot;self.xxx&amp;quot; have been updated to &amp;quot;@question.xxx&amp;quot; as self referred to question object discussed in 1. Comment added to describe the partial file. Refer the pull request to look at the code.&lt;br /&gt;
&lt;br /&gt;
===The complete Method===&lt;br /&gt;
All the code in the model included html thus was completely removed from there. It was moved to the partial file (app/views/questionnaires/_criterion_edit.html.erb) and the necessary changes were made. Since it was all HTML code, no comments were actually required. However, we still added comments describing the partial file itself. Other comments were added whenever changes were made.&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/questionnaires/edit.html.erb -''' This file calls the edit method for all types of question objects and the object type takes care of invoking the right overridden method. We modified this file to call the partial instead of edit method only for Criterion type of question objects. This view is invoked during edit on the questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% for @question in @questionnaire.questions %&amp;gt;&lt;br /&gt;
-   &amp;lt;%-# The following line call certain method of the object, which returns html string-%&amp;gt;&lt;br /&gt;
+   &amp;lt;%# E1911: Call the criterion_edit partial if question is of type Criterion -%&amp;gt;&lt;br /&gt;
+   &amp;lt;% if @question.is_a? Criterion %&amp;gt;&lt;br /&gt;
+     &amp;lt;%= render :partial =&amp;gt; 'criterion_edit' %&amp;gt;&lt;br /&gt;
+   &amp;lt;% else %&amp;gt;&lt;br /&gt;
      &amp;lt;%=@question.edit%&amp;gt;&lt;br /&gt;
+ &amp;lt;% end %&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/questionnaires/_questionnaire.html.erb -''' This partial file is called by new.html.erb when anew question is created. Same logic and changes as above.&lt;br /&gt;
'''3. views/questionnaires/_criterion_edit.html.erb -''' This file has all the html code that was earlier in the edit method of the criterion model. We changed the variables from &amp;quot;self.xxx&amp;quot; to &amp;quot;@question.xxx&amp;quot; because self was referring to question object in this context. Apart from this we changed the code to erb format. No more changes were deemed necessary. Please refer to the pull request to refer to the changes in this file as they are pure html and really long to be put in this wiki.&lt;br /&gt;
&lt;br /&gt;
{{| role=&amp;quot;presentation&amp;quot; class=&amp;quot;wikitable mw-collapsible&amp;quot;&lt;br /&gt;
| &amp;lt;strong&amp;gt;Code&amp;lt;/strong&amp;gt;&lt;br /&gt;
|asdasdasd&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
===The view_completed_question Method===&lt;br /&gt;
&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1.&lt;/div&gt;</summary>
		<author><name>Amadhus2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=E1911_Refactor_Criterion&amp;diff=122900</id>
		<title>E1911 Refactor Criterion</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=E1911_Refactor_Criterion&amp;diff=122900"/>
		<updated>2019-04-01T22:26:06Z</updated>

		<summary type="html">&lt;p&gt;Amadhus2: /* Affected View Files */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=E1911 Refactoring criterion.rb=&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create new assignments and customize new or existing assignments. It also allows the instructor to create a list of topics the students can sign up for. Students can form teams in Expertiza to work on various projects and assignments. Students can also peer review other students' submissions. Expertiza supports submission across various document types, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The bulk of the code in criterion is HTML. It is the violation of MVC architecture - Model should not concern itself with how the data is displayed. This code needs to be moved to a partial file, and the partial file needs to be called in all appropriate places which call the criterion’s model methods. Once the logic for the view is moved out of the model, the model should only be left with business logic. This business logic code can also be refactored. Plus there are virtually no comments, properly comment the code.&lt;br /&gt;
&lt;br /&gt;
==About Criterion.rb==&lt;br /&gt;
Criterion is one of the types of questions that can be added to a questionnaire. There are many other types of question objects like dropdown that have the implementation of similar methods. As of now, the criterion model holds 4 methods that are called from different places in the application. Each of these methods is storing a string value which contains the necessary HTML lines to display the required functionalities to the user. This string value is then returned to the calling methods from the respective views. This HTML string is then entered wherever necessary. This is ideally the exact function of a partial, and this page needs to be heavily reformatted to use partials instead of returning a string containing html code.&lt;br /&gt;
&lt;br /&gt;
===The pull request===&lt;br /&gt;
https://github.com/expertiza/expertiza/pull/1407&lt;br /&gt;
&lt;br /&gt;
===The edit method===&lt;br /&gt;
This method is one of the several other methods in other files like criterion.rb which gets called when the type of the question being created in the respective model. In the case of this problem, which deals with criterion type questions, the edit method defined in criterion.rb is called when the question.type is equal to &amp;quot;Criterion&amp;quot;. This method allows for a user to create the criterion question and enter the necessary details. This method is called only from two view files - one for creating (_questionnaire.html.erb partial file) and another for editing (edit.html.erb). Both these files are in questionnaires view. Verified this using both RubyMine and the grep command. Another interesting thing to note is the use of &amp;quot;self.&amp;quot; to get the attributes associated with question object. When we move this code to a partial, we need to change this in the erb file. The outcome of this method's refactoring will completely remove this method from the model file criterion.rb as there is no business logic involved here.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def edit(_count)&lt;br /&gt;
    html = '&amp;lt;td align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;a rel=&amp;quot;nofollow&amp;quot; data-method=&amp;quot;delete&amp;quot; href=&amp;quot;/questions/' + self.id.to_s + '&amp;quot;&amp;gt;Remove&amp;lt;/a&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;6&amp;quot; value=&amp;quot;' + self.seq.to_s + '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][seq]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_seq&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;textarea cols=&amp;quot;50&amp;quot; rows=&amp;quot;1&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][txt]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_txt&amp;quot; placeholder=&amp;quot;Edit question content here&amp;quot;&amp;gt;' + self.txt + '&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;10&amp;quot; disabled=&amp;quot;disabled&amp;quot; value=&amp;quot;' + self.type + '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][type]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_type&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;2&amp;quot; value=&amp;quot;' + self.weight.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][weight]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_weight&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;text area size &amp;lt;input size=&amp;quot;3&amp;quot; value=&amp;quot;' + self.size.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][size]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_size&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt; max_label &amp;lt;input size=&amp;quot;10&amp;quot; value=&amp;quot;' + self.max_label.to_s + '&amp;quot; name=&amp;quot;question[' + self.id.to_s&lt;br /&gt;
    html += '][max_label]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_max_label&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;  min_label &amp;lt;input size=&amp;quot;12&amp;quot; value=&amp;quot;' + self.min_label.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][min_label]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_min_label&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    safe_join([&amp;quot;&amp;lt;tr&amp;gt;&amp;quot;.html_safe, &amp;quot;&amp;lt;/tr&amp;gt;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The safe_join is later used to return the HTML string to the calling view.&lt;br /&gt;
&lt;br /&gt;
===The view_question_text method===&lt;br /&gt;
This method has the same explanation as the edit method except the fact that this method is called only during viewing of questionnaires by an instructor. We observed that this method is also called by in student_quiz view. On further analysis, we found that the student_quiz does not use criterion object and has only three options: TrueFalse, MultipleChoiceRadio and MultipleChoiceCheckbox. So no refactoring is required here. Verified this method isn't called anywhere else using RubyMine and grep command. The outcome of this method's refactoring will completely remove this method from the model file criterion.rb as there is no business logic in this method and is completely html code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def view_question_text&lt;br /&gt;
    html = '&amp;lt;TD align=&amp;quot;left&amp;quot;&amp;gt; ' + self.txt + ' &amp;lt;/TD&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;TD align=&amp;quot;left&amp;quot;&amp;gt;' + self.type + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;td align=&amp;quot;center&amp;quot;&amp;gt;' + self.weight.to_s + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    questionnaire = self.questionnaire&lt;br /&gt;
    if !self.max_label.nil? &amp;amp;&amp;amp; !self.min_label.nil?&lt;br /&gt;
      html += '&amp;lt;TD align=&amp;quot;center&amp;quot;&amp;gt; (' + self.min_label + ') ' + questionnaire.min_question_score.to_s&lt;br /&gt;
      html += ' to ' + questionnaire.max_question_score.to_s + ' (' + self.max_label + ')&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    else&lt;br /&gt;
      html += '&amp;lt;TD align=&amp;quot;center&amp;quot;&amp;gt;' + questionnaire.min_question_score.to_s + ' to ' + questionnaire.max_question_score.to_s + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    safe_join([&amp;quot;&amp;lt;TR&amp;gt;&amp;quot;.html_safe, &amp;quot;&amp;lt;/TR&amp;gt;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===The complete method===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===The view_completed_question method===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Proposed Solution==&lt;br /&gt;
All these methods contain HTML text. What we propose to do is to pick these lines of code and move them into an appropriate partial, in the required format. The next task is to find out where in the entire application do these methods get called. The multiple overriding of the method calls in this poorly structured application makes it a challenging task. These method-calls then have to be replaced with the appropriate rendering of a partial in the views. This would make the structure more MVC oriented, and help keep it clean and understandable for the next developer who accesses this file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Implementation==&lt;br /&gt;
The changes proposed above were implemented as described below.&lt;br /&gt;
&lt;br /&gt;
===The Edit Method===&lt;br /&gt;
All the code in the model was just html and thus was completely removed from there. It was moved to the partial file (views/questionnaires/_criterion_edit.html.rb) and the necessary changes were made. Since it was all HTML code, no comments were actually required. However, we still added comments describing the partial file itself. Other comments were added whenever changes were made.&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/questionnaires/edit.html.erb -''' This file calls the edit method for all types of question objects and the object type takes care of invoking the right overridden method. We modified this file to call the partial instead of edit method only for Criterion type of question objects. This view is invoked during edit on the questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% for @question in @questionnaire.questions %&amp;gt;&lt;br /&gt;
-   &amp;lt;%-# The following line call certain method of the object, which returns html string-%&amp;gt;&lt;br /&gt;
+   &amp;lt;%# E1911: Call the criterion_edit partial if question is of type Criterion -%&amp;gt;&lt;br /&gt;
+   &amp;lt;% if @question.is_a? Criterion %&amp;gt;&lt;br /&gt;
+     &amp;lt;%= render :partial =&amp;gt; 'criterion_edit' %&amp;gt;&lt;br /&gt;
+   &amp;lt;% else %&amp;gt;&lt;br /&gt;
      &amp;lt;%=@question.edit%&amp;gt;&lt;br /&gt;
+ &amp;lt;% end %&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/questionnaires/_questionnaire.html.erb -''' This partial file is called by new.html.erb when anew question is created. Same logic and changes as above.&lt;br /&gt;
'''3. views/questionnaires/_criterion_edit.html.erb -''' This file has all the html code that was earlier in the edit method of the criterion model. We changed the variables from &amp;quot;self.xxx&amp;quot; to &amp;quot;@question.xxx&amp;quot; because self was referring to question object in this context. Apart from this we changed the code to erb format. No more changes were deemed necessary. Please refer to the pull request to refer to the changes in this file as they are pure html and really long to be put in this wiki.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===The view_question_text Method===&lt;br /&gt;
This method did not contain any business logic and thus all code was formatted and moved to a new partial file (views/questionnaires/_criterion_view.html.erb). Again, no comments were required due to complete html code and a comment describing the partial was added in addition to other necessary comments in other files.&lt;br /&gt;
&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/questionnaires/view.html.erb -''' Modified to invoke the partial if question is of type Criterion only. Also changed the question variable to a instance variable (question =&amp;gt; @question) to extend it's scope to the partial. This view is invoked during the view of questions in a questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- &amp;lt;%questions.each do |question| %&amp;gt;&lt;br /&gt;
-   &amp;lt;%if question.is_a? Question%&amp;gt;&lt;br /&gt;
-     &amp;lt;%=question.view_question_text.html_safe%&amp;gt;&lt;br /&gt;
+ &amp;lt;% for @question in questions %&amp;gt;&lt;br /&gt;
+   &amp;lt;%# E1911: Call the criterion_view partial if question is of type Criterion %&amp;gt;&lt;br /&gt;
+   &amp;lt;%if @question.is_a? Criterion %&amp;gt;&lt;br /&gt;
+         &amp;lt;%= render :partial =&amp;gt; 'criterion_view' %&amp;gt;&lt;br /&gt;
+     &amp;lt;%elsif @question.is_a? Question%&amp;gt;&lt;br /&gt;
+         &amp;lt;%= @question.view_question_text.html_safe %&amp;gt;&lt;br /&gt;
    &amp;lt;%end%&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/questionnaires/_criterion_view.html.erb -''' This partial file has the moved html code from view_question_text. Note that the &amp;quot;self.xxx&amp;quot; have been updated to &amp;quot;@question.xxx&amp;quot; as self referred to question object discussed in 1. Comment added to describe the partial file. Refer the pull request to look at the code.&lt;br /&gt;
&lt;br /&gt;
===The complete Method===&lt;br /&gt;
All the code in the model included html thus was completely removed from there. It was moved to the partial file (app/views/questionnaires/_criterion_edit.html.erb) and the necessary changes were made. Since it was all HTML code, no comments were actually required. However, we still added comments describing the partial file itself. Other comments were added whenever changes were made.&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/questionnaires/edit.html.erb -''' This file calls the edit method for all types of question objects and the object type takes care of invoking the right overridden method. We modified this file to call the partial instead of edit method only for Criterion type of question objects. This view is invoked during edit on the questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% for @question in @questionnaire.questions %&amp;gt;&lt;br /&gt;
-   &amp;lt;%-# The following line call certain method of the object, which returns html string-%&amp;gt;&lt;br /&gt;
+   &amp;lt;%# E1911: Call the criterion_edit partial if question is of type Criterion -%&amp;gt;&lt;br /&gt;
+   &amp;lt;% if @question.is_a? Criterion %&amp;gt;&lt;br /&gt;
+     &amp;lt;%= render :partial =&amp;gt; 'criterion_edit' %&amp;gt;&lt;br /&gt;
+   &amp;lt;% else %&amp;gt;&lt;br /&gt;
      &amp;lt;%=@question.edit%&amp;gt;&lt;br /&gt;
+ &amp;lt;% end %&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/questionnaires/_questionnaire.html.erb -''' This partial file is called by new.html.erb when anew question is created. Same logic and changes as above.&lt;br /&gt;
'''3. views/questionnaires/_criterion_edit.html.erb -''' This file has all the html code that was earlier in the edit method of the criterion model. We changed the variables from &amp;quot;self.xxx&amp;quot; to &amp;quot;@question.xxx&amp;quot; because self was referring to question object in this context. Apart from this we changed the code to erb format. No more changes were deemed necessary. Please refer to the pull request to refer to the changes in this file as they are pure html and really long to be put in this wiki.&lt;br /&gt;
&lt;br /&gt;
{{| role=&amp;quot;presentation&amp;quot; class=&amp;quot;wikitable mw-collapsible&amp;quot;&lt;br /&gt;
| &amp;lt;strong&amp;gt;Code&amp;lt;/strong&amp;gt;&lt;br /&gt;
asdasdasd&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
===The view_completed_question Method===&lt;br /&gt;
&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1.&lt;/div&gt;</summary>
		<author><name>Amadhus2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=E1911_Refactor_Criterion&amp;diff=122899</id>
		<title>E1911 Refactor Criterion</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=E1911_Refactor_Criterion&amp;diff=122899"/>
		<updated>2019-04-01T22:23:45Z</updated>

		<summary type="html">&lt;p&gt;Amadhus2: /* Affected View Files */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=E1911 Refactoring criterion.rb=&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create new assignments and customize new or existing assignments. It also allows the instructor to create a list of topics the students can sign up for. Students can form teams in Expertiza to work on various projects and assignments. Students can also peer review other students' submissions. Expertiza supports submission across various document types, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The bulk of the code in criterion is HTML. It is the violation of MVC architecture - Model should not concern itself with how the data is displayed. This code needs to be moved to a partial file, and the partial file needs to be called in all appropriate places which call the criterion’s model methods. Once the logic for the view is moved out of the model, the model should only be left with business logic. This business logic code can also be refactored. Plus there are virtually no comments, properly comment the code.&lt;br /&gt;
&lt;br /&gt;
==About Criterion.rb==&lt;br /&gt;
Criterion is one of the types of questions that can be added to a questionnaire. There are many other types of question objects like dropdown that have the implementation of similar methods. As of now, the criterion model holds 4 methods that are called from different places in the application. Each of these methods is storing a string value which contains the necessary HTML lines to display the required functionalities to the user. This string value is then returned to the calling methods from the respective views. This HTML string is then entered wherever necessary. This is ideally the exact function of a partial, and this page needs to be heavily reformatted to use partials instead of returning a string containing html code.&lt;br /&gt;
&lt;br /&gt;
===The pull request===&lt;br /&gt;
https://github.com/expertiza/expertiza/pull/1407&lt;br /&gt;
&lt;br /&gt;
===The edit method===&lt;br /&gt;
This method is one of the several other methods in other files like criterion.rb which gets called when the type of the question being created in the respective model. In the case of this problem, which deals with criterion type questions, the edit method defined in criterion.rb is called when the question.type is equal to &amp;quot;Criterion&amp;quot;. This method allows for a user to create the criterion question and enter the necessary details. This method is called only from two view files - one for creating (_questionnaire.html.erb partial file) and another for editing (edit.html.erb). Both these files are in questionnaires view. Verified this using both RubyMine and the grep command. Another interesting thing to note is the use of &amp;quot;self.&amp;quot; to get the attributes associated with question object. When we move this code to a partial, we need to change this in the erb file. The outcome of this method's refactoring will completely remove this method from the model file criterion.rb as there is no business logic involved here.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def edit(_count)&lt;br /&gt;
    html = '&amp;lt;td align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;a rel=&amp;quot;nofollow&amp;quot; data-method=&amp;quot;delete&amp;quot; href=&amp;quot;/questions/' + self.id.to_s + '&amp;quot;&amp;gt;Remove&amp;lt;/a&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;6&amp;quot; value=&amp;quot;' + self.seq.to_s + '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][seq]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_seq&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;textarea cols=&amp;quot;50&amp;quot; rows=&amp;quot;1&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][txt]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_txt&amp;quot; placeholder=&amp;quot;Edit question content here&amp;quot;&amp;gt;' + self.txt + '&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;10&amp;quot; disabled=&amp;quot;disabled&amp;quot; value=&amp;quot;' + self.type + '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][type]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_type&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;2&amp;quot; value=&amp;quot;' + self.weight.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][weight]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_weight&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;text area size &amp;lt;input size=&amp;quot;3&amp;quot; value=&amp;quot;' + self.size.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][size]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_size&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt; max_label &amp;lt;input size=&amp;quot;10&amp;quot; value=&amp;quot;' + self.max_label.to_s + '&amp;quot; name=&amp;quot;question[' + self.id.to_s&lt;br /&gt;
    html += '][max_label]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_max_label&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;  min_label &amp;lt;input size=&amp;quot;12&amp;quot; value=&amp;quot;' + self.min_label.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][min_label]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_min_label&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    safe_join([&amp;quot;&amp;lt;tr&amp;gt;&amp;quot;.html_safe, &amp;quot;&amp;lt;/tr&amp;gt;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The safe_join is later used to return the HTML string to the calling view.&lt;br /&gt;
&lt;br /&gt;
===The view_question_text method===&lt;br /&gt;
This method has the same explanation as the edit method except the fact that this method is called only during viewing of questionnaires by an instructor. We observed that this method is also called by in student_quiz view. On further analysis, we found that the student_quiz does not use criterion object and has only three options: TrueFalse, MultipleChoiceRadio and MultipleChoiceCheckbox. So no refactoring is required here. Verified this method isn't called anywhere else using RubyMine and grep command. The outcome of this method's refactoring will completely remove this method from the model file criterion.rb as there is no business logic in this method and is completely html code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def view_question_text&lt;br /&gt;
    html = '&amp;lt;TD align=&amp;quot;left&amp;quot;&amp;gt; ' + self.txt + ' &amp;lt;/TD&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;TD align=&amp;quot;left&amp;quot;&amp;gt;' + self.type + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;td align=&amp;quot;center&amp;quot;&amp;gt;' + self.weight.to_s + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    questionnaire = self.questionnaire&lt;br /&gt;
    if !self.max_label.nil? &amp;amp;&amp;amp; !self.min_label.nil?&lt;br /&gt;
      html += '&amp;lt;TD align=&amp;quot;center&amp;quot;&amp;gt; (' + self.min_label + ') ' + questionnaire.min_question_score.to_s&lt;br /&gt;
      html += ' to ' + questionnaire.max_question_score.to_s + ' (' + self.max_label + ')&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    else&lt;br /&gt;
      html += '&amp;lt;TD align=&amp;quot;center&amp;quot;&amp;gt;' + questionnaire.min_question_score.to_s + ' to ' + questionnaire.max_question_score.to_s + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    safe_join([&amp;quot;&amp;lt;TR&amp;gt;&amp;quot;.html_safe, &amp;quot;&amp;lt;/TR&amp;gt;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===The complete method===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===The view_completed_question method===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Proposed Solution==&lt;br /&gt;
All these methods contain HTML text. What we propose to do is to pick these lines of code and move them into an appropriate partial, in the required format. The next task is to find out where in the entire application do these methods get called. The multiple overriding of the method calls in this poorly structured application makes it a challenging task. These method-calls then have to be replaced with the appropriate rendering of a partial in the views. This would make the structure more MVC oriented, and help keep it clean and understandable for the next developer who accesses this file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Implementation==&lt;br /&gt;
The changes proposed above were implemented as described below.&lt;br /&gt;
&lt;br /&gt;
===The Edit Method===&lt;br /&gt;
All the code in the model was just html and thus was completely removed from there. It was moved to the partial file (views/questionnaires/_criterion_edit.html.rb) and the necessary changes were made. Since it was all HTML code, no comments were actually required. However, we still added comments describing the partial file itself. Other comments were added whenever changes were made.&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/questionnaires/edit.html.erb -''' This file calls the edit method for all types of question objects and the object type takes care of invoking the right overridden method. We modified this file to call the partial instead of edit method only for Criterion type of question objects. This view is invoked during edit on the questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% for @question in @questionnaire.questions %&amp;gt;&lt;br /&gt;
-   &amp;lt;%-# The following line call certain method of the object, which returns html string-%&amp;gt;&lt;br /&gt;
+   &amp;lt;%# E1911: Call the criterion_edit partial if question is of type Criterion -%&amp;gt;&lt;br /&gt;
+   &amp;lt;% if @question.is_a? Criterion %&amp;gt;&lt;br /&gt;
+     &amp;lt;%= render :partial =&amp;gt; 'criterion_edit' %&amp;gt;&lt;br /&gt;
+   &amp;lt;% else %&amp;gt;&lt;br /&gt;
      &amp;lt;%=@question.edit%&amp;gt;&lt;br /&gt;
+ &amp;lt;% end %&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/questionnaires/_questionnaire.html.erb -''' This partial file is called by new.html.erb when anew question is created. Same logic and changes as above.&lt;br /&gt;
'''3. views/questionnaires/_criterion_edit.html.erb -''' This file has all the html code that was earlier in the edit method of the criterion model. We changed the variables from &amp;quot;self.xxx&amp;quot; to &amp;quot;@question.xxx&amp;quot; because self was referring to question object in this context. Apart from this we changed the code to erb format. No more changes were deemed necessary. Please refer to the pull request to refer to the changes in this file as they are pure html and really long to be put in this wiki.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===The view_question_text Method===&lt;br /&gt;
This method did not contain any business logic and thus all code was formatted and moved to a new partial file (views/questionnaires/_criterion_view.html.erb). Again, no comments were required due to complete html code and a comment describing the partial was added in addition to other necessary comments in other files.&lt;br /&gt;
&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/questionnaires/view.html.erb -''' Modified to invoke the partial if question is of type Criterion only. Also changed the question variable to a instance variable (question =&amp;gt; @question) to extend it's scope to the partial. This view is invoked during the view of questions in a questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- &amp;lt;%questions.each do |question| %&amp;gt;&lt;br /&gt;
-   &amp;lt;%if question.is_a? Question%&amp;gt;&lt;br /&gt;
-     &amp;lt;%=question.view_question_text.html_safe%&amp;gt;&lt;br /&gt;
+ &amp;lt;% for @question in questions %&amp;gt;&lt;br /&gt;
+   &amp;lt;%# E1911: Call the criterion_view partial if question is of type Criterion %&amp;gt;&lt;br /&gt;
+   &amp;lt;%if @question.is_a? Criterion %&amp;gt;&lt;br /&gt;
+         &amp;lt;%= render :partial =&amp;gt; 'criterion_view' %&amp;gt;&lt;br /&gt;
+     &amp;lt;%elsif @question.is_a? Question%&amp;gt;&lt;br /&gt;
+         &amp;lt;%= @question.view_question_text.html_safe %&amp;gt;&lt;br /&gt;
    &amp;lt;%end%&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/questionnaires/_criterion_view.html.erb -''' This partial file has the moved html code from view_question_text. Note that the &amp;quot;self.xxx&amp;quot; have been updated to &amp;quot;@question.xxx&amp;quot; as self referred to question object discussed in 1. Comment added to describe the partial file. Refer the pull request to look at the code.&lt;br /&gt;
&lt;br /&gt;
===The complete Method===&lt;br /&gt;
All the code in the model included html thus was completely removed from there. It was moved to the partial file (app/views/questionnaires/_criterion_edit.html.erb) and the necessary changes were made. Since it was all HTML code, no comments were actually required. However, we still added comments describing the partial file itself. Other comments were added whenever changes were made.&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/questionnaires/edit.html.erb -''' This file calls the edit method for all types of question objects and the object type takes care of invoking the right overridden method. We modified this file to call the partial instead of edit method only for Criterion type of question objects. This view is invoked during edit on the questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% for @question in @questionnaire.questions %&amp;gt;&lt;br /&gt;
-   &amp;lt;%-# The following line call certain method of the object, which returns html string-%&amp;gt;&lt;br /&gt;
+   &amp;lt;%# E1911: Call the criterion_edit partial if question is of type Criterion -%&amp;gt;&lt;br /&gt;
+   &amp;lt;% if @question.is_a? Criterion %&amp;gt;&lt;br /&gt;
+     &amp;lt;%= render :partial =&amp;gt; 'criterion_edit' %&amp;gt;&lt;br /&gt;
+   &amp;lt;% else %&amp;gt;&lt;br /&gt;
      &amp;lt;%=@question.edit%&amp;gt;&lt;br /&gt;
+ &amp;lt;% end %&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/questionnaires/_questionnaire.html.erb -''' This partial file is called by new.html.erb when anew question is created. Same logic and changes as above.&lt;br /&gt;
'''3. views/questionnaires/_criterion_edit.html.erb -''' This file has all the html code that was earlier in the edit method of the criterion model. We changed the variables from &amp;quot;self.xxx&amp;quot; to &amp;quot;@question.xxx&amp;quot; because self was referring to question object in this context. Apart from this we changed the code to erb format. No more changes were deemed necessary. Please refer to the pull request to refer to the changes in this file as they are pure html and really long to be put in this wiki.&lt;br /&gt;
&lt;br /&gt;
{| role=&amp;quot;presentation&amp;quot; class=&amp;quot;wikitable mw-collapsible&amp;quot;&lt;br /&gt;
| &amp;lt;strong&amp;gt;Code&amp;lt;/strong&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| asdasdasd&lt;br /&gt;
|asda&lt;br /&gt;
|sd &lt;br /&gt;
|asd &lt;br /&gt;
|as&lt;br /&gt;
|d &lt;br /&gt;
|as&lt;br /&gt;
|d &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===The view_completed_question Method===&lt;br /&gt;
&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1.&lt;/div&gt;</summary>
		<author><name>Amadhus2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=E1911_Refactor_Criterion&amp;diff=122898</id>
		<title>E1911 Refactor Criterion</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=E1911_Refactor_Criterion&amp;diff=122898"/>
		<updated>2019-04-01T22:23:21Z</updated>

		<summary type="html">&lt;p&gt;Amadhus2: /* Affected View Files */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=E1911 Refactoring criterion.rb=&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create new assignments and customize new or existing assignments. It also allows the instructor to create a list of topics the students can sign up for. Students can form teams in Expertiza to work on various projects and assignments. Students can also peer review other students' submissions. Expertiza supports submission across various document types, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The bulk of the code in criterion is HTML. It is the violation of MVC architecture - Model should not concern itself with how the data is displayed. This code needs to be moved to a partial file, and the partial file needs to be called in all appropriate places which call the criterion’s model methods. Once the logic for the view is moved out of the model, the model should only be left with business logic. This business logic code can also be refactored. Plus there are virtually no comments, properly comment the code.&lt;br /&gt;
&lt;br /&gt;
==About Criterion.rb==&lt;br /&gt;
Criterion is one of the types of questions that can be added to a questionnaire. There are many other types of question objects like dropdown that have the implementation of similar methods. As of now, the criterion model holds 4 methods that are called from different places in the application. Each of these methods is storing a string value which contains the necessary HTML lines to display the required functionalities to the user. This string value is then returned to the calling methods from the respective views. This HTML string is then entered wherever necessary. This is ideally the exact function of a partial, and this page needs to be heavily reformatted to use partials instead of returning a string containing html code.&lt;br /&gt;
&lt;br /&gt;
===The pull request===&lt;br /&gt;
https://github.com/expertiza/expertiza/pull/1407&lt;br /&gt;
&lt;br /&gt;
===The edit method===&lt;br /&gt;
This method is one of the several other methods in other files like criterion.rb which gets called when the type of the question being created in the respective model. In the case of this problem, which deals with criterion type questions, the edit method defined in criterion.rb is called when the question.type is equal to &amp;quot;Criterion&amp;quot;. This method allows for a user to create the criterion question and enter the necessary details. This method is called only from two view files - one for creating (_questionnaire.html.erb partial file) and another for editing (edit.html.erb). Both these files are in questionnaires view. Verified this using both RubyMine and the grep command. Another interesting thing to note is the use of &amp;quot;self.&amp;quot; to get the attributes associated with question object. When we move this code to a partial, we need to change this in the erb file. The outcome of this method's refactoring will completely remove this method from the model file criterion.rb as there is no business logic involved here.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def edit(_count)&lt;br /&gt;
    html = '&amp;lt;td align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;a rel=&amp;quot;nofollow&amp;quot; data-method=&amp;quot;delete&amp;quot; href=&amp;quot;/questions/' + self.id.to_s + '&amp;quot;&amp;gt;Remove&amp;lt;/a&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;6&amp;quot; value=&amp;quot;' + self.seq.to_s + '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][seq]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_seq&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;textarea cols=&amp;quot;50&amp;quot; rows=&amp;quot;1&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][txt]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_txt&amp;quot; placeholder=&amp;quot;Edit question content here&amp;quot;&amp;gt;' + self.txt + '&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;10&amp;quot; disabled=&amp;quot;disabled&amp;quot; value=&amp;quot;' + self.type + '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][type]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_type&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;2&amp;quot; value=&amp;quot;' + self.weight.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][weight]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_weight&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;text area size &amp;lt;input size=&amp;quot;3&amp;quot; value=&amp;quot;' + self.size.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][size]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_size&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt; max_label &amp;lt;input size=&amp;quot;10&amp;quot; value=&amp;quot;' + self.max_label.to_s + '&amp;quot; name=&amp;quot;question[' + self.id.to_s&lt;br /&gt;
    html += '][max_label]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_max_label&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;  min_label &amp;lt;input size=&amp;quot;12&amp;quot; value=&amp;quot;' + self.min_label.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][min_label]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_min_label&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    safe_join([&amp;quot;&amp;lt;tr&amp;gt;&amp;quot;.html_safe, &amp;quot;&amp;lt;/tr&amp;gt;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The safe_join is later used to return the HTML string to the calling view.&lt;br /&gt;
&lt;br /&gt;
===The view_question_text method===&lt;br /&gt;
This method has the same explanation as the edit method except the fact that this method is called only during viewing of questionnaires by an instructor. We observed that this method is also called by in student_quiz view. On further analysis, we found that the student_quiz does not use criterion object and has only three options: TrueFalse, MultipleChoiceRadio and MultipleChoiceCheckbox. So no refactoring is required here. Verified this method isn't called anywhere else using RubyMine and grep command. The outcome of this method's refactoring will completely remove this method from the model file criterion.rb as there is no business logic in this method and is completely html code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def view_question_text&lt;br /&gt;
    html = '&amp;lt;TD align=&amp;quot;left&amp;quot;&amp;gt; ' + self.txt + ' &amp;lt;/TD&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;TD align=&amp;quot;left&amp;quot;&amp;gt;' + self.type + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;td align=&amp;quot;center&amp;quot;&amp;gt;' + self.weight.to_s + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    questionnaire = self.questionnaire&lt;br /&gt;
    if !self.max_label.nil? &amp;amp;&amp;amp; !self.min_label.nil?&lt;br /&gt;
      html += '&amp;lt;TD align=&amp;quot;center&amp;quot;&amp;gt; (' + self.min_label + ') ' + questionnaire.min_question_score.to_s&lt;br /&gt;
      html += ' to ' + questionnaire.max_question_score.to_s + ' (' + self.max_label + ')&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    else&lt;br /&gt;
      html += '&amp;lt;TD align=&amp;quot;center&amp;quot;&amp;gt;' + questionnaire.min_question_score.to_s + ' to ' + questionnaire.max_question_score.to_s + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    safe_join([&amp;quot;&amp;lt;TR&amp;gt;&amp;quot;.html_safe, &amp;quot;&amp;lt;/TR&amp;gt;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===The complete method===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===The view_completed_question method===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Proposed Solution==&lt;br /&gt;
All these methods contain HTML text. What we propose to do is to pick these lines of code and move them into an appropriate partial, in the required format. The next task is to find out where in the entire application do these methods get called. The multiple overriding of the method calls in this poorly structured application makes it a challenging task. These method-calls then have to be replaced with the appropriate rendering of a partial in the views. This would make the structure more MVC oriented, and help keep it clean and understandable for the next developer who accesses this file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Implementation==&lt;br /&gt;
The changes proposed above were implemented as described below.&lt;br /&gt;
&lt;br /&gt;
===The Edit Method===&lt;br /&gt;
All the code in the model was just html and thus was completely removed from there. It was moved to the partial file (views/questionnaires/_criterion_edit.html.rb) and the necessary changes were made. Since it was all HTML code, no comments were actually required. However, we still added comments describing the partial file itself. Other comments were added whenever changes were made.&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/questionnaires/edit.html.erb -''' This file calls the edit method for all types of question objects and the object type takes care of invoking the right overridden method. We modified this file to call the partial instead of edit method only for Criterion type of question objects. This view is invoked during edit on the questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% for @question in @questionnaire.questions %&amp;gt;&lt;br /&gt;
-   &amp;lt;%-# The following line call certain method of the object, which returns html string-%&amp;gt;&lt;br /&gt;
+   &amp;lt;%# E1911: Call the criterion_edit partial if question is of type Criterion -%&amp;gt;&lt;br /&gt;
+   &amp;lt;% if @question.is_a? Criterion %&amp;gt;&lt;br /&gt;
+     &amp;lt;%= render :partial =&amp;gt; 'criterion_edit' %&amp;gt;&lt;br /&gt;
+   &amp;lt;% else %&amp;gt;&lt;br /&gt;
      &amp;lt;%=@question.edit%&amp;gt;&lt;br /&gt;
+ &amp;lt;% end %&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/questionnaires/_questionnaire.html.erb -''' This partial file is called by new.html.erb when anew question is created. Same logic and changes as above.&lt;br /&gt;
'''3. views/questionnaires/_criterion_edit.html.erb -''' This file has all the html code that was earlier in the edit method of the criterion model. We changed the variables from &amp;quot;self.xxx&amp;quot; to &amp;quot;@question.xxx&amp;quot; because self was referring to question object in this context. Apart from this we changed the code to erb format. No more changes were deemed necessary. Please refer to the pull request to refer to the changes in this file as they are pure html and really long to be put in this wiki.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===The view_question_text Method===&lt;br /&gt;
This method did not contain any business logic and thus all code was formatted and moved to a new partial file (views/questionnaires/_criterion_view.html.erb). Again, no comments were required due to complete html code and a comment describing the partial was added in addition to other necessary comments in other files.&lt;br /&gt;
&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/questionnaires/view.html.erb -''' Modified to invoke the partial if question is of type Criterion only. Also changed the question variable to a instance variable (question =&amp;gt; @question) to extend it's scope to the partial. This view is invoked during the view of questions in a questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- &amp;lt;%questions.each do |question| %&amp;gt;&lt;br /&gt;
-   &amp;lt;%if question.is_a? Question%&amp;gt;&lt;br /&gt;
-     &amp;lt;%=question.view_question_text.html_safe%&amp;gt;&lt;br /&gt;
+ &amp;lt;% for @question in questions %&amp;gt;&lt;br /&gt;
+   &amp;lt;%# E1911: Call the criterion_view partial if question is of type Criterion %&amp;gt;&lt;br /&gt;
+   &amp;lt;%if @question.is_a? Criterion %&amp;gt;&lt;br /&gt;
+         &amp;lt;%= render :partial =&amp;gt; 'criterion_view' %&amp;gt;&lt;br /&gt;
+     &amp;lt;%elsif @question.is_a? Question%&amp;gt;&lt;br /&gt;
+         &amp;lt;%= @question.view_question_text.html_safe %&amp;gt;&lt;br /&gt;
    &amp;lt;%end%&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/questionnaires/_criterion_view.html.erb -''' This partial file has the moved html code from view_question_text. Note that the &amp;quot;self.xxx&amp;quot; have been updated to &amp;quot;@question.xxx&amp;quot; as self referred to question object discussed in 1. Comment added to describe the partial file. Refer the pull request to look at the code.&lt;br /&gt;
&lt;br /&gt;
===The complete Method===&lt;br /&gt;
All the code in the model included html thus was completely removed from there. It was moved to the partial file (app/views/questionnaires/_criterion_edit.html.erb) and the necessary changes were made. Since it was all HTML code, no comments were actually required. However, we still added comments describing the partial file itself. Other comments were added whenever changes were made.&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/questionnaires/edit.html.erb -''' This file calls the edit method for all types of question objects and the object type takes care of invoking the right overridden method. We modified this file to call the partial instead of edit method only for Criterion type of question objects. This view is invoked during edit on the questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% for @question in @questionnaire.questions %&amp;gt;&lt;br /&gt;
-   &amp;lt;%-# The following line call certain method of the object, which returns html string-%&amp;gt;&lt;br /&gt;
+   &amp;lt;%# E1911: Call the criterion_edit partial if question is of type Criterion -%&amp;gt;&lt;br /&gt;
+   &amp;lt;% if @question.is_a? Criterion %&amp;gt;&lt;br /&gt;
+     &amp;lt;%= render :partial =&amp;gt; 'criterion_edit' %&amp;gt;&lt;br /&gt;
+   &amp;lt;% else %&amp;gt;&lt;br /&gt;
      &amp;lt;%=@question.edit%&amp;gt;&lt;br /&gt;
+ &amp;lt;% end %&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/questionnaires/_questionnaire.html.erb -''' This partial file is called by new.html.erb when anew question is created. Same logic and changes as above.&lt;br /&gt;
'''3. views/questionnaires/_criterion_edit.html.erb -''' This file has all the html code that was earlier in the edit method of the criterion model. We changed the variables from &amp;quot;self.xxx&amp;quot; to &amp;quot;@question.xxx&amp;quot; because self was referring to question object in this context. Apart from this we changed the code to erb format. No more changes were deemed necessary. Please refer to the pull request to refer to the changes in this file as they are pure html and really long to be put in this wiki.&lt;br /&gt;
&lt;br /&gt;
{| role=&amp;quot;presentation&amp;quot; class=&amp;quot;wikitable mw-collapsible&amp;quot;&lt;br /&gt;
| &amp;lt;strong&amp;gt;Code&amp;lt;/strong&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| asdasdasd&lt;br /&gt;
asda&lt;br /&gt;
sd &lt;br /&gt;
asd &lt;br /&gt;
as&lt;br /&gt;
d &lt;br /&gt;
as&lt;br /&gt;
d &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===The view_completed_question Method===&lt;br /&gt;
&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1.&lt;/div&gt;</summary>
		<author><name>Amadhus2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=E1911_Refactor_Criterion&amp;diff=122897</id>
		<title>E1911 Refactor Criterion</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=E1911_Refactor_Criterion&amp;diff=122897"/>
		<updated>2019-04-01T22:22:25Z</updated>

		<summary type="html">&lt;p&gt;Amadhus2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=E1911 Refactoring criterion.rb=&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==About Expertiza==&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create new assignments and customize new or existing assignments. It also allows the instructor to create a list of topics the students can sign up for. Students can form teams in Expertiza to work on various projects and assignments. Students can also peer review other students' submissions. Expertiza supports submission across various document types, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Problem Statement==&lt;br /&gt;
The bulk of the code in criterion is HTML. It is the violation of MVC architecture - Model should not concern itself with how the data is displayed. This code needs to be moved to a partial file, and the partial file needs to be called in all appropriate places which call the criterion’s model methods. Once the logic for the view is moved out of the model, the model should only be left with business logic. This business logic code can also be refactored. Plus there are virtually no comments, properly comment the code.&lt;br /&gt;
&lt;br /&gt;
==About Criterion.rb==&lt;br /&gt;
Criterion is one of the types of questions that can be added to a questionnaire. There are many other types of question objects like dropdown that have the implementation of similar methods. As of now, the criterion model holds 4 methods that are called from different places in the application. Each of these methods is storing a string value which contains the necessary HTML lines to display the required functionalities to the user. This string value is then returned to the calling methods from the respective views. This HTML string is then entered wherever necessary. This is ideally the exact function of a partial, and this page needs to be heavily reformatted to use partials instead of returning a string containing html code.&lt;br /&gt;
&lt;br /&gt;
===The pull request===&lt;br /&gt;
https://github.com/expertiza/expertiza/pull/1407&lt;br /&gt;
&lt;br /&gt;
===The edit method===&lt;br /&gt;
This method is one of the several other methods in other files like criterion.rb which gets called when the type of the question being created in the respective model. In the case of this problem, which deals with criterion type questions, the edit method defined in criterion.rb is called when the question.type is equal to &amp;quot;Criterion&amp;quot;. This method allows for a user to create the criterion question and enter the necessary details. This method is called only from two view files - one for creating (_questionnaire.html.erb partial file) and another for editing (edit.html.erb). Both these files are in questionnaires view. Verified this using both RubyMine and the grep command. Another interesting thing to note is the use of &amp;quot;self.&amp;quot; to get the attributes associated with question object. When we move this code to a partial, we need to change this in the erb file. The outcome of this method's refactoring will completely remove this method from the model file criterion.rb as there is no business logic involved here.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def edit(_count)&lt;br /&gt;
    html = '&amp;lt;td align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;a rel=&amp;quot;nofollow&amp;quot; data-method=&amp;quot;delete&amp;quot; href=&amp;quot;/questions/' + self.id.to_s + '&amp;quot;&amp;gt;Remove&amp;lt;/a&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;6&amp;quot; value=&amp;quot;' + self.seq.to_s + '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][seq]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_seq&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;textarea cols=&amp;quot;50&amp;quot; rows=&amp;quot;1&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][txt]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_txt&amp;quot; placeholder=&amp;quot;Edit question content here&amp;quot;&amp;gt;' + self.txt + '&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;10&amp;quot; disabled=&amp;quot;disabled&amp;quot; value=&amp;quot;' + self.type + '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][type]&amp;quot;'&lt;br /&gt;
    html += ' id=&amp;quot;question_' + self.id.to_s + '_type&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;&amp;lt;input size=&amp;quot;2&amp;quot; value=&amp;quot;' + self.weight.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][weight]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_weight&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt;text area size &amp;lt;input size=&amp;quot;3&amp;quot; value=&amp;quot;' + self.size.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][size]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_size&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    html += '&amp;lt;td&amp;gt; max_label &amp;lt;input size=&amp;quot;10&amp;quot; value=&amp;quot;' + self.max_label.to_s + '&amp;quot; name=&amp;quot;question[' + self.id.to_s&lt;br /&gt;
    html += '][max_label]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_max_label&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;  min_label &amp;lt;input size=&amp;quot;12&amp;quot; value=&amp;quot;' + self.min_label.to_s&lt;br /&gt;
    html += '&amp;quot; name=&amp;quot;question[' + self.id.to_s + '][min_label]&amp;quot; id=&amp;quot;question_' + self.id.to_s + '_min_label&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
    safe_join([&amp;quot;&amp;lt;tr&amp;gt;&amp;quot;.html_safe, &amp;quot;&amp;lt;/tr&amp;gt;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The safe_join is later used to return the HTML string to the calling view.&lt;br /&gt;
&lt;br /&gt;
===The view_question_text method===&lt;br /&gt;
This method has the same explanation as the edit method except the fact that this method is called only during viewing of questionnaires by an instructor. We observed that this method is also called by in student_quiz view. On further analysis, we found that the student_quiz does not use criterion object and has only three options: TrueFalse, MultipleChoiceRadio and MultipleChoiceCheckbox. So no refactoring is required here. Verified this method isn't called anywhere else using RubyMine and grep command. The outcome of this method's refactoring will completely remove this method from the model file criterion.rb as there is no business logic in this method and is completely html code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def view_question_text&lt;br /&gt;
    html = '&amp;lt;TD align=&amp;quot;left&amp;quot;&amp;gt; ' + self.txt + ' &amp;lt;/TD&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;TD align=&amp;quot;left&amp;quot;&amp;gt;' + self.type + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    html += '&amp;lt;td align=&amp;quot;center&amp;quot;&amp;gt;' + self.weight.to_s + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    questionnaire = self.questionnaire&lt;br /&gt;
    if !self.max_label.nil? &amp;amp;&amp;amp; !self.min_label.nil?&lt;br /&gt;
      html += '&amp;lt;TD align=&amp;quot;center&amp;quot;&amp;gt; (' + self.min_label + ') ' + questionnaire.min_question_score.to_s&lt;br /&gt;
      html += ' to ' + questionnaire.max_question_score.to_s + ' (' + self.max_label + ')&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    else&lt;br /&gt;
      html += '&amp;lt;TD align=&amp;quot;center&amp;quot;&amp;gt;' + questionnaire.min_question_score.to_s + ' to ' + questionnaire.max_question_score.to_s + '&amp;lt;/TD&amp;gt;'&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    safe_join([&amp;quot;&amp;lt;TR&amp;gt;&amp;quot;.html_safe, &amp;quot;&amp;lt;/TR&amp;gt;&amp;quot;.html_safe], html.html_safe)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===The complete method===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===The view_completed_question method===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Proposed Solution==&lt;br /&gt;
All these methods contain HTML text. What we propose to do is to pick these lines of code and move them into an appropriate partial, in the required format. The next task is to find out where in the entire application do these methods get called. The multiple overriding of the method calls in this poorly structured application makes it a challenging task. These method-calls then have to be replaced with the appropriate rendering of a partial in the views. This would make the structure more MVC oriented, and help keep it clean and understandable for the next developer who accesses this file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Implementation==&lt;br /&gt;
The changes proposed above were implemented as described below.&lt;br /&gt;
&lt;br /&gt;
===The Edit Method===&lt;br /&gt;
All the code in the model was just html and thus was completely removed from there. It was moved to the partial file (views/questionnaires/_criterion_edit.html.rb) and the necessary changes were made. Since it was all HTML code, no comments were actually required. However, we still added comments describing the partial file itself. Other comments were added whenever changes were made.&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/questionnaires/edit.html.erb -''' This file calls the edit method for all types of question objects and the object type takes care of invoking the right overridden method. We modified this file to call the partial instead of edit method only for Criterion type of question objects. This view is invoked during edit on the questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% for @question in @questionnaire.questions %&amp;gt;&lt;br /&gt;
-   &amp;lt;%-# The following line call certain method of the object, which returns html string-%&amp;gt;&lt;br /&gt;
+   &amp;lt;%# E1911: Call the criterion_edit partial if question is of type Criterion -%&amp;gt;&lt;br /&gt;
+   &amp;lt;% if @question.is_a? Criterion %&amp;gt;&lt;br /&gt;
+     &amp;lt;%= render :partial =&amp;gt; 'criterion_edit' %&amp;gt;&lt;br /&gt;
+   &amp;lt;% else %&amp;gt;&lt;br /&gt;
      &amp;lt;%=@question.edit%&amp;gt;&lt;br /&gt;
+ &amp;lt;% end %&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/questionnaires/_questionnaire.html.erb -''' This partial file is called by new.html.erb when anew question is created. Same logic and changes as above.&lt;br /&gt;
'''3. views/questionnaires/_criterion_edit.html.erb -''' This file has all the html code that was earlier in the edit method of the criterion model. We changed the variables from &amp;quot;self.xxx&amp;quot; to &amp;quot;@question.xxx&amp;quot; because self was referring to question object in this context. Apart from this we changed the code to erb format. No more changes were deemed necessary. Please refer to the pull request to refer to the changes in this file as they are pure html and really long to be put in this wiki.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===The view_question_text Method===&lt;br /&gt;
This method did not contain any business logic and thus all code was formatted and moved to a new partial file (views/questionnaires/_criterion_view.html.erb). Again, no comments were required due to complete html code and a comment describing the partial was added in addition to other necessary comments in other files.&lt;br /&gt;
&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/questionnaires/view.html.erb -''' Modified to invoke the partial if question is of type Criterion only. Also changed the question variable to a instance variable (question =&amp;gt; @question) to extend it's scope to the partial. This view is invoked during the view of questions in a questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- &amp;lt;%questions.each do |question| %&amp;gt;&lt;br /&gt;
-   &amp;lt;%if question.is_a? Question%&amp;gt;&lt;br /&gt;
-     &amp;lt;%=question.view_question_text.html_safe%&amp;gt;&lt;br /&gt;
+ &amp;lt;% for @question in questions %&amp;gt;&lt;br /&gt;
+   &amp;lt;%# E1911: Call the criterion_view partial if question is of type Criterion %&amp;gt;&lt;br /&gt;
+   &amp;lt;%if @question.is_a? Criterion %&amp;gt;&lt;br /&gt;
+         &amp;lt;%= render :partial =&amp;gt; 'criterion_view' %&amp;gt;&lt;br /&gt;
+     &amp;lt;%elsif @question.is_a? Question%&amp;gt;&lt;br /&gt;
+         &amp;lt;%= @question.view_question_text.html_safe %&amp;gt;&lt;br /&gt;
    &amp;lt;%end%&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/questionnaires/_criterion_view.html.erb -''' This partial file has the moved html code from view_question_text. Note that the &amp;quot;self.xxx&amp;quot; have been updated to &amp;quot;@question.xxx&amp;quot; as self referred to question object discussed in 1. Comment added to describe the partial file. Refer the pull request to look at the code.&lt;br /&gt;
&lt;br /&gt;
===The complete Method===&lt;br /&gt;
All the code in the model included html thus was completely removed from there. It was moved to the partial file (app/views/questionnaires/_criterion_edit.html.erb) and the necessary changes were made. Since it was all HTML code, no comments were actually required. However, we still added comments describing the partial file itself. Other comments were added whenever changes were made.&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1. views/questionnaires/edit.html.erb -''' This file calls the edit method for all types of question objects and the object type takes care of invoking the right overridden method. We modified this file to call the partial instead of edit method only for Criterion type of question objects. This view is invoked during edit on the questionnaire. Here are the changes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% for @question in @questionnaire.questions %&amp;gt;&lt;br /&gt;
-   &amp;lt;%-# The following line call certain method of the object, which returns html string-%&amp;gt;&lt;br /&gt;
+   &amp;lt;%# E1911: Call the criterion_edit partial if question is of type Criterion -%&amp;gt;&lt;br /&gt;
+   &amp;lt;% if @question.is_a? Criterion %&amp;gt;&lt;br /&gt;
+     &amp;lt;%= render :partial =&amp;gt; 'criterion_edit' %&amp;gt;&lt;br /&gt;
+   &amp;lt;% else %&amp;gt;&lt;br /&gt;
      &amp;lt;%=@question.edit%&amp;gt;&lt;br /&gt;
+ &amp;lt;% end %&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. views/questionnaires/_questionnaire.html.erb -''' This partial file is called by new.html.erb when anew question is created. Same logic and changes as above.&lt;br /&gt;
'''3. views/questionnaires/_criterion_edit.html.erb -''' This file has all the html code that was earlier in the edit method of the criterion model. We changed the variables from &amp;quot;self.xxx&amp;quot; to &amp;quot;@question.xxx&amp;quot; because self was referring to question object in this context. Apart from this we changed the code to erb format. No more changes were deemed necessary. Please refer to the pull request to refer to the changes in this file as they are pure html and really long to be put in this wiki.&lt;br /&gt;
&lt;br /&gt;
{| role=&amp;quot;presentation&amp;quot; class=&amp;quot;wikitable mw-collapsible&amp;quot;&lt;br /&gt;
| &amp;lt;strong&amp;gt;Code&amp;lt;/strong&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| asdasdasd&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===The view_completed_question Method===&lt;br /&gt;
&lt;br /&gt;
====Affected View Files====&lt;br /&gt;
'''1.&lt;/div&gt;</summary>
		<author><name>Amadhus2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=E1911_Refactor_Criterion&amp;diff=122339</id>
		<title>E1911 Refactor Criterion</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=E1911_Refactor_Criterion&amp;diff=122339"/>
		<updated>2019-03-26T00:29:31Z</updated>

		<summary type="html">&lt;p&gt;Amadhus2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==E1911 Refactoring criterion.rb==&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===About Expertiza===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create new assignments and customize new or existing assignments. It also allows the instructor to create a list of topics the students can sign up for. Students can form teams in Expertiza to work on various projects and assignments. Students can also peer review other students' submissions. Expertiza supports submission across various document types, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The bulk of the code in criterion is HTML. It is the violation of MVC architecture - Model should not concern itself with how the data is displayed. This code needs to be moved to a partial file, and the partial file needs to be called in all appropriate places which call the criterion’s model methods. Once the logic for view is moved out of the model, model should only be left with business logic. This business logic code can also be refactored. Plus there are virtually no comments, properly comment the code.&lt;/div&gt;</summary>
		<author><name>Amadhus2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=E1911_Refactor_Criterion&amp;diff=122313</id>
		<title>E1911 Refactor Criterion</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=E1911_Refactor_Criterion&amp;diff=122313"/>
		<updated>2019-03-26T00:08:48Z</updated>

		<summary type="html">&lt;p&gt;Amadhus2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==E1553. Refactoring the Versions Controller==&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===About Expertiza===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create new assignments and customize new or existing assignments. It also allows the instructor to create a list of topics the students can sign up for. Students can form teams in Expertiza to work on various projects and assignments. Students can also peer review other students' submissions. Expertiza supports submission across various document types, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The bulk of the code in criterion is HTML. It is the violation of MVC architecture - Model should not concern itself with how the data is displayed. This code needs to be moved to a partial file, and the partial file needs to be called in all appropriate places which call the criterion’s model methods. Once the logic for view is moved out of the model, model should only be left with business logic. This business logic code can also be refactored. Plus there are virtually no comments, properly comment the code.&lt;br /&gt;
&lt;br /&gt;
===About Versions Controller===&lt;br /&gt;
This class manages different versions of reviews. If a reviewer reviews a submission, and after that, the author revises the submission, the next time the reviewer does a review (s)he will create a new version. Sometimes it’s necessary to find the current version of a review; sometimes it’s necessary to find all versions. Similarly, a user may want to delete the current version of a review, or all versions of a review. Pagination of versions helps the user to view a subset of versions at a time. Considering the huge number of versions in the system, it is very useful to have a pagination mechanism and a filtering mechanism which can be applied on the whole set of versions. The idea is to display the versions in an ordered, comprehensible and logical manner. In Expertiza the gem ‘will_paginate’ is used to achieve pagination.&lt;br /&gt;
&lt;br /&gt;
===Current Implementation===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=====Functionality=====&lt;br /&gt;
* Any user irrespective of his/ her privileges can view all the versions.&lt;br /&gt;
::The versions which a particular user can view should be restricted based on the privileges of the user. For instance, only a user with Administrator privileges should be able to view all the versions in the system. However, that is not the case now. Every user can view all the versions irrespective of whether the user is a student or an administrator.&lt;br /&gt;
* Any user can delete any version&lt;br /&gt;
::The versions which a particular user can delete should be restricted based on the privileges of the user. For instance, a student should not be allowed to delete any version. According to the current implementation any user can delete any version in the system.&lt;br /&gt;
* Filtering of versions were restricted to the current user&lt;br /&gt;
::The filtering options on versions were restricted to the current user. Sometimes a user might want to view versions associated with other users. For instance, an instructor might want to view the list of versions created by a particular student. This is not possible with the current implementation.&lt;br /&gt;
&lt;br /&gt;
=====Drawbacks and Solutions=====&lt;br /&gt;
* '''Problem 1''': The method paginate_list is doing more than one thing.&lt;br /&gt;
::The method paginate_list was building a complex search criteria based on the input params, getting the list of versions from the Database matching this search criteria and then calling the Page API. All these tasks in a single method made it difficult to understand.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# For filtering the versions list with proper search and pagination.&lt;br /&gt;
  def paginate_list(id, user_id, item_type, event, datetime)&lt;br /&gt;
    # Set up the search criteria&lt;br /&gt;
    criteria = ''&lt;br /&gt;
    criteria = criteria + &amp;quot;id = #{id} AND &amp;quot; if id &amp;amp;&amp;amp; id.to_i &amp;gt; 0&lt;br /&gt;
    if current_user_role? == 'Super-Administrator'&lt;br /&gt;
      criteria = criteria + &amp;quot;whodunnit = #{user_id} AND &amp;quot; if user_id &amp;amp;&amp;amp; user_id.to_i &amp;gt; 0&lt;br /&gt;
    end&lt;br /&gt;
    criteria = criteria + &amp;quot;whodunnit = #{current_user.try(:id)} AND &amp;quot; if current_user.try(:id) &amp;amp;&amp;amp; current_user.try(:id).to_i &amp;gt; 0&lt;br /&gt;
    criteria = criteria + &amp;quot;item_type = '#{item_type}' AND &amp;quot; if item_type &amp;amp;&amp;amp; !(item_type.eql? 'Any')&lt;br /&gt;
    criteria = criteria + &amp;quot;event = '#{event}' AND &amp;quot; if event &amp;amp;&amp;amp; !(event.eql? 'Any')&lt;br /&gt;
    criteria = criteria + &amp;quot;created_at &amp;gt;= '#{time_to_string(params[:start_time])}' AND &amp;quot;&lt;br /&gt;
    criteria = criteria + &amp;quot;created_at &amp;lt;= '#{time_to_string(params[:end_time])}' AND &amp;quot;&lt;br /&gt;
&lt;br /&gt;
    if current_role == 'Instructor' || current_role == 'Administrator'&lt;br /&gt;
&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Remove the last ' AND '&lt;br /&gt;
    criteria = criteria[0..-5]&lt;br /&gt;
&lt;br /&gt;
    versions = Version.page(params[:page]).order('id').per_page(25).where(criteria)&lt;br /&gt;
    versions&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* '''Solution''': The implementation has been changed in such a way that the versions which a user is allowed to see depends on the privileges of the user. The approach we have taken is as follows:&lt;br /&gt;
**An administrator can see all the versions&lt;br /&gt;
**An instructor can see all the versions created by him and other users who are in his course or are participants in the assignments he creates.&lt;br /&gt;
**A TA can see all the versions created by him and other users who are in the course for which he/ she assists.&lt;br /&gt;
**A Student can see all the versions created by him/ her.&lt;br /&gt;
* '''Problem 2''': The search criteria created in the method paginate_list was difficult to comprehend.&lt;br /&gt;
::The code which builds the search criteria in the method paginate_list uses many string literals and conditions and is hardly intuitive. The programmer will have to spend some time to understand what the code is really doing.&lt;br /&gt;
* '''Solution''': The implementation has been changed. A student is not allowed to delete any versions now. Other types of users, for instance administrators, instructors and TAs are allowed to delete only the versions they are authorized to view.&lt;br /&gt;
* '''Problem 3''': The paginate method can be moved to a helper class.&lt;br /&gt;
::VersionsController is not the only component which require to paginate items. There are other components too. For instance, the UsersController has to paginate the list of users. Hence the Paginate method can be moved to a helper class which can be accessed by other components as well.&lt;br /&gt;
* '''Solution''': The filtering options has also been enhanced. The current user can now choose as part of the version search filter any user from a list of users if the current user is authorized to see the versions created by that user.&lt;br /&gt;
&lt;br /&gt;
===New Implementation===&lt;br /&gt;
*The method paginate_list has been split into 2 methods now. &lt;br /&gt;
** BuildSearchCriteria – as the name suggests the sole purpose of this method is to build a search criteria based on the input search filters when the current user initiates a search in versions.&lt;br /&gt;
** paginate_list – this method will call the paginate API.&lt;br /&gt;
:First the search criteria is built, then the criteria is applied to versions in the database to get all versions which matches the criteria and then the retrieved versions are paginated.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  # pagination.&lt;br /&gt;
  def paginate_list(versions)&lt;br /&gt;
    paginate(versions, VERSIONS_PER_PAGE);&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def BuildSearchCriteria(id, user_id, item_type, event)&lt;br /&gt;
    # Set up the search criteria&lt;br /&gt;
    search_criteria = ''&lt;br /&gt;
    search_criteria = search_criteria + add_id_filter_if_valid(id).to_s&lt;br /&gt;
    if current_user_role? == 'Super-Administrator'&lt;br /&gt;
      search_criteria = search_criteria + add_user_filter_for_super_admin(user_id).to_s&lt;br /&gt;
    end&lt;br /&gt;
    search_criteria = search_criteria + add_user_filter&lt;br /&gt;
    search_criteria = search_criteria + add_version_type_filter(item_type).to_s&lt;br /&gt;
    search_criteria = search_criteria + add_event_filter(event).to_s&lt;br /&gt;
    search_criteria = search_criteria + add_date_time_filter&lt;br /&gt;
    search_criteria&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The string literals and conditions in the method paginate_list were replaced with methods with intuitive names so that the programmer can understand the code more easily. We also removed an empty if clause and a redundant statement.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def add_id_filter_if_valid (id)&lt;br /&gt;
    &amp;quot;id = #{id} AND &amp;quot; if id &amp;amp;&amp;amp; id.to_i &amp;gt; 0&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def add_user_filter_for_super_admin (user_id)&lt;br /&gt;
    &amp;quot;whodunnit = #{user_id} AND &amp;quot; if user_id &amp;amp;&amp;amp; user_id.to_i &amp;gt; 0&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def add_user_filter&lt;br /&gt;
    &amp;quot;whodunnit = #{current_user.try(:id)} AND &amp;quot; if current_user.try(:id) &amp;amp;&amp;amp; current_user.try(:id).to_i &amp;gt; 0&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def add_event_filter (event)&lt;br /&gt;
    &amp;quot;event = '#{event}' AND &amp;quot; if event &amp;amp;&amp;amp; !(event.eql? 'Any')&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def add_date_time_filter&lt;br /&gt;
    &amp;quot;created_at &amp;gt;= '#{time_to_string(params[:start_time])}' AND &amp;quot; +&lt;br /&gt;
        &amp;quot;created_at &amp;lt;= '#{time_to_string(params[:end_time])}'&amp;quot;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def add_version_type_filter (version_type)&lt;br /&gt;
    &amp;quot;item_type = '#{version_type}' AND &amp;quot; if version_type &amp;amp;&amp;amp; !(version_type.eql? 'Any')&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The paginate method has been moved to the helper class Pagination_Helper. This new method can be now reused by the different components like UsersController etc. The method receives two parameters, first the list to paginate and second the number of items to be displayed in a page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
module PaginationHelper&lt;br /&gt;
&lt;br /&gt;
  def paginate (items, number_of_items_per_page)&lt;br /&gt;
    items.page(params[:page]).per_page(number_of_items_per_page)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Code improvements===&lt;br /&gt;
* Introduced a constant VERSIONS_PER_PAGE and assigned the value 25 to it. The pagination algorithm for VersionsController displays at most 25 versions in a page. The existing implementation uses the value 25 straight in the code and there are few problems associated with such an approach.&lt;br /&gt;
** It is not easy to understand what 25 is unless the programmer takes a close look at the code.&lt;br /&gt;
** In case if the value 25 is used at more than one places and in future a new requirement comes to show at most 30 versions in a page, all the values will have to be modified. It is not very DRY.&lt;br /&gt;
* The VersionsController was overriding AccessHelper - action_allowed? method to return true in all the cases. This was violating the whole purpose of the method action_allowed?. The purpose of this method is to determine whether the user who is triggering a CRUD operation is allowed to do so. So when the current user invokes a CRUD operation, the action_allowed? method is invoked first and if the method returns true the CRUD operation is triggered or else the user is intimated with a message and gracefully exited. Hence, when the action_allowed? method is overridden to return true always, it results in providing unauthorized access to certain users.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    true&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:With the new implementation the AccessHelper - action_allowed? method has been modified in such a way that unauthorized access is prevented. As per the new algorithm, 'new', 'create', 'edit', 'update' cannot be invoked by any user. These operations can be accessed only by ‘papertrail’ gem. Only an ‘Administrator’ or ‘Super-Administrator’ can call 'destroy_all' method. All the other methods are accessible to ‘Administrator’,  ‘Super-Administrator’, ‘Instructor’, ‘Teaching Assistant’ and ‘Student’.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'new', 'create', 'edit', 'update'&lt;br /&gt;
    #Modifications can only be done by papertrail&lt;br /&gt;
      return false&lt;br /&gt;
    when 'destroy_all'&lt;br /&gt;
      ['Super-Administrator',&lt;br /&gt;
       'Administrator'].include? current_role_name&lt;br /&gt;
    else&lt;br /&gt;
      #Allow all others&lt;br /&gt;
      ['Super-Administrator',&lt;br /&gt;
       'Administrator',&lt;br /&gt;
       'Instructor',&lt;br /&gt;
       'Teaching Assistant',&lt;br /&gt;
       'Student'].include? current_role_name&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Automated Testing using RSPEC===&lt;br /&gt;
The current version of expertiza did not have any test for VersionsController. Using the test driven development(TDD) approach, we have added an exhaustive set of RSPEC tests for VersionsController, to test all the modifications we have done to the code of the controller class. The tests use double and stub features of rspec-rails gem, to fake the log in by different users - Administrator, Instructor, Student etc. The tests can be executed &amp;quot;rpec spec&amp;quot; command as shown below.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
user-expertiza $rspec spec&lt;br /&gt;
.&lt;br /&gt;
.&lt;br /&gt;
.&lt;br /&gt;
Finished in 5.39 seconds (files took 25.33 seconds to load)&lt;br /&gt;
66 examples, 0 failures&lt;br /&gt;
&lt;br /&gt;
Randomized with seed 19254&lt;br /&gt;
.&lt;br /&gt;
.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Testing from UI===&lt;br /&gt;
Following are a few testcases with respectto our code changes that can be tried from UI:&lt;br /&gt;
1. To go to versions index page, type in the following url after logging in:&lt;br /&gt;
   http://152.46.16.81:3000/versions&lt;br /&gt;
&lt;br /&gt;
2. After logging in as student/instructor or admin : Try accessing the  new, create, edit, update actions. These actions are not allowed to any of the users.&lt;br /&gt;
   http://152.46.16.81:3000/versions/new&lt;br /&gt;
   This calls the new action. In the current production version of expertiza, it is unhandled and application gives a default 404 page.&lt;br /&gt;
&lt;br /&gt;
3. Another feature that can be tested from UI is Pagination. Try searching for a user's versions and see if the results are paginated or not. Search here:&lt;br /&gt;
   http://152.46.16.81:3000/versions/search&lt;br /&gt;
&lt;br /&gt;
4. Visit the same URL as step 3, you should see only the students under that instructor in the users dropdown.&lt;br /&gt;
&lt;br /&gt;
===References===&lt;br /&gt;
&lt;br /&gt;
#[https://github.com/expertiza/expertiza Expertiza on GitHub]&lt;br /&gt;
#[https://github.com/WintersLt/expertiza GitHub Project Repository Fork]&lt;br /&gt;
#[http://expertiza.ncsu.edu/ The live Expertiza website]&lt;br /&gt;
#[http://bit.ly/myexpertiza  Demo link] &lt;br /&gt;
#[http://wikis.lib.ncsu.edu/index.php/Expertiza Expertiza project documentation wiki]&lt;br /&gt;
#[https://relishapp.com/rspec Rspec Documentation]&lt;br /&gt;
#Clean Code: A handbook of agile software craftsmanship. Author: Robert.C.Martin&lt;/div&gt;</summary>
		<author><name>Amadhus2</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=E1911_Refactor_Criterion&amp;diff=122261</id>
		<title>E1911 Refactor Criterion</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=E1911_Refactor_Criterion&amp;diff=122261"/>
		<updated>2019-03-25T22:38:51Z</updated>

		<summary type="html">&lt;p&gt;Amadhus2: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==E1553. Refactoring the Versions Controller==&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===About Expertiza===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create new assignments and customize new or existing assignments. It also allows the instructor to create a list of topics the students can sign up for. Students can form teams in Expertiza to work on various projects and assignments. Students can also peer review other students' submissions. Expertiza supports submission across various document types, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The following tasks were accomplished in this project:&lt;br /&gt;
&lt;br /&gt;
* Improved the clarity of code by improving the variable and parameter names.&lt;br /&gt;
* Long character strings were taken and given appropriate names.&lt;br /&gt;
* Handled pagination by a separate helper module, which can be used by multiple controllers.&lt;br /&gt;
* Implemented action_allowed for access_control to prevent unauthorized access of methods.&lt;br /&gt;
* Prevented displaying of all versions for all users and tables when a user views the index page.&lt;br /&gt;
* Added missing CRUD methods to Versions Controller&lt;br /&gt;
* Added RSPEC testcases for testing changes done in Versions Controller&lt;br /&gt;
&lt;br /&gt;
===About Versions Controller===&lt;br /&gt;
This class manages different versions of reviews. If a reviewer reviews a submission, and after that, the author revises the submission, the next time the reviewer does a review (s)he will create a new version. Sometimes it’s necessary to find the current version of a review; sometimes it’s necessary to find all versions. Similarly, a user may want to delete the current version of a review, or all versions of a review. Pagination of versions helps the user to view a subset of versions at a time. Considering the huge number of versions in the system, it is very useful to have a pagination mechanism and a filtering mechanism which can be applied on the whole set of versions. The idea is to display the versions in an ordered, comprehensible and logical manner. In Expertiza the gem ‘will_paginate’ is used to achieve pagination.&lt;br /&gt;
&lt;br /&gt;
===Current Implementation===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=====Functionality=====&lt;br /&gt;
* Any user irrespective of his/ her privileges can view all the versions.&lt;br /&gt;
::The versions which a particular user can view should be restricted based on the privileges of the user. For instance, only a user with Administrator privileges should be able to view all the versions in the system. However, that is not the case now. Every user can view all the versions irrespective of whether the user is a student or an administrator.&lt;br /&gt;
* Any user can delete any version&lt;br /&gt;
::The versions which a particular user can delete should be restricted based on the privileges of the user. For instance, a student should not be allowed to delete any version. According to the current implementation any user can delete any version in the system.&lt;br /&gt;
* Filtering of versions were restricted to the current user&lt;br /&gt;
::The filtering options on versions were restricted to the current user. Sometimes a user might want to view versions associated with other users. For instance, an instructor might want to view the list of versions created by a particular student. This is not possible with the current implementation.&lt;br /&gt;
&lt;br /&gt;
=====Drawbacks and Solutions=====&lt;br /&gt;
* '''Problem 1''': The method paginate_list is doing more than one thing.&lt;br /&gt;
::The method paginate_list was building a complex search criteria based on the input params, getting the list of versions from the Database matching this search criteria and then calling the Page API. All these tasks in a single method made it difficult to understand.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# For filtering the versions list with proper search and pagination.&lt;br /&gt;
  def paginate_list(id, user_id, item_type, event, datetime)&lt;br /&gt;
    # Set up the search criteria&lt;br /&gt;
    criteria = ''&lt;br /&gt;
    criteria = criteria + &amp;quot;id = #{id} AND &amp;quot; if id &amp;amp;&amp;amp; id.to_i &amp;gt; 0&lt;br /&gt;
    if current_user_role? == 'Super-Administrator'&lt;br /&gt;
      criteria = criteria + &amp;quot;whodunnit = #{user_id} AND &amp;quot; if user_id &amp;amp;&amp;amp; user_id.to_i &amp;gt; 0&lt;br /&gt;
    end&lt;br /&gt;
    criteria = criteria + &amp;quot;whodunnit = #{current_user.try(:id)} AND &amp;quot; if current_user.try(:id) &amp;amp;&amp;amp; current_user.try(:id).to_i &amp;gt; 0&lt;br /&gt;
    criteria = criteria + &amp;quot;item_type = '#{item_type}' AND &amp;quot; if item_type &amp;amp;&amp;amp; !(item_type.eql? 'Any')&lt;br /&gt;
    criteria = criteria + &amp;quot;event = '#{event}' AND &amp;quot; if event &amp;amp;&amp;amp; !(event.eql? 'Any')&lt;br /&gt;
    criteria = criteria + &amp;quot;created_at &amp;gt;= '#{time_to_string(params[:start_time])}' AND &amp;quot;&lt;br /&gt;
    criteria = criteria + &amp;quot;created_at &amp;lt;= '#{time_to_string(params[:end_time])}' AND &amp;quot;&lt;br /&gt;
&lt;br /&gt;
    if current_role == 'Instructor' || current_role == 'Administrator'&lt;br /&gt;
&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Remove the last ' AND '&lt;br /&gt;
    criteria = criteria[0..-5]&lt;br /&gt;
&lt;br /&gt;
    versions = Version.page(params[:page]).order('id').per_page(25).where(criteria)&lt;br /&gt;
    versions&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* '''Solution''': The implementation has been changed in such a way that the versions which a user is allowed to see depends on the privileges of the user. The approach we have taken is as follows:&lt;br /&gt;
**An administrator can see all the versions&lt;br /&gt;
**An instructor can see all the versions created by him and other users who are in his course or are participants in the assignments he creates.&lt;br /&gt;
**A TA can see all the versions created by him and other users who are in the course for which he/ she assists.&lt;br /&gt;
**A Student can see all the versions created by him/ her.&lt;br /&gt;
* '''Problem 2''': The search criteria created in the method paginate_list was difficult to comprehend.&lt;br /&gt;
::The code which builds the search criteria in the method paginate_list uses many string literals and conditions and is hardly intuitive. The programmer will have to spend some time to understand what the code is really doing.&lt;br /&gt;
* '''Solution''': The implementation has been changed. A student is not allowed to delete any versions now. Other types of users, for instance administrators, instructors and TAs are allowed to delete only the versions they are authorized to view.&lt;br /&gt;
* '''Problem 3''': The paginate method can be moved to a helper class.&lt;br /&gt;
::VersionsController is not the only component which require to paginate items. There are other components too. For instance, the UsersController has to paginate the list of users. Hence the Paginate method can be moved to a helper class which can be accessed by other components as well.&lt;br /&gt;
* '''Solution''': The filtering options has also been enhanced. The current user can now choose as part of the version search filter any user from a list of users if the current user is authorized to see the versions created by that user.&lt;br /&gt;
&lt;br /&gt;
===New Implementation===&lt;br /&gt;
*The method paginate_list has been split into 2 methods now. &lt;br /&gt;
** BuildSearchCriteria – as the name suggests the sole purpose of this method is to build a search criteria based on the input search filters when the current user initiates a search in versions.&lt;br /&gt;
** paginate_list – this method will call the paginate API.&lt;br /&gt;
:First the search criteria is built, then the criteria is applied to versions in the database to get all versions which matches the criteria and then the retrieved versions are paginated.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  # pagination.&lt;br /&gt;
  def paginate_list(versions)&lt;br /&gt;
    paginate(versions, VERSIONS_PER_PAGE);&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def BuildSearchCriteria(id, user_id, item_type, event)&lt;br /&gt;
    # Set up the search criteria&lt;br /&gt;
    search_criteria = ''&lt;br /&gt;
    search_criteria = search_criteria + add_id_filter_if_valid(id).to_s&lt;br /&gt;
    if current_user_role? == 'Super-Administrator'&lt;br /&gt;
      search_criteria = search_criteria + add_user_filter_for_super_admin(user_id).to_s&lt;br /&gt;
    end&lt;br /&gt;
    search_criteria = search_criteria + add_user_filter&lt;br /&gt;
    search_criteria = search_criteria + add_version_type_filter(item_type).to_s&lt;br /&gt;
    search_criteria = search_criteria + add_event_filter(event).to_s&lt;br /&gt;
    search_criteria = search_criteria + add_date_time_filter&lt;br /&gt;
    search_criteria&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The string literals and conditions in the method paginate_list were replaced with methods with intuitive names so that the programmer can understand the code more easily. We also removed an empty if clause and a redundant statement.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def add_id_filter_if_valid (id)&lt;br /&gt;
    &amp;quot;id = #{id} AND &amp;quot; if id &amp;amp;&amp;amp; id.to_i &amp;gt; 0&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def add_user_filter_for_super_admin (user_id)&lt;br /&gt;
    &amp;quot;whodunnit = #{user_id} AND &amp;quot; if user_id &amp;amp;&amp;amp; user_id.to_i &amp;gt; 0&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def add_user_filter&lt;br /&gt;
    &amp;quot;whodunnit = #{current_user.try(:id)} AND &amp;quot; if current_user.try(:id) &amp;amp;&amp;amp; current_user.try(:id).to_i &amp;gt; 0&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def add_event_filter (event)&lt;br /&gt;
    &amp;quot;event = '#{event}' AND &amp;quot; if event &amp;amp;&amp;amp; !(event.eql? 'Any')&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def add_date_time_filter&lt;br /&gt;
    &amp;quot;created_at &amp;gt;= '#{time_to_string(params[:start_time])}' AND &amp;quot; +&lt;br /&gt;
        &amp;quot;created_at &amp;lt;= '#{time_to_string(params[:end_time])}'&amp;quot;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def add_version_type_filter (version_type)&lt;br /&gt;
    &amp;quot;item_type = '#{version_type}' AND &amp;quot; if version_type &amp;amp;&amp;amp; !(version_type.eql? 'Any')&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The paginate method has been moved to the helper class Pagination_Helper. This new method can be now reused by the different components like UsersController etc. The method receives two parameters, first the list to paginate and second the number of items to be displayed in a page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
module PaginationHelper&lt;br /&gt;
&lt;br /&gt;
  def paginate (items, number_of_items_per_page)&lt;br /&gt;
    items.page(params[:page]).per_page(number_of_items_per_page)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Code improvements===&lt;br /&gt;
* Introduced a constant VERSIONS_PER_PAGE and assigned the value 25 to it. The pagination algorithm for VersionsController displays at most 25 versions in a page. The existing implementation uses the value 25 straight in the code and there are few problems associated with such an approach.&lt;br /&gt;
** It is not easy to understand what 25 is unless the programmer takes a close look at the code.&lt;br /&gt;
** In case if the value 25 is used at more than one places and in future a new requirement comes to show at most 30 versions in a page, all the values will have to be modified. It is not very DRY.&lt;br /&gt;
* The VersionsController was overriding AccessHelper - action_allowed? method to return true in all the cases. This was violating the whole purpose of the method action_allowed?. The purpose of this method is to determine whether the user who is triggering a CRUD operation is allowed to do so. So when the current user invokes a CRUD operation, the action_allowed? method is invoked first and if the method returns true the CRUD operation is triggered or else the user is intimated with a message and gracefully exited. Hence, when the action_allowed? method is overridden to return true always, it results in providing unauthorized access to certain users.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    true&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:With the new implementation the AccessHelper - action_allowed? method has been modified in such a way that unauthorized access is prevented. As per the new algorithm, 'new', 'create', 'edit', 'update' cannot be invoked by any user. These operations can be accessed only by ‘papertrail’ gem. Only an ‘Administrator’ or ‘Super-Administrator’ can call 'destroy_all' method. All the other methods are accessible to ‘Administrator’,  ‘Super-Administrator’, ‘Instructor’, ‘Teaching Assistant’ and ‘Student’.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'new', 'create', 'edit', 'update'&lt;br /&gt;
    #Modifications can only be done by papertrail&lt;br /&gt;
      return false&lt;br /&gt;
    when 'destroy_all'&lt;br /&gt;
      ['Super-Administrator',&lt;br /&gt;
       'Administrator'].include? current_role_name&lt;br /&gt;
    else&lt;br /&gt;
      #Allow all others&lt;br /&gt;
      ['Super-Administrator',&lt;br /&gt;
       'Administrator',&lt;br /&gt;
       'Instructor',&lt;br /&gt;
       'Teaching Assistant',&lt;br /&gt;
       'Student'].include? current_role_name&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Automated Testing using RSPEC===&lt;br /&gt;
The current version of expertiza did not have any test for VersionsController. Using the test driven development(TDD) approach, we have added an exhaustive set of RSPEC tests for VersionsController, to test all the modifications we have done to the code of the controller class. The tests use double and stub features of rspec-rails gem, to fake the log in by different users - Administrator, Instructor, Student etc. The tests can be executed &amp;quot;rpec spec&amp;quot; command as shown below.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
user-expertiza $rspec spec&lt;br /&gt;
.&lt;br /&gt;
.&lt;br /&gt;
.&lt;br /&gt;
Finished in 5.39 seconds (files took 25.33 seconds to load)&lt;br /&gt;
66 examples, 0 failures&lt;br /&gt;
&lt;br /&gt;
Randomized with seed 19254&lt;br /&gt;
.&lt;br /&gt;
.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Testing from UI===&lt;br /&gt;
Following are a few testcases with respectto our code changes that can be tried from UI:&lt;br /&gt;
1. To go to versions index page, type in the following url after logging in:&lt;br /&gt;
   http://152.46.16.81:3000/versions&lt;br /&gt;
&lt;br /&gt;
2. After logging in as student/instructor or admin : Try accessing the  new, create, edit, update actions. These actions are not allowed to any of the users.&lt;br /&gt;
   http://152.46.16.81:3000/versions/new&lt;br /&gt;
   This calls the new action. In the current production version of expertiza, it is unhandled and application gives a default 404 page.&lt;br /&gt;
&lt;br /&gt;
3. Another feature that can be tested from UI is Pagination. Try searching for a user's versions and see if the results are paginated or not. Search here:&lt;br /&gt;
   http://152.46.16.81:3000/versions/search&lt;br /&gt;
&lt;br /&gt;
4. Visit the same URL as step 3, you should see only the students under that instructor in the users dropdown.&lt;br /&gt;
&lt;br /&gt;
===References===&lt;br /&gt;
&lt;br /&gt;
#[https://github.com/expertiza/expertiza Expertiza on GitHub]&lt;br /&gt;
#[https://github.com/WintersLt/expertiza GitHub Project Repository Fork]&lt;br /&gt;
#[http://expertiza.ncsu.edu/ The live Expertiza website]&lt;br /&gt;
#[http://bit.ly/myexpertiza  Demo link] &lt;br /&gt;
#[http://wikis.lib.ncsu.edu/index.php/Expertiza Expertiza project documentation wiki]&lt;br /&gt;
#[https://relishapp.com/rspec Rspec Documentation]&lt;br /&gt;
#Clean Code: A handbook of agile software craftsmanship. Author: Robert.C.Martin&lt;/div&gt;</summary>
		<author><name>Amadhus2</name></author>
	</entry>
</feed>