<commit_before>
// UI Definition
var GuacamoleUI = {

    "viewport"    : document.getElementById("viewportClone"),
    "display"     : document.getElementById("display"),
    "menu"        : document.getElementById("menu"),
    "menuControl" : document.getElementById("menuControl"),
    "touchMenu"   : document.getElementById("touchMenu"),
    "logo"        : document.getElementById("status-logo"),

    "buttons": {

        "showClipboard": document.getElementById("showClipboard"),
        "showKeyboard" : document.getElementById("showKeyboard"),
        "ctrlAltDelete": document.getElementById("ctrlAltDelete"),
        "reconnect"    : document.getElementById("reconnect"),
        "logout"       : document.getElementById("logout")

    },

    "containers": {
        "state"    : document.getElementById("statusDialog"),
        "clipboard": document.getElementById("clipboardDiv"),
        "keyboard" : document.getElementById("keyboardContainer")
    },

    "state"     : document.getElementById("statusText"),
    "clipboard" : document.getElementById("clipboard")

};

// Constant UI initialization and behavior
(function() {

    var menu_shaded = false;

    var shade_interval = null;
    var show_interval = null;

    // Cache error image (might not be available when error occurs)
    var guacErrorImage = new Image();
    guacErrorImage.src = "images/noguacamole-logo-24.png";

    // Function for adding a class to an element
    var addClass;

    // Function for removing a class from an element
    var removeClass;

    // If Node.classList is supported, implement addClass/removeClass using that
    if (Node.classList) {

        addClass = function(element, classname) {
            element.classList.add(classname);
        };

        removeClass = function(element, classname) {
            element.classList.remove(classname);
        };

    }

    // Otherwise, implement own
    else {

        addClass = function(element, classname) {

            // Simply add new class
            element.className += " " + classname;

        };

        removeClass = function(element, classname) {

            // Filter out classes with given name
            element.className = element.className.replace(/([^ ]+)[ ]*/g,
                function(match, testClassname, spaces, offset, string) {

                    // If same class, remove
                    if (testClassname == classname)
                        return "";

                    // Otherwise, allow
                    return match;

                }
            );

        };

    }

    GuacamoleUI.hideStatus = function() {
        removeClass(document.body, "guac-error");
        GuacamoleUI.containers.state.style.visibility = "hidden";
    };

    GuacamoleUI.showStatus = function(text) {
        removeClass(document.body, "guac-error");
        GuacamoleUI.containers.state.style.visibility = "visible";
        GuacamoleUI.state.textContent = text;
    };

    GuacamoleUI.showError = function(error) {
        addClass(document.body, "guac-error");
        GuacamoleUI.state.textContent = error;
    };

    GuacamoleUI.shadeMenu = function() {

        if (!menu_shaded) {

            var step = Math.floor(GuacamoleUI.menu.offsetHeight / 10) + 1;
            var offset = 0;
            menu_shaded = true;

            window.clearInterval(show_interval);
            shade_interval = window.setInterval(function() {

                offset -= step;
                GuacamoleUI.menu.style.top = offset + "px";

                if (offset <= -GuacamoleUI.menu.offsetHeight) {
                    window.clearInterval(shade_interval);
                    GuacamoleUI.menu.style.visiblity = "hidden";
                }

            }, 30);
        }

    };

    GuacamoleUI.showMenu = function() {

        if (menu_shaded) {

            var step = Math.floor(GuacamoleUI.menu.offsetHeight / 5) + 1;
            var offset = -GuacamoleUI.menu.offsetHeight;
            menu_shaded = false;
            GuacamoleUI.menu.style.visiblity = "";

            window.clearInterval(shade_interval);
            show_interval = window.setInterval(function() {

                offset += step;

                if (offset >= 0) {
                    offset = 0;
                    window.clearInterval(show_interval);
                }

                GuacamoleUI.menu.style.top = offset + "px";

            }, 30);
        }

    };

    // Show/Hide clipboard
    GuacamoleUI.buttons.showClipboard.onclick = function() {

        var displayed = GuacamoleUI.containers.clipboard.style.display;
        if (displayed != "block") {
            GuacamoleUI.containers.clipboard.style.display = "block";
            GuacamoleUI.buttons.showClipboard.innerHTML = "Hide Clipboard";
        }
        else {
            GuacamoleUI.containers.clipboard.style.display = "none";
            GuacamoleUI.buttons.showClipboard.innerHTML = "Show Clipboard";
            GuacamoleUI.clipboard.onchange();
        }

    };

    // Show/Hide keyboard
    var keyboardResizeInterval = null;
    GuacamoleUI.buttons.showKeyboard.onclick = function() {

        var displayed = GuacamoleUI.containers.keyboard.style.display;
        if (displayed != "block") {
            GuacamoleUI.containers.keyboard.style.display = "block";
            GuacamoleUI.buttons.showKeyboard.textContent = "Hide Keyboard";

            // Automatically update size
            window.onresize = updateKeyboardSize;
            keyboardResizeInterval = window.setInterval(updateKeyboardSize, 30);

            updateKeyboardSize();
        }
        else {
            GuacamoleUI.containers.keyboard.style.display = "none";
            GuacamoleUI.buttons.showKeyboard.textContent = "Show Keyboard";

            window.onresize = null;
            window.clearInterval(keyboardResizeInterval);
        }

    };

    // Logout
    GuacamoleUI.buttons.logout.onclick = function() {
        window.location.href = "logout";
    };

    // Timeouts for detecting if users wants menu to open or close
    var detectMenuOpenTimeout = null;
    var detectMenuCloseTimeout = null;

    // Clear detection timeouts
    GuacamoleUI.resetMenuDetect = function() {

        if (detectMenuOpenTimeout != null) {
            window.clearTimeout(detectMenuOpenTimeout);
            detectMenuOpenTimeout = null;
        }

        if (detectMenuCloseTimeout != null) {
            window.clearTimeout(detectMenuCloseTimeout);
            detectMenuCloseTimeout = null;
        }

    };

    // Initiate detection of menu open action. If not canceled through some
    // user event, menu will open.
    GuacamoleUI.startMenuOpenDetect = function() {

        if (!detectMenuOpenTimeout) {

            // Clear detection state
            GuacamoleUI.resetMenuDetect();

            // Wait and then show menu
            detectMenuOpenTimeout = window.setTimeout(function() {
                GuacamoleUI.showMenu();
                detectMenuOpenTimeout = null;
            }, 325);

        }

    };

    // Initiate detection of menu close action. If not canceled through some
    // user event, menu will close.
    GuacamoleUI.startMenuCloseDetect = function() {

        if (!detectMenuCloseTimeout) {

            // Clear detection state
            GuacamoleUI.resetMenuDetect();

            // Wait and then shade menu
            detectMenuCloseTimeout = window.setTimeout(function() {
                GuacamoleUI.shadeMenu();
                detectMenuCloseTimeout = null;
            }, 500);

        }

    };

    // Show menu if mouseover any part of menu
    GuacamoleUI.menu.addEventListener('mouseover', GuacamoleUI.showMenu, true);

    // Stop detecting menu state change intents if mouse is over menu
    GuacamoleUI.menu.addEventListener('mouseover', GuacamoleUI.resetMenuDetect, true);

    // When mouse hovers over top of screen, start detection of intent to open menu
    GuacamoleUI.menuControl.addEventListener('mousemove', GuacamoleUI.startMenuOpenDetect, true);

    var menuShowLongPressTimeout = null;

    GuacamoleUI.startLongPressDetect = function() {

        if (!menuShowLongPressTimeout) {

            menuShowLongPressTimeout = window.setTimeout(function() {

                menuShowLongPressTimeout = null;
                GuacamoleUI.showMenu();

            }, 800);

        }
    };

    GuacamoleUI.stopLongPressDetect = function() {
        window.clearTimeout(menuShowLongPressTimeout);
        menuShowLongPressTimeout = null;
    };

    // Detect long-press at bottom of screen
    document.body.addEventListener('touchstart', GuacamoleUI.startLongPressDetect, true);

    // Reconnect button
    GuacamoleUI.buttons.reconnect.onclick = function() {
        window.location.reload();
    };

    // On-screen keyboard
    GuacamoleUI.keyboard = new Guacamole.OnScreenKeyboard("layouts/en-us-qwerty-mobile.xml");
    GuacamoleUI.containers.keyboard.appendChild(GuacamoleUI.keyboard.getElement());

    // Function for automatically updating keyboard size
    var lastKeyboardWidth;
    function updateKeyboardSize() {
        var currentSize = GuacamoleUI.keyboard.getElement().offsetWidth;
        if (lastKeyboardWidth != currentSize) {
            GuacamoleUI.keyboard.resize(currentSize);
            lastKeyboardWidth = currentSize;
        }
    };

})();

// Tie UI events / behavior to a specific Guacamole client
GuacamoleUI.attach = function(guac) {

    var guac_display = guac.getDisplay();

    // When mouse enters display, start detection of intent to close menu
    guac_display.addEventListener('mouseover', GuacamoleUI.startMenuCloseDetect, true);

    guac_display.onclick = function(e) {
        e.preventDefault();
        return false;
    };

    // Mouse
    var mouse = new Guacamole.Mouse(guac_display);
    mouse.onmousedown = mouse.onmouseup = mouse.onmousemove =
        function(mouseState) {

            // Determine mouse position within view
            var mouse_view_x = mouseState.x + guac_display.offsetLeft - window.pageXOffset;
            var mouse_view_y = mouseState.y + guac_display.offsetTop  - window.pageYOffset;

            // Determine viewport dimensioins
            var view_width  = GuacamoleUI.viewport.offsetWidth;
            var view_height = GuacamoleUI.viewport.offsetHeight;

            // Determine scroll amounts based on mouse position relative to document

            var scroll_amount_x;
            if (mouse_view_x > view_width)
                scroll_amount_x = mouse_view_x - view_width;
            else if (mouse_view_x < 0)
                scroll_amount_x = mouse_view_x;
            else
                scroll_amount_x = 0;

            var scroll_amount_y;
            if (mouse_view_y > view_height)
                scroll_amount_y = mouse_view_y - view_height;
            else if (mouse_view_y < 0)
                scroll_amount_y = mouse_view_y;
            else
                scroll_amount_y = 0;

            // Scroll (if necessary) to keep mouse on screen.
            window.scrollBy(scroll_amount_x, scroll_amount_y);

            // Hide menu on movement
            GuacamoleUI.startMenuCloseDetect();

            // Stop detecting long presses if mouse is being used
            GuacamoleUI.stopLongPressDetect();

            // Send mouse event
            guac.sendMouseState(mouseState);

        };

    // Keyboard
    var keyboard = new Guacamole.Keyboard(document);

    function disableKeyboard() {
        keyboard.onkeydown = null;
        keyboard.onkeyup = null;
    }

    function enableKeyboard() {
        keyboard.onkeydown =
            function (keysym) {
                guac.sendKeyEvent(1, keysym);
            };

        keyboard.onkeyup =
            function (keysym) {
                guac.sendKeyEvent(0, keysym);
            };
    }

    // Enable keyboard by default
    enableKeyboard();

    // Handle client state change
    guac.onstatechange = function(clientState) {
        switch (clientState) {

            // Idle
            case 0:
                GuacamoleUI.showStatus("Idle.");
                break;

            // Connecting
            case 1:
                GuacamoleUI.shadeMenu();
                GuacamoleUI.showStatus("Connecting...");
                break;

            // Connected + waiting
            case 2:
                GuacamoleUI.showStatus("Connected, waiting for first update...");
                break;

            // Connected
            case 3:

                GuacamoleUI.hideStatus();
                GuacamoleUI.display.className =
                    GuacamoleUI.display.className.replace(/guac-loading/, '');

                GuacamoleUI.menu.className = "connected";
                break;

            // Disconnecting
            case 4:
                GuacamoleUI.showStatus("Disconnecting...");
                break;

            // Disconnected
            case 5:
                GuacamoleUI.showStatus("Disconnected.");
                break;

            // Unknown status code
            default:
                GuacamoleUI.showStatus("[UNKNOWN STATUS]");

        }
    };

    // Name instruction handler
    guac.onname = function(name) {
        document.title = name;
    };

    // Error handler
    guac.onerror = function(error) {

        // Disconnect, if connected
        guac.disconnect();

        // Display error message
        GuacamoleUI.showError(error);

    };

    // Disconnect on close
    window.onunload = function() {
        guac.disconnect();
    };

    // Handle clipboard events
    GuacamoleUI.clipboard.onchange = function() {

        var text = GuacamoleUI.clipboard.value;
        guac.setClipboard(text);

    };

    // Ignore keypresses when clipboard is focused
    GuacamoleUI.clipboard.onfocus = function() {
        disableKeyboard();
    };

    // Capture keypresses when clipboard is not focused
    GuacamoleUI.clipboard.onblur = function() {
        enableKeyboard();
    };

    // Server copy handler
    guac.onclipboard = function(data) {
        GuacamoleUI.clipboard.value = data;
    };

    GuacamoleUI.keyboard.onkeydown = function(keysym) {
        guac.sendKeyEvent(1, keysym);
    };

    GuacamoleUI.keyboard.onkeyup = function(keysym) {
        guac.sendKeyEvent(0, keysym);
    };

    // Send Ctrl-Alt-Delete
    GuacamoleUI.buttons.ctrlAltDelete.onclick = function() {

        var KEYSYM_CTRL   = 0xFFE3;
        var KEYSYM_ALT    = 0xFFE9;
        var KEYSYM_DELETE = 0xFFFF;

        guac.sendKeyEvent(1, KEYSYM_CTRL);
        guac.sendKeyEvent(1, KEYSYM_ALT);
        guac.sendKeyEvent(1, KEYSYM_DELETE);
        guac.sendKeyEvent(0, KEYSYM_DELETE);
        guac.sendKeyEvent(0, KEYSYM_ALT);
        guac.sendKeyEvent(0, KEYSYM_CTRL);
    };

};<commit_msg>Fade out display on error.<commit_after>
// UI Definition
var GuacamoleUI = {

    "viewport"    : document.getElementById("viewportClone"),
    "display"     : document.getElementById("display"),
    "menu"        : document.getElementById("menu"),
    "menuControl" : document.getElementById("menuControl"),
    "touchMenu"   : document.getElementById("touchMenu"),
    "logo"        : document.getElementById("status-logo"),

    "buttons": {

        "showClipboard": document.getElementById("showClipboard"),
        "showKeyboard" : document.getElementById("showKeyboard"),
        "ctrlAltDelete": document.getElementById("ctrlAltDelete"),
        "reconnect"    : document.getElementById("reconnect"),
        "logout"       : document.getElementById("logout")

    },

    "containers": {
        "state"    : document.getElementById("statusDialog"),
        "clipboard": document.getElementById("clipboardDiv"),
        "keyboard" : document.getElementById("keyboardContainer")
    },

    "state"     : document.getElementById("statusText"),
    "clipboard" : document.getElementById("clipboard")

};

