<commit_before>function Scene() {
    if (typeof Float64Array !== "undefined")
        glMatrixArrayType = Float64Array;

    /**
     * Called by scene.load() to create each individual object in a scene.
     * Hence obj is an object from the demo system specifying options,
     * a label, coordinates, and momentum.
     */
    this.createObject = function (obj) {
        if (typeof obj.options == "undefined") {
            obj.options = {};
        }
        if (typeof obj.label == "undefined") {
            obj.label = "";
        }

        // Copy object-specific options in on top of the global defaults
        obj.options = $.extend({}, this.options, obj.options);

        // Upgrade 2D to 3D
        if (obj.x.length == 2) {
            obj.x[2] = 0;
        }
        if (obj.p && obj.p.length == 2) {
            obj.p[2] = 0;
        }
        if (obj.shape) {
            var thingy = new obj.object(quat4.create([obj.x[0], obj.x[1], obj.x[2], 0]),
                                        quat4.create([obj.p[0], obj.p[1], obj.p[2], 0]), obj.label, obj.options, obj.shape, this.timeStep);
        } else if (obj.v) {
            var thingy = new obj.object(quat4.create([obj.x[0], obj.x[1], obj.x[2], 0]),
                                        quat4.create([obj.v[0], obj.v[1], obj.v[2], 0], obj.label, obj.options));
        } else {
            var thingy = new obj.object(quat4.create([obj.x[0], obj.x[1], obj.x[2], 0]),
                                        quat4.create([obj.p[0], obj.p[1], obj.p[2], 0]), obj.label, obj.options);
        }
        this.carray.push(thingy);

    };

    /**
     * Draw the scene onto the canvas. Uses requestAnimFrame to schedule the
     * next frame.
     */
    this.draw = function() {
        if (this.carray.length === 0) { return; }
        if (this.timeScale == 0) {
            this.frameEndTime = new Date().getTime();
            requestAnimFrame(drawScene);
            return;
        }
        this.frameStartTime = new Date().getTime();
        this.timeStep = (this.frameStartTime - this.frameEndTime) * this.timeScale;

        this.clear();
        drawLightCone(this);
        this.carray.forEach(function(obj) {
            obj.update(this.timeStep);
            obj.draw(this);
            obj.drawXT(this);
        }, this);
        this.drawCrosshairs();
        this.t = this.t + (this.timeStep * c);
        scene.g.fillStyle = "rgba(100,100,100,0.3)";
        scene.g.beginPath();
        scene.g.moveTo(10,10);
        scene.g.lineTo(150,10);
        scene.g.lineTo(150,100);
        scene.g.lineTo(10,100);
        scene.g.closePath();
        scene.g.fill();
        scene.g.fillStyle = "rgba(150,0,150,1)";
        scene.g.fillText("Game Time: " + Math.round(this.t/c) / 1000,30,30);
        scene.g.fillText("Real Time: " + Math.round((this.frameStartTime - this.initialTime)/c) / 1000,30,50);
        if (window.console && window.console.firebug) {
            scene.g.fillText("Fps: " + Math.round((1000/(-this.lastFrameEndTime + this.frameEndTime))),30,70);
            scene.g.fillText("c: " + c,30,90);

        }

        if (leftDown == true)     this.changeArrayFrame(nullQuat4, this.boost.left,  this.carray);
        if (upDown == true)       this.changeArrayFrame(nullQuat4, this.boost.up,    this.carray);
        if (downDown == true)     this.changeArrayFrame(nullQuat4, this.boost.down,  this.carray);
        if (rightDown == true)    this.changeArrayFrame(nullQuat4, this.boost.right, this.carray);
        if (rotLeftDown == true)  this.changeArrayFrame(nullQuat4, rotRight,   this.carray);
        if (rotRightDown == true) this.changeArrayFrame(nullQuat4, rotLeft,    this.carray);
        if (rotUpDown == true)    this.changeArrayFrame(nullQuat4, rotUp,      this.carray);
        if (rotDownDown == true)  this.changeArrayFrame(nullQuat4, rotDown,    this.carray);

        requestAnimFrame(drawScene);
        this.lastFrameEndTime = this.frameEndTime;
        this.frameEndTime = new Date().getTime();
    };

    this.clear = function() {
        this.g.clearRect(0, 0, this.width, this.height);
        this.h.clearRect(0, 0, this.width, this.height);
        this.TDC.clearRect(0, 0, this.width, this.height);
    };

    this.drawCrosshairs = function () {
        this.g.strokeStyle = "#fff";
        this.g.beginPath();
        this.g.moveTo(this.origin[0] - 10, this.origin[1]);
        this.g.lineTo(this.origin[0] + 10, this.origin[1]);
        this.g.stroke();

        this.g.beginPath();
        this.g.moveTo(this.origin[0], this.origin[1] - 10);
        this.g.lineTo(this.origin[0], this.origin[1] + 10);
        this.g.stroke();
    };

    this.startAnimation = function() {
        this.frameEndTime = new Date().getTime();
        this.t = 0;
        if (!this.drawing) {
            this.drawing = true;
            this.draw();
        }
    };

    this.nextStep = function() {
        if (this.curStep + 1 >= this.demo.steps.length)
            return;
        this.curStep += 1;
        this.replay();
    };

    this.prevStep = function() {
        if (this.curStep - 1 < 0)
            return;
        this.curStep -= 1;
        this.replay();
    };

    this.replay = function() {
        this.carray = [];
        this.load(this.demo, this.curStep);
        this.startAnimation();
    };

    this.load = function(demo, step) {
        this.carray = [];
        this.curStep = step;
        this.demo = demo;

        // If the demo specifies global options, set 'em
        if (typeof demo.steps[step].origin === "object") {
            this.origin = demo.steps[step].origin;
        }
        if (typeof demo.steps[step].timeScale === "number") {
            this.timeScale = demo.steps[step].timeScale;
        }
        if (typeof demo.steps[step].zoom === "number") {
            this.zoom = demo.steps[step].zoom;
        }

        // Clone defaults into options, rather than getting a reference to it
        this.options = jQuery.extend({}, this.defaults);

        if (typeof demo.steps[step].options === "object") {
            $.extend(this.options, demo.steps[step].options);
        }

        demo.steps[step].objects.forEach(this.createObject, this);

        $('#caption').html(demo.steps[step].caption);

        // If the demo specifies an object whose frame is preferred, shift to that frame.
        if (typeof demo.steps[step].frame === "number") {
            this.shiftToFrameOfObject(this.carray[demo.steps[step].frame]);
        }
    };

    /**
     * Find the closest object to the given (x,y), within a distance maxDist
     * in screen pixels (i.e. (x,y) is a screen location, not a scaled scene
     * coordinate)
     */
    this.findClosestObject = function(x, y, maxDist) {
        var i = 0;
        var minDist = this.width;
        var minElement = -1;

        for (i = 0; i < this.carray.length; i++) {
            var dist = getDistance([x,y], [this.carray[i].XView[0] / this.zoom + this.origin[0],
                                           this.carray[i].XView[1] / this.zoom + this.origin[1]]);
            if (dist < minDist) {
                minDist = dist;
                minElement = i;
            }
        }

        if (minDist < maxDist) {
            return this.carray[minElement];
        }
        return false;
    };

    // Take a given inertialObject and switch to its reference frame
    this.shiftToFrameOfObject = function(obj) {
        var newFrameBoost = cBoostMat(obj.V, c);

        var XShift = quat4.create(obj.X0);

        this.changeArrayFrame(XShift, newFrameBoost);
    };

    /**
     * Switch every object in the scene to a new reference frame given by
     * the provided translation and boost.
     */
    this.changeArrayFrame = function(translation, boost) {
        this.carray.forEach(function(obj) {
        if( obj.changeFrame) {obj.changeFrame(translation, boost)
        } else { obj.COM.changeFrame(translation, boost)};
        });
    };

    this.initialTime = new Date().getTime();
    this.g = $('#canvas')[0].getContext("2d");
    this.h = $('#minkowski')[0].getContext("2d");
    this.TDC = $('#3DCanvas')[0].getContext("2d");
    this.width = $("#canvas").width();
    this.height = $("#canvas").height();
    this.hwidth = this.width / 2;
    this.hheight = this.height / 2;
    this.origin = [this.hwidth, this.hheight, this.hheight];
    this.carray = [];
    this.zoom = 0.25;
    this.timeStep = 5;
    this.timeScale = 0.02;
    this.t = 0;

    this.defaults = {"showDoppler": true,
                     "showVisualPos": true,
                     "showFramePos": false,
                     "showVelocity": true,
                     "showTime": false,
                     "showGamma": true};

    this.boost = {"left": boostFrom3Vel(-0.005, 0, 0, this.zoom),
                  "right": boostFrom3Vel(0.005, 0, 0, this.zoom),
                  "up": boostFrom3Vel(0, 0.005, 0, this.zoom),
                  "down": boostFrom3Vel(0, -0.005, 0, this.zoom)};

    this.options = {"alwaysDoppler": false,
                    "neverDoppler": false,
                    "alwaysShowFramePos": false,
                    "neverShowFramePos": true,
                    "showTime": false};

    this.gameclock = $("#gameclock");
    this.time = $("#time");

    this.drawing = false;
}

/**
 * Helper function to draw the scene. Necessary because of the setInterval()
 * this problem.
 */
function drawScene(event) {
    scene.draw();
}

