<commit_before>/**
 * Class for handeling graph plotting of pulse data.
 * Still needs loads of work and is only a cut/paste from template for now
 */
var plot;
var GraphPlotter = {
    choiceContainer: null,
    datasets: null,
    backendUrl: null,
    max_hr: 200,
    markings: [],
    ranges: {},

    setRange: function(range) {
        this.ranges = range;
    },
    plot: function() {
        data = [];
        var that = this;
        var minIndex = null;
        var maxIndex = null;
        var min = null;
        var max = null;
        var xaxisattrs = {
            tickDecimals: 0,
            tickFormatter: this.xaxisformatter
        };
        if (this.ranges.xaxis != undefined) {
            min = this.ranges.xaxis.from;
            max = this.ranges.xaxis.to;
            xaxisattrs.min = min;
            xaxisattrs.max = max;

            for (dataset in this.datasets) {

                series = this.datasets[dataset]['data']

                for (k in series) {
                    if (min >= series[k][0]) {
                        minIndex = k;
                    }
                    if (max <= series[k][0]) {
                        maxIndex = k;
                        break;
                    }
                }
                break;
            }
        }
        $("#choices").find("input:checked").each(function () {
            var key = $(this).attr("name");
            if (key && that.datasets[key]) {
                if (key == 'hr')
                    that.datasets[key]['constraints'] = [that.constraint0, that.constraint1, that.constraint2, that.constraint3, that.constraint4, that.constraint5];
                if (key != 'lon' && key != 'lat') // lon and lat doesn't go in the graph
                    data.push(that.datasets[key]);
            }
        });

        if (data.length > 0) {
            plot = $.plot($("#exercisegraph"), data, {
                series: {
                    lines: {
                        lineWidth: 2, // less cluttere
                    },
                    shadowSize: 3 //drawing is faster without shadoes
                },
                yaxes: [
                    { tickFormatter: axisformatters['speed'] },
                    { position: "right", min: 80, max: this.max_hr, tickFormatter: axisformatters['hr'] },
                    { position: "right", tickFormatter: axisformatters['power']},
                    { tickFormatter: axisformatters['altitude']} ,
                    { tickFormatter: axisformatters['temp']},

                    ],
                xaxis: xaxisattrs,
                legend: {
                    container: $("#exercisegraph_legend"),
                    labelFormatter: function(label, series) {
                        // series is the series object for the label
                        return label;
                    },
                    noColumns: 15
                },
                grid: {
                    hoverable: true,
                    clickable: true,
                    backgroundColor: { colors: ["#fff", "#eee"] },
                    markings: this.markings,
                    markingsLineWidth: 1,
                },
                crosshair: { mode: "x" },
                selection: { mode: "x" }
            });
        }

        if (minIndex != null && maxIndex != null) {
            if (typeof(Mapper) != "undefined")
                Mapper.loadGeoJSON(minIndex, maxIndex);

            var segment_link = $("#segment_add");
            segment_link.attr('href' , segment_link.attr('href')+ '&start=' + minIndex + '&stop=' + maxIndex);
            $("#segment_add").removeClass("hidden");

            //window.location.hash = 'graph-zoom-' + Math.round(min*10)/10 + '-' + Math.round(max*10)/10;
            window.location.hash = 'graph-zoom-' + min + '-' + max;

            $.getJSON(this.backendUrl, { start: minIndex, stop: maxIndex }, function (avgs) {
                var items = $("#averages ul .data");
                $("#averages h4").removeClass("hidden");

                $.each(items, function (i, elem) {
                    var classlist = elem.className.split(" ");
                    for (k in classlist) {
                        if (classlist[k] in avgs) {
                            var key = classlist[k];
                            var e = $(elem);
                            var val = avgs[key];
                            if (val) {
                                val = Math.round(val * 10) / 10;
                                e.text(val);
                                e.parents(".hidden").removeClass("hidden");
                                e.attr('title', key.replace(/_/g, ' '))
                                e.parents('li').attr('title', key.replace(/_/g, ' '))
                            }
                        }
                    }
                });
            });
        }
        else {
            if (typeof(Mapper) != "undefined")
                Mapper.loadGeoJSON(0, 0);
            $("#averages ul li").addClass("hidden");
            $("#averages h4").addClass("hidden");
        }

    },
    updateLegend: function(pos) {
        this.updateLegendTimeout = null;
       // var pos = this.latestPosition;
        var axes = plot.getAxes();
        if (pos.x < axes.xaxis.min || pos.x > axes.xaxis.max ||
            pos.y < axes.yaxis.min || pos.y > axes.yaxis.max)
            return;

        var i, j, dataset = plot.getData();
        for (i = 0; i < dataset.length; ++i) {
            var series = dataset[i];

            // find the nearest points, x-wise
            for (j = 0; j < series.data.length; ++j)
                if (series.data[j]) {
                    if (series.data[j][0] > pos.x)
                        break;
                }

            // now interpolate
            var y, p1 = series.data[j - 1], p2 = series.data[j];

            if (p1 == null)
                y = p2[1];
            else if (p2 == null)
                y = p1[1];
            else
                y = p1[1] + (p2[1] - p1[1]) * (pos.x - p1[0]) / (p2[0] - p1[0]);

            this.legends.eq(i).text(series.label.replace(/=.*/, "= " + y.toFixed(2)));
        }
    },
    showTooltip: function (x, y, contents) {
        $('
' + contents + '
').css( {
            position: 'absolute',
            display: 'none',
            top: y + 5,
            left: x + 5,
            padding: '10px',
            opacity: 0.9
        }).appendTo("body").delay(200).fadeIn(200);
    },
    init: function(args) {
        this.datasets = args.datasets;
        var backendUrl = args.backendUrl;
        this.max_hr = args.max_hr;
        this.markings = args.markings;
        this.xaxisformatter = axisformatters[args.xaxisformatter];
        this.posFeature = null;
        this.fullscreen = false;
        function evaluate(y,threshold) {
            return y < threshold;
        }
        this.constraint0 = {
            threshold: this.max_hr*0.6,
            color: colors[0],
            evaluate : evaluate
        }
        this.constraint1 = {
            threshold: this.max_hr*0.72,
            color: colors[1],
            evaluate : evaluate
        }
        this.constraint2 = {
            threshold: this.max_hr*0.82,
            color: colors[2],
            evaluate : evaluate
        }
        this.constraint3 = {
            threshold: this.max_hr*0.87,
            color: colors[3],
            evaluate : evaluate
        }
        this.constraint4 = {
            threshold: this.max_hr*0.92,
            color: colors[4],
            evaluate : evaluate
        }
        this.constraint5 = {
            threshold: this.max_hr*0.97,
            color: colors[5],
            evaluate : evaluate
        }

        var that = this;
        this.backendUrl = backendUrl;
        this.choiceContainer = $("#choices");

        $.each(this.datasets, function(key, val) {
            var checked = "checked = checked";
            if (key == 'cadence')
                checked = ''
            if (key == 'temp')
                checked = ''
            if (key == 'power')
                checked = ''

            if (key != 'lon' && key != 'lat') {

                that.choiceContainer.append('<input type="checkbox" name="' + key +
                    '" ' + checked + ' id="chk_' + key + '">' + val.label + '</input>');
            }
        });
        $("#reset_zoom").bind("click", function(evt) {
            evt.preventDefault();
            $("#gtooltip").remove(); // tooltips messes up pos
            that.setRange({});
            that.plot();
        });
        $("#enlarge").bind("click", function(evt) {
            evt.preventDefault();
            $("#gtooltip").remove(); // tooltips messes up pos
            // Press escape to leave fullscreen
            $(window).bind("keyup", function(evt) { if (evt.keyCode == 27) { $('#enlarge').click() } });
            if(!that.fullscreen) {
                //$("#scrollhack").css("overflow", "scroll");
                //$("#exercisegraph").width( $("#exercisegraph").width()*4);
                $("#exercisegraph").appendTo('body');
                $("#exercisegraph").css("position", "absolute"); // Somehow needed, even though it's set in the css
                $("#exercisegraph").addClass('exercisegraphoverlay');
                $("#exercisegraph").removeClass('exercisegraph');
                $("#exercisegraph").css("overflow", "hidden");

                $("#averages").addClass('extraoverlay');
                $("#averages").appendTo('body');
                that.fullscreen = true;
            }
            else {
                $("#exercisegraph").removeClass('exercisegraphoverlay');
                $("#exercisegraph").addClass('exercisegraph');
                $("#exercisegraph").css("position", "relative"); // Somehow needed, even though it's set in the css
                $("#exercisegraph").appendTo($('#graphcontainer'));

                $("#averages").removeClass('extraoverlay');
                $("#averages").appendTo($('#graphcontainer'));
                that.fullscreen = false;
            }
        /* resize.js plugin does this
            plot.resize();
            plot.setupGrid();
            plot.draw();
        */
        });
        //$("#segment_add").bind("click", function(evt) {
        //});
        this.choiceContainer.find("input").bind("change", function(evt) {
                that.plot();
        });
        $('.legendColorBox > div').each(function(i){
            $(this).clone().prependTo(that.choiceContainer.find("li").eq(i));
        });

        this.legends = $(".legendLabel");
        this.legends.each(function () {
            // fix the widths so they don't jump around
            $(this).css('width', $(this).width());
        });

        var previousPoint = null;
        this.updateLegendTimeout = null;
        this.latestPosition = null;
        $("#exercisegraph").bind("plothover", function (event, pos, item) {
            that.latestPosition = pos;
  //          if (!that.updateLegendTimeout) that.updateLegendTimeout = setTimeout(that.updateLegend, 50);
            //that.updateLegend(pos);

            $("#gtooltip").remove();
            var axes = plot.getAxes();
            // Just retrn if we're hovering around outside the graph area
            if (pos.x < axes.xaxis.min || pos.x > axes.xaxis.max ||
                pos.y < axes.yaxis.min || pos.y > axes.yaxis.max)
                return;

            var posIndex = 0;
            for (serieskey in that.datasets) { // Find first and best series that we got
                var series = that.datasets[serieskey]['data'];
                for (key in series) {
                    if (series[key][0] >= pos.x) {
                        var posIndex = key;
                        break;
                    }
                }
                break;
            }
            if (posIndex <= 0)  // No index found
                return;

            // Move marker to current pos
            if (Mapper.map != null || Mapper.posLayer != undefined) {
                var route_lon = that.datasets['lon'];
                var route_lat = that.datasets['lat'];
                if (route_lon.length >= posIndex) {
                    var x = route_lon[posIndex];
                    var y = route_lat[posIndex];
                    if (!this.posFeature) {
                        this.posFeature = Mapper.createFeature(Mapper.posLayer, x, y, 0);
                    }
                    // Mapper.updatePosMarker(x, y);
                    Mapper.moveFeature(this.posFeature, x, y, 0); // Hardcoded to 0 degrees
                }
            }

            var x = pos.x;
            var highlightedseries = null;
            if (item)
                highlightedseries = item.series.label;

            var tooltipHtml = '
Data at ' + that.xaxisformatter(x, plot.getAxes().xaxis) + '

';
            for (skey in that.datasets) {
                if (skey == 'lon' || skey == 'lat')
                    continue;
                var series = that.datasets[skey];
                var label = series['label'];
                var tickFormatter = axisformatters[skey];
                if (skey == 'poweravg30s')
                    tickFormatter = axisformatters['power'];
                var val = series['data'][posIndex][1]; // Must fetch this from datasets rather thatn the graph data itself because of multiple treshold splits up the indexes
                if(tickFormatter != undefined)
                    val = tickFormatter(val, plot.getAxes().xaxis);
                var color = plot.getOptions().colors[series['color']];
                if(label == highlightedseries) // Highlight if item selected
                    skey += ' selected'
                tooltipHtml += '
' + label + ': ' + val + '
';
            }
            tooltipHtml += '
';
            that.showTooltip(pos.pageX, pos.pageY, tooltipHtml);

        });
        $("#exercisegraph").bind("plotclick", function (event, pos, item) {
            if (item) {
                plot.highlight(item.series, item.datapoint);
            }
            // reset zoom on click
            that.setRange({});
            that.plot();
        });

        $("#exercisegraph").bind("plotselected", function (event, ranges) {
            that.setRange(ranges);
            that.plot();
        });
    }
};

