Skip to main content

Exam 2: Structured Scheme-ing

Assigned
Wednesday, 6 March 2019
Due
Tuesday, 12 March 2019 by 10:30pm
Collaboration
You may not receive help from any person other than the instructor for this exam. See the exam procedures for a detailed description of the resources you can and cannot use.
Submitting
Rename the starter code file to 000000.rkt, but replace 000000 with your generated random number. Email this file as an attachment to the instructor when you are finished with your exam.

Please read the exam procedures page for policies, turn-in procedures, and grading details. If you have any questions about the exam, check the Q&A at the bottom of this page. We will generally spend some time in class every day on questions and answers while the exam is in progress.

While the exam is out, please check back periodically to see if we have reported any new errata.

Complete the exam using the exam02.rkt starter source code. Please rename this file to 000000.rkt, but replace 000000 with your generated random number.

Prologue

The prologue for this examination will be via email, which you should send to your instructor by 10:30 p.m. on Friday evening. Your message should be titled CSC 151.01: Exam Prologue (your name).

  1. For each problem, please include a short note about something that will help you solve the problem. Mostly, we want to see some evidence that you’ve thought about the problem. You might note some similar procedures you’ve written or problems you’ve solved in the past (e.g., in a lab or on a homework assignment). You might note procedures that you expect to use. You might sketch an algorithm. You might pose a question to yourself. (We won’t necessarily read this in a timely fashion, so if you have questions for your instructor, you should ask by email or in person.)

    If, when looking at a problem, you think you already know the answer, you can feel free to write something short like “solved” or “trivial”.

  2. Which of those problems do you expect to be the most difficult for you to solve? Why?

  3. Conclude by answering the question What is an approach that you expect will help you be successful on this exam? For example, you might suggest that you will work thirty minutes on the exam each day, or work on the exam at 7pm each day, when your brain is most able to process information.

Epilogue

The epilogue for this examination will also be via email, which you should send to your instructor by 10:30 p.m. on the evening after the exam is due. Your message should be titled CSC 151.01: Exam Epilogue (your name). Include answers to the following questions.

What was the most difficult part of the exam?

What made that part difficult?

What are two things you can do to be more successful on the next exam?

Problem 1: Inverting hashes

Topics: Hash tables, for-each

As you may recall, in the lab on hash tables, we manually changed sidekick to sidekick-protagonists. However, it should be possible to generate the latter hash table algorithmically. Here’s a sketch

Create a new hash table, which we'll call inverse
For each key in the hash table
  Get the corresponding value
  (hash-set! inverse value key)

Document and implement a procedure, (hash-invert hash) that takes a hash table as input and returns a new hash table whose keys are the values of the original hash table and whose values are the keys of the original.

> (define csfaculty (make-hash))
> (hash-set! csfaculty "Curtsinger" "Charles")
> (hash-set! csfaculty "Dahlby Albright" "Sarah")
> (hash-set! csfaculty "Eikmeier" "Nicole")
> (hash-set! csfaculty "Hamid" "Fahmida")
> (hash-set! csfaculty "Johnson" "Barbara")
> (hash-set! csfaculty "Osera" "Peter-Michael")
> (hash-set! csfaculty "Rebelsky" "Samuel")
> (hash-set! csfaculty "Stone" "John")
> (hash-set! csfaculty "Vostinar" "Anya")
> (hash-set! csfaculty "Walker" "Henry")
> (hash-set! csfaculty "Weinman" "Jerod")
> csfaculty
'#hash(("Curtsinger" . "Charles")
       ("Dahlby Albright" . "Sarah")
       ("Eikmeier" . "Nicole")
       ("Hamid" . "Fahmida")
       ("Johnson" . "Barbara")
       ("Osera" . "Peter-Michael")
       ("Rebelsky" . "Samuel")
       ("Stone" . "John")
       ("Vostinar" . "Anya")
       ("Walker" . "Henry")
       ("Weinman" . "Jerod"))
> (hash-ref csfaculty "Samuel")
Error! . . hash-ref: no value found for key
Error!   key: "Samuel"
> (define ytlucafsc (hash-invert csfaculty))
> (hash-ref ytlucafsc "Samuel")
"Rebelsky"
> (hash-ref ytlucafsc "Fahmida")
"Hamid"

Note that each time we call hash-invert, it should return a new hash table. For example,

