<commit_before>var arrow = [
    [ 2, 0 ],
    [ -10, -4 ],
    [ -10, 4]
];

function translateShape(shape,x,y) {
    var rv = [];
    for(p in shape)
        rv.push([ shape[p][0] + x, shape[p][1] + y ]);
    return rv;
}

function rotateShape(shape,ang) {
    var rv = [];
    for(p in shape)
        rv.push(rotatePoint(ang,shape[p][0],shape[p][1]));
    return rv;
}

function rotatePoint(ang,x,y) {
    return [
        (x * Math.cos(ang)) - (y * Math.sin(ang)),
        (x * Math.sin(ang)) + (y * Math.cos(ang))
    ];
}

function drawFilledPolygon(shape) {
    ctx.beginPath();
    ctx.moveTo(shape[0][0],shape[0][1]);

    for(p in shape)
        if (p > 0) ctx.lineTo(shape[p][0],shape[p][1]);

    ctx.lineTo(shape[0][0],shape[0][1]);
    ctx.fill();
};

function drawLineArrow(x1,y1,x2,y2) {
    ctx = $("canvas")[6].getContext('2d');
    ctx.beginPath();
    ctx.moveTo(x1,y1);
    ctx.lineTo(x2,y2);
    ctx.stroke();
    var ang = Math.atan2(y2-y1,x2-x1);
    drawFilledPolygon(translateShape(rotateShape(arrow,ang),x2,y2));
}

// simple draggable
var SimpleDraggable = function (selector, options) {

    options.onStart = options.onStart || function () {};
    options.onStop = options.onStop || function () {};
    options.onDrag = options.onDrag || function () {};

    var allElms = document.querySelectorAll (selector);
    for (var i = 0; i < allElms.length; ++i) {
        (function (cEl) {
            // document.body.appendChild(cEl);
            cEl.style.position = "absolute";
            cEl._simpleDraggable = {
               drag: false
            }

            cEl.addEventListener("mousedown", function (e) {
                cEl._simpleDraggable.drag = true;
                cEl._simpleDraggable.mousePos = {
                    x: e.clientX
                  , y: e.clientY
                }
                cEl._simpleDraggable.elPos = {
                    x: cEl.offsetLeft
                  , y: cEl.offsetTop
                }
            });

            cEl.addEventListener("mouseup", function (e) {
                cEl._simpleDraggable.drag = false;
                options.onStart.call(this, e, cEl);
            });

            document.body.addEventListener("mouseout", function (e) {
                cEl._simpleDraggable.drag = false;
                options.onStop.call(this, e, cEl);
            });

            document.body.addEventListener("mousemove", function (e) {
                if (!cEl._simpleDraggable.drag) { return; }

                if (options.onDrag.call(this, e, cEl) === false) {
                    return;
                }

                if (!options.onlyY) {
                    cEl.style.left = (cEl._simpleDraggable.elPos.x + e.clientX - cEl._simpleDraggable.mousePos.x) + "px";
                }
                if (!options.onlyX) {
                    cEl.style.top = (cEl._simpleDraggable.elPos.y + e.clientY - cEl._simpleDraggable.mousePos.y) + "px";
                }

            })
        })(allElms[i])
    }
};

/*
 *  Franck & Hertz Experiment
 *  Licensed under MIT license
 *
 * */
$(document).ready(function () {

    var initialPositions = {
        vol: {
            top: $(".physics-instrument.vol").css("top")
          , left: $(".physics-instrument.vol").css("left")
        }
      , amp: {
            top: $(".physics-instrument.amp").css("top")
          , left: $(".physics-instrument.amp").css("left")
        }
    };

    var termometer = {
        started: false
        // 206 ... 80
        // 20 .... 95
        // f (20) = 206;
        // f (95) = 80
        //
        // 20a + b = 206
        // 95a + b = 80
        // ------------
        // 75a = -126
        // a = -1.68
        // b = 239.6
      , setValue: function (deg) {
            $(".termometer-value > .v").text(deg);
            $(".termometer-level").css("top", (deg * (-1.68) + 239) + "px")
        }
      , stop: function () {
            clearInterval(termometer.interval);
            termometer.started = false;
        }
      //, handler: function () {
      //      if (termometer.started) { return; }
      //      termometer.started = true;
      //      termometer.setValue(value += 1);
      //      if (value >= 90) {
      //          clearInterval(termometer.interval);
      //      }
      //  }
    }

    $("select").on("keydown", function () {
        return false;
    });

    var degs = 0;

    $(".polarity").on("click", function () {
        if (!degs) { degs = 180; }
        else { degs = 0; }
        $(this).css ({
            "-webkit-transform": "rotateZ(" + degs + "deg)"
          , "-moz-transform": "rotateZ(" + degs + "deg)"
        });

        updateResult (0);
        $(".vol input").val("0.00");
        $(".cursor").css("top", min);
        termometer.setValue(20);
        termometer.stop();
        latest = null;
    });

    var screenVisible = true;

    // on change
    $("select.language").on("change", function () {
        // set the new language
        $.setLanguage({
            attribute: "data-lang"
          , lang: $(this).val()
        });

        if (!screenVisible) {
            $(".theory").hide();
        } else {
            $(".experiment").hide();
        }
    }).change();

    var currentElement = {};
    var values = {
        resistor: {
            name: "resistor"
          , functionLaw: function (x) {
                return 1 / 200 * x;
            }
          , x: {
                min: -12
              , max: 12
            }
          , afterInit: function () {
                var y = 145
                  , x = 178
                  ;
                drawLineArrow(0, y, 356, y);
                drawLineArrow(x, 290, x, 0);
                $(".termometer,.termistor-system").hide();
                $(".system").show();
                $(".physics-instrument.vol").css(initialPositions.vol);
                $(".physics-instrument.amp").css(initialPositions.amp);
            }
        }
      , bulb: {
            name: "bulb"
          , functionLaw: function (x) {
                if (x < 0) {
                    return -values.bulb.functionLaw (-x);
                }

                return Math.pow (x, 1/3);
            }
          , x: {
                min: -5
              , max: 5
            }
          , afterInit: function () {
                var y = 145
                  , x = 178
                  ;
                drawLineArrow(0, y, 350, y);
                drawLineArrow(x, 290, x, 0);
                $(".termometer,.termistor-system").hide();
                $(".system").show();
                $(".physics-instrument.vol").css(initialPositions.vol);
                $(".physics-instrument.amp").css(initialPositions.amp);
            }
        }
      , diode: {
            name: "diode"
          , functionLaw: function (x) {
                if (x >= 0) {
                    return Math.pow (x, 3 / 2) * 4;
                }
                if (x < 0 && x > -4) {
                    return x / 5;
                }

                return -98.50000000015939 * Math.pow(x, 2) - 796.8500000012887 * x - 1612.2000000026096;
            }
          , x: {
                min: -4.5
              , max: 4.5
            }
          , afterInit: function () {
                var y = 187
                  , x = 174
                  ;
                drawLineArrow(0, y, 350, y);
                drawLineArrow(x, 290, x, 0);
                $(".termometer,.termistor-system").hide();
                $(".system").show();
                $(".physics-instrument.vol").css(initialPositions.vol);
                $(".physics-instrument.amp").css(initialPositions.amp);
            }
        }
      , termistor: {
            name: "termistor"
          , functionLaw: function (x) {
                if (x < 3 && x > -3) {
                    termometer.setValue(20);
                    return x * 5;
                }

                // 3 ........ 25
                // 30 ....... 90
                // -------------
                // 30a + b = 90
                // 3a + b = 25
                // ------------
                // 27a = 65
                // a = 2.4
                // b =42

                function computeTermometerValue () {
                    return x * 2.4 + 42;
                }

                termometer.setValue(computeTermometerValue().toFixed());
                return (x < 0 ? -1 : 1 ) * 15 - x / 10;
            }
          , x: {
                min: -17
              , max: 17
            }
          , y: {
                min: -30
              , max: 30
            }
          , afterInit: function () {
                var y = 145
                  , x = 174
                  ;

                drawLineArrow(0, y, 350, y);
                drawLineArrow(x, 290, x, 0);

                $(".termometer,.termistor-system").show();
                $(".system").hide();
                $(".physics-instrument.vol").css("top", "83px");
                $(".physics-instrument.amp").css({
                    top: "-20px"
                  , left: "1px"
                });
            }
        }
    };

    // attach y values
    for (var el in values) {
        values[el].y = {
            min: (values[el].y || {}).min || values[el].functionLaw(values[el].x.min)
          , max: (values[el].y || {}).max || values[el].functionLaw(values[el].x.max)
        };
    }

    $("select.changeElement").on("change", function () {
        currentElement = values[$(this).val()];

        // update elements
        $("[data-name]", ".changeableElement").hide();
        $("[data-name='" + currentElement.name + "']", ".changeableElement").show();

        $("#graph").empty();

        expGraph  = $.jqplot ('graph', [[[]]], {
            axesDefaults: {
                labelRenderer: $.jqplot.CanvasAxisLabelRenderer
            }
          , seriesDefaults: {
                showLine:false
            }
          , axes: {
                xaxis: {
                    label: "U (V)"
                  , min: currentElement.x.min
                  , max: currentElement.x.max
                  , tickOptions: {
                        formatString: "%#.2f"
                      , howGridline: false
                      , textColor: '#ffffff'
                      , fontSize: '12px'
                    }
                  , numberTicks: 11
                }
              , yaxis: {
                    label: "I (mA)"
                  , min: currentElement.y.min
                  , max: currentElement.y.max
                  , tickOptions: {
                        formatString: "%#.2f"
                      , howGridline: false
                      , textColor: '#ffffff'
                      , fontSize: '12px'
                    }
                  , numberTicks: 11
                }
            }
        });

        setTimeout(function () {
        currentElement.afterInit();
        }, 100);

        updateResult (0);
        latest = null;
        $(".vol input").val("0.00");
        $(".cursor").css("top", min);
        termometer.setValue(20);
        termometer.stop();
    }).change();

    $(".add-points").css({
        "bottom": "-360px"
      , "position": "absolute"
      , "left": "855px"
      , "width": "352px"
      , "font-weight": "bold"
    });

    // initial animation
    $(".container").css("opacity", "0").animate({
        opacity: 1
      , top: "50%"
    }, 1000);

    $("div.button.theory-switch").on("click", function () {

        var $screen = $(".screen")
          , $docs   = $(".docs")
          ;

        if (screenVisible) {
            $screen.stop(true).fadeOut();
            $docs.stop(true).fadeIn();
            screenVisible = false;
            $(".experiment[data-lang='" + $("select.language").val() +"']", this).show();
            $(".theory", this).hide();
        } else {
            $screen.stop(true).fadeIn();
            $docs.stop(true).fadeOut();
            screenVisible = true;
            $(".experiment", this).hide();
            $(".theory[data-lang='" + $("select.language").val() +"']", this).show();
        }
    });

    var max = 176
      , min = 50
      ;

    $("img").on("dragstart", function () {
        return false;
    });

    var latest = null;
    SimpleDraggable(".cursor", {
        onlyY: true
      , onDrag: function (e, cEl) {

            var xMax = currentElement.x.max;

            // change x with y
            if (currentElement.name === "termistor") {
                xMax = currentElement.y.max;
            }

            var value = (cEl.offsetTop - min) / ((max - min) / xMax);
            value = (degs === 0 ? 1 : -1) * value;
            if (!degs && value < 0 || degs && value > 0) {
                value = 0;
            }

            if (latest === null) { latest = value; }
            if (value > latest) {
                for (var i = latest; i < value; i += 0.2) {
                    updateResult(i);
                }
            } else {
                for (var i = value; i < latest; i += 0.2) {
                    updateResult(i);
                }
            }

            latest = value;

            if (cEl.offsetTop > max) {
                cEl.style.top = (parseInt(cEl.style.top) - 1) + "px";
                return false;
            }

            if (cEl.offsetTop < min) {
                cEl.style.top = (parseInt(cEl.style.top) + 1) + "px";
                return false;
            }
        }
    });

    /**
     * private: updateResult
     *   This function updates the result when the voltmeter
     *   value is changed.
     *
     *    Arguments
     *      @value: the value of the voltmeter
     *
     */
    function updateResult (value) {
        var x = value
          , y = currentElement.functionLaw (value)
          ;

        // change x with y
        if (currentElement.name === "termistor") {
            var aux = x;
            x = y;
            y = aux;
        }

        if ($(".add-points input").prop("checked")) {
            var seriesObj = expGraph.series[0];
            seriesObj.data.push([x, y]);
            seriesObj.data.sort (function (a, b) {
                return a[0] - b[0];
            });

            expGraph.drawSeries({},0);
        }

        $(".vol input").val(x.toFixed(2));
        $(".amp input").val(y.toFixed(2));
    }

    $(".clear-graph").on("click", function () {
        var seriesObj = expGraph.series[0];
        seriesObj.data = [];
        expGraph.drawSeries({},0);
    });
});
<commit_msg>Fixed termometer value computing<commit_after>var arrow = [
    [ 2, 0 ],
    [ -10, -4 ],
    [ -10, 4]
];