<commit_msg>press f to enter fullscreen<commit_after>/**
 * Class for handeling graph plotting of pulse data.
 * Still needs loads of work and is only a cut/paste from template for now
 */
var plot;
var GraphPlotter = {
    choiceContainer: null,
    datasets: null,
    backendUrl: null,
    max_hr: 200,
    markings: [],
    ranges: {},

    setRange: function(range) {
        this.ranges = range;
    },
    plot: function() {
        data = [];
        var that = this;
        var minIndex = null;
        var maxIndex = null;
        var min = null;
        var max = null;
        var xaxisattrs = {
            tickDecimals: 0,
            tickFormatter: this.xaxisformatter
        };
        if (this.ranges.xaxis != undefined) {
            min = this.ranges.xaxis.from;
            max = this.ranges.xaxis.to;
            xaxisattrs.min = min;
            xaxisattrs.max = max;

            for (dataset in this.datasets) {

                series = this.datasets[dataset]['data']

                for (k in series) {
                    if (min >= series[k][0]) {
                        minIndex = k;
                    }
                    if (max <= series[k][0]) {
                        maxIndex = k;
                        break;
                    }
                }
                break;
            }
        }
        $("#choices").find("input:checked").each(function () {
            var key = $(this).attr("name");
            if (key && that.datasets[key]) {
                if (key == 'hr')
                    that.datasets[key]['constraints'] = [that.constraint0, that.constraint1, that.constraint2, that.constraint3, that.constraint4, that.constraint5];
                if (key != 'lon' && key != 'lat') // lon and lat doesn't go in the graph
                    data.push(that.datasets[key]);
            }
        });

        if (data.length > 0) {
            plot = $.plot($("#exercisegraph"), data, {
                series: {
                    lines: {
                        lineWidth: 2, // less cluttere
                    },
                    shadowSize: 3 //drawing is faster without shadoes
                },
                yaxes: [
                    { tickFormatter: axisformatters['speed'] },
                    { position: "right", min: 80, max: this.max_hr, tickFormatter: axisformatters['hr'] },
                    { position: "right", tickFormatter: axisformatters['power']},
                    { tickFormatter: axisformatters['altitude']} ,
                    { tickFormatter: axisformatters['temp']},

                    ],
                xaxis: xaxisattrs,
                legend: {
                    container: $("#exercisegraph_legend"),
                    labelFormatter: function(label, series) {
                        // series is the series object for the label
                        return label;
                    },
                    noColumns: 15
                },
                grid: {
                    hoverable: true,
                    clickable: true,
                    backgroundColor: { colors: ["#fff", "#eee"] },
                    markings: this.markings,
                    markingsLineWidth: 1,
                },
                crosshair: { mode: "x" },
                selection: { mode: "x" }
            });
        }

        if (minIndex != null && maxIndex != null) {
            if (typeof(Mapper) != "undefined")
                Mapper.loadGeoJSON(minIndex, maxIndex);

            var segment_link = $("#segment_add");
            segment_link.attr('href' , segment_link.attr('href')+ '&start=' + minIndex + '&stop=' + maxIndex);
            $("#segment_add").removeClass("hidden");

            //window.location.hash = 'graph-zoom-' + Math.round(min*10)/10 + '-' + Math.round(max*10)/10;
            window.location.hash = 'graph-zoom-' + min + '-' + max;

            $.getJSON(this.backendUrl, { start: minIndex, stop: maxIndex }, function (avgs) {
                var items = $("#averages ul .data");
                $("#averages h4").removeClass("hidden");

                $.each(items, function (i, elem) {
                    var classlist = elem.className.split(" ");
                    for (k in classlist) {
                        if (classlist[k] in avgs) {
                            var key = classlist[k];
                            var e = $(elem);
                            var val = avgs[key];
                            if (val) {
                                val = Math.round(val * 10) / 10;
                                e.text(val);
                                e.parents(".hidden").removeClass("hidden");
                                e.attr('title', key.replace(/_/g, ' '))
                                e.parents('li').attr('title', key.replace(/_/g, ' '))
                            }
                        }
                    }
                });
            });
        }
        else {
            if (typeof(Mapper) != "undefined")
                Mapper.loadGeoJSON(0, 0);
            $("#averages ul li").addClass("hidden");
            $("#averages h4").addClass("hidden");
        }

    },
    updateLegend: function(pos) {
        this.updateLegendTimeout = null;
       // var pos = this.latestPosition;
        var axes = plot.getAxes();
        if (pos.x < axes.xaxis.min || pos.x > axes.xaxis.max ||
            pos.y < axes.yaxis.min || pos.y > axes.yaxis.max)
            return;

        var i, j, dataset = plot.getData();
        for (i = 0; i < dataset.length; ++i) {
            var series = dataset[i];

            // find the nearest points, x-wise
            for (j = 0; j < series.data.length; ++j)
                if (series.data[j]) {
                    if (series.data[j][0] > pos.x)
                        break;
                }

            // now interpolate
            var y, p1 = series.data[j - 1], p2 = series.data[j];

            if (p1 == null)
                y = p2[1];
            else if (p2 == null)
                y = p1[1];
            else
                y = p1[1] + (p2[1] - p1[1]) * (pos.x - p1[0]) / (p2[0] - p1[0]);

            this.legends.eq(i).text(series.label.replace(/=.*/, "= " + y.toFixed(2)));
        }
    },
    showTooltip: function (x, y, contents) {
        $('
' + contents + '
').css( {
            position: 'absolute',
            display: 'none',
            top: y + 5,
            left: x + 5,
            padding: '10px',
            opacity: 0.9
        }).appendTo("body").delay(200).fadeIn(200);
    },
    init: function(args) {
        this.datasets = args.datasets;
        var backendUrl = args.backendUrl;
        this.max_hr = args.max_hr;
        this.markings = args.markings;
        this.xaxisformatter = axisformatters[args.xaxisformatter];
        this.posFeature = null;
        this.fullscreen = false;
        function evaluate(y,threshold) {
            return y < threshold;
        }
        this.constraint0 = {
            threshold: this.max_hr*0.6,
            color: colors[0],
            evaluate : evaluate
        }
        this.constraint1 = {
            threshold: this.max_hr*0.72,
            color: colors[1],
            evaluate : evaluate
        }
        this.constraint2 = {
            threshold: this.max_hr*0.82,
            color: colors[2],
            evaluate : evaluate
        }
        this.constraint3 = {
            threshold: this.max_hr*0.87,
            color: colors[3],
            evaluate : evaluate
        }
        this.constraint4 = {
            threshold: this.max_hr*0.92,
            color: colors[4],
            evaluate : evaluate
        }
        this.constraint5 = {
            threshold: this.max_hr*0.97,
            color: colors[5],
            evaluate : evaluate
        }

        var that = this;
        this.backendUrl = backendUrl;
        this.choiceContainer = $("#choices");

        $.each(this.datasets, function(key, val) {
            var checked = "checked = checked";
            if (key == 'cadence')
                checked = ''
            if (key == 'temp')
                checked = ''
            if (key == 'power')
                checked = ''

            if (key != 'lon' && key != 'lat') {

                that.choiceContainer.append('<input type="checkbox" name="' + key +
                    '" ' + checked + ' id="chk_' + key + '">' + val.label + '</input>');
            }
        });
        $("#reset_zoom").bind("click", function(evt) {
            evt.preventDefault();
            $("#gtooltip").remove(); // tooltips messes up pos
            that.setRange({});
            that.plot();
        });
        $(window).bind("keyup", function(evt) { if (evt.keyCode == 70) { $('#enlarge').click() } });
        $("#enlarge").bind("click", function(evt) {
            evt.preventDefault();
            $("#gtooltip").remove(); // tooltips messes up pos
            // Press escape to leave fullscreen
            $(window).bind("keyup", function(evt) { if (evt.keyCode == 27) { $('#enlarge').click() } });
            if(!that.fullscreen) {
                //$("#scrollhack").css("overflow", "scroll");
                //$("#exercisegraph").width( $("#exercisegraph").width()*4);
                $("#exercisegraph").appendTo('body');
                $("#exercisegraph").css("position", "absolute"); // Somehow needed, even though it's set in the css
                $("#exercisegraph").addClass('exercisegraphoverlay');
                $("#exercisegraph").removeClass('exercisegraph');
                $("#exercisegraph").css("overflow", "hidden");

                $("#averages").addClass('extraoverlay');
                $("#averages").appendTo('body');
                that.fullscreen = true;
            }
            else {
                $("#exercisegraph").removeClass('exercisegraphoverlay');
                $("#exercisegraph").addClass('exercisegraph');
                $("#exercisegraph").css("position", "relative"); // Somehow needed, even though it's set in the css
                $("#exercisegraph").appendTo($('#graphcontainer'));

                $("#averages").removeClass('extraoverlay');
                $("#averages").appendTo($('#graphcontainer'));
                that.fullscreen = false;
            }
        /* resize.js plugin does this
            plot.resize();
            plot.setupGrid();
            plot.draw();
        */
        });
        //$("#segment_add").bind("click", function(evt) {
        //});
        this.choiceContainer.find("input").bind("change", function(evt) {
                that.plot();
        });
        $('.legendColorBox > div').each(function(i){
            $(this).clone().prependTo(that.choiceContainer.find("li").eq(i));
        });

        this.legends = $(".legendLabel");
        this.legends.each(function () {
            // fix the widths so they don't jump around
            $(this).css('width', $(this).width());
        });

        var previousPoint = null;
        this.updateLegendTimeout = null;
        this.latestPosition = null;
        $("#exercisegraph").bind("plothover", function (event, pos, item) {
            that.latestPosition = pos;
  //          if (!that.updateLegendTimeout) that.updateLegendTimeout = setTimeout(that.updateLegend, 50);
            //that.updateLegend(pos);

            $("#gtooltip").remove();
            var axes = plot.getAxes();
            // Just retrn if we're hovering around outside the graph area
            if (pos.x < axes.xaxis.min || pos.x > axes.xaxis.max ||
                pos.y < axes.yaxis.min || pos.y > axes.yaxis.max)
                return;

            var posIndex = 0;
            for (serieskey in that.datasets) { // Find first and best series that we got
                var series = that.datasets[serieskey]['data'];
                for (key in series) {
                    if (series[key][0] >= pos.x) {
                        var posIndex = key;
                        break;
                    }
                }
                break;
            }
            if (posIndex <= 0)  // No index found
                return;

            // Move marker to current pos
            if (Mapper.map != null || Mapper.posLayer != undefined) {
                var route_lon = that.datasets['lon'];
                var route_lat = that.datasets['lat'];
                if (route_lon.length >= posIndex) {
                    var x = route_lon[posIndex];
                    var y = route_lat[posIndex];
                    if (!this.posFeature) {
                        this.posFeature = Mapper.createFeature(Mapper.posLayer, x, y, 0);
                    }
                    // Mapper.updatePosMarker(x, y);
                    Mapper.moveFeature(this.posFeature, x, y, 0); // Hardcoded to 0 degrees
                }
            }

            var x = pos.x;
            var highlightedseries = null;
            if (item)
                highlightedseries = item.series.label;

            var tooltipHtml = '
Data at ' + that.xaxisformatter(x, plot.getAxes().xaxis) + '

';
            for (skey in that.datasets) {
                if (skey == 'lon' || skey == 'lat')
                    continue;
                var series = that.datasets[skey];
                var label = series['label'];
                var tickFormatter = axisformatters[skey];
                if (skey == 'poweravg30s')
                    tickFormatter = axisformatters['power'];
                var val = series['data'][posIndex][1]; // Must fetch this from datasets rather thatn the graph data itself because of multiple treshold splits up the indexes
                if(tickFormatter != undefined)
                    val = tickFormatter(val, plot.getAxes().xaxis);
                var color = plot.getOptions().colors[series['color']];
                if(label == highlightedseries) // Highlight if item selected
                    skey += ' selected'
                tooltipHtml += '
' + label + ': ' + val + '
';
            }
            tooltipHtml += '
';
            that.showTooltip(pos.pageX, pos.pageY, tooltipHtml);

        });
        $("#exercisegraph").bind("plotclick", function (event, pos, item) {
            if (item) {
                plot.highlight(item.series, item.datapoint);
            }
            // reset zoom on click
            that.setRange({});
            that.plot();
        });

        $("#exercisegraph").bind("plotselected", function (event, ranges) {
            that.setRange(ranges);
            that.plot();
        });
    }
};

