<commit_before>/**
* @license Apache-2.0
*
* Copyright (c) 2020 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

// MODULES //

var isNonNegativeInteger = require( '@stdlib/assert/is-nonnegative-integer' ).isPrimitive;
var isPositiveInteger = require( '@stdlib/assert/is-positive-integer' );
var isInteger = require( '@stdlib/assert/is-integer' ).isPrimitive;
var isFunctionArray = require( '@stdlib/assert/is-function-array' );
var isFunction = require( '@stdlib/assert/is-function' );
var isStringArray = require( '@stdlib/assert/is-string-array' ).primitives;
var isCollection = require( '@stdlib/assert/is-collection' );
var abs = require( '@stdlib/math/base/special/abs' );
var dtype = require( '@stdlib/ndarray/base/buffer-dtype' );
var indexOfTypes = require( './index_of_types.js' );

// MAIN //

/**
* Returns a strided array function interface which performs multiple dispatch.
*
* @param {(FunctionArray|Function)} fcns - list of strided array functions
* @param {StringArray} types - one-dimensional list of strided array argument data types
* @param {(Collection|null)} data - strided array function data (e.g., callbacks)
* @param {PositiveInteger} nargs - total number of strided array function interface arguments (including strides and offsets)
* @param {NonNegativeInteger} nin - number of input strided arrays
* @param {NonNegativeInteger} nout - number of output strided arrays
* @throws {TypeError} first argument must be either a function or an array of functions
* @throws {TypeError} second argument must be an array of strings
* @throws {TypeError} third argument must be an array-like object or `null`
* @throws {Error} third and first arguments must have the same number of elements
* @throws {TypeError} fourth argument must be a positive integer
* @throws {TypeError} fifth argument must be a nonnegative integer
* @throws {TypeError} sixth argument must be a nonnegative integer
* @throws {Error} fourth argument must be compatible with the specified number of input and output arrays
* @throws {Error} number of types must match the number of functions times the total number of array arguments for each function
* @throws {Error} interface must accept at least one strided input and/or output array
* @returns {Function} strided array function interface
*
* @example
* var unary = require( '@stdlib/strided/base/unary' );
* var abs = require( '@stdlib/math/base/special/abs' );
* var Float64Array = require( '@stdlib/array/float64' );
*
* var types = [
*     'float64', 'float64'
* ];
*
* var data = [
*     abs
* ];
*
* var strided = dispatch( unary, types, data, 5, 1, 1 );
*
* // ...
*
* var x = new Float64Array( [ -1.0, -2.0, -3.0, -4.0, -5.0 ] );
* var y = new Float64Array( [ 0.0, 0.0, 0.0, 0.0, 0.0 ] );
*
* strided( x.length, x, 1, y, 1 );
* // y => <Float64Array>[ 1.0, 2.0, 3.0, 4.0, 5.0 ]
*/
function dispatch( fcns, types, data, nargs, nin, nout ) {
	var strideArgs;
	var hasOffsets;
	var narrays;
	var nfcns;
	var iout;
	var fcn;

	if ( isFunction( fcns ) ) {
		fcn = fcns;
	} else if ( !isFunctionArray( fcns ) ) {
		throw new TypeError( 'invalid argument. First argument must be either a function or an array of functions. Value: `' + fcns + '`.' );
	}
	if ( !isStringArray( types ) ) {
		throw new TypeError( 'invalid argument. Second argument must be an array of strings. Value: `' + types + '`.' );
	}
	if ( !isCollection( data ) && data !== null ) {
		throw new TypeError( 'invalid argument. Third argument must be an array-like object or `null`. Value: `' + data + '`.' );
	}
	if ( !isPositiveInteger( nargs ) ) {
		throw new TypeError( 'invalid argument. Fourth argument must be a positive integer. Value: `' + nargs + '`.' );
	}
	if ( !isNonNegativeInteger( nin ) ) {
		throw new TypeError( 'invalid argument. Fifth argument must be a nonnegative integer. Value: `' + nin + '`.' );
	}
	if ( !isNonNegativeInteger( nout ) ) {
		throw new TypeError( 'invalid argument. Sixth argument must be a nonnegative integer. Value: `' + nout + '`.' );
	}
	narrays = nin + nout;
	if ( narrays === 0 ) {
		throw new Error( 'invalid arguments. Interface must accept at least one strided input and/or output array. Based on the provided arguments, `nin+nout` equals `0`.' );
	}
	if ( fcn ) {
		nfcns = types.length / narrays;
		if ( !isInteger( nfcns ) ) {
			throw new Error( 'invalid argument. Unexpected number of types. A type must be specified for each strided input and output array for each provided strided array function.' );
		}
	} else {
		nfcns = fcns.length;
		if ( types.length !== nfcns*narrays ) {
			throw new Error( 'invalid argument. Unexpected number of types. A type must be specified for each strided input and output array for each provided strided array function.' );
		}
	}
	if ( data && data.length !== nfcns ) {
		throw new Error( 'invalid argument. The third argument must have the same number of elements as the first argument.' );
	}
	// Determine whether the strided array interface includes offsets:
	if ( (narrays*2)+1 === nargs ) {
		hasOffsets = false;
	} else if ( (narrays*3)+1 === nargs ) {
		hasOffsets = true;
	} else {
		throw new Error( 'invalid argument. Fourth argument is incompatible with the number of strided input and output arrays.' );
	}
	// Determine the "stride" for accessing related arguments:
	if ( hasOffsets ) {
		strideArgs = 3;
	} else {
		strideArgs = 2;
	}
	// Compute the index of the first output strided array argument:
	iout = ( nin*strideArgs ) + 1;

	return dispatcher;

	/**
	* Strided array function interface which performs multiple dispatch.
	*
	* @private
	* @param {integer} N - number of indexed elements
	* @param {Collection} x - strided array
	* @param {integer} strideX - index increment for `x`
	* @param {...(ArrayLikeObject|integer|NonNegativeInteger)} args - array arguments (arrays, strides, and offsets)
	* @throws {Error} insufficient arguments
	* @throws {Error} too many arguments
	* @throws {TypeError} first argument must be an integer
	* @throws {TypeError} input array strides must be integers
	* @throws {TypeError} output array strides must be integers
	* @throws {TypeError} input array offsets must be nonnegative integers
	* @throws {TypeError} output array offsets must be nonnegative integers
	* @throws {TypeError} input array arguments must be array-like objects
	* @throws {TypeError} output array arguments must be array-like objects
	* @throws {RangeError} input array arguments must have sufficient elements based on the associated stride and the number of indexed elements
	* @throws {RangeError} output array arguments must have sufficient elements based on the associated stride and the number of indexed elements
	* @throws {TypeError} unable to resolve a strided array function supporting the provided array argument data types
	* @returns {(ArrayLikeObject|Array<ArrayLikeObject>|void)} destination array(s)
	*/
	function dispatcher() {
		var strides;
		var offsets;
		var arrays;
		var dtypes;
		var shape;
		var argc;
		var idx;
		var N;
		var v;
		var f;
		var i;
		var j;

		argc = arguments.length;
		if ( argc !== nargs ) {
			if ( argc < nargs ) {
				throw new Error( 'invalid invocation. Insufficient arguments.' );
			}
			throw new Error( 'invalid invocation. Too many arguments.' );
		}
		N = arguments[ 0 ];
		if ( !isInteger( N ) ) {
			throw new TypeError( 'invalid argument. First argument must be an integer.' );
		}
		shape = [ N ];

		// Strides for both input and output strided arrays are every `strideArgs` arguments beginning from the third argument...
		strides = [];
		for ( i = 2; i < nargs; i += strideArgs ) {
			v = arguments[ i ];
			if ( !isInteger( v ) ) {
				if ( i < iout ) {
					throw new TypeError( 'invalid argument. Input array stride argument must be an integer.' );
				} else {
					throw new TypeError( 'invalid argument. Output array stride argument must be an integer.' );
				}
			}
			strides.push( v );
		}
		if ( hasOffsets ) {
			// Offsets for both input and output strided arrays are every `strideArgs` arguments beginning from the fourth argument...
			offsets = [];
			for ( i = 3; i < nargs; i += strideArgs ) {
				v = arguments[ i ];
				if ( !isNonNegativeInteger( v ) ) {
					if ( i < iout ) {
						throw new TypeError( 'invalid argument. Input array offset argument must be a nonnegative integer.' );
					} else {
						throw new TypeError( 'invalid argument. Output array offset argument must be a nonnegative integer.' );
					}
				}
				offsets.push( v );
			}
		}
		// Input and output strided arrays are every `strideArgs` arguments beginning from the second argument...
		arrays = [];
		dtypes = [];
		for ( i = 1; i < nargs; i += strideArgs ) {
			v = arguments[ i ];
			if ( !isCollection( v ) ) {
				if ( i < iout ) {
					throw new TypeError( 'invalid argument. Input array argument must be an array-like object.' );
				} else {
					throw new TypeError( 'invalid argument. Output array argument must be an array-like object.' );
				}
			}
			j = (i-1) / strideArgs;
			if ( hasOffsets ) {
				idx = offsets[ j ] + ( (N-1)*strides[j] );
				if ( N > 0 && (idx < 0 || idx >= v.length) ) {
					if ( i < iout ) {
						throw new RangeError( 'invalid argument. Input array argument has insufficient elements based on the associated stride and the number of indexed elements.' );
					} else {
						throw new RangeError( 'invalid argument. Output array argument has insufficient elements based on the associated stride and the number of indexed elements.' );
					}
				}
			} else if ( (N-1)*abs(strides[j]) >= v.length ) {
				if ( i < iout ) {
					throw new RangeError( 'invalid argument. Input array argument has insufficient elements based on the associated stride and the number of indexed elements.' );
				} else {
					throw new RangeError( 'invalid argument. Output array argument has insufficient elements based on the associated stride and the number of indexed elements.' );
				}
			}
			arrays.push( v );
			dtypes.push( dtype( v ) || 'generic' );
		}
		// Resolve the strided array function satisfying the input array types:
		idx = indexOfTypes( nfcns, narrays, types, narrays, 1, 0, dtypes, 1, 0 ); // eslint-disable-line max-len

		// Check whether we were able to successfully resolve a strided array function:
		if ( idx < 0 ) {
			throw new TypeError( 'invalid arguments. Unable to resolve a strided array function supporting the provided array argument data types.' );
		}
		// Retrieve the strided array function:
		if ( fcn ) {
			f = fcn;
		} else {
			f = fcns[ idx ];
		}
		// Evaluate the strided array function:
		if ( data ) {
			if ( hasOffsets ) {
				f( arrays, shape, strides, offsets, data[ idx ] );
			} else {
				f( arrays, shape, strides, data[ idx ] );
			}
		} else if ( hasOffsets ) {
			f( arrays, shape, strides, offsets );
		} else {
			f( arrays, shape, strides );
		}
		if ( nout === 1 ) {
			return arrays[ narrays-1 ];
		}
		if ( nout === 0 ) {
			return;
		}
		return arrays.slice( nin );
	}
}

