<commit_before>// Assignment Template

/* Check if an object in arr has value for field. */
function findObjectByField(arr, field, value) {
    for (var i = 0; i < arr.length; i += 1) {
        if (arr[i][field] == value) {
            return i;
        }
    }
    return -1;
}

medianX = function(medianArr) {
    count = medianArr.length;
    median = (count % 2 == 0) ? (medianArr[(medianArr.length / 2) - 1] + medianArr[(medianArr.length / 2)]) / 2 : medianArr[Math.floor(medianArr.length / 2)];
    return median;
}

toggleBands = function(chart) {
    var i = chart.xAxis[0].plotLinesAndBands.length;
    if (i > 0) {
        while (i--) {
            chart.xAxis[0].plotLinesAndBands[i].destroy();
        }
    } else {
        chart.xAxis[0].update({
            plotLines: plotLines,
            plotBands: plotBands
        });
    }
}

average = function(data) {
    var sum = data.reduce(function(sum, value) {
        return sum + value;
    }, 0);
    var avg = sum / data.length;
    return avg;
}

setTimeData = function(ret) {
    var data = Template.instance().readerSubmissionList.get();

    for (gId in data) {
	data[gId] = data[gId].map(function(e) {return e.graded_at ? new Date(e.graded_at) : null;});
    }
    var assignment = Session.get("assignment");
    var created = new Date(assignment.created_at);
    var lastDate = created;
    for (gId in data) {
	for (date in data[gId]) {
	    if (date > lastDate) {
		lastDate = date;
	    }
	}
    }
    console.log("LastDate: " + lastDate.toISOString());
    interval = (lastDate-created)/10
    cats = []
    for (var i=0; i < 10; i += 1) {
	cats.push(new Date((i*interval) + (created/1)));
    }
    duetime = assignment.due_at;
    sers = [];
    for (gId in data) {
	values = [];
	for (var j=0; j < cats.length; j += 1) {
	    date = cats[j];
	    console.log(data[gId][0] < date);
	    subs = data[gId].filter(function(e) {return e <= date;}).length;
	    console.log("SUBS: " + subs);
	    values.push(subs/data[gId].length);
	}
	ind = findObjectByField(ret, 'grader_id', gId);
	if (ind != -1) {
	    sers.push({
		name: ret[ind].grader_name,
		data: values
	    });
	}
    }
    Session.set("timeData", {
        title: {
            text: 'Reader Progress',
            x: -20 //center
        },
        xAxis: {
            categories: cats
        },
        yAxis: {
            title: {
                text: 'Percent Complete (%)'
            },
            plotLines: [{
                value: 0,
                width: 1,
                color: '#808080'
            }]
        },
        tooltip: {
            valueSuffix: '%'
        },
        legend: {
            layout: 'vertical',
            align: 'right',
            verticalAlign: 'middle',
            borderWidth: 0
        },
        series: sers
    });
}

setHistoData = function(ret) {
    var all = $.grep(ret, function(o) {
        return o.grader_id == "All";
    });
    all = all[0];
    var mean = all.mean;
    var scores = all.scores;
    var squareDiffs = scores.map(function(value) {
        var diff = value - mean;
        var sqr = diff * diff;
        return sqr;
    });
    var sd = Math.sqrt(average(squareDiffs));
    Session.set("standardDeviation", sd);
    Session.set("mean", mean);
    Session.set("median", medianX(scores));
    var plotLines = [{
        "value": mean,
        "width": 2,
        "color": "#666",
        "zIndex": 10,
        "dashStyle": "Dash",
        "label": {
            "text": "m",
            "rotation": 0,
            "align": "center",
            "x": 0,
            "y": -5,
            "style": {
                "fontSize": "10px"
            }
        }
    }];
    var sigmas = [-3, -2, -1, 1, 2, 3];
    for (s in sigmas) {
        plotLines.push({
            "value": mean + sd * sigmas[s],
            "width": 1,
            "color": "#999",
            "dashStyle": "Dash",
            "zIndex": 10,
            "label": {
                "text": sigmas[s].toString() + "s",
                "rotation": 0,
                "align": "center",
                "x": 0,
                "y": -5,
                "style": {
                    "fontSize": "10px"
                }
            }
        });
    }
    var plotBands = [{
        "from": -1 * sd + mean,
        "to": 1 * sd + mean,
        "color": "rgba(184,210,236,.1)",
        "zIndex": 0
    }, {
        "from": -2 * sd + mean,
        "to": 2 * sd + mean,
        "color": "rgba(184,210,236,.1)",
        "zIndex": 0
    }, {
        "from": -3 * sd + mean,
        "to": 3 * sd + mean,
        "color": "rgba(184,210,236,.1)",
        "zIndex": 0
    }];
    var maxPoints = Session.get("assignment").points_possible;
    var bucketSize = Math.ceil(maxPoints / 10);
    var bucketMargin = bucketSize / 2;
    var curBucket = bucketMargin;
    var buckets = [];
    var count = 0;
    while (curBucket < maxPoints) {
        count = 0;
        for (var i = 0; i < scores.length; i += 1) {
            if (scores[i] >= curBucket - bucketMargin && scores[i] < curBucket + bucketMargin) {
                count += 1;
            }
        }
        buckets.push([curBucket, count]);
        curBucket += bucketSize;
    }
    count = 0;
    for (var j = 0; j < scores.length; j += 1) {
        if (scores[j] == maxPoints) {
            count += 1;
        }
    }
    buckets[buckets.length - 1][1] += count;
    Session.set("histoData", {
        chart: {
            type: 'column',
            alignTicks: false,
            marginTop: 25,
            showAxes: true
        },
        exporting: {
            enabled: false
        },
        title: {
            text: 'Grade Histogram'
        },
        tooltip: {
            borderWidth: 1,
            pointFormatter: function() {
                lower = this.x - bucketMargin;
                upper = this.x + bucketMargin;
                return 'Range:
 ' + lower + ' - ' + upper + '
' +
                    'Count: ' + this.y;
            }
        },
        plotOptions: {
            series: {
                minPointLength: 1,
                shadow: false,
                marker: {
                    enabled: false
                }
            },
            area: {
                events: {
                    legendItemClick: function(e) {
                        if (this.name == 'Sigma Bands') {
                            toggleBands(this.chart);
                        }
                    }
                }
            }
        },
        xAxis: {
            title: {
                text: 'Point Buckets'
            },
            lineColor: '#999',
            tickColor: '#ccc',
            plotLines: plotLines,
            plotBands: plotBands
        },
        yAxis: {
            title: {
                text: 'Count'
            },
            gridLineColor: '#e9e9e9',
            tickWidth: 1,
            tickLength: 3,
            tickColor: '#ccc',
            lineColor: '#ccc',
            endOnTick: false,
        },
        series: [{
            name: 'Submission Samples',
            data: buckets,
            pointRange: bucketSize,
            borderWidth: .5,
            borderColor: '#666',
            pointPadding: 0,
            groupPadding: 0,
            color: '#e3e3e3',
            tooltip: {
                pointFormatter: function() {
                    lower = this.x - bucketMargin;
                    upper = this.x + bucketMargin;
                    return 'Range:
 ' + lower + ' - ' + upper + '
' + 'Count: ' + this.y;
                }
            }
        }, {
            type: 'area',
            name: 'Sigma Bands',
        }]
    });
}

computeStats = function(values) {
    var ret = [0, 0, 0, 0, 0];
    values.sort(function(a, b) {
        return a - b;
    });
    q1Arr = (values.length % 2 == 0) ? values.slice(0, (values.length / 2) + 1) : values.slice(0, Math.floor(values.length / 2) + 1);
    q2Arr = values;
    q3Arr = (values.length % 2 == 0) ? values.slice((values.length / 2) - 1, values.length) : values.slice(Math.ceil(values.length / 2) - 1, values.length);
    medianX(q1Arr);
    ret[1] = median;
    medianX(q2Arr);
    ret[2] = median;
    medianX(q3Arr);
    ret[3] = median;
    ret[0] = values[0];
    ret[4] = values[values.length - 1];
    return ret;
}

setBoxData = function(ret) {
    Session.set("boxData", {
        chart: {
            type: 'boxplot',
            backgroundColor: 'white' //"#BBBBBB"
        },
        title: {
            text: 'Reader Grade Distributions'
        },
        legend: {
            enabled: false
        },
        xAxis: {
            categories: ret.map(function(x) {
                return x.grader_name;
            }),
            title: {
                text: 'Grader'
            }
        },
        yAxis: {
            title: {
                text: 'Points Awarded'
            }
        },
        series: [{
            name: 'Grade Distribution',
            data: Session.get("ret").map(function(x) {
                return computeStats(x.scores);
            }),
            tooltip: {
                headerFormat: '{point.key} Grades
'
            }
        }, {
            name: 'Mean',
            color: Highcharts.getOptions().colors[0],
            type: 'scatter',
            data: ret.map(function(x) {
                return [ret.indexOf(x), x.scores.reduce(function(a, b) {
                    return a + b
                }, 0) / x.scores.length]
            }),
            marker: {
                fillColor: '#254A6E',
                lineWidth: 1,
                lineColor: Highcharts.getOptions().colors[0]
            },
            tooltip: {
                pointFormat: 'Value: {point.y}'
            }
        }]
    });
}

Template.assignment.created = function() {
    var self = this;
    self.submissionList = new ReactiveVar([]);
    Meteor.call("getSubmissions", Session.get("course").id, Session.get("assignment").id, function(err, value) {
        if (err) {
            console.log(err);
        } else {
            self.submissionList.set(value);
        }
    });

    self.mysubmissionList = new ReactiveVar([]);
    Meteor.call("mySubmissions", Session.get("assignment").id, function(err, value) {
        if (err) {
            console.log(err);
        } else {
            self.mysubmissionList.set(value);
        }
    });
    self.readerSubmissionList = new ReactiveVar([]);
    Meteor.call("assignedSubmissions", Session.get("course").id, Session.get("assignment").id, function(err, value) {
        if (err) {
            console.log(err);
        } else {
            self.readerSubmissionList.set(value);
        }
    });
}

Template.assignment.rendered = function() {
    $("#gradedata-toggle").click(function() {
        if ($("#gradeHistogram").contents().length != 0) {
            $("#gradeHistogram").html("");
        } else {
            $("#gradeHistogram").highcharts(Session.get("histoData"));
        }
    });
    $("#analytics-toggle").click(function() {
        if ($("#readerAverages").contents().length != 0) {
            $("#readerAverages").html("");
        } else {
            $("#readerAverages").highcharts(Session.get("boxData"));
        }
        if ($("#readerTimelines").contents().length != 0) {
            $("#readerTimelines").html("");
        } else {
            $("#readerTimelines").highcharts(Session.get("timeData"));
        }
    });
}

Template.assignment.helpers({
    assignment: function() {
        return Session.get("assignment");
    },
    course: function() {
        return Session.get("course");
    },
    submissions: function() {
        var data = Template.instance().submissionList.get();
        return data;
    },
    mysubmissions: function() {
        var data = Template.instance().mysubmissionList.get();
        return data;
    },
    graderStats: function() {
        var data = Template.instance().submissionList.get();
        var total = 0;
        var count = 0;
        var stats = {};
        var gId = 0;
        for (var i = 0; i < data.length; i += 1) {
            gId = data[i].grader_id;
            total += data[i].score;
            count += 1;
            if (stats[gId]) {
                stats[gId].count += 1;
                stats[gId].total += data[i].score;
                stats[gId].scores.push(data[i].score);
            } else {
                stats[gId] = {
                    count: 1,
                    total: data[i].score,
                    scores: [data[i].score],
                    grader_name: data[i].grader_name
                };
            }
        }
        var ret = [];
        ret.push({
            grader_id: "All",
            mean: total / count,
            total: total,
            count: count,
            scores: data.map(function(x) {
                return x.score;
            }),
            grader_name: "All"
        });
        for (grader in stats) {
            stats[grader].mean = stats[grader].total / stats[grader].count;
            stats[grader].grader_id = grader;
            ret.push(stats[grader]);
        }
        Session.set("classMean", total / count);
        Session.set("ret", ret);
        setBoxData(ret);
        setTimeData(ret);
	setHistoData(ret);
        return ret;
    },
    classMean: function() {
        return Session.get("classMean");
    },
    mean: function() {
        return Session.get("mean");
    },
    standardDeviation: function() {
        return Session.get("standardDeviation");
    },
    median: function() {
        return Session.get("standardDeviation");
    }
});