// Constant UI initialization and behavior
(function() {

    var menu_shaded = false;

    var shade_interval = null;
    var show_interval = null;

    // Cache error image (might not be available when error occurs)
    var guacErrorImage = new Image();
    guacErrorImage.src = "images/noguacamole-logo-24.png";

    // Function for adding a class to an element
    var addClass;

    // Function for removing a class from an element
    var removeClass;

    // If Node.classList is supported, implement addClass/removeClass using that
    if (Node.classList) {

        addClass = function(element, classname) {
            element.classList.add(classname);
        };

        removeClass = function(element, classname) {
            element.classList.remove(classname);
        };

    }

    // Otherwise, implement own
    else {

        addClass = function(element, classname) {

            // Simply add new class
            element.className += " " + classname;

        };

        removeClass = function(element, classname) {

            // Filter out classes with given name
            element.className = element.className.replace(/([^ ]+)[ ]*/g,
                function(match, testClassname, spaces, offset, string) {

                    // If same class, remove
                    if (testClassname == classname)
                        return "";

                    // Otherwise, allow
                    return match;

                }
            );

        };

    }

    GuacamoleUI.hideStatus = function() {
        removeClass(document.body, "guac-error");
        GuacamoleUI.containers.state.style.visibility = "hidden";
        GuacamoleUI.display.style.opacity = "1";
    };

    GuacamoleUI.showStatus = function(text) {
        removeClass(document.body, "guac-error");
        GuacamoleUI.containers.state.style.visibility = "visible";
        GuacamoleUI.state.textContent = text;
        GuacamoleUI.display.style.opacity = "1";
    };

    GuacamoleUI.showError = function(error) {
        addClass(document.body, "guac-error");
        GuacamoleUI.state.textContent = error;
        GuacamoleUI.display.style.opacity = "0.1";
    };

    GuacamoleUI.shadeMenu = function() {

        if (!menu_shaded) {

            var step = Math.floor(GuacamoleUI.menu.offsetHeight / 10) + 1;
            var offset = 0;
            menu_shaded = true;

            window.clearInterval(show_interval);
            shade_interval = window.setInterval(function() {

                offset -= step;
                GuacamoleUI.menu.style.top = offset + "px";

                if (offset <= -GuacamoleUI.menu.offsetHeight) {
                    window.clearInterval(shade_interval);
                    GuacamoleUI.menu.style.visiblity = "hidden";
                }

            }, 30);
        }

    };

    GuacamoleUI.showMenu = function() {

        if (menu_shaded) {

            var step = Math.floor(GuacamoleUI.menu.offsetHeight / 5) + 1;
            var offset = -GuacamoleUI.menu.offsetHeight;
            menu_shaded = false;
            GuacamoleUI.menu.style.visiblity = "";

            window.clearInterval(shade_interval);
            show_interval = window.setInterval(function() {

                offset += step;

                if (offset >= 0) {
                    offset = 0;
                    window.clearInterval(show_interval);
                }

                GuacamoleUI.menu.style.top = offset + "px";

            }, 30);
        }

    };

    // Show/Hide clipboard
    GuacamoleUI.buttons.showClipboard.onclick = function() {

        var displayed = GuacamoleUI.containers.clipboard.style.display;
        if (displayed != "block") {
            GuacamoleUI.containers.clipboard.style.display = "block";
            GuacamoleUI.buttons.showClipboard.innerHTML = "Hide Clipboard";
        }
        else {
            GuacamoleUI.containers.clipboard.style.display = "none";
            GuacamoleUI.buttons.showClipboard.innerHTML = "Show Clipboard";
            GuacamoleUI.clipboard.onchange();
        }

    };

    // Show/Hide keyboard
    var keyboardResizeInterval = null;
    GuacamoleUI.buttons.showKeyboard.onclick = function() {

        var displayed = GuacamoleUI.containers.keyboard.style.display;
        if (displayed != "block") {
            GuacamoleUI.containers.keyboard.style.display = "block";
            GuacamoleUI.buttons.showKeyboard.textContent = "Hide Keyboard";

            // Automatically update size
            window.onresize = updateKeyboardSize;
            keyboardResizeInterval = window.setInterval(updateKeyboardSize, 30);

            updateKeyboardSize();
        }
        else {
            GuacamoleUI.containers.keyboard.style.display = "none";
            GuacamoleUI.buttons.showKeyboard.textContent = "Show Keyboard";

            window.onresize = null;
            window.clearInterval(keyboardResizeInterval);
        }

    };

    // Logout
    GuacamoleUI.buttons.logout.onclick = function() {
        window.location.href = "logout";
    };

    // Timeouts for detecting if users wants menu to open or close
    var detectMenuOpenTimeout = null;
    var detectMenuCloseTimeout = null;

    // Clear detection timeouts
    GuacamoleUI.resetMenuDetect = function() {

        if (detectMenuOpenTimeout != null) {
            window.clearTimeout(detectMenuOpenTimeout);
            detectMenuOpenTimeout = null;
        }

        if (detectMenuCloseTimeout != null) {
            window.clearTimeout(detectMenuCloseTimeout);
            detectMenuCloseTimeout = null;
        }

    };

    // Initiate detection of menu open action. If not canceled through some
    // user event, menu will open.
    GuacamoleUI.startMenuOpenDetect = function() {

        if (!detectMenuOpenTimeout) {

            // Clear detection state
            GuacamoleUI.resetMenuDetect();

            // Wait and then show menu
            detectMenuOpenTimeout = window.setTimeout(function() {
                GuacamoleUI.showMenu();
                detectMenuOpenTimeout = null;
            }, 325);

        }

    };

    // Initiate detection of menu close action. If not canceled through some
    // user event, menu will close.
    GuacamoleUI.startMenuCloseDetect = function() {

        if (!detectMenuCloseTimeout) {

            // Clear detection state
            GuacamoleUI.resetMenuDetect();

            // Wait and then shade menu
            detectMenuCloseTimeout = window.setTimeout(function() {
                GuacamoleUI.shadeMenu();
                detectMenuCloseTimeout = null;
            }, 500);

        }

    };

    // Show menu if mouseover any part of menu
    GuacamoleUI.menu.addEventListener('mouseover', GuacamoleUI.showMenu, true);

    // Stop detecting menu state change intents if mouse is over menu
    GuacamoleUI.menu.addEventListener('mouseover', GuacamoleUI.resetMenuDetect, true);

    // When mouse hovers over top of screen, start detection of intent to open menu
    GuacamoleUI.menuControl.addEventListener('mousemove', GuacamoleUI.startMenuOpenDetect, true);

    var menuShowLongPressTimeout = null;

    GuacamoleUI.startLongPressDetect = function() {

        if (!menuShowLongPressTimeout) {

            menuShowLongPressTimeout = window.setTimeout(function() {

                menuShowLongPressTimeout = null;
                GuacamoleUI.showMenu();

            }, 800);

        }
    };

    GuacamoleUI.stopLongPressDetect = function() {
        window.clearTimeout(menuShowLongPressTimeout);
        menuShowLongPressTimeout = null;
    };

    // Detect long-press at bottom of screen
    document.body.addEventListener('touchstart', GuacamoleUI.startLongPressDetect, true);

    // Reconnect button
    GuacamoleUI.buttons.reconnect.onclick = function() {
        window.location.reload();
    };

    // On-screen keyboard
    GuacamoleUI.keyboard = new Guacamole.OnScreenKeyboard("layouts/en-us-qwerty-mobile.xml");
    GuacamoleUI.containers.keyboard.appendChild(GuacamoleUI.keyboard.getElement());

    // Function for automatically updating keyboard size
    var lastKeyboardWidth;
    function updateKeyboardSize() {
        var currentSize = GuacamoleUI.keyboard.getElement().offsetWidth;
        if (lastKeyboardWidth != currentSize) {
            GuacamoleUI.keyboard.resize(currentSize);
            lastKeyboardWidth = currentSize;
        }
    };

})();