<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { connect } from 'react-redux';

import { renderPreview } from '../actions/index';

const mapStateToProps = (state, ownProps) => {
	let { preview, previewLoading, selectedComponent } = state;

	let { cssPath, htmlPath } = preview;

	return {
		cssPath,
		htmlPath,
		previewLoading,
		selectedComponent
	};
};

const mapDispatchToProps = (dispatch, ownProps) => {
	return {
		dispatch,
		onLoaded: () => {
			dispatch({
				loading: false,
				type: 'SET_PREVIEW_LOADING'
			});
		}
	}
};

class PreviewBox extends Component {
	componentDidMount() {
		const { dispatch, selectedComponent } = this.props;

		dispatch(renderPreview(selectedComponent));

		this.refs.webview.addEventListener('did-stop-loading', () => {
			setTimeout(() => {
				this.props.onLoaded();
			}, 100);
		});
	}

	componentWillReceiveProps() {
		let { cssPath } = this.props;

		let scriptString = `
			var lexiconStylesheetLink = document.getElementById('lexiconStylesheetLink');
			var lexiconStylesheetLinkHREF = lexiconStylesheetLink.getAttribute('href');

			if (lexiconStylesheetLinkHREF != '${cssPath}') {
				lexiconStylesheetLink.setAttribute('href', '${cssPath}')
			};
		`;

		this.refs.webview.executeJavaScript(scriptString);
	}

	render() {
		let previewLoadingMask = this.props.previewLoading ? this.renderPreviewLoadingMask(): '';

		return (

				<webview autosize="on" id="webview" maxWidth="100%" ref="webview" src={this.props.htmlPath}></webview>

				{previewLoadingMask}

		);
	}

	renderPreviewLoadingMask() {
		return (

		);
	}
}

export default connect(mapStateToProps, mapDispatchToProps)(PreviewBox);
<commit_msg>Use next props<commit_after>import React, { Component } from 'react';
import { connect } from 'react-redux';

import { renderPreview } from '../actions/index';

const mapStateToProps = (state, ownProps) => {
	let { preview, previewLoading, selectedComponent } = state;

	let { cssPath, htmlPath } = preview;

	return {
		cssPath,
		htmlPath,
		previewLoading,
		selectedComponent
	};
};

const mapDispatchToProps = (dispatch, ownProps) => {
	return {
		dispatch,
		onLoaded: () => {
			dispatch({
				loading: false,
				type: 'SET_PREVIEW_LOADING'
			});
		}
	}
};

class PreviewBox extends Component {
	componentDidMount() {
		const { dispatch, selectedComponent } = this.props;

		dispatch(renderPreview(selectedComponent));

		this.refs.webview.addEventListener('did-stop-loading', () => {
			setTimeout(() => {
				this.props.onLoaded();
			}, 100);
		});
	}

	componentWillReceiveProps({ cssPath }) {
		let scriptString = `
			var lexiconStylesheetLink = document.getElementById('lexiconStylesheetLink');
			var lexiconStylesheetLinkHREF = lexiconStylesheetLink.getAttribute('href');

			if (lexiconStylesheetLinkHREF != '${cssPath}') {
				lexiconStylesheetLink.setAttribute('href', '${cssPath}')
			};
		`;

		this.refs.webview.executeJavaScript(scriptString);
	}

	render() {
		let previewLoadingMask = this.props.previewLoading ? this.renderPreviewLoadingMask(): '';

		return (

				<webview autosize="on" id="webview" maxWidth="100%" ref="webview" src={this.props.htmlPath}></webview>

				{previewLoadingMask}

		);
	}

	renderPreviewLoadingMask() {
		return (

		);
	}
}

export default connect(mapStateToProps, mapDispatchToProps)(PreviewBox);
<|endoftext|>


<commit_before>const fetch = require('node-fetch');
// eslint-disable-next-line import/no-unresolved
const credentials = require('./credentials');

const API_KEY = credentials.google_api_key;
const API_URL = 'https://www.googleapis.com/pagespeedonline/v1/runPagespeed?';

/**
 * @param {string} url The URL to run the Page Speed tests on.
 * @param {boolean} mobile Run the test as a mobile client.
 * @return {Promise<{ domains: number | null, requests: number | null, bytes: number | null, screenshot: string | null }>}
 */
function callPageSpeed(url, mobile) {
  const query = [`url=${encodeURIComponent(url)}`,
    'screenshot=true',
    `strategy=${mobile ? 'mobile' : 'desktop'}`,
    `key=${API_KEY}`,
  ].join('&');

  return fetch(API_URL + query, { method: 'get' }).then(response => Promise.all([response.ok, response.json()])).then(([ok, data]) => {
    if (!ok) {
      throw new Error(data.error.errors[0].message);
    }
    return data;
  }).then(({ pageStats, screenshot }) => {
    const domains = pageStats.numberHosts || 0;
    const requests = pageStats.numberResources || 0;

    let bytes = parseInt(pageStats.htmlResponseBytes, 10) || 0;
    bytes += parseInt(pageStats.cssResponseBytes, 10) || 0;
    bytes += parseInt(pageStats.imageResponseBytes, 10) || 0;
    bytes += parseInt(pageStats.javascriptResponseBytes, 10) || 0;
    bytes += parseInt(pageStats.otherResponseBytes, 10) || 0;

    return {
      domains, requests, bytes, screenshot,
    };
  });
}

exports.get = function get(db, req, res) {
  return callPageSpeed(req.query.url, req.query.mobile === 'mobile').then(results => res.send(results));
};

exports.callPageSpeed = callPageSpeed;
<commit_msg>Another fix for pagespeed mobile run<commit_after>const fetch = require('node-fetch');
// eslint-disable-next-line import/no-unresolved
const credentials = require('./credentials');

const API_KEY = credentials.google_api_key;
const API_URL = 'https://www.googleapis.com/pagespeedonline/v1/runPagespeed?';

/**
 * @param {string} url The URL to run the Page Speed tests on.
 * @param {boolean} mobile Run the test as a mobile client.
 * @return {Promise<{ domains: number | null, requests: number | null, bytes: number | null, screenshot: string | null }>}
 */
function callPageSpeed(url, mobile) {
  const query = [`url=${encodeURIComponent(url)}`,
    'screenshot=true',
    `strategy=${mobile ? 'mobile' : 'desktop'}`,
    `key=${API_KEY}`,
  ].join('&');

  return fetch(API_URL + query, { method: 'get' }).then(response => Promise.all([response.ok, response.json()])).then(([ok, data]) => {
    if (!ok) {
      throw new Error(data.error.errors[0].message);
    }
    return data;
  }).then(({ pageStats, screenshot }) => {
    const domains = pageStats.numberHosts || 0;
    const requests = pageStats.numberResources || 0;

    let bytes = parseInt(pageStats.htmlResponseBytes, 10) || 0;
    bytes += parseInt(pageStats.cssResponseBytes, 10) || 0;
    bytes += parseInt(pageStats.imageResponseBytes, 10) || 0;
    bytes += parseInt(pageStats.javascriptResponseBytes, 10) || 0;
    bytes += parseInt(pageStats.otherResponseBytes, 10) || 0;

    return {
      domains, requests, bytes, screenshot,
    };
  });
}