// EXPORTS //

module.exports = dispatch;
<commit_msg>Update type annotation<commit_after>/**
* @license Apache-2.0
*
* Copyright (c) 2020 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

// MODULES //

var isNonNegativeInteger = require( '@stdlib/assert/is-nonnegative-integer' ).isPrimitive;
var isPositiveInteger = require( '@stdlib/assert/is-positive-integer' );
var isInteger = require( '@stdlib/assert/is-integer' ).isPrimitive;
var isFunctionArray = require( '@stdlib/assert/is-function-array' );
var isFunction = require( '@stdlib/assert/is-function' );
var isStringArray = require( '@stdlib/assert/is-string-array' ).primitives;
var isCollection = require( '@stdlib/assert/is-collection' );
var abs = require( '@stdlib/math/base/special/abs' );
var dtype = require( '@stdlib/ndarray/base/buffer-dtype' );
var indexOfTypes = require( './index_of_types.js' );

// MAIN //

/**
* Returns a strided array function interface which performs multiple dispatch.
*
* @param {(FunctionArray|Function)} fcns - list of strided array functions
* @param {StringArray} types - one-dimensional list of strided array argument data types
* @param {(Collection|null)} data - strided array function data (e.g., callbacks)
* @param {PositiveInteger} nargs - total number of strided array function interface arguments (including strides and offsets)
* @param {NonNegativeInteger} nin - number of input strided arrays
* @param {NonNegativeInteger} nout - number of output strided arrays
* @throws {TypeError} first argument must be either a function or an array of functions
* @throws {TypeError} second argument must be an array of strings
* @throws {TypeError} third argument must be an array-like object or `null`
* @throws {Error} third and first arguments must have the same number of elements
* @throws {TypeError} fourth argument must be a positive integer
* @throws {TypeError} fifth argument must be a nonnegative integer
* @throws {TypeError} sixth argument must be a nonnegative integer
* @throws {Error} fourth argument must be compatible with the specified number of input and output arrays
* @throws {Error} number of types must match the number of functions times the total number of array arguments for each function
* @throws {Error} interface must accept at least one strided input and/or output array
* @returns {Function} strided array function interface
*
* @example
* var unary = require( '@stdlib/strided/base/unary' );
* var abs = require( '@stdlib/math/base/special/abs' );
* var Float64Array = require( '@stdlib/array/float64' );
*
* var types = [
*     'float64', 'float64'
* ];
*
* var data = [
*     abs
* ];
*
* var strided = dispatch( unary, types, data, 5, 1, 1 );
*
* // ...
*
* var x = new Float64Array( [ -1.0, -2.0, -3.0, -4.0, -5.0 ] );
* var y = new Float64Array( [ 0.0, 0.0, 0.0, 0.0, 0.0 ] );
*
* strided( x.length, x, 1, y, 1 );
* // y => <Float64Array>[ 1.0, 2.0, 3.0, 4.0, 5.0 ]
*/
function dispatch( fcns, types, data, nargs, nin, nout ) {
	var strideArgs;
	var hasOffsets;
	var narrays;
	var nfcns;
	var iout;
	var fcn;

	if ( isFunction( fcns ) ) {
		fcn = fcns;
	} else if ( !isFunctionArray( fcns ) ) {
		throw new TypeError( 'invalid argument. First argument must be either a function or an array of functions. Value: `' + fcns + '`.' );
	}
	if ( !isStringArray( types ) ) {
		throw new TypeError( 'invalid argument. Second argument must be an array of strings. Value: `' + types + '`.' );
	}
	if ( !isCollection( data ) && data !== null ) {
		throw new TypeError( 'invalid argument. Third argument must be an array-like object or `null`. Value: `' + data + '`.' );
	}
	if ( !isPositiveInteger( nargs ) ) {
		throw new TypeError( 'invalid argument. Fourth argument must be a positive integer. Value: `' + nargs + '`.' );
	}
	if ( !isNonNegativeInteger( nin ) ) {
		throw new TypeError( 'invalid argument. Fifth argument must be a nonnegative integer. Value: `' + nin + '`.' );
	}
	if ( !isNonNegativeInteger( nout ) ) {
		throw new TypeError( 'invalid argument. Sixth argument must be a nonnegative integer. Value: `' + nout + '`.' );
	}
	narrays = nin + nout;
	if ( narrays === 0 ) {
		throw new Error( 'invalid arguments. Interface must accept at least one strided input and/or output array. Based on the provided arguments, `nin+nout` equals `0`.' );
	}
	if ( fcn ) {
		nfcns = types.length / narrays;
		if ( !isInteger( nfcns ) ) {
			throw new Error( 'invalid argument. Unexpected number of types. A type must be specified for each strided input and output array for each provided strided array function.' );
		}
	} else {
		nfcns = fcns.length;
		if ( types.length !== nfcns*narrays ) {
			throw new Error( 'invalid argument. Unexpected number of types. A type must be specified for each strided input and output array for each provided strided array function.' );
		}
	}
	if ( data && data.length !== nfcns ) {
		throw new Error( 'invalid argument. The third argument must have the same number of elements as the first argument.' );
	}
	// Determine whether the strided array interface includes offsets:
	if ( (narrays*2)+1 === nargs ) {
		hasOffsets = false;
	} else if ( (narrays*3)+1 === nargs ) {
		hasOffsets = true;
	} else {
		throw new Error( 'invalid argument. Fourth argument is incompatible with the number of strided input and output arrays.' );
	}
	// Determine the "stride" for accessing related arguments:
	if ( hasOffsets ) {
		strideArgs = 3;
	} else {
		strideArgs = 2;
	}
	// Compute the index of the first output strided array argument:
	iout = ( nin*strideArgs ) + 1;

	return dispatcher;

	/**
	* Strided array function interface which performs multiple dispatch.
	*
	* @private
	* @param {integer} N - number of indexed elements
	* @param {Collection} x - strided array
	* @param {integer} strideX - index increment for `x`
	* @param {...(Collection|integer|NonNegativeInteger)} args - array arguments (arrays, strides, and offsets)
	* @throws {Error} insufficient arguments
	* @throws {Error} too many arguments
	* @throws {TypeError} first argument must be an integer
	* @throws {TypeError} input array strides must be integers
	* @throws {TypeError} output array strides must be integers
	* @throws {TypeError} input array offsets must be nonnegative integers
	* @throws {TypeError} output array offsets must be nonnegative integers
	* @throws {TypeError} input array arguments must be array-like objects
	* @throws {TypeError} output array arguments must be array-like objects
	* @throws {RangeError} input array arguments must have sufficient elements based on the associated stride and the number of indexed elements
	* @throws {RangeError} output array arguments must have sufficient elements based on the associated stride and the number of indexed elements
	* @throws {TypeError} unable to resolve a strided array function supporting the provided array argument data types
	* @returns {(Collection|Array<Collection>|void)} destination array(s)
	*/
	function dispatcher() {
		var strides;
		var offsets;
		var arrays;
		var dtypes;
		var shape;
		var argc;
		var idx;
		var N;
		var v;
		var f;
		var i;
		var j;

		argc = arguments.length;
		if ( argc !== nargs ) {
			if ( argc < nargs ) {
				throw new Error( 'invalid invocation. Insufficient arguments.' );
			}
			throw new Error( 'invalid invocation. Too many arguments.' );
		}
		N = arguments[ 0 ];
		if ( !isInteger( N ) ) {
			throw new TypeError( 'invalid argument. First argument must be an integer.' );
		}
		shape = [ N ];

		// Strides for both input and output strided arrays are every `strideArgs` arguments beginning from the third argument...
		strides = [];
		for ( i = 2; i < nargs; i += strideArgs ) {
			v = arguments[ i ];
			if ( !isInteger( v ) ) {
				if ( i < iout ) {
					throw new TypeError( 'invalid argument. Input array stride argument must be an integer.' );
				} else {
					throw new TypeError( 'invalid argument. Output array stride argument must be an integer.' );
				}
			}
			strides.push( v );
		}
		if ( hasOffsets ) {
			// Offsets for both input and output strided arrays are every `strideArgs` arguments beginning from the fourth argument...
			offsets = [];
			for ( i = 3; i < nargs; i += strideArgs ) {
				v = arguments[ i ];
				if ( !isNonNegativeInteger( v ) ) {
					if ( i < iout ) {
						throw new TypeError( 'invalid argument. Input array offset argument must be a nonnegative integer.' );
					} else {
						throw new TypeError( 'invalid argument. Output array offset argument must be a nonnegative integer.' );
					}
				}
				offsets.push( v );
			}
		}
		// Input and output strided arrays are every `strideArgs` arguments beginning from the second argument...
		arrays = [];
		dtypes = [];
		for ( i = 1; i < nargs; i += strideArgs ) {
			v = arguments[ i ];
			if ( !isCollection( v ) ) {
				if ( i < iout ) {
					throw new TypeError( 'invalid argument. Input array argument must be an array-like object.' );
				} else {
					throw new TypeError( 'invalid argument. Output array argument must be an array-like object.' );
				}
			}
			j = (i-1) / strideArgs;
			if ( hasOffsets ) {
				idx = offsets[ j ] + ( (N-1)*strides[j] );
				if ( N > 0 && (idx < 0 || idx >= v.length) ) {
					if ( i < iout ) {
						throw new RangeError( 'invalid argument. Input array argument has insufficient elements based on the associated stride and the number of indexed elements.' );
					} else {
						throw new RangeError( 'invalid argument. Output array argument has insufficient elements based on the associated stride and the number of indexed elements.' );
					}
				}
			} else if ( (N-1)*abs(strides[j]) >= v.length ) {
				if ( i < iout ) {
					throw new RangeError( 'invalid argument. Input array argument has insufficient elements based on the associated stride and the number of indexed elements.' );
				} else {
					throw new RangeError( 'invalid argument. Output array argument has insufficient elements based on the associated stride and the number of indexed elements.' );
				}
			}
			arrays.push( v );
			dtypes.push( dtype( v ) || 'generic' );
		}
		// Resolve the strided array function satisfying the input array types:
		idx = indexOfTypes( nfcns, narrays, types, narrays, 1, 0, dtypes, 1, 0 ); // eslint-disable-line max-len

		// Check whether we were able to successfully resolve a strided array function:
		if ( idx < 0 ) {
			throw new TypeError( 'invalid arguments. Unable to resolve a strided array function supporting the provided array argument data types.' );
		}
		// Retrieve the strided array function:
		if ( fcn ) {
			f = fcn;
		} else {
			f = fcns[ idx ];
		}
		// Evaluate the strided array function:
		if ( data ) {
			if ( hasOffsets ) {
				f( arrays, shape, strides, offsets, data[ idx ] );
			} else {
				f( arrays, shape, strides, data[ idx ] );
			}
		} else if ( hasOffsets ) {
			f( arrays, shape, strides, offsets );
		} else {
			f( arrays, shape, strides );
		}
		if ( nout === 1 ) {
			return arrays[ narrays-1 ];
		}
		if ( nout === 0 ) {
			return;
		}
		return arrays.slice( nin );
	}
}