// Tie UI events / behavior to a specific Guacamole client
GuacamoleUI.attach = function(guac) {

    var guac_display = guac.getDisplay();

    // When mouse enters display, start detection of intent to close menu
    guac_display.addEventListener('mouseover', GuacamoleUI.startMenuCloseDetect, true);

    guac_display.onclick = function(e) {
        e.preventDefault();
        return false;
    };

    // Mouse
    var mouse = new Guacamole.Mouse(guac_display);
    mouse.onmousedown = mouse.onmouseup = mouse.onmousemove =
        function(mouseState) {

            // Determine mouse position within view
            var mouse_view_x = mouseState.x + guac_display.offsetLeft - window.pageXOffset;
            var mouse_view_y = mouseState.y + guac_display.offsetTop  - window.pageYOffset;

            // Determine viewport dimensioins
            var view_width  = GuacamoleUI.viewport.offsetWidth;
            var view_height = GuacamoleUI.viewport.offsetHeight;

            // Determine scroll amounts based on mouse position relative to document

            var scroll_amount_x;
            if (mouse_view_x > view_width)
                scroll_amount_x = mouse_view_x - view_width;
            else if (mouse_view_x < 0)
                scroll_amount_x = mouse_view_x;
            else
                scroll_amount_x = 0;

            var scroll_amount_y;
            if (mouse_view_y > view_height)
                scroll_amount_y = mouse_view_y - view_height;
            else if (mouse_view_y < 0)
                scroll_amount_y = mouse_view_y;
            else
                scroll_amount_y = 0;

            // Scroll (if necessary) to keep mouse on screen.
            window.scrollBy(scroll_amount_x, scroll_amount_y);

            // Hide menu on movement
            GuacamoleUI.startMenuCloseDetect();

            // Stop detecting long presses if mouse is being used
            GuacamoleUI.stopLongPressDetect();

            // Send mouse event
            guac.sendMouseState(mouseState);

        };

    // Keyboard
    var keyboard = new Guacamole.Keyboard(document);

    function disableKeyboard() {
        keyboard.onkeydown = null;
        keyboard.onkeyup = null;
    }

    function enableKeyboard() {
        keyboard.onkeydown =
            function (keysym) {
                guac.sendKeyEvent(1, keysym);
            };

        keyboard.onkeyup =
            function (keysym) {
                guac.sendKeyEvent(0, keysym);
            };
    }

    // Enable keyboard by default
    enableKeyboard();

    // Handle client state change
    guac.onstatechange = function(clientState) {
        switch (clientState) {

            // Idle
            case 0:
                GuacamoleUI.showStatus("Idle.");
                break;

            // Connecting
            case 1:
                GuacamoleUI.shadeMenu();
                GuacamoleUI.showStatus("Connecting...");
                break;

            // Connected + waiting
            case 2:
                GuacamoleUI.showStatus("Connected, waiting for first update...");
                break;

            // Connected
            case 3:

                GuacamoleUI.hideStatus();
                GuacamoleUI.display.className =
                    GuacamoleUI.display.className.replace(/guac-loading/, '');

                GuacamoleUI.menu.className = "connected";
                break;

            // Disconnecting
            case 4:
                GuacamoleUI.showStatus("Disconnecting...");
                break;

            // Disconnected
            case 5:
                GuacamoleUI.showStatus("Disconnected.");
                break;

            // Unknown status code
            default:
                GuacamoleUI.showStatus("[UNKNOWN STATUS]");

        }
    };

    // Name instruction handler
    guac.onname = function(name) {
        document.title = name;
    };

    // Error handler
    guac.onerror = function(error) {

        // Disconnect, if connected
        guac.disconnect();

        // Display error message
        GuacamoleUI.showError(error);

    };

    // Disconnect on close
    window.onunload = function() {
        guac.disconnect();
    };

    // Handle clipboard events
    GuacamoleUI.clipboard.onchange = function() {

        var text = GuacamoleUI.clipboard.value;
        guac.setClipboard(text);

    };

    // Ignore keypresses when clipboard is focused
    GuacamoleUI.clipboard.onfocus = function() {
        disableKeyboard();
    };

    // Capture keypresses when clipboard is not focused
    GuacamoleUI.clipboard.onblur = function() {
        enableKeyboard();
    };

    // Server copy handler
    guac.onclipboard = function(data) {
        GuacamoleUI.clipboard.value = data;
    };

    GuacamoleUI.keyboard.onkeydown = function(keysym) {
        guac.sendKeyEvent(1, keysym);
    };

    GuacamoleUI.keyboard.onkeyup = function(keysym) {
        guac.sendKeyEvent(0, keysym);
    };

    // Send Ctrl-Alt-Delete
    GuacamoleUI.buttons.ctrlAltDelete.onclick = function() {

        var KEYSYM_CTRL   = 0xFFE3;
        var KEYSYM_ALT    = 0xFFE9;
        var KEYSYM_DELETE = 0xFFFF;

        guac.sendKeyEvent(1, KEYSYM_CTRL);
        guac.sendKeyEvent(1, KEYSYM_ALT);
        guac.sendKeyEvent(1, KEYSYM_DELETE);
        guac.sendKeyEvent(0, KEYSYM_DELETE);
        guac.sendKeyEvent(0, KEYSYM_ALT);
        guac.sendKeyEvent(0, KEYSYM_CTRL);
    };

};<|endoftext|>


