<commit_before>(function ($) {

    $.fn.circliful = function (options, callback) {

        var settings = $.extend({
            // These are the defaults.
            startdegree: 0,
            fgcolor: "#556b2f",
            bgcolor: "#eee",
            fill: false,
            width: 15,
            dimension: 200,
            fontsize: 15,
            percent: 50,
            animationstep: 1.0,
            iconsize: '20px',
            iconcolor: '#999',
            border: 'default',
            complete: null,
            bordersize: 10
        }, options);

        return this.each(function () {

            var customSettings = ["fgcolor", "bgcolor", "fill", "width", "dimension", "fontsize", "animationstep", "endPercent", "icon", "iconcolor", "iconsize", "border", "startdegree", "bordersize"];

            var customSettingsObj = {};
            var icon = '';
            var endPercent = 0;
            var obj = $(this);
            var fill = false;
            var text, info;

            obj.addClass('circliful');

            checkDataAttributes(obj);

            if (obj.data('text') != undefined) {
                text = obj.data('text');

                if (obj.data('icon') != undefined) {
                    icon = $('')
                        .addClass('fa ' + $(this).data('icon'))
                        .css({
                            'color': customSettingsObj.iconcolor,
                            'font-size': customSettingsObj.iconsize
                        });
                }

                if (obj.data('type') != undefined) {
                    type = $(this).data('type');

                    if (type == 'half') {
                        addCircleText(obj, 'circle-text-half', (customSettingsObj.dimension / 1.45));
                    } else {
                        addCircleText(obj, 'circle-text', customSettingsObj.dimension);
                    }
                } else {
                    addCircleText(obj, 'circle-text', customSettingsObj.dimension);
                }
            }

            if ($(this).data("total") != undefined && $(this).data("part") != undefined) {
                var total = $(this).data("total") / 100;

                percent = (($(this).data("part") / total) / 100).toFixed(3);
                endPercent = ($(this).data("part") / total).toFixed(3)
            } else {
                if ($(this).data("percent") != undefined) {
                    percent = $(this).data("percent") / 100;
                    endPercent = $(this).data("percent")
                } else {
                    percent = settings.percent / 100
                }
            }

            if ($(this).data('info') != undefined) {
                info = $(this).data('info');

                if ($(this).data('type') != undefined) {
                    type = $(this).data('type');

                    if (type == 'half') {
                        addInfoText(obj, 0.9);
                    } else {
                        addInfoText(obj, 1.25);
                    }
                } else {
                    addInfoText(obj, 1.25);
                }
            }

            $(this).width(customSettingsObj.dimension + 'px');

            var canvas = $('<canvas></canvas>').attr({
                width: customSettingsObj.dimension,
                height: customSettingsObj.dimension
            }).appendTo($(this)).get(0);

            var context = canvas.getContext('2d');
            var container = $(canvas).parent();
            var x = canvas.width / 2;
            var y = canvas.height / 2;
            var degrees = customSettingsObj.percent * 360.0;
            var radians = degrees * (Math.PI / 180);
            var radius = canvas.width / 2.5;
            var startAngle = 2.3 * Math.PI;
            var endAngle = 0;
            var counterClockwise = false;
            var curPerc = customSettingsObj.animationstep === 0.0 ? endPercent : 0.0;
            var curStep = Math.max(customSettingsObj.animationstep, 0.0);
            var circ = Math.PI * 2;
            var quart = Math.PI / 2;
            var type = '';
            var fireCallback = true;
            var additionalAngelPI = (customSettingsObj.startdegree / 180) * Math.PI;

            if ($(this).data('type') != undefined) {
                type = $(this).data('type');

                if (type == 'half') {
                    startAngle = 2.0 * Math.PI;
                    endAngle = 3.13;
                    circ = Math.PI;
                    quart = Math.PI / 0.996;
                }
            }

            //Run function when browser resizes
            $(window).resize(respondCanvas);

            function respondCanvas() {
                $(canvas).attr('width', $(container).width()); //max width

                if(type == 'half') {
                    $(canvas).attr('height', $(container).height() / 2); //max height
                } else {
                    $(canvas).attr('height', $(container).height()); //max height
                }

                //Call a function to redraw other content (texts, images etc)
            }

            //Initial call
            respondCanvas();

            /**
             * adds text to circle
             *
             * @param obj
             * @param cssClass
             * @param lineHeight
             */
            function addCircleText(obj, cssClass, lineHeight) {
                $("")
                    .appendTo(obj)
                    .addClass(cssClass)
                    .text(text)
                    .prepend(icon)
                    .css({
                        'line-height': lineHeight + 'px',
                        'font-size': customSettingsObj.fontsize + 'px'
                    });
            }

            /**
             * adds info text to circle
             *
             * @param obj
             * @param factor
             */
            function addInfoText(obj, factor) {
                $('')
                    .appendTo(obj)
                    .addClass('circle-info-half')
                    .css(
                        'line-height', (customSettingsObj.dimension * factor) + 'px'
                    )
                    .text(info);
            }

            /**
             * checks which data attributes are defined
             * @param obj
             */
            function checkDataAttributes(obj) {
                $.each(customSettings, function (index, attribute) {
                    if (obj.data(attribute) != undefined) {
                        customSettingsObj[attribute] = obj.data(attribute);
                    } else {
                        customSettingsObj[attribute] = $(settings).attr(attribute);
                    }

                    if (attribute == 'fill' && obj.data('fill') != undefined) {
                        fill = true;
                    }
                });
            }

            /**
             * animate foreground circle
             * @param current
             */
            function animate(current) {

                context.clearRect(0, 0, canvas.width, canvas.height);

                context.beginPath();
                context.arc(x, y, radius, endAngle, startAngle, false);

                context.lineWidth = customSettingsObj.bordersize + 1;

                context.strokeStyle = customSettingsObj.bgcolor;
                context.stroke();

                if (fill) {
                    context.fillStyle = customSettingsObj.fill;
                    context.fill();
                }

                context.beginPath();
                context.arc(x, y, radius, -(quart) + additionalAngelPI, ((circ) * current) - quart + additionalAngelPI, false);

                if (customSettingsObj.border == 'outline') {
                    context.lineWidth = customSettingsObj.width + 13;
                } else if (customSettingsObj.border == 'inline') {
                    context.lineWidth = customSettingsObj.width - 13;
                }

                context.strokeStyle = customSettingsObj.fgcolor;
                context.stroke();

                if (curPerc < endPercent) {
                    curPerc += curStep;
                    requestAnimationFrame(function () {
                        animate(Math.min(curPerc, endPercent) / 100);
                    }, obj);
                }

                if (curPerc == endPercent && fireCallback && typeof(options) != "undefined") {
                    if ($.isFunction(options.complete)) {
                        options.complete();

                        fireCallback = false;
                    }
                }
            }

            animate(curPerc / 100);

        });
    };
}(jQuery));
<commit_msg>Added new angle version <commit_after>(function ($) {

    $.fn.circliful = function (options, callback) {

        var settings = $.extend({
            // These are the defaults.
            startdegree: 0,
            fgcolor: "#556b2f",
            bgcolor: "#eee",
            fill: false,
            width: 15,
            dimension: 200,
            fontsize: 15,
            percent: 50,
            animationstep: 1.0,
            iconsize: '20px',
            iconcolor: '#999',
            border: 'default',
            complete: null,
            bordersize: 10
        }, options);

        return this.each(function () {

            var customSettings = ["fgcolor", "bgcolor", "fill", "width", "dimension", "fontsize", "animationstep", "endPercent", "icon", "iconcolor", "iconsize", "border", "startdegree", "bordersize"];

            var customSettingsObj = {};
            var icon = '';
            var endPercent = 0;
            var obj = $(this);
            var fill = false;
            var text, info;

            obj.addClass('circliful');

            checkDataAttributes(obj);

            if (obj.data('text') != undefined) {
                text = obj.data('text');

                if (obj.data('icon') != undefined) {
                    icon = $('')
                        .addClass('fa ' + $(this).data('icon'))
                        .css({
                            'color': customSettingsObj.iconcolor,
                            'font-size': customSettingsObj.iconsize
                        });
                }

                if (obj.data('type') != undefined) {
                    type = $(this).data('type');

                    if (type == 'half') {
                        addCircleText(obj, 'circle-text-half', (customSettingsObj.dimension / 1.45));
                    } else {
                        addCircleText(obj, 'circle-text', customSettingsObj.dimension);
                    }
                } else {
                    addCircleText(obj, 'circle-text', customSettingsObj.dimension);
                }
            }

            if ($(this).data("total") != undefined && $(this).data("part") != undefined) {
                var total = $(this).data("total") / 100;

                percent = (($(this).data("part") / total) / 100).toFixed(3);
                endPercent = ($(this).data("part") / total).toFixed(3)
            } else {
                if ($(this).data("percent") != undefined) {
                    percent = $(this).data("percent") / 100;
                    endPercent = $(this).data("percent")
                } else {
                    percent = settings.percent / 100
                }
            }

            if ($(this).data('info') != undefined) {
                info = $(this).data('info');

                if ($(this).data('type') != undefined) {
                    type = $(this).data('type');

                    if (type == 'half') {
                        addInfoText(obj, 0.9);
                    } else {
                        addInfoText(obj, 1.25);
                    }
                } else {
                    addInfoText(obj, 1.25);
                }
            }

            $(this).width(customSettingsObj.dimension + 'px');

            var canvas = $('<canvas></canvas>').attr({
                width: customSettingsObj.dimension,
                height: customSettingsObj.dimension
            }).appendTo($(this)).get(0);

            var context = canvas.getContext('2d');
            var container = $(canvas).parent();
            var x = canvas.width / 2;
            var y = canvas.height / 2;
            var degrees = customSettingsObj.percent * 360.0;
            var radians = degrees * (Math.PI / 180);
            var radius = canvas.width / 2.5;
            var startAngle = 2.3 * Math.PI;
            var endAngle = 0;
            var counterClockwise = false;
            var curPerc = customSettingsObj.animationstep === 0.0 ? endPercent : 0.0;
            var curStep = Math.max(customSettingsObj.animationstep, 0.0);
            var circ = Math.PI * 2;
            var quart = Math.PI / 2;
            var type = '';
            var fireCallback = true;
            var additionalAngelPI = (customSettingsObj.startdegree / 180) * Math.PI;

            if ($(this).data('type') != undefined) {
                type = $(this).data('type');

                if (type == 'half') {
                    startAngle = 2.0 * Math.PI;
                    endAngle = 3.13;
                    circ = Math.PI;
                    quart = Math.PI / 0.996;
                }
            }

            if ($(this).data('type') != undefined) {
                type = $(this).data('type');

                if (type == 'angle') {
                    startAngle = 2.25 * Math.PI;
                    endAngle = 2.4;
                    circ = 1.53 + Math.PI;
                    quart = 0.73 + Math.PI / 0.996;
                }
            }

            //Run function when browser resizes
            $(window).resize(respondCanvas);

            function respondCanvas() {
                $(canvas).attr('width', $(container).width()); //max width

                if(type == 'half') {
                    $(canvas).attr('height', $(container).height() / 2); //max height
                } else {
                    $(canvas).attr('height', $(container).height()); //max height
                }

                //Call a function to redraw other content (texts, images etc)
            }

            //Initial call
            respondCanvas();

            /**
             * adds text to circle
             *
             * @param obj
             * @param cssClass
             * @param lineHeight
             */
            function addCircleText(obj, cssClass, lineHeight) {
                $("")
                    .appendTo(obj)
                    .addClass(cssClass)
                    .text(text)
                    .prepend(icon)
                    .css({
                        'line-height': lineHeight + 'px',
                        'font-size': customSettingsObj.fontsize + 'px'
                    });
            }

            /**
             * adds info text to circle
             *
             * @param obj
             * @param factor
             */
            function addInfoText(obj, factor) {
                $('')
                    .appendTo(obj)
                    .addClass('circle-info-half')
                    .css(
                        'line-height', (customSettingsObj.dimension * factor) + 'px'
                    )
                    .text(info);
            }

            /**
             * checks which data attributes are defined
             * @param obj
             */
            function checkDataAttributes(obj) {
                $.each(customSettings, function (index, attribute) {
                    if (obj.data(attribute) != undefined) {
                        customSettingsObj[attribute] = obj.data(attribute);
                    } else {
                        customSettingsObj[attribute] = $(settings).attr(attribute);
                    }

                    if (attribute == 'fill' && obj.data('fill') != undefined) {
                        fill = true;
                    }
                });
            }

            /**
             * animate foreground circle
             * @param current
             */
            function animate(current) {

                context.clearRect(0, 0, canvas.width, canvas.height);

                context.beginPath();
                context.arc(x, y, radius, endAngle, startAngle, false);

                context.lineWidth = customSettingsObj.bordersize + 1;

                context.strokeStyle = customSettingsObj.bgcolor;
                context.stroke();

                if (fill) {
                    context.fillStyle = customSettingsObj.fill;
                    context.fill();
                }

                context.beginPath();
                context.arc(x, y, radius, -(quart) + additionalAngelPI, ((circ) * current) - quart + additionalAngelPI, false);

                if (customSettingsObj.border == 'outline') {
                    context.lineWidth = customSettingsObj.width + 13;
                } else if (customSettingsObj.border == 'inline') {
                    context.lineWidth = customSettingsObj.width - 13;
                }

                context.strokeStyle = customSettingsObj.fgcolor;
                context.stroke();

                if (curPerc < endPercent) {
                    curPerc += curStep;
                    requestAnimationFrame(function () {
                        animate(Math.min(curPerc, endPercent) / 100);
                    }, obj);
                }

                if (curPerc == endPercent && fireCallback && typeof(options) != "undefined") {
                    if ($.isFunction(options.complete)) {
                        options.complete();

                        fireCallback = false;
                    }
                }
            }

            animate(curPerc / 100);

        });
    };
}(jQuery));
<|endoftext|>