exports.get = function get(db, req, res) {
  return callPageSpeed(req.query.url, req.query.mobile === 'true').then(results => res.send(results));
};

exports.callPageSpeed = callPageSpeed;
<|endoftext|>


<commit_before>'use strict'

var thisMonth = require('../data/this-month.json')

function speakerSelectors (speaker) {
  return {
    '.name': speaker.name,
    '.title': speaker.title,
    '.desc': speaker.description,
    img: {
      src: speaker.img
    },
    '.lnug-twitterhandle a': {
      href: 'https://github.com/' + speaker.handle
    }
  }
}
var sortByTitle = function(a, b) {
  if(a.title < b.title) return -1;
  if(a.title > b.title) return 1;
  return 0;
}

module.exports = function (callback) {
  return thisMonth.sort(sortByTitle).map(speakerSelectors)
}
<commit_msg>set speaker url<commit_after>'use strict'

var thisMonth = require('../data/this-month.json')

function speakerSelectors (speaker) {

  var speakerUrl

  if (speaker.speakerUrl) {
    speakerUrl = speaker.speakerUrl
  } else {
    speakerUrl = 'https://github.com/' + speaker.handle
  }

  return {
    '.name': speaker.name,
    '.title': speaker.title,
    '.desc': speaker.description,
    img: {
      src: speaker.img
    },
    '.lnug-twitterhandle a': {
      href: speakerUrl
    }
  }
}
var sortByTitle = function(a, b) {
  if(a.title < b.title) return -1;
  if(a.title > b.title) return 1;
  return 0;
}

module.exports = function (callback) {
  return thisMonth.sort(sortByTitle).map(speakerSelectors)
}
<|endoftext|>


<commit_before>/*!
 * ${copyright}
 */
sap.ui.define([
	"sap/ui/thirdparty/jquery",
	"sap/ui/core/Core",
	"sap/ui/core/Control",
	"sap/ui/integration/util/Manifest",
	"sap/base/Log",
	'sap/ui/model/json/JSONModel',
	"sap/ui/model/resource/ResourceModel",
	"sap/ui/integration/WidgetRenderer",
	"sap/ui/integration/library",
	"sap/base/util/LoaderExtensions",
	"sap/ui/core/ComponentContainer"
], function (
	jQuery,
	Core,
	Control,
	WidgetManifest,
	Log,
	JSONModel,
	ResourceModel,
	WidgetRenderer,
	library,
	LoaderExtensions,
	ComponentContainer
) {
	"use strict";

	var MANIFEST_PATHS = {
		APP_TYPE: "/sap.app/type",
		PARAMS: "/sap.widget/configuration/parameters"
	};

	/**
	 * Constructor for a new Widget.
	 *
	 * @param {string} [sId] ID for the new control, generated automatically if no ID is given
	 * @param {object} [mSettings] Initial settings for the new control
	 *
	 *
Overview

	 * Widgets is a wrapper for @see{sap.ui.core.ComponentContainer}. They are configured via an app descriptor manifest.json file.
	 * @extends sap.ui.core.Control
	 *
	 * @author SAP SE
	 * @version ${version}
	 * @constructor
	 * @since 1.70
	 * @alias sap.ui.integration.Widget
	 *
	 * @experimental since 1.70
	 *
	 */
	var Widget = Control.extend("sap.ui.integration.Widget", /** @lends sap.ui.integration.Widget.prototype */ {
		metadata: {
			library: "sap.ui.integration",
			properties: {

				/**
				 * The URL of the manifest or an object.
				 */
				manifest: {
					type: "any",
					defaultValue: ""
				},

				/**
				 * The parameters used in the manifest.
				 */
				parameters: {
					type: "object",
					defaultValue: null
				},
				/**
				 * The configuration used in the manifest within the sap.widget section
				 * This data will be merged on to of an already given manifest
				 */
				configuration: {
					type: "object"
				},
				/**
				 * Base URL
				 */
				baseUrl: {
					type: "string",
					defaultValue: ""
				}
			},
			aggregations: {

				/**
				 * Defines the content of the Widget.
				 */
				_content: {
					type: "sap.ui.core.Control",
					multiple: false,
					visibility : "hidden"
				}
			},
			events: {

				/**
				 * Fired when an action is triggered on the Widget.
				 */
				action: {
					parameters: {

						/**
						 * The action source.
						 */
						actionSource: {
							type: "sap.ui.core.Control"
						},

						/**
						 * The manifest parameters related to the triggered action.
						*/
						manifestParameters: {
							type: "object"
						}
					}
				}
			}
		},
		renderer: WidgetRenderer
	});

	/**
	 * Initialization hook.
	 * @private
	 */
	Widget.prototype.init = function () {
		this.setBusyIndicatorDelay(0);
	};

	/**
	 * Called on before rendering of the control.
	 * @private
	 */
	Widget.prototype.onBeforeRendering = function () {
		if (this._bApplyManifest) {
			this._bApplyManifest = false;
			var vManifest = this.getManifest();

			if (!vManifest) {
				// Destroy the manifest when null/undefined/empty string are passed
				this.destroyManifest();
			} else {
				this.createManifest(vManifest, this.getBaseUrl());
			}
		}
	};

	/**
	 * Called on destroying the control
	 * @private
	 */
	Widget.prototype.exit = function () {
		this.destroyManifest();
	};

	/**
	 * Destroys everything configured by the manifest.
	 */
	Widget.prototype.destroyManifest = function () {
		if (this._oWidgetManifest) {
			this._oWidgetManifest.destroy();
			this._oWidgetManifest = null;
		}

		this.destroyAggregation("_content");
	};

	Widget.prototype.setManifest = function (vValue) {
		this.setProperty("manifest", vValue);
		this._bApplyManifest = true;
		return this;
	};

	Widget.prototype.setParameters = function (vValue) {
		this.setProperty("parameters", vValue);
		this._bApplyManifest = true;
		return this;
	};

	/**
	 * Overwrites getter for Widget manifest.
	 *
	 * @public
	 * @returns {string|Object} Cloned of the parameters.
	 */
	Widget.prototype.getManifest = function () {
		var vValue = this.getProperty("manifest");
		if (vValue && typeof vValue === "object") {
			return jQuery.extend(true, {}, vValue);
		}
		return vValue;
	};

	/**
	 * Instantiates a Widget Manifest.
	 *
	 * @param {Object|string} vManifest The manifest URL or the manifest JSON.
	 * @param {string} sBaseUrl The base URL of the manifest.
	 */
	Widget.prototype.createManifest = function (vManifest, sBaseUrl) {
		var mOptions = {};
		if (typeof vManifest === "string") {
			mOptions.manifestUrl = vManifest;
			vManifest = null;
		}

		this.setBusy(true);
		this._oWidgetManifest = new WidgetManifest("sap.widget", vManifest, sBaseUrl);
		this._oWidgetManifest
			.load(mOptions)
			.then(this._applyManifest.bind(this))
			.catch(this._applyManifest.bind(this));
	};

	/**
	 * Overwrites setter for Widget settings.
	 *
	 * @public
	 * @param {Object} vValue Settings to set in the Widget trough parameters property.
	 * @returns {sap.ui.integration.widgets.Widget} Pointer to the control instance to allow method chaining.
	 */
	Widget.prototype.setConfiguration = function (vValue) {
		this._bApplyManifest = true;
		this.setBusy(true);
		this.setProperty("configuration", vValue);
		return this;
	};

	/**
	 * Overwrites getter for Widget parameters.
	 *
	 * @public
	 * @returns {Object} A Clone of the parameters.
	 */
	Widget.prototype.getParameters = function () {
		var vValue = this.getProperty("parameters");
		if (vValue && typeof vValue === "object") {
			return jQuery.extend(true, {}, vValue);
		}
		return vValue;
	};

	/**
	 * Prepares the manifest and applies all settings.
	 */
	Widget.prototype._applyManifest = function () {
		var oParameters = this.getParameters(),
			sAppType = this._oWidgetManifest.get(MANIFEST_PATHS.APP_TYPE),
			//in case the manifest is passed as url we need to register the module path
			oConfiguration = this.getConfiguration();

		if (sAppType && sAppType !== "widget") {
			Log.error("sap.app/type entry in manifest is not 'widget'");
		}

		this._oWidgetManifest._mergeConfiguration(oConfiguration);
		this._createComponent(this._oWidgetManifest.getJson());
		this._registerManifestModulePath();
		this._oWidgetManifest.processParameters(oParameters);
	};

	/**
	 * Registers the manifest ID as a module path.
	 */
	Widget.prototype._registerManifestModulePath = function () {
		if (!this._oWidgetManifest) {
			return;
		}

		var sAppId = this._oWidgetManifest.get("/sap.app/id");
		if (sAppId) {
			LoaderExtensions.registerResourcePath(sAppId.replace(/\./g, "/"), this._oWidgetManifest.getUrl());
		} else {
			Log.error("Widget sap.app/id entry in the manifest is mandatory");
		}
	};

	/**
	 * Creates component container for Widget
	 *
	 * @param {Object} oManifest Manifest that is needed to create the component.
	 * @private
	 */
	Widget.prototype._createComponent = function (oManifest) {
			var oComponent = new ComponentContainer({
				manifest: oManifest,
				async: true,
				componentCreated: function (oEvent) {
					var oComponent = oEvent.getParameter("component");
					this.setBusy(false);
					oComponent.attachEvent("action", function (oEvent) {
						this.fireEvent("action", {
							actionSource: oEvent.getParameter("actionSource"),
							manifestParameters: oEvent.getParameter("manifestParameters")
						});
					}.bind(this));
				}.bind(this),
				componentFailed: function (oEvent) {
					this.setBusy(false);
					Log.error(oEvent.getParameter("reason"));
				}
			});

			this.setAggregation("_content", oComponent);
	};

	/**
	 * Loads the module designtime/Widget.designtime or the module given in
	 * "sap.widget": {
	 *    "designtime": "designtime/Own.designtime"
	 * }
	 * This file should contain the designtime configuration for the widget.
	 *
	 * Returns a promise that resolves with an object
	 * {
	 *    configuration: the current configuration
	 *    designtime: the designtime modules responce
	 *    manifest: the complete manifest json
	 * }
	 * The promise is rejected if the module cannot be loaded with an object:
	 * {
	 *     error: "Widget.designtime not found"
	 * }
	 *
	 * @returns {Promise} Promise resolves after the designtime configuration is loaded.
	 */
	Widget.prototype.loadDesigntime = function() {
		return new Promise(function(resolve, reject) {
			//build the module path to load as part of the widgets module path
			var sModule = this._sModulePath + "/" + (this._oWidgetManifest.get("/sap.widget/designtime") || "designtime/Widget.designtime");
			if (sModule) {
				sap.ui.require([sModule], function(oDesigntime) {
					//successfully loaded
					resolve({
						configuration: this._oWidgetManifest.get("/sap.widget"),
						designtime: oDesigntime,
						manifest: this._oWidgetManifest.oJson
					});
				}.bind(this), function () {
					//error
					reject({
						error: sModule + " not found"
					});
				});
			} else {
				reject();
			}
		}.bind(this));
	};

	return Widget;
});
<commit_msg>[INTERNAL][FIX] sap.ui.integration.Widget: Design time loading improved<commit_after>/*!
 * ${copyright}
 */