function drawLightCone(scene){
    var size = Math.max(scene.width,scene.height);
    scene.h.fillStyle = "#300";
    scene.h.beginPath();
    scene.h.moveTo(-size * c + scene.origin[0], -size + scene.origin[2]);
    scene.h.lineTo(-size * c + scene.origin[0], size + scene.origin[2]);
    scene.h.lineTo( size * c + scene.origin[0], -size + scene.origin[2]);
    scene.h.lineTo( size * c + scene.origin[0], size + scene.origin[2]);
    scene.h.moveTo(-size * c + scene.origin[0], -size + scene.origin[2]);
    scene.h.closePath();
    scene.h.fill();
    scene.h.fillStyle = "#003";
    scene.h.beginPath();
    scene.h.moveTo(-size * c + scene.origin[0], -size + scene.origin[2]);
    scene.h.lineTo( size * c + scene.origin[0], -size + scene.origin[2]);
    scene.h.lineTo(-size * c + scene.origin[0],  size + scene.origin[2]);
    scene.h.lineTo( size * c + scene.origin[0],  size + scene.origin[2]);
    scene.h.moveTo(-size * c + scene.origin[0], -size + scene.origin[2]);
    scene.h.closePath();
    scene.h.fill();
    scene.h.strokeStyle = "#FFF";
    scene.h.lineWidth = 3;
    scene.h.beginPath();
    scene.h.moveTo(0, scene.origin[2]);
    scene.h.lineTo(scene.width, scene.origin[2]);
    scene.h.moveTo(scene.origin[0], 0);
    scene.h.lineTo(scene.origin[0], scene.height);
    scene.h.stroke();
    scene.h.lineWidth = 1;
}
<commit_msg>Don't create jQuery objects for elements which no longer exist.<commit_after>function Scene() {
    if (typeof Float64Array !== "undefined")
        glMatrixArrayType = Float64Array;

    /**
     * Called by scene.load() to create each individual object in a scene.
     * Hence obj is an object from the demo system specifying options,
     * a label, coordinates, and momentum.
     */
    this.createObject = function (obj) {
        if (typeof obj.options == "undefined") {
            obj.options = {};
        }
        if (typeof obj.label == "undefined") {
            obj.label = "";
        }

        // Copy object-specific options in on top of the global defaults
        obj.options = $.extend({}, this.options, obj.options);

        // Upgrade 2D to 3D
        if (obj.x.length == 2) {
            obj.x[2] = 0;
        }
        if (obj.p && obj.p.length == 2) {
            obj.p[2] = 0;
        }
        if (obj.shape) {
            var thingy = new obj.object(quat4.create([obj.x[0], obj.x[1], obj.x[2], 0]),
                                        quat4.create([obj.p[0], obj.p[1], obj.p[2], 0]), obj.label, obj.options, obj.shape, this.timeStep);
        } else if (obj.v) {
            var thingy = new obj.object(quat4.create([obj.x[0], obj.x[1], obj.x[2], 0]),
                                        quat4.create([obj.v[0], obj.v[1], obj.v[2], 0], obj.label, obj.options));
        } else {
            var thingy = new obj.object(quat4.create([obj.x[0], obj.x[1], obj.x[2], 0]),
                                        quat4.create([obj.p[0], obj.p[1], obj.p[2], 0]), obj.label, obj.options);
        }
        this.carray.push(thingy);

    };

    /**
     * Draw the scene onto the canvas. Uses requestAnimFrame to schedule the
     * next frame.
     */
    this.draw = function() {
        if (this.carray.length === 0) { return; }
        if (this.timeScale == 0) {
            this.frameEndTime = new Date().getTime();
            requestAnimFrame(drawScene);
            return;
        }
        this.frameStartTime = new Date().getTime();
        this.timeStep = (this.frameStartTime - this.frameEndTime) * this.timeScale;

        this.clear();
        drawLightCone(this);
        this.carray.forEach(function(obj) {
            obj.update(this.timeStep);
            obj.draw(this);
            obj.drawXT(this);
        }, this);
        this.drawCrosshairs();
        this.t = this.t + (this.timeStep * c);
        scene.g.fillStyle = "rgba(100,100,100,0.3)";
        scene.g.beginPath();
        scene.g.moveTo(10,10);
        scene.g.lineTo(150,10);
        scene.g.lineTo(150,100);
        scene.g.lineTo(10,100);
        scene.g.closePath();
        scene.g.fill();
        scene.g.fillStyle = "rgba(150,0,150,1)";
        scene.g.fillText("Game Time: " + Math.round(this.t/c) / 1000,30,30);
        scene.g.fillText("Real Time: " + Math.round((this.frameStartTime - this.initialTime)/c) / 1000,30,50);
        if (window.console && window.console.firebug) {
            scene.g.fillText("Fps: " + Math.round((1000/(-this.lastFrameEndTime + this.frameEndTime))),30,70);
            scene.g.fillText("c: " + c,30,90);

        }

        if (leftDown == true)     this.changeArrayFrame(nullQuat4, this.boost.left,  this.carray);
        if (upDown == true)       this.changeArrayFrame(nullQuat4, this.boost.up,    this.carray);
        if (downDown == true)     this.changeArrayFrame(nullQuat4, this.boost.down,  this.carray);
        if (rightDown == true)    this.changeArrayFrame(nullQuat4, this.boost.right, this.carray);
        if (rotLeftDown == true)  this.changeArrayFrame(nullQuat4, rotRight,   this.carray);
        if (rotRightDown == true) this.changeArrayFrame(nullQuat4, rotLeft,    this.carray);
        if (rotUpDown == true)    this.changeArrayFrame(nullQuat4, rotUp,      this.carray);
        if (rotDownDown == true)  this.changeArrayFrame(nullQuat4, rotDown,    this.carray);

        requestAnimFrame(drawScene);
        this.lastFrameEndTime = this.frameEndTime;
        this.frameEndTime = new Date().getTime();
    };

    this.clear = function() {
        this.g.clearRect(0, 0, this.width, this.height);
        this.h.clearRect(0, 0, this.width, this.height);
        this.TDC.clearRect(0, 0, this.width, this.height);
    };

    this.drawCrosshairs = function () {
        this.g.strokeStyle = "#fff";
        this.g.beginPath();
        this.g.moveTo(this.origin[0] - 10, this.origin[1]);
        this.g.lineTo(this.origin[0] + 10, this.origin[1]);
        this.g.stroke();

        this.g.beginPath();
        this.g.moveTo(this.origin[0], this.origin[1] - 10);
        this.g.lineTo(this.origin[0], this.origin[1] + 10);
        this.g.stroke();
    };

    this.startAnimation = function() {
        this.frameEndTime = new Date().getTime();
        this.t = 0;
        if (!this.drawing) {
            this.drawing = true;
            this.draw();
        }
    };

    this.nextStep = function() {
        if (this.curStep + 1 >= this.demo.steps.length)
            return;
        this.curStep += 1;
        this.replay();
    };

    this.prevStep = function() {
        if (this.curStep - 1 < 0)
            return;
        this.curStep -= 1;
        this.replay();
    };

    this.replay = function() {
        this.carray = [];
        this.load(this.demo, this.curStep);
        this.startAnimation();
    };

    this.load = function(demo, step) {
        this.carray = [];
        this.curStep = step;
        this.demo = demo;

        // If the demo specifies global options, set 'em
        if (typeof demo.steps[step].origin === "object") {
            this.origin = demo.steps[step].origin;
        }
        if (typeof demo.steps[step].timeScale === "number") {
            this.timeScale = demo.steps[step].timeScale;
        }
        if (typeof demo.steps[step].zoom === "number") {
            this.zoom = demo.steps[step].zoom;
        }

        // Clone defaults into options, rather than getting a reference to it
        this.options = jQuery.extend({}, this.defaults);

        if (typeof demo.steps[step].options === "object") {
            $.extend(this.options, demo.steps[step].options);
        }

        demo.steps[step].objects.forEach(this.createObject, this);

        $('#caption').html(demo.steps[step].caption);

        // If the demo specifies an object whose frame is preferred, shift to that frame.
        if (typeof demo.steps[step].frame === "number") {
            this.shiftToFrameOfObject(this.carray[demo.steps[step].frame]);
        }
    };

    /**
     * Find the closest object to the given (x,y), within a distance maxDist
     * in screen pixels (i.e. (x,y) is a screen location, not a scaled scene
     * coordinate)
     */
    this.findClosestObject = function(x, y, maxDist) {
        var i = 0;
        var minDist = this.width;
        var minElement = -1;

        for (i = 0; i < this.carray.length; i++) {
            var dist = getDistance([x,y], [this.carray[i].XView[0] / this.zoom + this.origin[0],
                                           this.carray[i].XView[1] / this.zoom + this.origin[1]]);
            if (dist < minDist) {
                minDist = dist;
                minElement = i;
            }
        }

        if (minDist < maxDist) {
            return this.carray[minElement];
        }
        return false;
    };

    // Take a given inertialObject and switch to its reference frame
    this.shiftToFrameOfObject = function(obj) {
        var newFrameBoost = cBoostMat(obj.V, c);

        var XShift = quat4.create(obj.X0);

        this.changeArrayFrame(XShift, newFrameBoost);
    };

    /**
     * Switch every object in the scene to a new reference frame given by
     * the provided translation and boost.
     */
    this.changeArrayFrame = function(translation, boost) {
        this.carray.forEach(function(obj) {
        if( obj.changeFrame) {obj.changeFrame(translation, boost)
        } else { obj.COM.changeFrame(translation, boost)};
        });
    };

    this.initialTime = new Date().getTime();
    this.g = $('#canvas')[0].getContext("2d");
    this.h = $('#minkowski')[0].getContext("2d");
    this.TDC = $('#3DCanvas')[0].getContext("2d");
    this.width = $("#canvas").width();
    this.height = $("#canvas").height();
    this.hwidth = this.width / 2;
    this.hheight = this.height / 2;
    this.origin = [this.hwidth, this.hheight, this.hheight];
    this.carray = [];
    this.zoom = 0.25;
    this.timeStep = 5;
    this.timeScale = 0.02;
    this.t = 0;

    this.defaults = {"showDoppler": true,
                     "showVisualPos": true,
                     "showFramePos": false,
                     "showVelocity": true,
                     "showTime": false,
                     "showGamma": true};

    this.boost = {"left": boostFrom3Vel(-0.005, 0, 0, this.zoom),
                  "right": boostFrom3Vel(0.005, 0, 0, this.zoom),
                  "up": boostFrom3Vel(0, 0.005, 0, this.zoom),
                  "down": boostFrom3Vel(0, -0.005, 0, this.zoom)};

    this.options = {"alwaysDoppler": false,
                    "neverDoppler": false,
                    "alwaysShowFramePos": false,
                    "neverShowFramePos": true,
                    "showTime": false};

    this.drawing = false;
}

/**
 * Helper function to draw the scene. Necessary because of the setInterval()
 * this problem.
 */
function drawScene(event) {
    scene.draw();
}

function drawLightCone(scene){
    var size = Math.max(scene.width,scene.height);
    scene.h.fillStyle = "#300";
    scene.h.beginPath();
    scene.h.moveTo(-size * c + scene.origin[0], -size + scene.origin[2]);
    scene.h.lineTo(-size * c + scene.origin[0], size + scene.origin[2]);
    scene.h.lineTo( size * c + scene.origin[0], -size + scene.origin[2]);
    scene.h.lineTo( size * c + scene.origin[0], size + scene.origin[2]);
    scene.h.moveTo(-size * c + scene.origin[0], -size + scene.origin[2]);
    scene.h.closePath();
    scene.h.fill();
    scene.h.fillStyle = "#003";
    scene.h.beginPath();
    scene.h.moveTo(-size * c + scene.origin[0], -size + scene.origin[2]);
    scene.h.lineTo( size * c + scene.origin[0], -size + scene.origin[2]);
    scene.h.lineTo(-size * c + scene.origin[0],  size + scene.origin[2]);
    scene.h.lineTo( size * c + scene.origin[0],  size + scene.origin[2]);
    scene.h.moveTo(-size * c + scene.origin[0], -size + scene.origin[2]);
    scene.h.closePath();
    scene.h.fill();
    scene.h.strokeStyle = "#FFF";
    scene.h.lineWidth = 3;
    scene.h.beginPath();
    scene.h.moveTo(0, scene.origin[2]);
    scene.h.lineTo(scene.width, scene.origin[2]);
    scene.h.moveTo(scene.origin[0], 0);
    scene.h.lineTo(scene.origin[0], scene.height);
    scene.h.stroke();
    scene.h.lineWidth = 1;
}
<|endoftext|>


<commit_before>/**
 * Created by Logos on 2017-06-05.
 */
// Load the http module to create an http server.
var http = require('http');

// Configure our HTTP server to respond with Hello World to all requests.
var server = http.createServer(function (request, response) {
    response.writeHead(200, {"Content-Type": "text/plain"});
    response.end("Hello World\n");
});

// Listen on port 8000, IP defaults to 127.0.0.1
server.listen(8000);

// Put a friendly message on the terminal
console.log("Server running at http://127.0.0.1:8000/");<commit_msg>Initial<commit_after>/**
 * Created by Logos on 2017-06-05.
 */
// Load the http module to create an http server.
var http = require('http');

// Configure our HTTP server to respond with Hello World to all requests.
var server = http.createServer(function (request, response) {
    response.writeHead(200, {"Content-Type": "text/plain"});
    response.end("Hello World\n");
});

// Listen on port 8000, IP defaults to 127.0.0.1
server.listen(8000);

// Put a friendly message on the terminal
console.log("Server running at http://127.0.0.1:8000/");<|endoftext|>


<commit_before>"use strict";

