Full Code of osuushi/Smooth.js for AI

master 62233300e50f cached
22 files
36.7 KB
11.8k tokens
1 requests
Download .txt
Repository: osuushi/Smooth.js
Branch: master
Commit: 62233300e50f
Files: 22
Total size: 36.7 KB

Directory structure:
gitextract_dud26c8f/

├── ChangeLog.md
├── Readme.md
├── Smooth.coffee
├── Smooth.js MIT license.txt
├── bower.json
├── sindemo.coffee
└── test/
    ├── specs/
    │   ├── clip-clamp.spec.coffee
    │   ├── clip-mirror.spec.coffee
    │   ├── clip-perodic.spec.coffee
    │   ├── clip-zero.spec.coffee
    │   ├── cubic.spec.coffee
    │   ├── exceptions.spec.coffee
    │   ├── lanczos.spec.coffee
    │   ├── linear.spec.coffee
    │   ├── misc.spec.coffee
    │   ├── nearest.spec.coffee
    │   ├── properties.spec.coffee
    │   ├── scale.spec.coffee
    │   ├── sinc.spec.coffee
    │   ├── util.coffee
    │   └── vector.spec.coffee
    └── tests.sh

================================================
FILE CONTENTS
================================================

================================================
FILE: ChangeLog.md
================================================
#Smooth.js Change Log

This is a log of changes to the library itself. Other changes, like tests, are omitted.

##0.1.7

* Added properties to smoothed functions: `config`, `domain`, `count`, and `dimension`.

* Made code more concise.

##0.1.6

* Fixed bug where `Smooth()` would modify the config object passed to it, rather than working on a copy

##0.1.5

