<commit_before>(function( jQuery ) {

var rbrace = /^(?:\{.*\}|\[.*\])$/,
	rmultiDash = /([a-z])([A-Z])/g;

jQuery.extend({
	cache: {},

	// Please use with caution
	uuid: 0,

	// Unique for each copy of jQuery on the page
	// Non-digits removed to match rinlinejQuery
	expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),

	// The following elements throw uncatchable exceptions if you
	// attempt to add expando properties to them.
	noData: {
		"embed": true,
		// Ban all objects except for Flash (which handle expandos)
		"object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
		"applet": true
	},

	hasData: function( elem ) {
		elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];

		return !!elem && !isEmptyDataObject( elem );
	},

	data: function( elem, name, data, pvt /* Internal Use Only */ ) {
		if ( !jQuery.acceptData( elem ) ) {
			return;
		}

		var internalKey = jQuery.expando, getByName = typeof name === "string", thisCache,

			// We have to handle DOM nodes and JS objects differently because IE6-7
			// can't GC object references properly across the DOM-JS boundary
			isNode = elem.nodeType,

			// Only DOM nodes need the global jQuery cache; JS object data is
			// attached directly to the object so GC can occur automatically
			cache = isNode ? jQuery.cache : elem,

			// Only defining an ID for JS objects if its cache already exists allows
			// the code to shortcut on the same path as a DOM node with no cache
			id = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando;

		// Avoid doing any more work than we need to when trying to get data on an
		// object that has no data at all
		if ( (!id || (pvt && id && !cache[ id ][ internalKey ])) && getByName && data === undefined ) {
			return;
		}

		if ( !id ) {
			// Only DOM nodes need a new unique ID for each element since their data
			// ends up in the global cache
			if ( isNode ) {
				elem[ jQuery.expando ] = id = ++jQuery.uuid;
			} else {
				id = jQuery.expando;
			}
		}

		if ( !cache[ id ] ) {
			cache[ id ] = {};

			// TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery
			// metadata on plain JS objects when the object is serialized using
			// JSON.stringify
			if ( !isNode ) {
				cache[ id ].toJSON = jQuery.noop;
			}
		}

		// An object can be passed to jQuery.data instead of a key/value pair; this gets
		// shallow copied over onto the existing cache
		if ( typeof name === "object" || typeof name === "function" ) {
			if ( pvt ) {
				cache[ id ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name);
			} else {
				cache[ id ] = jQuery.extend(cache[ id ], name);
			}
		}

		thisCache = cache[ id ];

		// Internal jQuery data is stored in a separate object inside the object's data
		// cache in order to avoid key collisions between internal data and user-defined
		// data
		if ( pvt ) {
			if ( !thisCache[ internalKey ] ) {
				thisCache[ internalKey ] = {};
			}

			thisCache = thisCache[ internalKey ];
		}

		if ( data !== undefined ) {
			thisCache[ name ] = data;
		}

		// TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should
		// not attempt to inspect the internal events object using jQuery.data, as this
		// internal data object is undocumented and subject to change.
		if ( name === "events" && !thisCache[name] ) {
			return thisCache[ internalKey ] && thisCache[ internalKey ].events;
		}

		return getByName ? thisCache[ name ] : thisCache;
	},

	removeData: function( elem, name, pvt /* Internal Use Only */ ) {
		if ( !jQuery.acceptData( elem ) ) {
			return;
		}

		var internalKey = jQuery.expando, isNode = elem.nodeType,

			// See jQuery.data for more information
			cache = isNode ? jQuery.cache : elem,

			// See jQuery.data for more information
			id = isNode ? elem[ jQuery.expando ] : jQuery.expando;

		// If there is already no cache entry for this object, there is no
		// purpose in continuing
		if ( !cache[ id ] ) {
			return;
		}

		if ( name ) {
			var thisCache = pvt ? cache[ id ][ internalKey ] : cache[ id ];

			if ( thisCache ) {
				delete thisCache[ name ];

				// If there is no data left in the cache, we want to continue
				// and let the cache object itself get destroyed
				if ( !isEmptyDataObject(thisCache) ) {
					return;
				}
			}
		}

		// See jQuery.data for more information
		if ( pvt ) {
			delete cache[ id ][ internalKey ];

			// Don't destroy the parent cache unless the internal data object
			// had been the only thing left in it
			if ( !isEmptyDataObject(cache[ id ]) ) {
				return;
			}
		}

		var internalCache = cache[ id ][ internalKey ];

		// Browsers that fail expando deletion also refuse to delete expandos on
		// the window, but it will allow it on all other JS objects; other browsers
		// don't care
		if ( jQuery.support.deleteExpando || cache != window ) {
			delete cache[ id ];
		} else {
			cache[ id ] = null;
		}

		// We destroyed the entire user cache at once because it's faster than
		// iterating through each key, but we need to continue to persist internal
		// data if it existed
		if ( internalCache ) {
			cache[ id ] = {};
			// TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery
			// metadata on plain JS objects when the object is serialized using
			// JSON.stringify
			if ( !isNode ) {
				cache[ id ].toJSON = jQuery.noop;
			}

			cache[ id ][ internalKey ] = internalCache;

		// Otherwise, we need to eliminate the expando on the node to avoid
		// false lookups in the cache for entries that no longer exist
		} else if ( isNode ) {
			// IE does not allow us to delete expando properties from nodes,
			// nor does it have a removeAttribute function on Document nodes;
			// we must handle all of these cases
			if ( jQuery.support.deleteExpando ) {
				delete elem[ jQuery.expando ];
			} else if ( elem.removeAttribute ) {
				elem.removeAttribute( jQuery.expando );
			} else {
				elem[ jQuery.expando ] = null;
			}
		}
	},

	// For internal use only.
	_data: function( elem, name, data ) {
		return jQuery.data( elem, name, data, true );
	},

	// A method for determining if a DOM node can handle the data expando
	acceptData: function( elem ) {
		if ( elem.nodeName ) {
			var match = jQuery.noData[ elem.nodeName.toLowerCase() ];

			if ( match ) {
				return !(match === true || elem.getAttribute("classid") !== match);
			}
		}

		return true;
	}
});

jQuery.fn.extend({
	data: function( key, value ) {
		var data = null;

		if ( typeof key === "undefined" ) {
			if ( this.length ) {
				data = jQuery.data( this[0] );

				if ( this[0].nodeType === 1 ) {
			    var attr = this[0].attributes, name;
					for ( var i = 0, l = attr.length; i < l; i++ ) {
						name = attr[i].name;

						if ( name.indexOf( "data-" ) === 0 ) {
							name = jQuery.camelCase( name.substring(5) );

							dataAttr( this[0], name, data[ name ] );
						}
					}
				}
			}

			return data;

		} else if ( typeof key === "object" ) {
			return this.each(function() {
				jQuery.data( this, key );
			});
		}

		var parts = key.split(".");
		parts[1] = parts[1] ? "." + parts[1] : "";

		if ( value === undefined ) {
			data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);

			// Try to fetch any internally stored data first
			if ( data === undefined && this.length ) {
				data = jQuery.data( this[0], key );
				data = dataAttr( this[0], key, data );
			}

			return data === undefined && parts[1] ?
				this.data( parts[0] ) :
				data;

		} else {
			return this.each(function() {
				var $this = jQuery( this ),
					args = [ parts[0], value ];

				$this.triggerHandler( "setData" + parts[1] + "!", args );
				jQuery.data( this, key, value );
				$this.triggerHandler( "changeData" + parts[1] + "!", args );
			});
		}
	},

	removeData: function( key ) {
		return this.each(function() {
			jQuery.removeData( this, key );
		});
	}
});

function dataAttr( elem, key, data ) {
	// If nothing was found internally, try to fetch any
	// data from the HTML5 data-* attribute
	if ( data === undefined && elem.nodeType === 1 ) {
		name = "data-" + key.replace( rmultiDash, "$1-$2" ).toLowerCase();

		data = elem.getAttribute( name );

		if ( typeof data === "string" ) {
			try {
				data = data === "true" ? true :
				data === "false" ? false :
				data === "null" ? null :
				!jQuery.isNaN( data ) ? parseFloat( data ) :
					rbrace.test( data ) ? jQuery.parseJSON( data ) :
					data;
			} catch( e ) {}

			// Make sure we set the data so it isn't changed later
			jQuery.data( elem, key, data );

		} else {
			data = undefined;
		}
	}

	return data;
}

// TODO: This is a hack for 1.5 ONLY to allow objects with a single toJSON
// property to be considered empty objects; this property always exists in
// order to make sure JSON.stringify does not expose internal metadata
function isEmptyDataObject( obj ) {
	for ( var name in obj ) {
		if ( name !== "toJSON" ) {
			return false;
		}
	}

	return true;
}

})( jQuery );
<commit_msg>Global found in dataAttr function<commit_after>(function( jQuery ) {

var rbrace = /^(?:\{.*\}|\[.*\])$/,
	rmultiDash = /([a-z])([A-Z])/g;

jQuery.extend({
	cache: {},

	// Please use with caution
	uuid: 0,

	// Unique for each copy of jQuery on the page
	// Non-digits removed to match rinlinejQuery
	expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),

	// The following elements throw uncatchable exceptions if you
	// attempt to add expando properties to them.
	noData: {
		"embed": true,
		// Ban all objects except for Flash (which handle expandos)
		"object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
		"applet": true
	},

	hasData: function( elem ) {
		elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];

		return !!elem && !isEmptyDataObject( elem );
	},

	data: function( elem, name, data, pvt /* Internal Use Only */ ) {
		if ( !jQuery.acceptData( elem ) ) {
			return;
		}

		var internalKey = jQuery.expando, getByName = typeof name === "string", thisCache,

			// We have to handle DOM nodes and JS objects differently because IE6-7
			// can't GC object references properly across the DOM-JS boundary
			isNode = elem.nodeType,

			// Only DOM nodes need the global jQuery cache; JS object data is
			// attached directly to the object so GC can occur automatically
			cache = isNode ? jQuery.cache : elem,

			// Only defining an ID for JS objects if its cache already exists allows
			// the code to shortcut on the same path as a DOM node with no cache
			id = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando;

		// Avoid doing any more work than we need to when trying to get data on an
		// object that has no data at all
		if ( (!id || (pvt && id && !cache[ id ][ internalKey ])) && getByName && data === undefined ) {
			return;
		}

		if ( !id ) {
			// Only DOM nodes need a new unique ID for each element since their data
			// ends up in the global cache
			if ( isNode ) {
				elem[ jQuery.expando ] = id = ++jQuery.uuid;
			} else {
				id = jQuery.expando;
			}
		}

		if ( !cache[ id ] ) {
			cache[ id ] = {};

			// TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery
			// metadata on plain JS objects when the object is serialized using
			// JSON.stringify
			if ( !isNode ) {
				cache[ id ].toJSON = jQuery.noop;
			}
		}

		// An object can be passed to jQuery.data instead of a key/value pair; this gets
		// shallow copied over onto the existing cache
		if ( typeof name === "object" || typeof name === "function" ) {
			if ( pvt ) {
				cache[ id ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name);
			} else {
				cache[ id ] = jQuery.extend(cache[ id ], name);
			}
		}

		thisCache = cache[ id ];

		// Internal jQuery data is stored in a separate object inside the object's data
		// cache in order to avoid key collisions between internal data and user-defined
		// data
		if ( pvt ) {
			if ( !thisCache[ internalKey ] ) {
				thisCache[ internalKey ] = {};
			}

			thisCache = thisCache[ internalKey ];
		}

		if ( data !== undefined ) {
			thisCache[ name ] = data;
		}

		// TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should
		// not attempt to inspect the internal events object using jQuery.data, as this
		// internal data object is undocumented and subject to change.
		if ( name === "events" && !thisCache[name] ) {
			return thisCache[ internalKey ] && thisCache[ internalKey ].events;
		}

		return getByName ? thisCache[ name ] : thisCache;
	},

	removeData: function( elem, name, pvt /* Internal Use Only */ ) {
		if ( !jQuery.acceptData( elem ) ) {
			return;
		}

		var internalKey = jQuery.expando, isNode = elem.nodeType,

			// See jQuery.data for more information
			cache = isNode ? jQuery.cache : elem,

			// See jQuery.data for more information
			id = isNode ? elem[ jQuery.expando ] : jQuery.expando;

		// If there is already no cache entry for this object, there is no
		// purpose in continuing
		if ( !cache[ id ] ) {
			return;
		}

		if ( name ) {
			var thisCache = pvt ? cache[ id ][ internalKey ] : cache[ id ];

			if ( thisCache ) {
				delete thisCache[ name ];

				// If there is no data left in the cache, we want to continue
				// and let the cache object itself get destroyed
				if ( !isEmptyDataObject(thisCache) ) {
					return;
				}
			}
		}

		// See jQuery.data for more information
		if ( pvt ) {
			delete cache[ id ][ internalKey ];

			// Don't destroy the parent cache unless the internal data object
			// had been the only thing left in it
			if ( !isEmptyDataObject(cache[ id ]) ) {
				return;
			}
		}

		var internalCache = cache[ id ][ internalKey ];

		// Browsers that fail expando deletion also refuse to delete expandos on
		// the window, but it will allow it on all other JS objects; other browsers
		// don't care
		if ( jQuery.support.deleteExpando || cache != window ) {
			delete cache[ id ];
		} else {
			cache[ id ] = null;
		}

		// We destroyed the entire user cache at once because it's faster than
		// iterating through each key, but we need to continue to persist internal
		// data if it existed
		if ( internalCache ) {
			cache[ id ] = {};
			// TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery
			// metadata on plain JS objects when the object is serialized using
			// JSON.stringify
			if ( !isNode ) {
				cache[ id ].toJSON = jQuery.noop;
			}

			cache[ id ][ internalKey ] = internalCache;

		// Otherwise, we need to eliminate the expando on the node to avoid
		// false lookups in the cache for entries that no longer exist
		} else if ( isNode ) {
			// IE does not allow us to delete expando properties from nodes,
			// nor does it have a removeAttribute function on Document nodes;
			// we must handle all of these cases
			if ( jQuery.support.deleteExpando ) {
				delete elem[ jQuery.expando ];
			} else if ( elem.removeAttribute ) {
				elem.removeAttribute( jQuery.expando );
			} else {
				elem[ jQuery.expando ] = null;
			}
		}
	},

	// For internal use only.
	_data: function( elem, name, data ) {
		return jQuery.data( elem, name, data, true );
	},

	// A method for determining if a DOM node can handle the data expando
	acceptData: function( elem ) {
		if ( elem.nodeName ) {
			var match = jQuery.noData[ elem.nodeName.toLowerCase() ];

			if ( match ) {
				return !(match === true || elem.getAttribute("classid") !== match);
			}
		}

		return true;
	}
});