<commit_before>(function(ext) {

    var firstTime = true;
    var boolean = true;
    var jsonObject = null;
    var xScale = 240;
    var yScale = 180;
    var status = 2;
    //var headX = 0;

    alert("BEFORE CLICKING OK: Make sure you have have followed the instructions in Kinect2Scratch");
    console.log("Right after the alert");

    var wsImpl = window.WebSocket || window.MozWebSocket;

    console.log("connecting to server ..");

    // create a new websocket and connect
    window.ws = new wsImpl('ws://localhost:8181/');

    // when data is comming from the server, this metod is called
    ws.onmessage = function (evt) {
        //console.log(evt.data + '
');
        if(evt != "0")
        {
        jsonObject = JSON.parse(evt.data);
            if(jsonObject.bodies == null)
            {
                status = 1;
            } else
            {
                status = 2;
            }
        }
        //headX = parseInt(evt.data);
    };

    // when the connection is established, this method is called
    ws.onopen = function () {
        console.log('.. connection open');
        //status = 1;
    };

    // when the connection is closed, this method is called
    ws.onclose = function () {
        console.log('.. connection closed');
        status = 0;
    };

    // Cleanup function when the extension is unloaded
    ext._shutdown = function() {};

    // Status reporting code
    // Use this to report missing hardware, plugin or unsupported browser
    ext._getStatus = function() {
        if(status == 0)
        {
            return {status: 0, msg: 'Kinect is not connected'};
            //polling function for auto-reconnect should go here
        }
        if(status == 1)
        {
            return {status: 1, msg: 'Kinect is connected, but is not detecting any bodies'};
        }
        if(status == 2)
        {
            return {status: 2, msg: 'Kinect is sending body data'};
        }

    };

        // Block and block menu descriptions
    var descriptor = {
        blocks: [
            ['', 'My First Block', 'my_first_block'],
            ['r', '%n ^ %n', 'power', 2, 3],
            ['r', '%m.k sensor value', 'k', 'Head X'],
            ['', 'restart connection', 'restart'],
            ['', 'test block', 'test_block']
        ],

        menus: {
	    k: ['Left Ankle X', 'Left Ankle Y', 'Right Ankle X', 'Right Ankle Y', 'Left Elbow X', 'Left Elbow Y', 'Right Elbow X', 'Right Elbow Y', 'Left Foot X', 'Left Foot Y', 'Right Foot X', 'Right Foot Y', 'Left Hand X', 'Left Hand Y', 'Right Hand X', 'Right Hand Y', 'Left Hand Tip X', 'Left Hand Tip Y', 'Right Hand Tip X', 'Right Hand Tip Y', 'Head X', 'Head Y', 'Left Hip X', 'Left Hip Y', 'Right Hip X', 'Right Hip Y', 'Left Knee X', 'Left Knee Y', 'Right Knee X', 'Right Knee Y', 'Neck X', 'Neck Y', 'Left Shoulder X', 'Left Shoulder Y', 'Right Shoulder X', 'Right Shoulder Y', 'Spine Base X', 'Spine Base Y', 'Spine Middle X', 'Spine Middle Y', 'Spine Shoulder X', 'Spine Shoulder Y', 'Left Thumb X', 'Left Thumb Y', 'Right Thumb X', 'Right Thumb Y', 'Left Wrist X', 'Left Wrist Y', 'Right Wrist X', 'Right Wrist Y']
    }
    };

	ext.my_first_block = function() {
        console.log("My first block");
    };

    ext.restart = function() {
        console.log("connecting to server ..");
        window.ws = new wsImpl('ws://localhost:8181/');
    };

    ext.power = function(base, exponent) {
        return Math.pow(base, exponent);
    };

    ext.test_block = function() {
        console.log(jsonObject.bodies[0].joints[3].x);
    };

    ext.k = function(m) {
        switch(m){
            case 'Left Ankle X': return jsonObject.bodies[0].joints[14].x*xScale;
            case 'Left Ankle Y': return jsonObject.bodies[0].joints[14].y*yScale;
            case 'Right Ankle X': return jsonObject.bodies[0].joints[18].x*xScale;
            case 'Right Ankle Y': return jsonObject.bodies[0].joints[18].y*yScale;
            case 'Left Elbow X': return jsonObject.bodies[0].joints[5].x*xScale;
            case 'Left Elbow Y': return jsonObject.bodies[0].joints[5].y*yScale;
            case 'Right Elbow X': return jsonObject.bodies[0].joints[9].x*xScale;
            case 'Right Elbow Y': return jsonObject.bodies[0].joints[9].y*yScale;
            case 'Left Foot X': return jsonObject.bodies[0].joints[15].x*xScale;
            case 'Left Foot Y': return jsonObject.bodies[0].joints[15].y*yScale;
            case 'Right Foot X': return jsonObject.bodies[0].joints[19].x*xScale;
            case 'Right Foot Y': return jsonObject.bodies[0].joints[19].y*yScale;
            case 'Left Hand X': return jsonObject.bodies[0].joints[7].x*xScale;
            case 'Left Hand Y': return jsonObject.bodies[0].joints[7].y*yScale;
            case 'Right Hand X': return jsonObject.bodies[0].joints[11].x*xScale;
            case 'Right Hand Y': return jsonObject.bodies[0].joints[11].y*yScale;
            case 'Left Hand Tip X': return jsonObject.bodies[0].joints[21].x*xScale;
            case 'Left Hand Tip Y': return jsonObject.bodies[0].joints[21].y*yScale;
            case 'Right Hand Tip X': return jsonObject.bodies[0].joints[23].x*xScale;
            case 'Right Hand Tip Y': return jsonObject.bodies[0].joints[23].y*yScale;
            case 'Head X': return jsonObject.bodies[0].joints[3].x*xScale;
            case 'Head Y': return jsonObject.bodies[0].joints[3].y*yScale;
            case 'Left Hip X': return jsonObject.bodies[0].joints[12].x*xScale;
            case 'Left Hip Y': return jsonObject.bodies[0].joints[12].y*yScale;
            case 'Right Hip X': return jsonObject.bodies[0].joints[16].x*xScale;
            case 'Right Hip Y': return jsonObject.bodies[0].joints[16].y*yScale;
            case 'Left Knee X': return jsonObject.bodies[0].joints[13].x*xScale;
            case 'Left Knee Y': return jsonObject.bodies[0].joints[13].y*yScale;
            case 'Right Knee X': return jsonObject.bodies[0].joints[17].x*xScale;
            case 'Right Knee Y': return jsonObject.bodies[0].joints[17].y*yScale;
            case 'Neck X': return jsonObject.bodies[0].joints[2].x*xScale;
            case 'Neck Y': return jsonObject.bodies[0].joints[2].y*yScale;
            case 'Left Shoulder X': return jsonObject.bodies[0].joints[4].x*xScale;
            case 'Left Shoulder Y': return jsonObject.bodies[0].joints[4].y*yScale;
            case 'Right Shoulder X': return jsonObject.bodies[0].joints[8].x*xScale;
            case 'Right Shoulder Y': return jsonObject.bodies[0].joints[8].y*yScale;
            case 'Spine Base X': return jsonObject.bodies[0].joints[0].x*xScale;
            case 'Spine Base Y': return jsonObject.bodies[0].joints[0].x*xScale;
            case 'Spine Middle X': return jsonObject.bodies[0].joints[1].y*yScale;
            case 'Spine Middle Y': return jsonObject.bodies[0].joints[1].x*xScale;
            case 'Spine Shoulder X': return jsonObject.bodies[0].joints[20].y*yScale;
            case 'Spine Shoulder Y': return jsonObject.bodies[0].joints[20].x*xScale;
            case 'Left Thumb X': return jsonObject.bodies[0].joints[22].y*yScale;
            case 'Left Thumb Y': return jsonObject.bodies[0].joints[22].x*xScale;
            case 'Right Thumb X': return jsonObject.bodies[0].joints[24].y*yScale;
            case 'Right Thumb Y': return jsonObject.bodies[0].joints[24].x*xScale;
            case 'Left Wrist X': return jsonObject.bodies[0].joints[6].y*yScale;
            case 'Left Wrist Y': return jsonObject.bodies[0].joints[6].y*yScale;
            case 'Right Wrist X': return jsonObject.bodies[0].joints[10].x*xScale;
            case 'Right Wrist Y': return jsonObject.bodies[0].joints[10].y*yScale;
//            case 'ankleLeftX': return jsonObject.bodies[0].joints[14].x;
//            case 'ankleLeftY': return jsonObject.bodies[0].joints[14].y;
//            case 'ankleRightX': return jsonObject.bodies[0].joints[18].x;
//            case 'ankleRightY': return jsonObject.bodies[0].joints[18].y;
//            case 'elbowLeftX': return jsonObject.bodies[0].joints[5].x;
//            case 'elbowLeftY': return jsonObject.bodies[0].joints[5].y;
//            case 'elbowRightX': return jsonObject.bodies[0].joints[9].x;
//            case 'elbowRightY': return jsonObject.bodies[0].joints[9].y;
//            case 'footLeftX': return jsonObject.bodies[0].joints[15].x;
//            case 'footLeftY': return jsonObject.bodies[0].joints[15].y;
//            case 'footRightX': return jsonObject.bodies[0].joints[19].x;
//            case 'footRightY': return jsonObject.bodies[0].joints[19].y;
//            case 'handLeftX': return jsonObject.bodies[0].joints[7].x;
//            case 'handLeftY': return jsonObject.bodies[0].joints[7].y;
//            case 'handRightX': return jsonObject.bodies[0].joints[11].x;
//            case 'handRightY': return jsonObject.bodies[0].joints[11].y;
//            case 'handTipLeftX': return jsonObject.bodies[0].joints[21].x;
//            case 'handTipLeftY': return jsonObject.bodies[0].joints[21].y;
//            case 'handTipRightX': return jsonObject.bodies[0].joints[23].x;
//            case 'handTipRightY': return jsonObject.bodies[0].joints[23].y;
//            case 'headX': return jsonObject.bodies[0].joints[3].x;
//            case 'headY': return jsonObject.bodies[0].joints[3].y;
//            case 'hipLeftX': return jsonObject.bodies[0].joints[12].x;
//            case 'hipLeftY': return jsonObject.bodies[0].joints[12].y;
//            case 'hipRightX': return jsonObject.bodies[0].joints[16].x;
//            case 'hipRightY': return jsonObject.bodies[0].joints[16].y;
//            case 'kneeLeftX': return jsonObject.bodies[0].joints[13].x;
//            case 'kneeLeftY': return jsonObject.bodies[0].joints[13].y;
//            case 'kneeRightX': return jsonObject.bodies[0].joints[17].x;
//            case 'kneeRightY': return jsonObject.bodies[0].joints[17].y;
//            case 'neckX': return jsonObject.bodies[0].joints[2].x;
//            case 'neckY': return jsonObject.bodies[0].joints[2].y;
//            case 'shoulderLeftX': return jsonObject.bodies[0].joints[4].x;
//            case 'shoulderLeftY': return jsonObject.bodies[0].joints[4].y;
//            case 'shoulderRightX': return jsonObject.bodies[0].joints[8].x;
//            case 'shoulderRightY': return jsonObject.bodies[0].joints[8].y;
//            case 'spineBaseX': return jsonObject.bodies[0].joints[0].x;
//            case 'spineBaseY': return jsonObject.bodies[0].joints[0].y;
//            case 'spineMidX': return jsonObject.bodies[0].joints[1].x;
//            case 'spineMidY': return jsonObject.bodies[0].joints[1].y;
//            case 'spineShoulderX': return jsonObject.bodies[0].joints[20].x;
//            case 'spineShoulderY': return jsonObject.bodies[0].joints[20].y;
//            case 'thumbLeftX': return jsonObject.bodies[0].joints[22].x;
//            case 'thumbLeftY': return jsonObject.bodies[0].joints[22].y;
//            case 'thumbRightX': return jsonObject.bodies[0].joints[24].x;
//            case 'thumbRightY': return jsonObject.bodies[0].joints[24].y;
//            case 'wristLeftX': return jsonObject.bodies[0].joints[6].x;
//            case 'wristLeftY': return jsonObject.bodies[0].joints[6].y;
//            case 'wristRightX': return jsonObject.bodies[0].joints[10].x;
//            case 'wristRightY': return jsonObject.bodies[0].joints[10].y;
        }
    };

    // Register the extension
    ScratchExtensions.register('KinectinScratch', descriptor, ext);
})({});<commit_msg>Try a new comparison<commit_after>(function(ext) {

    var firstTime = true;
    var boolean = true;
    var jsonObject = null;
    var xScale = 240;
    var yScale = 180;
    var status = 2;
    //var headX = 0;

    alert("BEFORE CLICKING OK: Make sure you have have followed the instructions in Kinect2Scratch");
    console.log("Right after the alert");

    var wsImpl = window.WebSocket || window.MozWebSocket;

    console.log("connecting to server ..");

    // create a new websocket and connect
    window.ws = new wsImpl('ws://localhost:8181/');

    // when data is comming from the server, this metod is called
    ws.onmessage = function (evt) {
        //console.log(evt.data + '
');
        if(evt != "0")
        {
        jsonObject = JSON.parse(evt.data);
            if(jsonObject == {"bodies":[]})
            {
                status = 1;
            } else
            {
                status = 2;
            }
        }
        //headX = parseInt(evt.data);
    };

    // when the connection is established, this method is called
    ws.onopen = function () {
        console.log('.. connection open');
        //status = 1;
    };

    // when the connection is closed, this method is called
    ws.onclose = function () {
        console.log('.. connection closed');
        status = 0;
    };

    // Cleanup function when the extension is unloaded
    ext._shutdown = function() {};

    // Status reporting code
    // Use this to report missing hardware, plugin or unsupported browser
    ext._getStatus = function() {
        if(status == 0)
        {
            return {status: 0, msg: 'Kinect is not connected'};
            //polling function for auto-reconnect should go here
        }
        if(status == 1)
        {
            return {status: 1, msg: 'Kinect is connected, but is not detecting any bodies'};
        }
        if(status == 2)
        {
            return {status: 2, msg: 'Kinect is sending body data'};
        }

    };

        // Block and block menu descriptions
    var descriptor = {
        blocks: [
            ['', 'My First Block', 'my_first_block'],
            ['r', '%n ^ %n', 'power', 2, 3],
            ['r', '%m.k sensor value', 'k', 'Head X'],
            ['', 'restart connection', 'restart'],
            ['', 'test block', 'test_block']
        ],

        menus: {
	    k: ['Left Ankle X', 'Left Ankle Y', 'Right Ankle X', 'Right Ankle Y', 'Left Elbow X', 'Left Elbow Y', 'Right Elbow X', 'Right Elbow Y', 'Left Foot X', 'Left Foot Y', 'Right Foot X', 'Right Foot Y', 'Left Hand X', 'Left Hand Y', 'Right Hand X', 'Right Hand Y', 'Left Hand Tip X', 'Left Hand Tip Y', 'Right Hand Tip X', 'Right Hand Tip Y', 'Head X', 'Head Y', 'Left Hip X', 'Left Hip Y', 'Right Hip X', 'Right Hip Y', 'Left Knee X', 'Left Knee Y', 'Right Knee X', 'Right Knee Y', 'Neck X', 'Neck Y', 'Left Shoulder X', 'Left Shoulder Y', 'Right Shoulder X', 'Right Shoulder Y', 'Spine Base X', 'Spine Base Y', 'Spine Middle X', 'Spine Middle Y', 'Spine Shoulder X', 'Spine Shoulder Y', 'Left Thumb X', 'Left Thumb Y', 'Right Thumb X', 'Right Thumb Y', 'Left Wrist X', 'Left Wrist Y', 'Right Wrist X', 'Right Wrist Y']
    }
    };

	ext.my_first_block = function() {
        console.log("My first block");
    };

    ext.restart = function() {
        console.log("connecting to server ..");
        window.ws = new wsImpl('ws://localhost:8181/');
    };

    ext.power = function(base, exponent) {
        return Math.pow(base, exponent);
    };

    ext.test_block = function() {
        console.log(jsonObject.bodies[0].joints[3].x);
    };

    ext.k = function(m) {
        switch(m){
            case 'Left Ankle X': return jsonObject.bodies[0].joints[14].x*xScale;
            case 'Left Ankle Y': return jsonObject.bodies[0].joints[14].y*yScale;
            case 'Right Ankle X': return jsonObject.bodies[0].joints[18].x*xScale;
            case 'Right Ankle Y': return jsonObject.bodies[0].joints[18].y*yScale;
            case 'Left Elbow X': return jsonObject.bodies[0].joints[5].x*xScale;
            case 'Left Elbow Y': return jsonObject.bodies[0].joints[5].y*yScale;
            case 'Right Elbow X': return jsonObject.bodies[0].joints[9].x*xScale;
            case 'Right Elbow Y': return jsonObject.bodies[0].joints[9].y*yScale;
            case 'Left Foot X': return jsonObject.bodies[0].joints[15].x*xScale;
            case 'Left Foot Y': return jsonObject.bodies[0].joints[15].y*yScale;
            case 'Right Foot X': return jsonObject.bodies[0].joints[19].x*xScale;
            case 'Right Foot Y': return jsonObject.bodies[0].joints[19].y*yScale;
            case 'Left Hand X': return jsonObject.bodies[0].joints[7].x*xScale;
            case 'Left Hand Y': return jsonObject.bodies[0].joints[7].y*yScale;
            case 'Right Hand X': return jsonObject.bodies[0].joints[11].x*xScale;
            case 'Right Hand Y': return jsonObject.bodies[0].joints[11].y*yScale;
            case 'Left Hand Tip X': return jsonObject.bodies[0].joints[21].x*xScale;
            case 'Left Hand Tip Y': return jsonObject.bodies[0].joints[21].y*yScale;
            case 'Right Hand Tip X': return jsonObject.bodies[0].joints[23].x*xScale;
            case 'Right Hand Tip Y': return jsonObject.bodies[0].joints[23].y*yScale;
            case 'Head X': return jsonObject.bodies[0].joints[3].x*xScale;
            case 'Head Y': return jsonObject.bodies[0].joints[3].y*yScale;
            case 'Left Hip X': return jsonObject.bodies[0].joints[12].x*xScale;
            case 'Left Hip Y': return jsonObject.bodies[0].joints[12].y*yScale;
            case 'Right Hip X': return jsonObject.bodies[0].joints[16].x*xScale;
            case 'Right Hip Y': return jsonObject.bodies[0].joints[16].y*yScale;
            case 'Left Knee X': return jsonObject.bodies[0].joints[13].x*xScale;
            case 'Left Knee Y': return jsonObject.bodies[0].joints[13].y*yScale;
            case 'Right Knee X': return jsonObject.bodies[0].joints[17].x*xScale;
            case 'Right Knee Y': return jsonObject.bodies[0].joints[17].y*yScale;
            case 'Neck X': return jsonObject.bodies[0].joints[2].x*xScale;
            case 'Neck Y': return jsonObject.bodies[0].joints[2].y*yScale;
            case 'Left Shoulder X': return jsonObject.bodies[0].joints[4].x*xScale;
            case 'Left Shoulder Y': return jsonObject.bodies[0].joints[4].y*yScale;
            case 'Right Shoulder X': return jsonObject.bodies[0].joints[8].x*xScale;
            case 'Right Shoulder Y': return jsonObject.bodies[0].joints[8].y*yScale;
            case 'Spine Base X': return jsonObject.bodies[0].joints[0].x*xScale;
            case 'Spine Base Y': return jsonObject.bodies[0].joints[0].x*xScale;
            case 'Spine Middle X': return jsonObject.bodies[0].joints[1].y*yScale;
            case 'Spine Middle Y': return jsonObject.bodies[0].joints[1].x*xScale;
            case 'Spine Shoulder X': return jsonObject.bodies[0].joints[20].y*yScale;
            case 'Spine Shoulder Y': return jsonObject.bodies[0].joints[20].x*xScale;
            case 'Left Thumb X': return jsonObject.bodies[0].joints[22].y*yScale;
            case 'Left Thumb Y': return jsonObject.bodies[0].joints[22].x*xScale;
            case 'Right Thumb X': return jsonObject.bodies[0].joints[24].y*yScale;
            case 'Right Thumb Y': return jsonObject.bodies[0].joints[24].x*xScale;
            case 'Left Wrist X': return jsonObject.bodies[0].joints[6].y*yScale;
            case 'Left Wrist Y': return jsonObject.bodies[0].joints[6].y*yScale;
            case 'Right Wrist X': return jsonObject.bodies[0].joints[10].x*xScale;
            case 'Right Wrist Y': return jsonObject.bodies[0].joints[10].y*yScale;
//            case 'ankleLeftX': return jsonObject.bodies[0].joints[14].x;
//            case 'ankleLeftY': return jsonObject.bodies[0].joints[14].y;
//            case 'ankleRightX': return jsonObject.bodies[0].joints[18].x;
//            case 'ankleRightY': return jsonObject.bodies[0].joints[18].y;
//            case 'elbowLeftX': return jsonObject.bodies[0].joints[5].x;
//            case 'elbowLeftY': return jsonObject.bodies[0].joints[5].y;
//            case 'elbowRightX': return jsonObject.bodies[0].joints[9].x;
//            case 'elbowRightY': return jsonObject.bodies[0].joints[9].y;
//            case 'footLeftX': return jsonObject.bodies[0].joints[15].x;
//            case 'footLeftY': return jsonObject.bodies[0].joints[15].y;
//            case 'footRightX': return jsonObject.bodies[0].joints[19].x;
//            case 'footRightY': return jsonObject.bodies[0].joints[19].y;
//            case 'handLeftX': return jsonObject.bodies[0].joints[7].x;
//            case 'handLeftY': return jsonObject.bodies[0].joints[7].y;
//            case 'handRightX': return jsonObject.bodies[0].joints[11].x;
//            case 'handRightY': return jsonObject.bodies[0].joints[11].y;
//            case 'handTipLeftX': return jsonObject.bodies[0].joints[21].x;
//            case 'handTipLeftY': return jsonObject.bodies[0].joints[21].y;
//            case 'handTipRightX': return jsonObject.bodies[0].joints[23].x;
//            case 'handTipRightY': return jsonObject.bodies[0].joints[23].y;
//            case 'headX': return jsonObject.bodies[0].joints[3].x;
//            case 'headY': return jsonObject.bodies[0].joints[3].y;
//            case 'hipLeftX': return jsonObject.bodies[0].joints[12].x;
//            case 'hipLeftY': return jsonObject.bodies[0].joints[12].y;
//            case 'hipRightX': return jsonObject.bodies[0].joints[16].x;
//            case 'hipRightY': return jsonObject.bodies[0].joints[16].y;
//            case 'kneeLeftX': return jsonObject.bodies[0].joints[13].x;
//            case 'kneeLeftY': return jsonObject.bodies[0].joints[13].y;
//            case 'kneeRightX': return jsonObject.bodies[0].joints[17].x;
//            case 'kneeRightY': return jsonObject.bodies[0].joints[17].y;
//            case 'neckX': return jsonObject.bodies[0].joints[2].x;
//            case 'neckY': return jsonObject.bodies[0].joints[2].y;
//            case 'shoulderLeftX': return jsonObject.bodies[0].joints[4].x;
//            case 'shoulderLeftY': return jsonObject.bodies[0].joints[4].y;
//            case 'shoulderRightX': return jsonObject.bodies[0].joints[8].x;
//            case 'shoulderRightY': return jsonObject.bodies[0].joints[8].y;
//            case 'spineBaseX': return jsonObject.bodies[0].joints[0].x;
//            case 'spineBaseY': return jsonObject.bodies[0].joints[0].y;
//            case 'spineMidX': return jsonObject.bodies[0].joints[1].x;
//            case 'spineMidY': return jsonObject.bodies[0].joints[1].y;
//            case 'spineShoulderX': return jsonObject.bodies[0].joints[20].x;
//            case 'spineShoulderY': return jsonObject.bodies[0].joints[20].y;
//            case 'thumbLeftX': return jsonObject.bodies[0].joints[22].x;
//            case 'thumbLeftY': return jsonObject.bodies[0].joints[22].y;
//            case 'thumbRightX': return jsonObject.bodies[0].joints[24].x;
//            case 'thumbRightY': return jsonObject.bodies[0].joints[24].y;
//            case 'wristLeftX': return jsonObject.bodies[0].joints[6].x;
//            case 'wristLeftY': return jsonObject.bodies[0].joints[6].y;
//            case 'wristRightX': return jsonObject.bodies[0].joints[10].x;
//            case 'wristRightY': return jsonObject.bodies[0].joints[10].y;
        }
    };

    // Register the extension
    ScratchExtensions.register('KinectinScratch', descriptor, ext);
})({});<|endoftext|>