Template.assignment.events({
    'click .course-link': function(e) {
        Session.set("dashView", "course");
    },
    'click .grade-submission': function(e) {
        if (this.preview_url) {
            Session.set("submissionURL", this.preview_url);
        } else {
            Session.set("submissionURL", this.html_url);
        }
        window.open(Session.get("submissionURL"), "_blank").focus();
    },
    'click #doAssignment': function(e) {
        var assnID = Session.get('assignment').id
        var courseID = Session.get('course').id
        var pctConstraint = $('.pctConstraint').val();
        var numConstraint = $('.numConstraint').val();
        var params = {
            course: courseID,
            assign: assnID,
            pct: parseFloat(pctConstraint),
            num: parseFloat(numConstraint)
        }
        $('.assignconf').html('');
        Meteor.call('doReaderAssign', params, function(err, value) {
            if (err) {
                $('.assignconf').html(err);
            } else {
                $('.assignconf').html('
Success!
');
                Meteor.call("getSubmissions", Session.get("course").id, Session.get("assignment").id, function(err, value) {
                    if (err) {
                        console.log(err);
                    } else {
                        self.submissionList.set(value);
                    }
                });
            }
        });

    }
});
<commit_msg>it workkkkkkkkkkkkkkkssssssssssssssssssss, almost...it still doesn't include the last few...need to make it inclusive i guess?<commit_after>// Assignment Template

/* Check if an object in arr has value for field. */
function findObjectByField(arr, field, value) {
    for (var i = 0; i < arr.length; i += 1) {
        if (arr[i][field] == value) {
            return i;
        }
    }
    return -1;
}

medianX = function(medianArr) {
    count = medianArr.length;
    median = (count % 2 == 0) ? (medianArr[(medianArr.length / 2) - 1] + medianArr[(medianArr.length / 2)]) / 2 : medianArr[Math.floor(medianArr.length / 2)];
    return median;
}

toggleBands = function(chart) {
    var i = chart.xAxis[0].plotLinesAndBands.length;
    if (i > 0) {
        while (i--) {
            chart.xAxis[0].plotLinesAndBands[i].destroy();
        }
    } else {
        chart.xAxis[0].update({
            plotLines: plotLines,
            plotBands: plotBands
        });
    }
}

average = function(data) {
    var sum = data.reduce(function(sum, value) {
        return sum + value;
    }, 0);
    var avg = sum / data.length;
    return avg;
}

setTimeData = function(ret) {
    var data = Template.instance().readerSubmissionList.get();

    for (gId in data) {
	data[gId] = data[gId].map(function(e) {return e.graded_at ? new Date(e.graded_at) : null;});
    }
    var assignment = Session.get("assignment");
    var created = new Date(assignment.created_at);
    var lastDate = created;
    for (gId in data) {
	for (var k=0; k < data[gId].length; k += 1) {
	    console.log("DAAAAAAAAAAATE");
	    date = data[gId][k];
	    console.log(date);
	    if (date > lastDate) {
		lastDate = date;
	    }
	}
    }
    console.log("LastDate: " + lastDate.toISOString());
    interval = (lastDate-created)/10
    cats = []
    for (var i=0; i < 10; i += 1) {
	cats.push(new Date((i*interval) + (created/1)));
    }
    console.log("CATS");
    console.log(cats);
    duetime = assignment.due_at;
    sers = [];
    for (gId in data) {
	values = [];
	for (var j=0; j < cats.length; j += 1) {
	    date = cats[j];
	    subs = data[gId].filter(function(e) {return e <= date;}).length;
	    values.push(subs/data[gId].length);
	}
	ind = findObjectByField(ret, 'grader_id', gId);
	if (ind != -1) {
	    sers.push({
		name: ret[ind].grader_name,
		data: values
	    });
	}
    }
    Session.set("timeData", {
        title: {
            text: 'Reader Progress',
            x: -20 //center
        },
        xAxis: {
            categories: cats
        },
        yAxis: {
            title: {
                text: 'Percent Complete (%)'
            },
            plotLines: [{
                value: 0,
                width: 1,
                color: '#808080'
            }]
        },
        tooltip: {
            valueSuffix: '%'
        },
        legend: {
            layout: 'vertical',
            align: 'right',
            verticalAlign: 'middle',
            borderWidth: 0
        },
        series: sers
    });
}

setHistoData = function(ret) {
    var all = $.grep(ret, function(o) {
        return o.grader_id == "All";
    });
    all = all[0];
    var mean = all.mean;
    var scores = all.scores;
    var squareDiffs = scores.map(function(value) {
        var diff = value - mean;
        var sqr = diff * diff;
        return sqr;
    });
    var sd = Math.sqrt(average(squareDiffs));
    Session.set("standardDeviation", sd);
    Session.set("mean", mean);
    Session.set("median", medianX(scores));
    var plotLines = [{
        "value": mean,
        "width": 2,
        "color": "#666",
        "zIndex": 10,
        "dashStyle": "Dash",
        "label": {
            "text": "m",
            "rotation": 0,
            "align": "center",
            "x": 0,
            "y": -5,
            "style": {
                "fontSize": "10px"
            }
        }
    }];
    var sigmas = [-3, -2, -1, 1, 2, 3];
    for (s in sigmas) {
        plotLines.push({
            "value": mean + sd * sigmas[s],
            "width": 1,
            "color": "#999",
            "dashStyle": "Dash",
            "zIndex": 10,
            "label": {
                "text": sigmas[s].toString() + "s",
                "rotation": 0,
                "align": "center",
                "x": 0,
                "y": -5,
                "style": {
                    "fontSize": "10px"
                }
            }
        });
    }
    var plotBands = [{
        "from": -1 * sd + mean,
        "to": 1 * sd + mean,
        "color": "rgba(184,210,236,.1)",
        "zIndex": 0
    }, {
        "from": -2 * sd + mean,
        "to": 2 * sd + mean,
        "color": "rgba(184,210,236,.1)",
        "zIndex": 0
    }, {
        "from": -3 * sd + mean,
        "to": 3 * sd + mean,
        "color": "rgba(184,210,236,.1)",
        "zIndex": 0
    }];
    var maxPoints = Session.get("assignment").points_possible;
    var bucketSize = Math.ceil(maxPoints / 10);
    var bucketMargin = bucketSize / 2;
    var curBucket = bucketMargin;
    var buckets = [];
    var count = 0;
    while (curBucket < maxPoints) {
        count = 0;
        for (var i = 0; i < scores.length; i += 1) {
            if (scores[i] >= curBucket - bucketMargin && scores[i] < curBucket + bucketMargin) {
                count += 1;
            }
        }
        buckets.push([curBucket, count]);
        curBucket += bucketSize;
    }
    count = 0;
    for (var j = 0; j < scores.length; j += 1) {
        if (scores[j] == maxPoints) {
            count += 1;
        }
    }
    buckets[buckets.length - 1][1] += count;
    Session.set("histoData", {
        chart: {
            type: 'column',
            alignTicks: false,
            marginTop: 25,
            showAxes: true
        },
        exporting: {
            enabled: false
        },
        title: {
            text: 'Grade Histogram'
        },
        tooltip: {
            borderWidth: 1,
            pointFormatter: function() {
                lower = this.x - bucketMargin;
                upper = this.x + bucketMargin;
                return 'Range:
 ' + lower + ' - ' + upper + '
' +
                    'Count: ' + this.y;
            }
        },
        plotOptions: {
            series: {
                minPointLength: 1,
                shadow: false,
                marker: {
                    enabled: false
                }
            },
            area: {
                events: {
                    legendItemClick: function(e) {
                        if (this.name == 'Sigma Bands') {
                            toggleBands(this.chart);
                        }
                    }
                }
            }
        },
        xAxis: {
            title: {
                text: 'Point Buckets'
            },
            lineColor: '#999',
            tickColor: '#ccc',
            plotLines: plotLines,
            plotBands: plotBands
        },
        yAxis: {
            title: {
                text: 'Count'
            },
            gridLineColor: '#e9e9e9',
            tickWidth: 1,
            tickLength: 3,
            tickColor: '#ccc',
            lineColor: '#ccc',
            endOnTick: false,
        },
        series: [{
            name: 'Submission Samples',
            data: buckets,
            pointRange: bucketSize,
            borderWidth: .5,
            borderColor: '#666',
            pointPadding: 0,
            groupPadding: 0,
            color: '#e3e3e3',
            tooltip: {
                pointFormatter: function() {
                    lower = this.x - bucketMargin;
                    upper = this.x + bucketMargin;
                    return 'Range:
 ' + lower + ' - ' + upper + '
' + 'Count: ' + this.y;
                }
            }
        }, {
            type: 'area',
            name: 'Sigma Bands',
        }]
    });
}

computeStats = function(values) {
    var ret = [0, 0, 0, 0, 0];
    values.sort(function(a, b) {
        return a - b;
    });
    q1Arr = (values.length % 2 == 0) ? values.slice(0, (values.length / 2) + 1) : values.slice(0, Math.floor(values.length / 2) + 1);
    q2Arr = values;
    q3Arr = (values.length % 2 == 0) ? values.slice((values.length / 2) - 1, values.length) : values.slice(Math.ceil(values.length / 2) - 1, values.length);
    medianX(q1Arr);
    ret[1] = median;
    medianX(q2Arr);
    ret[2] = median;
    medianX(q3Arr);
    ret[3] = median;
    ret[0] = values[0];
    ret[4] = values[values.length - 1];
    return ret;
}

setBoxData = function(ret) {
    Session.set("boxData", {
        chart: {
            type: 'boxplot',
            backgroundColor: 'white' //"#BBBBBB"
        },
        title: {
            text: 'Reader Grade Distributions'
        },
        legend: {
            enabled: false
        },
        xAxis: {
            categories: ret.map(function(x) {
                return x.grader_name;
            }),
            title: {
                text: 'Grader'
            }
        },
        yAxis: {
            title: {
                text: 'Points Awarded'
            }
        },
        series: [{
            name: 'Grade Distribution',
            data: Session.get("ret").map(function(x) {
                return computeStats(x.scores);
            }),
            tooltip: {
                headerFormat: '{point.key} Grades
'
            }
        }, {
            name: 'Mean',
            color: Highcharts.getOptions().colors[0],
            type: 'scatter',
            data: ret.map(function(x) {
                return [ret.indexOf(x), x.scores.reduce(function(a, b) {
                    return a + b
                }, 0) / x.scores.length]
            }),
            marker: {
                fillColor: '#254A6E',
                lineWidth: 1,
                lineColor: Highcharts.getOptions().colors[0]
            },
            tooltip: {
                pointFormat: 'Value: {point.y}'
            }
        }]
    });
}

Template.assignment.created = function() {
    var self = this;
    self.submissionList = new ReactiveVar([]);
    Meteor.call("getSubmissions", Session.get("course").id, Session.get("assignment").id, function(err, value) {
        if (err) {
            console.log(err);
        } else {
            self.submissionList.set(value);
        }
    });

    self.mysubmissionList = new ReactiveVar([]);
    Meteor.call("mySubmissions", Session.get("assignment").id, function(err, value) {
        if (err) {
            console.log(err);
        } else {
            self.mysubmissionList.set(value);
        }
    });
    self.readerSubmissionList = new ReactiveVar([]);
    Meteor.call("assignedSubmissions", Session.get("course").id, Session.get("assignment").id, function(err, value) {
        if (err) {
            console.log(err);
        } else {
            self.readerSubmissionList.set(value);
        }
    });
}

Template.assignment.rendered = function() {
    $("#gradedata-toggle").click(function() {
        if ($("#gradeHistogram").contents().length != 0) {
            $("#gradeHistogram").html("");
        } else {
            $("#gradeHistogram").highcharts(Session.get("histoData"));
        }
    });
    $("#analytics-toggle").click(function() {
        if ($("#readerAverages").contents().length != 0) {
            $("#readerAverages").html("");
        } else {
            $("#readerAverages").highcharts(Session.get("boxData"));
        }
        if ($("#readerTimelines").contents().length != 0) {
            $("#readerTimelines").html("");
        } else {
            $("#readerTimelines").highcharts(Session.get("timeData"));
        }
    });
}

Template.assignment.helpers({
    assignment: function() {
        return Session.get("assignment");
    },
    course: function() {
        return Session.get("course");
    },
    submissions: function() {
        var data = Template.instance().submissionList.get();
        return data;
    },
    mysubmissions: function() {
        var data = Template.instance().mysubmissionList.get();
        return data;
    },
    graderStats: function() {
        var data = Template.instance().submissionList.get();
        var total = 0;
        var count = 0;
        var stats = {};
        var gId = 0;
        for (var i = 0; i < data.length; i += 1) {
            gId = data[i].grader_id;
            total += data[i].score;
            count += 1;
            if (stats[gId]) {
                stats[gId].count += 1;
                stats[gId].total += data[i].score;
                stats[gId].scores.push(data[i].score);
            } else {
                stats[gId] = {
                    count: 1,
                    total: data[i].score,
                    scores: [data[i].score],
                    grader_name: data[i].grader_name
                };
            }
        }
        var ret = [];
        ret.push({
            grader_id: "All",
            mean: total / count,
            total: total,
            count: count,
            scores: data.map(function(x) {
                return x.score;
            }),
            grader_name: "All"
        });
        for (grader in stats) {
            stats[grader].mean = stats[grader].total / stats[grader].count;
            stats[grader].grader_id = grader;
            ret.push(stats[grader]);
        }
        Session.set("classMean", total / count);
        Session.set("ret", ret);
        setBoxData(ret);
        setTimeData(ret);
	setHistoData(ret);
        return ret;
    },
    classMean: function() {
        return Session.get("classMean");
    },
    mean: function() {
        return Session.get("mean");
    },
    standardDeviation: function() {
        return Session.get("standardDeviation");
    },
    median: function() {
        return Session.get("standardDeviation");
    }
});

Template.assignment.events({
    'click .course-link': function(e) {
        Session.set("dashView", "course");
    },
    'click .grade-submission': function(e) {
        if (this.preview_url) {
            Session.set("submissionURL", this.preview_url);
        } else {
            Session.set("submissionURL", this.html_url);
        }
        window.open(Session.get("submissionURL"), "_blank").focus();
    },
    'click #doAssignment': function(e) {
        var assnID = Session.get('assignment').id
        var courseID = Session.get('course').id
        var pctConstraint = $('.pctConstraint').val();
        var numConstraint = $('.numConstraint').val();
        var params = {
            course: courseID,
            assign: assnID,
            pct: parseFloat(pctConstraint),
            num: parseFloat(numConstraint)
        }
        $('.assignconf').html('');
        Meteor.call('doReaderAssign', params, function(err, value) {
            if (err) {
                $('.assignconf').html(err);
            } else {
                $('.assignconf').html('
Success!
');
                Meteor.call("getSubmissions", Session.get("course").id, Session.get("assignment").id, function(err, value) {
                    if (err) {
                        console.log(err);
                    } else {
                        self.submissionList.set(value);
                    }
                });
            }
        });

    }
});
<|endoftext|>


<commit_before>'use strict';

/**
 * An Animator class for animating objects based on an AnimationData.
 *
 * @constructor
 * @param {THREE.Object[]} objects
 * The objects to animate.
 * @param {AnimationData} animationData
 * The AnimationData to animate with.
 */
function Animator(object, animationData) {
  EventEmitter.call(this);

  this.objects = object;
  this.data = animationData;
  this.currentTime = 0;
  this.isPlaying = false;
  this.isPaused = false;
  this.loop = true;
  this.timeScale = 1;
  this.length = this.data.frameCount / this.data.fps;
}

Animator.prototype = Object.create(EventEmitter.prototype);

Animator.prototype.play = function (startTime, weight) {
  this.currentTime = startTime !== undefined ? startTime : 0;
  this.weight = weight !== undefined ? weight : 1;

  this.reset();

  this.isPlaying = true;
  this.isPaused = false;

  THREE.AnimationHandler.play(this);
};

Animator.prototype.pause = function() {
  this.isPaused = true;
};

Animator.prototype.unpause = function() {
  this.isPaused = false;
};

Animator.prototype.stop = function () {
  if (!this.isPlaying) {
    return;
  }

  this.isPlaying = false;
  this.isPaused = false;

  THREE.AnimationHandler.stop(this);
};

Animator.prototype.reset = function () {
  for (var h = 0, hl = this.objects.length; h < hl; h++) {
    var object = this.objects[h];

    object.matrixAutoUpdate = true;

    if (object.animatorCache === undefined) {
      object.animatorCache = {
        blending: {
          positionWeight: 0.0,
          quaternionWeight: 0.0,
          scaleWeight: 0.0
        }
      }
    }
  }
};

Animator.prototype.resetBlendWeights = function () {
  for (var h = 0, hl = this.objects.length; h < hl; h++) {
    var object = this.objects[h];

    if (object.animatorCache !== undefined) {
      object.animatorCache.blending.positionWeight = 0.0;
      object.animatorCache.blending.quaternionWeight = 0.0;
      object.animatorCache.blending.scaleWeight = 0.0;
    }
  }
};

Animator.prototype._applyChannel = function(index, type, value) {
  var object = this.objects[index];
  var blending = object.animatorCache.blending;

  object.matrixAutoUpdate = true;
  object.matrixWorldNeedsUpdate = true;

  if (type === AnimationData.CHANNEL_TYPE.Position) {
    if (blending.positionWeight === 0) {
      object.position.copy(value);
      blending.positionWeight = this.weight;
    } else {
      var proportionalWeight = this.weight / (this.weight + blending.positionWeight);
      object.position.lerp(value, proportionalWeight);
      blending.positionWeight += this.weight;
    }
  } else if (AnimationData.CHANNEL_TYPE.Rotation) {
    if (blending.quaternionWeight === 0) {
      object.quaternion.copy(value);
      blending.quaternionWeight = this.weight;
    } else {
      var proportionalWeight = this.weight / (this.weight + blending.quaternionWeight);
      object.quaternion.slerp(value, proportionalWeight);
      blending.quaternionWeight += this.weight;
    }
  } else if (AnimationData.CHANNEL_TYPE.Scale) {
    if (blending.scaleWeight === 0) {
      object.scale.copy(value);
      blending.scaleWeight = this.weight;
    } else {
      var proportionalWeight = this.weight / (this.weight + blending.scaleWeight);
      object.scale.lerp(value, proportionalWeight);
      blending.scaleWeight += this.weight;
    }
  }
};

Animator.prototype.update = (function() {
  var _SLERPER = new THREE.Quaternion();
  var _V3LERPER = new THREE.Vector3();
  var _V2LERPER = new THREE.Vector2();

  return function (delta) {
    if (this.isPlaying === false) return delta;

    if (!this.isPaused) {
      this.currentTime += delta * this.timeScale;

      // If this is the last frame, we have to stop at the last frame, rather
      //   then blending back towards frame 0, remove that time.
      var endTime = this.length;
      if (this.loop === false || this.loop === 1) {
        endTime = (this.data.frameCount - 1) / this.data.fps;
      }

      if (this.currentTime >= endTime || this.currentTime < 0) {
        if (this.loop !== true && this.loop > 0) {
          this.loop--;
        }
        if (this.loop) {
          this.currentTime %= this.length;

          if (this.currentTime < 0) {
            this.currentTime += this.length;
          }

          this.reset();
          this.emit('restart');
        } else {
          var timeConsumed = endTime - this.currentTime;
          this.currentTime = endTime;
          this.pause();
          this.emit('finish');
          return delta - timeConsumed;
        }
      }
    }

    if (this.weight === 0) {
      return 0;
    }

    var thisFrame = Math.floor(this.currentTime * this.data.fps);
    // TODO: THIS SHOULD NOT BE NEEDED
    if (thisFrame >= this.data.frameCount) {
      thisFrame = this.data.frameCount - 1;
    }
    var nextFrame = thisFrame + 1;
    if (nextFrame >= this.data.frameCount) {
      if (this.loop) {
        nextFrame -= this.data.frameCount;
      } else {
        nextFrame = thisFrame;
      }
    }
    var frameWeight = ( this.currentTime - (thisFrame / this.data.fps) ) / (1 / this.data.fps);

    for (var i = 0; i < this.data.channels.length; ++i) {
      var c = this.data.channels[i];

      var f0 = c.frames[thisFrame];
      var f1 = c.frames[nextFrame];
      var f = null;
      if (frameWeight === 0) {
        f = f0;
      } else {
        if (f0 instanceof THREE.Quaternion) {
          f = THREE.Quaternion.slerp(f0, f1, _SLERPER, frameWeight);
        } else if (f0 instanceof THREE.Vector3) {
          f = _V3LERPER.copy(f0).lerp(f1, frameWeight);
        } else if (f0 instanceof THREE.Vector2) {
          f = _V2LERPER.copy(f0).lerp(f1, frameWeight);
        } else if (f0 instanceof Number) {
          f = f0 * (1 - frameWeight) + f1 * frameWeight;
        } else {
          f = f0;
        }
      }

      this._applyChannel(c.index, c.type, f);
    }

    return 0;
  };
})();
<commit_msg>Fix bug in Animator causing it to fail to optimize.<commit_after>'use strict';

/**
 * An Animator class for animating objects based on an AnimationData.
 *
 * @constructor
 * @param {THREE.Object[]} objects
 * The objects to animate.
 * @param {AnimationData} animationData
 * The AnimationData to animate with.
 */
function Animator(object, animationData) {
  EventEmitter.call(this);

  this.objects = object;
  this.data = animationData;
  this.currentTime = 0;
  this.isPlaying = false;
  this.isPaused = false;
  this.loop = true;
  this.timeScale = 1;
  this.length = this.data.frameCount / this.data.fps;
}

Animator.prototype = Object.create(EventEmitter.prototype);

Animator.prototype.play = function (startTime, weight) {
  this.currentTime = startTime !== undefined ? startTime : 0;
  this.weight = weight !== undefined ? weight : 1;

  this.reset();

  this.isPlaying = true;
  this.isPaused = false;

  THREE.AnimationHandler.play(this);
};

Animator.prototype.pause = function() {
  this.isPaused = true;
};

Animator.prototype.unpause = function() {
  this.isPaused = false;
};

Animator.prototype.stop = function () {
  if (!this.isPlaying) {
    return;
  }

  this.isPlaying = false;
  this.isPaused = false;

  THREE.AnimationHandler.stop(this);
};

Animator.prototype.reset = function () {
  for (var h = 0, hl = this.objects.length; h < hl; h++) {
    var object = this.objects[h];

    object.matrixAutoUpdate = true;

    if (object.animatorCache === undefined) {
      object.animatorCache = {
        blending: {
          positionWeight: 0.0,
          quaternionWeight: 0.0,
          scaleWeight: 0.0
        }
      }
    }
  }
};

Animator.prototype.resetBlendWeights = function () {
  for (var h = 0, hl = this.objects.length; h < hl; h++) {
    var object = this.objects[h];

    if (object.animatorCache !== undefined) {
      object.animatorCache.blending.positionWeight = 0.0;
      object.animatorCache.blending.quaternionWeight = 0.0;
      object.animatorCache.blending.scaleWeight = 0.0;
    }
  }
};

Animator.prototype._applyChannel = function(index, type, value) {
  var object = this.objects[index];
  var blending = object.animatorCache.blending;

  object.matrixAutoUpdate = true;
  object.matrixWorldNeedsUpdate = true;

  if (type === AnimationData.CHANNEL_TYPE.Position) {
    if (blending.positionWeight === 0) {
      object.position.copy(value);
      blending.positionWeight = this.weight;
    } else {
      var proportionalWeight = this.weight / (this.weight + blending.positionWeight);
      object.position.lerp(value, proportionalWeight);
      blending.positionWeight += this.weight;
    }
  } else if (AnimationData.CHANNEL_TYPE.Rotation) {
    if (blending.quaternionWeight === 0) {
      object.quaternion.copy(value);
      blending.quaternionWeight = this.weight;
    } else {
      var proportionalWeight = this.weight / (this.weight + blending.quaternionWeight);
      object.quaternion.slerp(value, proportionalWeight);
      blending.quaternionWeight += this.weight;
    }
  } else if (AnimationData.CHANNEL_TYPE.Scale) {
    if (blending.scaleWeight === 0) {
      object.scale.copy(value);
      blending.scaleWeight = this.weight;
    } else {
      var proportionalWeight = this.weight / (this.weight + blending.scaleWeight);
      object.scale.lerp(value, proportionalWeight);
      blending.scaleWeight += this.weight;
    }
  }
};

var _SLERPER = new THREE.Quaternion();
var _V3LERPER = new THREE.Vector3();
var _V2LERPER = new THREE.Vector2();
Animator.prototype.update = function (delta) {
  if (this.isPlaying === false) return delta;

  if (!this.isPaused) {
    this.currentTime += delta * this.timeScale;

    // If this is the last frame, we have to stop at the last frame, rather
    //   then blending back towards frame 0, remove that time.
    var endTime = this.length;
    if (this.loop === false || this.loop === 1) {
      endTime = (this.data.frameCount - 1) / this.data.fps;
    }

    if (this.currentTime >= endTime || this.currentTime < 0) {
      if (this.loop !== true && this.loop > 0) {
        this.loop--;
      }
      if (this.loop) {
        this.currentTime %= this.length;

        if (this.currentTime < 0) {
          this.currentTime += this.length;
        }

        this.reset();
        this.emit('restart');
      } else {
        var timeConsumed = endTime - this.currentTime;
        this.currentTime = endTime;
        this.pause();
        this.emit('finish');
        return delta - timeConsumed;
      }
    }
  }

  if (this.weight === 0) {
    return 0;
  }

  var thisFrame = Math.floor(this.currentTime * this.data.fps);
  // TODO: THIS SHOULD NOT BE NEEDED
  if (thisFrame >= this.data.frameCount) {
    thisFrame = this.data.frameCount - 1;
  }
  var nextFrame = thisFrame + 1;
  if (nextFrame >= this.data.frameCount) {
    if (this.loop) {
      nextFrame -= this.data.frameCount;
    } else {
      nextFrame = thisFrame;
    }
  }
  var frameWeight = ( this.currentTime - (thisFrame / this.data.fps) ) / (1 / this.data.fps);

  for (var i = 0; i < this.data.channels.length; ++i) {
    var c = this.data.channels[i];

    var f0 = c.frames[thisFrame];
    var f1 = c.frames[nextFrame];
    var f = null;
    if (frameWeight === 0) {
      f = f0;
    } else {
      if (f0 instanceof THREE.Quaternion) {
        f = THREE.Quaternion.slerp(f0, f1, _SLERPER, frameWeight);
      } else if (f0 instanceof THREE.Vector3) {
        f = _V3LERPER.copy(f0).lerp(f1, frameWeight);
      } else if (f0 instanceof THREE.Vector2) {
        f = _V2LERPER.copy(f0).lerp(f1, frameWeight);
      } else if (f0 instanceof Number) {
        f = f0 * (1 - frameWeight) + f1 * frameWeight;
      } else {
        f = f0;
      }
    }

    this._applyChannel(c.index, c.type, f);
  }

  return 0;
};
<|endoftext|>


<commit_before>var test = require('tape')

var events = require('../events')

function isObject(o) {
  return o && 'object' === typeof o
}

function isFunction (f) {
  return 'function' === typeof f
}

function is (t, actual, expected, path) {
  if(isFunction(expected))
    expected.call(actual, path.concat(k))
  else t.equal(expected, actual, 'expected '+path.join('.')+' to equal:'+actual)
}

function has (t, actual, expected, path) {
  path = path || []

  if(!(isObject(actual))) return is(t, actual, expected, path)

  if(!isObject(expected))
    return t.fail('expected object at path:'+path.join('.'))

  for(var k in expected)
    has(t, actual[k], expected[k], path.concat(k))
}

test('initialize, connect to new peer', function (t) {

  var state = events.initialize()

  state = events.connect(state, {id: 'alice'})
  state = events.peerClock(state, {id: 'alice', value: {}})

  has(t, state, {
    peers: {
      alice: { clock: {}, msgs: [], notes: {}, replicating: {} },
    }
  })

  state = events.clock(state, {})

  state = events.follow(state, {id: 'alice', value: true})

  t.deepEqual(state.follows, {alice: true})
  console.log(state.peers.alice)

  has(t, state.peers.alice, {
    clock: {},
    notes: { alice: 0 },
    replicating: {alice: {rx: true}}
  }, ['state', 'peers', 'alice'])

  //lets say we send the note

  state = events.notes(state, {id: 'alice', value: {alice: 2}})
  has(t, state, {
    clock: {},
    follows: {alice: true},
    peers: {
      alice: {
        clock: {alice: 2},
        replicating: {
          alice: {
            rx: true, tx: true
          }
        }
      }
    }
  })

  var msg = {author: 'alice', sequence: 1, content: {}}
  state = events.receive(state, {id: 'alice', value:msg})

  has(t, state, {
    peers: {
      alice: {
        clock: {alice: 2},
        replicating: {
          alice: {
            rx: true, tx: true
          }
        }
      }
    },
    receive: [msg],
  })

  var msg = state.receive.shift()

  state = events.append(state, msg)

  console.log(state)

  has(t, state, {
    clock: {alice: 1}
  })

  var msg2 = {author: 'alice', sequence: 2, content: {}}
  state = events.receive(state, {id: 'alice', value:msg2})
  state = events.append(state, state.receive.shift())

  has(t, state, {
    clock: {alice: 2}
  })

  var msg3 = {author: 'alice', sequence: 3, content: {}}
  state = events.receive(state, {id: 'alice', value:msg3})
  state = events.append(state, state.receive.shift())

  has(t, state, {
    clock: {alice: 3}
  })

  t.end()

})

test('initialize, but append before peerClock loads', function (t) {

  var state = events.initialize()
  state = events.clock(state, {alice: 1, bob: 2})

  state = events.connect(state, {id: 'alice'})
  state = events.append(state, {author: 'bob', sequence: 3, content: {}})

  state = events.peerClock(state, {id: 'alice', value: {}})
  t.end()
})

test('connect to two peers, append message one send, one note', function (t) {

  var state = {
    clock: { alice: 1 },
    peers: {
      bob: {
        clock: { alice: 1 },
        msgs: [], retrive: [],
        replicating: {
          alice: {
            rx: true, tx: true, sent: 1, retrive: false
          }
        }
      },
      charles: {
        clock: {alice: 1},
        msgs: [], retrive: [],
        replicating: {
          alice: {
            rx: false, tx: false, sent: 1, retrive: false
          }
        }
      }
    }
  }

  var msg = {author: 'alice', sequence: 2, content: {}}
  state = events.append(state, msg)

  has(t, state, {
    clock: { alice: 2 },
    peers: {
      bob: {
        clock: { alice: 1 },
        msgs: [msg],
        retrive: [],
        replicating: {
          alice: {
            rx: true, tx: true, sent: 2, retrive: false
          }
        }
      },
      charles: {
        clock: { alice: 1 },
        notes: { alice: -3 },
        retrive: [],
        replicating: {
          alice: {
            rx: false, tx: false, sent: 1
          }
        }
      }
    }
  })

  t.end()

})

test('reply to any clock they send, 1', function (t) {
  var state = {
    clock: { alice: 3, bob: 2, charles: 3 },
    follows: { alice: true, bob: true, charles: true, darlene: false },
    peers: {}
  }

  state = events.connect(state, {id: 'bob'})
  state = events.peerClock(state, {id: 'bob', value:{alice: 3, charles: 1}})
  t.deepEqual(state.peers.bob.notes, {bob: 2, charles: 3})

  state = events.notes(state, {id: 'bob', value: {alice: 3, darlene: 4}})

  //notes hasn't been sent, so this is merged with previous
  t.deepEqual(state.peers.bob.notes, {alice: ~3, bob: 2, charles: 3, darlene: -1})

  t.end()
})

test('reply to any clock they send, 2', function (t) {
  var state = {
    clock: { alice: 3, bob: 2},
    follows: { alice: true, bob: true},
    peers: {}
  }

  state = events.connect(state, {id: 'bob'})
  state = events.peerClock(state, {id: 'bob', value:{alice: 3, charles: 1}})
  t.deepEqual(state.peers.bob.notes, {bob: 2})

  state = events.notes(state, {id: 'bob', value: {alice: 3}})

  //notes hasn't been sent, so this is merged with previous
  t.deepEqual(state.peers.bob.notes, {alice: ~3, bob: 2})

  state = events.follow(state, {id: 'charles',value: true})
  t.deepEqual(state.peers.bob.notes, {alice: ~3, bob: 2, charles: 0})

  t.end()
})

test('append when not in TX mode', function (t) {
  var state = {
    clock: { alice: 3, bob: 2},
    follows: { alice: true, bob: true},
    peers: {}
  }
  state = events.connect(state, {id: 'bob'})
  state = events.peerClock(state, {id: 'bob', value:{alice: 3, charles: 1}})
  t.deepEqual(state.peers.bob.notes, {bob: 2})

  state = events.notes(state, {id: 'bob', value: {alice: ~3}})
  var rep = state.peers.bob.replicating.alice
  t.equal(rep.tx, false)
  t.equal(rep.sent, 3)

  console.log(state.peers.bob.replicating)

  state = events.append(state, {author: 'alice', sequence: 4, content: {}})
  t.deepEqual(state.peers.bob.notes, {bob: 2, alice: ~4})
  var rep = state.peers.bob.replicating.alice
  t.equal(rep.tx, false)
  t.equal(rep.sent, 3)

  state = events.notes(state, {id: 'bob', value: {alice: 3}})
  t.deepEqual(state.peers.bob.retrive, ['alice'])

  t.end()
})

test('note when not in RX mode', function (t) {
  var state = {
    clock: { alice: 3, bob: 2},
    follows: { alice: true, bob: true},
    peers: {
      bob: {
        clock: {alice: 3, bob: 2},
        retrive: [],
        msgs: [],
        notes: null,
        replicating: {
          alice: {
            tx:false, rx: false, sent: 3
          }
        }
      }
    }
  }

  state = events.notes(state, {id: 'bob', value: {alice: ~5}})
  var rep = state.peers.bob.replicating.alice
//  t.equal(rep.tx, true)
  t.equal(rep.rx, true)
  t.equal(rep.sent, 5)
  t.deepEqual(state.peers.bob.notes, {alice: 3})

  console.log(state.peers.bob.replicating)

//  state = events.append(state, {author: 'alice', sequence: 4, content: {}})
//  t.deepEqual(state.peers.bob.notes, {bob: 2, alice: ~4})
//  var rep = state.peers.bob.replicating.alice
//  t.equal(rep.tx, false)
//  t.equal(rep.sent, 3)
//
  t.end()

})

test('note when value is not integer', function (t) {
  var state = {
    clock: { alice: 3, bob: 2},
    follows: { alice: true, bob: true},
    peers: {}
  }

  state = events.connect(state, {id: 'bob'})
  state = events.peerClock(state, {id: 'bob', value:{}})

  t.deepEqual(state.peers.bob.clock, {})
  state = events.notes(state, {id: 'bob', value: {alice: true}})

  t.deepEqual(state.peers.bob.clock, {alice: -1})
  t.deepEqual(state.peers.bob.notes, {alice: 3, bob: 2})

  t.end()
})

test('test sends empty clock if nothing needed', function (t) {
  var state = {
    clock: { alice: 3, bob: 2},
    follows: { alice: true, bob: true},
    peers: {}
  }

  state = events.connect(state, {id: 'bob'})
  state = events.peerClock(state, {id: 'bob', value:{alice: 3, bob: 2}})

  t.deepEqual(state.peers.bob.clock, {alice: 3, bob: 2})
  t.deepEqual(state.peers.bob.notes, {})

  //receive empty clock
  state = events.notes(state, {id: 'bob', value: {}})
  t.deepEqual(state.peers.bob.replicating, {})

  t.end()
})

test('connects in sync then another message', function (t) {
  var state = {
    clock: { alice: 3, bob: 2},
    follows: { alice: true, bob: true},
    peers: {}
  }

  state = events.connect(state, {id: 'bob'})
  state = events.peerClock(state, {id: 'bob', value:{alice: 3, bob: 2}})

  t.deepEqual(state.peers.bob.clock, {alice: 3, bob: 2})
  t.deepEqual(state.peers.bob.notes, {})

  //receive empty clock
  state = events.notes(state, {id: 'bob', value: {}})
  t.deepEqual(state.peers.bob.replicating, {})

  state = events.append(state, {author: 'alice', sequence: 4, content: {}})
  t.deepEqual(state.peers.bob.notes, {alice: ~4})

  t.end()
})

<commit_msg>test behaviour triggered by unfollow<commit_after>var test = require('tape')

var events = require('../events')

function isObject(o) {
  return o && 'object' === typeof o
}

function isFunction (f) {
  return 'function' === typeof f
}

function is (t, actual, expected, path) {
  if(isFunction(expected))
    expected.call(actual, path.concat(k))
  else t.equal(expected, actual, 'expected '+path.join('.')+' to equal:'+actual)
}

function has (t, actual, expected, path) {
  path = path || []

  if(!(isObject(actual))) return is(t, actual, expected, path)

  if(!isObject(expected))
    return t.fail('expected object at path:'+path.join('.'))

  for(var k in expected)
    has(t, actual[k], expected[k], path.concat(k))
}

test('initialize, connect to new peer', function (t) {

  var state = events.initialize()

  state = events.connect(state, {id: 'alice'})
  state = events.peerClock(state, {id: 'alice', value: {}})

  has(t, state, {
    peers: {
      alice: { clock: {}, msgs: [], notes: {}, replicating: {} },
    }
  })

  state = events.clock(state, {})

  state = events.follow(state, {id: 'alice', value: true})

  t.deepEqual(state.follows, {alice: true})
  console.log(state.peers.alice)

  has(t, state.peers.alice, {
    clock: {},
    notes: { alice: 0 },
    replicating: {alice: {rx: true}}
  }, ['state', 'peers', 'alice'])

  //lets say we send the note

  state = events.notes(state, {id: 'alice', value: {alice: 2}})
  has(t, state, {
    clock: {},
    follows: {alice: true},
    peers: {
      alice: {
        clock: {alice: 2},
        replicating: {
          alice: {
            rx: true, tx: true
          }
        }
      }
    }
  })

  var msg = {author: 'alice', sequence: 1, content: {}}
  state = events.receive(state, {id: 'alice', value:msg})

  has(t, state, {
    peers: {
      alice: {
        clock: {alice: 2},
        replicating: {
          alice: {
            rx: true, tx: true
          }
        }
      }
    },
    receive: [msg],
  })

  var msg = state.receive.shift()

  state = events.append(state, msg)

  console.log(state)

  has(t, state, {
    clock: {alice: 1}
  })

  var msg2 = {author: 'alice', sequence: 2, content: {}}
  state = events.receive(state, {id: 'alice', value:msg2})
  state = events.append(state, state.receive.shift())

  has(t, state, {
    clock: {alice: 2}
  })

  var msg3 = {author: 'alice', sequence: 3, content: {}}
  state = events.receive(state, {id: 'alice', value:msg3})
  state = events.append(state, state.receive.shift())

  has(t, state, {
    clock: {alice: 3}
  })

  t.end()

})

test('initialize, but append before peerClock loads', function (t) {

  var state = events.initialize()
  state = events.clock(state, {alice: 1, bob: 2})

  state = events.connect(state, {id: 'alice'})
  state = events.append(state, {author: 'bob', sequence: 3, content: {}})

  state = events.peerClock(state, {id: 'alice', value: {}})
  t.end()
})

test('connect to two peers, append message one send, one note', function (t) {

  var state = {
    clock: { alice: 1 },
    peers: {
      bob: {
        clock: { alice: 1 },
        msgs: [], retrive: [],
        replicating: {
          alice: {
            rx: true, tx: true, sent: 1, retrive: false
          }
        }
      },
      charles: {
        clock: {alice: 1},
        msgs: [], retrive: [],
        replicating: {
          alice: {
            rx: false, tx: false, sent: 1, retrive: false
          }
        }
      }
    }
  }

  var msg = {author: 'alice', sequence: 2, content: {}}
  state = events.append(state, msg)

  has(t, state, {
    clock: { alice: 2 },
    peers: {
      bob: {
        clock: { alice: 1 },
        msgs: [msg],
        retrive: [],
        replicating: {
          alice: {
            rx: true, tx: true, sent: 2, retrive: false
          }
        }
      },
      charles: {
        clock: { alice: 1 },
        notes: { alice: -3 },
        retrive: [],
        replicating: {
          alice: {
            rx: false, tx: false, sent: 1
          }
        }
      }
    }
  })

  t.end()

})

test('reply to any clock they send, 1', function (t) {
  var state = {
    clock: { alice: 3, bob: 2, charles: 3 },
    follows: { alice: true, bob: true, charles: true, darlene: false },
    peers: {}
  }

  state = events.connect(state, {id: 'bob'})
  state = events.peerClock(state, {id: 'bob', value:{alice: 3, charles: 1}})
  t.deepEqual(state.peers.bob.notes, {bob: 2, charles: 3})

  state = events.notes(state, {id: 'bob', value: {alice: 3, darlene: 4}})

  //notes hasn't been sent, so this is merged with previous
  t.deepEqual(state.peers.bob.notes, {alice: ~3, bob: 2, charles: 3, darlene: -1})

  t.end()
})

test('reply to any clock they send, 2', function (t) {
  var state = {
    clock: { alice: 3, bob: 2},
    follows: { alice: true, bob: true},
    peers: {}
  }

  state = events.connect(state, {id: 'bob'})
  state = events.peerClock(state, {id: 'bob', value:{alice: 3, charles: 1}})
  t.deepEqual(state.peers.bob.notes, {bob: 2})

  state = events.notes(state, {id: 'bob', value: {alice: 3}})

  //notes hasn't been sent, so this is merged with previous
  t.deepEqual(state.peers.bob.notes, {alice: ~3, bob: 2})

  state = events.follow(state, {id: 'charles',value: true})
  t.deepEqual(state.peers.bob.notes, {alice: ~3, bob: 2, charles: 0})

  t.end()
})

test('append when not in TX mode', function (t) {
  var state = {
    clock: { alice: 3, bob: 2},
    follows: { alice: true, bob: true},
    peers: {}
  }
  state = events.connect(state, {id: 'bob'})
  state = events.peerClock(state, {id: 'bob', value:{alice: 3, charles: 1}})
  t.deepEqual(state.peers.bob.notes, {bob: 2})

  state = events.notes(state, {id: 'bob', value: {alice: ~3}})
  var rep = state.peers.bob.replicating.alice
  t.equal(rep.tx, false)
  t.equal(rep.sent, 3)

  console.log(state.peers.bob.replicating)

  state = events.append(state, {author: 'alice', sequence: 4, content: {}})
  t.deepEqual(state.peers.bob.notes, {bob: 2, alice: ~4})
  var rep = state.peers.bob.replicating.alice
  t.equal(rep.tx, false)
  t.equal(rep.sent, 3)

  state = events.notes(state, {id: 'bob', value: {alice: 3}})
  t.deepEqual(state.peers.bob.retrive, ['alice'])

  t.end()
})

test('note when not in RX mode', function (t) {
  var state = {
    clock: { alice: 3, bob: 2},
    follows: { alice: true, bob: true},
    peers: {
      bob: {
        clock: {alice: 3, bob: 2},
        retrive: [],
        msgs: [],
        notes: null,
        replicating: {
          alice: {
            tx:false, rx: false, sent: 3
          }
        }
      }
    }
  }

  state = events.notes(state, {id: 'bob', value: {alice: ~5}})
  var rep = state.peers.bob.replicating.alice
//  t.equal(rep.tx, true)
  t.equal(rep.rx, true)
  t.equal(rep.sent, 5)
  t.deepEqual(state.peers.bob.notes, {alice: 3})

  console.log(state.peers.bob.replicating)

//  state = events.append(state, {author: 'alice', sequence: 4, content: {}})
//  t.deepEqual(state.peers.bob.notes, {bob: 2, alice: ~4})
//  var rep = state.peers.bob.replicating.alice
//  t.equal(rep.tx, false)
//  t.equal(rep.sent, 3)
//
  t.end()

})

test('note when value is not integer', function (t) {
  var state = {
    clock: { alice: 3, bob: 2},
    follows: { alice: true, bob: true},
    peers: {}
  }

  state = events.connect(state, {id: 'bob'})
  state = events.peerClock(state, {id: 'bob', value:{}})

  t.deepEqual(state.peers.bob.clock, {})
  state = events.notes(state, {id: 'bob', value: {alice: true}})

  t.deepEqual(state.peers.bob.clock, {alice: -1})
  t.deepEqual(state.peers.bob.notes, {alice: 3, bob: 2})

  t.end()
})

test('test sends empty clock if nothing needed', function (t) {
  var state = {
    clock: { alice: 3, bob: 2},
    follows: { alice: true, bob: true},
    peers: {}
  }

  state = events.connect(state, {id: 'bob'})
  state = events.peerClock(state, {id: 'bob', value:{alice: 3, bob: 2}})

  t.deepEqual(state.peers.bob.clock, {alice: 3, bob: 2})
  t.deepEqual(state.peers.bob.notes, {})

  //receive empty clock
  state = events.notes(state, {id: 'bob', value: {}})
  t.deepEqual(state.peers.bob.replicating, {})

  t.end()
})

test('connects in sync then another message', function (t) {
  var state = {
    clock: { alice: 3, bob: 2},
    follows: { alice: true, bob: true},
    peers: {}
  }

  state = events.connect(state, {id: 'bob'})
  state = events.peerClock(state, {id: 'bob', value:{alice: 3, bob: 2}})

  t.deepEqual(state.peers.bob.clock, {alice: 3, bob: 2})
  t.deepEqual(state.peers.bob.notes, {})

  //receive empty clock
  state = events.notes(state, {id: 'bob', value: {}})
  t.deepEqual(state.peers.bob.replicating, {})

  state = events.append(state, {author: 'alice', sequence: 4, content: {}})
  t.deepEqual(state.peers.bob.notes, {alice: ~4})

  t.end()
})

test('unfollow', function (t) {

  var state = {
    clock: { alice: 3, bob: 2},
    follows: {},
    peers: {}
  }

  state = events.connect(state, {id: 'bob'})
  state = events.peerClock(state, {id: 'bob', value:{}})

  t.deepEqual(state.peers.bob.clock, {})
  t.deepEqual(state.peers.bob.notes, { })
  state = events.notes(state, {id: 'bob', value:{alice: 3, bob: 2}})
  t.deepEqual(state.peers.bob.notes, { alice: -1, bob: -1})

  state.peers.bob.notes = null

  state = events.follow(state, {id: 'alice', value: false})

  t.deepEqual(state.peers.bob.notes, null)

  state = events.notes(state, {id: 'bob', value:{charles: -1}})
  t.deepEqual(state.peers.bob.notes, {charles: -1})
  state.peers.bob.notes = null
  state = events.notes(state, {id: 'bob', value:{charles: -1}})
  t.deepEqual(state.peers.bob.notes, null)

  t.end()
})

<|endoftext|>


<commit_before>'use strict';

var SkillData = function() {
  EventEmitter.call(this);
  this.skills = [];
};

SkillData.prototype = Object.create(EventEmitter.prototype);

SkillData.prototype.useSkill = function(skill) {
  var skillData = GDM.getNow('skill_data');
  var data = skillData.getData(skill.skillIdx);
  var type = parseInt(data[SKILL.TYPE]);

  switch(type) {
  case SKILL_ACTION_TYPE.BASE_ACTION:
    var command = parseInt(data[SKILL.BASIC_COMMAND]);
    this._useCommand(command);
    break;
  case SKILL_ACTION_TYPE.EMOTION_ACTION:
    var motion = parseInt(data[SKILL.ANI_ACTION_TYPE]);
    netGame.setMotion(motion, 1);
    break;
  case SKILL_ACTION_TYPE.ACTION_IMMEDIATE:
    var target = MC.target.object;
    if (target) {
      netGame.useSkillOnTarget(skill.slot, target.serverObjectIdx);
    }
    break;
  default:
    console.warn('TODO: Unimplemented useSkill', skill);
    break;
  }
};

SkillData.prototype._useCommand = function(command) {
  switch (command) {
  case BASIC_COMMAND.PARTY:
    if (MC.party.exists) {
      if (MC.party.leaderTag === MC.uniqueTag) {
        //netGame.partyRequest(PARTY_REQ_JOIN, targetIdx);
      } else {
        GCM.system('Only the party leader can send party invites.');
      }
    } else {
      //netGame.partyRequest(PARTY_REQ_MAKE, targetIdx);
    }
    break;
  }
};

SkillData.prototype.setSkills = function(skills) {
  this.skills = skills;
  this.emit('changed');
};

SkillData.prototype.appendSkills = function(skills) {
  this.skills = this.skills.concat(skills);
  this.emit('changed');
};

SkillData.prototype.findBySlot = function(slotNo) {
  for (var i = 0; i < this.skills.length; ++i) {
    if (this.skills[i].slot === slotNo) {
      return this.skills[i];
    }
  }

  return null;
};
<commit_msg>Party skill!<commit_after>'use strict';

var SkillData = function() {
  EventEmitter.call(this);
  this.skills = [];
};

SkillData.prototype = Object.create(EventEmitter.prototype);

SkillData.prototype.useSkill = function(skill) {
  var skillData = GDM.getNow('skill_data');
  var data = skillData.getData(skill.skillIdx);
  var type = parseInt(data[SKILL.TYPE]);

  switch(type) {
  case SKILL_ACTION_TYPE.BASE_ACTION:
    var command = parseInt(data[SKILL.BASIC_COMMAND]);
    this._useCommand(command);
    break;
  case SKILL_ACTION_TYPE.EMOTION_ACTION:
    var motion = parseInt(data[SKILL.ANI_ACTION_TYPE]);
    netGame.setMotion(motion, 1);
    break;
  case SKILL_ACTION_TYPE.ACTION_IMMEDIATE:
    var target = MC.target.object;
    if (target) {
      netGame.useSkillOnTarget(skill.slot, target.serverObjectIdx);
    }
    break;
  default:
    console.warn('TODO: Unimplemented useSkill', skill);
    break;
  }
};

SkillData.prototype._useCommand = function(command) {
  var target = MC.target;
  switch (command) {
  case BASIC_COMMAND.PARTY:
    if (target) {
      if (MC.party.exists) {
        if (MC.party.leaderTag === MC.uniqueTag) {
          netGame.partyRequest(PARTY_REQ_JOIN, target.serverObjectIdx);
        } else {
          GCM.system('Only the party leader can send party invites.');
        }
      } else {
        netGame.partyRequest(PARTY_REQ_MAKE, target.serverObjectIdx);
      }
    }
    break;
  }
};

SkillData.prototype.setSkills = function(skills) {
  this.skills = skills;
  this.emit('changed');
};

SkillData.prototype.appendSkills = function(skills) {
  this.skills = this.skills.concat(skills);
  this.emit('changed');
};

SkillData.prototype.findBySlot = function(slotNo) {
  for (var i = 0; i < this.skills.length; ++i) {
    if (this.skills[i].slot === slotNo) {
      return this.skills[i];
    }
  }

  return null;
};
<|endoftext|>


<commit_before>import chai from 'chai';
import fs from 'fs';
import { GCodeParser, parseFile, parseText, parseStream } from '../dist/';
import _ from 'lodash';

const expect = chai.expect;
const should = chai.should();

describe('G-code Parser', (done) => {
	describe('Complete callback', (done) => {
		it('should call the callback at the end of parsing file.', (done) => {
            let sampleText = '';
            parseText(sampleText, (err, results) => {
                expect(err).to.be.null;
                expect(results).to.be.an('array');
                done();
            });
		});
    });

    describe('Empty data', (done) => {
		it('should get empty results.', (done) => {
            let sampleText = '';
            parseText(sampleText, (err, results) => {
                expect(results.length).to.be.empty;
                done();
            });
        });
    });

    describe('Contains only comments', (done) => {
		it('should get empty results.', (done) => {
            let sampleText = [
                ';',
                '; Operation:    0',
                '; Name:',
                '; Type:         Pocket',
                '; Paths:        3',
                '; Direction:    Conventional',
                '; Cut Depth:    3.175',
                '; Pass Depth:   1.9999999999999998',
                '; Plunge rate:  127',
                '; Cut rate:     1016',
                '  ' // empty line
            ].join('\n');
            parseText(sampleText, (err, results) => {
                expect(results.length).to.be.empty;
                done();
            });
        });
    });

	describe('File not found exception', (done) => {
		it('should fail the callback if a file is not present.', (done) => {
            parseFile('test/fixtures/NO_FILE_ERROR', (err, results) => {
                expect(err).to.not.be.null;
                expect(err.code).to.equal('ENOENT');
                done();
            });
		});
	});

	describe('parseStream / parseText / parseFile', (done) => {
        let expectedResults = [
            {
                line: 'G0 X-5 Y0 Z0 F200',
                N: undefined,
                words: [['G', 0], ['X', -5], ['Y', 0], ['Z', 0], ['F', 200]]
            },
            {
                line: 'G2 X0 Y5 I5 J0 F200',
                N: undefined,
                words: [['G', 2], ['X', 0], ['Y', 5], ['I', 5], ['J', 0], ['F', 200]]
            },
            {
                line: 'G02 X5 Y0 I0 J-5',
                N: undefined,
                words: [['G', 2], ['X', 5], ['Y', 0], ['I', 0], ['J', -5]]
            },
            {
                line: 'G02 X0 Y-5 I-5 J0',
                N: undefined,
                words: [['G', 2], ['X', 0], ['Y',-5], ['I', -5], ['J', 0]]
            },
            {
                line: 'G02 X-5 Y0 I0 J5',
                N: undefined,
                words: [['G', 2], ['X', -5], ['Y', 0], ['I', 0], ['J', 5]]
            },
            {
                line: 'G01 Z1 F500',
                N: undefined,
                words: [['G', 1], ['Z', 1], ['F', 500]]
            },
            {
                line: 'G00 X0 Y0 Z5',
                N: undefined,
                words: [['G', 0], ['X', 0], ['Y', 0], ['Z', 5]]
            }
        ];

        it('should get the expected results in the parseFile\'s callback.', (done) => {
            parseFile('test/fixtures/circle.nc', (err, results) => {
                expect(results).to.deep.equal(expectedResults);
                done();
            });
		});

        it('should get the expected results in the parseText\'s callback.', (done) => {
            let text = fs.readFileSync('test/fixtures/circle.nc', 'utf8');
            parseText(text, (err, results) => {
                expect(results).to.deep.equal(expectedResults);
                done();
            });
		});

        it('should get the expected results in the parseStream\'s callback.', (done) => {
            let stream = fs.createReadStream('test/fixtures/circle.nc', { encoding: 'utf8' });
            parseStream(stream, (err, results) => {
                expect(results).to.deep.equal(expectedResults);
                done();
            });
		});
	});

	describe('More G-code Examples', (done) => {
		it('should contain the line number.', (done) => {
            parseFile('test/fixtures/circle-inch.nc', (err, list) => {
                expect(err).to.be.null;
                list.forEach((data) => {
                    let { N } = data;
                    expect(N).to.exist;
                });
                done();
            });
        });
	});
});
<commit_msg>Fix code coverage<commit_after>import chai from 'chai';
import fs from 'fs';
import { GCodeParser, parseFile, parseText, parseStream } from '../dist/';
import _ from 'lodash';

const expect = chai.expect;
const should = chai.should();

describe('G-code Parser', (done) => {
	describe('Pass a null value as the first argument', (done) => {
		it('should call parseText\'s callback.', (done) => {
            parseText(null, (err, results) => {
                expect(err).to.be.okay;
                done();
            });
		});
		it('should call parseFile\'s callback.', (done) => {
            parseFile(null, (err, results) => {
                expect(err).to.be.okay;
                done();
            });
		});
		it('should call parseStream\'s callback.', (done) => {
            parseStream(null, (err, results) => {
                expect(err).to.be.okay;
                done();
            });
		});
    });

    describe('Pass an empty text as the first argument', (done) => {
		it('should get empty results.', (done) => {
            let sampleText = '';
            parseText(sampleText, (err, results) => {
                expect(results.length).to.be.empty;
                done();
            });
        });
    });

    describe('Contains only comments', (done) => {
		it('should get empty results.', (done) => {
            let sampleText = [
                ';',
                '; Operation:    0',
                '; Name:',
                '; Type:         Pocket',
                '; Paths:        3',
                '; Direction:    Conventional',
                '; Cut Depth:    3.175',
                '; Pass Depth:   1.9999999999999998',
                '; Plunge rate:  127',
                '; Cut rate:     1016',
                '  ' // empty line
            ].join('\n');
            parseText(sampleText, (err, results) => {
                expect(results.length).to.be.empty;
                done();
            });
        });
    });

	describe('File not found exception', (done) => {
		it('should fail the callback if a file is not present.', (done) => {
            parseFile('test/fixtures/NO_FILE_ERROR', (err, results) => {
                expect(err).to.not.be.null;
                expect(err.code).to.equal('ENOENT');
                done();
            });
		});
	});

	describe('parseStream / parseText / parseFile', (done) => {
        let expectedResults = [
            {
                line: 'G0 X-5 Y0 Z0 F200',
                N: undefined,
                words: [['G', 0], ['X', -5], ['Y', 0], ['Z', 0], ['F', 200]]
            },
            {
                line: 'G2 X0 Y5 I5 J0 F200',
                N: undefined,
                words: [['G', 2], ['X', 0], ['Y', 5], ['I', 5], ['J', 0], ['F', 200]]
            },
            {
                line: 'G02 X5 Y0 I0 J-5',
                N: undefined,
                words: [['G', 2], ['X', 5], ['Y', 0], ['I', 0], ['J', -5]]
            },
            {
                line: 'G02 X0 Y-5 I-5 J0',
                N: undefined,
                words: [['G', 2], ['X', 0], ['Y',-5], ['I', -5], ['J', 0]]
            },
            {
                line: 'G02 X-5 Y0 I0 J5',
                N: undefined,
                words: [['G', 2], ['X', -5], ['Y', 0], ['I', 0], ['J', 5]]
            },
            {
                line: 'G01 Z1 F500',
                N: undefined,
                words: [['G', 1], ['Z', 1], ['F', 500]]
            },
            {
                line: 'G00 X0 Y0 Z5',
                N: undefined,
                words: [['G', 0], ['X', 0], ['Y', 0], ['Z', 5]]
            }
        ];

        it('should get the expected results in the parseFile\'s callback.', (done) => {
            parseFile('test/fixtures/circle.nc', (err, results) => {
                expect(results).to.deep.equal(expectedResults);
                done();
            });
		});

        it('should get the expected results in the parseText\'s callback.', (done) => {
            let text = fs.readFileSync('test/fixtures/circle.nc', 'utf8');
            parseText(text, (err, results) => {
                expect(results).to.deep.equal(expectedResults);
                done();
            });
		});

        it('should get the expected results in the parseStream\'s callback.', (done) => {
            let stream = fs.createReadStream('test/fixtures/circle.nc', { encoding: 'utf8' });
            parseStream(stream, (err, results) => {
                expect(results).to.deep.equal(expectedResults);
                done();
            });
		});
	});

	describe('More G-code Examples', (done) => {
		it('should contain the line number.', (done) => {
            parseFile('test/fixtures/circle-inch.nc', (err, list) => {
                expect(err).to.be.null;
                list.forEach((data) => {
                    let { N } = data;
                    expect(N).to.exist;
                });
                done();
            });
        });
	});
});
<|endoftext|>


<commit_before>var Code = require('code');
var Lab = require('lab');
var lab = exports.lab = Lab.script();
var Wreck = require('wreck');
var querystring = require('querystring');
var identify = 'test-' + Date.now();
var EtcdConfig = require('../');

lab.experiment('etcd-config', function() {

    lab.before(function (done) {
        // set test keys
        Wreck.get('http://localhost:4001/version', function (err, res, payload) {
            //console.log('payload: %s', payload);
            if (err || res.statusCode !== 200) {
                return done(new Error('error connecting to etcd'));
            }
            return done();
        })
    });

    lab.before(function (done) {
        // set test keys
        var key = 'applications/' + identify + '/test';
        var path = '/v2/keys/' + key;
        var options = {
            payload: 'value=foo',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            }
        };
        Wreck.put('http://127.0.0.1:4001' + path, options, function (err, res, payload) {
            //console.log('payload: %s', payload);
            if (res.statusCode !== 201) {
                return done(new Error('error writing to etcd'));
            }
            return done();
        });
    });

    lab.before(function (done) {
        // set test keys
        var key = 'applications/' + identify + '/json';
        var path = '/v2/keys/' + key;
        var options = {
            payload: 'value=' + JSON.stringify(['foo', 'bar']),
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            }
        };
        Wreck.put('http://127.0.0.1:4001' + path, options, function (err, res, payload) {
            //console.log('payload: %s', payload);
            if (res.statusCode !== 201) {
                return done(new Error('error writing to etcd'));
            }
            return done();
        });
    });

    lab.before(function (done) {
        // set test keys
        var key = 'applications/' + identify + '/mest/test';
        var path = '/v2/keys/' + key;
        var options = {
            payload: 'value=moo',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            }
        };
        Wreck.put('http://127.0.0.1:4001' + path, options, function (err, res, payload) {
            //console.log('payload: %s', payload);
            if (res.statusCode !== 201) {
                return done(new Error('error writing to etcd'));
            }
            return done();
        });
    });

    lab.test('initializes', function (done) {
        var options = {
            connectionString: 'http://127.0.0.1:4001/'
        };
        var testConfig = new EtcdConfig(options);
        Code.expect(testConfig).to.exist();
        done();
    });

    lab.test('returns a config', function (done) {
        var options = {
            connectionString: 'http://127.0.0.1:4001/'
        };
        var testConfig = new EtcdConfig(options);
        testConfig.identify(identify);
        testConfig.load(function (err, config) {
            Code.expect(err).to.not.exist();
            Code.expect(config).to.exist();
            done();
        });
    });

    lab.after(function (done) {
        var key = 'applications/' + identify;
        var path = '/v2/keys/' + key + '?recursive=true&dir=false';
        Wreck.delete('http://127.0.0.1:4001' + path, null, function (err, res, payload) {
            //console.log('payload: %s', payload);
            if (res.statusCode !== 200) {
                return done(new Error('error deleting key in etcd'));
            }
            return done();
        });
    });
});<commit_msg>tests passing. not testing event listener for now<commit_after>var Code = require('code');
var Lab = require('lab');
var lab = exports.lab = Lab.script();
var Wreck = require('wreck');
var querystring = require('querystring');
var identify = 'test-' + Date.now();
var EtcdConfig = require('../');