// EXPORTS //

module.exports = dispatch;
<|endoftext|>


<commit_before>var height = 627,
  width = 627;

var outerRadius = Math.min(width, height) / 2 - 8,
  innerRadius = outerRadius - 30;

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

var svg = d3.select('#chart')
  .append('svg')
  .attr('width', width)
  .attr('height', height)
  .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

var groups = svg.append("g")
  .attr("class", "groups")
  .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

var chords = svg.append("g")
  .attr("class", "chords")
  .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

var layout = d3.layout.chord()
  .padding(0.02);

$.get("/data/airports.csv", function(airports) {
  airports = airports.split("\n");
  d3.json("/data/matrix.json", function(matrix) {
    layout.matrix(matrix);

    var dataGroups = groups.selectAll('path')
     .data(layout.groups);

    var dataChords = chords.selectAll('path')
      .data(layout.chords);

    dataGroups
      .enter()
      .append('path')
      .attr("d", arc);

    dataChords
      .enter()
      .append('path')
      .attr("d", d3.svg.chord().radius(innerRadius));

    svg.selectAll("g.chords path").data(layout.chords().slice(0, 100)).exit().remove();
  });
});
<commit_msg>Shitty working version, but it works<commit_after>var height = 627,
  width = 627,
  originalMatrix,
  layout;

var outerRadius = Math.min(width, height) / 2 - 8,
  innerRadius = outerRadius - 30;

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

var svg = d3.select('#chart')
  .append('svg')
  .attr('width', width)
  .attr('height', height)
  .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

var groups = svg.append("g")
  .attr("class", "groups")
  .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

var chords = svg.append("g")
  .attr("class", "chords")
  .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

function generateLayout() {
  return d3.layout.chord()
    .padding(0.02);
}

//////////////////////////////////////////////////
// Now Creating Functions
//////////////////////////////////////////////////

function filterMatrix(nodes, matrix) {
  var newMatrix = matrix
    .map(function(d, i) {
      return filterArray(nodes, d);
    })
  return filterArray(nodes, newMatrix);
}

function filterArray(nodes, array) {
  return array.filter(function(d, i) {
    return ($.inArray(i, nodes) > -1);
  });
}

function getIncludedChords(origin) {
  var asSource = layout.chords().filter(function(d, ind) {
    return d.source.index === origin;
  });

  var asTarget = layout.chords().filter(function(d, ind) {
    return d.target.index === origin;
  });

  return _.uniq(asSource.concat(asTarget));
}

function getIncludedGroups(chords, origin) {
  var targets = chords.map(function(d, i) {
    return d.source.index === origin ? d.target.index : undefined;
  });
  var sources = chords.map(function(d, i) {
    return d.target.index === origin ? d.source.index : undefined;
  });

  return _.uniq(targets.concat(sources).filter(function(d) {
    return d !== undefined;
  }));
}

function groupClick(g, i) {
  console.log("Source Node => " + i);

  var includedChords = getIncludedChords(i);
  var includedGroups = getIncludedGroups(includedChords, i);

  var newMatrix = filterMatrix(includedGroups, originalMatrix);
  layout = generateLayout();
  layout.matrix([]);
  draw();

  setTimeout(function() {

    layout = generateLayout();
    layout.matrix(newMatrix);

    draw();
  }, 500);

}

function draw() {
  var dataGroups = groups.selectAll('path')
    .data(layout.groups);

  var dataChords = chords.selectAll('path')
    .data(layout.chords);

  var enterGroups = dataGroups
    .enter()
    .append('path')
    .attr("d", arc)
    .on("click", groupClick);

  var enterChords = dataChords
    .enter()
    .append('path')
    .attr("d", d3.svg.chord().radius(innerRadius));

  dataGroups.exit().transition().remove();
  dataChords.exit().transition().remove();
}

//////////////////////////////////////////////////
// Initialization
//////////////////////////////////////////////////
$.get("/data/airports.csv", function(airports) {
  airports = airports.split("\n");
  d3.json("/data/matrix.json", function(matrix) {
    layout = generateLayout();
    layout.matrix(matrix);
    originalMatrix = matrix;
    draw();
  });
});
<|endoftext|>


<commit_before>var fs        = require('fs'),
    stemmer   = require('porter-stemmer').stemmer,
    stopwords = require('./stopwords').stopwords ;

require('./utils');

function textii(text, options, callback) {
  var self = this;

  self.text = text;

  self.default_options = {
    word_separator: /\W+/,
    min_word_length: 3,
    encoding: 'utf8'
  };

  textii.prototype.setOptions = function(opts) {
    if (opts) {
      self.options = opts;
      self.options.word_separator = opts.word_separator || self.default_options.word_separator;
      self.options.min_word_length = opts.min_word_length || self.default_options.min_word_length;
      self.options.encoding = opts.encoding || self.default_options.encoding;
    } else {
      self.options = self.default_options;
    }
  };
  self.setOptions(options);

  textii.prototype.get = function(opts) {
    self.getText(function(text) {
      self.split_text(text, function(words) {
        self.normalize_words(words, function(normalized_words) {
          self.index_words(normalized_words, opts, function(indexed_words) {
            self.clean_words(indexed_words);
          });
        });
      });
    });
  };

  textii.prototype.getText = function(callback) {
    callback(self.text)
  };

  textii.prototype.split_text = function(text, callback) {
    var words = text.split(self.options.word_separator);
    callback(words);
  };

  textii.prototype.normalize_words = function(words, callback) {
    var normalized_words = words.map(function(word) {
      return stemmer(word).toLowerCase();
    });
    callback(normalized_words);
  };

  textii.prototype.index_words = function(normalized_words, opts, callback) {
    var indexed_words = {};
    for (var i = 0; i < normalized_words.length; i++) {
      var word = normalized_words[i];
      if (opts && opts.section) {
        if (indexed_words[word] === undefined) {
          indexed_words[word] = {};
        }
        if (indexed_words[word][opts.section] === undefined) {
          indexed_words[word][opts.section] = [];
        }
        indexed_words[word][opts.section].push(i);
      } else {
        if (indexed_words[word] === undefined) {
          indexed_words[word] = [];
        }
        indexed_words[word].push(i);
      }
    }
    callback(indexed_words);
  };

  textii.prototype.clean_words = function(indexed_words) {
    var cleaned_words = indexed_words.filter_by_key(function(key) {
      var valid_length = (key.length >= self.options.min_word_length),
          not_a_stopword = (stopwords.indexOf(key) === -1);
      return valid_length && not_a_stopword;
    });
    callback(null, cleaned_words);
  };
}

// module exports
exports = module.exports = function(text, options, callback) {
  return new textii(text, options, callback);
};
<commit_msg>complete callback stack<commit_after>var fs        = require('fs'),
    stemmer   = require('porter-stemmer').stemmer,
    stopwords = require('./stopwords').stopwords ;

require('./utils');

function textii(text, options, callback) {
  var self = this;

  self.text = text;

  self.default_options = {
    word_separator: /\W+/,
    min_word_length: 3,
    encoding: 'utf8'
  };

  textii.prototype.setOptions = function(opts) {
    if (opts) {
      self.options = opts;
      self.options.word_separator = opts.word_separator || self.default_options.word_separator;
      self.options.min_word_length = opts.min_word_length || self.default_options.min_word_length;
      self.options.encoding = opts.encoding || self.default_options.encoding;
    } else {
      self.options = self.default_options;
    }
  };
  self.setOptions(options);

  textii.prototype.get = function(opts) {
    self.getText(function(text) {
      self.split_text(text, function(words) {
        self.normalize_words(words, function(normalized_words) {
          self.index_words(normalized_words, opts, function(indexed_words) {
            self.clean_words(indexed_words, function(cleaned_words) {
              callback(null, cleaned_words);
            });
          });
        });
      });
    });
  };

  textii.prototype.getText = function(callback) {
    callback(self.text)
  };

  textii.prototype.split_text = function(text, callback) {
    var words = text.split(self.options.word_separator);
    callback(words);
  };

  textii.prototype.normalize_words = function(words, callback) {
    var normalized_words = words.map(function(word) {
      return stemmer(word).toLowerCase();
    });
    callback(normalized_words);
  };

  textii.prototype.index_words = function(normalized_words, opts, callback) {
    var indexed_words = {};
    for (var i = 0; i < normalized_words.length; i++) {
      var word = normalized_words[i];
      if (opts && opts.section) {
        if (indexed_words[word] === undefined) {
          indexed_words[word] = {};
        }
        if (indexed_words[word][opts.section] === undefined) {
          indexed_words[word][opts.section] = [];
        }
        indexed_words[word][opts.section].push(i);
      } else {
        if (indexed_words[word] === undefined) {
          indexed_words[word] = [];
        }
        indexed_words[word].push(i);
      }
    }
    callback(indexed_words);
  };

  textii.prototype.clean_words = function(indexed_words, callback) {
    var cleaned_words = indexed_words.filter_by_key(function(key) {
      var valid_length = (key.length >= self.options.min_word_length),
          not_a_stopword = (stopwords.indexOf(key) === -1);
      return valid_length && not_a_stopword;
    });
    callback(cleaned_words);
  };
}

// module exports
exports = module.exports = function(text, options, callback) {
  return new textii(text, options, callback);
};
<|endoftext|>


<commit_before>"use strict";

var sys = require('sys');
var fs = require('fs');
var _ = require('lodash');
var serialPort = require("serialport");
var SerialPort = serialPort.SerialPort;
var RSVP = require('rsvp');

var call = function (callback) {
	if (!_.isFunction(callback)) {
		return;
	}
	var args = _.filter(arguments, function (arg, index) {
		return !!index;
	});

	return callback.apply(this, args);
};

var p = function (handler) {
	return new RSVP.Promise(handler);
};

var ptime = function (handler, delay, timeout) {
	return p(function (res, rej) {
		var t = setTimeout(function () {
			call(timeout);
			rej(new Error('Tosr0x timeout'));
		}, delay || 0);
		var newResolve = function () {
			clearTimeout(t);
			return res.apply(this, arguments);
		};
		var newReject = function () {
			clearTimeout(t);
			return rej.apply(this, arguments);
		};
		return handler(newResolve, newReject);
	});
};

