new chat authentication patern

This PR solves https://github.com/evantahler/actionHero/issues/266

By popular request, we are changing the chat sub-system to provide more fine-grain control over access to chat rooms to  API developers. 

## Philosophical Changes

- chat rooms now must be created before anyone can join them
  - `api.chatRoom.add` can be used for this, or you can append the array `api.configData.general.startingChatRooms`
  - you can remove chatRooms with `api.chatRoom.del`
- the authentication pattern for chat rooms is now about access rather than per message.  All members in all rooms will see all messages
  - access is still defined by looking at attributes of a connection, but only when the connection first joins a room.  This means that if a connection's attributes change, it will not be kicked out of the room
  - `api.chatRoom.setAuthenticationPatern` is used to define a room's access rules.  2 examples:
   - `api.chatRoom.setAuthenticationPatern('myRoom', 'type', 'websocket')` would only allow websocket clients in
   - `api.chatRoom.setAuthenticationPatern('myRoom', 'auteneticated', true)` would only allow  clients in which have previously been modified by `connection.auteneticated = true; connection._original_connection.authenticated = true;` probably in an action or middleware.

- connections start without being in any chat room at all and need to explicitly join a room
- connections can leave the room they are in with the new verb `roomLeave` (socket and websocket)
- connections may still `listenToRoom` and `silenceRoom` as they had before, but listening to a room will follow the same authentication logic as joining a room (listen can now return an error)

## API Changes

### `api.chatRoom.add(room, callback)`
  - callback will return 1 if you created the room, 0 if it already existed

### `api.chatRoom.del(room, callback)`
 - callback is empty

### `api.chatRoom.exists(room, callback)`
- callback returns (error, found); found is a boolean

### `api.chatRoom.setAuthenticationPatern(room, key, value, callback)`
- callback returns (error)

### `api.chatRoom.roomStatus(room, callback)`
- callback return (error, data)
- data is of the form:

```javascript
{
  room: "myRoom",
  membersCount: 2,
  members: {
    aaa: {id: "aaa", joinedAt: 123456789 },
    bbb: {id: "bbb", joinedAt: 123456789 },
  }
}
```

### `api.chatRoom.addMember(connection, room, callback)`
- callback is of the form (error, wasAdded)

### `api.chatRoom.removeMember(connection, callback)`
- callback is of the form (error, wasRemoved)