anchor.diff:    ((key :initarg :key :reader websocket-illegal-key-of
           :initform (required-argument :key)
           :documentation "Original, spurious key argument"))
  -  (:documentation "Signal in case the client has sent an erroneous handshake key"))
  +  (:documentation "Signalled if client sends erroneous handshake key"))
   
   (define-condition websocket-illegal-frame-type (condition)
     ((type :initarg :type :reader websocket-illegal-frame-type-of
            :initform (required-argument :type)
            :documentation "Spurious frame type received"))
  -  (:documentation "Signal in case the client has sent a spurious frame type"))
  -
  -(defun integer-octets-32be (number)
  -  "integer-octets-32be number => unsigned byte array
  -
  -Transform NUMBER into 32bit big endian octets. Required for the (luckily
  -obsoleted) old \"hixie\" and early \"hybi\" WebSocket drafts."
  -  (let ((result (make-array 4 :element-type '(unsigned-byte 8))))
  -    (dotimes (index 4 result)
  -      (let ((position #+little-endian (- 24 (* 8 index)) #-little-endian (* 8 index)))
  -        (setf (aref result index)
  -              (ldb (byte 8 position) number))))))
  -
  -(let ((digit-scanner (create-scanner "[^\\d]"))
  -      (space-scanner (create-scanner "[^ ]")))
  -  (defun websocket-keyhasha (key)
  -    "websocket-keyhash key => unsigned byte array
  -
  -Process a (legacy) WebSocket key and evaluate to a byte sequence that becomes
  -part of the challenge. An error will be signalled in case the key is spurious."
  -    (let ((number (parse-integer (regex-replace-all digit-scanner key "")
  -                                 :junk-allowed nil))
  -          (spaces (length (regex-replace-all space-scanner key ""))))
  -      (if (or (zerop spaces)
  -              (not (zerop (mod number spaces))))
  -          (error 'websocket-illegal-key :initarg key)
  -          (integer-octets-32be (/ number spaces)))))) ; crack-smoking mac pussies at google want big endian
  +  (:documentation "Signal if client sends spurious frame type"))
   
   (defun read-bytes-array (stream number)
  -  "read-bytes-array stream number => unsigned byte array
  -
  -Read NUMBER bytes from Chunga STREAM into array and return it."
  +  "Read NUMBER bytes from Chunga STREAM into array and return it."
     (let ((result (make-array number :element-type '(unsigned-byte 8))))
       (dotimes (index number result)
         (setf (aref result index)
               (char-int (read-char* stream t))))))
   
   (defun read-key3 (request)
  -  "read-key3 request => unsigned byte array
  -
  -Read eight bytes from REQUEST's content stream and return them as a byte
  +  "Read eight bytes from REQUEST's content stream and return them as a byte
   array."
     (read-bytes-array (content-stream request) 8))
   
   (defun digest-key (key)
  -  "digest-key key => unsigned byte array
  -
  -Evaluates to MD5 digest of KEY sequence."
  +  "Evaluates to MD5 digest of KEY sequence."
     (digest-sequence :md5 key))
   
   (defun websocket-uri (request host &optional ssl)
  -  "websocket-uri request host &optional ssl => URI string
  -
  -Evaluate arguments to corresponding WebSocket (ws:// or wss://) URL."
  +  "Form WebSocket URL (ws:// or wss://) URL."
     (format nil "~:[ws~;wss~]://~a~a" ssl host (script-name request)))
   
  -(defun handle-handshake-legacy (request reply)
  -  "handle-handshake-legacy request reply => challenge
  -
  -Legacy (< draft-hybi-02) method of performing a WebSocket handshake. Still in
  -use for FF4 (if activated) and many versions of Chromium. Also sets the
  -Sec-WebSocket-Origin, Sec-WebSocket-Location and Sec-WebSocket-Protocol response
  -headers, if successful. The challenge is sent over the raw TCP socket."
  -  (prog1
  -      (let* ((stream (make-in-memory-output-stream)))
  -        (mapc #'(lambda (key)
  -                  (write-sequence key stream))
  -              (list (websocket-keyhash (header-in :sec-websocket-key1 request))
  -                    (websocket-keyhash (header-in :sec-websocket-key2 request))
  -                    (read-key3 request)))
  -        (digest-key (get-output-stream-sequence stream)))
  -    (setf (header-out :sec-websocket-origin reply) (header-in :origin request)
  -          (header-out :sec-websocket-location reply) (or (websocket-uri request (header-in :host request)
  -                                                                        (ssl-p (request-acceptor request))))
  -          (header-out :sec-websocket-protocol reply) (header-in :sec-websocket-protocol request))))
  -
  -(defun handle-handshake (request reply)
  -  "handle-handshake for v13
  -
  -Also sets the
  -Sec-WebSocket-Origin, Sec-WebSocket-Location and Sec-WebSocket-Protocol response
  -headers, if successful. The challenge is sent over the raw TCP socket."
  -  (prog1
  -    (let ((sec-websocket-key+magic
  -            (concatenate 'string (header-in :sec-websocket-key request) "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")))
  -    (setf (header-out :sec-websocket-accept reply)
  -      (base64:usb8-array-to-base64-string
  -        (ironclad:digest-sequence 'ironclad:sha1 (ironclad:ascii-string-to-byte-array sec-websocket-key+magic))))
  -    (setf (header-out :sec-websocket-origin reply) (header-in :origin request)
  -          (header-out :sec-websocket-location reply) (or (websocket-uri request (header-in :host request)
  -                                                                        (ssl-p (request-acceptor request))))
  -          (header-out :sec-websocket-protocol reply) (header-in :sec-websocket-protocol request)))))
  -
  -(defun websocket-handle-handshake (request reply)
  -  "websocket-handle-handshake request reply => handshake
  -
  -Try to determine the WebSocket handshake version by checking REQUEST headers and
  -handle accordingly, if possible."
  -  (handler-case
  -      (prog1
  -          (cond ((not (equal "13" (header-in* :sec-websocket-version request)))
  -                 (error 'websocket-unsupported-version :version (header-in* :sec-websocket-version request)));; (header-in :sec-websocket-version request)))
  -                ((header-in :sec-websocket-draft request)
  -                 (error 'websocket-unsupported-version (header-in :sec-websocket-draft request)))
  -                ((header-in :sec-websocket-key request)
  -                 (handle-handshake request reply))
  -                (t (error 'websocket-unsupported-version :version "unknown")))
  -        (setf
  -          (return-code* reply) +http-switching-protocols+
  -          (header-out :upgrade reply) "WebSocket"
  -          (header-out :connection reply) "Upgrade"
  -          (content-type* reply) "application/octet-stream"))
  -    (websocket-illegal-key (condition)
  -      (hunchentoot-error "Illegal key ~a encountered" (websocket-illegal-key-of condition)))
  -    (websocket-unsupported-version ()
  -      (hunchentoot-error "WebSocket handshake failed because of unsupported protocol version"))))
  -
  -(defun websocket-send-term (&optional (stream *websocket-stream*) (mutex *websocket-stream-mutex*))
  -  "websocket-send-term &optional stream mutex => side effect
  -
  -Send the magic WebSocket termination sequence across STREAM."
  +(defun websocket-send-term (&optional
  +                              (stream *websocket-stream*)
  +                              (mutex *websocket-stream-mutex*))
  +  "Send the magic WebSocket termination sequence across STREAM."
     (with-lock-held (mutex)
       (write-sequence +websocket-terminator+ stream)
       (force-output stream)))
   
  -(defun websocket-send-message (message &optional (stream *websocket-stream*) (mutex *websocket-stream-mutex*))
  -  "websocket-send-message &optional stream mutex => side effect
  -
  -Encode MESSAGE as UTF-8 bytes and send it across STREAM in a proper frame."
  +(defun websocket-send-message (message &optional
  +                                         (stream *websocket-stream*)
  +                                         (mutex *websocket-stream-mutex*))
  +  "Encode MESSAGE as UTF-8 bytes and send it across STREAM in a proper frame."
     (when (> (length message) 0) ; empty message would send terminator
       (log-message* :debug "Going to send websocket message ~a" message)
       (with-lock-held (mutex)
  
positive.code: (defvar *websocket-socket* nil
    "The currently active WebSocket socket")
  
  (defparameter *websocket-handlers* nil
    "List of handler closures that will be queried for new connections")
  
  (defclass websocket-request (request)
    ((handler :accessor websocket-request-handler
              :initform nil
              :documentation "Message handler of the current request"))
    (:documentation "Subclass of the regular Hunchentoot request"))
  
  (defclass websocket-reply (reply) ()
    (:documentation "Subclass of the regular Hunchentoot reply (used only for dispatching)"))
  
  (defmethod initialize-instance :after ((reply websocket-reply) &rest initargs &key &allow-other-keys)
    "initialize-instance :after websocket-reply &rest initargs &key &allow-other-keys => side effect
  
  Set the reply's external format to Unix EOL / UTF-8 explicitly."
    (declare (ignore initargs))
    (setf (reply-external-format reply) (make-external-format :utf8 :eol-style :lf)))
  
  (defclass websocket-acceptor (acceptor)
    ((websocket-timeout :initarg :websocket-timeout
                        :accessor websocket-timeout
                        :initform 60
                        :documentation "Custom WebSocket timeout overriding the default usocket one"))
    (:default-initargs :request-class 'websocket-request :reply-class 'websocket-reply)
    (:documentation "Special WebSocket acceptor to be used in place of the regular Hunchentoot one"))
  
  (defclass websocket-ssl-acceptor (websocket-acceptor ssl-acceptor) ()
    (:documentation "Special WebSocket SSL acceptor"))
  
negative.code: 
  (in-package :hunchensocket)
  
  (define-constant +websocket-terminator+
      '(#x00 #xff)
    :test #'equal
    :documentation "Fixed WebSocket terminator value")
  (define-constant +websocket-magic-key+
    "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
    :test #'string=
    :documentation "Fixed magic WebSocket UUIDv4 key use in handshakes")
  
  (defvar *websocket-stream* nil
    "The currently active WebSocket stream")
  