var resolved = function (err, rej, callback) {
	if (!!err) {
		call(callback, err);
		rej(err);
	}
	return !err;
};

var log = function (t, cmd, msg) {
	if (!t._options.debug) {
		return;
	}
	if (!msg) {
		msg = cmd;
		cmd = 'log';
	}
	if (cmd !== 'dir') {
		msg = '[Tosr0x] ' + msg;
	}
	console[cmd](msg);
};

var T = exports.Tosr0x = function (uri, options) {
	this._serial = null;
	this._uri = uri || '/dev/ttyUSB0';
	this._buffer = '';
	this._options = _.assign({}, T.defaults, options || {});
	this._states = {};
	this.reads = [];
};

T.defaults = {
	// serial port specific
	baudRate: 9600,
	dataBits: 8,
	parity: 'none',
	stopBits: 1,
	flowControl: false,

	// Tosr0x specific
	debug: false,
	relayCount: 2,
	timeout: 1500
};

T.device = {
	vendorId: '0x0403',
	productId: '0x6001',
	moduleId: 15
};

T.portScan = function (callback) {
	return p(function (res, rej) {
		serialPort.list(function (err, ports) {
			if (resolved(err, rej)) {
				call(callback, ports);
				res(ports);
			}
		});
	});
};

T.fromPortScan = function (options, device, callback) {
	device = device || T.device;
	return p(function (res, rej) {
		T.portScan(function (ports) {
			var found = false;
			ports.forEach(function (port) {
				if (port.vendorId == device.vendorId &&
					port.productId === device.productId) {
					var t = new T(port.comName, options);
					call(callback, null, t);
					res(t);
					found = true;
				}
			});
			if (!found) {
				var err = new Error('No device found!');
				call(callback, err, null);
				rej(err);
			}
		});
	});
};

T.create = function (uri, options) {
	if (!uri) {
		return T.fromPortScan(options);
	} else {
		return p(function (res) {
			process.nextTick(function () {
				res(new T(uri, options));
			});
		});
	}
};

T.commands = {
	'version'    : 'Z',
	'states'     : '[',
	'voltage'    : ']',
	'temperature': 'b',
	'on'         : 100,
	'off'        : 110
};

var bufferIsNullTerminated = function (buffer) {
	return buffer.indexOf('\n') !== -1;
};

var dataListener = function (t) {
	return function dataListener(data) {
		var newReads = [];

		t.buffer += data.toString();
		log(t, 'Received ' + data.toString('hex'));

		_.forEach(t.reads, function (r) {
			var callR = function (data) {
				process.nextTick(function dataTick() {
					r(data);
				});
			};
			if (r.buffer) {
				if (!bufferIsNullTerminated(t.buffer)) {
					newReads.push(r);
				} else {
					callR(t.buffer);
				}
			} else {
				t.buffer = '';
				callR(data);
			}
		});

		t.reads = newReads;
		if (bufferIsNullTerminated(t.buffer)) {
			t.buffer = '';
		}
	};
};

var errorListener = function (t) {
	return function errorListener(err) {
		throw err;
	};
};

var closeListener = function (t) {
	return function closeListener() {
		t._serial = null;
		t._state = {};
		t.reads = [];
		log(t, 'Port closed.');
	};
};

T.prototype.open = function (callback) {
	var t = this;
	var opts = _.assign({}, this._options);
	t._serial = null;
	t._state = {};
	return p(function open(res, rej) {
		var s = new SerialPort(t._uri, opts, false);
		log(t, 'Opening port...');
		s.open(function (err) {
			if (resolved(err, rej, callback)) {
				s.on('data', dataListener(t));
				s.on('error', errorListener(t));
				s.on('close', closeListener(t));
				t._serial = s;

				call(callback, null, t);
				res(t);
			}
		});
	});
};

T.prototype.connected = function () {
	return !!this._serial;
};

T.prototype.options = function () {
	return _.assign({}, this._options);
};

T.prototype.state = function (relay) {
	if (_.isNumber(relay)) {
		return !!this._state[relay];
	}
	return _.assign({}, this._state);
};

T.prototype.close = function (callback) {
	var t = this;
	return p(function close(res, rej) {
		if (!t._serial) {
			log(t, 'error', 'Already closed.');
			// soft fail
			call(callback, null, t);
			res(t);
			return;
		}
		t._serial.flush(function (err) {
			if (resolved(err, rej, callback)) {
				t._serial.close(function (err) {
					if (resolved(err, rej, callback)) {
						call(callback, null, t);
						res(t);
					}
				});
			}
		});
	});
};

T.prototype.closeImmediate = function (callback) {
	if (!this._serial) {
		return;
	}
	this._serial.close(callback);
};

T.prototype.send = function (cmd, callback) {
	if (!this._serial) {
		throw new Error('Not connected.');
	}
	if (cmd.length !== 1) {
		throw new Error('cmd must be one ascii char');
	}
	var t = this;
	var s = this._serial;
	return ptime(function send(res, rej) {
		log(t, '------------------------------');
		log(t, 'Sending ' + cmd);
		s.write(cmd, function (err, bytesWritten) {
			if (resolved(err, rej, callback)) {
				s.drain(function (err) {
					if (resolved(err, rej, callback)) {
						call(callback, bytesWritten);
						res({bytesWritten:bytesWritten, ctl: t});
					}
				});
			}
		});
	}, this._options.timeout, function () { t.closeImmediate(); });
};

T.prototype.receive = function (callback, buffer) {
	callback.buffer = buffer || false;
	this.reads.push(callback);
};

T.prototype.switch = function (relay, on, callback) {
	relay = parseInt(relay, 10) || 0;
	if (relay < 0 || relay > this._options.relayCount) {
		throw new Error('realy out of range: must be [0, ' + this._options.relayCount + ']');
	}
	var cmd = !!on ? T.commands.on : T.commands.off;
	return this.send(String.fromCharCode(cmd + relay), function (err, ret) {
		call(callback, err, ret);
		if (!!err) {
			return;
		}
		if (relay === 0) { // all relays
			_.forOwn(this._state, function (val, key) {
				this._state[key] = !!on;
			}, this);
		} else {
			this._state[relay] = !!on;
		}
	});
};

T.prototype.on = function (relay, callback) {
	return this.switch(relay, true, callback);
};

T.prototype.off = function (relay, callback) {
	return this.switch(relay, false, callback);
};

T.prototype.toggle = function (relay, callback) {
	return this.switch(relay, !this._state[relay], callback);
};

T.prototype.states = T.prototype.refreshStates = function (callback) {
	var t = this;
	var promise = ptime(function version(res, rej) {
		t.receive(function (data) {
			var binStates = data[0];
			var relayCount = t._options.relayCount;
			for (var x = 0; x < relayCount; x++) {
				var mask = (1 << x);
				t._state[x + 1] = (binStates & mask) === mask;
			}
			call(callback, t._state);
			res({states: t._state, ctl: t});
		});
	}, this._options.timeout, function () { t.closeImmediate(); });
	this.send(T.commands.states);
	return promise;
};

T.prototype.version = function (callback) {
	var t = this;
	var promise = ptime(function version(res, rej) {
		t.receive(function (data) {
			// module should return 2-byte string:
			// module id, software version
			var v = -1;
			if (data[0] == T.device.moduleId) {
				v = data[1];
			}
			call(callback, v, t);
			res({version: v, ctl: t});
		});
	}, this._options.timeout, function () { t.closeImmediate(); });
	this.send(T.commands.version);
	return promise;
};

T.prototype.voltage = function (callback) {
	var t = this;
	var promise = ptime(function voltage(res, rej) {
		t.receive(function (data) {
			// voltage is a byte but the value
			// is a fixed floating point with precision of 1
			var v = data[0] * 0.1;
			call(callback, v);
			res({voltage: v, ctl: t});
		});
	}, this._options.timeout, function () { t.closeImmediate(); });
	this.send(T.commands.voltage);
	return promise;
};

T.prototype.temperature = function (callback) {
	var t = this;
	var promise = ptime(function temperature(res, rej) {
		t.receive(function (data) {
			call(callback, data);
			res({temperature: data, ctl: t});
		}, true);
	}, this._options.timeout, function () { t.closeImmediate(); });
	this.send(T.commands.temperature);
	return promise;
};
<commit_msg>keys do not needs escaping<commit_after>"use strict";

var sys = require('sys');
var fs = require('fs');
var _ = require('lodash');
var serialPort = require("serialport");
var SerialPort = serialPort.SerialPort;
var RSVP = require('rsvp');

var call = function (callback) {
	if (!_.isFunction(callback)) {
		return;
	}
	var args = _.filter(arguments, function (arg, index) {
		return !!index;
	});

	return callback.apply(this, args);
};

var p = function (handler) {
	return new RSVP.Promise(handler);
};

var ptime = function (handler, delay, timeout) {
	return p(function (res, rej) {
		var t = setTimeout(function () {
			call(timeout);
			rej(new Error('Tosr0x timeout'));
		}, delay || 0);
		var newResolve = function () {
			clearTimeout(t);
			return res.apply(this, arguments);
		};
		var newReject = function () {
			clearTimeout(t);
			return rej.apply(this, arguments);
		};
		return handler(newResolve, newReject);
	});
};

var resolved = function (err, rej, callback) {
	if (!!err) {
		call(callback, err);
		rej(err);
	}
	return !err;
};

var log = function (t, cmd, msg) {
	if (!t._options.debug) {
		return;
	}
	if (!msg) {
		msg = cmd;
		cmd = 'log';
	}
	if (cmd !== 'dir') {
		msg = '[Tosr0x] ' + msg;
	}
	console[cmd](msg);
};

var T = exports.Tosr0x = function (uri, options) {
	this._serial = null;
	this._uri = uri || '/dev/ttyUSB0';
	this._buffer = '';
	this._options = _.assign({}, T.defaults, options || {});
	this._states = {};
	this.reads = [];
};

T.defaults = {
	// serial port specific
	baudRate: 9600,
	dataBits: 8,
	parity: 'none',
	stopBits: 1,
	flowControl: false,

	// Tosr0x specific
	debug: false,
	relayCount: 2,
	timeout: 1500
};

T.device = {
	vendorId: '0x0403',
	productId: '0x6001',
	moduleId: 15
};

T.portScan = function (callback) {
	return p(function (res, rej) {
		serialPort.list(function (err, ports) {
			if (resolved(err, rej)) {
				call(callback, ports);
				res(ports);
			}
		});
	});
};

T.fromPortScan = function (options, device, callback) {
	device = device || T.device;
	return p(function (res, rej) {
		T.portScan(function (ports) {
			var found = false;
			ports.forEach(function (port) {
				if (port.vendorId == device.vendorId &&
					port.productId === device.productId) {
					var t = new T(port.comName, options);
					call(callback, null, t);
					res(t);
					found = true;
				}
			});
			if (!found) {
				var err = new Error('No device found!');
				call(callback, err, null);
				rej(err);
			}
		});
	});
};

