anchor.diff:                                           (second word-pronounciation)))))
           finally (return dict)))))
   
  +(defun lookup-syllables (dict word)
  +  (gethash (remove-if-not (lambda (c)
  +                            (or (alpha-char-p c)
  +                                (find c "'")))
  +                          (string-downcase word))
  +           dict))
  +
   (defun string-to-pattern (dict s)
     (join-to-string ""
                     (loop for word in (ppcre:split "\\s" s)
  -                        as pattern = (gethash (string-downcase word) dict)
  +                        as pattern = (lookup-syllables dict word)
                           collect (cond
                                     ((null pattern)
                                      ;; fail if a word can't be found.  We don't
                                      ;; want any false positives.
  -                                   (log:log-message :info "~a not found" word)
                                      (return-from string-to-pattern nil))
                                     ((= (length pattern) 1)
                                      ;; single words can match stressed or unstressed parts
  
positive.code:            (reply-to message "~a" (string-upcase sentence)))
            ((pattern-matches-p +camptown-pattern+ pattern)
             ;; Camptown ladies sing this song
             (reply-to message "doo-dah doo-dah"))
            ((= (length pattern) 17)
             ;; Haiku
             (reply-to message "~a said a haiku!" (source message))))))))
  
negative.code:             do (return nil)
            finally (return t))))
  
  (defun consume-n-syllables (tuples n)
    (let* ((line (loop
                  for tuple on tuples
                  as total = (cdr (first tuple)) then (+ total (cdr (first tuple)))
                  while (< total n)
                  collect (car (pop tuples)) into consumed
                  finally (return (and (= total n)
                                       (append consumed (list (car (pop tuples)))))))))
      (values line tuples)))
  
  (defun try-haiku (dict text)
    "Returns a string displaying the haiku if the text has words adding
    to 5 syllables, then 7, then 5."
    (let ((counts (loop for word in (ppcre:split "\\s" text)
                        collect (cons word (length (lookup-syllables dict word))))))
      (cond
        ((some (lambda (c) (zerop (cdr c))) counts) 
         ;; no false positives
         (return-from try-haiku nil))
        ((/= (reduce '+ counts :key 'cdr) 17)
         ;; All haiku have 17 syllables
         (return-from try-haiku nil))
        (t
         (with-output-to-string (result)
           (let (words-done words-left)
             (multiple-value-setq (words-done words-left)
               (consume-n-syllables counts 5))
             (unless words-done
               (return-from try-haiku nil))
             (write-string (join-to-string " " words-done) result)
             (write-string " / " result)
             (multiple-value-setq (words-done words-left)
               (consume-n-syllables words-left 7))
             (unless words-done
               (return-from try-haiku nil))
             (write-string (join-to-string " " words-done) result)
             (write-string " / " result)
             (multiple-value-setq (words-done words-left)
               (consume-n-syllables words-left 5))
             (unless words-done
               (return-from try-haiku nil))
             (write-string (join-to-string " " words-done) result)))))))
  
  (defmethod examine-message ((module poetry-module) (message irc:irc-privmsg-message))
    ;; Haikus get first dibs.
    (let ((haiku (try-haiku (syllables-of module) (second (arguments message)))))
      (when haiku
        (reply-to message "~a" haiku)
        (return-from examine-message)))
    
    (dolist (sentence (ppcre:split " *[.?!] *" (second (arguments message))))
      (let ((pattern (string-to-pattern (syllables-of module) sentence)))
        (when pattern
  