docs: function mprod( arr, W, clbk ) {
  	var len,
  		out,
  		val,
  		p,
  		i, j;
  	if ( !isArray( arr ) ) {
  		throw new TypeError( 'mprod()::invalid input argument. Must provide an array. Value: `' + arr + '`.' );
  	}
  	len = arr.length;
  	if ( !isPositiveInteger( W ) ) {
  		throw new TypeError( 'mprod()::invalid input argument. Window must be a positive integer. Value: `' + W + '`.' );
  	}
  	if ( W > len ) {
  		throw new Error( 'mprod()::invalid input argument. Window cannot exceed the array length.' );
  	}
  	if ( arguments.length > 2 ) {
  		if ( typeof clbk !== 'function' ) {
  			throw new TypeError( 'mprod()::invalid input argument. Accessor must be a function. Value: `' + clbk + '`.' );
  		}
  	}
  	len = len - W + 1;
  	out = new Array( len );
  
  	// NOTE: unlike sum, mean, and other moving calculations, a simple in-place update procedure is hard to come by. Instead, the straightforward solution of two FOR loops is used. While possibly not optimal, this solution requires fewer conditionals and is arguably easier to maintain.
  	if ( clbk ) {
  		for ( i = 0; i < len; i++ ) {
  			p = 1;
  			for ( j = i; j < i+W; j++ ) {
  				val = clbk( arr[ j ] );
  				if ( val === 0 ) {
  					p = 0;
  					break;
  				}
  				p *= val;
  			}
  			out[ i ] = p;
  		}
  	} else {
  		for ( i = 0; i < len; i++ ) {
  			p = 1;
  			for ( j = i; j < i+W; j++ ) {
  				val = arr[ j ];
  				if ( val === 0 ) {
  					p = 0;
  					break;
  				}
  				p *= val;
  			}
  			out[ i ] = p;
  		}
  	}
  	return out;
  }