You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@guacamole.apache.org by mj...@apache.org on 2018/10/01 03:24:02 UTC

[2/6] guacamole-website git commit: Deploy updated tests which pull guacamole-common-js directly from git.

http://git-wip-us.apache.org/repos/asf/guacamole-website/blob/f5235113/content/pub/tests/guac/modules/Mouse.js
----------------------------------------------------------------------
diff --git a/content/pub/tests/guac/modules/Mouse.js b/content/pub/tests/guac/modules/Mouse.js
deleted file mode 100644
index cdd1ae9..0000000
--- a/content/pub/tests/guac/modules/Mouse.js
+++ /dev/null
@@ -1,1090 +0,0 @@
-/*
- * Copyright (C) 2013 Glyptodon LLC
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-var Guacamole = Guacamole || {};
-
-/**
- * Provides cross-browser mouse events for a given element. The events of
- * the given element are automatically populated with handlers that translate
- * mouse events into a non-browser-specific event provided by the
- * Guacamole.Mouse instance.
- * 
- * @constructor
- * @param {Element} element The Element to use to provide mouse events.
- */
-Guacamole.Mouse = function(element) {
-
-    /**
-     * Reference to this Guacamole.Mouse.
-     * @private
-     */
-    var guac_mouse = this;
-
-    /**
-     * The number of mousemove events to require before re-enabling mouse
-     * event handling after receiving a touch event.
-     */
-    this.touchMouseThreshold = 3;
-
-    /**
-     * The minimum amount of pixels scrolled required for a single scroll button
-     * click.
-     */
-    this.scrollThreshold = 53;
-
-    /**
-     * The number of pixels to scroll per line.
-     */
-    this.PIXELS_PER_LINE = 18;
-
-    /**
-     * The number of pixels to scroll per page.
-     */
-    this.PIXELS_PER_PAGE = this.PIXELS_PER_LINE * 16;
-
-    /**
-     * The current mouse state. The properties of this state are updated when
-     * mouse events fire. This state object is also passed in as a parameter to
-     * the handler of any mouse events.
-     * 
-     * @type {Guacamole.Mouse.State}
-     */
-    this.currentState = new Guacamole.Mouse.State(
-        0, 0, 
-        false, false, false, false, false
-    );
-
-    /**
-     * Fired whenever the user presses a mouse button down over the element
-     * associated with this Guacamole.Mouse.
-     * 
-     * @event
-     * @param {Guacamole.Mouse.State} state The current mouse state.
-     */
-	this.onmousedown = null;
-
-    /**
-     * Fired whenever the user releases a mouse button down over the element
-     * associated with this Guacamole.Mouse.
-     * 
-     * @event
-     * @param {Guacamole.Mouse.State} state The current mouse state.
-     */
-	this.onmouseup = null;
-
-    /**
-     * Fired whenever the user moves the mouse over the element associated with
-     * this Guacamole.Mouse.
-     * 
-     * @event
-     * @param {Guacamole.Mouse.State} state The current mouse state.
-     */
-	this.onmousemove = null;
-
-    /**
-     * Fired whenever the mouse leaves the boundaries of the element associated
-     * with this Guacamole.Mouse.
-     * 
-     * @event
-     */
-	this.onmouseout = null;
-
-    /**
-     * Counter of mouse events to ignore. This decremented by mousemove, and
-     * while non-zero, mouse events will have no effect.
-     * @private
-     */
-    var ignore_mouse = 0;
-
-    /**
-     * Cumulative scroll delta amount. This value is accumulated through scroll
-     * events and results in scroll button clicks if it exceeds a certain
-     * threshold.
-     *
-     * @private
-     */
-    var scroll_delta = 0;
-
-    function cancelEvent(e) {
-        e.stopPropagation();
-        if (e.preventDefault) e.preventDefault();
-        e.returnValue = false;
-    }
-
-    // Block context menu so right-click gets sent properly
-    element.addEventListener("contextmenu", function(e) {
-        cancelEvent(e);
-    }, false);
-
-    element.addEventListener("mousemove", function(e) {
-
-        cancelEvent(e);
-
-        // If ignoring events, decrement counter
-        if (ignore_mouse) {
-            ignore_mouse--;
-            return;
-        }
-
-        guac_mouse.currentState.fromClientPosition(element, e.clientX, e.clientY);
-
-        if (guac_mouse.onmousemove)
-            guac_mouse.onmousemove(guac_mouse.currentState);
-
-    }, false);
-
-    element.addEventListener("mousedown", function(e) {
-
-        cancelEvent(e);
-
-        // Do not handle if ignoring events
-        if (ignore_mouse)
-            return;
-
-        switch (e.button) {
-            case 0:
-                guac_mouse.currentState.left = true;
-                break;
-            case 1:
-                guac_mouse.currentState.middle = true;
-                break;
-            case 2:
-                guac_mouse.currentState.right = true;
-                break;
-        }
-
-        if (guac_mouse.onmousedown)
-            guac_mouse.onmousedown(guac_mouse.currentState);
-
-    }, false);
-
-    element.addEventListener("mouseup", function(e) {
-
-        cancelEvent(e);
-
-        // Do not handle if ignoring events
-        if (ignore_mouse)
-            return;
-
-        switch (e.button) {
-            case 0:
-                guac_mouse.currentState.left = false;
-                break;
-            case 1:
-                guac_mouse.currentState.middle = false;
-                break;
-            case 2:
-                guac_mouse.currentState.right = false;
-                break;
-        }
-
-        if (guac_mouse.onmouseup)
-            guac_mouse.onmouseup(guac_mouse.currentState);
-
-    }, false);
-
-    element.addEventListener("mouseout", function(e) {
-
-        // Get parent of the element the mouse pointer is leaving
-       	if (!e) e = window.event;
-
-        // Check that mouseout is due to actually LEAVING the element
-        var target = e.relatedTarget || e.toElement;
-        while (target) {
-            if (target === element)
-                return;
-            target = target.parentNode;
-        }
-
-        cancelEvent(e);
-
-        // Release all buttons
-        if (guac_mouse.currentState.left
-            || guac_mouse.currentState.middle
-            || guac_mouse.currentState.right) {
-
-            guac_mouse.currentState.left = false;
-            guac_mouse.currentState.middle = false;
-            guac_mouse.currentState.right = false;
-
-            if (guac_mouse.onmouseup)
-                guac_mouse.onmouseup(guac_mouse.currentState);
-        }
-
-        // Fire onmouseout event
-        if (guac_mouse.onmouseout)
-            guac_mouse.onmouseout();
-
-    }, false);
-
-    // Override selection on mouse event element.
-    element.addEventListener("selectstart", function(e) {
-        cancelEvent(e);
-    }, false);
-
-    // Ignore all pending mouse events when touch events are the apparent source
-    function ignorePendingMouseEvents() { ignore_mouse = guac_mouse.touchMouseThreshold; }
-
-    element.addEventListener("touchmove",  ignorePendingMouseEvents, false);
-    element.addEventListener("touchstart", ignorePendingMouseEvents, false);
-    element.addEventListener("touchend",   ignorePendingMouseEvents, false);
-
-    // Scroll wheel support
-    function mousewheel_handler(e) {
-
-        // Determine approximate scroll amount (in pixels)
-        var delta = e.deltaY || -e.wheelDeltaY || -e.wheelDelta;
-
-        // If successfully retrieved scroll amount, convert to pixels if not
-        // already in pixels
-        if (delta) {
-
-            // Convert to pixels if delta was lines
-            if (e.deltaMode === 1)
-                delta = e.deltaY * guac_mouse.PIXELS_PER_LINE;
-
-            // Convert to pixels if delta was pages
-            else if (e.deltaMode === 2)
-                delta = e.deltaY * guac_mouse.PIXELS_PER_PAGE;
-
-        }
-
-        // Otherwise, assume legacy mousewheel event and line scrolling
-        else
-            delta = e.detail * guac_mouse.PIXELS_PER_LINE;
-        
-        // Update overall delta
-        scroll_delta += delta;
-
-        // Up
-        if (scroll_delta <= -guac_mouse.scrollThreshold) {
-
-            // Repeatedly click the up button until insufficient delta remains
-            do {
-
-                if (guac_mouse.onmousedown) {
-                    guac_mouse.currentState.up = true;
-                    guac_mouse.onmousedown(guac_mouse.currentState);
-                }
-
-                if (guac_mouse.onmouseup) {
-                    guac_mouse.currentState.up = false;
-                    guac_mouse.onmouseup(guac_mouse.currentState);
-                }
-
-                scroll_delta += guac_mouse.scrollThreshold;
-
-            } while (scroll_delta <= -guac_mouse.scrollThreshold);
-
-            // Reset delta
-            scroll_delta = 0;
-
-        }
-
-        // Down
-        if (scroll_delta >= guac_mouse.scrollThreshold) {
-
-            // Repeatedly click the down button until insufficient delta remains
-            do {
-
-                if (guac_mouse.onmousedown) {
-                    guac_mouse.currentState.down = true;
-                    guac_mouse.onmousedown(guac_mouse.currentState);
-                }
-
-                if (guac_mouse.onmouseup) {
-                    guac_mouse.currentState.down = false;
-                    guac_mouse.onmouseup(guac_mouse.currentState);
-                }
-
-                scroll_delta -= guac_mouse.scrollThreshold;
-
-            } while (scroll_delta >= guac_mouse.scrollThreshold);
-
-            // Reset delta
-            scroll_delta = 0;
-
-        }
-
-        cancelEvent(e);
-
-    }
-
-    element.addEventListener('DOMMouseScroll', mousewheel_handler, false);
-    element.addEventListener('mousewheel',     mousewheel_handler, false);
-    element.addEventListener('wheel',          mousewheel_handler, false);
-
-    /**
-     * Whether the browser supports CSS3 cursor styling, including hotspot
-     * coordinates.
-     *
-     * @private
-     * @type {Boolean}
-     */
-    var CSS3_CURSOR_SUPPORTED = (function() {
-
-        var div = document.createElement("div");
-
-        // If no cursor property at all, then no support
-        if (!("cursor" in div.style))
-            return false;
-
-        try {
-            // Apply simple 1x1 PNG
-            div.style.cursor = "url(data:image/png;base64,"
-                             + "iVBORw0KGgoAAAANSUhEUgAAAAEAAAAB"
-                             + "AQMAAAAl21bKAAAAA1BMVEX///+nxBvI"
-                             + "AAAACklEQVQI12NgAAAAAgAB4iG8MwAA"
-                             + "AABJRU5ErkJggg==) 0 0, auto";
-        }
-        catch (e) {
-            return false;
-        }
-
-        // Verify cursor property is set to URL with hotspot
-        return /\burl\([^()]*\)\s+0\s+0\b/.test(div.style.cursor || "");
-
-    })();
-
-    /**
-     * Changes the local mouse cursor to the given canvas, having the given
-     * hotspot coordinates. This affects styling of the element backing this
-     * Guacamole.Mouse only, and may fail depending on browser support for
-     * setting the mouse cursor.
-     * 
-     * If setting the local cursor is desired, it is up to the implementation
-     * to do something else, such as use the software cursor built into
-     * Guacamole.Display, if the local cursor cannot be set.
-     *
-     * @param {HTMLCanvasElement} canvas The cursor image.
-     * @param {Number} x The X-coordinate of the cursor hotspot.
-     * @param {Number} y The Y-coordinate of the cursor hotspot.
-     * @return {Boolean} true if the cursor was successfully set, false if the
-     *                   cursor could not be set for any reason.
-     */
-    this.setCursor = function(canvas, x, y) {
-
-        // Attempt to set via CSS3 cursor styling
-        if (CSS3_CURSOR_SUPPORTED) {
-            var dataURL = canvas.toDataURL('image/png');
-            element.style.cursor = "url(" + dataURL + ") " + x + " " + y + ", auto";
-            return true;
-        }
-
-        // Otherwise, setting cursor failed
-        return false;
-
-    };
-
-};
-
-/**
- * Simple container for properties describing the state of a mouse.
- * 
- * @constructor
- * @param {Number} x The X position of the mouse pointer in pixels.
- * @param {Number} y The Y position of the mouse pointer in pixels.
- * @param {Boolean} left Whether the left mouse button is pressed. 
- * @param {Boolean} middle Whether the middle mouse button is pressed. 
- * @param {Boolean} right Whether the right mouse button is pressed. 
- * @param {Boolean} up Whether the up mouse button is pressed (the fourth
- *                     button, usually part of a scroll wheel). 
- * @param {Boolean} down Whether the down mouse button is pressed (the fifth
- *                       button, usually part of a scroll wheel). 
- */
-Guacamole.Mouse.State = function(x, y, left, middle, right, up, down) {
-
-    /**
-     * Reference to this Guacamole.Mouse.State.
-     * @private
-     */
-    var guac_state = this;
-
-    /**
-     * The current X position of the mouse pointer.
-     * @type {Number}
-     */
-    this.x = x;
-
-    /**
-     * The current Y position of the mouse pointer.
-     * @type {Number}
-     */
-    this.y = y;
-
-    /**
-     * Whether the left mouse button is currently pressed.
-     * @type {Boolean}
-     */
-    this.left = left;
-
-    /**
-     * Whether the middle mouse button is currently pressed.
-     * @type {Boolean}
-     */
-    this.middle = middle;
-
-    /**
-     * Whether the right mouse button is currently pressed.
-     * @type {Boolean}
-     */
-    this.right = right;
-
-    /**
-     * Whether the up mouse button is currently pressed. This is the fourth
-     * mouse button, associated with upward scrolling of the mouse scroll
-     * wheel.
-     * @type {Boolean}
-     */
-    this.up = up;
-
-    /**
-     * Whether the down mouse button is currently pressed. This is the fifth 
-     * mouse button, associated with downward scrolling of the mouse scroll
-     * wheel.
-     * @type {Boolean}
-     */
-    this.down = down;
-
-    /**
-     * Updates the position represented within this state object by the given
-     * element and clientX/clientY coordinates (commonly available within event
-     * objects). Position is translated from clientX/clientY (relative to
-     * viewport) to element-relative coordinates.
-     * 
-     * @param {Element} element The element the coordinates should be relative
-     *                          to.
-     * @param {Number} clientX The X coordinate to translate, viewport-relative.
-     * @param {Number} clientY The Y coordinate to translate, viewport-relative.
-     */
-    this.fromClientPosition = function(element, clientX, clientY) {
-    
-        guac_state.x = clientX - element.offsetLeft;
-        guac_state.y = clientY - element.offsetTop;
-
-        // This is all JUST so we can get the mouse position within the element
-        var parent = element.offsetParent;
-        while (parent && !(parent === document.body)) {
-            guac_state.x -= parent.offsetLeft - parent.scrollLeft;
-            guac_state.y -= parent.offsetTop  - parent.scrollTop;
-
-            parent = parent.offsetParent;
-        }
-
-        // Element ultimately depends on positioning within document body,
-        // take document scroll into account. 
-        if (parent) {
-            var documentScrollLeft = document.body.scrollLeft || document.documentElement.scrollLeft;
-            var documentScrollTop = document.body.scrollTop || document.documentElement.scrollTop;
-
-            guac_state.x -= parent.offsetLeft - documentScrollLeft;
-            guac_state.y -= parent.offsetTop  - documentScrollTop;
-        }
-
-    };
-
-};
-
-/**
- * Provides cross-browser relative touch event translation for a given element.
- * 
- * Touch events are translated into mouse events as if the touches occurred
- * on a touchpad (drag to push the mouse pointer, tap to click).
- * 
- * @constructor
- * @param {Element} element The Element to use to provide touch events.
- */
-Guacamole.Mouse.Touchpad = function(element) {
-
-    /**
-     * Reference to this Guacamole.Mouse.Touchpad.
-     * @private
-     */
-    var guac_touchpad = this;
-
-    /**
-     * The distance a two-finger touch must move per scrollwheel event, in
-     * pixels.
-     */
-    this.scrollThreshold = 20 * (window.devicePixelRatio || 1);
-
-    /**
-     * The maximum number of milliseconds to wait for a touch to end for the
-     * gesture to be considered a click.
-     */
-    this.clickTimingThreshold = 250;
-
-    /**
-     * The maximum number of pixels to allow a touch to move for the gesture to
-     * be considered a click.
-     */
-    this.clickMoveThreshold = 10 * (window.devicePixelRatio || 1);
-
-    /**
-     * The current mouse state. The properties of this state are updated when
-     * mouse events fire. This state object is also passed in as a parameter to
-     * the handler of any mouse events.
-     * 
-     * @type {Guacamole.Mouse.State}
-     */
-    this.currentState = new Guacamole.Mouse.State(
-        0, 0, 
-        false, false, false, false, false
-    );
-
-    /**
-     * Fired whenever a mouse button is effectively pressed. This can happen
-     * as part of a "click" gesture initiated by the user by tapping one
-     * or more fingers over the touchpad element, as part of a "scroll"
-     * gesture initiated by dragging two fingers up or down, etc.
-     * 
-     * @event
-     * @param {Guacamole.Mouse.State} state The current mouse state.
-     */
-	this.onmousedown = null;
-
-    /**
-     * Fired whenever a mouse button is effectively released. This can happen
-     * as part of a "click" gesture initiated by the user by tapping one
-     * or more fingers over the touchpad element, as part of a "scroll"
-     * gesture initiated by dragging two fingers up or down, etc.
-     * 
-     * @event
-     * @param {Guacamole.Mouse.State} state The current mouse state.
-     */
-	this.onmouseup = null;
-
-    /**
-     * Fired whenever the user moves the mouse by dragging their finger over
-     * the touchpad element.
-     * 
-     * @event
-     * @param {Guacamole.Mouse.State} state The current mouse state.
-     */
-	this.onmousemove = null;
-
-    var touch_count = 0;
-    var last_touch_x = 0;
-    var last_touch_y = 0;
-    var last_touch_time = 0;
-    var pixels_moved = 0;
-
-    var touch_buttons = {
-        1: "left",
-        2: "right",
-        3: "middle"
-    };
-
-    var gesture_in_progress = false;
-    var click_release_timeout = null;
-
-    element.addEventListener("touchend", function(e) {
-        
-        e.preventDefault();
-            
-        // If we're handling a gesture AND this is the last touch
-        if (gesture_in_progress && e.touches.length === 0) {
-            
-            var time = new Date().getTime();
-
-            // Get corresponding mouse button
-            var button = touch_buttons[touch_count];
-
-            // If mouse already down, release anad clear timeout
-            if (guac_touchpad.currentState[button]) {
-
-                // Fire button up event
-                guac_touchpad.currentState[button] = false;
-                if (guac_touchpad.onmouseup)
-                    guac_touchpad.onmouseup(guac_touchpad.currentState);
-
-                // Clear timeout, if set
-                if (click_release_timeout) {
-                    window.clearTimeout(click_release_timeout);
-                    click_release_timeout = null;
-                }
-
-            }
-
-            // If single tap detected (based on time and distance)
-            if (time - last_touch_time <= guac_touchpad.clickTimingThreshold
-                    && pixels_moved < guac_touchpad.clickMoveThreshold) {
-
-                // Fire button down event
-                guac_touchpad.currentState[button] = true;
-                if (guac_touchpad.onmousedown)
-                    guac_touchpad.onmousedown(guac_touchpad.currentState);
-
-                // Delay mouse up - mouse up should be canceled if
-                // touchstart within timeout.
-                click_release_timeout = window.setTimeout(function() {
-                    
-                    // Fire button up event
-                    guac_touchpad.currentState[button] = false;
-                    if (guac_touchpad.onmouseup)
-                        guac_touchpad.onmouseup(guac_touchpad.currentState);
-                    
-                    // Gesture now over
-                    gesture_in_progress = false;
-
-                }, guac_touchpad.clickTimingThreshold);
-
-            }
-
-            // If we're not waiting to see if this is a click, stop gesture
-            if (!click_release_timeout)
-                gesture_in_progress = false;
-
-        }
-
-    }, false);
-
-    element.addEventListener("touchstart", function(e) {
-
-        e.preventDefault();
-
-        // Track number of touches, but no more than three
-        touch_count = Math.min(e.touches.length, 3);
-
-        // Clear timeout, if set
-        if (click_release_timeout) {
-            window.clearTimeout(click_release_timeout);
-            click_release_timeout = null;
-        }
-
-        // Record initial touch location and time for touch movement
-        // and tap gestures
-        if (!gesture_in_progress) {
-
-            // Stop mouse events while touching
-            gesture_in_progress = true;
-
-            // Record touch location and time
-            var starting_touch = e.touches[0];
-            last_touch_x = starting_touch.clientX;
-            last_touch_y = starting_touch.clientY;
-            last_touch_time = new Date().getTime();
-            pixels_moved = 0;
-
-        }
-
-    }, false);
-
-    element.addEventListener("touchmove", function(e) {
-
-        e.preventDefault();
-
-        // Get change in touch location
-        var touch = e.touches[0];
-        var delta_x = touch.clientX - last_touch_x;
-        var delta_y = touch.clientY - last_touch_y;
-
-        // Track pixels moved
-        pixels_moved += Math.abs(delta_x) + Math.abs(delta_y);
-
-        // If only one touch involved, this is mouse move
-        if (touch_count === 1) {
-
-            // Calculate average velocity in Manhatten pixels per millisecond
-            var velocity = pixels_moved / (new Date().getTime() - last_touch_time);
-
-            // Scale mouse movement relative to velocity
-            var scale = 1 + velocity;
-
-            // Update mouse location
-            guac_touchpad.currentState.x += delta_x*scale;
-            guac_touchpad.currentState.y += delta_y*scale;
-
-            // Prevent mouse from leaving screen
-
-            if (guac_touchpad.currentState.x < 0)
-                guac_touchpad.currentState.x = 0;
-            else if (guac_touchpad.currentState.x >= element.offsetWidth)
-                guac_touchpad.currentState.x = element.offsetWidth - 1;
-
-            if (guac_touchpad.currentState.y < 0)
-                guac_touchpad.currentState.y = 0;
-            else if (guac_touchpad.currentState.y >= element.offsetHeight)
-                guac_touchpad.currentState.y = element.offsetHeight - 1;
-
-            // Fire movement event, if defined
-            if (guac_touchpad.onmousemove)
-                guac_touchpad.onmousemove(guac_touchpad.currentState);
-
-            // Update touch location
-            last_touch_x = touch.clientX;
-            last_touch_y = touch.clientY;
-
-        }
-
-        // Interpret two-finger swipe as scrollwheel
-        else if (touch_count === 2) {
-
-            // If change in location passes threshold for scroll
-            if (Math.abs(delta_y) >= guac_touchpad.scrollThreshold) {
-
-                // Decide button based on Y movement direction
-                var button;
-                if (delta_y > 0) button = "down";
-                else             button = "up";
-
-                // Fire button down event
-                guac_touchpad.currentState[button] = true;
-                if (guac_touchpad.onmousedown)
-                    guac_touchpad.onmousedown(guac_touchpad.currentState);
-
-                // Fire button up event
-                guac_touchpad.currentState[button] = false;
-                if (guac_touchpad.onmouseup)
-                    guac_touchpad.onmouseup(guac_touchpad.currentState);
-
-                // Only update touch location after a scroll has been
-                // detected
-                last_touch_x = touch.clientX;
-                last_touch_y = touch.clientY;
-
-            }
-
-        }
-
-    }, false);
-
-};
-
-/**
- * Provides cross-browser absolute touch event translation for a given element.
- *
- * Touch events are translated into mouse events as if the touches occurred
- * on a touchscreen (tapping anywhere on the screen clicks at that point,
- * long-press to right-click).
- *
- * @constructor
- * @param {Element} element The Element to use to provide touch events.
- */
-Guacamole.Mouse.Touchscreen = function(element) {
-
-    /**
-     * Reference to this Guacamole.Mouse.Touchscreen.
-     * @private
-     */
-    var guac_touchscreen = this;
-
-    /**
-     * Whether a gesture is known to be in progress. If false, touch events
-     * will be ignored.
-     *
-     * @private
-     */
-    var gesture_in_progress = false;
-
-    /**
-     * The start X location of a gesture.
-     * @private
-     */
-    var gesture_start_x = null;
-
-    /**
-     * The start Y location of a gesture.
-     * @private
-     */
-    var gesture_start_y = null;
-
-    /**
-     * The timeout associated with the delayed, cancellable click release.
-     *
-     * @private
-     */
-    var click_release_timeout = null;
-
-    /**
-     * The timeout associated with long-press for right click.
-     *
-     * @private
-     */
-    var long_press_timeout = null;
-
-    /**
-     * The distance a two-finger touch must move per scrollwheel event, in
-     * pixels.
-     */
-    this.scrollThreshold = 20 * (window.devicePixelRatio || 1);
-
-    /**
-     * The maximum number of milliseconds to wait for a touch to end for the
-     * gesture to be considered a click.
-     */
-    this.clickTimingThreshold = 250;
-
-    /**
-     * The maximum number of pixels to allow a touch to move for the gesture to
-     * be considered a click.
-     */
-    this.clickMoveThreshold = 16 * (window.devicePixelRatio || 1);
-
-    /**
-     * The amount of time a press must be held for long press to be
-     * detected.
-     */
-    this.longPressThreshold = 500;
-
-    /**
-     * The current mouse state. The properties of this state are updated when
-     * mouse events fire. This state object is also passed in as a parameter to
-     * the handler of any mouse events.
-     *
-     * @type {Guacamole.Mouse.State}
-     */
-    this.currentState = new Guacamole.Mouse.State(
-        0, 0,
-        false, false, false, false, false
-    );
-
-    /**
-     * Fired whenever a mouse button is effectively pressed. This can happen
-     * as part of a "mousedown" gesture initiated by the user by pressing one
-     * finger over the touchscreen element, as part of a "scroll" gesture
-     * initiated by dragging two fingers up or down, etc.
-     *
-     * @event
-     * @param {Guacamole.Mouse.State} state The current mouse state.
-     */
-	this.onmousedown = null;
-
-    /**
-     * Fired whenever a mouse button is effectively released. This can happen
-     * as part of a "mouseup" gesture initiated by the user by removing the
-     * finger pressed against the touchscreen element, or as part of a "scroll"
-     * gesture initiated by dragging two fingers up or down, etc.
-     *
-     * @event
-     * @param {Guacamole.Mouse.State} state The current mouse state.
-     */
-	this.onmouseup = null;
-
-    /**
-     * Fired whenever the user moves the mouse by dragging their finger over
-     * the touchscreen element. Note that unlike Guacamole.Mouse.Touchpad,
-     * dragging a finger over the touchscreen element will always cause
-     * the mouse button to be effectively down, as if clicking-and-dragging.
-     *
-     * @event
-     * @param {Guacamole.Mouse.State} state The current mouse state.
-     */
-	this.onmousemove = null;
-
-    /**
-     * Presses the given mouse button, if it isn't already pressed. Valid
-     * button values are "left", "middle", "right", "up", and "down".
-     *
-     * @private
-     * @param {String} button The mouse button to press.
-     */
-    function press_button(button) {
-        if (!guac_touchscreen.currentState[button]) {
-            guac_touchscreen.currentState[button] = true;
-            if (guac_touchscreen.onmousedown)
-                guac_touchscreen.onmousedown(guac_touchscreen.currentState);
-        }
-    }
-
-    /**
-     * Releases the given mouse button, if it isn't already released. Valid
-     * button values are "left", "middle", "right", "up", and "down".
-     *
-     * @private
-     * @param {String} button The mouse button to release.
-     */
-    function release_button(button) {
-        if (guac_touchscreen.currentState[button]) {
-            guac_touchscreen.currentState[button] = false;
-            if (guac_touchscreen.onmouseup)
-                guac_touchscreen.onmouseup(guac_touchscreen.currentState);
-        }
-    }
-
-    /**
-     * Clicks (presses and releases) the given mouse button. Valid button
-     * values are "left", "middle", "right", "up", and "down".
-     *
-     * @private
-     * @param {String} button The mouse button to click.
-     */
-    function click_button(button) {
-        press_button(button);
-        release_button(button);
-    }
-
-    /**
-     * Moves the mouse to the given coordinates. These coordinates must be
-     * relative to the browser window, as they will be translated based on
-     * the touch event target's location within the browser window.
-     *
-     * @private
-     * @param {Number} x The X coordinate of the mouse pointer.
-     * @param {Number} y The Y coordinate of the mouse pointer.
-     */
-    function move_mouse(x, y) {
-        guac_touchscreen.currentState.fromClientPosition(element, x, y);
-        if (guac_touchscreen.onmousemove)
-            guac_touchscreen.onmousemove(guac_touchscreen.currentState);
-    }
-
-    /**
-     * Returns whether the given touch event exceeds the movement threshold for
-     * clicking, based on where the touch gesture began.
-     *
-     * @private
-     * @param {TouchEvent} e The touch event to check.
-     * @return {Boolean} true if the movement threshold is exceeded, false
-     *                   otherwise.
-     */
-    function finger_moved(e) {
-        var touch = e.touches[0] || e.changedTouches[0];
-        var delta_x = touch.clientX - gesture_start_x;
-        var delta_y = touch.clientY - gesture_start_y;
-        return Math.sqrt(delta_x*delta_x + delta_y*delta_y) >= guac_touchscreen.clickMoveThreshold;
-    }
-
-    /**
-     * Begins a new gesture at the location of the first touch in the given
-     * touch event.
-     * 
-     * @private
-     * @param {TouchEvent} e The touch event beginning this new gesture.
-     */
-    function begin_gesture(e) {
-        var touch = e.touches[0];
-        gesture_in_progress = true;
-        gesture_start_x = touch.clientX;
-        gesture_start_y = touch.clientY;
-    }
-
-    /**
-     * End the current gesture entirely. Wait for all touches to be done before
-     * resuming gesture detection.
-     * 
-     * @private
-     */
-    function end_gesture() {
-        window.clearTimeout(click_release_timeout);
-        window.clearTimeout(long_press_timeout);
-        gesture_in_progress = false;
-    }
-
-    element.addEventListener("touchend", function(e) {
-
-        // Do not handle if no gesture
-        if (!gesture_in_progress)
-            return;
-
-        // Ignore if more than one touch
-        if (e.touches.length !== 0 || e.changedTouches.length !== 1) {
-            end_gesture();
-            return;
-        }
-
-        // Long-press, if any, is over
-        window.clearTimeout(long_press_timeout);
-
-        // Always release mouse button if pressed
-        release_button("left");
-
-        // If finger hasn't moved enough to cancel the click
-        if (!finger_moved(e)) {
-
-            e.preventDefault();
-
-            // If not yet pressed, press and start delay release
-            if (!guac_touchscreen.currentState.left) {
-
-                var touch = e.changedTouches[0];
-                move_mouse(touch.clientX, touch.clientY);
-                press_button("left");
-
-                // Release button after a delay, if not canceled
-                click_release_timeout = window.setTimeout(function() {
-                    release_button("left");
-                    end_gesture();
-                }, guac_touchscreen.clickTimingThreshold);
-
-            }
-
-        } // end if finger not moved
-
-    }, false);
-
-    element.addEventListener("touchstart", function(e) {
-
-        // Ignore if more than one touch
-        if (e.touches.length !== 1) {
-            end_gesture();
-            return;
-        }
-
-        e.preventDefault();
-
-        // New touch begins a new gesture
-        begin_gesture(e);
-
-        // Keep button pressed if tap after left click
-        window.clearTimeout(click_release_timeout);
-
-        // Click right button if this turns into a long-press
-        long_press_timeout = window.setTimeout(function() {
-            var touch = e.touches[0];
-            move_mouse(touch.clientX, touch.clientY);
-            click_button("right");
-            end_gesture();
-        }, guac_touchscreen.longPressThreshold);
-
-    }, false);
-
-    element.addEventListener("touchmove", function(e) {
-
-        // Do not handle if no gesture
-        if (!gesture_in_progress)
-            return;
-
-        // Cancel long press if finger moved
-        if (finger_moved(e))
-            window.clearTimeout(long_press_timeout);
-
-        // Ignore if more than one touch
-        if (e.touches.length !== 1) {
-            end_gesture();
-            return;
-        }
-
-        // Update mouse position if dragging
-        if (guac_touchscreen.currentState.left) {
-
-            e.preventDefault();
-
-            // Update state
-            var touch = e.touches[0];
-            move_mouse(touch.clientX, touch.clientY);
-
-        }
-
-    }, false);
-
-};