function translateShape(shape,x,y) {
    var rv = [];
    for(p in shape)
        rv.push([ shape[p][0] + x, shape[p][1] + y ]);
    return rv;
}

function rotateShape(shape,ang) {
    var rv = [];
    for(p in shape)
        rv.push(rotatePoint(ang,shape[p][0],shape[p][1]));
    return rv;
}

function rotatePoint(ang,x,y) {
    return [
        (x * Math.cos(ang)) - (y * Math.sin(ang)),
        (x * Math.sin(ang)) + (y * Math.cos(ang))
    ];
}

function drawFilledPolygon(shape) {
    ctx.beginPath();
    ctx.moveTo(shape[0][0],shape[0][1]);

    for(p in shape)
        if (p > 0) ctx.lineTo(shape[p][0],shape[p][1]);

    ctx.lineTo(shape[0][0],shape[0][1]);
    ctx.fill();
};

function drawLineArrow(x1,y1,x2,y2) {
    ctx = $("canvas")[6].getContext('2d');
    ctx.beginPath();
    ctx.moveTo(x1,y1);
    ctx.lineTo(x2,y2);
    ctx.stroke();
    var ang = Math.atan2(y2-y1,x2-x1);
    drawFilledPolygon(translateShape(rotateShape(arrow,ang),x2,y2));
}

// simple draggable
var SimpleDraggable = function (selector, options) {

    options.onStart = options.onStart || function () {};
    options.onStop = options.onStop || function () {};
    options.onDrag = options.onDrag || function () {};

    var allElms = document.querySelectorAll (selector);
    for (var i = 0; i < allElms.length; ++i) {
        (function (cEl) {
            // document.body.appendChild(cEl);
            cEl.style.position = "absolute";
            cEl._simpleDraggable = {
               drag: false
            }

            cEl.addEventListener("mousedown", function (e) {
                cEl._simpleDraggable.drag = true;
                cEl._simpleDraggable.mousePos = {
                    x: e.clientX
                  , y: e.clientY
                }
                cEl._simpleDraggable.elPos = {
                    x: cEl.offsetLeft
                  , y: cEl.offsetTop
                }
            });

            cEl.addEventListener("mouseup", function (e) {
                cEl._simpleDraggable.drag = false;
                options.onStart.call(this, e, cEl);
            });

            document.body.addEventListener("mouseout", function (e) {
                cEl._simpleDraggable.drag = false;
                options.onStop.call(this, e, cEl);
            });

            document.body.addEventListener("mousemove", function (e) {
                if (!cEl._simpleDraggable.drag) { return; }

                if (options.onDrag.call(this, e, cEl) === false) {
                    return;
                }

                if (!options.onlyY) {
                    cEl.style.left = (cEl._simpleDraggable.elPos.x + e.clientX - cEl._simpleDraggable.mousePos.x) + "px";
                }
                if (!options.onlyX) {
                    cEl.style.top = (cEl._simpleDraggable.elPos.y + e.clientY - cEl._simpleDraggable.mousePos.y) + "px";
                }

            })
        })(allElms[i])
    }
};

/*
 *  Franck & Hertz Experiment
 *  Licensed under MIT license
 *
 * */
$(document).ready(function () {

    var initialPositions = {
        vol: {
            top: $(".physics-instrument.vol").css("top")
          , left: $(".physics-instrument.vol").css("left")
        }
      , amp: {
            top: $(".physics-instrument.amp").css("top")
          , left: $(".physics-instrument.amp").css("left")
        }
    };

    var termometer = {
        started: false
        // 206 ... 80
        // 20 .... 95
        // f (20) = 206;
        // f (95) = 80
        //
        // 20a + b = 206
        // 95a + b = 80
        // ------------
        // 75a = -126
        // a = -1.68
        // b = 239.6
      , setValue: function (deg) {
            $(".termometer-value > .v").text(deg);
            $(".termometer-level").css("top", (deg * (-1.68) + 239) + "px")
        }
      , stop: function () {
            clearInterval(termometer.interval);
            termometer.started = false;
        }
      //, handler: function () {
      //      if (termometer.started) { return; }
      //      termometer.started = true;
      //      termometer.setValue(value += 1);
      //      if (value >= 90) {
      //          clearInterval(termometer.interval);
      //      }
      //  }
    }

    $("select").on("keydown", function () {
        return false;
    });

    var degs = 0;

    $(".polarity").on("click", function () {
        if (!degs) { degs = 180; }
        else { degs = 0; }
        $(this).css ({
            "-webkit-transform": "rotateZ(" + degs + "deg)"
          , "-moz-transform": "rotateZ(" + degs + "deg)"
        });

        updateResult (0);
        $(".vol input").val("0.00");
        $(".cursor").css("top", min);
        termometer.setValue(20);
        termometer.stop();
        latest = null;
    });

    var screenVisible = true;

    // on change
    $("select.language").on("change", function () {
        // set the new language
        $.setLanguage({
            attribute: "data-lang"
          , lang: $(this).val()
        });

        if (!screenVisible) {
            $(".theory").hide();
        } else {
            $(".experiment").hide();
        }
    }).change();

    var currentElement = {};
    var values = {
        resistor: {
            name: "resistor"
          , functionLaw: function (x) {
                return 1 / 200 * x;
            }
          , x: {
                min: -12
              , max: 12
            }
          , afterInit: function () {
                var y = 145
                  , x = 178
                  ;
                drawLineArrow(0, y, 356, y);
                drawLineArrow(x, 290, x, 0);
                $(".termometer,.termistor-system").hide();
                $(".system").show();
                $(".physics-instrument.vol").css(initialPositions.vol);
                $(".physics-instrument.amp").css(initialPositions.amp);
            }
        }
      , bulb: {
            name: "bulb"
          , functionLaw: function (x) {
                if (x < 0) {
                    return -values.bulb.functionLaw (-x);
                }

                return Math.pow (x, 1/3);
            }
          , x: {
                min: -5
              , max: 5
            }
          , afterInit: function () {
                var y = 145
                  , x = 178
                  ;
                drawLineArrow(0, y, 350, y);
                drawLineArrow(x, 290, x, 0);
                $(".termometer,.termistor-system").hide();
                $(".system").show();
                $(".physics-instrument.vol").css(initialPositions.vol);
                $(".physics-instrument.amp").css(initialPositions.amp);
            }
        }
      , diode: {
            name: "diode"
          , functionLaw: function (x) {
                if (x >= 0) {
                    return Math.pow (x, 3 / 2) * 4;
                }
                if (x < 0 && x > -4) {
                    return x / 5;
                }

                return -98.50000000015939 * Math.pow(x, 2) - 796.8500000012887 * x - 1612.2000000026096;
            }
          , x: {
                min: -4.5
              , max: 4.5
            }
          , afterInit: function () {
                var y = 187
                  , x = 174
                  ;
                drawLineArrow(0, y, 350, y);
                drawLineArrow(x, 290, x, 0);
                $(".termometer,.termistor-system").hide();
                $(".system").show();
                $(".physics-instrument.vol").css(initialPositions.vol);
                $(".physics-instrument.amp").css(initialPositions.amp);
            }
        }
      , termistor: {
            name: "termistor"
          , functionLaw: function (x) {
                if (x < 3 && x > -3) {
                    termometer.setValue(20);
                    return x * 5;
                }

                function computeTermometerValue () {
                    return x * (65/27) + 160/9;
                }

                termometer.setValue(computeTermometerValue().toFixed());
                return (x < 0 ? -1 : 1 ) * 15 - x / 10;
            }
          , x: {
                min: -17
              , max: 17
            }
          , y: {
                min: -30
              , max: 30
            }
          , afterInit: function () {
                var y = 145
                  , x = 174
                  ;

                drawLineArrow(0, y, 350, y);
                drawLineArrow(x, 290, x, 0);

                $(".termometer,.termistor-system").show();
                $(".system").hide();
                $(".physics-instrument.vol").css("top", "83px");
                $(".physics-instrument.amp").css({
                    top: "-20px"
                  , left: "1px"
                });
            }
        }
    };

    // attach y values
    for (var el in values) {
        values[el].y = {
            min: (values[el].y || {}).min || values[el].functionLaw(values[el].x.min)
          , max: (values[el].y || {}).max || values[el].functionLaw(values[el].x.max)
        };
    }

    $("select.changeElement").on("change", function () {
        currentElement = values[$(this).val()];

        // update elements
        $("[data-name]", ".changeableElement").hide();
        $("[data-name='" + currentElement.name + "']", ".changeableElement").show();

        $("#graph").empty();

        expGraph  = $.jqplot ('graph', [[[]]], {
            axesDefaults: {
                labelRenderer: $.jqplot.CanvasAxisLabelRenderer
            }
          , seriesDefaults: {
                showLine:false
            }
          , axes: {
                xaxis: {
                    label: "U (V)"
                  , min: currentElement.x.min
                  , max: currentElement.x.max
                  , tickOptions: {
                        formatString: "%#.2f"
                      , howGridline: false
                      , textColor: '#ffffff'
                      , fontSize: '12px'
                    }
                  , numberTicks: 11
                }
              , yaxis: {
                    label: "I (mA)"
                  , min: currentElement.y.min
                  , max: currentElement.y.max
                  , tickOptions: {
                        formatString: "%#.2f"
                      , howGridline: false
                      , textColor: '#ffffff'
                      , fontSize: '12px'
                    }
                  , numberTicks: 11
                }
            }
        });

        setTimeout(function () {
        currentElement.afterInit();
        }, 100);

        updateResult (0);
        latest = null;
        $(".vol input").val("0.00");
        $(".cursor").css("top", min);
        termometer.setValue(20);
        termometer.stop();
    }).change();

    $(".add-points").css({
        "bottom": "-360px"
      , "position": "absolute"
      , "left": "855px"
      , "width": "352px"
      , "font-weight": "bold"
    });

    // initial animation
    $(".container").css("opacity", "0").animate({
        opacity: 1
      , top: "50%"
    }, 1000);

    $("div.button.theory-switch").on("click", function () {

        var $screen = $(".screen")
          , $docs   = $(".docs")
          ;

        if (screenVisible) {
            $screen.stop(true).fadeOut();
            $docs.stop(true).fadeIn();
            screenVisible = false;
            $(".experiment[data-lang='" + $("select.language").val() +"']", this).show();
            $(".theory", this).hide();
        } else {
            $screen.stop(true).fadeIn();
            $docs.stop(true).fadeOut();
            screenVisible = true;
            $(".experiment", this).hide();
            $(".theory[data-lang='" + $("select.language").val() +"']", this).show();
        }
    });

    var max = 176
      , min = 50
      ;

    $("img").on("dragstart", function () {
        return false;
    });

    var latest = null;
    SimpleDraggable(".cursor", {
        onlyY: true
      , onDrag: function (e, cEl) {

            var xMax = currentElement.x.max;

            // change x with y
            if (currentElement.name === "termistor") {
                xMax = currentElement.y.max;
            }

            var value = (cEl.offsetTop - min) / ((max - min) / xMax);
            value = (degs === 0 ? 1 : -1) * value;
            if (!degs && value < 0 || degs && value > 0) {
                value = 0;
            }

            if (latest === null) { latest = value; }
            if (value > latest) {
                for (var i = latest; i < value; i += 0.2) {
                    updateResult(i);
                }
            } else {
                for (var i = value; i < latest; i += 0.2) {
                    updateResult(i);
                }
            }

            latest = value;

            if (cEl.offsetTop > max) {
                cEl.style.top = (parseInt(cEl.style.top) - 1) + "px";
                return false;
            }

            if (cEl.offsetTop < min) {
                cEl.style.top = (parseInt(cEl.style.top) + 1) + "px";
                return false;
            }
        }
    });

    /**
     * private: updateResult
     *   This function updates the result when the voltmeter
     *   value is changed.
     *
     *    Arguments
     *      @value: the value of the voltmeter
     *
     */
    function updateResult (value) {
        var x = value
          , y = currentElement.functionLaw (value)
          ;

        // change x with y
        if (currentElement.name === "termistor") {
            var aux = x;
            x = y;
            y = aux;
        }

        if ($(".add-points input").prop("checked")) {
            var seriesObj = expGraph.series[0];
            seriesObj.data.push([x, y]);
            seriesObj.data.sort (function (a, b) {
                return a[0] - b[0];
            });

            expGraph.drawSeries({},0);
        }

        $(".vol input").val(x.toFixed(2));
        $(".amp input").val(y.toFixed(2));
    }

    $(".clear-graph").on("click", function () {
        var seriesObj = expGraph.series[0];
        seriesObj.data = [];
        expGraph.drawSeries({},0);
    });
});
<|endoftext|>


