Friday, May 2, 2014

Closing Thoughts

Most people enter into an endeavor expecting a finished product – something quantifiable to show for their weeks, months, or years worth of labor.  Even those observing them, whether casually or professionally, look for tangible results.  We live in a society where output is praised and admired, but the lack thereof is met with confusion or disdain.  One of the most significant lessons I’ve learned during the course of this internship is that, while the destination can be important - finishing a product or meeting your goals - often the journey there is more lastingly valuable.



My mentor and I set out to design and implement an interactive application in the Canvas learning system that creates customizable practice quizzes and exercises for college intro-level Math students.  Right now, a professor can create a test bank in Canvas and upload his/her own hand-made problem sets of any given size.  Canvas then generates “random” quizzes from these test banks, but there’s no real student input or feedback as to what they need more practice in.  We wanted to give the student the option to select a topic, range of difficulty, number of problems, and specific features regarding those problems.  For instance, a student could say, “I really need more practice factoring polynomials.”  They could log into Canvas and select easy, medium, or hard factoring problems, whether they wanted single or multi-variable polynomials, and how many problems they wanted to practice.  This application would act as a supplement to their current coursework – a way to catch up if they were behind, review their weakest areas for exams, or look ahead if they were nervous about upcoming material.  

It's easy to bite off more than you can chew


I’ve been told by several of my friends and colleagues that setting realistic goals and outlines for a programming project is one of the most difficult factors.  Often software developer teams are initially too ambitious and will have to significantly scale back their project features halfway through in order to meet their deadlines.  But, we were optimistic.  We figured that our concept was challenging but workable in the span of a five-month internship.  Our first step was to download the proper software and register for developer permissions in order to edit and submit code in Canvas.  This took two weeks.  Our next step was to work through some learning modules provided by Canvas developers to teach others how to create interactive LTI applications that could be hooked up to Canvas.  


This involved implementing security checks for parameters sent from the user, signature verification, and finding or creating a library to carry out all these functions.  This process lasted over two months.  We had reached the point where the semester was drawing to a close and we had no tangible product to show for our efforts.  By the end we developed a simple piece of code to generate random single-variable polynomials, print them to the web browser, and check the user’s input of their roots against SymPy’s factoring method to spit out a result, but it was nothing close to what we had envisioned at the beginning of the semester.


At first our project seemed like a failure – we had worked so hard and yet were unable to meet any of our previous goals.  But then I looked back on the entirety of the semester and realized how valuable my work would be going forward.  I’ve learned how to create simple programs in three new languages.  I know how to get a local server running and mount files to that server to display on a web browser.  I have access to a plethora of resources to seek help when faced with a seemingly insurmountable obstacle or daunting error message, and I’ve learned the basic techniques of gathering and processing user input from a web form.  These all may seem like trivial concepts on their face, but they have taken months to learn and implement in their most basic form, giving me a much more realistic perspective and deeper understanding of what is involved in web development. 

 


Even though our finished product is not at all what we expected, I have walked away with programming skills that will be invaluable to me in the future – skills that I could only pick up through direct, hands-on experience in the field.  Working with my graduate mentor, Itamar Gal, has also made the world of academia and the people associated with it more accessible – not just in the context of potential graduate school opportunities, but also to mold my undergraduate career into a more worthwhile experience.  If I am interested in a particular topic, want to learn more about a given field of study, or just want to discuss some concept that I’ve recently discovered, I know now that there are professors, graduate students, and even some undergraduates that would enjoy a lively discussion.  I feel more at ease interacting in the academic sphere.  Through this internship I’ve gained a sense of belonging and right – a sense that I am worthy of the knowledge I have gained and the encouragement to share that knowledge with any willing ear, which to me is the most valuable piece of all.  

Week 15: Final Countdown, First Prototype

In our last week of this internship, we were able to incorporate our Python script that generates random, single-variable polynomials within a given coefficient range with AJAX, MathJax, and Sympy to create our first prototype of our interactive app.

We started by tweaking the AJAX tutorial to fit our needs.  With it we were able to create interactive buttons to display different polynomials and take user input from a text box and submit it to be checked.