lab.experiment('etcd-config', function() {

    lab.before(function (done) {
        // set test keys
        Wreck.get('http://localhost:4001/version', function (err, res, payload) {
            if (err || res.statusCode !== 200) {
                return done(new Error('error connecting to etcd'));
            }
            return done();
        })
    });

    lab.before(function (done) {
        // set test keys
        var key = 'applications/' + identify + '/test';
        var path = '/v2/keys/' + key;
        var options = {
            payload: 'value=foo',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            }
        };
        Wreck.put('http://127.0.0.1:4001' + path, options, function (err, res, payload) {
            if (err || res.statusCode !== 201) {
                return done(new Error('error writing to etcd'));
            }
            return done();
        });
    });

    lab.before(function (done) {
        // set test keys
        var key = 'applications/' + identify + '/json';
        var path = '/v2/keys/' + key;
        var options = {
            payload: 'value=' + JSON.stringify(['foo', 'bar']),
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            }
        };
        Wreck.put('http://127.0.0.1:4001' + path, options, function (err, res, payload) {
            if (err || res.statusCode !== 201) {
                return done(new Error('error writing to etcd'));
            }
            return done();
        });
    });

    lab.before(function (done) {
        // set test keys
        var key = 'applications/' + identify + '/mest/test';
        var path = '/v2/keys/' + key;
        var options = {
            payload: 'value=moo',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            }
        };
        Wreck.put('http://127.0.0.1:4001' + path, options, function (err, res, payload) {
            if (err || res.statusCode !== 201) {
                return done(new Error('error writing to etcd'));
            }
            return done();
        });
    });

    lab.test('initializes', function (done) {
        var options = {
            connectionString: 'http://127.0.0.1:4001/'
        };
        var testConfig = new EtcdConfig(options);
        Code.expect(testConfig).to.exist();
        done();
    });

    lab.test('returns a valid config', function (done) {
        var options = {
            connectionString: 'http://127.0.0.1:4001/'
        };
        var testConfig = new EtcdConfig(options);
        testConfig.identify(identify);
        testConfig.load(function (err, config) {
            Code.expect(err).to.not.exist();
            Code.expect(config).to.exist();
            Code.expect(config.test).to.equal('foo');
            Code.expect(config.mest.test).to.equal('moo');
            done();
        });
    });

    lab.test('parses JSON values', function (done) {
        var options = {
            connectionString: 'http://127.0.0.1:4001/',
            jsonKeys: true
        };
        var testConfig = new EtcdConfig(options);
        testConfig.identify(identify);
        testConfig.load(function (err, config) {
            Code.expect(err).to.not.exist();
            Code.expect(config).to.exist();
            Code.expect(config.json).to.be.an.instanceOf(Array);
            done();
        });
    });