http://git-wip-us.apache.org/repos/asf/guacamole-website/blob/f5235113/content/pub/tests/guac/modules/Namespace.js
----------------------------------------------------------------------
diff --git a/content/pub/tests/guac/modules/Namespace.js b/content/pub/tests/guac/modules/Namespace.js
deleted file mode 100644
index 2942a63..0000000
--- a/content/pub/tests/guac/modules/Namespace.js
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2015 Glyptodon LLC
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-/**
- * The namespace used by the Guacamole JavaScript API. Absolutely all classes
- * defined by the Guacamole JavaScript API will be within this namespace.
- *
- * @namespace
- */
-var Guacamole = Guacamole || {};

http://git-wip-us.apache.org/repos/asf/guacamole-website/blob/f5235113/content/pub/tests/guac/modules/Object.js
----------------------------------------------------------------------
diff --git a/content/pub/tests/guac/modules/Object.js b/content/pub/tests/guac/modules/Object.js
deleted file mode 100644
index 2db8bc0..0000000
--- a/content/pub/tests/guac/modules/Object.js
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright (C) 2013 Glyptodon LLC
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-var Guacamole = Guacamole || {};
-
-/**
- * An object used by the Guacamole client to house arbitrarily-many named
- * input and output streams.
- * 
- * @constructor
- * @param {Guacamole.Client} client
- *     The client owning this object.
- *
- * @param {Number} index
- *     The index of this object.
- */
-Guacamole.Object = function guacamoleObject(client, index) {
-
-    /**
-     * Reference to this Guacamole.Object.
-     *
-     * @private
-     * @type {Guacamole.Object}
-     */
-    var guacObject = this;
-
-    /**
-     * Map of stream name to corresponding queue of callbacks. The queue of
-     * callbacks is guaranteed to be in order of request.
-     *
-     * @private
-     * @type {Object.<String, Function[]>}
-     */
-    var bodyCallbacks = {};
-
-    /**
-     * Removes and returns the callback at the head of the callback queue for
-     * the stream having the given name. If no such callbacks exist, null is
-     * returned.
-     *
-     * @private
-     * @param {String} name
-     *     The name of the stream to retrieve a callback for.
-     *
-     * @returns {Function}
-     *     The next callback associated with the stream having the given name,
-     *     or null if no such callback exists.
-     */
-    var dequeueBodyCallback = function dequeueBodyCallback(name) {
-
-        // If no callbacks defined, simply return null
-        var callbacks = bodyCallbacks[name];
-        if (!callbacks)
-            return null;
-
-        // Otherwise, pull off first callback, deleting the queue if empty
-        var callback = callbacks.shift();
-        if (callbacks.length === 0)
-            delete bodyCallbacks[name];
-
-        // Return found callback
-        return callback;
-
-    };
-
-    /**
-     * Adds the given callback to the tail of the callback queue for the stream
-     * having the given name.
-     *
-     * @private
-     * @param {String} name
-     *     The name of the stream to associate with the given callback.
-     *
-     * @param {Function} callback
-     *     The callback to add to the queue of the stream with the given name.
-     */
-    var enqueueBodyCallback = function enqueueBodyCallback(name, callback) {
-
-        // Get callback queue by name, creating first if necessary
-        var callbacks = bodyCallbacks[name];
-        if (!callbacks) {
-            callbacks = [];
-            bodyCallbacks[name] = callbacks;
-        }
-
-        // Add callback to end of queue
-        callbacks.push(callback);
-
-    };
-
-    /**
-     * The index of this object.
-     *
-     * @type {Number}
-     */
-    this.index = index;
-
-    /**
-     * Called when this object receives the body of a requested input stream.
-     * By default, all objects will invoke the callbacks provided to their
-     * requestInputStream() functions based on the name of the stream
-     * requested. This behavior can be overridden by specifying a different
-     * handler here.
-     *
-     * @event
-     * @param {Guacamole.InputStream} inputStream
-     *     The input stream of the received body.
-     *
-     * @param {String} mimetype
-     *     The mimetype of the data being received.
-     *
-     * @param {String} name
-     *     The name of the stream whose body has been received.
-     */
-    this.onbody = function defaultBodyHandler(inputStream, mimetype, name) {
-
-        // Call queued callback for the received body, if any
-        var callback = dequeueBodyCallback(name);
-        if (callback)
-            callback(inputStream, mimetype);
-
-    };
-
-    /**
-     * Called when this object is being undefined. Once undefined, no further
-     * communication involving this object may occur.
-     * 
-     * @event
-     */
-    this.onundefine = null;
-
-    /**
-     * Requests read access to the input stream having the given name. If
-     * successful, a new input stream will be created.
-     *
-     * @param {String} name
-     *     The name of the input stream to request.
-     *
-     * @param {Function} [bodyCallback]
-     *     The callback to invoke when the body of the requested input stream
-     *     is received. This callback will be provided a Guacamole.InputStream
-     *     and its mimetype as its two only arguments. If the onbody handler of
-     *     this object is overridden, this callback will not be invoked.
-     */
-    this.requestInputStream = function requestInputStream(name, bodyCallback) {
-
-        // Queue body callback if provided
-        if (bodyCallback)
-            enqueueBodyCallback(name, bodyCallback);
-
-        // Send request for input stream
-        client.requestObjectInputStream(guacObject.index, name);
-
-    };
-
-    /**
-     * Creates a new output stream associated with this object and having the
-     * given mimetype and name. The legality of a mimetype and name is dictated
-     * by the object itself.
-     *
-     * @param {String} mimetype
-     *     The mimetype of the data which will be sent to the output stream.
-     *
-     * @param {String} name
-     *     The defined name of an output stream within this object.
-     *
-     * @returns {Guacamole.OutputStream}
-     *     An output stream which will write blobs to the named output stream
-     *     of this object.
-     */
-    this.createOutputStream = function createOutputStream(mimetype, name) {
-        return client.createObjectOutputStream(guacObject.index, mimetype, name);
-    };
-
-};
-
-/**
- * The reserved name denoting the root stream of any object. The contents of
- * the root stream MUST be a JSON map of stream name to mimetype.
- *
- * @constant
- * @type {String}
- */
-Guacamole.Object.ROOT_STREAM = '/';
-
-/**
- * The mimetype of a stream containing JSON which maps available stream names
- * to their corresponding mimetype. The root stream of a Guacamole.Object MUST
- * have this mimetype.
- *
- * @constant
- * @type {String}
- */
-Guacamole.Object.STREAM_INDEX_MIMETYPE = 'application/vnd.glyptodon.guacamole.stream-index+json';