<commit_before>// The state of a ccg type card game.

require("seedrandom")

const CARDS = [
  {
    name: "Twobot",
    attack: 2,
    defense: 2,
    cost: 1
  },
  {
    name: "Threebot",
    attack: 3,
    defense: 3,
    cost: 2
  },
  {
    name: "Donk",
    description: "End the next two turns.",
    endTurn: 2,
    cost: 7
  },
  {
    name: "Moloch's Howl",
    description: "Destroy all creatures.",
    howl: true,
    cost: 4
  },
]

// The state of a single player.
class PlayerState {
  constructor(data) {
    this.name = data.name
    this.hand = data.hand || []
    this.board = data.board || []
    this.trash = data.trash || []
    this.life = data.life || 30
    this.mana = data.mana || 0
    this.maxMana = data.maxMana || 0
  }

  // Throws if the index is bad
  getHand(index) {
    if (index >= this.hand.length) {
      throw (this.name + "'s hand has no card at index " + index)
    }
    return this.hand[index]
  }

  // Throws if the index is bad
  getBoard(index) {
    if (index >= this.board.length) {
      throw (this.name + "'s board has no card at index " + index)
    }
    return this.board[index]
  }
}

// A turn goes like
//
// beginTurn
// Some number of attack, face, and play
// endTurn
//
class GameState {

  // name is the name of the human at the controls.
  constructor(data) {
    this.name = data.name
    this._started = data._started || false

    // Index of whose turn it is.
    // The human at the controls is always 0 here.
    // We just start off with it not being our turn so that the UI
    // will be disabled - when we actually start the game it may or
    // may not be our turn.
    this.turn = (data.turn == null) ? 1 : data.turn

    let playerInfo = data.players || [{name: this.name},
                                      {name: "waiting for opponent..."}]
    this.players = playerInfo.map(info => new PlayerState(info))

    // The name of the winner
    this.winner = data.winner || null
  }

  // The player whose turn it is
  current() {
    return this.players[this.turn]
  }

  // The player whose turn it isn't
  opponent() {
    return this.players[1 - this.turn]
  }

  // Each type of move has a JSON representation.
  //
  // The useful keys are:
  // op: the method name. beginTurn, attack, face, play, endTurn
  // from: the index a card is coming from
  // to: the index a card is going to
  //
  // The move also has a "player" and "id" but those are only used by
  // the networking layer.
  //
  // makeMove makes a move that is provided via a JSON representation.
  //
  // In typical operation, only the Client should call makeMove.
  //
  // Returns whether the move was understood.
  makeMove(move) {
    if (this.winner != null) {
      // You can't make normal moves when the game is over
      return false
    }

    if (move.op == "beginTurn") {
      this.beginTurn()
    } else if (move.op == "attack") {
      this.attack(move.from, move.to)
    } else if (move.op == "face") {
      this.face(move.from)
    } else if (move.op == "play") {
      this.play(move.from)
    } else if (move.op == "endTurn") {
      this.endTurn()
    } else {
      console.log("ignoring op: " + move.op)
      return false
    }
    return true
  }

  startGame(players, seed) {
    this.rng = new Math.seedrandom(seed)
    if (players[0] == this.name) {
      // We go first
      console.log(`we, ${this.name}, go first`)
      this.turn = 0

      this.players[1].name = players[1]
    } else if (players[1] == this.name) {
      // We go second
      console.log(`we, ${this.name}, go second`)
      this.turn = 1

      this.players[1].name = players[0]
    } else {
      console.log(`a game started without me, ${this.name}`)
      return
    }

    this._started = true
    this.beginTurn()
  }

  started() {
    return this._started;
  }

  resolveDamage() {
    for (let player of this.players) {
      player.board = player.board.filter(card => card.defense > 0)
    }
    if (this.current().life <= 0) {
      this.winner = this.opponent().name
    } else if (this.opponent().life <= 0) {
      this.winner = this.current().name
    }
    if (this.winner != null) {
      console.log(this.winner + " wins!")
    }
  }

  // from and to are indices into board
  attack(from, to) {
    let attacker = this.current().getBoard(from)
    let defender = this.opponent().getBoard(to)
    attacker.defense -= defender.attack
    defender.defense -= attacker.attack
    this.resolveDamage()
  }

  // Plays a card from the hand.
  // Throws if there's not enough mana.
  // from is an index of the hand
  play(from) {
    let player = this.current()
    let card = player.getHand(from)
    if (player.mana < card.cost) {
      throw `need ${card.cost} mana but only have ${player.mana}`
    }

    // Handle creatures
    if (card.defense) {
      player.board.push(card)
      player.hand.splice(from, 1)
      player.mana -= card.cost
      return
    }

    // Handle spells with custom effects
    if (card.donk) {
      player.trash.push(card)
      player.hand.splice(from, 1)
      for (let i = 0; i < card.donk; i++) {
        this.endTurn()
        this.beginTurn()
      }
    } else if (card.howl) {
      for (let player of this.players) {
        player.board = []
      }
    }
  }

  // Whether the game has started
  started() {
    return this._started
  }

  // Attacks face
  face(from) {
    let attacker = this.current().getBoard(from)
    this.opponent().life -= attacker.attack
    this.resolveDamage()
  }

  draw() {
    // Make a copy so that we can edit this card
    let card = CARDS[Math.floor(this.rng() * CARDS.length)]
    let copy = {}
    for (let key in card) {
      copy[key] = card[key]
    }

    this.current().hand.push(copy)
  }

  beginTurn() {
    this.current().maxMana = Math.min(1 + this.current().maxMana, 10)
    this.current().mana = this.current().maxMana
    this.draw()
  }

  endTurn() {
    this.turn = 1 - this.turn
  }

  log() {
    console.log("It is player " + this.turn + "'s turn")
    console.log(this.players)
  }
}

module.exports = GameState;
<commit_msg>fix free-spell bug<commit_after>// The state of a ccg type card game.

require("seedrandom")