jQuery.fn.extend({
	data: function( key, value ) {
		var data = null;

		if ( typeof key === "undefined" ) {
			if ( this.length ) {
				data = jQuery.data( this[0] );

				if ( this[0].nodeType === 1 ) {
			    var attr = this[0].attributes, name;
					for ( var i = 0, l = attr.length; i < l; i++ ) {
						name = attr[i].name;

						if ( name.indexOf( "data-" ) === 0 ) {
							name = jQuery.camelCase( name.substring(5) );

							dataAttr( this[0], name, data[ name ] );
						}
					}
				}
			}

			return data;

		} else if ( typeof key === "object" ) {
			return this.each(function() {
				jQuery.data( this, key );
			});
		}

		var parts = key.split(".");
		parts[1] = parts[1] ? "." + parts[1] : "";

		if ( value === undefined ) {
			data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);

			// Try to fetch any internally stored data first
			if ( data === undefined && this.length ) {
				data = jQuery.data( this[0], key );
				data = dataAttr( this[0], key, data );
			}

			return data === undefined && parts[1] ?
				this.data( parts[0] ) :
				data;

		} else {
			return this.each(function() {
				var $this = jQuery( this ),
					args = [ parts[0], value ];

				$this.triggerHandler( "setData" + parts[1] + "!", args );
				jQuery.data( this, key, value );
				$this.triggerHandler( "changeData" + parts[1] + "!", args );
			});
		}
	},

	removeData: function( key ) {
		return this.each(function() {
			jQuery.removeData( this, key );
		});
	}
});

function dataAttr( elem, key, data ) {
	// If nothing was found internally, try to fetch any
	// data from the HTML5 data-* attribute
	if ( data === undefined && elem.nodeType === 1 ) {
		var name = "data-" + key.replace( rmultiDash, "$1-$2" ).toLowerCase();

		data = elem.getAttribute( name );

		if ( typeof data === "string" ) {
			try {
				data = data === "true" ? true :
				data === "false" ? false :
				data === "null" ? null :
				!jQuery.isNaN( data ) ? parseFloat( data ) :
					rbrace.test( data ) ? jQuery.parseJSON( data ) :
					data;
			} catch( e ) {}

			// Make sure we set the data so it isn't changed later
			jQuery.data( elem, key, data );

		} else {
			data = undefined;
		}
	}

	return data;
}

// TODO: This is a hack for 1.5 ONLY to allow objects with a single toJSON
// property to be considered empty objects; this property always exists in
// order to make sure JSON.stringify does not expose internal metadata
function isEmptyDataObject( obj ) {
	for ( var name in obj ) {
		if ( name !== "toJSON" ) {
			return false;
		}
	}

	return true;
}

})( jQuery );
<|endoftext|>


<commit_before>'use strict';

var sales = [
  { product: 'Snickers',  count: 12 },
  { product: 'Twix',  count: 30 },
  { product: 'Pez', count: 9 },
  { product: 'Nerds', count: 19 },
  { product: 'Rollos', count: 10 },
  { product: 'Altoids', count: 5 },
  { product: 'N/A', count: 15 },
];
//set up the angles of the pie chart using the pie layout helper
var pie = d3.layout.pie()
  .value(function(d) { return d.count })

var slices = pie(sales);

var arc = d3.svg.arc()
  .innerRadius(0)
  .outerRadius(100);

// another helper that returns a color based on an ID, category10
var color = d3.scale.category10();

var svg = d3.select('svg.pie');
var g = svg.append('g')
  .attr('transform', 'translate(200, 100)')

g.selectAll('path.slice')
  .data(slices)
    .enter()
      .append('path')
        .attr('class', 'slice')
        .attr('d', arc)
        .attr('fill', function(d) {
          return color(d.data.product);
        });

// building a legend is as simple as binding
// more elements to the same data. in this case,
// <text> tags
svg.append('g')
  .attr('class', 'legend')
    .selectAll('text')
    .data(slices)
      .enter()
        .append('text')
          .text(function(d) { return '• ' + d.data.product + ' (' + d.data.count + ')'; })
          .attr('fill', function(d) { return color(d.data.product); })
          .attr('y', function(d, i) { return 20 * (i + 1); })

//EXAMPLE 2

var margin = {top: 20, right: 20, bottom: 30, left: 50},
    width = 600 - margin.left - margin.right,
    height = 400 - margin.top - margin.bottom;

var parseDate = d3.time.format("%d-%b-%y").parse;

var x = d3.time.scale()
    .range([0, width]);

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

var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom");

var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left");

var line = d3.svg.line()
    .x(function(d) { return x(d.date); })
    .y(function(d) { return y(d.users); });

var svg = d3.select(".linechart").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

d3.tsv("data.tsv", function(error, data) {
  if (error) throw error;

  data.forEach(function(d) {
    d.date = parseDate(d.date);
    d.percentage = +d.percentage;
  });

  x.domain(d3.extent(data, function(d) { return d.date; }));
  y.domain(d3.extent(data, function(d) { return d.users; }));

  svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis);

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

  svg.append("path")
      .datum(data)
      .attr("class", "line")
      .attr("d", line);
});
<commit_msg>One last<commit_after>'use strict';

var sales = [
  { product: 'Snickers',  count: 12 },
  { product: 'Twix',  count: 30 },
  { product: 'Pez', count: 9 },
  { product: 'Nerds', count: 19 },
  { product: 'Rollos', count: 10 },
  { product: 'Altoids', count: 5 },
  { product: 'N/A', count: 15 },
];
//set up the angles of the pie chart using the pie layout helper
var pie = d3.layout.pie()
  .value(function(d) { return d.count })

var slices = pie(sales);

var arc = d3.svg.arc()
  .innerRadius(0)
  .outerRadius(100);

// another helper that returns a color based on an ID, category10
var color = d3.scale.category10();

var svg = d3.select('svg.pie');
var g = svg.append('g')
  .attr('transform', 'translate(200, 100)')

g.selectAll('path.slice')
  .data(slices)
    .enter()
      .append('path')
        .attr('class', 'slice')
        .attr('d', arc)
        .attr('fill', function(d) {
          return color(d.data.product);
        });

// building a legend is as simple as binding
// more elements to the same data. in this case,
// <text> tags
svg.append('g')
  .attr('class', 'legend')
    .selectAll('text')
    .data(slices)
      .enter()
        .append('text')
          .text(function(d) { return '• ' + d.data.product + ' (' + d.data.count + ')'; })
          .attr('fill', function(d) { return color(d.data.product); })
          .attr('y', function(d, i) { return 20 * (i + 1); })

//EXAMPLE 2

var margin = {top: 20, right: 20, bottom: 30, left: 50},
    width = 600 - margin.left - margin.right,
    height = 400 - margin.top - margin.bottom;

var parseDate = d3.time.format("%d-%b-%y").parse;

var x = d3.time.scale()
    .range([0, width]);

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

var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom");

var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left");

var line = d3.svg.line()
    .x(function(d) { return x(d.date); })
    .y(function(d) { return y(d.users); });

var svg = d3.select(".linechart").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

d3.tsv("data.tsv", function(error, data) {
  if (error) throw error;

  data.forEach(function(d) {
    d.date = parseDate(d.date);
    d.users = +d.users;
  });

  x.domain(d3.extent(data, function(d) { return d.date; }));
  y.domain(d3.extent(data, function(d) { return d.users; }));

  svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis);

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

  svg.append("path")
      .datum(data)
      .attr("class", "line")
      .attr("d", line);
});
<|endoftext|>


<commit_before>/*!
 * context
 * Version: 0.0.1
 * Date: 2016/7/29
 * https://github.com/Nuintun/fengine
 *
 * Original Author: https://github.com/tmont/html-parser
 *
 * This is licensed under the MIT License (MIT).
 * For details, see: https://github.com/Nuintun/fengine/blob/master/LICENSE
 */

'use strict';

// lib
var util = require('./util');

// event types
var EVENTTYPES = [
  'openElement',
  'closeElement',
  'attribute',
  'comment',
  'cdata',
  'text',
  'docType',
  'xmlType',
  'closeOpenedElement'
];

/**
 * format rule
 * @param rule
 * @param porp
 */
function formatRule(rule, porp){
  switch (util.type(rule[porp])) {
    case 'string':
      rule[porp] = util.str2regex(rule[porp]);
      break;
    case 'regexp':
      if (rule[porp].global) {
        var attr = '';

        if (rule[porp].ignoreCase) {
          attr += 'i';
        }

        if (rule[porp].multiline) {
          attr += 'm';
        }

        rule[porp] = util.str2regex(rule[porp].source, attr);
      }
      break;
    default:
      throw new TypeError('rules.dataElements.' + porp + ' must be a sting or regexp.');
      break;
  }
}