http://git-wip-us.apache.org/repos/asf/guacamole-website/blob/f5235113/content/pub/tests/guac/modules/OnScreenKeyboard.js
----------------------------------------------------------------------
diff --git a/content/pub/tests/guac/modules/OnScreenKeyboard.js b/content/pub/tests/guac/modules/OnScreenKeyboard.js
deleted file mode 100644
index 81d5680..0000000
--- a/content/pub/tests/guac/modules/OnScreenKeyboard.js
+++ /dev/null
@@ -1,946 +0,0 @@
-/*
- * Copyright (C) 2015 Glyptodon LLC
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-var Guacamole = Guacamole || {};
-
-/**
- * Dynamic on-screen keyboard. Given the layout object for an on-screen
- * keyboard, this object will construct a clickable on-screen keyboard with its
- * own key events.
- *
- * @constructor
- * @param {Guacamole.OnScreenKeyboard.Layout} layout
- *     The layout of the on-screen keyboard to display.
- */
-Guacamole.OnScreenKeyboard = function(layout) {
-
-    /**
-     * Reference to this Guacamole.OnScreenKeyboard.
-     *
-     * @private
-     * @type {Guacamole.OnScreenKeyboard}
-     */
-    var osk = this;
-
-    /**
-     * Map of currently-set modifiers to the keysym associated with their
-     * original press. When the modifier is cleared, this keysym must be
-     * released.
-     *
-     * @private
-     * @type {Object.<String, Number>}
-     */
-    var modifierKeysyms = {};
-
-    /**
-     * Map of all key names to their current pressed states. If a key is not
-     * pressed, it may not be in this map at all, but all pressed keys will
-     * have a corresponding mapping to true.
-     *
-     * @private
-     * @type {Object.<String, Boolean>}
-     */
-    var pressed = {};
-
-    /**
-     * All scalable elements which are part of the on-screen keyboard. Each
-     * scalable element is carefully controlled to ensure the interface layout
-     * and sizing remains constant, even on browsers that would otherwise
-     * experience rounding error due to unit conversions.
-     *
-     * @private
-     * @type {ScaledElement[]}
-     */
-    var scaledElements = [];
-
-    /**
-     * Adds a CSS class to an element.
-     * 
-     * @private
-     * @function
-     * @param {Element} element
-     *     The element to add a class to.
-     *
-     * @param {String} classname
-     *     The name of the class to add.
-     */
-    var addClass = function addClass(element, classname) {
-
-        // If classList supported, use that
-        if (element.classList)
-            element.classList.add(classname);
-
-        // Otherwise, simply append the class
-        else
-            element.className += " " + classname;
-
-    };
-
-    /**
-     * Removes a CSS class from an element.
-     * 
-     * @private
-     * @function
-     * @param {Element} element
-     *     The element to remove a class from.
-     *
-     * @param {String} classname
-     *     The name of the class to remove.
-     */
-    var removeClass = function removeClass(element, classname) {
-
-        // If classList supported, use that
-        if (element.classList)
-            element.classList.remove(classname);
-
-        // Otherwise, manually filter out classes with given name
-        else {
-            element.className = element.className.replace(/([^ ]+)[ ]*/g,
-                function removeMatchingClasses(match, testClassname) {
-
-                    // If same class, remove
-                    if (testClassname === classname)
-                        return "";
-
-                    // Otherwise, allow
-                    return match;
-                    
-                }
-            );
-        }
-
-    };
-
-    /**
-     * Counter of mouse events to ignore. This decremented by mousemove, and
-     * while non-zero, mouse events will have no effect.
-     *
-     * @private
-     * @type {Number}
-     */
-    var ignoreMouse = 0;
-
-    /**
-     * Ignores all pending mouse events when touch events are the apparent
-     * source. Mouse events are ignored until at least touchMouseThreshold
-     * mouse events occur without corresponding touch events.
-     *
-     * @private
-     */
-    var ignorePendingMouseEvents = function ignorePendingMouseEvents() {
-        ignoreMouse = osk.touchMouseThreshold;
-    };
-
-    /**
-     * An element whose dimensions are maintained according to an arbitrary
-     * scale. The conversion factor for these arbitrary units to pixels is
-     * provided later via a call to scale().
-     *
-     * @private
-     * @constructor
-     * @param {Element} element
-     *     The element whose scale should be maintained.
-     *
-     * @param {Number} width
-     *     The width of the element, in arbitrary units, relative to other
-     *     ScaledElements.
-     *
-     * @param {Number} height
-     *     The height of the element, in arbitrary units, relative to other
-     *     ScaledElements.
-     *     
-     * @param {Boolean} [scaleFont=false]
-     *     Whether the line height and font size should be scaled as well.
-     */
-    var ScaledElement = function ScaledElement(element, width, height, scaleFont) {
-
-        /**
-         * The width of this ScaledElement, in arbitrary units, relative to
-         * other ScaledElements.
-         *
-         * @type {Number}
-         */
-         this.width = width;
-
-        /**
-         * The height of this ScaledElement, in arbitrary units, relative to
-         * other ScaledElements.
-         *
-         * @type {Number}
-         */
-         this.height = height;
- 
-        /**
-         * Resizes the associated element, updating its dimensions according to
-         * the given pixels per unit.
-         *
-         * @param {Number} pixels
-         *     The number of pixels to assign per arbitrary unit.
-         */
-        this.scale = function(pixels) {
-
-            // Scale element width/height
-            element.style.width  = (width  * pixels) + "px";
-            element.style.height = (height * pixels) + "px";
-
-            // Scale font, if requested
-            if (scaleFont) {
-                element.style.lineHeight = (height * pixels) + "px";
-                element.style.fontSize   = pixels + "px";
-            }
-
-        };
-
-    };
-
-    /**
-     * Returns whether all modifiers having the given names are currently
-     * active.
-     *
-     * @private
-     * @param {String[]} names
-     *     The names of all modifiers to test.
-     *
-     * @returns {Boolean}
-     *     true if all specified modifiers are pressed, false otherwise.
-     */
-    var modifiersPressed = function modifiersPressed(names) {
-
-        // If any required modifiers are not pressed, return false
-        for (var i=0; i < names.length; i++) {
-
-            // Test whether current modifier is pressed
-            var name = names[i];
-            if (!(name in modifierKeysyms))
-                return false;
-
-        }
-
-        // Otherwise, all required modifiers are pressed
-        return true;
-
-    };
-
-    /**
-     * Returns the single matching Key object associated with the key of the
-     * given name, where that Key object's requirements (such as pressed
-     * modifiers) are all currently satisfied.
-     *
-     * @private
-     * @param {String} keyName
-     *     The name of the key to retrieve.
-     *
-     * @returns {Guacamole.OnScreenKeyboard.Key}
-     *     The Key object associated with the given name, where that object's
-     *     requirements are all currently satisfied, or null if no such Key
-     *     can be found.
-     */
-    var getActiveKey = function getActiveKey(keyName) {
-
-        // Get key array for given name
-        var keys = osk.keys[keyName];
-        if (!keys)
-            return null;
-
-        // Find last matching key
-        for (var i = keys.length - 1; i >= 0; i--) {
-
-            // Get candidate key
-            var candidate = keys[i];
-
-            // If all required modifiers are pressed, use that key
-            if (modifiersPressed(candidate.requires))
-                return candidate;
-
-        }
-
-        // No valid key
-        return null;
-
-    };
-
-    /**
-     * Presses the key having the given name, updating the associated key
-     * element with the "guac-keyboard-pressed" CSS class. If the key is
-     * already pressed, this function has no effect.
-     *
-     * @private
-     * @param {String} keyName
-     *     The name of the key to press.
-     *
-     * @param {String} keyElement
-     *     The element associated with the given key.
-     */
-    var press = function press(keyName, keyElement) {
-
-        // Press key if not yet pressed
-        if (!pressed[keyName]) {
-
-            addClass(keyElement, "guac-keyboard-pressed");
-
-            // Get current key based on modifier state
-            var key = getActiveKey(keyName);
-
-            // Update modifier state
-            if (key.modifier) {
-
-                // Construct classname for modifier
-                var modifierClass = "guac-keyboard-modifier-" + getCSSName(key.modifier);
-
-                // Retrieve originally-pressed keysym, if modifier was already pressed
-                var originalKeysym = modifierKeysyms[key.modifier];
-
-                // Activate modifier if not pressed
-                if (!originalKeysym) {
-                    
-                    addClass(keyboard, modifierClass);
-                    modifierKeysyms[key.modifier] = key.keysym;
-                    
-                    // Send key event
-                    if (osk.onkeydown)
-                        osk.onkeydown(key.keysym);
-
-                }
-
-                // Deactivate if not pressed
-                else {
-
-                    removeClass(keyboard, modifierClass);
-                    delete modifierKeysyms[key.modifier];
-                    
-                    // Send key event
-                    if (osk.onkeyup)
-                        osk.onkeyup(originalKeysym);
-
-                }
-
-            }
-
-            // If not modifier, send key event now
-            else if (osk.onkeydown)
-                osk.onkeydown(key.keysym);
-
-            // Mark key as pressed
-            pressed[keyName] = true;
-
-        }
-
-    };
-
-    /**
-     * Releases the key having the given name, removing the
-     * "guac-keyboard-pressed" CSS class from the associated element. If the
-     * key is already released, this function has no effect.
-     *
-     * @private
-     * @param {String} keyName
-     *     The name of the key to release.
-     *
-     * @param {String} keyElement
-     *     The element associated with the given key.
-     */
-    var release = function release(keyName, keyElement) {
-
-        // Release key if currently pressed
-        if (pressed[keyName]) {
-
-            removeClass(keyElement, "guac-keyboard-pressed");
-
-            // Get current key based on modifier state
-            var key = getActiveKey(keyName);
-
-            // Send key event if not a modifier key
-            if (!key.modifier && osk.onkeyup)
-                osk.onkeyup(key.keysym);
-
-            // Mark key as released
-            pressed[keyName] = false;
-
-        }
-
-    };
-
-    // Create keyboard
-    var keyboard = document.createElement("div");
-    keyboard.className = "guac-keyboard";
-
-    // Do not allow selection or mouse movement to propagate/register.
-    keyboard.onselectstart =
-    keyboard.onmousemove   =
-    keyboard.onmouseup     =
-    keyboard.onmousedown   = function handleMouseEvents(e) {
-
-        // If ignoring events, decrement counter
-        if (ignoreMouse)
-            ignoreMouse--;
-
-        e.stopPropagation();
-        return false;
-
-    };
-
-    /**
-     * The number of mousemove events to require before re-enabling mouse
-     * event handling after receiving a touch event.
-     *
-     * @type {Number}
-     */
-    this.touchMouseThreshold = 3;
-
-    /**
-     * Fired whenever the user presses a key on this Guacamole.OnScreenKeyboard.
-     * 
-     * @event
-     * @param {Number} keysym The keysym of the key being pressed.
-     */
-    this.onkeydown = null;
-
-    /**
-     * Fired whenever the user releases a key on this Guacamole.OnScreenKeyboard.
-     * 
-     * @event
-     * @param {Number} keysym The keysym of the key being released.
-     */
-    this.onkeyup = null;
-
-    /**
-     * The keyboard layout provided at time of construction.
-     *
-     * @type {Guacamole.OnScreenKeyboard.Layout}
-     */
-    this.layout = new Guacamole.OnScreenKeyboard.Layout(layout);
-
-    /**
-     * Returns the element containing the entire on-screen keyboard.
-     * @returns {Element} The element containing the entire on-screen keyboard.
-     */
-    this.getElement = function() {
-        return keyboard;
-    };
-
-    /**
-     * Resizes all elements within this Guacamole.OnScreenKeyboard such that
-     * the width is close to but does not exceed the specified width. The
-     * height of the keyboard is determined based on the width.
-     * 
-     * @param {Number} width The width to resize this Guacamole.OnScreenKeyboard
-     *                       to, in pixels.
-     */
-    this.resize = function(width) {
-
-        // Get pixel size of a unit
-        var unit = Math.floor(width * 10 / osk.layout.width) / 10;
-
-        // Resize all scaled elements
-        for (var i=0; i<scaledElements.length; i++) {
-            var scaledElement = scaledElements[i];
-            scaledElement.scale(unit);
-        }
-
-    };
-
-    /**
-     * Given the name of a key and its corresponding definition, which may be
-     * an array of keys objects, a number (keysym), a string (key title), or a
-     * single key object, returns an array of key objects, deriving any missing
-     * properties as needed, and ensuring the key name is defined.
-     *
-     * @private
-     * @param {String} name
-     *     The name of the key being coerced into an array of Key objects.
-     *
-     * @param {Number|String|Guacamole.OnScreenKeyboard.Key|Guacamole.OnScreenKeyboard.Key[]} object
-     *     The object defining the behavior of the key having the given name,
-     *     which may be the title of the key (a string), the keysym (a number),
-     *     a single Key object, or an array of Key objects.
-     *     
-     * @returns {Guacamole.OnScreenKeyboard.Key[]}
-     *     An array of all keys associated with the given name.
-     */
-    var asKeyArray = function asKeyArray(name, object) {
-
-        // If already an array, just coerce into a true Key[] 
-        if (object instanceof Array) {
-            var keys = [];
-            for (var i=0; i < object.length; i++) {
-                keys.push(new Guacamole.OnScreenKeyboard.Key(object[i], name));
-            }
-            return keys;
-        }
-
-        // Derive key object from keysym if that's all we have
-        if (typeof object === 'number') {
-            return [new Guacamole.OnScreenKeyboard.Key({
-                name   : name,
-                keysym : object
-            })];
-        }
-
-        // Derive key object from title if that's all we have
-        if (typeof object === 'string') {
-            return [new Guacamole.OnScreenKeyboard.Key({
-                name  : name,
-                title : object
-            })];
-        }
-
-        // Otherwise, assume it's already a key object, just not an array
-        return [new Guacamole.OnScreenKeyboard.Key(object, name)];
-
-    };
-
-    /**
-     * Converts the rather forgiving key mapping allowed by
-     * Guacamole.OnScreenKeyboard.Layout into a rigorous mapping of key name
-     * to key definition, where the key definition is always an array of Key
-     * objects.
-     *
-     * @private
-     * @param {Object.<String, Number|String|Guacamole.OnScreenKeyboard.Key|Guacamole.OnScreenKeyboard.Key[]>} keys
-     *     A mapping of key name to key definition, where the key definition is
-     *     the title of the key (a string), the keysym (a number), a single
-     *     Key object, or an array of Key objects.
-     *
-     * @returns {Object.<String, Guacamole.OnScreenKeyboard.Key[]>}
-     *     A more-predictable mapping of key name to key definition, where the
-     *     key definition is always simply an array of Key objects.
-     */
-    var getKeys = function getKeys(keys) {
-
-        var keyArrays = {};
-
-        // Coerce all keys into individual key arrays
-        for (var name in layout.keys) {
-            keyArrays[name] = asKeyArray(name, keys[name]);
-        }
-
-        return keyArrays;
-
-    };
-
-    /**
-     * Map of all key names to their corresponding set of keys. Each key name
-     * may correspond to multiple keys due to the effect of modifiers.
-     *
-     * @type {Object.<String, Guacamole.OnScreenKeyboard.Key[]>}
-     */
-    this.keys = getKeys(layout.keys);
-
-    /**
-     * Given an arbitrary string representing the name of some component of the
-     * on-screen keyboard, returns a string formatted for use as a CSS class
-     * name. The result will be lowercase. Word boundaries previously denoted
-     * by CamelCase will be replaced by individual hyphens, as will all
-     * contiguous non-alphanumeric characters.
-     *
-     * @private
-     * @param {String} name
-     *     An arbitrary string representing the name of some component of the
-     *     on-screen keyboard.
-     *
-     * @returns {String}
-     *     A string formatted for use as a CSS class name.
-     */
-    var getCSSName = function getCSSName(name) {
-
-        // Convert name from possibly-CamelCase to hyphenated lowercase
-        var cssName = name
-               .replace(/([a-z])([A-Z])/g, '$1-$2')
-               .replace(/[^A-Za-z0-9]+/g, '-')
-               .toLowerCase();
-
-        return cssName;
-
-    };
-
-    /**
-     * Appends DOM elements to the given element as dictated by the layout
-     * structure object provided. If a name is provided, an additional CSS
-     * class, prepended with "guac-keyboard-", will be added to the top-level
-     * element.
-     * 
-     * If the layout structure object is an array, all elements within that
-     * array will be recursively appended as children of a group, and the
-     * top-level element will be given the CSS class "guac-keyboard-group".
-     *
-     * If the layout structure object is an object, all properties within that
-     * object will be recursively appended as children of a group, and the
-     * top-level element will be given the CSS class "guac-keyboard-group". The
-     * name of each property will be applied as the name of each child object
-     * for the sake of CSS. Each property will be added in sorted order.
-     *
-     * If the layout structure object is a string, the key having that name
-     * will be appended. The key will be given the CSS class
-     * "guac-keyboard-key" and "guac-keyboard-key-NAME", where NAME is the name
-     * of the key. If the name of the key is a single character, this will
-     * first be transformed into the C-style hexadecimal literal for the
-     * Unicode codepoint of that character. For example, the key "A" would
-     * become "guac-keyboard-key-0x41".
-     * 
-     * If the layout structure object is a number, a gap of that size will be
-     * inserted. The gap will be given the CSS class "guac-keyboard-gap", and
-     * will be scaled according to the same size units as each key.
-     *
-     * @private
-     * @param {Element} element
-     *     The element to append elements to.
-     *
-     * @param {Array|Object|String|Number} object
-     *     The layout structure object to use when constructing the elements to
-     *     append.
-     *
-     * @param {String} [name]
-     *     The name of the top-level element being appended, if any.
-     */
-    var appendElements = function appendElements(element, object, name) {
-
-        var i;
-
-        // Create div which will become the group or key
-        var div = document.createElement('div');
-
-        // Add class based on name, if name given
-        if (name)
-            addClass(div, 'guac-keyboard-' + getCSSName(name));
-
-        // If an array, append each element
-        if (object instanceof Array) {
-
-            // Add group class
-            addClass(div, 'guac-keyboard-group');
-
-            // Append all elements of array
-            for (i=0; i < object.length; i++)
-                appendElements(div, object[i]);
-
-        }
-
-        // If an object, append each property value
-        else if (object instanceof Object) {
-
-            // Add group class
-            addClass(div, 'guac-keyboard-group');
-
-            // Append all children, sorted by name
-            var names = Object.keys(object).sort();
-            for (i=0; i < names.length; i++) {
-                var name = names[i];
-                appendElements(div, object[name], name);
-            }
-
-        }
-
-        // If a number, create as a gap 
-        else if (typeof object === 'number') {
-
-            // Add gap class
-            addClass(div, 'guac-keyboard-gap');
-
-            // Maintain scale
-            scaledElements.push(new ScaledElement(div, object, object));
-
-        }
-
-        // If a string, create as a key
-        else if (typeof object === 'string') {
-
-            // If key name is only one character, use codepoint for name
-            var keyName = object;
-            if (keyName.length === 1)
-                keyName = '0x' + keyName.charCodeAt(0).toString(16);
-
-            // Add key container class
-            addClass(div, 'guac-keyboard-key-container');
-
-            // Create key element which will contain all possible caps
-            var keyElement = document.createElement('div');
-            keyElement.className = 'guac-keyboard-key '
-                                 + 'guac-keyboard-key-' + getCSSName(keyName);
-
-            // Add all associated keys as caps within DOM
-            var keys = osk.keys[object];
-            if (keys) {
-                for (i=0; i < keys.length; i++) {
-
-                    // Get current key
-                    var key = keys[i];
-
-                    // Create cap element for key
-                    var capElement = document.createElement('div');
-                    capElement.className   = 'guac-keyboard-cap';
-                    capElement.textContent = key.title;
-
-                    // Add classes for any requirements
-                    for (var j=0; j < key.requires.length; j++) {
-                        var requirement = key.requires[j];
-                        addClass(capElement, 'guac-keyboard-requires-' + getCSSName(requirement));
-                        addClass(keyElement, 'guac-keyboard-uses-'     + getCSSName(requirement));
-                    }
-
-                    // Add cap to key within DOM
-                    keyElement.appendChild(capElement);
-
-                }
-            }
-
-            // Add key to DOM, maintain scale
-            div.appendChild(keyElement);
-            scaledElements.push(new ScaledElement(div, osk.layout.keyWidths[object] || 1, 1, true));
-
-            /**
-             * Handles a touch event which results in the pressing of an OSK
-             * key. Touch events will result in mouse events being ignored for
-             * touchMouseThreshold events.
-             *
-             * @private
-             * @param {TouchEvent} e
-             *     The touch event being handled.
-             */
-            var touchPress = function touchPress(e) {
-                e.preventDefault();
-                ignoreMouse = osk.touchMouseThreshold;
-                press(object, keyElement);
-            };
-
-            /**
-             * Handles a touch event which results in the release of an OSK
-             * key. Touch events will result in mouse events being ignored for
-             * touchMouseThreshold events.
-             *
-             * @private
-             * @param {TouchEvent} e
-             *     The touch event being handled.
-             */
-            var touchRelease = function touchRelease(e) {
-                e.preventDefault();
-                ignoreMouse = osk.touchMouseThreshold;
-                release(object, keyElement);
-            };
-
-            /**
-             * Handles a mouse event which results in the pressing of an OSK
-             * key. If mouse events are currently being ignored, this handler
-             * does nothing.
-             *
-             * @private
-             * @param {MouseEvent} e
-             *     The touch event being handled.
-             */
-            var mousePress = function mousePress(e) {
-                e.preventDefault();
-                if (ignoreMouse === 0)
-                    press(object, keyElement);
-            };
-
-            /**
-             * Handles a mouse event which results in the release of an OSK
-             * key. If mouse events are currently being ignored, this handler
-             * does nothing.
-             *
-             * @private
-             * @param {MouseEvent} e
-             *     The touch event being handled.
-             */
-            var mouseRelease = function mouseRelease(e) {
-                e.preventDefault();
-                if (ignoreMouse === 0)
-                    release(object, keyElement);
-            };
-
-            // Handle touch events on key
-            keyElement.addEventListener("touchstart", touchPress,   true);
-            keyElement.addEventListener("touchend",   touchRelease, true);
-
-            // Handle mouse events on key
-            keyElement.addEventListener("mousedown", mousePress,   true);
-            keyElement.addEventListener("mouseup",   mouseRelease, true);
-            keyElement.addEventListener("mouseout",  mouseRelease, true);
-
-        } // end if object is key name
-
-        // Add newly-created group/key
-        element.appendChild(div);
-
-    };
-
-    // Create keyboard layout in DOM
-    appendElements(keyboard, layout.layout);
-
-};
-
-/**
- * Represents an entire on-screen keyboard layout, including all available
- * keys, their behaviors, and their relative position and sizing.
- *
- * @constructor
- * @param {Guacamole.OnScreenKeyboard.Layout|Object} template
- *     The object whose identically-named properties will be used to initialize
- *     the properties of this layout.
- */
-Guacamole.OnScreenKeyboard.Layout = function(template) {
-
-    /**
-     * The language of keyboard layout, such as "en_US". This property is for
-     * informational purposes only, but it is recommend to conform to the
-     * [language code]_[country code] format.
-     *
-     * @type {String}
-     */
-    this.language = template.language;
-
-    /**
-     * The type of keyboard layout, such as "qwerty". This property is for
-     * informational purposes only, and does not conform to any standard.
-     *
-     * @type {String}
-     */
-    this.type = template.type;
-
-    /**
-     * Map of key name to corresponding keysym, title, or key object. If only
-     * the keysym or title is provided, the key object will be created
-     * implicitly. In all cases, the name property of the key object will be
-     * taken from the name given in the mapping.
-     *
-     * @type {Object.<String, Number|String|Guacamole.OnScreenKeyboard.Key|Guacamole.OnScreenKeyboard.Key[]>}
-     */
-    this.keys = template.keys;
-
-    /**
-     * Arbitrarily nested, arbitrarily grouped key names. The contents of the
-     * layout will be traversed to produce an identically-nested grouping of
-     * keys in the DOM tree. All strings will be transformed into their
-     * corresponding sets of keys, while all objects and arrays will be
-     * transformed into named groups and anonymous groups respectively. Any
-     * numbers present will be transformed into gaps of that size, scaled
-     * according to the same units as each key.
-     *
-     * @type {Object}
-     */
-    this.layout = template.layout;
-
-    /**
-     * The width of the entire keyboard, in arbitrary units. The width of each
-     * key is relative to this width, as both width values are assumed to be in
-     * the same units. The conversion factor between these units and pixels is
-     * derived later via a call to resize() on the Guacamole.OnScreenKeyboard.
-     *
-     * @type {Number}
-     */
-    this.width = template.width;
-
-    /**
-     * The width of each key, in arbitrary units, relative to other keys in
-     * this layout. The true pixel size of each key will be determined by the
-     * overall size of the keyboard. If not defined here, the width of each
-     * key will default to 1.
-     *
-     * @type {Object.<String, Number>}
-     */
-    this.keyWidths = template.keyWidths || {};
-
-};
-
-/**
- * Represents a single key, or a single possible behavior of a key. Each key
- * on the on-screen keyboard must have at least one associated
- * Guacamole.OnScreenKeyboard.Key, whether that key is explicitly defined or
- * implied, and may have multiple Guacamole.OnScreenKeyboard.Key if behavior
- * depends on modifier states.
- *
- * @constructor
- * @param {Guacamole.OnScreenKeyboard.Key|Object} template
- *     The object whose identically-named properties will be used to initialize
- *     the properties of this key.
- *     
- * @param {String} [name]
- *     The name to use instead of any name provided within the template, if
- *     any. If omitted, the name within the template will be used, assuming the
- *     template contains a name.
- */
-Guacamole.OnScreenKeyboard.Key = function(template, name) {
-
-    /**
-     * The unique name identifying this key within the keyboard layout.
-     *
-     * @type {String}
-     */
-    this.name = name || template.name;
-
-    /**
-     * The human-readable title that will be displayed to the user within the
-     * key. If not provided, this will be derived from the key name.
-     *
-     * @type {String}
-     */
-    this.title = template.title || this.name;
-
-    /**
-     * The keysym to be pressed/released when this key is pressed/released. If
-     * not provided, this will be derived from the title if the title is a
-     * single character.
-     *
-     * @type {Number}
-     */
-    this.keysym = template.keysym || (function deriveKeysym(title) {
-
-        // Do not derive keysym if title is not exactly one character
-        if (!title || title.length !== 1)
-            return null;
-
-        // For characters between U+0000 and U+00FF, the keysym is the codepoint
-        var charCode = title.charCodeAt(0);
-        if (charCode >= 0x0000 && charCode <= 0x00FF)
-            return charCode;
-
-        // For characters between U+0100 and U+10FFFF, the keysym is the codepoint or'd with 0x01000000
-        if (charCode >= 0x0100 && charCode <= 0x10FFFF)
-            return 0x01000000 | charCode;
-
-        // Unable to derive keysym
-        return null;
-
-    })(this.title);
-
-    /**
-     * The name of the modifier set when the key is pressed and cleared when
-     * this key is released, if any. The names of modifiers are distinct from
-     * the names of keys; both the "RightShift" and "LeftShift" keys may set
-     * the "shift" modifier, for example. By default, the key will affect no
-     * modifiers.
-     * 
-     * @type {String}
-     */
-    this.modifier = template.modifier;
-
-    /**
-     * An array containing the names of each modifier required for this key to
-     * have an effect. For example, a lowercase letter may require nothing,
-     * while an uppercase letter would require "shift", assuming the Shift key
-     * is named "shift" within the layout. By default, the key will require
-     * no modifiers.
-     *
-     * @type {String[]}
-     */
-    this.requires = template.requires || [];
-
-};