const CARDS = [
  {
    name: "Twobot",
    attack: 2,
    defense: 2,
    cost: 1
  },
  {
    name: "Threebot",
    attack: 3,
    defense: 3,
    cost: 2
  },
  {
    name: "Donk",
    description: "End the next two turns.",
    endTurn: 2,
    cost: 7
  },
  {
    name: "Moloch's Howl",
    description: "Destroy all creatures.",
    howl: true,
    cost: 4
  },
]

// The state of a single player.
class PlayerState {
  constructor(data) {
    this.name = data.name
    this.hand = data.hand || []
    this.board = data.board || []
    this.trash = data.trash || []
    this.life = data.life || 30
    this.mana = data.mana || 0
    this.maxMana = data.maxMana || 0
  }

  // Throws if the index is bad
  getHand(index) {
    if (index >= this.hand.length) {
      throw (this.name + "'s hand has no card at index " + index)
    }
    return this.hand[index]
  }

  // Throws if the index is bad
  getBoard(index) {
    if (index >= this.board.length) {
      throw (this.name + "'s board has no card at index " + index)
    }
    return this.board[index]
  }
}

// A turn goes like
//
// beginTurn
// Some number of attack, face, and play
// endTurn
//
class GameState {

  // name is the name of the human at the controls.
  constructor(data) {
    this.name = data.name
    this._started = data._started || false

    // Index of whose turn it is.
    // The human at the controls is always 0 here.
    // We just start off with it not being our turn so that the UI
    // will be disabled - when we actually start the game it may or
    // may not be our turn.
    this.turn = (data.turn == null) ? 1 : data.turn

    let playerInfo = data.players || [{name: this.name},
                                      {name: "waiting for opponent..."}]
    this.players = playerInfo.map(info => new PlayerState(info))

    // The name of the winner
    this.winner = data.winner || null
  }

  // The player whose turn it is
  current() {
    return this.players[this.turn]
  }

  // The player whose turn it isn't
  opponent() {
    return this.players[1 - this.turn]
  }

  // Each type of move has a JSON representation.
  //
  // The useful keys are:
  // op: the method name. beginTurn, attack, face, play, endTurn
  // from: the index a card is coming from
  // to: the index a card is going to
  //
  // The move also has a "player" and "id" but those are only used by
  // the networking layer.
  //
  // makeMove makes a move that is provided via a JSON representation.
  //
  // In typical operation, only the Client should call makeMove.
  //
  // Returns whether the move was understood.
  makeMove(move) {
    if (this.winner != null) {
      // You can't make normal moves when the game is over
      return false
    }

    if (move.op == "beginTurn") {
      this.beginTurn()
    } else if (move.op == "attack") {
      this.attack(move.from, move.to)
    } else if (move.op == "face") {
      this.face(move.from)
    } else if (move.op == "play") {
      this.play(move.from)
    } else if (move.op == "endTurn") {
      this.endTurn()
    } else {
      console.log("ignoring op: " + move.op)
      return false
    }
    return true
  }

  startGame(players, seed) {
    this.rng = new Math.seedrandom(seed)
    if (players[0] == this.name) {
      // We go first
      console.log(`we, ${this.name}, go first`)
      this.turn = 0

      this.players[1].name = players[1]
    } else if (players[1] == this.name) {
      // We go second
      console.log(`we, ${this.name}, go second`)
      this.turn = 1

      this.players[1].name = players[0]
    } else {
      console.log(`a game started without me, ${this.name}`)
      return
    }

    this._started = true
    this.beginTurn()
  }

  started() {
    return this._started;
  }

  resolveDamage() {
    for (let player of this.players) {
      player.board = player.board.filter(card => card.defense > 0)
    }
    if (this.current().life <= 0) {
      this.winner = this.opponent().name
    } else if (this.opponent().life <= 0) {
      this.winner = this.current().name
    }
    if (this.winner != null) {
      console.log(this.winner + " wins!")
    }
  }

  // from and to are indices into board
  attack(from, to) {
    let attacker = this.current().getBoard(from)
    let defender = this.opponent().getBoard(to)
    attacker.defense -= defender.attack
    defender.defense -= attacker.attack
    this.resolveDamage()
  }

  // Plays a card from the hand.
  // Throws if there's not enough mana.
  // from is an index of the hand
  play(from) {
    let player = this.current()
    let card = player.getHand(from)
    if (player.mana < card.cost) {
      throw `need ${card.cost} mana but only have ${player.mana}`
    }
    player.mana -= card.cost

    // Handle creatures
    if (card.defense) {
      player.board.push(card)
      player.hand.splice(from, 1)
      return
    }

    // Handle spells with custom effects
    if (card.donk) {
      player.trash.push(card)
      player.hand.splice(from, 1)
      for (let i = 0; i < card.donk; i++) {
        this.endTurn()
        this.beginTurn()
      }
    } else if (card.howl) {
      for (let player of this.players) {
        player.board = []
      }
    }
  }

  // Whether the game has started
  started() {
    return this._started
  }

  // Attacks face
  face(from) {
    let attacker = this.current().getBoard(from)
    this.opponent().life -= attacker.attack
    this.resolveDamage()
  }

  draw() {
    // Make a copy so that we can edit this card
    let card = CARDS[Math.floor(this.rng() * CARDS.length)]
    let copy = {}
    for (let key in card) {
      copy[key] = card[key]
    }

    this.current().hand.push(copy)
  }

  beginTurn() {
    this.current().maxMana = Math.min(1 + this.current().maxMana, 10)
    this.current().mana = this.current().maxMana
    this.draw()
  }

  endTurn() {
    this.turn = 1 - this.turn
  }

  log() {
    console.log("It is player " + this.turn + "'s turn")
    console.log(this.players)
  }
}

module.exports = GameState;
<|endoftext|>


<commit_before>import 'babel-polyfill';
import {processDonationGraphs} from "./dashboardGraphLogic";

var fluxApp = angular.module('fluxApp', []);

// NOTE: This is just for dashboard.html; and is separate to the FluxController in members.html and membership-ng.js, etc
fluxApp.controller('GraphsController', function ($scope, $log, $rootScope, $http) {
  $rootScope._ = _;

  var flux = this;
  flux.membershipError = '';
  $scope._showExtraGraphs = false;
  flux.signupVolunteer = false;
  flux.growthDays = [];  // note: set later on to trigger redraw
  flux.nameTempVar = "Dashboard";
  flux.averageMonthlyGrowth = 0;
  flux.getinfo = {n_members_state: {}, n_members_validated_state: {}, validation_queue_state: {}};

  flux.debug = false;
  if (document.location.hostname === 'localhost') {
    flux.debug = true;
  }

  flux.handleError = function (error) {
    $log.log('An error occured:');
    $log.log(error);
  };

  flux.api = function (path) {
    if (flux.debug) {
      return "http://localhost:5000/api/v0/" + path;
    }
    return "https://api.voteflux.org/api/v0/" + path;
  };

  flux.growthStat = function (d) {
    return 0;
  };

  $http.get(flux.api('getinfo')).then(function (data) {
    flux.getinfo = data.data;
    console.log("Got getinfo: ", flux.getinfo);
  }, flux.handleError);

  // generate graphs from public stats
  $http.get(flux.api('public_stats')).then(function (data) {
    $log.log("Got public stats ---V ");
    $log.log(data['data']);

    // members over time
    var tss = _.map(data.data.signup_times, function (ts) {
      return new Date(ts * 1000);
    });
    tss.reverse();
    var ns = _.range(1, tss.length + 1);
    var plotData = [{x: tss, y: ns, type: 'scatter'}];
    Plotly.newPlot('membershipChart', plotData, {title: 'Members v Time'});

    // dob years histogram
    var years = Object.keys(data.data.dob_years);
    years.sort();
    var year_freq = _.map(years, function (y) {
      return data.data.dob_years[y]
    });
    var plotData2 = [{x: years, y: year_freq, type: 'bar'}];
    Plotly.newPlot('memberDobYearChart', plotData2, {title: 'Member Years of Birth'});

    // states histogram
    var states = Object.keys(data.data['states']);
    states.sort();
    var state_n = _.map(states, function (y) {
      return data.data['states'][y]
    });
    var plotData3 = [{x: states, y: state_n, type: 'bar'}];
    Plotly.newPlot('memberStateChart', plotData3, {title: 'Member States'});

    // members over last 60 days and 7 days (hourly)
    var nDays = 60;
    var nDaysForHours = 7;
    var _now = Date.now();
    var _7_days_ago = _now - (nDaysForHours * 24 * 60 * 60 * 1000);
    var _n_days_ago = _now - (nDays * 24 * 60 * 60 * 1000);
    var recent_tss = _.filter(data.data['signup_times'], function (timestamp) {
      return timestamp * 1000 > (_now - 1000 * 60 * 60 * 24 * (nDays + 1));
    });

    // http://stackoverflow.com/questions/3552461/how-to-format-a-javascript-date
    function toJSONLocal(date) {
      var local = new Date(date);
      local.setMinutes(date.getMinutes() - date.getTimezoneOffset());
      return local.toJSON().slice(0, 10);
    }

    var timestamp_counter = {};
    var timestamp_counter_for_hours = {};

    _.map(_.range(_n_days_ago, _now + 1000 * 60 * 60, 1000 * 60 * 60), function (ts) {
      var ts_date = new Date(ts);
      var y_m_d = toJSONLocal(ts_date);
      timestamp_counter[y_m_d] = 0;
      if (ts > _7_days_ago)
        timestamp_counter_for_hours[y_m_d + '-' + ts_date.getHours().toString()] = 0;
    });  // hourly increments set default.

    _.map(recent_tss, function (ts) {
      var ts_date = new Date(ts * 1000);
      var local_y_m_d = toJSONLocal(ts_date);
      timestamp_counter[local_y_m_d] += 1;
      if (ts * 1000 > _7_days_ago) {
        timestamp_counter_for_hours[local_y_m_d + '-' + ts_date.getHours().toString()] += 1;
      }
    });
    var results = timestamp_counter;
    $log.log(results);
    var dates4 = Object.keys(results);
    var datesSignupsHourly = Object.keys(timestamp_counter_for_hours);
    dates4.pop();  // account for the one day added when generating recent_tss;
    var newMembers = _.map(dates4, function (d) {
      return results[d];
    });
    var hourlySignups = _.map(datesSignupsHourly, function (d) {
      return timestamp_counter_for_hours[d];
    });
    var plotData4 = [{x: dates4, y: newMembers, type: 'bar'}];
    var plotDataSignupsHourly = [{type: 'bar', line: {shape: 'spline'}, x: datesSignupsHourly, y: hourlySignups}];

    Plotly.newPlot('memberSignupDaysAgo', plotData4, {
      title: 'Member Signup for Last ' + nDays.toString() + ' Days',
      xaxis: {title: 'Days Ago'}, yaxis: {title: '# Signups'}
    });
    Plotly.newPlot('memberSignupHoursAgo', plotDataSignupsHourly, {
      'title': 'Members Signups last 7 days, hourly',
      xaxis: {title: 'Signup time'}, yaxis: {title: '# Signups'}
    });

    // day and hour popularity
    var day_pop = {};
    var hour_pop = {};
    var day_map = {
      0: 'Sunday',
      1: 'Monday',
      2: 'Tuesday',
      3: 'Wednesday',
      4: 'Thursday',
      5: 'Friday',
      6: 'Saturday'
    };
    var days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
    _.map(tss, function (ts) {
      var d = day_map[ts.getDay()];
      if (day_pop[d] === undefined) day_pop[d] = 1;
      else day_pop[d] += 1;

      var h = ts.getHours();
      if (hour_pop[h] === undefined) hour_pop[h] = 1;
      else hour_pop[h] += 1;
    });
    var dp_x = days;
    var dh_x = Object.keys(hour_pop);
    var plotDataDayPop = [{
      x: dp_x, y: _.map(dp_x, function (x) {
        return day_pop[x];
      })
    }];
    var plotDataHourPop = [{
      x: dh_x, y: _.map(dh_x, function (x) {
        return hour_pop[x];
      })
    }];
    Plotly.newPlot('memberDayPopularity', plotDataDayPop, {
      title: 'All Member Signups By Day',
      yaxis: {'rangemode': 'tozero'}
    });
    Plotly.newPlot('memberHourPopularity', plotDataHourPop, {
      title: 'All Member Signups By Hour',
      yaxis: {'rangemode': 'tozero'}
    });

    // state signup times
    //var
    var drawStateSignupTimes = function () {
      var stateSignupTimes = data.data['state_signup_times'];
      var plotStateSignupTimes = [];
      var states = Object.keys(stateSignupTimes);
      states.forEach(function (stateName) {
        plotStateSignupTimes.push({
          x: _.map(stateSignupTimes[stateName], function (ts) {
            return new Date(ts * 1000);
          }),
          y: _.range(1, stateSignupTimes[stateName].length + 1),
          type: 'scatter',
          name: stateName
        })
      });
      Plotly.newPlot('stateSignupTimes', plotStateSignupTimes, {title: 'Members v Time by State'});
    };
    drawStateSignupTimes();

    flux.growthStat = function (d) {
      var ts_now = Date.now();
      var ts_ago = new Date(ts_now - (d * 24 * 60 * 60 * 1000));
      var tss_before = _.filter(tss, function (_ts) {
        return _ts < ts_ago;
      });
      var tss_after = _.filter(tss, function (_ts) {
        return _ts >= ts_ago;
      });
      return Math.round(tss_after.length / tss_before.length * 1000) / 1000;
    };
    flux.growthDays = [30, 7, 2, 1];

    // monthly growth
    flux.calcMonthlyGrowth = function (tss) {
      var month_count = {};
      _.map(tss, function (d) {
        var _month_id = d.toJSON().slice(0, 7);
        month_count[_month_id] = month_count[_month_id] ? month_count[_month_id] + 1 : 1;
      });
      var months = _.keys(month_count);
      months.sort();
      var members_per_month = _.map(months, function (m) {
        return month_count[m];
      });
      var cumulative = {};
      _.map(_.range(months.length), function (_i) {
        cumulative[months[_i]] = _.sum(_.slice(members_per_month, 0, _i + 1));
      });
      console.log(cumulative);
      console.log(members_per_month);
      flux.monthlyGrowth = [];
      var rates = [];
      _.map(_.range(2, months.length), function (_i) {
        var _rate = members_per_month[_i] / cumulative[months[_i - 1]] * 100;
        flux.monthlyGrowth.push({
          name: months[_i],
          rate: (_rate).toString().slice(0, 5)
        });
        rates.push(_rate);
      });
      flux.averageMonthlyGrowth = (_.sum(rates) / rates.length).toString().slice(0, 4);
    };
    flux.calcMonthlyGrowth(tss);

    $http.get(flux_api('api/v1/anon_donation_log')).then(data => {
      try {
        // this might fail for some due to using ES6
        flux.donationLog = processDonationGraphs(data);
      } catch (err) {
        console.log('Got error in donation graphs: ', err);
      }
    }, flux.handleError);

    $log.log('Init\'d charts');
  }, flux.handleError)
});
<commit_msg>Use some `let`s<commit_after>import 'babel-polyfill';
import {processDonationGraphs} from "./dashboardGraphLogic";