function Scene() {
    if (typeof Float64Array !== "undefined") {
        glMatrixArrayType = Float64Array;
    }

    /** Demo loading functions **/

    /**
     * Load the specified demo at the given step. (The step indexes into
     * the demo's steps array.)
     */
    this.load = function(demo, step) {
        this.carray = [];
        this.curStep = step;
        this.demo = demo;

        // If the demo specifies global options, set 'em
        if (typeof demo.steps[step].origin === "object") {
            this.origin = demo.steps[step].origin;
        }
        if (typeof demo.steps[step].timeScale === "number") {
            this.timeScale = demo.steps[step].timeScale;
        }
        if (typeof demo.steps[step].zoom === "number") {
            this.zoom = demo.steps[step].zoom;
        }

        // Clone defaults into curOptions, rather than getting a reference to it
        this.curOptions = jQuery.extend({}, this.defaults);

        if (typeof demo.steps[step].options === "object") {
            $.extend(this.curOptions, demo.steps[step].options);
        }

        // Update c with the demo's chosen value
        c = (this.curOptions.c) ? this.curOptions.c : 1;

        drawLightCone(this);

        this.boost = {"left": boostFrom3Vel(-0.005, 0, 0, this.zoom),
                      "right": boostFrom3Vel(0.005, 0, 0, this.zoom),
                      "up": boostFrom3Vel(0, 0.005, 0, this.zoom),
                      "down": boostFrom3Vel(0, -0.005, 0, this.zoom)};

        demo.steps[step].objects.forEach(this.createObject, this);

        $('#caption').html(demo.steps[step].caption);

        // If the demo specifies an object whose frame is preferred, shift to that frame.
        if (typeof demo.steps[step].frame === "number") {
            this.shiftToFrameOfObject(this.carray[demo.steps[step].frame], demo.steps[step].shift);
        }
        this.frameStartTime = new Date().getTime();
    };

    /**
     * Called by scene.load() to create each individual object in a scene.
     * Hence obj is an object from the demo system specifying options,
     * a label, coordinates, and momentum.
     */
    this.createObject = function (obj) {
        if (typeof obj.options === "undefined") {
            obj.options = {};
        }
        if (typeof obj.label === "undefined") {
            obj.label = "";
        }

        // Copy object-specific options in on top of the global defaults
        obj.options = $.extend({}, this.curOptions, obj.options);

        // Upgrade 2D to 3D
        if (obj.x.length == 2) {
            obj.x[2] = 0;
        }
        if (obj.p && obj.p.length == 2) {
            obj.p[2] = 0;
        }
        var thingy;
        if (obj.shape) {
            thingy = new obj.object(quat4.create([obj.x[0], obj.x[1], obj.x[2], 0]),
                                    quat4.create([obj.p[0], obj.p[1], obj.p[2], 0]), obj.label, obj.options, obj.shape);
        } else if (obj.v) {
            thingy = new obj.object(quat4.create([obj.x[0], obj.x[1], obj.x[2], 0]),
                                    quat4.create([obj.v[0], obj.v[1], obj.v[2], 0]), obj.label, obj.options);
        } else {
            thingy = new obj.object(quat4.create([obj.x[0], obj.x[1], obj.x[2], 0]),
                                    quat4.create([obj.p[0], obj.p[1], obj.p[2], 0]), obj.label, obj.options);
        }
        this.carray.push(thingy);
    };

    /** Scene drawing functions **/

    /**
     * Draw the scene onto the canvas. Uses requestAnimFrame to schedule the
     * next frame.
     */
    this.draw = function() {
        this.oldFrameStartTime = this.frameStartTime;
        this.frameStartTime = new Date().getTime();
        var timeStep = 0;
        if (this.drawing){
            timeStep = (this.frameStartTime - this.oldFrameStartTime) * this.timeScale;
        }
        this.clear();

        this.h.drawImage(this.lightConeCanvas, 0, 0);
        this.carray.forEach(function(obj) {
            obj.update(timeStep);
            obj.draw(this);
            obj.drawXT(this);
        }, this);
        this.drawCrosshairs();
        this.drawInfo();
        this.t = this.t + (timeStep * c);

        if (leftDown === true)     this.changeArrayFrame(nullQuat4, this.boost.left );
        if (upDown === true)       this.changeArrayFrame(nullQuat4, this.boost.up   );
        if (downDown === true)     this.changeArrayFrame(nullQuat4, this.boost.down );
        if (rightDown === true)    this.changeArrayFrame(nullQuat4, this.boost.right);
        if (rotLeftDown === true)  this.changeArrayFrame(nullQuat4, rotRight);
        if (rotRightDown === true) this.changeArrayFrame(nullQuat4, rotLeft );
        if (rotUpDown === true)    this.changeArrayFrame(nullQuat4, rotUp   );
        if (rotDownDown === true)  this.changeArrayFrame(nullQuat4, rotDown );

        if (this.drawing || this.keyDown) {
            requestAnimFrame(drawScene);
        }
        this.lastFrameEndTime = this.frameEndTime;
        this.frameEndTime = new Date().getTime();
    };

    this.drawInfo = function() {
        scene.g.fillStyle = "rgba(100,100,100,0.3)";
        scene.g.beginPath();
        scene.g.moveTo(10,10);
        scene.g.lineTo(150,10);
        scene.g.lineTo(150,100);
        scene.g.lineTo(10,100);
        scene.g.closePath();
        scene.g.fill();
        scene.g.fillStyle = "rgba(150,0,150,1)";
        scene.g.fillText("Game Time: " + Math.round(this.t/c), 30, 30);
        scene.g.fillText("Real Time: " + Math.round((this.frameStartTime - this.initialTime)/c) / 1000, 30, 50);

        if (window.console && window.console.firebug) {
            scene.g.fillText("Fps: " + Math.round((1000 / (-this.lastFrameEndTime + this.frameEndTime))), 30, 70);
            scene.g.fillText("c: " + c, 30, 80);
            scene.g.fillText("keyCode: " + this.kC, 30, 90);
        }
    };

    this.drawCrosshairs = function () {
        this.g.strokeStyle = "#fff";
        this.g.beginPath();
        this.g.moveTo(this.origin[0] - 10, this.origin[1]);
        this.g.lineTo(this.origin[0] + 10, this.origin[1]);
        this.g.stroke();

        this.g.beginPath();
        this.g.moveTo(this.origin[0], this.origin[1] - 10);
        this.g.lineTo(this.origin[0], this.origin[1] + 10);
        this.g.stroke();
    };

    this.clear = function() {
        this.g.clearRect(0, 0, this.width, this.height);
        this.h.clearRect(0, 0, this.mWidth, this.mHeight);
        this.TDC.clearRect(0, 0, this.tWidth, this.tHeight);
    };

    /** Animation and step control functions **/

    this.startAnimation = function() {
        // Frame timing is used to maintain constant speed. Reset.
        this.frameEndTime = new Date().getTime();
        this.initialTime = new Date().getTime();
        this.t = 0;

        // If not currently animating, draw the first frame.
        if (!this.drawing) {
            this.draw();
        }
    };

    this.nextStep = function() {
        if (this.curStep + 1 < this.demo.steps.length) {
            this.curStep += 1;
            this.replay();
        }
    };

    this.prevStep = function() {
        if (this.curStep > 0) {
            this.curStep -= 1;
            this.replay();
        }
    };

    /**
     * Reload the current demo from scratch and restart the animation.
     */
    this.replay = function() {
        this.load(this.demo, this.curStep);
        this.startAnimation();
    };

    this.pause = function() {
        if (!this.drawing) {
            this.frameStartTime = new Date().getTime();
            this.drawing = true;
            this.draw();
        } else {
            this.drawing = false;
        }
    };

    /** Object utilities **/

    /**
     * Find the closest object to the given (x,y), within a distance maxDist
     * in screen pixels (i.e. (x,y) is a screen location, not a scaled scene
     * coordinate)
     */
    this.findClosestObject = function(x, y, maxDist) {
        var minDist = this.width;
        var minElement = -1;

        for (var i = 0; i < this.carray.length; i++) {
            var dist = getDistance([x,y], [this.carray[i].XView[0] / this.zoom + this.origin[0],
                                           -this.carray[i].XView[1] / this.zoom + this.origin[1]]);
            if (dist < minDist) {
                minDist = dist;
                minElement = i;
            }
        }

        if (minDist < maxDist) {
            return this.carray[minElement];
        }
        return false;
    };

    // Take a given inertialObject and switch to its reference frame
    this.shiftToFrameOfObject = function(obj, shift) {
        if (shift) { this.changeArrayFrame(quat4.create(obj.X0), cBoostMat(obj.V, c), shift);}
        else { this.changeArrayFrame(quat4.create(obj.X0), cBoostMat(obj.V, c));}
    };

    /**
     * Switch every object in the scene to a new reference frame given by
     * the provided translation and boost.
     */
    this.changeArrayFrame = function(translation1, boost, translation2) {
        if (translation2){
            this.carray.forEach(function(obj) {
                obj.changeFrame(translation1, boost, translation2);
            });
        } else {
            this.carray.forEach(function(obj) {
                obj.changeFrame(translation1, boost);
            });
        }

    };

    this.initialTime = new Date().getTime();
    this.g = $('#canvas')[0].getContext("2d");
    this.h = $('#minkowski')[0].getContext("2d");
    this.TDC = $('#3DCanvas')[0].getContext("2d");
    this.width = $("#canvas").width();
    this.height = $("#canvas").height();
    this.mWidth = $("#minkowski").width();
    this.mHeight = $("#minkowski").height();
    this.tWidth = $("#3DCanvas").width();
    this.tHeight = $("#3DCanvas").height();

    this.lightConeCanvas = document.createElement('canvas');
    this.lightConeCanvas.width =  this.mWidth;
    this.lightConeCanvas.height =  this.mHeight;
    this.lCCtx = this.lightConeCanvas.getContext('2d');
    this.kC = 0;
    this.camBack = 0;
    this.hwidth = this.width / 2;
    this.hheight = this.height / 2;
    this.origin = [this.hwidth, this.hheight, this.hheight];
    this.carray = [];
    this.zoom = 0.25;
    this.timeScale = 0.02;
    this.t = 0;
    this.defaults = {"showDoppler": true,
                     "showVisualPos": true,
                     "showFramePos": false,
                     "showVelocity": true,
                     "showTime": false,
                     "showGamma": true,
                     "show3D": false,
                     "showPos": false,
                     "c": 3};

    this.options = {"alwaysDoppler": false,
                    "neverDoppler": false,
                    "alwaysShowFramePos": false,
                    "neverShowFramePos": false,
                    "alwaysShowVisualPos": false,
                    "neverShowVisualPos": false,
                    "showTime": false};

    this.drawing = true;
}

/**
 * Helper function to draw the scene. Necessary because of the setInterval()
 * this problem.
 */
function drawScene(event) {
    scene.draw();
}

function drawLightCone(scene){
    var size = Math.max(scene.mHeight - scene.origin[2], scene.origin[2]);
    scene.lCCtx.fillStyle = "#300";
    scene.lCCtx.beginPath();
    scene.lCCtx.moveTo(0,0);
    scene.lCCtx.lineTo(0, scene.mHeight);
    scene.lCCtx.lineTo(-size * c + scene.origin[0], size + scene.origin[2]);
    scene.lCCtx.lineTo( size * c + scene.origin[0], -size + scene.origin[2]);
    scene.lCCtx.lineTo(scene.mWidth, 0);
    scene.lCCtx.lineTo(scene.mWidth, scene.mHeight);
    scene.lCCtx.lineTo( size * c + scene.origin[0], size + scene.origin[2]);
    scene.lCCtx.lineTo(-size * c + scene.origin[0], -size + scene.origin[2]);
    scene.lCCtx.closePath();
    scene.lCCtx.fill();
    scene.lCCtx.fillStyle = "#003";
    scene.lCCtx.beginPath();
    scene.lCCtx.moveTo(-size * c + scene.origin[0], -size + scene.origin[2]);
    scene.lCCtx.lineTo( size * c + scene.origin[0], -size + scene.origin[2]);
    scene.lCCtx.lineTo(-size * c + scene.origin[0],  size + scene.origin[2]);
    scene.lCCtx.lineTo( size * c + scene.origin[0],  size + scene.origin[2]);
    scene.lCCtx.moveTo(-size * c + scene.origin[0], -size + scene.origin[2]);
    scene.lCCtx.closePath();
    scene.lCCtx.fill();
    scene.lCCtx.strokeStyle = "#FFF";
    scene.lCCtx.lineWidth = 3;
    scene.lCCtx.beginPath();
    scene.lCCtx.moveTo(0, scene.origin[2]);
    scene.lCCtx.lineTo(scene.mWidth, scene.origin[2]);
    scene.lCCtx.moveTo(scene.origin[0], 0);
    scene.lCCtx.lineTo(scene.origin[0], scene.mHeight);
    scene.lCCtx.stroke();
    scene.lCCtx.lineWidth = 1;
    scene.lCCtx.fillStyle = "#fff";
    scene.lCCtx.fillText("t(s)", 5 + scene.origin[0], 10);
    scene.lCCtx.fillText("x(m)", scene.width - 30, scene.origin[2] - 10);
}
<commit_msg>Scene.js was assuming Date().Time() was in metres.<commit_after>"use strict";