http://git-wip-us.apache.org/repos/asf/guacamole-website/blob/f5235113/content/pub/tests/guac/modules/OutputStream.js
----------------------------------------------------------------------
diff --git a/content/pub/tests/guac/modules/OutputStream.js b/content/pub/tests/guac/modules/OutputStream.js
deleted file mode 100644
index d4fdc58..0000000
--- a/content/pub/tests/guac/modules/OutputStream.js
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2013 Glyptodon LLC
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-var Guacamole = Guacamole || {};
-
-/**
- * Abstract stream which can receive data.
- * 
- * @constructor
- * @param {Guacamole.Client} client The client owning this stream.
- * @param {Number} index The index of this stream.
- */
-Guacamole.OutputStream = function(client, index) {
-
-    /**
-     * Reference to this stream.
-     * @private
-     */
-    var guac_stream = this;
-
-    /**
-     * The index of this stream.
-     * @type {Number}
-     */
-    this.index = index;
-
-    /**
-     * Fired whenever an acknowledgement is received from the server, indicating
-     * that a stream operation has completed, or an error has occurred.
-     * 
-     * @event
-     * @param {Guacamole.Status} status The status of the operation.
-     */
-    this.onack = null;
-
-    /**
-     * Writes the given base64-encoded data to this stream as a blob.
-     * 
-     * @param {String} data The base64-encoded data to send.
-     */
-    this.sendBlob = function(data) {
-        client.sendBlob(guac_stream.index, data);
-    };
-
-    /**
-     * Closes this stream.
-     */
-    this.sendEnd = function() {
-        client.endStream(guac_stream.index);
-    };
-
-};

