升级Tomcat版本 apache-tomcat-7.0.77
diff --git a/tomcat-cas/webapps/examples/websocket/chat.xhtml b/tomcat-cas/webapps/examples/websocket/chat.xhtml
new file mode 100644
index 0000000..5e31dab
--- /dev/null
+++ b/tomcat-cas/webapps/examples/websocket/chat.xhtml
@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+    <title>Apache Tomcat WebSocket Examples: Chat</title>
+    <style type="text/css"><![CDATA[
+        input#chat {
+            width: 410px
+        }
+
+        #console-container {
+            width: 400px;
+        }
+
+        #console {
+            border: 1px solid #CCCCCC;
+            border-right-color: #999999;
+            border-bottom-color: #999999;
+            height: 170px;
+            overflow-y: scroll;
+            padding: 5px;
+            width: 100%;
+        }
+
+        #console p {
+            padding: 0;
+            margin: 0;
+        }
+    ]]></style>
+    <script type="application/javascript"><![CDATA[
+        var Chat = {};
+
+        Chat.socket = null;
+
+        Chat.connect = (function(host) {
+            if ('WebSocket' in window) {
+                Chat.socket = new WebSocket(host);
+            } else if ('MozWebSocket' in window) {
+                Chat.socket = new MozWebSocket(host);
+            } else {
+                Console.log('Error: WebSocket is not supported by this browser.');
+                return;
+            }
+
+            Chat.socket.onopen = function () {
+                Console.log('Info: WebSocket connection opened.');
+                document.getElementById('chat').onkeydown = function(event) {
+                    if (event.keyCode == 13) {
+                        Chat.sendMessage();
+                    }
+                };
+            };
+
+            Chat.socket.onclose = function () {
+                document.getElementById('chat').onkeydown = null;
+                Console.log('Info: WebSocket closed.');
+            };
+
+            Chat.socket.onmessage = function (message) {
+                Console.log(message.data);
+            };
+        });
+
+        Chat.initialize = function() {
+            if (window.location.protocol == 'http:') {
+                Chat.connect('ws://' + window.location.host + '/examples/websocket/chat');
+            } else {
+                Chat.connect('wss://' + window.location.host + '/examples/websocket/chat');
+            }
+        };
+
+        Chat.sendMessage = (function() {
+            var message = document.getElementById('chat').value;
+            if (message != '') {
+                Chat.socket.send(message);
+                document.getElementById('chat').value = '';
+            }
+        });
+
+        var Console = {};
+
+        Console.log = (function(message) {
+            var console = document.getElementById('console');
+            var p = document.createElement('p');
+            p.style.wordWrap = 'break-word';
+            p.innerHTML = message;
+            console.appendChild(p);
+            while (console.childNodes.length > 25) {
+                console.removeChild(console.firstChild);
+            }
+            console.scrollTop = console.scrollHeight;
+        });
+
+        Chat.initialize();
+
+
+        document.addEventListener("DOMContentLoaded", function() {
+            // Remove elements with "noscript" class - <noscript> is not allowed in XHTML
+            var noscripts = document.getElementsByClassName("noscript");
+            for (var i = 0; i < noscripts.length; i++) {
+                noscripts[i].parentNode.removeChild(noscripts[i]);
+            }
+        }, false);
+
+    ]]></script>
+</head>
+<body>
+<div class="noscript"><h2 style="color: #ff0000">Seems your browser doesn't support Javascript! Websockets rely on Javascript being enabled. Please enable
+    Javascript and reload this page!</h2></div>
+<div>
+    <p>
+        <input type="text" placeholder="type and press enter to chat" id="chat" />
+    </p>
+    <div id="console-container">
+        <div id="console"/>
+    </div>
+</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/tomcat-cas/webapps/examples/websocket/drawboard.xhtml b/tomcat-cas/webapps/examples/websocket/drawboard.xhtml
new file mode 100644
index 0000000..342bef4
--- /dev/null
+++ b/tomcat-cas/webapps/examples/websocket/drawboard.xhtml
@@ -0,0 +1,897 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+    <title>Apache Tomcat WebSocket Examples: Drawboard</title>
+    <style type="text/css"><![CDATA[
+
+        body {
+            font-family: Arial, sans-serif;
+            font-size: 11pt;
+            background-color: #eeeeea;
+            padding: 10px;
+        }
+
+        #console-container {
+            float: left;
+            background-color: #fff;
+            width: 250px;
+        }
+
+        #console {
+            font-size: 10pt;
+            height: 600px;
+            overflow-y: scroll;
+            padding-left: 5px;
+            padding-right: 5px;
+        }
+
+        #console p {
+            padding: 0;
+            margin: 0;
+        }
+
+        #drawContainer {
+            float: left;
+            display: none;
+            margin-right: 25px;
+        }
+
+        #drawContainer canvas {
+            display: block;
+            -ms-touch-action: none;
+            touch-action: none; /* Disable touch behaviors, like pan and zoom */
+            cursor: crosshair;
+        }
+
+        #labelContainer {
+            margin-bottom: 15px;
+        }
+
+        #drawContainer, #console-container {
+            box-shadow: 0px 0px 8px 3px #bbb;
+            border: 1px solid #CCCCCC;
+        }
+
+    ]]></style>
+    <script type="application/javascript"><![CDATA[
+    "use strict";
+
+    (function() {
+
+        document.addEventListener("DOMContentLoaded", function() {
+            // Remove elements with "noscript" class - <noscript> is not
+            // allowed in XHTML
+            var noscripts = document.getElementsByClassName("noscript");
+            for (var i = 0; i < noscripts.length; i++) {
+                noscripts[i].parentNode.removeChild(noscripts[i]);
+            }
+
+            // Add script for expand content.
+            var expandElements = document.getElementsByClassName("expand");
+            for (var ixx = 0; ixx < expandElements.length; ixx++) {
+                (function(el) {
+                    var expandContent = document.getElementById(el.getAttribute("data-content-id"));
+                    expandContent.style.display = "none";
+                    var arrow = document.createTextNode("◢ ");
+                    var arrowSpan = document.createElement("span");
+                    arrowSpan.appendChild(arrow);
+
+                    var link = document.createElement("a");
+                    link.setAttribute("href", "#!");
+                    while (el.firstChild != null) {
+                        link.appendChild(el.removeChild(el.firstChild));
+                    }
+                    el.appendChild(arrowSpan);
+                    el.appendChild(link);
+
+                    var textSpan = document.createElement("span");
+                    textSpan.setAttribute("style", "font-weight: normal;");
+                    textSpan.appendChild(document.createTextNode(" (click to expand)"));
+                    el.appendChild(textSpan);
+
+
+                    var visible = true;
+
+                    var switchExpand = function() {
+                        visible = !visible;
+                        expandContent.style.display = visible ? "block" : "none";
+                        arrowSpan.style.color = visible ? "#000" : "#888";
+                        return false;
+                    };
+
+                    link.onclick = switchExpand;
+                    switchExpand();
+
+                })(expandElements[ixx]);
+            }
+
+
+            var Console = {};
+
+            Console.log = (function() {
+                var consoleContainer =
+                    document.getElementById("console-container");
+                var console = document.createElement("div");
+                console.setAttribute("id", "console");
+                consoleContainer.appendChild(console);
+
+                return function(message) {
+                    var p = document.createElement('p');
+                    p.style.wordWrap = "break-word";
+                    p.appendChild(document.createTextNode(message));
+                    console.appendChild(p);
+                    while (console.childNodes.length > 25) {
+                        console.removeChild(console.firstChild);
+                    }
+                    console.scrollTop = console.scrollHeight;
+                }
+            })();
+
+
+            function Room(drawContainer) {
+
+                /* A pausable event forwarder that can be used to pause and
+                 * resume handling of events (e.g. when we need to wait
+                 * for a Image's load event before we can process further
+                 * WebSocket messages).
+                 * The object's callFunction(func) should be called from an
+                 * event handler and give the function to handle the event as
+                 * argument.
+                 * Call pauseProcessing() to suspend event forwarding and
+                 * resumeProcessing() to resume it.
+                 */
+                function PausableEventForwarder() {
+
+                    var pauseProcessing = false;
+                    // Queue for buffering functions to be called.
+                    var functionQueue = [];
+
+                    this.callFunction = function(func) {
+                        // If message processing is paused, we push it
+                        // into the queue - otherwise we process it directly.
+                        if (pauseProcessing) {
+                            functionQueue.push(func);
+                        } else {
+                            func();
+                        }
+                    };
+
+                    this.pauseProcessing = function() {
+                        pauseProcessing = true;
+                    };
+
+                    this.resumeProcessing = function() {
+                        pauseProcessing = false;
+
+                        // Process all queued functions until some handler calls
+                        // pauseProcessing() again.
+                        while (functionQueue.length > 0 && !pauseProcessing) {
+                            var func = functionQueue.pop();
+                            func();
+                        }
+                    };
+                }
+
+                // The WebSocket object.
+                var socket;
+                // ID of the timer which sends ping messages.
+                var pingTimerId;
+
+                var isStarted = false;
+                var playerCount = 0;
+
+                // An array of PathIdContainer objects that the server
+                // did not yet handle.
+                // They are ordered by id (ascending).
+                var pathsNotHandled = [];
+
+                var nextMsgId = 1;
+
+                var canvasDisplay = document.createElement("canvas");
+                var canvasBackground = document.createElement("canvas");
+                var canvasServerImage = document.createElement("canvas");
+                var canvasArray = [canvasDisplay, canvasBackground,
+                    canvasServerImage];
+                canvasDisplay.addEventListener("mousedown", function(e) {
+                    // Prevent default mouse event to prevent browsers from marking text
+                    // (and Chrome from displaying the "text" cursor).
+                    e.preventDefault();
+                }, false);
+
+                var labelPlayerCount = document.createTextNode("0");
+                var optionContainer = document.createElement("div");
+
+
+                var canvasDisplayCtx = canvasDisplay.getContext("2d");
+                var canvasBackgroundCtx = canvasBackground.getContext("2d");
+                var canvasServerImageCtx = canvasServerImage.getContext("2d");
+                var canvasMouseMoveHandler;
+                var canvasMouseDownHandler;
+
+                var isActive = false;
+                var mouseInWindow = false;
+                var mouseDown = false;
+                var currentMouseX = 0, currentMouseY = 0;
+                var currentPreviewPath = null;
+
+                var availableColors = [];
+                var currentColorIndex;
+                var colorContainers;
+                var previewTransparency = 0.65;
+
+                var availableThicknesses = [2, 3, 6, 10, 16, 28, 50];
+                var currentThicknessIndex;
+                var thicknessContainers;
+
+                var availableDrawTypes = [
+                           { name: "Brush", id: 1, continuous: true },
+                           { name: "Line", id: 2, continuous: false },
+                           { name: "Rectangle", id: 3, continuous: false },
+                           { name: "Ellipse", id: 4, continuous: false }
+                ];
+                var currentDrawTypeIndex;
+                var drawTypeContainers;
+
+
+                var labelContainer = document.getElementById("labelContainer");
+                var placeholder = document.createElement("div");
+                placeholder.appendChild(document.createTextNode("Loading... "));
+                var progressElem = document.createElement("progress");
+                placeholder.appendChild(progressElem);
+
+                labelContainer.appendChild(placeholder);
+
+                function rgb(color) {
+                       return "rgba(" + color[0] + "," + color[1] + ","
+                               + color[2] + "," + color[3] + ")";
+                   }
+
+                function PathIdContainer(path, id) {
+                    this.path = path;
+                    this.id = id;
+                }
+
+                function Path(type, color, thickness, x1, y1, x2, y2, lastInChain) {
+                    this.type = type;
+                    this.color = color;
+                    this.thickness = thickness;
+                    this.x1 = x1;
+                    this.y1 = y1;
+                    this.x2 = x2;
+                    this.y2 = y2;
+                    this.lastInChain = lastInChain;
+
+                    function ellipse(ctx, x, y, w, h) {
+                        /* Drawing a ellipse cannot be done directly in a
+                         * CanvasRenderingContext2D - we need to use drawArc()
+                         * in conjunction with scaling the context so that we
+                         * get the needed proportion.
+                         */
+                        ctx.save();
+
+                        // Translate and scale the context so that we can draw
+                        // an arc at (0, 0) with a radius of 1.
+                        ctx.translate(x + w / 2, y + h / 2);
+                        ctx.scale(w / 2, h / 2);
+
+                        ctx.beginPath();
+                        ctx.arc(0, 0, 1, 0, Math.PI * 2, false);
+
+                        ctx.restore();
+                    }
+
+                    this.draw = function(ctx) {
+                        ctx.beginPath();
+                        ctx.lineCap = "round";
+                        ctx.lineWidth = thickness;
+                        var style = rgb(color);
+                        ctx.strokeStyle = style;
+
+                        if (x1 == x2 && y1 == y2) {
+                            // Always draw as arc to meet the behavior
+                            // in Java2D.
+                            ctx.fillStyle = style;
+                            ctx.arc(x1, y1, thickness / 2.0, 0,
+                                    Math.PI * 2.0, false);
+                            ctx.fill();
+                        } else {
+                            if (type == 1 || type == 2) {
+                                // Draw a line.
+                                ctx.moveTo(x1, y1);
+                                ctx.lineTo(x2, y2);
+                                ctx.stroke();
+                            } else if (type == 3) {
+                                // Draw a rectangle.
+                                if (x1 == x2 || y1 == y2) {
+                                    // Draw as line
+                                    ctx.moveTo(x1, y1);
+                                    ctx.lineTo(x2, y2);
+                                    ctx.stroke();
+                                } else {
+                                    ctx.strokeRect(x1, y1, x2 - x1, y2 - y1);
+                                }
+                            } else if (type == 4) {
+                                // Draw a ellipse.
+                                ellipse(ctx, x1, y1, x2 - x1, y2 - y1);
+                                ctx.closePath();
+                                ctx.stroke();
+                            }
+                        }
+                    };
+                }
+
+
+                function connect() {
+                    var host = (window.location.protocol == "https:"
+                            ? "wss://" : "ws://") + window.location.host
+                            + "/examples/websocket/drawboard";
+                    socket = new WebSocket(host);
+
+                    /* Use a pausable event forwarder.
+                     * This is needed when we load an Image object with data
+                     * from a previous message, because we must wait until the
+                     * Image's load event it raised before we can use it (and
+                     * in the meantime the socket.message event could be
+                     * raised).
+                     * Therefore we need this pausable event handler to handle
+                     * e.g. socket.onmessage and socket.onclose.
+                     */
+                    var eventForwarder = new PausableEventForwarder();
+
+                    socket.onopen = function () {
+                        // Socket has opened. Now wait for the server to
+                        // send us the initial packet.
+                        Console.log("WebSocket connection opened.");
+
+                        // Set up a timer for pong messages.
+                        pingTimerId = window.setInterval(function() {
+                            socket.send("0");
+                        }, 30000);
+                    };
+
+                    socket.onclose = function () {
+                        eventForwarder.callFunction(function() {
+                            Console.log("WebSocket connection closed.");
+                            disableControls();
+
+                            // Disable pong timer.
+                            window.clearInterval(pingTimerId);
+                        });
+                    };
+
+                    // Handles an incoming Websocket message.
+                    var handleOnMessage = function(message) {
+
+                        // Split joined message and process them
+                        // individually.
+                        var messages = message.data.split(";");
+                        for (var msgArrIdx = 0; msgArrIdx < messages.length;
+                                msgArrIdx++) {
+                            var msg = messages[msgArrIdx];
+                            var type = msg.substring(0, 1);
+
+                            if (type == "0") {
+                                // Error message.
+                                var error = msg.substring(1);
+                                // Log it to the console and show an alert.
+                                Console.log("Error: " + error);
+                                alert(error);
+
+                            } else {
+                                if (!isStarted) {
+                                    if (type == "2") {
+                                        // Initial message. It contains the
+                                        // number of players.
+                                        // After this message we will receive
+                                        // a binary message containing the current
+                                        // room image as PNG.
+                                        playerCount = parseInt(msg.substring(1));
+
+                                        refreshPlayerCount();
+
+                                        // The next message will be a binary
+                                        // message containing the room images
+                                        // as PNG. Therefore we temporarily swap
+                                        // the message handler.
+                                        var originalHandler = handleOnMessage;
+                                        handleOnMessage = function(message) {
+                                            // First, we restore the original handler.
+                                            handleOnMessage = originalHandler;
+
+                                            // Read the image.
+                                            var blob = message.data;
+                                            // Create new blob with correct MIME type.
+                                            blob = new Blob([blob], {type : "image/png"});
+
+                                            var url = URL.createObjectURL(blob);
+
+                                            var img = new Image();
+
+                                            // We must wait until the onload event is
+                                            // raised until we can draw the image onto
+                                            // the canvas.
+                                            // Therefore we need to pause the event
+                                            // forwarder until the image is loaded.
+                                            eventForwarder.pauseProcessing();
+
+                                            img.onload = function() {
+
+                                                // Release the object URL.
+                                                URL.revokeObjectURL(url);
+
+                                                // Set the canvases to the correct size.
+                                                for (var i = 0; i < canvasArray.length; i++) {
+                                                    canvasArray[i].width = img.width;
+                                                    canvasArray[i].height = img.height;
+                                                }
+
+                                                // Now draw the image on the last canvas.
+                                                canvasServerImageCtx.clearRect(0, 0,
+                                                        canvasServerImage.width,
+                                                        canvasServerImage.height);
+                                                canvasServerImageCtx.drawImage(img, 0, 0);
+
+                                                // Draw it on the background canvas.
+                                                canvasBackgroundCtx.drawImage(canvasServerImage,
+                                                        0, 0);
+
+                                                isStarted = true;
+                                                startControls();
+
+                                                // Refresh the display canvas.
+                                                refreshDisplayCanvas();
+
+
+                                                // Finally, resume the event forwarder.
+                                                eventForwarder.resumeProcessing();
+                                            };
+
+                                            img.src = url;
+                                        };
+                                    }
+                                } else {
+                                    if (type == "3") {
+                                        // The number of players in this room changed.
+                                        var playerAdded = msg.substring(1) == "+";
+                                        playerCount += playerAdded ? 1 : -1;
+                                        refreshPlayerCount();
+
+                                        Console.log("Player " + (playerAdded
+                                                ? "joined." : "left."));
+
+                                    } else if (type == "1") {
+                                        // We received a new DrawMessage.
+                                        var maxLastHandledId = -1;
+                                        var drawMessages = msg.substring(1).split("|");
+                                        for (var i = 0; i < drawMessages.length; i++) {
+                                            var elements = drawMessages[i].split(",");
+                                            var lastHandledId = parseInt(elements[0]);
+                                               maxLastHandledId = Math.max(maxLastHandledId,
+                                                       lastHandledId);
+
+                                            var path = new Path(
+                                                    parseInt(elements[1]),
+                                                    [parseInt(elements[2]),
+                                                    parseInt(elements[3]),
+                                                    parseInt(elements[4]),
+                                                    parseInt(elements[5]) / 255.0],
+                                                    parseFloat(elements[6]),
+                                                    parseFloat(elements[7]),
+                                                    parseFloat(elements[8]),
+                                                    parseFloat(elements[9]),
+                                                    parseFloat(elements[10]),
+                                                    elements[11] != "0");
+
+                                            // Draw the path onto the last canvas.
+                                            path.draw(canvasServerImageCtx);
+                                        }
+
+                                        // Draw the last canvas onto the background one.
+                                        canvasBackgroundCtx.drawImage(canvasServerImage,
+                                                0, 0);
+
+                                        // Now go through the pathsNotHandled array and
+                                        // remove the paths that were already handled by
+                                        // the server.
+                                        while (pathsNotHandled.length > 0
+                                                && pathsNotHandled[0].id <= maxLastHandledId)
+                                            pathsNotHandled.shift();
+
+                                        // Now me must draw the remaining paths onto
+                                        // the background canvas.
+                                        for (var i = 0; i < pathsNotHandled.length; i++) {
+                                            pathsNotHandled[i].path.draw(canvasBackgroundCtx);
+                                        }
+
+                                        refreshDisplayCanvas();
+                                    }
+                                }
+                            }
+                        }
+                    };
+
+                    socket.onmessage = function(message) {
+                        eventForwarder.callFunction(function() {
+                            handleOnMessage(message);
+                        });
+                    };
+
+                }
+
+
+                function refreshPlayerCount() {
+                    labelPlayerCount.nodeValue = String(playerCount);
+                }
+
+                function refreshDisplayCanvas() {
+                    if (!isActive) { // Don't draw a curser when not active.
+                        return;
+                    }
+
+                    canvasDisplayCtx.drawImage(canvasBackground, 0, 0);
+                    if (currentPreviewPath != null) {
+                        // Draw the preview path.
+                        currentPreviewPath.draw(canvasDisplayCtx);
+
+                    } else if (mouseInWindow && !mouseDown) {
+                        canvasDisplayCtx.beginPath();
+                        var color = availableColors[currentColorIndex].slice(0);
+                        color[3] = previewTransparency;
+                        canvasDisplayCtx.fillStyle = rgb(color);
+
+                        canvasDisplayCtx.arc(currentMouseX, currentMouseY,
+                                availableThicknesses[currentThicknessIndex] / 2,
+                                0, Math.PI * 2.0, true);
+                        canvasDisplayCtx.fill();
+                    }
+
+                }
+
+                function startControls() {
+                    isActive = true;
+
+                    labelContainer.removeChild(placeholder);
+                    placeholder = undefined;
+
+                    labelContainer.appendChild(
+                            document.createTextNode("Number of Players: "));
+                    labelContainer.appendChild(labelPlayerCount);
+
+
+                    drawContainer.style.display = "block";
+                    drawContainer.appendChild(canvasDisplay);
+
+                    drawContainer.appendChild(optionContainer);
+                    
+                    canvasMouseDownHandler = function(e) {
+                        if (e.button == 0) {
+                            currentMouseX = e.pageX - canvasDisplay.offsetLeft;
+                            currentMouseY = e.pageY - canvasDisplay.offsetTop;
+
+                            mouseDown = true;
+                            canvasMouseMoveHandler(e);
+
+                        } else if (mouseDown) {
+                            // Cancel drawing.
+                            mouseDown = false;
+                            currentPreviewPath = null;
+
+                            currentMouseX = e.pageX - canvasDisplay.offsetLeft;
+                            currentMouseY = e.pageY - canvasDisplay.offsetTop;
+
+                            refreshDisplayCanvas();
+                        }
+                    };
+                    canvasDisplay.addEventListener("mousedown", canvasMouseDownHandler, false);
+
+                    canvasMouseMoveHandler = function(e) {
+                        var mouseX = e.pageX - canvasDisplay.offsetLeft;
+                        var mouseY = e.pageY - canvasDisplay.offsetTop;
+
+                        if (mouseDown) {
+                            var drawType = availableDrawTypes[currentDrawTypeIndex];
+
+                            if (drawType.continuous) {
+
+                                var path = new Path(drawType.id,
+                                        availableColors[currentColorIndex],
+                                        availableThicknesses[currentThicknessIndex],
+                                        currentMouseX, currentMouseY, mouseX,
+                                        mouseY, false);
+                                // Draw it on the background canvas.
+                                path.draw(canvasBackgroundCtx);
+
+                                // Send it to the sever.
+                                pushPath(path);
+
+                                // Refresh old coordinates
+                                currentMouseX = mouseX;
+                                currentMouseY = mouseY;
+
+                            } else {
+                                // Create a new preview path.
+                                var color = availableColors[currentColorIndex].slice(0);
+                                color[3] = previewTransparency;
+                                currentPreviewPath = new Path(drawType.id,
+                                        color,
+                                        availableThicknesses[currentThicknessIndex],
+                                        currentMouseX, currentMouseY, mouseX,
+                                        mouseY, false);
+                            }
+
+                            refreshDisplayCanvas();
+                        } else {
+                            currentMouseX = mouseX;
+                            currentMouseY = mouseY;
+
+                            if (mouseInWindow) {
+                                refreshDisplayCanvas();
+                            }
+                        }
+
+                    };
+                    document.addEventListener("mousemove", canvasMouseMoveHandler, false);
+
+                    document.addEventListener("mouseup", function(e) {
+                        if (e.button == 0) {
+                            if (mouseDown) {
+                                mouseDown = false;
+                                currentPreviewPath = null;
+
+                                var mouseX = e.pageX - canvasDisplay.offsetLeft;
+                                var mouseY = e.pageY - canvasDisplay.offsetTop;
+                                var drawType = availableDrawTypes[currentDrawTypeIndex];
+
+                                var path = new Path(drawType.id, availableColors[currentColorIndex],
+                                        availableThicknesses[currentThicknessIndex],
+                                        currentMouseX, currentMouseY, mouseX,
+                                        mouseY, true);
+                                // Draw it on the background canvas.
+                                path.draw(canvasBackgroundCtx);
+
+                                // Send it to the sever.
+                                pushPath(path);
+
+                                // Refresh old coordinates
+                                currentMouseX = mouseX;
+                                currentMouseY = mouseY;
+
+                                refreshDisplayCanvas();
+                            }
+                        }
+                    }, false);
+
+                    canvasDisplay.addEventListener("mouseout", function(e) {
+                        mouseInWindow = false;
+                        refreshDisplayCanvas();
+                    }, false);
+
+                    canvasDisplay.addEventListener("mousemove", function(e) {
+                        if (!mouseInWindow) {
+                            mouseInWindow = true;
+                            refreshDisplayCanvas();
+                        }
+                    }, false);
+
+
+                    // Create color and thickness controls.
+                    var colorContainersBox = document.createElement("div");
+                    colorContainersBox.setAttribute("style",
+                            "margin: 4px; border: 1px solid #bbb; border-radius: 3px;");
+                    optionContainer.appendChild(colorContainersBox);
+
+                    colorContainers = new Array(3 * 3 * 3);
+                    for (var i = 0; i < colorContainers.length; i++) {
+                        var colorContainer = colorContainers[i] =
+                            document.createElement("div");
+                        var color = availableColors[i] =
+                            [
+                                Math.floor((i % 3) * 255 / 2),
+                                Math.floor((Math.floor(i / 3) % 3) * 255 / 2),
+                                Math.floor((Math.floor(i / (3 * 3)) % 3) * 255 / 2),
+                                1.0
+                            ];
+                        colorContainer.setAttribute("style",
+                                "margin: 3px; width: 18px; height: 18px; "
+                                + "float: left; background-color: " + rgb(color));
+                        colorContainer.style.border = '2px solid #000';
+                        colorContainer.addEventListener("mousedown", (function(ix) {
+                            return function() {
+                                setColor(ix);
+                            };
+                        })(i), false);
+
+                        colorContainersBox.appendChild(colorContainer);
+                    }
+
+                    var divClearLeft = document.createElement("div");
+                    divClearLeft.setAttribute("style", "clear: left;");
+                    colorContainersBox.appendChild(divClearLeft);
+
+
+                    var drawTypeContainersBox = document.createElement("div");
+                    drawTypeContainersBox.setAttribute("style",
+                           "float: right; margin-right: 3px; margin-top: 1px;");
+                    optionContainer.appendChild(drawTypeContainersBox);
+
+                    drawTypeContainers = new Array(availableDrawTypes.length);
+                    for (var i = 0; i < drawTypeContainers.length; i++) {
+                        var drawTypeContainer = drawTypeContainers[i] =
+                            document.createElement("div");
+                        drawTypeContainer.setAttribute("style",
+                                "text-align: center; margin: 3px; padding: 0 3px;"
+                                + "height: 18px; float: left;");
+                        drawTypeContainer.style.border = "2px solid #000";
+                        drawTypeContainer.appendChild(document.createTextNode(
+                                String(availableDrawTypes[i].name)));
+                        drawTypeContainer.addEventListener("mousedown", (function(ix) {
+                            return function() {
+                                setDrawType(ix);
+                            };
+                        })(i), false);
+
+                        drawTypeContainersBox.appendChild(drawTypeContainer);
+                    }
+
+
+                    var thicknessContainersBox = document.createElement("div");
+                    thicknessContainersBox.setAttribute("style",
+                            "margin: 3px; border: 1px solid #bbb; border-radius: 3px;");
+                    optionContainer.appendChild(thicknessContainersBox);
+
+                    thicknessContainers = new Array(availableThicknesses.length);
+                    for (var i = 0; i < thicknessContainers.length; i++) {
+                        var thicknessContainer = thicknessContainers[i] =
+                            document.createElement("div");
+                        thicknessContainer.setAttribute("style",
+                                "text-align: center; margin: 3px; width: 18px; "
+                                + "height: 18px; float: left;");
+                        thicknessContainer.style.border = "2px solid #000";
+                        thicknessContainer.appendChild(document.createTextNode(
+                                String(availableThicknesses[i])));
+                        thicknessContainer.addEventListener("mousedown", (function(ix) {
+                            return function() {
+                                setThickness(ix);
+                            };
+                        })(i), false);
+
+                        thicknessContainersBox.appendChild(thicknessContainer);
+                    }
+
+
+                    divClearLeft = document.createElement("div");
+                    divClearLeft.setAttribute("style", "clear: left;");
+                    thicknessContainersBox.appendChild(divClearLeft);
+
+
+                    setColor(0);
+                    setThickness(0);
+                    setDrawType(0);
+
+                }
+
+                function disableControls() {
+                    document.removeEventListener("mousedown", canvasMouseDownHandler);
+                    document.removeEventListener("mousemove", canvasMouseMoveHandler);
+                    mouseInWindow = false;
+                    refreshDisplayCanvas();
+
+                    isActive = false;
+                }
+
+                function pushPath(path) {
+
+                    // Push it into the pathsNotHandled array.
+                    var container = new PathIdContainer(path, nextMsgId++);
+                    pathsNotHandled.push(container);
+
+                    // Send the path to the server.
+                    var message = container.id + "|" + path.type + ","
+                            + path.color[0] + "," + path.color[1] + ","
+                            + path.color[2] + ","
+                            + Math.round(path.color[3] * 255.0) + ","
+                            + path.thickness + "," + path.x1 + ","
+                            + path.y1 + "," + path.x2 + "," + path.y2 + ","
+                            + (path.lastInChain ? "1" : "0");
+
+                    socket.send("1" + message);
+                }
+
+                function setThickness(thicknessIndex) {
+                    if (typeof currentThicknessIndex !== "undefined")
+                        thicknessContainers[currentThicknessIndex]
+                            .style.borderColor = "#000";
+                    currentThicknessIndex = thicknessIndex;
+                    thicknessContainers[currentThicknessIndex]
+                        .style.borderColor = "#d08";
+                }
+
+                function setColor(colorIndex) {
+                    if (typeof currentColorIndex !== "undefined")
+                        colorContainers[currentColorIndex]
+                            .style.borderColor = "#000";
+                    currentColorIndex = colorIndex;
+                    colorContainers[currentColorIndex]
+                        .style.borderColor = "#d08";
+                }
+
+                function setDrawType(drawTypeIndex) {
+                    if (typeof currentDrawTypeIndex !== "undefined")
+                        drawTypeContainers[currentDrawTypeIndex]
+                            .style.borderColor = "#000";
+                    currentDrawTypeIndex = drawTypeIndex;
+                    drawTypeContainers[currentDrawTypeIndex]
+                        .style.borderColor = "#d08";
+                }
+
+
+                connect();
+
+            }
+
+
+            // Initialize the room
+            var room = new Room(document.getElementById("drawContainer"));
+
+
+        }, false);
+
+    })();
+    ]]></script>
+</head>
+<body>
+    <div class="noscript"><div style="color: #ff0000; font-size: 16pt;">Seems your browser doesn't support Javascript! Websockets rely on Javascript being enabled. Please enable
+    Javascript and reload this page!</div></div>
+    <div id="labelContainer"/>
+    <div id="drawContainer"/>
+    <div id="console-container"/>
+    <div style="clear: left;"/>
+
+    <h1 class="expand" data-content-id="expandContent" style="font-size: 1.3em;"
+        >About Drawboard WebSocket Example</h1>
+    <div id="expandContent">
+        <p>
+            This drawboard is a page where you can draw with your mouse or touch input
+            (using different colors) and everybody else which has the page open will
+            <em>immediately</em> see what you are drawing.<br/>
+            If someone opens the page later, they will get the current room image (so they
+            can see what was already drawn by other people).
+        </p>
+        <p>
+            It uses asynchronous sending of messages so that it doesn't need separate threads
+            for each client to send messages (this needs NIO or APR connector to be used).<br/>
+            Each "Room" (where the drawing happens) uses a ReentrantLock to synchronize access
+            (currently, only a single Room is implemented).
+        </p>
+        <p>
+            When you open the page, first you will receive a binary websocket message containing
+            the current room image as PNG image. After that, you will receive string messages
+            that contain the drawing actions (line from x1,y1 to x2,y2).<br/>
+            <small>Note that it currently only uses simple string messages instead of JSON because
+            I did not want to introduce a dependency on a JSON lib.</small>
+        </p>
+        <p>
+            It uses synchronization mechanisms to ensure that the final image will look the same
+            for every user, regardless of what their network latency/speed is – e.g. if two user
+            draw at the same time on the same place, the server will decide which line was the
+            first one, and that will be reflected on every client.
+        </p>
+    </div>
+</body>
+</html>
\ No newline at end of file
diff --git a/tomcat-cas/webapps/examples/websocket/echo.xhtml b/tomcat-cas/webapps/examples/websocket/echo.xhtml
new file mode 100644
index 0000000..6153bff
--- /dev/null
+++ b/tomcat-cas/webapps/examples/websocket/echo.xhtml
@@ -0,0 +1,169 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+    <title>Apache Tomcat WebSocket Examples: Echo</title>
+    <style type="text/css"><![CDATA[
+        #connect-container {
+            float: left;
+            width: 400px
+        }
+
+        #connect-container div {
+            padding: 5px;
+        }
+
+        #console-container {
+            float: left;
+            margin-left: 15px;
+            width: 400px;
+        }
+
+        #console {
+            border: 1px solid #CCCCCC;
+            border-right-color: #999999;
+            border-bottom-color: #999999;
+            height: 170px;
+            overflow-y: scroll;
+            padding: 5px;
+            width: 100%;
+        }
+
+        #console p {
+            padding: 0;
+            margin: 0;
+        }
+    ]]></style>
+    <script type="application/javascript"><![CDATA[
+        var ws = null;
+
+        function setConnected(connected) {
+            document.getElementById('connect').disabled = connected;
+            document.getElementById('disconnect').disabled = !connected;
+            document.getElementById('echo').disabled = !connected;
+        }
+
+        function connect() {
+            var target = document.getElementById('target').value;
+            if (target == '') {
+                alert('Please select server side connection implementation.');
+                return;
+            }
+            if ('WebSocket' in window) {
+                ws = new WebSocket(target);
+            } else if ('MozWebSocket' in window) {
+                ws = new MozWebSocket(target);
+            } else {
+                alert('WebSocket is not supported by this browser.');
+                return;
+            }
+            ws.onopen = function () {
+                setConnected(true);
+                log('Info: WebSocket connection opened.');
+            };
+            ws.onmessage = function (event) {
+                log('Received: ' + event.data);
+            };
+            ws.onclose = function (event) {
+                setConnected(false);
+                log('Info: WebSocket connection closed, Code: ' + event.code + (event.reason == "" ? "" : ", Reason: " + event.reason));
+            };
+        }
+
+        function disconnect() {
+            if (ws != null) {
+                ws.close();
+                ws = null;
+            }
+            setConnected(false);
+        }
+
+        function echo() {
+            if (ws != null) {
+                var message = document.getElementById('message').value;
+                log('Sent: ' + message);
+                ws.send(message);
+            } else {
+                alert('WebSocket connection not established, please connect.');
+            }
+        }
+
+        function updateTarget(target) {
+            if (window.location.protocol == 'http:') {
+                document.getElementById('target').value = 'ws://' + window.location.host + target;
+            } else {
+                document.getElementById('target').value = 'wss://' + window.location.host + target;
+            }
+        }
+
+        function log(message) {
+            var console = document.getElementById('console');
+            var p = document.createElement('p');
+            p.style.wordWrap = 'break-word';
+            p.appendChild(document.createTextNode(message));
+            console.appendChild(p);
+            while (console.childNodes.length > 25) {
+                console.removeChild(console.firstChild);
+            }
+            console.scrollTop = console.scrollHeight;
+        }
+
+
+        document.addEventListener("DOMContentLoaded", function() {
+            // Remove elements with "noscript" class - <noscript> is not allowed in XHTML
+            var noscripts = document.getElementsByClassName("noscript");
+            for (var i = 0; i < noscripts.length; i++) {
+                noscripts[i].parentNode.removeChild(noscripts[i]);
+            }
+        }, false);
+    ]]></script>
+</head>
+<body>
+<div class="noscript"><h2 style="color: #ff0000">Seems your browser doesn't support Javascript! Websockets rely on Javascript being enabled. Please enable
+    Javascript and reload this page!</h2></div>
+<div>
+    <div id="connect-container">
+        <div>
+            <span>Connect to service implemented using:</span>
+            <!-- echo example using new programmatic API on the server side -->
+            <input id="radio1" type="radio" name="group1" value="/examples/websocket/echoProgrammatic"
+                   onclick="updateTarget(this.value);"/> <label for="radio1">programmatic API</label>
+            <!-- echo example using new annotation API on the server side -->
+            <input id="radio2" type="radio" name="group1" value="/examples/websocket/echoAnnotation"
+                   onclick="updateTarget(this.value);"/> <label for="radio2">annotation API</label>
+        </div>
+        <div>
+            <input id="target" type="text" size="40" style="width: 350px"/>
+        </div>
+        <div>
+            <button id="connect" onclick="connect();">Connect</button>
+            <button id="disconnect" disabled="disabled" onclick="disconnect();">Disconnect</button>
+        </div>
+        <div>
+            <textarea id="message" style="width: 350px">Here is a message!</textarea>
+        </div>
+        <div>
+            <button id="echo" onclick="echo();" disabled="disabled">Echo message</button>
+        </div>
+    </div>
+    <div id="console-container">
+        <div id="console"/>
+    </div>
+</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/tomcat-cas/webapps/examples/websocket/index.xhtml b/tomcat-cas/webapps/examples/websocket/index.xhtml
new file mode 100644
index 0000000..2b8d8cd
--- /dev/null
+++ b/tomcat-cas/webapps/examples/websocket/index.xhtml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+    <title>Apache Tomcat WebSocket Examples</title>
+</head>
+<body>
+<h1>Apache Tomcat WebSocket Examples</h1>
+<ul>
+    <li><a href="echo.xhtml">Echo example</a></li>
+    <li><a href="chat.xhtml">Chat example</a></li>
+    <li><a href="snake.xhtml">Multiplayer snake example</a></li>
+    <li><a href="drawboard.xhtml">Multiplayer drawboard example</a></li>
+
+</ul>
+</body>
+</html>
\ No newline at end of file
diff --git a/tomcat-cas/webapps/examples/websocket/snake.xhtml b/tomcat-cas/webapps/examples/websocket/snake.xhtml
new file mode 100644
index 0000000..86d1b3c
--- /dev/null
+++ b/tomcat-cas/webapps/examples/websocket/snake.xhtml
@@ -0,0 +1,266 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+    <title>Apache Tomcat WebSocket Examples: Multiplayer Snake</title>
+    <style type="text/css"><![CDATA[
+        #playground {
+            width: 640px;
+            height: 480px;
+            background-color: #000;
+        }
+
+        #console-container {
+            float: left;
+            margin-left: 15px;
+            width: 300px;
+        }
+
+        #console {
+            border: 1px solid #CCCCCC;
+            border-right-color: #999999;
+            border-bottom-color: #999999;
+            height: 480px;
+            overflow-y: scroll;
+            padding-left: 5px;
+            padding-right: 5px;
+            width: 100%;
+        }
+
+        #console p {
+            padding: 0;
+            margin: 0;
+        }
+    ]]></style>
+</head>
+<body>
+    <div class="noscript"><h2 style="color: #ff0000">Seems your browser doesn't support Javascript! Websockets rely on Javascript being enabled. Please enable
+    Javascript and reload this page!</h2></div>
+    <div style="float: left">
+        <canvas id="playground" width="640" height="480"/>
+    </div>
+    <div id="console-container">
+        <div id="console"/>
+    </div>
+    <script type="application/javascript"><![CDATA[
+
+        var Game = {};
+
+        Game.fps = 30;
+        Game.socket = null;
+        Game.nextFrame = null;
+        Game.interval = null;
+        Game.direction = 'none';
+        Game.gridSize = 10;
+
+        function Snake() {
+            this.snakeBody = [];
+            this.color = null;
+        }
+
+        Snake.prototype.draw = function(context) {
+            for (var id in this.snakeBody) {
+                context.fillStyle = this.color;
+                context.fillRect(this.snakeBody[id].x, this.snakeBody[id].y, Game.gridSize, Game.gridSize);
+            }
+        };
+
+        Game.initialize = function() {
+            this.entities = [];
+            canvas = document.getElementById('playground');
+            if (!canvas.getContext) {
+                Console.log('Error: 2d canvas not supported by this browser.');
+                return;
+            }
+            this.context = canvas.getContext('2d');
+            window.addEventListener('keydown', function (e) {
+                var code = e.keyCode;
+                if (code > 36 && code < 41) {
+                    switch (code) {
+                        case 37:
+                            if (Game.direction != 'east') Game.setDirection('west');
+                            break;
+                        case 38:
+                            if (Game.direction != 'south') Game.setDirection('north');
+                            break;
+                        case 39:
+                            if (Game.direction != 'west') Game.setDirection('east');
+                            break;
+                        case 40:
+                            if (Game.direction != 'north') Game.setDirection('south');
+                            break;
+                    }
+                }
+            }, false);
+            if (window.location.protocol == 'http:') {
+                Game.connect('ws://' + window.location.host + '/examples/websocket/snake');
+            } else {
+                Game.connect('wss://' + window.location.host + '/examples/websocket/snake');
+            }
+        };
+
+        Game.setDirection  = function(direction) {
+            Game.direction = direction;
+            Game.socket.send(direction);
+            Console.log('Sent: Direction ' + direction);
+        };
+
+        Game.startGameLoop = function() {
+            if (window.webkitRequestAnimationFrame) {
+                Game.nextFrame = function () {
+                    webkitRequestAnimationFrame(Game.run);
+                };
+            } else if (window.mozRequestAnimationFrame) {
+                Game.nextFrame = function () {
+                    mozRequestAnimationFrame(Game.run);
+                };
+            } else {
+                Game.interval = setInterval(Game.run, 1000 / Game.fps);
+            }
+            if (Game.nextFrame != null) {
+                Game.nextFrame();
+            }
+        };
+
+        Game.stopGameLoop = function () {
+            Game.nextFrame = null;
+            if (Game.interval != null) {
+                clearInterval(Game.interval);
+            }
+        };
+
+        Game.draw = function() {
+            this.context.clearRect(0, 0, 640, 480);
+            for (var id in this.entities) {
+                this.entities[id].draw(this.context);
+            }
+        };
+
+        Game.addSnake = function(id, color) {
+            Game.entities[id] = new Snake();
+            Game.entities[id].color = color;
+        };
+
+        Game.updateSnake = function(id, snakeBody) {
+            if (typeof Game.entities[id] != "undefined") {
+                Game.entities[id].snakeBody = snakeBody;
+            }
+        };
+
+        Game.removeSnake = function(id) {
+            Game.entities[id] = null;
+            // Force GC.
+            delete Game.entities[id];
+        };
+
+        Game.run = (function() {
+            var skipTicks = 1000 / Game.fps, nextGameTick = (new Date).getTime();
+
+            return function() {
+                while ((new Date).getTime() > nextGameTick) {
+                    nextGameTick += skipTicks;
+                }
+                Game.draw();
+                if (Game.nextFrame != null) {
+                    Game.nextFrame();
+                }
+            };
+        })();
+
+        Game.connect = (function(host) {
+            if ('WebSocket' in window) {
+                Game.socket = new WebSocket(host);
+            } else if ('MozWebSocket' in window) {
+                Game.socket = new MozWebSocket(host);
+            } else {
+                Console.log('Error: WebSocket is not supported by this browser.');
+                return;
+            }
+
+            Game.socket.onopen = function () {
+                // Socket open.. start the game loop.
+                Console.log('Info: WebSocket connection opened.');
+                Console.log('Info: Press an arrow key to begin.');
+                Game.startGameLoop();
+                setInterval(function() {
+                    // Prevent server read timeout.
+                    Game.socket.send('ping');
+                }, 5000);
+            };
+
+            Game.socket.onclose = function () {
+                Console.log('Info: WebSocket closed.');
+                Game.stopGameLoop();
+            };
+
+            Game.socket.onmessage = function (message) {
+                // _Potential_ security hole, consider using json lib to parse data in production.
+                var packet = eval('(' + message.data + ')');
+                switch (packet.type) {
+                    case 'update':
+                        for (var i = 0; i < packet.data.length; i++) {
+                            Game.updateSnake(packet.data[i].id, packet.data[i].body);
+                        }
+                        break;
+                    case 'join':
+                        for (var j = 0; j < packet.data.length; j++) {
+                            Game.addSnake(packet.data[j].id, packet.data[j].color);
+                        }
+                        break;
+                    case 'leave':
+                        Game.removeSnake(packet.id);
+                        break;
+                    case 'dead':
+                        Console.log('Info: Your snake is dead, bad luck!');
+                        Game.direction = 'none';
+                        break;
+                    case 'kill':
+                        Console.log('Info: Head shot!');
+                        break;
+                }
+            };
+        });
+
+        var Console = {};
+
+        Console.log = (function(message) {
+            var console = document.getElementById('console');
+            var p = document.createElement('p');
+            p.style.wordWrap = 'break-word';
+            p.innerHTML = message;
+            console.appendChild(p);
+            while (console.childNodes.length > 25) {
+                console.removeChild(console.firstChild);
+            }
+            console.scrollTop = console.scrollHeight;
+        });
+
+        Game.initialize();
+
+
+        document.addEventListener("DOMContentLoaded", function() {
+            // Remove elements with "noscript" class - <noscript> is not allowed in XHTML
+            var noscripts = document.getElementsByClassName("noscript");
+            for (var i = 0; i < noscripts.length; i++) {
+                noscripts[i].parentNode.removeChild(noscripts[i]);
+            }
+        }, false);
+
+        ]]></script>
+</body>
+</html>
\ No newline at end of file