function Scene() {
    if (typeof Float64Array !== "undefined") {
        glMatrixArrayType = Float64Array;
    }

    /** Demo loading functions **/

    /**
     * Load the specified demo at the given step. (The step indexes into
     * the demo's steps array.)
     */
    this.load = function(demo, step) {
        this.carray = [];
        this.curStep = step;
        this.demo = demo;

        // If the demo specifies global options, set 'em
        if (typeof demo.steps[step].origin === "object") {
            this.origin = demo.steps[step].origin;
        }
        if (typeof demo.steps[step].timeScale === "number") {
            this.timeScale = demo.steps[step].timeScale;
        }
        if (typeof demo.steps[step].zoom === "number") {
            this.zoom = demo.steps[step].zoom;
        }

        // Clone defaults into curOptions, rather than getting a reference to it
        this.curOptions = jQuery.extend({}, this.defaults);

        if (typeof demo.steps[step].options === "object") {
            $.extend(this.curOptions, demo.steps[step].options);
        }

        // Update c with the demo's chosen value
        c = (this.curOptions.c) ? this.curOptions.c : 1;

        drawLightCone(this);

        this.boost = {"left": boostFrom3Vel(-0.005, 0, 0, this.zoom),
                      "right": boostFrom3Vel(0.005, 0, 0, this.zoom),
                      "up": boostFrom3Vel(0, 0.005, 0, this.zoom),
                      "down": boostFrom3Vel(0, -0.005, 0, this.zoom)};

        demo.steps[step].objects.forEach(this.createObject, this);

        $('#caption').html(demo.steps[step].caption);

        // If the demo specifies an object whose frame is preferred, shift to that frame.
        if (typeof demo.steps[step].frame === "number") {
            this.shiftToFrameOfObject(this.carray[demo.steps[step].frame], demo.steps[step].shift);
        }
        this.frameStartTime = new Date().getTime();
    };

    /**
     * Called by scene.load() to create each individual object in a scene.
     * Hence obj is an object from the demo system specifying options,
     * a label, coordinates, and momentum.
     */
    this.createObject = function (obj) {
        if (typeof obj.options === "undefined") {
            obj.options = {};
        }
        if (typeof obj.label === "undefined") {
            obj.label = "";
        }

        // Copy object-specific options in on top of the global defaults
        obj.options = $.extend({}, this.curOptions, obj.options);

        // Upgrade 2D to 3D
        if (obj.x.length == 2) {
            obj.x[2] = 0;
        }
        if (obj.p && obj.p.length == 2) {
            obj.p[2] = 0;
        }
        var thingy;
        if (obj.shape) {
            thingy = new obj.object(quat4.create([obj.x[0], obj.x[1], obj.x[2], 0]),
                                    quat4.create([obj.p[0], obj.p[1], obj.p[2], 0]), obj.label, obj.options, obj.shape);
        } else if (obj.v) {
            thingy = new obj.object(quat4.create([obj.x[0], obj.x[1], obj.x[2], 0]),
                                    quat4.create([obj.v[0], obj.v[1], obj.v[2], 0]), obj.label, obj.options);
        } else {
            thingy = new obj.object(quat4.create([obj.x[0], obj.x[1], obj.x[2], 0]),
                                    quat4.create([obj.p[0], obj.p[1], obj.p[2], 0]), obj.label, obj.options);
        }
        this.carray.push(thingy);
    };

    /** Scene drawing functions **/

    /**
     * Draw the scene onto the canvas. Uses requestAnimFrame to schedule the
     * next frame.
     */
    this.draw = function() {
        this.oldFrameStartTime = this.frameStartTime;
        this.frameStartTime = new Date().getTime();
        var timeStep = 0;
        if (this.drawing){
            timeStep = (this.frameStartTime - this.oldFrameStartTime) * this.timeScale * c;
        }
        this.clear();

        this.h.drawImage(this.lightConeCanvas, 0, 0);
        this.carray.forEach(function(obj) {
            obj.update(timeStep);
            obj.draw(this);
            obj.drawXT(this);
        }, this);
        this.drawCrosshairs();
        this.drawInfo();
        this.t = this.t + (timeStep);

        if (leftDown === true)     this.changeArrayFrame(nullQuat4, this.boost.left );
        if (upDown === true)       this.changeArrayFrame(nullQuat4, this.boost.up   );
        if (downDown === true)     this.changeArrayFrame(nullQuat4, this.boost.down );
        if (rightDown === true)    this.changeArrayFrame(nullQuat4, this.boost.right);
        if (rotLeftDown === true)  this.changeArrayFrame(nullQuat4, rotRight);
        if (rotRightDown === true) this.changeArrayFrame(nullQuat4, rotLeft );
        if (rotUpDown === true)    this.changeArrayFrame(nullQuat4, rotUp   );
        if (rotDownDown === true)  this.changeArrayFrame(nullQuat4, rotDown );

        if (this.drawing || this.keyDown) {
            requestAnimFrame(drawScene);
        }
        this.lastFrameEndTime = this.frameEndTime;
        this.frameEndTime = new Date().getTime();
    };

    this.drawInfo = function() {
        scene.g.fillStyle = "rgba(100,100,100,0.3)";
        scene.g.beginPath();
        scene.g.moveTo(10,10);
        scene.g.lineTo(150,10);
        scene.g.lineTo(150,100);
        scene.g.lineTo(10,100);
        scene.g.closePath();
        scene.g.fill();
        scene.g.fillStyle = "rgba(150,0,150,1)";
        scene.g.fillText("Game Time: " + Math.round(this.t/c), 30, 30);
        scene.g.fillText("Real Time: " + Math.round((this.frameStartTime - this.initialTime)/c) / 1000, 30, 50);

        if (window.console && window.console.firebug) {
            scene.g.fillText("Fps: " + Math.round((1000 / (-this.lastFrameEndTime + this.frameEndTime))), 30, 70);
            scene.g.fillText("c: " + c, 30, 80);
            scene.g.fillText("keyCode: " + this.kC, 30, 90);
        }
    };

    this.drawCrosshairs = function () {
        this.g.strokeStyle = "#fff";
        this.g.beginPath();
        this.g.moveTo(this.origin[0] - 10, this.origin[1]);
        this.g.lineTo(this.origin[0] + 10, this.origin[1]);
        this.g.stroke();

        this.g.beginPath();
        this.g.moveTo(this.origin[0], this.origin[1] - 10);
        this.g.lineTo(this.origin[0], this.origin[1] + 10);
        this.g.stroke();
    };

    this.clear = function() {
        this.g.clearRect(0, 0, this.width, this.height);
        this.h.clearRect(0, 0, this.mWidth, this.mHeight);
        this.TDC.clearRect(0, 0, this.tWidth, this.tHeight);
    };

    /** Animation and step control functions **/

    this.startAnimation = function() {
        // Frame timing is used to maintain constant speed. Reset.
        this.frameEndTime = new Date().getTime();
        this.initialTime = new Date().getTime();
        this.t = 0;

        // If not currently animating, draw the first frame.
        if (!this.drawing) {
            this.draw();
        }
    };

    this.nextStep = function() {
        if (this.curStep + 1 < this.demo.steps.length) {
            this.curStep += 1;
            this.replay();
        }
    };

    this.prevStep = function() {
        if (this.curStep > 0) {
            this.curStep -= 1;
            this.replay();
        }
    };

    /**
     * Reload the current demo from scratch and restart the animation.
     */
    this.replay = function() {
        this.load(this.demo, this.curStep);
        this.startAnimation();
    };

    this.pause = function() {
        if (!this.drawing) {
            this.frameStartTime = new Date().getTime();
            this.drawing = true;
            this.draw();
        } else {
            this.drawing = false;
        }
    };

    /** Object utilities **/

    /**
     * Find the closest object to the given (x,y), within a distance maxDist
     * in screen pixels (i.e. (x,y) is a screen location, not a scaled scene
     * coordinate)
     */
    this.findClosestObject = function(x, y, maxDist) {
        var minDist = this.width;
        var minElement = -1;

        for (var i = 0; i < this.carray.length; i++) {
            var dist = getDistance([x,y], [this.carray[i].XView[0] / this.zoom + this.origin[0],
                                           -this.carray[i].XView[1] / this.zoom + this.origin[1]]);
            if (dist < minDist) {
                minDist = dist;
                minElement = i;
            }
        }

        if (minDist < maxDist) {
            return this.carray[minElement];
        }
        return false;
    };

    // Take a given inertialObject and switch to its reference frame
    this.shiftToFrameOfObject = function(obj, shift) {
        if (shift) { this.changeArrayFrame(quat4.create(obj.X0), cBoostMat(obj.V, c), shift);}
        else { this.changeArrayFrame(quat4.create(obj.X0), cBoostMat(obj.V, c));}
    };

    /**
     * Switch every object in the scene to a new reference frame given by
     * the provided translation and boost.
     */
    this.changeArrayFrame = function(translation1, boost, translation2) {
        if (translation2){
            this.carray.forEach(function(obj) {
                obj.changeFrame(translation1, boost, translation2);
            });
        } else {
            this.carray.forEach(function(obj) {
                obj.changeFrame(translation1, boost);
            });
        }

    };

    this.initialTime = new Date().getTime();
    this.g = $('#canvas')[0].getContext("2d");
    this.h = $('#minkowski')[0].getContext("2d");
    this.TDC = $('#3DCanvas')[0].getContext("2d");
    this.width = $("#canvas").width();
    this.height = $("#canvas").height();
    this.mWidth = $("#minkowski").width();
    this.mHeight = $("#minkowski").height();
    this.tWidth = $("#3DCanvas").width();
    this.tHeight = $("#3DCanvas").height();

    this.lightConeCanvas = document.createElement('canvas');
    this.lightConeCanvas.width =  this.mWidth;
    this.lightConeCanvas.height =  this.mHeight;
    this.lCCtx = this.lightConeCanvas.getContext('2d');
    this.kC = 0;
    this.camBack = 0;
    this.hwidth = this.width / 2;
    this.hheight = this.height / 2;
    this.origin = [this.hwidth, this.hheight, this.hheight];
    this.carray = [];
    this.zoom = 0.25;
    this.timeScale = 0.02;
    this.t = 0;
    this.defaults = {"showDoppler": true,
                     "showVisualPos": true,
                     "showFramePos": false,
                     "showVelocity": true,
                     "showTime": false,
                     "showGamma": true,
                     "show3D": false,
                     "showPos": false,
                     "c": 30};

    this.options = {"alwaysDoppler": false,
                    "neverDoppler": false,
                    "alwaysShowFramePos": false,
                    "neverShowFramePos": false,
                    "alwaysShowVisualPos": false,
                    "neverShowVisualPos": false,
                    "showTime": false};

    this.drawing = true;
}

/**
 * Helper function to draw the scene. Necessary because of the setInterval()
 * this problem.
 */
function drawScene(event) {
    scene.draw();
}

function drawLightCone(scene){
    var size = Math.max(scene.mHeight - scene.origin[2], scene.origin[2]);
    scene.lCCtx.fillStyle = "#300";
    scene.lCCtx.beginPath();
    scene.lCCtx.moveTo(0,0);
    scene.lCCtx.lineTo(0, scene.mHeight);
    scene.lCCtx.lineTo(-size * c + scene.origin[0], size + scene.origin[2]);
    scene.lCCtx.lineTo( size * c + scene.origin[0], -size + scene.origin[2]);
    scene.lCCtx.lineTo(scene.mWidth, 0);
    scene.lCCtx.lineTo(scene.mWidth, scene.mHeight);
    scene.lCCtx.lineTo( size * c + scene.origin[0], size + scene.origin[2]);
    scene.lCCtx.lineTo(-size * c + scene.origin[0], -size + scene.origin[2]);
    scene.lCCtx.closePath();
    scene.lCCtx.fill();
    scene.lCCtx.fillStyle = "#003";
    scene.lCCtx.beginPath();
    scene.lCCtx.moveTo(-size * c + scene.origin[0], -size + scene.origin[2]);
    scene.lCCtx.lineTo( size * c + scene.origin[0], -size + scene.origin[2]);
    scene.lCCtx.lineTo(-size * c + scene.origin[0],  size + scene.origin[2]);
    scene.lCCtx.lineTo( size * c + scene.origin[0],  size + scene.origin[2]);
    scene.lCCtx.moveTo(-size * c + scene.origin[0], -size + scene.origin[2]);
    scene.lCCtx.closePath();
    scene.lCCtx.fill();
    scene.lCCtx.strokeStyle = "#FFF";
    scene.lCCtx.lineWidth = 3;
    scene.lCCtx.beginPath();
    scene.lCCtx.moveTo(0, scene.origin[2]);
    scene.lCCtx.lineTo(scene.mWidth, scene.origin[2]);
    scene.lCCtx.moveTo(scene.origin[0], 0);
    scene.lCCtx.lineTo(scene.origin[0], scene.mHeight);
    scene.lCCtx.stroke();
    scene.lCCtx.lineWidth = 1;
    scene.lCCtx.fillStyle = "#fff";
    scene.lCCtx.fillText("t(s)", 5 + scene.origin[0], 10);
    scene.lCCtx.fillText("x(m)", scene.width - 30, scene.origin[2] - 10);
}
<|endoftext|>


