anchor.diff:    remaining to lowercase."
     (string-downcase (remove-if-not #'alphanumeric-p string)))
   
  -(defclass nominated-work ()
  -  ((raw-author :initarg :raw-author
  -               :reader raw-author
  -               :type string)
  -   (raw-title :initarg :raw-title
  -              :reader raw-title
  -              :type string)
  -   (canonical-title :initarg :canonical-title
  -                    :reader canonical-title
  -                    :type string))
  -  (:documentation
  -   "The title and author of a nominated work."))
  -
  -(defun make-nominated-work (author title)
  -  "Construct a nominated work instance."
  -  (make-instance 'nominated-work
  -                 :raw-author author
  -                 :raw-title title
  -                 :canonical-title (canonical-string title)))
  -
  -(defclass category-ballot ()
  -  ((category :initarg :category
  -             :reader category
  -             :type string)
  -   (nominated-works :initarg :nominated-works
  -                    :accessor nominated-works
  -                    :type list
  -                    :initform (list)))
  -  (:documentation
  -   "The list of nominated works for a category on a voter's ballot."))
  -
  -(defun make-category-ballot (category)
  -  "Construct a category ballot instance."
  -  (make-instance 'category-ballot :category category))
  -
  -(defclass ballot ()
  -  ((voter :initarg :voter
  -          :reader voter
  -          :type string)
  -   (ballot-categories :initarg :ballot-categories
  -                      :accessor ballot-categories
  -                      :type hash-table
  -                      :initform (make-hash-table :test 'equal)))
  -  (:documentation
  -   "A voter's Hugo ballot."))
  -
  -(defun make-ballot (voter)
  -  "Construct a ballot instance."
  -  (make-instance 'ballot :voter voter))
  -
  -(defgeneric add-nominated-work (ballot category nominated-work)
  -  (:documentation "Add a nominated work to a ballot."))
  -
  -(defmethod add-nominated-work ((ballot ballot) category nominated-work)
  -  "Add a nominated work to a ballot."
  -  (let ((category-ballot (gethash category (ballot-categories ballot)
  -                                  (make-category-ballot category))))
  -    (push nominated-work (nominated-works category-ballot))
  -    (setf (gethash category (ballot-categories ballot)) category-ballot)))
  -
  -(defgeneric category-nominated-works (ballot category)
  -  (:documentation "Return the list of nominated works in the CATEGORY."))
  -
  -(defmethod category-nominated-works ((ballot ballot) category)
  -  (let ((category-ballot (gethash category (ballot-categories ballot))))
  -    (unless (null category-ballot)
  -      (nominated-works category-ballot))))
  -
  -(defun category-ballots (ballots category)
  -  "Return a list of category-ballot objects for the CATEGORY."
  -  (remove-if #'null (mapcar (lambda (ballot)
  -                              (gethash category (ballot-categories ballot)))
  -                            ballots)))
  -
  -(defun category-votes (ballots category)
  -  "Return a list of lists with each inner list containing the title of a
  -  nominated work and the number of ballots on which it appeared."
  -  (let ((votes (list)))
  -    (dolist (ballot (category-ballots ballots category) votes)
  -      (dolist (work (nominated-works ballot))
  -        (let ((vote (find-if (lambda (vote)
  -                               (string= (car vote) (canonical-title work)))
  -                             votes)))
  -          (if (null vote)
  -              (push (list (canonical-title work) 1) votes)
  -              (incf (second vote))))))))
  -
  -(defun current-rule-results (ballots)
  -  "Return the list of nominated works in each category that result from
  -  applying the current rules to the BALLOTS."
  -  (dolist (category (categories))
  -    (let ((sorted-results (sort (category-votes ballots category)
  -                                #'> :key #'second)))
  -      (format t "~A~%" (category->description category))
  -      (dolist (result sorted-results)
  -        (when (>= (second result) (second (sixth sorted-results)))
  -          (format t "~A:  ~A~%" (first result) (second result)))))))
  -
   (defun find-ballot (voter ballots)
     "Find the ballot for VOTER."
  -  (find-if (lambda (ballot)
  -             (string= voter (voter ballot)))
  -           ballots))
  +  (assoc voter ballots :test 'string=))
   
   (defun file->ballots (filename)
     "Convert the raw data into ballots."
  
positive.code: 
  (defun elimination-phase (titles scores)
    "Return a list of one or more titles or authors on the fewest ballots."
    (let* ((titles-scores
            (remove-if-not (lambda (score)
                             (find (first score) titles :test 'string=))
                           scores))
           (ordered-by-ballots (sort (copy-seq titles-scores) #'< :key #'third))
           (cutoff (third (first ordered-by-ballots)))
           (eliminated (remove-if (lambda (score)
                                    (> (third score) cutoff))
                                  titles-scores)))
      (mapcar #'first eliminated)))
  
  (defun eliminate (eliminated title-lists)
    "Remove the ELIMINATED title or authors from the TITLE-LISTS."
    (dotimes (i (length title-lists))
      (setf (nth i title-lists)
            (set-difference (nth i title-lists) eliminated :test 'string=)))
    (remove-if #'null title-lists))
  
  (defmacro while (test &body body)
    "A little syntactic sugar around DO."
    `(do () ((not ,test)) ,@body))
  
  (defun fraction->string (fraction)
    "Reduce FRACTION and return it as a string."
  
negative.code:   ;; TODO:  in write up, write this first then the functions
    (dolist (category (categories))
      (let ((contenders (category-titles ballots category))
            (category-ballots (category-ballots ballots category)))
        (while (> (length contenders) +maximum-results+)
          (let* ((scores (score contenders category-ballots))
                 (least-popular (selection-phase scores))
                 (eliminated (elimination-phase least-popular scores)))
            (setf contenders (set-difference contenders eliminated))
            (setf category-ballots (eliminate eliminated category-ballots))
            (unless (> (length contenders) +maximum-results+)
              (category-eph-results category
                                    (score contenders category-ballots))))))))
  
  ;; To generate the results under the E Pluribus Hugo rules, evaluate
  ;;   (eph-rule-results *ballots*)
  