/**
 * create read
 * @param raw
 * @param callbacks
 * @param rules
 * @returns {{
 *   text: string,
 *   peek: context.peek,
 *   read: context.read,
 *   readUntilNonWhitespace: context.readUntilNonWhitespace,
 *   readRule: context.readRule,
 *   peekIgnoreWhitespace: context.peekIgnoreWhitespace
 * }}
 */
module.exports.create = function (raw, callbacks, rules){
  var index = 0;
  var current = null;
  var substring = null;

  var context = {
    text: '',
    peek: function (count){
      count = count || 1;

      return this.raw.substr(this.index + 1, count);
    },
    read: function (count, peek){
      var next;

      count = count || 1;

      if (peek) {
        next = this.peek(count);
      }

      this.index += count;

      if (this.index > this.length) {
        this.index = this.length;
      }

      return next;
    },
    readUntilNonWhitespace: function (){
      var next;
      var value = '';

      while (!this.EOF) {
        next = this.read(1, true);

        value += next;

        if (!/\s$/.test(value)) {
          break;
        }
      }

      return value;
    },
    readRule: function (rule){
      var match = rule.exec(this.raw.substring(this.index));
      var value = match ? match[0] : '';

      this.index += (match ? match.index : 0) + value.length;

      return value;
    },
    peekIgnoreWhitespace: function (count){
      count = count || 1;

      var value = '';
      var next = '';
      var offset = 0;

      do {
        next = this.raw.charAt(this.index + ++offset);

        if (!next) {
          break;
        }

        if (!/\s/.test(next)) {
          value += next;
        }
      } while (value.length < count);

      return value;
    }
  };

  // end of file
  context.__defineGetter__('EOF', function (){
    return this.index >= this.length;
  });

  // current char
  context.__defineGetter__('current', function (){
    return this.EOF ? '' : current === null ? (current = this.raw.charAt(this.index)) : current;
  });

  // raw code
  context.__defineGetter__('raw', function (){
    return raw;
  });

  // raw length
  context.__defineGetter__('length', function (){
    return this.raw.length;
  });

  // index
  context.__defineGetter__('index', function (){
    return index;
  });

  // set index
  context.__defineSetter__('index', function (value){
    index = value;
    current = null;
    substring = null;
  });

  // non parsed code
  context.__defineGetter__('substring', function (){
    return substring === null ? (substring = this.raw.substring(this.index)) : substring;
  });

  // callbacks
  context.callbacks = {};

  // format event callbacks
  EVENTTYPES.forEach(function (value){
    context.callbacks[value] = util.noop;
  });

  // merge callbacks
  util.merge(context.callbacks, callbacks || {});

  // rules
  context.rules = {
    name: /[a-zA-Z_][\w:.-]*/,
    attribute: /[a-zA-Z_][\w:.-]*/,
    dataElements: {
      cdata: {
        start: '<![CDATA[',
        end: ']]>'
      },
      comment: {
        start: '<!--',
        end: '-->'
      },
      docType: {
        start: /^<!DOCTYPE /i,
        end: '>'
      }
    }
  };

  // merge rules
  util.merge(context.rules, rules || {});

  var rule;
  var dataElements = context.rules.dataElements;

  for (var data in dataElements) {
    if (dataElements.hasOwnProperty(data)) {
      rule = dataElements[data];

      formatRule(rule, 'start');
      formatRule(rule, 'end');
    }
  }

  // return read
  return context;
};
<commit_msg>update files<commit_after>/*!
 * context
 * Version: 0.0.1
 * Date: 2016/7/29
 * https://github.com/Nuintun/fengine
 *
 * Original Author: https://github.com/tmont/html-parser
 *
 * This is licensed under the MIT License (MIT).
 * For details, see: https://github.com/Nuintun/fengine/blob/master/LICENSE
 */

'use strict';

// lib
var util = require('./util');

// event types
var EVENTTYPES = [
  'openElement',
  'closeElement',
  'attribute',
  'comment',
  'cdata',
  'text',
  'docType',
  'xmlType',
  'closeOpenedElement'
];

/**
 * format rule
 * @param rule
 * @param porp
 */
function formatRule(rule, porp){
  switch (util.type(rule[porp])) {
    case 'string':
      rule[porp] = util.str2regex(rule[porp]);
      break;
    case 'regexp':
      if (rule[porp].global) {
        var attr = '';

        if (rule[porp].ignoreCase) {
          attr += 'i';
        }

        if (rule[porp].multiline) {
          attr += 'm';
        }

        rule[porp] = util.str2regex(rule[porp].source, attr);
      }
      break;
    default:
      throw new TypeError('rules.dataElements.' + porp + ' must be a sting or regexp.');
      break;
  }
}

/**
 * create read
 * @param raw
 * @param callbacks
 * @param rules
 * @returns {{
 *   text: string,
 *   peek: context.peek,
 *   read: context.read,
 *   readUntilNonWhitespace: context.readUntilNonWhitespace,
 *   readRule: context.readRule,
 *   peekIgnoreWhitespace: context.peekIgnoreWhitespace
 * }}
 */
module.exports.create = function (raw, callbacks, rules){
  var index = 0;
  var current = null;
  var substring = null;

  var context = {
    text: '',
    peek: function (count){
      count = count || 1;

      return this.raw.substr(this.index + 1, count);
    },
    read: function (count, peek){
      var next;

      count = count || 1;

      if (peek) {
        next = this.peek(count);
      }

      this.index += count;

      if (this.index > this.length) {
        this.index = this.length;
      }

      return next;
    },
    readUntilNonWhitespace: function (){
      var next;
      var value = '';

      while (!this.EOF) {
        next = this.read(1, true);

        value += next;

        if (!/\s$/.test(value)) {
          break;
        }
      }

      return value;
    },
    readRule: function (rule){
      var match = rule.exec(this.substring);
      var value = match ? match[0] : '';

      this.index += (match ? match.index : 0) + value.length;

      return value;
    },
    peekIgnoreWhitespace: function (count){
      count = count || 1;

      var value = '';
      var next = '';
      var offset = 0;

      do {
        next = this.raw.charAt(this.index + ++offset);

        if (!next) {
          break;
        }

        if (!/\s/.test(next)) {
          value += next;
        }
      } while (value.length < count);

      return value;
    }
  };

  // end of file
  context.__defineGetter__('EOF', function (){
    return this.index >= this.length;
  });

  // current char
  context.__defineGetter__('current', function (){
    return this.EOF ? '' : current === null ? (current = this.raw.charAt(this.index)) : current;
  });

  // raw code
  context.__defineGetter__('raw', function (){
    return raw;
  });

  // raw length
  context.__defineGetter__('length', function (){
    return this.raw.length;
  });

  // index
  context.__defineGetter__('index', function (){
    return index;
  });

  // set index
  context.__defineSetter__('index', function (value){
    index = value;
    current = null;
    substring = null;
  });

  // non parsed code
  context.__defineGetter__('substring', function (){
    return substring === null ? (substring = this.raw.substring(this.index)) : substring;
  });

  // callbacks
  context.callbacks = {};

  // format event callbacks
  EVENTTYPES.forEach(function (value){
    context.callbacks[value] = util.noop;
  });

  // merge callbacks
  util.merge(context.callbacks, callbacks || {});

  // rules
  context.rules = {
    name: /[a-zA-Z_][\w:.-]*/,
    attribute: /[a-zA-Z_][\w:.-]*/,
    dataElements: {
      cdata: {
        start: '<![CDATA[',
        end: ']]>'
      },
      comment: {
        start: '<!--',
        end: '-->'
      },
      docType: {
        start: /^<!DOCTYPE /i,
        end: '>'
      }
    }
  };

  // merge rules
  util.merge(context.rules, rules || {});

  var rule;
  var dataElements = context.rules.dataElements;

  for (var data in dataElements) {
    if (dataElements.hasOwnProperty(data)) {
      rule = dataElements[data];

      formatRule(rule, 'start');
      formatRule(rule, 'end');
    }
  }

  // return read
  return context;
};
<|endoftext|>


<commit_before>'use strict';

var statusDiv = null;
var lastMove = 0;

var END_POINT = 'https://bitlyresolver.herokuapp.com/resolveBitly?url=';

var nodeNamesToIgnore = {
  'html': 'html',
  'body': 'body',
  'video': 'video',
  'audio': 'audio',
  'object': 'object',
  'script': 'script',
  'form': 'form',
  'iframe': 'iframe',
  'img': 'img'
};

var lastBitlyLinks = {};
var lastAjax = 0;

function init() {
  statusDiv = createStatusMessage();
  document.body.appendChild(statusDiv);

  bindListeners();
};

function bindListeners() {
  $(statusDiv).on('click', function() {
    hideStatus();
  });

  document.addEventListener('mousemove', function(mouseEvent) {
    if (Date.now() - lastAjax < 100) {
      return;
    }
    if (mouseEvent && mouseEvent.target && mouseEvent.target.children.length === 0) {
      var content = mouseEvent.target.innerText;
      var linkToCheck = getLinkToCheck(content);
      if (shouldCheckNode(mouseEvent.target) && linkToCheck) {
        setBubblePosition(mouseEvent.clientX, mouseEvent.clientY);
        if (lastBitlyLinks[content]) {
          updateStatus(lastBitlyLinks[content]);
        } else {
          lastAjax = Date.now();
          $.get(END_POINT + linkToCheck).then(function(res) {
            lastBitlyLinks[content] = res;
            updateStatus(lastBitlyLinks[content]);
          });
        }
      } else {
        hideStatus();
      }
    } else {
      hideStatus();
    }
  });
}

function getLinkToCheck(content) {
  var index = content.indexOf('http://bit.ly');
  if (index < 0) {
    index = content.indexOf('https://bit.ly')
  }
  if (index < 0) {
    index = content.indexOf('bit.ly');
  }
  if (index < 0) {
    return null;
  }
  return content.substr(index);
}

function shouldCheckNode(node) {
  var nodeName = (node || {}).nodeName;
  var nameAsLowerCase = (nodeName || '').toLowerCase();
  return !nodeNamesToIgnore[nameAsLowerCase];
}

function setBubblePosition(x, y) {
  if (y + 20 > document.documentElement.clientHeight) {
    y -= 20;
  }
  if (x + 150 > document.documentElement.clientWidth) {
    x-= 200;
  }
  statusDiv.style.top = y + 'px';
  statusDiv.style.left = x + 'px';
}

function updateStatus(result) {
  if (result.status === '200') {
    statusDiv.innerHTML = result.resolvedUrl;
    statusDiv.style.opacity = 1;
    var statusDivPos = $(statusDiv).position();
    var statusDivWidth = $(statusDiv).width();
    if (statusDivPos.left + statusDivWidth > document.documentElement.clientWidth) {
      statusDiv.style.right = 0;
      statusDiv.style.left = '';
    } else {
      statusDiv.style.right = '';
    }
  }
}

function hideStatus() {
  statusDiv.style.opacity = 0;
}

function createStatusMessage() {
  var statusDiv = document.createElement('div');
  statusDiv.innerHTML = '';
  $(statusDiv).css({
    'background': 'white',
    'border': '1px solid black',
    'padding': '5px',
    'position': 'fixed',
    'opacity': 0,
    'transition': '.3s ease all',
    'box-shadow': '5px 5px 5px #8ec78e',
    'max-width': '500px',
    'overflow-wrap': 'break-word';
    'z-index': 999999,
    'pointer-events': 'none'
  });
  return statusDiv;
}

init();
<commit_msg>fixing syntax error.<commit_after>'use strict';