<commit_before>'use strict';

var imagePaths = ['bag.jpg', 'banana.jpg', 'bathroom.jpg', 'boots.jpg', 'breakfast.jpg', 'bubblegum.jpg', 'chair.jpg', 'cthulhu.jpg', 'dog-duck.jpg', 'dragon.jpg', 'pen.jpg', 'pet-sweep.jpg', 'scissors.jpg', 'shark.jpg', 'sweep.png', 'tauntaun.jpg', 'unicorn.jpg', 'usb.gif', 'water-can.jpg', 'wine-glass.jpg'];
var images = [];
var currentImageIndices = [0, 1, 2];

// Looping through imagePaths array to create new Image object for each, which pushes to images array
for (var i = 0; i < imagePaths.length; i++) {
  var name = imagePaths[i];
  new Image(null, name);
}

// Create image li elements
var imageList = document.getElementById('images');

// Add event listener clickHandler for event 'click'
imageList.addEventListener('click', clickHandler);

// Use drawImage function to render an imageList (pass argument of currentImageIndices to ensure three different images are presented)
drawImage(0);
drawImage(1);
drawImage(2);

// Create clickHandler function for event 'click' which calls on drawImage function

function clickHandler(event) {
  console.log('Event target:', event.target);
  var matchPath = event.target.getAttribute('src');
  console.log('Match path:', matchPath);
  var arrayOfRandomIndices = randomIndices();
  console.log('Array of random indices:', arrayOfRandomIndices);

  for(var j = 0; j < currentImageIndices.length; j++) {
    var currentIndex = currentImageIndices[j];
    var displayedObject = images[currentIndex];
    displayedObject.views += 1;
  }

// Use event target to determine which image was clicked (loop through and compare paths of each)
  for (var k = 0; k < images.length; k++) {
    var currentImageObject = images[k];
    console.log('Images:', k, currentImageObject);
    if (currentImageObject.path === matchPath) {
      console.log('Found it!', currentImageObject);
      currentImageObject.clicks += 1
    }
  }
  currentImageIndices = arrayOfRandomIndices;
// Reset imageList;
    imageList.textContent = '';
    drawImage(arrayOfRandomIndices[0]);
    drawImage(arrayOfRandomIndices[1]);
    drawImage(arrayOfRandomIndices[2]);
}

// Create function to randomize image list by accessing three random indices of images array (if equal, generates new random number)
function randomIndices() {
  var firstRandomIndex = Math.floor(Math.random() * images.length);
  var secondRandomIndex = Math.floor(Math.random() * images.length);

  while (firstRandomIndex === secondRandomIndex) {
    secondRandomIndex = Math.floor(Math.random() * images.length);
  }

  var thirdRandomIndex = Math.floor(Math.random() * images.length);

  while (thirdRandomIndex === firstRandomIndex || thirdRandomIndex === secondRandomIndex) {
    thirdRandomIndex = Math.floor(Math.random() * images.length);
  }
  return [firstRandomIndex, secondRandomIndex, thirdRandomIndex];
}

// Create function to draw images based on object path
function drawImage(index) {
// Use the image path for the src
// (image.path)
    var img = document.createElement('img');
    var li = document.createElement('li');
    var imageList = document.getElementById('images');
    var randomPath = images[index].path;

// Set src
    img.setAttribute('src', randomPath);

// Add to DOM
    li.appendChild(img);
    imageList.appendChild(li);
}

function Image(name, path) {
  this.views = 0;
  this.clicks = 0;
  this.name = name;
  this.path = 'imgs/' + path;

  images.push(this);
}
<commit_msg>added more comments for randomIndices function<commit_after>'use strict';

var imagePaths = ['bag.jpg', 'banana.jpg', 'bathroom.jpg', 'boots.jpg', 'breakfast.jpg', 'bubblegum.jpg', 'chair.jpg', 'cthulhu.jpg', 'dog-duck.jpg', 'dragon.jpg', 'pen.jpg', 'pet-sweep.jpg', 'scissors.jpg', 'shark.jpg', 'sweep.png', 'tauntaun.jpg', 'unicorn.jpg', 'usb.gif', 'water-can.jpg', 'wine-glass.jpg'];
var images = [];
var currentImageIndices = [0, 1, 2];

// Looping through imagePaths array to create new Image object for each, which pushes to images array
for (var i = 0; i < imagePaths.length; i++) {
  var name = imagePaths[i];
  new Image(null, name);
}

// Create image li elements
var imageList = document.getElementById('images');

// Add event listener clickHandler for event 'click'
imageList.addEventListener('click', clickHandler);

// Use drawImage function to render an imageList (pass argument of currentImageIndices to ensure three different images are presented)
drawImage(0);
drawImage(1);
drawImage(2);

// Create clickHandler function for event 'click' which calls on drawImage function

function clickHandler(event) {
  console.log('Event target:', event.target);
  var matchPath = event.target.getAttribute('src');
  console.log('Match path:', matchPath);
  var arrayOfRandomIndices = randomIndices();
  console.log('Array of random indices:', arrayOfRandomIndices);

  for(var j = 0; j < currentImageIndices.length; j++) {
    var currentIndex = currentImageIndices[j];
    var displayedObject = images[currentIndex];
    displayedObject.views += 1;
  }

// Use event target to determine which image was clicked (loop through and compare paths of each)
  for (var k = 0; k < images.length; k++) {
    var currentImageObject = images[k];
    console.log('Images:', k, currentImageObject);
    if (currentImageObject.path === matchPath) {
      console.log('Found it!', currentImageObject);
      currentImageObject.clicks += 1
    }
  }
  currentImageIndices = arrayOfRandomIndices;
// Reset imageList;
    imageList.textContent = '';
    drawImage(arrayOfRandomIndices[0]);
    drawImage(arrayOfRandomIndices[1]);
    drawImage(arrayOfRandomIndices[2]);
}

// Create function to randomize image list by accessing three random indices of images array (if equal, generates new random number)
function randomIndices() {
  var firstRandomIndex = Math.floor(Math.random() * images.length);
  var secondRandomIndex = Math.floor(Math.random() * images.length);

// Create while loop to check first and secondRandomIndex against one another (if equal, generates new random number)
  while (firstRandomIndex === secondRandomIndex) {
    secondRandomIndex = Math.floor(Math.random() * images.length);
  }
  var thirdRandomIndex = Math.floor(Math.random() * images.length);

// Create second while loop to check third against first and secondRandomIndex
  while (thirdRandomIndex === firstRandomIndex || thirdRandomIndex === secondRandomIndex) {
    thirdRandomIndex = Math.floor(Math.random() * images.length);
  }

// Check random indices against currentImageIndices (ensures no repeated list presentation from one immediately preceeding, firstRandomIndex now has to be checked initially)
  return [firstRandomIndex, secondRandomIndex, thirdRandomIndex];
}

// Create function to draw images based on object path
function drawImage(index) {
// Use the image path for the src
// (image.path)
    var img = document.createElement('img');
    var li = document.createElement('li');
    var imageList = document.getElementById('images');
    var randomPath = images[index].path;

// Set src
    img.setAttribute('src', randomPath);

// Add to DOM
    li.appendChild(img);
    imageList.appendChild(li);
}

function Image(name, path) {
  this.views = 0;
  this.clicks = 0;
  this.name = name;
  this.path = 'imgs/' + path;

  images.push(this);
}
<|endoftext|>


<commit_before>const express = require('express')
var busboy = require('connect-busboy'); //middleware for form/file upload
var path = require('path');     //used for file path
var fs = require('fs-extra');       //File System - for file manipulation
const app = express()
var redis = require("redis"),
    client = redis.createClient();

client.on('error', function(err) {
  console.log(err);
})

app.use(busboy());
app.use(express.static(path.join(__dirname, 'public')));

app.get('/', function (req, res) {
  res.send('Hello World!')
})

app.get('/download/:id', function(req, res) {
  res.sendFile(path.join(__dirname + '/public/download.html'));
});

app.get('/assets/download/:id', function(req, res) {

  let id = req.params.id;
  client.hget(id, "filename", function(err, reply) { // maybe some expiration logic too
  if (!reply) {
      res.sendStatus(404);
    } else {
      res.setHeader('Content-Disposition', 'attachment; filename=' + reply);
      res.setHeader('Content-Type', 'application/octet-stream');

      res.download(__dirname + '/static/' + id, reply, function(err) {
        if (!err) {
          client.del(id);
          fs.unlink(__dirname + '/static/' + id);
        }
      });
    }
  })

});

app.route('/upload/:id')
    .post(function (req, res, next) {

        var fstream;
        req.pipe(req.busboy);
        req.busboy.on('file', function (fieldname, file, filename) {
            console.log("Uploading: " + filename);

            //Path where image will be uploaded
            fstream = fs.createWriteStream(__dirname + '/static/' + req.params.id);
            file.pipe(fstream);
            fstream.on('close', function () {
                let id = req.params.id;
                client.hset(id, "filename", filename, redis.print);
                client.hset(id, "expiration", 0, redis.print);
                client.expire(id, 86400000);
                console.log("Upload Finished of " + filename);
                res.send(id);
            });
        });
    });

app.listen(3000, function () {
  console.log('Portal app listening on port 3000!')
})

<commit_msg>changed to unlinkSync<commit_after>const express = require('express')
var busboy = require('connect-busboy'); //middleware for form/file upload
var path = require('path');     //used for file path
var fs = require('fs-extra');       //File System - for file manipulation
const app = express()
var redis = require("redis"),
    client = redis.createClient();

client.on('error', function(err) {
  console.log(err);
})

app.use(busboy());
app.use(express.static(path.join(__dirname, 'public')));

app.get('/', function (req, res) {
  res.send('Hello World!')
})

app.get('/download/:id', function(req, res) {
  res.sendFile(path.join(__dirname + '/public/download.html'));
});

app.get('/assets/download/:id', function(req, res) {

  let id = req.params.id;
  client.hget(id, "filename", function(err, reply) { // maybe some expiration logic too
  if (!reply) {
      res.sendStatus(404);
    } else {
      res.setHeader('Content-Disposition', 'attachment; filename=' + reply);
      res.setHeader('Content-Type', 'application/octet-stream');

      res.download(__dirname + '/static/' + id, reply, function(err) {
        if (!err) {
          client.del(id);
          fs.unlinkSync(__dirname + '/static/' + id);
        }
      });
    }
  })

});

app.route('/upload/:id')
    .post(function (req, res, next) {

        var fstream;
        req.pipe(req.busboy);
        req.busboy.on('file', function (fieldname, file, filename) {
            console.log("Uploading: " + filename);

            //Path where image will be uploaded
            fstream = fs.createWriteStream(__dirname + '/static/' + req.params.id);
            file.pipe(fstream);
            fstream.on('close', function () {
                let id = req.params.id;
                client.hset(id, "filename", filename, redis.print);
                client.hset(id, "expiration", 0, redis.print);
                client.expire(id, 86400000);
                console.log("Upload Finished of " + filename);
                res.send(id);
            });
        });
    });

app.listen(3000, function () {
  console.log('Portal app listening on port 3000!')
})

<|endoftext|>


<commit_before>/*
 * @author Daisuke Homma
 */