var fluxApp = angular.module('fluxApp', []);

// NOTE: This is just for dashboard.html; and is separate to the FluxController in members.html and membership-ng.js, etc
fluxApp.controller('GraphsController', function ($scope, $log, $rootScope, $http) {
  $rootScope._ = _;

  var flux = this;
  flux.membershipError = '';
  $scope._showExtraGraphs = false;
  flux.signupVolunteer = false;
  flux.growthDays = [];  // note: set later on to trigger redraw
  flux.nameTempVar = "Dashboard";
  flux.averageMonthlyGrowth = 0;
  flux.getinfo = {n_members_state: {}, n_members_validated_state: {}, validation_queue_state: {}};

  flux.debug = false;
  if (document.location.hostname === 'localhost') {
    flux.debug = true;
  }

  flux.handleError = function (error) {
    $log.log('An error occured:');
    $log.log(error);
  };

  flux.api = function (path) {
    if (flux.debug) {
      return "http://localhost:5000/api/v0/" + path;
    }
    return "https://api.voteflux.org/api/v0/" + path;
  };

  flux.growthStat = function (d) {
    return 0;
  };

  $http.get(flux.api('getinfo')).then(function (data) {
    flux.getinfo = data.data;
    console.log("Got getinfo: ", flux.getinfo);
  }, flux.handleError);

  // generate graphs from public stats
  $http.get(flux.api('public_stats')).then(function (data) {
    $log.log("Got public stats ---V ");
    $log.log(data['data']);

    // members over time
    var tss = _.map(data.data.signup_times, function (ts) {
      return new Date(ts * 1000);
    });
    tss.reverse();
    var ns = _.range(1, tss.length + 1);
    var plotData = [{x: tss, y: ns, type: 'scatter'}];
    Plotly.newPlot('membershipChart', plotData, {title: 'Members v Time'});

    // dob years histogram
    var years = Object.keys(data.data.dob_years);
    years.sort();
    var year_freq = _.map(years, function (y) {
      return data.data.dob_years[y]
    });
    var plotData2 = [{x: years, y: year_freq, type: 'bar'}];
    Plotly.newPlot('memberDobYearChart', plotData2, {title: 'Member Years of Birth'});

    // states histogram
    var states = Object.keys(data.data['states']);
    states.sort();
    var state_n = _.map(states, function (y) {
      return data.data['states'][y]
    });
    var plotData3 = [{x: states, y: state_n, type: 'bar'}];
    Plotly.newPlot('memberStateChart', plotData3, {title: 'Member States'});

    // members over last 60 days and 7 days (hourly)
    var nDays = 60;
    var nDaysForHours = 7;
    var _now = Date.now();
    var _7_days_ago = _now - (nDaysForHours * 24 * 60 * 60 * 1000);
    var _n_days_ago = _now - (nDays * 24 * 60 * 60 * 1000);
    var recent_tss = _.filter(data.data['signup_times'], function (timestamp) {
      return timestamp * 1000 > (_now - 1000 * 60 * 60 * 24 * (nDays + 1));
    });

    // http://stackoverflow.com/questions/3552461/how-to-format-a-javascript-date
    function toJSONLocal(date) {
      var local = new Date(date);
      local.setMinutes(date.getMinutes() - date.getTimezoneOffset());
      return local.toJSON().slice(0, 10);
    }

    var timestamp_counter = {};
    var timestamp_counter_for_hours = {};

    _.map(_.range(_n_days_ago, _now + 1000 * 60 * 60, 1000 * 60 * 60), function (ts) {
      let ts_date = new Date(ts);
      var y_m_d = toJSONLocal(ts_date);
      timestamp_counter[y_m_d] = 0;
      if (ts > _7_days_ago)
        timestamp_counter_for_hours[y_m_d + '-' + ts_date.getHours().toString()] = 0;
    });  // hourly increments set default.

    _.map(recent_tss, function (ts) {
      let ts_date = new Date(ts * 1000);
      var local_y_m_d = toJSONLocal(ts_date);
      timestamp_counter[local_y_m_d] += 1;
      if (ts * 1000 > _7_days_ago) {
        timestamp_counter_for_hours[local_y_m_d + '-' + ts_date.getHours().toString()] += 1;
      }
    });
    var results = timestamp_counter;
    $log.log(results);
    var dates4 = Object.keys(results);
    var datesSignupsHourly = Object.keys(timestamp_counter_for_hours);
    dates4.pop();  // account for the one day added when generating recent_tss;
    var newMembers = _.map(dates4, function (d) {
      return results[d];
    });
    var hourlySignups = _.map(datesSignupsHourly, function (d) {
      return timestamp_counter_for_hours[d];
    });
    var plotData4 = [{x: dates4, y: newMembers, type: 'bar'}];
    var plotDataSignupsHourly = [{type: 'bar', line: {shape: 'spline'}, x: datesSignupsHourly, y: hourlySignups}];

    Plotly.newPlot('memberSignupDaysAgo', plotData4, {
      title: 'Member Signup for Last ' + nDays.toString() + ' Days',
      xaxis: {title: 'Days Ago'}, yaxis: {title: '# Signups'}
    });
    Plotly.newPlot('memberSignupHoursAgo', plotDataSignupsHourly, {
      'title': 'Members Signups last 7 days, hourly',
      xaxis: {title: 'Signup time'}, yaxis: {title: '# Signups'}
    });

    // day and hour popularity
    var day_pop = {};
    var hour_pop = {};
    var day_map = {
      0: 'Sunday',
      1: 'Monday',
      2: 'Tuesday',
      3: 'Wednesday',
      4: 'Thursday',
      5: 'Friday',
      6: 'Saturday'
    };
    var days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
    _.map(tss, function (ts) {
      var d = day_map[ts.getDay()];
      if (day_pop[d] === undefined) day_pop[d] = 1;
      else day_pop[d] += 1;

      var h = ts.getHours();
      if (hour_pop[h] === undefined) hour_pop[h] = 1;
      else hour_pop[h] += 1;
    });
    var dp_x = days;
    var dh_x = Object.keys(hour_pop);
    var plotDataDayPop = [{
      x: dp_x, y: _.map(dp_x, function (x) {
        return day_pop[x];
      })
    }];
    var plotDataHourPop = [{
      x: dh_x, y: _.map(dh_x, function (x) {
        return hour_pop[x];
      })
    }];
    Plotly.newPlot('memberDayPopularity', plotDataDayPop, {
      title: 'All Member Signups By Day',
      yaxis: {'rangemode': 'tozero'}
    });
    Plotly.newPlot('memberHourPopularity', plotDataHourPop, {
      title: 'All Member Signups By Hour',
      yaxis: {'rangemode': 'tozero'}
    });

    // state signup times
    //var
    var drawStateSignupTimes = function () {
      var stateSignupTimes = data.data['state_signup_times'];
      var plotStateSignupTimes = [];
      var states = Object.keys(stateSignupTimes);
      states.forEach(function (stateName) {
        plotStateSignupTimes.push({
          x: _.map(stateSignupTimes[stateName], function (ts) {
            return new Date(ts * 1000);
          }),
          y: _.range(1, stateSignupTimes[stateName].length + 1),
          type: 'scatter',
          name: stateName
        })
      });
      Plotly.newPlot('stateSignupTimes', plotStateSignupTimes, {title: 'Members v Time by State'});
    };
    drawStateSignupTimes();

    flux.growthStat = function (d) {
      var ts_now = Date.now();
      var ts_ago = new Date(ts_now - (d * 24 * 60 * 60 * 1000));
      var tss_before = _.filter(tss, function (_ts) {
        return _ts < ts_ago;
      });
      var tss_after = _.filter(tss, function (_ts) {
        return _ts >= ts_ago;
      });
      return Math.round(tss_after.length / tss_before.length * 1000) / 1000;
    };
    flux.growthDays = [30, 7, 2, 1];

    // monthly growth
    flux.calcMonthlyGrowth = function (tss) {
      var month_count = {};
      _.map(tss, function (d) {
        var _month_id = d.toJSON().slice(0, 7);
        month_count[_month_id] = month_count[_month_id] ? month_count[_month_id] + 1 : 1;
      });
      var months = _.keys(month_count);
      months.sort();
      var members_per_month = _.map(months, function (m) {
        return month_count[m];
      });
      var cumulative = {};
      _.map(_.range(months.length), function (_i) {
        cumulative[months[_i]] = _.sum(_.slice(members_per_month, 0, _i + 1));
      });
      console.log(cumulative);
      console.log(members_per_month);
      flux.monthlyGrowth = [];
      var rates = [];
      _.map(_.range(2, months.length), function (_i) {
        var _rate = members_per_month[_i] / cumulative[months[_i - 1]] * 100;
        flux.monthlyGrowth.push({
          name: months[_i],
          rate: (_rate).toString().slice(0, 5)
        });
        rates.push(_rate);
      });
      flux.averageMonthlyGrowth = (_.sum(rates) / rates.length).toString().slice(0, 4);
    };
    flux.calcMonthlyGrowth(tss);

    $http.get(flux_api('api/v1/anon_donation_log')).then(data => {
      try {
        // this might fail for some due to using ES6
        flux.donationLog = processDonationGraphs(data);
      } catch (err) {
        console.log('Got error in donation graphs: ', err);
      }
    }, flux.handleError);

    $log.log('Init\'d charts');
  }, flux.handleError)
});
<|endoftext|>