http://git-wip-us.apache.org/repos/asf/guacamole-website/blob/f5235113/content/pub/tests/guac/modules/Parser.js
----------------------------------------------------------------------
diff --git a/content/pub/tests/guac/modules/Parser.js b/content/pub/tests/guac/modules/Parser.js
deleted file mode 100644
index ff03046..0000000
--- a/content/pub/tests/guac/modules/Parser.js
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (C) 2013 Glyptodon LLC
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-var Guacamole = Guacamole || {};
-
-/**
- * Simple Guacamole protocol parser that invokes an oninstruction event when
- * full instructions are available from data received via receive().
- * 
- * @constructor
- */
-Guacamole.Parser = function() {
-
-    /**
-     * Reference to this parser.
-     * @private
-     */
-    var parser = this;
-
-    /**
-     * Current buffer of received data. This buffer grows until a full
-     * element is available. After a full element is available, that element
-     * is flushed into the element buffer.
-     * 
-     * @private
-     */
-    var buffer = "";
-
-    /**
-     * Buffer of all received, complete elements. After an entire instruction
-     * is read, this buffer is flushed, and a new instruction begins.
-     * 
-     * @private
-     */
-    var element_buffer = [];
-
-    // The location of the last element's terminator
-    var element_end = -1;
-
-    // Where to start the next length search or the next element
-    var start_index = 0;
-
-    /**
-     * Appends the given instruction data packet to the internal buffer of
-     * this Guacamole.Parser, executing all completed instructions at
-     * the beginning of this buffer, if any.
-     *
-     * @param {String} packet The instruction data to receive.
-     */
-    this.receive = function(packet) {
-
-        // Truncate buffer as necessary
-        if (start_index > 4096 && element_end >= start_index) {
-
-            buffer = buffer.substring(start_index);
-
-            // Reset parse relative to truncation
-            element_end -= start_index;
-            start_index = 0;
-
-        }
-
-        // Append data to buffer
-        buffer += packet;
-
-        // While search is within currently received data
-        while (element_end < buffer.length) {
-
-            // If we are waiting for element data
-            if (element_end >= start_index) {
-
-                // We now have enough data for the element. Parse.
-                var element = buffer.substring(start_index, element_end);
-                var terminator = buffer.substring(element_end, element_end+1);
-
-                // Add element to array
-                element_buffer.push(element);
-
-                // If last element, handle instruction
-                if (terminator == ";") {
-
-                    // Get opcode
-                    var opcode = element_buffer.shift();
-
-                    // Call instruction handler.
-                    if (parser.oninstruction != null)
-                        parser.oninstruction(opcode, element_buffer);
-
-                    // Clear elements
-                    element_buffer.length = 0;
-
-                }
-                else if (terminator != ',')
-                    throw new Error("Illegal terminator.");
-
-                // Start searching for length at character after
-                // element terminator
-                start_index = element_end + 1;
-
-            }
-
-            // Search for end of length
-            var length_end = buffer.indexOf(".", start_index);
-            if (length_end != -1) {
-
-                // Parse length
-                var length = parseInt(buffer.substring(element_end+1, length_end));
-                if (length == NaN)
-                    throw new Error("Non-numeric character in element length.");
-
-                // Calculate start of element
-                start_index = length_end + 1;
-
-                // Calculate location of element terminator
-                element_end = start_index + length;
-
-            }
-            
-            // If no period yet, continue search when more data
-            // is received
-            else {
-                start_index = buffer.length;
-                break;
-            }
-
-        } // end parse loop
-
-    };
-
-    /**
-     * Fired once for every complete Guacamole instruction received, in order.
-     * 
-     * @event
-     * @param {String} opcode The Guacamole instruction opcode.
-     * @param {Array} parameters The parameters provided for the instruction,
-     *                           if any.
-     */
-    this.oninstruction = null;
-
-};