// Path: server/src/main/java/de/nixis/web/disco/dto/Base.java
// public class Base {
// 
// }
// 
// Path: server/src/main/java/de/nixis/web/disco/dto/ChannelLeave.java
// public class ChannelLeave extends Base {
// 
//   private String reason;
// 
//   public ChannelLeave() {
//   }
// 
//   public ChannelLeave(String reason) {
//     this.reason = reason;
//   }
// 
//   public String getReason() {
//     return reason;
//   }
// }
// 
// Path: server/src/main/java/de/nixis/web/disco/dto/ChannelOpen.java
// public class ChannelOpen extends Base {
// 
// }
// 
// Path: server/src/main/java/de/nixis/web/disco/dto/Participant.java
// public class Participant implements Comparable<Participant> {
// 
//   private ObjectId id;
// 
//   private String name;
// 
//   public Participant(String name) {
//     this.name = name;
// 
//     this.id = new ObjectId();
//   }
// 
//   public Participant() {
//   }
// 
//   public String getId() {
//     return id.toString();
//   }
// 
//   public String getName() {
//     return name;
//   }
// 
//   public void setName(String name) {
//     this.name = name;
//   }
// 
//   public int compareTo(Participant o) {
//     return o.id.compareTo(id);
//   }
// }
// 
// Path: server/src/main/java/de/nixis/web/disco/room/Room.java
// public interface Room {
// 
//   public String id();
// 
//   public Map<Channel, String> channelMap();
// 
//   public Set<Channel> channels();
// 
//   public <T> Attribute<T> attr(AttributeKey<T> key);
// 
//   Map<String, Participant> participantsMap();
// }
// 
// Path: server/src/main/java/de/nixis/web/disco/room/RoomHandler.java
// public interface RoomHandler<T> {
// 
//   public void handleMessage(RoomContext ctx, T message);
// 
// }
// 
// Path: server/src/main/java/de/nixis/web/disco/room/impl/RoomContextImpl.java
// public class RoomContextImpl implements RoomContext {
// 
//   private final Executor executor;
// 
//   private final Room room;
//   private final Channel channel;
// 
//   public RoomContextImpl(ChannelHandlerContext channelCtx, Room room) {
//     this(room, channelCtx.channel(), channelCtx.executor());
//   }
// 
//   public RoomContextImpl(Room room, Channel channel, Executor executor) {
//     this.room = room;
//     this.executor = executor;
//     this.channel = channel;
//   }
// 
//   public Executor executor() {
//     return executor;
//   }
// 
//   public Channel channel() {
//     return channel;
//   }
// 
//   public Set<Channel> channels() {
//     return room.channels();
//   }
// 
//   public Map<Channel, String> channelMap() {
//     return room.channelMap();
//   }
// 
//   public Room room() {
//     return room;
//   }
// 
//   public <T> Attribute<T> attr(AttributeKey<T> key) {
//     return room.attr(key);
//   }
// 
//   public RoomContext forChannel(Channel newChannel) {
//     return new RoomContextImpl(room, newChannel, executor);
//   }
// }
// 
// Path: server/src/main/java/de/nixis/web/disco/ws/RoomAwareWebSocketHandler.java
// public static enum ChannelEvent {
//   OPEN, CLOSE
// }