<commit_before>/*!
 * Start Bootstrap - Grayscale Bootstrap Theme (http://startbootstrap.com)
 * Code licensed under the Apache License v2.0.
 * For details, see http://www.apache.org/licenses/LICENSE-2.0.
 */

//Page Preloader
$(window).load(function(){
    $('#page-loader').fadeOut(500);
});

// jQuery to collapse the navbar on scroll
function collapseNavbar() {
    if ($(".navbar").offset().top > 50) {
        $(".navbar-fixed-top").addClass("top-nav-collapse");

    } else {
        $(".navbar-fixed-top").removeClass("top-nav-collapse");
    }
}

$(window).scroll(collapseNavbar);
$(document).ready(collapseNavbar);

// jQuery for page scrolling feature - requires jQuery Easing plugin
$(function() {
    $('a.page-scroll').bind('click', function(event) {
        var $anchor = $(this);
        $('html, body').stop().animate({
            scrollTop: $($anchor.attr('href')).offset().top
        }, 1500, 'easeInOutExpo');
        event.preventDefault();
    });
});

// Closes the Responsive Menu on Menu Item Click
$('.navbar-collapse ul li a').click(function() {
  if ($(this).attr('class') != 'dropdown-toggle active' && $(this).attr('class') != 'dropdown-toggle') {
    $('.navbar-toggle:visible').click();
  }
});

$('.intro').backstretch([
      "img/intro-bg.jpg",
      "img/intro-bg2.jpg",
      "img/intro-bg3.jpg"
  ], {duration: 5000, fade: 1000});

$('body').append('');

$('#sponsors').waypoint(function(direction){

    if($('.preload-image').length){$('.preload-image').remove();}

    $('.backstretch').remove();

    if (direction=='down'){
        $.backstretch('img/contact-bg.jpg');
    }else{
        // $.backstretch('assets/header-bg.jpg');
        $('.intro').backstretch([
              "img/intro-bg.jpg",
              "img/intro-bg2.jpg",
              "img/intro-bg3.jpg"
          ], {duration: 5000, fade: 1000});
    }
});

function isElementInViewport(elem) {
    var $elem = $(elem);

    // Get the scroll position of the page.
    var scrollElem = ((navigator.userAgent.toLowerCase().indexOf('webkit') != -1) ? 'body' : 'html');
    var viewportTop = $(scrollElem).scrollTop();
    var viewportBottom = viewportTop + $(window).height();

    // Get the position of the element on the page.
    var elemTop = Math.round( $elem.offset().top );
    var elemBottom = elemTop + $elem.height();
    var elemMid = (elemTop + elemBottom)/2
    return ((elemMid < viewportBottom) && (elemMid > viewportTop));
}

// Check if it's time to start the animation.
function checkAnimation($elem) {

    // If the animation has already been started
    if ($elem.hasClass('start')) {
        if (!isElementInViewport($elem))
            $elem.removeClass('start');
        else
            return;
    }
    if (isElementInViewport($elem)) {
        // Start the animation
        $elem.focus();
    } else {
        $elem.blur()
    }
}

$(document).ready(function(){
  $("#c1").on("hide.bs.collapse", function(){
    $("#b1").html(' Co-Chairs');
  });
  $("#c1").on("show.bs.collapse", function(){
    $("#b1").html(' Co-Chairs');
  });
});
$(document).ready(function(){
  $("#c2").on("hide.bs.collapse", function(){
    $("#b2").html(' Logistics');
  });
  $("#c2").on("show.bs.collapse", function(){
    $("#b2").html(' Logistics');
  });
});
$(document).ready(function(){
  $("#c3").on("hide.bs.collapse", function(){
    $("#b3").html(' Finance');
  });
  $("#c3").on("show.bs.collapse", function(){
    $("#b3").html(' Finanace');
  });
});
$(document).ready(function(){
  $("#c4").on("hide.bs.collapse", function(){
    $("#b4").html(' Workshops');
  });
  $("#c4").on("show.bs.collapse", function(){
    $("#b4").html(' Workshops');
  });
});
$(document).ready(function(){
  $("#c5").on("hide.bs.collapse", function(){
    $("#b5").html(' Publicity');
  });
  $("#c5").on("show.bs.collapse", function(){
    $("#b5").html(' Publicity');
  });
});
$(document).ready(function(){
  $("#c6").on("hide.bs.collapse", function(){
    $("#b6").html(' Multimedia');
  });
  $("#c6").on("show.bs.collapse", function(){
    $("#b6").html(' Multimedia');
  });
});
$(document).ready(function(){
  $("#c7").on("hide.bs.collapse", function(){
    $("#b7").html(' Community Liaison');
  });
  $("#c7").on("show.bs.collapse", function(){
    $("#b7").html(' Community Liaison');
  });
});
$(document).ready(function(){
  $("#c8").on("hide.bs.collapse", function(){
    $("#b8").html(' Entertainment');
  });
  $("#c8").on("show.bs.collapse", function(){
    $("#b8").html(' Entertainment');
  });
});
$(document).ready(function(){
  $("#c9").on("hide.bs.collapse", function(){
    $("#b9").html(' Registration');
  });
  $("#c9").on("show.bs.collapse", function(){
    $("#b9").html(' Registration');
  });
});
$(document).ready(function(){
  $("#c10").on("hide.bs.collapse", function(){
    $("#b10").html(' Volunteer Coordinator');
  });
  $("#c10").on("show.bs.collapse", function(){
    $("#b10").html(' Volunteer Coordinator');
  });
});
$(document).ready(function(){
  $("#c10").on("hide.bs.collapse", function(){
    $("#b10").html(' Volunteer Coordinator');
  });
  $("#c10").on("show.bs.collapse", function(){
    $("#b10").html(' Volunteer Coordinator');
  });
});
// I took out the lorem dim sum from this file, it now lives in schedule.js -tiners

$('.scrollimation').waypoint(function(){
        $(this).toggleClass('in');
    },{offset:'90%'});

// Capture scroll events
$(window).scroll(function(){
    checkAnimation($('.about'));
    checkAnimation($('.schedule'));
    checkAnimation($('.sponsors'));
    collapseSliders($('.board'));
});
<commit_msg>Update grayscale.js<commit_after>/*!
 * Start Bootstrap - Grayscale Bootstrap Theme (http://startbootstrap.com)
 * Code licensed under the Apache License v2.0.
 * For details, see http://www.apache.org/licenses/LICENSE-2.0.
 */

//Page Preloader
$(window).load(function(){
    $('#page-loader').fadeOut(500);
});

// jQuery to collapse the navbar on scroll
function collapseNavbar() {
    if ($(".navbar").offset().top > 50) {
        $(".navbar-fixed-top").addClass("top-nav-collapse");

    } else {
        $(".navbar-fixed-top").removeClass("top-nav-collapse");
    }
}

$(window).scroll(collapseNavbar);
$(document).ready(collapseNavbar);

// jQuery for page scrolling feature - requires jQuery Easing plugin
$(function() {
    $('a.page-scroll').bind('click', function(event) {
        var $anchor = $(this);
        $('html, body').stop().animate({
            scrollTop: $($anchor.attr('href')).offset().top
        }, 1500, 'easeInOutExpo');
        event.preventDefault();
    });
});

