Compare commits
7 Commits
Author | SHA1 | Date |
---|---|---|
Alan K | f331092772 | |
Alan K | cda0babfd7 | |
Alan K | 9baf9438ce | |
Alan K | 6ba5c99396 | |
Alan K | 7f8fb90c29 | |
Alan K | c2e9b38159 | |
Alan K | 15c5eac309 |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
After Width: | Height: | Size: 78 B |
Binary file not shown.
After Width: | Height: | Size: 463 B |
Binary file not shown.
After Width: | Height: | Size: 216 B |
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1 @@
|
|||
console.log('This would be the main JS file.');
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
<body>
|
||||
<progress id="progress" value=0></progress>
|
||||
<div id="output"></div>
|
||||
<div id="stderr"></div>
|
||||
</body>
|
||||
<script type="text/javascript" src="simple-statistics/src/simple_statistics.js"></script>
|
||||
<script src="../dist/filer-perf.js"></script>
|
||||
</html>
|
|
@ -0,0 +1,120 @@
|
|||
var Filer = require('..');
|
||||
var util = require('../tests/lib/test-utils.js');
|
||||
|
||||
function setImmediate(cb) {
|
||||
setTimeout(cb, 0);
|
||||
}
|
||||
|
||||
function parse_query() {
|
||||
var query = window.location.search.substring(1);
|
||||
var parsed = {};
|
||||
query.split('&').forEach(function(pair) {
|
||||
pair = pair.split('=');
|
||||
var key = decodeURIComponent(pair[0]);
|
||||
var value = decodeURIComponent(pair[1]);
|
||||
parsed[key] = value;
|
||||
});
|
||||
return parsed;
|
||||
}
|
||||
|
||||
var query = parse_query();
|
||||
|
||||
function time(test, cb) {
|
||||
var start = performance.now();
|
||||
function done() {
|
||||
var end = performance.now();
|
||||
cb(end - start);
|
||||
}
|
||||
test(done);
|
||||
}
|
||||
|
||||
var random_data = new Buffer(1024); // 1kB buffer
|
||||
var read_buffer = new Buffer(1024);
|
||||
|
||||
function run(iter) {
|
||||
iter = (undefined == iter) ? 0 : iter;
|
||||
|
||||
function before() {
|
||||
util.setup(function() {
|
||||
setImmediate(during);
|
||||
});
|
||||
}
|
||||
|
||||
function during() {
|
||||
var fs = util.fs();
|
||||
|
||||
window.crypto.getRandomValues(random_data);
|
||||
time(function(done) {
|
||||
fs.mkdir('/tmp', function(err) {
|
||||
fs.stat('/tmp', function(err, stats) {
|
||||
fs.open('/tmp/test', 'w', function(err, fd) {
|
||||
fs.write(fd, random_data, null, null, null, function(err, nbytes) {
|
||||
fs.close(fd, function(err) {
|
||||
fs.stat('/tmp/test', function(err, stats) {
|
||||
fs.open('/tmp/test', 'r', function(err, fd) {
|
||||
fs.read(fd, read_buffer, null, null, null, function(err, nbytes) {
|
||||
fs.close(fd, function(err) {
|
||||
fs.unlink('/tmp/test', function(err) {
|
||||
done();
|
||||
});});});});});});});});});});
|
||||
}, after);
|
||||
}
|
||||
|
||||
function after(dt) {
|
||||
util.cleanup(complete.bind(null, iter, dt));
|
||||
}
|
||||
|
||||
before();
|
||||
}
|
||||
|
||||
var results = [];
|
||||
function complete(iter, result) {
|
||||
results.push(result);
|
||||
|
||||
if(++iter < iterations) {
|
||||
setImmediate(run.bind(null, iter));
|
||||
} else {
|
||||
do_stats();
|
||||
}
|
||||
|
||||
progress.value = iter;
|
||||
}
|
||||
|
||||
function do_stats() {
|
||||
var output = document.getElementById("output");
|
||||
var stats = {
|
||||
mean: ss.mean(results) + " ms",
|
||||
min: ss.min(results),
|
||||
max: ss.max(results),
|
||||
med_abs_dev: ss.median_absolute_deviation(results),
|
||||
};
|
||||
|
||||
var t = document.createElement("table");
|
||||
var tbody = document.createElement("tbody");
|
||||
var keys = Object.keys(stats);
|
||||
keys.forEach(function(key) {
|
||||
var row = document.createElement("tr");
|
||||
|
||||
var key_cell = document.createElement("td");
|
||||
var key_cell_text = document.createTextNode(key);
|
||||
key_cell.appendChild(key_cell_text);
|
||||
row.appendChild(key_cell);
|
||||
|
||||
var val_cell = document.createElement("td");
|
||||
var val_cell_text = document.createTextNode(stats[key]);
|
||||
val_cell.appendChild(val_cell_text);
|
||||
row.appendChild(val_cell);
|
||||
|
||||
tbody.appendChild(row);
|
||||
});
|
||||
|
||||
t.appendChild(tbody);
|
||||
output.appendChild(t);
|
||||
}
|
||||
|
||||
var query = parse_query();
|
||||
var iterations = query.iterations || 10;
|
||||
var progress = document.getElementById("progress");
|
||||
progress.max = iterations;
|
||||
|
||||
run();
|
|
@ -0,0 +1,3 @@
|
|||
components
|
||||
build
|
||||
node_modules
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"indent": 4,
|
||||
"undef": true,
|
||||
"unused": true,
|
||||
"globals": {
|
||||
"require": true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
language: node_js
|
||||
node_js:
|
||||
- 0.10
|
||||
script:
|
||||
- npm install
|
||||
- npm test
|
||||
- npm run cov
|
|
@ -0,0 +1,242 @@
|
|||
Basic contracts of functions:
|
||||
|
||||
* Functions do not modify their arguments e.g. change their order
|
||||
* Invalid input, like empty lists to functions that need 1+ items to work, will cause functions to return `null`.
|
||||
|
||||
# Basic Array Operations
|
||||
|
||||
### .mixin(array)
|
||||
|
||||
_Optionally_ mix in the following functions into the `Array` prototype. Otherwise
|
||||
you can use them off of the simple-statistics object itself.
|
||||
|
||||
If given a particular array instance as an argument, this adds the functions
|
||||
only to that array rather than the global `Array.prototype`. Without an argument,
|
||||
it runs on the global `Array.prototype`.
|
||||
|
||||
### .mean(x)
|
||||
|
||||
Mean of a single-dimensional Array of numbers. _Also available as `.average(x)`_
|
||||
|
||||
### .sum(x)
|
||||
|
||||
Sum of a single-dimensional Array of numbers.
|
||||
|
||||
### .mode(x)
|
||||
|
||||
Returns the number that appears most frequently in a single-dimensional Array
|
||||
of numbers. If there are multiple modes, the one that appears last
|
||||
is returned.
|
||||
|
||||
### .variance(x)
|
||||
|
||||
[Variance](http://en.wikipedia.org/wiki/Variance) of a single-dimensional Array of numbers.
|
||||
|
||||
### .standard_deviation(x)
|
||||
|
||||
[Standard Deviation](http://en.wikipedia.org/wiki/Standard_deviation) of a single-dimensional Array of numbers.
|
||||
|
||||
### .sample(array, n)
|
||||
|
||||
Return a [simple random sample](http://en.wikipedia.org/wiki/Simple_random_sample)
|
||||
of the given array. The sampling is _without replacement_, and uses a Fisher-Yates
|
||||
sample to randomize.
|
||||
|
||||
### .median_absolute_deviation(x)
|
||||
|
||||
The Median Absolute Deviation (MAD) is a robust measure of statistical
|
||||
dispersion. It is more resilient to outliers than the standard deviation.
|
||||
Accepts a single-dimensional array of numbers and returns a dispersion value.
|
||||
|
||||
Also aliased to `.mad(x)` for brevity.
|
||||
|
||||
### .median(x)
|
||||
|
||||
[Median](http://en.wikipedia.org/wiki/Median) of a single-dimensional array of numbers.
|
||||
|
||||
### .geometric_mean(x)
|
||||
|
||||
[Geometric mean](http://en.wikipedia.org/wiki/Geometric_mean) of a single-dimensional array of **positive** numbers.
|
||||
|
||||
### .harmonic_mean(x)
|
||||
|
||||
[Harmonic mean](http://en.wikipedia.org/wiki/Harmonic_mean) of a single-dimensional array of **positive** numbers.
|
||||
|
||||
### .root_mean_square(x)
|
||||
|
||||
[Root mean square (RMS)](http://en.wikipedia.org/wiki/Root_mean_square) of a single-dimensional array of numbers.
|
||||
|
||||
Also aliased to `.rms(x)` for brevity.
|
||||
|
||||
### .min(x)
|
||||
|
||||
Finds the minimum of a single-dimensional array of numbers. This runs in linear `O(n)` time.
|
||||
|
||||
### .max(x)
|
||||
|
||||
Finds the maximum of a single-dimensional array of numbers. This runs in linear `O(n)` time.
|
||||
|
||||
### .t_test(sample, x)
|
||||
|
||||
Does a [student's t-test](http://en.wikipedia.org/wiki/Student's_t-test) of a dataset `sample`, represented by a single-dimensional array of numbers. `x` is the known value, and the result is a measure of [statistical significance](http://en.wikipedia.org/wiki/Statistical_significance).
|
||||
|
||||
### .t_test_two_sample(sample_x, sample_y, difference)
|
||||
|
||||
The two-sample t-test is used to compare samples from two populations or groups,
|
||||
confirming or denying the suspicion (null hypothesis) that the populations are
|
||||
the same. It returns a t-value that you can then look up to give certain
|
||||
judgements of confidence based on a t distribution table.
|
||||
|
||||
This implementation expects the samples `sample_x` and `sample_y` to be given
|
||||
as one-dimensional arrays of more than one number each.
|
||||
|
||||
### .sample_variance(x)
|
||||
|
||||
Produces [sample variance](http://mathworld.wolfram.com/SampleVariance.html)
|
||||
of a single-dimensional array of numbers.
|
||||
|
||||
### .sample_covariance(a, b)
|
||||
|
||||
Produces [sample covariance](http://en.wikipedia.org/wiki/Sample_mean_and_sample_covariance)
|
||||
of two single-dimensional arrays of numbers.
|
||||
|
||||
### .sample_correlation(a, b)
|
||||
|
||||
Produces [sample correlation](http://en.wikipedia.org/wiki/Correlation_and_dependence)
|
||||
of two single-dimensional arrays of numbers.
|
||||
|
||||
### .quantile(sample, p)
|
||||
|
||||
Does a [quantile](http://en.wikipedia.org/wiki/Quantile) of a dataset `sample`,
|
||||
at p. For those familiary with the `k/q` syntax, `p == k/q`. `sample` must
|
||||
be a single-dimensional array of numbers. p must be a number greater than or equal to
|
||||
than zero and less or equal to than one, or an array of numbers following that rule.
|
||||
If an array is given, an array of results will be returned instead of a single
|
||||
number.
|
||||
|
||||
### .chunk(sample, chunkSize)
|
||||
|
||||
Given a `sample` array, and a positive integer `chunkSize`, splits an array
|
||||
into chunks of `chunkSize` size and returns an array of those chunks. This
|
||||
does not change the input value. If the length of `sample` is not divisible
|
||||
by `chunkSize`, the last array will be shorter than the rest.
|
||||
|
||||
### .shuffle(sample)
|
||||
|
||||
Given a `sample` array (with any type of contents), return a random permutation
|
||||
of that array, using the [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle)
|
||||
algorithm.
|
||||
|
||||
### .shuffle_in_place(sample)
|
||||
|
||||
Given a `sample` array (with any type of contents), return a random permutation
|
||||
of that array, using the [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle)
|
||||
algorithm.
|
||||
|
||||
This changes the input array in-place, as well as returns it - unlike `.shuffle()`,
|
||||
it does not create a shallow copy of the array.
|
||||
|
||||
### .quantile_sorted(sample, p)
|
||||
|
||||
Does a [quantile](http://en.wikipedia.org/wiki/Quantile) of a dataset `sample`,
|
||||
at p. `sample` must be a one-dimensional _sorted_ array of numbers, and
|
||||
`p` must be a single number from zero to one.
|
||||
|
||||
### .iqr(sample)
|
||||
|
||||
Calculates the [Interquartile range](http://en.wikipedia.org/wiki/Interquartile_range) of
|
||||
a sample - the difference between the upper and lower quartiles. Useful
|
||||
as a measure of dispersion.
|
||||
|
||||
_Also available as `.interquartile_range(x)`_
|
||||
|
||||
### .sample_skewness(sample)
|
||||
|
||||
Calculates the [skewness](http://en.wikipedia.org/wiki/Skewness) of
|
||||
a sample, a measure of the extent to which a probability distribution of a
|
||||
real-valued random variable "leans" to one side of the mean.
|
||||
The skewness value can be positive or negative, or even undefined.
|
||||
|
||||
This implementation uses the [Fisher-Pearson standardized moment coefficient](http://en.wikipedia.org/wiki/Skewness#Pearson.27s_skewness_coefficients),
|
||||
which means that it behaves the same as Excel, Minitab, SAS, and SPSS.
|
||||
|
||||
Skewness is only valid for samples of over three values.
|
||||
|
||||
### .jenks(data, number_of_classes)
|
||||
|
||||
Find the [Jenks Natural Breaks](http://en.wikipedia.org/wiki/Jenks_natural_breaks_optimization) for
|
||||
a single-dimensional array of numbers as input and a desired `number_of_classes`.
|
||||
The result is a single-dimensional with class breaks, including the minimum
|
||||
and maximum of the input array.
|
||||
|
||||
### .r_squared(data, function)
|
||||
|
||||
Find the [r-squared](http://en.wikipedia.org/wiki/Coefficient_of_determination) value of a particular dataset, expressed as a two-dimensional `Array` of numbers, against a `Function`.
|
||||
|
||||
var r_squared = ss.r_squared([[1, 1]], function(x) { return x * 2; });
|
||||
|
||||
### .cumulative_std_normal_probability(z)
|
||||
|
||||
Look up the given `z` value in a [standard normal table](http://en.wikipedia.org/wiki/Standard_normal_table)
|
||||
to calculate the probability of a random variable appearing with a given value.
|
||||
|
||||
### .z_score(x, mean, standard_deviation)
|
||||
|
||||
The standard score is the number of standard deviations an observation
|
||||
or datum is above or below the mean.
|
||||
|
||||
### .standard_normal_table
|
||||
|
||||
A [standard normal table](http://en.wikipedia.org/wiki/Standard_normal_table) from
|
||||
which to pull values of Φ (phi).
|
||||
|
||||
## Regression
|
||||
|
||||
### .linear_regression()
|
||||
|
||||
Create a new linear regression solver.
|
||||
|
||||
#### .data([[1, 1], [2, 2]])
|
||||
|
||||
Set the data of a linear regression. The input is a two-dimensional array of numbers, which are treated as coordinates, like `[[x, y], [x1, y1]]`.
|
||||
|
||||
#### .line()
|
||||
|
||||
Get the linear regression line: this returns a function that you can
|
||||
give `x` values and it will return `y` values. Internally, this uses the `m()`
|
||||
and `b()` values and the classic `y = mx + b` equation.
|
||||
|
||||
var linear_regression_line = ss.linear_regression()
|
||||
.data([[0, 1], [2, 2], [3, 3]]).line();
|
||||
linear_regression_line(5);
|
||||
|
||||
#### .m()
|
||||
|
||||
Just get the slope of the fitted regression line, the `m` component of the full
|
||||
line equation. Returns a number.
|
||||
|
||||
#### .b()
|
||||
|
||||
Just get the y-intercept of the fitted regression line, the `b` component
|
||||
of the line equation. Returns a number.
|
||||
|
||||
## Classification
|
||||
|
||||
### .bayesian()
|
||||
|
||||
Create a naïve bayesian classifier.
|
||||
|
||||
### .train(item, category)
|
||||
|
||||
Train the classifier to classify a certain item, given as an object with keys,
|
||||
to be in a certain category, given as a string.
|
||||
|
||||
### .score(item)
|
||||
|
||||
Get the classifications of a certain item, given as an object of
|
||||
`category -> score` mappings.
|
||||
|
||||
var bayes = ss.bayesian();
|
||||
bayes.train({ species: 'Cat' }, 'animal');
|
||||
bayes.score({ species: 'Cat' });
|
||||
// { animal: 1 }
|
|
@ -0,0 +1,60 @@
|
|||
# CHANGELOG
|
||||
|
||||
## 0.9.0
|
||||
|
||||
* Adds `.sample` for simple random sampling
|
||||
* Adds `.shuffle` and `.shuffle_in_place` for random permutations
|
||||
* Adds `.chunk` for splitting arrays into chunked subsets
|
||||
|
||||
## 0.8.1
|
||||
|
||||
* fixes a bug in `mode` that favored the last new number
|
||||
|
||||
## 0.8.0
|
||||
|
||||
* `mixin` can now take an array in order to mixin functions into a single array
|
||||
instance rather than the global Array prototype.
|
||||
|
||||
## 0.7.0
|
||||
|
||||
* Adds `simple_statistics.harmonic_mean` thanks to [jseppi](https://github.com/jseppi)
|
||||
|
||||
## 0.6.0
|
||||
|
||||
* Adds `simple_statistics.quantile_sorted` thanks to [rluta](http://github.com/rluta)
|
||||
* `simple_statistics.quantile` now accepts a sorted list of quantiles as a second argument
|
||||
* Improved test coverage
|
||||
|
||||
## 0.5.0
|
||||
|
||||
* Adds `simple_statistics.cumulative_std_normal_probability` by [doronlinder](https://github.com/doronlinder)
|
||||
* Adds `simple_statistics.z_score` by doronlinder
|
||||
* Adds `simple_statistics.standard_normal_table`
|
||||
|
||||
## 0.4.0
|
||||
|
||||
* Adds `simple_statistics.median_absolute_deviation()` by siculars
|
||||
* Adds `simple_statistics.iqr()` by siculars
|
||||
* Adds `simple_statistics.skewness()` by Doron Linder
|
||||
* Lower-level accessors for linear regression allow users to do the line
|
||||
equation themselves
|
||||
|
||||
## 0.3.0
|
||||
|
||||
* Adds `simple_statistics.jenks()`
|
||||
* Adds `simple_statistics.jenksMatrices()`
|
||||
* Improves test coverage and validation
|
||||
|
||||
## 0.2.0
|
||||
|
||||
* Adds `simple_statistics.quantile()`
|
||||
* Adds `simple_statistics.mixin()`
|
||||
* Adds `simple_statistics.geometric_mean()`
|
||||
* Adds `simple_statistics.sample_variance()`
|
||||
* Adds `simple_statistics.sample_covariance()`
|
||||
|
||||
## 0.1.0
|
||||
|
||||
* Adds `simple_statistics.t_test()`
|
||||
* Adds `simple_statistics.min()`
|
||||
* Adds `simple_statistics.max()`
|
|
@ -0,0 +1,99 @@
|
|||
# Contributing to simple-statistics
|
||||
|
||||
Simple statistics is a statistics library that can be both used and read.
|
||||
It should help programmers learn statistics and statisticians learn programming.
|
||||
In order to achieve this goal, it must be **simple** and **explanatory**.
|
||||
|
||||
## Simple
|
||||
|
||||
`simple-statistics` is written in a subset of JavaScript. Unused features
|
||||
include:
|
||||
|
||||
* [Conditional Operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator)
|
||||
* [ES5 Array methods](http://ie.microsoft.com/TestDrive/HTML5/ECMAScript5Array/Default.html)
|
||||
* `with`, `eval`, and other forms of `eval`
|
||||
* Most micro-optimizations, like [alternative for loop forms](http://jsperf.com/loops/70)
|
||||
* [Shortcut branching](http://javascriptweblog.wordpress.com/2010/07/26/no-more-ifs-alternatives-to-statement-branching-in-javascript/)
|
||||
|
||||
## Explanatory
|
||||
|
||||
Example:
|
||||
|
||||
```js
|
||||
// # harmonic mean
|
||||
//
|
||||
// a mean function typically used to find the average of rates
|
||||
//
|
||||
// this is the reciprocal of the arithmetic mean of the reciprocals
|
||||
// of the input numbers
|
||||
//
|
||||
// This runs on `O(n)`, linear time in respect to the array
|
||||
```
|
||||
|
||||
`simple-statistics` tries to stay away from speaking only in the language of math:
|
||||
for instance, while JavaScript supports UTF8 characters like π, they are not used
|
||||
in the source:
|
||||
|
||||
* UTF8 in JavaScript on pages without specific meta-tag or Content-Type encodings will fail
|
||||
* UTF8 can be hard to type, since users need to memorize key combinations or code points
|
||||
* Mathematical symbols have meanings that are often better communicated by words:
|
||||
in the form of code, we do not run out of space on the paper, and can afford
|
||||
to call a variable `reciprocal_sum` instead of `r`.
|
||||
|
||||
Every function has a comment that ideally includes:
|
||||
|
||||
* The English, long-form name of the method
|
||||
* What the method does
|
||||
* What purpose the method typically serves
|
||||
* A link to a longer description on Wikipedia, Mathematica, or another
|
||||
web-accessible, non-paywalled source
|
||||
* The efficiency of the function in terms of Big-O notation, if appropriate
|
||||
* If the function depends on another function in the library, a note of this, like
|
||||
`depends on mean()`
|
||||
|
||||
## Tests
|
||||
|
||||
`simple-statistics` has a testsuite located in `test/spec/`. Each test file
|
||||
covers a specific topic and tries to test against known values:
|
||||
|
||||
* Values produced by trusted statistics software like R or scipy
|
||||
* Common-sense results
|
||||
|
||||
Tests can be run in [node.js](http://nodejs.org/) and are run on every commit
|
||||
to GitHub by Travis-CI.
|
||||
|
||||
To run tests:
|
||||
|
||||
```sh
|
||||
npm install
|
||||
npm test
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
While the code is meant to readable, it is not documentation. We maintain
|
||||
documentation in `API.md`, which has the simple form:
|
||||
|
||||
```md
|
||||
### .geometric_mean(x)
|
||||
|
||||
[Geometric mean](http://en.wikipedia.org/wiki/Geometric_mean) of a single-dimensional array of **positive** numbers.
|
||||
```
|
||||
|
||||
This file is written in [Markdown](https://daringfireball.net/projects/markdown/) and
|
||||
specifies which functions are available, what type of arguments they receive,
|
||||
what they compute, and what type of answer they return.
|
||||
|
||||
## Code Style
|
||||
|
||||
We use the [Airbnb style for Javascript](https://github.com/airbnb/javascript) with
|
||||
only one difference:
|
||||
|
||||
**4 space soft tabs always for Javascript, not 2.**
|
||||
|
||||
No aligned `=`, no aligned arguments, spaces are either indents or the 1
|
||||
space between expressions. No hard tabs.
|
||||
|
||||
* All comparisons should be as strict and obvious as possible: prefer `(foo === 0)` to
|
||||
`(!foo)`.
|
||||
* Straightforward code is more important than most optimizations.
|
|
@ -0,0 +1,13 @@
|
|||
Copyright (c) 2014, Tom MacWright
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
|
@ -0,0 +1,7 @@
|
|||
docs:
|
||||
docco src/*.js
|
||||
|
||||
test:
|
||||
mocha -R spec test/spec/*.js
|
||||
|
||||
.PHONY: docs test
|
|
@ -0,0 +1,337 @@
|
|||
[![Build Status](https://secure.travis-ci.org/tmcw/simple-statistics.png?branch=master)](http://travis-ci.org/tmcw/simple-statistics) [![Coverage Status](https://coveralls.io/repos/tmcw/simple-statistics/badge.png)](https://coveralls.io/r/tmcw/simple-statistics)
|
||||
|
||||
A JavaScript implementation of descriptive, regression, and inference statistics.
|
||||
|
||||
Implemented in literate JavaScript with no dependencies, designed to work
|
||||
in all modern browsers (including IE) as well as in node.js.
|
||||
|
||||
## [API Documentation](API.md)
|
||||
|
||||
---
|
||||
|
||||
Basic contracts of functions:
|
||||
|
||||
* Functions do not modify their arguments e.g. change their order
|
||||
* Invalid input, like empty lists to functions that need 1+ items to work, will cause functions to return `null`.
|
||||
|
||||
# Basic Array Operations
|
||||
|
||||
### .mixin(array)
|
||||
|
||||
_Optionally_ mix in the following functions into the `Array` prototype. Otherwise
|
||||
you can use them off of the simple-statistics object itself.
|
||||
|
||||
If given a particular array instance as an argument, this adds the functions
|
||||
only to that array rather than the global `Array.prototype`. Without an argument,
|
||||
it runs on the global `Array.prototype`.
|
||||
|
||||
### .mean(x)
|
||||
|
||||
Mean of a single-dimensional Array of numbers. _Also available as `.average(x)`_
|
||||
|
||||
### .sum(x)
|
||||
|
||||
Sum of a single-dimensional Array of numbers.
|
||||
|
||||
### .mode(x)
|
||||
|
||||
Returns the number that appears most frequently in a single-dimensional Array
|
||||
of numbers. If there are multiple modes, the one that appears last
|
||||
is returned.
|
||||
|
||||
### .variance(x)
|
||||
|
||||
[Variance](http://en.wikipedia.org/wiki/Variance) of a single-dimensional Array of numbers.
|
||||
|
||||
### .standard_deviation(x)
|
||||
|
||||
[Standard Deviation](http://en.wikipedia.org/wiki/Standard_deviation) of a single-dimensional Array of numbers.
|
||||
|
||||
### .median_absolute_deviation(x)
|
||||
|
||||
The Median Absolute Deviation (MAD) is a robust measure of statistical
|
||||
dispersion. It is more resilient to outliers than the standard deviation.
|
||||
Accepts a single-dimensional array of numbers and returns a dispersion value.
|
||||
|
||||
Also aliased to `.mad(x)` for brevity.
|
||||
|
||||
### .median(x)
|
||||
|
||||
[Median](http://en.wikipedia.org/wiki/Median) of a single-dimensional array of numbers.
|
||||
|
||||
### .geometric_mean(x)
|
||||
|
||||
[Geometric mean](http://en.wikipedia.org/wiki/Geometric_mean) of a single-dimensional array of **positive** numbers.
|
||||
|
||||
### .harmonic_mean(x)
|
||||
|
||||
[Harmonic mean](http://en.wikipedia.org/wiki/Harmonic_mean) of a single-dimensional array of **positive** numbers.
|
||||
|
||||
### .root_mean_square(x)
|
||||
|
||||
[Root mean square (RMS)](http://en.wikipedia.org/wiki/Root_mean_square) of a single-dimensional array of numbers.
|
||||
|
||||
### .min(x)
|
||||
|
||||
Finds the minimum of a single-dimensional array of numbers. This runs in linear `O(n)` time.
|
||||
|
||||
### .max(x)
|
||||
|
||||
Finds the maximum of a single-dimensional array of numbers. This runs in linear `O(n)` time.
|
||||
|
||||
### .t_test(sample, x)
|
||||
|
||||
Does a [student's t-test](http://en.wikipedia.org/wiki/Student's_t-test) of a dataset `sample`, represented by a single-dimensional array of numbers. `x` is the known value, and the result is a measure of [statistical significance](http://en.wikipedia.org/wiki/Statistical_significance).
|
||||
|
||||
### .t_test_two_sample(sample_x, sample_y, difference)
|
||||
|
||||
The two-sample t-test is used to compare samples from two populations or groups,
|
||||
confirming or denying the suspicion (null hypothesis) that the populations are
|
||||
the same. It returns a t-value that you can then look up to give certain
|
||||
judgements of confidence based on a t distribution table.
|
||||
|
||||
This implementation expects the samples `sample_x` and `sample_y` to be given
|
||||
as one-dimensional arrays of more than one number each.
|
||||
|
||||
### .sample_variance(x)
|
||||
|
||||
Produces [sample variance](http://mathworld.wolfram.com/SampleVariance.html)
|
||||
of a single-dimensional array of numbers.
|
||||
|
||||
### .sample_covariance(a, b)
|
||||
|
||||
Produces [sample covariance](http://en.wikipedia.org/wiki/Sample_mean_and_sample_covariance)
|
||||
of two single-dimensional arrays of numbers.
|
||||
|
||||
### .sample_correlation(a, b)
|
||||
|
||||
Produces [sample correlation](http://en.wikipedia.org/wiki/Correlation_and_dependence)
|
||||
of two single-dimensional arrays of numbers.
|
||||
|
||||
### .quantile(sample, p)
|
||||
|
||||
Does a [quantile](http://en.wikipedia.org/wiki/Quantile) of a dataset `sample`,
|
||||
at p. For those familiary with the `k/q` syntax, `p == k/q`. `sample` must
|
||||
be a single-dimensional array of numbers. p must be a number greater than or equal to zero and less than or equal to one, or an array of numbers following that rule.
|
||||
If an array is given, an array of results will be returned instead of a single
|
||||
number.
|
||||
|
||||
### .chunk(sample, chunkSize)
|
||||
|
||||
Given a `sample` array, and a positive integer `chunkSize`, splits an array
|
||||
into chunks of `chunkSize` size and returns an array of those chunks. This
|
||||
does not change the input value. If the length of `sample` is not divisible
|
||||
by `chunkSize`, the last array will be shorter than the rest.
|
||||
|
||||
### .quantile_sorted(sample, p)
|
||||
|
||||
Does a [quantile](http://en.wikipedia.org/wiki/Quantile) of a dataset `sample`,
|
||||
at p. `sample` must be a one-dimensional _sorted_ array of numbers, and
|
||||
`p` must be a single number greater than or equal to zero and less than or equal to one.
|
||||
|
||||
### .iqr(sample)
|
||||
|
||||
Calculates the [Interquartile range](http://en.wikipedia.org/wiki/Interquartile_range) of
|
||||
a sample - the difference between the upper and lower quartiles. Useful
|
||||
as a measure of dispersion.
|
||||
|
||||
_Also available as `.interquartile_range(x)`_
|
||||
|
||||
### .sample_skewness(sample)
|
||||
|
||||
Calculates the [skewness](http://en.wikipedia.org/wiki/Skewness) of
|
||||
a sample, a measure of the extent to which a probability distribution of a
|
||||
real-valued random variable "leans" to one side of the mean.
|
||||
The skewness value can be positive or negative, or even undefined.
|
||||
|
||||
This implementation uses the [Fisher-Pearson standardized moment coefficient](http://en.wikipedia.org/wiki/Skewness#Pearson.27s_skewness_coefficients),
|
||||
which means that it behaves the same as Excel, Minitab, SAS, and SPSS.
|
||||
|
||||
Skewness is only valid for samples of over three values.
|
||||
|
||||
### .jenks(data, number_of_classes)
|
||||
|
||||
Find the [Jenks Natural Breaks](http://en.wikipedia.org/wiki/Jenks_natural_breaks_optimization) for
|
||||
a single-dimensional array of numbers as input and a desired `number_of_classes`.
|
||||
The result is a single-dimensional with class breaks, including the minimum
|
||||
and maximum of the input array.
|
||||
|
||||
### .r_squared(data, function)
|
||||
|
||||
Find the [r-squared](http://en.wikipedia.org/wiki/Coefficient_of_determination) value of a particular dataset, expressed as a two-dimensional `Array` of numbers, against a `Function`.
|
||||
|
||||
var r_squared = ss.r_squared([[1, 1]], function(x) { return x * 2; });
|
||||
|
||||
### .cumulative_std_normal_probability(z)
|
||||
|
||||
Look up the given `z` value in a [standard normal table](http://en.wikipedia.org/wiki/Standard_normal_table)
|
||||
to calculate the probability of a random variable appearing with a given value.
|
||||
|
||||
### .z_score(x, mean, standard_deviation)
|
||||
|
||||
The standard score is the number of standard deviations an observation
|
||||
or datum is above or below the mean.
|
||||
|
||||
### .standard_normal_table
|
||||
|
||||
A [standard normal table](http://en.wikipedia.org/wiki/Standard_normal_table) from
|
||||
which to pull values of Φ (phi).
|
||||
|
||||
## Regression
|
||||
|
||||
### .linear_regression()
|
||||
|
||||
Create a new linear regression solver.
|
||||
|
||||
#### .data([[1, 1], [2, 2]])
|
||||
|
||||
Set the data of a linear regression. The input is a two-dimensional array of numbers, which are treated as coordinates, like `[[x, y], [x1, y1]]`.
|
||||
|
||||
#### .line()
|
||||
|
||||
Get the linear regression line: this returns a function that you can
|
||||
give `x` values and it will return `y` values. Internally, this uses the `m()`
|
||||
and `b()` values and the classic `y = mx + b` equation.
|
||||
|
||||
var linear_regression_line = ss.linear_regression()
|
||||
.data([[0, 1], [2, 2], [3, 3]]).line();
|
||||
linear_regression_line(5);
|
||||
|
||||
#### .m()
|
||||
|
||||
Just get the slope of the fitted regression line, the `m` component of the full
|
||||
line equation. Returns a number.
|
||||
|
||||
#### .b()
|
||||
|
||||
Just get the y-intercept of the fitted regression line, the `b` component
|
||||
of the line equation. Returns a number.
|
||||
|
||||
## Classification
|
||||
|
||||
### .bayesian()
|
||||
|
||||
Create a naïve bayesian classifier.
|
||||
|
||||
### .train(item, category)
|
||||
|
||||
Train the classifier to classify a certain item, given as an object with keys,
|
||||
to be in a certain category, given as a string.
|
||||
|
||||
### .score(item)
|
||||
|
||||
Get the classifications of a certain item, given as an object of
|
||||
`category -> score` mappings.
|
||||
|
||||
var bayes = ss.bayesian();
|
||||
bayes.train({ species: 'Cat' }, 'animal');
|
||||
bayes.score({ species: 'Cat' });
|
||||
// { animal: 1 }
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
## [Literate Source](http://macwright.org/simple-statistics/)
|
||||
|
||||
## Usage
|
||||
|
||||
To use it in browsers, grab [simple_statistics.js](https://raw.github.com/tmcw/simple-statistics/master/src/simple_statistics.js).
|
||||
To use it in node, install it with [npm](https://npmjs.org/) or add it to your package.json.
|
||||
|
||||
npm install simple-statistics
|
||||
|
||||
To use it with [component](https://github.com/component/component),
|
||||
|
||||
component install tmcw/simple-statistics
|
||||
|
||||
To use it with [bower](http://bower.io/),
|
||||
|
||||
bower install simple-statistics
|
||||
|
||||
## Basic Descriptive Statistics
|
||||
|
||||
```javascript
|
||||
// Require simple statistics
|
||||
var ss = require('simple-statistics');
|
||||
|
||||
// The input is a simple array
|
||||
var list = [1, 2, 3];
|
||||
|
||||
// Many different descriptive statistics are supported
|
||||
var sum = ss.sum(list),
|
||||
mean = ss.mean(list),
|
||||
min = ss.min(list),
|
||||
geometric_mean = ss.geometric_mean(list),
|
||||
max = ss.max(list),
|
||||
quantile = ss.quantile(0.25);
|
||||
```
|
||||
|
||||
## Linear Regression
|
||||
|
||||
```javascript
|
||||
// For a linear regression, it's a two-dimensional array
|
||||
var data = [ [1, 2], [2, 3] ];
|
||||
|
||||
// simple-statistics can produce a linear regression and return
|
||||
// a friendly javascript function for the line.
|
||||
var line = ss.linear_regression()
|
||||
.data(data)
|
||||
.line();
|
||||
|
||||
// get a point along the line function
|
||||
line(0);
|
||||
|
||||
var line = ss.linear_regression()
|
||||
|
||||
// Get the r-squared value of the line estimation
|
||||
ss.r_squared(data, line);
|
||||
```
|
||||
|
||||
### Bayesian Classifier
|
||||
|
||||
```javascript
|
||||
var bayes = ss.bayesian();
|
||||
bayes.train({ species: 'Cat' }, 'animal');
|
||||
bayes.score({ species: 'Cat' });
|
||||
// { animal: 1 }
|
||||
```
|
||||
|
||||
### Mixin Style
|
||||
|
||||
_This is **optional** and not used by default. You can opt-in to mixins
|
||||
with `ss.mixin()`._
|
||||
|
||||
This mixes `simple-statistics` methods into the Array prototype - note that
|
||||
[extending native objects](http://perfectionkills.com/extending-native-builtins/) is a
|
||||
tricky move.
|
||||
|
||||
This will _only work_ if `defineProperty` is available, which means modern browsers
|
||||
and nodejs - on IE8 and below, calling `ss.mixin()` will throw an exception.
|
||||
|
||||
```javascript
|
||||
// mixin to Array class
|
||||
ss.mixin();
|
||||
|
||||
// The input is a simple array
|
||||
var list = [1, 2, 3];
|
||||
|
||||
// The same descriptive techniques as above, but in a simpler style
|
||||
var sum = list.sum(),
|
||||
mean = list.mean(),
|
||||
min = list.min(),
|
||||
max = list.max(),
|
||||
quantile = list.quantile(0.25);
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
* [Linear regression with simple-statistics and d3js](http://bl.ocks.org/3931800)
|
||||
* [Jenks Natural Breaks with a choropleth map with d3js](http://bl.ocks.org/tmcw/4969184)
|
||||
|
||||
# Contributors
|
||||
|
||||
* Tom MacWright
|
||||
* [Matt Sacks](https://github.com/mattsacks)
|
||||
* Doron Linder
|
||||
* [Alexander Sicular](https://github.com/siculars)
|
|
@ -0,0 +1,157 @@
|
|||
[![Build Status](https://secure.travis-ci.org/tmcw/simple-statistics.png?branch=master)](http://travis-ci.org/tmcw/simple-statistics)
|
||||
|
||||
A JavaScript implementation of descriptive, regression, and inference statistics.
|
||||
|
||||
Implemented in literate JavaScript with no dependencies, designed to work
|
||||
in all modern browsers (including IE) as well as in node.js.
|
||||
|
||||
# [API](API.md)
|
||||
|
||||
[Full documentation](API.md)
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
Basic Array Operations
|
||||
.mixin()
|
||||
.mean(x)
|
||||
.sum(x)
|
||||
.variance(x)
|
||||
.standard_deviation(x)
|
||||
.median_absolute_deviation(x)
|
||||
.median(x)
|
||||
.geometric_mean(x)
|
||||
.harmonic_mean(x)
|
||||
.root_mean_square(x)
|
||||
.min(x)
|
||||
.max(x)
|
||||
.t_test(sample, x)
|
||||
.t_test_two_sample(sample_x, sample_y, difference)
|
||||
.sample_variance(x)
|
||||
.sample_covariance(x)
|
||||
.sample_correlation(x)
|
||||
.quantile(sample, p)
|
||||
.iqr(sample)
|
||||
.sample_skewness(sample)
|
||||
.jenks(data, number_of_classes)
|
||||
.r_squared(data, function)
|
||||
.cumulative_std_normal_probability(z)
|
||||
.z_score(x, mean, standard_deviation)
|
||||
.standard_normal_table
|
||||
Regression
|
||||
.linear_regression()
|
||||
.data([[1, 1], [2, 2]])
|
||||
.line()
|
||||
.m()
|
||||
.b()
|
||||
Classification
|
||||
.bayesian()
|
||||
.train(item, category)
|
||||
.score(item)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# [Literate Source](http://macwright.org/simple-statistics/)
|
||||
|
||||
## Usage
|
||||
|
||||
To use it in browsers, grab [simple_statistics.js](https://raw.github.com/tmcw/simple-statistics/master/src/simple_statistics.js).
|
||||
To use it in node, install it with [npm](https://npmjs.org/) or add it to your package.json.
|
||||
|
||||
npm install simple-statistics
|
||||
|
||||
To use it with [component](https://github.com/component/component),
|
||||
|
||||
component install tmcw/simple-statistics
|
||||
|
||||
To use it with [bower](http://bower.io/),
|
||||
|
||||
bower install simple-statistics
|
||||
|
||||
## Basic Descriptive Statistics
|
||||
|
||||
```javascript
|
||||
// Require simple statistics
|
||||
var ss = require('simple-statistics');
|
||||
|
||||
// The input is a simple array
|
||||
var list = [1, 2, 3];
|
||||
|
||||
// Many different descriptive statistics are supported
|
||||
var sum = ss.sum(list),
|
||||
mean = ss.mean(list),
|
||||
min = ss.min(list),
|
||||
geometric_mean = ss.geometric_mean(list),
|
||||
max = ss.max(list),
|
||||
quantile = ss.quantile(0.25);
|
||||
```
|
||||
|
||||
## Linear Regression
|
||||
|
||||
```javascript
|
||||
// For a linear regression, it's a two-dimensional array
|
||||
var data = [ [1, 2], [2, 3] ];
|
||||
|
||||
// simple-statistics can produce a linear regression and return
|
||||
// a friendly javascript function for the line.
|
||||
var line = ss.linear_regression()
|
||||
.data(data)
|
||||
.line();
|
||||
|
||||
// get a point along the line function
|
||||
line(0);
|
||||
|
||||
var line = ss.linear_regression()
|
||||
|
||||
// Get the r-squared value of the line estimation
|
||||
ss.r_squared(data, line);
|
||||
```
|
||||
|
||||
### Bayesian Classifier
|
||||
|
||||
```javascript
|
||||
var bayes = ss.bayesian();
|
||||
bayes.train({ species: 'Cat' }, 'animal');
|
||||
bayes.score({ species: 'Cat' });
|
||||
// { animal: 1 }
|
||||
```
|
||||
|
||||
### Mixin Style
|
||||
|
||||
_This is **optional** and not used by default. You can opt-in to mixins
|
||||
with `ss.mixin()`._
|
||||
|
||||
This mixes `simple-statistics` methods into the Array prototype - note that
|
||||
[extending native objects](http://perfectionkills.com/extending-built-in-native-objects-evil-or-not/) is a
|
||||
tricky move.
|
||||
|
||||
This will _only work_ if `defineProperty` is available, which means modern browsers
|
||||
and nodejs - on IE8 and below, calling `ss.mixin()` will throw an exception.
|
||||
|
||||
```javascript
|
||||
// mixin to Array class
|
||||
ss.mixin();
|
||||
|
||||
// The input is a simple array
|
||||
var list = [1, 2, 3];
|
||||
|
||||
// The same descriptive techniques as above, but in a simpler style
|
||||
var sum = list.sum(),
|
||||
mean = list.mean(),
|
||||
min = list.min(),
|
||||
max = list.max(),
|
||||
quantile = list.quantile(0.25);
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
* [Linear regression with simple-statistics and d3js](http://bl.ocks.org/3931800)
|
||||
* [Jenks Natural Breaks with a choropleth map with d3js](http://bl.ocks.org/tmcw/4969184)
|
||||
|
||||
# Contributors
|
||||
|
||||
* Tom MacWright
|
||||
* [Matt Sacks](https://github.com/mattsacks)
|
||||
* Doron Linder
|
||||
* [Alexander Sicular](https://github.com/siculars)
|
|
@ -0,0 +1,23 @@
|
|||
## See Also
|
||||
|
||||
* [stream-statistics](https://github.com/tmcw/stream-statistics), a sister project that implements
|
||||
many of the same measures for streaming data - as online algorithms
|
||||
|
||||
### Javascript
|
||||
|
||||
* [science.js](https://github.com/jasondavies/science.js)
|
||||
* [atoll.js](https://github.com/nsfmc/atoll.js)
|
||||
* [descriptive_statistics](https://github.com/thirtysixthspan/descriptive_statistics)
|
||||
* [jStat](http://www.jstat.org/)
|
||||
* [classifier](https://github.com/harthur/classifier) is a naive bayesian classifier (though specialized for the words-spam case)
|
||||
* [underscore.math](https://github.com/syntagmatic/underscore.math/blob/master/underscore.math.js)
|
||||
|
||||
### Python
|
||||
|
||||
* [Pandas](http://pandas.pydata.org/)
|
||||
* [SciPy](http://www.scipy.org/)
|
||||
|
||||
### Their Own Language
|
||||
|
||||
* [Julia Language](http://julialang.org/)
|
||||
* [R language](http://www.r-project.org/)
|
|
@ -0,0 +1,20 @@
|
|||
var fs = require('fs');
|
||||
|
||||
var readme = fs.readFileSync('README.md', 'utf8')
|
||||
.split('\n');
|
||||
|
||||
var a = true, b = true;
|
||||
|
||||
fs.writeFileSync('README.md', readme.filter(function(f) {
|
||||
if (f === '---') {
|
||||
a = !a;
|
||||
return true;
|
||||
}
|
||||
return a;
|
||||
}).map(function(f) {
|
||||
if (f === '---' && b) {
|
||||
f = f + '\n\n' + fs.readFileSync('API.md', 'utf8') + '\n\n';
|
||||
b = false;
|
||||
}
|
||||
return f;
|
||||
}).join('\n'));
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"name": "simple-statistics",
|
||||
"version": "0.9.0",
|
||||
"description": "Simple Statistics",
|
||||
"repo": "tmcw/simple-statistics",
|
||||
"keywords": [],
|
||||
"license": "ISC",
|
||||
"dependencies": {},
|
||||
"development": {},
|
||||
"main": "src/simple_statistics.js"
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"name": "simple-statistics",
|
||||
"version": "0.9.0",
|
||||
"description": "Simple Statistics",
|
||||
"repo": "tmcw/simple-statistics",
|
||||
"keywords": [],
|
||||
"license": "ISC",
|
||||
"dependencies": {},
|
||||
"development": {},
|
||||
"scripts": [
|
||||
"src/simple_statistics.js"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,506 @@
|
|||
/*--------------------- Typography ----------------------------*/
|
||||
|
||||
@font-face {
|
||||
font-family: 'aller-light';
|
||||
src: url('public/fonts/aller-light.eot');
|
||||
src: url('public/fonts/aller-light.eot?#iefix') format('embedded-opentype'),
|
||||
url('public/fonts/aller-light.woff') format('woff'),
|
||||
url('public/fonts/aller-light.ttf') format('truetype');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'aller-bold';
|
||||
src: url('public/fonts/aller-bold.eot');
|
||||
src: url('public/fonts/aller-bold.eot?#iefix') format('embedded-opentype'),
|
||||
url('public/fonts/aller-bold.woff') format('woff'),
|
||||
url('public/fonts/aller-bold.ttf') format('truetype');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'novecento-bold';
|
||||
src: url('public/fonts/novecento-bold.eot');
|
||||
src: url('public/fonts/novecento-bold.eot?#iefix') format('embedded-opentype'),
|
||||
url('public/fonts/novecento-bold.woff') format('woff'),
|
||||
url('public/fonts/novecento-bold.ttf') format('truetype');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/*--------------------- Layout ----------------------------*/
|
||||
html { height: 100%; }
|
||||
body {
|
||||
font-family: "aller-light";
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
color: #30404f;
|
||||
margin: 0; padding: 0;
|
||||
height:100%;
|
||||
}
|
||||
#container { min-height: 100%; }
|
||||
|
||||
a {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: normal;
|
||||
font-family: "aller-bold";
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 15px 0 0px;
|
||||
}
|
||||
.annotation ul, .annotation ol {
|
||||
margin: 25px 0;
|
||||
}
|
||||
.annotation ul li, .annotation ol li {
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
color: #112233;
|
||||
line-height: 1em;
|
||||
font-weight: normal;
|
||||
font-family: "novecento-bold";
|
||||
text-transform: uppercase;
|
||||
margin: 30px 0 15px 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 0;
|
||||
background: 1px #ddd;
|
||||
height: 1px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
pre, tt, code {
|
||||
font-size: 12px; line-height: 16px;
|
||||
font-family: Menlo, Monaco, Consolas, "Lucida Console", monospace;
|
||||
margin: 0; padding: 0;
|
||||
}
|
||||
.annotation pre {
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding: 7px 10px;
|
||||
background: #fcfcfc;
|
||||
-moz-box-shadow: inset 0 0 10px rgba(0,0,0,0.1);
|
||||
-webkit-box-shadow: inset 0 0 10px rgba(0,0,0,0.1);
|
||||
box-shadow: inset 0 0 10px rgba(0,0,0,0.1);
|
||||
overflow-x: auto;
|
||||
}
|
||||
.annotation pre code {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
|
||||
blockquote {
|
||||
border-left: 5px solid #ccc;
|
||||
margin: 0;
|
||||
padding: 1px 0 1px 1em;
|
||||
}
|
||||
.sections blockquote p {
|
||||
font-family: Menlo, Consolas, Monaco, monospace;
|
||||
font-size: 12px; line-height: 16px;
|
||||
color: #999;
|
||||
margin: 10px 0 0;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
ul.sections {
|
||||
list-style: none;
|
||||
padding:0 0 5px 0;;
|
||||
margin:0;
|
||||
}
|
||||
|
||||
/*
|
||||
Force border-box so that % widths fit the parent
|
||||
container without overlap because of margin/padding.
|
||||
|
||||
More Info : http://www.quirksmode.org/css/box.html
|
||||
*/
|
||||
ul.sections > li > div {
|
||||
-moz-box-sizing: border-box; /* firefox */
|
||||
-ms-box-sizing: border-box; /* ie */
|
||||
-webkit-box-sizing: border-box; /* webkit */
|
||||
-khtml-box-sizing: border-box; /* konqueror */
|
||||
box-sizing: border-box; /* css3 */
|
||||
}
|
||||
|
||||
|
||||
/*---------------------- Jump Page -----------------------------*/
|
||||
#jump_to, #jump_page {
|
||||
margin: 0;
|
||||
background: white;
|
||||
-webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777;
|
||||
-webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px;
|
||||
font: 16px Arial;
|
||||
cursor: pointer;
|
||||
text-align: right;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
#jump_to a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#jump_to a.large {
|
||||
display: none;
|
||||
}
|
||||
#jump_to a.small {
|
||||
font-size: 22px;
|
||||
font-weight: bold;
|
||||
color: #676767;
|
||||
}
|
||||
|
||||
#jump_to, #jump_wrapper {
|
||||
position: fixed;
|
||||
right: 0; top: 0;
|
||||
padding: 10px 15px;
|
||||
margin:0;
|
||||
}
|
||||
|
||||
#jump_wrapper {
|
||||
display: none;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
#jump_to:hover #jump_wrapper {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#jump_page {
|
||||
padding: 5px 0 3px;
|
||||
margin: 0 0 25px 25px;
|
||||
}
|
||||
|
||||
#jump_page .source {
|
||||
display: block;
|
||||
padding: 15px;
|
||||
text-decoration: none;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
|
||||
#jump_page .source:hover {
|
||||
background: #f5f5ff;
|
||||
}
|
||||
|
||||
#jump_page .source:first-child {
|
||||
}
|
||||
|
||||
/*---------------------- Low resolutions (> 320px) ---------------------*/
|
||||
@media only screen and (min-width: 320px) {
|
||||
.pilwrap { display: none; }
|
||||
|
||||
ul.sections > li > div {
|
||||
display: block;
|
||||
padding:5px 10px 0 10px;
|
||||
}
|
||||
|
||||
ul.sections > li > div.annotation ul, ul.sections > li > div.annotation ol {
|
||||
padding-left: 30px;
|
||||
}
|
||||
|
||||
ul.sections > li > div.content {
|
||||
overflow-x:auto;
|
||||
-webkit-box-shadow: inset 0 0 5px #e5e5ee;
|
||||
box-shadow: inset 0 0 5px #e5e5ee;
|
||||
border: 1px solid #dedede;
|
||||
margin:5px 10px 5px 10px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
ul.sections > li > div.annotation pre {
|
||||
margin: 7px 0 7px;
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
ul.sections > li > div.annotation p tt, .annotation code {
|
||||
background: #f8f8ff;
|
||||
border: 1px solid #dedede;
|
||||
font-size: 12px;
|
||||
padding: 0 0.2em;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------- (> 481px) ---------------------*/
|
||||
@media only screen and (min-width: 481px) {
|
||||
#container {
|
||||
position: relative;
|
||||
}
|
||||
body {
|
||||
background-color: #F5F5FF;
|
||||
font-size: 15px;
|
||||
line-height: 21px;
|
||||
}
|
||||
pre, tt, code {
|
||||
line-height: 18px;
|
||||
}
|
||||
p, ul, ol {
|
||||
margin: 0 0 15px;
|
||||
}
|
||||
|
||||
|
||||
#jump_to {
|
||||
padding: 5px 10px;
|
||||
}
|
||||
#jump_wrapper {
|
||||
padding: 0;
|
||||
}
|
||||
#jump_to, #jump_page {
|
||||
font: 10px Arial;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
#jump_page .source {
|
||||
padding: 5px 10px;
|
||||
}
|
||||
#jump_to a.large {
|
||||
display: inline-block;
|
||||
}
|
||||
#jump_to a.small {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#background {
|
||||
position: absolute;
|
||||
top: 0; bottom: 0;
|
||||
width: 350px;
|
||||
background: #fff;
|
||||
border-right: 1px solid #e5e5ee;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
ul.sections > li > div.annotation ul, ul.sections > li > div.annotation ol {
|
||||
padding-left: 40px;
|
||||
}
|
||||
|
||||
ul.sections > li {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
ul.sections > li > div {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
ul.sections > li > div.annotation {
|
||||
max-width: 350px;
|
||||
min-width: 350px;
|
||||
min-height: 5px;
|
||||
padding: 13px;
|
||||
overflow-x: hidden;
|
||||
white-space: normal;
|
||||
vertical-align: top;
|
||||
text-align: left;
|
||||
}
|
||||
ul.sections > li > div.annotation pre {
|
||||
margin: 15px 0 15px;
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
ul.sections > li > div.content {
|
||||
padding: 13px;
|
||||
vertical-align: top;
|
||||
border: none;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.pilwrap {
|
||||
position: relative;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.pilcrow {
|
||||
font: 12px Arial;
|
||||
text-decoration: none;
|
||||
color: #454545;
|
||||
position: absolute;
|
||||
top: 3px; left: -20px;
|
||||
padding: 1px 2px;
|
||||
opacity: 0;
|
||||
-webkit-transition: opacity 0.2s linear;
|
||||
}
|
||||
.for-h1 .pilcrow {
|
||||
top: 47px;
|
||||
}
|
||||
.for-h2 .pilcrow, .for-h3 .pilcrow, .for-h4 .pilcrow {
|
||||
top: 35px;
|
||||
}
|
||||
|
||||
ul.sections > li > div.annotation:hover .pilcrow {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------- (> 1025px) ---------------------*/
|
||||
@media only screen and (min-width: 1025px) {
|
||||
|
||||
body {
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
#background {
|
||||
width: 525px;
|
||||
}
|
||||
ul.sections > li > div.annotation {
|
||||
max-width: 525px;
|
||||
min-width: 525px;
|
||||
padding: 10px 25px 1px 50px;
|
||||
}
|
||||
ul.sections > li > div.content {
|
||||
padding: 9px 15px 16px 25px;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------- Syntax Highlighting -----------------------------*/
|
||||
|
||||
td.linenos { background-color: #f0f0f0; padding-right: 10px; }
|
||||
span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }
|
||||
/*
|
||||
|
||||
github.com style (c) Vasily Polovnyov <vast@whiteants.net>
|
||||
|
||||
*/
|
||||
|
||||
pre code {
|
||||
display: block; padding: 0.5em;
|
||||
color: #000;
|
||||
background: #f8f8ff
|
||||
}
|
||||
|
||||
pre .hljs-comment,
|
||||
pre .hljs-template_comment,
|
||||
pre .hljs-diff .hljs-header,
|
||||
pre .hljs-javadoc {
|
||||
color: #408080;
|
||||
font-style: italic
|
||||
}
|
||||
|
||||
pre .hljs-keyword,
|
||||
pre .hljs-assignment,
|
||||
pre .hljs-literal,
|
||||
pre .hljs-css .hljs-rule .hljs-keyword,
|
||||
pre .hljs-winutils,
|
||||
pre .hljs-javascript .hljs-title,
|
||||
pre .hljs-lisp .hljs-title,
|
||||
pre .hljs-subst {
|
||||
color: #954121;
|
||||
/*font-weight: bold*/
|
||||
}
|
||||
|
||||
pre .hljs-number,
|
||||
pre .hljs-hexcolor {
|
||||
color: #40a070
|
||||
}
|
||||
|
||||
pre .hljs-string,
|
||||
pre .hljs-tag .hljs-value,
|
||||
pre .hljs-phpdoc,
|
||||
pre .hljs-tex .hljs-formula {
|
||||
color: #219161;
|
||||
}
|
||||
|
||||
pre .hljs-title,
|
||||
pre .hljs-id {
|
||||
color: #19469D;
|
||||
}
|
||||
pre .hljs-params {
|
||||
color: #00F;
|
||||
}
|
||||
|
||||
pre .hljs-javascript .hljs-title,
|
||||
pre .hljs-lisp .hljs-title,
|
||||
pre .hljs-subst {
|
||||
font-weight: normal
|
||||
}
|
||||
|
||||
pre .hljs-class .hljs-title,
|
||||
pre .hljs-haskell .hljs-label,
|
||||
pre .hljs-tex .hljs-command {
|
||||
color: #458;
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
pre .hljs-tag,
|
||||
pre .hljs-tag .hljs-title,
|
||||
pre .hljs-rules .hljs-property,
|
||||
pre .hljs-django .hljs-tag .hljs-keyword {
|
||||
color: #000080;
|
||||
font-weight: normal
|
||||
}
|
||||
|
||||
pre .hljs-attribute,
|
||||
pre .hljs-variable,
|
||||
pre .hljs-instancevar,
|
||||
pre .hljs-lisp .hljs-body {
|
||||
color: #008080
|
||||
}
|
||||
|
||||
pre .hljs-regexp {
|
||||
color: #B68
|
||||
}
|
||||
|
||||
pre .hljs-class {
|
||||
color: #458;
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
pre .hljs-symbol,
|
||||
pre .hljs-ruby .hljs-symbol .hljs-string,
|
||||
pre .hljs-ruby .hljs-symbol .hljs-keyword,
|
||||
pre .hljs-ruby .hljs-symbol .hljs-keymethods,
|
||||
pre .hljs-lisp .hljs-keyword,
|
||||
pre .hljs-tex .hljs-special,
|
||||
pre .hljs-input_number {
|
||||
color: #990073
|
||||
}
|
||||
|
||||
pre .hljs-builtin,
|
||||
pre .hljs-constructor,
|
||||
pre .hljs-built_in,
|
||||
pre .hljs-lisp .hljs-title {
|
||||
color: #0086b3
|
||||
}
|
||||
|
||||
pre .hljs-preprocessor,
|
||||
pre .hljs-pi,
|
||||
pre .hljs-doctype,
|
||||
pre .hljs-shebang,
|
||||
pre .hljs-cdata {
|
||||
color: #999;
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
pre .hljs-deletion {
|
||||
background: #fdd
|
||||
}
|
||||
|
||||
pre .hljs-addition {
|
||||
background: #dfd
|
||||
}
|
||||
|
||||
pre .hljs-diff .hljs-change {
|
||||
background: #0086b3
|
||||
}
|
||||
|
||||
pre .hljs-chunk {
|
||||
color: #aaa
|
||||
}
|
||||
|
||||
pre .hljs-tex .hljs-formula {
|
||||
opacity: 0.5;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1 @@
|
|||
<meta http-equiv="refresh" content="0;URL='docs/simple_statistics.html'">
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"name": "simple-statistics",
|
||||
"version": "0.9.0",
|
||||
"description": "Simple Statistics",
|
||||
"author": "Tom MacWright <tom@macwright.org> (http://macwright.org/)",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/tmcw/simple-statistics.git"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"jshint": "2.5.3",
|
||||
"coveralls": "~2.11.1",
|
||||
"istanbul": "~0.3.0",
|
||||
"tape": "~2.14.0",
|
||||
"random-js": "~1.0.4"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "tape test/*.js",
|
||||
"cov": "istanbul cover ./node_modules/.bin/tape test/*.js && coveralls < ./coverage/lcov.info",
|
||||
"api": "node api.js"
|
||||
},
|
||||
"main": "src/simple_statistics.js",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
},
|
||||
"license": "ISC"
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,114 @@
|
|||
var ss = require('../');
|
||||
var test = require('tape');
|
||||
|
||||
test('bayes', function(t) {
|
||||
test('makes an easy call with one training round', function(t) {
|
||||
var bayes = ss.bayesian();
|
||||
bayes.train({
|
||||
species: 'Cat'
|
||||
}, 'animal');
|
||||
t.deepEqual(bayes.score({
|
||||
species: 'Cat'
|
||||
}), {
|
||||
animal: 1
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('makes fify-fifty call', function(t) {
|
||||
var bayes = ss.bayesian();
|
||||
bayes.train({
|
||||
species: 'Cat'
|
||||
}, 'animal');
|
||||
bayes.train({
|
||||
species: 'Cat'
|
||||
}, 'chair');
|
||||
t.deepEqual(bayes.score({
|
||||
species: 'Cat'
|
||||
}), {
|
||||
animal: 0.5,
|
||||
chair: 0.5
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('makes seventy-five/twenty-five call', function(t) {
|
||||
var bayes = ss.bayesian();
|
||||
bayes.train({
|
||||
species: 'Cat'
|
||||
}, 'animal');
|
||||
bayes.train({
|
||||
species: 'Cat'
|
||||
}, 'animal');
|
||||
bayes.train({
|
||||
species: 'Cat'
|
||||
}, 'animal');
|
||||
bayes.train({
|
||||
species: 'Cat'
|
||||
}, 'chair');
|
||||
t.deepEqual(bayes.score({
|
||||
species: 'Cat'
|
||||
}), {
|
||||
animal: 0.75,
|
||||
chair: 0.25
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('tests multiple properties', function(t) {
|
||||
var bayes = ss.bayesian();
|
||||
bayes.train({
|
||||
species: 'Cat'
|
||||
}, 'animal');
|
||||
bayes.train({
|
||||
species: 'Cat'
|
||||
}, 'animal');
|
||||
bayes.train({
|
||||
species: 'Cat'
|
||||
}, 'animal');
|
||||
bayes.train({
|
||||
species: 'Cat'
|
||||
}, 'chair');
|
||||
bayes.train({
|
||||
species: 'Cat',
|
||||
color: 'white'
|
||||
}, 'chair');
|
||||
t.deepEqual(bayes.score({
|
||||
color: 'white'
|
||||
}), {
|
||||
animal: 0,
|
||||
chair: 0.2
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('classifies multiple things', function(t) {
|
||||
var bayes = ss.bayesian();
|
||||
bayes.train({
|
||||
species: 'Cat'
|
||||
}, 'animal');
|
||||
bayes.train({
|
||||
species: 'Dog'
|
||||
}, 'animal');
|
||||
bayes.train({
|
||||
species: 'Dog'
|
||||
}, 'animal');
|
||||
bayes.train({
|
||||
species: 'Cat'
|
||||
}, 'chair');
|
||||
t.deepEqual(bayes.score({
|
||||
species: 'Cat'
|
||||
}), {
|
||||
animal: 0.25,
|
||||
chair: 0.25
|
||||
});
|
||||
t.deepEqual(bayes.score({
|
||||
species: 'Dog'
|
||||
}), {
|
||||
animal: 0.5,
|
||||
chair: 0
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,17 @@
|
|||
var test = require('tape');
|
||||
var ss = require('../');
|
||||
|
||||
test('bernoulli_distribution', function(t) {
|
||||
test('can return generate probability and cumulative probability distributions for p = 0.3', function(t) {
|
||||
t.equal('object', typeof ss.bernoulli_distribution(0.3));
|
||||
t.equal(ss.bernoulli_distribution(0.3)[0], 0.7, ss.epsilon);
|
||||
t.equal(ss.bernoulli_distribution(0.3)[1], 0.3, ss.epsilon);
|
||||
t.end();
|
||||
});
|
||||
test('can return null when p is not a valid probability', function(t) {
|
||||
t.equal(null, ss.bernoulli_distribution(-0.01), 'p should be greater than 0.0');
|
||||
t.equal(null, ss.bernoulli_distribution(1.5), 'p should be less than 1.0');
|
||||
t.end();
|
||||
});
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,31 @@
|
|||
var test = require('tape');
|
||||
var ss = require('../');
|
||||
|
||||
function rnd(n) {
|
||||
return parseFloat(n.toFixed(4));
|
||||
}
|
||||
|
||||
test('binomial_distribution', function(t) {
|
||||
// Data given in the [Wikipedia example](http://en.wikipedia.org/wiki/Binomial_distribution#Example) retrieved 29 Mar 2014
|
||||
// Cumulative probabilities worked by hand to mitigate accumulated rounding errors.
|
||||
test('can return generate probability and cumulative probability distributions for n = 6, p = 0.3', function(t) {
|
||||
t.equal('object', typeof ss.binomial_distribution(6, 0.3));
|
||||
t.equal(rnd(ss.binomial_distribution(6, 0.3)[0]), 0.1176, ss.epsilon);
|
||||
t.equal(rnd(ss.binomial_distribution(6, 0.3)[1]), 0.3025, ss.epsilon);
|
||||
t.equal(rnd(ss.binomial_distribution(6, 0.3)[2]), 0.3241, ss.epsilon);
|
||||
t.equal(rnd(ss.binomial_distribution(6, 0.3)[3]), 0.1852, ss.epsilon);
|
||||
t.equal(rnd(ss.binomial_distribution(6, 0.3)[4]), 0.0595, ss.epsilon);
|
||||
t.equal(rnd(ss.binomial_distribution(6, 0.3)[5]), 0.0102, ss.epsilon);
|
||||
t.equal(rnd(ss.binomial_distribution(6, 0.3)[6]), 0.0007, ss.epsilon);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('can return null when p or n are not valid parameters', function(t) {
|
||||
t.equal(null, ss.binomial_distribution(0, 0.5), 'n should be strictly positive');
|
||||
t.equal(null, ss.binomial_distribution(1.5, 0.5), 'n should be an integer');
|
||||
t.equal(null, ss.binomial_distribution(2, -0.01), 'p should be greater than 0.0');
|
||||
t.equal(null, ss.binomial_distribution(2, 1.5), 'p should be less than 1.0');
|
||||
t.end();
|
||||
});
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,23 @@
|
|||
var test = require('tape');
|
||||
var ss = require('../');
|
||||
|
||||
// Data from Poisson goodness-of-fit example 10-19 in William W. Hines & Douglas C. Montgomery,
|
||||
// "Probability and Statistics in Engineering and Management Science", Wiley (1980).
|
||||
var data_10_19 = [
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
3, 3, 3, 3
|
||||
];
|
||||
|
||||
test('chi_squared_goodness_of_fit', function(t) {
|
||||
test('can reject the null hypothesis with level of confidence specified at 0.05', function(t) {
|
||||
t.equal(false, ss.chi_squared_goodness_of_fit(data_10_19, ss.poisson_distribution, 0.05));
|
||||
t.end();
|
||||
});
|
||||
test('can accept the null hypothesis with level of confidence specified at 0.10', function(t) {
|
||||
t.equal(true, ss.chi_squared_goodness_of_fit(data_10_19, ss.poisson_distribution, 0.10));
|
||||
t.end();
|
||||
});
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,18 @@
|
|||
var test = require('tape');
|
||||
var ss = require('../');
|
||||
|
||||
test('chunks', function(t) {
|
||||
test('can get chunks of an array', function(t) {
|
||||
t.deepEqual(ss.chunk([1, 2], 1), [[1], [2]]);
|
||||
t.deepEqual(ss.chunk([1, 2], 2), [[1, 2]]);
|
||||
t.deepEqual(ss.chunk([1, 2, 3, 4], 4), [[1, 2, 3, 4]]);
|
||||
t.deepEqual(ss.chunk([1, 2, 3, 4], 2), [[1, 2], [3, 4]]);
|
||||
t.deepEqual(ss.chunk([1, 2, 3, 4], 3), [[1, 2, 3], [4]]);
|
||||
t.deepEqual(ss.chunk([1, 2, 3, 4, 5, 6, 7], 2), [[1, 2], [3, 4], [5, 6], [7]]);
|
||||
t.deepEqual(ss.chunk([], 2), []);
|
||||
t.deepEqual(ss.chunk([], 0), null);
|
||||
t.deepEqual(ss.chunk([1, 2], 0), null);
|
||||
t.end();
|
||||
});
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,13 @@
|
|||
var test = require('tape');
|
||||
var ss = require('../');
|
||||
|
||||
test('cumulative_std_normal_probability', function(t) {
|
||||
// https://en.wikipedia.org/wiki/Standard_normal_table#Examples_of_use
|
||||
test('wikipedia test example works', function(t) {
|
||||
for (var i = 0; i < ss.standard_normal_table.length; i++) {
|
||||
t.equal(ss.cumulative_std_normal_probability(0.4), 0.6554);
|
||||
}
|
||||
t.end();
|
||||
});
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,22 @@
|
|||
var test = require('tape');
|
||||
var ss = require('../');
|
||||
|
||||
test('factorial', function(t) {
|
||||
test('can return null given a negative number', function(t) {
|
||||
t.equal(null, ss.factorial(-1));
|
||||
t.end();
|
||||
});
|
||||
test('can calculate 0! = 1', function(t) {
|
||||
t.equal(ss.factorial(0), 1);
|
||||
t.end();
|
||||
});
|
||||
test('can calculate 1! = 1', function(t) {
|
||||
t.equal(ss.factorial(1), 1);
|
||||
t.end();
|
||||
});
|
||||
test('can calculate 100! = 1', function(t) {
|
||||
t.equal(ss.factorial(100), 9.33262154439441e+157);
|
||||
t.end();
|
||||
});
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,23 @@
|
|||
var test = require('tape');
|
||||
var ss = require('../');
|
||||
|
||||
test('geometric mean', function(t) {
|
||||
// From http://en.wikipedia.org/wiki/Geometric_mean
|
||||
test('can get the mean of two numbers', function(t) {
|
||||
t.equal(ss.geometric_mean([2, 8]), 4);
|
||||
t.equal(ss.geometric_mean([4, 1, 1 / 32]), 0.5);
|
||||
t.equal(Math.round(ss.geometric_mean([2, 32, 1])), 4);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('returns null for empty lists', function(t) {
|
||||
t.equal(ss.geometric_mean([]), null);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('returns null for lists with negative numbers', function(t) {
|
||||
t.equal(ss.geometric_mean([-1]), null);
|
||||
t.end();
|
||||
});
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,27 @@
|
|||
var test = require('tape');
|
||||
var ss = require('../');
|
||||
|
||||
function rnd(x) {
|
||||
return Math.round(x * 1000) / 1000;
|
||||
}
|
||||
|
||||
test('harmonic_mean', function(t) {
|
||||
// From http://en.wikipedia.org/wiki/Harmonic_mean
|
||||
test('can get the mean of two or more numbers', function(t) {
|
||||
t.equal(ss.harmonic_mean([1, 1]), 1);
|
||||
t.equal(rnd(ss.harmonic_mean([2, 3])), 2.4);
|
||||
t.equal(ss.harmonic_mean([1, 2, 4]), 12 / 7);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('returns null for empty lists', function(t) {
|
||||
t.equal(ss.harmonic_mean([]), null);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('returns null for lists with negative numbers', function(t) {
|
||||
t.equal(ss.harmonic_mean([-1]), null);
|
||||
t.end();
|
||||
});
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,24 @@
|
|||
var test = require('tape');
|
||||
var ss = require('../');
|
||||
|
||||
test('interquartile range (iqr)', function(t) {
|
||||
// Data and results from
|
||||
// [Wikipedia](http://en.wikipedia.org/wiki/Quantile#Quantiles_of_a_population)
|
||||
test('can get proper iqr of an even-length list', function(t) {
|
||||
var even = [3, 6, 7, 8, 8, 10, 13, 15, 16, 20];
|
||||
t.equal(ss.quantile(even, 0.75) - ss.quantile(even, 0.25), ss.iqr(even));
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('can get proper iqr of an odd-length list', function(t) {
|
||||
var odd = [3, 6, 7, 8, 8, 9, 10, 13, 15, 16, 20];
|
||||
t.equal(ss.quantile(odd, 0.75) - ss.quantile(odd, 0.25), ss.iqr(odd));
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('an iqr of a zero-length list produces null', function(t) {
|
||||
t.equal(ss.iqr([]), null);
|
||||
t.end();
|
||||
});
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
var test = require('tape');
|
||||
var ss = require('../');
|
||||
|
||||
test('jenks', function(t) {
|
||||
test('will not try to assign more classes than datapoints', function(t) {
|
||||
t.equal(ss.jenks([1, 2], 3), null);
|
||||
t.end();
|
||||
});
|
||||
test('assigns correct breaks', function(t) {
|
||||
t.deepEqual(ss.jenks([1, 2, 4, 5, 7, 9, 10, 20], 3), [1, 2, 5, 20]);
|
||||
t.end();
|
||||
});
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,54 @@
|
|||
var test = require('tape');
|
||||
var ss = require('../');
|
||||
|
||||
test('linear regression', function(t) {
|
||||
test('correctly generates a line for a 0, 0 to 1, 1 dataset', function(t) {
|
||||
var l = ss.linear_regression().data([[0, 0], [1, 1]]);
|
||||
t.equal(l.line()(0), 0);
|
||||
t.equal(l.line()(0.5), 0.5);
|
||||
t.equal(l.line()(1), 1);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('correctly generates a line for a 0, 0 to 1, 0 dataset', function(t) {
|
||||
var l = ss.linear_regression().data([[0, 0], [1, 0]]);
|
||||
t.equal(l.line()(0), 0);
|
||||
t.equal(l.line()(0.5), 0);
|
||||
t.equal(l.line()(1), 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('returns the data assigned to it', function(t) {
|
||||
var l = ss.linear_regression().data([[0, 0], [1, 0]]);
|
||||
t.deepEqual(l.data(), [[0, 0], [1, 0]]);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('handles a single-point sample', function(t) {
|
||||
var l = ss.linear_regression().data([[0, 0]]).line();
|
||||
t.deepEqual(l(10), 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('a straight line will have a slope of 0', function(t) {
|
||||
var l = ss.linear_regression().data([[0, 0], [1, 0]]);
|
||||
t.equal(l.m(), 0);
|
||||
t.equal(l.b(), 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('a line at 50% grade', function(t) {
|
||||
var l = ss.linear_regression().data([[0, 0], [1, 0.5]]);
|
||||
t.equal(l.m(), 0.5);
|
||||
t.equal(l.b(), 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('a line with a high y-intercept', function(t) {
|
||||
var l = ss.linear_regression().data([[0, 20], [1, 10]]);
|
||||
t.equal(l.m(), -10);
|
||||
t.equal(l.b(), 20);
|
||||
t.end();
|
||||
});
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,26 @@
|
|||
var test = require('tape');
|
||||
var ss = require('../');
|
||||
|
||||
test('median absolute deviation (mad)', function(t) {
|
||||
test('median absolute deviation of an example on wikipedia', function(t) {
|
||||
t.equal(ss.mad([1, 1, 2, 2, 4, 6, 9]), 1);
|
||||
t.end();
|
||||
});
|
||||
|
||||
// wolfram alpha: median absolute deviation {0,1,2,3,4,5,6,7,8,9,10}
|
||||
test('median absolute deviation of 0-10', function(t) {
|
||||
t.equal(ss.mad([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), 3);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('median absolute deviation of one number is zero', function(t) {
|
||||
t.equal(ss.mad([1]), 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('zero-length corner case', function(t) {
|
||||
t.equal(ss.mad([]), null);
|
||||
t.end();
|
||||
});
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,18 @@
|
|||
var test = require('tape');
|
||||
var ss = require('../');
|
||||
|
||||
test('mean', function(t) {
|
||||
test('can get the mean of two numbers', function(t) {
|
||||
t.equal(ss.mean([1, 2]), 1.5);
|
||||
t.end();
|
||||
});
|
||||
test('can get the mean of one number', function(t) {
|
||||
t.equal(ss.mean([1]), 1);
|
||||
t.end();
|
||||
});
|
||||
test('an empty list has no average', function(t) {
|
||||
t.equal(ss.mean([]), null);
|
||||
t.end();
|
||||
});
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,38 @@
|
|||
var test = require('tape');
|
||||
var ss = require('../');
|
||||
|
||||
test('median', function(t) {
|
||||
test('can get the median of three numbers', function(t) {
|
||||
t.equal(ss.median([1, 2, 3]), 2);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('can get the median of two numbers', function(t) {
|
||||
t.equal(ss.median([1, 2]), 1.5);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('can get the median of four numbers', function(t) {
|
||||
t.equal(ss.median([1, 2, 3, 4]), 2.5);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('gives null for the median of an empty list', function(t) {
|
||||
t.equal(ss.median([]), null);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('sorts numbers numerically', function(t) {
|
||||
t.equal(ss.median([8, 9, 10]), 9);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('does not change the sorting order of its input', function(t) {
|
||||
var x = [1, 0];
|
||||
t.equal(ss.median(x), 0.5);
|
||||
t.equal(x[0], 1);
|
||||
t.equal(x[1], 0);
|
||||
t.end();
|
||||
});
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,23 @@
|
|||
var test = require('tape');
|
||||
var ss = require('../');
|
||||
|
||||
test('min', function(t) {
|
||||
test('can get the minimum of one number', function(t) {
|
||||
t.equal(ss.min([1]), 1);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('can get the minimum of three numbers', function(t) {
|
||||
t.equal(ss.min([1, 7, -1000]), -1000);
|
||||
t.end();
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('max', function(t) {
|
||||
test('can get the maximum of three numbers', function(t) {
|
||||
t.equal(ss.max([1, 7, -1000]), 7);
|
||||
t.end();
|
||||
});
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,34 @@
|
|||
var test = require('tape');
|
||||
var ss = require('../');
|
||||
|
||||
test('mixin', function(t) {
|
||||
test('can mix into a single array', function(t) {
|
||||
var even = ss.mixin([2, 4, 6, 8]);
|
||||
t.equal(even.sum(), 20);
|
||||
t.equal(even.mean(), 5);
|
||||
t.equal(even.max(), 8);
|
||||
t.equal(even.min(), 2);
|
||||
t.equal(even.sample_skewness(), 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('can mix into Array.prototype', function(t) {
|
||||
ss.mixin();
|
||||
var even = [2, 4, 6, 8];
|
||||
t.equal(even.sum(), 20);
|
||||
t.equal(even.mean(), 5);
|
||||
t.equal(even.max(), 8);
|
||||
t.equal(even.min(), 2);
|
||||
t.equal(even.sample_skewness(), 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('mixins can take arguments', function(t) {
|
||||
ss.mixin();
|
||||
var even = [2, 4, 6, 8];
|
||||
t.equal(even.quantile(0.2), 2);
|
||||
t.equal(even.quantile(0.8), 8);
|
||||
t.end();
|
||||
});
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,37 @@
|
|||
var test = require('tape');
|
||||
var ss = require('../');
|
||||
|
||||
test('mode', function(t) {
|
||||
test('the mode of a single-number array is that one number', function(t) {
|
||||
t.equal(ss.mode([1]), 1);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('the mode of a two-number array is that one number', function(t) {
|
||||
t.equal(ss.mode([1, 1]), 1);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('other cases', function(t) {
|
||||
t.equal(ss.mode([1, 1, 2]), 1);
|
||||
t.equal(ss.mode([1, 1, 2, 3]), 1);
|
||||
t.equal(ss.mode([1, 1, 2, 3, 3]), 1);
|
||||
t.equal(ss.mode([1, 1, 2, 3, 3, 3]), 3);
|
||||
t.equal(ss.mode([1, 1, 2, 2, 2, 2, 3, 3, 3]), 2);
|
||||
t.equal(ss.mode([1, 2, 3, 4, 5]), 1);
|
||||
t.equal(ss.mode([1, 2, 3, 4, 5, 5]), 5);
|
||||
t.equal(ss.mode([1, 1, 1, 2, 2, 3, 3, 4, 4]), 1);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('the mode of an empty array is null', function(t) {
|
||||
t.equal(ss.mode([]), null);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('the mode of a three-number array with two same numbers is the repeated one', function(t) {
|
||||
t.equal(ss.mode([1, 2, 2]), 2);
|
||||
t.end();
|
||||
});
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,60 @@
|
|||
var test = require('tape');
|
||||
var ss = require('../');
|
||||
|
||||
test('natural distribution and z-score', function(t) {
|
||||
|
||||
test('normal table is exposed in the API', function(t) {
|
||||
t.equal(ss.standard_normal_table.length, 310);
|
||||
t.equal(ss.standard_normal_table[0], 0.5);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('P(Z <= 0.4) is 0.6554', function(t) {
|
||||
// Taken from the examples of use in http://en.wikipedia.org/wiki/Standard_normal_table
|
||||
t.equal(ss.cumulative_std_normal_probability(0.4), 0.6554);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('P(Z <= -1.20) is 0.1151', function(t) {
|
||||
// Taken from the examples of use in http://en.wikipedia.org/wiki/Standard_normal_table
|
||||
t.equal(ss.cumulative_std_normal_probability(-1.20), 0.1151);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('P(X <= 82) when X ~ N (80, 25) is 0.6554', function(t) {
|
||||
// Taken from the examples of use in http://en.wikipedia.org/wiki/Standard_normal_table
|
||||
// A professor's exam scores are approximately distributed normally with mean 80 and standard deviation 5.
|
||||
// What is the probability that a student scores an 82 or less?
|
||||
t.equal(ss.cumulative_std_normal_probability(ss.z_score(82, 80, 5)), 0.6554);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('P(X >= 90) when X ~ N (80, 25) is 0.0228', function(t) {
|
||||
// Taken from the examples of use in http://en.wikipedia.org/wiki/Standard_normal_table
|
||||
// A professor's exam scores are approximately distributed normally with mean 80 and standard deviation 5.
|
||||
// What is the probability that a student scores a 90 or more?
|
||||
t.equal(+(1 - ss.cumulative_std_normal_probability(ss.z_score(90, 80, 5))).toPrecision(5), 0.0228);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('P(X <= 74) when X ~ N (80, 25) is 0.1151', function(t) {
|
||||
// Taken from the examples of use in http://en.wikipedia.org/wiki/Standard_normal_table
|
||||
// A professor's exam scores are approximately distributed normally with mean 80 and standard deviation 5.
|
||||
// What is the probability that a student scores a 74 or less?
|
||||
t.equal(ss.cumulative_std_normal_probability(ss.z_score(74, 80, 5)), 0.1151);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('P(78 <= X <= 88) when X ~ N (80, 25) is 0.6006', function(t) {
|
||||
// Taken from the examples of use in http://en.wikipedia.org/wiki/Standard_normal_table
|
||||
// A professor's exam scores are approximately distributed normally with mean 80 and standard deviation 5.
|
||||
// What is the probability that a student scores between 78 and 88?
|
||||
var prob88 = ss.cumulative_std_normal_probability(ss.z_score(88, 80, 5)),
|
||||
prob78 = ss.cumulative_std_normal_probability(ss.z_score(78, 80, 5));
|
||||
|
||||
t.equal(+(prob88 - prob78).toPrecision(5), 0.6006);
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,37 @@
|
|||
var test = require('tape');
|
||||
var ss = require('../');
|
||||
|
||||
function rnd(n) {
|
||||
return parseFloat(n.toFixed(4));
|
||||
}
|
||||
|
||||
// expected cumulative probabilities taken from Appendix 1, Table I of William W. Hines & Douglas C.
|
||||
// Montgomery, "Probability and Statistics in Engineering and Management Science", Wiley (1980).
|
||||
test('poisson_distribution', function(t) {
|
||||
test('can return generate probability and cumulative probability distributions for lambda = 3.0', function(t) {
|
||||
t.equal('object', typeof ss.poisson_distribution(3.0));
|
||||
t.equal(rnd(ss.poisson_distribution(3.0)[3]), 0.2240, ss.epsilon);
|
||||
t.end();
|
||||
});
|
||||
test('can generate probability and cumulative probability distributions for lambda = 4.0', function(t) {
|
||||
t.equal('object', typeof ss.poisson_distribution(4.0));
|
||||
t.equal(rnd(ss.poisson_distribution(4.0)[2]), 0.1465, ss.epsilon);
|
||||
t.end();
|
||||
});
|
||||
test('can generate probability and cumulative probability distributions for lambda = 5.5', function(t) {
|
||||
t.equal('object', typeof ss.poisson_distribution(5.5));
|
||||
t.equal(rnd(ss.poisson_distribution(5.5)[7]), 0.1234, ss.epsilon);
|
||||
t.end();
|
||||
});
|
||||
test('can generate probability and cumulative probability distributions for lambda = 9.5', function(t) {
|
||||
t.equal('object', typeof ss.poisson_distribution(9.5));
|
||||
t.equal(rnd(ss.poisson_distribution(9.5)[17]), 0.0088, ss.epsilon);
|
||||
t.end();
|
||||
});
|
||||
test('can return null when lambda <= 0', function(t) {
|
||||
t.equal(null, ss.poisson_distribution(0));
|
||||
t.equal(null, ss.poisson_distribution(-10));
|
||||
t.end();
|
||||
});
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,64 @@
|
|||
var test = require('tape');
|
||||
var ss = require('../');
|
||||
|
||||
test('quantile', function(t) {
|
||||
// Data and results from
|
||||
// [Wikipedia](http://en.wikipedia.org/wiki/Quantile#Quantiles_of_a_population)
|
||||
test('can get proper quantiles of an even-length list', function(t) {
|
||||
var even = [3, 6, 7, 8, 8, 10, 13, 15, 16, 20];
|
||||
t.equal(ss.quantile(even, 0.25), 7);
|
||||
t.equal(ss.quantile(even, 0.5), 9);
|
||||
t.equal(ss.quantile(even, 0.75), 15);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('can get proper quantiles of an odd-length list', function(t) {
|
||||
var odd = [3, 6, 7, 8, 8, 9, 10, 13, 15, 16, 20];
|
||||
t.equal(ss.quantile(odd, 0.25), 7);
|
||||
t.equal(ss.quantile(odd, 0.5), 9);
|
||||
t.equal(ss.quantile(odd, 0.75), 15);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('the median quantile is equal to the median', function(t) {
|
||||
var rand = [1, 4, 5, 8];
|
||||
t.equal(ss.quantile(rand, 0.5), ss.median(rand));
|
||||
var rand2 = [10, 50, 2, 4, 4, 5, 8];
|
||||
t.equal(ss.quantile(rand2, 0.5), ss.median(rand2));
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('a zero-length list produces null', function(t) {
|
||||
t.equal(ss.quantile([], 0.5), null);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('test odd-value case', function(t) {
|
||||
t.equal(ss.quantile([0, 1, 2, 3, 4], 0.2), 1);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('bad bounds produce null', function(t) {
|
||||
t.equal(ss.quantile([1, 2, 3], 1.1), null);
|
||||
t.equal(ss.quantile([1, 2, 3], -0.5), null);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('max quantile is equal to the max', function(t) {
|
||||
t.equal(ss.quantile([1, 2, 3], 1), ss.max([1, 2, 3]));
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('min quantile is equal to the min', function(t) {
|
||||
t.equal(ss.quantile([1, 2, 3], 0), ss.min([1, 2, 3]));
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('if quantile arg is an array, response is an array of quantiles', function(t) {
|
||||
var odd = [3, 6, 7, 8, 8, 9, 10, 13, 15, 16, 20];
|
||||
t.deepEqual(ss.quantile(odd, [0, 0.25, 0.5, 0.75, 1]), [3, 7, 9, 15, 20]);
|
||||
t.deepEqual(ss.quantile(odd, [0.75, 0.5]), [15, 9]);
|
||||
t.end();
|
||||
});
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,15 @@
|
|||
var test = require('tape');
|
||||
var ss = require('../');
|
||||
|
||||
test('quantile_sorted', function(t) {
|
||||
// Data and results from
|
||||
// [Wikipedia](http://en.wikipedia.org/wiki/Quantile#Quantiles_of_a_population)
|
||||
test('can get proper quantiles of an even-length list', function(t) {
|
||||
var even = [3, 6, 7, 8, 8, 10, 13, 15, 16, 20];
|
||||
t.equal(ss.quantile_sorted(even, 0.25), 7);
|
||||
t.equal(ss.quantile_sorted(even, 0.5), 9);
|
||||
t.equal(ss.quantile_sorted(even, 0.75), 15);
|
||||
t.end();
|
||||
});
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,26 @@
|
|||
var test = require('tape');
|
||||
var ss = require('../');
|
||||
|
||||
test('r-squared', function(t) {
|
||||
test('says that the r squared of a two-point line is perfect', function(t) {
|
||||
var d = [[0, 0], [1, 1]];
|
||||
var l = ss.linear_regression().data(d);
|
||||
t.equal(ss.r_squared(d, l.line()), 1);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('says that the r squared of a three-point line is not perfect', function(t) {
|
||||
var d = [[0, 0], [0.5, 0.2], [1, 1]];
|
||||
var l = ss.linear_regression().data(d);
|
||||
t.notEqual(ss.r_squared(d, l.line()), 1);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('r-squared of single sample is 1', function(t) {
|
||||
var d = [[0, 0]];
|
||||
var l = ss.linear_regression().data(d);
|
||||
t.equal(ss.r_squared(d, l.line()), 1);
|
||||
t.end();
|
||||
});
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,23 @@
|
|||
var test = require('tape');
|
||||
var ss = require('../');
|
||||
|
||||
function rnd(x) {
|
||||
return Math.round(x * 1000) / 1000;
|
||||
}
|
||||
|
||||
test('root_mean_square', function(t) {
|
||||
// From http://en.wikipedia.org/wiki/Root_mean_square
|
||||
test('can get the RMS of two or more numbers', function(t) {
|
||||
t.equal(ss.root_mean_square([1, 1]), 1);
|
||||
t.equal(rnd(ss.root_mean_square([3, 4, 5])), 4.082);
|
||||
t.equal(rnd(ss.root_mean_square([-0.1, 5, -2, 10])), 5.679);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('returns null for empty lists', function(t) {
|
||||
t.equal(ss.root_mean_square([]), null);
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,19 @@
|
|||
var test = require('tape');
|
||||
var Random = require('random-js');
|
||||
var random = new Random(Random.engines.mt19937().seed(0));
|
||||
var ss = require('../');
|
||||
|
||||
function rng() { return random.real(0, 1); }
|
||||
|
||||
test('sample', function(t) {
|
||||
t.deepEqual(ss.sample([], 0, rng), [], 'edge case - zero array');
|
||||
t.deepEqual(ss.sample([], 2, rng), [], 'edge case - zero array');
|
||||
t.deepEqual(ss.sample([1,2,3], 0, rng, 0), [], 'edge case - zero array');
|
||||
t.deepEqual(ss.sample([1,2,3], 1, rng), [1], 'edge case - sample of 1');
|
||||
t.deepEqual(ss.sample([1,2,3], 1, rng), [2]);
|
||||
t.deepEqual(ss.sample([1,2,3], 3, rng), [2,3,1]);
|
||||
t.deepEqual(ss.sample([1,2,3,4], 2, rng), [3,1]);
|
||||
t.deepEqual(ss.sample([1,2,3,4,6,7,8], 2, rng), [8,7]);
|
||||
t.deepEqual(ss.sample(['foo', 'bar'], 1, rng), ['foo'], 'non-number contents');
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,29 @@
|
|||
var test = require('tape');
|
||||
var ss = require('../');
|
||||
|
||||
function rnd(x) {
|
||||
return Math.round(x * 1000) / 1000;
|
||||
}
|
||||
|
||||
test('sample correlation', function(t) {
|
||||
|
||||
test('can get the sample correlation of identical arrays', function(t) {
|
||||
var data = [1, 2, 3, 4, 5, 6];
|
||||
t.equal(rnd(ss.sample_correlation(data, data)), 1);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('can get the sample correlation of different arrays', function(t) {
|
||||
var a = [1, 2, 3, 4, 5, 6];
|
||||
var b = [2, 2, 3, 4, 5, 60];
|
||||
t.equal(rnd(ss.sample_correlation(a, b)), 0.691);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('zero-length corner case', function(t) {
|
||||
t.equal(rnd(ss.sample_correlation([], [])), 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,34 @@
|
|||
var test = require('tape');
|
||||
var ss = require('../');
|
||||
|
||||
function rnd(x) {
|
||||
return Math.round(x * 1000) / 1000;
|
||||
}
|
||||
|
||||
test('sample covariance', function(t) {
|
||||
test('can get perfect negative covariance', function(t) {
|
||||
var x = [1, 2, 3, 4, 5, 6];
|
||||
var y = [6, 5, 4, 3, 2, 1];
|
||||
t.equal(rnd(ss.sample_covariance(x, y)), -3.5);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('covariance of something with itself is its variance', function(t) {
|
||||
var x = [1, 2, 3, 4, 5, 6];
|
||||
t.equal(rnd(ss.sample_covariance(x, x)), 3.5);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('covariance is zero for something with no correlation', function(t) {
|
||||
var x = [1, 2, 3, 4, 5, 6];
|
||||
var y = [1, 1, 2, 2, 1, 1];
|
||||
t.equal(rnd(ss.sample_covariance(x, y)), 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('zero-length corner case', function(t) {
|
||||
t.equal(rnd(ss.sample_covariance([], [])), 0);
|
||||
t.end();
|
||||
});
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,48 @@
|
|||
var test = require('tape');
|
||||
var ss = require('../');
|
||||
|
||||
test('sample skewness', function(t) {
|
||||
|
||||
test('the skewness of an empty sample is null', function(t) {
|
||||
var data = [];
|
||||
t.equal(ss.sample_skewness(data), null);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('the skewness of an sample with one number is null', function(t) {
|
||||
var data = [1];
|
||||
t.equal(ss.sample_skewness(data), null);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('the skewness of an sample with two numbers is null', function(t) {
|
||||
var data = [1, 2];
|
||||
t.equal(ss.sample_skewness(data), null);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('can calculate the skewness of SAS example 1', function(t) {
|
||||
// Data and answer taken from SKEWNESS function documentation at
|
||||
// http://support.sas.com/documentation/c../lrdict/64316/HTML/default/viewer.htm#a000245947.htm
|
||||
var data = [0, 1, 1];
|
||||
t.equal(+ss.sample_skewness(data).toPrecision(10), -1.732050808);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('can calculate the skewness of SAS example 2', function(t) {
|
||||
// Data and answer taken from SKEWNESS function documentation at
|
||||
// http://support.sas.com/documentation/c../lrdict/64316/HTML/default/viewer.htm#a000245947.htm
|
||||
var data = [2, 4, 6, 3, 1];
|
||||
t.equal(+ss.sample_skewness(data).toPrecision(10), 0.5901286564);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('can calculate the skewness of SAS example 3', function(t) {
|
||||
// Data and answer taken from SKEWNESS function documentation at
|
||||
// http://support.sas.com/documentation/c../lrdict/64316/HTML/default/viewer.htm#a000245947.htm
|
||||
var data = [2, 0, 0];
|
||||
t.equal(+ss.sample_skewness(data).toPrecision(10), 1.732050808);
|
||||
t.end();
|
||||
});
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,19 @@
|
|||
var test = require('tape');
|
||||
var ss = require('../');
|
||||
|
||||
function rnd(x) {
|
||||
return Math.round(x * 1000) / 1000;
|
||||
}
|
||||
|
||||
test('sample_standard_deviation', function(t) {
|
||||
test('can get the standard deviation of an example on wikipedia', function(t) {
|
||||
t.equal(rnd(ss.sample_standard_deviation([2, 4, 4, 4, 5, 5, 7, 9])), 2.138);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('zero-length corner case', function(t) {
|
||||
t.equal(rnd(ss.sample_standard_deviation([])), 0);
|
||||
t.end();
|
||||
});
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,38 @@
|
|||
var test = require('tape');
|
||||
var ss = require('../');
|
||||
|
||||
function rnd(x) {
|
||||
return Math.round(x * 1000) / 1000;
|
||||
}
|
||||
|
||||
test('sample variance', function(t) {
|
||||
test('can get the sample variance of a six-sided die', function(t) {
|
||||
t.equal(rnd(ss.sample_variance([1, 2, 3, 4, 5, 6])), 3.5);
|
||||
t.end();
|
||||
});
|
||||
|
||||
// confirmed in R
|
||||
//
|
||||
// > var(1:10)
|
||||
// [1] 9.166667
|
||||
test('can get the sample variance of numbers 1-10', function(t) {
|
||||
t.equal(rnd(ss.sample_variance([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])), 9.167);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('the sample variance of two numbers that are the same is 0', function(t) {
|
||||
t.equal(rnd(ss.sample_variance([1, 1])), 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('the sample variance of one number is null', function(t) {
|
||||
t.equal(ss.sample_variance([1]), null);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('the sample variance of no numbers is null', function(t) {
|
||||
t.equal(ss.sample_variance([]), null);
|
||||
t.end();
|
||||
});
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,24 @@
|
|||
var test = require('tape');
|
||||
var Random = require('random-js');
|
||||
var random = new Random(Random.engines.mt19937().seed(0));
|
||||
var ss = require('../');
|
||||
|
||||
function rng() { return random.real(0, 1); }
|
||||
|
||||
test('shuffle', function(t) {
|
||||
var input = [1, 2, 3, 4, 5, 6];
|
||||
t.deepEqual(ss.shuffle([], rng), []);
|
||||
t.deepEqual(ss.shuffle(input, rng), [1, 5, 3, 2, 4, 6]);
|
||||
t.deepEqual(input, [1, 2, 3, 4, 5, 6], 'does not change original array');
|
||||
t.deepEqual(ss.shuffle(input, rng), [5, 4, 1, 3, 6, 2]);
|
||||
t.deepEqual(input, [1, 2, 3, 4, 5, 6], 'does not change original array');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('shuffle_in_place', function(t) {
|
||||
var input = [1, 2, 3, 4, 5, 6];
|
||||
t.deepEqual(ss.shuffle_in_place([], rng), []);
|
||||
t.deepEqual(ss.shuffle_in_place(input, rng), [6, 1, 5, 2, 4, 3]);
|
||||
t.deepEqual(input, [6, 1, 5, 2, 4, 3], 'changes original array');
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,39 @@
|
|||
var test = require('tape');
|
||||
var ss = require('../');
|
||||
|
||||
function rnd(x) {
|
||||
return Math.round(x * 1000) / 1000;
|
||||
}
|
||||
|
||||
test('standard_deviation', function(t) {
|
||||
test('can get the standard deviation of an example on wikipedia', function(t) {
|
||||
t.equal(rnd(ss.standard_deviation([2, 4, 4, 4, 5, 5, 7, 9])), 2);
|
||||
t.end();
|
||||
});
|
||||
|
||||
// confirmed with numpy
|
||||
// In [4]: numpy.std([1,2,3])
|
||||
// Out[4]: 0.81649658092772603
|
||||
test('can get the standard deviation of 1-3', function(t) {
|
||||
t.equal(rnd(ss.standard_deviation([1, 2, 3])), 0.816);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('zero-length array corner case', function(t) {
|
||||
t.equal(rnd(ss.standard_deviation([])), 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
// In [6]: numpy.std([0,1,2,3,4,5,6,7,8,9,10])
|
||||
// Out[6]: 3.1622776601683795
|
||||
test('can get the standard deviation of 1-10', function(t) {
|
||||
t.equal(rnd(ss.standard_deviation([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])), 3.162);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('the standard deviation of one number is zero', function(t) {
|
||||
t.equal(rnd(ss.standard_deviation([1])), 0);
|
||||
t.end();
|
||||
});
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
var test = require('tape');
|
||||
var ss = require('../');
|
||||
|
||||
test('standard_normal_table', function(t) {
|
||||
test('all entries are numeric', function(t) {
|
||||
for (var i = 0; i < ss.standard_normal_table.length; i++) {
|
||||
t.equal(typeof ss.standard_normal_table[i], 'number');
|
||||
t.ok(ss.standard_normal_table[i] >= 0);
|
||||
t.ok(ss.standard_normal_table[i] <= 1);
|
||||
}
|
||||
t.end();
|
||||
});
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,15 @@
|
|||
var test = require('tape');
|
||||
var ss = require('../');
|
||||
|
||||
test('sum', function(t) {
|
||||
test('can get the sum of two numbers', function(t) {
|
||||
t.equal(ss.sum([1, 2]), 3);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('the sum of no numbers is zero', function(t) {
|
||||
t.equal(ss.sum([]), 0);
|
||||
t.end();
|
||||
});
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,38 @@
|
|||
var test = require('tape'),
|
||||
ss = require('../');
|
||||
|
||||
test('t test', function(t) {
|
||||
|
||||
test('can compare a known value to the mean of samples', function(t) {
|
||||
var res = ss.t_test([1, 2, 3, 4, 5, 6], 3.385);
|
||||
t.equal(res, 0.1649415480881466);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('can test independency of two samples', function(t) {
|
||||
var res = ss.t_test_two_sample([1, 2, 3, 4], [3, 4, 5, 6], 0);
|
||||
t.equal(res, -2.1908902300206643);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('can test independency of two samples (mu == -2)', function(t) {
|
||||
var res = ss.t_test_two_sample([1, 2, 3, 4], [3, 4, 5, 6], -2);
|
||||
t.equal(res, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('can test independency of two samples of different lengths', function(t) {
|
||||
var res = ss.t_test_two_sample([1, 2, 3, 4], [3, 4, 5, 6, 1, 2, 0]);
|
||||
t.equal(res, -0.4165977904505309);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('has an edge case for one sample being of size zero', function(t) {
|
||||
t.equal(ss.t_test_two_sample([1, 2, 3, 4], []), null);
|
||||
t.equal(ss.t_test_two_sample([], [1, 2, 3, 4]), null);
|
||||
t.equal(ss.t_test_two_sample([], []), null);
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,24 @@
|
|||
var test = require('tape');
|
||||
var ss = require('../');
|
||||
|
||||
function rnd(x) {
|
||||
return Math.round(x * 1000) / 1000;
|
||||
}
|
||||
|
||||
test('variance', function(t) {
|
||||
test('can get the variance of a six-sided die', function(t) {
|
||||
t.equal(rnd(ss.variance([1, 2, 3, 4, 5, 6])), 2.917);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('the variance of one number is zero', function(t) {
|
||||
t.equal(rnd(ss.variance([1])), 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('the variance of no numbers is null', function(t) {
|
||||
t.equal(ss.variance([]), null);
|
||||
t.end();
|
||||
});
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,70 @@
|
|||
.highlight .hll { background-color: #ffffcc }
|
||||
.highlight { background: #f0f3f3; }
|
||||
.highlight .c { color: #0099FF; font-style: italic } /* Comment */
|
||||
.highlight .err { color: #AA0000; background-color: #FFAAAA } /* Error */
|
||||
.highlight .k { color: #006699; font-weight: bold } /* Keyword */
|
||||
.highlight .o { color: #555555 } /* Operator */
|
||||
.highlight .cm { color: #0099FF; font-style: italic } /* Comment.Multiline */
|
||||
.highlight .cp { color: #009999 } /* Comment.Preproc */
|
||||
.highlight .c1 { color: #0099FF; font-style: italic } /* Comment.Single */
|
||||
.highlight .cs { color: #0099FF; font-weight: bold; font-style: italic } /* Comment.Special */
|
||||
.highlight .gd { background-color: #FFCCCC; border: 1px solid #CC0000 } /* Generic.Deleted */
|
||||
.highlight .ge { font-style: italic } /* Generic.Emph */
|
||||
.highlight .gr { color: #FF0000 } /* Generic.Error */
|
||||
.highlight .gh { color: #003300; font-weight: bold } /* Generic.Heading */
|
||||
.highlight .gi { background-color: #CCFFCC; border: 1px solid #00CC00 } /* Generic.Inserted */
|
||||
.highlight .go { color: #AAAAAA } /* Generic.Output */
|
||||
.highlight .gp { color: #000099; font-weight: bold } /* Generic.Prompt */
|
||||
.highlight .gs { font-weight: bold } /* Generic.Strong */
|
||||
.highlight .gu { color: #003300; font-weight: bold } /* Generic.Subheading */
|
||||
.highlight .gt { color: #99CC66 } /* Generic.Traceback */
|
||||
.highlight .kc { color: #006699; font-weight: bold } /* Keyword.Constant */
|
||||
.highlight .kd { color: #006699; font-weight: bold } /* Keyword.Declaration */
|
||||
.highlight .kn { color: #006699; font-weight: bold } /* Keyword.Namespace */
|
||||
.highlight .kp { color: #006699 } /* Keyword.Pseudo */
|
||||
.highlight .kr { color: #006699; font-weight: bold } /* Keyword.Reserved */
|
||||
.highlight .kt { color: #007788; font-weight: bold } /* Keyword.Type */
|
||||
.highlight .m { color: #FF6600 } /* Literal.Number */
|
||||
.highlight .s { color: #CC3300 } /* Literal.String */
|
||||
.highlight .na { color: #330099 } /* Name.Attribute */
|
||||
.highlight .nb { color: #336666 } /* Name.Builtin */
|
||||
.highlight .nc { color: #00AA88; font-weight: bold } /* Name.Class */
|
||||
.highlight .no { color: #336600 } /* Name.Constant */
|
||||
.highlight .nd { color: #9999FF } /* Name.Decorator */
|
||||
.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */
|
||||
.highlight .ne { color: #CC0000; font-weight: bold } /* Name.Exception */
|
||||
.highlight .nf { color: #CC00FF } /* Name.Function */
|
||||
.highlight .nl { color: #9999FF } /* Name.Label */
|
||||
.highlight .nn { color: #00CCFF; font-weight: bold } /* Name.Namespace */
|
||||
.highlight .nt { color: #330099; font-weight: bold } /* Name.Tag */
|
||||
.highlight .nv { color: #003333 } /* Name.Variable */
|
||||
.highlight .ow { color: #000000; font-weight: bold } /* Operator.Word */
|
||||
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
|
||||
.highlight .mf { color: #FF6600 } /* Literal.Number.Float */
|
||||
.highlight .mh { color: #FF6600 } /* Literal.Number.Hex */
|
||||
.highlight .mi { color: #FF6600 } /* Literal.Number.Integer */
|
||||
.highlight .mo { color: #FF6600 } /* Literal.Number.Oct */
|
||||
.highlight .sb { color: #CC3300 } /* Literal.String.Backtick */
|
||||
.highlight .sc { color: #CC3300 } /* Literal.String.Char */
|
||||
.highlight .sd { color: #CC3300; font-style: italic } /* Literal.String.Doc */
|
||||
.highlight .s2 { color: #CC3300 } /* Literal.String.Double */
|
||||
.highlight .se { color: #CC3300; font-weight: bold } /* Literal.String.Escape */
|
||||
.highlight .sh { color: #CC3300 } /* Literal.String.Heredoc */
|
||||
.highlight .si { color: #AA0000 } /* Literal.String.Interpol */
|
||||
.highlight .sx { color: #CC3300 } /* Literal.String.Other */
|
||||
.highlight .sr { color: #33AAAA } /* Literal.String.Regex */
|
||||
.highlight .s1 { color: #CC3300 } /* Literal.String.Single */
|
||||
.highlight .ss { color: #FFCC33 } /* Literal.String.Symbol */
|
||||
.highlight .bp { color: #336666 } /* Name.Builtin.Pseudo */
|
||||
.highlight .vc { color: #003333 } /* Name.Variable.Class */
|
||||
.highlight .vg { color: #003333 } /* Name.Variable.Global */
|
||||
.highlight .vi { color: #003333 } /* Name.Variable.Instance */
|
||||
.highlight .il { color: #FF6600 } /* Literal.Number.Integer.Long */
|
||||
|
||||
.type-csharp .highlight .k { color: #0000FF }
|
||||
.type-csharp .highlight .kt { color: #0000FF }
|
||||
.type-csharp .highlight .nf { color: #000000; font-weight: normal }
|
||||
.type-csharp .highlight .nc { color: #2B91AF }
|
||||
.type-csharp .highlight .nn { color: #000000 }
|
||||
.type-csharp .highlight .s { color: #A31515 }
|
||||
.type-csharp .highlight .sc { color: #A31515 }
|
|
@ -0,0 +1,425 @@
|
|||
/*******************************************************************************
|
||||
Slate Theme for GitHub Pages
|
||||
by Jason Costello, @jsncostello
|
||||
*******************************************************************************/
|
||||
|
||||
@import url(pygment_trac.css);
|
||||
|
||||
/*******************************************************************************
|
||||
MeyerWeb Reset
|
||||
*******************************************************************************/
|
||||
|
||||
html, body, div, span, applet, object, iframe,
|
||||
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||
a, abbr, acronym, address, big, cite, code,
|
||||
del, dfn, em, img, ins, kbd, q, s, samp,
|
||||
small, strike, strong, sub, sup, tt, var,
|
||||
b, u, i, center,
|
||||
dl, dt, dd, ol, ul, li,
|
||||
fieldset, form, label, legend,
|
||||
table, caption, tbody, tfoot, thead, tr, th, td,
|
||||
article, aside, canvas, details, embed,
|
||||
figure, figcaption, footer, header, hgroup,
|
||||
menu, nav, output, ruby, section, summary,
|
||||
time, mark, audio, video {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
font: inherit;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
/* HTML5 display-role reset for older browsers */
|
||||
article, aside, details, figcaption, figure,
|
||||
footer, header, hgroup, menu, nav, section {
|
||||
display: block;
|
||||
}
|
||||
|
||||
ol, ul {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
Theme Styles
|
||||
*******************************************************************************/
|
||||
|
||||
body {
|
||||
box-sizing: border-box;
|
||||
color:#373737;
|
||||
background: #212121;
|
||||
font-size: 16px;
|
||||
font-family: 'Myriad Pro', Calibri, Helvetica, Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
margin: 10px 0;
|
||||
font-weight: 700;
|
||||
color:#222222;
|
||||
font-family: 'Lucida Grande', 'Calibri', Helvetica, Arial, sans-serif;
|
||||
letter-spacing: -1px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 36px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
h2 {
|
||||
padding-bottom: 10px;
|
||||
font-size: 32px;
|
||||
background: url('../images/bg_hr.png') repeat-x bottom;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 21px;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 10px 0 15px 0;
|
||||
}
|
||||
|
||||
footer p {
|
||||
color: #f2f2f2;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #007edf;
|
||||
text-shadow: none;
|
||||
|
||||
transition: color 0.5s ease;
|
||||
transition: text-shadow 0.5s ease;
|
||||
-webkit-transition: color 0.5s ease;
|
||||
-webkit-transition: text-shadow 0.5s ease;
|
||||
-moz-transition: color 0.5s ease;
|
||||
-moz-transition: text-shadow 0.5s ease;
|
||||
-o-transition: color 0.5s ease;
|
||||
-o-transition: text-shadow 0.5s ease;
|
||||
-ms-transition: color 0.5s ease;
|
||||
-ms-transition: text-shadow 0.5s ease;
|
||||
}
|
||||
|
||||
a:hover, a:focus {text-decoration: underline;}
|
||||
|
||||
footer a {
|
||||
color: #F2F2F2;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
em {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
img {
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
max-width: 739px;
|
||||
padding: 5px;
|
||||
margin: 10px 0 10px 0;
|
||||
border: 1px solid #ebebeb;
|
||||
|
||||
box-shadow: 0 0 5px #ebebeb;
|
||||
-webkit-box-shadow: 0 0 5px #ebebeb;
|
||||
-moz-box-shadow: 0 0 5px #ebebeb;
|
||||
-o-box-shadow: 0 0 5px #ebebeb;
|
||||
-ms-box-shadow: 0 0 5px #ebebeb;
|
||||
}
|
||||
|
||||
p img {
|
||||
display: inline;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
border: none;
|
||||
}
|
||||
|
||||
pre, code {
|
||||
width: 100%;
|
||||
color: #222;
|
||||
background-color: #fff;
|
||||
|
||||
font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace;
|
||||
font-size: 14px;
|
||||
|
||||
border-radius: 2px;
|
||||
-moz-border-radius: 2px;
|
||||
-webkit-border-radius: 2px;
|
||||
}
|
||||
|
||||
pre {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
box-shadow: 0 0 10px rgba(0,0,0,.1);
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
code {
|
||||
padding: 3px;
|
||||
margin: 0 3px;
|
||||
box-shadow: 0 0 10px rgba(0,0,0,.1);
|
||||
}
|
||||
|
||||
pre code {
|
||||
display: block;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
color: #666;
|
||||
margin-bottom: 20px;
|
||||
padding: 0 0 0 20px;
|
||||
border-left: 3px solid #bbb;
|
||||
}
|
||||
|
||||
|
||||
ul, ol, dl {
|
||||
margin-bottom: 15px
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-position: inside;
|
||||
list-style: disc;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
ol {
|
||||
list-style-position: inside;
|
||||
list-style: decimal;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
dl dt {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
dl dd {
|
||||
padding-left: 20px;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
dl p {
|
||||
padding-left: 20px;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
hr {
|
||||
height: 1px;
|
||||
margin-bottom: 5px;
|
||||
border: none;
|
||||
background: url('../images/bg_hr.png') repeat-x center;
|
||||
}
|
||||
|
||||
table {
|
||||
border: 1px solid #373737;
|
||||
margin-bottom: 20px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
th {
|
||||
font-family: 'Lucida Grande', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
padding: 10px;
|
||||
background: #373737;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 10px;
|
||||
border: 1px solid #373737;
|
||||
}
|
||||
|
||||
form {
|
||||
background: #f2f2f2;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
Full-Width Styles
|
||||
*******************************************************************************/
|
||||
|
||||
.outer {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.inner {
|
||||
position: relative;
|
||||
max-width: 640px;
|
||||
padding: 20px 10px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
#forkme_banner {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top:0;
|
||||
right: 10px;
|
||||
z-index: 10;
|
||||
padding: 10px 50px 10px 10px;
|
||||
color: #fff;
|
||||
background: url('../images/blacktocat.png') #0090ff no-repeat 95% 50%;
|
||||
font-weight: 700;
|
||||
box-shadow: 0 0 10px rgba(0,0,0,.5);
|
||||
border-bottom-left-radius: 2px;
|
||||
border-bottom-right-radius: 2px;
|
||||
}
|
||||
|
||||
#header_wrap {
|
||||
background: #212121;
|
||||
background: -moz-linear-gradient(top, #373737, #212121);
|
||||
background: -webkit-linear-gradient(top, #373737, #212121);
|
||||
background: -ms-linear-gradient(top, #373737, #212121);
|
||||
background: -o-linear-gradient(top, #373737, #212121);
|
||||
background: linear-gradient(top, #373737, #212121);
|
||||
}
|
||||
|
||||
#header_wrap .inner {
|
||||
padding: 50px 10px 30px 10px;
|
||||
}
|
||||
|
||||
#project_title {
|
||||
margin: 0;
|
||||
color: #fff;
|
||||
font-size: 42px;
|
||||
font-weight: 700;
|
||||
text-shadow: #111 0px 0px 10px;
|
||||
}
|
||||
|
||||
#project_tagline {
|
||||
color: #fff;
|
||||
font-size: 24px;
|
||||
font-weight: 300;
|
||||
background: none;
|
||||
text-shadow: #111 0px 0px 10px;
|
||||
}
|
||||
|
||||
#downloads {
|
||||
position: absolute;
|
||||
width: 210px;
|
||||
z-index: 10;
|
||||
bottom: -40px;
|
||||
right: 0;
|
||||
height: 70px;
|
||||
background: url('../images/icon_download.png') no-repeat 0% 90%;
|
||||
}
|
||||
|
||||
.zip_download_link {
|
||||
display: block;
|
||||
float: right;
|
||||
width: 90px;
|
||||
height:70px;
|
||||
text-indent: -5000px;
|
||||
overflow: hidden;
|
||||
background: url(../images/sprite_download.png) no-repeat bottom left;
|
||||
}
|
||||
|
||||
.tar_download_link {
|
||||
display: block;
|
||||
float: right;
|
||||
width: 90px;
|
||||
height:70px;
|
||||
text-indent: -5000px;
|
||||
overflow: hidden;
|
||||
background: url(../images/sprite_download.png) no-repeat bottom right;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.zip_download_link:hover {
|
||||
background: url(../images/sprite_download.png) no-repeat top left;
|
||||
}
|
||||
|
||||
.tar_download_link:hover {
|
||||
background: url(../images/sprite_download.png) no-repeat top right;
|
||||
}
|
||||
|
||||
#main_content_wrap {
|
||||
background: #f2f2f2;
|
||||
border-top: 1px solid #111;
|
||||
border-bottom: 1px solid #111;
|
||||
}
|
||||
|
||||
#main_content {
|
||||
padding-top: 40px;
|
||||
}
|
||||
|
||||
#footer_wrap {
|
||||
background: #212121;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
Small Device Styles
|
||||
*******************************************************************************/
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
body {
|
||||
font-size:14px;
|
||||
}
|
||||
|
||||
#downloads {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.inner {
|
||||
min-width: 320px;
|
||||
max-width: 480px;
|
||||
}
|
||||
|
||||
#project_title {
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 21px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
code, pre {
|
||||
min-width: 320px;
|
||||
max-width: 480px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
}
|
|
@ -8,7 +8,7 @@ describe('sh.cd doesn\'t seem to be working from a relative path if I am one or
|
|||
|
||||
it('should properly deal with relative paths missing ./ and ../', function(done) {
|
||||
var fs = util.fs();
|
||||
var sh = fs.Shell();
|
||||
var sh = new fs.Shell();
|
||||
|
||||
sh.mkdirp('/home/scott', function(err) {
|
||||
if(err) throw err;
|
||||
|
|
|
@ -9,7 +9,7 @@ describe('sh.ls and deep directory trees', function() {
|
|||
|
||||
it('should not crash when calling sh.ls() on deep directory layouts', function(done) {
|
||||
var fs = util.fs();
|
||||
var sh = fs.Shell();
|
||||
var sh = new fs.Shell();
|
||||
|
||||
var path = '';
|
||||
for(var i=0; i<50; i++) {
|
||||
|
@ -29,7 +29,7 @@ describe('sh.ls and deep directory trees', function() {
|
|||
|
||||
it('should not crash when calling sh.ls() on wide directory layouts', function(done) {
|
||||
var fs = util.fs();
|
||||
var sh = fs.Shell();
|
||||
var sh = new fs.Shell();
|
||||
|
||||
var dirName = '/dir';
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ require("./spec/times.spec");
|
|||
require("./spec/time-flags.spec");
|
||||
require("./spec/fs.watch.spec");
|
||||
require("./spec/errors.spec");
|
||||
require("./spec/fs.shell.spec");
|
||||
|
||||
// Filer.FileSystem.providers.*
|
||||
require("./spec/providers/providers.spec");
|
||||
|
@ -54,6 +55,7 @@ require("./spec/shell/ls.spec");
|
|||
require("./spec/shell/rm.spec");
|
||||
require("./spec/shell/env.spec");
|
||||
require("./spec/shell/mkdirp.spec");
|
||||
require("./spec/shell/find.spec");
|
||||
|
||||
// Ported node.js tests (filenames match names in https://github.com/joyent/node/tree/master/test)
|
||||
require("./spec/node-js/simple/test-fs-mkdir");
|
||||
|
|
|
@ -17,6 +17,8 @@ function IndexedDBTestProvider(name) {
|
|||
var that = this;
|
||||
|
||||
function cleanup(callback) {
|
||||
callback = callback || function(){};
|
||||
|
||||
if(!that.provider || _done) {
|
||||
return callback();
|
||||
}
|
||||
|
@ -27,7 +29,6 @@ function IndexedDBTestProvider(name) {
|
|||
that.provider.db.close();
|
||||
}
|
||||
|
||||
callback = callback || function(){};
|
||||
var request = indexedDB.deleteDatabase(name);
|
||||
function finished() {
|
||||
that.provider = null;
|
||||
|
|
|
@ -4,6 +4,8 @@ function MemoryTestProvider(name) {
|
|||
var that = this;
|
||||
|
||||
function cleanup(callback) {
|
||||
callback = callback || function(){};
|
||||
|
||||
that.provider = null;
|
||||
callback();
|
||||
}
|
||||
|
|
|
@ -85,7 +85,8 @@
|
|||
}
|
||||
|
||||
function shell(options) {
|
||||
return fs().Shell(options);
|
||||
var _fs = fs();
|
||||
return new _fs.Shell(options);
|
||||
}
|
||||
|
||||
function cleanup(callback) {
|
||||
|
|
|
@ -12,9 +12,12 @@ function WebSQLTestProvider(name) {
|
|||
var that = this;
|
||||
|
||||
function cleanup(callback) {
|
||||
callback = callback || function(){};
|
||||
|
||||
if(!that.provider || _done) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
// Provider is there, but db was never touched
|
||||
if(!that.provider.db) {
|
||||
return callback();
|
||||
|
|
|
@ -9,4 +9,8 @@ describe("Filer", function() {
|
|||
it("has FileSystem constructor", function() {
|
||||
expect(typeof Filer.FileSystem).to.equal('function');
|
||||
});
|
||||
|
||||
it("has Shell constructor", function() {
|
||||
expect(typeof Filer.Shell).to.equal('function');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -61,4 +61,28 @@ describe('fs.read', function() {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail to read a directory', function(done) {
|
||||
var fs = util.fs();
|
||||
var buf = new Filer.Buffer(20);
|
||||
var buf2 = new Filer.Buffer(20);
|
||||
buf.fill(0);
|
||||
buf2.fill(0);
|
||||
|
||||
fs.mkdir('/mydir', function(error) {
|
||||
if(error) throw err;
|
||||
|
||||
fs.open('/mydir', 'r', function(error, fd) {
|
||||
if(error) throw error;
|
||||
|
||||
fs.read(fd, buf, 0, buf.length, 0, function(error, result) {
|
||||
expect(error).to.exist;
|
||||
expect(error.code).to.equal('EISDIR');
|
||||
expect(result).to.equal(0);
|
||||
expect(buf).to.deep.equal(buf2);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -47,4 +47,108 @@ describe('fs.rename', function() {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should rename an existing directory', function(done) {
|
||||
var fs = util.fs();
|
||||
|
||||
fs.mkdir('/mydir', function(error) {
|
||||
if(error) throw error;
|
||||
|
||||
fs.rename('/mydir', '/myotherdir', function(error) {
|
||||
expect(error).not.to.exist;
|
||||
fs.stat('/mydir', function(error) {
|
||||
expect(error).to.exist;
|
||||
expect(error.code).to.equal('ENOENT');
|
||||
|
||||
fs.stat('/myotherdir', function(error, result) {
|
||||
expect(error).not.to.exist;
|
||||
expect(result.nlinks).to.equal(1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should rename an existing directory if the new path points to an existing directory', function(done) {
|
||||
var fs = util.fs();
|
||||
|
||||
fs.mkdir('/mydir', function(error) {
|
||||
if(error) throw error;
|
||||
|
||||
fs.mkdir('/myotherdir', function(error) {
|
||||
if(error) throw error;
|
||||
|
||||
fs.rename('/mydir', '/myotherdir', function(error) {
|
||||
expect(error).not.to.exist;
|
||||
fs.stat('/mydir', function(error) {
|
||||
expect(error).to.exist;
|
||||
expect(error.code).to.equal('ENOENT');
|
||||
|
||||
fs.stat('/myotherdir', function(error, result) {
|
||||
expect(error).not.to.exist;
|
||||
expect(result.nlinks).to.equal(1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail to rename an existing directory if the new path points to an existing directory that is not empty', function(done) {
|
||||
var fs = util.fs();
|
||||
|
||||
fs.mkdir('/mydir', function(error) {
|
||||
if(error) throw error;
|
||||
|
||||
fs.mkdir('/myotherdir', function(error) {
|
||||
if(error) throw error;
|
||||
|
||||
fs.writeFile('/myotherdir/myfile', 'This is a file', function(error) {
|
||||
if(error) throw error;
|
||||
|
||||
fs.rename('/mydir', '/myotherdir', function(error) {
|
||||
expect(error).to.exist;
|
||||
expect(error.code).to.equal('ENOTEMPTY');
|
||||
|
||||
fs.stat('/mydir', function(error) {
|
||||
expect(error).not.to.exist;
|
||||
|
||||
fs.stat('/myotherdir', function(error) {
|
||||
expect(error).not.to.exist;
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail to rename an existing directory if the new path points to an existing file', function(done) {
|
||||
var fs = util.fs();
|
||||
|
||||
fs.mkdir('/mydir', function(error) {
|
||||
if(error) throw error;
|
||||
|
||||
fs.writeFile('/myfile', 'This is a file', function(error) {
|
||||
if(error) throw error;
|
||||
|
||||
fs.rename('/mydir', '/myfile', function(error) {
|
||||
expect(error).to.exist;
|
||||
expect(error.code).to.equal('ENOTDIR');
|
||||
|
||||
fs.stat('/mydir', function(error) {
|
||||
expect(error).not.to.exist;
|
||||
|
||||
fs.stat('/myfile', function(error) {
|
||||
expect(error).not.to.exist;
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
var Filer = require('../..');
|
||||
var util = require('../lib/test-utils.js');
|
||||
var expect = require('chai').expect;
|
||||
|
||||
describe("fs.Shell", function() {
|
||||
beforeEach(util.setup);
|
||||
afterEach(util.cleanup);
|
||||
|
||||
it("is a function", function(done) {
|
||||
var fs = util.fs();
|
||||
expect(typeof fs.Shell).to.equal('function');
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
it('should return a FileSystemShell instance', function(done) {
|
||||
var fs = util.fs();
|
||||
var sh = new fs.Shell();
|
||||
|
||||
expect(sh.prototype).to.deep.equal((new Filer.Shell(fs)).prototype);
|
||||
done();
|
||||
});
|
||||
|
||||
it('should reflect changes to the prototype', function(done){
|
||||
var fs = util.fs();
|
||||
var sh = new fs.Shell();
|
||||
|
||||
Filer.Shell.prototype.test = "foo";
|
||||
|
||||
expect(sh.test).to.equal("foo");
|
||||
done();
|
||||
});
|
||||
});
|
|
@ -223,4 +223,22 @@ describe('path resolution', function() {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should properly add trailing slashes with Path.addTrailing()', function() {
|
||||
var Path = Filer.Path;
|
||||
expect(Path.addTrailing('/')).to.equal('/');
|
||||
expect(Path.addTrailing('/////')).to.equal('/');
|
||||
expect(Path.addTrailing('.')).to.equal('./');
|
||||
expect(Path.addTrailing('/dir')).to.equal('/dir/');
|
||||
expect(Path.addTrailing('/dir/')).to.equal('/dir/');
|
||||
});
|
||||
|
||||
it('should properly remove trailing slashes with Path.removeTrailing()', function() {
|
||||
var Path = Filer.Path;
|
||||
expect(Path.removeTrailing('/')).to.equal('/');
|
||||
expect(Path.removeTrailing('/////')).to.equal('/');
|
||||
expect(Path.removeTrailing('./')).to.equal('.');
|
||||
expect(Path.removeTrailing('/dir/')).to.equal('/dir');
|
||||
expect(Path.removeTrailing('/dir//')).to.equal('/dir');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -13,7 +13,7 @@ describe('FileSystemShell.cat', function() {
|
|||
|
||||
it('should fail when files argument is absent', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
|
||||
shell.cat(null, function(error, data) {
|
||||
expect(error).to.exist;
|
||||
|
@ -25,7 +25,7 @@ describe('FileSystemShell.cat', function() {
|
|||
|
||||
it('should return the contents of a single file', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
var contents = "file contents";
|
||||
|
||||
fs.writeFile('/file', contents, function(err) {
|
||||
|
@ -41,7 +41,7 @@ describe('FileSystemShell.cat', function() {
|
|||
|
||||
it('should return the contents of multiple files', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
var contents = "file contents";
|
||||
var contents2 = contents + '\n' + contents;
|
||||
|
||||
|
@ -62,7 +62,7 @@ describe('FileSystemShell.cat', function() {
|
|||
|
||||
it('should fail if any of multiple file paths is invalid', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
var contents = "file contents";
|
||||
var contents2 = contents + '\n' + contents;
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ describe('FileSystemShell.cd', function() {
|
|||
|
||||
it('should allow changing the path to a valid dir', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
|
||||
fs.mkdir('/dir', function(err) {
|
||||
if(err) throw err;
|
||||
|
@ -34,7 +34,7 @@ describe('FileSystemShell.cd', function() {
|
|||
|
||||
it('should fail when changing the path to an invalid dir', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
|
||||
fs.mkdir('/dir', function(err) {
|
||||
if(err) throw err;
|
||||
|
@ -51,7 +51,7 @@ describe('FileSystemShell.cd', function() {
|
|||
|
||||
it('should fail when changing the path to a file', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
|
||||
fs.writeFile('/file', 'file', function(err) {
|
||||
if(err) throw err;
|
||||
|
@ -68,7 +68,7 @@ describe('FileSystemShell.cd', function() {
|
|||
|
||||
it('should allow relative paths for a valid dir', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
|
||||
fs.mkdir('/dir', function(err) {
|
||||
if(err) throw err;
|
||||
|
@ -84,7 +84,7 @@ describe('FileSystemShell.cd', function() {
|
|||
|
||||
it('should allow .. in paths for a valid dir', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
|
||||
fs.mkdir('/dir', function(err) {
|
||||
if(err) throw err;
|
||||
|
@ -111,7 +111,7 @@ describe('FileSystemShell.cd', function() {
|
|||
fs.symlink('/dir', '/link', function(error) {
|
||||
if(error) throw error;
|
||||
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
shell.cd('link', function(error) {
|
||||
expect(error).not.to.exist;
|
||||
expect(shell.pwd()).to.equal('/link');
|
||||
|
|
|
@ -34,7 +34,7 @@ describe('FileSystemShell.env', function() {
|
|||
|
||||
it('should fail when dirs argument is absent', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
|
||||
shell.cat(null, function(error, list) {
|
||||
expect(error).to.exist;
|
||||
|
@ -46,7 +46,7 @@ describe('FileSystemShell.env', function() {
|
|||
|
||||
it('should give new value for shell.pwd() when cwd changes', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
|
||||
fs.mkdir('/dir', function(err) {
|
||||
if(err) throw err;
|
||||
|
@ -62,7 +62,7 @@ describe('FileSystemShell.env', function() {
|
|||
|
||||
it('should create/return the default tmp dir', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
|
||||
expect(shell.env.get('TMP')).to.equal('/tmp');
|
||||
shell.tempDir(function(err, tmp) {
|
||||
|
@ -77,7 +77,7 @@ describe('FileSystemShell.env', function() {
|
|||
|
||||
it('should create/return the tmp dir specified in env.TMP', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell({
|
||||
var shell = new fs.Shell({
|
||||
env: {
|
||||
TMP: '/tempdir'
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ describe('FileSystemShell.env', function() {
|
|||
|
||||
it('should allow repeated calls to tempDir()', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
|
||||
expect(shell.env.get('TMP')).to.equal('/tmp');
|
||||
shell.tempDir(function(err, tmp) {
|
||||
|
|
|
@ -13,7 +13,7 @@ describe('FileSystemShell.exec', function() {
|
|||
|
||||
it('should be able to execute a command .js file from the filesystem', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
var cmdString = "fs.writeFile(args[0], args[1], callback);";
|
||||
|
||||
fs.writeFile('/cmd.js', cmdString, function(error) {
|
||||
|
|
|
@ -0,0 +1,206 @@
|
|||
var Filer = require('../../..');
|
||||
var util = require('../../lib/test-utils.js');
|
||||
var expect = require('chai').expect;
|
||||
|
||||
describe('FileSystemShell.find', function() {
|
||||
beforeEach(function(done) {
|
||||
util.setup(function() {
|
||||
var fs = util.fs();
|
||||
/**
|
||||
* Create a basic fs layout for each test:
|
||||
*
|
||||
* /
|
||||
* --file1
|
||||
* --file2
|
||||
* --dir1/
|
||||
* --file3
|
||||
* --subdir1/
|
||||
* --dir2/
|
||||
* --file4
|
||||
*/
|
||||
fs.writeFile('/file1', 'file1', function(err) {
|
||||
if(err) throw err;
|
||||
|
||||
fs.writeFile('/file2', 'file2', function(err) {
|
||||
if(err) throw err;
|
||||
|
||||
fs.mkdir('/dir1', function(err) {
|
||||
if(err) throw err;
|
||||
|
||||
fs.writeFile('/dir1/file3', 'file3', function(err) {
|
||||
if(err) throw err;
|
||||
|
||||
fs.mkdir('/dir1/subdir1', function(err) {
|
||||
if(err) throw err;
|
||||
|
||||
fs.mkdir('/dir2', function(err) {
|
||||
if(err) throw err;
|
||||
|
||||
fs.writeFile('/dir2/file4', 'file4', function(err) {
|
||||
if(err) throw err;
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
afterEach(util.cleanup);
|
||||
|
||||
it('should be a function', function() {
|
||||
var shell = util.shell();
|
||||
expect(shell.find).to.be.a('function');
|
||||
});
|
||||
|
||||
it('should fail when path does not exist', function(done) {
|
||||
var shell = util.shell();
|
||||
|
||||
shell.find('/no-such-folder', function(err, found) {
|
||||
expect(err).to.exist;
|
||||
expect(err.code).to.equal('ENOENT');
|
||||
expect(found).not.to.exist;
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail when path exists but is non-dir', function(done) {
|
||||
var shell = util.shell();
|
||||
|
||||
shell.find('/file1', function(err, found) {
|
||||
expect(err).to.exist;
|
||||
expect(err.code).to.equal('ENOTDIR');
|
||||
expect(found).not.to.exist;
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should find all paths in the filesystem with no options', function(done) {
|
||||
var shell = util.shell();
|
||||
|
||||
shell.find('/', function(err, found) {
|
||||
expect(err).not.to.exist;
|
||||
|
||||
var expected = [
|
||||
'/',
|
||||
'/file1',
|
||||
'/file2',
|
||||
'/dir1/',
|
||||
'/dir1/file3',
|
||||
'/dir1/subdir1/',
|
||||
'/dir2/',
|
||||
'/dir2/file4'
|
||||
];
|
||||
expect(found).to.deep.equal(expected);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should get same paths in exec as are found when complete', function(done) {
|
||||
var shell = util.shell();
|
||||
var pathsSeen = [];
|
||||
|
||||
function processPath(path, next) {
|
||||
pathsSeen.push(path);
|
||||
next();
|
||||
}
|
||||
|
||||
shell.find('/', {exec: processPath}, function(err, found) {
|
||||
expect(err).not.to.exist;
|
||||
|
||||
expect(found).to.deep.equal(pathsSeen);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should return only paths that match a regex pattern', function(done) {
|
||||
var shell = util.shell();
|
||||
|
||||
shell.find('/', {regex: /file\d$/}, function(err, found) {
|
||||
expect(err).not.to.exist;
|
||||
|
||||
var expected = [
|
||||
'/file1',
|
||||
'/file2',
|
||||
'/dir1/file3',
|
||||
'/dir2/file4'
|
||||
];
|
||||
expect(found).to.deep.equal(expected);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should append a / to the end of a dir path', function(done) {
|
||||
var shell = util.shell();
|
||||
var dirsSeen = 0;
|
||||
|
||||
function endsWith(str, suffix) {
|
||||
var lastIndex = str.lastIndexOf(suffix);
|
||||
return (lastIndex !== -1) && (lastIndex + suffix.length === str.length);
|
||||
}
|
||||
|
||||
function processPath(path, next) {
|
||||
expect(endsWith(path, '/')).to.be.true;
|
||||
dirsSeen++;
|
||||
next();
|
||||
}
|
||||
|
||||
shell.find('/', {regex: /dir\d$/, exec: processPath}, function(err) {
|
||||
expect(err).not.to.exist;
|
||||
expect(dirsSeen).to.equal(3);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should only look below the specified dir path', function(done) {
|
||||
var shell = util.shell();
|
||||
|
||||
shell.find('/dir1', function(err, found) {
|
||||
expect(err).not.to.exist;
|
||||
|
||||
var expected = [
|
||||
'/dir1/',
|
||||
'/dir1/file3',
|
||||
'/dir1/subdir1/'
|
||||
];
|
||||
expect(found).to.deep.equal(expected);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow using options.name to match basename with a pattern', function(done) {
|
||||
var shell = util.shell();
|
||||
|
||||
shell.find('/', {name: 'file*'}, function(err, found) {
|
||||
expect(err).not.to.exist;
|
||||
|
||||
var expected = [
|
||||
'/file1',
|
||||
'/file2',
|
||||
'/dir1/file3',
|
||||
'/dir2/file4'
|
||||
];
|
||||
expect(found).to.deep.equal(expected);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow using options.path to match dirname with a pattern', function(done) {
|
||||
var shell = util.shell();
|
||||
|
||||
shell.find('/', {name: '*ir1*'}, function(err, found) {
|
||||
expect(err).not.to.exist;
|
||||
|
||||
var expected = [
|
||||
'/dir1/',
|
||||
'/dir1/subdir1/'
|
||||
];
|
||||
expect(found).to.deep.equal(expected);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
|
@ -13,7 +13,7 @@ describe('FileSystemShell.ls', function() {
|
|||
|
||||
it('should fail when dirs argument is absent', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
|
||||
shell.cat(null, function(error, list) {
|
||||
expect(error).to.exist;
|
||||
|
@ -25,7 +25,7 @@ describe('FileSystemShell.ls', function() {
|
|||
|
||||
it('should return the contents of a simple dir', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
var contents = "a";
|
||||
var contents2 = "bb";
|
||||
|
||||
|
@ -63,7 +63,7 @@ describe('FileSystemShell.ls', function() {
|
|||
|
||||
it('should return the shallow contents of a dir tree', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
var contents = "a";
|
||||
|
||||
fs.mkdir('/dir', function(err) {
|
||||
|
@ -119,7 +119,7 @@ describe('FileSystemShell.ls', function() {
|
|||
|
||||
it('should return the deep contents of a dir tree', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
var contents = "a";
|
||||
|
||||
fs.mkdir('/dir', function(err) {
|
||||
|
|
|
@ -13,7 +13,7 @@ describe('FileSystemShell.mkdirp', function() {
|
|||
|
||||
it('should fail without a path provided', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
|
||||
shell.mkdirp(null, function(err) {
|
||||
expect(err).to.exist;
|
||||
|
@ -24,7 +24,7 @@ describe('FileSystemShell.mkdirp', function() {
|
|||
|
||||
it('should succeed if provided path is root', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
shell.mkdirp('/', function(err) {
|
||||
expect(err).to.not.exist;
|
||||
done();
|
||||
|
@ -33,7 +33,7 @@ describe('FileSystemShell.mkdirp', function() {
|
|||
|
||||
it('should succeed if the directory exists', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
fs.mkdir('/test', function(err){
|
||||
expect(err).to.not.exist;
|
||||
shell.mkdirp('/test',function(err) {
|
||||
|
@ -45,7 +45,7 @@ describe('FileSystemShell.mkdirp', function() {
|
|||
|
||||
it('fail if a file name is provided', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
fs.writeFile('/test.txt', 'test', function(err){
|
||||
expect(err).to.not.exist;
|
||||
shell.mkdirp('/test.txt', function(err) {
|
||||
|
@ -58,7 +58,7 @@ describe('FileSystemShell.mkdirp', function() {
|
|||
|
||||
it('should succeed on a folder on root (\'/test\')', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
shell.mkdirp('/test', function(err) {
|
||||
expect(err).to.not.exist;
|
||||
fs.exists('/test', function(dir){
|
||||
|
@ -70,7 +70,7 @@ describe('FileSystemShell.mkdirp', function() {
|
|||
|
||||
it('should succeed on a folder with a nonexistant parent (\'/test/test\')', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
shell.mkdirp('/test/test', function(err) {
|
||||
expect(err).to.not.exist;
|
||||
fs.exists('/test', function(dir1){
|
||||
|
@ -85,7 +85,7 @@ describe('FileSystemShell.mkdirp', function() {
|
|||
|
||||
it('should fail on a folder with a file for its parent (\'/test.txt/test\')', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
fs.writeFile('/test.txt', 'test', function(err){
|
||||
expect(err).to.not.exist;
|
||||
shell.mkdirp('/test.txt/test', function(err) {
|
||||
|
|
|
@ -13,7 +13,7 @@ describe('FileSystemShell.rm', function() {
|
|||
|
||||
it('should fail when path argument is absent', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
|
||||
shell.rm(null, function(error, list) {
|
||||
expect(error).to.exist;
|
||||
|
@ -25,7 +25,7 @@ describe('FileSystemShell.rm', function() {
|
|||
|
||||
it('should remove a single file', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
var contents = "a";
|
||||
|
||||
fs.writeFile('/file', contents, function(err) {
|
||||
|
@ -45,7 +45,7 @@ describe('FileSystemShell.rm', function() {
|
|||
|
||||
it('should remove an empty dir', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
|
||||
fs.mkdir('/dir', function(err) {
|
||||
if(err) throw err;
|
||||
|
@ -64,7 +64,7 @@ describe('FileSystemShell.rm', function() {
|
|||
|
||||
it('should fail to remove a non-empty dir', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
|
||||
fs.mkdir('/dir', function(err) {
|
||||
if(err) throw err;
|
||||
|
@ -83,7 +83,7 @@ describe('FileSystemShell.rm', function() {
|
|||
|
||||
it('should remove a non-empty dir with option.recursive set', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
|
||||
fs.mkdir('/dir', function(err) {
|
||||
if(err) throw err;
|
||||
|
@ -106,7 +106,7 @@ describe('FileSystemShell.rm', function() {
|
|||
|
||||
it('should work on a complex dir structure', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
var contents = "a";
|
||||
|
||||
fs.mkdir('/dir', function(err) {
|
||||
|
|
|
@ -20,7 +20,7 @@ describe('FileSystemShell.touch', function() {
|
|||
|
||||
it('should create a new file if path does not exist', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
|
||||
shell.touch('/newfile', function(error) {
|
||||
if(error) throw error;
|
||||
|
@ -35,7 +35,7 @@ describe('FileSystemShell.touch', function() {
|
|||
|
||||
it('should skip creating a new file if options.updateOnly is true', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
|
||||
shell.touch('/newfile', { updateOnly: true }, function(error) {
|
||||
if(error) throw error;
|
||||
|
@ -49,7 +49,7 @@ describe('FileSystemShell.touch', function() {
|
|||
|
||||
it('should update times if path does exist', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
var atime = Date.parse('1 Oct 2000 15:33:22');
|
||||
var mtime = Date.parse('30 Sep 2000 06:43:54');
|
||||
|
||||
|
@ -80,7 +80,7 @@ describe('FileSystemShell.touch', function() {
|
|||
|
||||
it('should update times to specified date if path does exist', function(done) {
|
||||
var fs = util.fs();
|
||||
var shell = fs.Shell();
|
||||
var shell = new fs.Shell();
|
||||
var date = Date.parse('1 Oct 2001 15:33:22');
|
||||
|
||||
fs.open('/newfile', 'w', function (error, fd) {
|
||||
|
|
Loading…
Reference in New Issue