<commit_before>var module = angular.module(PKG.name+'.commons');

var baseDirective = {
  restrict: 'E',
  templateUrl: 'flow-graph/flow.html',
  scope: {
    model: '='
  },
  controller: 'myFlowController'
};

module.factory('d3', function ($window) {
  return $window.d3;
});

module.factory('dagreD3', function ($window) {
  return $window.dagreD3;
});

module.controller('myFlowController', function($scope, d3, dagreD3) {
  function update(newVal, oldVal) {
    if (angular.isObject(newVal) && Object.keys(newVal).length) {
      $scope.render();
    }
  }

  $scope.instanceMap = {};
  $scope.labelMap = {};

  /**
   * Gets number of instances from node map.
   */
  $scope.getInstances = function(nodeId) {
    return $scope.instanceMap[nodeId].instances ? $scope.instanceMap[nodeId].instances : 0;
  }

  $scope.$watch('model', update);
  $scope.$watchCollection('model.metrics', update);
});

module.directive('myFlowGraph', function ($filter, $state) {
  return angular.extend({
    link: function (scope, elem, attr) {
      scope.render = genericRender.bind(null, scope, $filter);
      var metricCircleRadius = 25;
      var instanceCircleRadius = 10;
      var flowletCircleRadius = 60;
      // Since names are padded inside of shapes, this needs the same padding to be vertically center aligned.
      var metricCountPadding = 5;
      var streamDiagramWidth = 40;
      var streamDiagramHeight = 30;
      var instanceBufferHeight = 30;
      var numberFilter = $filter('myNumber');
      scope.getShapes = function() {
        var shapes = {};
        shapes.flowlet = function(parent, bbox, node) {
          var w = bbox.width;
          var h = bbox.height;
          var points = [
            //clockwise points from top
            { x: -streamDiagramWidth, y: streamDiagramHeight}, //e
            { x: -streamDiagramWidth, y: -h - streamDiagramHeight}, //a
            { x: w/2, y: -h - streamDiagramHeight}, //b
            { x: w, y: -h/2}, //c
            { x: w/2, y: streamDiagramHeight} //d
          ];
          var instances = scope.getInstances(node.elem.__data__); // No other way to get name from node.
          var instanceCircleScaled = scope.getInstancesScaledRadius(instances, instanceCircleRadius);
          var shapeSvg = parent.insert('circle', ':first-child')
            .attr('x', -bbox.width / 2)
            .attr('y', -bbox.height / 2)
            .attr('r', flowletCircleRadius)
            .attr('class', 'flow-shapes foundation-shape flowlet-svg');

          parent.insert('circle')
            .attr('cx', flowletCircleRadius - instanceCircleScaled)
            .attr('cy', -instanceBufferHeight)
            .attr('r', instanceCircleScaled)
            .attr('class', 'flow-shapes flowlet-instances');

          parent.insert('text')
            .attr('x', flowletCircleRadius - instanceCircleScaled)
            .attr('y', -instanceBufferHeight + metricCountPadding)
            .text(instances)
            .attr('class', 'flow-shapes flowlet-instance-count');

          parent.insert('circle')
            .attr('cx', - flowletCircleRadius)
            .attr('r', metricCircleRadius)
            .attr('class', 'flow-shapes flowlet-events');

          parent.insert('text')
            .attr('x', - flowletCircleRadius)
            .attr('y', metricCountPadding)
            .text(numberFilter(scope.model.metrics[scope.labelMap[node.label].name]))
            .attr('class', 'flow5shapes flowlet-event-count');

          node.intersect = function(point) {
            return dagreD3.intersect.circle(node, flowletCircleRadius, point);
          };

          return shapeSvg;
        };

        shapes.stream = function(parent, bbox, node) {
          var w = bbox.width,
          h = bbox.height,
          points = [
            { x:   -streamDiagramWidth, y: streamDiagramHeight}, //e
            { x:   -streamDiagramWidth, y: -h - streamDiagramHeight}, //a
            { x:   w/2, y: -h - streamDiagramHeight}, //b
            { x: w, y: -h/2}, //c
            { x: w/2, y: streamDiagramHeight} //d
          ],
          shapeSvg = parent.insert('polygon', ':first-child')
            .attr('points', points.map(function(d) { return d.x + ',' + d.y; }).join(' '))
            .attr('transform', 'translate(' + (-w/8) + ',' + (h * 1/2) + ')')
            .attr('class', 'flow-shapes foundation-shape stream-svg');

          // Elements are positioned with respect to shapeSvg.
          var width = shapeSvg.node().getBBox().width;
          var circleXPos = -1 * width/2;

          parent.append('circle')
            .attr('cx', circleXPos)
            .attr('r', metricCircleRadius)
            .attr('class', 'flow-shapes stream-events');

          parent.append('text')
            .attr('x', circleXPos)
            .attr('y', metricCountPadding)
            .text(numberFilter(scope.model.metrics[scope.labelMap[node.label].name]))
            .attr('class', 'flow-shapes stream-event-count');

          node.intersect = function(point) {
            return dagreD3.intersect.polygon(node, points, point);
          };

          return shapeSvg;
        };

        return shapes;
      };

      scope.getShape = function(name) {
        var shapeName;

        switch(name) {
          case 'STREAM':
            shapeName = 'stream';
            break;
          default:
            shapeName = 'flowlet';
            break;
        }
        return shapeName;
      };

      scope.handleNodeClick = function(nodeId) {
        handleHideTip(nodeId);
        var instance = instanceMap[nodeId];
        $state.go('flows.detail.runs.tabs.status.flowletsDetail', {flowletId: nodeId});
      };

      /**
       * Radius for instances circle in flowlets. This is a determined as a factor of the size of the
       * instances text.
       */
      scope.getInstancesScaledRadius = function(instances, radius) {
        var base = radius;
        var extra = (instances.toString().length - 1) * base / 2;
        return base + extra;
      }

    }
  }, baseDirective);
});

module.directive('myWorkflowGraph', function ($filter, $state) {
  return angular.extend({
    link: function (scope, elem, attr) {
      scope.render = genericRender.bind(null, scope, $filter);
      var defaultRadius = 50;
      scope.getShapes = function() {
        var shapes = {};
        shapes.job = function(parent, bbox, node) {
          var w = bbox.width;
          var h = bbox.height;
          var points = [
            //clockwise points from top
            { x: -defaultRadius * 2/3, y: -defaultRadius * 2/3}, //a
            { x: 0, y: -defaultRadius}, // b
            { x: defaultRadius * 2/3, y: -defaultRadius * 2/3}, // c
            { x: defaultRadius, y: 0}, // d
            { x: defaultRadius * 2/3, y: defaultRadius * 2/3}, // e
            { x: 0, y: defaultRadius}, // f
            { x: -defaultRadius * 2/3, y: defaultRadius * 2/3}, // g
            { x: -defaultRadius, y: -0}, //h
          ];
          var shapeSvg = parent.insert('polygon', ':first-child')
            .attr('points', points.map(function(p) { return p.x + ',' + p.y; }).join(' '))
            .attr('class', 'workflow-shapes foundation-shape job-svg');

          node.intersect = function(point) {
            return dagreD3.intersect.polygon(node, points, point);
          };

          return shapeSvg;
        };

        shapes.start = function(parent, bbox, node) {
          var w = bbox.width;
          var h = bbox.height;
          var points = [
            // draw a triangle facing right
            { x: -30, y: -40},
            { x: 30, y: 0},
            { x: -30, y: 40},
          ];
          var shapeSvg = parent.insert('polygon', ':first-child')
            .attr('points', points.map(function(p) { return p.x + ',' + p.y; }).join(' '))
            .attr('transform', 'translate(' + (w/6) + ')')
            .attr('class', 'workflow-shapes foundation-shape start-svg');

          node.intersect = function(point) {
            return dagreD3.intersect.polygon(node, points, point);
          };

          return shapeSvg;
        };

        shapes.end = function(parent, bbox, node) {
          var w = bbox.width;
          var h = bbox.height;
          var points = [
            // draw a triangle facing right
            { x: -30, y: 0},
            { x: 30, y: 40},
            { x: 30, y: -40},
          ];
          var shapeSvg = parent.insert('polygon', ':first-child')
            .attr('points', points.map(function(p) { return p.x + ',' + p.y; }).join(' '))
            .attr('transform', 'translate(' + (-w/6) + ')')
            .attr('class', 'workflow-shapes foundation-shape end-svg');

          node.intersect = function(point) {
            return dagreD3.intersect.polygon(node, points, point);
          };

          return shapeSvg;
        };

        shapes.conditional = function(parent, bbox, node) {
          var w = (bbox.width * Math.SQRT2) / 2,
          h = (bbox.height * Math.SQRT2) / 2,
          points = [
            // draw a diamond
            { x:  0, y: -defaultRadius },
            { x: -defaultRadius, y:  0 },
            { x:  0, y:  defaultRadius },
            { x:  defaultRadius, y:  0 }
          ],
          shapeSvg = parent.insert('polygon', ':first-child')
            .attr('points', points.map(function(p) { return p.x + ',' + p.y; }).join(' '))
            .attr('class', 'workflow-shapes foundation-shape conditional-svg');

          node.intersect = function(p) {
            return dagreD3.intersect.polygon(node, points, p);
          };
          return shapeSvg;
        };

        return shapes;
      };

      scope.getShape = function(name) {
        var shapeName;

        switch(name) {
          case 'ACTION':
            shapeName = 'job';
            break;
          case 'START':
            shapeName = 'start';
            break;
          case 'END':
            shapeName = 'end';
            break;
          default:
            shapeName = 'conditional';
            break;
        }
        return shapeName;
      }

      scope.handleNodeClick = function(nodeId) {
        // Temporary fix for 2.8.0. Should be removed first thing post 2.8.
        if ($state.includes('**.workflows.**')) {
          return;
        }
        handleHideTip(nodeId);
        var instance = instanceMap[nodeId];
        $state.go('flows.detail.runs.tabs.status.flowletsDetail', {flowletId: nodeId});
      }

    }
  }, baseDirective);
});