This was done through a combination of coding in Python with Sympy imports, Javascript that used Mathjax source code to display polynomials in a more readable format, and HTML to interact with the user. 

Our app continued to develop into a more straightforward and usable layout. 


Finally, with a bit of code cleaning on my mentor's end, our first prototype looked like this: 


It currently grabs a randomly generated polynomial from our Python script, displays it with MathJax, then takes the user input of the polynomials derivative, checks it against the derivative calculated by Sympy, and displays feedback.



Since the semester is drawing to a close, this is currently as far as we will be able to develop our app.  If we were continue with this project in the future, we would add more features to make the webpage more user friendly, expand the apps functionality to perform several operations for diverse practice problems, tweak the interface to invite more user personalization (difficulty level/number/number range of problems). 






Week 14: Mad Dash to the End

Last time we developed a short program in Python to generate random, single-variable polynomials within a given range of coefficients.  Our next step was to incorporate that code into an HTML webform that could interact with the user.

We found an API called Jinja that we tried to learn, but with our limited time constraints, it was too intensive to work with.


Additionally, we found another platform called web2py that seemed more straightforward.  I was able to make a little more progress on that, but it was still too complicated for our time constraints. We were getting down to bare bones here!



Finally, my mentor found an AJAX tutorial that was just what we needed. It used a combination of Javascript and XML to create interactive buttons and text boxes.  


Next week we'll use this tutorial to incorporate our Python script. 



Thursday, April 17, 2014

Week 13: App Development!

The learning modules have officially proved excessively difficult, so now that we know how to hook up an app with a simple URL to Canvas, we branched out to program an app on our own!

This week we wrote a simple piece of code in Python using the SymPy interface to generate "random" (within an integer range) polynomials and check the roots of the polynomial entered by the user.


The code works great in Terminal, but now we need to actually access it in a web form in order to take user input from a webpage. To do this, we first had to enable Python in apache (we used these instructions).

Next, we need to be able to use our Python code in an HTML form. We found this tutorial on how to embed Python in HTML using Jinja to accomplish this goal, but we'll see how intuitive it is.


We also want to incorporate MathJax into our program to display the polynomials (and any other functions we might want to add to our app functionality in the future) more elegantly.

Goals for next week:

  1. Ensure Python is enabled in apache
  2. Work through Jinja tutorial



Thursday, April 10, 2014

Week 12: Sometimes Ignorance Really is Bliss

Updating my system to 10.9 worked! Whatever bugs were in OS 10.8 somehow did not transfer over to 10.9.  Once updated, I re-worked through all the steps to set up apache and php again and any local server launch was successful:



Sometimes the solution to knocking your head against a wall is just to paint over it.

Now that we've got both a functional default and personal server, we started working with the OAuth library that we got from the Canvas forum to see if we could finally verify the signatures from the Canvas modules.

We were able to hook the library up to our server and connect it to the LTI module. 


Unfortunately, we keep getting a "could not establish context" error when running through the modules, so we posted in the forum for some advice. 


The forum led us here where we connected our 'app' to our test course and added it to a test module. 




Success!

So we have now "established context" in the scope of our course, but have yet to figure out how that ties in to the Learning Modules.  Back to the forum!

Alternatively, we considered different learning modules or attempting to program our app on our own without the modules, but it seems every path presents its own unique roadblocks and challenges. 

Goals for this week:
  1. Find out how Course/App connection is tied to the Canvas Learning Modules
  2. Explore alternatives to the modules (programming app solo, or finding alternate LTI materials)


Sunday, April 6, 2014

Week 11: Forms and 403's

This week our goal was to get some code working on our local server and eventually start creating an app that could process the encryption parameters sent to us from the Canvas test modules.

Using the tutorials from here and here, we were able to create a very basic web form and have it appear on our local test-website.local:


Unfortunately, once we had a test website working, we were no longer able to access the default local server on my operating system (Mac OSX). 


We think this has something to do with how we enabled apache and cgi, but we made so many changes without going through bash that it's harder to step backward and error check.  We tried changing the permissions via the terminal, but still no luck:


Even more mind-boggling is that the permissions work on my mentor's system even though we made all the same changes. We tried re-working through several tutorials: hereherehere, and here to enable apache without any success.  Our final hope is to update my operating system to 10.9, which will reset apache, and just start again from scratch (feels like the case of the missing bracket all over again). We're also going to try posting our error to apple.stackexchange and see if we can get some more detailed feedback.

On the app front, I wrote a short bit of code that will hopefully seek out the necessary parameters and write them to a file: 


Unfortunately, we have no way to test this code until we get our server up-and-running properly. What a world!

Goals for next week:



  1. Update operating system in order reset apache2 and cgi
  2. Test and tweak app to gather necessary Canvas parameters

Thursday, March 27, 2014

Week 10: Serving Up Our Server

This week our goal was to get simple code to run on our web server.  Because I have a different version of Mac OSX (10.8), Web Sharing was no longer an option.  Instead we used apachectl in the terminal to get the server running.

From there, we enabled Virtual Hosts and created a simple html script to print out a result message.  We accessed these files in /private/etc. The only files we needed to modify were httpd.conf, httpd-vhosts.conf, and hosts:


In httpd.conf, we just uncommented the Virtual hosts line, "Include /private/etc/apache2/extra/httpd-vhosts.conf"


Unfortunately, it seems we can access the default data in local host or the data in our test website, but not both (i.e. we can't have both available to choose between them).  We think it is some problem in httpd.conf, but we're not quite sure how to fix it quite yet. 

But progress!!

Goals for next week:
  1. Get both localhost data and test-website.local data to display when we want
  2. Enable CGI on our Apache server in order to link data to where we want it and run different apps




Week 9: Blazing the Trail....that was already tread

Ultimately we were not able to make any progress with the libraries.  It is time to admit defeat. We decided instead to implement our own version of a "library" just to deal with simple verification of a base string of variables sent from Canvas.  This was something that everyone else on the Internet forums seemed to be doing, but we thought that was the "hard way." Lesson 1 learned.

We found some helpful files already written here but, being the total newb that I am, didn't know how to mount those files onto our local server.  Lesson 2 learned: ask the mentor before posting stupid questions on the Internet....

In order to check given signatures, I wrote some simple code in Java to complete the following steps in creating and verifying an OAuth signature:

The 4 Steps to Generating an OAuth Signature

1. Collect all request parameters:

All parameters related to OAuth which start with oauth_ except for
oauth_signature should be collected. If parameters are used in the POST
body, they also should be collected. For us, this means we need all the
LTI parameters, e.g. lti_message_type, user_id, etc.

2. Normalize the parameters:

First, sort all parameters in alphabetical order and apply URL encoding
(rfc3986) to each key and value. Second, list the results of the URL
encoding in <key>=<value> format, and insert "&" between each pair.
Finally, apply URL encoding to the entire result.

NOTE: URL encoding is also called percent-encoding. Long story short, it
involves replacing certain non-ASCII characters with escape sequences
which begin with a percent symbol. For example, the ampersand "&" is
replaced with the escape code "%26". Check out the wikipedia entry for
more information:

http://en.wikipedia.org/wiki/Percent-encoding

3. Create a Signature Base String:

Combine the HTTP method name (GET or POST), the HTTP URL address called by
the Consumer (except for parameters), and the normalized parameter by
using "&". The combination becomes "[GET|POST] + & + [URL string except
for parameters] + & + [Normalized Parameter]".

4. Generate a Key

Encrypt the string generated at stage 3 using the Consumer Secret Key.
This Consumer Secret Key is obtained when the Consumer has registered in
Service Provider. Using the encryption method such as HMAC-SHA1, generate
the final oauth_signature.

That's it!

The code currently just reads from a file of parameters and encrypts them.  Our step is to us HMAC-SHA1 to generate the final signature and validate it. 