var statusDiv = null;
var lastMove = 0;

var END_POINT = 'https://bitlyresolver.herokuapp.com/resolveBitly?url=';

var nodeNamesToIgnore = {
  'html': 'html',
  'body': 'body',
  'video': 'video',
  'audio': 'audio',
  'object': 'object',
  'script': 'script',
  'form': 'form',
  'iframe': 'iframe',
  'img': 'img'
};

var lastBitlyLinks = {};
var lastAjax = 0;

function init() {
  statusDiv = createStatusMessage();
  document.body.appendChild(statusDiv);

  bindListeners();
};

function bindListeners() {
  $(statusDiv).on('click', function() {
    hideStatus();
  });

  document.addEventListener('mousemove', function(mouseEvent) {
    if (Date.now() - lastAjax < 100) {
      return;
    }
    if (mouseEvent && mouseEvent.target && mouseEvent.target.children.length === 0) {
      var content = mouseEvent.target.innerText;
      var linkToCheck = getLinkToCheck(content);
      if (shouldCheckNode(mouseEvent.target) && linkToCheck) {
        setBubblePosition(mouseEvent.clientX, mouseEvent.clientY);
        if (lastBitlyLinks[content]) {
          updateStatus(lastBitlyLinks[content]);
        } else {
          lastAjax = Date.now();
          $.get(END_POINT + linkToCheck).then(function(res) {
            lastBitlyLinks[content] = res;
            updateStatus(lastBitlyLinks[content]);
          });
        }
      } else {
        hideStatus();
      }
    } else {
      hideStatus();
    }
  });
}

function getLinkToCheck(content) {
  var index = content.indexOf('http://bit.ly');
  if (index < 0) {
    index = content.indexOf('https://bit.ly')
  }
  if (index < 0) {
    index = content.indexOf('bit.ly');
  }
  if (index < 0) {
    return null;
  }
  return content.substr(index);
}

function shouldCheckNode(node) {
  var nodeName = (node || {}).nodeName;
  var nameAsLowerCase = (nodeName || '').toLowerCase();
  return !nodeNamesToIgnore[nameAsLowerCase];
}

function setBubblePosition(x, y) {
  if (y + 20 > document.documentElement.clientHeight) {
    y -= 20;
  }
  if (x + 150 > document.documentElement.clientWidth) {
    x-= 200;
  }
  statusDiv.style.top = y + 'px';
  statusDiv.style.left = x + 'px';
}

function updateStatus(result) {
  if (result.status === '200') {
    statusDiv.innerHTML = result.resolvedUrl;
    statusDiv.style.opacity = 1;
    var statusDivPos = $(statusDiv).position();
    var statusDivWidth = $(statusDiv).width();
    if (statusDivPos.left + statusDivWidth > document.documentElement.clientWidth) {
      statusDiv.style.right = 0;
      statusDiv.style.left = '';
    } else {
      statusDiv.style.right = '';
    }
  }
}

function hideStatus() {
  statusDiv.style.opacity = 0;
}

function createStatusMessage() {
  var statusDiv = document.createElement('div');
  statusDiv.innerHTML = '';
  $(statusDiv).css({
    'background': 'white',
    'border': '1px solid black',
    'padding': '5px',
    'position': 'fixed',
    'opacity': 0,
    'transition': '.3s ease all',
    'box-shadow': '5px 5px 5px #8ec78e',
    'max-width': '500px',
    'overflow-wrap': 'break-word',
    'z-index': 999999,
    'pointer-events': 'none'
  });
  return statusDiv;
}

init();
<|endoftext|>


<commit_before>//     Zepto.js
//     (c) 2010-2012 Thomas Fuchs
//     Zepto.js may be freely distributed under the MIT license.

// The following code is heavily inspired by jQuery's $.fn.data()

;(function($) {
  var data = {}, dataAttr = $.fn.data,
    uuid = $.uuid = +new Date(),
    exp  = $.expando = 'Zepto' + uuid

  function getData(node, name) {
    var id = node[exp], store = id && data[id]
    return name === undefined ? store || setData(node) :
      (store && store[name]) || dataAttr.call($(node), name)
  }

  function setData(node, name, value) {
    var id = node[exp] || (node[exp] = ++uuid),
      store = data[id] || (data[id] = {})
    if (name !== undefined) store[name] = value
    return store
  }

  $.fn.data = function(name, value) {
    return value === undefined ?
      this.length == 0 ? undefined : getData(this[0], name) :
      this.each(function(idx){
        setData(this, name, $.isFunction(value) ?
                value.call(this, idx, getData(this, name)) : value)
      })
  }
})(Zepto)
<commit_msg>Update src/data.js to allow the storing of functions as data. This is consistent with the JQuery documentation. <commit_after>//     Zepto.js
//     (c) 2010-2012 Thomas Fuchs
//     Zepto.js may be freely distributed under the MIT license.

// The following code is heavily inspired by jQuery's $.fn.data()

;(function($) {
  var data = {}, dataAttr = $.fn.data,
    uuid = $.uuid = +new Date(),
    exp  = $.expando = 'Zepto' + uuid

  function getData(node, name) {
    var id = node[exp], store = id && data[id]
    return name === undefined ? store || setData(node) :
      (store && store[name]) || dataAttr.call($(node), name)
  }

  function setData(node, name, value) {
    var id = node[exp] || (node[exp] = ++uuid),
      store = data[id] || (data[id] = {})
    if (name !== undefined) store[name] = value
    return store
  }

  $.fn.data = function(name, value) {
    return value === undefined ?
      this.length == 0 ? undefined : getData(this[0], name) :
      this.each(function(idx){
        setData(this, name, value);
      });
  };
})(Zepto)
<|endoftext|>


<commit_before>'use strict';
/**
 * @ngdoc overview
 * @name clientApp
 * @description
 * # clientApp
 *
 * Main module of the application.
 */
angular
  .module('clientApp', [
    'angularCharts',
    'btford.socket-io',
    'ngAnimate',
    'ngCookies',
    'ngResource',
    'ngRoute',
    'ngSanitize',
    'ngTouch'
  ])
  .config(function ($routeProvider) {
    $routeProvider
      .when('/', {
        templateUrl: 'views/main.html',
        controller: 'MainCtrl'
      })
      .when('/:roomid', {
        templateUrl: 'views/session.html',
        controller: 'SessionCtrl'
      })
      .when('/about', {
        templateUrl: 'views/about.html',
        controller: 'AboutCtrl'
      })
      .when('/session', {
        templateUrl: 'views/session.html',
        controller: 'SessionCtrl'
      })
      .otherwise({
        redirectTo: '/'
      });
  })
  .factory('mySocket', function (socketFactory) {
    var myIoSocket = io.connect('http://172.18.1.251:3000');

    var mySocket = socketFactory({
      ioSocket: myIoSocket
    });

    return mySocket;
  });<commit_msg>Fixed routes to twerk sessions overriding any other routes (except the main index)<commit_after>'use strict';
/**
 * @ngdoc overview
 * @name clientApp
 * @description
 * # clientApp
 *
 * Main module of the application.
 */
angular
  .module('clientApp', [
    'angularCharts',
    'btford.socket-io',
    'ngAnimate',
    'ngCookies',
    'ngResource',
    'ngRoute',
    'ngSanitize',
    'ngTouch'
  ])
  .config(function ($routeProvider) {
    $routeProvider
      .when('/', {
        templateUrl: 'views/main.html',
        controller: 'MainCtrl'
      })
      .when('/about', {
        templateUrl: 'views/about.html',
        controller: 'AboutCtrl'
      })
      .when('/:roomid', {
        //Always put this route AFTER other major routes otherwise it will override them
        //e.g. it will think /about is a room with id "about"
        templateUrl: 'views/session.html',
        controller: 'SessionCtrl'
      })
      .otherwise({
        redirectTo: '/'
      });
  })
  .factory('mySocket', function (socketFactory) {
    var myIoSocket = io.connect('http://172.18.1.251:3000');

    var mySocket = socketFactory({
      ioSocket: myIoSocket
    });

    return mySocket;
  });<|endoftext|>


<commit_before>class AnimatedEntityRenderer{
  constructor(entity, url, mirrorBasedOnVel = false){
    this.entity = entity;
    this.lastDirection = 1;
    this.httpRequest = new XMLHttpRequest();
    this.mirrorBasedOnVel = mirrorBasedOnVel;

    let self = this;
    this.httpRequest.onreadystatechange = function(){self.finish()};
    this.httpRequest.open('GET', url);
    this.httpRequest.setRequestHeader('Content-Type', 'text/json');
    this.httpRequest.send();
    this.animations = {};
  }

  finish(){
    if (this.httpRequest.readyState === XMLHttpRequest.DONE) {
      if (this.httpRequest.status === 200) {
        this.data = JSON.parse(this.httpRequest.responseText);
        for(let animation of this.data.animations){
          let images = [];
          images.frameDuration = animation.frameDuration;
          this.animations[animation.name] = images;
          for(let i = animation.range[0]; i<= animation.range[1]; i++){
            let url = this.data.base + animation.path + i + animation.extention;
            images.push(PIXI.Texture.fromImage(url, false, PIXI.SCALE_MODES.NEAREST));
          }
        }
        this.sprite = new PIXI.Sprite(this.animations[this.data.default][0]);
        this.index = 0;
        this.animation = this.data.default;
        //UPDATE VALUE 60FPS right now
        this.delay = this.animations[this.data.default].frameDuration/16;
        this.delayLeft = this.delay;
        this.needToAdd = true;
      }
    }
  }

  update(stage){
    if(this.needToAdd){
      stage.addChild(this.sprite);
    }
    if(!this.sprite){
      return;
    }
    this.sprite.position.x = this.entity.pos.x-this.sprite.width/2;
    this.sprite.position.y = -this.entity.pos.y-74;
    this.sprite.scale.x = this.entity.box.width/this.data.width;
    this.sprite.scale.y = this.entity.box.width/this.data.width;
    if(this.mirrorBasedOnVel){
      let mirror = (this.entity.vel.x > 0) ? -1 : 1;
      let inverseMirror = (this.entity.vel.x < 0) ? -1 : 1;
      this.sprite.scale.x *= (mirror !== inverseMirror) ? mirror : this.lastDirection;
      this.lastDirection = (mirror !== inverseMirror) ? mirror : this.lastDirection;
      this.sprite.position.x += (this.sprite.scale.x < 0) ? this.sprite.width : 0;
    }
    this.delayLeft --;
    if(this.animation !== this.entity.state){
      if(this.animations[this.entity.state]){
        this.delayLeft = 0;
        //UPDATE VALUE 60FPS right now
        this.delay = this.animations[this.entity.state].frameDuration/16;
        this.animation = this.entity.state;
      }
    }
    if(this.delayLeft < 0){
      this.index ++;
      if(this.index >= this.animations[this.animation].length){
        this.index = 0;
      }
      this.sprite.texture = this.animations[this.animation][this.index];
      this.delayLeft = this.delay;
    }
  }
}

