<commit_before>/** Bubbles **/
Flotr.addType('bubbles', {
  options: {
    show: false,      // => setting to true will show radar chart, false will hide
    lineWidth: 2,     // => line width in pixels
    fill: true,       // => true to fill the area from the line to the x axis, false for (transparent) no fill
    fillOpacity: 0.4, // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill
    baseRadius: 2     // => ratio of the radar, against the plot size
  },
  draw : function (options) {
    var
      context     = options.context,
      shadowSize  = options.shadowSize;

    context.save();
    context.translate(options.offsetLeft, options.offsetTop);
    context.lineWidth = options.lineWidth;

    // Shadows
    context.fillStyle = 'rgba(0,0,0,0.05)';
    context.strokeStyle = 'rgba(0,0,0,0.05)';
    this.plot(options, shadowSize / 2);
    context.strokeStyle = 'rgba(0,0,0,0.1)';
    this.plot(options, shadowSize / 4);

    // Chart
    context.strokeStyle = options.color;
    context.fillStyle = options.fillStyle;
    this.plot(options);

    context.restore();
  },
  plot : function (options, offset) {

    var
      data    = options.data,
      context = options.context,
      i, x, y, z;

    offset = offset || 0;

    for (i = 0; i < data.length; ++i){

      x = options.xScale(data[i][0]) + offset,
      y = options.yScale(data[i][1]) + offset,
      z = data[i][2] * options.baseRadius;

      context.beginPath();
      context.arc(x, y, z, 0, Math.PI*2, true);
      context.stroke();
      if (options.fill) context.fill();
      context.closePath();
    }
  },
  drawHit: function(n){

    var octx = this.octx,
        s = n.series,
        xa = n.xaxis,
        ya = n.yaxis,
        z = s.data[0][2],
        r = this.options.bubbles.baseRadius;

    octx.save();
    octx.lineWidth = s.points.lineWidth;
    octx.strokeStyle = s.mouse.lineColor;
    octx.fillStyle = this.processColor(s.mouse.fillColor || '#ffffff', {opacity: s.mouse.fillOpacity});

    octx.translate(this.plotOffset.left, this.plotOffset.top);
    octx.beginPath();
      octx.arc(xa.d2p(n.x), ya.d2p(n.y), z*r, 0, 2 * Math.PI, true);
      octx.fill();
      octx.stroke();
    octx.closePath();
    octx.restore();
  },
  clearHit: function(){
    var prevHit = this.prevHit,
        plotOffset = this.plotOffset,
        s = prevHit.series,
        lw = s.bars.lineWidth,
        xa = prevHit.xaxis,
        ya = prevHit.yaxis,
        z = s.data[0][2],
        r = this.options.bubbles.baseRadius,
        offset = z*r+lw;

    this.octx.clearRect(
      plotOffset.left + xa.d2p(prevHit.x) - offset,
      plotOffset.top  + ya.d2p(prevHit.y) - offset,
      offset*2,
      offset*2
    );
  }

/*,
  extendXRange: function(axis){
    if(axis.options.max == null){
      var newmin = axis.min,
          newmax = axis.max,
          i, j, c, r, data, d;

      for(i = 0; i < this.series.length; ++i){
        c = this.series[i].bubbles;
        if(c.show && this.series[i].xaxis == axis) {
          data = this.series[i].data;
          if (data)
          for(j = 0; j < data.length; j++) {
            d = data[j];
            r = d[2] * c.baseRadius * (this.plotWidth / (axis.datamax - axis.datamin));
              newmax = Math.max(d[0] + r, newmax);
              newmin = Math.min(d[0] - r, newmin);
          }
        }
      }
      axis.max = newmax;
      axis.min = newmin;
    }
  },
  extendYRange: function(axis){
    if(axis.options.max == null){
      var newmin = axis.min,
          newmax = axis.max,
          i, j, c, r, data, d;

      for(i = 0; i < this.series.length; ++i){
        c = this.series[i].bubbles;
        if(c.show && this.series[i].yaxis == axis) {
          data = this.series[i].data;
          if (data)
          for(j = 0; j < data.length; j++) {
            d = data[j];
            r = d[2] * c.baseRadius;
            newmax = Math.max(d[1] + r, newmax);
            newmin = Math.min(d[1] - r, newmin);
          }
        }
      }
      axis.max = newmax;
      axis.min = newmin;
    }
  }*/
});
<commit_msg>Fixed coupling of bubbles drawHit.<commit_after>/** Bubbles **/
Flotr.addType('bubbles', {
  options: {
    show: false,      // => setting to true will show radar chart, false will hide
    lineWidth: 2,     // => line width in pixels
    fill: true,       // => true to fill the area from the line to the x axis, false for (transparent) no fill
    fillOpacity: 0.4, // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill
    baseRadius: 2     // => ratio of the radar, against the plot size
  },
  draw : function (options) {
    var
      context     = options.context,
      shadowSize  = options.shadowSize;

    context.save();
    context.translate(options.offsetLeft, options.offsetTop);
    context.lineWidth = options.lineWidth;

    // Shadows
    context.fillStyle = 'rgba(0,0,0,0.05)';
    context.strokeStyle = 'rgba(0,0,0,0.05)';
    this.plot(options, shadowSize / 2);
    context.strokeStyle = 'rgba(0,0,0,0.1)';
    this.plot(options, shadowSize / 4);

    // Chart
    context.strokeStyle = options.color;
    context.fillStyle = options.fillStyle;
    this.plot(options);

    context.restore();
  },
  plot : function (options, offset) {

    var
      data    = options.data,
      context = options.context,
      i, x, y, z;

    offset = offset || 0;

    for (i = 0; i < data.length; ++i){

      x = options.xScale(data[i][0]) + offset,
      y = options.yScale(data[i][1]) + offset,
      z = data[i][2] * options.baseRadius;

      context.beginPath();
      context.arc(x, y, z, 0, Math.PI*2, true);
      context.stroke();
      if (options.fill) context.fill();
      context.closePath();
    }
  },
  drawHit : function (options) {

    var
      data    = options.data,
      args    = options.args,
      context = options.context,
      x       = options.xScale(args.x),
      y       = options.yScale(args.y),
      z       = data[args.index][2] * options.baseRadius;

    context.save();
    context.lineWidth = options.lineWidth;
    context.fillStyle = options.fillStyle;
    context.strokeStyle = options.color;
    context.translate(options.offsetLeft, options.offsetTop);
    context.beginPath();
    context.arc(x, y, z, 0, 2 * Math.PI, true);
    context.fill();
    context.stroke();
    context.closePath();
    context.restore();
  },
  clearHit: function(){
    var prevHit = this.prevHit,
        plotOffset = this.plotOffset,
        s = prevHit.series,
        lw = s.bars.lineWidth,
        xa = prevHit.xaxis,
        ya = prevHit.yaxis,
        z = s.data[0][2],
        r = this.options.bubbles.baseRadius,
        offset = z*r+lw;

    this.context.clearRect(
      plotOffset.left + xa.d2p(prevHit.x) - offset,
      plotOffset.top  + ya.d2p(prevHit.y) - offset,
      offset*2,
      offset*2
    );
  }

/*,
  extendXRange: function(axis){
    if(axis.options.max == null){
      var newmin = axis.min,
          newmax = axis.max,
          i, j, c, r, data, d;

      for(i = 0; i < this.series.length; ++i){
        c = this.series[i].bubbles;
        if(c.show && this.series[i].xaxis == axis) {
          data = this.series[i].data;
          if (data)
          for(j = 0; j < data.length; j++) {
            d = data[j];
            r = d[2] * c.baseRadius * (this.plotWidth / (axis.datamax - axis.datamin));
              newmax = Math.max(d[0] + r, newmax);
              newmin = Math.min(d[0] - r, newmin);
          }
        }
      }
      axis.max = newmax;
      axis.min = newmin;
    }
  },
  extendYRange: function(axis){
    if(axis.options.max == null){
      var newmin = axis.min,
          newmax = axis.max,
          i, j, c, r, data, d;

      for(i = 0; i < this.series.length; ++i){
        c = this.series[i].bubbles;
        if(c.show && this.series[i].yaxis == axis) {
          data = this.series[i].data;
          if (data)
          for(j = 0; j < data.length; j++) {
            d = data[j];
            r = d[2] * c.baseRadius;
            newmax = Math.max(d[1] + r, newmax);
            newmin = Math.min(d[1] - r, newmin);
          }
        }
      }
      axis.max = newmax;
      axis.min = newmin;
    }
  }*/
});
<|endoftext|>


<commit_before>var processInputMapping = {};
var processOutputMapping = {};

d3.json('./../js/data.json', function(data) {
    var results = data['results']['bindings'];
    var processNodeIndices = {};
    var putNodeIndices = {};

    /*
        @params: string processName, string inputName
        - inserts the inputName to the list of inputs that the processName maps
        to within the object processInputMapping
    */
    var addInputProcess = function(processName, inputName) {
        processInputMapping[processName] = processInputMapping[processName] || [];
        processInputMapping[processName].push(inputName);
    }

    /*
        @params: string processName, string outputName
        - inserts the outputName to the list of outputs that the processName maps
        to within the object processOutputMapping
    */
    var addOutputProcess = function(processName, outputName) {
        processOutputMapping[processName] = processOutputMapping[processName] || [];
        processOutputMapping[processName].push(outputName);
    }

    /*
        @params: string URI
        @return: a parsed, human-readable substring of the URI
    */
    var stripNameFromURI = function(uri) {
        return uri.substring(uri.lastIndexOf('CE_')+3, uri.length).toLowerCase();
    }

    /*
        @params: dagreD3 graph
        - pulls from JSON result and sets nodes according to whether or not they are labeled as inputs, outputs, or processes
    */
    var mapNodesEdges = function(graph) {
        var j = 0;
        for (var i = 0; i < results.length; i++) {
            //get URI of step from JSON
            var step = results[i].hasOwnProperty('step') ? results[i]['step']['value'] : null;

            //add step to processNodeIndices if the step hasn't been added yet
            if (processNodeIndices[step] == null) {
                processNodeIndices[step] = j;
                //get readable display for step name
                var stepToDisplay = stripNameFromURI(step);
                stepToDisplay = stepToDisplay.substring(0, stepToDisplay.lastIndexOf('node')) == '' ? stepToDisplay : stepToDisplay.substring(0, stepToDisplay.lastIndexOf('node'));
                vis.setNode(j, {
                    label: stepToDisplay,
                    labelStyle: "fill: #000",
                    style: "fill: #FFCC99;",
                    uri: step
                });
                j++;
            }
            if (results[i].hasOwnProperty('input')) {
                //get URI of input from JSON
                var input = results[i]['input']['value'];
                if (putNodeIndices[input] == null) {
                    putNodeIndices[input] = j;
                    //get readable display for input name
                    var inputToDisplay = stripNameFromURI(input);
                    vis.setNode(j, {
                        label: inputToDisplay,
                        labelStyle: "fill: #FFF",
                        shape: 'ellipse',
                        style: "fill: #003366;",
                        uri: input
                    });
                    j++;
                }
                addInputProcess(step, input);
            } else if (results[i].hasOwnProperty('output')) {
                //get URI of output from JSON
                var output = results[i]['output']['value'];
                if (putNodeIndices[output] == null) {
                    putNodeIndices[output] = j;
                    //get readable display for output name
                    var outputToDisplay = stripNameFromURI(output);
                    vis.setNode(j, {
                        label: outputToDisplay,
                        labelStyle: "fill: #FFF",
                        shape: 'ellipse',
                        style: "fill: #003366;",
                        uri: output
                    });
                    j++;
                }
                addOutputProcess(step, output);
            }
        }
    }

    /*
        params: dagreD3 vis
        - connects nodes to each other via node numbers from processInputMapping
        and processOutputMapping
    */
    var setGraphEdges = function (vis) {
        for (var process in processInputMapping) {
            for (var i = 0; i < processInputMapping[process].length; i++) {
                vis.setEdge(putNodeIndices[processInputMapping[process][i]], processNodeIndices[process], {
                    style: "stroke: #000; fill:none"
                });
            }
        }
        for (var process in processOutputMapping) {
            for (var i = 0; i < processOutputMapping[process].length; i++) {
                vis.setEdge(processNodeIndices[process], putNodeIndices[processOutputMapping[process][i]], {
                    style: "stroke: #000; fill:none"
                });
            }
        }
    }

    /*
        renders graph
    */
    var vis = new dagreD3.graphlib.Graph()
        .setGraph({
            nodesep: 10,
            ranksep: 20,
        })
        .setDefaultEdgeLabel(function() {
            return {}
        });

    mapNodesEdges(vis);
    setGraphEdges(vis);

    // Create the renderer
    var render = new dagreD3.render();

    // Set up an SVG group so that we can translate the final graph.
    var svg = d3.select("svg").attr('width','50%').attr('height','100%'), svgGroup = svg.append("g");

    // Set up zoom support
    var zoom = d3.behavior.zoom().on("zoom", function() {
        svgGroup.attr("transform", "translate(" + d3.event.translate + ")" +
                                    "scale(" + d3.event.scale + ")");
    });
    svg.call(zoom);

    // Run the renderer. This is what draws the final graph.
    render(svgGroup, vis);

    //centers graph and calculates top margin of graph based on screen size
    var xCenterOffset = (document.getElementsByClassName('visualization-container')[0].clientWidth / 2 - vis.graph().width) / 2;
    var yTopMargin = screen.height * .05;
    var scale = 1;
    zoom
      .translate([xCenterOffset, 20])
      .scale(scale)
      .event(svg);
    svg.attr('height', vis.graph().height * scale + yTopMargin);

    setupNodeOnClick(svg, vis);
    addHover(svg);
});