<commit_before>'use strict';

var TestimonialSlide = function(data, options) {
  this.data = this.createData(data);

  this.createOptions(options);
  this.createSlide();
};

TestimonialSlide.prototype = {
  createData: function(data) {
    var emptydata = {
      author: {
        name: '',
        url: '',
        avatar: ''
      },
      company: {
        name: '',
        url: ''
      },
      quote: ''
    };
    var resultData = $.extend(emptydata, data);
    return resultData;
  },

  createOptions: function(options) {
    var defaultOptions = this.getDefaultOptions();
    this.options = $.extend({}, defaultOptions, options);
  },

  getDefaultOptions: function() {
    var defaultOptions = {
      width: 700,
      duration: 750,
      distance: 250,
      cssClass: 'testimonial_slide',
      indents: 20
    };
    return defaultOptions;
  },

  setHeightForBlockDiv: function() {
    var height = this.$domNode.height();
    this.$domNode.find('.block').height(height);
  },

  createSlide: function() {
    this.createTemplate();
    this.renderTemplate();
  },

  animateHide: function() {
    var self = this;

    var marginLeft = '+=' + this.options.distance + 'px';
    var options = {
      'margin-left': marginLeft,
      opacity: '0'
    };

    this.$domNode.animate(options,
      this.options.duration,
      function() {
        self.hideSlide();
      }
    );
  },

  animateShow: function() {
    var marginLeft = '+=' + this.options.distance + 'px';
    var options = {
      'margin-left': marginLeft,
      opacity: '1'
    };

    var duration = this.options.duration * 2;
    this.$domNode.show().animate(options, duration);
  },

  hideSlide: function() {
    var marginLeft = '-' + this.options.distance + 'px';
    var css = {
      display: 'none',
      opacity: 0,
      'margin-left': marginLeft
    };
    this.$domNode.css(css);
  },

  height: function() {
    return this.$domNode.height();
  },

  remove: function() {
    this.$domNode.empty();
    this.$domNode.remove();
  },

  createTemplate: function() {
    this.template = '' +
      '
' +
        '
' +
          '
' +
            '
' +
              '
' +
                '' +
              '
' +
              '{{slide.quote}}' +
              '
' +
                '' +
              '
' +
            '
' +
            '
' +
              '
' +
                '―' +
                  '{{slide.author.name}}' +
                '' +
              '
' +
              '
' +
                '' +
                  '{{slide.company.name}}' +
                '' +
              '
' +
            '
' +
          '
' +
          '
' +
            '
' +
              '
' +
                '' +
              '
' +
              '
' +
              '
' +
            '
' +
          '
' +
        '
' +
      '
';
  },

  renderTemplate: function() {
    /* global Handlebars: false */
    var template = Handlebars.compile(this.template);
    var data = this.getDataForTemplate();
    var result = template(data);
    this.$domNode = $(result);
  },

  getDataForTemplate: function() {
    var magicNumber = 180;
    var width = this.options.width - magicNumber;
    var data = {
      main: {
        width: width
      }
    };
    data.slide = this.data;
    data.slide.width = this.options.width - this.options.indents;
    return data;
  },

  renderTo: function($parent) {
    $parent.append(this.$domNode);
    this.setHeightForBlockDiv();
  }
};
<commit_msg>Update<commit_after>'use strict';

var TestimonialSlide = function(data, options) {
  this.data = this.createData(data);

  this.createOptions(options);
  this.createSlide();
};

TestimonialSlide.prototype = {
  createData: function(data) {
    var emptydata = {
      author: {
        name: '',
        url: '',
        avatar: ''
      },
      company: {
        name: '',
        url: ''
      },
      quote: ''
    };
    var resultData = $.extend(emptydata, data);
    return resultData;
  },

  createOptions: function(options) {
    var defaultOptions = this.getDefaultOptions();
    this.options = $.extend({}, defaultOptions, options);
  },

  getDefaultOptions: function() {
    var defaultOptions = {
      width: 700,
      duration: 750,
      distance: 250,
      cssClass: 'testimonial_slide',
      indents: 20
    };
    return defaultOptions;
  },

  setHeightForBlockDiv: function() {
    var height = this.$domNode.height();
    this.$domNode.find('.block').height(height);
  },

  createSlide: function() {
    this.createTemplate();
    this.renderTemplate();
  },

  animateHide: function() {
    var self = this;

    var marginLeft = '+=' + this.options.distance + 'px';
    var options = {
      'margin-left': marginLeft,
      opacity: '0'
    };

    this.$domNode.animate(options,
      this.options.duration,
      function() {
        self.hideSlide();
      }
    );
  },

  animateShow: function() {
    var marginLeft = '+=' + this.options.distance + 'px';
    var options = {
      'margin-left': marginLeft,
      opacity: '1'
    };

    var duration = this.options.duration * 2;
    this.$domNode.show().animate(options, duration);
  },

  hideSlide: function() {
    var marginLeft = '-' + this.options.distance + 'px';
    var css = {
      display: 'none',
      opacity: 0,
      'margin-left': marginLeft
    };
    this.$domNode.css(css);
  },

  height: function() {
    return this.$domNode.height();
  },

  remove: function() {
    this.$domNode.empty();
    this.$domNode.remove();
  },

  createTemplate: function() {
    this.template = '' +
      '
' +
        '
' +
          '
' +
            '
' +
              '
' +
                '' +
              '
' +
              '{{slide.quote}}' +
              '
' +
                '' +
              '
' +
            '
' +
            '
' +
              '
' +
                '― ' +
                  '{{slide.author.name}}' +
                '' +
              '
' +
              '
' +
                '' +
                  '{{slide.company.name}}' +
                '' +
              '
' +
            '
' +
          '
' +
          '
' +
            '
' +
              '
' +
                '' +
              '
' +
              '
' +
              '
' +
            '
' +
          '
' +
        '
' +
      '
';
  },

  renderTemplate: function() {
    /* global Handlebars: false */
    var template = Handlebars.compile(this.template);
    var data = this.getDataForTemplate();
    var result = template(data);
    this.$domNode = $(result);
  },

  getDataForTemplate: function() {
    var magicNumber = 180;
    var width = this.options.width - magicNumber;
    var data = {
      main: {
        width: width
      }
    };
    data.slide = this.data;
    data.slide.width = this.options.width - this.options.indents;
    return data;
  },

  renderTo: function($parent) {
    $parent.append(this.$domNode);
    this.setHeightForBlockDiv();
  }
};
<|endoftext|>


<commit_before>// Substitutes

var chars = {
	'o': ['0'],
	'e': ['3'],
	'i': ['1']
}

// this is matched using regex (case-insensitive)
var words = {
	'tha': 'da',
	'wha': 'wa'
}
// the follwing should match at word end (or they should be complete words)
var endWords = {
	'you': 'u',
	'ith': 'id',
	'the': 'da',
	'this': 'dis',
	'([ei])s': '$1zz',  // lookahead if word end
	'my': 'mah'
}

// convert endWords into words
for (var key in endWords){
	words[key + '(?=[^a-z])'] = endWords[key]
}

function convertChars(text){
	var text = String(text)
	var probab = 0.6

	for (var key in words) {
		reg = new RegExp(key, "gi")
		if (reg.test(text)){
			chance = Math.random()
			if (chance <= probab){
				text = text.replace(reg, words[key])
			}
		}
	}

	return text
}