T.create = function (uri, options) {
	if (!uri) {
		return T.fromPortScan(options);
	} else {
		return p(function (res) {
			process.nextTick(function () {
				res(new T(uri, options));
			});
		});
	}
};

T.commands = {
	version     : 'Z',
	states      : '[',
	voltage     : ']',
	temperature : 'b',
	on          : 100,
	off         : 110
};

var bufferIsNullTerminated = function (buffer) {
	return buffer.indexOf('\n') !== -1;
};

var dataListener = function (t) {
	return function dataListener(data) {
		var newReads = [];

		t.buffer += data.toString();
		log(t, 'Received ' + data.toString('hex'));

		_.forEach(t.reads, function (r) {
			var callR = function (data) {
				process.nextTick(function dataTick() {
					r(data);
				});
			};
			if (r.buffer) {
				if (!bufferIsNullTerminated(t.buffer)) {
					newReads.push(r);
				} else {
					callR(t.buffer);
				}
			} else {
				t.buffer = '';
				callR(data);
			}
		});

		t.reads = newReads;
		if (bufferIsNullTerminated(t.buffer)) {
			t.buffer = '';
		}
	};
};

var errorListener = function (t) {
	return function errorListener(err) {
		throw err;
	};
};

var closeListener = function (t) {
	return function closeListener() {
		t._serial = null;
		t._state = {};
		t.reads = [];
		log(t, 'Port closed.');
	};
};

T.prototype.open = function (callback) {
	var t = this;
	var opts = _.assign({}, this._options);
	t._serial = null;
	t._state = {};
	return p(function open(res, rej) {
		var s = new SerialPort(t._uri, opts, false);
		log(t, 'Opening port...');
		s.open(function (err) {
			if (resolved(err, rej, callback)) {
				s.on('data', dataListener(t));
				s.on('error', errorListener(t));
				s.on('close', closeListener(t));
				t._serial = s;

				call(callback, null, t);
				res(t);
			}
		});
	});
};

T.prototype.connected = function () {
	return !!this._serial;
};

T.prototype.options = function () {
	return _.assign({}, this._options);
};

T.prototype.state = function (relay) {
	if (_.isNumber(relay)) {
		return !!this._state[relay];
	}
	return _.assign({}, this._state);
};

T.prototype.close = function (callback) {
	var t = this;
	return p(function close(res, rej) {
		if (!t._serial) {
			log(t, 'error', 'Already closed.');
			// soft fail
			call(callback, null, t);
			res(t);
			return;
		}
		t._serial.flush(function (err) {
			if (resolved(err, rej, callback)) {
				t._serial.close(function (err) {
					if (resolved(err, rej, callback)) {
						call(callback, null, t);
						res(t);
					}
				});
			}
		});
	});
};

T.prototype.closeImmediate = function (callback) {
	if (!this._serial) {
		return;
	}
	this._serial.close(callback);
};

T.prototype.send = function (cmd, callback) {
	if (!this._serial) {
		throw new Error('Not connected.');
	}
	if (cmd.length !== 1) {
		throw new Error('cmd must be one ascii char');
	}
	var t = this;
	var s = this._serial;
	return ptime(function send(res, rej) {
		log(t, '------------------------------');
		log(t, 'Sending ' + cmd);
		s.write(cmd, function (err, bytesWritten) {
			if (resolved(err, rej, callback)) {
				s.drain(function (err) {
					if (resolved(err, rej, callback)) {
						call(callback, bytesWritten);
						res({bytesWritten:bytesWritten, ctl: t});
					}
				});
			}
		});
	}, this._options.timeout, function () { t.closeImmediate(); });
};

T.prototype.receive = function (callback, buffer) {
	callback.buffer = buffer || false;
	this.reads.push(callback);
};

T.prototype.switch = function (relay, on, callback) {
	relay = parseInt(relay, 10) || 0;
	if (relay < 0 || relay > this._options.relayCount) {
		throw new Error('realy out of range: must be [0, ' + this._options.relayCount + ']');
	}
	var cmd = !!on ? T.commands.on : T.commands.off;
	return this.send(String.fromCharCode(cmd + relay), function (err, ret) {
		call(callback, err, ret);
		if (!!err) {
			return;
		}
		if (relay === 0) { // all relays
			_.forOwn(this._state, function (val, key) {
				this._state[key] = !!on;
			}, this);
		} else {
			this._state[relay] = !!on;
		}
	});
};

T.prototype.on = function (relay, callback) {
	return this.switch(relay, true, callback);
};

T.prototype.off = function (relay, callback) {
	return this.switch(relay, false, callback);
};

T.prototype.toggle = function (relay, callback) {
	return this.switch(relay, !this._state[relay], callback);
};

T.prototype.states = T.prototype.refreshStates = function (callback) {
	var t = this;
	var promise = ptime(function version(res, rej) {
		t.receive(function (data) {
			var binStates = data[0];
			var relayCount = t._options.relayCount;
			for (var x = 0; x < relayCount; x++) {
				var mask = (1 << x);
				t._state[x + 1] = (binStates & mask) === mask;
			}
			call(callback, t._state);
			res({states: t._state, ctl: t});
		});
	}, this._options.timeout, function () { t.closeImmediate(); });
	this.send(T.commands.states);
	return promise;
};

T.prototype.version = function (callback) {
	var t = this;
	var promise = ptime(function version(res, rej) {
		t.receive(function (data) {
			// module should return 2-byte string:
			// module id, software version
			var v = -1;
			if (data[0] == T.device.moduleId) {
				v = data[1];
			}
			call(callback, v, t);
			res({version: v, ctl: t});
		});
	}, this._options.timeout, function () { t.closeImmediate(); });
	this.send(T.commands.version);
	return promise;
};

T.prototype.voltage = function (callback) {
	var t = this;
	var promise = ptime(function voltage(res, rej) {
		t.receive(function (data) {
			// voltage is a byte but the value
			// is a fixed floating point with precision of 1
			var v = data[0] * 0.1;
			call(callback, v);
			res({voltage: v, ctl: t});
		});
	}, this._options.timeout, function () { t.closeImmediate(); });
	this.send(T.commands.voltage);
	return promise;
};

T.prototype.temperature = function (callback) {
	var t = this;
	var promise = ptime(function temperature(res, rej) {
		t.receive(function (data) {
			call(callback, data);
			res({temperature: data, ctl: t});
		}, true);
	}, this._options.timeout, function () { t.closeImmediate(); });
	this.send(T.commands.temperature);
	return promise;
};
<|endoftext|>


<commit_before>/*!
 * Copyright by Oleg Efimov
 *
 * See license text in LICENSE file
 */

// Require dependencies
var Buffer = require('buffer').Buffer;
var EventEmitter = require('events').EventEmitter;
var assert = require('assert');
var util = require('util');
var strtok = require('strtok');

// Extend `strtok` for reading/writing float and double numbers
require('./strtok-extend.js');

// Require UBJSON parser, packer and stream
var UbjsonParser = require("./ubjson-parser.js");
var ubjsonPack = require("./ubjson-pack.js");
var UbjsonStream = require("./ubjson-stream.js");

// Require class for int64 storing
var Int64 = require('./int64.js');

// A mock stream implementation that breaks up provided data into
// 1-byte chunks and emits 'data' events. This is used to simulate
// data arriving with arbitrary packet boundaries.
function BufferStream(buffer) {
    EventEmitter.call(this);

    var self = this;

    var emitData = function() {
        var len = 1;

        var b;

        if (len < buffer.length) {
            b = buffer.slice(0, len);

            buffer = buffer.slice(len, buffer.length);

            process.nextTick(emitData);
        } else {
            b = buffer.slice(0, buffer.length);

            process.nextTick(function() {
                self.emit('end');
            });
        }

        self.emit('data', b);
    };

    process.nextTick(emitData);
}
util.inherits(BufferStream, EventEmitter);

function unpackBuffer(buffer, callback) {
  var stream = new BufferStream(buffer);

  var ubjsonStrtokParser = new UbjsonParser(function (value) {
    if (value instanceof Error) {
      var remainingData = new Buffer(buffer.length);
      var remainingDataLength = 0;

      stream.on('data', function (data) {
        data.copy(remainingData, remainingDataLength);
        remainingDataLength += data.length;
      });

      stream.on('end', function () {
        value.remainingData = remainingData.slice(0, remainingDataLength);

        callback(value);
      });
    } else {
      callback(null, value);
    }
  });

  strtok.parse(stream, ubjsonStrtokParser);
}

/*!
 * Internal functions
 */
function packToBufferWithOffsetSync(value, buffer, bufferOffset) {
  return ubjsonPack(
    null /* stream */,
    buffer /* buffer */, bufferOffset /* buffer offset */, value /* value */,
    null /* flush */
  );
}

function packToBufferSync(value, buffer) {
  return packToBufferWithOffsetSync(value, buffer, 0);
}

function packToBuffer(value, buffer, callback) {
  try {
    var offset = packToBufferSync(value, buffer);

    process.nextTick(function() {
      callback(null, offset);
    });
  } catch (e) {
    process.nextTick(function() {
      callback(e);
    });
  }
}

// Export public functions

/**
 * UBJSON
 *
 * Functions and classes, exported from Node.js `ubjson` module.
 **/

/**
 * UBJSON.unpackBuffer(buffer, callback)
 * - buffer (Buffer): Buffer to unpack
 * - callback (Function): Callback, gets JavaScript value
 *
 * Unpacks buffer with UBJSON data into JavaScript value.
 **/
exports.unpackBuffer = unpackBuffer;

/**
 * UBJSON.packToBuffer(value, buffer, callback)
 * - value (mixed): Value to pack
 * - buffer (Buffer): Buffer to resulting UBJSON data
 * - callback (Function): Callback, gets buffer (error, offset)
 *
 * Packs JavaScript value into UBJSON.
 **/
exports.packToBuffer = packToBuffer;

/**
 * UBJSON.packToBufferSync(value, buffer) -> Integer
 * - value (mixed): Value to pack
 * - buffer (Buffer): Buffer to resulting UBJSON data
 *
 * Synchronous [[UBJSON.packToBuffer]]. Returns buffer offset.
 **/
exports.packToBufferSync = packToBufferSync;

/**
 * == Classes ==
 *
 * Exported classes.
 **/

/** alias of: UbjsonStream
 * class UBJSON.Stream < EventEmitter
 **/
exports.Stream = UbjsonStream;

/** alias of: Int64
 * class UBJSON.Int64
 **/