/*
    @params: d3 svg
    - setup on click process for each node
*/
var setupNodeOnClick = function (svg, vis) {
    //setup on click listeners for every node
    svg.selectAll("g.node").on("click", function(id) {
        addProcessInfo(vis.node(id).uri, processInputMapping[vis.node(id).uri], processOutputMapping[vis.node(id).uri]);
    });
}

/*
    @params: d3 svg
    - add hover opacity effect for each node when it is moused over, and returns back to normal opacity when it is moused out
*/
var addHover = function(svg) {
    //change opacity of nodes based on whether or not the mouse is hovering over them
    svg.selectAll('g.node').on('mouseover', function(id) {
        svg.selectAll('g.node').style('opacity', function(id1){
            if (id == id1) return 0.7;
        });
    });

    svg.selectAll('g.node').on('mouseout', function(id) {
        svg.selectAll('g.node').style('opacity', function(id1){
            return 1;
        });
    });
}<commit_msg>Allowing others to call stripNameFromURI<commit_after>var processInputMapping = {};
var processOutputMapping = {};

d3.json('./../js/data.json', function(data) {
    var results = data['results']['bindings'];
    var processNodeIndices = {};
    var putNodeIndices = {};

    /*
        @params: string processName, string inputName
        - inserts the inputName to the list of inputs that the processName maps
        to within the object processInputMapping
    */
    var addInputProcess = function(processName, inputName) {
        processInputMapping[processName] = processInputMapping[processName] || [];
        processInputMapping[processName].push(inputName);
    }

    /*
        @params: string processName, string outputName
        - inserts the outputName to the list of outputs that the processName maps
        to within the object processOutputMapping
    */
    var addOutputProcess = function(processName, outputName) {
        processOutputMapping[processName] = processOutputMapping[processName] || [];
        processOutputMapping[processName].push(outputName);
    }

    /*
        @params: dagreD3 graph
        - pulls from JSON result and sets nodes according to whether or not they are labeled as inputs, outputs, or processes
    */
    var mapNodesEdges = function(graph) {
        var j = 0;
        for (var i = 0; i < results.length; i++) {
            //get URI of step from JSON
            var step = results[i].hasOwnProperty('step') ? results[i]['step']['value'] : null;

            //add step to processNodeIndices if the step hasn't been added yet
            if (processNodeIndices[step] == null) {
                processNodeIndices[step] = j;
                //get readable display for step name
                var stepToDisplay = stripNameFromURI(step);
                stepToDisplay = stepToDisplay.substring(0, stepToDisplay.lastIndexOf('node')) == '' ? stepToDisplay : stepToDisplay.substring(0, stepToDisplay.lastIndexOf('node'));
                vis.setNode(j, {
                    label: stepToDisplay,
                    labelStyle: "fill: #000",
                    style: "fill: #FFCC99;",
                    uri: step
                });
                j++;
            }
            if (results[i].hasOwnProperty('input')) {
                //get URI of input from JSON
                var input = results[i]['input']['value'];
                if (putNodeIndices[input] == null) {
                    putNodeIndices[input] = j;
                    //get readable display for input name
                    var inputToDisplay = stripNameFromURI(input);
                    vis.setNode(j, {
                        label: inputToDisplay,
                        labelStyle: "fill: #FFF",
                        shape: 'ellipse',
                        style: "fill: #003366;",
                        uri: input
                    });
                    j++;
                }
                addInputProcess(step, input);
            } else if (results[i].hasOwnProperty('output')) {
                //get URI of output from JSON
                var output = results[i]['output']['value'];
                if (putNodeIndices[output] == null) {
                    putNodeIndices[output] = j;
                    //get readable display for output name
                    var outputToDisplay = stripNameFromURI(output);
                    vis.setNode(j, {
                        label: outputToDisplay,
                        labelStyle: "fill: #FFF",
                        shape: 'ellipse',
                        style: "fill: #003366;",
                        uri: output
                    });
                    j++;
                }
                addOutputProcess(step, output);
            }
        }
    }

    /*
        params: dagreD3 vis
        - connects nodes to each other via node numbers from processInputMapping
        and processOutputMapping
    */
    var setGraphEdges = function (vis) {
        for (var process in processInputMapping) {
            for (var i = 0; i < processInputMapping[process].length; i++) {
                vis.setEdge(putNodeIndices[processInputMapping[process][i]], processNodeIndices[process], {
                    style: "stroke: #000; fill:none"
                });
            }
        }
        for (var process in processOutputMapping) {
            for (var i = 0; i < processOutputMapping[process].length; i++) {
                vis.setEdge(processNodeIndices[process], putNodeIndices[processOutputMapping[process][i]], {
                    style: "stroke: #000; fill:none"
                });
            }
        }
    }

    /*
        renders graph
    */
    var vis = new dagreD3.graphlib.Graph()
        .setGraph({
            nodesep: 10,
            ranksep: 20,
        })
        .setDefaultEdgeLabel(function() {
            return {}
        });

    mapNodesEdges(vis);
    setGraphEdges(vis);

    // Create the renderer
    var render = new dagreD3.render();

    // Set up an SVG group so that we can translate the final graph.
    var svg = d3.select("svg").attr('width','50%').attr('height','100%'), svgGroup = svg.append("g");

    // Set up zoom support
    var zoom = d3.behavior.zoom().on("zoom", function() {
        svgGroup.attr("transform", "translate(" + d3.event.translate + ")" +
                                    "scale(" + d3.event.scale + ")");
    });
    svg.call(zoom);

    // Run the renderer. This is what draws the final graph.
    render(svgGroup, vis);

    //centers graph and calculates top margin of graph based on screen size
    var xCenterOffset = (document.getElementsByClassName('visualization-container')[0].clientWidth / 2 - vis.graph().width) / 2;
    var yTopMargin = screen.height * .05;
    var scale = 1;
    zoom
      .translate([xCenterOffset, 20])
      .scale(scale)
      .event(svg);
    svg.attr('height', vis.graph().height * scale + yTopMargin);

    setupNodeOnClick(svg, vis);
    addHover(svg);
});

/*
    @params: d3 svg
    - setup on click process for each node
*/
var setupNodeOnClick = function (svg, vis) {
    //setup on click listeners for every node
    svg.selectAll("g.node").on("click", function(id) {
        addProcessInfo(vis.node(id).uri, processInputMapping[vis.node(id).uri], processOutputMapping[vis.node(id).uri]);
    });
}

/*
    @params: d3 svg
    - add hover opacity effect for each node when it is moused over, and returns back to normal opacity when it is moused out
*/
var addHover = function(svg) {
    //change opacity of nodes based on whether or not the mouse is hovering over them
    svg.selectAll('g.node').on('mouseover', function(id) {
        svg.selectAll('g.node').style('opacity', function(id1){
            if (id == id1) return 0.7;
        });
    });

    svg.selectAll('g.node').on('mouseout', function(id) {
        svg.selectAll('g.node').style('opacity', function(id1){
            return 1;
        });
    });
}

/*
    @params: string URI
    @return: a parsed, human-readable substring of the URI
*/
var stripNameFromURI = function(uri) {
    return uri.substring(uri.lastIndexOf('CE_')+3, uri.length).toLowerCase();
}<|endoftext|>


<commit_before>//Fill weapons select boxes
$(".weapon-select").each(function() {
	var elem = $(this);

	//On change update the weapon Row
	elem.on("change", updateFromWeapon);

	// Add empty first option
	elem.append(htmlOption('', ''));

	_(Data.get('weapons'))
		.groupBy((weapon) => weapon.group)
		.map((groupWeapons, groupName) =>
			htmlOptGroup(
				groupName,
				_.reduce(groupWeapons, (html, weapon) => html + htmlOption(weapon.id, weapon.name), '')
			)
		)
		.each(appendIn(elem))
});

//Fill qualities select boxes
$(".quality-select").each(function() {
	var elem = $(this);

	//On change update the weapon Row
	elem.on("change", updateFromQuality);

	// Add empty first option
	elem.append(htmlOption('', ''));

	_(Data.get('qualities'))
		.map((quality) => htmlOption(quality.id, quality.name, quality.title))
		.each(appendIn(elem))
});

// Listen to some skills value changed
$("#agility").bind("change", updateWeapons)
$("#athl").bind("change", updateWeapons)
$("#cac").bind("change", updateWeapons)
$("#tir").bind("change", updateWeapons)
// Listen to all spe for value changed
$('.skills td:nth-child(3)').bind("DOMSubtreeModified", updateWeapons);

function updateWeapons() {
  $(".weapon-select").each(function() {
    updateFromWeapon.call(this)
  })
}

function updateFromWeapon(){
	var weapon = _.find(Data.get('weapons'), (o) => o.id == this.value);
	var qualityValue = $(this).closest('tr').find('.quality-select').val();

	if (weapon) {
		$(this)
			.closest('td')
			.next('td').html(specialityToValue(weapon, qualityValue))
			.next('td')
			.next('td').html(weapon.calculateDamage(qualityValue))
			.next('td').html(weapon.getAttribute(qualityValue))
	}
	else{
		$(this)
			.closest('td')
			.next('td').html('')
			.next('td')
			.next('td').html('')
			.next('td').html('')
	}
}

function updateFromQuality(){
	var quality = _.find(Data.get('qualities'), (o) => o.id == this.value);
	var weaponValue = $(this).closest('tr').find('.weapon-select').val();
	var waepon = _.find(Data.get('weapons'), (o) => o.id == weaponValue);

	if (quality && weaponValue) {
		$(this)
			.closest('td')
			.prev('td').html(specialityToValue(waepon, this.value))
			.next('td')
			.next('td').html(quality.calculateDamage(weaponValue))
			.next('td').html(quality.calculateAttribute(weaponValue))
	}
	else if (weaponValue) {
		var weapon = _.find(Data.get('weapons'), (o) => o.id == weaponValue);
		$(this)
			.closest('td')
			.next('td').html(weapon.calculateDamage())
			.next('td').html(weapon.getAttribute())
	}
	else{
		$(this)
			.closest('td')
			.prev('td').html('')
			.next('td')
			.next('td').html('')
			.next('td').html('')
	}
}

// Private

function htmlOption(value, text, title) {
	return $("<option></option>").attr("value", value).attr("title", title).text(text)[0].outerHTML
}

function htmlOptGroup(name, htmlContent) {
	return $("<optgroup></optgroup>").attr('label', name).html(htmlContent)[0].outerHTML
}