* Lanczos interpolation. See [Lanczos resampling](http://en.wikipedia.org/wiki/Lanczos_resampling).

* Windowed sinc filter interpolation. See [sinc filter](http://en.wikipedia.org/wiki/Sinc_filter). 

* Deep input validation; input arrays are now thoroughly examined when calling `Smooth()`. Disable with 
`Smooth.deepValidation = false`. 

* `scaleTo` with ranges; you can now scale the function's domain to fit to a specific range.


##0.1.3

* New `scaleTo` config option scales the output function's domain.

* Changed enums to string constants. For example, you can use either `Smooth.METHOD_CUBIC` or just `'cubic'`.

##0.1.2

* Fixed tension parameter bug in cubic splines. Catmull-Rom splines are now the default.


##0.1.0

(Initial release)

================================================
FILE: Readme.md
================================================
![Smooth.js](images/logo-white.png)

#### Table of Contents
[        What is this for?](#rm-what)<br/>
[        How do I use it?](#rm-how)<br/>
[                Configuration](#rm-config)<br/>
[                        Interpolation Methods](#rm-method)<br/>
[                        Clipping Modes](#rm-clip)<br/>
[                        Scaling](#rm-scale)<br/>
[                        Validation](#rm-valid)<br/>
[                Interpolating Vectors](#rm-vec)<br/>
[                Function Properties](#rm-prop)<br/>
[        Future Plans](#rm-future)<br/>

<a name = "rm-what" />

# What is this for?

Smooth.js takes an array of numbers or vectors and returns a parametric function that continuously interpolates
that array. Smooth.js supports several interpolation methods, and flexible options for boundary behavior.

Smooth.js is written in clean, easy-to-read CoffeeScript, and has no external dependencies. It is licensed 
under the permissive MIT license, so you can use it in just about any project.

This [demo](http://osuushi.github.com/plotdemo016.html) (requires a modern browser) gives a 
visualization of the interpolation Smooth.js performs.

<a name = "rm-how" />

# How do I use it?

You can compile to javascript from the Smooth.coffee source file, or 
[download the latest compiled release](https://github.com/downloads/osuushi/Smooth.js/Smooth-0.1.7.js)

Smooth.js exposes one public function, `Smooth`. The simplest use case is like this:

```js
var s = Smooth([1, 2, 3, 4]);
console.log(s(1));			// => 2
console.log(s(1.5));		// => 2.5
```

The first line will make `s` a function that interpolates the array [1,2,3,4] as a cubic spline. the second line
will print out index 1 of the array, which is 2. The third line *interpolates* 
halfway between indexes 1 and 2 of the array, yielding 2.5

<a name = "rm-config" />

## Configuration

The `Smooth` function can take an object as an optional second argument which specifies the configuration 
options described below.

<a name = "rm-method" />

### Interpolation Methods

        (For visual illustrations of these interpolation methods see 
[the wiki](https://github.com/osuushi/Smooth.js/wiki/Interpolation-Methods))

The `method` config option specifies the interpolation method. There are three possible values for this 
option:

#### Nearest Neighbor

```js
Smooth.METHOD_NEAREST = 'nearest'
```

This interpolation method is like stair steps. The parameter is simply rounded to the nearest integer and 
that element of the array is returned.

Time complexity to interpolate a point: O(1)

#### Linear

```js
Smooth.METHOD_LINEAR = 'linear'
```

Linear interpolation creates line segments between the input points and interpolates along those segments. 
While smoother than nearest neighbor, this interpolation method produces sharp corners where the parameter is
an integer.

Time complexity to interpolate a point: O(1)

#### Cubic

```js
Smooth.METHOD_CUBIC = 'cubic'
```

This is the default interpolation method, which turns the array into a 
[cubic Hermite spline](http://en.wikipedia.org/wiki/Cubic_Hermite_spline). This method is very smooth and will
not produce sharp corners.

The cubic Hermite spline used by Smooth.js is known as a 
[cardinal spline](http://en.wikipedia.org/wiki/Cubic_hermite_spline#Cardinal_spline). This kind of spline 
allows you to choose a "tension" parameter as the `cubicTension` field of the config object. Two constants are
provided for this value: `Smooth.CUBIC_TENSION_DEFAULT` and `Smooth.CUBIC_TENSION_CATMULL_ROM`, but you can 
use any value between 0 and 1.

`Smooth.CUBIC_TENSION_CATMULL_ROM` produces a 
[Catmull-Rom spline](http://en.wikipedia.org/wiki/Cubic_hermite_spline#Catmull.E2.80.93Rom_spline), which is commonly
used for inbetweening keyframe animations. It is equal to a tension parameter of zero.

`Smooth.CUBIC_TENSION_DEFAULT` is an alias for `CUBIC_TENSION_CATMULL_ROM`.

Time complexity to interpolate a point: O(1)

#### Windowed sinc filter

```js
Smooth.METHOD_SINC = 'sinc'
```

Interpolate by applying a windowed version of the [sinc filter](http://en.wikipedia.org/wiki/Sinc_filter).

You can specify the size of the window with the `sincFilterSize` config parameter. The window will extend by
this value in either direction from the origin. This value must be a positive integer. The default is 2.

You must also provide a window function via the `sincWindow` configuration option. This function should take
one numeric parameter and return a numeric value. For example:

```js
var s = Smooth([1, 2, 3], {
	method: 'sinc',
	sincFilterSize: 2
	sincWindow: function(x) { return Math.exp(-x * x); }
});
```

will create a sinc filter with a Gaussian window function.

The window function is implicitly further multiplied by a rectangular window determined by sincFilterSize, so

```js
	sincWindow: function(x) { return 1; }
```

will create a sinc filter with a simple rectangular window function.

Time complexity to interpolate a point: O(N), where N = `sincFilterSize` (assuming your window function is
O(1))

#### Lanczos

```js
Smooth.METHOD_LANCZOS = 'lanczos'
```

Interpolate via [Lanczos resampling](http://en.wikipedia.org/wiki/Lanczos_resampling). Convolves the input
array by a Lanczos kernel to produce intermediate points.

The size of the Lanczos kernel can be specified via the `lanczosFilterSize` config parameter (default = 2). 
This parameter should be a positive integer.

**Note:** This filter is actually a specific case of the sinc filter. The `lanczosFilterSize` config option
is an alias for `sincFilterSize`, and the Lanczos window function is automatically created for you based on 
this parameter. 

Time complexity to interpolate a point: O(N), where N = `lanczosFilterSize`

<a name = "rm-clip" />

### Clipping modes

In addition to interpolating an array, Smooth.js allows you to specify the behavior of the output function 
when the parameter is outside the array's bounds. This also has an effect on cubic and sinc interpolation when 
interpolating near the array's bounds.

The `clip` config option specifies the clipping mode, and can take the following values:

#### Clamp

```js
Smooth.CLIP_CLAMP = 'clamp'
```

The default clipping mode; the ends of the array are simply repeated to infinity.

#### Zero

```js
Smooth.CLIP_ZERO = 'zero'
```

Outside the array bounds, the value drops to zero.

#### Periodic

```js
Smooth.CLIP_PERIODIC = 'periodic'
```

The whole array repeats infinitely in both directions. This is useful, for example, if you want values for a
looping animation.


#### Mirror

```js
Smooth.CLIP_MIRROR = 'mirror'
```

Repeats the array infinitely in both directions, reflecting each time. For example, if you applied this to 
`[1, 2, 3, 4]` then the result would be `[1, 2, 3, 4, 3, 2, 1, 2, 3, 4...]`. Useful for "loop back and forth" style 
animations, for example.

<a name = "rm-scale" />

### Scaling

The `scaleTo` config option allows you to scale the domain of the function. The default value is 0, which 
tells Smooth.js to leave the domain like the original array, so that for any integer `i`, `s(i) == arr[i]`.

Setting the `scaleTo` option to non-zero will scale the domain to that value. For example:

```js
var s = Smooth([1, 2, 3], { scaleTo: 1 });
console.log(s(0));		// => 1
console.log(s(1 / 2));		// => 2
console.log(s(1));		// => 3
```

You can also provide a range for the `scaleTo` option, as an array of two numbers. This will scale the 
function to fit in that range. For example

```js
var s = Smooth([1, 2, 3], { scaleTo: [10, 12] });
console.log(s(10));		// => 1
console.log(s(12));		// => 2
console.log(s(14));		// => 3
```

When using `Smooth.CLIP_PERIODIC`, the behavior of the `scaleTo` option is slightly different; instead of
scaling to place the end of the array at the value of `scaleTo`, the value is used as the *period* of the
function.

For the sake of readability, the `period` config option is aliased to `scaleTo`. Thus:

```js
var s = Smooth([1, 2, 3], { period: 1, clip:Smooth.CLIP_PERIODIC });
console.log(s(0));		// => 1
console.log(s(1 / 3));		// => 2
console.log(s(2 / 3));		// => 3
console.log(s(1));		// => 1
```

<a name="rm-valid" />

### Validation

By default the input array you pass to `Smooth` will be examined thoroughly to make sure that the input is 
valid, and exceptions will be thrown if any problems are found. This can be a performance consideration if you
are dealing with large amounts of data.

This deep validation behavior can be disabled globally like so:

```js
Smooth.deepValidation = false;
```

This will cause the Smooth function to only validate the first element of each array, and only minimally.


<a name = "rm-vec" />

## Interpolating Vectors

So far all of the example code we've seen has used scalar arrays, but Smooth.js supports interpolation of 
vectors of arbitrary dimension. Simply supply the vectors as arrays. For example, this code:

```js
var points = [
	[0, 1],
	[4, 5],
	[5, 3],
	[2, 0]
];

var path = Smooth(points, {
	method: Smooth.METHOD_CUBIC, 
	clip: Smooth.CLIP_PERIODIC, 
	cubicTension: Smooth.CUBIC_TENSION_CATMULL_ROM
});
```

could be used to create a path function along which to animate a sprite in a loop.

<a name = "rm-prop" />

## Function Properties

The function returned by `Smooth()` has a few properties which provide information about it. **Changing these
properties has no effect on the function.**

`s.config` : a shallow copy of the config object you provided when creating the function. If you did not 
provide a config object, `s.config` will be an empty object. Note that this is a *shallow* copy, so any 
modifications you make to object properties of the config will be reflected by `s.config`, although the 
behavior of `s` itself will not be affected.

`s.domain` : The interval on which the function is defined. Outside of this interval, the function's behavior
is determined by the clipping mode. This property is affected by the `scaleTo` parameter.

`s.count` : The number of elements in the input array.

`s.dimension` : If the input array contains scalar numbers, `s.dimension` will be `'scalar'`. If the input 
array contains vectors, `s.dimension` will be the vector size.

<a name = "rm-future" />

# Future Plans

* Interpolation of non-uniform arrays (objects with arbitrary numeric indexes)
* More interpolation methods
* Custom interpolation methods (maybe)


================================================
FILE: Smooth.coffee
================================================
###
Smooth.js version 0.1.7

Turn arrays into smooth functions.

Copyright 2012 Spencer Cohen
Licensed under MIT license (see "Smooth.js MIT license.txt")

###


###Constants (these are accessible by Smooth.WHATEVER in user space)###
Enum = 
	###Interpolation methods###
	METHOD_NEAREST: 'nearest' #Rounds to nearest whole index
	METHOD_LINEAR: 'linear' 
	METHOD_CUBIC: 'cubic' # Default: cubic interpolation
	METHOD_LANCZOS: 'lanczos'
	METHOD_SINC: 'sinc'

	###Input clipping modes###
	CLIP_CLAMP: 'clamp' # Default: clamp to [0, arr.length-1]
	CLIP_ZERO: 'zero' # When out of bounds, clip to zero
	CLIP_PERIODIC: 'periodic' # Repeat the array infinitely in either direction
	CLIP_MIRROR: 'mirror' # Repeat infinitely in either direction, flipping each time

	### Constants for control over the cubic interpolation tension ###
	CUBIC_TENSION_DEFAULT: 0 # Default tension value
	CUBIC_TENSION_CATMULL_ROM: 0


defaultConfig = 
	method: Enum.METHOD_CUBIC                       #The interpolation method
	
	cubicTension: Enum.CUBIC_TENSION_DEFAULT        #The cubic tension parameter
	
	clip: Enum.CLIP_CLAMP                           #The clipping mode
	
	scaleTo: 0                                      #The scale-to value (0 means don't scale) (can also be a range)
	
	sincFilterSize: 2                               #The size of the sinc filter kernel (must be an integer)

	sincWindow: undefined                           #The window function for the sinc filter

###Index clipping functions###
clipClamp = (i, n) -> Math.max 0, Math.min i, n - 1

clipPeriodic = (i, n) ->
	i = i % n #wrap
	i += n if i < 0 #if negative, wrap back around
	i

clipMirror = (i, n) ->
	period = 2*(n - 1) #period of index mirroring function
	i = clipPeriodic i, period
	i = period - i if i > n - 1 #flip when out of bounds 
	i


###
Abstract scalar interpolation class which provides common functionality for all interpolators

Subclasses must override interpolate().
###

class AbstractInterpolator

	constructor: (array, config) ->
		@array = array.slice 0 #copy the array
		@length = @array.length #cache length

		#Set the clipping helper method
		throw "Invalid clip: #{config.clip}" unless @clipHelper = {
			clamp: @clipHelperClamp
			zero: @clipHelperZero
			periodic: @clipHelperPeriodic
			mirror: @clipHelperMirror
		}[config.clip]


    # Get input array value at i, applying the clipping method
	getClippedInput: (i) ->
		#Normal behavior for indexes within bounds
		if 0 <= i < @length
			@array[i]
		else
			@clipHelper i

	clipHelperClamp: (i) -> @array[clipClamp i, @length]

	clipHelperZero: (i) -> 0

	clipHelperPeriodic: (i) -> @array[clipPeriodic i, @length]

	clipHelperMirror: (i) -> @array[clipMirror i, @length]

	interpolate: (t) -> throw 'Subclasses of AbstractInterpolator must override the interpolate() method.'


#Nearest neighbor interpolator (round to whole index)
class NearestInterpolator extends AbstractInterpolator
	interpolate: (t) -> @getClippedInput Math.round t


#Linear interpolator (first order Bezier)
class LinearInterpolator extends AbstractInterpolator
	interpolate: (t) ->
		k = Math.floor t
		#Translate t to interpolate between k and k+1
		t -= k
		return (1-t)*@getClippedInput(k) + (t)*@getClippedInput(k+1)


class CubicInterpolator extends AbstractInterpolator
	constructor: (array, config)->
		#clamp cubic tension to [0,1] range
		@tangentFactor = 1 - Math.max 0, Math.min 1, config.cubicTension
		super

	# Cardinal spline with tension 0.5)
	getTangent: (k) -> @tangentFactor*(@getClippedInput(k + 1) - @getClippedInput(k - 1))/2

	interpolate: (t) ->
		k = Math.floor t
		m = [(@getTangent k), (@getTangent k+1)] #get tangents
		p = [(@getClippedInput k), (@getClippedInput k+1)] #get points
		#Translate t to interpolate between k and k+1
		t -= k
		t2 = t*t #t^2
		t3 = t*t2 #t^3
		#Apply cubic hermite spline formula
		return (2*t3 - 3*t2 + 1)*p[0] + (t3 - 2*t2 + t)*m[0] + (-2*t3 + 3*t2)*p[1] + (t3 - t2)*m[1]

{sin, PI} = Math
#Normalized sinc function
sinc = (x) -> if x is 0 then 1 else sin(PI*x)/(PI*x)

#Make a lanczos window function for a given filter size 'a'
makeLanczosWindow = (a) -> (x) -> sinc(x/a)

#Make a sinc kernel function by multiplying the sinc function by a window function
makeSincKernel = (window) -> (x) -> sinc(x)*window(x)

class SincFilterInterpolator extends AbstractInterpolator
	constructor: (array, config) ->
		super
		#Create the lanczos kernel function
		@a = config.sincFilterSize

		#Cannot make sinc filter without a window function
		throw 'No sincWindow provided' unless config.sincWindow
		#Window the sinc function to make the kernel
		@kernel = makeSincKernel config.sincWindow

	interpolate: (t) ->
		k = Math.floor t
		#Convolve with Lanczos kernel
		sum = 0
		sum += @kernel(t - n)*@getClippedInput(n) for n in [(k - @a + 1)..(k + @a)]
		sum


#Extract a column from a two dimensional array
getColumn = (arr, i) -> (row[i] for row in arr)


#Take a function with one parameter and apply a scale factor to its parameter
makeScaledFunction = (f, baseScale, scaleRange) ->
	if scaleRange.join is '0,1'
		f #don't wrap the function unecessarily
	else 
		scaleFactor = baseScale/(scaleRange[1] - scaleRange[0])
		translation = scaleRange[0]
		(t) -> f scaleFactor*(t - translation)


getType = (x) -> Object::toString.call(x)[('[object '.length)...-1]

#Throw exception if input is not a number
validateNumber = (n) ->
	throw 'NaN in Smooth() input' if isNaN n
	throw 'Non-number in Smooth() input' unless getType(n) is 'Number'
	throw 'Infinity in Smooth() input' unless isFinite n
		

#Throw an exception if input is not a vector of numbers which is the correct length
validateVector = (v, dimension) ->
	throw 'Non-vector in Smooth() input' unless getType(v) is 'Array'
	throw 'Inconsistent dimension in Smooth() input' unless v.length is dimension
	validateNumber n for n in v
	return

isValidNumber = (n) -> (getType(n) is 'Number') and isFinite(n) and not isNaN(n)

normalizeScaleTo = (s) ->
	invalidErr = "scaleTo param must be number or array of two numbers"
	switch getType s
		when 'Number'
			throw invalidErr unless isValidNumber s
			s = [0, s]
		when 'Array'
			throw invalidErr unless s.length is 2
			throw invalidErr unless isValidNumber(s[0]) and isValidNumber(s[1])
		else throw invalidErr
	return s

shallowCopy = (obj) ->
	copy = {}
	copy[k] = v for own k,v of obj
	copy

Smooth = (arr, config = {}) ->
	#Properties to copy to the function once it is created
	properties = {}
	#Make a copy of the config object to modify
	config = shallowCopy config

	#Make another copy of the config object to save to the function
	properties.config = shallowCopy config

	#Alias 'period' to 'scaleTo'
	config.scaleTo ?= config.period

	#Alias lanczosFilterSize to sincFilterSize
	config.sincFilterSize ?= config.lanczosFilterSize

	config[k] ?= v for own k,v of defaultConfig #fill in defaults

	#Get the interpolator class according to the configuration
	throw "Invalid method: #{config.method}" unless interpolatorClass = {
			nearest: NearestInterpolator
			linear: LinearInterpolator
			cubic: CubicInterpolator
			lanczos: SincFilterInterpolator #lanczos is a specific case of sinc filter
			sinc: SincFilterInterpolator
	}[config.method]

	if config.method is 'lanczos'
		#Setup lanczos window
		config.sincWindow = makeLanczosWindow config.sincFilterSize


	#Make sure there's at least one element in the input array
	throw 'Array must have at least two elements' if arr.length < 2

	#save count property
	properties.count = arr.length

	#See what type of data we're dealing with

	smoothFunc = switch getType arr[0]
			when 'Number' #scalar
				properties.dimension = 'scalar'
				#Validate all input if deep validation is on
				validateNumber n for n in arr if Smooth.deepValidation
				#Create the interpolator
				interpolator = new interpolatorClass arr, config
				#make function that runs the interpolator
				(t) -> interpolator.interpolate t

			when 'Array' # vector
				properties.dimension = dimension = arr[0].length
				throw 'Vectors must be non-empty' unless dimension
				#Validate all input if deep validation is on
				validateVector v, dimension for v in arr if Smooth.deepValidation
				#Create interpolator for each column
				interpolators = (new interpolatorClass(getColumn(arr, i), config) for i in [0...dimension])
				#make function that runs the interpolators and puts them into an array
				(t) -> (interpolator.interpolate(t) for interpolator in interpolators)

			else throw "Invalid element type: #{getType arr[0]}"

	# Determine the end of the original function's domain
	if config.clip is 'periodic' then baseDomainEnd = arr.length #after last element for periodic
	else baseDomainEnd = arr.length - 1 #at last element for non-periodic

	config.scaleTo ||= baseDomainEnd #default scales to the end of the original domain for no effect
	
	properties.domain = normalizeScaleTo config.scaleTo
	smoothFunc = makeScaledFunction smoothFunc, baseDomainEnd, properties.domain
	properties.domain.sort()

	###copy properties###
	smoothFunc[k] = v for own k,v of properties

	return smoothFunc

#Copy enums to Smooth
Smooth[k] = v for own k,v of Enum

Smooth.deepValidation = true

(exports ? window).Smooth = Smooth


================================================
FILE: Smooth.js MIT license.txt
================================================
Smooth.js Copyright (c) 2012 Spencer Cohen

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without restriction, including without
limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
Software, and to permit persons to whom the Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions
of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.


================================================
FILE: bower.json
================================================
{
  "name": "smooth.js",
  "homepage": "https://github.com/osuushi/Smooth.js",
  "authors": [
    "yournamehere <someone@somewhere.com>"
  ],
  "description": "Smooth.js is an array interpolation library for Javascript",
  "main": "",
  "moduleType": [],
  "keywords": [
    "interpolation",
    "javascript",
    "smoothjs"
  ],
  "license": "MIT",
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components",
    "test",
    "tests"
  ]
}


================================================
FILE: sindemo.coffee
================================================
###
sindemo

Sample and cubic interpolate the sin function, then print out max and average error.
###

{Smooth} = require './Smooth'

s = (Math.sin 2*Math.PI*x for x in [0...1] by 1/8)


#Scale the function
smooth_sin = ((f) ->
	scaleVal = 0.5*s.length/Math.PI
	return (x) -> f x*scaleVal
) Smooth s, method:Smooth.METHOD_CUBIC, clip:Smooth.CLIP_PERIODIC

totalError = 0
count = 0
maxError = 0
for x in [-10..10] by .001
	error = Math.abs Math.sin(x) - smooth_sin(x)
	maxError = Math.max error, maxError
	totalError += error
	count++

console.log "Max Error:\t #{(100*maxError).toFixed(10)}%"
console.log "Average Error:\t #{(100*totalError/count).toFixed(10)}%"

================================================
FILE: test/specs/clip-clamp.spec.coffee
================================================
{Smooth} = require '../../Smooth.coffee'

describe "Clip Clamp", ->
	arr = [1,2,3,4]
	len = arr.length
	s = Smooth arr, clip:Smooth.CLIP_CLAMP

	it 'should extend first value to negative infinity', ->
		expect(s -1).toEqual arr[0]
		expect(s -5.8).toEqual arr[0]
		expect(s -100.3).toEqual arr[0]

	it 'should extend last value to positive infinity', ->
		expect(s len+1).toEqual arr[len-1]
		expect(s len+12.2).toEqual arr[len-1]
		expect(s len+1000).toEqual arr[len-1]

	it 'should leave in-bounds values untouched', ->
		expect(s 0).toEqual arr[0]
		expect(s 1).toEqual arr[1]
		expect(s 2).toEqual arr[2]

================================================
FILE: test/specs/clip-mirror.spec.coffee
================================================
{Smooth} = require '../../Smooth.coffee'

describe "Clip Mirror", ->
	arr = [1,2,3,4]
	len = arr.length
	s = Smooth arr, clip:Smooth.CLIP_MIRROR

	it 'should reflect across the origin', ->
		expect(s -1).toEqual arr[1]
		expect(s -2).toEqual arr[2]
		expect(s -3).toEqual arr[3]
	
	it 'should produce a predictable pattern', ->
		mirrorArray = arr.concat (arr[i] for i in [len-2...0]) #create pattern to repeat
		expect( (s i for i in [0...20]).join() )
			.toBe (mirrorArray[i%mirrorArray.length] for i in [0...20]).join()


	it 'should leave in-bounds values untouched', ->
		expect(s 0).toEqual arr[0]
		expect(s 1).toEqual arr[1]
		expect(s 3).toEqual arr[3]

================================================
FILE: test/specs/clip-perodic.spec.coffee
================================================
{Smooth} = require '../../Smooth.coffee'

describe "Clip Periodic", ->
	arr = [1,2,3,4]
	len = arr.length
	s = Smooth arr, clip:Smooth.CLIP_PERIODIC

	it 'should repeat the same value for a shift by any integer multiple of the array length', ->
		expect(s 0 - 98*len).toEqual arr[0]
		expect(s 1 + 12*len).toEqual arr[1]
		expect(s 2 - 13*len).toEqual arr[2]
		expect(s 3 + 47*len).toEqual arr[3]

	it 'should leave in-bounds values untouched', ->
		expect(s 0).toEqual arr[0]
		expect(s 1).toEqual arr[1]
		expect(s 3).toEqual arr[3]

================================================
FILE: test/specs/clip-zero.spec.coffee
================================================
{Smooth} = require '../../Smooth.coffee'

describe "Clip Zero", ->
	arr = [1,2,3,4]
	len = arr.length
	s = Smooth arr, clip:Smooth.CLIP_ZERO

	it 'should be zero when out of bounds', ->
		expect(s -1).toEqual 0
		expect(s -100.3).toEqual 0
		expect(s len+1).toEqual 0
		expect(s len+12.2).toEqual 0
		expect(s len+1000).toEqual 0

	it 'should leave in-bounds values untouched', ->
		expect(s 0).toEqual arr[0]
		expect(s 1).toEqual arr[1]
		expect(s 2).toEqual arr[2]

================================================
FILE: test/specs/cubic.spec.coffee
================================================
{Smooth} = require '../../Smooth.coffee'

{deriv} = require './util.coffee'


describe 'Cubic Interpolator', ->
	describe 'Catmull-Rom', ->
		arr = [4,6,-2,3]
		s = Smooth arr, method:Smooth.METHOD_CUBIC, cubicTension: Smooth.CATMULL_ROM

		it 'should match integer indexes', ->
			expect(s 0).toEqual arr[0]
			expect(s 1).toEqual arr[1]
			expect(s 2).toEqual arr[2]
			expect(s 3).toEqual arr[3]

		it 'should have neighbor-slope tangent at integers', ->
			expect(deriv(s) 1).toBeCloseTo (arr[2]-arr[0])/2
			expect(deriv(s) 2).toBeCloseTo (arr[3]-arr[1])/2

		it 'should repeat when periodic', ->
		p = Smooth arr, method:'cubic', cubicTension: Smooth.CATMULL_ROM, clip:'periodic', scaleTo: 1
		for i in [-2..2] by 1/16
			expect(p i).toEqual p i - Math.floor i

	describe 'Tension=1', ->
		arr = [8,2,-4,9]
		s = Smooth arr, method:Smooth.METHOD_CUBIC, cubicTension: 1


		it 'should match integer indexes', ->
			expect(s 0).toEqual arr[0]
			expect(s 1).toEqual arr[1]
			expect(s 2).toEqual arr[2]
			expect(s 3).toEqual arr[3]

		it 'should have zero derivatives at integers', ->
			expect(deriv(s) 0).toBeCloseTo 0
			expect(deriv(s) 1).toBeCloseTo 0
			expect(deriv(s) 2).toBeCloseTo 0
			expect(deriv(s) 3).toBeCloseTo 0

================================================
FILE: test/specs/exceptions.spec.coffee
================================================
{Smooth} = require '../../Smooth.coffee'

describe 'Exceptions', ->
	it 'should throw for invalid methods', ->
		expect(-> Smooth [1,2], method: 'lanscoz').toThrow "Invalid method: lanscoz"
		expect(-> Smooth [1,2], method: 'Cubic').toThrow "Invalid method: Cubic"

	it 'should throw for invalid clipping mode', ->
		expect(-> Smooth [1,2], clip: 'mirorr').toThrow "Invalid clip: mirorr"
		expect(-> Smooth [1,2], clip: 'Linear').toThrow "Invalid clip: Linear"

	it 'should throw for invalid arrays', ->
		expect(-> Smooth []).toThrow 'Array must have at least two elements'
		expect(-> Smooth [0]).toThrow 'Array must have at least two elements'

	it 'should throw for bad input', ->
		expect(-> Smooth ['a','b']).toThrow 'Invalid element type: String'
		expect(-> Smooth [(->), (->)]).toThrow 'Invalid element type: Function'
		expect(-> Smooth [[], []]).toThrow 'Vectors must be non-empty'

	it 'should throw for sinc filter with no window', ->
		expect(-> Smooth [1,2], method:'sinc').toThrow 'No sincWindow provided'

	it 'should throw for invalid scaleTo', ->
		expect(-> Smooth [1,2], scaleTo:[1]).toThrow 'scaleTo param must be number or array of two numbers'
		expect(-> Smooth [1,2], scaleTo:[1,2,3]).toThrow 'scaleTo param must be number or array of two numbers'
		expect(-> Smooth [1,2], scaleTo:'a').toThrow 'scaleTo param must be number or array of two numbers'
		expect(-> Smooth [1,2], scaleTo:[1,'x']).toThrow 'scaleTo param must be number or array of two numbers'
		expect(-> Smooth [1,2], scaleTo:Infinity).toThrow 'scaleTo param must be number or array of two numbers'

	describe 'With deep validation on...', ->
		it 'should throw for bad input deep inside the input', ->
			Smooth.deepValidation = true
			expect(-> Smooth [1,2,'a']).toThrow 'NaN in Smooth() input'
			expect(-> Smooth [1,2,'3']).toThrow 'Non-number in Smooth() input'
			expect(-> Smooth [1,2, Infinity]).toThrow 'Infinity in Smooth() input'

			expect(-> Smooth [[1],[2],['a']]).toThrow 'NaN in Smooth() input'
			expect(-> Smooth [[1],[2],['3']]).toThrow 'Non-number in Smooth() input'
			expect(-> Smooth [[1],[2], [Infinity]]).toThrow 'Infinity in Smooth() input'

			expect(-> Smooth [[1], 1]).toThrow 'Non-vector in Smooth() input'
			expect(-> Smooth [[1], [1,2]]).toThrow 'Inconsistent dimension in Smooth() input'

	describe 'With deep validation off...', ->
		it 'should not throw for bad input deep inside the input', ->
			Smooth.deepValidation = false
			expect(Smooth [1,2,'a']).toBeTruthy()
			expect(Smooth [1,2,'3']).toBeTruthy()
			expect(Smooth [1,2, Infinity]).toBeTruthy()

			expect(Smooth [[1],[2],['a']]).toBeTruthy()
			expect(Smooth [[1],[2],['3']]).toBeTruthy()
			expect(Smooth [[1],[2], [Infinity]]).toBeTruthy()

			expect(Smooth [[1], 1]).toBeTruthy()
			expect(Smooth [[1], [1,2]]).toBeTruthy()



================================================
FILE: test/specs/lanczos.spec.coffee
================================================
{Smooth} = require '../../Smooth.coffee'

{deriv} = require './util.coffee'

describe 'Lanczos Interpolator', ->
	arr = [1,3,-2,8]
	s = Smooth arr, method: 'lanczos'

	it 'should be close to array at integer indexes', ->
		for i in [0...arr.length]
			expect(s i).toBeCloseTo arr[i]

	it 'should be continuous everywhere', ->
		delta = 0.00001
		for i in [-1..arr.length] by 1/64
			expect(s i).toBeCloseTo s(i-delta), 0

	it 'should be differentiable everywhere', ->
		delta = 0.00001
		ds = deriv s
		for i in [-1..arr.length] by 1/64
			expect(ds i).toBeCloseTo ds(i-delta), 0

	it 'should repeat when periodic', ->
		p = Smooth arr, method:'lanczos', clip: 'periodic', scaleTo: 1
		for i in [-2..2] by 1/16
			expect(p i).toEqual p i - Math.floor i

================================================
FILE: test/specs/linear.spec.coffee
================================================
{Smooth} = require '../../Smooth.coffee'

{deriv} = require './util.coffee'


describe 'Linear Interpolator', ->
	arr = [1,4,3,8]
	s = Smooth arr, method:Smooth.METHOD_LINEAR

	it 'should match integer indexes', ->
		expect(s 0).toEqual arr[0]
		expect(s 1).toEqual arr[1]
		expect(s 2).toEqual arr[2]
		expect(s 3).toEqual arr[3]

	it 'should have arithmetic mean for midpoints', ->
		expect(s 0.5).toBeCloseTo (arr[0]+arr[1])/2
		expect(s 1.5).toBeCloseTo (arr[1]+arr[2])/2
		expect(s 2.5).toBeCloseTo (arr[2]+arr[3])/2

	it 'should have derivatives equal to point differences', ->
		expect(deriv(s) 0.2).toBeCloseTo arr[1] - arr[0]
		expect(deriv(s) 0.8).toBeCloseTo arr[1] - arr[0]
		expect(deriv(s) 1.4).toBeCloseTo arr[2] - arr[1]
		expect(deriv(s) 2.7).toBeCloseTo arr[3] - arr[2]

	it 'should repeat when periodic', ->
		p = Smooth arr, method:'linear', clip: 'periodic', scaleTo: 1
		for i in [-2..2] by 1/16
			expect(p i).toEqual p i - Math.floor i

================================================
FILE: test/specs/misc.spec.coffee
================================================
{Smooth} = require '../../Smooth.coffee'
util = require './util'

describe "Misc...", ->
	it 'should not modify the original config object', ->
		config = lanczosFilterSize: 2
		configCopy = util.shallowCopy config
		s = Smooth [1,2,3], config
		#check object equality
		expect(config).toEqual configCopy



================================================
FILE: test/specs/nearest.spec.coffee
================================================
{Smooth} = require '../../Smooth.coffee'

{deriv} = require './util.coffee'

describe 'Nearest Neighbor Interpolator', ->
	arr = [1,2,3,4]
	s = Smooth arr, method:Smooth.METHOD_NEAREST

	it 'should match integer indexes', ->
		expect(s 0).toEqual arr[0]
		expect(s 1).toEqual arr[1]
		expect(s 2).toEqual arr[2]
		expect(s 3).toEqual arr[3]

	it 'should round fractional parameter', ->
		expect(s 0.1).toEqual arr[0]
		expect(s 1.9).toEqual arr[2]
		expect(s 2.2).toEqual arr[2]
		expect(s 2.8).toEqual arr[3]
	
	it 'should have zero derivatives where fraction != .5', ->
		expect(deriv(s) 1).toBeCloseTo 0
		expect(deriv(s) 1.1).toBeCloseTo 0
		expect(deriv(s) 1.9).toBeCloseTo 0
		expect(deriv(s) 3.2).toBeCloseTo 0

	it 'should repeat when periodic', ->
		p = Smooth arr, method:'nearest', clip: 'periodic', scaleTo: 1
		for i in [-2..2] by 1/16
			expect(p i).toEqual p i - Math.floor i


================================================
FILE: test/specs/properties.spec.coffee
================================================
{Smooth} = require '../../Smooth.coffee'
util = require './util'

describe "Smooth function properties...", ->
	it 'should save a shallow copy of the config passed in by the user', ->
		config = cubicTension: 1, method: 'cubic', clip: 'zero'
		s = Smooth [1,2,3], config
		expect(s.config).toEqual config

	it 'should save the domain correctly', ->
		expect((Smooth [1,1,1]).domain).toEqual [0, 2]
		expect((Smooth [1,1,1,1], clip:'periodic').domain).toEqual [0, 4]
		expect((Smooth [1,1,1], scaleTo:2).domain).toEqual [0, 2]
		expect((Smooth [1,1,1], scaleTo:[1,5]).domain).toEqual [1, 5]
		expect((Smooth [1,1,1], clip:'periodic', scaleTo:[1,5]).domain).toEqual [1, 5]
		expect((Smooth [1,1,1], scaleTo:[5,1]).domain).toEqual [1, 5]

	it 'should save the count correctly', ->
		expect(Smooth([1,1,3]).count).toBe 3
		expect(Smooth([1,2,3], scaleTo:5).count).toBe 3
	
	it 'should save the dimension correctly', ->
		expect(Smooth([1,2,3]).dimension).toBe 'scalar'
		expect(Smooth([[1],[2],[3]]).dimension).toBe 1
		expect(Smooth([[1,2],[2,3],[3,4]]).dimension).toBe 2


================================================
FILE: test/specs/scale.spec.coffee
================================================
{Smooth} = require '../../Smooth.coffee'

describe "Scale to...", ->
	arr = [1,2,3,4]

	it 'should scale to [0,1]', ->
		s = Smooth arr, scaleTo: 1
		expect(s 0).toBeCloseTo arr[0]
		expect(s 1/3).toBeCloseTo arr[1]
		expect(s 2/3).toBeCloseTo arr[2]
		expect(s 1).toBeCloseTo arr[3]

	it 'should scale to [0, length-1] with no change from unscaled', ->
		s_noscale = Smooth arr
		s_scale = Smooth arr, scaleTo: arr.length-1

		expect(s_scale 0).toBeCloseTo s_noscale 0
		expect(s_scale 2).toBeCloseTo s_noscale 2
		expect(s_scale 2.5).toBeCloseTo s_noscale 2.5
		expect(s_scale 3).toBeCloseTo s_noscale 3

	it 'should scale to [0, 9]', ->
		s = Smooth arr, scaleTo: 9
		expect(s 0).toBeCloseTo arr[0]
		expect(s 3).toBeCloseTo arr[1]
		expect(s 6).toBeCloseTo arr[2]
		expect(s 9).toBeCloseTo arr[3]

	it 'should reflect when scaling to -(length-1)', ->
		s = Smooth arr, scaleTo: -(arr.length - 1)
		expect(s 0).toBeCloseTo arr[0]
		expect(s -1).toBeCloseTo arr[1]
		expect(s -2).toBeCloseTo arr[2]
		expect(s -3).toBeCloseTo arr[3]

	it 'should scale to the next cycle for periodic functions', ->
		s = Smooth arr, scaleTo: 1, clip:Smooth.CLIP_PERIODIC
		expect(s 0).toBeCloseTo s 1
		expect(s 0.5).toBeCloseTo s 2.5
		expect(s 3.8).toBeCloseTo s -9.2

	describe 'range scaling', ->
		it 'should scale to [-1, 1]', ->
			s = Smooth arr, scaleTo: [-1, 1]
			expect(s -1).toBeCloseTo arr[0]
			expect(s -1/3).toBeCloseTo arr[1]
			expect(s 1/3).toBeCloseTo arr[2]
			expect(s 1).toBeCloseTo arr[3]

		it 'should scale periodic to [0.5, 1.5]', ->
			s = Smooth arr, scaleTo: [0.5, 1.5], clip:'periodic'
			expect(s 0).toBeCloseTo s 1
			expect(s 0.5).toBeCloseTo s 2.5
			expect(s 3.8).toBeCloseTo s -9.2




================================================
FILE: test/specs/sinc.spec.coffee
================================================
{Smooth} = require '../../Smooth.coffee'

{deriv} = require './util.coffee'

describe 'Sinc Filter Interpolator', ->
	arr = [1,3,-2,8]
	describe 'Gaussian window', ->
		s = Smooth arr, method: 'sinc', sincWindow: (x) -> Math.exp -x*x

		it 'should be close to array at integer indexes', ->
			for i in [0...arr.length]
				expect(s i).toBeCloseTo arr[i]

		it 'should be continuous everywhere', ->
			delta = 0.00001
			for i in [-1..arr.length] by 1/64
				expect(s i).toBeCloseTo s(i-delta), 0

		it 'should be differentiable everywhere', ->
			delta = 0.00001
			ds = deriv s
			for i in [-1..arr.length] by 1/64
				expect(ds i).toBeCloseTo ds(i-delta), 0

		it 'should repeat when periodic', ->
			p = Smooth arr, method: 'sinc', scaleTo: 1, clip: 'periodic', sincWindow: (x) -> Math.exp -x*x
			for i in [-2..2] by 1/16
				expect(p i).toEqual p i - Math.floor i

	describe 'Circular window', ->
		s = Smooth arr, method: 'sinc', sincWindow: (x) -> Math.sqrt(1 - x*x/4)

		it 'should be close to array at integer indexes', ->
			for i in [0...arr.length]
				expect(s i).toBeCloseTo arr[i]

		it 'should be continuous everywhere', ->
			delta = 0.00001
			for i in [-1..arr.length] by 1/64
				expect(s i).toBeCloseTo s(i-delta), 0

		it 'should be differentiable everywhere', ->
			delta = 0.00001
			ds = deriv s
			for i in [-1..arr.length] by 1/64
				expect(ds i).toBeCloseTo ds(i-delta), 0

		it 'should repeat when periodic', ->
			p = Smooth arr, method: 'sinc', scaleTo: 1, clip: 'periodic', sincWindow: (x) -> Math.sqrt(1 - x*x/4)
			for i in [-2..2] by 1/16
				expect(p i).toEqual p i - Math.floor i



================================================
FILE: test/specs/util.coffee
================================================
### Helper code for tests ###


#Approximate derivative function with some delta value
exports.deriv = (f, delta = 0.0001) -> 
	(t) -> ((f t+delta) - (f t))/delta

exports.distance = (a, b) ->
	sqDist = 0
	l = a.length
	sqDist += Math.pow a[i]-b[i], 2 for i in [0...l]
	return Math.sqrt sqDist


exports.shallowCopy = (obj) ->
	copy = {}
	copy[k] = v for own k,v of obj
	copy


================================================
FILE: test/specs/vector.spec.coffee
================================================
{Smooth} = require '../../Smooth.coffee'

{distance} = require './util.coffee'

describe 'Vector', ->
	it 'should approximate a unit circle', ->
		{sin, cos, PI} = Math
		circle_points = ([cos(PI*t), sin(PI*t)] for t in [0...2] by 1/6)
		#Make into a function
		circle = Smooth circle_points, period:1, clip:Smooth.CLIP_PERIODIC

		#Integrate arc length
		l = 0
		start = [1,0]
		for t in [0..1] by .0001
			end = circle t
			l += distance start, end
			start = end

		#Result length should be approximately 2*pi
		expect(l).toBeCloseTo 2*Math.PI



================================================
FILE: test/tests.sh
================================================
#!/usr/bin/env bash

# (requires jasmine-node)

jasmine-node --coffee --verbose `dirname $0`/specs
Download .txt
gitextract_dud26c8f/

├── ChangeLog.md
├── Readme.md
├── Smooth.coffee
├── Smooth.js MIT license.txt
├── bower.json
├── sindemo.coffee
└── test/
    ├── specs/
    │   ├── clip-clamp.spec.coffee
    │   ├── clip-mirror.spec.coffee
    │   ├── clip-perodic.spec.coffee
    │   ├── clip-zero.spec.coffee
    │   ├── cubic.spec.coffee
    │   ├── exceptions.spec.coffee
    │   ├── lanczos.spec.coffee
    │   ├── linear.spec.coffee
    │   ├── misc.spec.coffee
    │   ├── nearest.spec.coffee
    │   ├── properties.spec.coffee
    │   ├── scale.spec.coffee
    │   ├── sinc.spec.coffee
    │   ├── util.coffee
    │   └── vector.spec.coffee
    └── tests.sh
Condensed preview — 22 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (41K chars).
[
  {
    "path": "ChangeLog.md",
    "chars": 1111,
    "preview": "#Smooth.js Change Log\n\nThis is a log of changes to the library itself. Other changes, like tests, are omitted.\n\n##0.1.7\n"
  },
  {
    "path": "Readme.md",
    "chars": 10414,
    "preview": "![Smooth.js](images/logo-white.png)\n\n#### Table of Contents\n[        What is this for?](#rm-what)<br/>\n[        How do I"
  },
  {
    "path": "Smooth.coffee",
    "chars": 9243,
    "preview": "###\nSmooth.js version 0.1.7\n\nTurn arrays into smooth functions.\n\nCopyright 2012 Spencer Cohen\nLicensed under MIT license"
  },
  {
    "path": "Smooth.js MIT license.txt",
    "chars": 1067,
    "preview": "Smooth.js Copyright (c) 2012 Spencer Cohen\n\nPermission is hereby granted, free of charge, to any person obtaining a copy"
  },
  {
    "path": "bower.json",
    "chars": 451,
    "preview": "{\n  \"name\": \"smooth.js\",\n  \"homepage\": \"https://github.com/osuushi/Smooth.js\",\n  \"authors\": [\n    \"yournamehere <someone"
  },
  {
    "path": "sindemo.coffee",
    "chars": 662,
    "preview": "###\nsindemo\n\nSample and cubic interpolate the sin function, then print out max and average error.\n###\n\n{Smooth} = requir"
  },
  {
    "path": "test/specs/clip-clamp.spec.coffee",
    "chars": 608,
    "preview": "{Smooth} = require '../../Smooth.coffee'\n\ndescribe \"Clip Clamp\", ->\n\tarr = [1,2,3,4]\n\tlen = arr.length\n\ts = Smooth arr, "
  },
  {
    "path": "test/specs/clip-mirror.spec.coffee",
    "chars": 662,
    "preview": "{Smooth} = require '../../Smooth.coffee'\n\ndescribe \"Clip Mirror\", ->\n\tarr = [1,2,3,4]\n\tlen = arr.length\n\ts = Smooth arr,"
  },
  {
    "path": "test/specs/clip-perodic.spec.coffee",
    "chars": 534,
    "preview": "{Smooth} = require '../../Smooth.coffee'\n\ndescribe \"Clip Periodic\", ->\n\tarr = [1,2,3,4]\n\tlen = arr.length\n\ts = Smooth ar"
  },
  {
    "path": "test/specs/clip-zero.spec.coffee",
    "chars": 467,
    "preview": "{Smooth} = require '../../Smooth.coffee'\n\ndescribe \"Clip Zero\", ->\n\tarr = [1,2,3,4]\n\tlen = arr.length\n\ts = Smooth arr, c"
  },
  {
    "path": "test/specs/cubic.spec.coffee",
    "chars": 1233,
    "preview": "{Smooth} = require '../../Smooth.coffee'\n\n{deriv} = require './util.coffee'\n\n\ndescribe 'Cubic Interpolator', ->\n\tdescrib"
  },
  {
    "path": "test/specs/exceptions.spec.coffee",
    "chars": 2818,
    "preview": "{Smooth} = require '../../Smooth.coffee'\n\ndescribe 'Exceptions', ->\n\tit 'should throw for invalid methods', ->\n\t\texpect("
  },
  {
    "path": "test/specs/lanczos.spec.coffee",
    "chars": 752,
    "preview": "{Smooth} = require '../../Smooth.coffee'\n\n{deriv} = require './util.coffee'\n\ndescribe 'Lanczos Interpolator', ->\n\tarr = "
  },
  {
    "path": "test/specs/linear.spec.coffee",
    "chars": 959,
    "preview": "{Smooth} = require '../../Smooth.coffee'\n\n{deriv} = require './util.coffee'\n\n\ndescribe 'Linear Interpolator', ->\n\tarr = "
  },
  {
    "path": "test/specs/misc.spec.coffee",
    "chars": 306,
    "preview": "{Smooth} = require '../../Smooth.coffee'\nutil = require './util'\n\ndescribe \"Misc...\", ->\n\tit 'should not modify the orig"
  },
  {
    "path": "test/specs/nearest.spec.coffee",
    "chars": 891,
    "preview": "{Smooth} = require '../../Smooth.coffee'\n\n{deriv} = require './util.coffee'\n\ndescribe 'Nearest Neighbor Interpolator', -"
  },
  {
    "path": "test/specs/properties.spec.coffee",
    "chars": 1069,
    "preview": "{Smooth} = require '../../Smooth.coffee'\nutil = require './util'\n\ndescribe \"Smooth function properties...\", ->\n\tit 'shou"
  },
  {
    "path": "test/specs/scale.spec.coffee",
    "chars": 1707,
    "preview": "{Smooth} = require '../../Smooth.coffee'\n\ndescribe \"Scale to...\", ->\n\tarr = [1,2,3,4]\n\n\tit 'should scale to [0,1]', ->\n\t"
  },
  {
    "path": "test/specs/sinc.spec.coffee",
    "chars": 1619,
    "preview": "{Smooth} = require '../../Smooth.coffee'\n\n{deriv} = require './util.coffee'\n\ndescribe 'Sinc Filter Interpolator', ->\n\tar"
  },
  {
    "path": "test/specs/util.coffee",
    "chars": 376,
    "preview": "### Helper code for tests ###\n\n\n#Approximate derivative function with some delta value\nexports.deriv = (f, delta = 0.000"
  },
  {
    "path": "test/specs/vector.spec.coffee",
    "chars": 548,
    "preview": "{Smooth} = require '../../Smooth.coffee'\n\n{distance} = require './util.coffee'\n\ndescribe 'Vector', ->\n\tit 'should approx"
  },
  {
    "path": "test/tests.sh",
    "chars": 99,
    "preview": "#!/usr/bin/env bash\n\n# (requires jasmine-node)\n\njasmine-node --coffee --verbose `dirname $0`/specs\n"
  }
]

About this extraction

This page contains the full source code of the osuushi/Smooth.js GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 22 files (36.7 KB), approximately 11.8k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!