Compare commits

...

No commits in common. "master" and "next" have entirely different histories.
master ... next

239 changed files with 3890 additions and 59685 deletions

View File

@ -1 +0,0 @@
tests/dist/

View File

@ -1,36 +0,0 @@
{
"env": {
"browser": true,
"commonjs": true,
"es6": true,
"mocha": true,
"node": true
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 2017,
"sourceType": "module"
},
"rules": {
"indent": [
"error",
2
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"single"
],
"semi": [
"error",
"always"
],
"eqeqeq": [
"error",
"always"
]
}
}

1
.gitattributes vendored
View File

@ -1 +0,0 @@
* text=auto eol=lf

View File

@ -1,27 +0,0 @@
name: node-js-ci
on:
pull_request:
branches:
- master
push:
branches:
- master
jobs:
build:
runs-on: ${{matrix.os}}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
node: ['14', '16']
name: Node ${{ matrix.node }} on ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- name: Test
uses: actions/setup-node@v2.4.1
with:
node-version: ${{ matrix.node }}
- run: npm install
- run: npm test

12
.gitignore vendored
View File

@ -1,13 +1,5 @@
node_modules
bower_components
.env
*~
.vscode
.idea
# Parcel build dirs
.cache
tests/dist
# nyc code coverage
.nyc_output
coverage
dist/filer-issue225.js

1
.npmrc
View File

@ -1 +0,0 @@
loglevel=silent

View File

@ -1,17 +0,0 @@
{
"hooks": {
"before:init": ["npm run test"],
"before:bump": ["npm run build"]
},
"git": {
"pushRepo": "git@github.com:filerjs/filer.git",
"tagName": "v${version}"
},
"npm": {
"publish": true
},
"github": {
"pushRepo": "git@github.com:filerjs/filer.git",
"release": true
}
}

View File

@ -1,32 +0,0 @@
sudo: false
language: node_js
node_js:
- "lts/*"
cache:
directories:
- "node_modules"
os:
- linux
- osx
# Setup headless Firefox and Chrome support
# https://docs.travis-ci.com/user/gui-and-headless-browsers/#Using-the-Chrome-addon-in-the-headless-mode
env:
- MOZ_HEADLESS=1
addons:
chrome: stable
firefox: latest
before_install:
- google-chrome-stable --headless --disable-gpu --remote-debugging-port=9222 http://localhost &
after_success:
- npm install -g codecov
- npm run coverage
- codecov
notifications:
email: false
irc: "irc.mozilla.org#filer"

View File

@ -1,9 +0,0 @@
Alan K <ack@modeswitch.org> (blog.modeswitch.org)
David Humphrey <david.humphrey@senecacollege.ca> (@humphd)
Abir Viqar <abiviq@hushmail.com>
Barry Tulchinsky <barry.tulchinsky@gmail.com> (@btulchinsky)
Kieran Sedgwick <kieran.sedgwick@gmail.com> (@sedge)
Yoav Gurevich <ygurevich@ymail.com>
Gideon Thomas <r.gideonthomas@gmail.com>
Abdirahman Guled <aguled2@myseneca.ca>
Ben Heidemann <ben@heidemann.co.uk>

View File

