You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by kp...@apache.org on 2013/10/11 15:29:13 UTC

svn commit: r1531291 [2/2] - in /tomcat/tc7.0.x/trunk: ./ webapps/docs/ webapps/examples/WEB-INF/classes/websocket/drawboard/ webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/ webapps/examples/websocket/

Modified: tomcat/tc7.0.x/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/StringWebsocketMessage.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/StringWebsocketMessage.java?rev=1531291&r1=1530296&r2=1531291&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/StringWebsocketMessage.java (original)
+++ tomcat/tc7.0.x/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/StringWebsocketMessage.java Fri Oct 11 13:29:12 2013
@@ -1,34 +1,34 @@
-/*
- *  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.
- */
-package websocket.drawboard.wsmessages;
-
-/**
- * Represents a string websocket message.
- *
- */
-public final class StringWebsocketMessage extends AbstractWebsocketMessage {
-    private final String string;
-
-    public StringWebsocketMessage(String string) {
-        this.string = string;
-    }
-
-    public String getString() {
-        return string;
-    }
-
-}
+/*
+ *  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.
+ */
+package websocket.drawboard.wsmessages;
+
+/**
+ * Represents a string websocket message.
+ *
+ */
+public final class StringWebsocketMessage extends AbstractWebsocketMessage {
+    private final String string;
+
+    public StringWebsocketMessage(String string) {
+        this.string = string;
+    }
+
+    public String getString() {
+        return string;
+    }
+
+}

Propchange: tomcat/tc7.0.x/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/StringWebsocketMessage.java
------------------------------------------------------------------------------
    svn:eol-style = native