function appendIn(elem) {
	return (item) => elem.append(item)
}

// TODO refactor this thing, truth comes from one point
function specialityToValue(weapon, qualityId) {
	if (weapon) {
		var spe = weapon.getSpeciality(),
				speValue;

		if (spe == 'Jet') {
			var cell = $('.skills td:nth-child(2):contains("' + spe + '")')[1]
			speValue = toInt($(cell).next('td').html())
		} else {
			speValue = toInt($('.skills td:nth-child(2):contains("' + spe + '")').next('td').html())
		}
		var skillValue = (['Arbalètes', 'Arcs', 'Jet', 'Siège'].includes(spe)) ? v('tir') : v('cac')

		var bonusStr = ''
		if(qualityId) {
			var quality = _.find(Data.get('qualities'), (o) => o.id == qualityId)
			if (quality.bonus.spe > 0) {
				bonusStr = ' (+' + quality.bonus.spe + ')'
			} else if (quality.bonus.spe > 0) {
				bonusStr = ' (' + quality.bonus.spe + ')'
			}
		}

		return skillValue + ' + ' + speValue + 'B' + bonusStr
  }

  return ''
}<commit_msg>Fix bug Dices Armes de jet<commit_after>//Fill weapons select boxes
$(".weapon-select").each(function() {
	var elem = $(this);

	//On change update the weapon Row
	elem.on("change", updateFromWeapon);

	// Add empty first option
	elem.append(htmlOption('', ''));

	_(Data.get('weapons'))
		.groupBy((weapon) => weapon.group)
		.map((groupWeapons, groupName) =>
			htmlOptGroup(
				groupName,
				_.reduce(groupWeapons, (html, weapon) => html + htmlOption(weapon.id, weapon.name), '')
			)
		)
		.each(appendIn(elem))
});

//Fill qualities select boxes
$(".quality-select").each(function() {
	var elem = $(this);

	//On change update the weapon Row
	elem.on("change", updateFromQuality);

	// Add empty first option
	elem.append(htmlOption('', ''));

	_(Data.get('qualities'))
		.map((quality) => htmlOption(quality.id, quality.name, quality.title))
		.each(appendIn(elem))
});

// Listen to some skills value changed
$("#agility").bind("change", updateWeapons)
$("#athl").bind("change", updateWeapons)
$("#cac").bind("change", updateWeapons)
$("#tir").bind("change", updateWeapons)
// Listen to all spe for value changed
$('.skills td:nth-child(3)').bind("DOMSubtreeModified", updateWeapons);

function updateWeapons() {
  $(".weapon-select").each(function() {
    updateFromWeapon.call(this)
  })
}

function updateFromWeapon(){
	var weapon = _.find(Data.get('weapons'), (o) => o.id == this.value);
	var qualityValue = $(this).closest('tr').find('.quality-select').val();

	if (weapon) {
		$(this)
			.closest('td')
			.next('td').html(specialityToValue(weapon, qualityValue))
			.next('td')
			.next('td').html(weapon.calculateDamage(qualityValue))
			.next('td').html(weapon.getAttribute(qualityValue))
	}
	else{
		$(this)
			.closest('td')
			.next('td').html('')
			.next('td')
			.next('td').html('')
			.next('td').html('')
	}
}

function updateFromQuality(){
	var quality = _.find(Data.get('qualities'), (o) => o.id == this.value);
	var weaponValue = $(this).closest('tr').find('.weapon-select').val();
	var waepon = _.find(Data.get('weapons'), (o) => o.id == weaponValue);

	if (quality && weaponValue) {
		$(this)
			.closest('td')
			.prev('td').html(specialityToValue(waepon, this.value))
			.next('td')
			.next('td').html(quality.calculateDamage(weaponValue))
			.next('td').html(quality.calculateAttribute(weaponValue))
	}
	else if (weaponValue) {
		var weapon = _.find(Data.get('weapons'), (o) => o.id == weaponValue);
		$(this)
			.closest('td')
			.next('td').html(weapon.calculateDamage())
			.next('td').html(weapon.getAttribute())
	}
	else{
		$(this)
			.closest('td')
			.prev('td').html('')
			.next('td')
			.next('td').html('')
			.next('td').html('')
	}
}

// Private

function htmlOption(value, text, title) {
	return $("<option></option>").attr("value", value).attr("title", title).text(text)[0].outerHTML
}

function htmlOptGroup(name, htmlContent) {
	return $("<optgroup></optgroup>").attr('label', name).html(htmlContent)[0].outerHTML
}

function appendIn(elem) {
	return (item) => elem.append(item)
}

// TODO refactor this thing, truth comes from one point
function specialityToValue(weapon, qualityId) {
	if (weapon) {
		var spe = weapon.getSpeciality(),
				speValue,
                skillValue;

        speValue = toInt($('.skills td:nth-child(2):contains("' + spe + '")').next('td').html())
		skillValue = (['Arbalètes', 'Arcs', 'Armes de Jet', 'Siège'].includes(spe)) ? v('tir') : v('cac')

		var bonusStr = ''
		if(qualityId) {
			var quality = _.find(Data.get('qualities'), (o) => o.id == qualityId)
			if (quality.bonus.spe > 0) {
				bonusStr = ' (+' + quality.bonus.spe + ')'
			} else if (quality.bonus.spe > 0) {
				bonusStr = ' (' + quality.bonus.spe + ')'
			}
		}

		return skillValue + ' + ' + speValue + 'B' + bonusStr
  }

  return ''
}<|endoftext|>


<commit_before>// -------------------------------------------------
// -------------------- Worker ---------------------
// -------------------------------------------------

importScripts('utils.js', 'dev/framebuffer.js', 'dev/ethmac.js', 'dev/ata.js',
    'dev/uart.js', 'dev/touchscreen.js', 'dev/keyboard.js', 'dev/virtio.js', 'ram.js',
    'system.js', 'bzip2.js', 'cpu/cpu.js', 'cpu/fastcpu.js', 'cpu/safecpu.js',
    'dev/virtio/9p.js', 'filesystem.js');

var sys = new System();
DebugMessage("System initialized");

onmessage = function(e) {
    switch(e.data.command)
    {
        case "execute":
            sys.MainLoop();
            break;
        case "ethmac":
            sys.ethdev.Receive(new Uint8Array(e.data.data));
            break;
        case "GetFB":
            if (sys.status == SYSTEM_RUN) {
                SendToMaster("GetFB", sys.fbdev.GetBuffer());
            }
            break;
        case "tty0":
            sys.uartdev0.ReceiveChar(e.data.data);
            break;
        case "tty1":
            sys.uartdev1.ReceiveChar(e.data.data);
            break;
        case "GetIPS":
            SendToMaster("GetIPS", sys.GetIPS());
            break;
        case "keydown":
            sys.kbddev.OnKeyDown(e.data.data);
            break;
        case "keyup":
            sys.kbddev.OnKeyUp(e.data.data);
            break;
        case "tsmousedown":
            sys.tsdev.onmousedown(e.data.data);
            break;
        case "tsmouseup":
            sys.tsdev.onmouseup(e.data.data);
            break;
        case "tsmousemove":
            sys.tsdev.onmousemove(e.data.data);
            break;
        case "Reset":
            sys.Reset(e.data.data);
            break;
        case "ChangeCore":
            sys.ChangeCore(e.data.data, true);
            break;
        case "LoadAndStart":
            sys.LoadImageAndStart(e.data.data);
            break;
        case "MergeFile":
            sys.filesystem.MergeFile(e.data.data);
            break;
        case "tar":
            SendToMaster("tar", sys.filesystem.TAR(e.data.data));
            break;
        case "sync":
            SendToMaster("sync", sys.filesystem.TAR(e.data.data));
            break;
    }

}
<commit_msg>Framebuffer update: update also, when in idle mode, but only every 8th time<commit_after>// -------------------------------------------------
// -------------------- Worker ---------------------
// -------------------------------------------------

importScripts('utils.js', 'dev/framebuffer.js', 'dev/ethmac.js', 'dev/ata.js',
    'dev/uart.js', 'dev/touchscreen.js', 'dev/keyboard.js', 'dev/virtio.js', 'ram.js',
    'system.js', 'bzip2.js', 'cpu/cpu.js', 'cpu/fastcpu.js', 'cpu/safecpu.js',
    'dev/virtio/9p.js', 'filesystem.js');

var sys = new System();
DebugMessage("System initialized");

fbupdatecount = 0;

onmessage = function(e) {
    switch(e.data.command)
    {
        case "execute":
            sys.MainLoop();
            break;
        case "ethmac":
            sys.ethdev.Receive(new Uint8Array(e.data.data));
            break;
        case "GetFB":
            fbupdatecount++;
            if (sys.status == SYSTEM_RUN) {
                    SendToMaster("GetFB", sys.fbdev.GetBuffer());
            } else {
                if ((fbupdatecount&7) == 0) {
                    SendToMaster("GetFB", sys.fbdev.GetBuffer());
                }
            }
            break;
        case "tty0":
            sys.uartdev0.ReceiveChar(e.data.data);
            break;
        case "tty1":
            sys.uartdev1.ReceiveChar(e.data.data);
            break;
        case "GetIPS":
            SendToMaster("GetIPS", sys.GetIPS());
            break;
        case "keydown":
            sys.kbddev.OnKeyDown(e.data.data);
            break;
        case "keyup":
            sys.kbddev.OnKeyUp(e.data.data);
            break;
        case "tsmousedown":
            sys.tsdev.onmousedown(e.data.data);
            break;
        case "tsmouseup":
            sys.tsdev.onmouseup(e.data.data);
            break;
        case "tsmousemove":
            sys.tsdev.onmousemove(e.data.data);
            break;
        case "Reset":
            sys.Reset(e.data.data);
            break;
        case "ChangeCore":
            sys.ChangeCore(e.data.data, true);
            break;
        case "LoadAndStart":
            sys.LoadImageAndStart(e.data.data);
            break;
        case "MergeFile":
            sys.filesystem.MergeFile(e.data.data);
            break;
        case "tar":
            SendToMaster("tar", sys.filesystem.TAR(e.data.data));
            break;
        case "sync":
            SendToMaster("sync", sys.filesystem.TAR(e.data.data));
            break;
    }
}
<|endoftext|>


