Web Programming

CSC 210, Spring 2014

Assignment #3

For this assignment you will write PHP code for movie review pages much like your TMNT page from HW2. Please secure it using .htaccess as you did for the previous assignments - unless you turned it off, your existing .htaccess file should still be protecting it.

Git Setup

Setting up Git to work for groups is different from the setup that was used in the class in previous years. Now, instead of downloading the files from the course Git repo, you will get the files from a directory on Betaweb (betaweb.csug.rocehster.edu. You will copy these files into the team repository on Betaweb, then add then to the repository. The team's repository in in in directory in /p/csc210/ for example, Backslash's Git repo is in /p/csc210/Backslash.git. This repository will not let you put anything into it directory. This is deliberate so that no code gets added to the team's repository that is not committed. Instead, you will add the files you need to a repository somewhere else, then push it to the team's repository. Each of you already has an account on Betaweb, so the easiest thing to do it to add the files you need to a clone of the team's repository in your home directory on Betaweb, then push it to the teams repo.

Scrum Master: Getting the files to the Team's Git repo initially

This needs to be done only once, so the team should have the Scrum Master do it. The Scrum Master will make a clone of the team repo in his or her home directory, add the files to the repo there, commit changes, then push the changes to the team's repository. For example, suppose the Scrum Master for Backslash, martin, is doing this work. Assuming that the Scrum Master has already done a git clone /p/csc210/Backslash in their home directory, they might see the following.


$ pwd
/home/martin
$ ls
Backslash
$ cd Backslash
$ pwd
/home/martin/Backslash
  
>

This is one of the few times it is reasonable to work in the master branch directly.


$ git checkout master
Switched to branch 'master'
$ git status
# On branch master
nothing to commit (working directory clean)
$ ls
0  1  2  Assignment1  Assignment2
  

We do a git checkout master to move to the master branch. We do the git status just to make sure that everything worked. Both of these command are Git commands, so the start with git. When we do an ls command in the master branch, we see that we have directories for 0, 1, and 2; the place where we are keeping the code for the first and second assignments. And we have the directories Assignment 1 and Assignment 2 that have the original files for the first two assignments. We are going to put the initial files in the new directory Assignment 3.

The first thing we do is copy the files from /home/martin/Assignment3 to the Scrum Master's git repository. Because we did a git checkout master we are working in the master branch.


$ mkdir Assignment3
$ cp -r /home/martin/Assignment3/* Assignment3
$ ls -l Assignment3
total 696
drwxr-xr-x 6 martin users   4096 Feb  8 16:39 moviefiles
-rw-r--r-- 1 martin users 707740 Feb  8 16:39 moviefiles.zip
-bash-4.1$ ls -l Assignment3/moviefiles
total 16
drwxr-xr-x 2 martin users 4096 Feb  8 16:39 mortalkombat
drwxr-xr-x 2 martin users 4096 Feb  8 16:39 princessbride
drwxr-xr-x 2 martin users 4096 Feb  8 16:39 tmnt
drwxr-xr-x 2 martin users 4096 Feb  8 16:39 tmnt2
  

Notice that we do a cp -r /home/martin/Assignment3/* Assignment3 The -r flag says to copy recursively, i.e., to copy all of the directories, and all of the contents of those directories. When we to an ls -l Assignment3 after the cp we see that we have copies the file moviefiles.zip and the directory moviefiles. When we list the contents of moviefiles we see more files in there.

Now when we do a git status it tells us that there is an untracked file and suggests that we add it to be included in subsequent commits.

-bash-4.1$ git status
# On branch master
# Untracked files:
#   (use "git add ..." to include in what will be committed)
#
	#Assignment3/
nothing added to commit but untracked files present (use "git add" to track)
  

We do a git add a git commit and a git push to get it back to the team's repo.


$ git add Assignment3
$ git commit
  

When you do the commit Git opens up vim so you can add a commit message. The first line in the commit message is the title, followed by a blank line and a message. Git can be set up so that it sends an email to all of the members of the team whenever a push is done, in which case it will use the first line as the email title and the rest as the message. Note that the Committer is listed in the message along with all of the files that are being committed.


Adding the initial files for Assignment 3

These file contain the information need to the Rancid Tomatoes movie site.
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Committer: Nat Martin 
#
# On branch master
# Changes to be committed:
#   (use "git reset HEAD ..." to unstage)
#
#       new file:   Assignment3/moviefiles.zip
#       new file:   Assignment3/moviefiles/mortalkombat/info.txt
#       new file:   Assignment3/moviefiles/mortalkombat/overview.jpg
#       new file:   Assignment3/moviefiles/mortalkombat/overview.png
#       new file:   Assignment3/moviefiles/mortalkombat/overview.txt
#       new file:   Assignment3/moviefiles/mortalkombat/review1.txt
#       new file:   Assignment3/moviefiles/mortalkombat/review2.txt
#       new file:   Assignment3/moviefiles/mortalkombat/review3.txt
#       new file:   Assignment3/moviefiles/mortalkombat/review4.txt
#       new file:   Assignment3/moviefiles/mortalkombat/review5.txt
#       new file:   Assignment3/moviefiles/mortalkombat/review6.txt
#       new file:   Assignment3/moviefiles/mortalkombat/review7.txt
#       new file:   Assignment3/moviefiles/mortalkombat/review8.txt
#       new file:   Assignment3/moviefiles/mortalkombat/review9.txt
#       new file:   Assignment3/moviefiles/princessbride/info.txt
#       new file:   Assignment3/moviefiles/princessbride/overview.png
#       new file:   Assignment3/moviefiles/princessbride/overview.txt
#       new file:   Assignment3/moviefiles/princessbride/review1.txt
#       new file:   Assignment3/moviefiles/princessbride/review2.txt
#       new file:   Assignment3/moviefiles/princessbride/review3.txt
#       new file:   Assignment3/moviefiles/princessbride/review4.txt
#       new file:   Assignment3/moviefiles/princessbride/review5.txt
#       new file:   Assignment3/moviefiles/princessbride/review6.txt
#       new file:   Assignment3/moviefiles/princessbride/review7.txt
#       new file:   Assignment3/moviefiles/tmnt/info.txt
#       new file:   Assignment3/moviefiles/tmnt/overview.png
#       new file:   Assignment3/moviefiles/tmnt/overview.txt
#       new file:   Assignment3/moviefiles/tmnt/review1.txt
#       new file:   Assignment3/moviefiles/tmnt/review2.txt
#       new file:   Assignment3/moviefiles/tmnt/review3.txt
#       new file:   Assignment3/moviefiles/tmnt/review4.txt
#       new file:   Assignment3/moviefiles/tmnt/review5.txt
#       new file:   Assignment3/moviefiles/tmnt/review6.txt
#       new file:   Assignment3/moviefiles/tmnt/review7.txt
#       new file:   Assignment3/moviefiles/tmnt/review8.txt
#       new file:   Assignment3/moviefiles/tmnt2/info.txt
#       new file:   Assignment3/moviefiles/tmnt2/overview.png
#       new file:   Assignment3/moviefiles/tmnt2/overview.txt
#       new file:   Assignment3/moviefiles/tmnt2/review01.txt
#       new file:   Assignment3/moviefiles/tmnt2/review02.txt
#       new file:   Assignment3/moviefiles/tmnt2/review03.txt
#       new file:   Assignment3/moviefiles/tmnt2/review04.txt
#       new file:   Assignment3/moviefiles/tmnt2/review05.txt
#       new file:   Assignment3/moviefiles/tmnt2/review06.txt
#       new file:   Assignment3/moviefiles/tmnt2/review07.txt
#       new file:   Assignment3/moviefiles/tmnt2/review08.txt
#       new file:   Assignment3/moviefiles/tmnt2/review09.txt
#       new file:   Assignment3/moviefiles/tmnt2/review10.txt
#       new file:   Assignment3/moviefiles/tmnt2/review11.txt
  

When you have added your message, hit <esc>, then type :wq and press enter.

Next do a git pull origin master to make sure your repo is up to date, then do a git push origin master


$ git pull origin master
Already up-to-date.
$ git push origin master
Counting objects: 20, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (12/12), done.
Writing objects: 100% (12/12), 1.55 KiB, done.
Total 12 (delta 7), reused 0 (delta 0)
Unpacking objects: 100% (12/12), done.
To /p/csc210/Backslash
   c84a22c..f8179c3  master -> master
  

Everyone: Update your AWS server with the new files

Now you are ready to update your files on your AWS server. That is where you really need them to be. To do that, go into your Git repo on AWS and do a git pull.


ec2-user$ pwd
/home/ec2-user/Backslash
ec2-user$ git pull
martin@betaweb.csug.rochester.edu's password: 
remote: Counting objects: 57, done.
remote: Compressing objects: 100% (52/52), done.
remote: Total 56 (delta 1), reused 48 (delta 0)
Unpacking objects: 100% (56/56), done.
From betaweb.csug.rochester.edu:/p/csc210/Backslash
   f8179c3..f860489  master     -> origin/master
Updating f8179c3..f860489
Fast-forward
 Assignment3/moviefiles.zip                        | Bin 0 -> 707740 bytes
 Assignment3/moviefiles/mortalkombat/info.txt      |   3 +++
 Assignment3/moviefiles/mortalkombat/overview.jpg  | Bin 0 -> 35048 bytes
 Assignment3/moviefiles/mortalkombat/overview.png  | Bin 0 -> 158103 bytes
 Assignment3/moviefiles/mortalkombat/overview.txt  |  10 ++++++++++
 Assignment3/moviefiles/mortalkombat/review1.txt   |   4 ++++
...
 49 files changed, 191 insertions(+)
 create mode 100644 Assignment3/moviefiles.zip
 create mode 100644 Assignment3/moviefiles/mortalkombat/info.txt
` create mode 100644 Assignment3/moviefiles/mortalkombat/overview.jpg
...
 create mode 100644 Assignment3/moviefiles/tmnt2/review11.txt
  

Now we have the original files in our AWS server, but the files are still only on the master branch. If you do an ls you will see Assignment3 in the master branch, but not when you move to your branch. When you do a git checkout martin to get to your branch, the new files will not be there. To move the files to your working branch, you will need to do a git merge master from your personal branch.


ec2-user$ checkout martin
Already on 'martin'
ec2-user$ git status
# On branch martin
nothing to commit, working directory clean
ec2-user$ ls
0  1  2  Assignment1  Assignment2  CSC210  index.html  README.md
  

When you do the merge, Git will tell you that it is updating your branch. When it is done, you will have the files in your branch and you can start working with them.


ec2-user$ git merge master
Updating fdcdc6a..f860489
Fast-forward
 0/index.html                                      |   3 ++-
 Assignment3/moviefiles.zip                        | Bin 0 -> 707740 bytes
 Assignment3/moviefiles/mortalkombat/info.txt      |   3 +++
 Assignment3/moviefiles/mortalkombat/overview.jpg  | Bin 0 -> 35048 bytes
 Assignment3/moviefiles/mortalkombat/overview.png  | Bin 0 -> 158103 bytes
 Assignment3/moviefiles/mortalkombat/overview.txt  |  10 ++++++++++
...
  

Now when you do an ls, you see the new directory.


ec2-user$ ls
0  1  2  Assignment1  Assignment2  Assignment3  CSC210  index.html  README.md
  

Everyone: Working with the new files

To use the new files, you will need to copy them to /var/html/www, so Apache can see the. First make a new directory in your Git directory and copy the files there. An alternative would be to have the Scrum Master make a directory 3 in the master branch and then everyone will get it, but I didn't think of that when I was doing it.


ec2-user$ mkdir 3
$ cp -r Assignment3/* 3
ec2-user$ ls 3
moviefiles  moviefiles.zip
  

Remember to use the -r flag. Next copy the directory to /var/www/html


ec2-user$ cd /var/www/html
ec2-user$ ls
0  1  2  index.html  README.md  test  test.html  test.html~
ec2-user$ mkdir 3
ec2-user$ cp -r ~/csc210TA/3/* 3
ec2-user$ ls 3
moviefiles  moviefiles.zip
  

The tilde character, ~, refers to your home directory. Now we can edit the index.html to get started with the assignment.

Everyone: Putting your code back into the Git Repository

You should keep your code in the Git repository for you team. That way, anyone on the team can see and integrate your code with the work the rest of the team has done. If you are away and someone needs the code you have written, it will not help them if it is living on your AWS server. Your team mates cannot get to it.

The first thing you do is add, commit and push to your directory


ec2-user$ git status
# On branch martin
nothing to commit, working directory clean
ec2-user$ ls
0  1  2  3  Assignment1  Assignment2  Assignment3  CSC210  index.html  README.md
ec2-user$ ls 3
moviefiles  moviefiles.zip
ec2-user$ ls /var/www/html/3
background.png  critic.gif  index.html~  moviefiles.zip  movie.php     rbg.png        test.php   w3c-css.png
bannerbg.png    fresh.gif   movie.css    movie.html      movie.php~    rottenbig.png  test.php~  w3c-xhtml.png
banner.png      index.html  moviefiles   movie.html~     overview.png  rotten.gif     tmnt.png
ec2-user$ cp /var/www/html/3 3
cp: omitting directory `/var/www/html/3'
ec2-user$ cp /var/www/html/3/* 3
cp: omitting directory `/var/www/html/3/moviefiles'
ec2-user$ cd 3
  

I move to my team repository and make sure I am on my own branch with git status. I am so I check out the directories. Everything is there. I look in directory 3 and the original files are there. I look in /var/www/html/3 and I see that I have moved all of the pictures from assignment 4 in and I have added a new file called movie.php. I should have removed the backup files (i.e. the ones that end with a tilde) but I forgot. Next I copy all of the file from /var/www/html/3 to ~/Backslash/3. Notice that I don't need to use the -r flag this time because I am only copying file. The command notifies me that it did not copy /var/www/html/3/moviefiles, but that is OK because I did not change them. (And if I did, it was by accident and I don't want to save the changes.)


ec2-user$ git add .
ec2-user$ git commit
[martin 80995aa] Putting back yesterday's work
 70 files changed, 1392 insertions(+)
 create mode 100644 3/background.png
  

Lots of other files that I changed


 create mode 100644 3/tmnt.png
 create mode 100644 3/w3c-css.png
 create mode 100644 3/w3c-xhtml.png
  

Once I have committed the code I push it back to my branch.


ec2-user$ git push origin martin
martin@betaweb.csug.rochester.edu's password: 
Counting objects: 12, done.
Compressing objects: 100% (11/11), done.
Writing objects: 100% (11/11), 6.70 KiB | 0 bytes/s, done.
Total 11 (delta 4), reused 0 (delta 0)
To martin@betaweb.csug.rochester.edu:/p/csc210/csc210TA
   c84a22c..80995aa  martin -> martin
  

Everyone: Pushing back to the staging branch

Now that I have pushed everything back to my branch, I decide that it is worth combining with whatever other have put back. I first pull from the staging branch. Then merge with the branch and finally push it back.


ec2-user$ git pull origin staging
martin@betaweb.csug.rochester.edu's password: 
From betaweb.csug.rochester.edu:/p/csc210/csc210TA
 * branch            staging     -> FETCH_HEAD
Already up-to-date.
ec2-user$ git checkout staging
Switched to branch 'staging'
ec2-user$ git status
# On branch staging
nothing to commit, working directory clean
ec2-user$ git merge martin
Updating f860489..80995aa
Fast-forward
 3/background.png                        | Bin 0 -> 2763 bytes
 3/banner.png                            | Bin 0 -> 63487 bytes
 3/bannerbg.png                          | Bin 0 -> 189 bytes
 3/critic.gif                            | Bin 0 -> 1484 bytes
 3/fresh.gif                             | Bin 0 -> 1367 bytes
 3/index.html                            |  37 +++++++++++++
  

Lots of other files that I changed


ec2-user$ git commit
# On branch status
# Your branch is ahead of 'origin/status' by 1 commit.
#   (use "git push" to publish your local commits)
#
nothing to commit, working directory clean
  

No one else has checked in since I last pulled, which, I suppose is unsurprising.


ec2-user$ git push origin master
martin@betaweb.csug.rochester.edu's password: 
Total 0 (delta 0), reused 0 (delta 0)
To martin@betaweb.csug.rochester.edu:/p/csc210/csc210TA
   f860489..80995aa  master -> master
  

Now everything is back in staging. The scrum master will want to merge and check everything in to master periodially to make sure that it is up to date.

Assignment Requirements

Your PHP code will allow you to generate reviews for a variety of movies using the same code. For example:

expected output
click for a full-resolution view

Turn in the following files:

  • movie.php (code to produce review pages for movies)
  • movie.css (the style sheet for your pages; does not need to be modified from HW2 version)

Your pages must match the appearance specified in this document. It would be difficult to produce a pixel-perfect representation of the page that matches the image shown here, and we do not expect you to do so. But your page should follow all of the styles specified in this document and should match the overall look, layout, and behavior of the page shown here as closely as possible.

You should base your movie.php on the tmnt.html you wrote in HW2. You can also reuse your style sheet, movie.css. The modifications you need to make to your HTML code are to cause it to read the movie information using PHP so that the same file can produce different movie review pages.

Appearance Details:

The overall page has the same appearance as it did in Homework 2. The difference is that the page might show reviews and information for a film other than TMNT. The page's title should reflect the movie; for example, when showing The Princess Bride, the page title should be The Princess Bride - Rancid Tomatoes.

freshbig The page uses the same images as HW2 with the same file/path names, with two minor changes. The tmnt.html page showed a large rottenbig.png icon next to its 32% overall rating. But in this version, some films have high overall ratings. Any film whose overall rating is 60% or above should instead show the new image freshbig.png, shown at right. Also, the generaloverview.png image has moved, for reasons we will describe in the next section. As before, you should link to all images using their full absolute URLs, not relative ones. The general overview images are the one exception; since these now reside in the folder with the movie's information, you should link to these using a relative path such as "tmnt2/generaloverview.png".

Dynamic Page Content:

Your movie.php page will show reviews of different movies based upon a query parameter that is passed from the browser to the page in its URL. The browser will request your page with a URL such as the following:

http://<public-dns>/3/movie.php?film=princessbride

Your PHP code can store this parameter's into a variable using code such as the following:

$movie = $_REQUEST["film"];

You may assume that the browser has properly supplied this parameter and has given it a valid value. You do not have to handle the case of a missing or empty film parameter, a value that contains bad characters, a value of a movie that is not found, etc.

Based upon the film requested by the browser, you are to display a review of that film. Each film is stored in a directory whose name is the same as the film parameter. For example, the film princessbride stores its files in a folder named princessbride/. The files associated with each movie are the following:

  • info.txt, a file with exactly four lines of general information about the film: its title, year, overall rating, and number of reviews. Example:
    The Princess Bride
    1987
    95
    17
          
  • generaloverview.txt, a file with information to be placed in the General Overview section of your page. Each line contains one item of information, with its title and value separated by a colon. The number of lines in the file varies from movie to movie. Example:
    STARRING:Cary Elwes, Robin Wright, Andre the Giant, Mandy Patinkin
    DIRECTOR:Rob Reiner
    PRODUCER:Arnold Scheinman, Rob Reiner
    SCREENWRITER:William Goldman
    RATING:PG
    RELEASE DATE:September 25, 1987 (USA)
    RUNTIME:98 min
    SYNOPSIS:Director Rob Reiner breathes vividly colored cinematic life into ...
    RELEASE COMPANY:20th Century Fox
    
  • general overview for Princess Bride generaloverview.png, an image to display at the top of the General Overview section. This is the movie poster for the film, such as the one shown at right.
  • review1.txt, review2.txt, ..., files containing information for each review of the film. Each review file contains exactly four lines: The review, a fresh/rotten rating, the reviewer's name, and the publication. Example review1.txt:
    One of Reiner's most entertaining films, effective as a swashbuckling...
    FRESH
    Emanuel Levy
    emanuellevy.com
          

You map assume that all of the above files exist and are valid for the films your page is displaying. Part of your task is to successfully open these files, read the information from them, and display that information on the page. For example, if your page is requested as movie.php?film=princessbride, you should open princessbride/info.txt to read the film's title/year/etc. and display that in the headings and other text on the page. You would open the file princessbride/generaloverview.txt and display its contents in the General Overview section on the right side of the page. You would look for all review text files in the princessbride/ folder and would display each of them in the reviews area of the page.

Different movies have different numbers of reviews. You should show the first half of the reviews in the left column on the page, and the rest on the right. If a given movie has an odd number of reviews, the right column should receive the extra review. For example, Princess Bride has 7 reviews, so the first three go into the left column and the last four into the right column. You do not have to worry about the possibility that the general overview section and the reviews sections will be wildly different in height; this would potentially upset the appearance of the page, but your page does not need to handle this.

The image for each review are affected by the contents of the corresponding review text file. If the critic gave the film a FRESH rating, you should display an icon of fresh.gif in the review. If the critic gave the film a ROTTEN rating, you should display an icon of rotten.gif in the review.

Several other various pieces of text on the page is now related to the contents of these input files. For example, the display of the number of reviews shown, the number of total reviews, and the large red rating text all adjust based on the film's input files. The number of total reviews comes from the info.txt file, and the number of reviews shown comes from the count of the number of review text files.

Fortunately, you don't need to create and type all these text content for input files. You should get them from the my directory on betaweb.


cp -r /home/martin/Assignment3 
When you have copied them over put them in your Git repository.

Here is the screen shot of the outputs of these films for reference.

expected output   expected output

expected output   expected output

(click each screen shot for a full-resolution view)

Development Strategy and Hints:

PHP code is difficult to debug if you have lots of errors on your page. It is wise to write this program incrementally, adding small pieces of code to a known working page, and not advancing until you have tested and debugged the new code. Rather than trying to generalize all of your page at once, focus on incorporating a particular aspect or input file. Once this is successful, move on to the next.

We suggest that get your page to display a single film (such as princessbride or tmnt2) first, then generalize it for other films. None of your code should refer to specific names of films such as princessbride.

Since this program uses PHP code, you will need to upload your files to AWS to test your work (unless you install Apache/PHP on your own local machine!). Changes you make to your files will not be shown in the browser until you re-upload the file and refresh.

The following PHP functions may be helpful to you in implementing this program:

  • count - returns the number of elements in an array
  • explode - breaks apart a string into an array of smaller strings based on a delimiter
  • file - reads the lines of a file and returns them as an array
  • glob - given a file path or wildcard such as foo/bar*.jpg, returns an array of matching file names
  • list - unpacks an array into a set of variables; useful for dealing with fixed-size arrays of data
  • trim - removes whitespace at the start/end of a string (gets rid of stray spaces in output)

To make your code efficient and clear, you might want to avoid redundancy. One possible source redundancy is between different movies. You should not have code that depends on particular movies or that uses lots of if/else statements to figure out which movie to display; the same code should be able to display any movie. Use loops, functions, variables, if/else factoring, etc. to ensure that your code is not redundant.

You should also reduce the number of large complex chunks of PHP code that are injected into the middle of your HTML code. When possible, try to replace such chunks with functions that are called in the HTML and declared at the bottom of your file. Also, you should minimize the use of print and echo statements. As much as possible you should insert dynamic content into the page using PHP expression blocks as taught in class. Here is a bad example that print HTML tags into the page such as the following:

print "<p>I am adding content to the page!</p>";   # bad

Need help?

There are lots of resources available for this assignment, as is the case for all assignments. See the above PHP.net references for the functions you will likely find most useful; that website is a great source. For HTML and CSS materials, you may find w3schools useful. Of course there is workshop and office hours available as well, and you are definitely encouraged to talk with us there. The earlier you start, the more resources you will have at your disposal.

Submission and Grading:

Implement the HTML output of your web page using XHTML 1.1 as taught in class. For full credit, your page's output for all films must successfully pass the W3C XHTML validator. (Not the PHP source code itself, but the HTML output it generates, must validate.) Do not use HTML tables on this assignment.

Your PHP code should generate no error or warning messages when run using reasonable sets of parameters. Decompose the problem into functions as appropriate, minimize global variables, utilize parameters/returns properly, correctly use indentation/spacing, and avoid long PHP lines over 100 characters. Use material that discussed during the first three weeks of class or the first six chapters of the textbook.

You should follow the same directory and file structure as the previous assignments, including a README at index.html. You should not modify the subdirectory skeleton for your source files pulled from the master branch.

Part of your grade will also come from successfully uploading your files to the web server, then to github. Please do not place a solution to this assignment online on a publicly accessible web site. Doing so is considered a violation of our course academic integrity policy, so make sure your web site is asking for a password before you start putting your assignment files up on the web. Submit your assignment via github using the same push + pull request protocol in assignments 1 and 2. There is no need to provide us with additional information on blackboard, as we already have your .htaccess username and password from assignment 0.

Extra Credit

As usual, there are a number of entertaining and challenging extra credit options to choose from for this assignment. We strongly recommend trying some; they are useful in numerous real-world applications, fun, and boost your grade.

Props

This document's contents are (C) Copyright 2013
Marty Stepp / Jessica Miller and licensed under Creative Commons Attribution 2.5 License.
It's been changed and adapted to the UofR by Jeffrey Bigham and Zhuan Chen.

Please email Nat Martin at martin@cs.rochester.edu with questions.

Valid XHTML 1.0 Transitional Valid CSS!