> (define hash1 (hash-invert '#hash(("a" . "apple") ("b" . "banana"))))
> (define hash2 (hash-invert '#hash(("red" . "apple") ("yellow" . "banana"))))
> hash1
'#hash(("apple" . "a") ("banana" . "b"))
> hash2
'#hash(("apple" . "red") ("banana" . "yellow"))

Note: When documenting the procedure, make sure to consider special cases, such as what happens when two keys in the original hash table share the same value.

Problem 2: Sequential sentences

Topics: randomness, local bindings, text generation

As you may recall, in the reading on randomness and the corresponding lab, we developed programs that wrote simple sentences. Here’s a variant of that code.

;;; Procedure:
;;;   random-elt
;;; Parameters:
;;;   lst, a non-empty list 
;;; Purpose:
;;;   Unpredictably pick an element of lst.
;;; Produces:
;;;   val, a value
;;; Preconditions:
;;;   [No additional]
;;; Postconditions:
;;;   * val is an element of lst.
;;;   * If lst contains more than one element, it is difficult to predict 
;;;     which element val is.
(define random-elt
  (lambda (lst)
    (list-ref lst (random (length lst)))))

;;; Procedure:
;;;   random-sentence
;;; Parameters:
;;;   [None]
;;; Purpose:
;;;   Generate a simple, unpredictable, sentence.
;;; Produces:
;;;   sentence, a string.
;;; Preconditions:
;;;   [No additional]
;;; Postconditions:
;;;   sentence is a simple English sentence.
(define random-sentence
  (lambda ()
    (string-append
     "The "
     (random-thing) " "
     (random-elt transitive-verbs) " "
     (add-indefinite-article (random-thing)) ".")))

;;; Procedure:
;;;   capitalize
;;; Parameters:
;;;   str, a string
;;; Purpose:
;;;   Capitalizes a string
;;; Produces:
;;;   capitalized, a string
;;; Preconditions:
;;;   [No additional]
;;; Postconditions:
;;;   * (substring capitalized 1) = (substring str 1)
;;;   * If (string-ref str 0) is a lowercase letter,
;;;     (string-ref capitalized 0) is (char-upcase (string-ref str 0))
;;;   * Otherwise, (string-ref capitalized 0) is (string-ref str 0)
(define capitalize
  (lambda (str)
    (regexp-replace "^[a-z]" str string-upcase)))

;;; Procedure:
;;;   add-indefinite-article
;;; Parameters:
;;;   str, a string
;;; Purpose:
;;;   Add the appropriate article to the front of a string
;;; Produces:
;;;   extended, a string
;;; Preconditions:
;;;   [No additional]
;;; Postconditions:
;;;   * If str begins with a lowercase vowel, extended is "an str"
;;;   * If str begins with an uppercase vowel, extended is "An str"
;;;   * If str begins with an uppercase consonant, extended is "A str"
;;;   * Otherwise, extended is "a str"
(define add-indefinite-article
  (lambda (str)
    (cond
      [(regexp-match? #px"^[aeiou]" str)
       (string-append "an " str)]
      [(regexp-match? #px"^[AEIOU]" str)
       (string-append "An " str)]
      [(regexp-match? #px"^[A-Z]" str)
       (string-append "A " str)]
      [else
       (string-append "a " str)])))
     
;;; Procedure:
;;;   random-thing
;;; Parameters:
;;;   [None]
;;; Purpose:
;;;   Generate a simple, unpredictable, noun phrase.
;;; Produces:
;;;   thing, a string
;;; Preconditions:
;;;   [No additional]
;;; Postconditions:
;;;   thing is a noun phrase, something that can serve as the
;;;   subject or object of a transitive verb.  However, thing
;;;   still requires an article.
(define random-thing
  (lambda ()
    (string-append
     (random-elt adjectives) " "
     (random-elt nouns))))

;;; Values:
;;;   adjectives
;;;   nouns
;;;   transitive-verbs
;;; Type:
;;;   list of strings
(define adjectives 
  (list "heavy" "blue" "green" "hot" "cold" "disgusting"
        "antipodean" "existential"))
(define nouns 
  (list "aardvark" "baboon" "civet" "dingo" "emu" "zebra"))
(define transitive-verbs
  (list "saw" "threw" "attacked" "considered" "studied" "visited"))

One might hope to use some of these techniques to write stories, or at least story-like things. Unfortunately, each random sentence appears to be independent of every other sentence.

Document and write a procedure, (random-story), that generates six random sentences with the restriction that the subject of each sentence after the first must be either the subject or the object of the previous sentence, with the choice between the two made randomly.

> (random-story)
"The existential civet threw an existential dingo.  The existential civet visited a green baboon.  The green baboon considered a hot dingo.  The hot dingo saw a blue civet.  The blue civet studied an antipodean baboon.  The antipodean baboon considered a green civet."

Note: You will not be able to call random-sentence in writing random-story. Rather, you’ll need to generate the sequence of subjects and objects and then combine them into a story. We would recommend that you consider using local bindings to do so.

Note: You should feel free to choose different lists of nouns so that your stories are a bit more varied and interesting.

Problem 3: Whatzitdo?

Topics: documentation, code reading, numeric values

Sometimes students (and professors) come up with difficult-to-read solutions to simple problems, like this one below:

(define what ( lambda ( scale)
(let* ( [p symbol?] [q list?]
[ r 'other ] [s 'symbol ] [t 
'hash] [ u number?][v hash?
] [w 'list] [x 'string] [y
 'number ] [z  string?] [
image ( lambda ( drawing
)(cond [( u drawing ) y
]      [ (and ( not (u
drawing) )( p drawing
) ) s] [ (q drawing)
w] [(or (q drawing)
( v drawing)) t][(
z   drawing ) x][
else r] ))])(map
image scale))))

a. Clean up this procedure. You should reformat the code; rename the procedure, parameters, and variables; and simplify any unnecessarily complicated code.

b. Write 6P-style documentation for the code.

c. Explain how the code achieves its purpose.

Problem 4: Extracting entries

Topics: regular expressions

In your solution to the Twitter problem in assignment 6, you may have written a procedure something like the following. (You probably didn’t use quite as many backslashes as we did.)

;;; Procedure:
;;;   extract-tweet-text-field
;;; Parameters:
;;;   tweetstring, a tweet
;;; Purpose:
;;;   Extract the text field from the given string.
;;; Produces:
;;;   text, a string
;;; Preconditions:
;;;   tweetstring has the standard string/JSON representation of tweets,
;;;   e.g., "{\"source\:": \"...\", \"id_str\": \"...\", ...}"
;;; Postconditions:
;;;   text is the portion of the string corresponding to the text section.
(define extract-tweet-text-field
  (lambda (tweetstring)
    (regexp-replace* "^.*\"text\": \"(([^\"\\\\]|\\\\\")*?)\".*$" tweetstring "\\1")))

Let’s see how well it works.

> tweet
"{\"source\": \"Twitter for Android\", \"id_str\": \"812815404175421445\", \"text\": \".@FoxNews - \\\"Objectified\\\" tonight at 10:00 P.M. Enjoy!\", \"created_at\": \"Sun Dec 25 00:21:08 +0000 2016\", \"retweet_count\": 1482, \"in_reply_to_user_id_str\": null, \"favorite_count\": 5871, \"is_retweet\": false}\n"
> (extract-tweet-text-field tweet)
".@FoxNews - \\\"Objectified\\\" tonight at 10:00 P.M. Enjoy!"
> (extract-tweet-text-field "{\"text\": \"this is an example\"}")
"this is an example"

Not bad.

But we should be writing more general procedures.

Write, but do not document a procedure, (extract-field field str), that takes two parameters, a field name (e.g., "source" or "text") and a string like the tweet above, and extracts the given field from the string. (You need only support fields that name strings.)

;;; Procedure:
;;;   extract-field
;;; Parameters:
;;;   field, a string
;;;   str, a string
;;; Purpose:
;;;   Extract a field from a JSON string of the form 
;;;   "{\"field1\": \"contents1\", \"field2\": \"contents2\", ...}"
;;; Produces:
;;;   contents, a string
;;; Preconditions:
;;;   str contains a field of the given form.
;;; Postconditions:
;;;   contents contains the associated value.
(define extract-field
  (lambda (field str)
    ...))

Here are some examples of the procedure in action.

> (extract-field "text" tweet)
".@FoxNews - \\\"Objectified\\\" tonight at 10:00 P.M. Enjoy!"
> (extract-field "id_str" tweet)
"812815404175421445"
> (extract-field "source" tweet)
"Twitter for Android"

Your procedure should work with anything of a similar form, not just tweets.

> (extract-field "thing" "{\"thing\": \"abcde\", \"more\": \"efghi\"}")
"abcde"
> (extract-field "more" "{\"thing\": \"abcde\", \"more\": \"efghi\"}")
"efghi"

Problem 5: Sorting strings starting with the shortest

Topics: sorting, conditionals, precondition testing

Document and write a procedure, (sort-by-length strings), that takes as input a list of strings and sorts that list by length. If two strings are the same length, they should be ordered alphabetically.

> (sort-by-length (string-split "once upon a time in a land far far away there lived a strange language"))
'("a" "a" "a" "in" "far" "far" "away" "land" "once" "time" "upon" "lived" "there" "strange" "language")
> (sort-by-length (string-split "he took his vorpal sword in hand"))
'("he" "in" "his" "hand" "took" "sword" "vorpal")
> (sort-by-length (string-split "long time the manxome foe he sought"))
'("he" "foe" "the" "long" "time" "sought" "manxome")

Your procedure should check its preconditions and report appropriate error messages if those preconditions are not met.

> (sort-by-length "this is a bad input")
Error! sort-by-length: Invalid input; expected a list of strings, received "this is bad input"

Note that you will likely find it useful to write a helper procedure, (shorter? str1 str2), that returns true when str1 is shorter than str2 or when the two strings are of equal length and str1 alphabetically precedes str2.

Problem 6: Representing ‘blog posts

Topics: XML, processing XML, structs

We’ve considered a variety of techniques for representing structured data, including XML, lists, and Racket structs. Consider simple ‘blog posts. In representing such posts, we might want to store the following information.

  • a title (a string),
  • an author (also a string),
  • the content (also a string),
  • its tags (a list of strings),
  • the number of views (an integer)

In Racket, we would probably define that struct as follows.

(struct post (title author content tags views))

In XML, we might represent a simple ‘blog post as follows.

<post>
  <title>A sample post</title>
  <author>Some Body</author>
  <content>This is my first post!  Aren't you impressed?</content>
  <tags>
    <tag>First</tag>
    <tag>Boring</tag>
    <tag>Example</tag>
  </tags>
  <views>5</views>
</post>

In the list-based representation, that XML would appear as follows.

'(post (title "A sample post") (author "Some Body") (content "This is my first post!  Aren't you impressed?") (tags (tag "First") (tag "Boring") (tag "Example")) (views "5"))

a. Write, but do not document, a procedure, (post->xml post), that takes as a parameter a post struct and returns an XML list of the appropriate form.

> (post->xml (post "A" "B" "C" (list "D" "E") 3))
'(post (title "A") (author "B") (content "C") (tags (tag "D") (tag "E")) (views "3"))
> (xml->string (post->xml (post "A" "B" "C" (list "D" "E") 3)))
"<post><title>A</title><author>B</author><content>C</content><tags><tag>D</tag><tag>E</tag></tags><views>3</views></post>"

b. Write, but do not document, a procedure, (xml->post xml), that takes the XML for a ‘blog post and returns a post struct.

> (define sample (xml->post '(post (title "Title") (author "Author") (content "Content") (tags (tag "Tag1") (tag "Tag2")) (views "11"))))
> sample
#<post>
> (post-title sample)
"Title"
> (post-author sample)
"Author"
> (post-content sample)
"Content"
> (post-tags sample)
'("Tag1" "Tag2")
> (post-views sample)
11
> (define sample2 (xml->post (string->xml "<post><author>An author</author><title>A post</title><content>Some content.</content><tags><tag>This</tag><tag>That</tag></tags><views>42</views></post>")))
> sample2
#<post>
> (post-title sample2)
"A post"
> (post-author sample2)
"An author"
> (post-tags sample2)
'("This" "That")
> (post-views sample2)
42
> 

Questions and Answers

We will post answers to questions of general interest here while the exam is in progress. Please check here before emailing questions!

General Questions

What is a general question?
A question that is about the exam in general, not a particular problem.
Are we allowed to talk to others about general issues from the first few weeks of class, such as the syntax of section?
No. We’ve had too many problems with “slippery slope” issues.
Questions should go to the instructors.
Do all the sections have the same exam?
Yes.
Can we still invoke the “There’s more to life” clause if we spend more than five hours on the exam?
Yes. However, we really do recommend that you stop at five hours unless you are very close to finishing. It’s not worth your time or stress to spend more effort on the exam. It is, however, worth your time to come talk to us, and perhaps to get a mentor or more help (not on this exam, but on the class). There’s likely some concept you’re missing, and we can help figure that out.
What do you mean by “implement?”
Write a procedure or procedures that accomplish the given task.
Do we have to make our code concise?
You should strive for readable and correct code. If you can make it concise, that’s a plus, but concision is secondary to readability and correctness. Long or muddled code is likely to lose points, even if it is correct.
Much of your sample 6P-style documentation has incomplete sentences. Can we follow that model? That is, can we use incomplete sentences in our 6P-style documentation?
Yes, you can use incomplete sentences in 6P-style documentation.
You tell us to start the exam early, but then you add corrections and questions and answers. Isn’t that contradictory? Aren’t we better off waiting until you’ve answered the questions and corrected any errors?
We think you’re better able to get your questions answered early if you start early. Later questions will generally receive a response of “See the notes on the exam.”
How do we know what our random number is?
You should have received instructions on how to generate your random number on the day the exam was distributed. If you don’t have a number, ask your professor for one before submitting your exam.
To show we’ve tested the code informally, would you just like us to just post the inputs we used to test the procedure? If so, how should we list those?
Copy and paste the interactions pane into the appropriate place in the definitions pane. Put a #| before the pasted material. Put a |# after the pasted material.
Should we cite our partner from a past lab or assignment if we use code from a past lab or assignment?
You should cite both yourself and your partner, although you should do so as anonymously as possible. For example “Ideas taken from the solution to problem 7 on assignment 2 written by student 641321 and partner.”
If we write a broken procedure and replace it later, should we keep the previous one?
Yes! This will help us give you partial credit if your final procedure isn’t quite right. But make sure to comment out the old one using #| and |# or semicolons. You might also add a note or two as to what you were trying to do.
Do I need to document helper procedures?
You must document helpers using the 4Ps.
Can I use procedures that we have not covered in class?
Probably not. Ask about individual procedures if you’re not sure.
I discovered a way to define procedures without using lambda that looks like (define (proc params) body). Can I use that?
No.
Is extra credit available on this exam?
No explicit extra credit is available. However, we may find that you’ve come up with such wonderful answers that we cannot help but give you extra credit. (Don’t laugh. It happens almost every time.)
DrRacket crashed and ate my exam. What do I do?
Send your instructor the exam file and any backups that DrRacket seems to have made. (Those tend to have a similar file name, but with pound signs or tildes added at the front or back.) In the future, email yourself a copy of the exam each time you pause.
How do I know when you’ve added a new question or answer?
We try to add a date stamp to the questions and answers. Those without a date stamp were likely present when the exam was released.
Should we cite readings from the CSC 151 Web site? If so, how much information should we give?
Yes. The title and URL should suffice.
Can I use other websites as a reference for the exam?
As the exam policies page states, “This examination is open book, open notes, open mind, open computer, open Web.” Note that it also states “If you find ideas in a book or on the Web, be sure to cite them appropriately.”
Do we have to cite the exam itself?
No.
How do I generate a random six digit number?
(random 1000000). If you end up with a number less than six digits, add zeros to the left side of the number until you have six digits.
Some of the problems are based on a recent homework assignment. Should I cite my work on that assignment?
If you refer to your work on that assignment in solving the problem, you should cite your assignment.
How do I cite my work on an assignment?
Something like “Student 123456 and partner. Homework Assignment 3. CSC 151.01. 6 February 2019.”
I see the comment ; STUB on some of the procedures. What does that mean?
We use the term “STUB” for a procedure that gives some default value rather than the correct one. Stub procedures are useful when you need the procedure to exist during development, but have not yet had time to implement it. You should remove these comments as you replace stub procedures with real implementations.
Are there any requirements for informal tests?
Sort of. They should be good tests, though they need not be exhaustive. Your informal tests only count if they are different from the examples on the exam.
Do we need to show examples of running our helper procedures?
No, but you should be checking them carefully. You don’t need to include these examples in your exam.
How much time do you think each problem should take? [2019-03-06, 12:30 p.m.; revised 2019-03-06, 6:00 p.m.]
These are SamR’s answers.
Problem 1 should be straightforward, although there are some things to think about in the documentation. I would expect 15 minutes to write the code and 15 minutes for documentation.
Problem 2 has a lot of chances to go wrong. If things go right, this should be about thirty minutes, but I would budget an hour for it.
Problem 3 is a standard whatzitdo. 45 minutes seems reasonable.
Problem 4 requires a bit of reading, but the task itself is straightforward if you understand how to generalize code. (You don’t have to understand much of the horrible regular expression; you just have to generate a siilar string.) Somewhere between 15 minutes and 30 minutes.
Problem 5 is another one that should be about 15 minutes for documentation and 15 minutes for code. Writing the shorter? procedure is core to this problem.
Problem 6 has enough moving pieces (but no documentation) that I would budget an hour. There are some subtleties to sxpath-match that might take a little time to work through (send questions when you’re not sure, or look at the reading/lab).
You can keep the times lower by sending us questions when you hit barriers.
How much time did it take you to solve each problem? [2019-03-06, 12:30 p.m.; revisted 5:30 p.m.]
Problem 1: Seven minutes. Problem 2: Six minutes. Problem 3: Fourteen minutes. Problem 4: Five minutes. Problem 5: Four minutes. Problem 6: Thirteen minutes.
Some of the problems say “Write, but do not document”. Should we write 4P-style documentation for such procedures? [2019-03-06, 12:30 p.m.]
We’ve done our best to provide documentation for those procedures.

Questions on problem 1

Questions on problem 2

Questions on problem 3

What do you mean by “simplify any unneccessarily complicated code”? [2019-03-07, 4:00 p.m.]
There’s a lot of useless code in the procedure. Get rid of it. It
Why do I get '(list) as an output when I use '('sym) as my input? I would assume that I’d get '(symbol). [2019-03-07, 4:00 p.m.]
Please don’t nest the single quotes. That leads to unexpected behavior. You should get the output you’d expect if you use (list 'sym) as the input.
What is pair?. [2019-03-07, 4:00 p.m.]
Something that should not have been there. We fixed it in the code file before release, but appear to have neglected to do so in the instructions.

Questions on problem 4

Do we need to understand that strange regular expression? [2019-03-06, 12:30 p.m.]
Nope.
Can we assume that the given field appears somewhere in the string? [2019-03-06, 12:30 p.m.]
Yes.

Questions on problem 5

How does sort work? [2019-03-06, 4:00 p.m.]
sort takes a list and a “less than” procedure that compares two values and reorders the list so that each element is less than the subsequent element. You don’t need to know the details of how it does that (yet). For now, you can think of it as using the second parameter to compare neighboring elements and swapping them when they are out of order.
Do we have to explain the type of the incorrect input? [2019-03-09, 9:30 p.m.]
Nope. You can use our standard pattern.
How do I check all the values in a list? [2019-03-09, 9:30 p.m.]
We discuss that in the reading on precondition checking.
I defined shorter? as you suggested and things are not working. [2019-03-09, 9:30 p.m.]
What does your shorter? do with equal length strings? Remember that we said that shorter? should return true for equal length strings only when the first alphabetically precedes the second.
> (shorter? "once" "time")
#t
> (shorter? "once" "away")
#f
Why is it not working when I use map or reduce? [2019-03-09, 9:30 p.m.]
Because map and reduce aren’t really intended for sorting.

Questions on problem 6

I see that the number of views is represented as a string in the list representation and an integer in the struct representation. Is that what you intend? [2019-03-06, 12:30 p.m.]
Yes, that’s what we intend. We generally don’t include numbers in the list-based representation of XML.
Do we have to deal with fields whose contents are not strings, but rather numbers or true or false? [2019-03-07, 4:00 p.m.]
Nope.
Do we have to deal with fields whose contents strings contain quotation marks, backslashes, or commas? [2019-03-07, 4:00 p.m.]
Preferably.

Errata

Please check back periodically in case we find any new issues.

  • Sam forgot to include the instructions for the prologue. [NK and JT, 1 point]
  • The whatzitdo code in the exam does not match the code in the .rkt file. [MX, 1 point]
  • The sample output for the random-story procedure appears incorrect. [JSC, 1 point]
  • The procedure in problem 1 is sometimes called hash-invert and sometimes called hash-inverse. [KS, 1 point]
  • There’s a missing </tags> in problem 6. [LT, 1 point]
  • The last problem says “most” instead of “post”. [SH and JT, 1 point]

Acknowledgements

Some of the problems on this exam are based on—and at times copied from—problems on previous exams for the course. Those exams were written by Charlie Curtsinger, Janet Davis, Fahmida Hamid, Rhys Price Jones, Titus Klinge, Samuel A. Rebelsky, John David Stone, Henry Walker, and Jerod Weinman. Many were written collaboratively, or were themselves based upon prior examinations, so precise credit is difficult, if not impossible.

Some problems on this exam were inspired by conversations with our students and by correct and incorrect student solutions on a variety of problems. We thank our students for that inspiration. Usually, a combination of questions or discussions inspired a problem, so it is difficult and inappropriate to credit individual students.