{ // namespace boundary

let jsutils = jsutils || window;
const lib = jsutils;

//// repeat
// repeat nth with index
// # usage
// repeat(3,(i)=>console.log(i))

lib.repeat = (n, fun) => { for(let i = 0; i < n; i++) fun(i) }

//// loop
// repeat nth without index
// # usage
// loop(3,()=>console.log("foo"))

lib.loop = (n, fun) => { while(n--) fun() }

//// pipeline
// execute functions one by one, tail to nose (i.e. in reverse order)
// using returned value from previous function
// # usage
// const read = (fun) => process.stdin.on('data', fun);
// const write = (data) => process.stdout.write(data);
// execute(read, write);

lib.execute = (...funs) => funs.reduce((f1, f2) => f1(f2));

//// value type check
lib.isNull = val => val == null;
lib.isBoolean = val => typeof val === "boolean";
lib.isNumber = val => typeof val === "number";
lib.isString = val => typeof val === "string";
lib.isDate = val => val instanceof Date;
lib.isObject = val => typeof val === "object";

lib.isHTMLElement = val => ( (val instanceof Node) ||
                             (val instanceof HTMLElement) );

//// CSS

// convert foo-bar-baz to fooBarBaz
lib.toCamel = str => str.replace(/-([a-z])/g,
                                   (match, p1) => p1.toUpperCase());

//// String
lib.explode = str => Object.values(str);
lib.implode = arr => arr.join('');

// Apply Array.map to String
lib.stringMap = (str, fun) => map.call(str, fun);

} // namespace boundary
<commit_msg>committed on 2017/12/23 20:06.<commit_after>/*
 * @author Daisuke Homma
 */

{ // namespace boundary

let jsutils = jsutils || window;
const lib = jsutils;

//// repeat
// repeat nth with index
// # usage
// repeat(3,(i)=>console.log(i))

lib.repeat = (n, fun) => { for(let i = 0; i < n; i++) fun(i) }

//// loop
// repeat nth without index
// # usage
// loop(3,()=>console.log("foo"))

lib.loop = (n, fun) => { while(n--) fun() }

//// pipeline
// execute functions one by one, tail to nose (i.e. in reverse order)
// using returned value from previous function
// # usage
// const read = (fun) => process.stdin.on('data', fun);
// const write = (data) => process.stdout.write(data);
// execute(read, write);

lib.execute = (...funs) => funs.reduce((f1, f2) => f1(f2));

//// value type check
lib.isNull = val => val == null;
lib.isBoolean = val => typeof val === "boolean";
lib.isNumber = val => typeof val === "number";
lib.isString = val => typeof val === "string";
lib.isDate = val => val instanceof Date;
lib.isObject = val => typeof val === "object";

lib.isHTMLElement = val => ( (val instanceof Node) ||
                             (val instanceof HTMLElement) );

//// CSS

// convert foo-bar-baz to fooBarBaz
lib.toCamel = str => str.replace(/-([a-z])/g,
                                   (match, p1) => p1.toUpperCase());

//// String
lib.explode = str => Object.values(str);
lib.implode = arr => arr.join('');

// Apply Array.map to String
// same as below
// (str, fun) => Object.values(str).map(fun);
lib.stringMap = (str, fun) => Array.prototype.map.call(str, fun);

} // namespace boundary
<|endoftext|>


<commit_before>var alexa = require('alexa-app');
var config = require("./config.json");
var route = config.route || "tivo_control";
var port = process.env.port || config.port || 8080;
var bodyParser = require('body-parser');
var express = require('express');
var net = require('net');

var express_app = express();
express_app.use(bodyParser.urlencoded({ extended: true }));
express_app.use(bodyParser.json());
express_app.set('view engine','ejs');

var app = new alexa.app(route);

app.launch(function(request,response) {
    response.say("Welcome to Tivo Control");
});

var IRCODE_COMMANDS = ["UP", "DOWN", "LEFT", "RIGHT", "SELECT", "TIVO", "LIVETV", "GUIDE", "INFO", "EXIT", "THUMBSUP", "THUMBSDOWN", "CHANNELUP", "CHANNELDOWN", "MUTE", "VOLUMEUP", "VOLUMEDOWN", "TVINPUT", "VIDEO_MODE_FIXED_480i", "VIDEO_MODE_FIXED_480p", "VIDEO_MODE_FIXED_720p", "VIDEO_MODE_FIXED_1080i", "VIDEO_MODE_HYBRID", "VIDEO_MODE_HYBRID_720p", "VIDEO_MODE_HYBRID_1080i", "VIDEO_MODE_NATIVE", "CC_ON", "CC_OFF", "OPTIONS", "ASPECT_CORRECTION_FULL", "ASPECT_CORRECTION_PANEL", "ASPECT_CORRECTION_ZOOM", "ASPECT_CORRECTION_WIDE_ZOOM", "PLAY", "FORWARD", "REVERSE", "PAUSE", "SLOW", "REPLAY", "ADVANCE", "RECORD", "NUM0", "NUM1", "NUM2", "NUM3", "NUM4", "NUM5", "NUM6", "NUM7", "NUM8", "NUM9", "ENTER", "CLEAR", "ACTION_A", "ACTION_B", "ACTION_C", "ACTION_D"];
var KEYBOARD_COMMANDS = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "MINUS", "EQUALS", "LBRACKET", "RBRACKET", "BACKSLASH", "SEMICOLON", "QUOTE", "COMMA", "PERIOD", "SLASH", "BACKQUOTE", "SPACE", "KBDUP", "KBDDOWN", "KBDLEFT", "KBDRIGHT", "PAGEUP", "PAGEDOWN", "HOME", "END", "CAPS", "LSHIFT", "RSHIFT", "INSERT", "BACKSPACE", "DELETE", "KBDENTER", "STOP", "VIDEO_ON_DEMAND"];
var TELEPORT_COMMANDS = ["TIVO", "LIVETV", "GUIDE", "NOWPLAYING"];

app.dictionary = {"commands":["UP", "DOWN", "LEFT", "RIGHT", "SELECT", "TIVO", "THUMBSUP", "THUMBSDOWN", "CHANNELUP", "CHANNELDOWN", "MUTE", "VOLUMEDOWN", "VOLUMEUP", "TVINPUT", "OPTIONS", "RECORD", "DISPLAY", "DIRECTV", "ENTER", "CLEAR", "PLAY", "PAUSE", "SLOW", "FORWARD", "REVERSE", "STANDBY", "NOWSHOWING", "REPLAY", "ADVANCE", "DELIMITER", "GUIDE", "KBDUP", "KBDDOWN", "KBDLEFT", "KBDRIGHT", "PAGEUP", "PAGEDOWN", "HOME", "END", "SPACE", "BACKQUOTE", "SLASH", "PERIOD", "COMMA", "QUOTE", "SEMICOLON", "BACKSLASH", "RBRACKET", "LBRACKET", "EQUALS", "MINUS", "CAPS", "LSHIFT", "RSHIFT", "INSERT", "BACKSPACE", "DELETE", "KBDENTER", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]};

app.intent('SendCommand',
    {
        "slots":{"TIVOCOMMAND":"LITERAL"},
        "utterances":[ "send {the|} {command|} {commands|TIVOCOMMAND}" ]
    },
    function(request,response) {
        sendCommand(request.slot("TIVOCOMMAND").toUpperCase());
    });

app.intent('Pause',
    {
        "slots":{},
        "utterances":[ "pause" ]
    },
    function(request,response) {
        sendCommand("PAUSE");
});

app.intent('LiveTV',
    {
        "slots":{},
        "utterances":[ "send {the|} {command|} live tv", "go to live tv" ]
    },
    function(request,response) {
        sendCommand("GUIDE");
        sendCommand("LIVETV");
    });

app.intent('Play',
    {
        "slots":{},
        "utterances":[ "play" ]
    },
    function(request,response) {
        sendCommand("PLAY");
});

app.intent('FastForward',
    {
        "slots":{},
        "utterances":[ "fast forward" ]
    },
    function(request,response) {
        sendCommand("FORWARD");
});

app.intent('SkipCommerial',
    {
        "slots":{},
        "utterances":[ "skip {the|} {this|} {commercial|forward|ahead}" ]
    },
    function(request,response) {
        sendCommand("ACTION_D");
});

app.intent('Record',
    {
        "slots":{},
        "utterances":[ "record {this|the|} {show|current show|this}" ]
    },
    function(request,response) {
        sendCommand("RECORD");
});

app.intent('GoHome',
    {
        "slots":{},
        "utterances":[ "{show|go} {to the|} home {screen|}" ]
    },
    function(request,response) {
        sendCommand("TIVO");
    });

app.intent('Netflix',
    {
        "slots":{},
        "utterances":[ "{go to|open|turn on|open up|display|jump to|} netflix" ]
    },
    function(request,response) {
        var commands = [
            "GUIDE",
            "TIVO",
            "DOWN",
            "DOWN",
            "RIGHT",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "RIGHT"
        ];
        sendCommands(commands);
    });

app.intent('Amazon',
    {
        "slots":{},
        "utterances":[ "{go to|open|turn on|open up|display|jump to|} amazon {video|}" ]
    },
    function(request,response) {
        var commands = [
            "GUIDE",
            "TIVO",
            "DOWN",
            "DOWN",
            "RIGHT",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "RIGHT"
        ];
        sendCommands(commands);
    });

app.intent('Hulu',
    {
        "slots":{},
        "utterances":[ "{go to|open|turn on|open up|display|jump to|} hulu" ]
    },
    function(request,response) {
        var commands = [
            "GUIDE",
            "TIVO",
            "DOWN",
            "DOWN",
            "RIGHT",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "RIGHT"
        ];
        sendCommands(commands);
    });

app.intent('YouTube',
    {
        "slots":{},
        "utterances":[ "{go to|open|turn on|open up|display|jump to|} youtube" ]
    },
    function(request,response) {
        var commands = [
            "GUIDE",
            "TIVO",
            "DOWN",
            "DOWN",
            "RIGHT",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "RIGHT"
        ];
        sendCommands(commands);
    });

app.intent('ChangeChannel',
    {
        "slots":{"TIVOCHANNEL":"NUMBER"},
        "utterances":[ "{change|go to} channel {1-100|TIVOCHANNEL}" ]
    },
    function(request,response) {
        changeChannel(request.slot("TIVOCHANNEL"));
    });

app.intent('ForceChannel',
    {
        "slots":{"TIVOCHANNEL":"NUMBER"},
        "utterances":[ "force channel {1-100|TIVOCHANNEL}" ]
    },
    function(request,response) {
        forceChannel(request.slot("TIVOCHANNEL"));
    });

// Manually hook the handler function into express
express_app.post('/'+route,function(req,res) {
    app.request(req.body)        // connect express to alexa-app
        .then(function(response) { // alexa-app returns a promise with the response
            res.json(response);      // stream it to express' output
        });
});

app.express(express_app, "/", true);

if ((process.argv.length === 3) && (process.argv[2] === 'schema'))  {
    console.log (app.schema ());
    console.log (app.utterances ());
}

function sendNextCommand () {
    clearInterval(interval);
    if(queuedCommands.length == 0) {
        if(typeof telnetSocket != "undefined" && typeof telnetSocket.end != "undefined") {
            telnetSocket.end();
            telnetSocket.destroy();
        }
        socketOpen = false;
    }
    else {
        var command = queuedCommands.shift();
        var timeToWait = 100;
        if(typeof command == "object" && typeof command["explicit"] != "undefined") {
            telnetSocket.write(command["command"].toUpperCase() + "\r");
            console.log("Sending Command: " + command["command"].toUpperCase());
            if(command.indexOf("TELEPORT"))
                timeToWait = 700;
        }
        else {
            if(typeof command == "object")
                command = command["command"];
            var prefix = determinePrefix(command);
            if(prefix === false) {
                console.log("ERROR: Command Not Supported: " + command);
                telnetSocket.end();
            }
            else {
                telnetSocket.write(prefix + " " + command.toUpperCase() + "\r");
                console.log("Sending Command: "+prefix + " " + command.toUpperCase());
            }
            if(prefix == "TELEPORT")
                timeToWait = 700;
        }
        setTimeout(sendNextCommand, timeToWait);
    }
}

var queuedCommands = [];
var telnetSocket;
var socketOpen = false;
var interval;
var noResponse = true;
function sendCommands(commands) {

    var host = config.tivoIP;
    var port = config.tivoPort;

    queuedCommands = [];
    for(var i=0; i<commands.length; i++) {
        queuedCommands.push(commands[i]);
    }
    console.log("QueuedCommands: "+queuedCommands.join(","));

    telnetSocket = net.createConnection({
        port: port,
        host: host
    });
    console.log("Connection Created");
    socketOpen = true;
    telnetSocket.on('data', function(data) {
        noResponse = false;
        console.log("RECEIVED: "+data.toString());
        interval = setInterval(sendNextCommand, 100);
    });
    telnetSocket.on('timeout', function(data) {
        console.log("TIMEOUT RECEIVED");
        if(socketOpen)
            sendNextCommand();
    });
    telnetSocket.on('end', function(data) {
        socketOpen = false;
    });
    noResponse = true;
    setTimeout(function(){
        if(noResponse) {
            telnetSocket.write("TELEPORT GUIDE" + "\r");
        }
    }, 700);
}