// Figure out how to test this. Async issues with before and after causing this to fail
/*
    lab.test('emits changed events', function (done) {
        var options = {
            connectionString: 'http://127.0.0.1:4001/',
            jsonKeys: true
        };
        var testConfig = new EtcdConfig(options);
        testConfig.identify(identify);
        testConfig.load(function (err, config) {
            Code.expect(err).to.not.exist();
            Code.expect(config).to.exist();
            Code.expect(config.test).to.equal('foo');

            testConfig.on('changed', function (item) {
                console.log('changed: %j', item);
                Code.expect(item.key).to.equal('test');
                Code.expect(item.value).to.equal('choochoo');
                done();
            });

            var key = 'applications/' + identify + '/test';
            var path = '/v2/keys/' + key;
            var options = {
                payload: 'value=choochoo',
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded'
                }
            };
            Wreck.put('http://127.0.0.1:4001' + path, options, function (err, res, payload) {
                console.log('payload: %s', payload);
                console.log('code: %s', res.statusCode)
                if (err || res.statusCode !== 200) {
                    return done(new Error('error writing to etcd'));
                }
            });
        });
    });
*/

    lab.after(function (done) {
        var key = 'applications/' + identify;
        var path = '/v2/keys/' + key + '?recursive=true&dir=false';
        Wreck.delete('http://127.0.0.1:4001' + path, null, function (err, res, payload) {
            if (err || res.statusCode !== 200) {
                return done(new Error('error deleting key in etcd'));
            }
            return done();
        });
    });
});<|endoftext|>