export default AnimatedEntityRenderer;
<commit_msg>Added jsDocs to AnimatedEntityRenderer.js<commit_after>class AnimatedEntityRenderer{
  /**
  * Creates a AnimatedEntityRederer object that animates the player character
  * @param {Entity} entity the character that is to be animated
  * @param {String} url the location of the images of the character
  * @param {boolean} mirrorBasedOnVel the direction character faces based on their velocity
  */
  constructor(entity, url, mirrorBasedOnVel = false){
    this.entity = entity;
    this.lastDirection = 1;
    this.httpRequest = new XMLHttpRequest();
    this.mirrorBasedOnVel = mirrorBasedOnVel;

    let self = this;
    this.httpRequest.onreadystatechange = function(){self.finish()};
    this.httpRequest.open('GET', url);
    this.httpRequest.setRequestHeader('Content-Type', 'text/json');
    this.httpRequest.send();
    this.animations = {};
  }
  /**
  * puts images of the sprite in an array of images to be animated
  */
  finish(){
    if (this.httpRequest.readyState === XMLHttpRequest.DONE) {
      if (this.httpRequest.status === 200) {
        this.data = JSON.parse(this.httpRequest.responseText);
        for(let animation of this.data.animations){
          let images = [];
          images.frameDuration = animation.frameDuration;
          this.animations[animation.name] = images;
          for(let i = animation.range[0]; i<= animation.range[1]; i++){
            let url = this.data.base + animation.path + i + animation.extention;
            images.push(PIXI.Texture.fromImage(url, false, PIXI.SCALE_MODES.NEAREST));
          }
        }
        this.sprite = new PIXI.Sprite(this.animations[this.data.default][0]);
        this.index = 0;
        this.animation = this.data.default;
        //UPDATE VALUE 60FPS right now
        this.delay = this.animations[this.data.default].frameDuration/16;
        this.delayLeft = this.delay;
        this.needToAdd = true;
      }
    }
  }
/**
* updates the stage and the location of the character
* @param {Container} stage the level where the game is being played
*/
  update(stage){
    if(this.needToAdd){
      stage.addChild(this.sprite);
    }
    if(!this.sprite){
      return;
    }
    this.sprite.position.x = this.entity.pos.x-this.sprite.width/2;
    this.sprite.position.y = -this.entity.pos.y-74;
    this.sprite.scale.x = this.entity.box.width/this.data.width;
    this.sprite.scale.y = this.entity.box.width/this.data.width;
    if(this.mirrorBasedOnVel){
      let mirror = (this.entity.vel.x > 0) ? -1 : 1;
      let inverseMirror = (this.entity.vel.x < 0) ? -1 : 1;
      this.sprite.scale.x *= (mirror !== inverseMirror) ? mirror : this.lastDirection;
      this.lastDirection = (mirror !== inverseMirror) ? mirror : this.lastDirection;
      this.sprite.position.x += (this.sprite.scale.x < 0) ? this.sprite.width : 0;
    }
    this.delayLeft --;
    if(this.animation !== this.entity.state){
      if(this.animations[this.entity.state]){
        this.delayLeft = 0;
        //UPDATE VALUE 60FPS right now
        this.delay = this.animations[this.entity.state].frameDuration/16;
        this.animation = this.entity.state;
      }
    }
    if(this.delayLeft < 0){
      this.index ++;
      if(this.index >= this.animations[this.animation].length){
        this.index = 0;
      }
      this.sprite.texture = this.animations[this.animation][this.index];
      this.delayLeft = this.delay;
    }
  }
}

export default AnimatedEntityRenderer;
<|endoftext|>


<commit_before>'use strict'

const assert = require('assert')

const { parse } = require('./parser')
const Bitmask = require('./bitmask')

const P = new WeakMap()
const U = new WeakMap()
const A = new WeakMap()
const X = new WeakMap()

class ExtDate extends Date {
  static parse(input) {
    return parse(input, { types: ['Date'] })
  }

  constructor(...args) { // eslint-disable-line complexity
    let precision = 0
    let uncertain, approximate, unspecified

    switch (args.length) {
    case 0:
      break

    case 1:
      switch (typeof args[0]) {
      case 'number':
        break

      case 'string':
        args = [ExtDate.parse(args[0])]
        // eslint-disable-line no-fallthrough

      case 'object':
        if (Array.isArray(args[0]))
          args[0] = { type: 'Date', values: args[0] }

        {
          let obj = args[0]

          if (obj.type) assert.equal('Date', obj.type)

          assert(obj.values)
          assert(obj.values.length)

          precision = obj.values.length
          args = obj.values.slice()

          // ECMA Date constructor needs at least two date parts!
          if (args.length < 2) args.push(0)

          if (obj.offset) {
            if (args.length < 3) args.push(1)
            while (args.length < 5) args.push(0)

            // ECMA Date constructor handles overflows so we
            // simply add the offset!
            args[4] = args[4] + obj.offset
          }

          args = [Date.UTC(...args)]

          // ECMA Date constructor converts 0-99 to 1900-1999!
          if (obj.values[0] >= 0 && obj.values[0] < 100)
            args[0] = adj(new Date(args[0]));

          ({ uncertain, approximate, unspecified } = obj)
        }
        break

      default:
        throw new RangeError('Invalid time value')
      }

      break

    default:
      precision = args.length
    }

    super(...args)

    this.precision = precision

    this.uncertain = uncertain
    this.approximate = approximate
    this.unspecified = unspecified
  }

  set precision(value) {
    P[this] = Number(value) % 4
  }

  get precision() {
    return P[this]
  }

  set uncertain(value) {
    U[this] = new Bitmask(value)
  }

  get uncertain() {
    return U[this]
  }

  set approximate(value) {
    A[this] = new Bitmask(value)
  }

  get approximate() {
    return A[this]
  }

  set unspecified(value) {
    X[this] = new Bitmask(value)
  }

  get unspecified() {
    return X[this]
  }

  get type() {
    return 'Date'
  }

  get edtf() {
    return this.toEDTF()
  }

  get min() {
    return this.getTime()
  }

  get year() {
    return this.getUTCFullYear()
  }

  get month() {
    return this.getUTCMonth()
  }

  get date() {
    return this.getUTCDate()
  }

  get hours() {
    return this.getUTCHours()
  }

  get minutes() {
    return this.getUTCMinutes()
  }

  get seconds() {
    return this.getUTCSeconds()
  }

  get values() {
    switch (this.precision) {
    case 1:
      return [this.year]
    case 2:
      return [this.year, this.month]
    case 3:
      return [this.year, this.month, this.date]
    default:
      return [
        this.year, this.month, this.date, this.hours, this.minutes, this.seconds
      ]
    }
  }

  toEDTF() {
    if (!this.precision) return this.toISOString()

    return this.values.map(pad).join('-')
  }
}

ExtDate.prototype.toJSON = ExtDate.prototype.toEDTF

function adj(date, by = 1900) {
  date.setUTCFullYear(date.getUTCFullYear() - by)
  return date.getTime()
}

function pad(number, idx = 0) { // idx 0 = year, 1 = month, ...
  if (!idx) {
    let abs = Math.abs(number)
    let sign = (abs === number) ? '' : '-'

    if (abs < 10)   return `${sign}000${abs}`
    if (abs < 100)  return `${sign}00${abs}`
    if (abs < 1000) return `${sign}0${abs}`

    return `${number}`
  }

  if (idx === 1) number = number + 1

  return (number < 10) ? `0${number}` : `${number}`
}

module.exports = ExtDate
<commit_msg>Override Date.@@toPrimitive<commit_after>'use strict'

const assert = require('assert')

const { parse } = require('./parser')
const Bitmask = require('./bitmask')

const P = new WeakMap()
const U = new WeakMap()
const A = new WeakMap()
const X = new WeakMap()

class ExtDate extends Date {
  static parse(input) {
    return parse(input, { types: ['Date'] })
  }

  constructor(...args) { // eslint-disable-line complexity
    let precision = 0
    let uncertain, approximate, unspecified

    switch (args.length) {
    case 0:
      break

    case 1:
      switch (typeof args[0]) {
      case 'number':
        break

      case 'string':
        args = [ExtDate.parse(args[0])]
        // eslint-disable-line no-fallthrough

      case 'object':
        if (Array.isArray(args[0]))
          args[0] = { type: 'Date', values: args[0] }

        {
          let obj = args[0]

          if (obj.type) assert.equal('Date', obj.type)

          assert(obj.values)
          assert(obj.values.length)

          precision = obj.values.length
          args = obj.values.slice()

          // ECMA Date constructor needs at least two date parts!
          if (args.length < 2) args.push(0)

          if (obj.offset) {
            if (args.length < 3) args.push(1)
            while (args.length < 5) args.push(0)

            // ECMA Date constructor handles overflows so we
            // simply add the offset!
            args[4] = args[4] + obj.offset
          }

          args = [Date.UTC(...args)]

          // ECMA Date constructor converts 0-99 to 1900-1999!
          if (obj.values[0] >= 0 && obj.values[0] < 100)
            args[0] = adj(new Date(args[0]));

          ({ uncertain, approximate, unspecified } = obj)
        }
        break

      default:
        throw new RangeError('Invalid time value')
      }

      break

    default:
      precision = args.length
    }

    super(...args)

    this.precision = precision

    this.uncertain = uncertain
    this.approximate = approximate
    this.unspecified = unspecified
  }

  set precision(value) {
    P[this] = Number(value) % 4
  }

  get precision() {
    return P[this]
  }

  set uncertain(value) {
    U[this] = new Bitmask(value)
  }

  get uncertain() {
    return U[this]
  }

  set approximate(value) {
    A[this] = new Bitmask(value)
  }

  get approximate() {
    return A[this]
  }

  set unspecified(value) {
    X[this] = new Bitmask(value)
  }

  get unspecified() {
    return X[this]
  }

  get type() {
    return 'Date'
  }

  get edtf() {
    return this.toEDTF()
  }

  get min() {
    return this.getTime()
  }

  get year() {
    return this.getUTCFullYear()
  }

  get month() {
    return this.getUTCMonth()
  }

  get date() {
    return this.getUTCDate()
  }

  get hours() {
    return this.getUTCHours()
  }

  get minutes() {
    return this.getUTCMinutes()
  }

  get seconds() {
    return this.getUTCSeconds()
  }

  get values() {
    switch (this.precision) {
    case 1:
      return [this.year]
    case 2:
      return [this.year, this.month]
    case 3:
      return [this.year, this.month, this.date]
    default:
      return [
        this.year, this.month, this.date, this.hours, this.minutes, this.seconds
      ]
    }
  }

  toEDTF() {
    if (!this.precision) return this.toISOString()

    return this.values.map(pad).join('-')
  }

  [Symbol.toPrimitive](hint) {
    return (hint === 'number') ? this.valueOf() : this.toISOString()
  }
}

ExtDate.prototype.toJSON = ExtDate.prototype.toEDTF

function adj(date, by = 1900) {
  date.setUTCFullYear(date.getUTCFullYear() - by)
  return date.getTime()
}

function pad(number, idx = 0) { // idx 0 = year, 1 = month, ...
  if (!idx) {
    let abs = Math.abs(number)
    let sign = (abs === number) ? '' : '-'

    if (abs < 10)   return `${sign}000${abs}`
    if (abs < 100)  return `${sign}00${abs}`
    if (abs < 1000) return `${sign}0${abs}`

    return `${number}`
  }

  if (idx === 1) number = number + 1

  return (number < 10) ? `0${number}` : `${number}`
}

module.exports = ExtDate
<|endoftext|>


<commit_before>const { expect } = require('chai');