Copied: tomcat/tc7.0.x/trunk/webapps/examples/websocket/drawboard.xhtml (from r1530296, tomcat/trunk/webapps/examples/websocket/drawboard.xhtml)
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/webapps/examples/websocket/drawboard.xhtml?p2=tomcat/tc7.0.x/trunk/webapps/examples/websocket/drawboard.xhtml&p1=tomcat/trunk/webapps/examples/websocket/drawboard.xhtml&r1=1530296&r2=1531291&rev=1531291&view=diff
==============================================================================
--- tomcat/trunk/webapps/examples/websocket/drawboard.xhtml (original)
+++ tomcat/tc7.0.x/trunk/webapps/examples/websocket/drawboard.xhtml Fri Oct 11 13:29:12 2013
@@ -1,611 +1,797 @@
-<?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; /* Disable touch behaviors, like pan and zoom */
-        }
-
-        #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]);
-            }
-
-
-            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) {
-
-                // 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];
-
-                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 mouseInWindow = false;
-                var mouseDown = false;
-                var currentMouseX = 0, currentMouseY = 0;
-
-                var availableColors = [];
-                var currentColorIndex;
-                var colorContainers;
-
-                var availableThicknesses = [2, 3, 6, 10, 16, 28, 50];
-                var currentThicknessIndex;
-                var thicknessContainers;
-
-
-                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) {
-                    this.type = type;
-                    this.color = color;
-                    this.thickness = thickness;
-                    this.x1 = x1;
-                    this.y1 = y1;
-                    this.x2 = x2;
-                    this.y2 = y2;
-
-                    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) {
-                                // Draw a line.
-                                ctx.moveTo(x1, y1);
-                                ctx.lineTo(x2, y2);
-                                ctx.stroke();
-                            }
-                        }
-                    };
-                }
-
-
-                function connect() {
-                    var host = (window.location.protocol == "https:"
-                            ? "wss://" : "ws://") + window.location.host
-                            + "/examples/websocket/drawboard";
-                    socket = new WebSocket(host);
-
-                    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 () {
-                        Console.log("WebSocket connection closed.");
-                        disableControls();
-
-                        // Disable pong timer.
-                        window.clearInterval(pingTimerId);
-                    }
-
-                    socket.onmessage = function(message) {
-
-                        // Split joined message and process them
-                        // invidividually.
-                        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 = socket.onmessage;
-                                        socket.onmessage = function(message) {
-                                            // First, we restore the original handler.
-                                            socket.onmessage = 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.
-                                            
-                                            // TODO: I don't know if there is a guarantee
-                                            // that no WebSocket events (onmessage) will
-                                            // be raised until the onload event of this
-                                            // image is raised. Maybe we need to need to
-                                            // push websocket messages on a queue until
-                                            // this onload function is called.
-                                            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);
-
-                                                // Refresh the display canvas.
-                                                refreshDisplayCanvas();
-
-                                                isStarted = true;
-                                                startControls();
-                                            };
-
-                                            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]),
-                                                    parseInt(elements[7]),
-                                                    parseInt(elements[8]),
-                                                    parseInt(elements[9]),
-                                                    parseInt(elements[10]));
-
-                                            // 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();
-                                    } 
-                                }
-                            }
-                        }
-                    };
-
-                }
-
-                function refreshPlayerCount() {
-                    labelPlayerCount.nodeValue = String(playerCount);
-                }
-
-                function refreshDisplayCanvas() {
-                    canvasDisplayCtx.drawImage(canvasBackground, 0, 0);
-                    if (mouseInWindow && !mouseDown) {
-                        canvasDisplayCtx.beginPath();
-                        var color = availableColors[currentColorIndex].slice(0);
-                        color[3] = 0.5;
-                        canvasDisplayCtx.fillStyle = rgb(color);
-                        
-                        canvasDisplayCtx.arc(currentMouseX, currentMouseY, availableThicknesses[currentThicknessIndex] / 2, 0, Math.PI * 2.0, true);
-                        
-                        canvasDisplayCtx.fill();
-                    }
-                }
-
-                function startControls() {
-                    var labelContainer = document.getElementById("labelContainer");
-                    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);
-
-                    canvasDisplay.onmousemove = function(e) {
-                        mouseInWindow = true;
-                        var oldMouseX = currentMouseX, oldMouseY = currentMouseY;
-                        currentMouseX = e.pageX - canvasDisplay.offsetLeft;
-                        currentMouseY = e.pageY - canvasDisplay.offsetTop;
-
-                        if (mouseDown) {
-                            var path = new Path(1, availableColors[currentColorIndex],
-                                    availableThicknesses[currentThicknessIndex],
-                                    oldMouseX, oldMouseY, currentMouseX,
-                                    currentMouseY);
-                            // Draw it on the background canvas.
-                            path.draw(canvasBackgroundCtx);
-
-                            // Send it to the sever.
-                            pushPath(path);
-                        }
-
-                        refreshDisplayCanvas();
-                    };
-
-                    canvasDisplay.onmousedown = function(e) {
-                        currentMouseX = e.pageX - canvasDisplay.offsetLeft;
-                        currentMouseY = e.pageY - canvasDisplay.offsetTop;
-
-                        if (e.button == 0) {
-                            mouseDown = true;
-
-                            var path = new Path(1, availableColors[currentColorIndex],
-                                    availableThicknesses[currentThicknessIndex],
-                                    currentMouseX, currentMouseY, currentMouseX,
-                                    currentMouseY);
-                            // Draw it on the background canvas.
-                            path.draw(canvasBackgroundCtx);
-
-                            // Send it to the sever.
-                            pushPath(path);
-
-                            refreshDisplayCanvas();
-
-                        } else if (mouseDown) {
-                            // Cancel drawing.
-                            mouseDown = false;
-
-                            refreshDisplayCanvas();
-                        }
-                    }
-
-                    canvasDisplay.onmouseup = function(e) {
-                        if (e.button == 0) {
-                            if (mouseDown) {
-                                mouseDown = false;
-
-                                refreshDisplayCanvas();
-                            }
-                        }
-                    };
-
-                    canvasDisplay.onmouseout = function() {
-                        mouseInWindow = false;
-                        refreshDisplayCanvas();
-                    };
-
-
-                    // 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.onmousedown = (function(ix) {
-                            return function() {
-                                setColor(ix);
-                            };
-                        })(i);
-
-                        colorContainersBox.appendChild(colorContainer);
-                    }
-
-                    var divClearLeft = document.createElement("div");
-                    divClearLeft.setAttribute("style", "clear: left;");
-                    colorContainersBox.appendChild(divClearLeft);
-
-                    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.onmousedown = (function(ix) {
-                            return function() {
-                                setThickness(ix);
-                            };
-                        })(i);
-
-                        thicknessContainersBox.appendChild(thicknessContainer);
-                    }
-
-                    divClearLeft = document.createElement("div");
-                    divClearLeft.setAttribute("style", "clear: left;");
-                    thicknessContainersBox.appendChild(divClearLeft);
-
-
-                    setColor(0);
-                    setThickness(0);
-
-                }
-
-                function disableControls() {
-                    canvasDisplay.onmousemove = canvasDisplay.onmousedown =
-                        undefined;
-                    mouseInWindow = false;
-                    refreshDisplayCanvas();
-                }
-
-                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;
-                    
-                    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";
-                }
-
-
-                connect();
-
-            }
-
-
-            // Initialize the room
-            var room = new Room(document.getElementById("drawContainer"));
-
-
-        }, 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 id="labelContainer"/>
-    <div id="drawContainer"/>
-    <div id="console-container"/>
-
-</body>
+<?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 */
+        }
+
+        #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]);
+            }
+
+
+            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];
+
+                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 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
+                        // invidividually.
+                        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);
+
+                                                // Refresh the display canvas.
+                                                refreshDisplayCanvas();
+
+                                                isStarted = true;
+                                                startControls();
+
+
+                                                // 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() {
+                    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() {
+                    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);
+
+                    canvasDisplay.onmousedown = function(e) {
+                        if (e.button == 0) {
+                            currentMouseX = e.pageX - canvasDisplay.offsetLeft;
+                            currentMouseY = e.pageY - canvasDisplay.offsetTop;
+
+                            mouseDown = true;
+                            canvasMouseMove(e);
+
+                        } else if (mouseDown) {
+                            // Cancel drawing.
+                            mouseDown = false;
+                            currentPreviewPath = null;
+
+                            currentMouseX = e.pageX - canvasDisplay.offsetLeft;
+                            currentMouseY = e.pageY - canvasDisplay.offsetTop;
+
+                            refreshDisplayCanvas();
+                        }
+                    }
+
+                    var canvasMouseMove = canvasDisplay.onmousemove = function(e) {
+                        mouseInWindow = true;
+                        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);
+                            }
+                        } else {
+                            currentMouseX = mouseX;
+                            currentMouseY = mouseY;
+                        }
+
+                        refreshDisplayCanvas();
+                    };
+
+                    canvasDisplay.onmouseup = 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();
+                            }
+                        }
+                    };
+
+                    canvasDisplay.onmouseout = function() {
+                        mouseInWindow = false;
+                        refreshDisplayCanvas();
+                    };
+
+
+                    // 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.onmousedown = (function(ix) {
+                            return function() {
+                                setColor(ix);
+                            };
+                        })(i);
+
+                        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.onmousedown = (function(ix) {
+                            return function() {
+                                setDrawType(ix);
+                            };
+                        })(i);
+
+                        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.onmousedown = (function(ix) {
+                            return function() {
+                                setThickness(ix);
+                            };
+                        })(i);
+
+                        thicknessContainersBox.appendChild(thicknessContainer);
+                    }
+
+
+                    divClearLeft = document.createElement("div");
+                    divClearLeft.setAttribute("style", "clear: left;");
+                    thicknessContainersBox.appendChild(divClearLeft);
+
+
+                    setColor(0);
+                    setThickness(0);
+                    setDrawType(0);
+
+                }
+
+                function disableControls() {
+                    canvasDisplay.onmousemove = canvasDisplay.onmousedown =
+                        undefined;
+                    mouseInWindow = false;
+                    refreshDisplayCanvas();
+                }
+
+                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"><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 id="labelContainer"/>
+    <div id="drawContainer"/>
+    <div id="console-container"/>
+
+</body>
 </html>
\ No newline at end of file

Propchange: tomcat/tc7.0.x/trunk/webapps/examples/websocket/drawboard.xhtml
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tomcat/tc7.0.x/trunk/webapps/examples/websocket/index.xhtml
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/webapps/examples/websocket/index.xhtml?rev=1531291&r1=1531290&r2=1531291&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/webapps/examples/websocket/index.xhtml (original)
+++ tomcat/tc7.0.x/trunk/webapps/examples/websocket/index.xhtml Fri Oct 11 13:29:12 2013
@@ -25,6 +25,8 @@
     <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



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org