function genericRender(scope, $filter) {
  var nodes = scope.model.nodes;
  var edges = scope.model.edges;

  var renderer = new dagreD3.render();
  var g = new dagreD3.graphlib.Graph();

  g.setGraph({
    nodesep: 60,
    ranksep: 70,
    rankdir: 'LR',
    marginx: 30,
    marginy: 30
  })
    .setDefaultEdgeLabel(function () { return {}; });

  // First set nodes and edges.
  angular.forEach(nodes, function (node) {
    var nodeLabel = node.name.length > 8 ? node.name.substr(0, 5) + '...' : node.name;
    scope.instanceMap[node.name] = node;
    scope.labelMap[nodeLabel] = node;
    g.setNode(node.name, { shape: scope.getShape(node.type), label: nodeLabel});
  });

  angular.forEach(edges, function (edge) {
    g.setEdge(edge.sourceName, edge.targetName);
  });

  angular.extend(renderer.shapes(), scope.getShapes());

  // Set up an SVG group so that we can translate the final graph and tooltip.
  var svg = d3.select('svg').attr('fill', 'white');
  var svgGroup = d3.select('svg g');
  var tip = d3.tip()
    .attr('class', 'd3-tip')
    .offset([-10, 0]);
  svg.call(tip);

  // Set up zoom support
  var zoom = d3.behavior.zoom().on('zoom', function() {
    svgGroup.attr('transform', 'translate(' + d3.event.translate + ')' +
                                'scale(' + d3.event.scale + ')');
  });
  // svg.call(zoom);

  // Run the renderer. This is what draws the final graph.
  renderer(d3.select('svg g'), g);

  // Set up onclick after rendering.
  svg
    .selectAll('g.node')
    .on('click', scope.handleNodeClick);

  svg
    .selectAll('g.node text')
    .on('mouseover', handleShowTip)
    .on('mouseout', handleHideTip);

  // Center svg.
  var initialScale = 1.1;
  var svgWidth = svg.node().getBoundingClientRect().width;
  zoom
    .translate([(svgWidth - g.graph().width * initialScale) / 2, 20])
    .scale(initialScale)
    .event(svg);
  svg.attr('height', g.graph().height * initialScale + 40);

  /**
   * Handles showing tooltip on mouseover of node name.
   */
  function handleShowTip(nodeId) {
    tip
      .html(function(d) {
        return '' + scope.instanceMap[nodeId].type +': '+ nodeId +'';
      })
      .show();
  }

  /**
   * Handles hiding tooltip on mouseout of node name.
   */
  function handleHideTip(nodeId) {
    tip.hide();
  }
};
<commit_msg>fix flow render<commit_after>var module = angular.module(PKG.name+'.commons');

var baseDirective = {
  restrict: 'E',
  templateUrl: 'flow-graph/flow.html',
  scope: {
    model: '='
  },
  controller: 'myFlowController'
};

module.factory('d3', function ($window) {
  return $window.d3;
});

module.factory('dagreD3', function ($window) {
  return $window.dagreD3;
});

module.controller('myFlowController', function($scope, d3, dagreD3) {
  function update(newVal, oldVal) {
    if (angular.isObject(newVal) && Object.keys(newVal).length) {
      $scope.render();
    }
  }

  $scope.instanceMap = {};
  $scope.labelMap = {};

  /**
   * Gets number of instances from node map.
   */
  $scope.getInstances = function(nodeId) {
    return $scope.instanceMap[nodeId].instances ? $scope.instanceMap[nodeId].instances : 0;
  }

  $scope.$watch('model', update);
  $scope.$watchCollection('model.metrics', update);
});

module.directive('myFlowGraph', function ($filter, $state) {
  return angular.extend({
    link: function (scope, elem, attr) {
      scope.render = genericRender.bind(null, scope, $filter);
      var metricCircleRadius = 25;
      var instanceCircleRadius = 10;
      var flowletCircleRadius = 60;
      // Since names are padded inside of shapes, this needs the same padding to be vertically center aligned.
      var metricCountPadding = 5;
      var streamDiagramWidth = 40;
      var streamDiagramHeight = 30;
      var instanceBufferHeight = 30;
      var numberFilter = $filter('myNumber');
      scope.getShapes = function() {
        var shapes = {};
        shapes.flowlet = function(parent, bbox, node) {
          var w = bbox.width;
          var h = bbox.height;
          var points = [
            //clockwise points from top
            { x: -streamDiagramWidth, y: streamDiagramHeight}, //e
            { x: -streamDiagramWidth, y: -h - streamDiagramHeight}, //a
            { x: w/2, y: -h - streamDiagramHeight}, //b
            { x: w, y: -h/2}, //c
            { x: w/2, y: streamDiagramHeight} //d
          ];
          var instances = scope.getInstances(node.elem.__data__); // No other way to get name from node.
          var instanceCircleScaled = scope.getInstancesScaledRadius(instances, instanceCircleRadius);
          var shapeSvg = parent.insert('circle', ':first-child')
            .attr('x', -bbox.width / 2)
            .attr('y', -bbox.height / 2)
            .attr('r', flowletCircleRadius)
            .attr('class', 'flow-shapes foundation-shape flowlet-svg');

          parent.insert('circle')
            .attr('cx', flowletCircleRadius - instanceCircleScaled)
            .attr('cy', -instanceBufferHeight)
            .attr('r', instanceCircleScaled)
            .attr('class', 'flow-shapes flowlet-instances');

          parent.insert('text')
            .attr('x', flowletCircleRadius - instanceCircleScaled)
            .attr('y', -instanceBufferHeight + metricCountPadding)
            .text(instances)
            .attr('class', 'flow-shapes flowlet-instance-count');

          parent.insert('circle')
            .attr('cx', - flowletCircleRadius)
            .attr('r', metricCircleRadius)
            .attr('class', 'flow-shapes flowlet-events');

          parent.insert('text')
            .attr('x', - flowletCircleRadius)
            .attr('y', metricCountPadding)
            .text(numberFilter(scope.model.metrics[scope.labelMap[node.label].name]))
            .attr('class', 'flow5shapes flowlet-event-count');

          node.intersect = function(point) {
            return dagreD3.intersect.circle(node, flowletCircleRadius, point);
          };

          return shapeSvg;
        };

        shapes.stream = function(parent, bbox, node) {
          var w = bbox.width,
          h = bbox.height,
          points = [
            { x:   -streamDiagramWidth, y: streamDiagramHeight}, //e
            { x:   -streamDiagramWidth, y: -h - streamDiagramHeight}, //a
            { x:   w/2, y: -h - streamDiagramHeight}, //b
            { x: w, y: -h/2}, //c
            { x: w/2, y: streamDiagramHeight} //d
          ],
          shapeSvg = parent.insert('polygon', ':first-child')
            .attr('points', points.map(function(d) { return d.x + ',' + d.y; }).join(' '))
            .attr('transform', 'translate(' + (-w/8) + ',' + (h * 1/2) + ')')
            .attr('class', 'flow-shapes foundation-shape stream-svg');

          // Elements are positioned with respect to shapeSvg.
          var width = shapeSvg.node().getBBox().width;
          var circleXPos = -1 * width/2;

          parent.append('circle')
            .attr('cx', circleXPos)
            .attr('r', metricCircleRadius)
            .attr('class', 'flow-shapes stream-events');

          parent.append('text')
            .attr('x', circleXPos)
            .attr('y', metricCountPadding)
            .text(numberFilter(scope.model.metrics[scope.labelMap[node.label].name]))
            .attr('class', 'flow-shapes stream-event-count');

          node.intersect = function(point) {
            return dagreD3.intersect.polygon(node, points, point);
          };

          return shapeSvg;
        };

        return shapes;
      };

      scope.getShape = function(name) {
        var shapeName;

        switch(name) {
          case 'STREAM':
            shapeName = 'stream';
            break;
          default:
            shapeName = 'flowlet';
            break;
        }
        return shapeName;
      };

      scope.handleNodeClick = function(nodeId) {
        scope.handleHideTip(nodeId);
        var instance = scope.instanceMap[nodeId];
        $state.go('flows.detail.runs.tabs.status.flowletsDetail', {flowletId: nodeId});
      };

      /**
       * Radius for instances circle in flowlets. This is a determined as a factor of the size of the
       * instances text.
       */
      scope.getInstancesScaledRadius = function(instances, radius) {
        var base = radius;
        var extra = (instances.toString().length - 1) * base / 2;
        return base + extra;
      }

    }
  }, baseDirective);
});

module.directive('myWorkflowGraph', function ($filter, $state) {
  return angular.extend({
    link: function (scope, elem, attr) {
      scope.render = genericRender.bind(null, scope, $filter);
      var defaultRadius = 50;
      scope.getShapes = function() {
        var shapes = {};
        shapes.job = function(parent, bbox, node) {
          var w = bbox.width;
          var h = bbox.height;
          var points = [
            //clockwise points from top
            { x: -defaultRadius * 2/3, y: -defaultRadius * 2/3}, //a
            { x: 0, y: -defaultRadius}, // b
            { x: defaultRadius * 2/3, y: -defaultRadius * 2/3}, // c
            { x: defaultRadius, y: 0}, // d
            { x: defaultRadius * 2/3, y: defaultRadius * 2/3}, // e
            { x: 0, y: defaultRadius}, // f
            { x: -defaultRadius * 2/3, y: defaultRadius * 2/3}, // g
            { x: -defaultRadius, y: -0}, //h
          ];
          var shapeSvg = parent.insert('polygon', ':first-child')
            .attr('points', points.map(function(p) { return p.x + ',' + p.y; }).join(' '))
            .attr('class', 'workflow-shapes foundation-shape job-svg');

          node.intersect = function(point) {
            return dagreD3.intersect.polygon(node, points, point);
          };

          return shapeSvg;
        };

        shapes.start = function(parent, bbox, node) {
          var w = bbox.width;
          var h = bbox.height;
          var points = [
            // draw a triangle facing right
            { x: -30, y: -40},
            { x: 30, y: 0},
            { x: -30, y: 40},
          ];
          var shapeSvg = parent.insert('polygon', ':first-child')
            .attr('points', points.map(function(p) { return p.x + ',' + p.y; }).join(' '))
            .attr('transform', 'translate(' + (w/6) + ')')
            .attr('class', 'workflow-shapes foundation-shape start-svg');

          node.intersect = function(point) {
            return dagreD3.intersect.polygon(node, points, point);
          };

          return shapeSvg;
        };

        shapes.end = function(parent, bbox, node) {
          var w = bbox.width;
          var h = bbox.height;
          var points = [
            // draw a triangle facing right
            { x: -30, y: 0},
            { x: 30, y: 40},
            { x: 30, y: -40},
          ];
          var shapeSvg = parent.insert('polygon', ':first-child')
            .attr('points', points.map(function(p) { return p.x + ',' + p.y; }).join(' '))
            .attr('transform', 'translate(' + (-w/6) + ')')
            .attr('class', 'workflow-shapes foundation-shape end-svg');

          node.intersect = function(point) {
            return dagreD3.intersect.polygon(node, points, point);
          };

          return shapeSvg;
        };

        shapes.conditional = function(parent, bbox, node) {
          var w = (bbox.width * Math.SQRT2) / 2,
          h = (bbox.height * Math.SQRT2) / 2,
          points = [
            // draw a diamond
            { x:  0, y: -defaultRadius },
            { x: -defaultRadius, y:  0 },
            { x:  0, y:  defaultRadius },
            { x:  defaultRadius, y:  0 }
          ],
          shapeSvg = parent.insert('polygon', ':first-child')
            .attr('points', points.map(function(p) { return p.x + ',' + p.y; }).join(' '))
            .attr('class', 'workflow-shapes foundation-shape conditional-svg');

          node.intersect = function(p) {
            return dagreD3.intersect.polygon(node, points, p);
          };
          return shapeSvg;
        };

        return shapes;
      };

      scope.getShape = function(name) {
        var shapeName;

        switch(name) {
          case 'ACTION':
            shapeName = 'job';
            break;
          case 'START':
            shapeName = 'start';
            break;
          case 'END':
            shapeName = 'end';
            break;
          default:
            shapeName = 'conditional';
            break;
        }
        return shapeName;
      }

      scope.handleNodeClick = function(nodeId) {
        // Temporary fix for 2.8.0. Should be removed first thing post 2.8.
        if ($state.includes('**.workflows.**')) {
          return;
        }
        scope.handleHideTip(nodeId);
        var instance = scope.instanceMap[nodeId];
        $state.go('flows.detail.runs.tabs.status.flowletsDetail', {flowletId: nodeId});
      }

    }
  }, baseDirective);
});