@ -1,75 +0,0 @@
# How to Contribute
The best way to get started is to read through the `Getting Started` and `Example`
sections before having a look through the open [issues](https://github.com/js-platform/filer/issues).
Some of the issues are marked as `good first bug`, but feel free to contribute to
any of the issues there, or open a new one if the thing you want to work on isn't
there yet. If you would like to have an issue assigned to you, please send me a
message and I'll update it.
## Setup
To get a working build system do the following:
```
npm install
```
Next, make sure you have installed Chrome and Firefox, which are needed for
running headless versions of the tests with `npm test`.
## Tests
Tests are written using [Mocha](https://mochajs.org/) and [Chai](http://chaijs.com/api/bdd/).
There are a number of ways to run the tests. The preferred way is:
```
npm test
```
This will do a build, run the linting, start a server, and load the tests into
headless versions of Chrome and Firefox.
If you want more control over how tests are run, you can use other scripts:
* Linting is done via `npm run lint` or `npm run eslint`, both of which will run `eslint` on the `src` and `tests` directories. You can also use `npm run lint:fix` or `npm run eslint:fix`, which will run `eslint` with `--fix` on the `src` and `tests` directories, automatically fixing minor issues. Linting is run by default as part of `npm test`
* In headless versions of Chrome and Firefox using `npm test`. A report at the end will tell you what happened with each browser. Browser tests are preferred because they also test our providers (e.g., IndexedDB). They do take longer to run. You can also use `npm run karma-mocha-firefox` or `npm run karma-mocha-chrome` to run the tests in only one of the two headless browsers.
* In node.js using the Memory provider using `npm run test:node`. These run much faster, but don't run all tests (e.g., providers, watches).
* If you need to debug browser tests, or want to run them in a different browser, use `npm run test:manual`, which will start a server and you can point your browser to [http://localhost:1234](http://localhost:1234). Running the tests this way will also automatically watch your files, and hot-reload your code and tests, which is useful for debugging and trial/error testing.
* If you need to debug node.js test runs, you can do so using `npm run test:node-debug`. Then, open Chrome and browse to [chrome://inspect](chrome://inspect) and click on your tests in the inspector. The easiest way to get a breakpoint is to manually add a `debugger` keyword to your test code where you want the tests to stop.
> Tip: you can add `skip()` to any `it()` or `describe()` in Mocha to skip a test, or `only()` to have only that test run. For example: `describe.skip(...)` or `it.only(...)`.
* If you want to run migration tests separate from unit tests, use `npm run test:migrations`. Migration tests run at the end of a typical `npm test` run. If you need to create a new migration test, see [`tools/fs-image.js`](tools/fs-image.js) for details on how to generate a filesystem image, and [tests/filesystems/images/README.md](tests/filesystems/images/README.md) for more docs.
* If you want to manually generate coverage info for the tests, use `npm run coverage`. This is done automatically in Travis, so you shouldn't need to do it. You can see [https://codecov.io/gh/filerjs/filer](https://codecov.io/gh/filerjs/filer) for detailed reports.
There are a number of configurable options for the test suite, which are set via query string params.
First, you can choose which filer source to use (i.e., src/, dist/filer-test.js, dist/filer.js or dist/filer.min.js). The default is to use what is in /dist/filer-test.js, and you can switch to other versions like so:
* tests/index.html?filer-dist/filer.js
* tests/index.html?filer-dist/filer.min.js
* tests/index.html?filer-src/filer.js (from src)
Second, you can specify which provider to use for all non-provider specific tests (i.e., most of the tests).
The default provider is `Memory`, and you can switch it like so:
* tests/index.html?filer-provider=memory
* tests/index.html?filer-provider=indexeddb
If you're writing tests, make sure you write them in the same style as existing tests, which are
provider agnostic. See [`tests/lib/test-utils.js`](tests/lib/test-utils.js) and how it gets used
in various tests as an example.
## Releases
In order to perform a release, you'll need commit access to the main Filer repo,
as well as access to publish to Filer's npm module. To do a release:
1. Make sure you have a .env file, with your `GITHUB_TOKEN` included. See [`env.sample`](env.sample) for more info on how to create one.
1. Login to the `npm` registry if you haven't already using `npm login`
1. Run `npm run release`. Releases are done interactively using [release-it](https://www.npmjs.com/package/release-it), and our config is defined in [`.release-it.json`](.release-it.json).

View File

@ -1,9 +0,0 @@
Copyright (c) 2013 - 2019 Alan Kligman and the Filer contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

1754
README.md

File diff suppressed because it is too large Load Diff

21346
dist/filer.js vendored

File diff suppressed because one or more lines are too long

1
dist/filer.js.map vendored

File diff suppressed because one or more lines are too long

1
dist/filer.map vendored

File diff suppressed because one or more lines are too long

249
dist/filer.min.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
dist/filer.min.map vendored

File diff suppressed because one or more lines are too long

View File

@ -1,9 +0,0 @@
###
# Dev ENVIRONMENT file
#
# Copy to .env to use defaults when releasing via `npm release`
###
# GitHub Personal Access Token (to push releases)
# https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/
GITHUB_TOKEN=

View File

@ -1,28 +0,0 @@
module.exports = function(config) {
config.set({
singleRun: true,
basePath: '',
files: [
'node_modules/regenerator-runtime/runtime.js',
'tests/dist/index.js'
],
frameworks: ['mocha', 'chai'],
reporters: ['mocha', 'summary'],
client: {
captureConsole: true,
mocha: {
ui: 'bdd',
timeout: 5000,
slow: 250
}
},
summaryReporter: {
// 'failed', 'skipped' or 'all'
show: 'failed',
// Limit the spec label to this length
specLength: 50,
// Show an 'all' column as a summary
overviewColumn: true
}
});
};

View File

@ -1,85 +0,0 @@
/*global setImmediate: false, setTimeout: false, console: false */
/**
* async.js shim, based on https://raw.github.com/caolan/async/master/lib/async.js Feb 18, 2014
* Used under MIT - https://github.com/caolan/async/blob/master/LICENSE
*/
(function () {
var async = {};
// async.js functions used in Filer
//// nextTick implementation with browser-compatible fallback ////
if (typeof process === 'undefined' || !(process.nextTick)) {
if (typeof setImmediate === 'function') {
async.nextTick = function (fn) {
// not a direct alias for IE10 compatibility
setImmediate(fn);
};
async.setImmediate = async.nextTick;
}
else {
async.nextTick = function (fn) {
setTimeout(fn, 0);
};
async.setImmediate = async.nextTick;
}
}
else {
async.nextTick = process.nextTick;
if (typeof setImmediate !== 'undefined') {
async.setImmediate = function (fn) {
// not a direct alias for IE10 compatibility
setImmediate(fn);
};
}
else {
async.setImmediate = async.nextTick;
}
}
async.eachSeries = function (arr, iterator, callback) {
callback = callback || function () {};
if (!arr.length) {
return callback();
}
var completed = 0;
var iterate = function () {
iterator(arr[completed], function (err) {
if (err) {
callback(err);
callback = function () {};
}
else {
completed += 1;
if (completed >= arr.length) {
callback();
}
else {
iterate();
}
}
});
};
iterate();
};
async.forEachSeries = async.eachSeries;
// AMD / RequireJS
if (typeof define !== 'undefined' && define.amd) {
define([], function () {
return async;
});
}
// Node.js
else if (typeof module !== 'undefined' && module.exports) {
module.exports = async;
}
// included directly via <script> tag
else {
root.async = async;
}
}());

View File

@ -1,71 +0,0 @@
// Based on https://github.com/diy/intercom.js/blob/master/lib/events.js
// Copyright 2012 DIY Co Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
function removeItem(item, array) {
for (var i = array.length - 1; i >= 0; i--) {
if (array[i] === item) {
array.splice(i, 1);
}
}
return array;
}
var EventEmitter = function() {};
EventEmitter.createInterface = function(space) {
var methods = {};
methods.on = function(name, fn) {
if (typeof this[space] === 'undefined') {
this[space] = {};
}
if (!this[space].hasOwnProperty(name)) {
this[space][name] = [];
}
this[space][name].push(fn);
};
methods.off = function(name, fn) {
if (typeof this[space] === 'undefined') return;
if (this[space].hasOwnProperty(name)) {
removeItem(fn, this[space][name]);
}
};
methods.trigger = function(name) {
if (typeof this[space] !== 'undefined' && this[space].hasOwnProperty(name)) {
var args = Array.prototype.slice.call(arguments, 1);
for (var i = 0; i < this[space][name].length; i++) {
this[space][name][i].apply(this[space][name][i], args);
}
}
};
methods.removeAllListeners = function(name) {
if (typeof this[space] === 'undefined') return;
var self = this;
self[space][name].forEach(function(fn) {
self.off(name, fn);
});
};
return methods;
};
var pvt = EventEmitter.createInterface('_handlers');
EventEmitter.prototype._on = pvt.on;
EventEmitter.prototype._off = pvt.off;
EventEmitter.prototype._trigger = pvt.trigger;
var pub = EventEmitter.createInterface('handlers');
EventEmitter.prototype.on = function() {
pub.on.apply(this, arguments);
Array.prototype.unshift.call(arguments, 'on');
this._trigger.apply(this, arguments);
};
EventEmitter.prototype.off = pub.off;
EventEmitter.prototype.trigger = pub.trigger;
EventEmitter.prototype.removeAllListeners = pub.removeAllListeners;
module.exports = EventEmitter;

View File

@ -1,318 +0,0 @@
// Based on https://github.com/diy/intercom.js/blob/master/lib/intercom.js
// Copyright 2012 DIY Co Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
var EventEmitter = require('./eventemitter.js');
var guid = require('../src/shared.js').guid;
function throttle(delay, fn) {
var last = 0;
return function() {
var now = Date.now();
if (now - last > delay) {
last = now;
fn.apply(this, arguments);
}
};
}
function extend(a, b) {
if (typeof a === 'undefined' || !a) { a = {}; }
if (typeof b === 'object') {
for (var key in b) {
if (b.hasOwnProperty(key)) {
a[key] = b[key];
}
}
}
return a;
}
var localStorage = (function(window) {
if (typeof window === 'undefined' ||
typeof window.localStorage === 'undefined') {
return {
getItem : function() {},
setItem : function() {},
removeItem : function() {}
};
}
return window.localStorage;
}(global));
function Intercom() {
var self = this;
var now = Date.now();
this.origin = guid();
this.lastMessage = now;
this.receivedIDs = {};
this.previousValues = {};
var storageHandler = function() {
self._onStorageEvent.apply(self, arguments);
};
// If we're in node.js, skip event registration
if (typeof document === 'undefined') {
return;
}
if (document.attachEvent) {
document.attachEvent('onstorage', storageHandler);
} else {
global.addEventListener('storage', storageHandler, false);
}
}
Intercom.prototype._transaction = function(fn) {
var TIMEOUT = 1000;
var WAIT = 20;
var self = this;
var executed = false;
var listening = false;
var waitTimer = null;
function lock() {
if (executed) {
return;
}
var now = Date.now();
var activeLock = localStorage.getItem(INDEX_LOCK)|0;
if (activeLock && now - activeLock < TIMEOUT) {
if (!listening) {
self._on('storage', lock);
listening = true;
}
waitTimer = setTimeout(lock, WAIT);
return;
}
executed = true;
localStorage.setItem(INDEX_LOCK, now);
fn();
unlock();
}
function unlock() {
if (listening) {
self._off('storage', lock);
}
if (waitTimer) {
clearTimeout(waitTimer);
}
localStorage.removeItem(INDEX_LOCK);
}
lock();
};
Intercom.prototype._cleanup_emit = throttle(100, function() {
var self = this;
self._transaction(function() {
var now = Date.now();
var threshold = now - THRESHOLD_TTL_EMIT;
var changed = 0;
var messages;
try {
messages = JSON.parse(localStorage.getItem(INDEX_EMIT) || '[]');
} catch(e) {
messages = [];
}
for (var i = messages.length - 1; i >= 0; i--) {
if (messages[i].timestamp < threshold) {
messages.splice(i, 1);
changed++;
}
}
if (changed > 0) {
localStorage.setItem(INDEX_EMIT, JSON.stringify(messages));
}
});
});
Intercom.prototype._cleanup_once = throttle(100, function() {
var self = this;
self._transaction(function() {
var timestamp, ttl, key;
var table;
var now = Date.now();
var changed = 0;
try {
table = JSON.parse(localStorage.getItem(INDEX_ONCE) || '{}');
} catch(e) {
table = {};
}
for (key in table) {
if (self._once_expired(key, table)) {
delete table[key];
changed++;
}
}
if (changed > 0) {
localStorage.setItem(INDEX_ONCE, JSON.stringify(table));
}
});
});
Intercom.prototype._once_expired = function(key, table) {
if (!table) {
return true;
}
if (!table.hasOwnProperty(key)) {
return true;
}
if (typeof table[key] !== 'object') {
return true;
}
var ttl = table[key].ttl || THRESHOLD_TTL_ONCE;
var now = Date.now();
var timestamp = table[key].timestamp;
return timestamp < now - ttl;
};
Intercom.prototype._localStorageChanged = function(event, field) {
if (event && event.key) {
return event.key === field;
}
var currentValue = localStorage.getItem(field);
if (currentValue === this.previousValues[field]) {
return false;
}
this.previousValues[field] = currentValue;
return true;
};
Intercom.prototype._onStorageEvent = function(event) {
event = event || global.event;
var self = this;
if (this._localStorageChanged(event, INDEX_EMIT)) {
this._transaction(function() {
var now = Date.now();
var data = localStorage.getItem(INDEX_EMIT);
var messages;
try {
messages = JSON.parse(data || '[]');
} catch(e) {
messages = [];
}
for (var i = 0; i < messages.length; i++) {
if (messages[i].origin === self.origin) continue;
if (messages[i].timestamp < self.lastMessage) continue;
if (messages[i].id) {
if (self.receivedIDs.hasOwnProperty(messages[i].id)) continue;
self.receivedIDs[messages[i].id] = true;
}
self.trigger(messages[i].name, messages[i].payload);
}
self.lastMessage = now;
});
}
this._trigger('storage', event);
};
Intercom.prototype._emit = function(name, message, id) {
id = (typeof id === 'string' || typeof id === 'number') ? String(id) : null;
if (id && id.length) {
if (this.receivedIDs.hasOwnProperty(id)) return;
this.receivedIDs[id] = true;
}
var packet = {
id : id,
name : name,
origin : this.origin,
timestamp : Date.now(),
payload : message
};
var self = this;
this._transaction(function() {
var data = localStorage.getItem(INDEX_EMIT) || '[]';
var delimiter = (data === '[]') ? '' : ',';
data = [data.substring(0, data.length - 1), delimiter, JSON.stringify(packet), ']'].join('');
localStorage.setItem(INDEX_EMIT, data);
self.trigger(name, message);
setTimeout(function() {
self._cleanup_emit();
}, 50);
});
};
Intercom.prototype.emit = function(name, message) {
this._emit.apply(this, arguments);
this._trigger('emit', name, message);
};
Intercom.prototype.once = function(key, fn, ttl) {
if (!Intercom.supported) {
return;
}
var self = this;
this._transaction(function() {
var data;
try {
data = JSON.parse(localStorage.getItem(INDEX_ONCE) || '{}');
} catch(e) {
data = {};
}
if (!self._once_expired(key, data)) {
return;
}
data[key] = {};
data[key].timestamp = Date.now();
if (typeof ttl === 'number') {
data[key].ttl = ttl * 1000;
}
localStorage.setItem(INDEX_ONCE, JSON.stringify(data));
fn();
setTimeout(function() {
self._cleanup_once();
}, 50);
});
};
extend(Intercom.prototype, EventEmitter.prototype);
Intercom.supported = (typeof localStorage !== 'undefined');
var INDEX_EMIT = 'intercom';
var INDEX_ONCE = 'intercom_once';
var INDEX_LOCK = 'intercom_lock';
var THRESHOLD_TTL_EMIT = 50000;
var THRESHOLD_TTL_ONCE = 1000 * 3600;
Intercom.destroy = function() {
localStorage.removeItem(INDEX_LOCK);
localStorage.removeItem(INDEX_EMIT);
localStorage.removeItem(INDEX_ONCE);
};
Intercom.getInstance = (function() {
var intercom;
return function() {
if (!intercom) {
intercom = new Intercom();
}
return intercom;
};
})();
module.exports = Intercom;

13840
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -5,91 +5,43 @@
"fs",
"node",
"file",
"filesystem",
"system",
"browser",
"indexeddb",
"idb"
"idb",
"websql"
],
"version": "1.4.1",
"version": "1.0.0",
"author": "Alan K <ack@modeswitch.org> (http://blog.modeswitch.org)",
"homepage": "http://filerjs.github.io/filer",
"bugs": "https://github.com/filerjs/filer/issues",
"license": "BSD-2-Clause",
"license": "BSD",
"scripts": {
"eslint": "npm run lint",
"eslint:fix": "npm run lint:fix",
"lint": "eslint src tests",
"lint:fix": "eslint --fix src tests",
"test:node": "mocha --timeout 5000 tests",
"pretest:node-debug": "echo \"Open Chrome to chrome://inspect to debug tests...\"",
"test:node-debug": "mocha --timeout 5000 --inspect-brk tests",
"test:manual": "parcel tests/index.html --out-dir tests/dist",
"test:migrations": "mocha tests/filesystems/migrations",
"pretest": "npm run lint",
"test": "npm run karma-mocha",
"posttest": "npm run test:migrations",
"prebuild": "parcel build --global Filer src/index.js --no-minify --out-file filer.js",
"build": "parcel build --global Filer src/index.js --out-file filer.min.js --detailed-report",
"build-tests": "parcel build tests/index.js --no-source-maps --out-dir tests/dist",
"prekarma-mocha-firefox": "npm run build-tests",
"karma-mocha-firefox": "karma start karma.conf.js --browsers FirefoxHeadless",
"prekarma-mocha-chrome": "npm run build-tests",
"karma-mocha-chrome": "karma start karma.conf.js --browsers ChromeHeadless",
"prekarma-mocha": "npm run build-tests",
"karma-mocha": "karma start karma.conf.js --browsers ChromeHeadless,FirefoxHeadless",
"coverage": "nyc mocha tests/index.js",
"release": "run.env release-it"
"build": "rollup -c --environment=development",
"test": "node node_modules/mocha/bin/mocha test/"
},
"repository": {
"type": "git",
"url": "https://github.com/filerjs/filer.git"
},
"dependencies": {
"es6-promisify": "^7.0.0",
"base64-arraybuffer": "^0.1.2",
"buffer": "^5.1.0",
"debug": "^3.1.0",
"minimatch": "^3.0.4",
"schema-utils": "^3.1.1"
"mocha": "^5.2.0",
"should": "^13.2.1",
"source-map-support": "^0.5.6",
"url-parse": "^1.4.1",
"uuid-base62": "^0.1.0",
"uuid-parse": "^1.0.0"
},
"devDependencies": {
"regenerator-runtime": "^0.13.9",
"chai": "^4.3.4",
"chai-datetime": "^1.8.0",
"eslint": "^7.32.0",
"fake-indexeddb": "^3.1.7",
"karma": "^6.3.8",
"karma-chai": "^0.1.0",
"karma-chrome-launcher": "^3.1.0",
"karma-firefox-launcher": "^2.1.2",
"karma-mocha": "^2.0.1",
"karma-mocha-reporter": "^2.2.5",
"karma-summary-reporter": "^3.0.0",
"meow": "^10.0.1",
"mocha": "^9.1.3",
"nyc": "^15.1.0",
"parcel-bundler": "^1.12.5",
"pretty-bytes": "^5.6.0",
"release-it": "^14.11.6",
"run.env": "^1.1.0",
"unused-filename": "^3.0.1",
"walk": "^2.3.15"
"rollup": "^0.59.4",
"rollup-plugin-node-resolve": "^3.3.0",
"rollup-plugin-uglify": "^4.0.0",
"semver": "^5.5.0"
},
"main": "./src/index.js",
"browser": "./dist/filer.min.js",
"files": [
"src",
"lib",
"dist",
"shims",
"webpack"
],
"nyc": {
"exclude": [
"tests/**/*.js",
"lib/**/*.js",
"src/providers/**/*.js"
],
"reporter": [
"lcov",
"text"
]
}
"main": "dist/filer.js",
"module": "src/index.js"
}

View File

@ -1,13 +0,0 @@
<!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>

View File

@ -1,119 +0,0 @@
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();

View File

@ -1,3 +0,0 @@
components
build
node_modules

View File

@ -1,8 +0,0 @@
{
"indent": 4,
"undef": true,
"unused": true,
"globals": {
"require": true
}
}

View File

@ -1,7 +0,0 @@
language: node_js
node_js:
- 0.10
script:
- npm install
- npm test
- npm run cov

View File

@ -1,242 +0,0 @@
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 }

View File

@ -1,60 +0,0 @@
# 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()`

View File

@ -1,99 +0,0 @@
# 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.

View File

@ -1,13 +0,0 @@
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.

View File

@ -1,7 +0,0 @@
docs:
docco src/*.js
test:
mocha -R spec test/spec/*.js
.PHONY: docs test

View File

@ -1,337 +0,0 @@
[![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)

View File

@ -1,157 +0,0 @@
[![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)

View File

@ -1,23 +0,0 @@
## 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/)

View File

@ -1,20 +0,0 @@
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'));

View File

@ -1,11 +0,0 @@
{
"name": "simple-statistics",
"version": "0.9.0",
"description": "Simple Statistics",
"repo": "tmcw/simple-statistics",
"keywords": [],
"license": "ISC",
"dependencies": {},
"development": {},
"main": "src/simple_statistics.js"
}

View File

@ -1,13 +0,0 @@
{
"name": "simple-statistics",
"version": "0.9.0",
"description": "Simple Statistics",
"repo": "tmcw/simple-statistics",
"keywords": [],
"license": "ISC",
"dependencies": {},
"development": {},
"scripts": [
"src/simple_statistics.js"
]
}

View File

@ -1,506 +0,0 @@
/*--------------------- 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

View File

@ -1 +0,0 @@
<meta http-equiv="refresh" content="0;URL='docs/simple_statistics.html'">

View File

@ -1,28 +0,0 @@
{
"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

View File

@ -1,114 +0,0 @@
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();
});

View File

@ -1,17 +0,0 @@
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();
});

View File

@ -1,31 +0,0 @@
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();
});

View File

@ -1,23 +0,0 @@
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();
});

View File

@ -1,18 +0,0 @@
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();
});

View File

@ -1,13 +0,0 @@
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();
});

View File

@ -1,22 +0,0 @@
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();
});

View File

@ -1,23 +0,0 @@
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();
});

View File

@ -1,27 +0,0 @@
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();
});

View File

@ -1,24 +0,0 @@
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();
});

View File

@ -1,14 +0,0 @@
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();
});

View File

@ -1,54 +0,0 @@
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();
});

View File

@ -1,26 +0,0 @@
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();
});

View File

@ -1,18 +0,0 @@
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();
});

View File

@ -1,38 +0,0 @@
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();
});

View File

@ -1,23 +0,0 @@
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();
});

View File

@ -1,34 +0,0 @@
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();
});

View File

@ -1,37 +0,0 @@
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();
});

View File

@ -1,60 +0,0 @@
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();
});

View File

@ -1,37 +0,0 @@
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();
});

View File

@ -1,64 +0,0 @@
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();
});

View File

@ -1,15 +0,0 @@
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();
});

View File

@ -1,26 +0,0 @@
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();
});

View File

@ -1,23 +0,0 @@
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();
});

View File

@ -1,19 +0,0 @@
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();
});

View File

@ -1,29 +0,0 @@
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();
});

View File

@ -1,34 +0,0 @@
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();
});

View File

@ -1,48 +0,0 @@
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();
});

View File

@ -1,19 +0,0 @@
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();
});

View File

@ -1,38 +0,0 @@
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();
});

View File

@ -1,24 +0,0 @@
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();
});

View File

@ -1,39 +0,0 @@
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();
});

View File

@ -1,14 +0,0 @@
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();
});

View File

@ -1,15 +0,0 @@
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();
});

View File

@ -1,38 +0,0 @@
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();
});

View File

@ -1,24 +0,0 @@
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();
});

13
rollup.config.js Normal file
View File

@ -0,0 +1,13 @@
// import pkg from "./package.json";
export default [
{
input: "src/index.js",
output: {
name: "Filer",
file: "dist/filer.js",
format: "umd",
sourcemap: "inline",
},
},
];

View File

@ -1,65 +0,0 @@
const { FileSystem } = require('../src/index');
let Provider;
try {
Provider = require('fsProvider');
}
catch (err) {
Provider = require('./providers/default');
}
const provider = new Provider();
let onFsReady;
let onFsError;
let fsReady = new Promise((resolve, reject) => {
onFsReady = resolve;
onFsError = reject;
});
var fsInstance = new FileSystem({ provider }, (err) => {
if (err) {
onFsError(err);
} else {
onFsReady(true);
}
});
function proxyHasProp(target, prop) {
return prop in target;
}
const fsPromises = new Proxy(fsInstance.promises, {
get(target, prop) {
if (!proxyHasProp(target, prop)) {
return;
}
return async (...args) => {
await fsReady;
return await target[prop](...args);
};
},
});
const fs = new Proxy(fsInstance, {
get(target, prop) {
if (!proxyHasProp(target, prop)) {
return;
}
if (prop === 'promises') {
return fsPromises;
}
return (...args) => {
(async () => {
await fsReady;
target[prop](...args);
})();
};
},
});
module.exports = fs;

View File

@ -1,3 +0,0 @@
const { path } = require('../src/index');
module.exports = path;

View File

@ -1,2 +0,0 @@
const { Default } = require('../../src/providers/index');
module.exports = Default;

View File

@ -1,2 +0,0 @@
const IndexedDB = require('../../src/providers/indexeddb');
module.exports = IndexedDB;

View File

@ -1,2 +0,0 @@
const Memory = require('../../src/providers/memory');
module.exports = Memory;

76
src/common/buffer.js Normal file
View File

@ -0,0 +1,76 @@
const INSPECT_MAX_BYTES = 50;
const K_MAX_LENGTH = 0x7fffffff;
class Buffer extends Uint8Array
{
constructor(arg, encodingOrOffset, length)
{
if (typeof arg === "number") {
if (typeof encodingOrOffset === "string") {
throw new TypeError(`The "string" argument must be of type string. Received type number`);
}
return allocUnsafe(arg);
}
return from(arg, encodingOrOffset, length);
}
static get INSPECT_MAX_BYTES() { return 50 }
static get K_MAX_LENGTH() { return 0x7fffffff }
static isSupported()
{
try {
var arr = new Uint8Array(1)
arr.__proto__ = {__proto__: Uint8Array.prototype, foo: function () { return 42 }}
return arr.foo() === 42
} catch (e) {
return false
}
}
static from(value, encodingOrOffset, length)
{
if (typeof value === 'string') {
return fromString(value, encodingOrOffset)
}
if (ArrayBuffer.isView(value)) {
return fromArrayLike(value)
}
if (value == null) {
throw TypeError(`The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type ${typeof value}`);
}
if (isInstance(value, ArrayBuffer) ||
(value && isInstance(value.buffer, ArrayBuffer))) {
return fromArrayBuffer(value, encodingOrOffset, length)
}
if (typeof value === 'number') {
throw new TypeError(
'The "value" argument must not be of type number. Received type number'
)
}
var valueOf = value.valueOf && value.valueOf();
if(valueOf != null && valueOf !== value) {
return Buffer.from(valueOf, encodingOrOffset, length);
}
var b = fromObject(value);
if(b) {
return b;
}
if(typeof Symbol !== "undefined" && Symbol.toPrimitive != null &&
typeof value[Symbol.toPrimitive] === "function") {
return Buffer.from(value[Symbol.toPrimitive]("string"), encodingOrOffset, length);
}
throw new TypeError(`The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type ${typeof value}`);
}
}
export default Buffer;

28
src/common/constants.js Normal file
View File

@ -0,0 +1,28 @@
import Buffer from "./buffer";
export const SUPER_NODE_ID = "0000000000000000000000";
export const MODE_FILE = "FILE";
export const MODE_DIRECTORY = "DIRECTORY";
export const MODE_SYMBOLIC_LINK = "MODE_SYMBOLIC_LINK";
export const MODE_META = "META";
export const MODE_SOCKET = "SOCKET";
export const MODE_FIFO = "FIFO";
export const MODE_CHARACTER_DEVICE = "CHARACTER_DEVICE";
export const MODE_BLOCK_DEVICE = "BLOCK_DEVICE";
export const ROOT_DIRECTORY_NAME = "/"; // basename(normalize(path))
export const STDIN = 0;
export const STDOUT = 1;
export const STDERR = 2;
export const FIRST_DESCRIPTOR = 3;
export const N_VFS_DESCRIPTORS = 1024;
export const DATA_BLOCK_SEPARATOR = "#";
export const MNT_READ_ONLY = "READ_ONLY";
export const SYMLOOP_MAX = 10;

26
src/common/crypto.js Normal file
View File

@ -0,0 +1,26 @@
import Platform from "./platform";
import E from "./errors";
let Crypto;
if(Platform.supportsWebCrypto()) {
Crypto = class Crypto
{
static randomBytes(arrayBuffer)
{
return window.crypto.getRandomValues(arrayBuffer);
}
}
} else if(Platform.supportsNodeCrypto()) {
let nodeCrypto = require("crypto");
Crypto = class Crypto
{
static randomBytes(arrayBuffer)
{
return nodeCrypto.randomFillSync(arrayBuffer);
}
}
} else {
throw new E.ENOTSUPPORTED("crypto support is not available on this platform");
}
export default Crypto;

68
src/common/errors.js Normal file
View File

@ -0,0 +1,68 @@
class FilerError extends Error
{
constructor(message, path = null)
{
super(message);
this.path = path;
}
}
const errors = {};
const errorDefinitions =
[
{ errno: -1, name: "UNKNOWN", text: "unknown error" },
{ errno: 0, name: "OK", text: "success" },
{ errno: 1, name: "EOF", text: "end of file" },
{ errno: 9, name: "EBADF", text: "bad file descriptor" },
{ errno: 10, name: "EBUSY", text: "resource busy or locked" },
{ errno: 18, name: "EINVAL", text: "invalid argument" },
{ errno: 27, name: "ENOTDIR", text: "not a directory" },
{ errno: 28, name: "EISDIR", text: "illegal operation on directory" },
{ errno: 34, name: "ENOENT", text: "no such file or directory" },
{ errno: 47, name: "EEXIST", text: "file already exists" },
{ errno: 50, name: "EPERM", text: "operation not permitted" },
{ errno: 51, name: "ELOOP", text: "too many symbolic links encountered" },
{ errno: 53, name: "ENOTEMPTY", text: "directory not empty" },
{ errno: 55, name: "EIO", text: "i/o error" },
{ errno: 56, name: "EROFS", text: "read-only file system" },
{ errno: 57, name: "ENODEV", text: "no such device" },
{ errno: 58, name: "ECANCELED", text: "operation canceled" },
{ errno: 1000, name: "ENOTSUPPORTED", text: "platform is not supported" },
]
for (let error of errorDefinitions) {
errors[error.errno] = errors[error.name] = class extends FilerError {
constructor(message, path)
{
super(message || error.text, path);
}
get name() { return error.name }
get code() { return error.name }
get errno() { return error.errno }
get message() { return this.message }
get stack() { return (new Error(this.message)).stack }
get toString() {
pathInfo = this.path ? (', \'' + this.path + '\'') : '';
return `${this.name}: ${this.message}${pathInfo}`;
}
}
}
export default errors;

0
src/common/index.js Normal file
View File

204
src/common/path.js Normal file
View File

@ -0,0 +1,204 @@
import E from "./errors";
function normalizeArray(parts, allowAboveRoot) {
// if the path tries to go above the root, `up` ends up > 0
var up = 0;
for (var i = parts.length - 1; i >= 0; i--) {
var last = parts[i];
if (last === '.') {
parts.splice(i, 1);
} else if (last === '..') {
parts.splice(i, 1);
up++;
} else if (up) {
parts.splice(i, 1);
up--;
}
}
// if the path is allowed to go above the root, restore leading ..s
if (allowAboveRoot) {
for (; up--; up) {
parts.unshift('..');
}
}
return parts;
}
// Split a filename into [root, dir, basename, ext], unix version
// 'root' is just a slash, or nothing.
var splitPathRe =
/^(\/?)([\s\S]+\/(?!$)|\/)?((?:\.{1,2}$|[\s\S]+?)?(\.[^.\/]*)?)$/;
var splitPath = function(filename) {
var result = splitPathRe.exec(filename);
return [result[1] || '', result[2] || '', result[3] || '', result[4] || ''];
};
// path.resolve([from ...], to)
export function resolve() {
var resolvedPath = '',
resolvedAbsolute = false;
for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
// XXXfiler: we don't have process.cwd() so we use '/' as a fallback
var path = (i >= 0) ? arguments[i] : '/';
// Skip empty and invalid entries
if (typeof path !== 'string' || !path) {
continue;
}
resolvedPath = path + '/' + resolvedPath;
resolvedAbsolute = path.charAt(0) === '/';
}
// At this point the path should be resolved to a full absolute path, but
// handle relative paths to be safe (might happen when process.cwd() fails)
// Normalize the path
resolvedPath = normalizeArray(resolvedPath.split('/').filter(function(p) {
return !!p;
}), !resolvedAbsolute).join('/');
return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
}
// path.normalize(path)
export function normalize(path) {
var isAbsolute = path.charAt(0) === '/',
trailingSlash = path.substr(-1) === '/';
// Normalize the path
path = normalizeArray(path.split('/').filter(function(p) {
return !!p;
}), !isAbsolute).join('/');
if (!path && !isAbsolute) {
path = '.';
}
/*
if (path && trailingSlash) {
path += '/';
}
*/
return (isAbsolute ? '/' : '') + path;
}
export function join() {
var paths = Array.prototype.slice.call(arguments, 0);
return normalize(paths.filter(function(p, index) {
return p && typeof p === 'string';
}).join('/'));
}
// path.relative(from, to)
export function relative(from, to) {
from = resolve(from).substr(1);
to = resolve(to).substr(1);
function trim(arr) {
var start = 0;
for (; start < arr.length; start++) {
if (arr[start] !== '') break;
}
var end = arr.length - 1;
for (; end >= 0; end--) {
if (arr[end] !== '') break;
}
if (start > end) return [];
return arr.slice(start, end - start + 1);
}
var fromParts = trim(from.split('/'));
var toParts = trim(to.split('/'));
var length = Math.min(fromParts.length, toParts.length);
var samePartsLength = length;
for (var i = 0; i < length; i++) {
if (fromParts[i] !== toParts[i]) {
samePartsLength = i;
break;
}
}
var outputParts = [];
for (var i = samePartsLength; i < fromParts.length; i++) {
outputParts.push('..');
}
outputParts = outputParts.concat(toParts.slice(samePartsLength));
return outputParts.join('/');
}
export function dirname(path) {
var result = splitPath(path),
root = result[0],
dir = result[1];
if (!root && !dir) {
// No dirname whatsoever
return '.';
}
if (dir) {
// It has a dirname, strip trailing slash
dir = dir.substr(0, dir.length - 1);
}
return root + dir;
}
export function basename(path, ext) {
var f = splitPath(path)[2];
// TODO: make this comparison case-insensitive on windows?
if (ext && f.substr(-1 * ext.length) === ext) {
f = f.substr(0, f.length - ext.length);
}
// XXXfiler: node.js just does `return f`
return f === "" ? "/" : f;
}
export function extname(path) {
return splitPath(path)[3];
}
export function isAbsolute(path) {
if(path.charAt(0) === '/') {
return true;
}
return false;
}
export function isNull(path) {
if (('' + path).indexOf('\u0000') !== -1) {
return true;
}
return false;
}
// Make sure we don't double-add a trailing slash (e.g., '/' -> '//')
export function addTrailing(path) {
return path.replace(/\/*$/, '/');
}
// Deal with multiple slashes at the end, one, or none
// and make sure we don't return the empty string.
export function removeTrailing(path) {
path = path.replace(/\/*$/, '');
return path === '' ? '/' : path;
}
export function check(path) {
if(!path) {
throw new E.EINVAL('path must be a string', path);
} else if(isNull(path)) {
throw new E.EINVAL('path must be a string without null bytes', path);
} else if(!isAbsolute(path)) {
throw new E.EINVAL('path must be absolute', path);
}
}

24
src/common/platform.js Normal file
View File

@ -0,0 +1,24 @@
class Platform
{
static supportsWebCrypto()
{
return ("undefined" !== typeof window &&
"undefined" !== typeof window.crypto &&
"function" === typeof window.crypto.getRandomValues);
}
static supportsNodeCrypto()
{
if("undefined" !== typeof process) {
try {
require.resolve("crypto");
return true;
} catch(e) {
}
}
return false;
}
}
export default Platform;

117
src/common/url.js Normal file
View File

@ -0,0 +1,117 @@
const __ = new WeakMap();
const URL_REGEX = /^((\w+)\+(\w+):)?(\/\/((\w+)?(:(\w+))?@)?([^\/\?:]+)(:(\d+))?)?(\/?([^\/\?#][^\?#]*)?)?(\?([^#]+))?(#(\w*))?/i;
class URL
{
constructor(urlString)
{
__.set(this, {
});
const self = __.get(this);
let match = urlString.match(URL_REGEX);
self.originalURL = match[0];
if(match[2]) {
self.protocol = match[2];
}
if(match[3]) {
self.subprotocol = match[3];
}
if(match[6]) {
self.username = match[6];
}
if(match[8]) {
self.password = match[8];
}
if(match[9]) {
self.host = match[9];
} else {
self.host = "";
}
if(match[11]) {
self.port = match[11];
}
if(match[12]) {
self.path = match[12];
} else {
self.path = "";
}
if(match[15]) {
let queryList = match[15].split("&");
let query = {};
for(let item of queryList) {
let [key, value] = item.split("=");
if(!(query.hasOwnProperty(key))) {
query[key] = [];
}
if(value) {
query[key].push(value);
}
}
self.query = query;
} else {
self.query = {};
}
if(match[17]) {
self.fragment = match[17];
} else {
self.fragment = "";
}
}
get protocol() { return __.get(this).protocol }
set protocol(value) { return __.get(this).protocol = value }
get subprotocol() { return __.get(this).subprotocol }
set subprotocol(value) { return __.get(this).subprotocol = value }
get username() { return __.get(this).username }
set username(value) { return __.get(this).username = value }
get password() { return __.get(this).password }
set password(value) { return __.get(this).password = value }
get host() { return __.get(this).host }
set host(value) { return __.get(this).host = value }
get port() { return __.get(this).port }
set port(value) { return __.get(this).port = value }
get path() { return __.get(this).path }
set path(value) { return __.get(this).path = value }
get query() { return __.get(this).query }
set query(value) { return __.get(this).query = value }
get fragment() { return __.get(this).fragment }
set fragment(value) { return __.get(this).fragment = value }
toJSON()
{
return {
protocol: this.protocol,
subprotocol: this.subprotocol,
username: this.username,
password: this.password,
host: this.host,
port: this.port,
path: this.path,
query: this.query,
fragment: this.fragment,
};
}
}
export default URL;

63
src/common/uuid.js Normal file
View File

@ -0,0 +1,63 @@
import Crypto from "./crypto";
const UUID_SHORT_REGEX = /^[0-9a-zA-Z]{22}$/;
const BASE = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".split('');
const BASE_MAP = {};
for (var z = 0; z < BASE.length; z += 1) {
var x = BASE[z];
if (BASE_MAP[x] !== undefined) throw new TypeError(`${x} is ambiguous`)
BASE_MAP[x] = z;
}
function encode(source) {
if (source.length === 0) return ''
var digits = [0]
for (var i = 0; i < source.length; ++i) {
for (var j = 0, carry = source[i]; j < digits.length; ++j) {
carry += digits[j] << 8
digits[j] = carry % BASE.length
carry = (carry / BASE.length) | 0
}
while (carry > 0) {
digits.push(carry % BASE.length)
carry = (carry / BASE.length) | 0
}
}
var string = "";
for (var k = 0; source[k] === 0 && k < source.length - 1; ++k)
string += BASE[0];
for (var q = digits.length - 1; q >= 0; --q)
string += BASE[digits[q]];
return string
}
class UUID {
static v4()
{
let buffer = new Uint8Array(16);
Crypto.randomBytes(buffer);
buffer[6] &= 0b00001111;
buffer[6] |= 0b01000000;
buffer[8] &= 0b00111111;
buffer[8] |= 0b10000000;
return encode(buffer);
}
static short()
{
return this.v4();
}
}
export default UUID;

View File

@ -1,130 +0,0 @@
var O_READ = 'READ';
var O_WRITE = 'WRITE';
var O_CREATE = 'CREATE';
var O_EXCLUSIVE = 'EXCLUSIVE';
var O_TRUNCATE = 'TRUNCATE';
var O_APPEND = 'APPEND';
var XATTR_CREATE = 'CREATE';
var XATTR_REPLACE = 'REPLACE';
module.exports = {
FILE_SYSTEM_NAME: 'local',
FILE_STORE_NAME: 'files',
IDB_RO: 'readonly',
IDB_RW: 'readwrite',
WSQL_VERSION: '1',
WSQL_SIZE: 5 * 1024 * 1024,
WSQL_DESC: 'FileSystem Storage',
NODE_TYPE_FILE: 'FILE',
NODE_TYPE_DIRECTORY: 'DIRECTORY',
NODE_TYPE_SYMBOLIC_LINK: 'SYMLINK',
NODE_TYPE_META: 'META',
DEFAULT_DIR_PERMISSIONS: 0x1ED, // 755
DEFAULT_FILE_PERMISSIONS: 0x1A4, // 644
FULL_READ_WRITE_EXEC_PERMISSIONS: 0x1FF, // 777
READ_WRITE_PERMISSIONS: 0x1B6, /// 666
SYMLOOP_MAX: 10,
BINARY_MIME_TYPE: 'application/octet-stream',
JSON_MIME_TYPE: 'application/json',
ROOT_DIRECTORY_NAME: '/', // basename(normalize(path))
// FS Mount Flags
FS_FORMAT: 'FORMAT',
FS_NOCTIME: 'NOCTIME',
FS_NOMTIME: 'NOMTIME',
FS_NODUPEIDCHECK: 'FS_NODUPEIDCHECK',
// FS File Open Flags
O_READ: O_READ,
O_WRITE: O_WRITE,
O_CREATE: O_CREATE,
O_EXCLUSIVE: O_EXCLUSIVE,
O_TRUNCATE: O_TRUNCATE,
O_APPEND: O_APPEND,
O_FLAGS: {
'r': [O_READ],
'r+': [O_READ, O_WRITE],
'w': [O_WRITE, O_CREATE, O_TRUNCATE],
'w+': [O_WRITE, O_READ, O_CREATE, O_TRUNCATE],
'wx': [O_WRITE, O_CREATE, O_EXCLUSIVE, O_TRUNCATE],
'wx+': [O_WRITE, O_READ, O_CREATE, O_EXCLUSIVE, O_TRUNCATE],
'a': [O_WRITE, O_CREATE, O_APPEND],
'a+': [O_WRITE, O_READ, O_CREATE, O_APPEND],
'ax': [O_WRITE, O_CREATE, O_EXCLUSIVE, O_APPEND],
'ax+': [O_WRITE, O_READ, O_CREATE, O_EXCLUSIVE, O_APPEND]
},
XATTR_CREATE: XATTR_CREATE,
XATTR_REPLACE: XATTR_REPLACE,
FS_READY: 'READY',
FS_PENDING: 'PENDING',
FS_ERROR: 'ERROR',
SUPER_NODE_ID: '00000000-0000-0000-0000-000000000000',
// Reserved File Descriptors for streams
STDIN: 0,
STDOUT: 1,
STDERR: 2,
FIRST_DESCRIPTOR: 3,
ENVIRONMENT: {
TMP: '/tmp',
PATH: ''
},
// Duplicate Node's fs.constants
fsConstants: {
O_RDONLY: 0,
O_WRONLY: 1,
O_RDWR: 2,
S_IFMT: 61440,
S_IFREG: 32768,
S_IFDIR: 16384,
S_IFCHR: 8192,
S_IFBLK: 24576,
S_IFIFO: 4096,
S_IFLNK: 40960,
S_IFSOCK: 49152,
O_CREAT: 512,
O_EXCL: 2048,
O_NOCTTY: 131072,
O_TRUNC: 1024,
O_APPEND: 8,
O_DIRECTORY: 1048576,
O_NOFOLLOW: 256,
O_SYNC: 128,
O_DSYNC: 4194304,
O_SYMLINK: 2097152,
O_NONBLOCK: 4,
S_IRWXU: 448,
S_IRUSR: 256,
S_IWUSR: 128,
S_IXUSR: 64,
S_IRWXG: 56,
S_IRGRP: 32,
S_IWGRP: 16,
S_IXGRP: 8,
S_IRWXO: 7,
S_IROTH: 4,
S_IWOTH: 2,
S_IXOTH: 1,
F_OK: 0,
R_OK: 4,
W_OK: 2,
X_OK: 1,
UV_FS_COPYFILE_EXCL: 1,
COPYFILE_EXCL: 1
}
};

View File

@ -1,6 +0,0 @@
var NODE_TYPE_FILE = require('./constants.js').NODE_TYPE_FILE;
module.exports = function DirectoryEntry(id, type) {
this.id = id;
this.type = type || NODE_TYPE_FILE;
};

View File

@ -1,12 +0,0 @@
'use strict';
const Stats = require('./stats.js');
function Dirent(path, fileNode, devName) {
this.constructor = Dirent;
Stats.call(this, path, fileNode, devName);
}
Dirent.prototype = Stats.prototype;
module.exports = Dirent;

Some files were not shown because too many files have changed in this diff Show More