exports.Int64 = Int64;
<commit_msg>Introduce setImmediate()<commit_after>/*!
 * Copyright by Oleg Efimov
 *
 * See license text in LICENSE file
 */

// Require dependencies
var Buffer = require('buffer').Buffer;
var EventEmitter = require('events').EventEmitter;
var assert = require('assert');
var util = require('util');
var strtok = require('strtok');

// Extend `strtok` for reading/writing float and double numbers
require('./strtok-extend.js');

// Require UBJSON parser, packer and stream
var UbjsonParser = require("./ubjson-parser.js");
var ubjsonPack = require("./ubjson-pack.js");
var UbjsonStream = require("./ubjson-stream.js");

// Require class for int64 storing
var Int64 = require('./int64.js');

if (typeof setImmediate !== "function") {
  var setImmediate = function (callback) {
    process.nextTick(callback);
  };
}

// A mock stream implementation that breaks up provided data into
// 1-byte chunks and emits 'data' events. This is used to simulate
// data arriving with arbitrary packet boundaries.
function BufferStream(buffer) {
    EventEmitter.call(this);

    var self = this;

    var emitData = function() {
        var len = 1;

        var b;

        if (len < buffer.length) {
            b = buffer.slice(0, len);

            buffer = buffer.slice(len, buffer.length);

            setImmediate(emitData);
        } else {
            b = buffer.slice(0, buffer.length);

            setImmediate(function() {
                self.emit('end');
            });
        }

        self.emit('data', b);
    };

    setImmediate(emitData);
}
util.inherits(BufferStream, EventEmitter);

function unpackBuffer(buffer, callback) {
  var stream = new BufferStream(buffer);

  var ubjsonStrtokParser = new UbjsonParser(function (value) {
    if (value instanceof Error) {
      var remainingData = new Buffer(buffer.length);
      var remainingDataLength = 0;

      stream.on('data', function (data) {
        data.copy(remainingData, remainingDataLength);
        remainingDataLength += data.length;
      });

      stream.on('end', function () {
        value.remainingData = remainingData.slice(0, remainingDataLength);

        callback(value);
      });
    } else {
      callback(null, value);
    }
  });

  strtok.parse(stream, ubjsonStrtokParser);
}

/*!
 * Internal functions
 */
function packToBufferWithOffsetSync(value, buffer, bufferOffset) {
  return ubjsonPack(
    null /* stream */,
    buffer /* buffer */, bufferOffset /* buffer offset */, value /* value */,
    null /* flush */
  );
}

function packToBufferSync(value, buffer) {
  return packToBufferWithOffsetSync(value, buffer, 0);
}

function packToBuffer(value, buffer, callback) {
  try {
    var offset = packToBufferSync(value, buffer);

    setImmediate(function() {
      callback(null, offset);
    });
  } catch (e) {
    setImmediate(function() {
      callback(e);
    });
  }
}

// Export public functions

/**
 * UBJSON
 *
 * Functions and classes, exported from Node.js `ubjson` module.
 **/

/**
 * UBJSON.unpackBuffer(buffer, callback)
 * - buffer (Buffer): Buffer to unpack
 * - callback (Function): Callback, gets JavaScript value
 *
 * Unpacks buffer with UBJSON data into JavaScript value.
 **/
exports.unpackBuffer = unpackBuffer;

/**
 * UBJSON.packToBuffer(value, buffer, callback)
 * - value (mixed): Value to pack
 * - buffer (Buffer): Buffer to resulting UBJSON data
 * - callback (Function): Callback, gets buffer (error, offset)
 *
 * Packs JavaScript value into UBJSON.
 **/
exports.packToBuffer = packToBuffer;

/**
 * UBJSON.packToBufferSync(value, buffer) -> Integer
 * - value (mixed): Value to pack
 * - buffer (Buffer): Buffer to resulting UBJSON data
 *
 * Synchronous [[UBJSON.packToBuffer]]. Returns buffer offset.
 **/
exports.packToBufferSync = packToBufferSync;

/**
 * == Classes ==
 *
 * Exported classes.
 **/

/** alias of: UbjsonStream
 * class UBJSON.Stream < EventEmitter
 **/
exports.Stream = UbjsonStream;

/** alias of: Int64
 * class UBJSON.Int64
 **/
exports.Int64 = Int64;
<|endoftext|>


<commit_before>/**
 * Vector: One dimensional array.
 * Extends upon the Array datatype to do some serious number crunching.
 * @author Fredrick Galoso
 */

var Vector = function(values) {

    var vector = !(values instanceof Array) ?
        Array.prototype.slice.call(arguments) :
        values;

    if (Array.prototype.slice.call(arguments).length === 0)
        vector = [];

    var cache = {};

    // Sorting primatives
    var asc = function(a, b) {
        return a - b;
    };

    var desc = function(a, b) {
        return b - a;
    };

    vector.sum = function(callback) {
        var sum = 0.0;
        for (var i = 0; i < vector.length;) {
            sum += vector[i++];
        }
        cache.sum = sum;
        if (callback)
            return callback(sum);
        else
            return sum;
    };

    vector.product = function(callback) {
        for (var i = 0, product = 1.0; i < vector.length;) {
            product *= vector[i++];
        }
        if (callback)
            return callback(product);
        else
            return product;
    };

    vector.mean = function(callback) {
        var mean = vector.sum() / vector.length;
        if (callback)
            return callback(mean);
        else
            return mean;
    };

    vector.gmean = function(callback) {
        var gmean = Math.pow(Math.abs(vector.product()), 1 / vector.length);
        if (callback)
            return callback(gmean);
        else
            return gmean;
    };

    vector.hmean = function(callback) {
        function reciprocalSum(set) {
            for (var i = 0, sum = 0.0; i < set.length;) {
                sum += 1 / Math.abs(set[i++]);
            }
            return sum;
        }
        var hmean = vector.length / reciprocalSum(vector);
        if (callback)
            return callback(hmean);
        else
            return hmean;
    };

    vector.qmean = function(callback) {
        var qmean = Math.sqrt(vector.pow(2).sum() / vector.length)
        if (callback)
            return callback(qmean);
        else
            return qmean;
    };

    vector.median = function(callback) {
        var buffer = vector.copy();
        buffer.sort(asc);
        var median = (vector.length % 2 === 0) ?
            (buffer[vector.length / 2 - 1] + buffer[vector.length / 2]) / 2 :
            buffer[parseInt(vector.length / 2)];
        if (callback)
            return callback(median);
        else
            return median;
    };

    vector.mode = function(callback) {
        var map = {};
        var count = 1;
        var modes = new Vector();
        for (var i = 0; i < vector.length; i++) {
            var e = vector[i];
            if (map[e] == null)
                map[e] = 1;
            else
                map[e]++;
            if (map[e] > count) {
                modes = new Vector(e);
                count = map[e];
            } else if (map[e] == count) {
                modes.push(e);
                count = map[e];
            }
        }
        if (modes.length === 1)
            modes = modes[0];
        if (callback)
            return callback(modes);
        else
            return modes;
    };

    vector.range = function(callback) {
        var range = vector.max() - vector.min();
        if (callback)
            return callback(range);
        else
            return range;
    };

    vector.variance = function(callback) {
        for (var i = 0, variance = 0.0; i < vector.length;) {
            variance += Math.pow((vector[i++] - vector.mean()), 2);
        }
        variance /= vector.length;
        if (callback)
            return callback(variance);
        else
            return variance;
    };

    vector.stdev = function(percentile, callback) {
        var stdev = 0.0;
        if (!percentile)
            stdev = Math.sqrt(vector.variance());
        else
            return vector.density(percentile).stdev();
        if (callback)
            return callback(stdev);
        else
            return stdev;
    };

    /* Returns the frequency of an element in the array */
    vector.frequency = function(element, callback) {
        var freq = 0;
        /*TODO if element is not given, display frequency distribution*/
        if (vector.indexOf(element) !== -1) {
            var buffer = vector.copy();
            buffer.sort(asc);
            freq = buffer.lastIndexOf(element) - buffer.indexOf(element) + 1;
        }
        if (callback)
            return callback(freq);
        else
            return freq;
    };

    /* Returns an element from an array given a percentile */
    vector.percentile = function(percent, callback) {
        var buffer = vector.copy();
        buffer.sort(asc);
        var percentile = buffer[0];
        if (percent > 0)
            percentile = buffer[Math.floor(vector.length * percent)];
        if (callback)
            return callback(percentile);
        else
            return percentile;
    };

    /**
     * Returns a Vector (Array) of values within a given percent density
     *
     * Example:
     *    vector.density(0.50); would return an array consisting of the values
     *    between the 25% and 75% percentile of the population
     */
    vector.density = function(percent, callback) {
        var slice;
        var buffer = vector.copy();
        buffer.sort(asc);
        if (percent == 1)
            return buffer;
        else {
            var begin = Math.round(vector.length * (0.5 - percent / 2) - 1);
            var end = Math.round(vector.length * (0.5 + percent / 2) - 1);
            slice = new Vector(buffer.slice(begin, end));
        }
        if (callback)
            return callback(slice);
        else
            return slice;
    };

    /**
     * Returns an Object containing the distribution of values within the array
     * @param format Override distribution format with Percent Distribution. Default: Raw count
     */
    vector.distribution = function(format, callback) {
        var buffer = vector.copy();
        buffer.sort(asc);
        var map = function (array, index, format, distribution) {
            if (index === array.length)
                return distribution;
            else {
                distribution[array[index]] = (format === 'relative') ?
                array.frequency(array[index]) / array.length : array.frequency(array[index]);
                return map(array, array.lastIndexOf(array[index]) + 1, format, distribution);
            }
        }
        var result = (format === 'relative') ? map(buffer, 0, 'relative', {}) : map(buffer, 0, 'raw', {});
        if (callback)
            return callback(result);
        else
            return result;
    };

    vector.quantile = function(quantity, callback) {
        var buffer = vector.copy();
        buffer.sort(asc);
        var increment = 1.0 / quantity;
        var results = new Vector();
        if (quantity > vector.length)
            throw new RangeError('Subset quantity is greater than the Vector length');
        for (var i = increment; i < 1; i += increment) {
            var index = Math.round(buffer.length * i) - 1;
            if (index < buffer.length - 1)
                results.push(buffer[index]);
        }
        if (callback)
            return callback(results);
        else
            return results;
    };

    /* Returns a new Vector containing the sequential difference between numbers in a sequence */
    vector.delta = function(callback) {
        var delta = new Vector();
        for (var i = 1; i < vector.length; i++) {
            delta.push(vector[i] - vector[i - 1]);
        }
        if (callback)
            return callback(delta);
        else
            return delta;
    };

    /** Moving average */
    /**
     * Returns a new Vector of the simple moving average (SMA); unweighted means of the previous n data points
     * @param period Length of observation window for moving average
     */
    vector.sma = function(period, callback) {
        var sma;
        if (period === 1) sma = vector;
        else {
            // Memoize (rolling) sum to avoid additional O(n) overhead
            var sum = new Vector(vector.slice(0, period)).sum();
            sma = new Vector([sum / period]);
            for (var i = 1; i < vector.length - period + 1; i++) {
                sum += vector[i + period - 1] - vector[i - 1];
                sma.push(sum / period);
            }
        }
        if (callback)
            return callback(sma);
        else
            return sma;
    };

    /**
     * Returns a new Vector of the exponential moving average (EMA); weighted means of the previous n data points
     * @param options
     *   Number Length of the observation window for moving average, use default smoothing ratio (2 / period + 1)
     *   or
     *   Object.period Length of the observation window for moving average
     *   Object.ratio Function returning a Number to be used as smoothing ratio
     */
    vector.ema = function(options, callback) {
        // Single numeric argument defining the smoothing period
        if (typeof(options) === 'number') {
            var length = options;
            options = {
                period: length,
                ratio: function(n) { return 2 / (n + 1); }
            };
        }
        var sum = new Vector(vector.slice(0, options.period)).sum(),
            ema = new Vector([sum / options.period]),
            ratio = options.ratio(options.period);
        for (var i = 1; i < vector.length - options.period + 1; i++) {
            ema.push(
                ratio
                * (vector[i + options.period - 1] - ema[i - 1])
                + ema[i - 1]
            );
        }
        if (callback)
            return callback(ema);
        else
            return ema;
    };

    /**
     * Apply JavaScript Math methods to an entire Vector set of numbers
     */
    vector.max = function(callback) {
        var max = Math.max.apply({}, vector);
        if (callback)
            return callback(max);
        else
            return max;
    };

    vector.min = function(callback) {
        var min = Math.min.apply({}, vector);
        if (callback)
            return callback(min);
        else
            return min;
    };

    vector.abs = function(callback) {
        var abs = vector.map(function(x) {
            return Math.abs(x);
        });
        if (callback)
            return callback(abs);
        else
            return abs;
    };

    vector.acos = function(callback) {
        var acos = vector.map(function(x) {
            return Math.acos(x);
        });
        if (callback)
            return callback(acos);
        else
            return acos;
    };

    vector.asin = function(callback) {
        var asin = vector.map(function(x) {
           return Math.asin(x);
        });
        if (callback)
            return callback(asin);
        else
            return asin;
    };

    vector.atan = function(callback) {
        var atan = vector.map(function(x) {
            return Math.atan(x);
        });
        if (callback)
            return callback(atan);
        else
            return atan;
    };

    vector.ceil = function(callback) {
        var ceil = vector.map(function(x) {
            return Math.ceil(x);
        });
        if (callback)
            return callback(ceil);
        else
            return ceil;
    };

    vector.cos = function(callback) {
        var cos = vector.map(function(x) {
            return Math.cos(x);
        });
        if (callback)
            return callback(cos);
        else
            return cos;
    };

    vector.exp = function(callback) {
        var exp = vector.map(function(x) {
            return Math.exp(x);
        });
        if (callback)
            return callback(exp);
        else
            return exp;
    };

    vector.floor = function(callback) {
        var floor = vector.map(function(x) {
            return Math.floor(x);
        });
        if (callback)
            return callback(floor);
        else
            return floor;
    };

    vector.log = function(callback) {
        var log = vector.map(function(x) {
            return Math.log(x);
        });
        if (callback)
            return callback(log);
        else
            return log;
    };

    vector.pow = function(exponent, callback) {
        var pow = vector.map(function(x) {
            return Math.pow(x, exponent);
        });
        if (callback)
            return callback(pow);
        else
            return pow;
    };

    vector.round = function(callback) {
        var round = vector.map(function(x) {
            return Math.round(x);
        });
        if (callback)
            return callback(round);
        else
            return round;
    };

    vector.sin = function(callback) {
        var sin = vector.map(function(x) {
           return Math.sin(x);
        });
        if (callback)
            return callback(sin);
        else
            return sin;
    };

    vector.sqrt = function(callback) {
        var sqrt = vector.map(function(x) {
            return Math.sqrt(x);
        });
        if (callback)
            return callback(sqrt);
        else
            return sqrt;
    };

    vector.tan = function(callback) {
        var tan = vector.map(function(x) {
            return Math.tan(x);
        });
        if (callback)
            return callback(tan);
        else
            return tan;
    };

    /* Returns a clone of the Vector object */
    vector.clone = function(callback) {
        var object = (vector instanceof Array) ? [] : {};
        for (i in vector) {
            if (i === 'clone') continue;
            if (vector[i] && typeof vector[i] === 'object') {
                object[i] = vector[i].clone();
            } else object[i] = vector[i]
        }
        if (callback)
            return callback(object);
        else
            return object;
    };

    /* Returns a copy of the values in a Vector object */
    vector.copy = function(callback) {
        var copy = new Vector(vector.slice());
        if (callback)
            return callback(copy);
        else
            return copy;
    };

    /* Returns a vanilla Array of values */
    vector.array = function(callback) {
        var array = Array.prototype.slice.call(vector);
        if (callback)
            return callback(array);
        else
            return array;
    };

    /**
     * Override Array methods and add Vector functionality
     */

    /* Mutator methods */

    /* Accessor methods */
    vector.slice = function(begin, end, callback) {
        var args = Array.prototype.slice.call(arguments);
        var slice;
        if (args.length === 3)
            return callback(new Vector(vector.array().slice(begin, end)));
        else if (args.length === 2) {
            if (typeof args[1] === 'function')
                return callback(new Vector(vector.array().slice(begin)));
            else
                return new Vector(vector.array().slice(begin, end));
        }
        else if (args.length === 1)
            return new Vector(vector.array().slice(begin));
        else
            return new Vector(vector.array().slice());
    };

    /* Iteration methods */
    vector.map = function(callback) {
        var map = vector.array().map(callback);
        return new Vector(map);
    };

    return vector;
};

