anchor.diff:                      | None ->
                           let userName = packet.Data.[1].ToObject<string>()
                           Interlocked.Increment(&userCount) |> ignore
  +                        logVerbose (sprintf "[%A] JOIN" userName)
                           socket.Broadcast (chatPacket "user joined" { UserJoinedEvent.username = userName; numUsers = userCount })
                           socket.Send (chatPacket "login" { UserJoinedEvent.username = userName; numUsers = userCount })
                           { state with userName = Some userName }
  
positive.code:         let! p = socket.Receive()
          match p with
          | Some packet ->
              log.info (eventX (sprintf "< %A" packet))
              match packet.EventId with
              | Some id -> socket.Send({ Packet.ofType Ack with EventId = Some id })
              | None -> ()
  
negative.code:                     logVerbose (sprintf "Unknown command: %s" cmd)
                      state
  
              return! handlePacket newState socket
          | None ->
              let userName = defaultArg state.userName "???"
              logVerbose (sprintf "[%A] LEAVE" userName)
              match state.userName with
              | Some userName ->
                  Interlocked.Decrement(&userCount) |> ignore
                  socket.Broadcast (chatPacket "user left" { UserJoinedEvent.username = userName; numUsers = userCount })
              | None -> ()
              return ()
      }
  
      let app =
          choose [
              socketio (handlePacket State.empty)
              GET >=> choose [
                  browseHome
              
  