<commit_before>(function(undefined){

    //Create gaffa
    window.gaffa = window.gaffa || newGaffa();

    //internal varaibles
    var internalDataModel = {}, //these must always be objects.
        internalPresModel = {};

    //internal functions

    //Lost of similarities between get and set, refactor later to reuse code.
    function get(path, model){
        var keys = path.split("/"),
            reference = model;

        for(var keyIndex = 0; keyIndex < keys.length; keyIndex++){
            //Up a level.
            if(keys[keyIndex] === ".."){
                keys.splice(Math.max(keyIndex-1,0), keyIndex);
                keyIndex--;
            }else{
                if(typeof reference[keys[keyIndex]] === "object"){
                    reference = reference[keys[keyIndex]];
                }else if(reference[keys[keyIndex]] == undefined){
                    reference = undefined;
                    break;
                }else{
                    reference = reference[keys[keyIndex]];
                }
            }
        }

        return reference;
    }

    function set(path, value, model){
        var currentValue = get(path, model),
            fireChanged = false,
            keys = path.split("/"),
            reference = model,
            keyIndex;

        for(keyIndex = 0; keyIndex < keys.length; keyIndex++){
            //Up a level.
            if(keys[keyIndex] === ".."){
                keys.splice(Math.max(keyIndex-1,0), keyIndex);
                keyIndex--;
            }
        }

        for(keyIndex = 0; keyIndex < keys.length; keyIndex++){
            //Up a level.
            if(typeof reference[keys[keyIndex]] !== "object" && keyIndex < keys.length - 1){
                if(!isNaN(keys[keyIndex + 1])){
                    reference[keys[keyIndex]] = [];
                    reference = reference[keys[keyIndex]];
                }else{
                    reference[keys[keyIndex]] = {};
                    reference = reference[keys[keyIndex]];
                }
            }else if(keyIndex === keys.length - 1){
                reference[keys[keyIndex]] = value;
            }else{
                reference = reference[keys[keyIndex]];
            }
        }

        if(typeof currentValue === "object"){
            fireChanged = true;
            currentValue = value;
        }else if(currentValue === value){
            fireChanged = true;
        }

        if(fireChanged){
            $().trigger();
        }
    }

    function newGaffa(){

        function gaffa(){

        }

        gaffa.prototype = {
            presModel:{
                get: function(path){
                    return get(path, internalPresModel);
                },
                set: function(path, value){
                    return set(path, value, internalPresModel);
                },
                update: function(path, value){

                },
            },
            dataModel: {
                get: function(path){
                    return get(path, internalDataModel);
                },
                set: function(path, value){
                    return set(path, value, internalDataModel);
                },
                update: function(path, value){

                },
            },
            view: {
                render: function(views){ //parameter optional.

                },
                add: function(views){

                }
            }
        };

        return new gaffa();
    }
})();<commit_msg>cleaned up get and set code, added comments, made some constants...<commit_after>(function(undefined){

    //Create gaffa
    var gaffa = window.gaffa = window.gaffa || newGaffa();

    //"constants"
    // functions to make it 'getter only'
    gaffa.pathSeparator = function(){return "/";};
    gaffa.upALevel = function(){return "..";};

    //internal varaibles
    var internalDataModel = {}, //these must always be objects.
        internalPresModel = {};

    //internal functions

    //Lost of similarities between get and set, refactor later to reuse code.
    function get(path, model){
        var keys = path.split(gaffa.pathSeparator()),
            reference = model;

        for(var keyIndex = 0; keyIndex < keys.length; keyIndex++){

            //Up a level string. if encountered, knock out the previous key and the current one.
            if(keys[keyIndex] === gaffa.upALevel()){
                keys.splice(Math.max(keyIndex-1,0), keyIndex);
                keyIndex--;

            }else{

                /*
                    if the thing at the current key in the model is an object
                    or an array (both typeof to object),
                    set it as the thing we want to look into next.
                */
                if(typeof reference[keys[keyIndex]] === "object"){
                    reference = reference[keys[keyIndex]];

                /*
                    else if there isn't anything at this key, exit the loop,
                    and return undefined.
                */
                }else if(reference[keys[keyIndex]] === undefined){
                    reference = undefined;
                    break;

                /*
                    otherwise, we're at the end of the line. return whatever's
                    there
                */
                }else{
                    reference = reference[keys[keyIndex]];
                    break;
                }
            }
        }

        return reference;
    }

    function set(path, value, model){
        var currentValue = get(path, model),
            fireChanged = false,
            keys = path.split(gaffa.pathSeparator()),
            reference = model,
            keyIndex;

        for(keyIndex = 0; keyIndex < keys.length; keyIndex++){
            //Up a level.
            if(keys[keyIndex] === gaffa.upALevel()){
                keys.splice(Math.max(keyIndex-1,0), keyIndex);
                keyIndex--;
            }
        }

        for(keyIndex = 0; keyIndex < keys.length; keyIndex++){

            //if we have hit a non-object and we have more keys after this one
            //make an object (or array) here and move on.
            if(typeof reference[keys[keyIndex]] !== "object" && keyIndex < keys.length - 1){
                if(!isNaN(keys[keyIndex + 1])){
                    reference[keys[keyIndex]] = [];
                    reference = reference[keys[keyIndex]];
                }else{
                    reference[keys[keyIndex]] = {};
                    reference = reference[keys[keyIndex]];
                }

            // if we are at the end of the line, set to the model
            }else if(keyIndex === keys.length - 1){
                reference[keys[keyIndex]] = value;

            //otherwise, RECURSANIZE!
            }else{
                reference = reference[keys[keyIndex]];
            }
        }

        if(typeof currentValue === "object"){
            fireChanged = true;
            //to begin with we won't do a smart compare on objects, just fire changed every time.
            //ToDo: smart compare, and fire events only for changed props.
        }else if(currentValue === value){
            fireChanged = true;
        }

        if(fireChanged){
            $(gaffa.model).trigger("change." + keys.join("."));
        }
    }

    function newGaffa(){

        function gaffa(){
        }

        gaffa.prototype = {
            presModel:{
                get: function(path){
                    return get(path, internalPresModel);
                },
                set: function(path, value){
                    return set(path, value, internalPresModel);
                },
                update: function(path, value){

                },
            },
            dataModel: {
                get: function(path){
                    return get(path, internalDataModel);
                },
                set: function(path, value){
                    return set(path, value, internalDataModel);
                },
                update: function(path, value){

                },
            },
            view: {
                render: function(views){ //parameter optional.

                },
                add: function(views){

                }
            }
        };

        return new gaffa();
    }
})();<|endoftext|>


<commit_before>/*
 * gesso.js - A simple wrapper for html canvas streamlining.
 * (c) 2012 Russell Munson
 * http://github.com/rmunson/gesso
 */

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(function () {
            return factory();
        });
    } else{
    	root.gesso=factory();
    }
})(this,function(){
	'use strict'
	var meth,
		can=window.document && document.createElement('canvas'),
		og=can && can.getContext && can.getContext('2d')||{},
		proto={},

	cap = function(str){
		return str.charAt(0).toUpperCase() + str.substr(1);
	},
	ensureArray = function (obj){
		return obj = obj && (Array.isArray(obj) ? obj : [obj]) || [];
    },

    	/* used in constructing api (free to clear) */
	wrap=function(_meth){
		return typeof og[_meth]==="function" ? function(){
				//Return value if available, or chain.
			return this._ctx_[_meth] && this._ctx_[_meth].apply(this._ctx_,arguments) || this;
		} : function(val){
			this._ctx_[_meth]=val;
			return this;
		};
	},
		/* used in constructing api (free to clear) */
	grouper = function(item){
		var og=proto[item],
			run=function(props){
				for(var key in props){
					this[item+cap(key)] && this[item+cap(key)].apply(this,ensureArray(props[key]));
				}
			return this
		};
		return og ? function(props){
			return !props ? og.call(this) : run.call(this,props);
		} : run
	},

	gesso = function(can){
		this._ctx_=can && can.getContext && can.getContext('2d')||{};
	};

	for(meth in og){
		proto[meth]=wrap(meth);
	}

	'shadow,line,text,fill,stroke'.split(',').forEach(function(group){
		proto[group]=grouper(group);
	});
	gesso.prototype=proto;

	/* clear out garbage */
	can=og=wrap=grouper=meth=null;

 	/**
 	 * Expose gesso for CommonJS, AMD, or non-require environments.
 	 * Use available define method or attach to exports if present. Otherwise
 	 * assign to window.gesso.
 	 * @param  {function} g Closure function to handle setup.
 	 */
 	return function(can){
		return new gesso(can);
	};
});<commit_msg>umd and getters for the origina canvas and context<commit_after>/*
 * gesso.js - "Canvas and canvas context wrapper.  Supplies a chainable api of canvas methods, and command grouping."
 * (c) 2012 Russell Munson
 * http://github.com/rmunson/gesso
 */

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(function () {
            return factory();
        });
    } else{
    	root.gesso=factory();
    }
})(this,function(){
	'use strict'
	var meth,
		can=window.document && document.createElement('canvas'),
		og=can && can.getContext && can.getContext('2d')||{},
		proto={},

	cap = function(str){
		return str.charAt(0).toUpperCase() + str.substr(1);
	},
	ensureArray = function (obj){
		return obj = obj && (Array.isArray(obj) ? obj : [obj]) || [];
    },

    	/* used in constructing api (free to clear) */
	wrap=function(_meth){
		return typeof og[_meth]==="function" ? function(){
				//Return value if available, or chain.
			return this._ctx_[_meth] && this._ctx_[_meth].apply(this._ctx_,arguments) || this;
		} : function(val){
			this._ctx_[_meth]=val;
			return this;
		};
	},
		/* used in constructing api (free to clear) */
	grouper = function(item){
		var og=proto[item],
			run=function(props){
				for(var key in props){
					this[item+cap(key)] && this[item+cap(key)].apply(this,ensureArray(props[key]));
				}
			return this
		};
		return og ? function(props){
			return !props ? og.call(this) : run.call(this,props);
		} : run
	};

	for(meth in og){
		proto[meth]=wrap(meth);
	}

	'shadow,line,text,fill,stroke'.split(',').forEach(function(group){
		proto[group]=grouper(group);
	});

	proto.getContext = function(){
		return this._ctx_;
	};
	proto.getCanvas = function(){
		return this._ctx_.canvas;
	};

	function gesso( can ){
		if(!(this instanceof gesso)){
			return new gesso(can);
		}
		this._ctx_=can && can.getContext && can.getContext('2d')||{};
	};

	gesso.prototype=proto;

	/* clear out garbage */
	can=og=wrap=grouper=meth=null;

 	/**
 	 * Expose gesso for CommonJS, AMD, or non-require environments.
 	 * Use available define method or attach to exports if present. Otherwise
 	 * assign to window.gesso.
 	 * @param  {function} g Closure function to handle setup.
 	 */
 	return gesso;
});<|endoftext|>