function genericRender(scope, $filter) {
  var nodes = scope.model.nodes;
  var edges = scope.model.edges;

  var renderer = new dagreD3.render();
  var g = new dagreD3.graphlib.Graph();

  g.setGraph({
    nodesep: 60,
    ranksep: 70,
    rankdir: 'LR',
    marginx: 30,
    marginy: 30
  })
    .setDefaultEdgeLabel(function () { return {}; });

  // First set nodes and edges.
  angular.forEach(nodes, function (node) {
    var nodeLabel = node.name.length > 8 ? node.name.substr(0, 5) + '...' : node.name;
    scope.instanceMap[node.name] = node;
    scope.labelMap[nodeLabel] = node;
    g.setNode(node.name, { shape: scope.getShape(node.type), label: nodeLabel});
  });

  angular.forEach(edges, function (edge) {
    g.setEdge(edge.sourceName, edge.targetName);
  });

  angular.extend(renderer.shapes(), scope.getShapes());

  // Set up an SVG group so that we can translate the final graph and tooltip.
  var svg = d3.select('svg').attr('fill', 'white');
  var svgGroup = d3.select('svg g');
  var tip = d3.tip()
    .attr('class', 'd3-tip')
    .offset([-10, 0]);
  svg.call(tip);

  // Set up zoom support
  var zoom = d3.behavior.zoom().on('zoom', function() {
    svgGroup.attr('transform', 'translate(' + d3.event.translate + ')' +
                                'scale(' + d3.event.scale + ')');
  });
  // svg.call(zoom);

  // Run the renderer. This is what draws the final graph.
  renderer(d3.select('svg g'), g);

  // Set up onclick after rendering.
  svg
    .selectAll('g.node')
    .on('click', scope.handleNodeClick);

  svg
    .selectAll('g.node text')
    .on('mouseover', scope.handleShowTip)
    .on('mouseout', scope.handleHideTip);

  // Center svg.
  var initialScale = 1.1;
  var svgWidth = svg.node().getBoundingClientRect().width;
  zoom
    .translate([(svgWidth - g.graph().width * initialScale) / 2, 20])
    .scale(initialScale)
    .event(svg);
  svg.attr('height', g.graph().height * initialScale + 40);

  /**
   * Handles showing tooltip on mouseover of node name.
   */
  scope.handleShowTip = function(nodeId) {
    tip
      .html(function(d) {
        return '' + scope.instanceMap[nodeId].type +': '+ nodeId +'';
      })
      .show();
  }

  /**
   * Handles hiding tooltip on mouseout of node name.
   */
  scope.handleHideTip = function(nodeId) {
    tip.hide();
  }
};
<|endoftext|>


<commit_before>var fs = require("fs");
var json = require("./GCD_9_721_730.json");

var kick_null_object=function(json){
	var newjson=[];
	for (i=0;i<json.length;i++){
		if (json[i].Entry !== "" || json[i].TibetanDefination !== "" || json[i].中文解釋 !== "") newjson.push(json[i]);
	}
	return newjson;
}

var build_cdef_obj=function(json){
	var newjson=[];
	for (i=0;i<json.length;i++){
		var cdef_obj={}, cdef={}, abrr_arr=[], syn_arr=[];
		cdef_obj["page"]=json[i].Page; cdef_obj["entry"]=json[i].Entry; cdef_obj["tdefinition"]=json[i].TibetanDefination;
		if (json[i].中文解釋 !== "") cdef["cdef"]=json[i].中文解釋;
		if (json[i].略語1 !== "") abrr_arr.push(json[i].略語1);
		if (json[i].略語2 !== "") abrr_arr.push(json[i].略語2);
		if (json[i].略語3 !== "") abrr_arr.push(json[i].略語3);
		if (json[i].同義詞1 !== "") syn_arr.push(json[i].同義詞1);
		if (json[i].同義詞2 !== "") syn_arr.push(json[i].同義詞2);
		if (json[i].同義詞3 !== "") syn_arr.push(json[i].同義詞3);
		cdef["abbreviation"] = abrr_arr;
		cdef["synonym"] = syn_arr;
		if (json[i].注記 !== "") cdef["note"] = json[i].注記;
		cdef_obj["cdefinition"] = cdef; newjson.push(cdef_obj);
	}
	return newjson;
};

var build_tdef_obj = function(json){
	var newjson=[], tdef_obj={}, tdef={}, cdefinition=[];
	for (i=0;i<json.length;i++){
		if ( !tdef_obj["page"]) tdef_obj["page"]=json[i].page;
		if ( !tdef_obj["entry"]) tdef_obj["entry"]=json[i].entry;
		if ( !tdef["tdef"]) tdef["tdef"]=json[i].tdefinition;
		cdefinition.push(json[i].cdefinition);
		if ((json[i+1] && json[i+1].entry !== "") || (json[i+1] && json[i+1].tdefinition !== "") || (json[i+1] && json[i+1].cdefinition.abbreviation[0] === "增") || !json[i+1] ){
			tdef["cdefinition"] = cdefinition; tdef_obj["tdefinition"]=tdef; newjson.push(tdef_obj); cdefinition=[]; tdef={}; tdef_obj={};
		}
	}
	return newjson;
}

var build_entry_obj =function(json){
	var newjson=[]; entry_obj={}; tdefinition=[];
	for(i=0;i<json.length;i++){
		if ( !entry_obj["page"]) entry_obj["page"]=json[i].page;
		if ( !entry_obj["entry"]) entry_obj["entry"]=json[i].entry;
		tdefinition.push(json[i].tdefinition);
		if ((json[i+1] && json[i+1].entry !== "") || !json[i+1]){
			entry_obj["tdefinition"]=tdefinition; newjson.push(entry_obj); tdefinition = []; entry_obj={};
		}
	}
	return newjson;
}

var out = kick_null_object(json);
var out2 = build_cdef_obj(out);
var out3 = build_tdef_obj(out2);
var output = build_entry_obj(out3);
fs.writeFileSync("./output.json",JSON.stringify(output,"","  "),"utf8");<commit_msg>add plural<commit_after>var fs = require("fs");
var json = require("./GCD_9_721_730.json");

var kick_null_object=function(json){
	var newjson=[];
	for (i=0;i<json.length;i++){
		if (json[i].Entry !== "" || json[i]["Tibetan Defination"] !== "" || json[i].中文解釋 !== "") newjson.push(json[i]);
	}
	return newjson;
}

var build_cdef_obj=function(json){
	var newjson=[];
	for (i=0;i<json.length;i++){
		var cdef_obj={}, cdef={}, abrr_arr=[], syn_arr=[];
		cdef_obj["page"]=json[i].Page; cdef_obj["entry"]=json[i].Entry; cdef_obj["tdefinition"]=json[i]["Tibetan Defination"];
		if (json[i].中文解釋 !== "") cdef["cdef"]=json[i].中文解釋;
		if (json[i].略語1 !== "") abrr_arr.push(json[i].略語1);
		if (json[i].略語2 !== "") abrr_arr.push(json[i].略語2);
		if (json[i].略語3 !== "") abrr_arr.push(json[i].略語3);
		if (json[i].同義詞1 !== "") syn_arr.push(json[i].同義詞1);
		if (json[i].同義詞2 !== "") syn_arr.push(json[i].同義詞2);
		if (json[i].同義詞3 !== "") syn_arr.push(json[i].同義詞3);
		cdef["abbreviations"] = abrr_arr;
		cdef["synonyms"] = syn_arr;
		if (json[i].注記 !== "") cdef["note"] = json[i].注記;
		cdef_obj["cdefinition"] = cdef; newjson.push(cdef_obj);
	}
	return newjson;
};

var build_tdef_obj = function(json){
	var newjson=[], tdef_obj={}, tdef={}, cdefinitions=[];
	for (i=0;i<json.length;i++){
		if ( !tdef_obj["page"]) tdef_obj["page"]=json[i].page;
		if ( !tdef_obj["entry"]) tdef_obj["entry"]=json[i].entry;
		if ( !tdef["tdef"]) tdef["tdef"]=json[i].tdefinition;
		cdefinitions.push(json[i].cdefinition);
		if ((json[i+1] && json[i+1].entry !== "") || (json[i+1] && json[i+1].tdefinition !== "") || (json[i+1] && json[i+1].cdefinition.abbreviations[0] === "增") || !json[i+1] ){
			tdef["cdefinitions"] = cdefinitions; tdef_obj["tdefinition"]=tdef; newjson.push(tdef_obj); cdefinitions=[]; tdef={}; tdef_obj={};
		}
	}
	return newjson;
}

var build_entry_obj =function(json){
	var newjson=[]; entry_obj={}; tdefinitions=[];
	for(i=0;i<json.length;i++){
		if ( !entry_obj["page"]) entry_obj["page"]=json[i].page;
		if ( !entry_obj["entry"]) entry_obj["entry"]=json[i].entry;
		tdefinitions.push(json[i].tdefinition);
		if ((json[i+1] && json[i+1].entry !== "") || !json[i+1]){
			entry_obj["tdefinitions"]=tdefinitions; newjson.push(entry_obj); tdefinitions = []; entry_obj={};
		}
	}
	return newjson;
}

var out = kick_null_object(json);
var out2 = build_cdef_obj(out);
var out3 = build_tdef_obj(out2);
var output = build_entry_obj(out3);
fs.writeFileSync("./output.json",JSON.stringify(output,"","  "),"utf8");<|endoftext|>


<commit_before>/**
 * the block editing form for editing a single block within a page
 * displayed in the sidebar
 *
 * listens to validation events from block-form and updates validation
 * within the the global vuex state
 */
import { mapState, mapMutations, mapGetters } from 'vuex';
import EditOptions from 'components/EditOptions';

export default {

	name: 'edit-block',

	extends: EditOptions,

	created() {
		eventBus.$on('block:setValidation', this.setValidation);
		eventBus.$on('block:setValidation', this.setValidation);
	},

	computed: {
		...mapGetters([
			'currentBlock',
			'currentDefinition'
		]),

		...mapState({
			currentRegion: state => state.contenteditor.currentRegionName,
			currentSectionName: state => state.contenteditor.currentSectionName,
			currentIndex: state => state.contenteditor.currentBlockIndex
		}),

		definition() {
			return this.currentDefinition;
		},

		currentItem() {
			return this.currentBlock && this.currentBlock.fields;
		},

		identifier() {
			return `${this.currentRegion}_${this.currentSectionName}_${this.currentIndex}`;
		}
	},

	watch: {
		currentBlock(val, oldVal) {
			// if block is removed hide sidebar
			if(val === void 0) {
				this.setBlock();
			}
			// if block changes scroll to top
			if(val && oldVal && val.id !== oldVal.id) {
				this.$refs['options-list'].scrollTop = 0;
			}
		},
	},

	methods: {
		...mapMutations([
			'setBlock',
			'addBlockValidationIssue',
			'deleteBlockValidationIssue'
		]),

		/**
		 * toggles the validation of this current block in the vuex state
		 * @param {bool} status
		 */
		setValidation(status) {
			if (this.currentBlock) {
				if (status) {
					this.deleteBlockValidationIssue(this.currentBlock.id);
				}
				else {
					this.addBlockValidationIssue(this.currentBlock.id);
				}
			}
		}
	}
};
<commit_msg>removed repeated event watcher - my bad :-)<commit_after>/**
 * the block editing form for editing a single block within a page
 * displayed in the sidebar
 *
 * listens to validation events from block-form and updates validation
 * within the the global vuex state
 */
import { mapState, mapMutations, mapGetters } from 'vuex';
import EditOptions from 'components/EditOptions';

export default {

	name: 'edit-block',

	extends: EditOptions,

	created() {
		eventBus.$on('block:setValidation', this.setValidation);
	},

	computed: {
		...mapGetters([
			'currentBlock',
			'currentDefinition'
		]),

		...mapState({
			currentRegion: state => state.contenteditor.currentRegionName,
			currentSectionName: state => state.contenteditor.currentSectionName,
			currentIndex: state => state.contenteditor.currentBlockIndex
		}),

		definition() {
			return this.currentDefinition;
		},

		currentItem() {
			return this.currentBlock && this.currentBlock.fields;
		},

		identifier() {
			return `${this.currentRegion}_${this.currentSectionName}_${this.currentIndex}`;
		}
	},

	watch: {
		currentBlock(val, oldVal) {
			// if block is removed hide sidebar
			if(val === void 0) {
				this.setBlock();
			}
			// if block changes scroll to top
			if(val && oldVal && val.id !== oldVal.id) {
				this.$refs['options-list'].scrollTop = 0;
			}
		},
	},

	methods: {
		...mapMutations([
			'setBlock',
			'addBlockValidationIssue',
			'deleteBlockValidationIssue'
		]),

		/**
		 * toggles the validation of this current block in the vuex state
		 * @param {bool} status
		 */
		setValidation(status) {
			if (this.currentBlock) {
				if (status) {
					this.deleteBlockValidationIssue(this.currentBlock.id);
				}
				else {
					this.addBlockValidationIssue(this.currentBlock.id);
				}
			}
		}
	}
};
<|endoftext|>