sap.ui.define([
	"sap/ui/thirdparty/jquery",
	"sap/ui/core/Core",
	"sap/ui/core/Control",
	"sap/ui/integration/util/Manifest",
	"sap/base/Log",
	'sap/ui/model/json/JSONModel',
	"sap/ui/model/resource/ResourceModel",
	"sap/ui/integration/WidgetRenderer",
	"sap/ui/integration/library",
	"sap/base/util/LoaderExtensions",
	"sap/ui/core/ComponentContainer"
], function (
	jQuery,
	Core,
	Control,
	WidgetManifest,
	Log,
	JSONModel,
	ResourceModel,
	WidgetRenderer,
	library,
	LoaderExtensions,
	ComponentContainer
) {
	"use strict";

	var MANIFEST_PATHS = {
		APP_TYPE: "/sap.app/type",
		PARAMS: "/sap.widget/configuration/parameters"
	};

	/**
	 * Constructor for a new Widget.
	 *
	 * @param {string} [sId] ID for the new control, generated automatically if no ID is given
	 * @param {object} [mSettings] Initial settings for the new control
	 *
	 *
Overview

	 * Widgets is a wrapper for @see{sap.ui.core.ComponentContainer}. They are configured via an app descriptor manifest.json file.
	 * @extends sap.ui.core.Control
	 *
	 * @author SAP SE
	 * @version ${version}
	 * @constructor
	 * @since 1.70
	 * @alias sap.ui.integration.Widget
	 *
	 * @experimental since 1.70
	 *
	 */
	var Widget = Control.extend("sap.ui.integration.Widget", /** @lends sap.ui.integration.Widget.prototype */ {
		metadata: {
			library: "sap.ui.integration",
			properties: {

				/**
				 * The URL of the manifest or an object.
				 */
				manifest: {
					type: "any",
					defaultValue: ""
				},

				/**
				 * The parameters used in the manifest.
				 */
				parameters: {
					type: "object",
					defaultValue: null
				},
				/**
				 * The configuration used in the manifest within the sap.widget section
				 * This data will be merged on to of an already given manifest
				 */
				configuration: {
					type: "object"
				},
				/**
				 * Base URL
				 */
				baseUrl: {
					type: "string",
					defaultValue: ""
				}
			},
			aggregations: {

				/**
				 * Defines the content of the Widget.
				 */
				_content: {
					type: "sap.ui.core.Control",
					multiple: false,
					visibility : "hidden"
				}
			},
			events: {

				/**
				 * Fired when an action is triggered on the Widget.
				 */
				action: {
					parameters: {

						/**
						 * The action source.
						 */
						actionSource: {
							type: "sap.ui.core.Control"
						},

						/**
						 * The manifest parameters related to the triggered action.
						*/
						manifestParameters: {
							type: "object"
						}
					}
				}
			}
		},
		renderer: WidgetRenderer
	});

	/**
	 * Initialization hook.
	 * @private
	 */
	Widget.prototype.init = function () {
		this.setBusyIndicatorDelay(0);
	};

	/**
	 * Called on before rendering of the control.
	 * @private
	 */
	Widget.prototype.onBeforeRendering = function () {
		if (this._bApplyManifest) {
			this._bApplyManifest = false;
			var vManifest = this.getManifest();

			if (!vManifest) {
				// Destroy the manifest when null/undefined/empty string are passed
				this.destroyManifest();
			} else {
				this.createManifest(vManifest, this.getBaseUrl());
			}
		}
	};

	/**
	 * Called on destroying the control
	 * @private
	 */
	Widget.prototype.exit = function () {
		this.destroyManifest();
	};

	/**
	 * Destroys everything configured by the manifest.
	 */
	Widget.prototype.destroyManifest = function () {
		if (this._oWidgetManifest) {
			this._oWidgetManifest.destroy();
			this._oWidgetManifest = null;
		}

		this.destroyAggregation("_content");
	};

	Widget.prototype.setManifest = function (vValue) {
		this.setProperty("manifest", vValue);
		this._bApplyManifest = true;
		return this;
	};

	Widget.prototype.setParameters = function (vValue) {
		this.setProperty("parameters", vValue);
		this._bApplyManifest = true;
		return this;
	};

	/**
	 * Overwrites getter for Widget manifest.
	 *
	 * @public
	 * @returns {string|Object} Cloned of the parameters.
	 */
	Widget.prototype.getManifest = function () {
		var vValue = this.getProperty("manifest");
		if (vValue && typeof vValue === "object") {
			return jQuery.extend(true, {}, vValue);
		}
		return vValue;
	};

	/**
	 * Instantiates a Widget Manifest.
	 *
	 * @param {Object|string} vManifest The manifest URL or the manifest JSON.
	 * @param {string} sBaseUrl The base URL of the manifest.
	 */
	Widget.prototype.createManifest = function (vManifest, sBaseUrl) {
		var mOptions = {};
		if (typeof vManifest === "string") {
			mOptions.manifestUrl = vManifest;
			vManifest = null;
		}

		this.setBusy(true);
		this._oWidgetManifest = new WidgetManifest("sap.widget", vManifest, sBaseUrl);
		this._oWidgetManifest
			.load(mOptions)
			.then(this._applyManifest.bind(this))
			.catch(this._applyManifest.bind(this));
	};

	/**
	 * Overwrites setter for Widget settings.
	 *
	 * @public
	 * @param {Object} vValue Settings to set in the Widget trough parameters property.
	 * @returns {sap.ui.integration.widgets.Widget} Pointer to the control instance to allow method chaining.
	 */
	Widget.prototype.setConfiguration = function (vValue) {
		this._bApplyManifest = true;
		this.setBusy(true);
		this.setProperty("configuration", vValue);
		return this;
	};

	/**
	 * Overwrites getter for Widget parameters.
	 *
	 * @public
	 * @returns {Object} A Clone of the parameters.
	 */
	Widget.prototype.getParameters = function () {
		var vValue = this.getProperty("parameters");
		if (vValue && typeof vValue === "object") {
			return jQuery.extend(true, {}, vValue);
		}
		return vValue;
	};

	/**
	 * Prepares the manifest and applies all settings.
	 */
	Widget.prototype._applyManifest = function () {
		var oParameters = this.getParameters(),
			sAppType = this._oWidgetManifest.get(MANIFEST_PATHS.APP_TYPE),
			//in case the manifest is passed as url we need to register the module path
			oConfiguration = this.getConfiguration();

		if (sAppType && sAppType !== "widget") {
			Log.error("sap.app/type entry in manifest is not 'widget'");
		}

		this._oWidgetManifest._mergeConfiguration(oConfiguration);
		this._createComponent(this._oWidgetManifest.getJson());
		this._registerManifestModulePath();
		this._oWidgetManifest.processParameters(oParameters);
	};

	/**
	 * Registers the manifest ID as a module path.
	 */
	Widget.prototype._registerManifestModulePath = function () {
		if (!this._oWidgetManifest) {
			return;
		}

		var sAppId = this._oWidgetManifest.get("/sap.app/id");
		if (sAppId) {
			LoaderExtensions.registerResourcePath(sAppId.replace(/\./g, "/"), this._oWidgetManifest.getUrl());
		} else {
			Log.error("Widget sap.app/id entry in the manifest is mandatory");
		}
	};

	/**
	 * Creates component container for Widget
	 *
	 * @param {Object} oManifest Manifest that is needed to create the component.
	 * @private
	 */
	Widget.prototype._createComponent = function (oManifest) {
			var oComponent = new ComponentContainer({
				manifest: oManifest,
				async: true,
				componentCreated: function (oEvent) {
					var oComponent = oEvent.getParameter("component");
					this.setBusy(false);
					oComponent.attachEvent("action", function (oEvent) {
						this.fireEvent("action", {
							actionSource: oEvent.getParameter("actionSource"),
							manifestParameters: oEvent.getParameter("manifestParameters")
						});
					}.bind(this));
				}.bind(this),
				componentFailed: function (oEvent) {
					this.setBusy(false);
					Log.error(oEvent.getParameter("reason"));
				}
			});

			this.setAggregation("_content", oComponent);
	};

	/**
	 * Loads the module designtime/Widget.designtime or the module given in
	 * "sap.widget": {
	 *    "designtime": "designtime/Own.designtime"
	 * }
	 * This file should contain the designtime configuration for the widget.
	 *
	 * Returns a promise that resolves with an object
	 * {
	 *    configuration: the current configuration
	 *    designtime: the designtime modules responce
	 *    manifest: the complete manifest json
	 * }
	 * The promise is rejected if the module cannot be loaded with an object:
	 * {
	 *     error: "Widget.designtime not found"
	 * }
	 *
	 * @returns {Promise} Promise resolves after the designtime configuration is loaded.
	 */
	Widget.prototype.loadDesigntime = function() {
		if (!this._oWidgetManifest) {
			return Promise.reject("Manifest not yet available");
		}
		var sAppId = this._oWidgetManifest.get("/sap.app/id");
		if (!sAppId) {
			return Promise.reject("App id not maintained");
		}
		var sModulePath = sAppId.replace(/\./g,"/");
		return new Promise(function(resolve, reject) {
			//build the module path to load as part of the widgets module path
			var sModule = sModulePath + "/" + (this._oWidgetManifest.get("/sap.widget/designtime") || "designtime/Widget.designtime");
			if (sModule) {
				sap.ui.require([sModule, "sap/base/util/deepClone"], function(oDesigntime, deepClone) {
					//successfully loaded
					resolve({
						configuration: deepClone(this._oWidgetManifest.get("/sap.widget"), 30),
						designtime: oDesigntime,
						manifest: deepClone(this._oWidgetManifest.oJson, 30)
					});
				}.bind(this), function () {
					//error
					reject({
						error: sModule + " not found"
					});
				});
			} else {
				reject();
			}
		}.bind(this));
	};

	return Widget;
});
<|endoftext|>