import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import de.nixis.web.disco.dto.Base;
import de.nixis.web.disco.dto.ChannelLeave;
import de.nixis.web.disco.dto.ChannelOpen;
import de.nixis.web.disco.dto.Participant;
import de.nixis.web.disco.room.Room;
import de.nixis.web.disco.room.RoomHandler;
import de.nixis.web.disco.room.impl.RoomContextImpl;
import de.nixis.web.disco.ws.RoomAwareWebSocketHandler.ChannelEvent;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import io.netty.util.AttributeMap;
import io.netty.util.DefaultAttributeMap;
            Unpooled.wrappedBuffer((cause.getMessage()).getBytes()));

        ctx.channel().write(response).addListener(ChannelFutureListener.CLOSE);
    }
  }

  ///////// helper stuff ////////////////////////////////////////

  protected interface Rooms {

    /**
     * Get room with the specified id
     *
     * @param key
     * @return
     */
    public Room get(Object key);

    /**
     * Returns all rooms a channel is associated with
     *
     * @param channel
     * @return
     */
    Set<Room> getByChannel(Channel channel);
  }

  private static class RoomsImpl extends ConcurrentSkipListMap<String, Room> implements Rooms {

    @Override
// Path: server/src/main/java/de/nixis/web/disco/dto/Base.java
// public class Base {
// 
// }
// 
// Path: server/src/main/java/de/nixis/web/disco/dto/ChannelLeave.java
// public class ChannelLeave extends Base {
// 
//   private String reason;
// 
//   public ChannelLeave() {
//   }
// 
//   public ChannelLeave(String reason) {
//     this.reason = reason;
//   }
// 
//   public String getReason() {
//     return reason;
//   }
// }
// 
// Path: server/src/main/java/de/nixis/web/disco/dto/ChannelOpen.java
// public class ChannelOpen extends Base {
// 
// }
// 
// Path: server/src/main/java/de/nixis/web/disco/dto/Participant.java
// public class Participant implements Comparable<Participant> {
// 
//   private ObjectId id;
// 
//   private String name;
// 
//   public Participant(String name) {
//     this.name = name;
// 
//     this.id = new ObjectId();
//   }
// 
//   public Participant() {
//   }
// 
//   public String getId() {
//     return id.toString();
//   }
// 
//   public String getName() {
//     return name;
//   }
// 
//   public void setName(String name) {
//     this.name = name;
//   }
// 
//   public int compareTo(Participant o) {
//     return o.id.compareTo(id);
//   }
// }
// 
// Path: server/src/main/java/de/nixis/web/disco/room/Room.java
// public interface Room {
// 
//   public String id();
// 
//   public Map<Channel, String> channelMap();
// 
//   public Set<Channel> channels();
// 
//   public <T> Attribute<T> attr(AttributeKey<T> key);
// 
//   Map<String, Participant> participantsMap();
// }
// 
// Path: server/src/main/java/de/nixis/web/disco/room/RoomHandler.java
// public interface RoomHandler<T> {
// 
//   public void handleMessage(RoomContext ctx, T message);
// 
// }
// 
// Path: server/src/main/java/de/nixis/web/disco/room/impl/RoomContextImpl.java
// public class RoomContextImpl implements RoomContext {
// 
//   private final Executor executor;
// 
//   private final Room room;
//   private final Channel channel;
// 
//   public RoomContextImpl(ChannelHandlerContext channelCtx, Room room) {
//     this(room, channelCtx.channel(), channelCtx.executor());
//   }
// 
//   public RoomContextImpl(Room room, Channel channel, Executor executor) {
//     this.room = room;
//     this.executor = executor;
//     this.channel = channel;
//   }
// 
//   public Executor executor() {
//     return executor;
//   }
// 
//   public Channel channel() {
//     return channel;
//   }
// 
//   public Set<Channel> channels() {
//     return room.channels();
//   }
// 
//   public Map<Channel, String> channelMap() {
//     return room.channelMap();
//   }
// 
//   public Room room() {
//     return room;
//   }
// 
//   public <T> Attribute<T> attr(AttributeKey<T> key) {
//     return room.attr(key);
//   }
// 
//   public RoomContext forChannel(Channel newChannel) {
//     return new RoomContextImpl(room, newChannel, executor);
//   }
// }
// 
// Path: server/src/main/java/de/nixis/web/disco/ws/RoomAwareWebSocketHandler.java
// public static enum ChannelEvent {
//   OPEN, CLOSE
// }


// Path: server/src/main/java/de/nixis/web/disco/ws/RoomAwareHandler.java
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import de.nixis.web.disco.dto.Base;
import de.nixis.web.disco.dto.ChannelLeave;
import de.nixis.web.disco.dto.ChannelOpen;
import de.nixis.web.disco.dto.Participant;
import de.nixis.web.disco.room.Room;
import de.nixis.web.disco.room.RoomHandler;
import de.nixis.web.disco.room.impl.RoomContextImpl;
import de.nixis.web.disco.ws.RoomAwareWebSocketHandler.ChannelEvent;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import io.netty.util.AttributeMap;
import io.netty.util.DefaultAttributeMap;

            Unpooled.wrappedBuffer((cause.getMessage()).getBytes()));

        ctx.channel().write(response).addListener(ChannelFutureListener.CLOSE);
    }
  }

  ///////// helper stuff ////////////////////////////////////////

  protected interface Rooms {

    /**
     * Get room with the specified id
     *
     * @param key
     * @return
     */
    public Room get(Object key);

    /**
     * Returns all rooms a channel is associated with
     *
     * @param channel
     * @return
     */
    Set<Room> getByChannel(Channel channel);
  }

  private static class RoomsImpl extends ConcurrentSkipListMap<String, Room> implements Rooms {

    @Override
    public Room get(Object key) {