module.exports = function ({ cv, utils }) {

  const {
    assertError,
    assertPropsWithValue,
    assertMetaData,
    funcShouldRequireArgs,
    readTestImage,
    generateAPITests
  } = utils;

  describe('inpaint', () => {

    it('should have constants', () => {
      expect(isNaN(cv.INPAINT_TELEA)).to.be.equal(false);
      expect(isNaN(cv.INPAINT_NS)).to.be.equal(false);
    });

    it('should perform inpainting', () => {

      // construct a black image with a white dot in the middle
      const imgData = new Array(7*7).fill(0);
      imgData[7 * 3 + 3] = 255;
      const image = new cv.Mat(Buffer.from(imgData), 7,7,cv.CV_8U);
      // construct the mask from the same image (since we want to inpaint the white dot)
      const mask = image.copy();

      // perform inpainting
      const inpainted = cv.inpaint(image, mask, 3, cv.INPAINT_TELEA);

      // now the result should be all black
      const sum = inpainted.sum();

      // so sum should be 0
      expect(sum).to.be.equal(0);
    });

    it('should perform inpainting async', (done) => {

      // construct a black image with a white dot in the middle
      const imgData = new Array(7*7).fill(0);
      imgData[7 * 3 + 3] = 255;
      const image = new cv.Mat(Buffer.from(imgData), 7,7,cv.CV_8U);
      // construct the mask from the same image (since we want to inpaint the white dot)
      const mask = image.copy();

      // perform inpainting
      cv.inpaintAsync(image, mask, 3, cv.INPAINT_TELEA)
        .then(inpainted => {
          // now the result should be all black
          const sum = inpainted.sum();

          // so sum should be 0
          expect(sum).to.be.equal(0);

          done();
        }).catch(done);
    });
  });

  describe('seamlessClone', () => {

    it('should have constants', () => {
      expect(isNaN(cv.NORMAL_CLONE)).to.be.equal(false);
      expect(isNaN(cv.MIXED_CLONE)).to.be.equal(false);
      expect(isNaN(cv.MONOCHROME_TRANSFER)).to.be.equal(false);
    });

    const src = new cv.Mat(5, 5, cv.CV_8UC3, [128, 128, 128]);
    const dest = new cv.Mat(10, 10, cv.CV_8UC3, [32, 32, 32]);
    const mask = new cv.Mat(10, 10, cv.CV8U, 255);
    const center = new cv.Point(5, 5);
    const cloneType = cv.NORMAL_CLONE;

    const expectOutput = (res) => {
      assertMetaData(res)(dest.rows, dest.cols, cv.CV_8UC3);
    };

    generateAPITests({
      getDut: () => cv,
      methodName: 'seamlessClone',
      getRequiredArgs: () => ([
        src,
        dest,
        mask,
        center,
        cloneType
      ]),
      expectOutput
    });
  });

};
<commit_msg>Using cv.Point() causes segfault on OpenCV < 3.4, use cv.Point2() instead<commit_after>const { expect } = require('chai');

module.exports = function ({ cv, utils }) {

  const {
    assertError,
    assertPropsWithValue,
    assertMetaData,
    funcShouldRequireArgs,
    readTestImage,
    generateAPITests
  } = utils;

  describe('inpaint', () => {

    it('should have constants', () => {
      expect(isNaN(cv.INPAINT_TELEA)).to.be.equal(false);
      expect(isNaN(cv.INPAINT_NS)).to.be.equal(false);
    });

    it('should perform inpainting', () => {

      // construct a black image with a white dot in the middle
      const imgData = new Array(7*7).fill(0);
      imgData[7 * 3 + 3] = 255;
      const image = new cv.Mat(Buffer.from(imgData), 7,7,cv.CV_8U);
      // construct the mask from the same image (since we want to inpaint the white dot)
      const mask = image.copy();

      // perform inpainting
      const inpainted = cv.inpaint(image, mask, 3, cv.INPAINT_TELEA);

      // now the result should be all black
      const sum = inpainted.sum();

      // so sum should be 0
      expect(sum).to.be.equal(0);
    });

    it('should perform inpainting async', (done) => {

      // construct a black image with a white dot in the middle
      const imgData = new Array(7*7).fill(0);
      imgData[7 * 3 + 3] = 255;
      const image = new cv.Mat(Buffer.from(imgData), 7,7,cv.CV_8U);
      // construct the mask from the same image (since we want to inpaint the white dot)
      const mask = image.copy();

      // perform inpainting
      cv.inpaintAsync(image, mask, 3, cv.INPAINT_TELEA)
        .then(inpainted => {
          // now the result should be all black
          const sum = inpainted.sum();

          // so sum should be 0
          expect(sum).to.be.equal(0);

          done();
        }).catch(done);
    });
  });

  describe('seamlessClone', () => {

    it('should have constants', () => {
      expect(isNaN(cv.NORMAL_CLONE)).to.be.equal(false);
      expect(isNaN(cv.MIXED_CLONE)).to.be.equal(false);
      expect(isNaN(cv.MONOCHROME_TRANSFER)).to.be.equal(false);
    });

    const src = new cv.Mat(5, 5, cv.CV_8UC3, [128, 128, 128]);
    const dest = new cv.Mat(10, 10, cv.CV_8UC3, [32, 32, 32]);
    const mask = new cv.Mat(5, 5, cv.CV_8UC3, [255, 255, 255]);
    const center = new cv.Point2(5, 5);
    const cloneType = cv.NORMAL_CLONE;

    const expectOutput = (res) => {
      assertMetaData(res)(dest.rows, dest.cols, cv.CV_8UC3);
    };

    generateAPITests({
      getDut: () => cv,
      methodName: 'seamlessClone',
      getRequiredArgs: () => ([
        src,
        dest,
        mask,
        center,
        cloneType
      ]),
      expectOutput
    });
  });

};
<|endoftext|>