<commit_before>/**
 * Class for handeling graph plotting of pulse data.
 * Still needs loads of work and is only a cut/paste from template for now
 */
var plot;
var GraphPlotter = {
    choiceContainer: null,
    datasets: null,
    backendUrl: null,
    max_hr: 200,
    formatters: {
            speed: function(val, axis) {
                return (val / 1000).toFixed(axis.tickDecimals) + ' km/h';
            },
            altitude: function(val, axis) {
                return (val / 1000).toFixed(axis.tickDecimals) + ' m';
            },
            length: function(val, axis) {
                return (val).toFixed(axis.tickDecimals) + ' km';
            },
            time: function(val, axis) {
                var hours = Math.floor(val / 60);
                var minutes = val;

                if (hours)
                        return hours + 'h ' + minutes + 'm';
                return minutes + 'm';
            }

    },

    plotAccordingToChoices: function(ranges) {
        data = [];
        var that = this;
        var minIndex = null;
        var maxIndex = null;
        var min = null;
        var max = null;
        var xaxisattrs = {
            tickDecimals: 0,
            tickFormatter: this.xaxisformatter
        };
        if (ranges.xaxis != undefined) {
            var xaxe = plot.getXAxes()[0];
            min = ranges.xaxis.from;
            max = ranges.xaxis.to;
            xaxisattrs.min = min;
            xaxisattrs.max = max;

            for (k in this.datasets.index) {
                if (min >= this.datasets.index[k])
                    minIndex = k;
                if (max <= this.datasets.index[k]) {
                    maxIndex = k;
                    break;
                }
            }
        }
        $("#choices").find("input:checked").each(function () {
            var key = $(this).attr("name");
            if (key && that.datasets[key])
                data.push(that.datasets[key]);
        });

        if (data.length > 0) {
            plot = $.plot($("#tripdiv"), data, {
                yaxes: [{ min: 0 }, { position: "right", min: 80, max: this.max_hr }, { position: "right"}],
                xaxis: xaxisattrs,
                legend: { container: $("#tripdiv_legend") },
                grid: {
                    hoverable: true,
                    clickable: true,
                },
                selection: { mode: "x" }
            });
        }

        if (minIndex != null && maxIndex != null) {
            if (typeof(Mapper) != "undefined")
                Mapper.loadGeoJSON(minIndex, maxIndex);
            $.getJSON(this.backendUrl, { start: minIndex, stop: maxIndex }, function (avgs) {
                var items = $("#averages ul .data");
                $("#averages h4").removeClass("hidden");

                $.each(items, function (i, elem) {
                    var classlist = elem.className.split(" ");
                    for (k in classlist) {
                        if (classlist[k] in avgs) {
                            var key = classlist[k];
                            var e = $(elem);
                            var val = Math.round(avgs[key] * 10) / 10;
                            e.text(val);
                            e.parents(".hidden").removeClass("hidden");
                        }
                    }
                });
            });
        }
        else {
            if (typeof(Mapper) != "undefined")
                Mapper.loadGeoJSON(0, 0);
            $("#averages ul li").addClass("hidden");
            $("#averages h4").addClass("hidden");
        }

    },
    showTooltip: function (x, y, contents) {
        $('
' + contents + '
').css( {
            position: 'absolute',
            display: 'none',
            top: y + 5,
            left: x + 5,
            border: '1px solid #fdd',
            padding: '2px',
            'background-color': '#fee',
            opacity: 0.80
        }).appendTo("body").fadeIn(200);
    },
    init: function(args) {
        this.datasets = args.datasets;
        var backendUrl = args.backendUrl;
        this.max_hr = args.max_hr;
        this.xaxisformatter = this.formatters[args.xaxisformatter];

        var that = this;
        this.backendUrl = backendUrl;
        this.choiceContainer = $("#choices");

        $.each(this.datasets, function(key, val) {
            if (key != "index")
                that.choiceContainer.append('<input type="checkbox" name="' + key +
                    '" checked="checked" id="chk_' + key + '">' + val.label + '</input>');
        });
        this.choiceContainer.append('<input type="reset" value="Reset zoom" />');
        this.choiceContainer.find("input").bind("click", function(evt) {
                that.plotAccordingToChoices({});
        });
        this.plotAccordingToChoices({});
        var previousPoint = null;
        $("#tripdiv").bind("plothover", function (event, pos, item) {
            if (item) {
                // Move marker to current pos
                if (typeof(Mapper) != "undefined") {
                    var x = route_points[item.dataIndex].x;
                    var y = route_points[item.dataIndex].y;
                    Mapper.updatePosMarker(x, y);
                }

                if (previousPoint != item.datapoint) {
                    previousPoint = item.datapoint;

                    $("#tooltip").remove();
                    var x = item.datapoint[0].toFixed(2),
                        y = item.datapoint[1].toFixed(2);

                    that.showTooltip(item.pageX, item.pageY,
                    item.series.label + " at " + x + " is " + y);

                }
            }
            else {
                $("#tooltip").remove();
                previousPoint = null;
            }
        });

        $("#tripdiv").bind("plotclick", function (event, pos, item) {
            if (item) {
                $("#clickdata").text("You clicked point " + item.dataIndex + " in " + item.series.label + ".");
                plot.highlight(item.series, item.datapoint);
            }
        });

        $("#tripdiv").bind("plotselected", function (event, ranges) {
            that.plotAccordingToChoices(ranges);
        });
    }
};

<commit_msg>deactive broken position code for now<commit_after>/**
 * Class for handeling graph plotting of pulse data.
 * Still needs loads of work and is only a cut/paste from template for now
 */
var plot;
var GraphPlotter = {
    choiceContainer: null,
    datasets: null,
    backendUrl: null,
    max_hr: 200,
    formatters: {
            speed: function(val, axis) {
                return (val / 1000).toFixed(axis.tickDecimals) + ' km/h';
            },
            altitude: function(val, axis) {
                return (val / 1000).toFixed(axis.tickDecimals) + ' m';
            },
            length: function(val, axis) {
                return (val).toFixed(axis.tickDecimals) + ' km';
            },
            time: function(val, axis) {
                var hours = Math.floor(val / 60);
                var minutes = val;

                if (hours)
                        return hours + 'h ' + minutes + 'm';
                return minutes + 'm';
            }

    },

    plotAccordingToChoices: function(ranges) {
        data = [];
        var that = this;
        var minIndex = null;
        var maxIndex = null;
        var min = null;
        var max = null;
        var xaxisattrs = {
            tickDecimals: 0,
            tickFormatter: this.xaxisformatter
        };
        if (ranges.xaxis != undefined) {
            var xaxe = plot.getXAxes()[0];
            min = ranges.xaxis.from;
            max = ranges.xaxis.to;
            xaxisattrs.min = min;
            xaxisattrs.max = max;

            for (k in this.datasets.index) {
                if (min >= this.datasets.index[k])
                    minIndex = k;
                if (max <= this.datasets.index[k]) {
                    maxIndex = k;
                    break;
                }
            }
        }
        $("#choices").find("input:checked").each(function () {
            var key = $(this).attr("name");
            if (key && that.datasets[key])
                data.push(that.datasets[key]);
        });

        if (data.length > 0) {
            plot = $.plot($("#tripdiv"), data, {
                yaxes: [{ min: 0 }, { position: "right", min: 80, max: this.max_hr }, { position: "right"}],
                xaxis: xaxisattrs,
                legend: { container: $("#tripdiv_legend") },
                grid: {
                    hoverable: true,
                    clickable: true,
                },
                selection: { mode: "x" }
            });
        }

        if (minIndex != null && maxIndex != null) {
            if (typeof(Mapper) != "undefined")
                Mapper.loadGeoJSON(minIndex, maxIndex);
            $.getJSON(this.backendUrl, { start: minIndex, stop: maxIndex }, function (avgs) {
                var items = $("#averages ul .data");
                $("#averages h4").removeClass("hidden");

                $.each(items, function (i, elem) {
                    var classlist = elem.className.split(" ");
                    for (k in classlist) {
                        if (classlist[k] in avgs) {
                            var key = classlist[k];
                            var e = $(elem);
                            var val = Math.round(avgs[key] * 10) / 10;
                            e.text(val);
                            e.parents(".hidden").removeClass("hidden");
                        }
                    }
                });
            });
        }
        else {
            if (typeof(Mapper) != "undefined")
                Mapper.loadGeoJSON(0, 0);
            $("#averages ul li").addClass("hidden");
            $("#averages h4").addClass("hidden");
        }

    },
    showTooltip: function (x, y, contents) {
        $('
' + contents + '
').css( {
            position: 'absolute',
            display: 'none',
            top: y + 5,
            left: x + 5,
            border: '1px solid #fdd',
            padding: '2px',
            'background-color': '#fee',
            opacity: 0.80
        }).appendTo("body").fadeIn(200);
    },
    init: function(args) {
        this.datasets = args.datasets;
        var backendUrl = args.backendUrl;
        this.max_hr = args.max_hr;
        this.xaxisformatter = this.formatters[args.xaxisformatter];

        var that = this;
        this.backendUrl = backendUrl;
        this.choiceContainer = $("#choices");

        $.each(this.datasets, function(key, val) {
            if (key != "index")
                that.choiceContainer.append('<input type="checkbox" name="' + key +
                    '" checked="checked" id="chk_' + key + '">' + val.label + '</input>');
        });
        this.choiceContainer.append('<input type="reset" value="Reset zoom" />');
        this.choiceContainer.find("input").bind("click", function(evt) {
                that.plotAccordingToChoices({});
        });
        this.plotAccordingToChoices({});
        var previousPoint = null;
        $("#tripdiv").bind("plothover", function (event, pos, item) {
            if (item) {
            /* FIXME
                // Move marker to current pos
                if (typeof(Mapper) != "undefined") {
                    var x = route_points[item.dataIndex].x;
                    var y = route_points[item.dataIndex].y;
                    Mapper.updatePosMarker(x, y);
                }
            */

                if (previousPoint != item.datapoint) {
                    previousPoint = item.datapoint;

                    $("#tooltip").remove();
                    var x = item.datapoint[0].toFixed(2),
                        y = item.datapoint[1].toFixed(2);

                    that.showTooltip(item.pageX, item.pageY,
                    item.series.label + " at " + x + " is " + y);

                }
            }
            else {
                $("#tooltip").remove();
                previousPoint = null;
            }
        });

        $("#tripdiv").bind("plotclick", function (event, pos, item) {
            if (item) {
                $("#clickdata").text("You clicked point " + item.dataIndex + " in " + item.series.label + ".");
                plot.highlight(item.series, item.datapoint);
            }
        });

        $("#tripdiv").bind("plotselected", function (event, ranges) {
            that.plotAccordingToChoices(ranges);
        });
    }
};

