anchor.diff:                                          (:= 'id row-id))))
           (and (not expiredp) session-string)))))
   
  +(defun handle-new-client (res ws-client json-message
  +                          &aux (message (jsown:parse json-message)))
  +  (let* ((client (make-client :ws-client ws-client
  +                              :user-agent (jsown:val message "useragent")
  +                              :validation-token (jsown:val message "token")))
  +         (client-valid-p (validate-client res client))
  +         (char-index (jsown:val message "char"))
  +         (entity-id (nth char-index (account-characters (client-account-id client)))))
  +    (cond ((and client-valid-p entity-id)
  +           (logit "Client validated: ~S.~%It's now playing as ~A."
  +                  client (character-name entity-id))
  +           ;; TODO - Need to do something about clients connecting to the same entity.
  +           (setf (client-entity-id client) entity-id)
  +           (add-client res client))
  +          (t
  +           (logit "No session. Disconnecting client. (~S)" client)
  +           (disconnect-client res client)))))
  +
  +;;;
  +;;; Protocol implementations
  +;;;
  +(defmethod ws:resource-client-disconnected ((res chat-server) ws-client
  +                                            &aux (client (find-client res ws-client)))
  +  (logit "Client ~S disconnected." client)
  +  (continuable (remove-client res client)))
  +
  +(defmethod ws:resource-received-text ((res chat-server) ws-client message)
  +  (continuable
  +    (let ((client (find-client res ws-client)))
  +      (if (and client (client-session client))
  +          (handle-client-message res client message)
  +          (handle-new-client res ws-client message)))))
  +
  +(defmethod add-client ((srv chat-server) client)
  +  (logit "Adding pending client ~S." client)
  +  (setf (gethash (client-ws-client client) (slot-value srv 'clients))
  +        client))
  +
  +(defmethod remove-client ((srv chat-server) client)
  +  (remhash (client-ws-client client) (slot-value srv 'clients)))
  +
  +(defmethod disconnect-client ((server chat-server) client)
  +  (ws:write-to-client-close (client-ws-client client)))
  +
   (defmethod validate-client ((srv chat-server) client &aux (*acceptor* *server*))
     (logit "Attempting to validate client: ~S" client)
     (when-let* ((session-string (find-session-string-by-token (client-validation-token client)))
  
positive.code:             (logit "Got an error while the handler for '~A': ~A" raw-message e))))
        (logit "Unknown command '~A'. Ignoring." (car message)))))
  
  (defhandler ooc (message)
    (map nil (rcurry #'send-ooc (account-display-name (client-account-id *client*)) message)
         (local-actors *client*)))
  
  (defhandler dialogue (message)
    (handler-case
  
negative.code: 
  (defvar *websocket-server*)
  
  (defclass chat-server (ws:ws-resource)
    ((clients :initform (make-hash-table :test #'eq))))
  
  (defun register-chat-server ()
    (ws:register-global-resource
     "/chat"
     (setf *websocket-server* (make-instance 'chat-server))
     (ws:origin-prefix "http://zushakon.sykosomatic.org")))
  
  (defgeneric add-client (chat-server client))
  (defgeneric remove-client (chat-server client))
  