exports = module.exports = Vector;
<commit_msg>Array extensions are no longer enumerable, console.log and util.inspect now only show Array like representation<commit_after>/**
 * Vector: One dimensional array.
 * Extends upon the Array datatype to do some serious number crunching.
 * @author Fredrick Galoso
 */

var Vector = function(values) {

    var vector = !(values instanceof Array) ?
        Array.prototype.slice.call(arguments) :
        values;

    if (Array.prototype.slice.call(arguments).length === 0)
        vector = [];

    var cache = {};

    // Sorting primatives
    var asc = function(a, b) {
        return a - b;
    };

    var desc = function(a, b) {
        return b - a;
    };

    Object.defineProperties(vector, {
        'sum': {
            value: function(callback) {
                var sum = 0.0;
                for (var i = 0; i < vector.length;) {
                    sum += vector[i++];
                }
                cache.sum = sum;
                if (callback)
                    return callback(sum);
                else
                    return sum;
            },
            writable: true,
            enumerable: false
        },
        'product': {
            value: function(callback) {
                for (var i = 0, product = 1.0; i < vector.length;) {
                    product *= vector[i++];
                }
                if (callback)
                    return callback(product);
                else
                    return product;
            },
            writable: true,
            enumerable: false
        },
        'mean': {
            value: function(callback) {
                var mean = vector.sum() / vector.length;
                if (callback)
                    return callback(mean);
                else
                    return mean;
            },
            writable: true,
            enumerable: false
        },
        'gmean': {
            value: function(callback) {
                var gmean = Math.pow(Math.abs(vector.product()), 1 / vector.length);
                if (callback)
                    return callback(gmean);
                else
                    return gmean;
            },
            writable: true,
            enumerable: false
        },
        'hmean': {
            value: function(callback) {
                function reciprocalSum(set) {
                    for (var i = 0, sum = 0.0; i < set.length;) {
                        sum += 1 / Math.abs(set[i++]);
                    }
                    return sum;
                }
                var hmean = vector.length / reciprocalSum(vector);
                if (callback)
                    return callback(hmean);
                else
                    return hmean;
            },
            writable: true,
            enumerable: false
        },
        'qmean': {
            value: function(callback) {
                var qmean = Math.sqrt(vector.pow(2).sum() / vector.length)
                if (callback)
                    return callback(qmean);
                else
                    return qmean;
            },
            writable: true,
            enumerable: false
        },
        'median': {
            value: function(callback) {
                var buffer = vector.copy();
                buffer.sort(asc);
                var median = (vector.length % 2 === 0) ?
                    (buffer[vector.length / 2 - 1] + buffer[vector.length / 2]) / 2 :
                    buffer[parseInt(vector.length / 2)];
                if (callback)
                    return callback(median);
                else
                    return median;
            },
            writable: true,
            enumerable: false
        },
        'mode': {
            value: function(callback) {
                var map = {};
                var count = 1;
                var modes = new Vector();
                for (var i = 0; i < vector.length; i++) {
                    var e = vector[i];
                    if (map[e] == null)
                        map[e] = 1;
                    else
                        map[e]++;
                    if (map[e] > count) {
                        modes = new Vector(e);
                        count = map[e];
                    } else if (map[e] == count) {
                        modes.push(e);
                        count = map[e];
                    }
                }
                if (modes.length === 1)
                    modes = modes[0];
                if (callback)
                    return callback(modes);
                else
                    return modes;
            },
            writable: true,
            enumerable: false
        },
        'range': {
            value: function(callback) {
                var range = vector.max() - vector.min();
                if (callback)
                    return callback(range);
                else
                    return range;
            },
            writable: true,
            enumerable: false
        },
        'variance': {
            value: function(callback) {
                for (var i = 0, variance = 0.0; i < vector.length;) {
                    variance += Math.pow((vector[i++] - vector.mean()), 2);
                }
                variance /= vector.length;
                if (callback)
                    return callback(variance);
                else
                    return variance;
            },
            writable: true,
            enumerable: false
        },
        'stdev': {
            value: function(percentile, callback) {
                var stdev = 0.0;
                if (!percentile)
                    stdev = Math.sqrt(vector.variance());
                else
                    return vector.density(percentile).stdev();
                if (callback)
                    return callback(stdev);
                else
                    return stdev;
            },
            writable: true,
            enumerable: false
        },
        /* Returns the frequency of an element in the array */
        'frequency': {
            value: function(element, callback) {
                var freq = 0;
                /*TODO if element is not given, display frequency distribution*/
                if (vector.indexOf(element) !== -1) {
                    var buffer = vector.copy();
                    buffer.sort(asc);
                    freq = buffer.lastIndexOf(element) - buffer.indexOf(element) + 1;
                }
                if (callback)
                    return callback(freq);
                else
                    return freq;
            },
            writable: true,
            enumerable: false
        },
        /* Returns an element from an array given a percentile */
        'percentile' : {
            value: function(percent, callback) {
                var buffer = vector.copy();
                buffer.sort(asc);
                var percentile = buffer[0];
                if (percent > 0)
                    percentile = buffer[Math.floor(vector.length * percent)];
                if (callback)
                    return callback(percentile);
                else
                    return percentile;
            },
            writable: true,
            enumerable: false
        },
        /**
         * Returns a Vector (Array) of values within a given percent density
         *
         * Example:
         *    vector.density(0.50); would return an array consisting of the values
         *    between the 25% and 75% percentile of the population
         */
        'density': {
            value: function(percent, callback) {
                var slice;
                var buffer = vector.copy();
                buffer.sort(asc);
                if (percent == 1)
                    return buffer;
                else {
                    var begin = Math.round(vector.length * (0.5 - percent / 2) - 1);
                    var end = Math.round(vector.length * (0.5 + percent / 2) - 1);
                    slice = new Vector(buffer.slice(begin, end));
                }
                if (callback)
                    return callback(slice);
                else
                    return slice;
            },
            writable: true,
            enumerable: false
        },
        /**
         * Returns an Object containing the distribution of values within the array
         * @param format Override distribution format with Percent Distribution. Default: Raw count
         */
        'distribution': {
            value: function(format, callback) {
                var buffer = vector.copy();
                buffer.sort(asc);
                var map = function (array, index, format, distribution) {
                    if (index === array.length)
                        return distribution;
                    else {
                        distribution[array[index]] = (format === 'relative') ?
                        array.frequency(array[index]) / array.length : array.frequency(array[index]);
                        return map(array, array.lastIndexOf(array[index]) + 1, format, distribution);
                    }
                }
                var result = (format === 'relative') ? map(buffer, 0, 'relative', {}) : map(buffer, 0, 'raw', {});
                if (callback)
                    return callback(result);
                else
                    return result;
            },
            writable: true,
            enumerable: false
        },
        'quantile': {
            value: function(quantity, callback) {
                var buffer = vector.copy();
                buffer.sort(asc);
                var increment = 1.0 / quantity;
                var results = new Vector();
                if (quantity > vector.length)
                    throw new RangeError('Subset quantity is greater than the Vector length');
                for (var i = increment; i < 1; i += increment) {
                    var index = Math.round(buffer.length * i) - 1;
                    if (index < buffer.length - 1)
                        results.push(buffer[index]);
                }
                if (callback)
                    return callback(results);
                else
                    return results;
            },
            writable: true,
            enumerable: false
        },
        /* Returns a new Vector containing the sequential difference between numbers in a sequence */
        'delta': {
            value: function(callback) {
                var delta = new Vector();
                for (var i = 1; i < vector.length; i++) {
                    delta.push(vector[i] - vector[i - 1]);
                }
                if (callback)
                    return callback(delta);
                else
                    return delta;
            },
            writable: true,
            enumerable: false
        },
        /** Moving average */
        /**
         * Returns a new Vector of the simple moving average (SMA); unweighted means of the previous n data points
         * @param period Length of observation window for moving average
         */
        'sma': {
            value: function(period, callback) {
                var sma;
                if (period === 1) sma = vector;
                else {
                    // Memoize (rolling) sum to avoid additional O(n) overhead
                    var sum = new Vector(vector.slice(0, period)).sum();
                    sma = new Vector([sum / period]);
                    for (var i = 1; i < vector.length - period + 1; i++) {
                        sum += vector[i + period - 1] - vector[i - 1];
                        sma.push(sum / period);
                    }
                }
                if (callback)
                    return callback(sma);
                else
                    return sma;
            },
            writable: true,
            enumerable: false
        },
        /**
         * Returns a new Vector of the exponential moving average (EMA); weighted means of the previous n data points
         * @param options
         *   Number Length of the observation window for moving average, use default smoothing ratio (2 / period + 1)
         *   or
         *   Object.period Length of the observation window for moving average
         *   Object.ratio Function returning a Number to be used as smoothing ratio
         */
        'ema': {
            value: function(options, callback) {
                // Single numeric argument defining the smoothing period
                if (typeof(options) === 'number') {
                    var length = options;
                    options = {
                        period: length,
                        ratio: function(n) { return 2 / (n + 1); }
                    };
                }
                var sum = new Vector(vector.slice(0, options.period)).sum(),
                    ema = new Vector([sum / options.period]),
                    ratio = options.ratio(options.period);
                for (var i = 1; i < vector.length - options.period + 1; i++) {
                    ema.push(
                        ratio
                        * (vector[i + options.period - 1] - ema[i - 1])
                        + ema[i - 1]
                    );
                }
                if (callback)
                    return callback(ema);
                else
                    return ema;
            },
            writable: true,
            enumerable: false
        },
        /**
         * Apply JavaScript Math methods to an entire Vector set of numbers
         */
        'max': {
            value: function(callback) {
                var max = Math.max.apply({}, vector);
                if (callback)
                    return callback(max);
                else
                    return max;
            },
            writable: true,
            enumerable: false
        },
        'min': {
            value: function(callback) {
                var min = Math.min.apply({}, vector);
                if (callback)
                    return callback(min);
                else
                    return min;
            },
            writable: true,
            enumerable: false
        },
        'abs': {
            value: function(callback) {
                var abs = vector.map(function(x) {
                    return Math.abs(x);
                });
                if (callback)
                    return callback(abs);
                else
                    return abs;
            },
            writable: true,
            enumerable: false
        },
        'acos': {
            value: function(callback) {
                var acos = vector.map(function(x) {
                    return Math.acos(x);
                });
                if (callback)
                    return callback(acos);
                else
                    return acos;
            },
            writable: true,
            enumerable: false
        },
        'asin': {
            value: function(callback) {
                var asin = vector.map(function(x) {
                   return Math.asin(x);
                });
                if (callback)
                    return callback(asin);
                else
                    return asin;
            },
            writable: true,
            enumerable: false
        },
        'atan': {
            value: function(callback) {
                var atan = vector.map(function(x) {
                    return Math.atan(x);
                });
                if (callback)
                    return callback(atan);
                else
                    return atan;
            },
            writable: true,
            enumerable: false
        },
        'ceil': {
            value: function(callback) {
                var ceil = vector.map(function(x) {
                    return Math.ceil(x);
                });
                if (callback)
                    return callback(ceil);
                else
                    return ceil;
            },
            writable: true,
            enumerable: false
        },
        'cos': {
            value: function(callback) {
                var cos = vector.map(function(x) {
                    return Math.cos(x);
                });
                if (callback)
                    return callback(cos);
                else
                    return cos;
            },
            writable: true,
            enumerable: false
        },
        'exp': {
            value: function(callback) {
                var exp = vector.map(function(x) {
                    return Math.exp(x);
                });
                if (callback)
                    return callback(exp);
                else
                    return exp;
            },
            writable: true,
            enumerable: false
        },
        'floor': {
            value: function(callback) {
                var floor = vector.map(function(x) {
                    return Math.floor(x);
                });
                if (callback)
                    return callback(floor);
                else
                    return floor;
            },
            writable: true,
            enumerable: false
        },
        'log': {
            value: function(callback) {
                var log = vector.map(function(x) {
                    return Math.log(x);
                });
                if (callback)
                    return callback(log);
                else
                    return log;
            },
            writable: true,
            enumerable: false
        },
        'pow': {
            value: function(exponent, callback) {
                var pow = vector.map(function(x) {
                    return Math.pow(x, exponent);
                });
                if (callback)
                    return callback(pow);
                else
                    return pow;
            },
            writable: true,
            enumerable: false
        },
        'round': {
            value: function(callback) {
                var round = vector.map(function(x) {
                    return Math.round(x);
                });
                if (callback)
                    return callback(round);
                else
                    return round;
            },
            writable: true,
            enumerable: false
        },
        'sin': {
            value: function(callback) {
                var sin = vector.map(function(x) {
                   return Math.sin(x);
                });
                if (callback)
                    return callback(sin);
                else
                    return sin;
            },
            writable: true,
            enumerable: false
        },
        'sqrt': {
            value: function(callback) {
                var sqrt = vector.map(function(x) {
                    return Math.sqrt(x);
                });
                if (callback)
                    return callback(sqrt);
                else
                    return sqrt;
            },
            writable: true,
            enumerable: false
        },
        'tan': {
            value: function(callback) {
                var tan = vector.map(function(x) {
                    return Math.tan(x);
                });
                if (callback)
                    return callback(tan);
                else
                    return tan;
            },
            writable: true,
            enumerable: false
        },
        /* Returns a clone of the Vector object */
        'clone': {
            value: function(callback) {
                var object = (vector instanceof Array) ? [] : {};
                for (i in vector) {
                    if (i === 'clone') continue;
                    if (vector[i] && typeof vector[i] === 'object') {
                        object[i] = vector[i].clone();
                    } else object[i] = vector[i]
                }
                if (callback)
                    return callback(object);
                else
                    return object;
            },
            writable: true,
            enumerable: false
        },
        /* Returns a copy of the values in a Vector object */
        'copy': {
            value: function(callback) {
                var copy = new Vector(vector.slice());
                if (callback)
                    return callback(copy);
                else
                    return copy;
            },
            writable: true,
            enumerable: false
        },
        /* Returns a vanilla Array of values */
        'array': {
            value: function(callback) {
                var array = Array.prototype.slice.call(vector);
                if (callback)
                    return callback(array);
                else
                    return array;
            },
            writable: true,
            enumerable: false
        },
        /**
         * Override Array methods and add Vector functionality
         */

        /* Mutator methods */

        /* Accessor methods */
        'slice': {
            value: function(begin, end, callback) {
                var args = Array.prototype.slice.call(arguments);
                var slice;
                if (args.length === 3)
                    return callback(new Vector(vector.array().slice(begin, end)));
                else if (args.length === 2) {
                    if (typeof args[1] === 'function')
                        return callback(new Vector(vector.array().slice(begin)));
                    else
                        return new Vector(vector.array().slice(begin, end));
                }
                else if (args.length === 1)
                    return new Vector(vector.array().slice(begin));
                else
                    return new Vector(vector.array().slice());
            },
            writable: true,
            enumerable: false
        },
        /* Iteration methods */
        'filter': {
            value: function(callback, next) {
                var filter = new Vector(vector.array().filter(callback));
                    if (next)
                        return next(filter);
                    else
                        return filter;
            },
            writable: true,
            enumerable: false
        },
        'map': {
            value: function(callback, next) {
                var map = new Vector(vector.array().map(callback));
                if (next)
                    return next(map);
                else
                    return map;
            },
            writable: true,
            enumerable: false
        }
    });

    return vector;
};

exports = module.exports = Vector;
<|endoftext|>