<|endoftext|>


<commit_before>var defaultTitle = 'This is ZenPen';
var defaultContent =
'
\
A minimalist writing zone, where you can block out all distractions and get to what\'s important. The writing!  \

\

 \
	To get started, all you need to do is delete this text (seriously, just highlight it and hit delete), and fill the page with your own fantastic words. You can even change the title!  \

 \

 \
	You can use bold, italics, both and  urls  just by highlighting the text and selecting them from the tiny options box that appears above it.\

\

\
	Quotes are easy to add too!\

\

\
	For questions and open source info, Click that little question mark at the bottom left of the screen.\

\

Happy Typing! ~ Tim Holman (@twholman)
';
<commit_msg>Added hyphen to 'bottom left'<commit_after>var defaultTitle = 'This is ZenPen';
var defaultContent =
'
\
A minimalist writing zone, where you can block out all distractions and get to what\'s important. The writing!  \

\

 \
	To get started, all you need to do is delete this text (seriously, just highlight it and hit delete), and fill the page with your own fantastic words. You can even change the title!  \

 \

 \
	You can use bold, italics, both and  urls  just by highlighting the text and selecting them from the tiny options box that appears above it.\

\

\
	Quotes are easy to add too!\

\

\
	For questions and open source info, Click that little question mark at the bottom-left of the screen.\

\

Happy Typing! ~ Tim Holman (@twholman)
';
<|endoftext|>


<commit_before>
function setEntityInclude() {
	var entityType = document.getElementById("entity.type").value;
	CompositionEntityManager.getEntityIncludePage(entityType, populatePage);
}
function populatePage(pageData) {
	dwr.util.setValue("entityInclude", pageData, {escapeHtml:false});
}

<commit_msg>update the element ID for the nanoparticle entity type select element.<commit_after>
function setEntityInclude() {
	var entityType = document.getElementById("peType").value;
	CompositionEntityManager.getEntityIncludePage(entityType, populatePage);
}
function populatePage(pageData) {
	dwr.util.setValue("entityInclude", pageData, {escapeHtml:false});
}

<|endoftext|>


<commit_before>const debug = require('debug')('sekshi:karma')
const assign = require('object-assign')
const { User, Karma } = require('../models')
const SekshiModule = require('../Module')
const moment = require('moment')
const utils = require('../utils')

export default class UserKarma extends SekshiModule {

  constructor(sekshi, options) {
    this.author = 'brookiebeast'
    this.version = '0.3.0'
    this.description = 'Keeps track of users\' earned internet points.'

    super(sekshi, options)

    this.permissions = {
      karma: sekshi.USERROLE.NONE,
      bump: sekshi.USERROLE.NONE,
      thump: sekshi.USERROLE.NONE,
      karmawhores: sekshi.USERROLE.NONE,
      bitch: sekshi.USERROLE.NONE,
      pimp: sekshi.USERROLE.NONE,
      fistbump: sekshi.USERROLE.NONE,
      fistthump: sekshi.USERROLE.NONE
    }
  }

  karma(user, username, time = 'w') {
    let self = false
    if (username && /(^[dwmf]$)|(^\d+$)/.test(username)) {
      self = true
      time = username
    }
    const since = utils.spanToTime(time)
    const hours = moment().diff(since, 'hours')
    const allTime = time === 'f'

    if (username && username.charAt(0) === '@') username = username.slice(1)
    if (!self && username) {
      User.findOne({ username }).exec()
      .then(usar => {
        if (!usar) {
          this.sekshi.sendChat(`@${user.username} I don't know ${username} yet`)
          return undefined
        }
        Karma.find({date: {"$gte": since.toDate()}, target:usar._id }).select('amount').exec().then(karmaList => {
          let karma = karmaList.reduce( (a, b) => { return a + b.amount }, 0)
          let msg = `@${user.username} ${username} has ${karma} karma`
          if (!allTime) msg += ` from the past ${utils.days(hours)}`
          this.sekshi.sendChat(`${msg}.`)
        }
        , err => {debug(err)})

        return usar
      })
    } else {
      User.findById(user.id).exec()
      .then(usar => {
        if (!usar) {
          this.sekshi.sendChat(`@${user.username} who are you?`)
          return undefined
        }
        Karma.find({date: {"$gte": since.toDate()}, target:usar._id }).select('amount').exec().then(karmaList => {
          let karma = karmaList.reduce( (a, b) => { return a + b.amount }, 0)
          let msg = `@${user.username} you have ${karma} karma`
          if (!allTime) msg += ` from the past ${utils.days(hours)}`
          this.sekshi.sendChat(`${msg}.`)
        }
        , err => {debug(err)})
        return usar
      })
    }
  }

  karmawhores(user, time = 'w') {
    // stole all this shit from !mostplayed in MediaStats
    const since = utils.spanToTime(time)
    const hours = moment().diff(since, 'hours')
    const allTime = time === 'f'

    Karma.aggregate()
    .match({ date: { $gte: since.toDate() } })
    .group({ _id: "$target", karma: { $sum: "$amount" } })
    .sort({ karma: -1 }).exec().then(karmaList => {
      if (karmaList.length === 0) {
        this.sekshi.sendChat(`@${user.username} none of you like each other T_T`)
      } else {
        let title = `@${user.username} Karma leaders`
        if (!allTime) title += ` over the last ${utils.days(hours)}`
        this.sekshi.sendChat(`${title}:`)
        let rank = 0
        let l = Math.min(karmaList.length, 5)
        for (let i = 0; i < l; ++i) {
          let karma = karmaList[i]['karma']
          User.findById(karmaList[i]['_id']).exec().then(usar => {
            this.sekshi.sendChat(`${++rank} - ${usar.username}: ${karma}`)
          })
        }
      }
    },
    err => {
      debug(`${err}`)
    })
  }

  bump(user, username, ...reason) {
    if (!username) {
      this.sekshi.sendChat(`@${user.username} You must provide a user to bump`)
      return
    }
    if (username.charAt(0) === '@') username = username.slice(1)
    let other = this.sekshi.getUserByName(username, true)
    if (!other) {
      this.sekshi.sendChat(`@${user.username} That's not a real person…`)
      return
    }
    if (other.id === user.id) {
      this.sekshi.sendChat(`@${user.username} Nice try, smartass!`)
      return
    }

    debug('karma bump', `${other.username} (${other.id})`)
    User.fromPlugUser(other).then(target => {
      if (target) {
        if (reason && reason.length > 0) {
          this.sekshi.sendChat(`@${user.username} bumped @${other.username}\'s karma ${reason.join(' ')}`)
        } else {
          this.sekshi.sendChat(`@${user.username} bumped @${other.username}\'s karma!`)
        }

        let bump = new Karma({ target: target.id, giver: user.id })
        if (reason && reason.length > 0)
          bump.reason = reason.join(' ')
        bump.save()

        return target
      }
    })
  }

  thump(user, username, ...reason) {
    if (!username) {
      debug('karma thump no username')
      this.sekshi.sendChat(`@${user.username} You must provide a user to thump`)
      return
    }
    if (username.charAt(0) === '@') username = username.slice(1)
    let other = this.sekshi.getUserByName(username, true)
    if (!other) {
      this.sekshi.sendChat(`@${user.username} That's not a real person…`)
      return
    }
    if (other.id === user.id) {
      this.sekshi.sendChat(`@${user.username} You\'re weird.`)
    }

    User.fromPlugUser(other).then(target => {
      if (target) {
        if (reason && reason.length > 0) {
          this.sekshi.sendChat(`@${user.username} thumped @${other.username}\'s karma ${reason.join(' ')}`)
        } else {
          this.sekshi.sendChat(`@${user.username} thumped @${other.username}\'s karma!`)
        }

        let thump = new Karma({ target: target.id, giver: user.id, amount: -1 })
        if (reason && reason.length > 0)
          thump.reason = reason.join(' ')
        thump.save()

        return target
      }
    })
  }

  bitch(user, time = 'w') {
    const since = utils.spanToTime(time)
    const hours = moment().diff(since, 'hours')
    const allTime = time === 'f'

    Karma.aggregate()
    .match({ target: user.id, date: { $gte: since.toDate() } })
    .group({ _id: "$giver", karma: { $sum: "$amount" } })
    .sort({ karma: -1 }).exec().then(karmaList => {
      if (karmaList.length === 0) {
        let msg = `@${user.username} you have no bitches`
        if (!allTime) msg += ` from the past ${utils.days(hours)}`
        this.sekshi.sendChat(`${msg}. :cry:`)
      } else {
        let karma = karmaList[0]['karma']
        User.findById(karmaList[0]['_id']).exec().then(usar => {
          let msg = `@${user.username}, ${usar.username} is your bitch. They gave you ${karma} karma`
          if (!allTime) msg += ` in the past ${utils.days(hours)}`
          this.sekshi.sendChat(`${msg}.`)
        })
      }
    },
    err => {
      debug(`${err}`)
    })
  }

  pimp(user, time = 'w') {
    const since = utils.spanToTime(time)
    const hours = moment().diff(since, 'hours')
    const allTime = time === 'f'

    Karma.aggregate()
    .match({ giver: user.id, date: { $gte: since.toDate() } })
    .group({ _id: "$target", karma: { $sum: "$amount" } })
    .sort({ karma: -1 }).exec().then(karmaList => {
      if (karmaList.length === 0) {
        let msg = `@${user.username} you have been noone's bitch`
        if (!allTime) msg += ` in the past ${utils.days(hours)}`
        this.sekshi.sendChat(`${msg}. :smirk:`)
      } else {
        let karma = karmaList[0]['karma']
        User.findById(karmaList[0]['_id']).exec().then(usar => {
          let msg = `@${user.username}, ${usar.username} is your pimp. You gave them ${karma} karma`
          if (!allTime) msg += ` in the past ${utils.days(hours)}`
          this.sekshi.sendChat(`${msg}.`)
        })
      }
    },
    err => {
      debug(`${err}`)
    })
  }