<commit_before>/**
 * Display the details of the user with the given email.
 * @param email
 */
function viewUserDetails(email) {

  getUsers(
    success = function (user) {
      populateUserDetails(user, email);
    },
    error = function (response) {
      handleApiError(response);
    },
    email
  );

  function populateUserDetails(user, email) {

    var html = window.templates.userDetails(user);
    $('.collection-selected').html(html).animate({right: "0%"}, 500);

    $('.btn-user-change-password').click(function () {
      var currentPasswordRequired = false;
      viewChangePassword(email, currentPasswordRequired);
    });

    $('.btn-user-delete').click(function () {
      var result = confirm("Are you sure you want to delete this user?");
      if (result === true) {
        deleteUser(email);
      }
    });

    $('.collection-selected .btn-collection-cancel').click(function () {
      $('.collection-selected').stop().animate({right: "-50%"}, 500);
      $('.collections-select-table tbody tr').removeClass('selected');
      // Wait until the animation ends
      setTimeout(function () {
        //viewController('users');
      }, 500);
    });
  }
}<commit_msg>Prompt the user to enter the email of the user they wish to delete before deleting.<commit_after>/**
 * Display the details of the user with the given email.
 * @param email
 */
function viewUserDetails(email) {

  getUsers(
    success = function (user) {
      populateUserDetails(user, email);
    },
    error = function (response) {
      handleApiError(response);
    },
    email
  );

  function populateUserDetails(user, email) {

    var html = window.templates.userDetails(user);
    $('.collection-selected').html(html).animate({right: "0%"}, 500);

    $('.btn-user-change-password').click(function () {
      var currentPasswordRequired = false;
      viewChangePassword(email, currentPasswordRequired);
    });

    $('.btn-user-delete').click(function () {

      var result = prompt("Please enter the email of the user to confirm the delete");
      if (result != null) {
        if (result === email) {
          deleteUser(email);
        } else {
          alert('The email you entered did not match the user you want to delete.')
        }
      }
    });

    $('.collection-selected .btn-collection-cancel').click(function () {
      $('.collection-selected').stop().animate({right: "-50%"}, 500);
      $('.collections-select-table tbody tr').removeClass('selected');
      // Wait until the animation ends
      setTimeout(function () {
        //viewController('users');
      }, 500);
    });
  }
}<|endoftext|>