// Closes the Responsive Menu on Menu Item Click
$('.navbar-collapse ul li a').click(function() {
  if ($(this).attr('class') != 'dropdown-toggle active' && $(this).attr('class') != 'dropdown-toggle') {
    $('.navbar-toggle:visible').click();
  }
});

$('.intro').backstretch([
      "img/intro-bg.jpg",
      "img/intro-bg2.jpg",
      "img/intro-bg3.jpg"
  ], {duration: 5000, fade: 1000});

$('body').append('');

$('#sponsors').waypoint(function(direction){

    if($('.preload-image').length){$('.preload-image').remove();}

    $('.backstretch').remove();

    if (direction=='down'){
        $.backstretch('img/contact-bg.jpg');
    }else{
        // $.backstretch('assets/header-bg.jpg');
        $('.intro').backstretch([
              "img/intro-bg.jpg",
              "img/intro-bg2.jpg",
              "img/intro-bg3.jpg"
          ], {duration: 5000, fade: 1000});
    }
});

function isElementInViewport(elem) {
    var $elem = $(elem);

    // Get the scroll position of the page.
    var scrollElem = ((navigator.userAgent.toLowerCase().indexOf('webkit') != -1) ? 'body' : 'html');
    var viewportTop = $(scrollElem).scrollTop();
    var viewportBottom = viewportTop + $(window).height();

    // Get the position of the element on the page.
    var elemTop = Math.round( $elem.offset().top );
    var elemBottom = elemTop + $elem.height();
    var elemMid = (elemTop + elemBottom)/2
    return ((elemMid < viewportBottom) && (elemMid > viewportTop));
}

// Check if it's time to start the animation.
function checkAnimation($elem) {

    // If the animation has already been started
    if ($elem.hasClass('start')) {
        if (!isElementInViewport($elem))
            $elem.removeClass('start');
        else
            return;
    }
    if (isElementInViewport($elem)) {
        // Start the animation
        $elem.focus();
    } else {
        $elem.blur()
    }
}

$(document).ready(function(){
  $("#c1").on("hide.bs.collapse", function(){
    $("#b1").html(' Co-Chairs');
  });
  $("#c1").on("show.bs.collapse", function(){
    $("#b1").html(' Co-Chairs');
  });
});
$(document).ready(function(){
  $("#c2").on("hide.bs.collapse", function(){
    $("#b2").html(' Logistics');
  });
  $("#c2").on("show.bs.collapse", function(){
    $("#b2").html(' Logistics');
  });
});
$(document).ready(function(){
  $("#c3").on("hide.bs.collapse", function(){
    $("#b3").html(' Finance');
  });
  $("#c3").on("show.bs.collapse", function(){
    $("#b3").html(' Finanace');
  });
});
$(document).ready(function(){
  $("#c4").on("hide.bs.collapse", function(){
    $("#b4").html(' Workshops');
  });
  $("#c4").on("show.bs.collapse", function(){
    $("#b4").html(' Workshops');
  });
});
$(document).ready(function(){
  $("#c5").on("hide.bs.collapse", function(){
    $("#b5").html(' Publicity');
  });
  $("#c5").on("show.bs.collapse", function(){
    $("#b5").html(' Publicity');
  });
});
$(document).ready(function(){
  $("#c6").on("hide.bs.collapse", function(){
    $("#b6").html(' Multimedia');
  });
  $("#c6").on("show.bs.collapse", function(){
    $("#b6").html(' Multimedia');
  });
});
$(document).ready(function(){
  $("#c7").on("hide.bs.collapse", function(){
    $("#b7").html(' Community Liaison');
  });
  $("#c7").on("show.bs.collapse", function(){
    $("#b7").html(' Community Liaison');
  });
});
$(document).ready(function(){
  $("#c8").on("hide.bs.collapse", function(){
    $("#b8").html(' Entertainment');
  });
  $("#c8").on("show.bs.collapse", function(){
    $("#b8").html(' Entertainment');
  });
});
$(document).ready(function(){
  $("#c9").on("hide.bs.collapse", function(){
    $("#b9").html(' Registration');
  });
  $("#c9").on("show.bs.collapse", function(){
    $("#b9").html(' Registration');
  });
});
$(document).ready(function(){
  $("#c10").on("hide.bs.collapse", function(){
    $("#b10").html(' Volunteer Coordinator');
  });
  $("#c10").on("show.bs.collapse", function(){
    $("#b10").html(' Volunteer Coordinator');
  });
});
$(document).ready(function(){
  $("#c10").on("hide.bs.collapse", function(){
    $("#b10").html(' Volunteer Coordinator');
  });
  $("#c10").on("show.bs.collapse", function(){
    $("#b10").html(' Volunteer Coordinator');
  });
});
// I took out the lorem dim sum from this file, it now lives in schedule.js -tiners

$('.scrollimation').waypoint(function(){
        $(this).toggleClass('in');
    },{offset:'90%'});

// Capture scroll events
$(window).scroll(function(){
    checkAnimation($('.about'));
    checkAnimation($('.schedule'));
    checkAnimation($('.sponsors'));
});
<|endoftext|>


<commit_before>/*!
 * Start Bootstrap - Grayscale Bootstrap Theme (http://startbootstrap.com)
 * Code licensed under the Apache License v2.0.
 * For details, see http://www.apache.org/licenses/LICENSE-2.0.
 */

//Page Preloader
$(window).load(function(){
    $('#page-loader').fadeOut(500);
});

$(document).ready(collapseNavbar);

// jQuery to collapse the navbar on scroll
function collapseNavbar() {
    if ($(".navbar").offset().top > 50) {
        $(".navbar-fixed-top").addClass("top-nav-collapse");
    } else {
        $(".navbar-fixed-top").removeClass("top-nav-collapse");
    }
}

$(window).scroll(collapseNavbar);

// jQuery for page scrolling feature - requires jQuery Easing plugin
$(function() {
    $('a.page-scroll').bind('click', function(event) {
        var $anchor = $(this);
        $('html, body').stop().animate({
            scrollTop: $($anchor.attr('href')).offset().top
        }, 1500, 'easeInOutExpo');
        event.preventDefault();
    });
});

// Closes the Responsive Menu on Menu Item Click
$('.navbar-collapse ul li a').click(function() {
  if ($(this).attr('class') != 'dropdown-toggle active' && $(this).attr('class') != 'dropdown-toggle') {
    $('.navbar-toggle:visible').click();
  }
});

$('.intro').backstretch([
      "img/intro-bg.jpg",
      "img/intro-bg2.jpg",
      "img/intro-bg3.jpg"
  ], {duration: 5000, fade: 1000});

$('body').append('');

$('#board').waypoint(function(direction){

    if($('.preload-image').length){$('.preload-image').remove();}

    $('.backstretch').remove();

    if (direction=='down'){
        $.backstretch('img/contact-bg.jpg');
    }else{
        // $.backstretch('assets/header-bg.jpg');
        $('.intro').backstretch([
              "img/intro-bg.jpg",
              "img/intro-bg2.jpg",
              "img/intro-bg3.jpg"
          ], {duration: 5000, fade: 1000});
    }
});

function isElementInViewport(elem) {
    var $elem = $(elem);

    // Get the scroll position of the page.
    var scrollElem = ((navigator.userAgent.toLowerCase().indexOf('webkit') != -1) ? 'body' : 'html');
    var viewportTop = $(scrollElem).scrollTop();
    var viewportBottom = viewportTop + $(window).height();

    // Get the position of the element on the page.
    var elemTop = Math.round( $elem.offset().top );
    var elemBottom = elemTop + $elem.height();
    var elemMid = (elemTop + elemBottom)/2
    return ((elemMid < viewportBottom) && (elemMid > viewportTop));
}

// Check if it's time to start the animation.
function checkAnimation($elem) {

    // If the animation has already been started
    if ($elem.hasClass('start')) {
        if (!isElementInViewport($elem))
            $elem.removeClass('start');
        else
            return;
    }
    if (isElementInViewport($elem)) {
        // Start the animation
        $elem.focus();
    } else {
        $elem.blur()
    }
}

$(document).on('scroll', function() {
  var scrollBottom = $(window).scrollTop() + $(window).height();
  var scrollMid = $(window).scrollTop() + $(window).height()/2;
  var scrollTop = $(this).scrollTop();
  var panelTop = $('#workshop').position().top - 5;
  var panelBottom = $('#workshop').offset().top + $('#workshop').outerHeight(true);
  var tableBottom = $('#workshop-table').offset().top + $('#workshop-table').outerHeight(true);
  var infoBottom = $('#workshop-p').offset().top + $('#workshop-p').outerHeight(true);
  var arrowBottom = $('#workshop-arrow').offset().top + $('#workshop-arrow').outerHeight(true);

  if(scrollTop >= panelTop && scrollMid < arrowBottom && !$('#workshop-p').hasClass('wfix')){
    $('#workshop-p').addClass('wfix').fadeIn(200);
  }

  else if(scrollMid >= arrowBottom && $('#workshop-p').hasClass('wfix')) {
    $('#workshop-p').fadeOut(200, function() {
      $('#workshop-p').removeClass('wfix');
    });
  }
  else if(scrollTop < panelTop && $('#workshop-p').hasClass('wfix')) {
    $('#workshop-p').removeClass('wfix');
  }
});