<commit_before>var Ghost = function(args) {
  this.x = args.startX;
  this.y = args.startY;
  this.direction = args.direction ? args.direction : "left";
  this.nextDirection = this.direction;
  this.speed = GHOST_MOVE_DELAY;
  this.isMoving = false;
  this.context = args.context;
  this.name = args.name;
  this.color = nameToColor[args.name];
  this.animStep = 0;
  this.movementMode = "scatter";
  this.targetTile = {
    x: 0,
    y: 0
  }

  setInterval(function() {
    switch(this.animStep) {
      case 0: this.animStep = 1; break;
      case 1: this.animStep = 0; break;
    }
  }.bind(this), GHOST_TENDRIL_DELAY);
}
Ghost.prototype.clear = function() {
  this.context.clearRect(this.x - 7, this.y - 7, 14, 16);
};
Ghost.prototype.render = function() {
  this.context.fillStyle = this.color;

  var x = this.x;
  var y = this.y;

  // body
  this.context.beginPath();
  this.context.arc(x, y, 6, Math.PI, 0, false);
  this.context.moveTo(x += 7, y);
  this.context.lineTo(x, y += 5);
  this.context.lineTo(x -= 14, y);
  this.context.lineTo(x, y -= 5);
  this.context.closePath();
  this.context.fill();

  this.renderTendrils();
  this.renderEyes();
};
Ghost.prototype.renderTendrils = function() {
  var x = this.x + 7;
  var y = this.y + 5;

  this.context.moveTo(x, y);
  switch(this.animStep) {
    case 0:
      this.context.lineTo(x, y += 3);
      this.context.lineTo(x -= 1, y);
      this.context.lineTo(x -= 2, y -= 2.5);
      this.context.lineTo(x -= 2, y += 2.5);
      this.context.lineTo(x -= 1, y);
      this.context.lineTo(x, y -= 2);
      this.context.lineTo(x -= 2, y);
      this.context.lineTo(x, y += 2);
      this.context.lineTo(x -= 1, y);
      this.context.lineTo(x -= 2, y -= 2.5);
      this.context.lineTo(x -= 2, y += 2.5);
      this.context.lineTo(x -= 1, y);
      this.context.lineTo(x, y -= 3);
    break;
    case 1:
      this.context.lineTo(x, y += 1);
      this.context.lineTo(x -= 2, y += 2.5);
      this.context.lineTo(x -= 2, y -= 2.5);
      this.context.lineTo(x -= 1, y);
      this.context.lineTo(x -= 2, y += 2.5);
      this.context.lineTo(x -= 2, y -= 2.5);
      this.context.lineTo(x -= 1, y);
      this.context.lineTo(x -= 2, y += 2.5);
      this.context.lineTo(x -= 2, y -= 2.5);
      this.context.lineTo(x, y -= 1);
    break;
  }
  this.context.closePath();
  this.context.fill();
};
Ghost.prototype.renderEyes = function() {
  this.context.fillStyle = "#FFF";
  var x = this.x - 3;
  var y = this.y - 3;

  switch(this.direction) {
    case "up": y -= 2; break;
    case "down": y += 1; break;
    case "left": x--; break;
    case "right": x++; break;
  }

  // Whites of eyes
  this.context.beginPath();
  this.context.moveTo(x, y);
  this.context.lineTo(x += 0.5, y);
  this.context.lineTo(x += 1.5, y += 1.5);
  this.context.lineTo(x, y += 2);
  this.context.lineTo(x -= 1.5, y += 1.5);
  this.context.lineTo(x -= 1, y);
  this.context.lineTo(x -= 1.5, y -= 1.5);
  this.context.lineTo(x, y -= 2);
  this.context.lineTo(x += 1.5, y -= 1.5);
  this.context.moveTo(x += 6.5, y);
  this.context.lineTo(x += 0.5, y);
  this.context.lineTo(x += 1.5, y += 1.5);
  this.context.lineTo(x, y += 2);
  this.context.lineTo(x -= 1.5, y += 1.5);
  this.context.lineTo(x -= 1, y);
  this.context.lineTo(x -= 1.5, y -= 1.5);
  this.context.lineTo(x, y -= 2);
  this.context.lineTo(x += 1.5, y -= 1.5);
  this.context.fill();

  switch(this.direction) {
    case "up":
      x = this.x - 4;
      y = this.y - 5;
    break;
    case "down":
      x = this.x - 4;
      y = this.y + 1;
    break;
    case "left":
      x = this.x - 6;
      y = this.y - 1;
    break;
    case "right":
      x = this.x - 2;
      y = this.y - 1;
    break;
  }

  // Pupils
  this.context.fillStyle = "#22F";
  this.context.fillRect(x, y, 2, 2);
  this.context.fillRect(x += 6, y, 2, 2);
};
Ghost.prototype.move = function() {
  this.clear();
  switch(this.direction){
    case "up": this.y--; break;
    case "down": this.y++; break;
    case "left": this.x--; break;
    case "right": this.x++; break;
  }
  if(this.x % 8 == 4 && this.y % 8 == 4) {
    this.setNextDirection();
    this.direction = this.nextDirection;
  }
  this.render();
};
Ghost.prototype.setNextDirection = function() {
  var currentTile = {
    x: Math.floor(this.x / 8),
    y: Math.floor(this.y / 8) - 3
  }
  var adjacentTiles = gameBoard.getAdjacentTiles({x: this.x, y: this.y});
  adjacentTiles[oppositeDirection(this.direction)] = undefined;

  var emptyTiles = gameBoard.getEmptyTiles(adjacentTiles);
  var nextTile = gameBoard.getClosestTile({
    tiles: emptyTiles,
    target: this.targetTile
  });

  if(nextTile.x < currentTile.x) {
    this.nextDirection = "left";
  }
  else if(nextTile.x > currentTile.x) {
    this.nextDirection = "right";
  }
  else if(nextTile.y < currentTile.y) {
    this.nextDirection = "up";
  }
  else if(nextTile.y > currentTile.y) {
    this.nextDirection = "down";
  }
};
<commit_msg>Add Ghost.setMode to only allow valide movement modes<commit_after>var Ghost = function(args) {
  this.x = args.startX;
  this.y = args.startY;
  this.direction = args.direction ? args.direction : "left";
  this.nextDirection = this.direction;
  this.speed = GHOST_MOVE_DELAY;
  this.isMoving = false;
  this.context = args.context;
  this.name = args.name;
  this.color = nameToColor[args.name];
  this.animStep = 0;
  this.movementMode = "scatter";
  this.targetTile = {
    x: 0,
    y: 0
  }

  setInterval(function() {
    switch(this.animStep) {
      case 0: this.animStep = 1; break;
      case 1: this.animStep = 0; break;
    }
  }.bind(this), GHOST_TENDRIL_DELAY);
}
Ghost.prototype.clear = function() {
  this.context.clearRect(this.x - 7, this.y - 7, 14, 16);
};
Ghost.prototype.render = function() {
  this.context.fillStyle = this.color;

  var x = this.x;
  var y = this.y;

  // body
  this.context.beginPath();
  this.context.arc(x, y, 6, Math.PI, 0, false);
  this.context.moveTo(x += 7, y);
  this.context.lineTo(x, y += 5);
  this.context.lineTo(x -= 14, y);
  this.context.lineTo(x, y -= 5);
  this.context.closePath();
  this.context.fill();

  this.renderTendrils();
  this.renderEyes();
};
Ghost.prototype.renderTendrils = function() {
  var x = this.x + 7;
  var y = this.y + 5;

  this.context.moveTo(x, y);
  switch(this.animStep) {
    case 0:
      this.context.lineTo(x, y += 3);
      this.context.lineTo(x -= 1, y);
      this.context.lineTo(x -= 2, y -= 2.5);
      this.context.lineTo(x -= 2, y += 2.5);
      this.context.lineTo(x -= 1, y);
      this.context.lineTo(x, y -= 2);
      this.context.lineTo(x -= 2, y);
      this.context.lineTo(x, y += 2);
      this.context.lineTo(x -= 1, y);
      this.context.lineTo(x -= 2, y -= 2.5);
      this.context.lineTo(x -= 2, y += 2.5);
      this.context.lineTo(x -= 1, y);
      this.context.lineTo(x, y -= 3);
    break;
    case 1:
      this.context.lineTo(x, y += 1);
      this.context.lineTo(x -= 2, y += 2.5);
      this.context.lineTo(x -= 2, y -= 2.5);
      this.context.lineTo(x -= 1, y);
      this.context.lineTo(x -= 2, y += 2.5);
      this.context.lineTo(x -= 2, y -= 2.5);
      this.context.lineTo(x -= 1, y);
      this.context.lineTo(x -= 2, y += 2.5);
      this.context.lineTo(x -= 2, y -= 2.5);
      this.context.lineTo(x, y -= 1);
    break;
  }
  this.context.closePath();
  this.context.fill();
};
Ghost.prototype.renderEyes = function() {
  this.context.fillStyle = "#FFF";
  var x = this.x - 3;
  var y = this.y - 3;

  switch(this.direction) {
    case "up": y -= 2; break;
    case "down": y += 1; break;
    case "left": x--; break;
    case "right": x++; break;
  }

  // Whites of eyes
  this.context.beginPath();
  this.context.moveTo(x, y);
  this.context.lineTo(x += 0.5, y);
  this.context.lineTo(x += 1.5, y += 1.5);
  this.context.lineTo(x, y += 2);
  this.context.lineTo(x -= 1.5, y += 1.5);
  this.context.lineTo(x -= 1, y);
  this.context.lineTo(x -= 1.5, y -= 1.5);
  this.context.lineTo(x, y -= 2);
  this.context.lineTo(x += 1.5, y -= 1.5);
  this.context.moveTo(x += 6.5, y);
  this.context.lineTo(x += 0.5, y);
  this.context.lineTo(x += 1.5, y += 1.5);
  this.context.lineTo(x, y += 2);
  this.context.lineTo(x -= 1.5, y += 1.5);
  this.context.lineTo(x -= 1, y);
  this.context.lineTo(x -= 1.5, y -= 1.5);
  this.context.lineTo(x, y -= 2);
  this.context.lineTo(x += 1.5, y -= 1.5);
  this.context.fill();

  switch(this.direction) {
    case "up":
      x = this.x - 4;
      y = this.y - 5;
    break;
    case "down":
      x = this.x - 4;
      y = this.y + 1;
    break;
    case "left":
      x = this.x - 6;
      y = this.y - 1;
    break;
    case "right":
      x = this.x - 2;
      y = this.y - 1;
    break;
  }

  // Pupils
  this.context.fillStyle = "#22F";
  this.context.fillRect(x, y, 2, 2);
  this.context.fillRect(x += 6, y, 2, 2);
};
Ghost.prototype.move = function() {
  this.clear();
  switch(this.direction){
    case "up": this.y--; break;
    case "down": this.y++; break;
    case "left": this.x--; break;
    case "right": this.x++; break;
  }
  if(this.x % 8 == 4 && this.y % 8 == 4) {
    this.setNextDirection();
    this.direction = this.nextDirection;
  }
  this.render();
};
Ghost.prototype.setMode = function(modeName) {
  if(GHOST_MODES.includes(modeName)) {
    this.movementMode = modeName;
  }
};
Ghost.prototype.setNextDirection = function() {
  var currentTile = {
    x: Math.floor(this.x / 8),
    y: Math.floor(this.y / 8) - 3
  }
  var adjacentTiles = gameBoard.getAdjacentTiles({x: this.x, y: this.y});
  adjacentTiles[oppositeDirection(this.direction)] = undefined;

  var emptyTiles = gameBoard.getEmptyTiles(adjacentTiles);
  var nextTile = gameBoard.getClosestTile({
    tiles: emptyTiles,
    target: this.targetTile
  });

  if(nextTile.x < currentTile.x) {
    this.nextDirection = "left";
  }
  else if(nextTile.x > currentTile.x) {
    this.nextDirection = "right";
  }
  else if(nextTile.y < currentTile.y) {
    this.nextDirection = "up";
  }
  else if(nextTile.y > currentTile.y) {
    this.nextDirection = "down";
  }
};
<|endoftext|>


