anchor.diff:                 (prog1 nil (handle-disconnect *reply* session-id)))))
         (handle-handshake scanner message-handler)))
   
  +;;; exported
   (defmacro define-socket.io-handler (message-handler &key (name 'socket.io) (prefix "/socket.io"))
     `(let ((scanner (create-scanner (concatenate 'string "^" ,prefix "/1(/.*)?")))) ; v1
        (define-easy-handler (,name :uri #'(lambda (request)
                                             (scan scanner (script-name request)))) ()
          (handle-socket.io-request (path-info*) scanner ,message-handler))))
  +
  +(defun define-socket.io-event-handler (event handler)
  +  (setf (event-handler event) handler))
  +
  +(defmacro socket.io-on (event args &body body)
  +  `(define-socket.io-event-handler ,event
  +       #'(lambda ,args
  +           ,@body)))
  
positive.code: (defun handle-ack (id data data-ack-p)
    (cond ((and data-ack-p (not id))
           (log-message :warning "Data acknowledgement requested without id, ignoring"))
          (data-ack-p (send-ack id (encode-json-to-string data)))
          (id (send-ack id))))
  
  ; [message type] ':' [message id ('+')] ':' [message endpoint] (':' [message data])
  
negative.code:                (handle-ack id (funcall message-handler (decode-json-from-string data)) data-ack))
                (:event
                 (log-message :debug "Client sent event message ~s" data)
                 (let* ((data (decode-json-from-string data))
                        (event (cdr (assoc :name data :test #'eq)))
                        (args (cdr (assoc :args data :test #'eq))))
                   (handle-ack id (alexandria:if-let ((handler (event-handler event)))
                                    (apply handler args)
                                    nil)
                               data-ack)))
                (:ack
                 (destructuring-bind (id data)
                     (coerce (nth-value 1 (scan-to-strings message-splitter data)) 'list)
  