<commit_before>/**
 * This file provided by Facebook is for non-commercial testing and evaluation purposes only.
 * Facebook reserves all rights not expressly granted.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

var Comment = React.createClass({
  render: function() {
    var rawMarkup = marked(this.props.children.toString(), {sanitize: true});
    return (

          {this.props.author}

    );
  }
});

var CommentBox = React.createClass({
  loadCommentsFromServer: function() {
    $.ajax({
      url: this.props.url,
      dataType: 'json',
      cache: false,
      success: function(data) {
        this.setState({data: data});
      }.bind(this),
      error: function(xhr, status, err) {
        console.error(this.props.url, status, err.toString());
      }.bind(this)
    });
  },
  handleCommentSubmit: function(comment) {
    var comments = this.state.data;
    comments.push(comment);
    this.setState({data: comments}, function() {
      // `setState` accepts a callback. To avoid (improbable) race condition,
      // `we'll send the ajax request right after we optimistically set the new
      // `state.
      $.ajax({
        url: this.props.url,
        dataType: 'json',
        type: 'POST',
        data: comment,
        success: function(data) {
          this.setState({data: data});
        }.bind(this),
        error: function(xhr, status, err) {
          console.error(this.props.url, status, err.toString());
        }.bind(this)
      });
    });
  },
  getInitialState: function() {
    return {data: []};
  },
  componentDidMount: function() {
    this.loadCommentsFromServer();
    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
  },
  render: function() {
    return (

Comments

        <CommentList data={this.state.data} />
        <CommentForm onCommentSubmit={this.handleCommentSubmit} />

    );
  }
});

var CommentList = React.createClass({
  render: function() {
    var commentNodes = this.props.data.map(function(comment, index) {
      return (
        // `key` is a React-specific concept and is not mandatory for the
        // purpose of this tutorial. if you're curious, see more here:
        // http://facebook.github.io/react/docs/multiple-components.html#dynamic-children
        <Comment author={comment.author} key={index}>
          {comment.text}
        </Comment>
      );
    });
    return (

        {commentNodes}

    );
  }
});

var CommentForm = React.createClass({
  handleSubmit: function(e) {
    e.preventDefault();
    var author = React.findDOMNode(this.refs.author).value.trim();
    var text = React.findDOMNode(this.refs.text).value.trim();
    if (!text || !author) {
      return;
    }
    this.props.onCommentSubmit({author: author, text: text});
    React.findDOMNode(this.refs.author).value = '';
    React.findDOMNode(this.refs.text).value = '';
  },
  render: function() {
    return (
      <form className="commentForm" onSubmit={this.handleSubmit}>
        <input type="text" placeholder="Your name" ref="author" />
        <input type="text" placeholder="Say something..." ref="text" />
        <input type="submit" value="Post" />
      </form>
    );
  }
});

React.render(
  <CommentBox url="comments.json" pollInterval={2000} />,
  document.getElementById('content')
);
<commit_msg>Fix typo<commit_after>/**
 * This file provided by Facebook is for non-commercial testing and evaluation purposes only.
 * Facebook reserves all rights not expressly granted.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

var Comment = React.createClass({
  render: function() {
    var rawMarkup = marked(this.props.children.toString(), {sanitize: true});
    return (

          {this.props.author}

    );
  }
});

var CommentBox = React.createClass({
  loadCommentsFromServer: function() {
    $.ajax({
      url: this.props.url,
      dataType: 'json',
      cache: false,
      success: function(data) {
        this.setState({data: data});
      }.bind(this),
      error: function(xhr, status, err) {
        console.error(this.props.url, status, err.toString());
      }.bind(this)
    });
  },
  handleCommentSubmit: function(comment) {
    var comments = this.state.data;
    comments.push(comment);
    this.setState({data: comments}, function() {
      // `setState` accepts a callback. To avoid (improbable) race condition,
      // we'll send the ajax request right after we optimistically set the new
      // state.
      $.ajax({
        url: this.props.url,
        dataType: 'json',
        type: 'POST',
        data: comment,
        success: function(data) {
          this.setState({data: data});
        }.bind(this),
        error: function(xhr, status, err) {
          console.error(this.props.url, status, err.toString());
        }.bind(this)
      });
    });
  },
  getInitialState: function() {
    return {data: []};
  },
  componentDidMount: function() {
    this.loadCommentsFromServer();
    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
  },
  render: function() {
    return (

Comments

        <CommentList data={this.state.data} />
        <CommentForm onCommentSubmit={this.handleCommentSubmit} />

    );
  }
});

var CommentList = React.createClass({
  render: function() {
    var commentNodes = this.props.data.map(function(comment, index) {
      return (
        // `key` is a React-specific concept and is not mandatory for the
        // purpose of this tutorial. if you're curious, see more here:
        // http://facebook.github.io/react/docs/multiple-components.html#dynamic-children
        <Comment author={comment.author} key={index}>
          {comment.text}
        </Comment>
      );
    });
    return (

        {commentNodes}

    );
  }
});

var CommentForm = React.createClass({
  handleSubmit: function(e) {
    e.preventDefault();
    var author = React.findDOMNode(this.refs.author).value.trim();
    var text = React.findDOMNode(this.refs.text).value.trim();
    if (!text || !author) {
      return;
    }
    this.props.onCommentSubmit({author: author, text: text});
    React.findDOMNode(this.refs.author).value = '';
    React.findDOMNode(this.refs.text).value = '';
  },
  render: function() {
    return (
      <form className="commentForm" onSubmit={this.handleSubmit}>
        <input type="text" placeholder="Your name" ref="author" />
        <input type="text" placeholder="Say something..." ref="text" />
        <input type="submit" value="Post" />
      </form>
    );
  }
});

React.render(
  <CommentBox url="comments.json" pollInterval={2000} />,
  document.getElementById('content')
);
<|endoftext|>


<commit_before>import * as THREE from 'three';
import { arrayToBox, getLongestEdgeIndex } from './BoundsUtilities.js';
import { CENTER, AVERAGE, SAH } from './Constants.js';

const xyzFields = [ 'x', 'y', 'z' ];

function getTriangleCount( geo ) {

	return geo.index ? ( geo.index.count / 3 ) : ( geo.attributes.position.count / 3 );

}

// TODO: This could probably be optimizied to not dig so deeply into an object
// and reust some of the fetch values in some cases
function getBufferGeometryVertexElem( geo, tri, vert, elem ) {

	return geo.attributes.position.array[ ( geo.index ? geo.index.array[ 3 * tri + vert ] : ( 3 * tri + vert ) ) * 3 + elem ];

}

// precomputes data about each triangle required for quickly calculating tree splits:
//
// - bounds: an array of size tris.length * 6 where triangle i maps to a
//   [x_min, x_max, y_min, y_max, z_min, z_max] tuple starting at index i * 6,
//   representing the minimum and maximum extent in each dimension of triangle i
//
// - centroids: an array of size tris.length * 3 where triangle i maps to an [x, y, z] triplet
//   starting at index i * 3, representing the centroid of triangle i
//
function computeTriangleData( geo ) {

	const triCount = getTriangleCount( geo );
	const bounds = new Float32Array( triCount * 6 );
	const centroids = new Float32Array( triCount * 3 );

	for ( let tri = 0; tri < triCount; tri ++ ) {

		for ( let el = 0; el < 3; el ++ ) {

			const a = getBufferGeometryVertexElem( geo, tri, 0, el );
			const b = getBufferGeometryVertexElem( geo, tri, 1, el );
			const c = getBufferGeometryVertexElem( geo, tri, 2, el );
			bounds[ tri * 6 + el * 2 ] = Math.min( a, b, c );
			bounds[ tri * 6 + el * 2 + 1 ] = Math.max( a, b, c );
			centroids[ tri * 3 + el ] = ( a + b + c ) / 3;

		}

	}

	return { bounds, centroids };

}

const boxtemp = new THREE.Box3();

export default class BVHConstructionContext {

	constructor( geo, options ) {

		this.geo = geo;
		this.options = options;

		const data = computeTriangleData( geo );
		this.centroids = data.centroids;
		this.bounds = data.bounds;

		// a list of every available triangle index
		const triCount = getTriangleCount( geo );
		this.tris = new Array( triCount );
		for ( let i = 0; i < triCount; i ++ ) this.tris[ i ] = i;

		// SAH Initialization
		this.sahplanes = null;
		if ( options.strategy === SAH ) {

			this.sahplanes = [ new Array( triCount ), new Array( triCount ), new Array( triCount ) ];
			for ( let tri = 0; tri < triCount; tri ++ ) {

				for ( let el = 0; el < 3; el ++ ) {

					this.sahplanes[ el ][ tri ] = { p: this.centroids[ tri * 3 + el ], tri };

				}

			}

		}

	}

	// returns the average coordinate on the specified axis of the all the provided triangles
	getAverage( offset, count, axis ) {

		let avg = 0;
		const centroids = this.centroids;
		const tris = this.tris;

		for ( let i = offset, end = offset + count; i < end; i ++ ) {

			avg += centroids[ tris[ i ] * 3 + axis ];

		}

		return avg / ( count * 3 );

	}

	// shrinks the provided bounds on any dimensions to fit the provided triangles
	shrinkBoundsTo( offset, count, parent, target ) {

		let minx = Infinity;
		let miny = Infinity;
		let minz = Infinity;
		let maxx = - Infinity;
		let maxy = - Infinity;
		let maxz = - Infinity;
		const bounds = this.bounds;
		const tris = this.tris;

		for ( let i = offset, end = offset + count; i < end; i ++ ) {

			const tri = tris[ i ];

			minx = Math.min( minx, bounds[ tri * 6 + 0 ] );
			maxx = Math.max( maxx, bounds[ tri * 6 + 1 ] );
			miny = Math.min( miny, bounds[ tri * 6 + 2 ] );
			maxy = Math.max( maxy, bounds[ tri * 6 + 3 ] );
			minz = Math.min( minz, bounds[ tri * 6 + 4 ] );
			maxz = Math.max( maxz, bounds[ tri * 6 + 5 ] );

		}

		target[ 0 ] = Math.max( minx, parent[ 0 ] );
		target[ 1 ] = Math.max( miny, parent[ 1 ] );
		target[ 2 ] = Math.max( minz, parent[ 2 ] );

		target[ 3 ] = Math.min( maxx, parent[ 3 ] );
		target[ 4 ] = Math.min( maxy, parent[ 4 ] );
		target[ 5 ] = Math.min( maxz, parent[ 5 ] );

		return target;

	}

	// writes entries into a new geometry index (target) with the vertices of triangles from
	// offset through count
	writeReorderedIndices( offset, count, target ) {

		const tris = this.tris;
		const oldIndices = this.geo.index ? this.geo.index.array : null;

		for ( let i = offset, end = offset + count; i < end; i ++ ) {

			const oldTri = tris[ i ];
			target[ 3 * i + 0 ] = oldIndices ? oldIndices[ 3 * oldTri + 0 ] : 3 * oldTri + 0;
			target[ 3 * i + 1 ] = oldIndices ? oldIndices[ 3 * oldTri + 1 ] : 3 * oldTri + 1;
			target[ 3 * i + 2 ] = oldIndices ? oldIndices[ 3 * oldTri + 2 ] : 3 * oldTri + 1;

		}

	}

	// reorders `tris` such that for `count` elements after `offset`, elements on the left side of the split
	// will be on the left and elements on the right side of the split will be on the right. returns the index
	// of the first element on the right side, or offset + count if there are no elements on the right side.
	partition( offset, count, split ) {

		let left = offset;
		let right = offset + count - 1;
		const pos = split.pos;
		const axis = split.axis;
		const tris = this.tris;
		const centroids = this.centroids;

		// hoare partitioning, see e.g. https://en.wikipedia.org/wiki/Quicksort#Hoare_partition_scheme
		while ( left <= right ) {

			while ( centroids[ tris[ left ] * 3 + axis ] < pos ) {

				left ++;

			}

			while ( centroids[ tris[ right ] * 3 + axis ] >= pos ) {

				right --;

			}

			if ( left <= right ) {

				let tmp = tris[ left ];
				tris[ left ] = tris[ right ];
				tris[ right ] = tmp;
				left ++;
				right --;

			}

		}

		return left;

	}

	getOptimalSplit( bounds, offset, count, strategy ) {

		let axis = - 1;
		let pos = 0;

		// Center
		if ( strategy === CENTER ) {

			axis = getLongestEdgeIndex( bounds );
			if ( axis !== - 1 ) {

				pos = ( bounds[ axis + 3 ] + bounds[ axis ] ) / 2;

			}

		} else if ( strategy === AVERAGE ) {

			axis = getLongestEdgeIndex( bounds );
			if ( axis !== - 1 ) {

				pos = this.getAverage( offset, count, axis );

			}

		} else if ( strategy === SAH ) {

			// Surface Area Heuristic
			// In order to make this code more terse, the x, y, and z
			// variables of various structures have been stuffed into
			// 0, 1, and 2 array indices so they can be easily computed
			// and accessed within array iteration

			// Cost values defineed for operations. We're using bounds for traversal, so
			// the cost of traversing one more layer is more than intersecting a triangle.
			const TRAVERSAL_COST = 3;
			const INTERSECTION_COST = 1;
			const tris = this.tris;
			const bb = arrayToBox( bounds, boxtemp );

			// Define the width, height, and depth of the bounds as a box
			const dim = [
				bb.max.x - bb.min.x,
				bb.max.y - bb.min.y,
				bb.max.z - bb.min.z
			];
			const sa = 2 * ( dim[ 0 ] * dim[ 1 ] + dim[ 0 ] * dim[ 2 ] + dim[ 1 ] * dim[ 2 ] );

			// Get the precalculated planes based for the triangles we're
			// testing here
			const filteredLists = [[], [], []];
			for ( let i = offset, end = offset + count; i < end; i ++ ) {

				let t = tris[ i ];
				for ( let v = 0; v < 3; v ++ ) {

					filteredLists[ v ].push( this.sahplanes[ v ][ t ] );

				}

			}
			filteredLists.forEach( planes => planes.sort( ( a, b ) => a.p - b.p ) );

			// this bounds surface area, left bound SA, left triangles, right bound SA, right triangles
			const getCost = ( sa, sal, nl, sar, nr ) =>
				  TRAVERSAL_COST + INTERSECTION_COST * ( ( sal / sa ) * nl + ( sar / sa ) * nr );

			// the cost of _not_ splitting into smaller bounds
			const noSplitCost = INTERSECTION_COST * count;

			axis = - 1;
			let bestCost = noSplitCost;
			for ( let i = 0; i < 3; i ++ ) {

				// o1 and o2 represent the _other_ two axes in the
				// the space. So if we're checking the x (0) dimension,
				// then o1 and o2 would be y and z (1 and 2)
				const o1 = ( i + 1 ) % 3;
				const o2 = ( i + 2 ) % 3;

				const bmin = bb.min[ xyzFields[ i ] ];
				const bmax = bb.max[ xyzFields[ i ] ];
				const planes = filteredLists[ i ];

				// The number of left and right triangles on either side
				// given the current split
				let nl = 0;
				let nr = count;
				for ( let p = 0; p < planes.length; p ++ ) {

					const pinfo = planes[ p ];

					// As the plane moves, we have to increment or decrement the
					// number of triangles on either side of the plane
					nl ++;
					nr --;

					// the distance from the plane to the edge of the broader bounds
					const ldim = pinfo.p - bmin;
					const rdim = bmax - pinfo.p;

					// same for the other two dimensions
					let ldimo1 = dim[ o1 ], rdimo1 = dim[ o1 ];
					let ldimo2 = dim[ o2 ], rdimo2 = dim[ o2 ];

					/*
					// compute the other bounding planes for the box
					// if only the current triangles are considered to
					// be in the box
					// This is really slow and probably not really worth it
					const o1planes = this.sahplanes[o1];
					const o2planes = this.sahplanes[o2];
					let lmin = Infinity, lmax = -Infinity;
					let rmin = Infinity, rmax = -Infinity;
					planes.forEach((p, i) => {
					const tri2 = p.tri * 2;
					const inf1 = o1planes[tri2 + 0];
					const inf2 = o1planes[tri2 + 1];
					if (i <= nl) {
					lmin = Math.min(inf1.p, inf2.p, lmin);
					lmax = Math.max(inf1.p, inf2.p, lmax);
					}
					if (i >= nr) {
					rmin = Math.min(inf1.p, inf2.p, rmin);
					rmax = Math.max(inf1.p, inf2.p, rmax);
					}
					})
					ldimo1 = Math.min(lmax - lmin, ldimo1);
					rdimo1 = Math.min(rmax - rmin, rdimo1);

					planes.forEach((p, i) => {
					const tri2 = p.tri * 2;
					const inf1 = o2planes[tri2 + 0];
					const inf2 = o2planes[tri2 + 1];
					if (i <= nl) {
					lmin = Math.min(inf1.p, inf2.p, lmin);
					lmax = Math.max(inf1.p, inf2.p, lmax);
					}
					if (i >= nr) {
					rmin = Math.min(inf1.p, inf2.p, rmin);
					rmax = Math.max(inf1.p, inf2.p, rmax);
					}
					})
					ldimo2 = Math.min(lmax - lmin, ldimo2);
					rdimo2 = Math.min(rmax - rmin, rdimo2);
					*/

					// surface areas and cost
					const sal = 2 * ( ldimo1 * ldimo2 + ldimo1 * ldim + ldimo2 * ldim );
					const sar = 2 * ( rdimo1 * rdimo2 + rdimo1 * rdim + rdimo2 * rdim );
					const cost = getCost( sa, sal, nl, sar, nr );

					if ( cost < bestCost ) {

						axis = i;
						pos = pinfo.p;
						bestCost = cost;

					}

				}

			}

		}

		return { axis, pos };

	}

}
<commit_msg>Check bounds while partitioning<commit_after>import * as THREE from 'three';
import { arrayToBox, getLongestEdgeIndex } from './BoundsUtilities.js';
import { CENTER, AVERAGE, SAH } from './Constants.js';

const xyzFields = [ 'x', 'y', 'z' ];

function getTriangleCount( geo ) {

	return geo.index ? ( geo.index.count / 3 ) : ( geo.attributes.position.count / 3 );

}