<commit_before>var Gmail =  function() {

  var api = {
              get : {},
              observe : {},
              check : {},
              tools : {},
              tracker : {},
              dom : {}
            };

  api.get.user_email = function() {
    return GLOBALS[10];
  };

  api.check.is_thread = function() {
    var check_1 = $($($('.nH .if').children()[1]).children().children()[1]).children();
    var check_2 = $($($($('.nH .if').children()[1]).children()).children()[1]).children();
    var check_3 = api.get.email_ids();

    return (check_1.length > 1 || check_2.length > 1) || check_3.length > 1;
  };

  api.dom.inbox_content = function() {
    return $('div[role=main]:first');
  }

  api.check.is_preview_pane = function() {
    var dom = api.dom.inbox_content();
    var box = dom.find("[gh=tl]");

    if(box.length > 0) {
      return box[0].getAttribute('class').indexOf('aia') != -1;
    }

    return false;
  }

  api.check.is_horizontal_split = function() {
    var dom = api.dom.inbox_content();
    var box = dom.find("[gh=tl]").find('.nn');

    return box.length == 0;
  }

  api.check.is_vertical_split = function() {
    return api.check.is_horizontal_split() == false;
  }

  api.check.is_tabbed_inbox = function() {
    return $(".aKh").length == 1;
  }

  api.check.is_right_side_chat = function() {
    return $('.ApVoH')[0].getAttribute('aria-labelledby') == ':wf';
  }

  api.check.is_google_apps_user =function() {
    var email = api.get.user_email();
    return email.indexOf('gmail.com', email.length - 'gmail.com'.length) == -1;
  }

  api.get.storage_info = function() {
    var div = $('.md.mj').find('div')[0];
    var used = $(div).find('span')[0].innerText;
    var total = $(div).find('span')[1].innerText;
    var percent = parseFloat(used.replace(/[^0-9\.]/g, '')) * 100 / parseFloat(total.replace(/[^0-9\.]/g, ''));

    return {used : used, total : total, percent : Math.floor(percent)}
  }

  api.dom.email_subject = function () {
    return $('h1.ha');
  }

  api.get.email_subject = function() {
    var subject_dom = api.dom.email_subject();

    return subject_dom.find('.hP')[0].innerText;
  }

  api.dom.email_body = function() {
    return $('.nH.hx');
  }

  api.check.is_inside_email = function() {
    return api.dom.email_contents().length > 0;
  }

  api.dom.email_contents = function() {
    return $('.ii.gt');
  }

  api.get.email_ids = function () {
    var items = api.dom.email_contents();
    var ids = [];

    for(var i=0; i<items.length; i++) {
      var mail_id = items[i].getAttribute('class').split(' ')[2];
      var is_editable = items[i].getAttribute('contenteditable');
      if(mail_id != 'undefined' && mail_id != undefined) {
        if(is_editable != 'true') {
          ids.push(mail_id);
        }
      }
    }

    return ids;
  }

  api.get.email_id = function() {
    var hash = null;

    if(api.check.is_inside_email()) {
      if(api.check.is_preview_pane()) {
        var text = api.get.email_ids();
        hash = text[0].substring(1, text[0].length);
      } else {
        hash = window.location.hash.split("/").pop().replace(/#/, '').split('?')[0];
      }

    }

    return hash;
  }

  api.check.is_priority_inbox = function() {
    return $('.qh').length > 0;
  }

  api.check.is_rapportive_installed = function() {
    return $('#rapportive-sidebar').length == 1;
  }

  api.check.is_streak_installed = function() {
    return $("[id^='bentoBox'],[id*=' bentoBox'],[class*=' bentoBox'],[class*='bentoBox']").length > 0;
  }

  api.check.is_anydo_installed = function() {
    return $("[id^='anydo'],[id*=' anydo'],[class*=' anydo'],[class*='anydo']").length > 0;
  }

  api.check.is_boomerang_installed = function() {
    return $("[id^='b4g_'],[id*=' b4g_'],[class*=' b4g_'],[class*='b4g_']").length > 0;
  }

  api.check.is_xobini_installed = function() {
    return $('#xobni_frame').length > 0;
  }

  api.check.is_signal_installed = function() {
    return $("[id^='Signal'],[id*=' Signal'],[class*=' signal'],[class*='signal']").length > 0;
  }

  api.dom.get_left_sidebar_links = function() {
    return $("div[role=navigation] [title]");
  }

  api.dom.search_bar = function() {
    return $("[gh=sb]");
  }

  api.get.search_query = function() {
    var dom = api.dom.search_bar();
    return dom.find('input')[0].value;
  }

  api.get.unread_inbox_emails = function() {
    var dom = $("div[role=navigation]").find("[title*='Inbox']");

    if(dom.length > 0) {
      if(dom[0].innerText.indexOf('(') != -1) {
        return parseInt(dom[0].innerText.replace(/[^0-9]/g, ''));
      }
    }

    return -1;
  }

  api.get.unread_draft_emails = function() {
    var dom = $("div[role=navigation]").find("[title*='Drafts']");

    if(dom.length > 0) {
      if(dom[0].innerText.indexOf('(') != -1) {
        return parseInt(dom[0].innerText.replace(/[^0-9]/g, ''));
      }
    }

    return -1;
  }

  api.get.unread_spam_emails = function() {
    var dom = $("div[role=navigation]").find("[title*='Spam']");

    if(dom.length > 0) {
      if(dom[0].innerText.indexOf('(') != -1) {
        return parseInt(dom[0].innerText.replace(/[^0-9]/g, ''));
      }
    }

    return -1;
  }

  api.get.unread_forum_emails = function() {
    var dom = $("div[role=navigation]").find("[title*='Forums']");

    if(dom.length > 0) {
      if(dom[0].innerText.indexOf('(') != -1) {
        return parseInt(dom[0].innerText.replace(/[^0-9]/g, ''));
      }
    }

    return -1;
  }

  api.get.unread_notification_emails = function() {
    var dom = $("div[role=navigation]").find("[title*='Notifications']");

    if(dom.length > 0) {
      if(dom[0].innerText.indexOf('(') != -1) {
        return parseInt(dom[0].innerText.replace(/[^0-9]/g, ''));
      }
    }

    return -1;
  }

  api.get.unread_promotion_emails = function() {
    var dom = $("div[role=navigation]").find("[title*='Promotions']");

    if(dom.length > 0) {
      if(dom[0].innerText.indexOf('(') != -1) {
        return parseInt(dom[0].innerText.replace(/[^0-9]/g, ''));
      }
    }

    return -1;
  }

  api.get.unread_social_emails = function() {
    var dom = $("div[role=navigation]").find("[title*='Social Updates']");

    if(dom.length > 0) {
      if(dom[0].innerText.indexOf('(') != -1) {
        return parseInt(dom[0].innerText.replace(/[^0-9]/g, ''));
      }
    }

    return -1;
  }

  api.get.beta = function() {
    var features = {
                    "new_nav_bar" : $('#gbz').length == 0
                   }

    return features;
  }

  api.get.unread_emails = function() {
    return { inbox         : api.get.unread_inbox_emails(),
             drafts        : api.get.unread_draft_emails(),
             spam          : api.get.unread_spam_emails(),
             forum         : api.get.unread_forum_emails(),
             notifications : api.get.unread_notification_emails(),
             promotions    : api.get.unread_promotion_emails(),
             social        : api.get.unread_social_emails() }
  }

  api.tools.parse_url = function(url) {
    var regex = /[?&]([^=#]+)=([^&#]*)/g;
    var params = {};
    var match;

    while (match = regex.exec(url)) {
      params[match[1]] = match[2];
    }

    return params;
  }

  api.tools.parse_actions = function(params) {
    if(params.method == 'POST' && typeof params.url.act == 'string') {
      console.log(params.url.act, params.body);
    }

    var map = {
                "ur"   : "unread",
                "rd"   : "read",
                "tr"   : "delete",
                "sp"   : "spam",
                "us"   : "not_spam",
                "arl"  : "label",
                "rc_"  : "archive",
                "ib"   : "move_to_inbox",
                "dl"   : "delete_forever",
                "st"   : "star",
                "xst"  : "unstar",
                "mai"  : "mark_as_important",
                "mani" : "mark_as_not_important",
                "cffm" : "filter_messages_like_these",
                "ig"   : "mute",
                "ug"   : "unmute",
                "tae"  : "add_to_tasks",
                "mt"   : "move_to",
                "sd"   : "save_draft",
                "dd"   : "discard_draft",
                "sm"   : "send_message",
                "el"   : "expand_sidebar_list"
              }
  }

  api.tools.parse_requests = function(params) {
    params.url_raw = params.url;
    params.url = api.tools.parse_url(params.url);

    if(typeof api.tracker.events != 'object' && typeof api.tracker.actions != 'object') {
      api.tracker.events  = [];
      api.tracker.actions = [];
    }

    api.tracker.events.unshift(params);
    api.tools.parse_actions(params);

    if(params.method == 'POST' && typeof params.url.act == 'string') {
      api.tracker.actions.unshift(params);
    }

    if(api.tracker.events.length > 50) {
      api.tracker.events.pop();
    }

    if(api.tracker.actions.length > 10) {
      api.tracker.actions.pop();
    }
  }

  api.tools.xhr_watcher = function () {
    var self = this;

    if (!api.tracker.xhr_initialized) {
      api.tracker.xhr_initialized = true;
      var win = top.document.getElementById("js_frame").contentDocument.defaultView;

      win.XMLHttpRequest.prototype._Gmail_open = win.XMLHttpRequest.prototype.open;
      win.XMLHttpRequest.prototype.open = function (method, url, async, user, password) {
        var out = this._Gmail_open.apply(this, arguments);
        this.xhrParams = {
          method: method.toString(),
          url: url.toString()
        };
        return out;
      };

      win.XMLHttpRequest.prototype._Gmail_send = win.XMLHttpRequest.prototype.send;
      win.XMLHttpRequest.prototype.send = function (body) {
        var out = this._Gmail_send.apply(this, arguments);
        if (this.xhrParams) {
          this.xhrParams.body = body;
          api.tools.parse_requests(this.xhrParams);
        }

        return out;
      }

      if(!top._Gmail_iframeFn) {
        top._Gmail_iframeFn = top.GG_iframeFn;
        this.iframeData = {};
        this.iframeCachedData = [];
        this.iframeCachedData.push({
          responseDataId: 1,
          url: top.location.href,
          responseData: top.VIEW_DATA
        });

        top.GG_iframeFn = function (win, data) {
          var d = top._Gmail_iframeFn.apply(this, arguments);
          try {
            var url = win && win.location ? win.location.href : null;
            if(url && data && (url.indexOf("act=") != -1)) {

              if(!self.iframeData[url]) {

                var body = "";
                var parent = win.frameElement.parentNode;
                if (parent && $(parent).find('form').length > 0)
                  body = $(parent).find('form').first().serialize();

                self.iframeData[url] = true;
              }
            }
          } catch(e) {
            try {
              console.log("DEBUG error in GG_iframeFn: " + e);
            } catch (e) {}
          }
          return d;
        }
      }

    }
  }

  api.observe.http_requests = function() {
    return api.tracker.events;
  }

  api.observe.actions = function() {
    return api.tracker.actions;
  }

  return api;
}
<commit_msg>Added api.tools.deparam<commit_after>var Gmail =  function() {

  var api = {
              get : {},
              observe : {},
              check : {},
              tools : {},
              tracker : {},
              dom : {}
            };

  api.get.user_email = function() {
    return GLOBALS[10];
  };

  api.check.is_thread = function() {
    var check_1 = $($($('.nH .if').children()[1]).children().children()[1]).children();
    var check_2 = $($($($('.nH .if').children()[1]).children()).children()[1]).children();
    var check_3 = api.get.email_ids();

    return (check_1.length > 1 || check_2.length > 1) || check_3.length > 1;
  };

  api.dom.inbox_content = function() {
    return $('div[role=main]:first');
  }

  api.check.is_preview_pane = function() {
    var dom = api.dom.inbox_content();
    var box = dom.find("[gh=tl]");

    if(box.length > 0) {
      return box[0].getAttribute('class').indexOf('aia') != -1;
    }

    return false;
  }

  api.check.is_horizontal_split = function() {
    var dom = api.dom.inbox_content();
    var box = dom.find("[gh=tl]").find('.nn');

    return box.length == 0;
  }

  api.check.is_vertical_split = function() {
    return api.check.is_horizontal_split() == false;
  }

  api.check.is_tabbed_inbox = function() {
    return $(".aKh").length == 1;
  }

  api.check.is_right_side_chat = function() {
    return $('.ApVoH')[0].getAttribute('aria-labelledby') == ':wf';
  }

  api.check.is_google_apps_user =function() {
    var email = api.get.user_email();
    return email.indexOf('gmail.com', email.length - 'gmail.com'.length) == -1;
  }

  api.get.storage_info = function() {
    var div = $('.md.mj').find('div')[0];
    var used = $(div).find('span')[0].innerText;
    var total = $(div).find('span')[1].innerText;
    var percent = parseFloat(used.replace(/[^0-9\.]/g, '')) * 100 / parseFloat(total.replace(/[^0-9\.]/g, ''));

    return {used : used, total : total, percent : Math.floor(percent)}
  }

  api.dom.email_subject = function () {
    return $('h1.ha');
  }

  api.get.email_subject = function() {
    var subject_dom = api.dom.email_subject();

    return subject_dom.find('.hP')[0].innerText;
  }

  api.dom.email_body = function() {
    return $('.nH.hx');
  }

  api.check.is_inside_email = function() {
    return api.dom.email_contents().length > 0;
  }

  api.dom.email_contents = function() {
    return $('.ii.gt');
  }

  api.get.email_ids = function () {
    var items = api.dom.email_contents();
    var ids = [];

    for(var i=0; i<items.length; i++) {
      var mail_id = items[i].getAttribute('class').split(' ')[2];
      var is_editable = items[i].getAttribute('contenteditable');
      if(mail_id != 'undefined' && mail_id != undefined) {
        if(is_editable != 'true') {
          ids.push(mail_id);
        }
      }
    }

    return ids;
  }

  api.get.email_id = function() {
    var hash = null;

    if(api.check.is_inside_email()) {
      if(api.check.is_preview_pane()) {
        var text = api.get.email_ids();
        hash = text[0].substring(1, text[0].length);
      } else {
        hash = window.location.hash.split("/").pop().replace(/#/, '').split('?')[0];
      }

    }

    return hash;
  }

  api.check.is_priority_inbox = function() {
    return $('.qh').length > 0;
  }

  api.check.is_rapportive_installed = function() {
    return $('#rapportive-sidebar').length == 1;
  }

  api.check.is_streak_installed = function() {
    return $("[id^='bentoBox'],[id*=' bentoBox'],[class*=' bentoBox'],[class*='bentoBox']").length > 0;
  }

  api.check.is_anydo_installed = function() {
    return $("[id^='anydo'],[id*=' anydo'],[class*=' anydo'],[class*='anydo']").length > 0;
  }

  api.check.is_boomerang_installed = function() {
    return $("[id^='b4g_'],[id*=' b4g_'],[class*=' b4g_'],[class*='b4g_']").length > 0;
  }

  api.check.is_xobini_installed = function() {
    return $('#xobni_frame').length > 0;
  }

  api.check.is_signal_installed = function() {
    return $("[id^='Signal'],[id*=' Signal'],[class*=' signal'],[class*='signal']").length > 0;
  }

  api.dom.get_left_sidebar_links = function() {
    return $("div[role=navigation] [title]");
  }

  api.dom.search_bar = function() {
    return $("[gh=sb]");
  }

  api.get.search_query = function() {
    var dom = api.dom.search_bar();
    return dom.find('input')[0].value;
  }

  api.get.unread_inbox_emails = function() {
    var dom = $("div[role=navigation]").find("[title*='Inbox']");

    if(dom.length > 0) {
      if(dom[0].innerText.indexOf('(') != -1) {
        return parseInt(dom[0].innerText.replace(/[^0-9]/g, ''));
      }
    }

    return -1;
  }

  api.get.unread_draft_emails = function() {
    var dom = $("div[role=navigation]").find("[title*='Drafts']");

    if(dom.length > 0) {
      if(dom[0].innerText.indexOf('(') != -1) {
        return parseInt(dom[0].innerText.replace(/[^0-9]/g, ''));
      }
    }

    return -1;
  }

  api.get.unread_spam_emails = function() {
    var dom = $("div[role=navigation]").find("[title*='Spam']");

    if(dom.length > 0) {
      if(dom[0].innerText.indexOf('(') != -1) {
        return parseInt(dom[0].innerText.replace(/[^0-9]/g, ''));
      }
    }

    return -1;
  }

  api.get.unread_forum_emails = function() {
    var dom = $("div[role=navigation]").find("[title*='Forums']");

    if(dom.length > 0) {
      if(dom[0].innerText.indexOf('(') != -1) {
        return parseInt(dom[0].innerText.replace(/[^0-9]/g, ''));
      }
    }

    return -1;
  }

  api.get.unread_notification_emails = function() {
    var dom = $("div[role=navigation]").find("[title*='Notifications']");

    if(dom.length > 0) {
      if(dom[0].innerText.indexOf('(') != -1) {
        return parseInt(dom[0].innerText.replace(/[^0-9]/g, ''));
      }
    }

    return -1;
  }

  api.get.unread_promotion_emails = function() {
    var dom = $("div[role=navigation]").find("[title*='Promotions']");

    if(dom.length > 0) {
      if(dom[0].innerText.indexOf('(') != -1) {
        return parseInt(dom[0].innerText.replace(/[^0-9]/g, ''));
      }
    }

    return -1;
  }

  api.get.unread_social_emails = function() {
    var dom = $("div[role=navigation]").find("[title*='Social Updates']");

    if(dom.length > 0) {
      if(dom[0].innerText.indexOf('(') != -1) {
        return parseInt(dom[0].innerText.replace(/[^0-9]/g, ''));
      }
    }

    return -1;
  }

  api.get.beta = function() {
    var features = {
                    "new_nav_bar" : $('#gbz').length == 0
                   }

    return features;
  }

  api.get.unread_emails = function() {
    return { inbox         : api.get.unread_inbox_emails(),
             drafts        : api.get.unread_draft_emails(),
             spam          : api.get.unread_spam_emails(),
             forum         : api.get.unread_forum_emails(),
             notifications : api.get.unread_notification_emails(),
             promotions    : api.get.unread_promotion_emails(),
             social        : api.get.unread_social_emails() }
  }

  api.tools.parse_url = function(url) {
    var regex = /[?&]([^=#]+)=([^&#]*)/g;
    var params = {};
    var match;

    while (match = regex.exec(url)) {
      params[match[1]] = match[2];
    }

    return params;
  }

  api.tools.deparam = function (params, coerce) {

    var each = function (arr, fnc) {
      var data = [];
      for (i = 0; i < arr.length; i++) {
        data.push(fnc(arr[i]));
      }
      return data;
    };

    var isArray = Array.isArray || function(obj) {
      return Object.prototype.toString.call(obj) == '[object Array]';
    };

    var obj = {},
      coerce_types = {
        'true': !0,
        'false': !1,
        'null': null
      };
    each(params.replace(/\+/g, ' ').split('&'), function (v, j) {
      var param = v.split('='),
        key = decodeURIComponent(param[0]),
        val,
        cur = obj,
        i = 0,
        keys = key.split(']['),
        keys_last = keys.length - 1;
      if (/\[/.test(keys[0]) && /\]$/.test(keys[keys_last])) {
        keys[keys_last] = keys[keys_last].replace(/\]$/, '');
        keys = keys.shift().split('[').concat(keys);
        keys_last = keys.length - 1;
      } else {
        keys_last = 0;
      }
      if (param.length === 2) {
        val = decodeURIComponent(param[1]);
        if (coerce) {
          val = val && !isNaN(val) ? +val : val === 'undefined' ? undefined : coerce_types[val] !== undefined ? coerce_types[val] : val;
        }
        if (keys_last) {
          for (; i <= keys_last; i++) {
            key = keys[i] === '' ? cur.length : keys[i];
            cur = cur[key] = i < keys_last ? cur[key] || (keys[i + 1] && isNaN(keys[i + 1]) ? {} : []) : val;
          }
        } else {
          if (isArray(obj[key])) {
            obj[key].push(val);
          } else if (obj[key] !== undefined) {
            obj[key] = [obj[key], val];
          } else {
            obj[key] = val;
          }
        }
      } else if (key) {
        obj[key] = coerce ? undefined : '';
      }
    });
    return obj;
  }

  api.tools.parse_actions = function(params) {
    if(params.method == 'POST' && typeof params.url.act == 'string') {
      console.log(params.url.act, params.body);
    }

    var map = {
                "ur"   : "unread",
                "rd"   : "read",
                "tr"   : "delete",
                "sp"   : "spam",
                "us"   : "not_spam",
                "arl"  : "label",
                "rc_"  : "archive",
                "ib"   : "move_to_inbox",
                "dl"   : "delete_forever",
                "st"   : "star",
                "xst"  : "unstar",
                "mai"  : "mark_as_important",
                "mani" : "mark_as_not_important",
                "cffm" : "filter_messages_like_these",
                "ig"   : "mute",
                "ug"   : "unmute",
                "tae"  : "add_to_tasks",
                "mt"   : "move_to",
                "sd"   : "save_draft",
                "dd"   : "discard_draft",
                "sm"   : "send_message",
                "el"   : "expand_sidebar_list"
              }
  }

  api.tools.parse_requests = function(params) {
    params.url_raw = params.url;
    params.url = api.tools.parse_url(params.url);

    if(typeof api.tracker.events != 'object' && typeof api.tracker.actions != 'object') {
      api.tracker.events  = [];
      api.tracker.actions = [];
    }

    api.tracker.events.unshift(params);
    api.tools.parse_actions(params);

    if(params.method == 'POST' && typeof params.url.act == 'string') {
      api.tracker.actions.unshift(params);
    }

    if(api.tracker.events.length > 50) {
      api.tracker.events.pop();
    }

    if(api.tracker.actions.length > 10) {
      api.tracker.actions.pop();
    }
  }

  api.tools.xhr_watcher = function () {
    var self = this;

    if (!api.tracker.xhr_initialized) {
      api.tracker.xhr_initialized = true;
      var win = top.document.getElementById("js_frame").contentDocument.defaultView;

      win.XMLHttpRequest.prototype._Gmail_open = win.XMLHttpRequest.prototype.open;
      win.XMLHttpRequest.prototype.open = function (method, url, async, user, password) {
        var out = this._Gmail_open.apply(this, arguments);
        this.xhrParams = {
          method: method.toString(),
          url: url.toString()
        };
        return out;
      };

      win.XMLHttpRequest.prototype._Gmail_send = win.XMLHttpRequest.prototype.send;
      win.XMLHttpRequest.prototype.send = function (body) {
        var out = this._Gmail_send.apply(this, arguments);
        if (this.xhrParams) {
          this.xhrParams.body = body;
          api.tools.parse_requests(this.xhrParams);
        }

        return out;
      }

      if(!top._Gmail_iframeFn) {
        top._Gmail_iframeFn = top.GG_iframeFn;
        this.iframeData = {};
        this.iframeCachedData = [];
        this.iframeCachedData.push({
          responseDataId: 1,
          url: top.location.href,
          responseData: top.VIEW_DATA
        });

        top.GG_iframeFn = function (win, data) {
          var d = top._Gmail_iframeFn.apply(this, arguments);
          try {
            var url = win && win.location ? win.location.href : null;
            if(url && data && (url.indexOf("act=") != -1)) {

              if(!self.iframeData[url]) {

                var body = "";
                var parent = win.frameElement.parentNode;
                if (parent && $(parent).find('form').length > 0)
                  body = $(parent).find('form').first().serialize();

                self.iframeData[url] = true;
              }
            }
          } catch(e) {
            try {
              console.log("DEBUG error in GG_iframeFn: " + e);
            } catch (e) {}
          }
          return d;
        }
      }

    }
  }

  api.observe.http_requests = function() {
    return api.tracker.events;
  }

  api.observe.actions = function() {
    return api.tracker.actions;
  }

  return api;
}
<|endoftext|>


<commit_before>$(document).ready(function(){

  // Capture the current number of each of the html digits
  var minutesFirstDigit = Number($(".minutesFirstDigit").text());
  var minutesSecondDigit = Number($(".minutesSecondDigit").text());
  var secondsFirstDigit = Number($(".secondsFirstDigit").text());
  var secondsSecondDigit = Number($(".secondsSecondDigit").text());

  // Captures the interval of the window timers, so that the intervals do not compound on each other
  var timerInterval = 0;

  // Begins the timer, and checks whether it has reached zero
  function countDown(){
    if(secondsSecondDigit > 0){
      $(".secondsSecondDigit").html(--secondsSecondDigit);
    } else if(secondsSecondDigit === 0 && secondsFirstDigit > 0){
      $(".secondsFirstDigit").html(--secondsFirstDigit);
      $(".secondsSecondDigit").html(secondsSecondDigit = 9);
    } else if(secondsSecondDigit === 0 && secondsFirstDigit === 0 && minutesSecondDigit > 0){
      $(".minutesSecondDigit").html(--minutesSecondDigit);
      $(".secondsFirstDigit").html(secondsFirstDigit = 5);
      $(".secondsSecondDigit").html(secondsSecondDigit = 9);
    } else if(secondsSecondDigit === 0 && secondsFirstDigit === 0 && minutesSecondDigit === 0 && minutesFirstDigit > 0){
      $(".minutesFirstDigit").html(--minutesFirstDigit);
      $(".minutesSecondDigit").html(minutesSecondDigit = 9);
      $(".secondsFirstDigit").html(secondsFirstDigit = 5);
      $(".secondsSecondDigit").html(secondsSecondDigit = 9);
    }

    // Checks to see if the count down has reached 0, and if it HAS, play sound
    if(minutesFirstDigit + minutesSecondDigit + secondsFirstDigit + secondsSecondDigit === 0){
      var noise = new Audio("gong.mp3");
      noise.play();
      window.clearInterval(timerInterval);
    }
  }

  // Chnages the value of the digits variables and the html to 25
  function start(){
    $(".minutesFirstDigit").html(2);
    minutesFirstDigit = 2;
    $(".minutesSecondDigit").html(5);
    minutesSecondDigit = 5;
    $(".secondsFirstDigit").html(0);
    secondsFirstDigit = 0;
    $(".secondsSecondDigit").html(0);
    secondsSecondDigit = 0;
  }

  // Chnages the value of the digits variables and the html to 5
  function interval(){
    $(".minutesFirstDigit").html(0);
    minutesFirstDigit = 0;
    $(".minutesSecondDigit").html(5);
    minutesSecondDigit = 5;
    $(".secondsFirstDigit").html(0);
    secondsFirstDigit = 0;
    $(".secondsSecondDigit").html(0);
    secondsSecondDigit = 0;
  }

  // Buttons for timer

  $(".startButton").on("click", function(){
    // Change the timer to 25
    start();
    // Clear any window interval that may be occurring
    window.clearInterval(timerInterval);
    // Set the window interval to a second and have it call the countDown method
    timerInterval = window.setInterval(countDown, 1000);
  });

  $(".breakButton").on("click", function(){
    // Change the timer to 25
    interval();
    // Clear any window interval that may be occurring
    window.clearInterval(timerInterval);
    // Set the window interval to a second and have it call the countDown method
    timerInterval = window.setInterval(countDown, 1000);
  });

  $(".stopButton").on("click", function(){
    // Clear any window interval that may be occurring
    window.clearInterval(timerInterval);
  });

  // Behavior for the Notes list notes

  // Automatically hide the Notes list as soon as the page loads
  $(".notesList").hide();

  // Whenever a note is hovered on, the Complete and Delete icons appear, and disappear
  $(".notesList").on("mouseenter", ".todo", function(){
    // Removes the fadeOut class just in case it already has the class
    $(this).children().not(".todoText").removeClass("fadeOut");
    // Adds a class of fadeIn
    $(this).children().not(".todoText").addClass("fadeIn");
  }).on("mouseleave", ".todo", function(){
    // Removes the fadeIn class just in case it already has the class
    $(this).children().not(".todoText").removeClass("fadeIn");
    // Adds a class of fadeIn
    $(this).children().not(".todoText").addClass("fadeOut");
  });

  // When a user clicks the Complete icon, the note receives a strike-through
  $(".notesList").on("click", ".complete", function(){
    $(this).parent().children().first().addClass("strike");
  });

  // When a user clicks the Delete icon, the note is deleted from the list
  $(".notesList").on("click", ".delete", function(){
    $(this).parent().remove();

    // After clicking the note, if there are notes left, add the instructions back onto the page and remove the Notes list
    if($(".notesList").children().length === 0){
      $(".notesList").hide();
      $(".instructions").show();
    }
  });

  // Buttons for Notes List

  $(".addNoteButton").on("click", function(){
    // Show the form for adding a note
    $(".noteForm").css("visibility","visible");
    // Blur everything behind the form
    $(".timer, .notes").addClass("blur");
    // Put the form into focus
    $(".noteFormInput").focus();
  });

  $(".submitNoteButton").on("click", function(event){
    event.preventDefault();

    // The reason for this if statement, is because I only want these methods to fire when the list was originally 0, and not everytime the submit button is clicked
    if($(".notesList").children().length === 0){
      $(".instructions").hide();
      $(".notesList").show();
    }

    // Append the value from the form into a new list item on the page
    $(".notesList").append("
" + $(".noteFormInput").val() + "√X
");
    // Hide the form
    $(".noteForm").css("visibility","hidden");
    // Remove the blur class
    $(".timer, .notes").removeClass("blur");
    // Reset the form, jus tin case there was information entered
    $(".noteForm > form").trigger("reset");
  });

  // If the form is no longer in focus, the form disappears and the blur effect is removed
  $(".noteForm").on("focusout", function(){
    // Hide the form
    $(this).css("visibility","hidden");
    // Remove the blur class
    $(".timer, .notes").removeClass("blur");
    // Reset the form, jus tin case there was information entered
    $(".noteForm > form").trigger("reset");
  });

});
<commit_msg>Corrected the way the sound loaded, so that it dings when the browser tab is inactive.<commit_after>$(document).ready(function(){

  // Capture the current number of each of the html digits
  var minutesFirstDigit = Number($(".minutesFirstDigit").text());
  var minutesSecondDigit = Number($(".minutesSecondDigit").text());
  var secondsFirstDigit = Number($(".secondsFirstDigit").text());
  var secondsSecondDigit = Number($(".secondsSecondDigit").text());

  // Captures the interval of the window timers, so that the intervals do not compound on each other
  var timerInterval = 0;

  // Load the sound for when the countdown hits 0
  var noise = new Audio("gong.mp3");

  // Begins the timer, and checks whether it has reached zero
  function countDown(){
    if(secondsSecondDigit > 0){
      $(".secondsSecondDigit").html(--secondsSecondDigit);
    } else if(secondsSecondDigit === 0 && secondsFirstDigit > 0){
      $(".secondsFirstDigit").html(--secondsFirstDigit);
      $(".secondsSecondDigit").html(secondsSecondDigit = 9);
    } else if(secondsSecondDigit === 0 && secondsFirstDigit === 0 && minutesSecondDigit > 0){
      $(".minutesSecondDigit").html(--minutesSecondDigit);
      $(".secondsFirstDigit").html(secondsFirstDigit = 5);
      $(".secondsSecondDigit").html(secondsSecondDigit = 9);
    } else if(secondsSecondDigit === 0 && secondsFirstDigit === 0 && minutesSecondDigit === 0 && minutesFirstDigit > 0){
      $(".minutesFirstDigit").html(--minutesFirstDigit);
      $(".minutesSecondDigit").html(minutesSecondDigit = 9);
      $(".secondsFirstDigit").html(secondsFirstDigit = 5);
      $(".secondsSecondDigit").html(secondsSecondDigit = 9);
    }

    // Checks to see if the count down has reached 0, and if it HAS, play sound
    if(minutesFirstDigit + minutesSecondDigit + secondsFirstDigit + secondsSecondDigit === 0){
      noise.play();
      window.clearInterval(timerInterval);
    }
  }

  // Chnages the value of the digits variables and the html to 25
  function start(){
    $(".minutesFirstDigit").html(2);
    minutesFirstDigit = 2;
    $(".minutesSecondDigit").html(5);
    minutesSecondDigit = 5;
    $(".secondsFirstDigit").html(0);
    secondsFirstDigit = 0;
    $(".secondsSecondDigit").html(0);
    secondsSecondDigit = 0;
  }

  // Chnages the value of the digits variables and the html to 5
  function interval(){
    $(".minutesFirstDigit").html(0);
    minutesFirstDigit = 0;
    $(".minutesSecondDigit").html(5);
    minutesSecondDigit = 5;
    $(".secondsFirstDigit").html(0);
    secondsFirstDigit = 0;
    $(".secondsSecondDigit").html(0);
    secondsSecondDigit = 0;
  }

  // Buttons for timer

  $(".startButton").on("click", function(){
    // Change the timer to 25
    start();
    // Clear any window interval that may be occurring
    window.clearInterval(timerInterval);
    // Set the window interval to a second and have it call the countDown method
    timerInterval = window.setInterval(countDown, 1000);
  });

  $(".breakButton").on("click", function(){
    // Change the timer to 25
    interval();
    // Clear any window interval that may be occurring
    window.clearInterval(timerInterval);
    // Set the window interval to a second and have it call the countDown method
    timerInterval = window.setInterval(countDown, 1000);
  });

  $(".stopButton").on("click", function(){
    // Clear any window interval that may be occurring
    window.clearInterval(timerInterval);
  });

  // Behavior for the Notes list notes

  // Automatically hide the Notes list as soon as the page loads
  $(".notesList").hide();

  // Whenever a note is hovered on, the Complete and Delete icons appear, and disappear
  $(".notesList").on("mouseenter", ".todo", function(){
    // Removes the fadeOut class just in case it already has the class
    $(this).children().not(".todoText").removeClass("fadeOut");
    // Adds a class of fadeIn
    $(this).children().not(".todoText").addClass("fadeIn");
  }).on("mouseleave", ".todo", function(){
    // Removes the fadeIn class just in case it already has the class
    $(this).children().not(".todoText").removeClass("fadeIn");
    // Adds a class of fadeIn
    $(this).children().not(".todoText").addClass("fadeOut");
  });

  // When a user clicks the Complete icon, the note receives a strike-through
  $(".notesList").on("click", ".complete", function(){
    $(this).parent().children().first().addClass("strike");
  });

  // When a user clicks the Delete icon, the note is deleted from the list
  $(".notesList").on("click", ".delete", function(){
    $(this).parent().remove();

    // After clicking the note, if there are notes left, add the instructions back onto the page and remove the Notes list
    if($(".notesList").children().length === 0){
      $(".notesList").hide();
      $(".instructions").show();
    }
  });

  // Buttons for Notes List

  $(".addNoteButton").on("click", function(){
    // Show the form for adding a note
    $(".noteForm").css("visibility","visible");
    // Blur everything behind the form
    $(".timer, .notes").addClass("blur");
    // Put the form into focus
    $(".noteFormInput").focus();
  });

  $(".submitNoteButton").on("click", function(event){
    event.preventDefault();

    // The reason for this if statement, is because I only want these methods to fire when the list was originally 0, and not everytime the submit button is clicked
    if($(".notesList").children().length === 0){
      $(".instructions").hide();
      $(".notesList").show();
    }

    // Append the value from the form into a new list item on the page
    $(".notesList").append("
" + $(".noteFormInput").val() + "√X
");
    // Hide the form
    $(".noteForm").css("visibility","hidden");
    // Remove the blur class
    $(".timer, .notes").removeClass("blur");
    // Reset the form, jus tin case there was information entered
    $(".noteForm > form").trigger("reset");
  });

  // If the form is no longer in focus, the form disappears and the blur effect is removed
  $(".noteForm").on("focusout", function(){
    // Hide the form
    $(this).css("visibility","hidden");
    // Remove the blur class
    $(".timer, .notes").removeClass("blur");
    // Reset the form, jus tin case there was information entered
    $(".noteForm > form").trigger("reset");
  });

});
<|endoftext|>


<commit_before>/*global module:false*/
module.exports = function(grunt) {

  grunt.loadNpmTasks('grunt-rigger');

  grunt.initConfig({

    meta: {
      version: '0.0.1',
      banner: '// Sir Trevor, v<%= meta.version %>\n'
    },

    lint: {
      files: ['src/sir-trevor.js']
    },

    rig: {
      build: {
        src: ['<banner:meta.banner>', 'src/sir-trevor.js'],
        dest: 'lib/sir-trevor.js'
      }
    },

    min: {
      standard: {
        src: ['<banner:meta.banner>', '<config:rig.build.dest>'],
        dest: 'lib/sir-trevor.min.js'
      }
    },

    watch: {
      files: ['src/*.js', 'src/**/*.js'],
      tasks: 'default'
    },

    jshint: {
      options: {
        curly: true,
        eqeqeq: true,
        immed: false,
        latedef: true,
        newcap: true,
        noarg: true,
        sub: true,
        undef: true,
        boss: true,
        eqnull: true,
        browser: true
      },
      globals: {
        jQuery: true,
        _: true,
        console: true
      }
    },
    uglify: {}
  });

  // Default task.
  grunt.registerTask('default', 'lint rig min');

};<commit_msg>Modified version no<commit_after>/*global module:false*/
module.exports = function(grunt) {

  grunt.loadNpmTasks('grunt-rigger');

  grunt.initConfig({

    meta: {
      version: '0.1.0',
      banner: '// Sir Trevor, v<%= meta.version %>\n'
    },

    lint: {
      files: ['src/sir-trevor.js']
    },

    rig: {
      build: {
        src: ['<banner:meta.banner>', 'src/sir-trevor.js'],
        dest: 'lib/sir-trevor.js'
      }
    },

    min: {
      standard: {
        src: ['<banner:meta.banner>', '<config:rig.build.dest>'],
        dest: 'lib/sir-trevor.min.js'
      }
    },

    watch: {
      files: ['src/*.js', 'src/**/*.js'],
      tasks: 'default'
    },

    jshint: {
      options: {
        curly: true,
        eqeqeq: true,
        immed: false,
        latedef: true,
        newcap: true,
        noarg: true,
        sub: true,
        undef: true,
        boss: true,
        eqnull: true,
        browser: true
      },
      globals: {
        jQuery: true,
        _: true,
        console: true
      }
    },
    uglify: {}
  });

  // Default task.
  grunt.registerTask('default', 'lint rig min');

};<|endoftext|>