<commit_before>// The index.js tests portal.js as a Node.js client and
// requires a running portal server
//
// To run portal server, execute the command in another console
//     node server

var qunit = require("qunit");

qunit.run({
	deps: {path: "webapp/assets/helper.js", namespace: "helper"},
	code: {path: "../portal.js", namespace: "portal"},
	tests: ["webapp/client.js", "webapp/server.js"]
});
<commit_msg>Consider where node command is called<commit_after>// The index.js tests portal.js as a Node.js client and
// requires a running portal server
//
// To run portal server, execute the command in another console
//     node server

var qunit = require("qunit");

qunit.run({
	deps: {path: __dirname + "/webapp/assets/helper.js", namespace: "helper"},
	code: {path: __dirname + "/../portal.js", namespace: "portal"},
	tests: [__dirname + "/webapp/client.js", __dirname + "/webapp/server.js"]
});
<|endoftext|>


<commit_before>var _ = require('lodash')
var React = require('react')

var Requirement = require('./requirement')

function findType(result, details, title) {
	var type = 'null'

	if (_.isArray(details)) {
		type = 'array/requirementSet'
	}

	else if (!details && _.isBoolean(result)) {
		type = 'boolean'
	}

	else if (_.isPlainObject(details)) {
		if (_.every(details, _.isBoolean)) {
			type = 'object/boolean'
		}
		else if (_.some(details, _.isNumber)) {
			type = 'object/number'
		}
	}

	// console.log('findType', title, result, details, type)
	return type
}