// TODO: This could probably be optimizied to not dig so deeply into an object
// and reust some of the fetch values in some cases
function getBufferGeometryVertexElem( geo, tri, vert, elem ) {

	return geo.attributes.position.array[ ( geo.index ? geo.index.array[ 3 * tri + vert ] : ( 3 * tri + vert ) ) * 3 + elem ];

}

// precomputes data about each triangle required for quickly calculating tree splits:
//
// - bounds: an array of size tris.length * 6 where triangle i maps to a
//   [x_min, x_max, y_min, y_max, z_min, z_max] tuple starting at index i * 6,
//   representing the minimum and maximum extent in each dimension of triangle i
//
// - centroids: an array of size tris.length * 3 where triangle i maps to an [x, y, z] triplet
//   starting at index i * 3, representing the centroid of triangle i
//
function computeTriangleData( geo ) {

	const triCount = getTriangleCount( geo );
	const bounds = new Float32Array( triCount * 6 );
	const centroids = new Float32Array( triCount * 3 );

	for ( let tri = 0; tri < triCount; tri ++ ) {

		for ( let el = 0; el < 3; el ++ ) {

			const a = getBufferGeometryVertexElem( geo, tri, 0, el );
			const b = getBufferGeometryVertexElem( geo, tri, 1, el );
			const c = getBufferGeometryVertexElem( geo, tri, 2, el );
			bounds[ tri * 6 + el * 2 ] = Math.min( a, b, c );
			bounds[ tri * 6 + el * 2 + 1 ] = Math.max( a, b, c );
			centroids[ tri * 3 + el ] = ( a + b + c ) / 3;

		}

	}

	return { bounds, centroids };

}

const boxtemp = new THREE.Box3();

export default class BVHConstructionContext {

	constructor( geo, options ) {

		this.geo = geo;
		this.options = options;

		const data = computeTriangleData( geo );
		this.centroids = data.centroids;
		this.bounds = data.bounds;

		// a list of every available triangle index
		const triCount = getTriangleCount( geo );
		this.tris = new Array( triCount );
		for ( let i = 0; i < triCount; i ++ ) this.tris[ i ] = i;

		// SAH Initialization
		this.sahplanes = null;
		if ( options.strategy === SAH ) {

			this.sahplanes = [ new Array( triCount ), new Array( triCount ), new Array( triCount ) ];
			for ( let tri = 0; tri < triCount; tri ++ ) {

				for ( let el = 0; el < 3; el ++ ) {

					this.sahplanes[ el ][ tri ] = { p: this.centroids[ tri * 3 + el ], tri };

				}

			}

		}

	}

	// returns the average coordinate on the specified axis of the all the provided triangles
	getAverage( offset, count, axis ) {

		let avg = 0;
		const centroids = this.centroids;
		const tris = this.tris;

		for ( let i = offset, end = offset + count; i < end; i ++ ) {

			avg += centroids[ tris[ i ] * 3 + axis ];

		}

		return avg / ( count * 3 );

	}

	// shrinks the provided bounds on any dimensions to fit the provided triangles
	shrinkBoundsTo( offset, count, parent, target ) {

		let minx = Infinity;
		let miny = Infinity;
		let minz = Infinity;
		let maxx = - Infinity;
		let maxy = - Infinity;
		let maxz = - Infinity;
		const bounds = this.bounds;
		const tris = this.tris;

		for ( let i = offset, end = offset + count; i < end; i ++ ) {

			const tri = tris[ i ];

			minx = Math.min( minx, bounds[ tri * 6 + 0 ] );
			maxx = Math.max( maxx, bounds[ tri * 6 + 1 ] );
			miny = Math.min( miny, bounds[ tri * 6 + 2 ] );
			maxy = Math.max( maxy, bounds[ tri * 6 + 3 ] );
			minz = Math.min( minz, bounds[ tri * 6 + 4 ] );
			maxz = Math.max( maxz, bounds[ tri * 6 + 5 ] );

		}

		target[ 0 ] = Math.max( minx, parent[ 0 ] );
		target[ 1 ] = Math.max( miny, parent[ 1 ] );
		target[ 2 ] = Math.max( minz, parent[ 2 ] );

		target[ 3 ] = Math.min( maxx, parent[ 3 ] );
		target[ 4 ] = Math.min( maxy, parent[ 4 ] );
		target[ 5 ] = Math.min( maxz, parent[ 5 ] );

		return target;

	}

	// writes entries into a new geometry index (target) with the vertices of triangles from
	// offset through count
	writeReorderedIndices( offset, count, target ) {

		const tris = this.tris;
		const oldIndices = this.geo.index ? this.geo.index.array : null;

		for ( let i = offset, end = offset + count; i < end; i ++ ) {

			const oldTri = tris[ i ];
			target[ 3 * i + 0 ] = oldIndices ? oldIndices[ 3 * oldTri + 0 ] : 3 * oldTri + 0;
			target[ 3 * i + 1 ] = oldIndices ? oldIndices[ 3 * oldTri + 1 ] : 3 * oldTri + 1;
			target[ 3 * i + 2 ] = oldIndices ? oldIndices[ 3 * oldTri + 2 ] : 3 * oldTri + 1;

		}

	}

	// reorders `tris` such that for `count` elements after `offset`, elements on the left side of the split
	// will be on the left and elements on the right side of the split will be on the right. returns the index
	// of the first element on the right side, or offset + count if there are no elements on the right side.
	partition( offset, count, split ) {

		let left = offset;
		let right = offset + count - 1;
		const pos = split.pos;
		const axis = split.axis;
		const tris = this.tris;
		const centroids = this.centroids;

		// hoare partitioning, see e.g. https://en.wikipedia.org/wiki/Quicksort#Hoare_partition_scheme
		while ( left <= right ) {

			while ( left <= right && centroids[ tris[ left ] * 3 + axis ] < pos) {

				left ++;

			}

			while ( left <= right && centroids[ tris[ right ] * 3 + axis ] >= pos ) {

				right --;

			}

			if ( left <= right ) {

				let tmp = tris[ left ];
				tris[ left ] = tris[ right ];
				tris[ right ] = tmp;
				left ++;
				right --;

			}

		}

		return left;

	}

	getOptimalSplit( bounds, offset, count, strategy ) {

		let axis = - 1;
		let pos = 0;

		// Center
		if ( strategy === CENTER ) {

			axis = getLongestEdgeIndex( bounds );
			if ( axis !== - 1 ) {

				pos = ( bounds[ axis + 3 ] + bounds[ axis ] ) / 2;

			}

		} else if ( strategy === AVERAGE ) {

			axis = getLongestEdgeIndex( bounds );
			if ( axis !== - 1 ) {

				pos = this.getAverage( offset, count, axis );

			}

		} else if ( strategy === SAH ) {

			// Surface Area Heuristic
			// In order to make this code more terse, the x, y, and z
			// variables of various structures have been stuffed into
			// 0, 1, and 2 array indices so they can be easily computed
			// and accessed within array iteration

			// Cost values defineed for operations. We're using bounds for traversal, so
			// the cost of traversing one more layer is more than intersecting a triangle.
			const TRAVERSAL_COST = 3;
			const INTERSECTION_COST = 1;
			const tris = this.tris;
			const bb = arrayToBox( bounds, boxtemp );

			// Define the width, height, and depth of the bounds as a box
			const dim = [
				bb.max.x - bb.min.x,
				bb.max.y - bb.min.y,
				bb.max.z - bb.min.z
			];
			const sa = 2 * ( dim[ 0 ] * dim[ 1 ] + dim[ 0 ] * dim[ 2 ] + dim[ 1 ] * dim[ 2 ] );

			// Get the precalculated planes based for the triangles we're
			// testing here
			const filteredLists = [[], [], []];
			for ( let i = offset, end = offset + count; i < end; i ++ ) {

				let t = tris[ i ];
				for ( let v = 0; v < 3; v ++ ) {

					filteredLists[ v ].push( this.sahplanes[ v ][ t ] );

				}

			}
			filteredLists.forEach( planes => planes.sort( ( a, b ) => a.p - b.p ) );

			// this bounds surface area, left bound SA, left triangles, right bound SA, right triangles
			const getCost = ( sa, sal, nl, sar, nr ) =>
				  TRAVERSAL_COST + INTERSECTION_COST * ( ( sal / sa ) * nl + ( sar / sa ) * nr );

			// the cost of _not_ splitting into smaller bounds
			const noSplitCost = INTERSECTION_COST * count;

			axis = - 1;
			let bestCost = noSplitCost;
			for ( let i = 0; i < 3; i ++ ) {

				// o1 and o2 represent the _other_ two axes in the
				// the space. So if we're checking the x (0) dimension,
				// then o1 and o2 would be y and z (1 and 2)
				const o1 = ( i + 1 ) % 3;
				const o2 = ( i + 2 ) % 3;

				const bmin = bb.min[ xyzFields[ i ] ];
				const bmax = bb.max[ xyzFields[ i ] ];
				const planes = filteredLists[ i ];

				// The number of left and right triangles on either side
				// given the current split
				let nl = 0;
				let nr = count;
				for ( let p = 0; p < planes.length; p ++ ) {

					const pinfo = planes[ p ];

					// As the plane moves, we have to increment or decrement the
					// number of triangles on either side of the plane
					nl ++;
					nr --;

					// the distance from the plane to the edge of the broader bounds
					const ldim = pinfo.p - bmin;
					const rdim = bmax - pinfo.p;

					// same for the other two dimensions
					let ldimo1 = dim[ o1 ], rdimo1 = dim[ o1 ];
					let ldimo2 = dim[ o2 ], rdimo2 = dim[ o2 ];

					/*
					// compute the other bounding planes for the box
					// if only the current triangles are considered to
					// be in the box
					// This is really slow and probably not really worth it
					const o1planes = this.sahplanes[o1];
					const o2planes = this.sahplanes[o2];
					let lmin = Infinity, lmax = -Infinity;
					let rmin = Infinity, rmax = -Infinity;
					planes.forEach((p, i) => {
					const tri2 = p.tri * 2;
					const inf1 = o1planes[tri2 + 0];
					const inf2 = o1planes[tri2 + 1];
					if (i <= nl) {
					lmin = Math.min(inf1.p, inf2.p, lmin);
					lmax = Math.max(inf1.p, inf2.p, lmax);
					}
					if (i >= nr) {
					rmin = Math.min(inf1.p, inf2.p, rmin);
					rmax = Math.max(inf1.p, inf2.p, rmax);
					}
					})
					ldimo1 = Math.min(lmax - lmin, ldimo1);
					rdimo1 = Math.min(rmax - rmin, rdimo1);

					planes.forEach((p, i) => {
					const tri2 = p.tri * 2;
					const inf1 = o2planes[tri2 + 0];
					const inf2 = o2planes[tri2 + 1];
					if (i <= nl) {
					lmin = Math.min(inf1.p, inf2.p, lmin);
					lmax = Math.max(inf1.p, inf2.p, lmax);
					}
					if (i >= nr) {
					rmin = Math.min(inf1.p, inf2.p, rmin);
					rmax = Math.max(inf1.p, inf2.p, rmax);
					}
					})
					ldimo2 = Math.min(lmax - lmin, ldimo2);
					rdimo2 = Math.min(rmax - rmin, rdimo2);
					*/

					// surface areas and cost
					const sal = 2 * ( ldimo1 * ldimo2 + ldimo1 * ldim + ldimo2 * ldim );
					const sar = 2 * ( rdimo1 * rdimo2 + rdimo1 * rdim + rdimo2 * rdim );
					const cost = getCost( sa, sal, nl, sar, nr );

					if ( cost < bestCost ) {

						axis = i;
						pos = pinfo.p;
						bestCost = cost;

					}

				}

			}

		}

		return { axis, pos };

	}

}
<|endoftext|>