  fistbump(user) {
    Karma.find({ reason: { $ne: null } }).where('amount').gt(0).populate('giver').exec().then( reasonList => {
      let reason = ''
      if (reasonList.length > 0) {
        reason = ` "${reasonList[Math.floor(Math.random() * reasonList.length)]}"`
      }
      this.sekshi.sendChat(`@${user.username} you were bumped by @${chosen.giver.username}` +
                           `${reason} ${moment(chosen.date).fromNow()}`)
    })
  }

  fistthump(user) {
    Karma.find({ reason: { $ne: null } }).where('amount').lt(0).populate('giver').exec().then( reasonList => {
      let reason = ''
      if (reasonList.length > 0) {
        reason = ` "${reasonList[Math.floor(Math.random() * reasonList.length)]}"`
      }
      this.sekshi.sendChat(`@${user.username} you were thumped by @${chosen.giver.username}` +
                           `${reason} ${moment(chosen.date).fromNow()}`)
    })
  }
}<commit_msg>fix karmawhores sorting<commit_after>const debug = require('debug')('sekshi:karma')
const assign = require('object-assign')
const { User, Karma } = require('../models')
const SekshiModule = require('../Module')
const moment = require('moment')
const utils = require('../utils')

export default class UserKarma extends SekshiModule {

  constructor(sekshi, options) {
    this.author = 'brookiebeast'
    this.version = '0.4.0'
    this.description = 'Keeps track of users\' earned internet points.'

    super(sekshi, options)

    this.permissions = {
      karma: sekshi.USERROLE.NONE,
      bump: sekshi.USERROLE.NONE,
      thump: sekshi.USERROLE.NONE,
      karmawhores: sekshi.USERROLE.NONE,
      bitch: sekshi.USERROLE.NONE,
      pimp: sekshi.USERROLE.NONE,
      fistbump: sekshi.USERROLE.NONE,
      fistthump: sekshi.USERROLE.NONE
    }
  }

  karma(user, username, time = 'w') {
    let self = false
    if (username && /(^[dwmf]$)|(^\d+$)/.test(username)) {
      self = true
      time = username
    }
    const since = utils.spanToTime(time)
    const hours = moment().diff(since, 'hours')
    const allTime = time === 'f'

    if (username && username.charAt(0) === '@') username = username.slice(1)
    if (!self && username) {
      User.findOne({ username }).exec()
      .then(usar => {
        if (!usar) {
          this.sekshi.sendChat(`@${user.username} I don't know ${username} yet`)
          return undefined
        }
        Karma.find({date: {"$gte": since.toDate()}, target:usar._id }).select('amount').exec().then(karmaList => {
          let karma = karmaList.reduce( (a, b) => { return a + b.amount }, 0)
          let msg = `@${user.username} ${username} has ${karma} karma`
          if (!allTime) msg += ` from the past ${utils.days(hours)}`
          this.sekshi.sendChat(`${msg}.`)
        }
        , err => {debug(err)})

        return usar
      })
    } else {
      User.findById(user.id).exec()
      .then(usar => {
        if (!usar) {
          this.sekshi.sendChat(`@${user.username} who are you?`)
          return undefined
        }
        Karma.find({date: {"$gte": since.toDate()}, target:usar._id }).select('amount').exec().then(karmaList => {
          let karma = karmaList.reduce( (a, b) => { return a + b.amount }, 0)
          let msg = `@${user.username} you have ${karma} karma`
          if (!allTime) msg += ` from the past ${utils.days(hours)}`
          this.sekshi.sendChat(`${msg}.`)
        }
        , err => {debug(err)})
        return usar
      })
    }
  }

  karmawhores(user, time = 'w') {
    // stole all this shit from !mostplayed in MediaStats
    const since = utils.spanToTime(time)
    const hours = moment().diff(since, 'hours')
    const allTime = time === 'f'

    Karma.aggregate()
      .match({ date: { $gte: since.toDate() } })
      .group({ _id: "$target", karma: { $sum: "$amount" } })
      .sort({ karma: -1 })
      .limit(5)
      .exec()
      .then(karmaList => {
        if (karmaList.length === 0) {
          this.sekshi.sendChat(`@${user.username} none of you like each other T_T`)
        }
        else {
          let karmas = {}
          karmaList.forEach(k => { karmas[k._id] = k.karma })
          User.where('_id').in(karmaList.map(k => k._id)).lean().exec()
            .then(users => users.map(u => assign(u, { karma: karmas[u._id] })))
            .then(users => users.sort((a, b) => a.karma > b.karma ? -1 : 1))
            .then(
              users => {
                let title = `@${user.username} Karma leaders`
                if (!allTime) title += ` over the last ${utils.days(hours)}`
                this.sekshi.sendChat(`${title}:`)
                users.forEach((u, rank) => {
                  this.sekshi.sendChat(`${rank + 1} - ${u.username}: ${u.karma}`)
                })
              },
              err => {}
            )
        }
      },
      err => {
        debug(`${err}`)
      })
  }

  bump(user, username, ...reason) {
    if (!username) {
      this.sekshi.sendChat(`@${user.username} You must provide a user to bump`)
      return
    }
    if (username.charAt(0) === '@') username = username.slice(1)
    let other = this.sekshi.getUserByName(username, true)
    if (!other) {
      this.sekshi.sendChat(`@${user.username} That's not a real person…`)
      return
    }
    if (other.id === user.id) {
      this.sekshi.sendChat(`@${user.username} Nice try, smartass!`)
      return
    }

    debug('karma bump', `${other.username} (${other.id})`)
    User.fromPlugUser(other).then(target => {
      if (target) {
        if (reason && reason.length > 0) {
          this.sekshi.sendChat(`@${user.username} bumped @${other.username}\'s karma ${reason.join(' ')}`)
        } else {
          this.sekshi.sendChat(`@${user.username} bumped @${other.username}\'s karma!`)
        }

        let bump = new Karma({ target: target.id, giver: user.id })
        if (reason && reason.length > 0)
          bump.reason = reason.join(' ')
        bump.save()

        return target
      }
    })
  }

  thump(user, username, ...reason) {
    if (!username) {
      debug('karma thump no username')
      this.sekshi.sendChat(`@${user.username} You must provide a user to thump`)
      return
    }
    if (username.charAt(0) === '@') username = username.slice(1)
    let other = this.sekshi.getUserByName(username, true)
    if (!other) {
      this.sekshi.sendChat(`@${user.username} That's not a real person…`)
      return
    }
    if (other.id === user.id) {
      this.sekshi.sendChat(`@${user.username} You\'re weird.`)
    }

    User.fromPlugUser(other).then(target => {
      if (target) {
        if (reason && reason.length > 0) {
          this.sekshi.sendChat(`@${user.username} thumped @${other.username}\'s karma ${reason.join(' ')}`)
        } else {
          this.sekshi.sendChat(`@${user.username} thumped @${other.username}\'s karma!`)
        }

        let thump = new Karma({ target: target.id, giver: user.id, amount: -1 })
        if (reason && reason.length > 0)
          thump.reason = reason.join(' ')
        thump.save()

        return target
      }
    })
  }

  bitch(user, time = 'w') {
    const since = utils.spanToTime(time)
    const hours = moment().diff(since, 'hours')
    const allTime = time === 'f'

    Karma.aggregate()
    .match({ target: user.id, date: { $gte: since.toDate() } })
    .group({ _id: "$giver", karma: { $sum: "$amount" } })
    .sort({ karma: -1 }).exec().then(karmaList => {
      if (karmaList.length === 0) {
        let msg = `@${user.username} you have no bitches`
        if (!allTime) msg += ` from the past ${utils.days(hours)}`
        this.sekshi.sendChat(`${msg}. :cry:`)
      } else {
        let karma = karmaList[0]['karma']
        User.findById(karmaList[0]['_id']).exec().then(usar => {
          let msg = `@${user.username}, ${usar.username} is your bitch. They gave you ${karma} karma`
          if (!allTime) msg += ` in the past ${utils.days(hours)}`
          this.sekshi.sendChat(`${msg}.`)
        })
      }
    },
    err => {
      debug(`${err}`)
    })
  }

  pimp(user, time = 'w') {
    const since = utils.spanToTime(time)
    const hours = moment().diff(since, 'hours')
    const allTime = time === 'f'

    Karma.aggregate()
    .match({ giver: user.id, date: { $gte: since.toDate() } })
    .group({ _id: "$target", karma: { $sum: "$amount" } })
    .sort({ karma: -1 }).exec().then(karmaList => {
      if (karmaList.length === 0) {
        let msg = `@${user.username} you have been noone's bitch`
        if (!allTime) msg += ` in the past ${utils.days(hours)}`
        this.sekshi.sendChat(`${msg}. :smirk:`)
      } else {
        let karma = karmaList[0]['karma']
        User.findById(karmaList[0]['_id']).exec().then(usar => {
          let msg = `@${user.username}, ${usar.username} is your pimp. You gave them ${karma} karma`
          if (!allTime) msg += ` in the past ${utils.days(hours)}`
          this.sekshi.sendChat(`${msg}.`)
        })
      }
    },
    err => {
      debug(`${err}`)
    })
  }

  fistbump(user) {
    Karma.find({ reason: { $ne: null } }).where('amount').gt(0).populate('giver').exec().then( reasonList => {
      let reason = ''
      if (reasonList.length > 0) {
        reason = ` "${reasonList[Math.floor(Math.random() * reasonList.length)]}"`
      }
      this.sekshi.sendChat(`@${user.username} you were bumped by @${chosen.giver.username}` +
                           `${reason} ${moment(chosen.date).fromNow()}`)
    })
  }

  fistthump(user) {
    Karma.find({ reason: { $ne: null } }).where('amount').lt(0).populate('giver').exec().then( reasonList => {
      let reason = ''
      if (reasonList.length > 0) {
        reason = ` "${reasonList[Math.floor(Math.random() * reasonList.length)]}"`
      }
      this.sekshi.sendChat(`@${user.username} you were thumped by @${chosen.giver.username}` +
                           `${reason} ${moment(chosen.date).fromNow()}`)
    })
  }
}<|endoftext|>