var BooleanRequirement = React.createClass({
	render: function() {
		return React.DOM.div(
			{
				className: 'requirement-result requirement-result-boolean'
			},
			React.DOM.span(
				{className: this.props.result ? ' completed' : ' incomplete'},
				this.props.result ? 'Completed' : 'Incomplete')
		)
	}
})

var BooleanArrayRequirement = React.createClass({
	render: function() {
		// console.log('BooleanObjectRequirement', this.props)
		return React.DOM.div(
			{className: 'requirement-result requirement-result-object-boolean'},
			React.DOM.ul(
				{className: 'requirement-detail-list'},
				_.map(this.props.details, function(req) {
					return React.DOM.li(
						{
							key: req.title,
							className: req.result ? 'completed' : 'incomplete',
							title: req.title + ': ' + (req.result ? 'Completed.' : 'Incomplete!')
						},
						req
					)
				})
			)
		)
	}
})

var NumberObjectRequirement = React.createClass({
	render: function() {
		return React.DOM.div(
			{className: 'requirement-result requirement-result-object-number'},
			React.DOM.span(
				{className: this.props.result ? 'completed' : 'incomplete'},
				this.props.details.has, ' of ', this.props.details.needs
			),
			React.DOM.ul(
				{className: 'requirement-detail-list'},
				_.map(this.props.details.matches, function(match) {
					return React.DOM.li({key: match.deptnum}, match.deptnum)
				})
			)
		)
	}
})