function sendCommand(command, explicit) {
    if(typeof explicit == "undefined") {
        explicit = false;
    }
    var host = config.tivoIP;
    var port = config.tivoPort;
    var telnetSocket = net.createConnection({
        port: port,
        host: host
    });
    telnetSocket.on('data', function(data) {
        console.log("RECEIVED: "+data.toString());
    });
    if(explicit) {
        telnetSocket.write(command.toUpperCase() + "\r");
        console.log("Sending Command: " + command.toUpperCase());
    }
    else {
        var prefix = determinePrefix(command);
        if(prefix === false)
            console.log("ERROR: Command Not Support: "+command);
        else {
            telnetSocket.write(prefix + " " + command.toUpperCase() + "\r");
            console.log("Sending Command: "+prefix + " " + command.toUpperCase());
        }
    }
    telnetSocket.end();
    telnetSocket.destroy();
}

function changeChannel(channel) {
    return sendCommand("SETCH "+channel, true);
}

function forceChannel(channel) {
    return sendCommand("FORCECH "+channel, true);
}

function determinePrefix(command) {
    if(TELEPORT_COMMANDS.indexOf(command) != -1)
        return "TELEPORT";
    else if(IRCODE_COMMANDS.indexOf(command) != -1)
        return "IRCODE";
    else if(KEYBOARD_COMMANDS.indexOf(command) != -1)
        return "KEYBOARD";
    else
        return false;
}

express_app.listen(port);<commit_msg>Fix for repeated navigation from one app to another.<commit_after>var alexa = require('alexa-app');
var config = require("./config.json");
var route = config.route || "tivo_control";
var port = process.env.port || config.port || 8080;
var bodyParser = require('body-parser');
var express = require('express');
var net = require('net');

var express_app = express();
express_app.use(bodyParser.urlencoded({ extended: true }));
express_app.use(bodyParser.json());
express_app.set('view engine','ejs');

var app = new alexa.app(route);

app.launch(function(request,response) {
    response.say("Welcome to Tivo Control");
});

var IRCODE_COMMANDS = ["UP", "DOWN", "LEFT", "RIGHT", "SELECT", "TIVO", "LIVETV", "GUIDE", "INFO", "EXIT", "THUMBSUP", "THUMBSDOWN", "CHANNELUP", "CHANNELDOWN", "MUTE", "VOLUMEUP", "VOLUMEDOWN", "TVINPUT", "VIDEO_MODE_FIXED_480i", "VIDEO_MODE_FIXED_480p", "VIDEO_MODE_FIXED_720p", "VIDEO_MODE_FIXED_1080i", "VIDEO_MODE_HYBRID", "VIDEO_MODE_HYBRID_720p", "VIDEO_MODE_HYBRID_1080i", "VIDEO_MODE_NATIVE", "CC_ON", "CC_OFF", "OPTIONS", "ASPECT_CORRECTION_FULL", "ASPECT_CORRECTION_PANEL", "ASPECT_CORRECTION_ZOOM", "ASPECT_CORRECTION_WIDE_ZOOM", "PLAY", "FORWARD", "REVERSE", "PAUSE", "SLOW", "REPLAY", "ADVANCE", "RECORD", "NUM0", "NUM1", "NUM2", "NUM3", "NUM4", "NUM5", "NUM6", "NUM7", "NUM8", "NUM9", "ENTER", "CLEAR", "ACTION_A", "ACTION_B", "ACTION_C", "ACTION_D"];
var KEYBOARD_COMMANDS = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "MINUS", "EQUALS", "LBRACKET", "RBRACKET", "BACKSLASH", "SEMICOLON", "QUOTE", "COMMA", "PERIOD", "SLASH", "BACKQUOTE", "SPACE", "KBDUP", "KBDDOWN", "KBDLEFT", "KBDRIGHT", "PAGEUP", "PAGEDOWN", "HOME", "END", "CAPS", "LSHIFT", "RSHIFT", "INSERT", "BACKSPACE", "DELETE", "KBDENTER", "STOP", "VIDEO_ON_DEMAND"];
var TELEPORT_COMMANDS = ["TIVO", "LIVETV", "GUIDE", "NOWPLAYING"];

app.dictionary = {"commands":["UP", "DOWN", "LEFT", "RIGHT", "SELECT", "TIVO", "THUMBSUP", "THUMBSDOWN", "CHANNELUP", "CHANNELDOWN", "MUTE", "VOLUMEDOWN", "VOLUMEUP", "TVINPUT", "OPTIONS", "RECORD", "DISPLAY", "DIRECTV", "ENTER", "CLEAR", "PLAY", "PAUSE", "SLOW", "FORWARD", "REVERSE", "STANDBY", "NOWSHOWING", "REPLAY", "ADVANCE", "DELIMITER", "GUIDE", "KBDUP", "KBDDOWN", "KBDLEFT", "KBDRIGHT", "PAGEUP", "PAGEDOWN", "HOME", "END", "SPACE", "BACKQUOTE", "SLASH", "PERIOD", "COMMA", "QUOTE", "SEMICOLON", "BACKSLASH", "RBRACKET", "LBRACKET", "EQUALS", "MINUS", "CAPS", "LSHIFT", "RSHIFT", "INSERT", "BACKSPACE", "DELETE", "KBDENTER", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]};

app.intent('SendCommand',
    {
        "slots":{"TIVOCOMMAND":"LITERAL"},
        "utterances":[ "send {the|} {command|} {commands|TIVOCOMMAND}" ]
    },
    function(request,response) {
        sendCommand(request.slot("TIVOCOMMAND").toUpperCase());
    });

app.intent('Pause',
    {
        "slots":{},
        "utterances":[ "pause" ]
    },
    function(request,response) {
        sendCommand("PAUSE");
});

app.intent('LiveTV',
    {
        "slots":{},
        "utterances":[ "send {the|} {command|} live tv", "go to live tv" ]
    },
    function(request,response) {
        sendCommand("GUIDE");
        sendCommand("LIVETV");
    });

app.intent('Play',
    {
        "slots":{},
        "utterances":[ "play" ]
    },
    function(request,response) {
        sendCommand("PLAY");
});

app.intent('FastForward',
    {
        "slots":{},
        "utterances":[ "fast forward" ]
    },
    function(request,response) {
        sendCommand("FORWARD");
});

app.intent('SkipCommerial',
    {
        "slots":{},
        "utterances":[ "skip {the|} {this|} {commercial|forward|ahead}" ]
    },
    function(request,response) {
        sendCommand("ACTION_D");
});

app.intent('Record',
    {
        "slots":{},
        "utterances":[ "record {this|the|} {show|current show|this}" ]
    },
    function(request,response) {
        sendCommand("RECORD");
});

app.intent('GoHome',
    {
        "slots":{},
        "utterances":[ "{show|go} {to the|} home {screen|}" ]
    },
    function(request,response) {
        sendCommand("TIVO");
    });

app.intent('Netflix',
    {
        "slots":{},
        "utterances":[ "{go to|open|turn on|open up|display|jump to|} netflix" ]
    },
    function(request,response) {
        var commands = [
            "GUIDE",
            "TIVO",
            "DOWN",
            "DOWN",
            "RIGHT",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "RIGHT"
        ];
        sendCommands(commands);
    });

app.intent('Amazon',
    {
        "slots":{},
        "utterances":[ "{go to|open|turn on|open up|display|jump to|} amazon {video|}" ]
    },
    function(request,response) {
        var commands = [
            "GUIDE",
            "TIVO",
            "DOWN",
            "DOWN",
            "RIGHT",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "RIGHT"
        ];
        sendCommands(commands);
    });

app.intent('Hulu',
    {
        "slots":{},
        "utterances":[ "{go to|open|turn on|open up|display|jump to|} hulu" ]
    },
    function(request,response) {
        var commands = [
            "GUIDE",
            "TIVO",
            "DOWN",
            "DOWN",
            "RIGHT",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "RIGHT"
        ];
        sendCommands(commands);
    });

app.intent('YouTube',
    {
        "slots":{},
        "utterances":[ "{go to|open|turn on|open up|display|jump to|} youtube" ]
    },
    function(request,response) {
        var commands = [
            "GUIDE",
            "TIVO",
            "DOWN",
            "DOWN",
            "RIGHT",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "RIGHT"
        ];
        sendCommands(commands);
    });

app.intent('ChangeChannel',
    {
        "slots":{"TIVOCHANNEL":"NUMBER"},
        "utterances":[ "{change|go to} channel {1-100|TIVOCHANNEL}" ]
    },
    function(request,response) {
        changeChannel(request.slot("TIVOCHANNEL"));
    });

app.intent('ForceChannel',
    {
        "slots":{"TIVOCHANNEL":"NUMBER"},
        "utterances":[ "force channel {1-100|TIVOCHANNEL}" ]
    },
    function(request,response) {
        forceChannel(request.slot("TIVOCHANNEL"));
    });

// Manually hook the handler function into express
express_app.post('/'+route,function(req,res) {
    app.request(req.body)        // connect express to alexa-app
        .then(function(response) { // alexa-app returns a promise with the response
            res.json(response);      // stream it to express' output
        });
});

app.express(express_app, "/", true);

if ((process.argv.length === 3) && (process.argv[2] === 'schema'))  {
    console.log (app.schema ());
    console.log (app.utterances ());
}

function sendNextCommand () {
    clearInterval(interval);
    if(queuedCommands.length == 0) {
        if(typeof telnetSocket != "undefined" && typeof telnetSocket.end != "undefined") {
            telnetSocket.end();
            telnetSocket.destroy();
        }
        socketOpen = false;
    }
    else {
        var command = queuedCommands.shift();
        var timeToWait = 150;
        if(typeof command == "object" && typeof command["explicit"] != "undefined") {
            telnetSocket.write(command["command"].toUpperCase() + "\r");
            console.log("Sending Command: " + command["command"].toUpperCase());
            if(command.indexOf("TELEPORT"))
                timeToWait = 700;
        }
        else {
            if(typeof command == "object")
                command = command["command"];
            var prefix = determinePrefix(command);
            if(prefix === false) {
                console.log("ERROR: Command Not Supported: " + command);
                telnetSocket.end();
            }
            else {
                telnetSocket.write(prefix + " " + command.toUpperCase() + "\r");
                console.log("Sending Command: "+prefix + " " + command.toUpperCase());
            }
            if(prefix == "TELEPORT")
                timeToWait = 700;
        }
        setTimeout(sendNextCommand, timeToWait);
    }
}

var queuedCommands = [];
var telnetSocket;
var socketOpen = false;
var interval;
var noResponse = true;
function sendCommands(commands) {

    var host = config.tivoIP;
    var port = config.tivoPort;

    queuedCommands = [];
    for(var i=0; i<commands.length; i++) {
        queuedCommands.push(commands[i]);
    }
    console.log("QueuedCommands: "+queuedCommands.join(","));

    telnetSocket = net.createConnection({
        port: port,
        host: host
    });
    console.log("Connection Created");
    socketOpen = true;
    telnetSocket.on('data', function(data) {
        noResponse = false;
        console.log("RECEIVED: "+data.toString());
        interval = setInterval(sendNextCommand, 100);
    });
    telnetSocket.on('timeout', function(data) {
        console.log("TIMEOUT RECEIVED");
        if(socketOpen)
            sendNextCommand();
    });
    telnetSocket.on('end', function(data) {
        socketOpen = false;
    });
    noResponse = true;
    setTimeout(function(){
        if(noResponse) {
            telnetSocket.write("TELEPORT GUIDE" + "\r");
        }
    }, 700);
}