function loadSubstitutes(orig, newCh){
	list = [newCh]
	orig = orig.toLowerCase()
	if (orig in chars) {
		Array.prototype.push.apply(list, chars[orig]);
	}
	return list
}

function convertSingleChar(text){
	var probab = 0.5
	len = text.length
	var newText = ""

	for (var i=0; i < len; i++){
		charCode = text[i].charCodeAt()
		chance = Math.random()

		if (chance <= probab){
			if (charCode >= 65 && charCode <= 90){
				subs = loadSubstitutes(text[i], String.fromCharCode(charCode + 32))
				newText += subs[Math.floor(Math.random() * subs.length)]; // random from list
			} else if (charCode >= 97 && charCode <= 122){
				subs = loadSubstitutes(text[i], String.fromCharCode(charCode - 32))
				newText += subs[Math.floor(Math.random() * subs.length)];
			} else {
				newText += text[i]
			}
		} else {
			newText += text[i]
		}
	}

	return newText
}

function inputChangeEvent(){
	val = $("#input").val()
	newVal = convertChars(val)
	console.log(newVal)
	newVal = convertSingleChar(newVal)
	console.log(newVal)
	$("#output").text(newVal)
}

$(document).ready(function(){
	$("#input").bind('input propertychange', inputChangeEvent)
})
<commit_msg>major update, don’t substitute all strings together<commit_after>// Substitutes

var chars = {
	'o': ['0'],
	'e': ['3'],
	'i': ['1']
}

// this is matched using regex (case-insensitive)
var words = {
	'tha': 'da',
	'wha': 'wa'
}
// the follwing should match at word end (or they should be complete words)
var endWords = {
	'you': 'u',
	'ith': 'id',
	'the': 'da',
	'this': 'dis',
	'es': 'ezz',  // lookahead if word end
	'my': 'mah'
}

// convert endWords into words
for (var key in endWords){
	words[key + '(?=[^a-z])'] = endWords[key]
}