$(document).ready(function(){
  $('#workshop-table').on('click', 'tbody tr', function(event) {
    $(this).addClass('highlight').siblings().removeClass('highlight');
  });
  $("#c1").on("hide.bs.collapse", function(){
    $("#b1").html(' Co-Chairs');
  });
  $("#c1").on("show.bs.collapse", function(){
    $("#b1").html(' Co-Chairs');
  });
  $("#typed").typed({
      stringsElement: $('#typed-strings'),
      typeSpeed: 100,
      backSpeed: 50,
      backDelay: 1500,
      cursorChar: "|",
      loop: true
  });
});
$(document).ready(function(){
  $("#c2").on("hide.bs.collapse", function(){
    $("#b2").html(' Logistics');
  });
  $("#c2").on("show.bs.collapse", function(){
    $("#b2").html(' Logistics');
  });
});
$(document).ready(function(){
  $("#c3").on("hide.bs.collapse", function(){
    $("#b3").html(' Finance');
  });
  $("#c3").on("show.bs.collapse", function(){
    $("#b3").html(' Finance');
  });
});
$(document).ready(function(){
  $("#c4").on("hide.bs.collapse", function(){
    $("#b4").html(' Workshops');
  });
  $("#c4").on("show.bs.collapse", function(){
    $("#b4").html(' Workshops');
  });
});
$(document).ready(function(){
  $("#c5").on("hide.bs.collapse", function(){
    $("#b5").html(' Publicity');
  });
  $("#c5").on("show.bs.collapse", function(){
    $("#b5").html(' Publicity');
  });
});
$(document).ready(function(){
  $("#c6").on("hide.bs.collapse", function(){
    $("#b6").html(' Multimedia');
  });
  $("#c6").on("show.bs.collapse", function(){
    $("#b6").html(' Multimedia');
  });
});
$(document).ready(function(){
  $("#c7").on("hide.bs.collapse", function(){
    $("#b7").html(' Community Liaison');
  });
  $("#c7").on("show.bs.collapse", function(){
    $("#b7").html(' Community Liaison');
  });
});
$(document).ready(function(){
  $("#c8").on("hide.bs.collapse", function(){
    $("#b8").html(' Entertainment');
  });
  $("#c8").on("show.bs.collapse", function(){
    $("#b8").html(' Entertainment');
  });
});
$(document).ready(function(){
  $("#c9").on("hide.bs.collapse", function(){
    $("#b9").html(' Registration');
  });
  $("#c9").on("show.bs.collapse", function(){
    $("#b9").html(' Registration');
  });
});
$(document).ready(function(){
  $("#c10").on("hide.bs.collapse", function(){
    $("#b10").html(' Leadership Development Coordinator');
  });
  $("#c10").on("show.bs.collapse", function(){
    $("#b10").html(' Leadership Development Coordinator');
  });
});
$(document).ready(function(){
  $("#c11").on("hide.bs.collapse", function(){
    $("#b11").html(' Freshmen Representative');
  });
  $("#c11").on("show.bs.collapse", function(){
    $("#b11").html(' Freshmen Representative');
  });
});
$(document).ready(function(){
  $("#c12").on("hide.bs.collapse", function(){
    $("#b12").html(' MAASU Advisor');
  });
  $("#c12").on("show.bs.collapse", function(){
    $("#b12").html(' MAASU Advisor');
  });
});
// I took out the lorem dim sum from this file, it now lives in schedule.js -tiners

$('.scrollimation').waypoint(function(){
    if ($(this).hasClass('done')) {
      return;
    }
    else {
      $(this).toggleClass('in');
      $(this).addClass('done');
    }
  },{offset:'90%'});

// Capture scroll events
$(window).scroll(function(){
    checkAnimation($('.about'));
    checkAnimation($('.schedule'));
});
<commit_msg>eskjrekr<commit_after>/*!
 * Start Bootstrap - Grayscale Bootstrap Theme (http://startbootstrap.com)
 * Code licensed under the Apache License v2.0.
 * For details, see http://www.apache.org/licenses/LICENSE-2.0.
 */

// MOBILE DETECTION //
var isMobile = false; //initiate as false
// device detection
if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(navigator.userAgent)
    || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(navigator.userAgent.substr(0,4)))
{
  window.location = "./mobile"
}

//Page Preloader
$(window).load(function(){
    $('#page-loader').fadeOut(500);
});

$(document).ready(collapseNavbar);

// jQuery to collapse the navbar on scroll
function collapseNavbar() {
    if ($(".navbar").offset().top > 50) {
        $(".navbar-fixed-top").addClass("top-nav-collapse");
    } else {
        $(".navbar-fixed-top").removeClass("top-nav-collapse");
    }
}

$(window).scroll(collapseNavbar);

// jQuery for page scrolling feature - requires jQuery Easing plugin
$(function() {
    $('a.page-scroll').bind('click', function(event) {
        var $anchor = $(this);
        $('html, body').stop().animate({
            scrollTop: $($anchor.attr('href')).offset().top
        }, 1500, 'easeInOutExpo');
        event.preventDefault();
    });
});

// Closes the Responsive Menu on Menu Item Click
$('.navbar-collapse ul li a').click(function() {
  if ($(this).attr('class') != 'dropdown-toggle active' && $(this).attr('class') != 'dropdown-toggle') {
    $('.navbar-toggle:visible').click();
  }
});

$('.intro').backstretch([
      "img/intro-bg.jpg",
      "img/intro-bg2.jpg",
      "img/intro-bg3.jpg"
  ], {duration: 5000, fade: 1000});

$('body').append('');

$('#board').waypoint(function(direction){

    if($('.preload-image').length){$('.preload-image').remove();}

    $('.backstretch').remove();

    if (direction=='down'){
        $.backstretch('img/contact-bg.jpg');
    }else{
        // $.backstretch('assets/header-bg.jpg');
        $('.intro').backstretch([
              "img/intro-bg.jpg",
              "img/intro-bg2.jpg",
              "img/intro-bg3.jpg"
          ], {duration: 5000, fade: 1000});
    }
});

function isElementInViewport(elem) {
    var $elem = $(elem);

    // Get the scroll position of the page.
    var scrollElem = ((navigator.userAgent.toLowerCase().indexOf('webkit') != -1) ? 'body' : 'html');
    var viewportTop = $(scrollElem).scrollTop();
    var viewportBottom = viewportTop + $(window).height();

    // Get the position of the element on the page.
    var elemTop = Math.round( $elem.offset().top );
    var elemBottom = elemTop + $elem.height();
    var elemMid = (elemTop + elemBottom)/2
    return ((elemMid < viewportBottom) && (elemMid > viewportTop));
}

// Check if it's time to start the animation.
function checkAnimation($elem) {

    // If the animation has already been started
    if ($elem.hasClass('start')) {
        if (!isElementInViewport($elem))
            $elem.removeClass('start');
        else
            return;
    }
    if (isElementInViewport($elem)) {
        // Start the animation
        $elem.focus();
    } else {
        $elem.blur()
    }
}

$(document).on('scroll', function() {
  var scrollBottom = $(window).scrollTop() + $(window).height();
  var scrollMid = $(window).scrollTop() + $(window).height()/2;
  var scrollTop = $(this).scrollTop();
  var panelTop = $('#workshop').position().top - 5;
  var panelBottom = $('#workshop').offset().top + $('#workshop').outerHeight(true);
  var tableBottom = $('#workshop-table').offset().top + $('#workshop-table').outerHeight(true);
  var infoBottom = $('#workshop-p').offset().top + $('#workshop-p').outerHeight(true);
  var arrowBottom = $('#workshop-arrow').offset().top + $('#workshop-arrow').outerHeight(true);

  if(scrollTop >= panelTop && scrollMid < arrowBottom && !$('#workshop-p').hasClass('wfix')){
    $('#workshop-p').addClass('wfix').fadeIn(200);
  }

  else if(scrollMid >= arrowBottom && $('#workshop-p').hasClass('wfix')) {
    $('#workshop-p').fadeOut(200, function() {
      $('#workshop-p').removeClass('wfix');
    });
  }
  else if(scrollTop < panelTop && $('#workshop-p').hasClass('wfix')) {
    $('#workshop-p').removeClass('wfix');
  }
});

$(document).ready(function(){
  $('#workshop-table').on('click', 'tbody tr', function(event) {
    $(this).addClass('highlight').siblings().removeClass('highlight');
  });
  $("#c1").on("hide.bs.collapse", function(){
    $("#b1").html(' Co-Chairs');
  });
  $("#c1").on("show.bs.collapse", function(){
    $("#b1").html(' Co-Chairs');
  });
  $("#typed").typed({
      stringsElement: $('#typed-strings'),
      typeSpeed: 100,
      backSpeed: 50,
      backDelay: 1500,
      cursorChar: "|",
      loop: true
  });
});
$(document).ready(function(){
  $("#c2").on("hide.bs.collapse", function(){
    $("#b2").html(' Logistics');
  });
  $("#c2").on("show.bs.collapse", function(){
    $("#b2").html(' Logistics');
  });
});
$(document).ready(function(){
  $("#c3").on("hide.bs.collapse", function(){
    $("#b3").html(' Finance');
  });
  $("#c3").on("show.bs.collapse", function(){
    $("#b3").html(' Finance');
  });
});
$(document).ready(function(){
  $("#c4").on("hide.bs.collapse", function(){
    $("#b4").html(' Workshops');
  });
  $("#c4").on("show.bs.collapse", function(){
    $("#b4").html(' Workshops');
  });
});
$(document).ready(function(){
  $("#c5").on("hide.bs.collapse", function(){
    $("#b5").html(' Publicity');
  });
  $("#c5").on("show.bs.collapse", function(){
    $("#b5").html(' Publicity');
  });
});
$(document).ready(function(){
  $("#c6").on("hide.bs.collapse", function(){
    $("#b6").html(' Multimedia');
  });
  $("#c6").on("show.bs.collapse", function(){
    $("#b6").html(' Multimedia');
  });
});
$(document).ready(function(){
  $("#c7").on("hide.bs.collapse", function(){
    $("#b7").html(' Community Liaison');
  });
  $("#c7").on("show.bs.collapse", function(){
    $("#b7").html(' Community Liaison');
  });
});
$(document).ready(function(){
  $("#c8").on("hide.bs.collapse", function(){
    $("#b8").html(' Entertainment');
  });
  $("#c8").on("show.bs.collapse", function(){
    $("#b8").html(' Entertainment');
  });
});
$(document).ready(function(){
  $("#c9").on("hide.bs.collapse", function(){
    $("#b9").html(' Registration');
  });
  $("#c9").on("show.bs.collapse", function(){
    $("#b9").html(' Registration');
  });
});
$(document).ready(function(){
  $("#c10").on("hide.bs.collapse", function(){
    $("#b10").html(' Leadership Development Coordinator');
  });
  $("#c10").on("show.bs.collapse", function(){
    $("#b10").html(' Leadership Development Coordinator');
  });
});
$(document).ready(function(){
  $("#c11").on("hide.bs.collapse", function(){
    $("#b11").html(' Freshmen Representative');
  });
  $("#c11").on("show.bs.collapse", function(){
    $("#b11").html(' Freshmen Representative');
  });
});
$(document).ready(function(){
  $("#c12").on("hide.bs.collapse", function(){
    $("#b12").html(' MAASU Advisor');
  });
  $("#c12").on("show.bs.collapse", function(){
    $("#b12").html(' MAASU Advisor');
  });
});
// I took out the lorem dim sum from this file, it now lives in schedule.js -tiners

$('.scrollimation').waypoint(function(){
    if ($(this).hasClass('done')) {
      return;
    }
    else {
      $(this).toggleClass('in');
      $(this).addClass('done');
    }
  },{offset:'90%'});

// Capture scroll events
$(window).scroll(function(){
    checkAnimation($('.about'));
    checkAnimation($('.schedule'));
});
<|endoftext|>