var RequirementSet = React.createClass({
	render: function() {
		// console.log('requirement-set render', this.props)

		var details = undefined
		var type = this.props.type || findType(this.props.result, this.props.details, this.props.title)
		console.log('reqSetType', this.props.title, type, this.props.type)

		if (type === 'array/requirementSet') {
			details = _.map(this.props.details, function(requirement, index) {
				return RequirementSet(_.merge({key: index}, requirement))
			})
		}

		else if (type === 'array/boolean') {
			details = _.map(this.props.details, function(requirement, index) {
				return BooleanArrayRequirement(_.merge({key: index}, requirement))
			})
		}

		else if (type === 'boolean') {
			details = BooleanRequirement({result: this.props.result})
		}

		else if (type === 'object/number') {
			details = NumberObjectRequirement({result: this.props.result, details: this.props.details})
		}

		return (
			React.DOM.div(
				{
					className: 'requirement-set',
					'data-type': type,
				},
				React.DOM.h2(
					{
						className: this.props.result ? 'completed' : 'incomplete',
						title: this.props.description,
					},
					this.props.title
				),
				details
			)
		)
	}
})

module.exports = RequirementSet
<commit_msg>Turn of the reqSetType logging for now<commit_after>var _ = require('lodash')
var React = require('react')

var Requirement = require('./requirement')

function findType(result, details, title) {
	var type = 'null'

	if (_.isArray(details)) {
		type = 'array/requirementSet'
	}

	else if (!details && _.isBoolean(result)) {
		type = 'boolean'
	}

	else if (_.isPlainObject(details)) {
		if (_.every(details, _.isBoolean)) {
			type = 'object/boolean'
		}
		else if (_.some(details, _.isNumber)) {
			type = 'object/number'
		}
	}

	// console.log('findType', title, result, details, type)
	return type
}

var BooleanRequirement = React.createClass({
	render: function() {
		return React.DOM.div(
			{
				className: 'requirement-result requirement-result-boolean'
			},
			React.DOM.span(
				{className: this.props.result ? ' completed' : ' incomplete'},
				this.props.result ? 'Completed' : 'Incomplete')
		)
	}
})

var BooleanArrayRequirement = React.createClass({
	render: function() {
		// console.log('BooleanObjectRequirement', this.props)
		return React.DOM.div(
			{className: 'requirement-result requirement-result-object-boolean'},
			React.DOM.ul(
				{className: 'requirement-detail-list'},
				_.map(this.props.details, function(req) {
					return React.DOM.li(
						{
							key: req.title,
							className: req.result ? 'completed' : 'incomplete',
							title: req.title + ': ' + (req.result ? 'Completed.' : 'Incomplete!')
						},
						req
					)
				})
			)
		)
	}
})

var NumberObjectRequirement = React.createClass({
	render: function() {
		return React.DOM.div(
			{className: 'requirement-result requirement-result-object-number'},
			React.DOM.span(
				{className: this.props.result ? 'completed' : 'incomplete'},
				this.props.details.has, ' of ', this.props.details.needs
			),
			React.DOM.ul(
				{className: 'requirement-detail-list'},
				_.map(this.props.details.matches, function(match) {
					return React.DOM.li({key: match.deptnum}, match.deptnum)
				})
			)
		)
	}
})

var RequirementSet = React.createClass({
	render: function() {
		// console.log('requirement-set render', this.props)

		var details = undefined
		var type = this.props.type || findType(this.props.result, this.props.details, this.props.title)
		// console.log('reqSetType', this.props.title, type, this.props.type)

		if (type === 'array/requirementSet') {
			details = _.map(this.props.details, function(requirement, index) {
				return RequirementSet(_.merge({key: index}, requirement))
			})
		}

		else if (type === 'array/boolean') {
			details = _.map(this.props.details, function(requirement, index) {
				return BooleanArrayRequirement(_.merge({key: index}, requirement))
			})
		}

		else if (type === 'boolean') {
			details = BooleanRequirement({result: this.props.result})
		}

		else if (type === 'object/number') {
			details = NumberObjectRequirement({result: this.props.result, details: this.props.details})
		}

		return (
			React.DOM.div(
				{
					className: 'requirement-set',
					'data-type': type,
				},
				React.DOM.h2(
					{
						className: this.props.result ? 'completed' : 'incomplete',
						title: this.props.description,
					},
					this.props.title
				),
				details
			)
		)
	}
})

module.exports = RequirementSet
<|endoftext|>


<commit_before>const gulp = require('gulp');
const sourcemaps = require('gulp-sourcemaps');
const babel = require('gulp-babel');
const concat = require('gulp-concat');
const uglify = require('gulp-uglify');
const rename = require('gulp-rename');

gulp.task('build:designer:babel', () => {
    gulp.src([
        'js/util/**/*.js',
        'js/designer/**/*.js'
    ])
        .pipe(sourcemaps.init())
        .pipe(babel({
            presets: ['babel-preset-env']
        }))
        .pipe(concat('designer.js'))
        .pipe(sourcemaps.write('.'))
        .pipe(gulp.dest('js'));
});

gulp.task('build:frontend:babel', () => {
    gulp.src([
        'js/util/**/*.js',
        'js/frontend/perfect-scrollbar.js',
        'js/frontend/scrollhelper.js'
    ])
        .pipe(sourcemaps.init())
        .pipe(babel({
            presets: ['babel-preset-env']
        }))
        .pipe(concat('frontend.js'))
        .pipe(sourcemaps.write('.'))
        .pipe(gulp.dest('js'));
});

gulp.task('build:frontend:uglify', ['build:frontend:babel'], () => {
    gulp.src('js/frontend.js')
        .pipe(uglify())
        .pipe(rename('frontend.min.js'))
        .pipe(gulp.dest('js'));
});

gulp.task('build:designer:uglify', ['build:designer:babel'], () => {
    gulp.src('js/designer.js')
        .pipe(uglify())
        .pipe(rename('designer.min.js'))
        .pipe(gulp.dest('js'));
});

gulp.task('build', ['build:designer:uglify', "build:frontend:uglify"]);

gulp.task('default', ['build']);<commit_msg>Added minification<commit_after>const gulp = require('gulp');
const sourcemaps = require('gulp-sourcemaps');
const babel = require('gulp-babel');
const concat = require('gulp-concat');
const uglify = require('gulp-uglify');
const rename = require('gulp-rename');

gulp.task('build:designer:babel', () => {
    gulp.src([
        'src/js/util/**/*.js',
        'src/js/designer/**/*.js'
    ])
        .pipe(sourcemaps.init())
        .pipe(babel({
            presets: ['babel-preset-env']
        }))
        .pipe(concat('designer.js'))
        .pipe(sourcemaps.write())
        .pipe(gulp.dest('dist'))
        .pipe(sourcemaps.init())
        .pipe(uglify())
        .pipe(rename('designer.min.js'))
        .pipe(sourcemaps.write())
        .pipe(gulp.dest('dist'));
});

gulp.task('build:frontend:babel', () => {
    gulp.src([
        'src/js/util/**/*.js',
        'src/js/frontend/perfect-scrollbar.js',
        'src/js/frontend/scrollhelper.js'
    ])
        .pipe(sourcemaps.init())
        .pipe(babel({
            presets: ['babel-preset-env']
        }))
        .pipe(concat('frontend.js'))
        .pipe(sourcemaps.write())
        .pipe(gulp.dest('dist'))
        .pipe(sourcemaps.init())
        .pipe(uglify())
        .pipe(rename('frontend.min.js'))
        .pipe(sourcemaps.write())
        .pipe(gulp.dest('dist'));
});

gulp.task('build', ['build:designer:babel', "build:frontend:babel"]);

gulp.task('default', ['build']);<|endoftext|>