function convertChars(text){
	var text = String(text)
	var probab = 0.5

	for (var key in words) {
		reg = new RegExp(key, "gi")
		var bracketCount = (key.match(/\(/g) || []).length

		if (reg.test(text)){
			// replace
			text = text.replace(reg, (match, p1, p2) => {
				chance = Math.random()
				if (chance <= probab){
					if (bracketCount < 2){
						return words[key]
					} else if (bracketCount == 2){
						return words[key].replace("$1", p1)
					}
				} else {
					return match
				}
			})
			// end replace
		}
	}

	return text
}

function loadSubstitutes(orig, newCh){
	list = [newCh]
	orig = orig.toLowerCase()
	if (orig in chars) {
		Array.prototype.push.apply(list, chars[orig]);
	}
	return list
}

function convertSingleChar(text){
	var probab = 0.5
	len = text.length
	var newText = ""

	for (var i=0; i < len; i++){
		charCode = text[i].charCodeAt()
		chance = Math.random()

		if (chance <= probab){
			if (charCode >= 65 && charCode <= 90){
				subs = loadSubstitutes(text[i], String.fromCharCode(charCode + 32))
				newText += subs[Math.floor(Math.random() * subs.length)]; // random from list
			} else if (charCode >= 97 && charCode <= 122){
				subs = loadSubstitutes(text[i], String.fromCharCode(charCode - 32))
				newText += subs[Math.floor(Math.random() * subs.length)];
			} else {
				newText += text[i]
			}
		} else {
			newText += text[i]
		}
	}

	return newText
}

function inputChangeEvent(){
	val = $("#input").val()
	newVal = convertChars(val)
	console.log(newVal)
	newVal = convertSingleChar(newVal)
	console.log(newVal)
	$("#output").text(newVal)
}

$(document).ready(function(){
	$("#input").bind('input propertychange', inputChangeEvent)
})
<|endoftext|>


<commit_before>// It's important that the polyfills and error fallback get loaded first!
import {} from "src/browser/Polyfills.js"
import {hookErrorHandler} from "src/fallback.js"
hookErrorHandler();
import {} from "src/issues.js"

import CircuitDefinition from "src/circuit/CircuitDefinition.js"
import CooldownThrottle from "src/base/CooldownThrottle.js"
import Config from "src/Config.js"
import DisplayedInspector from "src/ui/DisplayedInspector.js"
import Painter from "src/draw/Painter.js"
import Rect from "src/math/Rect.js"
import RestartableRng from "src/base/RestartableRng.js"
import Revision from "src/base/Revision.js"
import Serializer from "src/circuit/Serializer.js"
import TouchScrollBlocker from "src/browser/TouchScrollBlocker.js"
import Util from "src/base/Util.js"
import { initializedWglContext } from "src/webgl/WglContext.js"
import { watchDrags, isMiddleClicking, eventPosRelativeTo } from "src/browser/MouseWatcher.js"
import { Observable, ObservableValue } from "src/base/Obs.js"
import { initExports } from "src/ui/exports.js"
import { initForge } from "src/ui/forge.js"
import { initUndoRedo } from "src/ui/undo.js"
import { initUrlCircuitSync } from "src/ui/url.js"
import { initTitleSync } from "src/ui/title.js"
import { simulate } from "src/ui/sim.js"

const canvasDiv = document.getElementById("canvasDiv");

//noinspection JSValidateTypes
/** @type {!HTMLCanvasElement} */
const canvas = document.getElementById("drawCanvas");
//noinspection JSValidateTypes
if (!canvas) {
    throw new Error("Couldn't find 'drawCanvas'");
}
canvas.width = canvasDiv.clientWidth;
canvas.height = window.innerHeight*0.9;
let haveLoaded = false;
const semiStableRng = (() => {
    const target = {cur: new RestartableRng()};
    let cycleRng;
    cycleRng = () => {
        target.cur = new RestartableRng();
        //noinspection DynamicallyGeneratedCodeJS
        setTimeout(cycleRng, Config.SEMI_STABLE_RANDOM_VALUE_LIFETIME_MILLIS*0.99);
    };
    cycleRng();
    return target;
})();

//noinspection JSValidateTypes
/** @type {!HTMLDivElement} */
const inspectorDiv = document.getElementById("inspectorDiv");

/** @type {ObservableValue.<!DisplayedInspector>} */
const displayed = new ObservableValue(
    DisplayedInspector.empty(new Rect(0, 0, canvas.clientWidth, canvas.clientHeight)));
/** @type {!Revision} */
let revision = Revision.startingAt(displayed.get().snapshot());

revision.latestActiveCommit().subscribe(jsonText => {
    let circuitDef = Serializer.fromJson(CircuitDefinition, JSON.parse(jsonText));
    let newInspector = displayed.get().withCircuitDefinition(circuitDef);
    displayed.set(newInspector);
});

let desiredCanvasSizeFor = curInspector => {
    return {
        w: Math.max(canvasDiv.clientWidth, curInspector.desiredWidth()),
        h: curInspector.desiredHeight()
    };
};

/**
 * @param {!DisplayedInspector} ins
 * @returns {!DisplayedInspector}
 */
const syncArea = ins => {
    let size = desiredCanvasSizeFor(ins);
    ins.updateArea(new Rect(0, 0, size.w, size.h));
    return ins;
};

// Gradually fade out old errors as user manipulates circuit.
displayed.observable().
    map(e => e.displayedCircuit.circuitDefinition).
    whenDifferent(Util.CUSTOM_IS_EQUAL_TO_EQUALITY).
    subscribe(() => {
        let errDivStyle = document.getElementById('error-div').style;
        errDivStyle.opacity *= 0.9;
        if (errDivStyle.opacity < 0.06) {
            errDivStyle.display = 'None'
        }
    });

/** @type {!CooldownThrottle} */
let redrawThrottle;
const scrollBlocker = new TouchScrollBlocker(canvasDiv);
const redrawNow = () => {
    if (!haveLoaded) {
        // Don't draw while loading. It's a huge source of false-positive circuit-load-failed errors during development.
        return;
    }

    let shown = syncArea(displayed.get()).previewDrop();
    let stats = simulate(shown.displayedCircuit.circuitDefinition);

    let size = desiredCanvasSizeFor(shown);
    canvas.width = size.w;
    canvas.height = size.h;
    let painter = new Painter(canvas, semiStableRng.cur.restarted());
    shown.updateArea(painter.paintableArea());
    shown.paint(painter, stats);
    painter.paintDeferred();

    displayed.get().hand.paintCursor(painter);
    scrollBlocker.setBlockers(painter.touchBlockers, painter.desiredCursorStyle);
    canvas.style.cursor = painter.desiredCursorStyle || 'auto';

    let dt = displayed.get().stableDuration();
    if (dt < Infinity) {
        window.requestAnimationFrame(() => redrawThrottle.trigger());
    }
};
redrawThrottle = new CooldownThrottle(redrawNow, Config.REDRAW_COOLDOWN_MILLIS);
window.addEventListener('resize', () => redrawThrottle.trigger(), false);
displayed.observable().subscribe(() => redrawThrottle.trigger());

watchDrags(canvasDiv,
    /**
     * Grab
     * @param {!Point} pt
     * @param {!MouseEvent|!TouchEvent} ev
     */
    (pt, ev) => {
        let oldInspector = displayed.get();
        let newHand = oldInspector.hand.withPos(pt);
        let newInspector = syncArea(oldInspector.withHand(newHand)).afterGrabbing(ev.shiftKey);
        if (displayed.get().isEqualTo(newInspector) || !newInspector.hand.isBusy()) {
            return;
        }

        // Add extra wire temporarily.
        revision.startedWorkingOnCommit();
        displayed.set(
            syncArea(oldInspector.withHand(newHand).withJustEnoughWires(newInspector.hand, 1)).
                afterGrabbing(ev.shiftKey));

        ev.preventDefault();
    },
    /**
     * Cancel
     * @param {!MouseEvent|!TouchEvent} ev
     */
    ev => {
        revision.cancelCommitBeingWorkedOn();
        ev.preventDefault();
    },
    /**
     * Drag
     * @param {undefined|!Point} pt
     * @param {!MouseEvent|!TouchEvent} ev
     */
    (pt, ev) => {
        if (!displayed.get().hand.isBusy()) {
            return;
        }

        let newHand = displayed.get().hand.withPos(pt);
        let newInspector = displayed.get().withHand(newHand);
        displayed.set(newInspector);
        ev.preventDefault();
    },
    /**
     * Drop
     * @param {undefined|!Point} pt
     * @param {!MouseEvent|!TouchEvent} ev
     */
    (pt, ev) => {
        if (!displayed.get().hand.isBusy()) {
            return;
        }

        let newHand = displayed.get().hand.withPos(pt);
        let newInspector = syncArea(displayed.get()).withHand(newHand).afterDropping().afterTidyingUp();
        let clearHand = newInspector.hand.withPos(undefined);
        let clearInspector = newInspector.withJustEnoughWires(clearHand, 0);
        revision.commit(clearInspector.snapshot());
        ev.preventDefault();
    });

// Middle-click to delete a gate.
canvasDiv.addEventListener('mousedown', ev => {
    if (!isMiddleClicking(ev)) {
        return;
    }
    let newHand = displayed.get().hand.withPos(eventPosRelativeTo(ev, canvas));
    let newInspector = syncArea(displayed.get()).
        withHand(newHand).
        afterGrabbing(false). // Grab the gate.
        withHand(newHand). // Lose the gate.
        afterTidyingUp().
        withJustEnoughWires(newHand, 0);
    if (!displayed.get().isEqualTo(newInspector)) {
        revision.commit(newInspector.snapshot());
        ev.preventDefault();
    }
});

// When mouse moves without dragging, track it (for showing hints and things).
canvasDiv.addEventListener('mousemove', ev => {
    if (!displayed.get().hand.isBusy()) {
        let newHand = displayed.get().hand.withPos(eventPosRelativeTo(ev, canvas));
        let newInspector = displayed.get().withHand(newHand);
        displayed.set(newInspector);
    }
});
document.addEventListener('mouseleave', () => {
    if (!displayed.get().hand.isBusy()) {
        let newHand = displayed.get().hand.withPos(undefined);
        let newInspector = displayed.get().withHand(newHand);
        displayed.set(newInspector);
    }
});

initUrlCircuitSync(revision);
initExports(revision);
initForge(revision);
initUndoRedo(revision);
initTitleSync(revision);

// If the webgl initialization is going to fail, don't fail during the module loading phase.
haveLoaded = true;
setTimeout(() => {
    inspectorDiv.style.display = 'block';
    redrawNow();
    document.getElementById("loading-div").style.display = 'none';
    try {
        initializedWglContext().onContextRestored = () => redrawThrottle.trigger();
    } catch (ex) {
        // If that failed, the user is already getting warnings about WebGL not being supported.
        // Just silently log it.
        console.error(ex);
    }
}, 0);
<commit_msg>Fixed tooltips continuing to display when cursor quickly leaves canvas<commit_after>// It's important that the polyfills and error fallback get loaded first!
import {} from "src/browser/Polyfills.js"
import {hookErrorHandler} from "src/fallback.js"
hookErrorHandler();
import {} from "src/issues.js"

import CircuitDefinition from "src/circuit/CircuitDefinition.js"
import CooldownThrottle from "src/base/CooldownThrottle.js"
import Config from "src/Config.js"
import DisplayedInspector from "src/ui/DisplayedInspector.js"
import Painter from "src/draw/Painter.js"
import Rect from "src/math/Rect.js"
import RestartableRng from "src/base/RestartableRng.js"
import Revision from "src/base/Revision.js"
import Serializer from "src/circuit/Serializer.js"
import TouchScrollBlocker from "src/browser/TouchScrollBlocker.js"
import Util from "src/base/Util.js"
import { initializedWglContext } from "src/webgl/WglContext.js"
import { watchDrags, isMiddleClicking, eventPosRelativeTo } from "src/browser/MouseWatcher.js"
import { Observable, ObservableValue } from "src/base/Obs.js"
import { initExports } from "src/ui/exports.js"
import { initForge } from "src/ui/forge.js"
import { initUndoRedo } from "src/ui/undo.js"
import { initUrlCircuitSync } from "src/ui/url.js"
import { initTitleSync } from "src/ui/title.js"
import { simulate } from "src/ui/sim.js"

const canvasDiv = document.getElementById("canvasDiv");

//noinspection JSValidateTypes
/** @type {!HTMLCanvasElement} */
const canvas = document.getElementById("drawCanvas");
//noinspection JSValidateTypes
if (!canvas) {
    throw new Error("Couldn't find 'drawCanvas'");
}
canvas.width = canvasDiv.clientWidth;
canvas.height = window.innerHeight*0.9;
let haveLoaded = false;
const semiStableRng = (() => {
    const target = {cur: new RestartableRng()};
    let cycleRng;
    cycleRng = () => {
        target.cur = new RestartableRng();
        //noinspection DynamicallyGeneratedCodeJS
        setTimeout(cycleRng, Config.SEMI_STABLE_RANDOM_VALUE_LIFETIME_MILLIS*0.99);
    };
    cycleRng();
    return target;
})();

//noinspection JSValidateTypes
/** @type {!HTMLDivElement} */
const inspectorDiv = document.getElementById("inspectorDiv");

/** @type {ObservableValue.<!DisplayedInspector>} */
const displayed = new ObservableValue(
    DisplayedInspector.empty(new Rect(0, 0, canvas.clientWidth, canvas.clientHeight)));
/** @type {!Revision} */
let revision = Revision.startingAt(displayed.get().snapshot());

revision.latestActiveCommit().subscribe(jsonText => {
    let circuitDef = Serializer.fromJson(CircuitDefinition, JSON.parse(jsonText));
    let newInspector = displayed.get().withCircuitDefinition(circuitDef);
    displayed.set(newInspector);
});

let desiredCanvasSizeFor = curInspector => {
    return {
        w: Math.max(canvasDiv.clientWidth, curInspector.desiredWidth()),
        h: curInspector.desiredHeight()
    };
};

/**
 * @param {!DisplayedInspector} ins
 * @returns {!DisplayedInspector}
 */
const syncArea = ins => {
    let size = desiredCanvasSizeFor(ins);
    ins.updateArea(new Rect(0, 0, size.w, size.h));
    return ins;
};

// Gradually fade out old errors as user manipulates circuit.
displayed.observable().
    map(e => e.displayedCircuit.circuitDefinition).
    whenDifferent(Util.CUSTOM_IS_EQUAL_TO_EQUALITY).
    subscribe(() => {
        let errDivStyle = document.getElementById('error-div').style;
        errDivStyle.opacity *= 0.9;
        if (errDivStyle.opacity < 0.06) {
            errDivStyle.display = 'None'
        }
    });

/** @type {!CooldownThrottle} */
let redrawThrottle;
const scrollBlocker = new TouchScrollBlocker(canvasDiv);
const redrawNow = () => {
    if (!haveLoaded) {
        // Don't draw while loading. It's a huge source of false-positive circuit-load-failed errors during development.
        return;
    }

    let shown = syncArea(displayed.get()).previewDrop();
    let stats = simulate(shown.displayedCircuit.circuitDefinition);

    let size = desiredCanvasSizeFor(shown);
    canvas.width = size.w;
    canvas.height = size.h;
    let painter = new Painter(canvas, semiStableRng.cur.restarted());
    shown.updateArea(painter.paintableArea());
    shown.paint(painter, stats);
    painter.paintDeferred();

    displayed.get().hand.paintCursor(painter);
    scrollBlocker.setBlockers(painter.touchBlockers, painter.desiredCursorStyle);
    canvas.style.cursor = painter.desiredCursorStyle || 'auto';

    let dt = displayed.get().stableDuration();
    if (dt < Infinity) {
        window.requestAnimationFrame(() => redrawThrottle.trigger());
    }
};
redrawThrottle = new CooldownThrottle(redrawNow, Config.REDRAW_COOLDOWN_MILLIS);
window.addEventListener('resize', () => redrawThrottle.trigger(), false);
displayed.observable().subscribe(() => redrawThrottle.trigger());

watchDrags(canvasDiv,
    /**
     * Grab
     * @param {!Point} pt
     * @param {!MouseEvent|!TouchEvent} ev
     */
    (pt, ev) => {
        let oldInspector = displayed.get();
        let newHand = oldInspector.hand.withPos(pt);
        let newInspector = syncArea(oldInspector.withHand(newHand)).afterGrabbing(ev.shiftKey);
        if (displayed.get().isEqualTo(newInspector) || !newInspector.hand.isBusy()) {
            return;
        }

        // Add extra wire temporarily.
        revision.startedWorkingOnCommit();
        displayed.set(
            syncArea(oldInspector.withHand(newHand).withJustEnoughWires(newInspector.hand, 1)).
                afterGrabbing(ev.shiftKey));

        ev.preventDefault();
    },
    /**
     * Cancel
     * @param {!MouseEvent|!TouchEvent} ev
     */
    ev => {
        revision.cancelCommitBeingWorkedOn();
        ev.preventDefault();
    },
    /**
     * Drag
     * @param {undefined|!Point} pt
     * @param {!MouseEvent|!TouchEvent} ev
     */
    (pt, ev) => {
        if (!displayed.get().hand.isBusy()) {
            return;
        }

        let newHand = displayed.get().hand.withPos(pt);
        let newInspector = displayed.get().withHand(newHand);
        displayed.set(newInspector);
        ev.preventDefault();
    },
    /**
     * Drop
     * @param {undefined|!Point} pt
     * @param {!MouseEvent|!TouchEvent} ev
     */
    (pt, ev) => {
        if (!displayed.get().hand.isBusy()) {
            return;
        }

        let newHand = displayed.get().hand.withPos(pt);
        let newInspector = syncArea(displayed.get()).withHand(newHand).afterDropping().afterTidyingUp();
        let clearHand = newInspector.hand.withPos(undefined);
        let clearInspector = newInspector.withJustEnoughWires(clearHand, 0);
        revision.commit(clearInspector.snapshot());
        ev.preventDefault();
    });

// Middle-click to delete a gate.
canvasDiv.addEventListener('mousedown', ev => {
    if (!isMiddleClicking(ev)) {
        return;
    }
    let newHand = displayed.get().hand.withPos(eventPosRelativeTo(ev, canvas));
    let newInspector = syncArea(displayed.get()).
        withHand(newHand).
        afterGrabbing(false). // Grab the gate.
        withHand(newHand). // Lose the gate.
        afterTidyingUp().
        withJustEnoughWires(newHand, 0);
    if (!displayed.get().isEqualTo(newInspector)) {
        revision.commit(newInspector.snapshot());
        ev.preventDefault();
    }
});

// When mouse moves without dragging, track it (for showing hints and things).
canvasDiv.addEventListener('mousemove', ev => {
    if (!displayed.get().hand.isBusy()) {
        let newHand = displayed.get().hand.withPos(eventPosRelativeTo(ev, canvas));
        let newInspector = displayed.get().withHand(newHand);
        displayed.set(newInspector);
    }
});
canvasDiv.addEventListener('mouseleave', () => {
    if (!displayed.get().hand.isBusy()) {
        let newHand = displayed.get().hand.withPos(undefined);
        let newInspector = displayed.get().withHand(newHand);
        displayed.set(newInspector);
    }
});

initUrlCircuitSync(revision);
initExports(revision);
initForge(revision);
initUndoRedo(revision);
initTitleSync(revision);

// If the webgl initialization is going to fail, don't fail during the module loading phase.
haveLoaded = true;
setTimeout(() => {
    inspectorDiv.style.display = 'block';
    redrawNow();
    document.getElementById("loading-div").style.display = 'none';
    try {
        initializedWglContext().onContextRestored = () => redrawThrottle.trigger();
    } catch (ex) {
        // If that failed, the user is already getting warnings about WebGL not being supported.
        // Just silently log it.
        console.error(ex);
    }
}, 0);
<|endoftext|>


<commit_before>function Button(name, url, type, img) {
    document.write('' + name + '
');
    document.write('' + type + '
');
    document.write('');
    document.write('  ');
}
function NedGames() {
    Button("NedGames", "games.nedhome.ml", "NedGames", "nedhome.ml/imgs/games.png");
}
function B(name, url, type, img) {
    Button(name, url, type, img);
}
function NedTool(name, url, img) {
    Button(name, url, "NedTool", img)
}
function OutherSite(name, url, img) {
    Button(name, url, "Outher Site", img)
}
function SocialMedia(name, url, img) {
    Button(name, url, "Social Media", img);
}
function NewLine(type) {
    if(type == "p") {
        document.write("
")
    } else if(type == "br") {
        document.write("
")
    }
}
<commit_msg>Update Sites.js<commit_after>function Button(name, url, type, img) {
    document.write('' + name + '
');
    document.write('' + type + '
');
    document.write('');
    document.write('  ');
}
function NedGames() {
    Button("NedGames", "games.nedhome.ml", "NedGames", "nedhome.ml/imgs/games.png");
}
function B(name, url, type, img) {
    Button(name, url, type, img);
}
function NedTool(name, url, img) {
    Button(name, url, "NedTool", img)
}
function OutherSite(name, url, img) {
    Button(name, url, "Outher Site", img)
}
function SocialMedia(name, url, img) {
    Button(name, url, "Social Media", img);
}
function NewLine(type) {
    if(type == "p") {
        document.write("
")
    } else if(type == "br") {
        document.write("
")
    }
}
<|endoftext|>


<commit_before>/*
  LUMBER.js

    Crafted with <3 by John Otander(@4lpine).
    MIT Licensed
 */

function hasLumberDependencies() {
  return "d3" in window &&
         "addEventListener" in window &&
         "querySelector" in document &&
         Array.prototype.forEach
}

var lumber = {}

/*
  getGraphs

    Select all the DOM elements with the class '.lumber'.

    Returns:
      Array of all DOM elements with the class '.lumber'.
 */
lumber.getGraphs = lumber_getGraphs;
function lumber_getGraphs() {
  return document.querySelectorAll(".lumber");
}

lumber.graph = lumber_graph;
function lumber_graph(chartDiv) {
  chartDiv = d3.select(chartDiv);

  lumberOpts = {}
  lumberOpts.data   = chartDiv.attr("data-lumber-values").split(",");
  lumberOpts.width  = chartDiv.attr("data-lumber-width") || 500;
  lumberOpts.height = chartDiv.attr("data-lumber-height") || 250;
  lumberOpts.type   = chartDiv.attr("data-lumber-type") || "bar";
  lumberOpts.yAxis  = chartDiv.attr("data-lumber-y-axis-label") || "Y Axis";
  lumberOpts.xAxis  = chartDiv.attr("data-lumber-x-axis-label") || "X Axis";

  if (lumber.type == "bar")              { lumber.barChart(chartDiv, lumberOpts);    }
  else if (lumber.type == "pie")         { lumber.pieChart(chartDiv, lumberOpts);    }
  else if (lumber.type == "line")        { lumber.lineChart(chartDiv, lumberOpts);   }
  else if (lumber.type == "histogram")   { lumber.histogram(chartDiv, lumberOpts);   }
  else if (lumber.type == "scatterplot") { lumber.scatterplot(chartDiv, lumberOpts); }
}

/*
  barChart

    Create a lovely bar chart that is so beautiful no one will even care what
    the data even means.

    This will use the lumberOpts parameter to create a bar chart within the
    chartDiv. The chartDiv is assumed to be an svg DOM element.

    Params:
      chartDiv   = string for selection, for example "#chart" or ".lumber-chart"
      lumberOpts = options hash of information for creating the chart.

    Requirements (as keys in lumberOpts):
      type   = Specified by the lumber-type data attribute

      data   = The data is expected to be a data attribute with the form:
               'x1:y1,x2:y2,...,xn:yn'

      yAxis  = Utilizes the lumber-y-axis-label data attribute
      xAxis  = Utilizes the lumber-x-axis-label data attribute

      width  = Specified by the lumber-width data attribute
      height = Specified by the lumber-height data attribute

 */
lumber.barChart = lumber_barChart;
function lumber_barChart(chartDiv, lumberOpts) {
  var margin = {top: 20, right: 30, bottom: 30, left: 40},
      width  = lumberOpts.width - margin.left - margin.right,
      height = lumberOpts.height - margin.top - margin.bottom;

  var x = d3.scale.ordinal()
    .rangeRoundBands([0, width], .1);

  var y = d3.scale.linear()
    .range([height, 0]);

  var xAxis = d3.svg.axis().scale(x).orient("bottom");
  var yAxis = d3.svg.axis().scale(y).orient("left").ticks(2, "%");

  x.domain(lumberOpts.data.map(function(d) { return d; }))
  y.domain([0, d3.max(lumberOpts.data, function(d) { return d; })])

  var chart = chartDiv
      .attr("width", lumberOpts.width)
      .attr("height", lumberOpts.height)
    .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")")

  chart.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis)
    .append("text")
      .attr("y", 30)
      .attr("x", margin.left - 6)
      .attr("dx", ".71em")
      .style("text-anchor", "end")
      .text(lumberOpts.xAxis);

  chart.append("g")
      .attr("class", "y axis")
      .call(yAxis)
    .append("text")
      .attr("transform", "rotate(-90)")
      .attr("y", 6)
      .attr("dy", ".71em")
      .style("text-anchor", "end")
      .text(lumberOpts.yAxis);

  chart.selectAll(".bar")
      .data(lumberOpts.data)
    .enter().append("rect")
      .attr("class", "bar")
      .attr("x", function(d) { return x(d); })
      .attr("y", function(d) { return y(d); })
      .attr("height", function(d) { return height - y(d); })
      .attr("width", x.rangeBand());
}

lumber.pieChart = lumber_pieChart;
function lumber_pieChart(chartDiv, lumberOpts) {
  // ...
}

lumber.lineChart = lumber_lineChart;
function lumber_lineChart(chartDiv, lumberOpts) {
  // ...
}

lumber.histogram = lumber_histogram;
function lumber_histogram(chartDiv, lumberOpts) {
  // ...
}

lumber.scatterplot = lumber_scatterplot;
function lumber_scatterplot(chartDiv, lumberOpts) {
  // ...
}

function type(d) {
  d.value = +d.value; // coerce to number
  return d;
}

if (!hasLumberDependencies()) {
  console.log("Missing dependencies for lumber.js.");
}
<commit_msg>Use lumber opts for check.<commit_after>/*
  LUMBER.js

    Crafted with <3 by John Otander(@4lpine).
    MIT Licensed
 */

function hasLumberDependencies() {
  return "d3" in window &&
         "addEventListener" in window &&
         "querySelector" in document &&
         Array.prototype.forEach
}

var lumber = {}

/*
  getGraphs

    Select all the DOM elements with the class '.lumber'.

    Returns:
      Array of all DOM elements with the class '.lumber'.
 */
lumber.getGraphs = lumber_getGraphs;
function lumber_getGraphs() {
  return document.querySelectorAll(".lumber");
}

lumber.graph = lumber_graph;
function lumber_graph(chartDiv) {
  chartDiv = d3.select(chartDiv);

  lumberOpts = {}
  lumberOpts.data   = chartDiv.attr("data-lumber-values").split(",");
  lumberOpts.width  = chartDiv.attr("data-lumber-width") || 500;
  lumberOpts.height = chartDiv.attr("data-lumber-height") || 250;
  lumberOpts.type   = chartDiv.attr("data-lumber-type") || "bar";
  lumberOpts.yAxis  = chartDiv.attr("data-lumber-y-axis-label") || "Y Axis";
  lumberOpts.xAxis  = chartDiv.attr("data-lumber-x-axis-label") || "X Axis";

  if (lumberOpts.type == "bar")              { lumber.barChart(chartDiv, lumberOpts);    }
  else if (lumberOpts.type == "pie")         { lumber.pieChart(chartDiv, lumberOpts);    }
  else if (lumberOpts.type == "line")        { lumber.lineChart(chartDiv, lumberOpts);   }
  else if (lumberOpts.type == "histogram")   { lumber.histogram(chartDiv, lumberOpts);   }
  else if (lumberOpts.type == "scatterplot") { lumber.scatterplot(chartDiv, lumberOpts); }
}

/*
  barChart

    Create a lovely bar chart that is so beautiful no one will even care what
    the data even means.

    This will use the lumberOpts parameter to create a bar chart within the
    chartDiv. The chartDiv is assumed to be an svg DOM element.

    Params:
      chartDiv   = string for selection, for example "#chart" or ".lumber-chart"
      lumberOpts = options hash of information for creating the chart.

    Requirements (as keys in lumberOpts):
      type   = Specified by the lumber-type data attribute

      data   = The data is expected to be a data attribute with the form:
               'x1:y1,x2:y2,...,xn:yn'

      yAxis  = Utilizes the lumber-y-axis-label data attribute
      xAxis  = Utilizes the lumber-x-axis-label data attribute

      width  = Specified by the lumber-width data attribute
      height = Specified by the lumber-height data attribute

 */
lumber.barChart = lumber_barChart;
function lumber_barChart(chartDiv, lumberOpts) {
  var margin = {top: 20, right: 30, bottom: 30, left: 40},
      width  = lumberOpts.width - margin.left - margin.right,
      height = lumberOpts.height - margin.top - margin.bottom;

  var x = d3.scale.ordinal()
    .rangeRoundBands([0, width], .1);

  var y = d3.scale.linear()
    .range([height, 0]);

  var xAxis = d3.svg.axis().scale(x).orient("bottom");
  var yAxis = d3.svg.axis().scale(y).orient("left").ticks(2, "%");

  x.domain(lumberOpts.data.map(function(d) { return d; }))
  y.domain([0, d3.max(lumberOpts.data, function(d) { return d; })])

  var chart = chartDiv
      .attr("width", lumberOpts.width)
      .attr("height", lumberOpts.height)
    .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")")

  chart.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis)
    .append("text")
      .attr("y", 30)
      .attr("x", margin.left - 6)
      .attr("dx", ".71em")
      .style("text-anchor", "end")
      .text(lumberOpts.xAxis);

  chart.append("g")
      .attr("class", "y axis")
      .call(yAxis)
    .append("text")
      .attr("transform", "rotate(-90)")
      .attr("y", 6)
      .attr("dy", ".71em")
      .style("text-anchor", "end")
      .text(lumberOpts.yAxis);

  chart.selectAll(".bar")
      .data(lumberOpts.data)
    .enter().append("rect")
      .attr("class", "bar")
      .attr("x", function(d) { return x(d); })
      .attr("y", function(d) { return y(d); })
      .attr("height", function(d) { return height - y(d); })
      .attr("width", x.rangeBand());
}

lumber.pieChart = lumber_pieChart;
function lumber_pieChart(chartDiv, lumberOpts) {
  // ...
}

lumber.lineChart = lumber_lineChart;
function lumber_lineChart(chartDiv, lumberOpts) {
  // ...
}

lumber.histogram = lumber_histogram;
function lumber_histogram(chartDiv, lumberOpts) {
  // ...
}

lumber.scatterplot = lumber_scatterplot;
function lumber_scatterplot(chartDiv, lumberOpts) {
  // ...
}

function type(d) {
  d.value = +d.value; // coerce to number
  return d;
}

if (!hasLumberDependencies()) {
  console.log("Missing dependencies for lumber.js.");
}
<|endoftext|>


<commit_before>var Images = {
  debug: 1,

  get: function(affiliation, links, callback, options) {

    // Return with stacktrace if links is undefined
    if (links == undefined) {
      if (this.debug) console.log('ERROR: no image links, var links is undefined');
      return;
    }

    // TODO: Point of improvement: A few sites have differing selectors for
    // news articles across different news pages. Like e.g. if one of their
    // news pages have a regular header image and another has a slideshow.
    // Make sure this function can check for multiple different selectors.
    // TODO: Refactor, think of an awesome new way to organize this function.

    // Possible values in options:
    // options = {
    //   newsSelector: 'div.news_item', // if website uses uncommon selectors for news containers it must be defined here
    //   domainUrl: 'hybrida.no', // if website uses relative links, split by this url and search for last part of the link
    //   linkDelimiter: '?', // if the link contains parameter data which isn't used in the on-site link, trash the parameter data after this specified delimiter
    //   imageIndex: 2, // if the first picture in each post is a bad fit, use the one at specified index, note that this is zero-indexed
    //   noscriptMatching: /src="(http:\/\/gfx.nrk.no\/\/[a-zA-Z0-9]+)"/ // If a noscript tag is used we'll just search the contents of the noscript tag for the image src with regex
    // };

    // Create empty object to avoid crashes when looking up undefined props of undefined object
    if (options == undefined)
      options = {};

    var url = affiliation.web;
    var isSingleLink = false;
    if (typeof links == 'string') {
      url = links;
      // If links is just a single link, convert to single item array
      links = [links];
      isSingleLink = true;
    }

    // Array of possible news containers sorted by estimated probabilty
    var containers = [
      'div.entry',
      'div.post', // some blogs have div.entry inside a div.post, therefore we check div.entry first
      'article', // leave <article> at the bottom of the preferred list, it's a bit misused
    ];

    // In case we don't find any images, prepare an array with placeholders
    var placeholder = affiliation.placeholder;
    var placeholders = [];
    for (var i=0; i<links.length; i++)
      placeholders.push(placeholder);

    // If jQuery or Ajaxer.js is not loaded yet, just return placeholders.
    // This could occur with like one in a million probability, but like almost everything else it's handled.
    if (typeof $ == 'undefined' || typeof Ajaxer == 'undefined') {
      if (this.debug) console.log('ERROR: getImages called before $ and Ajaxer was ready');
      return placeholders;
    }

    var self = this;
    Ajaxer.getCleanHtml({
      url: url,
      success: function(html) {
      try {
        // jQuery 1.9+ does not consider pages starting with a newline as HTML, first char should be "<"
        html = $.trim(html);
        // jQuery tries to preload images found in the string, the following line causes errors, ignore it for now
        var doc = $(html);

        //
        // Decide which selector to use for identifying news containers
        //

        var newsSelector = null;
        if (options.newsSelector) {
        newsSelector = options.newsSelector;
        if (self.debug) console.log('Using selector', '"'+newsSelector+'" for news at '+url+'\n');
        }
        else {
        for (var i=0; i<containers.length; i++) {
          var current = containers[i];
          if (doc.find(current).length != 0) {
          newsSelector = current;
          if (self.debug) console.log('Using selector', '"'+current+'" for news at '+url+'\n');
          break;
          }
        }
        }

        // A place to store all the image links
        var images = [];

        for (i in links) {

        //
        // Find the news container which contains the news image, using our selector
        //

        var link = links[i];

        if (self.debug) console.log('Checking for '+(isSingleLink? 'image at' : 'posts with link'), link);

        // If posts are using relative links, split by domainUrl, like 'hist.no'
        if (options.domainUrl) {
          if (self.debug) console.log('Splitting link by domain url', options.domainUrl);
          link = links[i].split(options.domainUrl)[1];
        }

        // Trash link suffix data (found after delimiter) which is included in some news feeds for the sake of statistics and such
        if (options.linkDelimiter) {
          if (self.debug) console.log('Splitting link by delimiter', options.linkDelimiter);
          link = links[i].split(options.linkDelimiter)[0];
        }

        // Look up the first post with the link inside it...
        var image = doc.find(newsSelector + ' a[href="' + link + '"]');

        // ...then find parent 'article' or 'div.post' or the like...
        if (image.length != 0) {
          if (self.debug) console.log('Found something with the link, finding the parent (the news box');
          image = image.parents(newsSelector);
        }
        // ...unless we didn't find anything with the link, in which case we just look for the news selector
        else if (isSingleLink) {
          if (self.debug) console.log('Found nothing with a[href=url], trying news selector instead');
          // On a specific news page (not a frontpage) we can allow ourselves to search
          // more broadly if we didn't find anything while searching for the link. We'll
          // search for the newsSelector instead and assume that the first news container
          // we find contains the image we're looking for (which is highly likely based
          // on experience).
          image = doc.find(newsSelector);
        }

        //
        // Presumably we've found the news container here, now we need to find the image within it
        //

        if (options.noscriptMatching) {
          // If a <noscript> tag is used, we'll just find the image URL by matching
          // NOTE: This is for very special cases only! Like NRK.no, lulz @ nrk
          image = image.html().match(options.noscriptMatching)[1];
        }
        else {
          // Find all image tags within post
          image = image.find('pic');

          // Exclude gifs since they're most likely smilies and the likes
          image = image.not('pic[src*=".gif"]');
          image = image.not('pic[src*="data:image/gif"]');

          // Exclude social image icons (only applies for some blogs)
          image = image.not('pic[src*="sociable"]');

          // Exclude static content, most likely icons
          image = image.not('pic[src*="static"]');

          // Exclude comments, most likely text in image as "Add comment here"
          image = image.not('pic[src*="comments"]');

          // Use image at specified index if requested
          if (options.imageIndex)
          image = image.eq(options.imageIndex);

          // Get the src for the first image left in the array
          image = image.attr('src');
        }

        //
        // Here we determine whether we have found an image or not, and callback the image or a placeholder
        //

        // If image is undefined
        if (typeof image == 'undefined') {
          if (self.debug) console.log('No image exists for link', link);
          image = placeholder;
        }
        // If image needs to be prefixed with the domain name
        else if (options.domainUrl) {
          image = 'http://' + options.domainUrl + image;
          if (self.debug) console.log('Found a good image at', image);
        }
        // If image is something useless like "//assets.pinterest.com/whatever.png"
        // NOTE: Must be done after adding "http" and domainUrl
        else if (image.match('^https?://') == null) {
          if (self.debug) console.log('No good image exists for link', link);
          image = placeholder;
        }
        // If all is good
        else {
          if (self.debug) console.log('Found a good image at', image);
        }
        if (self.debug) console.log('\n');

        images.push(image);
        }
        callback(links, images);
      }
      catch (e) {
        if (self.debug) console.log('ERROR: could not parse '+affiliation.name+' website');
        callback(links, placeholders);
      }
      },
      error: function(e) {
      if (self.debug) console.log('ERROR: could not fetch '+affiliation.name+' website');
      callback(links, placeholders);
      },
    });
  },

  control: function(imageUrl) {
    if (isEmpty(imageUrl)) {
      if (this.debug) console.log('ERROR: Images.control received empty imageUrl');
      return false;
    }
    // Exclude gifs since they're most likely smilies and the likes
    if (imageUrl.indexOf('.gif') != -1) return false;
    if (imageUrl.indexOf('data:image/gif') != -1) return false;
    // Exclude social image icons (only applies for some blogs)
    if (imageUrl.indexOf('sociable') != -1) return false;
    // Exclude static content, most likely icons
    if (imageUrl.indexOf('static') != -1) return false;
    // Exclude comments, most likely text in image as "Add comment here"
    if (imageUrl.indexOf('comments') != -1) return false;
    // Control out
    return true;
  },

}
<commit_msg>images: commented<commit_after>var Images = {
  debug: 1,

  get: function(affiliation, links, callback, options) {

    // Return with stacktrace if links is undefined
    if (links == undefined) {
      if (this.debug) console.log('ERROR: no image links, var links is undefined');
      return;
    }

    // TODO: Point of improvement: A few sites have differing selectors for
    // news articles across different news pages. Like e.g. if one of their
    // news pages have a regular header image and another has a slideshow.
    // Make sure this function can check for multiple different selectors.
    // TODO: Refactor, think of an awesome new way to organize this function.

    // Possible values in options:
    // options = {
    //   newsSelector: 'div.news_item', // if website uses uncommon selectors for news containers it must be defined here
    //   domainUrl: 'hybrida.no', // if website uses relative links, split by this url and search for last part of the link
    //   linkDelimiter: '?', // if the link contains parameter data which isn't used in the on-site link, trash the parameter data after this specified delimiter
    //   imageIndex: 2, // if the first picture in each post is a bad fit, use the one at specified index, note that this is zero-indexed
    //   noscriptMatching: /src="(http:\/\/gfx.nrk.no\/\/[a-zA-Z0-9]+)"/ // If a noscript tag is used we'll just search the contents of the noscript tag for the image src with regex
    // };

    // Create empty object to avoid crashes when looking up undefined props of undefined object
    if (options == undefined)
      options = {};

    var url = affiliation.web;
    var isSingleLink = false;
    if (typeof links == 'string') {
      url = links;
      // If links is just a single link, convert to single item array
      links = [links];
      isSingleLink = true;
    }

    // Array of possible news containers sorted by estimated probabilty
    var containers = [
      'div.entry',
      'div.post', // some blogs have div.entry inside a div.post, therefore we check div.entry first
      'article', // leave <article> at the bottom of the preferred list, it's a bit misused
    ];

    // In case we don't find any images, prepare an array with placeholders
    var placeholder = affiliation.placeholder;
    var placeholders = [];
    for (var i=0; i<links.length; i++)
      placeholders.push(placeholder);

    // If jQuery or Ajaxer.js is not loaded yet, just return placeholders.
    // This could occur with like one in a million probability, but like almost everything else it's handled.
    if (typeof $ == 'undefined' || typeof Ajaxer == 'undefined') {
      if (this.debug) console.log('ERROR: getImages called before $ and Ajaxer was ready');
      return placeholders;
    }

    var self = this;
    Ajaxer.getCleanHtml({
      url: url,
      success: function(html) {
      try {
        // jQuery 1.9+ does not consider pages starting with a newline as HTML, first char should be "<"
        html = $.trim(html);
        // jQuery tries to preload images found in the string, the following line causes errors, ignore it for now
        var doc = $(html);

        //
        // Decide which selector to use for identifying news containers
        //

        var newsSelector = null;
        if (options.newsSelector) {
        newsSelector = options.newsSelector;
        if (self.debug) console.log('Using selector', '"'+newsSelector+'" for news at '+url+'\n');
        }
        else {
        for (var i=0; i<containers.length; i++) {
          var current = containers[i];
          if (doc.find(current).length != 0) {
          newsSelector = current;
          if (self.debug) console.log('Using selector', '"'+current+'" for news at '+url+'\n');
          break;
          }
        }
        }

        // A place to store all the image links
        var images = [];

        for (i in links) {

        //
        // Find the news container which contains the news image, using our selector
        //

        var link = links[i];

        if (self.debug) console.log('Checking for '+(isSingleLink? 'image at' : 'posts with link'), link);

        // If posts are using relative links, split by domainUrl, like 'hist.no'
        if (options.domainUrl) {
          if (self.debug) console.log('Splitting link by domain url', options.domainUrl);
          link = links[i].split(options.domainUrl)[1];
        }

        // Trash link suffix data (found after delimiter) which is included in some news feeds for the sake of statistics and such
        if (options.linkDelimiter) {
          if (self.debug) console.log('Splitting link by delimiter', options.linkDelimiter);
          link = links[i].split(options.linkDelimiter)[0];
        }

        // Look up the first post with the link inside it...
        var image = doc.find(newsSelector + ' a[href="' + link + '"]');

        // ...then find parent 'article' or 'div.post' or the like...
        if (image.length != 0) {
          if (self.debug) console.log('Found something with the link, finding the parent (the news box');
          image = image.parents(newsSelector);
        }
        // ...unless we didn't find anything with the link, in which case we just look for the news selector
        else if (isSingleLink) {
          if (self.debug) console.log('Found nothing with a[href=url], trying news selector instead');
          // On a specific news page (not a frontpage) we can allow ourselves to search
          // more broadly if we didn't find anything while searching for the link. We'll
          // search for the newsSelector instead and assume that the first news container
          // we find contains the image we're looking for (which is highly likely based
          // on experience).
          image = doc.find(newsSelector);
        }

        //
        // Presumably we've found the news container here, now we need to find the image within it
        //

        if (options.noscriptMatching) {
          // If a <noscript> tag is used, we'll just find the image URL by matching
          // NOTE: This is for very special cases only! Like NRK.no, lulz @ nrk
          image = image.html().match(options.noscriptMatching)[1];
        }
        else {
          // Find all image tags within post
          image = image.find('pic');

          // Exclude gifs since they're most likely smilies and the likes
          image = image.not('pic[src*=".gif"]');
          image = image.not('pic[src*="data:image/gif"]');

          // Exclude social image icons (only applies for some blogs)
          image = image.not('pic[src*="sociable"]');

          // Exclude static content, most likely icons
          image = image.not('pic[src*="static"]');

          // Exclude comments, most likely text in image as "Add comment here"
          image = image.not('pic[src*="comments"]');

          // Use image at specified index if requested
          if (options.imageIndex)
          image = image.eq(options.imageIndex);

          // Get the src for the first image left in the array
          image = image.attr('src');
        }

        //
        // Here we determine whether we have found an image or not, and callback the image or a placeholder
        //

        // If image is undefined
        if (typeof image == 'undefined') {
          if (self.debug) console.log('No image exists for link', link);
          image = placeholder;
        }
        // If image needs to be prefixed with the domain name
        else if (options.domainUrl) {
          image = 'http://' + options.domainUrl + image;
          if (self.debug) console.log('Found a good image at', image);
        }
        // If image is something useless like "//assets.pinterest.com/whatever.png"
        // NOTE: Must be done after adding "http" and domainUrl
        else if (image.match('^https?://') == null) {
          if (self.debug) console.log('No good image exists for link', link);
          image = placeholder;
        }
        // If all is good
        else {
          if (self.debug) console.log('Found a good image at', image);
        }
        if (self.debug) console.log('\n');

        images.push(image);
        }
        callback(links, images);
      }
      catch (e) {
        if (self.debug) console.log('ERROR: could not parse '+affiliation.name+' website');
        callback(links, placeholders);
      }
      },
      error: function(e) {
      if (self.debug) console.log('ERROR: could not fetch '+affiliation.name+' website');
      callback(links, placeholders);
      },
    });
  },

  control: function(imageUrl) {
    // This function is primarily used by news.js for controlling the goodness
    // of image URLs found in items that contain HTML descriptions (in RSS feeds)
    if (isEmpty(imageUrl)) {
      if (this.debug) console.log('ERROR: Images.control received empty imageUrl');
      return false;
    }
    // Exclude gifs since they're most likely smilies and the likes
    if (imageUrl.indexOf('.gif') != -1) return false;
    if (imageUrl.indexOf('data:image/gif') != -1) return false;
    // Exclude social image icons (only applies for some blogs)
    if (imageUrl.indexOf('sociable') != -1) return false;
    // Exclude static content, most likely icons
    if (imageUrl.indexOf('static') != -1) return false;
    // Exclude comments, most likely text in image as "Add comment here"
    if (imageUrl.indexOf('comments') != -1) return false;
    // Control out
    return true;
  },

}
<|endoftext|>


<commit_before>const { DEFAULT } = require("./constant.js");
const Headers = require("./headers.js");

class Request {
    constructor(event, context) {
        this.method = event.httpMethod;
        this.version = DEFAULT;
        if (event.queryStringParameters && (event.queryStringParameters.v || event.queryStringParameters.version)) {
            if (event.queryStringParameters.v) {
                this.version = event.queryStringParameters.v;
            } else {
                this.version = event.queryStringParameters.version;
            }
        }
        this.path = event.path;
        this.headers = new Headers(event.headers);
        this.body = null;
        if (event.body) {
            this.body = JSON.parse(event.body);
        }
        this.parameters = {};
        if (event.queryStringParameters) {
            this.parameters = event.queryStringParameters;
        }
        this.user = null;
        if (event.requestContext && event.requestContext.authorizer && Object.keys(event.requestContext.authorizer).length > 0) {
            this.user = Object.assign({}, event.requestContext.authorizer);
        }
        if (event.requestContext && event.requestContext.requestId) {
            this.requestId = event.requestContext.requestId;
        }
        if (event.requestContext && event.requestContext.identity && event.requestContext.identity.caller) {
            if (this.user === null) {
                this.user = {};
            }
            this.user.caller = event.requestContext.identity.caller;
        }
        if (event.requestContext && event.requestContext.identity && event.requestContext.identity.userArn) {
            if (this.user === null) {
                this.user = {};
            }
            this.user.userArn = event.requestContext.identity.userArn;
        }
        if (event.requestContext && event.requestContext.identity && event.requestContext.identity.user) {
            if (this.user === null) {
                this.user = {};
            }
            this.user.user = event.requestContext.identity.user;
        }
        this._route = null;
        this.originalEvent = event;
        this.context = context;
    }

    set route(route) {
        this._route = route;
        Object.assign(this.parameters, route.parameters);
        return this;
    }

    get route() {
        return this._route;
    }

}

module.exports = Request;
<commit_msg>Fix empty body<commit_after>const { DEFAULT } = require("./constant.js");
const Headers = require("./headers.js");

class Request {
    constructor(event, context) {
        this.method = event.httpMethod;
        this.version = DEFAULT;
        if (event.queryStringParameters && (event.queryStringParameters.v || event.queryStringParameters.version)) {
            if (event.queryStringParameters.v) {
                this.version = event.queryStringParameters.v;
            } else {
                this.version = event.queryStringParameters.version;
            }
        }
        this.path = event.path;
        this.headers = new Headers(event.headers);
        this.body = {};
        if (event.body) {
            this.body = JSON.parse(event.body);
        }
        this.parameters = {};
        if (event.queryStringParameters) {
            this.parameters = event.queryStringParameters;
        }
        this.user = null;
        if (event.requestContext && event.requestContext.authorizer && Object.keys(event.requestContext.authorizer).length > 0) {
            this.user = Object.assign({}, event.requestContext.authorizer);
        }
        if (event.requestContext && event.requestContext.requestId) {
            this.requestId = event.requestContext.requestId;
        }
        if (event.requestContext && event.requestContext.identity && event.requestContext.identity.caller) {
            if (this.user === null) {
                this.user = {};
            }
            this.user.caller = event.requestContext.identity.caller;
        }
        if (event.requestContext && event.requestContext.identity && event.requestContext.identity.userArn) {
            if (this.user === null) {
                this.user = {};
            }
            this.user.userArn = event.requestContext.identity.userArn;
        }
        if (event.requestContext && event.requestContext.identity && event.requestContext.identity.user) {
            if (this.user === null) {
                this.user = {};
            }
            this.user.user = event.requestContext.identity.user;
        }
        this._route = null;
        this.originalEvent = event;
        this.context = context;
    }

    set route(route) {
        this._route = route;
        Object.assign(this.parameters, route.parameters);
        return this;
    }

    get route() {
        return this._route;
    }

}

module.exports = Request;
<|endoftext|>


<commit_before>// TODO: add more test specs (see matchHeight.spec.js)
// TODO: travis CI

var gulp = require('gulp');
var uglify = require('gulp-uglify');
var rename = require('gulp-rename');
var header = require('gulp-header');
var eslint = require('gulp-eslint');
var gulpBump = require('gulp-bump');
var changelog = require('gulp-conventional-changelog');
var tag = require('gulp-tag-version');
var sequence = require('run-sequence');
var replace = require('gulp-replace');
var webdriver = require('gulp-webdriver');
var webserver = require('gulp-webserver');
var selenium = require('selenium-standalone');
var browserStack = require('gulp-browserstack');
var staticTransform = require('connect-static-transform');
var privateConfig = require('./test/conf/private.conf.js').config;
var pkg = require('./package.json');
var server;

gulp.task('release', function(callback) {
    var type = process.argv[4] || 'minor';
    sequence('lint', 'test', 'build', 'bump:' + type, 'changelog', 'tag', callback);
});

gulp.task('build', function() {
    return gulp.src(pkg.main)
        .pipe(replace("version = 'master'", "version = '" + pkg.version + "'"))
        .pipe(uglify())
        .pipe(header(banner, { pkg: pkg }))
        .pipe(rename({ suffix: '-min' }))
        .pipe(gulp.dest('.'));
});

gulp.task('lint', function() {
    return gulp.src(pkg.main)
        .pipe(eslint())
        .pipe(eslint.format())
        .pipe(eslint.failAfterError());
});

var bump = function(options) {
    return gulp.src(['package.json', 'bower.json'])
        .pipe(gulpBump(options))
        .pipe(gulp.dest('.'));
};

gulp.task('bump:patch', function() {
    return bump({ type: 'patch' });
});

gulp.task('bump:minor', function() {
    return bump({ type: 'minor' });
});

gulp.task('bump:major', function() {
    return bump({ type: 'major' });
});

gulp.task('tag', function() {
    return gulp.src('package.json')
        .pipe(tag({ prefix: '' }));
});

gulp.task('changelog', function () {
    return gulp.src('CHANGELOG.md')
        .pipe(changelog())
        .pipe(gulp.dest('.'));
});

gulp.task('serve', function() {
    server = gulp.src('.')
        .pipe(webserver({
            host: '0.0.0.0',
            //livereload: true,
            directoryListing: true,
            middleware: function(req, res, next) {
                var ieMode = (req._parsedUrl.query || '').replace('=','');
                if (ieMode in emulateIEMiddleware) {
                    emulateIEMiddleware[ieMode](req, res, next);
                } else {
                    next();
                }
            }
        }));
});

gulp.task('selenium', function(done) {
    console.log('Setting up Selenium server...');
    selenium.install({
        logger: function(message) { console.log(message); }
    }, function(err) {
        if (err) {
            done(err);
            return;
        }
        console.log('Starting Selenium server...');
        selenium.start(function(err, child) {
            console.log('Selenium server started');
            selenium.child = child;
            done(err);
        });
    });
});

gulp.task('test', ['serve', 'selenium'], function(done) {
    var error;
    console.log('Starting webdriver...');

    var finish = function(err) {
        console.log('Webdriver stopped');
        selenium.child.kill();
        console.log('Selenium server stopped');
        if (server) {
            try {
                server.emit('kill');
            } catch(e) {}
            console.log('Web server stopped');
        }
        done(error || err);
    };

    gulp.src('test/conf/local.conf.js')
        .pipe(webdriver())
        .on('error', function(err) { error = err; })
        .on('finish', finish);
});

gulp.task('test:cloud', ['serve'], function(done) {
    gulp.src('test/conf/cloud.conf.js')
    .pipe(browserStack.startTunnel({
        key: privateConfig.key,
        hosts: [{
            name: 'localhost',
            port: 8000,
            sslFlag: 0
        }]
    }))
    .pipe(webdriver())
    .pipe(browserStack.stopTunnel())
    .on('finish', function(err) {
        if (server) {
            try {
                server.emit('kill');
            } catch(e) {}
            console.log('Web server stopped');
        }
        done(err);
    });
});

gulp.task('test:cloud:all', function(done) {
    return gulp
    .src('test/conf/cloud-all.conf.js')
    .pipe(browserStack.startTunnel({
        key: privateConfig.key,
        hosts: [{
            name: 'localhost',
            port: 8000,
            sslFlag: 0
        }]
    }))
    .pipe(webdriver())
    .pipe(browserStack.stopTunnel());
});

var banner = [
  '/*',
  '* <%= pkg.name %> v<%= pkg.version %> by @liabru',
  '* <%= pkg.homepage %>',
  '* License <%= pkg.license %>',
  '*/',
  ''
].join('\n');

var emulateIEMiddlewareFactory = function(version) {
    return staticTransform({
        root: __dirname,
        match: /(.+)\.html/,
        transform: function (path, text, send) {
            send(text.replace('content="IE=edge,chrome=1"', 'content="IE=' + version + '"'));
        }
    });
};

var emulateIEMiddleware = {
    'ie8': emulateIEMiddlewareFactory(8),
    'ie9': emulateIEMiddlewareFactory(9),
    'ie10': emulateIEMiddlewareFactory(10)
};<commit_msg>handle error when test server is already running<commit_after>// TODO: add more test specs (see matchHeight.spec.js)
// TODO: travis CI

var gulp = require('gulp');
var uglify = require('gulp-uglify');
var rename = require('gulp-rename');
var header = require('gulp-header');
var eslint = require('gulp-eslint');
var gulpBump = require('gulp-bump');
var changelog = require('gulp-conventional-changelog');
var tag = require('gulp-tag-version');
var sequence = require('run-sequence');
var replace = require('gulp-replace');
var webdriver = require('gulp-webdriver');
var webserver = require('gulp-webserver');
var selenium = require('selenium-standalone');
var browserStack = require('gulp-browserstack');
var staticTransform = require('connect-static-transform');
var privateConfig = require('./test/conf/private.conf.js').config;
var pkg = require('./package.json');
var server;

gulp.task('release', function(callback) {
    var type = process.argv[4] || 'minor';
    sequence('lint', 'test', 'build', 'bump:' + type, 'changelog', 'tag', callback);
});

gulp.task('build', function() {
    return gulp.src(pkg.main)
        .pipe(replace("version = 'master'", "version = '" + pkg.version + "'"))
        .pipe(uglify())
        .pipe(header(banner, { pkg: pkg }))
        .pipe(rename({ suffix: '-min' }))
        .pipe(gulp.dest('.'));
});

gulp.task('lint', function() {
    return gulp.src(pkg.main)
        .pipe(eslint())
        .pipe(eslint.format())
        .pipe(eslint.failAfterError());
});

var bump = function(options) {
    return gulp.src(['package.json', 'bower.json'])
        .pipe(gulpBump(options))
        .pipe(gulp.dest('.'));
};

gulp.task('bump:patch', function() {
    return bump({ type: 'patch' });
});

gulp.task('bump:minor', function() {
    return bump({ type: 'minor' });
});

gulp.task('bump:major', function() {
    return bump({ type: 'major' });
});

gulp.task('tag', function() {
    return gulp.src('package.json')
        .pipe(tag({ prefix: '' }));
});

gulp.task('changelog', function () {
    return gulp.src('CHANGELOG.md')
        .pipe(changelog())
        .pipe(gulp.dest('.'));
});

gulp.task('serve', function() {
    process.on('uncaughtException', function(err) {
        if (err.errno === 'EADDRINUSE') {
            console.log('Server already running (or port is otherwise in use)');
        }
    });

    server = gulp.src('.')
        .pipe(webserver({
            host: '0.0.0.0',
            //livereload: true,
            directoryListing: true,
            middleware: function(req, res, next) {
                var ieMode = (req._parsedUrl.query || '').replace('=','');
                if (ieMode in emulateIEMiddleware) {
                    emulateIEMiddleware[ieMode](req, res, next);
                } else {
                    next();
                }
            }
        }));
});

gulp.task('selenium', function(done) {
    console.log('Setting up Selenium server...');
    selenium.install({
        logger: function(message) { console.log(message); }
    }, function(err) {
        if (err) {
            done(err);
            return;
        }
        console.log('Starting Selenium server...');
        selenium.start(function(err, child) {
            console.log('Selenium server started');
            selenium.child = child;
            done(err);
        });
    });
});

gulp.task('test', ['serve', 'selenium'], function(done) {
    var error;
    console.log('Starting webdriver...');

    var finish = function(err) {
        console.log('Webdriver stopped');
        selenium.child.kill();
        console.log('Selenium server stopped');
        if (server) {
            try {
                server.emit('kill');
            } catch(e) {}
            console.log('Web server stopped');
        }
        done(error || err);
    };

    gulp.src('test/conf/local.conf.js')
        .pipe(webdriver())
        .on('error', function(err) { error = err; })
        .on('finish', finish);
});

gulp.task('test:cloud', ['serve'], function(done) {
    gulp.src('test/conf/cloud.conf.js')
    .pipe(browserStack.startTunnel({
        key: privateConfig.key,
        hosts: [{
            name: 'localhost',
            port: 8000,
            sslFlag: 0
        }]
    }))
    .pipe(webdriver())
    .pipe(browserStack.stopTunnel())
    .on('finish', function(err) {
        if (server) {
            try {
                server.emit('kill');
            } catch(e) {}
            console.log('Web server stopped');
        }
        done(err);
    });
});

gulp.task('test:cloud:all', function(done) {
    return gulp
    .src('test/conf/cloud-all.conf.js')
    .pipe(browserStack.startTunnel({
        key: privateConfig.key,
        hosts: [{
            name: 'localhost',
            port: 8000,
            sslFlag: 0
        }]
    }))
    .pipe(webdriver())
    .pipe(browserStack.stopTunnel());
});

var banner = [
  '/*',
  '* <%= pkg.name %> v<%= pkg.version %> by @liabru',
  '* <%= pkg.homepage %>',
  '* License <%= pkg.license %>',
  '*/',
  ''
].join('\n');

var emulateIEMiddlewareFactory = function(version) {
    return staticTransform({
        root: __dirname,
        match: /(.+)\.html/,
        transform: function (path, text, send) {
            send(text.replace('content="IE=edge,chrome=1"', 'content="IE=' + version + '"'));
        }
    });
};

var emulateIEMiddleware = {
    'ie8': emulateIEMiddlewareFactory(8),
    'ie9': emulateIEMiddlewareFactory(9),
    'ie10': emulateIEMiddlewareFactory(10)
};<|endoftext|>