function sendCommand(command, explicit) {
    if(typeof explicit == "undefined") {
        explicit = false;
    }
    var host = config.tivoIP;
    var port = config.tivoPort;
    var telnetSocket = net.createConnection({
        port: port,
        host: host
    });
    telnetSocket.on('data', function(data) {
        console.log("RECEIVED: "+data.toString());
    });
    if(explicit) {
        telnetSocket.write(command.toUpperCase() + "\r");
        console.log("Sending Command: " + command.toUpperCase());
    }
    else {
        var prefix = determinePrefix(command);
        if(prefix === false)
            console.log("ERROR: Command Not Support: "+command);
        else {
            telnetSocket.write(prefix + " " + command.toUpperCase() + "\r");
            console.log("Sending Command: "+prefix + " " + command.toUpperCase());
        }
    }
    telnetSocket.end();
    telnetSocket.destroy();
}

function changeChannel(channel) {
    return sendCommand("SETCH "+channel, true);
}

function forceChannel(channel) {
    return sendCommand("FORCECH "+channel, true);
}

function determinePrefix(command) {
    if(TELEPORT_COMMANDS.indexOf(command) != -1)
        return "TELEPORT";
    else if(IRCODE_COMMANDS.indexOf(command) != -1)
        return "IRCODE";
    else if(KEYBOARD_COMMANDS.indexOf(command) != -1)
        return "KEYBOARD";
    else
        return false;
}

express_app.listen(port);<|endoftext|>


<commit_before>var getItemSizeCacheValue = {};

function getItemSize(cssClass) {
  if (!getItemSizeCacheValue[cssClass]) {
    var $item = $('

')
      .addClass(cssClass.toString())
      .attr('style', 'display: none;');
    $(document.body).append($item);
    getItemSizeCacheValue[cssClass] = {
      height: $item.outerHeight(true) || 0,
      width: $item.outerWidth(true) || 0
    };
    $item.remove();
  }
  return getItemSizeCacheValue[cssClass];
}

function dataProvider() {
  var items = [];

  function getItems() {
    if (!items.length) {
      for (var i = 0; i < 100; i++) {
        items.push({
          title: faker.name.findName(),
          value: faker.company.companyName()
        });
      }
    }
    return items;
  }

  return {
    getItems: getItems
  }
}

function drResizeEvent() {
  return {
    scope: true,
    link: function link(scope, element, attrs) {
      var frameElementStyles = [
        'top: 0',
        'bottom: 0',
        'left: 0',
        'right: 0',
        'position: absolute',
        'width: 100%',
        'height: 100%',
        'z-index: -1',
        'border: none',
        'background-color: rgba(0, 0, 0, 0)'
      ].join(';');
      var frameElement = '';
      element.append(frameElement);
      scope.element = element;
      var resizeHelper = $(element).find('> iframe');
      var resizeHandler = null;
      resizeHelper.get(0).contentWindow.onresize = function () {
        if (resizeHandler) {
          clearTimeout(resizeHandler);
        }
        resizeHandler = setTimeout(function () {
          var size = {width: resizeHelper.width(), height: resizeHelper.height()};
          scope.$broadcast('element::resize', size);
          scope.$digest();
        }, 20);
      };
    }
  };
}

function dataController(dataProvider) {
  this.items = dataProvider.getItems();
}

function animateCtrl($scope, dataProvider) {
  this.items = dataProvider.getItems();
  this.lines = [];

  var itemSize = getItemSize('animation-list-item');
  var colItemsCount, rowItemsCount, lastIndex = 0;

  function getRow(itemList) {
    var row = [];
    if (lastIndex > itemList.length - 1) {
      lastIndex = 0;
    }
    for (var i = 0; i < colItemsCount; i++) {
      row.push(itemList[lastIndex++]);
    }
    return row;
  }

  this.prev = function () {
    this.lines.unshift(getRow(this.items));
    this.lines.pop();
  };

  this.next = function () {
    this.lines.push(getRow(this.items));
    this.lines.shift();
  };

  (function (instance, scope) {
    scope.$on('element::resize', function (event, data) {
      console.log(event, data);
      if (data) {
        colItemsCount = Math.floor(data.width / itemSize.width) || 0;
        rowItemsCount = Math.floor(data.height / itemSize.height) || 0;
        instance.lines = [];
        for (var i = 0; i < rowItemsCount; i++) {
          instance.lines.push(getRow(instance.items));
        }
      }
    });
  }(this, $scope));
}

function drAnimationList($animateCss) {
  return {
    replace: true,
    scope: {items: '=drAnimationList'},
    templateUrl: 'animation-list.html',
    link: function (scope, element) {
      scope.listElemnent = element.find('.animation-list-wrapper');
      scope.lines = [];

      var itemSize = getItemSize('animation-list-item');
      var containerSize = getItemSize('animation-list-container');

      var colItemsCount, rowItemsCount, lastIndex = 0;
      var animation = { easing: 'ease-out', duration: 0.5 };

      console.log(
        '$scope.$id', scope.$id, '; ',
        'itemSize', JSON.stringify(itemSize), '; ',
        'containerSize', JSON.stringify(containerSize),
        'colItemsCount', JSON.stringify(colItemsCount), '; ',
        'rowItemsCount', JSON.stringify(rowItemsCount), '; '
      );

      scope.isRunning = false;

      function getRow(itemList) {
        var row = [];
        if (lastIndex > itemList.length - 1) {
          lastIndex = 0;
        }
        for (var i = 0; i < colItemsCount; i++) {
          row.push(itemList[lastIndex++]);
        }
        return row;
      }

      var animationTop = '-' + itemSize.height + 'px';

      scope.prev = function () {
        if (!scope.isRunning) {
          scope.isRunning = true;
          scope.listElemnent.get(0).style.top = animationTop;
          scope.lines.unshift(getRow(this.items));
          animation.from = {top: animationTop};
          animation.to = {top: '0px'};
          $animateCss(scope.listElemnent, animation).start().then(function () {
            scope.lines.pop();
            scope.isRunning = false;
          });
        }
      };

      scope.next = function () {
        if (!scope.isRunning) {
          scope.isRunning = true;
          scope.lines.push(getRow(this.items));
          animation.from = {top: '0px'};
          animation.to = {top: animationTop};
          $animateCss(scope.listElemnent, animation).start().then(function () {
            scope.listElemnent.get(0).style.top = '0px';
            scope.lines.shift();
            scope.isRunning = false;
          });
        }
      };

      (function (instance, scope) {
        scope.$on('element::resize', function (event, data) {
          if (data) {
            colItemsCount = Math.floor(data.width / itemSize.width) || 0;
            rowItemsCount = Math.floor(data.height / itemSize.height) || 0;
            instance.lines = [];
            for (var i = 0; i < rowItemsCount; i++) {
              instance.lines.push(getRow(instance.items));
            }
          }
        });
      }(scope, scope));
    }
  }
}

angular.element(document).ready(function () {
  var appName = 'ngApp';
  angular.module(appName, ['ngAnimate'])
    .controller('dataController', dataController)
    .controller('animateCtrl', animateCtrl)
    .directive('drAnimationList', drAnimationList)
    .directive('drResizeEvent', drResizeEvent)
    .factory('dataProvider', dataProvider);
  angular.bootstrap(document, [appName]);
});
<commit_msg>remove conosole.log<commit_after>var getItemSizeCacheValue = {};

function getItemSize(cssClass) {
  if (!getItemSizeCacheValue[cssClass]) {
    var $item = $('

')
      .addClass(cssClass.toString())
      .attr('style', 'display: none;');
    $(document.body).append($item);
    getItemSizeCacheValue[cssClass] = {
      height: $item.outerHeight(true) || 0,
      width: $item.outerWidth(true) || 0
    };
    $item.remove();
  }
  return getItemSizeCacheValue[cssClass];
}

function dataProvider() {
  var items = [];

  function getItems() {
    if (!items.length) {
      for (var i = 0; i < 100; i++) {
        items.push({
          title: faker.name.findName(),
          value: faker.company.companyName()
        });
      }
    }
    return items;
  }

  return {
    getItems: getItems
  }
}

function drResizeEvent() {
  return {
    scope: true,
    link: function link(scope, element, attrs) {
      var frameElementStyles = [
        'top: 0',
        'bottom: 0',
        'left: 0',
        'right: 0',
        'position: absolute',
        'width: 100%',
        'height: 100%',
        'z-index: -1',
        'border: none',
        'background-color: rgba(0, 0, 0, 0)'
      ].join(';');
      var frameElement = '';
      element.append(frameElement);
      scope.element = element;
      var resizeHelper = $(element).find('> iframe');
      var resizeHandler = null;
      resizeHelper.get(0).contentWindow.onresize = function () {
        if (resizeHandler) {
          clearTimeout(resizeHandler);
        }
        resizeHandler = setTimeout(function () {
          var size = {width: resizeHelper.width(), height: resizeHelper.height()};
          scope.$broadcast('element::resize', size);
          scope.$digest();
        }, 20);
      };
    }
  };
}

function dataController(dataProvider) {
  this.items = dataProvider.getItems();
}

function animateCtrl($scope, dataProvider) {
  this.items = dataProvider.getItems();
  this.lines = [];

  var itemSize = getItemSize('animation-list-item');
  var colItemsCount, rowItemsCount, lastIndex = 0;

  function getRow(itemList) {
    var row = [];
    if (lastIndex > itemList.length - 1) {
      lastIndex = 0;
    }
    for (var i = 0; i < colItemsCount; i++) {
      row.push(itemList[lastIndex++]);
    }
    return row;
  }

  this.prev = function () {
    this.lines.unshift(getRow(this.items));
    this.lines.pop();
  };

  this.next = function () {
    this.lines.push(getRow(this.items));
    this.lines.shift();
  };

  (function (instance, scope) {
    scope.$on('element::resize', function (event, data) {
      if (data) {
        colItemsCount = Math.floor(data.width / itemSize.width) || 0;
        rowItemsCount = Math.floor(data.height / itemSize.height) || 0;
        instance.lines = [];
        for (var i = 0; i < rowItemsCount; i++) {
          instance.lines.push(getRow(instance.items));
        }
      }
    });
  }(this, $scope));
}

function drAnimationList($animateCss) {
  return {
    replace: true,
    scope: {items: '=drAnimationList'},
    templateUrl: 'animation-list.html',
    link: function (scope, element) {
      scope.listElemnent = element.find('.animation-list-wrapper');
      scope.lines = [];

      var itemSize = getItemSize('animation-list-item');
      var containerSize = getItemSize('animation-list-container');

      var colItemsCount, rowItemsCount, lastIndex = 0;
      var animation = { easing: 'ease-out', duration: 0.5 };

      scope.isRunning = false;

      function getRow(itemList) {
        var row = [];
        if (lastIndex > itemList.length - 1) {
          lastIndex = 0;
        }
        for (var i = 0; i < colItemsCount; i++) {
          row.push(itemList[lastIndex++]);
        }
        return row;
      }

      var animationTop = '-' + itemSize.height + 'px';

      scope.prev = function () {
        if (!scope.isRunning) {
          scope.isRunning = true;
          scope.listElemnent.get(0).style.top = animationTop;
          scope.lines.unshift(getRow(this.items));
          animation.from = {top: animationTop};
          animation.to = {top: '0px'};
          $animateCss(scope.listElemnent, animation).start().then(function () {
            scope.lines.pop();
            scope.isRunning = false;
          });
        }
      };

      scope.next = function () {
        if (!scope.isRunning) {
          scope.isRunning = true;
          scope.lines.push(getRow(this.items));
          animation.from = {top: '0px'};
          animation.to = {top: animationTop};
          $animateCss(scope.listElemnent, animation).start().then(function () {
            scope.listElemnent.get(0).style.top = '0px';
            scope.lines.shift();
            scope.isRunning = false;
          });
        }
      };

      (function (instance, scope) {
        scope.$on('element::resize', function (event, data) {
          if (data) {
            colItemsCount = Math.floor(data.width / itemSize.width) || 0;
            rowItemsCount = Math.floor(data.height / itemSize.height) || 0;
            instance.lines = [];
            for (var i = 0; i < rowItemsCount; i++) {
              instance.lines.push(getRow(instance.items));
            }
          }
        });
      }(scope, scope));
    }
  }
}

angular.element(document).ready(function () {
  var appName = 'ngApp';
  angular.module(appName, ['ngAnimate'])
    .controller('dataController', dataController)
    .controller('animateCtrl', animateCtrl)
    .directive('drAnimationList', drAnimationList)
    .directive('drResizeEvent', drResizeEvent)
    .factory('dataProvider', dataProvider);
  angular.bootstrap(document, [appName]);
});
<|endoftext|>