<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: [],
    formatters: {
            speed: function(val, axis) {
                return (val).toFixed(axis.tickDecimals) + ' km/h';
            },
            altitude: function(val, axis) {
                return (val).toFixed(axis.tickDecimals) + ' m';
            },
            length: function(val, axis) {
                return (val).toFixed(axis.tickDecimals) + ' km';
            },
            power: function(val, axis) {
                return (val).toFixed(axis.tickDecimals) + ' W';
            },
            hr: function(val, axis) {
                return (val).toFixed(axis.tickDecimals) + ' BPM';
            },
            temp: function(val, axis) {
                return (val).toFixed(axis.tickDecimals) + ' ℃';
            },
            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 (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];
                data.push(that.datasets[key]);
            }
        });

        if (data.length > 0) {
            plot = $.plot($("#tripdiv"), data, {
                yaxes: [
                    { tickFormatter: this.formatters['speed'], max: 100},
                    { position: "right", min: 80, max: this.max_hr, tickFormatter: this.formatters['hr'] },
                    { position: "right", tickFormatter: this.formatters['power']},
                    { tickFormatter: this.formatters['altitude']} ,
                    { tickFormatter: this.formatters['temp']},

                    ],
                xaxis: xaxisattrs,
                legend: {
                    container: $("#tripdiv_legend"),
                    noColumns: 15
                },
                grid: {
                    hoverable: true,
                    clickable: true,
                    markings: this.markings,
                },
                crosshair: { mode: "x" },
                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");
                            e.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][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: '2px',
            opacity: 0.80
        }).appendTo("body").fadeIn(100);
    },
    init: function(args) {
        this.datasets = args.datasets;
        var backendUrl = args.backendUrl;
        this.max_hr = args.max_hr;
        this.markings = args.markings;
        this.xaxisformatter = this.formatters[args.xaxisformatter];
        function evaluate(y,threshold) {
            return y < threshold;
        }
        this.constraint0 = {
            threshold: this.max_hr*0.6,
            color: "rgb(240,240,240)",
            evaluate : evaluate
        }
        this.constraint1 = {
            threshold: this.max_hr*0.72,
            color: "rgb(204,204,204)",
            evaluate : evaluate
        }
        this.constraint2 = {
            threshold: this.max_hr*0.82,
            color: "rgb(51,102,255)",
            evaluate : evaluate
        }
        this.constraint3 = {
            threshold: this.max_hr*0.87,
            color: "rgb(102,204,0)",
            evaluate : evaluate
        }
        this.constraint4 = {
            threshold: this.max_hr*0.92,
            color: "rgb(255,153,0)",
            evaluate : evaluate
        }
        this.constraint5 = {
            threshold: this.max_hr*0.97,
            color: "rgb(255,0,0)",
            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 = ''

            that.choiceContainer.append('<input type="checkbox" name="' + key +
                '" ' + checked + ' id="chk_' + key + '">' + val.label + '</input>');
        });
        $("#reset_zoom").bind("click", function(evt) {
            evt.preventDefault();
            $("#scrollhacks").css("overflow", "hidden");
            $("#tripdiv").width( $("#tripdiv").width(980));
            that.plotAccordingToChoices({});
        });
        $("#enlarge").bind("click", function(evt) {
            evt.preventDefault();
            $("#scrollhacks").css("overflow", "scroll");
            $("#tripdiv").width( $("#tripdiv").width()*4);
        });
        this.choiceContainer.find("input").bind("click", function(evt) {
                that.plotAccordingToChoices({});
        });
        this.plotAccordingToChoices({});
        this.legends = $("#tripdiv .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;
        $("#tripdiv").bind("plothover", function (event, pos, item) {
//            that.latestPosition = pos;
  //          if (!that.updateLegendTimeout) that.updateLegendTimeout = setTimeout(that.updateLegend, 50);
//            that.updateLegend(pos);
            if (item) {
                // Move marker to current pos
                if (typeof(Mapper) != "undefined") {
                    if (route_points.length >= item.dataIndex) {

                        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;

                    $("#gtooltip").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 {
                $("#gtooltip").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>only display non-0 values in legend<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: [],
    formatters: {
            speed: function(val, axis) {
                return (val).toFixed(axis.tickDecimals) + ' km/h';
            },
            altitude: function(val, axis) {
                return (val).toFixed(axis.tickDecimals) + ' m';
            },
            length: function(val, axis) {
                return (val).toFixed(axis.tickDecimals) + ' km';
            },
            power: function(val, axis) {
                return (val).toFixed(axis.tickDecimals) + ' W';
            },
            hr: function(val, axis) {
                return (val).toFixed(axis.tickDecimals) + ' BPM';
            },
            temp: function(val, axis) {
                return (val).toFixed(axis.tickDecimals) + ' ℃';
            },
            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 (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];
                data.push(that.datasets[key]);
            }
        });

        if (data.length > 0) {
            plot = $.plot($("#tripdiv"), data, {
                yaxes: [
                    { tickFormatter: this.formatters['speed'], max: 100},
                    { position: "right", min: 80, max: this.max_hr, tickFormatter: this.formatters['hr'] },
                    { position: "right", tickFormatter: this.formatters['power']},
                    { tickFormatter: this.formatters['altitude']} ,
                    { tickFormatter: this.formatters['temp']},

                    ],
                xaxis: xaxisattrs,
                legend: {
                    container: $("#tripdiv_legend"),
                    noColumns: 15
                },
                grid: {
                    hoverable: true,
                    clickable: true,
                    markings: this.markings,
                },
                crosshair: { mode: "x" },
                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 = avgs[key];
                            if (val) {
                                val = Math.round(val * 10) / 10;
                                e.text(val);
                                e.parents(".hidden").removeClass("hidden");
                                e.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][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: '2px',
            opacity: 0.80
        }).appendTo("body").fadeIn(100);
    },
    init: function(args) {
        this.datasets = args.datasets;
        var backendUrl = args.backendUrl;
        this.max_hr = args.max_hr;
        this.markings = args.markings;
        this.xaxisformatter = this.formatters[args.xaxisformatter];
        function evaluate(y,threshold) {
            return y < threshold;
        }
        this.constraint0 = {
            threshold: this.max_hr*0.6,
            color: "rgb(240,240,240)",
            evaluate : evaluate
        }
        this.constraint1 = {
            threshold: this.max_hr*0.72,
            color: "rgb(204,204,204)",
            evaluate : evaluate
        }
        this.constraint2 = {
            threshold: this.max_hr*0.82,
            color: "rgb(51,102,255)",
            evaluate : evaluate
        }
        this.constraint3 = {
            threshold: this.max_hr*0.87,
            color: "rgb(102,204,0)",
            evaluate : evaluate
        }
        this.constraint4 = {
            threshold: this.max_hr*0.92,
            color: "rgb(255,153,0)",
            evaluate : evaluate
        }
        this.constraint5 = {
            threshold: this.max_hr*0.97,
            color: "rgb(255,0,0)",
            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 = ''

            that.choiceContainer.append('<input type="checkbox" name="' + key +
                '" ' + checked + ' id="chk_' + key + '">' + val.label + '</input>');
        });
        $("#reset_zoom").bind("click", function(evt) {
            evt.preventDefault();
            $("#scrollhacks").css("overflow", "hidden");
            $("#tripdiv").width( $("#tripdiv").width(980));
            that.plotAccordingToChoices({});
        });
        $("#enlarge").bind("click", function(evt) {
            evt.preventDefault();
            $("#scrollhacks").css("overflow", "scroll");
            $("#tripdiv").width( $("#tripdiv").width()*4);
        });
        this.choiceContainer.find("input").bind("click", function(evt) {
                that.plotAccordingToChoices({});
        });
        this.plotAccordingToChoices({});
        this.legends = $("#tripdiv .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;
        $("#tripdiv").bind("plothover", function (event, pos, item) {
//            that.latestPosition = pos;
  //          if (!that.updateLegendTimeout) that.updateLegendTimeout = setTimeout(that.updateLegend, 50);
//            that.updateLegend(pos);
            if (item) {
                // Move marker to current pos
                if (typeof(Mapper) != "undefined") {
                    if (route_points.length >= item.dataIndex) {

                        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;

                    $("#gtooltip").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 {
                $("#gtooltip").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>/**
 * The JSON file format used by SUNRUSE.Studio to store a project.
 * @nameSpace ProjectSchema
 */
/**
 * A container object for all of the data held by a project.
 * @class Project
 * @memberOf ProjectSchema
 */
/**
 * The tempo of the project, in beats per minute.  Should be greater than zero.
 * @member {Integer} tempo
 * @memberOf ProjectSchema.Project
/**
 * @member {Track} tracks
 * @memberOf ProjectSchema.Project
 */
/**
 * A set of {@link ProjectSchema.Loop}s in a {@link ProjectSchema.Project}, with
 * a description of how they should be synthesized.
 * @class Track
 * @memberOf ProjectSchema
 */
/**
 * The {@link ProjectSchema.Loop}s this {@link ProjectSchema.Track} contains;
 * these should not overlap when repeats are taken into account.
 * @member {Loop} loops
 * @memberOf ProjectSchema.Track
 */
/**
 * A repeatable section of a {@link ProjectSchema.Track}.
 * @class Loop
 * @memberOf ProjectSchema
 */
/**
 * The start time of the {@link ProjectSchema.Loop}, in beats, from the
 * beginning of the {@link ProjectSchema.Project}.  Should be greater than or
 * equal to zero.
 * @member {Integer} start
 * @memberOf ProjectSchema.Loop
 */
/**
 * The duration of one repeat of the {@link ProjectSchema.Loop}, in beats.
 * Should be greater than zero.
 * @member {Integer} duration
 * @memberOf ProjectSchema.Loop
 */
/**
 * The number of times to repeat the {@link ProjectSchema.Loop}.
 * Should be greater than zero.
 * @member {Integer} repeats
 * @memberOf ProjectSchema.Loop
 */
/**
 * The {@link ProjectSchema.Note}s this {@link ProjectSchema.Loop} contains.
 * Repeated during playback the number of times specified by repeats.  Notes
 * should not begin before the start of the {@link ProjectSchema.Loop}, not on
 * or after the end; though they may extend beyond the end.
 * @member {Note} notes
 * @memberOf ProjectSchema.Loop
 */
/**
 * A single tone in a {@link ProjectSchema.Loop}
 * @class Note
 * @memberOf ProjectSchema
 */
/**
 * The time, in hemidemisemiquavers (1/64th beats) from the start of the loop
 * at which to start playing a tone.
 * Should be greater than or equal to zero and less than the duration of the
 * parent {@link ProjectSchema.Loop}.
 * @member {Integer} start
 * @memberOf ProjectSchema.Note
 */
/**
 * The time, in hemidemisemiquavers (1/64th beats) from the start of the loop
 * at which to stop playing a tone.
 * Should be greater than start.
 * @member {Integer} end
 * @memberOf ProjectSchema.Note
 */
/**
 * The note number in the Western scale at which to play, where zero is C0
 * (16.35Hz) and 107 is B8 (7902.13Hz).  Should be within these values,
 * inclusive.  To calculate the frequency of a note, use
 * 16.35 * (2^12)^frequency.
 * @member {Integer} frequency
 * @memberOf ProjectSchema.Note
 */
 <commit_msg>Corrected arrays not being documented as such (Loop.Notes, etc.) and the documentation comment for Project.tempo not being closed.<commit_after>/**
 * The JSON file format used by SUNRUSE.Studio to store a project.
 * @nameSpace ProjectSchema
 */
/**
 * A container object for all of the data held by a project.
 * @class Project
 * @memberOf ProjectSchema
 */
/**
 * The tempo of the project, in beats per minute.  Should be greater than zero.
 * @member {Integer} tempo
 * @memberOf ProjectSchema.Project
 */
/**
 * @member {ProjectSchema.Track[]} tracks
 * @memberOf ProjectSchema.Project
 */
/**
 * A set of {@link ProjectSchema.Loop}s in a {@link ProjectSchema.Project}, with
 * a description of how they should be synthesized.
 * @class Track
 * @memberOf ProjectSchema
 */
/**
 * The {@link ProjectSchema.Loop}s this {@link ProjectSchema.Track} contains;
 * these should not overlap when repeats are taken into account.
 * @member {ProjectSchema.Loop[]} loops
 * @memberOf ProjectSchema.Track
 */
/**
 * A repeatable section of a {@link ProjectSchema.Track}.
 * @class Loop
 * @memberOf ProjectSchema
 */
/**
 * The start time of the {@link ProjectSchema.Loop}, in beats, from the
 * beginning of the {@link ProjectSchema.Project}.  Should be greater than or
 * equal to zero.
 * @member {Integer} start
 * @memberOf ProjectSchema.Loop
 */
/**
 * The duration of one repeat of the {@link ProjectSchema.Loop}, in beats.
 * Should be greater than zero.
 * @member {Integer} duration
 * @memberOf ProjectSchema.Loop
 */
/**
 * The number of times to repeat the {@link ProjectSchema.Loop}.
 * Should be greater than zero.
 * @member {Integer} repeats
 * @memberOf ProjectSchema.Loop
 */
/**
 * The {@link ProjectSchema.Note}s this {@link ProjectSchema.Loop} contains.
 * Repeated during playback the number of times specified by repeats.  Notes
 * should not begin before the start of the {@link ProjectSchema.Loop}, not on
 * or after the end; though they may extend beyond the end.
 * @member {ProjectSchema.Note[]} notes
 * @memberOf ProjectSchema.Loop
 */
/**
 * A single tone in a {@link ProjectSchema.Loop}
 * @class Note
 * @memberOf ProjectSchema
 */
/**
 * The time, in hemidemisemiquavers (1/64th beats) from the start of the loop
 * at which to start playing a tone.
 * Should be greater than or equal to zero and less than the duration of the
 * parent {@link ProjectSchema.Loop}.
 * @member {Integer} start
 * @memberOf ProjectSchema.Note
 */
/**
 * The time, in hemidemisemiquavers (1/64th beats) from the start of the loop
 * at which to stop playing a tone.
 * Should be greater than start.
 * @member {Integer} end
 * @memberOf ProjectSchema.Note
 */
/**
 * The note number in the Western scale at which to play, where zero is C0
 * (16.35Hz) and 107 is B8 (7902.13Hz).  Should be within these values,
 * inclusive.  To calculate the frequency of a note, use
 * 16.35 * (2^12)^frequency.
 * @member {Integer} frequency
 * @memberOf ProjectSchema.Note
 */
 <|endoftext|>


<commit_before>
import {ael, rel, grp, ev, isParent} from './tools'
import {DIR, ACTION} from './constants'

export default class Screen {
  constructor(element = null, options= {}) {
    if (!element) { throw new Error('Invalid arguments, at least DOM element have to be passed') }
    this.element = element
    this.threshold = options.threshold || 150
    this.restraint = options.restraint || 300
    this.callback  = options.callback  || function() {}
    this.direction = options.direction || DIR.HORIZONTAL
    this.mouse = options.mouse || true
    this.mouseDelta = options.mouseDelta || 0

    this.reinit()
    this.resize()

    this.currentScreen = null

    this.touchStartFn = this.touchStart.bind(this)
    this.touchMoveFn = this.touchMove.bind(this)
    this.touchEndFn = this.touchEnd.bind(this)
    this.mouseWheel = this.mouseWheel.bind(this)

    ael(window, 'mousedown', this.touchStartFn)
    ael(window, 'mousemove', this.touchMoveFn)
    ael(window, 'mouseup', this.touchEndFn)
    //ael(this.element, 'mouseout', this.touchEndFn)
    ael(window, 'touchstart', this.touchStartFn)
    ael(window, 'touchmove', this.touchMoveFn)
    ael(window, 'touchend', this.touchEndFn)

    if (this.mouse === true) {
      ael(window, 'wheel', this.mouseWheel)
    }
  }

  resize() {
    if (this.direction === DIR.VERTICAL) {
      if (isNaN(parseInt(this.element.style.top)) || parseInt(this.element.style.top) === 0 ) {
        this.element.style.top = this.element.offsetTop + 'px'
      }
      this.elementInitial = parseInt(this.element.style.top)
      this.elementLen = [].slice.call(this.element.children)
        .reduce((p,c) => p + c.offsetHeight , 0)
    } else {
      if (isNaN(parseInt(this.element.style.left)) || parseInt(this.element.style.left) === 0 ) {
        this.element.style.left = this.element.offsetLeft + 'px'
      }
      this.elementInitial = parseInt(this.element.style.left)
      this.elementLen = [].slice.call(this.element.children)
        .reduce((p,c) => p + c.offsetWidth , 0)
    }

    this.elementWidth = this.element.offsetWidth
    this.elementStop = (this.elementLen - this.elementWidth) * -1
    this.mouseDelta = this.elementWidth / 2  + 1
  }

  destroy() {
    this.reinit()

    rel(window, 'mousedown', this.touchStartFn)
    rel(window, 'mousemove', this.touchMoveFn)
    rel(window, 'mouseup', this.touchEndFn)
    //rel(this.element, 'mouseout', this.touchEndFn)
    rel(window, 'touchstart', this.touchStartFn)
    rel(window, 'touchmove', this.touchMoveFn)
    rel(window, 'touchend', this.touchEndFn)

    if (this.mouse === true) {
      rel(window, 'wheel', this.mouseWheel)
    }
  }

  reinit() {
    this.start = false
    this.starPos = 0
    this.startTime = null
  }

  mouseWheel(e) {

    if (new Date().getTime() - this.startTime >= this.restraint) {

      this.startTime = new Date().getTime()
      if (this.direction === DIR.VERTICAL) {
        this.initial = parseInt(this.element.style.top)
      } else {
        this.initial = parseInt(this.element.style.left)
      }

      let delta = e.deltaY < 0 ?
       (this.mouseDelta + this.initial) : (this.initial - this.mouseDelta)

      this.startPos = this.initial

      this.moveElementTo(delta, true)
    }

    e.preventDefault()
  }

  touchStart(e) {
    if (isParent(e.target, this.element)) {
      this.start = true
      this.startTime = new Date().getTime()

      if (this.direction === DIR.VERTICAL) {
        this.startPos = ev(e).y
        this.initial = parseInt(this.element.style.top)
      } else {
        this.startPos = ev(e).x
        this.initial = parseInt(this.element.style.left)
      }
    }
    e.preventDefault()
  }

  touchMove(e) {
    if (this.start === true) {
      const cur = this.direction === DIR.VERTICAL ? ev(e).y: ev(e).x
      this.moveElementTo(cur)
    }
    e.preventDefault()
  }

  touchEnd(e) {
    if (this.start === true) {
      const cur = this.direction === DIR.VERTICAL ? ev(e).y: ev(e).x
      this.moveElementTo(cur, true)
      this.reinit()
    }
  }

  setDuration(duration, easing = 'ease') {
    const direction = this.direction === DIR.HORIZONTAL ? 'left' : 'top'
    this.element.style.transition = `${direction} ${duration} ${easing}`
  }

  moveElementTo(cur, isEnd = false) {
    const til = cur - this.startPos
    let offset = this.initial + til

    if (isEnd === true) {
      offset =  Math.round(offset / this.elementWidth) * this.elementWidth
    }

    if (isEnd === true && offset > this.elementInitial) {
      offset = this.elementInitial
    } else  if (isEnd === true && offset < this.elementStop) {
      offset = this.elementStop
    }

    if (isEnd === true) {
      if (this.currentScreen !== Math.round(offset / this.elementWidth)) {
        this.currentScreen = Math.round(offset / this.elementWidth)
        this.callback(Math.abs(this.currentScreen))
      }

      this.setDuration('.3s', 'ease-out')
      setTimeout(() => {
        this.setDuration('.0s')
      }, 300)
    }

    if (this.direction === DIR.VERTICAL) {
      this.element.style.top = offset + 'px'
    } else {
      this.element.style.left = offset + 'px'
    }
  }
}
<commit_msg>threshold fix<commit_after>
import {ael, rel, grp, ev, isParent} from './tools'
import {DIR, ACTION} from './constants'

export default class Screen {
  constructor(element = null, options= {}) {
    if (!element) { throw new Error('Invalid arguments, at least DOM element have to be passed') }
    this.element = element
    this.threshold = options.threshold || 120
    this.restraint = options.restraint || 300
    this.callback  = options.callback  || function() {}
    this.direction = options.direction || DIR.HORIZONTAL
    this.mouse = options.mouse || true
    this.mouseDelta = options.mouseDelta || 0

    this.reinit()
    this.resize()

    this.currentScreen = null

    this.touchStartFn = this.touchStart.bind(this)
    this.touchMoveFn = this.touchMove.bind(this)
    this.touchEndFn = this.touchEnd.bind(this)
    this.mouseWheel = this.mouseWheel.bind(this)

    ael(window, 'mousedown', this.touchStartFn)
    ael(window, 'mousemove', this.touchMoveFn)
    ael(window, 'mouseup', this.touchEndFn)
    //ael(this.element, 'mouseout', this.touchEndFn)
    ael(window, 'touchstart', this.touchStartFn)
    ael(window, 'touchmove', this.touchMoveFn)
    ael(window, 'touchend', this.touchEndFn)

    if (this.mouse === true) {
      ael(window, 'wheel', this.mouseWheel)
    }
  }

  resize() {
    if (this.direction === DIR.VERTICAL) {
      if (isNaN(parseInt(this.element.style.top)) || parseInt(this.element.style.top) === 0 ) {
        this.element.style.top = this.element.offsetTop + 'px'
      }
      this.elementInitial = parseInt(this.element.style.top)
      this.elementLen = [].slice.call(this.element.children)
        .reduce((p,c) => p + c.offsetHeight , 0)
    } else {
      if (isNaN(parseInt(this.element.style.left)) || parseInt(this.element.style.left) === 0 ) {
        this.element.style.left = this.element.offsetLeft + 'px'
      }
      this.elementInitial = parseInt(this.element.style.left)
      this.elementLen = [].slice.call(this.element.children)
        .reduce((p,c) => p + c.offsetWidth , 0)
    }

    this.elementWidth = this.element.offsetWidth
    this.elementStop = (this.elementLen - this.elementWidth) * -1
    this.mouseDelta = this.elementWidth / 2  + 1
  }

  destroy() {
    this.reinit()

    rel(window, 'mousedown', this.touchStartFn)
    rel(window, 'mousemove', this.touchMoveFn)
    rel(window, 'mouseup', this.touchEndFn)
    //rel(this.element, 'mouseout', this.touchEndFn)
    rel(window, 'touchstart', this.touchStartFn)
    rel(window, 'touchmove', this.touchMoveFn)
    rel(window, 'touchend', this.touchEndFn)

    if (this.mouse === true) {
      rel(window, 'wheel', this.mouseWheel)
    }
  }

  reinit() {
    this.start = false
    this.starPos = 0
    this.startTime = null
  }

  mouseWheel(e) {

    if (new Date().getTime() - this.startTime >= this.restraint) {

      this.startTime = new Date().getTime()
      if (this.direction === DIR.VERTICAL) {
        this.initial = parseInt(this.element.style.top)
      } else {
        this.initial = parseInt(this.element.style.left)
      }

      let delta = e.deltaY < 0 ?
       (this.mouseDelta + this.initial) : (this.initial - this.mouseDelta)

      this.startPos = this.initial

      this.moveElementTo(delta, true)
    }

    e.preventDefault()
  }

  touchStart(e) {
    if (isParent(e.target, this.element)) {
      this.start = true
      this.startTime = new Date().getTime()

      if (this.direction === DIR.VERTICAL) {
        this.startPos = ev(e).y
        this.initial = parseInt(this.element.style.top)
      } else {
        this.startPos = ev(e).x
        this.initial = parseInt(this.element.style.left)
      }
    }
    e.preventDefault()
  }

  touchMove(e) {
    if (this.start === true) {
      const cur = this.direction === DIR.VERTICAL ? ev(e).y: ev(e).x
      this.moveElementTo(cur)
    }
    e.preventDefault()
  }

  touchEnd(e) {
    if (this.start === true) {
      const cur = this.direction === DIR.VERTICAL ? ev(e).y: ev(e).x
      this.moveElementTo(cur, true)
      this.reinit()
    }
  }

  setDuration(duration, easing = 'ease') {
    const direction = this.direction === DIR.HORIZONTAL ? 'left' : 'top'
    this.element.style.transition = `${direction} ${duration} ${easing}`
  }

  moveElementTo(cur, isEnd = false) {
    const til = cur - this.startPos
    let offset = this.initial + til

    if (isEnd === true) {
      if (Math.abs(til) >= this.threshold) {
        offset = (til < 0 ? (this.currentScreen - 1) : this.currentScreen + 1) * this.elementWidth
      } else {
        offset =  Math.round(offset / this.elementWidth) * this.elementWidth
      }
    }

    if (isEnd === true && offset > this.elementInitial) {
      offset = this.elementInitial
    } else  if (isEnd === true && offset < this.elementStop) {
      offset = this.elementStop
    }

    if (isEnd === true) {
      if (this.currentScreen !== Math.round(offset / this.elementWidth)) {
        this.currentScreen = Math.round(offset / this.elementWidth)
        this.callback(Math.abs(this.currentScreen))
      }

      this.setDuration('.3s', 'ease-out')
      setTimeout(() => {
        this.setDuration('.0s')
      }, 300)
    }

    if (this.direction === DIR.VERTICAL) {
      this.element.style.top = offset + 'px'
    } else {
      this.element.style.left = offset + 'px'
    }
  }
}
<|endoftext|>


<commit_before>const _ = require('lodash');
const Promise = require("bluebird");
const path = require("path");
const chalk = require('chalk');
const util = require('./util.js');
const Web3 = new require('web3');
const SolidityEvent = require('web3/lib/web3/event.js');
const EthWallet = require('ethereumjs-wallet');
const ethUtil = require('ethereumjs-util');
const fs = require('fs');
const yamljs = require('yamljs');
Promise.config({
  longStackTraces: false
});

module.exports = exports = function(file, extra, walletFile, showTransactions, showEvents, genPreload) {
  var ALL_STEPS, VARS, CONTRACTS, STEP_INDEX, CONTRACT_ADDRESS, TX2CB, TEST_RESULTS = [];

  util.readFile(file).then(function(data) {
    var cf;
    try {
      cf = JSON.parse(data);
    } catch(e) {
      cf = yamljs.parse(data);

      if (!cf) {
        console.log(chalk.red("Failed parsing config file: " + e));
        process.exit();
      }
    }
    VARS = _.extend(_.get(cf, 'vars', {}), extra);
    ALL_STEPS = _.get(cf, 'steps', []);
    CONTRACTS = {};
    CONTRACT_ADDRESS = _.get(cf, 'addresses', {});
    TX2CB = {};
    STEP_INDEX = 0;

    var walletPromise;
    if (walletFile) {
      walletPromise = extractPrivateKeyFromWallet(walletFile);
    } else {
      walletPromise = Promise.resolve();
    }

    var scriptDir = path.dirname(file);

    return walletPromise.then(function() {
      return util.step('Compiling contracts', Promise.map(cf.contracts || [], function(file) {
        return util.getContract(path.resolve(scriptDir, file));
      }).then(function(res) {
        res.forEach(function(c) {
          CONTRACTS[c.name] = c;
        });
      })).then(execStep);
    }).then(() => {
      if (genPreload) {
        let preload = [];
        _.each(CONTRACT_ADDRESS, (addr, name) => {
          let abi = CONTRACTS[name].abi;
          preload.push(`${name} = eth.contract(${JSON.stringify(abi)}).at(${JSON.stringify(addr)});\n`);
        });

        return new Promise((resolve, reject) => {
          fs.writeFile(genPreload, preload.join('\n'), function(err) {
            if (err) {
              reject(`Failed writing preload file at ${genPreload}`);
            } else {
              console.log(chalk.green(`Preload file writen in ${genPreload}`));
              resolve();
            }
          });
        });
      }
    });
  }).catch(util.printException).finally(function() {
    if (TEST_RESULTS.length>0) {
      console.log();
      console.log();
      console.log('Test results:');
      TEST_RESULTS.forEach(function(line) {
        console.log(line);
      });
    }
    process.exit();
  });

  var resolveVar = function(name) {
    var val = name;
    while (true) {
      if (CONTRACT_ADDRESS[val]!==undefined) {
        return CONTRACT_ADDRESS[val];
      } else if (VARS[val]!==undefined) {
        val = VARS[val];
      } else {
        if (_.isArray(val)) {
          val = _.map(val, resolveVar);
        }
        break;
      }
    };

    return val;
  };

  var resolveName = function(name) {
    var val = name;
    while (true) {
      if (VARS[val]!==undefined) {
        val = VARS[val];
      } else {
        if (_.isArray(val)) {
          val = _.map(val, resolveName);
        }
        break;
      }
    };

    return val;
  };

  var prepareStep = function(step) {
    var keys = step.key;
    if (!_.isArray(keys)) {
      keys = [keys];
    }
    keys = _.flatten(_.map(keys, resolveVar));

    return keys.map(function(key) {
      var toArray = function(v) {
        if (_.isArray(v)) {
          return v;
        }
        return [v];
      };
      args = toArray(step.args || []).map(function(arg) {
        return resolveVar(arg);
      });

      var res = _.extend({
        key: key,
        args: args
      }, _.pick(step, ['type', 'contract', 'method', 'value', 'as']));

      if (step.address) {
        res['address'] = resolveVar(step.address);
      }

      return res;
    });
  };

  var prepareTxForStep = function(key, nonce, step) {
    var to;
    var args = [];
    var contractName = resolveName(step.contract);
    var contractInfo = CONTRACTS[contractName];
    if (!contractInfo) {
      console.log(chalk.red(`Unknown contract ${contractName}`));
      process.exit();
    }
    var contract = contractInfo.contract;
    var method;
    var methodName;
    var methodAbi;
    var data;

    var abiReplaceBinaries = function(abi) {
      return abi.replace(/__(.{38})/g, function(lib) {
        lib = _.trim(lib, '_').split(':')[0].replace(/\.sol$/, '');
        if (!CONTRACT_ADDRESS[lib]) {
          console.log(chalk.red(`Library address for ${lib} unknown`));
          process.exit();
        }
        return CONTRACT_ADDRESS[lib].substr(2);
      });
    };

    if (step.type=='call') {
      to = resolveVar(contractInfo.name);
      if (!to) {
        console.log(chalk.red("Contract ${contractName} missing address"));
      }
      methodName = resolveName(step.method);
      methodAbi = contractInfo.abi.find(function(item) {
        if (item.type=='function' && item.name==methodName) {
          return true;
        }
      });
      if (!methodAbi) {
        console.log(chalk.red(`Unknown method ${methodName}`));
        process.exit();
      }
      contract = contract.at(to);
      method = contract[methodName];
    } else if (step.type=='deploy') {
      to = null;

      methodName = 'new';
      methodAbi = contractInfo.abi.find(function(item) {
        if (item.type=='constructor') {
          return true;
        }
      }) || {inputs:[]};
      method = contract[methodName];
    }

    var args = util.prepareArgs(methodAbi.inputs, step.args).map(function(item) {
      return item.value;
    });
    if (step.type=='deploy') {
      args.push({
        data: abiReplaceBinaries(contractInfo.byteCode)
      });
    }
    data = method.getData.apply(method, args);
    if (step.type=='deploy') {
      data = '0x'+data;
    }

    if (data.substr(0, 2)!='0x' || data.substr(0, 4)=='0x0x') {
      throw new Error('Bad data');
    }

    return {
      sign: util.signWithNonce(key, nonce, util.privateToAddress(key), to, step.value||0, data),
      cb: function(messages) {
        return function(info, basic) {
          var outOfGas = info.gasUsed == basic.gas;

          if (step.type=='deploy') {
            CONTRACT_ADDRESS[step.as || contractName] = info.contractAddress;
            var alias = '';
            if (step.as) {
              alias = ` (${step.as})`;
            }
            if (!outOfGas) {
              messages.push('Contract '+chalk.blue(contractName)+alias+' mined at '+chalk.blue(info.contractAddress));
            } else {
              messages.push(chalk.red('Contract '+contractNam)+alias+' not deployed, out of gas');
            }
          } else if (step.type=='call') {
            if (!outOfGas) {
              messages.push('Method '+contractName+'@'+methodName+' executed');
            } else {
              messages.push(chalk.red('Method '+contractName+'@'+methodName+' failed, out of gas'));
              return;
            }
            var formater = contract.allEvents().formatter;
            info.logs.forEach(function(log) {
              if (log.address!=to) {
                return;
              }

              var result = formater(log);

              if (showEvents) {
                messages.push('  '+result.event+': '+JSON.stringify(result.args));
              }

              if (result.event=='AssertSuccess') {
                TEST_RESULTS.push(chalk.green(`+ ${contractName}@${methodName} ${result.args.msg}`));
              } else if (result.event=='AssertFailure') {
                TEST_RESULTS.push(chalk.red(`- ${contractName}@${methodName} ${result.args.msg}`));
              }
            });
          }
        };
      }
    }
  };

  var execStep = function() {
    STEP_INDEX++;

    var steps = ALL_STEPS.shift();
    if (!steps) {
      return;
    }

    if (!_.isArray(steps)) {
      steps = [steps];
    }

    steps = _.reduce(steps, function(res, step) {
      return res.concat(prepareStep(step));
    }, []);

    var stepByKey = _.groupBy(steps, "key");

    var usedKeys = _.keys(stepByKey);
    var usedAddresses = _.map(usedKeys, util.privateToAddress);
    var keyToAddress = _.zipObject(usedKeys, usedAddresses);
    var promises = [];
    var afterDeployed = [];
    var afterMined = {};
    var txList = [];
    var txToWatch = [];
    var messages = [];

    // prepare and sign txs
    util.writeLabel('Executing step '+STEP_INDEX);
    return util.getNonce(usedAddresses).then(function(nonces) {
      _.each(stepByKey, function(steps, key) {
        var fromAddress = keyToAddress[key];
        _.each(steps, function(step, ii) {
          if (step.type=='test') {
            var testMethods = CONTRACTS[resolveName(step.contract)].abi.filter(function(item) {
              return item.type=='function' && /^test/.test(item.name);
            }).map(function(item) {
              var testStep = _.extend(_.pick(step, ['key', 'contract']), {
                type: 'call',
                method: item.name
              });

              var res = prepareTxForStep(key, nonces[fromAddress]++, testStep);
              promises.push(res.sign);
              afterDeployed.push(res.cb);
            });
            return;
          }

          var res = prepareTxForStep(key, nonces[fromAddress]++, step);
          promises.push(res.sign);
          afterDeployed.push(res.cb);
        });
      });
    }).then(function() {
      // broadcast txs
      return Promise.all(promises).then(function(signed) {
        return Promise.map(signed, util.sendRaw).then(function(res) {
          _.map(res, function(tx, ii) {
            txToWatch.push(tx);
            txList.push(tx);
            afterMined[tx] = afterDeployed[ii](messages);
          });
        });
      }).then(function() {
        return util.watchTxs(txToWatch, afterMined);
      });
    }).then(function() {
      util.writeDone();
      if (showTransactions) {
        console.log('Transactions:');
        txList.forEach(function(tx) {
          console.log('- '+tx);
        });
      }
      console.log('Messages:');
      messages.forEach(function(msg) {
        console.log("- "+msg);
      });
    }).then(execStep);
  };

  var extractPrivateKeyFromWallet = function(file) {
    return util.readFile(file).then(function(data) {
      var wallet = JSON.parse(data);
      if (wallet.Crypto && !wallet.crypto) {
        wallet.crypto = wallet.Crypto;
      }

      var privateKey, address;
      return util.read({ prompt: chalk.red(chalk.blue("Enter wallet password: ")), silent: true }).then(function(password) {
        privateKey = EthWallet.fromV3(wallet, password).getPrivateKey().toString('hex');

        var public = ethUtil.privateToPublic(new Buffer(privateKey, 'hex'));
        address = '0x' + ethUtil.publicToAddress(public).toString('hex');

        console.log(chalk.green(`Wallet decoded, you will be signing as ${address}`));
        return util.read({ prompt: chalk.blue("[yes]/no: ") });
      }).then(function(answer) {
        if (answer=='yes' || answer=='y') {
        } else {
          process.exit();
        }

        VARS['__WALLET_ADDRESS__'] = address;
        VARS['__WALLET_KEY__'] = privateKey;
      });
    });
  };
};
<commit_msg>Fix typo<commit_after>const _ = require('lodash');
const Promise = require("bluebird");
const path = require("path");
const chalk = require('chalk');
const util = require('./util.js');
const Web3 = new require('web3');
const SolidityEvent = require('web3/lib/web3/event.js');
const EthWallet = require('ethereumjs-wallet');
const ethUtil = require('ethereumjs-util');
const fs = require('fs');
const yamljs = require('yamljs');
Promise.config({
  longStackTraces: false
});

module.exports = exports = function(file, extra, walletFile, showTransactions, showEvents, genPreload) {
  var ALL_STEPS, VARS, CONTRACTS, STEP_INDEX, CONTRACT_ADDRESS, TX2CB, TEST_RESULTS = [];

  util.readFile(file).then(function(data) {
    var cf;
    try {
      cf = JSON.parse(data);
    } catch(e) {
      cf = yamljs.parse(data);

      if (!cf) {
        console.log(chalk.red("Failed parsing config file: " + e));
        process.exit();
      }
    }
    VARS = _.extend(_.get(cf, 'vars', {}), extra);
    ALL_STEPS = _.get(cf, 'steps', []);
    CONTRACTS = {};
    CONTRACT_ADDRESS = _.get(cf, 'addresses', {});
    TX2CB = {};
    STEP_INDEX = 0;

    var walletPromise;
    if (walletFile) {
      walletPromise = extractPrivateKeyFromWallet(walletFile);
    } else {
      walletPromise = Promise.resolve();
    }

    var scriptDir = path.dirname(file);

    return walletPromise.then(function() {
      return util.step('Compiling contracts', Promise.map(cf.contracts || [], function(file) {
        return util.getContract(path.resolve(scriptDir, file));
      }).then(function(res) {
        res.forEach(function(c) {
          CONTRACTS[c.name] = c;
        });
      })).then(execStep);
    }).then(() => {
      if (genPreload) {
        let preload = [];
        _.each(CONTRACT_ADDRESS, (addr, name) => {
          let abi = CONTRACTS[name].abi;
          preload.push(`${name} = eth.contract(${JSON.stringify(abi)}).at(${JSON.stringify(addr)});\n`);
        });

        return new Promise((resolve, reject) => {
          fs.writeFile(genPreload, preload.join('\n'), function(err) {
            if (err) {
              reject(`Failed writing preload file at ${genPreload}`);
            } else {
              console.log(chalk.green(`Preload file writen in ${genPreload}`));
              resolve();
            }
          });
        });
      }
    });
  }).catch(util.printException).finally(function() {
    if (TEST_RESULTS.length>0) {
      console.log();
      console.log();
      console.log('Test results:');
      TEST_RESULTS.forEach(function(line) {
        console.log(line);
      });
    }
    process.exit();
  });

  var resolveVar = function(name) {
    var val = name;
    while (true) {
      if (CONTRACT_ADDRESS[val]!==undefined) {
        return CONTRACT_ADDRESS[val];
      } else if (VARS[val]!==undefined) {
        val = VARS[val];
      } else {
        if (_.isArray(val)) {
          val = _.map(val, resolveVar);
        }
        break;
      }
    };

    return val;
  };

  var resolveName = function(name) {
    var val = name;
    while (true) {
      if (VARS[val]!==undefined) {
        val = VARS[val];
      } else {
        if (_.isArray(val)) {
          val = _.map(val, resolveName);
        }
        break;
      }
    };

    return val;
  };

  var prepareStep = function(step) {
    var keys = step.key;
    if (!_.isArray(keys)) {
      keys = [keys];
    }
    keys = _.flatten(_.map(keys, resolveVar));

    return keys.map(function(key) {
      var toArray = function(v) {
        if (_.isArray(v)) {
          return v;
        }
        return [v];
      };
      args = toArray(step.args || []).map(function(arg) {
        return resolveVar(arg);
      });

      var res = _.extend({
        key: key,
        args: args
      }, _.pick(step, ['type', 'contract', 'method', 'value', 'as']));

      if (step.address) {
        res['address'] = resolveVar(step.address);
      }

      return res;
    });
  };

  var prepareTxForStep = function(key, nonce, step) {
    var to;
    var args = [];
    var contractName = resolveName(step.contract);
    var contractInfo = CONTRACTS[contractName];
    if (!contractInfo) {
      console.log(chalk.red(`Unknown contract ${contractName}`));
      process.exit();
    }
    var contract = contractInfo.contract;
    var method;
    var methodName;
    var methodAbi;
    var data;

    var abiReplaceBinaries = function(abi) {
      return abi.replace(/__(.{38})/g, function(lib) {
        lib = _.trim(lib, '_').split(':')[0].replace(/\.sol$/, '');
        if (!CONTRACT_ADDRESS[lib]) {
          console.log(chalk.red(`Library address for ${lib} unknown`));
          process.exit();
        }
        return CONTRACT_ADDRESS[lib].substr(2);
      });
    };

    if (step.type=='call') {
      to = resolveVar(contractInfo.name);
      if (!to) {
        console.log(chalk.red("Contract ${contractName} missing address"));
      }
      methodName = resolveName(step.method);
      methodAbi = contractInfo.abi.find(function(item) {
        if (item.type=='function' && item.name==methodName) {
          return true;
        }
      });
      if (!methodAbi) {
        console.log(chalk.red(`Unknown method ${methodName}`));
        process.exit();
      }
      contract = contract.at(to);
      method = contract[methodName];
    } else if (step.type=='deploy') {
      to = null;

      methodName = 'new';
      methodAbi = contractInfo.abi.find(function(item) {
        if (item.type=='constructor') {
          return true;
        }
      }) || {inputs:[]};
      method = contract[methodName];
    }

    var args = util.prepareArgs(methodAbi.inputs, step.args).map(function(item) {
      return item.value;
    });
    if (step.type=='deploy') {
      args.push({
        data: abiReplaceBinaries(contractInfo.byteCode)
      });
    }
    data = method.getData.apply(method, args);
    if (step.type=='deploy') {
      data = '0x'+data;
    }

    if (data.substr(0, 2)!='0x' || data.substr(0, 4)=='0x0x') {
      throw new Error('Bad data');
    }

    return {
      sign: util.signWithNonce(key, nonce, util.privateToAddress(key), to, step.value||0, data),
      cb: function(messages) {
        return function(info, basic) {
          var outOfGas = info.gasUsed == basic.gas;

          if (step.type=='deploy') {
            CONTRACT_ADDRESS[step.as || contractName] = info.contractAddress;
            var alias = '';
            if (step.as) {
              alias = ` (${step.as})`;
            }
            if (!outOfGas) {
              messages.push('Contract '+chalk.blue(contractName)+alias+' mined at '+chalk.blue(info.contractAddress));
            } else {
              messages.push(chalk.red('Contract '+contractName)+alias+' not deployed, out of gas');
            }
          } else if (step.type=='call') {
            if (!outOfGas) {
              messages.push('Method '+contractName+'@'+methodName+' executed');
            } else {
              messages.push(chalk.red('Method '+contractName+'@'+methodName+' failed, out of gas'));
              return;
            }
            var formater = contract.allEvents().formatter;
            info.logs.forEach(function(log) {
              if (log.address!=to) {
                return;
              }

              var result = formater(log);

              if (showEvents) {
                messages.push('  '+result.event+': '+JSON.stringify(result.args));
              }

              if (result.event=='AssertSuccess') {
                TEST_RESULTS.push(chalk.green(`+ ${contractName}@${methodName} ${result.args.msg}`));
              } else if (result.event=='AssertFailure') {
                TEST_RESULTS.push(chalk.red(`- ${contractName}@${methodName} ${result.args.msg}`));
              }
            });
          }
        };
      }
    }
  };

  var execStep = function() {
    STEP_INDEX++;

    var steps = ALL_STEPS.shift();
    if (!steps) {
      return;
    }

    if (!_.isArray(steps)) {
      steps = [steps];
    }

    steps = _.reduce(steps, function(res, step) {
      return res.concat(prepareStep(step));
    }, []);

    var stepByKey = _.groupBy(steps, "key");

    var usedKeys = _.keys(stepByKey);
    var usedAddresses = _.map(usedKeys, util.privateToAddress);
    var keyToAddress = _.zipObject(usedKeys, usedAddresses);
    var promises = [];
    var afterDeployed = [];
    var afterMined = {};
    var txList = [];
    var txToWatch = [];
    var messages = [];

    // prepare and sign txs
    util.writeLabel('Executing step '+STEP_INDEX);
    return util.getNonce(usedAddresses).then(function(nonces) {
      _.each(stepByKey, function(steps, key) {
        var fromAddress = keyToAddress[key];
        _.each(steps, function(step, ii) {
          if (step.type=='test') {
            var testMethods = CONTRACTS[resolveName(step.contract)].abi.filter(function(item) {
              return item.type=='function' && /^test/.test(item.name);
            }).map(function(item) {
              var testStep = _.extend(_.pick(step, ['key', 'contract']), {
                type: 'call',
                method: item.name
              });

              var res = prepareTxForStep(key, nonces[fromAddress]++, testStep);
              promises.push(res.sign);
              afterDeployed.push(res.cb);
            });
            return;
          }

          var res = prepareTxForStep(key, nonces[fromAddress]++, step);
          promises.push(res.sign);
          afterDeployed.push(res.cb);
        });
      });
    }).then(function() {
      // broadcast txs
      return Promise.all(promises).then(function(signed) {
        return Promise.map(signed, util.sendRaw).then(function(res) {
          _.map(res, function(tx, ii) {
            txToWatch.push(tx);
            txList.push(tx);
            afterMined[tx] = afterDeployed[ii](messages);
          });
        });
      }).then(function() {
        return util.watchTxs(txToWatch, afterMined);
      });
    }).then(function() {
      util.writeDone();
      if (showTransactions) {
        console.log('Transactions:');
        txList.forEach(function(tx) {
          console.log('- '+tx);
        });
      }
      console.log('Messages:');
      messages.forEach(function(msg) {
        console.log("- "+msg);
      });
    }).then(execStep);
  };

  var extractPrivateKeyFromWallet = function(file) {
    return util.readFile(file).then(function(data) {
      var wallet = JSON.parse(data);
      if (wallet.Crypto && !wallet.crypto) {
        wallet.crypto = wallet.Crypto;
      }

      var privateKey, address;
      return util.read({ prompt: chalk.red(chalk.blue("Enter wallet password: ")), silent: true }).then(function(password) {
        privateKey = EthWallet.fromV3(wallet, password).getPrivateKey().toString('hex');

        var public = ethUtil.privateToPublic(new Buffer(privateKey, 'hex'));
        address = '0x' + ethUtil.publicToAddress(public).toString('hex');

        console.log(chalk.green(`Wallet decoded, you will be signing as ${address}`));
        return util.read({ prompt: chalk.blue("[yes]/no: ") });
      }).then(function(answer) {
        if (answer=='yes' || answer=='y') {
        } else {
          process.exit();
        }

        VARS['__WALLET_ADDRESS__'] = address;
        VARS['__WALLET_KEY__'] = privateKey;
      });
    });
  };
};
<|endoftext|>


<commit_before>'use strict'

const path = require('path')
const handler = require('rosid-handler-js')

module.exports = (() => {

	const filePath = path.resolve(__dirname, './client.js')
	const browserify = {}
	const babel = { babelrc: false }
	const opts = { optimize: false, browserify, babel }

	return handler(filePath, opts)

})()<commit_msg>Code styleing adjustment<commit_after>'use strict'

const path = require('path')
const handler = require('rosid-handler-js')

module.exports = (() => {

	const filePath = path.resolve(__dirname, './client.js')

	const browserify = {}
	const babel = { babelrc: false }
	const opts = { optimize: false, browserify, babel }

	return handler(filePath, opts)

})()<|endoftext|>


<commit_before>window.langDB = {
  "articles": {
    "webgl-shaders-and-glsl.html": {
      "en": true
    },
    "webgl-text-glyphs.html": {
      "en": true
    },
    "webgl-scene-graph.html": {
      "en": true
    },
    "webgl-text-canvas2d.html": {
      "en": true
    },
    "webgl-text-texture.html": {
      "en": true
    },
    "webgl-text-html.html": {
      "en": true
    },
    "webgl-drawing-multiple-things.html": {
      "en": true
    },
    "webgl-resizing-the-canvas.html": {
      "en": true
    },
    "webgl-less-code-more-fun.html": {
      "en": true
    },
    "webgl-anti-patterns.html": {
      "en": true
    },
    "webgl-3d-textures.html": {
      "en": true
    },
    "webgl-animation.html": {
      "en": true
    },
    "webgl-3d-camera.html": {
      "en": true
    },
    "webgl-2-textures.html": {
      "en": true
    },
    "webgl-2d-vs-3d-library.html": {
      "en": true,
      "pl": true
    },
    "webgl-3d-perspective.html": {
      "en": true
    },
    "webgl-3d-orthographic.html": {
      "en": true
    },
    "webgl-image-processing-continued.html": {
      "en": true
    },
    "webgl-image-processing.html": {
      "en": true
    },
    "webgl-and-alpha.html": {
      "en": true
    },
    "webgl-fundamentals.html": {
      "en": true,
      "pl": true
    },
    "webgl-2d-matrices.html": {
      "en": true
    },
    "webgl-how-it-works.html": {
      "en": true
    },
    "webgl-2d-translation.html": {
      "en": true
    },
    "webgl-2d-scale.html": {
      "en": true
    },
    "webgl-2d-rotation.html": {
      "en": true
    },
    "webgl-boilerplate.html": {
      "en": true
    }
  },
  "langs": {
    "en": {
      "lang": "en",
      "language": "English"
    },
    "pl": {
      "lang": "pl",
      "language": "Polski"
    }
  }
}<commit_msg>Polish translation info<commit_after>window.langDB = {
  "articles": {
    "webgl-shaders-and-glsl.html": {
      "en": true
    },
    "webgl-text-glyphs.html": {
      "en": true
    },
    "webgl-scene-graph.html": {
      "en": true
    },
    "webgl-text-canvas2d.html": {
      "en": true
    },
    "webgl-text-texture.html": {
      "en": true
    },
    "webgl-text-html.html": {
      "en": true
    },
    "webgl-drawing-multiple-things.html": {
      "en": true
    },
    "webgl-resizing-the-canvas.html": {
      "en": true
    },
    "webgl-less-code-more-fun.html": {
      "en": true
    },
    "webgl-anti-patterns.html": {
      "en": true
    },
    "webgl-3d-textures.html": {
      "en": true
    },
    "webgl-animation.html": {
      "en": true
    },
    "webgl-3d-camera.html": {
      "en": true
    },
    "webgl-2-textures.html": {
      "en": true
    },
    "webgl-2d-vs-3d-library.html": {
      "en": true,
      "pl": true
    },
    "webgl-3d-perspective.html": {
      "en": true
    },
    "webgl-3d-orthographic.html": {
      "en": true
    },
    "webgl-image-processing-continued.html": {
      "en": true
    },
    "webgl-image-processing.html": {
      "en": true
    },
    "webgl-and-alpha.html": {
      "en": true
    },
    "webgl-fundamentals.html": {
      "en": true,
      "pl": true
    },
    "webgl-2d-matrices.html": {
      "en": true
    },
    "webgl-how-it-works.html": {
      "en": true
    },
    "webgl-2d-translation.html": {
      "en": true,
      "pl": true
    },
    "webgl-2d-scale.html": {
      "en": true
    },
    "webgl-2d-rotation.html": {
      "en": true,
      "pl": true
    },
    "webgl-boilerplate.html": {
      "en": true
    }
  },
  "langs": {
    "en": {
      "lang": "en",
      "language": "English"
    },
    "pl": {
      "lang": "pl",
      "language": "Polski"
    }
  }
}<|endoftext|>


<commit_before>/**
 * Copyright (c) 2011 Bruno Jouhier <bruno.jouhier@sage.com>
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */
"use strict";
var fs = require("fs");
var path = require("path");
var transform = require("./transform");
var registered = false;

exports.register = function(options) {
	if (registered)
		return;
	registered = true;

	require.extensions[".js"] = function(module, filename) {
		var content = exports.loadFile(filename, options);
		module._compile(content, filename);
	};

	// we'll also override .coffee registration to support streamlining, but
	// only if .coffee has already been registered. if not, nothing to do:
	if (!require.extensions['.coffee'])
		return;

	// .coffee has been registered, so we'll include coffee-script, but be
	// robust to failure (this is an edge case though).
	try {
		var coffee = require('coffee-script');
	} catch (ex) {
		return;
	}

	var origCoffeeRequire = require.extensions['.coffee'];
	require.extensions['.coffee'] = function(module, filename) {
		// we'll only handle files that are named in the streamline style:
		if (!filename.match(/_\.coffee$/)) {
			return origCoffeeRequire(module, filename);
		}

		// coffee compiles by default with a function wrapper. this breaks
		// streamline since the function wrapper doesn't have the necessary
		// callback parameter. we could manually add it (e.g. using regex),
		// but the good news is we don't need coffee's function wrapper,
		// since streamline adds its own, so we tell coffee not to add it.
		var content = transform.transform(coffee.compile(fs.readFileSync(filename, 'utf8'), {
			bare: true
		}));

		module._compile(content, filename);
	};
};
exports.loadFile = function(filename, options) {
	options = options || {};
	options.sourceName = filename;

	var dirname = path.dirname(filename);
	var ext = path.extname(filename);
	var basename = path.basename(filename, ext);
	var filename_;
	var endsWithUnderscore = basename[basename.length - 1] == '_';
	if (endsWithUnderscore) {
		filename_ = filename;
		filename = path.join(dirname, basename.substring(0, basename.length - 1) + ext);
		options.lines = options.lines || "preserve";
	} else {
		filename_  = path.join(dirname, basename + '_' + ext);
		options.lines = options.lines || "mark";
	}
	var mtime = function(fname) {
		try {
			return fs.statSync(fname).mtime;
		} catch (err) {
			return 0;
		}
	}
	var underscore_mtime = mtime(filename_);

	var banner = transform.banner();
	if (options.lines !== "preserve") {
		banner += "\n";
	}

	function _transformIt() {
		if (options.verbose)
			console.log("streamline: transforming: " + filename)
		var content = fs.readFileSync(filename_, 'utf8');
		var transformed = transform.transform(content, options);
		transformed = banner + transformed;
		if (!endsWithUnderscore)
			fs.writeFileSync(filename, transformed, 'utf8');
		return transformed;
	}

	if (underscore_mtime != 0) {
		if (endsWithUnderscore || (!options.forceTransform && underscore_mtime > mtime(filename))) {
			return _transformIt();
		} else {
			var content = fs.readFileSync(filename, 'utf8');
			if (content.substring(0, banner.length) == banner) {
				if (options.verbose)
					console.log("streamline: from cache: " + filename)
				return content;
			} else {
				return _transformIt();
			}
		}
	} else {
		return fs.readFileSync(filename, 'utf8');
	}
}
<commit_msg>Add file-level options support to Coffee files.<commit_after>/**
 * Copyright (c) 2011 Bruno Jouhier <bruno.jouhier@sage.com>
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */
"use strict";
var fs = require("fs");
var path = require("path");
var transform = require("./transform");
var registered = false;

exports.register = function(options) {
	if (registered)
		return;
	registered = true;

	require.extensions[".js"] = function(module, filename) {
		var content = exports.loadFile(filename, options);
		module._compile(content, filename);
	};

	// we'll also override .coffee registration to support streamlining, but
	// only if .coffee has already been registered. if not, nothing to do:
	if (!require.extensions['.coffee'])
		return;

	// .coffee has been registered, so we'll include coffee-script, but be
	// robust to failure (this is an edge case though).
	try {
		var coffee = require('coffee-script');
	} catch (ex) {
		return;
	}

	var origCoffeeRequire = require.extensions['.coffee'];
	require.extensions['.coffee'] = function(module, filename) {
		// we'll only handle files that are named in the streamline style:
		if (!filename.match(/_\.coffee$/)) {
			return origCoffeeRequire(module, filename);
		}

		var content = fs.readFileSync(filename, 'utf8');

		// coffee compiles by default with a function wrapper. this breaks
		// streamline since the function wrapper doesn't have the necessary
		// callback parameter. we could manually add it (e.g. using regex),
		// but the good news is we don't need coffee's function wrapper,
		// since streamline adds its own, so we tell coffee not to add it.
		var compiled = coffee.compile(content, {
			bare: true
		});

        // support the same file-level options that we support in JS, e.g. a
        // custom callback parameter. we unfortunately need to duplicate this
        // logic that's already in transform() because the JS generated by
        // coffee doesn't include single-line comments (e.g. # foo).
        var options;
        var sourceOptions = /streamline\.options\s*=\s*(\{.*\})/.exec(content);
        if (sourceOptions) {
            options = JSON.parse(sourceOptions[1]);
        } else {
            options = {};
        }

        // either way, default to "lines preserve" since we're require()-ing.
        options.lines = options.lines || "preserve";

		module._compile(transform.transform(compiled, options), filename);
	};
};
exports.loadFile = function(filename, options) {
	options = options || {};
	options.sourceName = filename;

	var dirname = path.dirname(filename);
	var ext = path.extname(filename);
	var basename = path.basename(filename, ext);
	var filename_;
	var endsWithUnderscore = basename[basename.length - 1] == '_';
	if (endsWithUnderscore) {
		filename_ = filename;
		filename = path.join(dirname, basename.substring(0, basename.length - 1) + ext);
		options.lines = options.lines || "preserve";
	} else {
		filename_  = path.join(dirname, basename + '_' + ext);
		options.lines = options.lines || "mark";
	}
	var mtime = function(fname) {
		try {
			return fs.statSync(fname).mtime;
		} catch (err) {
			return 0;
		}
	}
	var underscore_mtime = mtime(filename_);

	var banner = transform.banner();
	if (options.lines !== "preserve") {
		banner += "\n";
	}

	function _transformIt() {
		if (options.verbose)
			console.log("streamline: transforming: " + filename)
		var content = fs.readFileSync(filename_, 'utf8');
		var transformed = transform.transform(content, options);
		transformed = banner + transformed;
		if (!endsWithUnderscore)
			fs.writeFileSync(filename, transformed, 'utf8');
		return transformed;
	}

	if (underscore_mtime != 0) {
		if (endsWithUnderscore || (!options.forceTransform && underscore_mtime > mtime(filename))) {
			return _transformIt();
		} else {
			var content = fs.readFileSync(filename, 'utf8');
			if (content.substring(0, banner.length) == banner) {
				if (options.verbose)
					console.log("streamline: from cache: " + filename)
				return content;
			} else {
				return _transformIt();
			}
		}
	} else {
		return fs.readFileSync(filename, 'utf8');
	}
}
<|endoftext|>


<commit_before>var _utils = require('./utils');
var escape = _utils.escape;
var unescape = _utils.unescape;

/**
 * Renderer
 */

var defaultOptions = {
  langPrefix: 'lang-',
  smartypants: false,
  headerPrefix: '',
  xhtml: false,
};

function Renderer(options) {
  this.options = options || defaultOptions;
}

Renderer.prototype.code = function(code, lang, escaped) {
  if (this.options.highlight) {
    var out = this.options.highlight(code, lang);
    if (out != null && out !== code) {
      escaped = true;
      code = out;
    }
  }

  if (!lang) {
    return '
'
      + (escaped ? code : escape(code, true))
      + '\n
';
  }

  return '
'
    + (escaped ? code : escape(code, true))
    + '\n
\n';
};

Renderer.prototype.blockquote = function(quote) {
  return '
\n' + quote + '
\n';
};

Renderer.prototype.html = function(html) {
  return html;
};

Renderer.prototype._createId = function(str) {
  // replace " " and all punctuation characters to "-"
  str = str.toLowerCase().replace(/[\s\]\[\!\"\#\$\%\&\'\(\)\*\+\,\.\/\:\;\<\=\>\?\@\\\^\_\`\{\|\}\~\-]+/g, '-');
  try {
    str = encodeURIComponent(str);
  } catch (e) {
    str = str.replace(/[^\w]+/g, '-');
  }
  return str.replace(/-$/, '');
};

Renderer.prototype.heading = function(text, level, raw) {
  var id = /({#)(.+)(})/g.exec(raw);
  return '<h'
    + level
    + ' id="'
    + this.options.headerPrefix
    + (id ? id[2] : this._createId(raw))
    + '">'
    + text.replace(/{#.+}/g, '')
    + '</h'
    + level
    + '>\n';
};

Renderer.prototype.hr = function() {
  return this.options.xhtml ? '
\n' : '
\n';
};

Renderer.prototype.list = function(body, ordered) {
  var type = ordered ? 'ol' : 'ul';
  return '<' + type + '>\n' + body + '</' + type + '>\n';
};

Renderer.prototype.listitem = function(text) {
  return '
' + text + '
\n';
};

Renderer.prototype.paragraph = function(text) {
  return '
' + text + '
\n';
};

Renderer.prototype.table = function(header, body) {
  return '
\n'
    + '
\n'
    + header
    + '
\n'
    + '
\n'
    + body
    + '
\n'
    + '
\n';
};

Renderer.prototype.tablerow = function(content) {
  return '
\n' + content + '
\n';
};

Renderer.prototype.tablecell = function(content, flags) {
  var type = flags.header ? 'th' : 'td';
  var tag = flags.align
    ? '<' + type + ' style="text-align:' + flags.align + '">'
    : '<' + type + '>';
  return tag + content + '</' + type + '>\n';
};

Renderer.prototype.math = function(content, language, display) {
  mode = display ? '; mode=display' : '';
  return '';
}

// span level renderer
Renderer.prototype.strong = function(text) {
  return '' + text + '';
};

Renderer.prototype.em = function(text) {
  return '' + text + '';
};

Renderer.prototype.codespan = function(text) {
  return '' + text + '';
};

Renderer.prototype.br = function() {
  return this.options.xhtml ? '
' : '
';
};

Renderer.prototype.del = function(text) {
  return '' + text + '';
};

Renderer.prototype.reffn = function(refname) {
  return '' + refname + ''
}

Renderer.prototype.footnote = function(refname, text) {
  return '
\n'
    + '' + refname + '. '
    + text
    + ' ↩\n'
    + '
\n';
}

Renderer.prototype.link = function(href, title, text) {
  if (this.options.sanitize) {
    try {
      var prot = decodeURIComponent(unescape(href))
        .replace(/[^\w:]/g, '')
        .toLowerCase();
    } catch (e) {
      return '';
    }
    if (prot.indexOf('javascript:') === 0) {
      return '';
    }
  }
  var out = '' + text + '';
  return out;
};

Renderer.prototype.image = function(href, title, text) {
  var out = '' : '>';
  return out;
};

module.exports = Renderer;
<commit_msg>Add option headerAutoId to renderer<commit_after>var _utils = require('./utils');
var escape = _utils.escape;
var unescape = _utils.unescape;

/**
 * Renderer
 */

var defaultOptions = {
  langPrefix: 'lang-',
  smartypants: false,
  headerPrefix: '',
  headerAutoId: true,
  xhtml: false,
};

function Renderer(options) {
  this.options = options || defaultOptions;
}

Renderer.prototype.code = function(code, lang, escaped) {
  if (this.options.highlight) {
    var out = this.options.highlight(code, lang);
    if (out != null && out !== code) {
      escaped = true;
      code = out;
    }
  }

  if (!lang) {
    return '
'
      + (escaped ? code : escape(code, true))
      + '\n
';
  }

  return '
'
    + (escaped ? code : escape(code, true))
    + '\n
\n';
};

Renderer.prototype.blockquote = function(quote) {
  return '
\n' + quote + '
\n';
};

Renderer.prototype.html = function(html) {
  return html;
};

Renderer.prototype._createId = function(str) {
  // replace " " and all punctuation characters to "-"
  str = str.toLowerCase().replace(/[\s\]\[\!\"\#\$\%\&\'\(\)\*\+\,\.\/\:\;\<\=\>\?\@\\\^\_\`\{\|\}\~\-]+/g, '-');
  try {
    str = encodeURIComponent(str);
  } catch (e) {
    str = str.replace(/[^\w]+/g, '-');
  }
  return str.replace(/-$/, '');
};

Renderer.prototype.heading = function(text, level, raw) {
  var id = /({#)(.+)(})/g.exec(raw);
  id = id? id[2] : null;

  if (!id && this.options.headerAutoId !== false) id = this._createId(raw)

  return '<h'
    + level
    + (id? ' id="' + id + '"' : '')
    + '>'
    + text.replace(/{#.+}/g, '')
    + '</h'
    + level
    + '>\n';
};

Renderer.prototype.hr = function() {
  return this.options.xhtml ? '
\n' : '
\n';
};

Renderer.prototype.list = function(body, ordered) {
  var type = ordered ? 'ol' : 'ul';
  return '<' + type + '>\n' + body + '</' + type + '>\n';
};

Renderer.prototype.listitem = function(text) {
  return '
' + text + '
\n';
};

Renderer.prototype.paragraph = function(text) {
  return '
' + text + '
\n';
};

Renderer.prototype.table = function(header, body) {
  return '
\n'
    + '
\n'
    + header
    + '
\n'
    + '
\n'
    + body
    + '
\n'
    + '
\n';
};

Renderer.prototype.tablerow = function(content) {
  return '
\n' + content + '
\n';
};

Renderer.prototype.tablecell = function(content, flags) {
  var type = flags.header ? 'th' : 'td';
  var tag = flags.align
    ? '<' + type + ' style="text-align:' + flags.align + '">'
    : '<' + type + '>';
  return tag + content + '</' + type + '>\n';
};

Renderer.prototype.math = function(content, language, display) {
  mode = display ? '; mode=display' : '';
  return '';
}

// span level renderer
Renderer.prototype.strong = function(text) {
  return '' + text + '';
};

Renderer.prototype.em = function(text) {
  return '' + text + '';
};

Renderer.prototype.codespan = function(text) {
  return '' + text + '';
};

Renderer.prototype.br = function() {
  return this.options.xhtml ? '
' : '
';
};

Renderer.prototype.del = function(text) {
  return '' + text + '';
};

Renderer.prototype.reffn = function(refname) {
  return '' + refname + ''
}

Renderer.prototype.footnote = function(refname, text) {
  return '
\n'
    + '' + refname + '. '
    + text
    + ' ↩\n'
    + '
\n';
}

Renderer.prototype.link = function(href, title, text) {
  if (this.options.sanitize) {
    try {
      var prot = decodeURIComponent(unescape(href))
        .replace(/[^\w:]/g, '')
        .toLowerCase();
    } catch (e) {
      return '';
    }
    if (prot.indexOf('javascript:') === 0) {
      return '';
    }
  }
  var out = '' + text + '';
  return out;
};

Renderer.prototype.image = function(href, title, text) {
  var out = '' : '>';
  return out;
};

module.exports = Renderer;
<|endoftext|>