<commit_before>// setup scene for workout

var camera, scene, renderer, mesh,
  lastTime = new Date();

function init () {
  var tunnel = new THREE.BoxGeometry( 600, 1200, 3000 );

  var material = new THREE.MeshBasicMaterial({
    color: 0xaffff,
    opacity: 0.5,
    wireframe: true,
    transparent: true
  })

  var tunnelMesh = new THREE.Mesh( tunnel, material );
  tunnelMesh.position.y = 300;
  tunnelMesh.position.z = -1200;

  //

  renderer = new THREE.WebGLRenderer({
    alpha: true
  });
  renderer.setPixelRatio( window.devicePixelRatio );
  renderer.setSize( window.innerWidth, window.innerHeight );
  document.body.appendChild( renderer.domElement );

  //

  camera = new THREE.PerspectiveCamera( 70, window.innerWidth /
    window.innerHeight, 1, 4000 );

  camera.position.y = 400;
  camera.position.z = 100;

  //

  scene = new THREE.Scene();
  scene.add( tunnelMesh );

  window.addEventListener( 'resize', onWindowResize, false );
  document.addEventListener( 'keyup', onKeyUp, false);

  startObstacles();
  addVideoFeed();
}

function startObstacles () {
  setInterval(function(){
    var geometry = new THREE.BoxGeometry( 100, 100, 100 );

    var material = new THREE.MeshBasicMaterial({
      color: 0xaff00,
      wireframe: true,
      wireframeLinewidth: 2
    });

    mesh = new THREE.Mesh( geometry, material );
    mesh.position.y = 400;
    mesh.position.z = -1500;

    var position = {
        x: mesh.position.x,
        y: mesh.position.y,
        z: mesh.position.z
      },
      target = {
        x: 0,
        y: 0,
        z: 3000
      };

    scene.add( mesh );

    doTween(position, target, mesh, TWEEN.Easing.Circular.Out, 100000);

  }, Math.random() * 100 + 3000);
}

function onWindowResize() {

  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize( window.innerWidth, window.innerHeight );

}

function animate() {

  requestAnimationFrame( animate );

  TWEEN.update();

  renderer.render( scene, camera );

}

var cameraMaxY = 400,
  cameraMinY = 200,
  cameraMaxX = 300,
  cameraMinX = -100;

function onKeyUp (event) {
  var increment = 100,
    position = {
      x: camera.position.x,
      y: camera.position.y,
      z: camera.position.z
    },
    target = {
      x: 0,
      y: 0,
      z: 0
    },
    tween;

  event.preventDefault();

  switch(event.keyCode) {
    case 38: //Up
      // if camera not at top position
      if (camera.position.y < cameraMaxY) {
        target.y = cameraMaxY;
        target.z = camera.position.z;

        doTween(position, target, camera, TWEEN.Easing.Circular.Out, increment);
      }
      break;

    case 40: //Down
      if (camera.position.y > cameraMinY) {
        target.y = cameraMinY;
        target.z = camera.position.z;

        doTween(position, target, camera, TWEEN.Easing.Circular.Out, increment);
      }
      break;

    // case 39: //Right
    //   break;

    // case 37:// left
    //   break;
  }

}

function initGyro() {
  var increment = 100,
    position = {
      x: camera.position.x,
      y: camera.position.y,
      z: camera.position.z
    },
    target = {
      x: 0,
      y: 0,
      z: 0
    },
    tween;

  var lastXAccel = false;

  gyro.frequency = 100;

  // some comments
  gyro.startTracking(function(o) {
    console.log("start tracking");
    var xAccel = parseFloat(o.x.toFixed(3)),
      currentTime = new Date(),
      dAccel, timeElapsed;

    if (lastXAccel !== false && lastTime !== false) {
      timeElapsed = currentTime - lastTime;

      if (timeElapsed > 300) {
        dAccel = xAccel - lastXAccel;

        console.log("dAccel: " + dAccel);
        if (dAccel >= 3) {
          console.log("Move up");
          if (camera.position.y < cameraMaxY) {
            target.y = cameraMaxY;
            target.z = camera.position.z;

            doTween(position, target, camera, TWEEN.Easing.Circular.Out,
                increment);
          }

          lastTime = currentTime;

        } else if (dAccel <= -3){
          console.log("Move down");
          if (camera.position.y > cameraMinY) {
            target.y = cameraMinY;
            target.z = camera.position.z;

            doTween(position, target, camera, TWEEN.Easing.Circular.Out,
                increment);
          }

          lastTime = currentTime;
        }
      }
    }
    lastXAccel = xAccel;
  });
}

function doTween (position, target, obj, easing, time) {
  var tween = new TWEEN.Tween(position).to(target, time);

  tween.onUpdate(function(){
    obj.position.x = position.x;
    obj.position.y = position.y;
    obj.position.z = position.z;
  });

  tween.easing(easing);

  tween.start();
}

function videoSuccess (stream) {
  video.src = stream;
  video.play();
}

function videoError (err) {
  console.log(err);
}

function sourceSelected (videoSource) {
  var constraints = {
    // audio: {
    //   optional: [{sourceId: audioSource}]
    // },
    video: {
      optional: [{sourceId: videoSource}]
    }
  };

  navigator.getUserMedia(constraints, videoSuccess, videoError);
}

function addVideoFeed () {
  var videoSource = null,
    video = document.getElementById("video"),
    errBack = function(error) {
      console.log("Video capture error: ", error.code);
    };

    var getUserMedia = navigator.getUserMedia ? function(a, b, c) {
          navigator.getUserMedia(a, b, c);
        } : (navigator.webkitGetUserMedia ? function(a, b, c) {
              navigator.webkitGetUserMedia(a, b, c);
            } : null);

  MediaStreamTrack.getSources(function(sourceInfos) {
    var sourceInfo;

    for (var i = 0; i != sourceInfos.length; ++i) {
      sourceInfo = sourceInfos[i];

      if (sourceInfo.kind === 'video') {
        console.log(sourceInfo);
        videoSource = sourceInfo.id;

      } else {
        console.log('Some other kind of source: ', sourceInfo);
      }
    }

    getUserMedia.call(this, {
      video: {
        optional: [{sourceId: videoSource}]
      }
    }, function(stream) {
      console.log("getUserMedia");
      console.log(video);
      // window.stream = stream; // make stream available to console
      video.src = window.URL.createObjectURL(stream);
      video.play();
    }, errBack);

  });

}

init();
animate();
initGyro();
<commit_msg>showing video error<commit_after>// setup scene for workout

var camera, scene, renderer, mesh,
  lastTime = new Date();

function init () {
  var tunnel = new THREE.BoxGeometry( 600, 1200, 3000 );

  var material = new THREE.MeshBasicMaterial({
    color: 0xaffff,
    opacity: 0.5,
    wireframe: true,
    transparent: true
  })

  var tunnelMesh = new THREE.Mesh( tunnel, material );
  tunnelMesh.position.y = 300;
  tunnelMesh.position.z = -1200;

  //

  renderer = new THREE.WebGLRenderer({
    alpha: true
  });
  renderer.setPixelRatio( window.devicePixelRatio );
  renderer.setSize( window.innerWidth, window.innerHeight );
  document.body.appendChild( renderer.domElement );

  //

  camera = new THREE.PerspectiveCamera( 70, window.innerWidth /
    window.innerHeight, 1, 4000 );

  camera.position.y = 400;
  camera.position.z = 100;

  //

  scene = new THREE.Scene();
  scene.add( tunnelMesh );

  window.addEventListener( 'resize', onWindowResize, false );
  document.addEventListener( 'keyup', onKeyUp, false);

  startObstacles();
  addVideoFeed();
}

function startObstacles () {
  setInterval(function(){
    var geometry = new THREE.BoxGeometry( 100, 100, 100 );

    var material = new THREE.MeshBasicMaterial({
      color: 0xaff00,
      wireframe: true,
      wireframeLinewidth: 2
    });

    mesh = new THREE.Mesh( geometry, material );
    mesh.position.y = 400;
    mesh.position.z = -1500;

    var position = {
        x: mesh.position.x,
        y: mesh.position.y,
        z: mesh.position.z
      },
      target = {
        x: 0,
        y: 0,
        z: 3000
      };

    scene.add( mesh );

    doTween(position, target, mesh, TWEEN.Easing.Circular.Out, 100000);

  }, Math.random() * 100 + 3000);
}

function onWindowResize() {

  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize( window.innerWidth, window.innerHeight );

}

function animate() {

  requestAnimationFrame( animate );

  TWEEN.update();

  renderer.render( scene, camera );

}

var cameraMaxY = 400,
  cameraMinY = 200,
  cameraMaxX = 300,
  cameraMinX = -100;

function onKeyUp (event) {
  var increment = 100,
    position = {
      x: camera.position.x,
      y: camera.position.y,
      z: camera.position.z
    },
    target = {
      x: 0,
      y: 0,
      z: 0
    },
    tween;

  event.preventDefault();

  switch(event.keyCode) {
    case 38: //Up
      // if camera not at top position
      if (camera.position.y < cameraMaxY) {
        target.y = cameraMaxY;
        target.z = camera.position.z;

        doTween(position, target, camera, TWEEN.Easing.Circular.Out, increment);
      }
      break;

    case 40: //Down
      if (camera.position.y > cameraMinY) {
        target.y = cameraMinY;
        target.z = camera.position.z;

        doTween(position, target, camera, TWEEN.Easing.Circular.Out, increment);
      }
      break;

    // case 39: //Right
    //   break;

    // case 37:// left
    //   break;
  }

}

function initGyro() {
  var increment = 100,
    position = {
      x: camera.position.x,
      y: camera.position.y,
      z: camera.position.z
    },
    target = {
      x: 0,
      y: 0,
      z: 0
    },
    tween;

  var lastXAccel = false;

  gyro.frequency = 100;

  // some comments
  gyro.startTracking(function(o) {
    console.log("start tracking");
    var xAccel = parseFloat(o.x.toFixed(3)),
      currentTime = new Date(),
      dAccel, timeElapsed;

    if (lastXAccel !== false && lastTime !== false) {
      timeElapsed = currentTime - lastTime;

      if (timeElapsed > 400) {
        dAccel = xAccel - lastXAccel;

        console.log("dAccel: " + dAccel);
        if (dAccel >= 3) {
          console.log("Move up");
          if (camera.position.y < cameraMaxY) {
            target.y = cameraMaxY;
            target.z = camera.position.z;

            doTween(position, target, camera, TWEEN.Easing.Circular.Out,
                increment);
          }

          lastTime = currentTime;

        } else if (dAccel <= -3){
          console.log("Move down");
          if (camera.position.y > cameraMinY) {
            target.y = cameraMinY;
            target.z = camera.position.z;

            doTween(position, target, camera, TWEEN.Easing.Circular.Out,
                increment);
          }

          lastTime = currentTime;
        }
      }
    }
    lastXAccel = xAccel;
  });
}

function doTween (position, target, obj, easing, time) {
  var tween = new TWEEN.Tween(position).to(target, time);

  tween.onUpdate(function(){
    obj.position.x = position.x;
    obj.position.y = position.y;
    obj.position.z = position.z;
  });

  tween.easing(easing);

  tween.start();
}

function addVideoFeed () {
  var videoSource = null,
    video = document.getElementById("video"),
    errBack = function(error) {
      console.log("Video capture error: ", error);
    };

  var getUserMedia = navigator.getUserMedia ?
      function(a, b, c) { navigator.getUserMedia(a, b, c); } :
      (navigator.webkitGetUserMedia ?
          function(a, b, c) { navigator.webkitGetUserMedia(a, b, c); } : null);

  MediaStreamTrack.getSources(function(sourceInfos) {
    var sourceInfo;

    for (var i = 0; i != sourceInfos.length; ++i) {
      sourceInfo = sourceInfos[i];

      if (sourceInfo.kind === 'video') {
        console.log(sourceInfo);
        videoSource = sourceInfo.id;

      } else {
        console.log('Some other kind of source: ', sourceInfo);
      }
    }

    getUserMedia.call(this, {
      video: {
        optional: [{sourceId: videoSource}]
      }
    }, function(stream) {
      console.log("getUserMedia");
      console.log(video);
      // window.stream = stream; // make stream available to console
      video.src = window.URL.createObjectURL(stream);
      video.play();
    }, errBack);

  });

}

init();
animate();
initGyro();
<|endoftext|>