We also discovered that linking our Canvas server (http://0.0.0.0:3000/) was generating an error message, not a proper list of parameters (so we were cheating).  Instead to properly pass through the modules, we need to have a working app on our local server that processes the data in a logical way.

Goals for next week:
  1. Get local server running
  2. Construct app to process parameters from Canvas



Saturday, March 8, 2014

Week 8: No News is Not Good News

Still working on the OAuth library.... This is the first time both my mentor and I have been completely out of our element, but it's been an interesting challenge.

I posted a more detailed question about our problems here and we've gotten what looks like a helpful response.  Hopefully we can make some progress with it by next week.

Friday, February 28, 2014

Week 7: OAuth Library is Overdue

We left off last week trying to use an OAuth library for signature verification in order to continue working through the Canvas LTI modules. This proved a more complicated task than we anticipated.

There are libraries in every language, and so many of the resources online give tutorials on how to build your own library, which the modules do not suggest and seems far beyond our abilities. We decided to find an OAuth library in Ruby so we get more familiar with parsing that language in Canvas.

Starting in the Canvas forum, we found a plethora of "helpful" resources, but there were so many in so many different languages that it quickly became difficult to sort through them all. Some of the more useful sites for Ruby OAuth libraries were linked from here and here, and the one we're currently working through right now is here.

In trying to install oauth I got an error that oauth-instructure was interfering with the install (a question I posted here). But for some reason I was able to install oauth-simple without any trouble and so proceeded with that version.

With it we started writing our own ruby test code.

Using this...

...we wrote this.

Since we're still not super familiar with Ruby, implementing the proper code is proving challenging as we get seemingly simple errors like: 


that we're not sure how to fix yet.  By the end, I'm sure we'll know more about Ruby and OAuth libraries than we ever thought we wanted to....

Goals for next week:
  1. Learn to use Ruby's OAuth Library for signature verification
  2. Complete Canvas LTI modules


Thursday, February 20, 2014

Week 6: The LTI Structure for Randomness

Now that we are more familiar with the Canvas coding structure and have built a working question type, we wanted to look into the real goal of our project: Adding an option in Canvas to create randomized quizzes and question practice for students.  Canvas has a similar option to this already, but the teachers still have to create a question bank and then "random" questions are pulled from that question bank.  Our goal is to make the process more automated and easier for students to access a wide range of practice problems given specific parameters.

I began by looking into creating random Math problems in general and came across this helpful resource. But the more important goal at the moment is to find a way to integrate this "Random Quiz" option into the Canvas interface.  Our first thought was to simply add a button in the Manage Question Bank area of Canvas and link our "Random Quiz" from there.

I found some useful tips here and more specifically here for how to add buttons in Canvas.  They mostly pointed me in the direction of using LTI and building our own app (an idea we had had in the background for awhile), so we started pursuing those learning modules more earnestly.

I recommend using Safari as your browser for these modules, as the server launch interface was very straightforward there and less buggy than in Chrome or Firefox (at least on my machine). We used the URL for our own server for these modules.

The first module was fairly straightforward - teaching us to recognize required parameters to build/use an app in Canvas and to ensure we had the proper setup. It wasn't until we got to the second module on signature verification that we ran into trouble.


The module suggested we use a library for signature verification, but neither of us knew how to implement one. So, we trudged along until we reached a point where manual verification was too tedious and time consuming (see above screenshot).  

Luckily, others ran into trouble at this exact spot, and we found what looks to be very useful advice in the Canvas forum

Goals for next week:
  1. Find out how to implement library to automate signature verification
  2. Continue LTI modules




Thursday, February 13, 2014

Week 5: Bugs in Canvas - Painting the Ugly Picture

This week we worked on de-bugging the code in Canvas to create our own question type.  We decided to do an additional walk-through on my mentor's system to copy the steps I took and see if similar errors cropped up.  When we finished the process, his version was a success, so we had to go back to my code and check in further detail.

I found some easy-to-fix, rookie mistakes that I had made (mostly boolean logic in conditional statements).  However, by the end of the first day we discovered I had apparently missed a curly brace in one of the files - most likely due to a difference in style in the original code. Once again a major facepalm on my part - the whole world broken by a single curly brace.

At that point we decided it would be easier to revert my files to their original state and re-do the question development steps now that we were more familiar with the structure of the code.  We used the "git status" command in terminal to see what files specifically had been changed and used "git checkout ." to revert the tracked files to their original state.  The base file that we created in the first step of the tutorial remained since it was never being tracked.  I worked through the steps a second time with a more familiar eye, and it worked! We were able to access our own question type at the front end of Canvas.


Our next step will be to become familiar with the front end interface to see if we can create a question that will meet our needs.  This mainly means increased student interaction with questions types via the ability to generate truly random questions and specify number or question type ranges for the kinds of problems they would potentially want to practice. 

On a side note, we are also working on making our private server faster, as development flow is nearly impossible at its current speed.  Our workaround for now to get familiar with the front-end interface has been to create a teacher's account in canvas (a free service offered by the website).  We are also looking into further tutorials linked on the Canvas Quick Start Guide. 

Goals for this week: 
  1. Keep working on LTI learning modules in the background
  2. Become familiar with question tools already present in Canvas - strengths and weaknesses


Friday, February 7, 2014

Week 4: Coding Blind

Our main goal this week was to create our own question type in Canvas using the following tutorial.  I had never coded in Ruby or HTML before, so it was an entirely new and worthwhile learning experience.  For ease and speed of testing purposes, we are modeling our question after the multiple choice question (as far as settings, answer type, etc), but naming our type "sympy_question."

Our first step was to create a new file in "app/models/quiz_question/" that extends QuizQuestion::Base.  Since we're modeling after multiple choice, we just copied the multiple choice file in terminal using the "cp multiple_choice_question.rb sympy_question.rb," making sure we were in the "quiz_question" directory.

Next we added our question type String to the list of question types in "Assessment Question" and created a new struct in QuizzesHelper in the method answer_type, once again modeling after the multiple choice question format.


Modeling after the multiple choice made the coding process much easier because there was a straightforward template to work from.  Once we get more familiar with coding in Ruby, we'll be able to add more detailed design. 


I skipped over updating "parse_question" since there are no new features to add yet, so my next step was to add a question form description that works with HTML and update the quizzes.js file to recognize my "sympy_question" type. 



Since we're not adding any new features yet, I didn't need to update _multiple_answer.html.erb or _form_answer.html.erb, but that may come later. 

Once I had the code together, we tried creating our own question type from the front end - which failed utterly. At this point, the "Add Question" button is unresponsive, so I've done just enough coding to break everything.  I suppose it's some kind of progress...

Goals for next week:
  1. Debug 'create new question' code
  2. Familiarize ourselves with LTI learning modules on Canvas as possible alternative
  3. Look at Mathjax for inspiration


Week 3: Snow Day + Facepalm

So we did not make as much progress as we had hoped this week.  Part of this I will blame on the closing of the university due to "snow," but mostly I blame a brilliant moment of utter incompetence, which I will explain below.

We left off replacing some code that we got from the Google Canvas forum in order to fix a problem in the Canvas install.

Our next step was to start the server and log into Canvas using the "bundle exec script/server" command, a step we expected to be pretty straightforward.  First we had to make sure that our Ruby version matched our Gems version (1.9.3) with a simple "rvm use 1.9.3," but when I tried to start the server, I kept getting this message:

WARNING: Nokogiri was built against LibXML version 2.9.1, but has dynamically loaded 2.7.8
=> Call with -d to detach
=> Ctrl-C to shutdown server

I spent the rest of the week frantically searching forums looking for a solution and functionally getting nowhere.  When we were finally able to reconvene at the end of the week, we realized that the WARNING was just that - only a warning.  The server had been working the whole time (major facepalm).  

I think that's one of the most valuable lessons I've learned in this process so far: sometimes you get so deep in the weeds that you almost expect things to go wrong at every step and end up losing sight of the real problem.  Often the best solution is to pull back and look at the bigger picture. 

So now that we were finally able to log in to Canvas on our server, we familiarized ourselves with the interface (creating classes, quizzes, etc) and then began trying to make our own question type, which we will hopefully be able to incorporate SymPy into. 

The tutorial to create a new question type was shared on the Google Canvas forum and can be found here

Goals for next week: 
  1. Create/code new question in Canvas (finish 'create question' tutorial)
  2. Familiarize ourselves with LTI learning modules on Canvas as possible alternative
  3. Mathjax for inspiration

Thursday, January 23, 2014

Week 2: The Install is Half the Work

We left off last week with some errors installing postgres and with the intention of completing the Canvas install.

It turns out we just needed to update Homebrew ("brew update") to finish installing xmlsec1 and postgres.

Our next step was to install RubyGems and Bundler, but the version of RVM (1.9.3) that we installed included these already, so we just checked to ensure that they had made it to the right place:

wireless-10-146-97-126:~ Michelle$ which ruby
/Users/Michelle/.rvm/rubies/ruby-1.9.2-p320/bin/ruby
wireless-10-146-97-126:~ Michelle$ which gem
/Users/Michelle/.rvm/rubies/ruby-1.9.2-p320/bin/gem
wireless-10-146-97-126:~ Michelle$ which bundler
/Users/Michelle/.rvm/gems/ruby-1.9.2-p320@global/bin/bundler
wireless-10-146-97-126:~ Michelle$ echo $GEM_HOME
/Users/Michelle/.rvm/gems/ruby-1.9.2-p320
wireless-10-146-97-126:~ Michelle$ echo $GEM_PATH
/Users/Michelle/.rvm/gems/ruby-1.9.2-p320:/Users/Michelle/.rvm/gems/ruby-1.9.2-p320@global


Looks good!

Since we're using PostgresSQL, we needed to tell canvas to ignore MySQL with :
bundle install --without mysql
However, the Bundler we installed was not compatible with the Gem version we were using, so we had to downgrade it to an older version, a solution we found here. We could then execute the command like so: "bundle _1.3.5_ install --without mysql"

Continuing with the Quick Start guide, we ran into a js:build error during Database population. It seems we just needed to install jsnode manually ("brew install node"). 

We are now nearing the final steps of installation. We decided to skip over testing database configuration and the performance tweaks as they leant little purpose to our goal, so our next hiccup was running the script/server daemon.  The error crashed our entire terminal shell with little clue as to why. 

This proved to be an excellent opportunity to consult the Canvas forum.  We were able to glean some advice from more experienced software engineers, but have not yet found a solution. 


Goals for the upcoming week:
  1. Find solution to server error (via Canvas forum, Ruby forum, and/or general Google search)
  2. Check out MathJax for front end equation display inspiration
  3. Begin planning out Python functions to:
    1. Check roots of a polynomial
    2. Ensure user input of roots is in factored form
    3. Check if polynomial is factor of another polynomial
    4. Generally process input --> get a polynomial from String, etc.

Monday, January 20, 2014

Week 1-ish: The Newb at Work

Welcome! 

This is the official blog space for Itamar Gal and Michelle Lawrence's 2014 research project. Here you will find a detailed description of our attempt to:



  1. Develop self-contained learning modules using the Python SymPy package
  2. Integrate Python/SymPy with a CMS (Canvas in this case) via LTI

I, Michelle, will be logging our weekly progress in a step-by-step format both for my record-keeping benefit and as an open-source tool for anyone wanting to try something similar.  Some of these steps may seem embarrassingly straightforward to those more experienced coders and researchers, but I'm still a newb, so bear with me. 

Week 1: 


Our first steps involved acquiring the proper development tools. Using Homebrew we installed the following: 



  1. SymPy
  2. Canvas which involved:
    1. Installing RVM to run the required version of Ruby (1.9.3)
    2. Xcode development tools
    3. Postgres and the xmlsec library - just using the command line:


$ brew install xmlsec1 postgresql
We ran into a few problems during install. For instance, the proper RVM wouldn't install before Xcode was on the system completely. If you download Xcode via the terminal, make sure to launch it once to complete the install process. Once it has been launched, go into its Preferences, select the Downloads tab, and click "Install" next to the Command Line Tools package. Otherwise, the proper RVM cannot finish installing, a solution I found here.

I'm still having some additional errors downloading Postgres, which are still being parsed. Often the easiest way to find a solution to an error or bug is simply to Google it. 

Goals for the upcoming week:
  1. Finish installing tools
  2. Begin writing Python functions to:
    1. Check roots of a polynomial
    2. Ensure user input of roots is in factored form
    3. Check if polynomial is factor of another polynomial
    4. Generally process input --> get a polynomial from String, etc.
Stay tuned!