diff --git a/.eslintrc.json b/.eslintrc.json
new file mode 100644
index 00000000..90b26d15
--- /dev/null
+++ b/.eslintrc.json
@@ -0,0 +1,134 @@
+{
+ "env": {
+ "browser": true,
+ "jquery": true,
+ "node": true,
+ "es6": true
+ },
+ "globals": {
+ "expect": true,
+ "it": true,
+ "describe": true,
+ "beforeEach": true,
+ "afterEach": true
+ },
+ "parserOptions": {
+ "ecmaVersion": 6
+ },
+ "rules": {
+ "camelcase": 2,
+ "eqeqeq": 2,
+ "indent": [
+ 2,
+ 2,
+ {
+ "SwitchCase": 1
+ }
+ ],
+ "no-use-before-define": [
+ 2,
+ {
+ "functions": false
+ }
+ ],
+ "no-caller": 2,
+ "new-cap": 0,
+ "quotes": [
+ 2,
+ "single"
+ ],
+ "no-unused-vars": 2,
+ "strict": [
+ 2,
+ "function"
+ ],
+ "no-extend-native": 2,
+ "wrap-iife": [
+ 2,
+ "any"
+ ],
+ "no-empty": 2,
+ "no-plusplus": 2,
+ "no-undef": 2,
+ "linebreak-style": 0,
+ "max-depth": [
+ 2,
+ 4
+ ],
+ "no-loop-func": 2,
+ "complexity": [
+ 2,
+ 13
+ ],
+ "max-len": [
+ 2,
+ {
+ "code": 120,
+ "ignoreComments": true
+ }
+ ],
+ "max-params": [
+ 2,
+ 5
+ ],
+ "curly": [
+ 2,
+ "all"
+ ],
+ "keyword-spacing": [
+ 2,
+ {}
+ ],
+ "one-var": [
+ 2,
+ "never"
+ ],
+ "array-bracket-spacing": [
+ 2,
+ "never",
+ {}
+ ],
+ "space-in-parens": [
+ 2,
+ "never"
+ ],
+ "key-spacing": [
+ 2,
+ {
+ "beforeColon": false,
+ "afterColon": true
+ }
+ ],
+ "quote-props": [
+ 2,
+ "as-needed"
+ ],
+ "space-infix-ops": 2,
+ "space-unary-ops": [
+ 2,
+ {
+ "words": false,
+ "nonwords": false
+ }
+ ],
+ "no-implicit-coercion": [
+ 2,
+ {
+ "boolean": false,
+ "string": true,
+ "number": true
+ }
+ ],
+ "no-with": 2,
+ "no-multiple-empty-lines": 2,
+ "brace-style": [
+ 2,
+ "1tbs",
+ {
+ "allowSingleLine": true
+ }
+ ],
+ "eol-last": 2,
+ "no-trailing-spaces": 2
+ }
+}
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644
index 00000000..16f9bad5
--- /dev/null
+++ b/.github/workflows/main.yml
@@ -0,0 +1,17 @@
+name: Node.js CI
+
+on: [push]
+
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+ - name: Use Node.js
+ uses: actions/setup-node@v3
+ with:
+ node-version: '17.7.x'
+ - run: yarn --frozen-lockfile
+ - run: npm test
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..b563f830
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+node_modules
+.vscode
+npm-debug.log
+debug
+dist
+.idea
diff --git a/.jshintrc b/.jshintrc
deleted file mode 100644
index f715520a..00000000
--- a/.jshintrc
+++ /dev/null
@@ -1,35 +0,0 @@
-{
- "node": true,
- "esnext": true,
- "bitwise": true,
- "camelcase": true,
- "curly": true,
- "eqeqeq": true,
- "indent": 2,
- "latedef": true,
- "noarg": true,
- "newcap": false,
- "quotmark": "single",
- "unused": true,
- "strict": true,
- "trailing": true,
- "smarttabs": true,
- "white": true,
- "freeze": true,
- "immed": true,
- "noempty": true,
- "plusplus": true,
- "undef": true,
- "laxbreak": true,
- "maxdepth": 3,
- "loopfunc": true,
- "maxcomplexity": 9,
- "maxlen": 80,
- "globals": {
- "window": true,
- "it": true,
- "beforeEach": true,
- "describe": true,
- "expect": true
- }
-}
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 00000000..07d8aa30
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,4 @@
+language: node_js
+node_js:
+ - "8"
+script: npm run build
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 00000000..02a003f5
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,76 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, sex characteristics, gender identity and expression,
+level of experience, education, socio-economic status, nationality, personal
+appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or
+ advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviors that they deem inappropriate,
+threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by contacting the project team at minko@gechev.io. All
+complaints will be reviewed and investigated and will result in a response that
+is deemed necessary and appropriate to the circumstances. The project team is
+obligated to maintain confidentiality with regard to the reporter of an incident.
+Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good
+faith may face temporary or permanent repercussions as determined by other
+members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
+available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
+
+[homepage]: https://www.contributor-covenant.org
+
+For answers to common questions about this code of conduct, see
+https://www.contributor-covenant.org/faq
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 00000000..c617c7e0
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Minko Gechev
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/doc-config.json b/doc-config.json
new file mode 100644
index 00000000..520991a4
--- /dev/null
+++ b/doc-config.json
@@ -0,0 +1,34 @@
+{
+ "tags": {
+ "allowUnknownTags": true
+ },
+ "source": {
+ "include": [
+ "./src/combinatorics/",
+ "./src/compression/",
+ "./src/data-structures/",
+ "./src/graphics/",
+ "./src/graphs/others/",
+ "./src/graphs/searching/",
+ "./src/graphs/shortest-path/",
+ "./src/graphs/spanning-trees/",
+ "./src/others/",
+ "./src/primes/",
+ "./src/searching/",
+ "./src/sets/",
+ "./src/shuffle/",
+ "./src/sorting/"
+ ],
+ "includePattern": ".+\\.js(doc)?$",
+ "excludePattern": "docs"
+ },
+ "plugins": [],
+ "opts": {
+ "template": "node_modules/@jeremyckahn/minami",
+ "encoding": "utf8",
+ "destination": "dist",
+ "recurse": true,
+ "private": false,
+ "readme": "./readme.md"
+ }
+}
diff --git a/gulpfile.js b/gulpfile.js
new file mode 100644
index 00000000..47c08e1c
--- /dev/null
+++ b/gulpfile.js
@@ -0,0 +1,19 @@
+const gulp = require('gulp');
+const eslint = require('gulp-eslint');
+const jasmine = require('gulp-jasmine');
+
+gulp.task('test', () => {
+ 'use strict';
+ return gulp.src('test/**/*.spec.js')
+ .pipe(jasmine());
+});
+
+gulp.task('lint', ()=> {
+ 'use strict';
+ return gulp.src(['src/**/*.js', 'test/**/*.js'])
+ .pipe(eslint())
+ .pipe(eslint.format())
+ .pipe(eslint.failAfterError());
+});
+
+gulp.task('build', gulp.parallel(['lint', 'test']));
diff --git a/package.json b/package.json
new file mode 100644
index 00000000..190c1a5f
--- /dev/null
+++ b/package.json
@@ -0,0 +1,36 @@
+{
+ "name": "javascript-algorithms",
+ "version": "0.0.0",
+ "description": "Implementations of different computer science algorithms",
+ "main": "index.js",
+ "directories": {
+ "test": "test"
+ },
+ "devDependencies": {
+ "@jeremyckahn/minami": "^1.3.1",
+ "gh-pages": "^1.1.0",
+ "gulp": "^4.0.2",
+ "gulp-eslint": "^3.0.1",
+ "gulp-jasmine": "^2.0.1",
+ "jsdoc": "3.5.5",
+ "live-server": "^1.2.0"
+ },
+ "scripts": {
+ "build": "gulp build",
+ "test": "gulp test",
+ "deploy": "npm run doc:build && gh-pages -d dist -b gh-pages",
+ "doc": "npm run doc:build && npm run doc:view",
+ "doc:build": "jsdoc -c doc-config.json",
+ "doc:view": "live-server dist --port=9124"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/mgechev/javascript-algorithms"
+ },
+ "author": "@mgechev",
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/mgechev/javascript-algorithms/issues"
+ },
+ "homepage": "https://github.com/mgechev/javascript-algorithms"
+}
diff --git a/readme.md b/readme.md
index 2f06c36e..945b4238 100644
--- a/readme.md
+++ b/readme.md
@@ -1,20 +1,95 @@
## About
-This repository contains different famous Computer Science algorithms implemented in JavaScript
+This repository contains JavaScript implementations of famous computer science algorithms.
-In order to run the tests use:
+API reference with usage examples available
+here.
-```Bash
-jasmine-node test/
+## Development
+
+**To install all dev dependencies**
+
+Call:
+
+```bash
+npm install
+```
+
+**To setup repository with documentation**
+
+```bash
+npm run doc
+```
+
+This will build the documentation and open it in your browser.
+
+**To update .html files with documentation**
+
+Just run `npm run doc` again.
+
+**To run tests**
+
+Call:
+
+```bash
+npm run test
```
-and all `*.spec.js` files will be executed.
+This will execute all `*.spec.js` files.
+
+**To deploy documentation site**
+
+```bash
+npm run deploy
+```
+
+This requires you to have commit access to your Git remote.
## Contributions
-Fork the repo and make requred changes. After that push your changes in branch, which is named according to the changes you did.
-Initiate the PR.
+Fork the repo and make required changes. Afterwards, push your changes in branch. The name will be according to the changes you did. Initiate the pull request.
+
+Make sure your editor makes validations according to the `.jshintrc` in the root directory of the repository.
+
+Before pushing to the repository, run:
+
+```bash
+npm run build
+```
+
+If the build is not successful, fix your code in order for the tests and jshint validation to run successfully. Then create a pull request.
+
+## Contributors
+
+[
](https://github.com/mgechev) |[
](https://github.com/AndriiHeonia) |[
](https://github.com/Jakehp) |[
](https://github.com/lygstate) |[
](https://github.com/mik-laj) |[
](https://github.com/krzysztof-grzybek) |
+:---: |:---: |:---: |:---: |:---: |:---: |
+[mgechev](https://github.com/mgechev) |[AndriiHeonia](https://github.com/AndriiHeonia) |[Jakehp](https://github.com/Jakehp) |[lygstate](https://github.com/lygstate) |[mik-laj](https://github.com/mik-laj) |[krzysztof-grzybek](https://github.com/krzysztof-grzybek) |
+
+[
](https://github.com/pvoznenko) |[
](https://github.com/jettcalleja) |[
](https://github.com/filipefalcaos) |[
](https://github.com/kdamball) |[
](https://github.com/lekkas) |[
](https://github.com/infusion) |
+:---: |:---: |:---: |:---: |:---: |:---: |
+[pvoznenko](https://github.com/pvoznenko) |[jettcalleja](https://github.com/jettcalleja) |[filipefalcaos](https://github.com/filipefalcaos) |[kdamball](https://github.com/kdamball) |[lekkas](https://github.com/lekkas) |[infusion](https://github.com/infusion) |
+
+[
](https://github.com/deniskyashif) |[
](https://github.com/brunohadlich) |[
](https://github.com/designeng) |[
](https://github.com/Microfed) |[
](https://github.com/Nirajkashyap) |[
](https://github.com/pkerpedjiev) |
+:---: |:---: |:---: |:---: |:---: |:---: |
+[deniskyashif](https://github.com/deniskyashif) |[brunohadlich](https://github.com/brunohadlich) |[designeng](https://github.com/designeng) |[Microfed](https://github.com/Microfed) |[Nirajkashyap](https://github.com/Nirajkashyap) |[pkerpedjiev](https://github.com/pkerpedjiev) |
+
+[
](https://github.com/duffman85) |[
](https://github.com/Xuefeng-Zhu) |[
](https://github.com/emyarod) |[
](https://github.com/alexjoverm) |[
](https://github.com/amilajack) |[
](https://github.com/BorislavBorisov22) |
+:---: |:---: |:---: |:---: |:---: |:---: |
+[duffman85](https://github.com/duffman85) |[Xuefeng-Zhu](https://github.com/Xuefeng-Zhu) |[emyarod](https://github.com/emyarod) |[alexjoverm](https://github.com/alexjoverm) |[amilajack](https://github.com/amilajack) |[BorislavBorisov22](https://github.com/BorislavBorisov22) |
+
+[
](https://github.com/brunob15) |[
](https://github.com/BryanChan777) |[
](https://github.com/ysharplanguage) |[
](https://github.com/jurassix) |[
](https://github.com/fisenkodv) |[
](https://github.com/contra) |
+:---: |:---: |:---: |:---: |:---: |:---: |
+[brunob15](https://github.com/brunob15) |[BryanChan777](https://github.com/BryanChan777) |[ysharplanguage](https://github.com/ysharplanguage) |[jurassix](https://github.com/jurassix) |[fisenkodv](https://github.com/fisenkodv) |[contra](https://github.com/contra) |
+
+[
](https://github.com/liesislukas) |[
](https://github.com/marrcelo) |[
](https://github.com/wnvko) |[
](https://github.com/millerrach) |[
](https://github.com/xiedezhuo) |[
](https://github.com/DengYiping) |
+:---: |:---: |:---: |:---: |:---: |:---: |
+[liesislukas](https://github.com/liesislukas) |[marrcelo](https://github.com/marrcelo) |[wnvko](https://github.com/wnvko) |[millerrach](https://github.com/millerrach) |[xiedezhuo](https://github.com/xiedezhuo) |[DengYiping](https://github.com/DengYiping) |
+
+[
](https://github.com/fanixk) |[
](https://github.com/wlx199x) |[
](https://github.com/shaunak1111) |
+:---: |:---: |:---: |
+[fanixk](https://github.com/fanixk) |[wlx199x](https://github.com/wlx199x) |[shaunak1111](https://github.com/shaunak1111) |
## License
The code in this repository is distributed under the terms of the MIT license.
+
diff --git a/src/combinatorics/cartesianproduct.js b/src/combinatorics/cartesianproduct.js
new file mode 100644
index 00000000..a1940f32
--- /dev/null
+++ b/src/combinatorics/cartesianproduct.js
@@ -0,0 +1,49 @@
+(function (exports) {
+ 'use strict';
+
+ var cartesianProduct = (function () {
+ var result;
+
+ function cartesianProduct(sets, index, current) {
+ if (index === sets.length) {
+ return result.push(current.slice());
+ }
+ for (var i = 0; i < sets[index].length; i += 1) {
+ current[index] = sets[index][i];
+ cartesianProduct(sets, index + 1, current);
+ }
+ }
+
+ /**
+ * Calculates Cartesian product of provided sets.
+ *
+ * @module combinatorics/cartesianproduct
+ * @public
+ * @param {Array} sets Array of sets.
+ * @return {Array} Cartesian product of provided sets.
+ *
+ * @example
+ * var product = require('path-to-algorithms/src/combinatorics/' +
+ * 'cartesianproduct').cartesianProduct;
+ * var result = product([[1, 2, 3], [3, 2, 1]]);
+ * // [ [ 1, 3 ],
+ * // [ 1, 2 ],
+ * // [ 1, 1 ],
+ * // [ 2, 3 ],
+ * // [ 2, 2 ],
+ * // [ 2, 1 ],
+ * // [ 3, 3 ],
+ * // [ 3, 2 ],
+ * // [ 3, 1 ] ]
+ * console.log(result);
+ */
+ return function (sets) {
+ result = [];
+ cartesianProduct(sets, 0, []);
+ return result;
+ };
+ }());
+
+ exports.cartesianProduct = cartesianProduct;
+
+}((typeof window === 'undefined') ? module.exports : window));
diff --git a/src/combinatorics/combinations.js b/src/combinatorics/combinations.js
new file mode 100644
index 00000000..9f72d17e
--- /dev/null
+++ b/src/combinatorics/combinations.js
@@ -0,0 +1,54 @@
+(function (exports) {
+ 'use strict';
+
+ var combinations = (function () {
+ var res = [];
+
+ function combinations(arr, k, start, idx, current) {
+ if (idx === k) {
+ res.push(current.slice());
+ return;
+ }
+ for (var i = start; i < arr.length; i += 1) {
+ current[idx] = arr[i];
+ combinations(arr, k, i + 1, idx + 1, current);
+ }
+ }
+
+ /**
+ * Finds all the combinations of given array.
+ * A combination is a way of selecting members from a grouping,
+ * such that (unlike permutations) the order of selection does not matter.
+ * For example given three fruits, say an apple, an orange and a pear,
+ * there are three combinations of two that can be drawn from this set:
+ * an apple and a pear; an apple and an orange; or a pear and an orange.
+ *
+ * @example
+ *
+ * var combinations = require('path-to-algorithms/src/' +
+ * 'combinatorics/combinations').combinations;
+ * var result = combinations(['apple', 'orange', 'pear'], 2);
+ * // [['apple', 'orange'],
+ * // ['apple', 'pear'],
+ * // ['orange', 'pear']]
+ * console.log(result);
+ *
+ * @module combinatorics/combinations
+ * @public
+ * @param arr {Array} Set of items.
+ * @param k {Number} Size of each combination.
+ * @return {Array} Returns all combinations.
+ */
+ return function (arr, k) {
+ res = [];
+ combinations(arr, k, 0, 0, []);
+ var temp = res;
+ // Free the extra memory
+ res = null;
+ return temp;
+ };
+ }());
+
+ exports.combinations = combinations;
+
+}((typeof window === 'undefined') ? module.exports : window));
diff --git a/src/combinatorics/permutations.js b/src/combinatorics/permutations.js
new file mode 100644
index 00000000..0ab94b77
--- /dev/null
+++ b/src/combinatorics/permutations.js
@@ -0,0 +1,63 @@
+(function (exports) {
+ 'use strict';
+ var permutations = (function () {
+
+ var res;
+
+ function swap(arr, i, j) {
+ var temp = arr[i];
+ arr[i] = arr[j];
+ arr[j] = temp;
+ }
+
+ function permutations(arr, current) {
+ if (current >= arr.length) {
+ return res.push(arr.slice());
+ }
+ for (var i = current; i < arr.length; i += 1) {
+ swap(arr, i, current);
+ permutations(arr, current + 1);
+ swap(arr, i, current);
+ }
+ }
+
+ /**
+ * Finds all the permutations of given array.
+ * Permutation relates to the act of rearranging, or permuting,
+ * all the members of a set into some sequence or order.
+ * For example there are six permutations of the set {1,2,3}, namely:
+ * (1,2,3), (1,3,2), (2,1,3), (2,3,1), (3,1,2), and (3,2,1).
+ * Complexity: O(N*N!).
+ *
+ * @example
+ *
+ * var permutations = require('path-to-algorithms/src/' +
+ * 'combinatorics/permutations').permutations;
+ * var result = permutations(['apple', 'orange', 'pear']);
+ *
+ * // [ [ 'apple', 'orange', 'pear' ],
+ * // [ 'apple', 'pear', 'orange' ],
+ * // [ 'orange', 'apple', 'pear' ],
+ * // [ 'orange', 'pear', 'apple' ],
+ * // [ 'pear', 'orange', 'apple' ],
+ * // [ 'pear', 'apple', 'orange' ] ]
+ * console.log(result);
+ *
+ * @module combinatorics/permutations
+ * @public
+ * @param {Array} arr Array to find the permutations of.
+ * @returns {Array} Array containing all the permutations.
+ */
+ return function (arr) {
+ res = [];
+ permutations(arr, 0);
+ var temp = res;
+ // Free the extra memory
+ res = null;
+ return temp;
+ };
+ }());
+
+ exports.permutations = permutations;
+
+}((typeof window === 'undefined') ? module.exports : window));
diff --git a/src/combinatorics/variations-repetition.js b/src/combinatorics/variations-repetition.js
new file mode 100644
index 00000000..22ba009c
--- /dev/null
+++ b/src/combinatorics/variations-repetition.js
@@ -0,0 +1,55 @@
+(function (exports) {
+ 'use strict';
+
+ var variationsWithRepetition = (function () {
+ var res;
+
+ function variations(arr, k, index, current) {
+ if (k === index) {
+ return res.push(current.slice());
+ }
+ for (var i = 0; i < arr.length; i += 1) {
+ current[index] = arr[i];
+ variations(arr, k, index + 1, current);
+ }
+ }
+
+ /**
+ * Finds all the variations with repetition of given array.
+ * Variations with repetition is the number of ways to sample k elements
+ * from a set of elements (which may be repeated).
+ *
+ * @example
+ * var variations = require('path-to-algorithms/src/combinatorics/' +
+ * 'variations-repetition').variationsWithRepetition;
+ * var result = variations(['apple', 'orange', 'pear'], 2);
+ *
+ * // [['apple', 'apple'],
+ * // ['apple', 'orange'],
+ * // ['apple', 'pear'],
+ * // ['orange', 'apple'],
+ * // ['orange', 'orange'],
+ * // ['orange', 'pear'],
+ * // ['pear', 'apple'],
+ * // ['pear', 'orange'],
+ * // ['pear', 'pear']]
+ * console.log(result);
+ *
+ * @module combinatorics/variations-repetition
+ * @public
+ * @param arr {Array} Set of items.
+ * @param k {Number} Size of each combination.
+ * @return {Array} Returns all combinations.
+ */
+ return function (arr, k) {
+ res = [];
+ variations(arr, k, 0, []);
+ var temp = res;
+ res = undefined;
+ return temp;
+ };
+ }());
+
+ exports.variationsWithRepetition = variationsWithRepetition;
+
+}((typeof window === 'undefined') ? module.exports : window));
diff --git a/src/compression/LZW/LZW.js b/src/compression/LZW/LZW.js
new file mode 100644
index 00000000..9c1f9c06
--- /dev/null
+++ b/src/compression/LZW/LZW.js
@@ -0,0 +1,95 @@
+/**
+ * LZW Encoding/Decoding
+ *
+ * Lempel–Ziv–Welch (LZW) is a universal lossless data
+ * compression algorithm. It is an improved implementation
+ * of the LZ78 algorithm.
+ *
+ * @example
+ * var lzwModule = require('path-to-algorithms/src/compression'+
+ * '/LZW/LZW');
+ * var lzw = new lzwModule.LZW();
+ *
+ * var compressed = lzw.compress("ABCABCABCABCABCABC");
+ * console.log(compressed);
+ *
+ * var decompressed = lzw.decompress(compressed);
+ * console.log(decompressed);
+ *
+ * @module compression/LZW/LZW
+ */
+(function (exports) {
+ 'use strict';
+
+ exports.LZW = function () {
+ this.dictionarySize = 256;
+ };
+
+ exports.LZW.compress = function (data) {
+ var i;
+ var dictionary = {};
+ var character;
+ var wc;
+ var w = '';
+ var result = [];
+
+ for (i = 0; i < this.dictionarySize; i = i + 1) {
+ dictionary[String.fromCharCode(i)] = i;
+ }
+
+ for (i = 0; i < data.length; i = i + 1) {
+ character = data.charAt(i);
+ wc = w + character;
+ if (dictionary.hasOwnProperty(wc)) {
+ w = wc;
+ } else {
+ result.push(dictionary[w]);
+ dictionary[wc] = this.dictionarySize;
+ this.dictionarySize = this.dictionarySize + 1;
+ w = String(character);
+ }
+ }
+
+ if (w !== '') {
+ result.push(dictionary[w]);
+ }
+
+ return result;
+ };
+
+ exports.LZW.decompress = function (compressedData) {
+ var i;
+ var dictionary = [];
+ var w;
+ var result;
+ var key;
+ var entry = '';
+
+ for (i = 0; i < this.dictionarySize; i = i + 1) {
+ dictionary[i] = String.fromCharCode(i);
+ }
+
+ w = String.fromCharCode(compressedData[0]);
+ result = w;
+
+ for (i = 1; i < compressedData.length; i = i + 1) {
+ key = compressedData[i];
+ if (dictionary[key]) {
+ entry = dictionary[key];
+ } else {
+ if (key === this.dictionarySize) {
+ entry = w + w.charAt(0);
+ } else {
+ return null;
+ }
+ }
+
+ result += entry;
+ dictionary[this.dictionarySize] = w + entry.charAt(0);
+ this.dictionarySize = this.dictionarySize + 1;
+ w = entry;
+ }
+
+ return result;
+ };
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/compression/burrows-wheeler/burrows-wheeler.js b/src/compression/burrows-wheeler/burrows-wheeler.js
new file mode 100644
index 00000000..f2f68e03
--- /dev/null
+++ b/src/compression/burrows-wheeler/burrows-wheeler.js
@@ -0,0 +1,84 @@
+(function (exports) {
+ 'use strict';
+
+ /**
+ * Burrows Wheeler.
+ *
+ * This algorithm is commonly used as a step in the process of compressing data,
+ * it rearranges a character string into runs of similar characters making algorithms
+ * like move-to-front transform and run-length encoding reach higher compression
+ * rates. This implementation only supports characters with ascii code greater than $(36) as
+ * 36 is used at the process of encode and decode.
+ *
+ * @example
+ * const burrows = require('path-to-algorithms/src/burrows-wheeler/burrows-wheeler').burrowsWheeler;
+ * const s = 'ananabanana';
+ * const encodedStr = burrows.encode(s);
+ * console.log(encodedStr);
+ * const decodedStr = burrows.decode(encodedStr);
+ * console.log(decodedStr);
+ *
+ * @module compression/burrows-wheeler/burrows-wheeler
+ */
+ exports.burrowsWheeler = function() {
+
+ }
+
+ /**
+ * Consumes n^2 space.
+ */
+ exports.burrowsWheeler.encode = function(str) {
+ str = '$' + str;
+ var combinations = [];
+ for (let i = 0; i < str.length; i += 1) {
+ combinations.push(str.substring(i) + str.substring(0, i));
+ }
+ var sorted = combinations.sort();
+ var result = [];
+ for (let i = 0; i < sorted.length; i += 1) {
+ result.push(combinations[i][str.length - 1]);
+ }
+ return result.join('');
+ }
+
+ exports.burrowsWheeler.decode = function(encodedStr) {
+ const sortedCharSequence = encodedStr.split('').sort().join('');
+ const leftSide = {};
+ const rightSide = {};
+ var maxEachCharLeft = {};
+ var maxEachCharRight = {};
+
+ for (let i = 0; i < encodedStr.length; i += 1) {
+ var idLeft = sortedCharSequence[i];
+ if (idLeft in maxEachCharLeft) {
+ maxEachCharLeft[idLeft] = maxEachCharLeft[idLeft] + 1;
+ } else {
+ maxEachCharLeft[idLeft] = 1;
+ }
+ idLeft += String(maxEachCharLeft[idLeft]);
+
+ var idRight = encodedStr[i];
+ if (idRight in maxEachCharRight) {
+ maxEachCharRight[idRight] = maxEachCharRight[idRight] + 1;
+ } else {
+ maxEachCharRight[idRight] = 1;
+ }
+ idRight += String(maxEachCharRight[idRight]);
+
+ leftSide[idLeft] = {char: sortedCharSequence[i], right: idRight};
+ rightSide[idRight] = {char: encodedStr[i], left: idRight};
+ }
+ var result = '';
+ var firstChar = sortedCharSequence[0];
+ var searchChar = firstChar + '1';
+ var endChar = searchChar;
+ while (rightSide[leftSide[searchChar].right].left !== endChar) {
+ result += leftSide[searchChar].char;
+ searchChar = rightSide[leftSide[searchChar].right].left;
+ }
+ result += leftSide[searchChar].char;
+ result = result.substring(1).split('').reverse().join('');
+ return result;
+ }
+
+}(typeof exports === 'undefined' ? window : exports));
diff --git a/src/compression/runlength/runlength.js b/src/compression/runlength/runlength.js
index 1040d456..f5cebb37 100644
--- a/src/compression/runlength/runlength.js
+++ b/src/compression/runlength/runlength.js
@@ -4,64 +4,61 @@
* give us representation of string in binary which in which the
* zeros will be stripped and replaced with their count.
*/
-var runLengthEncoding = (function () {
-
+(function (exports) {
'use strict';
- /**
- * Convers a given string to sequence of numbers
- * This takes O(n).
- */
- function convertToAscii(str) {
- var result = '',
- currentChar = '',
- i = 0;
- for (; i < str.length; i += 1) {
- currentChar = str[i].charCodeAt(0).toString(2);
- if (currentChar.length < 8) {
- while (8 - currentChar.length) {
- currentChar = '0' + currentChar;
- }
+ var runLengthEncoding = (function () {
+
+ /**
+ * Converts a given string to sequence of numbers
+ * This takes O(n).
+ */
+ function convertToAscii(str) {
+ var result = [];
+ var currentChar = '';
+ var i = 0;
+ for (; i < str.length; i += 1) {
+ currentChar = str[i].charCodeAt(0).toString(2);
+ currentChar = new Array(9 - currentChar.length).join('0') + currentChar;
+ result.push(currentChar);
}
- result += currentChar;
+ return result.join('');
}
- return result;
- }
- /**
- * Encodes the binary string to run-length encoding.
- * Takes O(n^2).
- */
- function runLength(vector) {
- var result = '',
- zeros = 0,
- zerosTemp = '',
- wordLength = 0,
- i = 0;
- for (; i < vector.length; i += 1) {
- if (vector[i] === '0') {
- zeros += 1;
- } else {
- zerosTemp = zeros.toString(2);
- wordLength = zerosTemp.length - 1;
- while (wordLength) {
- result = result + '1';
- wordLength -= 1;
+ /**
+ * Encodes the binary string to run-length encoding.
+ * Takes O(n^2).
+ */
+ function runLength(vector) {
+ var result = [];
+ var zeros = 0;
+ var zerosTemp = '';
+ var i = 0;
+ for (; i < vector.length; i += 1) {
+ if (vector[i] === '0') {
+ zeros += 1;
+ } else {
+ zerosTemp = zeros.toString(2);
+ result.push(new Array(zerosTemp.length).join('1'));
+ result.push('0' + zerosTemp);
+ zeros = 0;
}
- result += '0' + zerosTemp;
- zeros = 0;
}
+ return result.join('');
}
- return result;
- }
- /**
- * Accepts a string and returns it's run-length encoded binary representation.
- * Takes O(n^2).
- */
- return function (str) {
- var asciiString = convertToAscii(str);
- return runLength(asciiString);
- };
+ /**
+ * Accepts a string and returns it's run-length
+ * encoded binary representation.
+ * Takes O(n^2).
+ */
+ return function (str) {
+ var asciiString = convertToAscii(str);
+ return runLength(asciiString);
+ };
+
+ }());
+
+ exports.runLength = runLengthEncoding;
-}());
\ No newline at end of file
+}(typeof exports === 'undefined' ? window : exports));
diff --git a/src/data-structures/avl-tree.js b/src/data-structures/avl-tree.js
new file mode 100644
index 00000000..b1d8b2d2
--- /dev/null
+++ b/src/data-structures/avl-tree.js
@@ -0,0 +1,774 @@
+/**
+ * AVL tree, a Binary Search Tree that satisfies the Height-Balance
+ * Property.
+ *
+ * @example
+ * var avlTree = require('path-to-algorithms/src/data-structures'+
+ * '/avl-tree');
+ * var avl = new avlTree.AVLTree();
+ *
+ * avl.insert(2000);
+ * avl.insert(1989);
+ * avl.insert(1991);
+ * avl.insert(2001);
+ * avl.insert(1966);
+ *
+ * @module data-structures/avl-tree
+ */
+(function (exports) {
+ 'use strict';
+
+ /**
+ * Node of the tree.
+ *
+ * @public
+ * @constructor
+ * @param {Number|String} value Value of the node.
+ * @param {Node} left Left sibling.
+ * @param {Node} right Right sibling.
+ * @param {Node} parent Parent of the node.
+ * @param {Number} height Height of the node.
+ */
+ exports.Node = function (value, left, right, parent, height) {
+ /**
+ * @member {Number|String}
+ */
+ this.value = value;
+ this._left = left;
+ this._right = right;
+ this._parent = parent;
+ this._height = height;
+ };
+
+ /**
+ * AVL Tree.
+ *
+ * @public
+ * @constructor
+ */
+ exports.AVLTree = function () {
+ this._root = null;
+ };
+
+ /**
+ * Calculates the height of a node based on height
+ * property of children.
+ *
+ * @public
+ * @method
+ * @param {Node} node Given node's height is returned.
+ */
+ exports.AVLTree.prototype._getHeightAtNode = function (node) {
+ if (node._left !== null && node._right !== null){
+ var height = Math.max(node._left._height, node._right._height);
+ height += 1;
+ return height;
+ } else if (node._left !== null){
+ return node._left._height + 1;
+ } else if (node._right !== null){
+ return node._right._height + 1;
+ } else {
+ return 1;
+ }
+ };
+
+ /**
+ * Checks if a given node has an imbalance.
+ *
+ * @public
+ * @method
+ * @param {Node} node Given node's children are checked for
+ * imbalance.
+ */
+ exports.AVLTree.prototype._isBalancedAtNode = function (node) {
+ if (node._left !== null && node._right !== null){
+ return (Math.abs(node._left._height - node._right._height) <= 1);
+ }
+ if (node._right !== null && node._left === null){
+ return node._right._height < 2;
+ }
+ if (node._left !== null && node._right === null){
+ return node._left._height < 2;
+ }
+ return true;
+ };
+
+ /**
+ * Gets the nodes to be restructured during an AVL restructure
+ * after a remove/delete takes place.
+ *
+ * @public
+ * @method
+ * @param {Array} traveledNodes Array of previously traveled nodes
+ * that are used to help determine the nodes to be restructured.
+ */
+ exports.AVLTree.prototype._getNodesToRestructureRemove = function (traveledNodes) {
+ // z is last traveled node - imbalance found at z
+ var zIndex = traveledNodes.length;
+ zIndex -= 1;
+ var z = traveledNodes[zIndex];
+ // y should be child of z with larger height
+ // (cannot be ancestor of removed node)
+ var y;
+ if ((z._left !== null && z._right !== null) || (z._left !== null && z._right === null)){
+ y = z._left;
+ } else if (z._right !== null && z._left === null){
+ y = z._right;
+ }
+ // x should be tallest child of y.
+ // If children same height, x should be child of y
+ // that has same orientation as z to y.
+ var x;
+ if (y._left !== null && y._right !== null){
+ if (y._left._height > y._right._height){
+ x = y._left;
+ } else if (y._left._height < y._right._height){
+ x = y._right;
+ } else if (y._left._height === y._right._height){
+ x = (z._left === y) ? y._left : y._right;
+ }
+ } else if (y._left !== null && y._right === null){
+ x = y._left;
+ } else if (y._right !== null && y._left === null){
+ x = y._right;
+ }
+ return [x, y, z];
+ };
+
+ /**
+ * Gets the nodes to be restructured during an AVL restructure
+ * after an insert takes place.
+ *
+ * @public
+ * @method
+ * @param {Array} traveledNodes Array of previously traveled nodes
+ * that are used to help determine the nodes to be restructured.
+ */
+ exports.AVLTree.prototype._getNodesToRestructureInsert = function (traveledNodes) {
+ // z is last traveled node - imbalance found at z
+ var zIndex = traveledNodes.length;
+ zIndex -= 1;
+ var z = traveledNodes[zIndex];
+ // y should be child of z with larger height
+ // (must be ancestor of inserted node)
+ // therefore, last traveled node is correct.
+ var yIndex = traveledNodes.length;
+ yIndex -= 2;
+ var y = traveledNodes[yIndex];
+ // x should be tallest child of y.
+ // If children same height, x should be ancestor
+ // of inserted node (in traveled path).
+ var x;
+ if (y._left !== null && y._right !== null){
+ if (y._left._height > y._right._height){
+ x = y._left;
+ } else if (y._left._height < y._right._height){
+ x = y._right;
+ } else if (y._left._height === y._right._height){
+ var xIndex = traveledNodes.length;
+ xIndex -= 3;
+ x = traveledNodes[xIndex];
+ }
+ } else if (y._left !== null && y._right === null){
+ x = y._left;
+ } else if (y._right !== null && y._left === null){
+ x = y._right;
+ }
+ return [x, y, z];
+ };
+
+ /**
+ * Maintains the height balance property by
+ * walking to root and checking for invalid height
+ * differences between children and restructuring
+ * appropriately.
+ *
+ * @public
+ * @method
+ * @param {Node} node Started node.
+ * @param {Boolean} isRemove Represents if method was called after remove.
+ */
+ exports.AVLTree.prototype._maintainHeightBalanceProperty = function (node, isRemove) {
+ var current = node;
+ var traveledNodes = [];
+ while (current !== null){
+ traveledNodes.push(current);
+ current._height = this._getHeightAtNode(current);
+ if (!this._isBalancedAtNode(current)){
+ var nodesToBeRestructured = (isRemove)
+ ? this._getNodesToRestructureRemove(traveledNodes)
+ : this._getNodesToRestructureInsert(traveledNodes);
+ this._restructure(nodesToBeRestructured);
+ }
+ current = current._parent;
+ }
+ };
+
+ /**
+ * Identifies the pattern of given nodes, then calls
+ * the appropriate pattern rotator.
+ *
+ * @public
+ * @method
+ * @param {Array} nodesToBeRestructured
+ * array of nodes, in format, [x, y, z], to be restructured
+ */
+ exports.AVLTree.prototype._restructure = function (nodesToBeRestructured) {
+ var x = nodesToBeRestructured[0];
+ var y = nodesToBeRestructured[1];
+ var z = nodesToBeRestructured[2];
+ //Determine Rotation Pattern
+ if (z._right === y && y._right === x){
+ this._rightRight(x, y, z);
+ } else if (z._left === y && y._left === x){
+ this._leftLeft(x, y, z);
+ } else if (z._right === y && y._left === x){
+ this._rightLeft(x, y, z);
+ } else if (z._left === y && y._right === x){
+ this._leftRight(x, y, z);
+ }
+ };
+
+ /**
+ * Rotates the given nodes from a right right pattern
+ * to a parent, with 2 children.
+ *
+ * @public
+ * @method
+ * @param {Node} x node with lowest height to be restructured.
+ * @param {Node} y parent of x parameter.
+ * @param {Node} z grandparent of x, largest height.
+ */
+ exports.AVLTree.prototype._rightRight = function (x, y, z) {
+ /*
+ z
+ y => y
+ x z x
+ */
+ // pass z parent to y and move y's left to z's right
+ if (z._parent !== null){
+ var orientation = (z._parent._left === z) ? '_left' : '_right';
+ z._parent[orientation] = y;
+ y._parent = z._parent;
+ } else {
+ this._root = y;
+ y._parent = null;
+ }
+ // z adopts y's left.
+ z._right = y._left;
+ if (z._right !== null){
+ z._right._parent = z;
+ }
+ // y adopts z
+ y._left = z;
+ z._parent = y;
+ // Correct each nodes height - order matters, children first
+ x._height = this._getHeightAtNode(x);
+ z._height = this._getHeightAtNode(z);
+ y._height = this._getHeightAtNode(y);
+ };
+
+ /**
+ * Rotates the given nodes from a left left pattern
+ * to a parent, with 2 children.
+ *
+ * @public
+ * @method
+ * @param {Node} x node with lowest height to be restructured.
+ * @param {Node} y parent of x parameter.
+ * @param {Node} z grandparent of x, largest height.
+ */
+ exports.AVLTree.prototype._leftLeft = function (x, y, z) {
+ /*
+ z
+ y => y
+ x x z
+ */
+ //pass z parent to y and move y's right to z's left
+ if (z._parent !== null){
+ var orientation = (z._parent._left === z) ? '_left' : '_right';
+ z._parent[orientation] = y;
+ y._parent = z._parent;
+ } else {
+ this._root = y;
+ y._parent = null;
+ }
+ z._left = y._right;
+ if (z._left !== null) {
+ z._left._parent = z;
+ }
+ //fix y right child
+ y._right = z;
+ z._parent = y;
+ // Correct each nodes height - order matters, children first
+ x._height = this._getHeightAtNode(x);
+ z._height = this._getHeightAtNode(z);
+ y._height = this._getHeightAtNode(y);
+ };
+
+ /**
+ * Rotates the given nodes from a right left pattern
+ * to a parent, with 2 children.
+ *
+ * @public
+ * @method
+ * @param {Node} x node with lowest height to be restructured.
+ * @param {Node} y parent of x parameter.
+ * @param {Node} z grandparent of x, largest height.
+ */
+ exports.AVLTree.prototype._rightLeft = function (x, y, z) {
+ /*
+ z
+ y => x
+ x z y
+ */
+ //pass z parent to x
+ if (z._parent !== null){
+ var orientation = (z._parent._left === z) ? '_left' : '_right';
+ z._parent[orientation] = x;
+ x._parent = z._parent;
+ } else {
+ this._root = x;
+ x._parent = null;
+ }
+ // Adoptions
+ z._right = x._left;
+ if (z._right !== null){
+ z._right._parent = z;
+ }
+ y._left = x._right;
+ if (y._left !== null){
+ y._left._parent = y;
+ }
+ // Point to new children (x new parent)
+ x._left = z;
+ x._right = y;
+ x._left._parent = x;
+ x._right._parent = x;
+ // Correct each nodes height - order matters, children first
+ y._height = this._getHeightAtNode(y);
+ z._height = this._getHeightAtNode(z);
+ x._height = this._getHeightAtNode(x);
+ };
+
+ /**
+ * Rotates the given nodes from a left right pattern
+ * to a parent, with 2 children.
+ *
+ * @public
+ * @method
+ * @param {Node} x node with lowest height to be restructured.
+ * @param {Node} y parent of x parameter.
+ * @param {Node} z grandparent of x, largest height.
+ */
+ exports.AVLTree.prototype._leftRight = function (x, y, z) {
+ /*
+ z
+ y => x
+ x y z
+ */
+ //pass z parent to x
+ if (z._parent !== null){
+ var orientation = (z._parent._left === z) ? '_left' : '_right';
+ z._parent[orientation] = x;
+ x._parent = z._parent;
+ } else {
+ this._root = x;
+ x._parent = null;
+ }
+ // Adoptions
+ z._left = x._right;
+ if (z._left !== null){
+ z._left._parent = z;
+ }
+ y._right = x._left;
+ if (y._right !== null){
+ y._right._parent = y;
+ }
+ // Point to new children (x new parent)
+ x._right = z;
+ x._left = y;
+ x._left._parent = x;
+ x._right._parent = x;
+ // Correct each nodes height - order matters, children first
+ y._height = this._getHeightAtNode(y);
+ z._height = this._getHeightAtNode(z);
+ x._height = this._getHeightAtNode(x);
+ };
+
+ /**
+ * Inserts a node into the AVL Tree.
+ * Time complexity: O(log N) in the average case
+ * and O(N) in the worst case.
+ *
+ * @public
+ * @method
+ * @param {Number|String} value Node value.
+ * @param {Node} current Current node.
+ */
+ exports.AVLTree.prototype.insert = function (value, current) {
+ if (this._root === null) {
+ this._root = new exports.Node(value, null, null, null, 1);
+ this._maintainHeightBalanceProperty(this._root);
+ return;
+ }
+ var insertKey;
+ current = current || this._root;
+ if (current.value > value) {
+ insertKey = '_left';
+ } else {
+ insertKey = '_right';
+ }
+ if (!current[insertKey]) {
+ current[insertKey] = new exports.Node(value, null, null, current);
+ this._maintainHeightBalanceProperty(current[insertKey], false);
+ } else {
+ this.insert(value, current[insertKey]);
+ }
+ };
+
+ /**
+ * In-order traversal from the given node.
+ *
+ * @private
+ * @param {Node} current Node from which to start the traversal.
+ * @param {Function} callback Callback which
+ * will be called for each traversed node.
+ */
+ exports.AVLTree.prototype._inorder = function (current, callback) {
+ if (!current) {
+ return;
+ }
+ this._inorder(current._left, callback);
+ if (typeof callback === 'function') {
+ callback(current);
+ }
+ this._inorder(current._right, callback);
+ };
+
+ /**
+ * In-order traversal of the whole AVL tree.
+ *
+ * @public
+ * @method
+ * @param {Function} callback Callback which will be
+ * called for each traversed node.
+ */
+ exports.AVLTree.prototype.inorder = function (callback) {
+ return this._inorder(this._root, callback);
+ };
+
+ /**
+ * Post-order traversal from given node.
+ *
+ * @private
+ * @param {Node} current Node from which to start the traversal.
+ * @param {Function} callback Callback which will
+ * be called for each traversed node
+ */
+ exports.AVLTree.prototype._postorder = function (current, callback) {
+ if (!current) {
+ return;
+ }
+ if (typeof callback === 'function') {
+ callback(current);
+ }
+ this._postorder(current._left, callback);
+ this._postorder(current._right, callback);
+ };
+
+ /**
+ * Post-order traversal of the whole tree.
+ *
+ * @public
+ * @param {Function} callback Callback which
+ * will be called for each traversed node.
+ */
+ exports.AVLTree.prototype.postorder = function (callback) {
+ return this._postorder(this._root, callback);
+ };
+
+ /**
+ * Pre-order traversal of the tree from given node.
+ *
+ * @private
+ * @param {Node} current Node from which to start the traversal.
+ * @param {Function} callback Callback which
+ * will be called for each traversed node.
+ */
+ exports.AVLTree.prototype._preorder = function (current, callback) {
+ if (!current) {
+ return;
+ }
+ if (typeof callback === 'function') {
+ callback(current);
+ }
+ this._preorder(current._left, callback);
+ this._preorder(current._right, callback);
+ };
+
+ /**
+ * Pre-order preorder traversal of the whole tree.
+ *
+ * @public
+ * @param {Function} callback Callback which will
+ * be called for each traversed node.
+ */
+ exports.AVLTree.prototype.preorder = function (callback) {
+ return this._preorder(this._root, callback);
+ };
+
+ /**
+ * Finds a node by it's value.
+ * Average time complexity: O(log N).
+ *
+ * @public
+ * @param {Number|String} value of the node which should be found.
+ */
+ exports.AVLTree.prototype.find = function (value) {
+ return this._find(value, this._root);
+ };
+
+ /**
+ * Finds a node by it's value in a given sub-tree.
+ * Average time complexity: O(log N).
+ *
+ * @private
+ * @param {Number|String} value of the node which should be found.
+ * @param {Node} current node to be checked.
+ */
+ exports.AVLTree.prototype._find = function (value, current) {
+ if (!current) {
+ return null;
+ }
+
+ if (current.value === value) {
+ return current;
+ }
+
+ if (current.value > value) {
+ return this._find(value, current._left);
+ }
+
+ if (current.value < value) {
+ return this._find(value, current._right);
+ }
+ };
+
+ /**
+ * Replaces given child with new one, for given parent.
+ *
+ * @private
+ * @param {Node} parent Parent node.
+ * @param {Node} oldChild Child to be replaced.
+ * @param {Node} newChild Child replacement.
+ */
+ exports.AVLTree.prototype._replaceChild = function (parent, oldChild, newChild) {
+ if (parent === null) {
+ this._root = newChild;
+ if (this._root !== null){
+ this._root._parent = null;
+ }
+ } else {
+ if (parent._left === oldChild) {
+ parent._left = newChild;
+ } else {
+ parent._right = newChild;
+ }
+ if (newChild) {
+ newChild._parent = parent;
+ }
+ }
+ };
+
+ /**
+ * Removes node from the tree.
+ * Average runtime complexity: O(log N).
+ *
+ * @public
+ * @param {Number|String} value of node to be removed
+ * @returns {Boolean} True/false depending
+ * on whether the given node is removed.
+ */
+ exports.AVLTree.prototype.remove = function (value) {
+ var node = this.find(value);
+ if (!node) {
+ return false;
+ }
+ if (node._left && node._right) {
+ var min = this._findMin(node._right);
+ var temp = node.value;
+ node.value = min.value;
+ min.value = temp;
+ return this.remove(temp);
+ } else {
+ if (node._left) {
+ this._replaceChild(node._parent, node, node._left);
+ this._maintainHeightBalanceProperty(node._left, true);
+ } else if (node._right) {
+ this._replaceChild(node._parent, node, node._right);
+ this._maintainHeightBalanceProperty(node._right, true);
+ } else {
+ this._replaceChild(node._parent, node, null);
+ this._maintainHeightBalanceProperty(node._parent, true);
+ }
+ return true;
+ }
+ };
+
+ /**
+ * Finds the node with minimum value in given sub-tree.
+ *
+ * @private
+ * @param {Node} node Root of the sub-tree.
+ * @param {Number|String} current Current minimum value of the sub-tree.
+ * @returns {Node} Node with the minimum value in the sub-tree.
+ */
+ exports.AVLTree.prototype._findMin = function (node, current) {
+ current = current || { value: Infinity };
+ if (!node) {
+ return current;
+ }
+ if (current.value > node.value) {
+ current = node;
+ }
+ return this._findMin(node._left, current);
+ };
+
+ /**
+ * Finds the node with maximum value in given sub-tree.
+ *
+ * @private
+ * @param {Node} node Root of the sub-tree.
+ * @param {Number|String} current Current maximum value of the sub-tree.
+ * @returns {Node} Node with the maximum value in the sub-tree.
+ */
+ exports.AVLTree.prototype._findMax = function (node, current) {
+ current = current || { value: -Infinity };
+ if (!node) {
+ return current;
+ }
+ if (current.value < node.value) {
+ current = node;
+ }
+ return this._findMax(node._right, current);
+ };
+
+ /**
+ * Finds the node with minimum value in the whole tree.
+ *
+ * @public
+ * @returns {Node} The minimum node of the tree.
+ */
+ exports.AVLTree.prototype.findMin = function () {
+ return this._findMin(this._root);
+ };
+
+ /**
+ * Finds the node with maximum value in the whole tree.
+ *
+ * @public
+ * @returns {Node} The maximum node of the tree.
+ *
+ */
+ exports.AVLTree.prototype.findMax = function () {
+ return this._findMax(this._root);
+ };
+
+ exports.AVLTree.prototype._isBalanced = function (current) {
+ if (!current) {
+ return true;
+ }
+ return this._isBalanced(current._left) &&
+ this._isBalanced(current._right) &&
+ Math.abs(this._getHeight(current._left) -
+ this._getHeight(current._right)) <= 1;
+ };
+
+ /**
+ * Returns whether the AVL Tree is balanced.
+ *
+ * @public
+ * @returns {Boolean} Whether the tree is balanced or not.
+ */
+ exports.AVLTree.prototype.isBalanced = function () {
+ return this._isBalanced(this._root);
+ };
+
+ /**
+ * Finds the diameter of the AVL tree.
+ *
+ * @public
+ * @returns {Number} The longest path in the AVL Tree.
+ */
+ exports.AVLTree.prototype.getDiameter = function () {
+ var getDiameter = function (root) {
+ if (!root) {
+ return 0;
+ }
+ var leftHeight = this._getHeight(root._left);
+ var rightHeight = this._getHeight(root._right);
+ var path = leftHeight + rightHeight + 1;
+ return Math.max(path, getDiameter(root._left), getDiameter(root._right));
+ }.bind(this);
+ return getDiameter(this._root);
+ };
+
+ /**
+ * Returns the height of the tree.
+ *
+ * @public
+ * @returns {Number} The height of the tree.
+ */
+ exports.AVLTree.prototype.getTreeHeight = function () {
+ return this._getHeight(this._root);
+ };
+
+ exports.AVLTree.prototype._getHeight = function (node) {
+ if (!node) {
+ return 0;
+ }
+ return 1 + Math.max(this._getHeight(node._left),
+ this._getHeight(node._right));
+ };
+
+ /**
+ * Finds the lowest common ancestor of two nodes.
+ *
+ * @public
+ * @returns {Node} The lowest common ancestor of the two nodes or null.
+ */
+ exports.AVLTree.prototype.lowestCommonAncestor = function (firstNode, secondNode) {
+ return this._lowestCommonAncestor(firstNode, secondNode, this._root);
+ };
+
+ exports.AVLTree.prototype._lowestCommonAncestor = function (firstNode, secondNode, current) {
+ var firstNodeInLeft = this._existsInSubtree(firstNode, current._left);
+ var secondNodeInLeft = this._existsInSubtree(secondNode, current._left);
+ var firstNodeInRight = this._existsInSubtree(firstNode, current._right);
+ var secondNodeInRight = this._existsInSubtree(secondNode, current._right);
+ if ((firstNodeInLeft && secondNodeInRight) ||
+ (firstNodeInRight && secondNodeInLeft)) {
+ return current;
+ }
+ if (secondNodeInLeft && firstNodeInLeft) {
+ return this._lowestCommonAncestor(firstNode, secondNode, current._left);
+ }
+ if (secondNodeInRight && secondNodeInLeft) {
+ return this._lowestCommonAncestor(firstNode, secondNode, current._right);
+ }
+ return null;
+ };
+
+ exports.AVLTree.prototype._existsInSubtree = function (node, root) {
+ if (!root) {
+ return false;
+ }
+ if (node === root.value) {
+ return true;
+ }
+ return this._existsInSubtree(node, root._left) ||
+ this._existsInSubtree(node, root._right);
+ };
+
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/data-structures/binary-search-tree.js b/src/data-structures/binary-search-tree.js
index 3677c604..cf059a27 100644
--- a/src/data-structures/binary-search-tree.js
+++ b/src/data-structures/binary-search-tree.js
@@ -1,275 +1,465 @@
/**
- * Implementation of binary search tree.
- */
-
-/**
- * A node of the tree
+ * Binary search tree.
*
- * @public
- * @constructor
- * @param {number|string} Value of the node
- * @param {Node} Left subling
- * @param {Node} Right sibling
- * @param {Node} Parent of the node
- */
-function Node(value, left, right, parent) {
- this.value = value;
- this._left = left;
- this._right = right;
- this._parent = parent;
-}
-
-/**
- * Defines the binary tree
+ * @example
+ * var BST = require('path-to-algorithms/src/data-structures'+
+ * '/binary-search-tree');
+ * var bst = new BST.BinaryTree();
*
- * @public
- * @constructor
- */
-function BinaryTree() {
- this._root = null;
-}
-
-/**
- * Inserts a node into the binary tree. The method's complexity is O(log n) in the average case and
- * O(n) in the worst case.
+ * bst.insert(2000);
+ * bst.insert(1989);
+ * bst.insert(1991);
+ * bst.insert(2001);
+ * bst.insert(1966);
*
- * @public
- * @param {number|string} Value
- * @param {[Node]} Current node
- */
-BinaryTree.prototype.insert = function (value, current) {
- if (this._root === null) {
- this._root = new Node(value, null, null, null);
- return;
- }
-
- var insertKey;
- current = current || this._root;
- if (current.value > value)
- insertKey = '_left';
- else
- insertKey = '_right';
- if (!current[insertKey])
- current[insertKey] = new Node(value, null, null, current);
- else
- this.insert(value, current[insertKey]);
-};
-
-/**
- * Prints the nodes of the tree in order. It starts the tree traversal from a given node.
+ * var node = bst.find(1989);
+ * console.log(node.value); // 1989
*
- * @private
- * @param {Node} Node from which to start the traversal
- * @param {Function} Callback which will be called for each traversed node
- */
-BinaryTree.prototype._inorder = function (current, callback) {
- if (!current)
- return;
- this._inorder(current._left, callback);
- if (typeof callback === 'function')
- callback(current);
- this._inorder(current._right, callback);
-};
-
-/**
- * Inorder traversal of the whole binary search tree
+ * var minNode = bst.findMin();
+ * console.log(minNode.value); // 1966
*
- * @public
- * @param {Function} Callback which will be called for each traversed node
- */
-BinaryTree.prototype.inorder = function (callback) {
- return this._inorder(this._root, callback);
-};
-
-/**
- * Post-order traversal from given node
+ * var maxNode = bst.findMax();
+ * console.log(maxNode.value); //2001
*
- * @private
- * @param {Node} Node from which to start the traversal
- * @param {Function} Callback which will be called for each traversed node
+ * @module data-structures/binary-search-tree
*/
-BinaryTree.prototype._postorder = function (current, callback) {
- if (!current)
- return;
- if (typeof callback === 'function')
- callback(current);
- this._postorder(current._left, callback);
- this._postorder(current._right, callback);
-};
+(function (exports) {
+ 'use strict';
-/**
- * Post-order traversal of the whole tree
- *
- * @public
- * @param {Function} Callback which will be called for each traversed node
- */
-BinaryTree.prototype.postorder = function (callback) {
- return this._postorder(this._root, callback);
-};
+ /**
+ * Node of the tree.
+ *
+ * @public
+ * @constructor
+ * @param {Number|String} value Value of the node.
+ * @param {Node} left Left sibling.
+ * @param {Node} right Right sibling.
+ * @param {Node} parent Parent of the node.
+ */
+ exports.Node = function (value, left, right, parent) {
+ /**
+ * @member {Number|String}
+ */
+ this.value = value;
+ this._left = left;
+ this._right = right;
+ this._parent = parent;
+ };
-/**
- * Pre-order traversal of the tree from given node
- *
- * @private
- * @param {Node} Node from which to start the traversal
- * @param {Function} Callback which will be called for each traversed node
- */
-BinaryTree.prototype._preorder = function (current, callback) {
- if (!current)
- return;
- if (typeof callback === 'function')
- callback(current);
- this._preorder(current._left, callback);
- this._preorder(current._right, callback);
-};
+ /**
+ * Binary tree.
+ *
+ * @public
+ * @constructor
+ */
+ exports.BinaryTree = function () {
+ this._root = null;
+ };
-/**
- * Pre-order preorder traversal of the whole tree
- *
- * @public
- * @param {Function} Callback which will be called for each traversed node
- */
-BinaryTree.prototype.preorder = function (callback) {
- return this._preorder(this._root, callback);
-};
+ /**
+ * Inserts a node into the binary search tree.
+ * Time complexity: O(log N) in the average case
+ * and O(N) in the worst case.
+ *
+ * @public
+ * @method
+ * @param {Number|String} value Node value.
+ * @param {Node} current Current node.
+ */
+ exports.BinaryTree.prototype.insert = function (value, current) {
+ if (this._root === null) {
+ this._root = new exports.Node(value, null, null, null);
+ return;
+ }
+ var insertKey;
+ current = current || this._root;
+ if (current.value > value) {
+ insertKey = '_left';
+ } else {
+ insertKey = '_right';
+ }
+ if (!current[insertKey]) {
+ current[insertKey] = new exports.Node(value, null, null, current);
+ } else {
+ this.insert(value, current[insertKey]);
+ }
+ };
-/**
- * Finds a node by it's value. Average runtime complexity O(log n)
- *
- * @public
- * @param {number|string} Value of the node which should be found
- */
-BinaryTree.prototype.find = function (value) {
- return this._find(value, this._root);
-};
+ /**
+ * In-order traversal from the given node.
+ *
+ * @private
+ * @param {Node} current Node from which to start the traversal.
+ * @param {Function} callback Callback which
+ * will be called for each traversed node.
+ */
+ exports.BinaryTree.prototype._inorder = function (current, callback) {
+ if (!current) {
+ return;
+ }
+ this._inorder(current._left, callback);
+ if (typeof callback === 'function') {
+ callback(current);
+ }
+ this._inorder(current._right, callback);
+ };
-/**
- * Finds a node by it's value in given sub-tree. Average runtime complexity: O(log n).
- *
- * @private
- * @param {number|string} Value of the node which should be found
- * @param {Node} Current node to be checked
- */
-BinaryTree.prototype._find = function (value, current) {
- if (!current)
- return null;
-
- if (current.value === value)
- return current;
-
- if (current.value > value)
- return this._find(value, current._left);
-
- if (current.value < value)
- return this._find(value, current._right);
-
-};
+ /**
+ * In-order traversal of the whole binary search tree.
+ *
+ * @public
+ * @method
+ * @param {Function} callback Callback which will be
+ * called for each traversed node.
+ */
+ exports.BinaryTree.prototype.inorder = function (callback) {
+ return this._inorder(this._root, callback);
+ };
-/**
- * Replaces given child with new one, for given parent
- *
- * @private
- * @param {Node} Parent node
- * @param {Node} Child to be replaced
- * @param {Node} Child replacement
- */
-BinaryTree.prototype._replaceChild = function (parent, oldChild, newChild) {
- if (!parent) {
- this._root = newChild;
- this._root._parent = null;
- } else {
+ /**
+ * Post-order traversal from given node.
+ *
+ * @private
+ * @param {Node} current Node from which to start the traversal.
+ * @param {Function} callback Callback which will
+ * be called for each traversed node
+ */
+ exports.BinaryTree.prototype._postorder = function (current, callback) {
+ if (!current) {
+ return;
+ }
+ this._postorder(current._left, callback);
+ this._postorder(current._right, callback);
+ if (typeof callback === 'function') {
+ callback(current);
+ }
+ };
- if (parent._left === oldChild)
- parent._left = newChild;
- else
- parent._right = newChild;
+ /**
+ * Post-order traversal of the whole tree.
+ *
+ * @public
+ * @param {Function} callback Callback which
+ * will be called for each traversed node.
+ */
+ exports.BinaryTree.prototype.postorder = function (callback) {
+ return this._postorder(this._root, callback);
+ };
- if (newChild) {
- newChild._parent = parent;
+ /**
+ * Pre-order traversal of the tree from given node.
+ *
+ * @private
+ * @param {Node} current Node from which to start the traversal.
+ * @param {Function} callback Callback which
+ * will be called for each traversed node.
+ */
+ exports.BinaryTree.prototype._preorder = function (current, callback) {
+ if (!current) {
+ return;
+ }
+ if (typeof callback === 'function') {
+ callback(current);
}
- }
-};
+ this._preorder(current._left, callback);
+ this._preorder(current._right, callback);
+ };
-/**
- * Removes node from the tree. Average runtime complexity: O(log n).
- *
- * @public
- * @param {Node} Node to be removed
- * @returns {boolean} True/false depending on whether the given node is removed
- */
-BinaryTree.prototype.remove = function (node) {
- if (!node)
- return false;
+ /**
+ * Pre-order preorder traversal of the whole tree.
+ *
+ * @public
+ * @param {Function} callback Callback which will
+ * be called for each traversed node.
+ */
+ exports.BinaryTree.prototype.preorder = function (callback) {
+ return this._preorder(this._root, callback);
+ };
- if (node._left && node._right) {
- var min = this._findMin(node._right),
- temp = node.value;
+ /**
+ * Finds a node by it's value.
+ * Average time complexity: O(log N).
+ *
+ * @public
+ * @param {Number|String} value of the node which should be found.
+ */
+ exports.BinaryTree.prototype.find = function (value) {
+ return this._find(value, this._root);
+ };
- node.value = min.value;
- min.value = temp;
- return this.remove(min);
- } else {
- if (node._left)
- this._replaceChild(node._parent, node, node._left);
- else if (node._right)
- this._replaceChild(node._parent, node, node._right);
- else
- this._replaceChild(node._parent, node, null);
- return true;
- }
-};
+ /**
+ * Finds a node by it's value in a given sub-tree.
+ * Average time complexity: O(log N).
+ *
+ * @private
+ * @param {Number|String} value of the node which should be found.
+ * @param {Node} current node to be checked.
+ */
+ exports.BinaryTree.prototype._find = function (value, current) {
+ if (!current) {
+ return null;
+ }
-/**
- * Finds the node with minimum value in given sub-tree
- *
- * @private
- * @param {Node} Root of the sub-tree
- * @param {[number|string]} Current minimum value of the sub-tree
- * @returns {Node} The node with minimum value in the sub-tree
- */
-BinaryTree.prototype._findMin = function (node, current) {
- current = current || { value: Infinity };
- if (!node)
- return current;
- if (current.value > node.value)
- current = node;
- return this._findMin(node._left, current);
-};
+ if (current.value === value) {
+ return current;
+ }
-/**
- * Finds the node with maximum value in given sub-tree
- *
- * @private
- * @param {Node} Root of the sub-tree
- * @param {[number|string]} Current maximum value of the sub-tree
- * @returns {Node} The node with maximum value in the sub-tree
- */
-BinaryTree.prototype._findMax = function (node, current) {
- current = current || { value: -Infinity };
- if (!node)
- return current;
- if (current.value < node.value)
- current = node;
- return this._findMax(node._right, current);
-};
+ if (current.value > value) {
+ return this._find(value, current._left);
+ }
-/**
- * Finds the node with minimum value in the whole tree
- *
- * @public
- * @returns {Node} The minimum node of the tree
- */
-BinaryTree.prototype.findMin = function () {
- return this._findMin(this._root);
-};
+ if (current.value < value) {
+ return this._find(value, current._right);
+ }
+ };
-/**
- * Finds the maximum node of the tree
- *
- * @public
- * @returns {Node} The maximum node of the tree
- *
- */
-BinaryTree.prototype.findMax = function () {
- return this._findMax(this._root);
-};
+ /**
+ * Replaces given child with new one, for given parent.
+ *
+ * @private
+ * @param {Node} parent Parent node.
+ * @param {Node} oldChild Child to be replaced.
+ * @param {Node} newChild Child replacement.
+ */
+ exports.BinaryTree.prototype._replaceChild = function (parent, oldChild, newChild) {
+ if (!parent) {
+ this._root = newChild;
+ if (this._root !== null){
+ this._root._parent = null;
+ }
+ } else {
+ if (parent._left === oldChild) {
+ parent._left = newChild;
+ } else {
+ parent._right = newChild;
+ }
+ if (newChild) {
+ newChild._parent = parent;
+ }
+ }
+ };
+
+ /**
+ * Removes node from the tree.
+ * Average runtime complexity: O(log N).
+ *
+ * @public
+ * @param {Node} node to be removed
+ * @returns {Boolean} True/false depending
+ * on whether the given node is removed.
+ */
+ exports.BinaryTree.prototype.remove = function (node) {
+ if (!node) {
+ return false;
+ }
+ if (node._left && node._right) {
+ var min = this._findMin(node._right);
+ var temp = node.value;
+ node.value = min.value;
+ min.value = temp;
+ return this.remove(min);
+ } else {
+ if (node._left) {
+ this._replaceChild(node._parent, node, node._left);
+ } else if (node._right) {
+ this._replaceChild(node._parent, node, node._right);
+ } else {
+ this._replaceChild(node._parent, node, null);
+ }
+ return true;
+ }
+ };
+
+ /**
+ * Finds the node with minimum value in given sub-tree.
+ *
+ * @private
+ * @param {Node} node Root of the sub-tree.
+ * @param {Number|String} current Current minimum value of the sub-tree.
+ * @returns {Node} Node with the minimum value in the sub-tree.
+ */
+ exports.BinaryTree.prototype._findMin = function (node, current) {
+ current = current || { value: Infinity };
+ if (!node) {
+ return current;
+ }
+ if (current.value > node.value) {
+ current = node;
+ }
+ return this._findMin(node._left, current);
+ };
+
+ /**
+ * Finds the node with maximum value in given sub-tree.
+ *
+ * @private
+ * @param {Node} node Root of the sub-tree.
+ * @param {Number|String} current Current maximum value of the sub-tree.
+ * @returns {Node} Node with the maximum value in the sub-tree.
+ */
+ exports.BinaryTree.prototype._findMax = function (node, current) {
+ current = current || { value: -Infinity };
+ if (!node) {
+ return current;
+ }
+ if (current.value < node.value) {
+ current = node;
+ }
+ return this._findMax(node._right, current);
+ };
+
+ /**
+ * Finds the node with minimum value in the whole tree.
+ *
+ * @public
+ * @returns {Node} The minimum node of the tree.
+ */
+ exports.BinaryTree.prototype.findMin = function () {
+ return this._findMin(this._root);
+ };
+
+ /**
+ * Finds the node with maximum value in the whole tree.
+ *
+ * @public
+ * @returns {Node} The maximum node of the tree.
+ *
+ */
+ exports.BinaryTree.prototype.findMax = function () {
+ return this._findMax(this._root);
+ };
+
+ /**
+ * Checks if a given node is balanced.
+ *
+ * @private
+ * @param {Node} current Node to have balance checked.
+ * @returns {Boolean} Boolean of whether or not provided node is balanced.
+ */
+ exports.BinaryTree.prototype._isBalanced = function (current) {
+ if (!current) {
+ return true;
+ }
+ return this._isBalanced(current._left) &&
+ this._isBalanced(current._right) &&
+ Math.abs(this._getHeight(current._left) -
+ this._getHeight(current._right)) <= 1;
+ };
+
+ /**
+ * Returns whether the BST is balanced.
+ *
+ * @public
+ * @returns {Boolean} Whether the tree is balanced or not.
+ */
+ exports.BinaryTree.prototype.isBalanced = function () {
+ return this._isBalanced(this._root);
+ };
+
+ /**
+ * Finds the diameter of the binary tree.
+ *
+ * @public
+ * @returns {Number} The longest path in the BST.
+ */
+ exports.BinaryTree.prototype.getDiameter = function () {
+ var getDiameter = function (root) {
+ if (!root) {
+ return 0;
+ }
+ var leftHeight = this._getHeight(root._left);
+ var rightHeight = this._getHeight(root._right);
+ var path = leftHeight + rightHeight + 1;
+ return Math.max(path, getDiameter(root._left), getDiameter(root._right));
+ }.bind(this);
+ return getDiameter(this._root);
+ };
+
+ /**
+ * Returns the height of the tree.
+ *
+ * @public
+ * @returns {Number} The height of the tree.
+ */
+ exports.BinaryTree.prototype.getHeight = function () {
+ return this._getHeight(this._root);
+ };
+
+ /**
+ * Recursive worker function for getHeight()
+ *
+ * @private
+ * @param {Node} node Node at current recursive frame.
+ * @returns {Number} Height of the Node in the parameter.
+ */
+ exports.BinaryTree.prototype._getHeight = function (node) {
+ if (!node) {
+ return 0;
+ }
+ return 1 + Math.max(this._getHeight(node._left),
+ this._getHeight(node._right));
+ };
+
+ /**
+ * Finds the lowest common ancestor of two nodes.
+ *
+ * @public
+ * @param {Node} firstNode First node to be considered when checking
+ * for ancestor.
+ * @param {Node} secondNode Second node to be considered when checking
+ * for ancestor.
+ * @returns {Node} The lowest common ancestor of the two nodes or null.
+ */
+ exports.BinaryTree.prototype.lowestCommonAncestor = function (firstNode, secondNode) {
+ return this._lowestCommonAncestor(firstNode, secondNode, this._root);
+ };
+
+ /**
+ * Obtains the lowest common ancestor for the given nodes.
+ *
+ * @private
+ * @param {Node} firstNode First node to be considered when checking
+ * for ancestor.
+ * @param {Node} secondNode Second node to be considered when checking
+ * for ancestor.
+ * @param {Node} current Current node.
+ * @returns {Node} The lowest common ancestor of the two nodes or null.
+ */
+ exports.BinaryTree.prototype._lowestCommonAncestor = function (firstNode, secondNode, current) {
+ var firstNodeInLeft = this._existsInSubtree(firstNode, current._left);
+ var secondNodeInLeft = this._existsInSubtree(secondNode, current._left);
+ var firstNodeInRight = this._existsInSubtree(firstNode, current._right);
+ var secondNodeInRight = this._existsInSubtree(secondNode, current._right);
+ if ((firstNodeInLeft && secondNodeInRight) ||
+ (firstNodeInRight && secondNodeInLeft)) {
+ return current;
+ }
+ if (secondNodeInLeft && firstNodeInLeft) {
+ return this._lowestCommonAncestor(firstNode, secondNode, current._left);
+ }
+ if (secondNodeInRight && secondNodeInLeft) {
+ return this._lowestCommonAncestor(firstNode, secondNode, current._right);
+ }
+ return null;
+ };
+
+ /**
+ * Checks if a given node exists in a subtree.
+ *
+ * @private
+ * @param {Node} node Node to check for.
+ * @param {Node} root Root node of a given subtree.
+ * @returns {Node} The lowest common ancestor of the two nodes or null.
+ */
+ exports.BinaryTree.prototype._existsInSubtree = function (node, root) {
+ if (!root) {
+ return false;
+ }
+ if (node.value === root.value) {
+ return true;
+ }
+ return this._existsInSubtree(node, root._left) ||
+ this._existsInSubtree(node, root._right);
+ };
+
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/data-structures/bloomfilter.js b/src/data-structures/bloomfilter.js
new file mode 100644
index 00000000..f3432a0d
--- /dev/null
+++ b/src/data-structures/bloomfilter.js
@@ -0,0 +1,221 @@
+/**
+ * Bloomfilter and a bitmap.
+ * Probablistic data structure useful for deduplication
+ *
+ * @example
+ * // create a bloom filter with capacity of 1024 and 0.01 error rat
+ * var bloomfilter = new Bloomfilter(1024, 0.01);
+ * bloomfilter.set('hello');
+ * bloomfilter.get('hello') === true;
+ * bloomfilter.get('world') === false;
+ * @module data-structures/bloomfilter
+ */
+(function(exports) {
+ 'use strict';
+
+ function randomUint32() {
+ return Math.floor(Math.random() * Math.pow(2, 32));
+ }
+ /**
+ * Calculate a 32 bit FNV-1a hash
+ * Found here: https://gist.github.com/vaiorabbit/5657561
+ * Ref.: http://isthe.com/chongo/tech/comp/fnv/
+ *
+ * @param {string} str the input value
+ * @param {boolean} [asString=false] set to true to return the hash value as
+ * 8-digit hex string instead of an integer
+ * @param {integer} [seed] optionally pass the hash of the previous chunk
+ * @returns {integer | string}
+ */
+ function hashFnv32a(str, asString, seed) {
+ /*jshint bitwise:false */
+ var i;
+ var l;
+ var hval = seed === undefined ? 0x811c9dc5 : seed;
+
+ for (i = 0, l = str.length; i < l; i = i + 1) {
+ hval ^= str.charCodeAt(i);
+ hval +=
+ (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
+ }
+ if (asString) {
+ // Convert to 8 digit hex string
+ return ('0000000' + (hval >>> 0).toString(16)).substr(-8);
+ }
+ return hval >>> 0;
+ }
+
+ // Make a hash function
+ function mkHashFun(seed, limit) {
+ return function(value) {
+ return hashFnv32a(value, false, seed) % limit;
+ };
+ }
+ /**
+ * Create a bitmap with a given size
+ * Bit map is not resizeable
+ * @public
+ * @constructor
+ * @param {Number} size the size of the bitmap
+ */
+ exports.Bitmap = function(size) {
+ size = size || 1024;
+ if (size < 0) {
+ throw new Error('The size cannot be negative');
+ }
+ this.size = size;
+ this.intSize = Math.ceil(size / 32); // number of underlying integers
+ // Create a 0 initialized array
+ this.intArray = Array.from({ length: this.intSize }, function() {
+ return 0;
+ });
+ };
+
+ /**
+ * Get the size of the bit map
+ * @public
+ * @return {Number} size of the bit map
+ */
+ exports.Bitmap.prototype.getSize = function() {
+ return this.size;
+ };
+
+ /**
+ * Get if a bit is set at a particular index
+ * @public
+ * @return {Boolean} true or false value of the bit
+ */
+ exports.Bitmap.prototype.exists = function(index) {
+ // Necessary boundary check
+ if (index < 0 || index > this.size) {
+ throw new Error('Index out of bound')
+ }
+
+ // Calculate the offset within the int
+ var intOffset = index % 32;
+ var arrayOffset = Math.floor(index / 32); // the offset for the array
+ var mask = 1 << intOffset;
+ return (mask & this.intArray[arrayOffset]) !== 0;
+ };
+
+ /**
+ * Get the bit at a particular index
+ * @public
+ * @return {Number} true or false value of the bit
+ */
+ exports.Bitmap.prototype.get = function(index) {
+ // Necessary boundary check
+ if (index < 0 || index > this.size) {
+ throw new Error('Index out of bound')
+ }
+
+ // Calculate the offset within the int
+ var intOffset = index % 32;
+ var arrayOffset = Math.floor(index / 32); // the offset for the array
+ var mask = 1 << intOffset;
+ if ((mask & this.intArray[arrayOffset]) !== 0) {
+ return 1;
+ } else {
+ return 0;
+ }
+ };
+
+ /**
+ * Set the bit at a particular index
+ * @public
+ * @param {Number} index the index to set
+ * @param {Boolean} value the value that is necessary
+ */
+ exports.Bitmap.prototype.set = function(index, value) {
+ // necessary boundary check
+ if (index < 0 || index > this.size) {
+ throw new Error('Index out of bound')
+ }
+
+ var intOffset = index % 32; //calculate the offset within the int
+ var arrayOffset = Math.floor(index / 32); // the offset for the array
+ var mask = 1 << intOffset;
+
+ // Check trutyness
+ if (value) {
+ this.intArray[arrayOffset] |= mask; // or operation
+ } else {
+ this.intArray[arrayOffset] &= ~mask; // and opertation to set 0
+ }
+ };
+
+ /**
+ * Construct a bloom filter by given the capacity and the error rate, default error rate is 0.001
+ * @public
+ * @constructor
+ * @param {Number} capacity the maximum capacity to maintain the given error rate
+ * @param {Number} errorRate the error rate expected under maximum capacity
+ */
+ exports.Bloomfilter = function(capacity, errorRate) {
+ errorRate = errorRate || 0.001; // default error rate
+ if (errorRate > 1 || errorRate < 0) {
+ throw new Error('The error rate range is outside of bound');
+ }
+ if (capacity < 0) {
+ throw new Error('The capacity cannot be negative');
+ }
+ this.capacity = capacity;
+ this.errorRate = errorRate;
+
+ // Calculate the optimal size of the bitmap
+ var numBit = Math.ceil(
+ (capacity * Math.log(1.0 / errorRate)) / Math.pow(Math.log(2), 2)
+ );
+
+ // Calculate the optimal number of hash functions
+ this.numHashFunction = Math.ceil(Math.log(2), numBit / capacity);
+
+ // Create a bitmap
+ this.bitmap = new exports.Bitmap(numBit);
+
+ // Generate an array of hash functions
+ this.hashFunctions = Array.from(
+ { length: this.numHashFunction },
+ function() {
+ return mkHashFun(randomUint32(), numBit);
+ }.bind(this)
+ );
+ };
+
+ /**
+ * To check if an item is in the filter. If it is in, it will return true,
+ * if it is not in the filter, highly likely it will return false, but guaranteed
+ * @param {Number | String} value the value that we are trying to check in the filter
+ */
+ exports.Bloomfilter.prototype.get = function(value) {
+ value = String(value); // make it string
+ var hashes = this.hashFunctions.map(function(hashFct) {
+ return hashFct(value);
+ });
+
+ // if one of the bits is not set
+ for (var i = 0; i < hashes.length; i = i + 1) {
+ if (this.bitmap.exists(hashes[i]) === false) {
+ return false;
+ }
+ }
+ return true;
+ };
+
+ /**
+ * To set(put) an item in the bloom filter
+ * @public
+ * @param {Number | String} value the value that is been set in the filter
+ */
+ exports.Bloomfilter.prototype.set = function(value) {
+ value = String(value); // make it string
+ var hashes = this.hashFunctions.map(function(hashFct) {
+ return hashFct(value);
+ });
+
+ // Set all the corresponding bits
+ for (var i = 0; i < hashes.length; i = i + 1) {
+ this.bitmap.set(hashes[i], true);
+ }
+ };
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/data-structures/edge.js b/src/data-structures/edge.js
new file mode 100644
index 00000000..e16e343a
--- /dev/null
+++ b/src/data-structures/edge.js
@@ -0,0 +1,20 @@
+(function (exports) {
+ 'use strict';
+
+ /**
+ * Graph edge.
+ *
+ * @constructor
+ * @public
+ * @param {Vertex} e Vertex which this edge connects.
+ * @param {Vertex} v Vertex which this edge connects.
+ * @param {Number} distance Weight of the edge.
+ * @module data-structures/edge
+ */
+ exports.Edge = function (e, v, distance) {
+ this.from = e;
+ this.to = v;
+ this.distance = distance;
+ };
+
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/data-structures/hash-table.js b/src/data-structures/hash-table.js
new file mode 100644
index 00000000..1635e484
--- /dev/null
+++ b/src/data-structures/hash-table.js
@@ -0,0 +1,255 @@
+/**
+ * Hash Table
+ *
+ * An associative array, that can map keys
+ * (strings and numbers) to values in O(1).
+ *
+ * @example
+ * var hash = require('path-to-algorithms/src/data-structures'+
+ * '/hash-table');
+ * var hashTable = new hash.Hashtable();
+ *
+ * hashTable.put(10, 'value');
+ * hashTable.put('key', 10);
+ *
+ * console.log(hashTable.get(10)); // 'value'
+ * console.log(hashTable.get('key')); // 10
+ *
+ * hashTable.remove(10);
+ * hashTable.remove('key');
+ *
+ * console.log(hashTable.get(10)); // undefined
+ * console.log(hashTable.get('key')); // undefined
+ *
+ * @module data-structures/hash-table
+*/
+(function (exports) {
+ 'use strict';
+
+ /**
+ * Constructs a Node to store data and next/prev nodes in Hash table.
+ *
+ * @public
+ * @constructor
+ * @param {Number|String} key Key of the node.
+ * @param {Number|String} data Data to be stored in hash table.
+ */
+ exports.Node = function (key, data) {
+ this.key = key;
+ this.data = data;
+ this.next = undefined;
+ this.prev = undefined;
+ };
+
+ /**
+ * Construct a Hash table..
+ *
+ * @public
+ * @constructor
+ */
+ exports.Hashtable = function () {
+ this.buckets = [];
+ // The higher the bucket count; less likely for collisions.
+ this.maxBucketCount = 100;
+ };
+
+ /**
+ * Simple non-crypto hash used to hash keys, which determines
+ * which bucket the value will be placed in.
+ * A javascript implementation of Java's 32bitint hash.
+ *
+ * @public
+ * @method
+ * @param {Number|String} val Key to be hashed.
+ */
+ exports.Hashtable.prototype.hashCode = function (val) {
+ var i;
+ var hashCode = 0;
+ var character;
+
+ // If value to be hashed is already an integer, return it.
+ if (val.length === 0 || val.length === undefined) {
+ return val;
+ }
+
+ for (i = 0; i < val.length; i += 1) {
+ character = val.charCodeAt(i);
+ /*jshint -W016 */
+ hashCode = ((hashCode << 5) - hashCode) + character;
+ hashCode = hashCode & hashCode;
+ /*jshint -W016 */
+ }
+
+ return hashCode;
+ };
+
+ /**
+ * Puts data into the table based on hashed key value.
+ *
+ * @public
+ * @method
+ * @param {Number|String} key Key for data.
+ * @param {Number|String} data Data to be stored in table.
+ */
+ exports.Hashtable.prototype.put = function (key, data, hashCode) {
+ /*
+ Make collision testing easy with optional hashCode parameter.
+ That should not be used! Only by spec/tests.
+ */
+ if (hashCode === undefined) {
+ // Typical use
+ hashCode = this.hashCode(key);
+ } else if (hashCode.length > 0) {
+ // Testing/Spec - String hash passed, convert to int based hash.
+ hashCode = this.hashCode(hashCode);
+ }
+ // Adjust hash to fit within buckets.
+ hashCode = hashCode % this.maxBucketCount;
+
+ var newNode = new exports.Node(key, data);
+
+ // No element exists at hash/index for given key -> put in table.
+ if (this.buckets[hashCode] === undefined) {
+ this.buckets[hashCode] = newNode;
+ return;
+ }
+
+ // Element exists at hash/index for given key, but, same key -> overwrite.
+ if (this.buckets[hashCode].key === key) {
+ this.buckets[hashCode].data = data;
+ return;
+ }
+
+ /*
+ Item exists at hash/index for key, but different key.
+ Handle collision.
+ */
+ var first = this.buckets[hashCode];
+ while (first.next !== undefined) {
+ first = first.next;
+ }
+ first.next = newNode;
+ newNode.prev = first;
+ };
+
+ /**
+ * Get's data from the table based on key.
+ *
+ * @public
+ * @method
+ * @param {Number|String} key Key for data to be retrieved.
+ */
+ exports.Hashtable.prototype.get = function (key, hashCode) {
+ /*
+ Make collision testing easy with optional hashCode parameter.
+ That should not be used! Only by spec/tests.
+ */
+ if (hashCode === undefined) {
+ // Typical use
+ hashCode = this.hashCode(key);
+ } else if (hashCode.length > 0) {
+ // Testing/Spec - String hash passed, convert to int based hash.
+ hashCode = this.hashCode(hashCode);
+ }
+ hashCode = hashCode % this.maxBucketCount;
+
+ if (this.buckets[hashCode] === undefined) {
+ return undefined;
+ } else if (
+ this.buckets[hashCode].next === undefined &&
+ this.buckets[hashCode].key === key
+ ) {
+ return this.buckets[hashCode].data;
+ } else {
+ var first = this.buckets[hashCode];
+ while (
+ first !== undefined &&
+ first.next !== undefined &&
+ first.key !== key
+ ) {
+ first = first.next;
+ }
+
+ if (first.key === key) {
+ return first.data;
+ } else {
+ return undefined;
+ }
+ }
+ };
+
+ /**
+ * Removes data from the table based on key.
+ *
+ * @public
+ * @method
+ * @param {Number|String} key Key of the data to be removed.
+ */
+ exports.Hashtable.prototype.remove = function (key, hashCode) {
+ /*
+ Make collision testing easy with optional hashCode parameter.
+ That should not be used! Only by spec/tests.
+ */
+ if (hashCode === undefined) {
+ // Typical use
+ hashCode = this.hashCode(key);
+ } else if (hashCode.length > 0) {
+ // Testing/Spec - String hash passed, convert to int based hash.
+ hashCode = this.hashCode(hashCode);
+ }
+ hashCode = hashCode % this.maxBucketCount;
+
+ if (this.buckets[hashCode] === undefined) {
+ return undefined;
+ } else if (this.buckets[hashCode].next === undefined) {
+ this.buckets[hashCode] = undefined;
+ } else {
+ var first = this.buckets[hashCode];
+
+ while (
+ first !== undefined &&
+ first.next !== undefined &&
+ first.key !== key
+ ) {
+ first = first.next;
+ }
+
+ var removedValue = first.data;
+
+ // Removing (B)
+ // (B) : only item in bucket
+ if (first.prev === undefined && first.next === undefined) {
+ first = undefined;
+ return removedValue;
+ }
+
+ // (B) - A - C: start link in bucket
+ if (first.prev === undefined && first.next !== undefined) {
+ first.data = first.next.data;
+ first.key = first.next.key;
+ if (first.next.next !== undefined) {
+ first.next = first.next.next;
+ } else {
+ first.next = undefined;
+ }
+ return removedValue;
+ }
+
+ // A - (B) : end link in bucket
+ if (first.prev !== undefined && first.next === undefined) {
+ first.prev.next = undefined;
+ first = undefined;
+ return removedValue;
+ }
+
+ // A - (B) - C : middle link in bucket
+ if (first.prev !== undefined && first.next !== undefined) {
+ first.prev.next = first.next;
+ first.next.prev = first.prev;
+ first = undefined;
+ return removedValue;
+ }
+
+ }
+ };
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/data-structures/heap.js b/src/data-structures/heap.js
index 231794e5..cb936575 100644
--- a/src/data-structures/heap.js
+++ b/src/data-structures/heap.js
@@ -1,12 +1,55 @@
+/**
+ * A binary heap is a complete binary tree which
+ * satisfies the heap ordering property.
+ *
+ * @example
+ * var Heap = require('path-to-algorithms/src/data-structures/heap').Heap;
+ *
+ * var heap = new Heap(function(a, b) {
+ * return a.birthyear - b.birthyear;
+ * });
+ *
+ * heap.add({
+ * name: 'John',
+ * birthyear: 1981
+ * });
+ * heap.add({
+ * name: 'Pavlo',
+ * birthyear: 2000
+ * });
+ * heap.add({
+ * name: 'Garry',
+ * birthyear: 1989
+ * });
+ * heap.add({
+ * name: 'Derek',
+ * birthyear: 1990
+ * });
+ * heap.add({
+ * name: 'Ivan',
+ * birthyear: 1966
+ * });
+ *
+ * console.log(heap.extract()); // { name: 'Pavlo', birthyear: 2000 }
+ * console.log(heap.extract()); // { name: 'Derek', birthyear: 1990 }
+ * console.log(heap.extract()); // { name: 'Garry', birthyear: 1989 }
+ * console.log(heap.extract()); // { name: 'John', birthyear: 1981 }
+ * console.log(heap.extract()); // { name: 'Ivan', birthyear: 1966 }
+ *
+ * @module data-structures/heap
+ */
(function (exports) {
+ 'use strict';
+
/**
- * Constructor function of minimum heap
+ * Minimum heap constructor.
*
* @public
- * @param {function} Function used for comparition between the elements
+ * @constructor
+ * @param {Function} cmp Function used for comparison between the elements.
*/
- function Heap(cmp) {
+ exports.Heap = function (cmp) {
this._heap = [];
if (typeof cmp === 'function') {
this._cmp = cmp;
@@ -15,27 +58,34 @@
return a - b;
};
}
- }
+ };
/**
* Exchange indexes with start index given as argument
* to turn the tree into a valid heap. On a single call
- * this method maintains only a single "branch" of the heap. Complexity O(log n)
+ * this method maintains only a single "branch" of the heap.
+ *
+ * Time complexity: O(log N).
*
* @private
- * @param {number} index The parent
+ * @param {Number} index The parent.
*/
- Heap.prototype._heapify = function (index) {
- var extr = index,
- left = 2 * index + 1,
- right = 2 * index + 2,
- temp;
+ exports.Heap.prototype._heapify = function (index) {
+ var extr = index;
+ var left = 2 * index + 1;
+ var right = 2 * index + 2;
+ var temp;
- if (left < this._heap.length && this._cmp(this._heap[left], this._heap[index]) > 0)
+ if (left < this._heap.length &&
+ this._cmp(this._heap[left], this._heap[index]) > 0) {
extr = left;
+ }
- if (right < this._heap.length && this._cmp(this._heap[right], this._heap[index]) > 0)
+ if (right < this._heap.length &&
+ this._cmp(this._heap[right], this._heap[index]) > 0 &&
+ this._cmp(this._heap[right], this._heap[left]) > 0) {
extr = right;
+ }
if (index !== extr) {
temp = this._heap[index];
@@ -46,17 +96,19 @@
};
/**
- * Changes the key for give index. Complexity O(log n).
+ * Changes the key.
+ * Complexity: O(log N).
*
* @public
- * @param {number} index Index which key should be changed
- * @param {number} value New value of the key
- * @returns {number} parent The new position of the element
+ * @param {Number} index Index of the value which should be changed.
+ * @param {Number|Object} value New value according to the index.
+ * @return {Number} New position of the element.
*/
- Heap.prototype.changeKey = function (index, value) {
- var elem = this._heap[index],
- parent = Math.floor(index / 2),
- temp;
+ exports.Heap.prototype.changeKey = function (index, value) {
+ this._heap[index] = value;
+ var elem = this._heap[index];
+ var parent = Math.floor(index / 2);
+ var temp;
if (elem !== undefined) {
while (parent >= 0 && this._cmp(elem, this._heap[parent]) > 0) {
temp = this._heap[parent];
@@ -65,52 +117,79 @@
index = parent;
parent = Math.floor(parent / 2);
}
+ this._heapify(index);
}
return parent;
};
/**
- * Adds new element to the heap. Complexity O(log n).
+ * Updates a given node. This operation is useful
+ * in algorithms like Dijkstra, A* where we need
+ * to decrease/increase value of the given node.
*
* @public
- * @param {number} value The new value which will be inserted
- * @returns {number} The index of the inserted value
+ * @param {Number|Object} node Node which should be updated.
*/
- Heap.prototype.add = function (value) {
+ exports.Heap.prototype.update = function (node) {
+ var idx = this._heap.indexOf(node);
+ if (idx >= 0) {
+ this.changeKey(idx, node);
+ }
+ };
+
+ /**
+ * Adds new element to the heap.
+ * Complexity: O(log N).
+ *
+ * @public
+ * @param {Number|Object} value Value which will be inserted.
+ * @return {Number} Index of the inserted value.
+ */
+ exports.Heap.prototype.add = function (value) {
this._heap.push(value);
return this.changeKey(this._heap.length - 1, value);
};
/**
- * Gets the current value which is on the top of the heap. Complexity O(1).
+ * Returns current value which is on the top of the heap.
+ * Complexity: O(1).
*
* @public
- * returns {numner} The current top value.
+ * @return {Number|Object} Current top value.
*/
- Heap.prototype.top = function () {
+ exports.Heap.prototype.top = function () {
return this._heap[0];
};
/**
- * Removes and returns the current extremum value which is on the top of the heap.
- * Complexity O(log n).
+ * Removes and returns the current extremum value
+ * which is on the top of the heap.
+ * Complexity: O(log N).
*
* @public
- * @returns {number} The extremum value
+ * @returns {Number|Object} The extremum value.
*/
- Heap.prototype.extract = function () {
- if (!this._heap.length)
+ exports.Heap.prototype.extract = function () {
+ if (!this._heap.length) {
throw 'The heap is already empty!';
-
+ }
var extr = this._heap.shift();
this._heapify(0);
return extr;
};
- Heap.prototype.isEmpty = function () {
- return !this._heapify.length;
+ exports.Heap.prototype.getCollection = function () {
+ return this._heap;
};
- exports.Heap = Heap;
+ /**
+ * Checks or heap is empty.
+ *
+ * @public
+ * @returns {Boolean} Returns true if heap is empty.
+ */
+ exports.Heap.prototype.isEmpty = function () {
+ return !this._heap.length;
+ };
-}(typeof exports === 'undefined' ? window : exports));
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/data-structures/interval-tree.js b/src/data-structures/interval-tree.js
new file mode 100644
index 00000000..24663c98
--- /dev/null
+++ b/src/data-structures/interval-tree.js
@@ -0,0 +1,312 @@
+/**
+ * Interval tree is an ordered tree data structure to hold intervals.
+ *
+ * @example
+ *
+ * var IT = require('path-to-algorithms/src/data-structures/interval-tree');
+ * var intervalTree = new IT.IntervalTree();
+ *
+ * intervalTree.add([0, 100]);
+ * intervalTree.add([101, 200]);
+ * intervalTree.add([10, 50]);
+ * intervalTree.add([120, 220]);
+ *
+ * console.log(intervalTree.contains(150)); // true
+ * console.log(intervalTree.contains(250)); // false
+ * console.log(intervalTree.intersects([210, 310])); // true
+ * console.log(intervalTree.intersects([310, 320])); // false
+ *
+ * @module data-structures/interval-tree
+ */
+(function (exports) {
+
+ 'use strict';
+
+ /**
+ * Node which describes an interval.
+ *
+ * @public
+ * @constructor
+ * @param {Number} start Start of the interval.
+ * @param {Number} end End of the interval.
+ * @param {Node} left Left child node.
+ * @param {Node} right Right child node.
+ */
+ exports.Node = function (start, end, left, right) {
+ /**
+ * Node interval.
+ * @member {Array}
+ */
+ this.interval = [start, end];
+ /**
+ * Max endpoint in subtree which starts from this node.
+ * @member {Number}
+ */
+ this.max = -Infinity;
+ /**
+ * Parent node.
+ * @member {Node}
+ */
+ this.parentNode = null;
+ /**
+ * Left child node.
+ * @member {Node}
+ */
+ this.left = left;
+ /**
+ * Right child node.
+ * @member {Node}
+ */
+ this.right = right;
+ };
+
+ /**
+ * Interval tree.
+ *
+ * @public
+ * @constructor
+ */
+ exports.IntervalTree = function () {
+ /**
+ * Root node of the tree.
+ * @member {Node}
+ */
+ this.root = null;
+ };
+
+ function addNode(node, side, interval) {
+ var child = new exports.Node(interval[0], interval[1]);
+ child.max = interval[1];
+ child.parentNode = node;
+ node[side] = child;
+ if (node.max < interval[1]) {
+ while (child) {
+ if (child.max < interval[1]) {
+ child.max = interval[1];
+ }
+ child = child.parentNode;
+ }
+ }
+ }
+
+ function addHelper(node, interval) {
+ if (node.interval[0] > interval[0]) {
+ if (node.left) {
+ addHelper(node.left, interval);
+ } else {
+ addNode(node, 'left', interval);
+ }
+ } else {
+ if (node.right) {
+ addHelper(node.right, interval);
+ } else {
+ addNode(node, 'right', interval);
+ }
+ }
+ }
+
+ /**
+ * Add new interval to the tree.
+ *
+ * @public
+ * @param {Array} intreval Array with start and end points of the interval.
+ */
+ exports.IntervalTree.prototype.add = function (interval) {
+ if (!this.root) {
+ this.root = new exports.Node(interval[0], interval[1]);
+ this.root.max = interval[1];
+ return;
+ }
+ addHelper(this.root, interval);
+ };
+
+ function contains(point, node) {
+ if (!node) {
+ return false;
+ }
+ if (node.interval[0] <= point && node.interval[1] >= point) {
+ return true;
+ }
+ var result = false;
+ var temp;
+ ['left', 'right'].forEach(function (key) {
+ temp = node[key];
+ if (temp) {
+ if (temp.max > point) {
+ result = result || contains(point, temp);
+ }
+ }
+ });
+ return result;
+ }
+
+ /**
+ * Checks or point belongs to at least one intarval from the tree.
+ * Complexity: O(log N).
+ *
+ * @public
+ * @method
+ * @param {Number} point Point which should be checked.
+ * @return {Boolean} True if point belongs to one of the intervals.
+ */
+ exports.IntervalTree.prototype.contains = function (point) {
+ return contains(point, this.root);
+ };
+
+ function intersects(a, b) {
+ return (a[0] <= b[0] && a[1] >= b[0]) || (a[0] <= b[1] && a[1] >= b[1]) ||
+ (b[0] <= a[0] && b[1] >= a[0]) || (b[0] <= a[1] && b[1] >= a[1]);
+ }
+
+ function intersectsHelper(interval, node) {
+ if (!node) {
+ return false;
+ }
+ if (intersects(node.interval, interval)) {
+ return true;
+ }
+ var result = false;
+ var temp;
+ ['left', 'right'].forEach(function (side) {
+ temp = node[side];
+ if (temp && temp.max >= interval[0]) {
+ result = result || intersectsHelper(interval, temp);
+ }
+ });
+ return result;
+ }
+
+ /**
+ * Checks or interval belongs to at least one intarval from the tree.
+ * Complexity: O(log N).
+ *
+ * @public
+ * @method
+ * @param {Array} interval Interval which should be checked.
+ * @return {Boolean} True if interval intersects with one of the intervals.
+ */
+ exports.IntervalTree.prototype.intersects = function (interval) {
+ return intersectsHelper(interval, this.root);
+ };
+
+ function heightHelper(node) {
+ if (!node) {
+ return 0;
+ }
+ return 1 + Math.max(heightHelper(node.left), heightHelper(node.right));
+ }
+
+ /**
+ * Returns height of the tree.
+ *
+ * @public
+ * @method
+ * @return {Number} Height of the tree.
+ */
+ exports.IntervalTree.prototype.height = function () {
+ return heightHelper(this.root);
+ };
+
+ /**
+ * Returns node with the max endpoint in subtree.
+ *
+ * @public
+ * @method
+ * @param {Node} node Root node of subtree.
+ * @return {Node} Node with the largest endpoint.
+ */
+ exports.IntervalTree.prototype.findMax = function (node) {
+ var stack = [node];
+ var current;
+ var max = -Infinity;
+ var maxNode;
+ while (stack.length) {
+ current = stack.pop();
+ if (current.left) {
+ stack.push(current.left);
+ }
+ if (current.right) {
+ stack.push(current.right);
+ }
+ if (current.interval[1] > max) {
+ max = current.interval[1];
+ maxNode = current;
+ }
+ }
+ return maxNode;
+ };
+
+ // adjust the max value
+ exports.IntervalTree.prototype._removeHelper = function (interval, node) {
+ if (!node) {
+ return;
+ }
+ if (node.interval[0] === interval[0] &&
+ node.interval[1] === interval[1]) {
+ // When left and right children exists
+ if (node.left && node.right) {
+ var replacement = node.left;
+ while (replacement.left) {
+ replacement = replacement.left;
+ }
+ var temp = replacement.interval;
+ replacement.interval = node.interval;
+ node.interval = temp;
+ this._removeHelper(replacement.interval, node);
+ } else {
+ // When only left or right child exists
+ var side = 'left';
+ if (node.right) {
+ side = 'right';
+ }
+ var parentNode = node.parentNode;
+ if (parentNode) {
+ if (parentNode.left === node) {
+ parentNode.left = node[side];
+ } else {
+ parentNode.right = node[side];
+ }
+ if (node[side]) {
+ node[side].parentNode = parentNode;
+ }
+ } else {
+ this.root = node[side];
+ // last node removed
+ if (this.root) {
+ this.root.parentNode = null;
+ }
+ }
+ }
+ // Adjust the max value
+ var p = node.parentNode;
+ if (p) {
+ var maxNode = this.findMax(p);
+ var max = maxNode.interval[1];
+ while (maxNode) {
+ if (maxNode.max === node.interval[1]) {
+ maxNode.max = max;
+ maxNode = maxNode.parentNode;
+ } else {
+ maxNode = false;
+ }
+ }
+ }
+ } else {
+ // could be optimized
+ this._removeHelper(interval, node.left);
+ this._removeHelper(interval, node.right);
+ }
+ };
+
+ /**
+ * Remove interval from the tree.
+ *
+ * @public
+ * @method
+ * @param {Array} intreval Array with start and end of the interval.
+ */
+ exports.IntervalTree.prototype.remove = function (interval) {
+ return this._removeHelper(interval, this.root);
+ };
+
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/data-structures/linked-list.js b/src/data-structures/linked-list.js
new file mode 100644
index 00000000..9027f16e
--- /dev/null
+++ b/src/data-structures/linked-list.js
@@ -0,0 +1,279 @@
+/**
+ * Linked list.
+ *
+ * @example
+ *
+ * var LL = require('path-to-algorithms/src/data-structures/linked-list');
+ *
+ * var linkedList = new LL.LinkedList();
+ *
+ * linkedList.push({
+ * name: 'John',
+ * birthyear: 1981
+ * });
+ * linkedList.push({
+ * name: 'Pavlo',
+ * birthyear: 2000
+ * });
+ * linkedList.push({
+ * name: 'Garry',
+ * birthyear: 1989
+ * });
+ * linkedList.push({
+ * name: 'Derek',
+ * birthyear: 1990
+ * });
+ * linkedList.push({
+ * name: 'Ivan',
+ * birthyear: 1966
+ * });
+ *
+ * console.log(linkedList.shift().data); // { name: 'John', birthyear: 1981 }
+ * console.log(linkedList.pop().data); // { name: 'Ivan', birthyear: 1966 }
+ *
+ * @module data-structures/linked-list
+ */
+(function (exports) {
+
+ 'use strict';
+
+ /**
+ * Linked list node.
+ *
+ * @public
+ * @constructor
+ * @param {Object} data Data of the node.
+ */
+ exports.Node = function (data) {
+ /**
+ * Data of the node.
+ * @member {Object}
+ */
+ this.data = data;
+ /**
+ * Next node.
+ * @member {Node}
+ */
+ this.next = null;
+ /**
+ * Previous node.
+ * @member {Node}
+ */
+ this.prev = null;
+ };
+
+ /**
+ * Linked list.
+ *
+ * @public
+ * @constructor
+ */
+ exports.LinkedList = function () {
+ this.first = null;
+ this.last = null;
+ };
+
+ /**
+ * Add data to the end of linked list.
+ *
+ * @public
+ * @method
+ * @param {Object} data Data which should be added.
+ */
+ exports.LinkedList.prototype.push = function (data) {
+ var node = new exports.Node(data);
+ if (this.first === null) {
+ this.first = this.last = node;
+ } else {
+ var temp = this.last;
+ this.last = node;
+ node.prev = temp;
+ temp.next = node;
+ }
+ };
+
+ /**
+ * Add data to the beginning of linked list.
+ *
+ * @public
+ * @method
+ * @param {Object} data Data which should be added.
+ */
+ exports.LinkedList.prototype.unshift = function (data) {
+ var node = new exports.Node(data);
+ if (this.first === null) {
+ this.first = this.last = node;
+ } else {
+ var temp = this.first;
+ this.first = node;
+ node.next = temp;
+ temp.prev = node;
+ }
+ };
+
+ /**
+ * In order traversal of the linked list.
+ *
+ * @public
+ * @method
+ * @param {Function} cb Callback which should be executed on each node.
+ */
+ exports.LinkedList.prototype.inorder = function (cb) {
+ var temp = this.first;
+ while (temp) {
+ cb(temp);
+ temp = temp.next;
+ }
+ };
+
+ /**
+ * Remove data from the linked list.
+ *
+ * @public
+ * @method
+ * @param {Object} data Data which should be removed.
+ * @return {Boolean} Returns true if data has been removed.
+ */
+ exports.LinkedList.prototype.remove = function (data, equals) {
+ if (this.first === null) {
+ return false;
+ }
+ var temp = this.first;
+ var next;
+ var prev;
+ while (temp) {
+ var dataFound = equals ? equals(temp.data, data) : temp.data === data;
+ if (dataFound) {
+ next = temp.next;
+ prev = temp.prev;
+ if (next) {
+ next.prev = prev;
+ }
+ if (prev) {
+ prev.next = next;
+ }
+ if (temp === this.first) {
+ this.first = next;
+ }
+ if (temp === this.last) {
+ this.last = prev;
+ }
+ return true;
+ }
+ temp = temp.next;
+ }
+ return false;
+ };
+
+ /**
+ * Check if linked list contains cycle.
+ *
+ * @public
+ * @method
+ * @return {Boolean} Returns true if linked list contains cycle.
+ */
+ exports.LinkedList.prototype.hasCycle = function () {
+ var fast = this.first;
+ var slow = this.first;
+ while (true) {
+ if (fast === null) {
+ return false;
+ }
+ fast = fast.next;
+ if (fast === null) {
+ return false;
+ }
+ fast = fast.next;
+ slow = slow.next;
+ if (fast === slow) {
+ return true;
+ }
+ }
+ };
+
+ /**
+ * Return last node from the linked list.
+ *
+ * @public
+ * @method
+ * @return {Node} Last node.
+ */
+ exports.LinkedList.prototype.pop = function () {
+ if (this.last === null) {
+ return null;
+ }
+ var temp = this.last;
+ this.last = this.last.prev;
+ return temp;
+ };
+
+ /**
+ * Return first node from the linked list.
+ *
+ * @public
+ * @method
+ * @return {Node} First node.
+ */
+ exports.LinkedList.prototype.shift = function () {
+ if (this.first === null) {
+ return null;
+ }
+ var temp = this.first;
+ this.first = this.first.next;
+ return temp;
+ };
+
+ /**
+ * Reverses the linked list recursively
+ *
+ * @public
+ * @method
+ */
+ exports.LinkedList.prototype.recursiveReverse = function () {
+
+ function inverse(current, next) {
+ if (!next) {
+ return;
+ }
+ inverse(next, next.next);
+ next.prev = next.next;
+ next.next = current;
+ }
+
+ if (!this.first) {
+ return;
+ }
+ inverse(this.first, this.first.next);
+ this.first.prev = this.first.next;
+ this.first.next = null;
+ var temp = this.first;
+ this.first = this.last;
+ this.last = temp;
+ };
+
+ /**
+ * Reverses the linked list iteratively
+ *
+ * @public
+ * @method
+ */
+ exports.LinkedList.prototype.reverse = function () {
+ if (!this.first || !this.first.next) {
+ return;
+ }
+ var current = this.first
+ var next
+
+ do {
+ next = current.next
+ current.next = current.prev
+ current.prev = next
+ current = next
+ } while (next)
+
+ var tmp = this.first
+ this.first = this.last
+ this.last = tmp
+ };
+
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/data-structures/red-black-tree.js b/src/data-structures/red-black-tree.js
index 58dd7017..970fe16d 100644
--- a/src/data-structures/red-black-tree.js
+++ b/src/data-structures/red-black-tree.js
@@ -1,4 +1,34 @@
-(function (global) {
+/**
+ * Red-Black tree is a data structure which is
+ * a type of self-balancing binary search tree.
+ *
+ * @example
+ *
+ * var RBTree = require('../src/data-structures/red-black-tree').RBTree;
+ * var rbTree = new RBTree();
+ *
+ * rbTree.put(1981, {
+ * name: 'John',
+ * surname: 'Smith'
+ * });
+ * rbTree.put(2000, {
+ * name: 'Pavlo',
+ * surname: 'Popov'
+ * });
+ * rbTree.put(1989, {
+ * name: 'Garry',
+ * surname: 'Fisher'
+ * });
+ * rbTree.put(1990, {
+ * name: 'Derek',
+ * surname: 'Anderson'
+ * });
+ *
+ * console.log(rbTree.get(1989)); // { name: 'Garry', surname: 'Fisher' }
+ *
+ * @module data-structures/red-black-tree
+ */
+(function (exports) {
'use strict';
@@ -9,14 +39,18 @@
RED: 0,
BLACK: 1
};
-
- global.Colors = Colors;
-
+ exports.Colors = Colors;
/**
- * Represents given node in the tree.
+ * Node of the Red-Black tree.
*
+ * @private
* @constructor
+ * @param {Number} key Key of the node.
+ * @param {Object} value Value assigned to the node.
+ * @param {Node} left Left node.
+ * @param {Node} right Right node.
+ * @param {Number} color Node color.
*/
function Node(key, value, left, right, color) {
this._key = key;
@@ -26,10 +60,23 @@
this._color = color;
}
+ /**
+ * Check or node is red.
+ *
+ * @private
+ * @method
+ * @return {Boolean} Returns true if node is red.
+ */
Node.prototype.isRed = function () {
return this._color === Colors.RED;
};
+ /**
+ * Changes node color.
+ *
+ * @private
+ * @method
+ */
Node.prototype.flipColor = function () {
if (this._color === Colors.RED) {
this._color = Colors.BLACK;
@@ -54,23 +101,28 @@
};
});
- global.Node = Node;
-
+ exports.Node = Node;
/**
- * Represents a Red-Black Tree
+ * Red-Black Tree.
*
+ * @public
* @constructor
*/
- function RBTree() {
+ exports.RBTree = function () {
this._root = null;
- }
+ };
/**
- * Adds value associated with given key.
- * Complexity O(log n)
+ * Add value associated with a given key.
+ * Complexity: O(log N).
+ *
+ * @public
+ * @method
+ * @param {Number} key Key.
+ * @param {Object} value Value.
*/
- RBTree.prototype.put = function (key, value) {
+ exports.RBTree.prototype.put = function (key, value) {
this._root = this._put(key, value, this._root);
this._root.setColor(Colors.BLACK);
};
@@ -78,8 +130,13 @@
/**
* Returns true or false depending on whether
* given node is red.
+ *
+ * @private
+ * @method
+ * @param {Node} node Node which sould be checked.
+ * @return Returns true if node is red.
*/
- RBTree.prototype.isRed = function (node) {
+ exports.RBTree.prototype.isRed = function (node) {
if (!node) {
return false;
}
@@ -87,10 +144,16 @@
};
/**
- * Helper function for insertion of given key, value pair
- * into the red-black tree.
+ * Helper function for insertion of given key,
+ * value pair into the Red-Black tree.
+ *
+ * @private
+ * @method
+ * @param {Number} key Key.
+ * @param {Object} value Value.
+ * @param {Node} node Node.
*/
- RBTree.prototype._put = function (key, value, node) {
+ exports.RBTree.prototype._put = function (key, value, node) {
var newRoot = node;
if (node === null) {
return new Node(key, value, null, null, Colors.RED);
@@ -115,19 +178,28 @@
};
/**
- * Flip the colors of the both neighbours of given node.
- * Complexity O(1).
+ * Flip the colors of the both neighbours of given node.
+ * Complexity: O(1).
+ *
+ * @private
+ * @method
+ * @param {Node} node Node.
*/
- RBTree.prototype._flipColors = function (node) {
+ exports.RBTree.prototype._flipColors = function (node) {
node.getLeft().flipColor();
node.getRight().flipColor();
};
/*
- * Rotates given node to left.
- * Complexity O(1).
+ * Rotates given node to the left.
+ * Complexity: O(1).
+ *
+ * @private
+ * @method
+ * @param {Node} node Node.
+ * @return {Node} Right node.
*/
- RBTree.prototype._rotateLeft = function (node) {
+ exports.RBTree.prototype._rotateLeft = function (node) {
var x = node.getRight();
if (x !== null) {
var temp = x.getLeft();
@@ -140,10 +212,15 @@
};
/*
- * Rotates given node to right.
- * Complexity O(1).
+ * Rotates given node to the right.
+ * Complexity: O(1).
+ *
+ * @private
+ * @method
+ * @param {Node} node Node.
+ * @return {Node} Left node.
*/
- RBTree.prototype._rotateRight = function (node) {
+ exports.RBTree.prototype._rotateRight = function (node) {
var x = node.getLeft();
if (x !== null) {
var temp = x.getRight();
@@ -156,17 +233,26 @@
};
/**
- * Gets value by given key.
- * Complexity O(log n).
+ * Get value by the given key.
+ * Complexity: O(log N).
*
- * @param {*} key A key to be searched for
- * @return {*} A value which will be returned based on the passed key
+ * @public
+ * @param {Number} key A key to be searched for.
+ * @return {Object} A value which will be returned based on the key.
*/
- RBTree.prototype.get = function (key) {
+ exports.RBTree.prototype.get = function (key) {
return this._get(this._root, key);
};
- RBTree.prototype._get = function (node, key) {
+ /**
+ * Get value by the given key.
+ *
+ * @private
+ * @param {Node} node Node to start with.
+ * @param {Number} key A key to be searched for.
+ * @return {Object} A value which will be returned based on the key.
+ */
+ exports.RBTree.prototype._get = function (node, key) {
if (node === null) {
return undefined;
}
@@ -180,8 +266,34 @@
}
};
- global.RBTree = RBTree;
-
-
-}(typeof window === 'undefined' ? module.exports : window));
+ /**
+ * Get Level Order Traversal for the given Red Black Tree,
+ * returns 'Tree is empty' string when tree has no Nodes.
+ * Complexity: O(N).
+ *
+ * @public
+ * @return {String} The keys of the tree in level order traversal.
+ *
+ */
+ exports.RBTree.prototype.levelOrderTraversal = function () {
+ var queue = [];
+ var levelOrderString = '';
+ if (this._root){
+ queue.push(this._root);
+ } else {
+ levelOrderString = ' Tree is empty';
+ }
+ while (queue.length !== 0){
+ var tempNode = queue.shift();
+ levelOrderString += ' ' + tempNode.getKey();
+ if (tempNode.getLeft() !== null){
+ queue.push(tempNode.getLeft());
+ }
+ if (tempNode.getRight() !== null){
+ queue.push(tempNode.getRight());
+ }
+ }
+ return 'Level Order Traversal -:' + levelOrderString;
+ };
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/data-structures/segment-tree.js b/src/data-structures/segment-tree.js
new file mode 100644
index 00000000..4acc1f60
--- /dev/null
+++ b/src/data-structures/segment-tree.js
@@ -0,0 +1,105 @@
+/**
+ * Implementation of a segment tree.
+ *
+ * @example
+ * var SegmentTree = require('path-to-algorithms/src/data-structures'+
+ * '/segment-tree').SegmentTree;
+ *
+ * var tree = SegmentTree.indexArray([-1, 2, 4, 0], Infinity, function (a, b) {
+ * return Math.min(a, b);
+ * });
+ *
+ * @public
+ * @constructor
+ * @param {any} placeholder A placeholder value dpendent on the aggregate.
+ * @param {Function} aggregate Generates the values for the intermediate nodes.
+ * @module data-structures/segment-tree
+ */
+(function (exports) {
+
+ 'use strict';
+
+ /**
+ * SegmentTree constructor.
+ *
+ * @public
+ * @constructor
+ * @param {any} invalidValue Invalid value to be returned depending
+ * on the aggregate.
+ * @param {Function} aggregate Function to generate the intermediate
+ * values in the tree.
+ */
+ function SegmentTree(invalidValue, aggregate) {
+ this._data = [];
+ this._original = null;
+ this._invalidValue = invalidValue;
+ this._aggregate = aggregate;
+ }
+
+ /**
+ * Creates a segment tree using an array passed as element.
+ *
+ * @static
+ * @public
+ * @param {Array} array Array to be indexed.
+ * @param {Function} aggregate Function used for generation of
+ * intermediate nodes.
+ */
+ SegmentTree.indexArray = function (array, placeholder, aggregate) {
+ var segmentize = function (original, data, lo, hi, idx) {
+ if (lo === hi) {
+ data[idx] = original[lo];
+ } else {
+ var mid = Math.floor((lo + hi) / 2);
+ var left = 2 * idx + 1;
+ var right = 2 * idx + 2;
+ segmentize(original, data, lo, mid, left);
+ segmentize(original, data, mid + 1, hi, right);
+ data[idx] = aggregate(data[left], data[right]);
+ }
+ };
+ var result = [];
+ if (array && array.length) {
+ segmentize(array, result, 0, array.length - 1, 0);
+ }
+ var tree = new SegmentTree(placeholder, aggregate);
+ tree._data = result;
+ tree._original = array;
+ return tree;
+ };
+
+ /**
+ * Queries the SegmentTree in given range based on the set aggregate.
+ *
+ * @param {Number} start The start index of the interval.
+ * @param {Number} end The end index of the interval.
+ */
+ SegmentTree.prototype.query = function (start, end) {
+ if (start > end) {
+ throw new Error('The start index should be smaller by the end index');
+ }
+ var findEl = function (originalArrayStart, originalArrayEnd, current) {
+ if (start > originalArrayEnd) {
+ return this._invalidValue;
+ }
+ if (end < originalArrayStart) {
+ return this._invalidValue;
+ }
+ if (start === originalArrayStart && end === originalArrayEnd ||
+ originalArrayStart === originalArrayEnd) {
+ return this._data[current];
+ }
+ var originalArrayMid =
+ Math.floor((originalArrayStart + originalArrayEnd) / 2);
+ return this._aggregate(
+ findEl(originalArrayStart, originalArrayMid, 2 * current + 1),
+ findEl(originalArrayMid + 1, originalArrayEnd, 2 * current + 2)
+ );
+ }.bind(this);
+ return findEl(0, this._original.length - 1, 0, this._aggregate);
+ };
+
+ exports.SegmentTree = SegmentTree;
+
+}(typeof window === 'undefined' ? module.exports : window));
+
diff --git a/src/data-structures/size-balanced-tree.js b/src/data-structures/size-balanced-tree.js
new file mode 100644
index 00000000..ed7e1943
--- /dev/null
+++ b/src/data-structures/size-balanced-tree.js
@@ -0,0 +1,369 @@
+/**
+ * Size balanced tree is a data structure which is
+ * a type of self-balancing binary search tree that use
+ * the tree size attribute for re-balancing the tree.
+ *
+ * @example
+ *
+ * var SBTree = require('../src/data-structures/size-balanced-tree').SBTree;
+ * var sbTree = new SBTree();
+ *
+ * var treeNode = sbTree.push({
+ * name: 'John',
+ * surname: 'Smith'
+ * });
+ * sbTree.insert(0, {
+ * name: 'Pavlo',
+ * surname: 'Popov'
+ * });
+ * sbTree.insert(1, {
+ * name: 'Garry',
+ * surname: 'Fisher'
+ * });
+ * sbTree.insert(0, {
+ * name: 'Derek',
+ * surname: 'Anderson'
+ * });
+ *
+ * console.log(sbTree.get(0)); // { name: 'Derek', surname: 'Anderson' }
+ *
+ * @module data-structures/size-balanced-tree
+ */
+
+function CreateSBTreeClass (Node, Nil, updateChild) {
+ 'use strict';
+
+ function LeftRotate(node, childNode) {
+ /*
+ Before rotate:
+ node
+ / \
+ NL childNode
+ / \
+ CL CR
+ After rotate:
+
+ childNode
+ / \
+ node CR
+ / \
+ NL CL
+ */
+ node.right = childNode.left;
+ if (node.right !== Nil) {
+ node.right.parent = node;
+ }
+ childNode.left = node;
+ // setting childNode's parent to node's parent
+ updateChild(node, childNode);
+ return childNode;
+ }
+
+ function RightRotate(node, childNode) {
+ /*
+ Before rotate:
+ node
+ / \
+ childNode NR
+ / \
+ CL CR
+ After rotate:
+
+ childNode
+ / \
+ CL node
+ / \
+ CR NR
+ */
+ node.left = childNode.right;
+ if (node.left !== Nil) {
+ node.left.parent = node;
+ }
+ childNode.right = node;
+ // setting childNode's parent to node's parent
+ updateChild(node, childNode);
+ return childNode;
+ }
+
+ function maintain(node, leftChild) {
+ if (node === Nil) {
+ return node;
+ }
+ var savedNode = node;
+ if (leftChild) {
+ if (node.left.left.size > node.right.size) {
+ node = RightRotate(node, node.left);
+ } else if (node.left.right.size > node.right.size) {
+ LeftRotate(node.left, node.left.right);
+ node = RightRotate(node, node.left);
+ }
+ } else {
+ if (node.right.right.size > node.left.size) {
+ node = LeftRotate(node, node.right);
+ } else if (node.right.left.size > node.left.size) {
+ RightRotate(node.right, node.right.left);
+ node = LeftRotate(node, node.right);
+ }
+ }
+ if (node === savedNode) {
+ return node;
+ }
+ maintain(node.left, false);
+ maintain(node.right, true);
+ node = maintain(node, true);
+ node = maintain(node, false);
+ return node;
+ }
+
+ function maintainSizeBalancedTree(node) {
+ while (node.parent !== Nil) {
+ var childNode = node;
+ node = node.parent;
+ if (node.left === childNode) {
+ node = maintain(node, true);
+ } else {
+ node = maintain(node, false);
+ }
+ }
+ return node;
+ }
+
+ function findNodeAtPos(node, pos) {
+ while (pos !== node.left.size) {
+ if (pos < node.left.size) {
+ node = node.left;
+ } else {
+ pos -= node.left.size;
+ pos -= 1; //The node element should be decrement by 1
+ node = node.right;
+ }
+ }
+ return node;
+ }
+
+ /**
+ * Size Balanced Tree.
+ *
+ * @public
+ * @constructor
+ */
+ var SBTree = function () {};
+
+ SBTree.prototype = {
+ _root: Nil,
+ get size() {
+ return this._root.size;
+ },
+
+ get root() {
+ return this._root;
+ },
+
+ binarySearch: function (cmp, value) {
+ var left = -1;
+ var right = this.size;
+ while (left + 1 < right) {
+ var middle = (left + right) >> 1; // jshint ignore:line
+ var result = cmp(this.get(middle).value, value);
+ if (result <= 0) {
+ left = middle;
+ } else {
+ right = middle;
+ }
+ }
+ return left + 1;
+ },
+ };
+
+ SBTree.prototype.get = function (pos) {
+ if (pos >= this.size) {
+ return Nil;
+ }
+ return findNodeAtPos(this._root, pos);
+ };
+
+ SBTree.prototype.getIndex = function (node) {
+ var index = node.left.size;
+ while (node !== this._root) {
+ var parent = node.parent;
+ if (parent.right === node) {
+ index += parent.left.size + 1;
+ }
+ node = parent;
+ }
+ return index;
+ };
+
+ SBTree.prototype.shiftDown = function (node) {
+ var direction = 0;
+ while (true) {
+ if (node.left !== Nil && node.right !== Nil) {
+ switch (direction) {
+ case 0:
+ RightRotate(node, node.left);
+ break;
+ case 1:
+ LeftRotate(node, node.right);
+ break;
+ }
+ direction = 1 - direction;
+ } else if (node.left !== Nil) {
+ RightRotate(node, node.left);
+ } else if (node.right !== Nil) {
+ LeftRotate(node, node.right);
+ } else {
+ break; // The node could be able to removed
+ }
+ }
+ };
+
+ SBTree.prototype.insertLeafNode = function (node) {
+ var parent = node.parent;
+ while (parent !== Nil) {
+ parent.size = parent.size + 1;
+ parent = parent.parent;
+ }
+ };
+
+ SBTree.prototype.removeLeafNode = function (node) {
+ var parent = node.parent;
+ while (parent !== Nil) {
+ parent.size = parent.size - 1;
+ parent = parent.parent;
+ }
+ };
+
+ SBTree.prototype.insert = function (pos, value) {
+ var node = Nil;
+ var newNode = new Node(value, Nil, Nil, Nil, 1);
+ if (pos === this.size) {
+ if (pos > 0) {
+ node = findNodeAtPos(this._root, pos - 1);
+ node.right = newNode;
+ }
+ } else {
+ node = findNodeAtPos(this._root, pos);
+ if (node.left !== Nil) {
+ this.shiftDown(node);
+ }
+ node.left = newNode;
+ }
+ newNode.parent = node;
+ this.insertLeafNode(newNode);
+ this._root = maintainSizeBalancedTree(newNode);
+ return newNode;
+ };
+
+ /**
+ * Push a value to the end of tree.
+ * Complexity: O(log N).
+ *
+ * @public
+ * @method
+ * @param {Object} value Value.
+ */
+ SBTree.prototype.push = function (value) {
+ this.insert(this.size, value);
+ };
+
+ SBTree.prototype.removeNode = function (node) {
+ this.shiftDown(node);
+ var maintainNode = node.parent;
+ if (maintainNode.left === node) {
+ maintainNode.left = Nil;
+ } else if (maintainNode.right === node) {
+ maintainNode.right = Nil;
+ }
+ this.removeLeafNode(node);
+ this._root = maintainSizeBalancedTree(maintainNode);
+ return node;
+ };
+
+ SBTree.prototype.remove = function (pos) {
+ if (pos >= this._root.size) {
+ return Nil; // There is no element to remove
+ }
+ var node = findNodeAtPos(this._root, pos);
+ return this.removeNode(node);
+ };
+
+ return SBTree;
+}
+
+(function (exports) {
+ 'use strict';
+
+ /**
+ * Node constructor of the Size-Balanced tree.
+ *
+ * @private
+ * @constructor
+ * @param {Object} value Value assigned to the node.
+ * @param {Node} parent Parent node.
+ * @param {Node} left Left node.
+ * @param {Node} right Right node.
+ * @param {Number} size Node's, means the Node count of this .
+ */
+ var NodeConstructor = function (value, parent, left, right, size) {
+ this.value = value;
+ this.parent = parent;
+ this.left = left;
+ this.right = right;
+ this.size = size;
+ };
+
+ var createNil = function (Node, value) {
+ var Nil = new Node(value, null, null, null, 0);
+ Nil.parent = Nil;
+ Nil.left = Nil;
+ Nil.right = Nil;
+ return Nil;
+ };
+
+ /**
+ * Update node's size.
+ *
+ * @private
+ * @method
+ */
+ var updateSize = function () {
+ this.size = this.left.size + this.right.size + 1;
+ };
+
+ // node, childNode must not be Nil,
+ // if the childNode turn out to be the root, the parent should be Nil
+ var updateChild = function (node, childNode) {
+ var parent = node.parent;
+ node.parent = childNode;
+ childNode.parent = parent;
+
+ node.updateSize();
+ childNode.updateSize();
+ if (parent.right === node) {
+ parent.right = childNode;
+ parent.updateSize();
+ } else if (parent.left === node) {
+ parent.left = childNode;
+ parent.updateSize();
+ } // otherwise parent is Nil
+ };
+
+ var Node = function () {
+ NodeConstructor.apply(this, arguments);
+ };
+
+ Node.prototype.updateSize = updateSize;
+
+ var Nil = createNil(Node, null);
+
+ exports.NodeConstructor = NodeConstructor;
+ exports.createNil = createNil;
+ exports.updateSize = updateSize;
+ exports.updateChild = updateChild;
+ exports.CreateSBTreeClass = CreateSBTreeClass;
+
+ exports.Node = Node;
+ exports.Nil = Nil;
+ exports.SBTree = CreateSBTreeClass(Node, Nil, updateChild);
+
+})(typeof module === 'undefined' ? window : module.exports);
diff --git a/src/data-structures/splay-tree.js b/src/data-structures/splay-tree.js
new file mode 100644
index 00000000..20b80716
--- /dev/null
+++ b/src/data-structures/splay-tree.js
@@ -0,0 +1,595 @@
+/**
+ * Splay Tree.
+ *
+ * @example
+ * var STree = require('path-to-algorithms/src/data-structures'+
+ * '/splay-tree');
+ * var sTree = new STree.SplayTree();
+ * sTree.insert(10);
+ * sTree.insert(5);
+ * sTree.insert(15);
+ * sTree.insert(7);
+ * sTree.insert(12);
+ * sTree.search(10);
+ * console.log(sTree._root);
+ * sTree.remove(10);
+ * console.log(sTree._root);
+ * sTree.search(15);
+ * console.log(sTree._root);
+ *
+ * @module data-structures/splay-tree
+ */
+(function (exports) {
+ 'use strict';
+
+ /**
+ * Node of the tree.
+ *
+ * @public
+ * @constructor
+ * @param {Number|String} value Value of the node.
+ * @param {Node} left Left sibling.
+ * @param {Node} right Right sibling.
+ * @param {Node} parent Parent of the node.
+ */
+ exports.Node = function (value, left, right, parent) {
+ /**
+ * @member {Number|String}
+ */
+ this.value = value;
+ this._left = left;
+ this._right = right;
+ this._parent = parent;
+ };
+
+ /**
+ * Splay tree.
+ * {@link http://en.wikipedia.org/wiki/Splay_tree}
+ * @public
+ * @constructor
+ */
+ exports.SplayTree = function () {
+ this._root = null;
+ };
+
+ /**
+ * Splays a node to the root.
+ *
+ * @private
+ * @method
+ * @param {Node} node Node to be splayed.
+ * @returns {Node} The same node from the parameter, post splayed.
+ */
+ exports.SplayTree.prototype._splay = function (node) {
+ while (this._root !== node) {
+ var hasParent = node._parent !== null;
+ var hasGrandparent = (hasParent && node._parent._parent !== null);
+ if (hasParent && hasGrandparent) {
+ var isLeftChild = node._parent._left === node;
+ var isParentLeftChild = node._parent._parent._left === node._parent;
+ if (
+ (isLeftChild && isParentLeftChild) ||
+ (!isLeftChild && !isParentLeftChild)
+ ) {
+ node = this._zigZig(node);
+ } else {
+ node = this._zigZag(node);
+ }
+ } else {
+ node = this._zig(node);
+ }
+ }
+ return node;
+ };
+
+ /**
+ * Performs a zig-zig splay pattern
+ *
+ * @private
+ * @method
+ * @param {Node} node Node to be zig-zig'd.
+ * @returns {Node} The same node from the parameter, post splayed.
+ */
+ exports.SplayTree.prototype._zigZig = function (node) {
+
+ var parent = node._parent;
+ var grandParent = node._parent._parent;
+ var greatGrandParent = grandParent._parent !== undefined ?
+ grandParent._parent : null;
+
+ var orientation = (parent._right === node) ? '_right' : '_left';
+ var oppositeOrientation = (orientation === '_left') ? '_right' : '_left';
+ var grandParentOrientation = (greatGrandParent !== null &&
+ greatGrandParent._left === grandParent) ? '_left' : '_right';
+
+ // Fix grandparent & great if it exists/not root
+ if (this._root === grandParent) {
+ this._root = node;
+ } else {
+ greatGrandParent[grandParentOrientation] = node;
+ }
+ grandParent._parent = parent;
+ // Fix grandparent subtree
+ grandParent[orientation] = parent[oppositeOrientation];
+ if (grandParent[orientation] !== null) {
+ grandParent[orientation]._parent = grandParent;
+ }
+ // Fix Parent
+ parent[oppositeOrientation] = grandParent;
+ parent[orientation] = node[oppositeOrientation];
+ if (parent[orientation] !== null) {
+ parent[orientation]._parent = parent;
+ }
+ parent._parent = node;
+ // Fix Curr Node
+ node[oppositeOrientation] = parent;
+ if (node === this._root) {
+ node._parent = null;
+ } else if (greatGrandParent !== null) {
+ node._parent = greatGrandParent;
+ }
+
+ return node;
+ };
+
+ /**
+ * Performs a zig-zag splay pattern
+ *
+ * @private
+ * @method
+ * @param {Node} node Node to be zig-zag'd.
+ * @returns {Node} The same node from the parameter, post splayed.
+ */
+ exports.SplayTree.prototype._zigZag = function (node) {
+
+ var parent = node._parent;
+ var grandParent = parent._parent;
+ var greatGrandParent = grandParent._parent !== undefined ?
+ grandParent._parent : null;
+
+ var orientation = (parent._left === node) ? '_left' : '_right';
+ var oppositeOrientation = (orientation === '_right') ? '_left' : '_right';
+ var grandParentOrientation = (greatGrandParent !== null &&
+ greatGrandParent._left === grandParent) ? '_left' : '_right';
+
+ // Fix GrandParent
+ if (this._root === grandParent) {
+ this._root = node;
+ } else {
+ greatGrandParent[grandParentOrientation] = node;
+ }
+ grandParent._parent = node;
+ // Fix GrandParent subtree
+ grandParent[oppositeOrientation] = node[orientation];
+ if (grandParent[oppositeOrientation] !== null) {
+ grandParent[oppositeOrientation]._parent = grandParent;
+ }
+ // Fix Parent
+ parent[orientation] = node[oppositeOrientation];
+ if (parent[orientation] !== null) {
+ parent[orientation]._parent = parent;
+ }
+ parent._parent = node;
+ // Fix Curr Node
+ node[orientation] = grandParent;
+ node[oppositeOrientation] = parent;
+ if (this._root === node) {
+ node._parent = null;
+ } else if (greatGrandParent !== null) {
+ node._parent = greatGrandParent;
+ }
+
+ return node;
+ };
+
+ /**
+ * Performs a zig splay pattern
+ *
+ * @private
+ * @method
+ * @param {Node} node Node to be zig'd.
+ * @returns {Node} The same node from the parameter, post splayed.
+ */
+ exports.SplayTree.prototype._zig = function (node) {
+
+ var parent = node._parent;
+ var orientation = (parent._right === node) ? '_right' : '_left';
+ var oppositeOrientation = (orientation === '_right') ? '_left' : '_right';
+
+ if (this._root === parent) {
+ this._root = node;
+ }
+ // Fix Parent
+ parent[orientation] = node[oppositeOrientation];
+ if (parent[orientation] !== null) {
+ parent[orientation]._parent = parent;
+ }
+ parent._parent = node;
+ // Fix Curr Node
+ node[oppositeOrientation] = parent;
+ node._parent = null;
+
+ return node;
+ };
+
+ /**
+ * Inserts a node into the splay tree.
+ * Time complexity: O(log N) in the average case
+ * and amortized O(log n) in the worst case.
+ *
+ * @public
+ * @method
+ * @param {Number|String} value Node value.
+ * @param {Node} current Current node.
+ */
+ exports.SplayTree.prototype.insert = function (value, current) {
+ if (this._root === null) {
+ this._root = new exports.Node(value, null, null, null);
+ return;
+ }
+ var insertKey;
+ current = current || this._root;
+ if (current.value > value) {
+ insertKey = '_left';
+ } else {
+ insertKey = '_right';
+ }
+ if (!current[insertKey]) {
+ current[insertKey] = new exports.Node(value, null, null, current);
+ this._splay(current[insertKey]);
+ } else {
+ this.insert(value, current[insertKey]);
+ }
+ };
+
+ /**
+ * In-order traversal from the given node.
+ *
+ * @private
+ * @param {Node} current Node from which to start the traversal.
+ * @param {Function} callback Callback which
+ * will be called for each traversed node.
+ */
+ exports.SplayTree.prototype._inorder = function (current, callback) {
+ if (!current) {
+ return;
+ }
+ this._inorder(current._left, callback);
+ if (typeof callback === 'function') {
+ callback(current);
+ }
+ this._inorder(current._right, callback);
+ };
+
+ /**
+ * In-order traversal of the whole Splay Tree.
+ *
+ * @public
+ * @method
+ * @param {Function} callback Callback which will be
+ * called for each traversed node.
+ */
+ exports.SplayTree.prototype.inorder = function (callback) {
+ return this._inorder(this._root, callback);
+ };
+
+ /**
+ * Post-order traversal from given node.
+ *
+ * @private
+ * @param {Node} current Node from which to start the traversal.
+ * @param {Function} callback Callback which will
+ * be called for each traversed node
+ */
+ exports.SplayTree.prototype._postorder = function (current, callback) {
+ if (!current) {
+ return;
+ }
+ if (typeof callback === 'function') {
+ callback(current);
+ }
+ this._postorder(current._left, callback);
+ this._postorder(current._right, callback);
+ };
+
+ /**
+ * Post-order traversal of the whole tree.
+ *
+ * @public
+ * @param {Function} callback Callback which
+ * will be called for each traversed node.
+ */
+ exports.SplayTree.prototype.postorder = function (callback) {
+ return this._postorder(this._root, callback);
+ };
+
+ /**
+ * Pre-order traversal of the tree from given node.
+ *
+ * @private
+ * @param {Node} current Node from which to start the traversal.
+ * @param {Function} callback Callback which
+ * will be called for each traversed node.
+ */
+ exports.SplayTree.prototype._preorder = function (current, callback) {
+ if (!current) {
+ return;
+ }
+ if (typeof callback === 'function') {
+ callback(current);
+ }
+ this._preorder(current._left, callback);
+ this._preorder(current._right, callback);
+ };
+
+ /**
+ * Pre-order preorder traversal of the whole tree.
+ *
+ * @public
+ * @param {Function} callback Callback which will
+ * be called for each traversed node.
+ */
+ exports.SplayTree.prototype.preorder = function (callback) {
+ return this._preorder(this._root, callback);
+ };
+
+ /**
+ * Finds a node by it's value.
+ * Average time complexity: O(log N).
+ *
+ * @public
+ * @param {Number|String} value of the node which should be found.
+ */
+ exports.SplayTree.prototype.search = function (value) {
+ var node = this._search(value, this._root);
+ return this._splay(node);
+ };
+
+ /**
+ * Finds a node by it's value.
+ * Average time complexity: O(log N).
+ *
+ * @public
+ * @param {Number|String} value of the node which should be found.
+ */
+ exports.SplayTree.prototype._splaylessSearch = function (value) {
+ return this._search(value, this._root);
+ };
+
+ /**
+ * Finds a node by it's value in a given sub-tree.
+ * Average time complexity: O(log N).
+ *
+ * @private
+ * @param {Number|String} value of the node which should be found.
+ * @param {Node} current node to be checked.
+ */
+ exports.SplayTree.prototype._search = function (value, current) {
+ if (!current) {
+ return null;
+ }
+
+ if (current.value === value) {
+ return current;
+ }
+
+ if (current.value > value) {
+ return this._search(value, current._left);
+ }
+
+ if (current.value < value) {
+ return this._search(value, current._right);
+ }
+ };
+
+ /**
+ * Replaces given child with new one, for given parent.
+ *
+ * @private
+ * @param {Node} parent Parent node.
+ * @param {Node} oldChild Child to be replaced.
+ * @param {Node} newChild Child replacement.
+ */
+ exports.SplayTree.prototype._replaceChild =
+ function (parent, oldChild, newChild) {
+ if (!parent) {
+ this._root = newChild;
+ this._root._parent = null;
+ } else {
+ if (parent._left === oldChild) {
+ parent._left = newChild;
+ } else {
+ parent._right = newChild;
+ }
+
+ if (newChild) {
+ newChild._parent = parent;
+ }
+ }
+ };
+
+ /**
+ * Removes node with given value from the tree.
+ * Average runtime complexity: O(log N).
+ *
+ * @public
+ * @param {Number|String} value Value to be removed
+ * @returns {Boolean} True/false depending
+ * on whether the given node is removed.
+ */
+ exports.SplayTree.prototype.remove = function (value) {
+ var node = this._splaylessSearch(value);
+ if (!node) {
+ return false;
+ }
+ if (node._left && node._right) {
+ var min = this._findMin(node._right);
+ var temp = node.value;
+
+ node.value = min.value;
+ min.value = temp;
+ return this.remove(min);
+ } else {
+ if (node._parent !== null) {
+ if (node._left) {
+ this._replaceChild(node._parent, node, node._left);
+ } else if (node._right) {
+ this._replaceChild(node._parent, node, node._right);
+ } else {
+ this._replaceChild(node._parent, node, null);
+ }
+ this._splay(node._parent);
+ } else {
+ this._root = null;
+ }
+ return true;
+ }
+ };
+
+ /**
+ * Finds the node with minimum value in given sub-tree.
+ *
+ * @private
+ * @param {Node} node Root of the sub-tree.
+ * @param {Number|String} current Current minimum value of the sub-tree.
+ * @returns {Node} Node with the minimum value in the sub-tree.
+ */
+ exports.SplayTree.prototype._findMin = function (node, current) {
+ current = current || {
+ value: Infinity
+ };
+ if (!node) {
+ return current;
+ }
+ if (current.value > node.value) {
+ current = node;
+ }
+ return this._findMin(node._left, current);
+ };
+
+ exports.SplayTree.prototype._isBalanced = function (current) {
+ if (!current) {
+ return true;
+ }
+ return this._isBalanced(current._left) &&
+ this._isBalanced(current._right) &&
+ Math.abs(this._getHeight(current._left) -
+ this._getHeight(current._right)) <= 1;
+ };
+
+ /**
+ * Returns whether the Splay Tree is balanced.
+ *
+ * @public
+ * @returns {Boolean} Whether the tree is balanced or not.
+ */
+ exports.SplayTree.prototype.isBalanced = function () {
+ return this._isBalanced(this._root);
+ };
+
+ /**
+ * Finds the diameter of the Splay Tree.
+ *
+ * @public
+ * @returns {Number} The longest path in the tree.
+ */
+ exports.SplayTree.prototype.getDiameter = function () {
+ var getDiameter = function (root) {
+ if (!root) {
+ return 0;
+ }
+ var leftHeight = this._getHeight(root._left);
+ var rightHeight = this._getHeight(root._right);
+ var path = leftHeight + rightHeight + 1;
+ return Math.max(path, getDiameter(root._left), getDiameter(root._right));
+ }.bind(this);
+ return getDiameter(this._root);
+ };
+
+ /**
+ * Returns the height of the tree.
+ *
+ * @public
+ * @returns {Number} The height of the tree.
+ */
+ exports.SplayTree.prototype.getHeight = function () {
+ return this._getHeight(this._root);
+ };
+
+ /**
+ * Recursive worker function for getHeight()
+ *
+ * @public
+ * @param {Node} node The node of the current recursive frame.
+ * @returns {Number} The height of the tree.
+ */
+ exports.SplayTree.prototype._getHeight = function (node) {
+ if (!node) {
+ return 0;
+ }
+ return 1 + Math.max(this._getHeight(node._left),
+ this._getHeight(node._right));
+ };
+
+ /**
+ * Finds the lowest common ancestor of two nodes.
+ *
+ * @public
+ * @returns {Node} The lowest common ancestor of the two nodes or null.
+ */
+ exports.SplayTree.prototype.lowestCommonAncestor =
+ function (firstNode, secondNode) {
+ return this._lowestCommonAncestor(firstNode, secondNode, this._root);
+ };
+
+ /**
+ * Obtains the lowest common ancestor for the given nodes.
+ *
+ * @private
+ * @param {Node} firstNode First node to be considered when checking
+ * for ancestor.
+ * @param {Node} secondNode Second node to be considered when checking
+ * for ancestor.
+ * @param {Node} current Current node.
+ * @returns {Node} The lowest common ancestor of the two nodes or null.
+ */
+ exports.SplayTree.prototype._lowestCommonAncestor =
+ function (firstNode, secondNode, current) {
+ var firstNodeInLeft = this._existsInSubtree(firstNode, current._left);
+ var secondNodeInLeft = this._existsInSubtree(secondNode, current._left);
+ var firstNodeInRight = this._existsInSubtree(firstNode, current._right);
+ var secondNodeInRight = this._existsInSubtree(secondNode, current._right);
+ if ((firstNodeInLeft && secondNodeInRight) ||
+ (firstNodeInRight && secondNodeInLeft)) {
+ return current;
+ }
+ if (secondNodeInLeft && firstNodeInLeft) {
+ return this._lowestCommonAncestor(firstNode, secondNode, current._left);
+ }
+ if (secondNodeInRight && secondNodeInLeft) {
+ return this._lowestCommonAncestor(firstNode, secondNode,
+ current._right);
+ }
+ return null;
+ };
+
+ /**
+ * Checks if a given node exists in a subtree.
+ *
+ * @private
+ * @param {Node} node Node to check for.
+ * @param {Node} root Root node of a given subtree.
+ * @returns {Node} The lowest common ancestor of the two nodes or null.
+ */
+ exports.SplayTree.prototype._existsInSubtree = function (node, root) {
+ if (!root) {
+ return false;
+ }
+ if (node === root.value) {
+ return true;
+ }
+ return this._existsInSubtree(node, root._left) ||
+ this._existsInSubtree(node, root._right);
+ };
+
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/data-structures/suffix-tree.js b/src/data-structures/suffix-tree.js
new file mode 100644
index 00000000..e6b917c4
--- /dev/null
+++ b/src/data-structures/suffix-tree.js
@@ -0,0 +1,72 @@
+(function (exports) {
+ 'use strict';
+
+ function Node(val) {
+ this.value = val;
+ this.nodes = {};
+ }
+
+ function SuffixTree() {
+ this.root = new Node();
+ }
+
+ SuffixTree.prototype.addNode = (function () {
+
+ function maxPrefix(a, b) {
+ var res = [];
+ for (var i = 0; i < Math.min(a.length, b.length); i += 1) {
+ if (a[i] === b[i]) {
+ res.push(a[i]);
+ } else {
+ return '';
+ }
+ }
+ return res.join('');
+ }
+
+ function addNode(suffix, current) {
+ // Empty string already exists in the suffix tree
+ if (!suffix) {
+ return;
+ }
+ // The suffix is already inside the tree
+ if (current.value === suffix) {
+ return;
+ }
+ // Insert recursively
+ if (current.nodes[suffix[0]]) {
+ return addNode(suffix.substr(1, suffix.length),
+ current.nodes[suffix[0]]);
+ }
+ // Find the maximum prefix and split the current node if prefix exists
+ var prefix = maxPrefix(current.value, suffix);
+ if (prefix.length) {
+ var temp = current.value;
+ var suffixSuffix = suffix.substr(prefix.length, suffix.length);
+ var currentSuffix = temp.substr(prefix.length, temp.length);
+ current.value = prefix;
+ addNode(currentSuffix, current);
+ addNode(suffixSuffix, current);
+ // If prefix doesn't exists add new child node
+ } else {
+ current.nodes[suffix[0]] = new Node(suffix);
+ }
+ }
+
+ return function (suffix) {
+ addNode(suffix, this.root);
+ };
+ }());
+
+ // O(n^2) or even O(n^3) because of maxPrefix
+ SuffixTree.prototype.build = function (string) {
+ this.root.value = string;
+ for (var i = 1; i < string.length; i += 1) {
+ this.addNode(string.substr(i, string.length));
+ }
+ };
+
+ exports.Node = Node;
+ exports.SuffixTree = SuffixTree;
+
+}(typeof exports === 'undefined' ? window : exports));
diff --git a/src/data-structures/vertex.js b/src/data-structures/vertex.js
new file mode 100644
index 00000000..93afa98e
--- /dev/null
+++ b/src/data-structures/vertex.js
@@ -0,0 +1,16 @@
+(function (exports) {
+ 'use strict';
+
+ /**
+ * Graph vertex.
+ *
+ * @constructor
+ * @public
+ * @param {Number} id Id of the vertex.
+ * @module data-structures/vertex
+ */
+ exports.Vertex = function (id) {
+ this.id = id;
+ };
+
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/graphics/bezier.js b/src/graphics/bezier.js
new file mode 100644
index 00000000..1e0ccf80
--- /dev/null
+++ b/src/graphics/bezier.js
@@ -0,0 +1,19 @@
+(function (exports) {
+ 'use strict';
+
+ function linearBezier(p0, p1, t) {
+ return p0 + t * (p1 - p0);
+ }
+
+ function quadraticBezier(p0, p1, p2, t) {
+ return linearBezier(linearBezier(p0, p1, t), linearBezier(p1, p2, t), t);
+ }
+
+ function cubicBezier(p0, p1, p2, p3, t) {
+ return linearBezier(quadraticBezier(p0, p1, p2, t), quadraticBezier(p1, p2, p3, t), t);
+ }
+
+ exports.linearBezier = linearBezier;
+ exports.quadraticBezier = quadraticBezier;
+ exports.cubicBezier = cubicBezier;
+})(typeof exports === 'undefined' ? window : exports);
diff --git a/src/graphics/bresenham-line-drawing.js b/src/graphics/bresenham-line-drawing.js
index 3e4fa39a..73267f32 100644
--- a/src/graphics/bresenham-line-drawing.js
+++ b/src/graphics/bresenham-line-drawing.js
@@ -1,38 +1,47 @@
-/**
- * Bresenham's line drawing algorithm.
- * It has complexity O(n)
- * @param {number} x1 The first coordinate of the beginning of the line
- * @param {number} y1 The second coordinate of the beginning of the line
- * @param {number} x2 The first coordinate of the end of the line
- * @param {number} y2 The second coordinate of the end of the line
- */
-function drawLine(x1, y1, x2, y2) {
- var dx = Math.abs(x2 - x1),
- dy = Math.abs(y2 - y1),
- cx = (x1 < x2) ? 1 : -1,
- cy = (y1 < y2) ? 1 : -1,
- error = dx - dy,
- doubledError;
-
- while (x1 !== x2 || y1 !== y2) {
- drawPoint(x1, y1);
- doubledError = error + error;
- if (doubledError > -dy) {
- error -= dy;
- x1 += cx;
- }
- if (doubledError < dx) {
- error += dx;
- y1 += cy;
+(function (exports) {
+ 'use strict';
+
+ /**
+ * Draws (prints) the given coordinates
+ * @param {number} x The first coordinate of the point
+ * @param {number} y The second coordinate of the point
+ */
+ function drawPoint(x, y) {
+ console.log(x, y);
+ }
+
+ /**
+ * Bresenham's line drawing algorithm.
+ * It has complexity O(n)
+ * @param {number} x1 The first coordinate of the beginning of the line
+ * @param {number} y1 The second coordinate of the beginning of the line
+ * @param {number} x2 The first coordinate of the end of the line
+ * @param {number} y2 The second coordinate of the end of the line
+ * @param {function} draw Optional custom drawing function.
+ */
+ function drawLine(x1, y1, x2, y2, draw) {
+ var drawPointStrategy = draw || drawPoint;
+ var dx = Math.abs(x2 - x1);
+ var dy = Math.abs(y2 - y1);
+ var cx = (x1 < x2) ? 1 : -1;
+ var cy = (y1 < y2) ? 1 : -1;
+ var error = dx - dy;
+ var doubledError;
+
+ while (x1 !== x2 || y1 !== y2) {
+ drawPointStrategy(x1, y1);
+ doubledError = error + error;
+ if (doubledError > -dy) {
+ error -= dy;
+ x1 += cx;
+ }
+ if (doubledError < dx) {
+ error += dx;
+ y1 += cy;
+ }
}
}
-}
-/**
- * Draws (prints) the given coordinates
- * @param {number} x The first coordinate of the point
- * @param {number} y The second coordinate of the point
- */
-function drawPoint(x, y) {
- console.log(x, y);
-}
\ No newline at end of file
+ exports.drawLine = drawLine;
+
+}(typeof exports === 'undefined' ? window : exports));
diff --git a/src/graphics/graham.js b/src/graphics/graham.js
new file mode 100644
index 00000000..aa1d9862
--- /dev/null
+++ b/src/graphics/graham.js
@@ -0,0 +1,79 @@
+(function(exports) {
+ 'use strict';
+
+ const slope = (p, a) => (a.y - p.y) / (a.x - p.x);
+
+ const dist = (a, b) => Math.sqrt((b.y - a.y) * (b.y - a.y) + (b.x - a.x) * (b.x - a.x));
+
+ const sort = (p, memo, a, b) => {
+ const sa = slope(p, a);
+ const sb = slope(p, b);
+ [[sa, a], [sb, b]].forEach(e => {
+ const el = memo.get(e[0]);
+ if (!el || dist(p, el) < dist(p, e[1])) {
+ memo.set(e[0], e[1]);
+ }
+ });
+ return sa - sb;
+ };
+
+ const ccw = (a, b, c) => (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
+
+ /**
+ * Graham's algorithm for calculating the convex hull.
+ *
+ * @public
+ * @module graphics/graham
+ * @param {Array} all
+ * @returns {Array}
+ *
+ * @example
+ * const points = [
+ * { x: 0, y: 0 },
+ * { x: 1, y: 0 },
+ * { x: 0, y: 1 },
+ * { x: 0.15, y: 0.15 },
+ * { x: 0.5, y: 0.5 }
+ * ];
+ * const list = convexHull(points);
+ * // [{ x: 0, y: 0 },
+ * // { x: 1, y: 0 },
+ * // { x: 0.5, y: 0.5 },
+ * // { x: 0, y: 1 }]
+ */
+ const convexHull = all => {
+ if (!all.length) {
+ return [];
+ }
+
+ const p = all.reduce((a, c) => {
+ if (a.y < c.y) {
+ return a;
+ }
+ if (a.y > c.y) {
+ return c;
+ }
+ if (a.x < c.x) {
+ return a;
+ }
+ return c;
+ });
+
+ const memo = new Map();
+ const stack = [];
+
+ all
+ .sort(sort.bind(null, p, memo))
+ .filter(c => memo.get(slope(p, c)) === c)
+ .forEach(p => {
+ while (stack.length > 1 && ccw(stack[stack.length - 2], stack[stack.length - 1], p) < 0) {
+ stack.pop();
+ }
+ stack.push(p);
+ });
+
+ return stack;
+ };
+
+ exports.convexHull = convexHull;
+})(typeof exports === 'undefined' ? window : exports);
diff --git a/src/graphs/others/tarjan-connected-components.js b/src/graphs/others/tarjan-connected-components.js
new file mode 100644
index 00000000..c131f6dc
--- /dev/null
+++ b/src/graphs/others/tarjan-connected-components.js
@@ -0,0 +1,75 @@
+(function (exports) {
+ 'use strict';
+
+ /**
+ * Tarjan's algorithm for finding the connected components in a graph.
+ * Time complexity: O(|E| + |V|) where E is a number of edges and |V|
+ * is the number of nodes.
+ *
+ * @public
+ * @module graphs/others/tarjan-connected-components
+ * @param {Array} graph Adjacency list, which represents the graph.
+ * @returns {Array} Connected components.
+ *
+ * @example
+ * var tarjanConnectedComponents =
+ * require('path-to-algorithms/src/graphs/' +
+ * 'others/tarjan-connected-components').tarjanConnectedComponents;
+ * var graph = {
+ * v1: ['v2', 'v5'],
+ * v2: [],
+ * v3: ['v1', 'v2', 'v4', 'v5'],
+ * v4: [],
+ * v5: []
+ * };
+ * var vertices = topsort(graph); // ['v3', 'v4', 'v1', 'v5', 'v2']
+ */
+ function tarjanConnectedComponents(graph) {
+ graph = graph || {};
+ const indexes = {};
+ const lowIndexes = {};
+ const onStack = {};
+ const result = [];
+ const stack = [];
+ var index = 1;
+
+ const connectedComponent = function (node) {
+ stack.push(node);
+ onStack[node] = true;
+ indexes[node] = index;
+ lowIndexes[node] = index;
+ index += 1;
+ graph[node].forEach(function (n) {
+ if (indexes[n] === undefined) {
+ connectedComponent(n);
+ lowIndexes[node] = Math.min(lowIndexes[n], lowIndexes[node]);
+ } else if (onStack[n]) {
+ lowIndexes[node] = Math.min(lowIndexes[node], indexes[n]);
+ }
+ });
+ // This is a "root" node
+ const cc = [];
+ if (indexes[node] === lowIndexes[node]) {
+ var current;
+ do {
+ current = stack.pop();
+ onStack[current] = false;
+ cc.push(current);
+ } while (stack.length > 0 && node !== current);
+ result.push(cc);
+ }
+ };
+
+ Object.keys(graph)
+ .forEach(function (n) {
+ if (!indexes[n]) {
+ connectedComponent(n);
+ }
+ });
+
+ return result;
+ }
+
+ exports.tarjanConnectedComponents = tarjanConnectedComponents;
+
+}(typeof exports === 'undefined' ? window : exports));
diff --git a/src/graphs/others/topological-sort.js b/src/graphs/others/topological-sort.js
new file mode 100644
index 00000000..f32ee48a
--- /dev/null
+++ b/src/graphs/others/topological-sort.js
@@ -0,0 +1,61 @@
+(function (exports) {
+ 'use strict';
+
+ var topologicalSort = (function () {
+
+ function topologicalSortHelper(node, visited, temp, graph, result) {
+ temp[node] = true;
+ var neighbors = graph[node];
+ for (var i = 0; i < neighbors.length; i += 1) {
+ var n = neighbors[i];
+ if (temp[n]) {
+ throw new Error('The graph is not a DAG');
+ }
+ if (!visited[n]) {
+ topologicalSortHelper(n, visited, temp, graph, result);
+ }
+ }
+ temp[node] = false;
+ visited[node] = true;
+ result.push(node);
+ }
+
+ /**
+ * Topological sort algorithm of a directed acyclic graph.
+ * Time complexity: O(|E| + |V|) where E is a number of edges
+ * and |V| is the number of nodes.
+ *
+ * @public
+ * @module graphs/others/topological-sort
+ * @param {Array} graph Adjacency list, which represents the graph.
+ * @returns {Array} Ordered vertices.
+ *
+ * @example
+ * var topsort =
+ * require('path-to-algorithms/src/graphs/' +
+ * 'others/topological-sort').topologicalSort;
+ * var graph = {
+ * v1: ['v2', 'v5'],
+ * v2: [],
+ * v3: ['v1', 'v2', 'v4', 'v5'],
+ * v4: [],
+ * v5: []
+ * };
+ * var vertices = topsort(graph); // ['v3', 'v4', 'v1', 'v5', 'v2']
+ */
+ return function (graph) {
+ var result = [];
+ var visited = [];
+ var temp = [];
+ for (var node in graph) {
+ if (!visited[node] && !temp[node]) {
+ topologicalSortHelper(node, visited, temp, graph, result);
+ }
+ }
+ return result.reverse();
+ };
+ }());
+
+ exports.topologicalSort = topologicalSort;
+
+}(typeof exports === 'undefined' ? window : exports));
diff --git a/src/graphs/searching/bfs.js b/src/graphs/searching/bfs.js
index 6b40f3e0..9b3e1cad 100644
--- a/src/graphs/searching/bfs.js
+++ b/src/graphs/searching/bfs.js
@@ -1,135 +1,64 @@
(function (exports) {
-
'use strict';
- /**
- * Breadth-first search algorithm for matrix representation of graph.
- * The algorithm finds whether there's a path between two given nodes.
- */
- var breadthFirstSearch = (function () {
-
- var visited = [],
- queue = [],
- target,
- graph;
-
- /**
- * Initializes the algorithm
- *
- * @private
- * @param {array} inputGraph The input matrix of the graph
- * @param {array} destination The destination
- */
- function init(inputGraph, destination) {
- graph = inputGraph;
- target = destination;
- queue = [];
- visited = {};
- }
-
- /**
- * Adds a valid node to the queue
- * @param {array} node Node to be added to the queue
- */
- function addNode(node) {
- if (visited[node] ||
- node[0] < 0 || node[1] < 0 ||
- node[0] >= graph.length || node[1] >= graph[0].length ||
- !graph[node[0]][node[1]]) {
- return;
- }
- queue.push(node);
- }
-
- /**
- * Process given node
- *
- * @param {array} destination The destionation, which should be reached
- * @param {array} current The current node
- */
- function processNode(destination, current) {
- if (destination.toString() === current.toString()) {
- return true;
- } else {
- addNode([current[0], current[1] + 1]);
- addNode([current[0], current[1] - 1]);
- addNode([current[0] + 1, current[1]]);
- addNode([current[0] - 1, current[1]]);
- return false;
- }
- }
+ var bfs = (function () {
- /**
- * Validates the params
- *
- * @param {array} graph A matrix representation of the graph
- * @param {array} source The source node
- * @param {array} destination The destination node
- */
- function validateParams(graph, source, destination) {
- if (!graph) {
- throw new Error('The graph should be represented as a matrix');
+ function buildPath(parents, targetNode) {
+ var result = [targetNode];
+ while (parents[targetNode] !== null) {
+ targetNode = parents[targetNode];
+ result.push(targetNode);
}
- if (graph[0] === undefined) {
- throw new Error('The graph should be represented as ' +
- 'a matrix, with size at least 1x1');
- }
- var width = graph[0].length;
- for (var i = 1; i < graph.length; i += 1) {
- if (graph[i].length !== width) {
- throw new Error('The graph should be represented as a matrix');
- }
- }
- source.concat(destination).filter(function (c, i) {
- if (c < 0) {
- throw new Error('The source and destination coordinates ' +
- 'should be above zero');
- }
- if (i % 2 === 0) {
- if (c >= graph.length) {
- throw new Error('The source and destination coordinates ' +
- 'should not be above graph\'s size');
- }
- } else {
- if (c >= graph[0].length) {
- throw new Error('The source and destination coordinates ' +
- 'should not be above graph\'s size');
- }
- }
- });
- return true;
+ return result.reverse();
}
/**
- * Finds whether there's a path between a given start node
- * to given destination
+ * Breath-First graph searching algorithm.
+ * Returns the shortest path between startNode and targetNode.
+ * Time complexity: O(|V|^2).
*
* @public
- * @param {array} graph A matrix representation of the graph
- * @param {array} source The source node
- * @param {array} destination The destination node
- * @returns {boolean} true/false depending whether there's
- * a path between the nodes
+ * @module graphs/searching/bfs
+ * @param {Array} graph Adjacency matrix, which represents the graph.
+ * @param {Number} startNode Start node.
+ * @param {Number} targetNode Target, which should be reached.
+ * @returns {Array} Shortest path from startNode to targetNode.
+ *
+ * @example
+ * var bfs = require('path-to-algorithms/src/graphs/searching/bfs').bfs;
+ * var graph = [[1, 1, 0, 0, 1, 0],
+ * [1, 0, 1, 0, 1, 0],
+ * [0, 1, 0, 1, 0, 0],
+ * [0, 0, 1, 0, 1, 1],
+ * [1, 1, 0, 1, 0, 0],
+ * [0, 0, 0, 1, 0, 0]];
+ * var shortestPath = bfs(graph, 1, 5); // [1, 2, 3, 5]
*/
- return function (graph, source, destination) {
- validateParams(graph, source, destination);
- init(graph, destination);
+ return function (graph, startNode, targetNode) {
+ var parents = [];
+ var queue = [];
+ var visited = [];
var current;
- queue.push(source);
- while (queue.length > 0) {
+ queue.push(startNode);
+ parents[startNode] = null;
+ visited[startNode] = true;
+ while (queue.length) {
current = queue.shift();
- visited[current] = true;
- if (graph[current[0]][current[1]]) {
- var result = processNode(destination, current);
- if (result) {
- return true;
+ if (current === targetNode) {
+ return buildPath(parents, targetNode);
+ }
+ for (var i = 0; i < graph.length; i += 1) {
+ if (i !== current && graph[current][i] && !visited[i]) {
+ parents[i] = current;
+ visited[i] = true;
+ queue.push(i);
}
}
}
- return false;
+ return null;
};
}());
- exports.breadthFirstSearch = breadthFirstSearch;
+ exports.bfs = bfs;
-}(typeof exports === 'undefined' ? window : exports));
+}((typeof window === 'undefined') ? module.exports : window));
diff --git a/src/graphs/searching/dfs.js b/src/graphs/searching/dfs.js
index ce3a37f9..82f0caf3 100644
--- a/src/graphs/searching/dfs.js
+++ b/src/graphs/searching/dfs.js
@@ -1,129 +1,56 @@
-'use strict';
-
-/* * * * * * * * * * * * * * * * * *
-
- Sample graph
-
-var graph = [[1,0,1,0,0,0],
- [0,1,0,1,0,0],
- [1,0,1,0,1,0],
- [0,1,0,1,1,0],
- [0,0,1,1,1,1],
- [0,0,0,0,1,1]];
-* * * * * * * * * * * * * * * * * */
-
(function (exports) {
- /**
- * Depth-first search algorithm for matrix representation of graph.
- * The algorithm finds whether there's a path between two given nodes.
- */
- var depthFirstSearch = (function () {
+ 'use strict';
- var visited = [],
- target,
- graph;
+ var dfs = (function () {
- /**
- * Returns whether the destination could be reached
- * from given node
- *
- * @private
- * @param {number} current Current node
- * @returns {boolean} True/false depending whether
- * the destination can be reached from the current node
- */
- function dfs(current) {
- if (visited[current] ||
- current[0] < 0 || current[1] < 0 ||
- current[0] >= graph.length || current[1] >= graph[0].length ||
- !graph[current[0]][current[1]]) {
- return false;
- }
- if (current[0] === target[0] &&
- current[1] === target[1]) {
- return true;
- }
+ function hasPath(graph, current, goal) {
+ var stack = [];
+ var visited = [];
+ var node;
+ stack.push(current);
visited[current] = true;
- return dfs([current[0] + 1, current[1]]) ||
- dfs([current[0] - 1, current[1]]) ||
- dfs([current[0], current[1] + 1]) ||
- dfs([current[0], current[1] - 1]);
- }
-
- /**
- * Initializes the algorithm
- *
- * @private
- * @param {array} inputGraph The input matrix of the graph
- * @param {number} destination The destination
- */
- function init(inputGraph, destination) {
- graph = inputGraph;
- target = destination;
- visited = {};
- }
-
- /**
- * Validates the params
- *
- * @param {array} graph A matrix representation of the graph
- * @param {array} source The source node
- * @param {array} destination The destination node
- */
- function validateParams(graph, source, destination) {
- if (!graph) {
- throw new Error('The graph should be represented as a matrix');
- }
- if (graph[0] === undefined) {
- throw new Error('The graph should be represented as ' +
- 'a matrix, with size at least 1x1');
- }
- var width = graph[0].length;
- for (var i = 1; i < graph.length; i += 1) {
- if (graph[i].length !== width) {
- throw new Error('The graph should be represented as a matrix');
+ while (stack.length) {
+ node = stack.pop();
+ if (node === goal) {
+ return true;
}
- }
- source.concat(destination).filter(function (c, i) {
- if (c < 0) {
- throw new Error('The source and destination coordinates ' +
- 'should be above zero');
- }
- if (i % 2 === 0) {
- if (c >= graph.length) {
- throw new Error('The source and destination coordinates ' +
- 'should not be above graph\'s size');
- }
- } else {
- if (c >= graph[0].length) {
- throw new Error('The source and destination coordinates ' +
- 'should not be above graph\'s size');
+ for (var i = 0; i < graph[node].length; i += 1) {
+ if (graph[node][i] && !visited[i]) {
+ stack.push(i);
+ visited[i] = true;
}
}
- });
- return true;
+ }
+ return false;
}
/**
- * Finds whether there's a path between a given start node
- * to given destination
+ * Depth-First graph searching algorithm.
+ * Returns whether there's a path between two nodes in a graph.
+ * Time complexity: O(|V|^2).
*
+ * @module graphs/searching/dfs
* @public
- * @param {array} graph A matrix representation of the graph
- * @param {number} source The source node
- * @param {number} destination The destination node
- * @returns {boolean} true/false depending
- * whether there's a path between the nodes
+ * @param {Array} graph Adjacency matrix, which represents the graph.
+ * @param {Number} start Start node.
+ * @param {Number} goal Target node.
+ * @return {Boolean} Returns true if path between two nodes exists.
+ *
+ * @example
+ * var dfs = require('../src/graphs/searching/dfs').dfs;
+ * var graph = [[1, 1, 0, 0, 1, 0],
+ * [1, 0, 1, 0, 1, 0],
+ * [0, 1, 0, 1, 0, 0],
+ * [0, 0, 1, 0, 1, 1],
+ * [1, 1, 0, 1, 0, 0],
+ * [0, 0, 0, 1, 0, 0]];
+ * var pathExists = dfs(graph, 1, 5); // true
*/
- return function (graph, source, destination) {
- validateParams(graph, source, destination);
- init(graph, destination);
- return dfs(source);
+ return function (graph, start, goal) {
+ return hasPath(graph, start, goal);
};
-
-
}());
- exports.depthFirstSearch = depthFirstSearch;
+ exports.dfs = dfs;
-}(typeof exports === 'undefined' ? window : exports));
\ No newline at end of file
+}(typeof exports === 'undefined' ? window : exports));
diff --git a/src/graphs/searching/quickfind.js b/src/graphs/searching/quickfind.js
deleted file mode 100644
index 373c62f2..00000000
--- a/src/graphs/searching/quickfind.js
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * Checks whether there is a path between two nodes.
- * The initialization is O(n).
- *
- * @constructor
- * @param {numner} size The count of the nodes
- */
-function QuickFind(size) {
- this._ids = [];
- for (var i = 0; i < size; i += 1)
- this._ids[i] = i;
-}
-
-/**
- * Connects two nodes - p and q.
- * Complexity O(n).
- *
- * @param {number} p The first node
- * @param {number} q The second node
- */
-QuickFind.prototype.union = function (p, q) {
- var size = this._ids.length,
- pval = this._ids[p],
- qval = this._ids[q];
- for (var i = 0; i < size; i += 1) {
- if (this._ids[i] === qval)
- this._ids[i] = pval;
- }
-};
-
-/**
- * Checks whether two nodes are connected.
- * Complexity O(1).
- *
- * @param {number} p The first node
- * @param {number} q The second node
- *
- */
-QuickFind.prototype.connected = function (p, q) {
- return this._ids[p] === this._ids[q];
-};
-
-//var find = new QuickFind(10);
-//find.union(0, 1);
-//find.union(2, 1);
-//find.union(3, 4);
-//find.union(8, 9);
-//find.union(4, 8);
-//
-//console.log(find.connected(0, 9)); //expected false
-//console.log(find.connected(3, 9)); //expected true
diff --git a/src/graphs/searching/quickunion.js b/src/graphs/searching/quickunion.js
deleted file mode 100644
index 6e63e5f4..00000000
--- a/src/graphs/searching/quickunion.js
+++ /dev/null
@@ -1,61 +0,0 @@
-/**
- * Checks whether path between two nodes exists.
- * The initialization has O(n) complexity.
- *
- * @constructor
- * @param {number} n Nodes count
- *
- */
-function QuickUnion(n) {
- this._ids = [];
- for (var i = 0; i < n; i += 1) {
- this._ids[i] = i;
- }
-}
-
-/**
- * Finds the root of given node.
- * Complexity O(n).
- *
- * @param {number} i The given node
- * @return {number} The root of the given node
- */
-QuickUnion.prototype._root = function (i) {
- while (i !== this._ids[i]) i = this._ids[i];
- return i;
-};
-
-/**
- * Unions two nodes.
- * Complexity O(n).
- *
- * @param {number} p The first node
- * @param {number} q The second node
- */
-QuickUnion.prototype.union = function (p, q) {
- var pRoot = this._root(p),
- qRoot = this._root(q);
- this._ids[pRoot] = qRoot;
-};
-
-/**
- * Checks whether two nodes are connected.
- * Complexity O(n).
- *
- * @param {number} p The first node.
- * @param {number} q The second node.
- * @return {boolean} True/false depending on whether the nodes are connected.
- */
-QuickUnion.prototype.connected = function (p, q) {
- return this._root(p) === this._root(q);
-};
-
-//var union = new QuickUnion(10);
-//union.union(0, 1);
-//union.union(2, 1);
-//union.union(3, 4);
-//union.union(8, 9);
-//union.union(4, 8);
-//
-//console.log(union.connected(0, 9)); //expected false
-//console.log(union.connected(3, 9)); //expected true
diff --git a/src/graphs/searching/weightquickunion.js b/src/graphs/searching/weightquickunion.js
deleted file mode 100644
index 22142ff9..00000000
--- a/src/graphs/searching/weightquickunion.js
+++ /dev/null
@@ -1,74 +0,0 @@
-/**
- * Checks whether there is a path between two nodes
- * Complexity of the initialization O(n).
- *
- * @constructor
- * @param {number} n The nodes count
- */
-function QuickUnion(n) {
- this._ids = [];
- this._size = [];
- for (var i = 0; i < n; i += 1) {
- this._ids[i] = i;
- this._size[i] = 1;
- }
-}
-
-/**
- * Finds the root of given node.
- * The complexity is around O(logn)
- *
- * @param {number} i The given node
- * @return {number} The root of the node
- */
-QuickUnion.prototype._root = function (i) {
- while (i !== this._ids[i]) {
-// this._ids = this._ids[this._ids[i]]; //enables the path compression
- i = this._ids[i];
- }
- return i;
-};
-
-/**
- * Checks whether two nodes are connected.
- * Complexity O(logn)
- *
- * @param {number} p The first node
- * @param {number} q The second node
- * @return {boolean} True/false depending on whether the nodes are connected
- */
-QuickUnion.prototype.connected = function (p, q) {
- return this._root(p) === this._root(q);
-};
-
-/**
- * Unions two nodes.
- * Complexity O(logn)
- *
- * @param {number} p The first node
- * @param {number} q The second node
- */
-QuickUnion.prototype.union = function (p, q) {
- var pf = this._root(p);
- var qf = this._root(q);
- if (pf == qf) return; // already linked
- var psz = this._size[qf];
- var qsz = this._size[pf];
- if (psz < qsz) {
- this._ids[pf] = qf;
- this._size[qf] += psz;
- } else {
- this._ids[qf] = pf;
- this._size[pf] += qsz;
- }
-};
-
-//var union = new QuickUnion(10);
-//union.union(0, 1);
-//union.union(2, 1);
-//union.union(3, 4);
-//union.union(8, 9);
-//union.union(4, 8);
-//
-//console.log(union.connected(0, 9)); //expected false
-//console.log(union.connected(3, 9)); //expected true
diff --git a/src/graphs/shortest-path/bellman-ford.js b/src/graphs/shortest-path/bellman-ford.js
new file mode 100644
index 00000000..d7fcf45b
--- /dev/null
+++ b/src/graphs/shortest-path/bellman-ford.js
@@ -0,0 +1,90 @@
+/**
+ * Bellman–Ford algorithm computes shortest paths from a single source
+ * vertex to all of the other vertices in a weighted digraph
+ * (negative weights allowed).
+ * Time complexity: O(|V||E|) where V and E are the number of
+ * vertices and edges respectively.
+ *
+ * @example
+ *
+ * var BellmanFord =
+ * require('path-to-algorithms/src/graphs/shortest-path/bellman-ford');
+ * var Edge = BellmanFord.Edge;
+ * var bellmanFord = BellmanFord.bellmanFord;
+ * var edges = [];
+ * var vertexes = [
+ * new Vertex(0),
+ * new Vertex(1),
+ * new Vertex(2),
+ * new Vertex(3),
+ * new Vertex(4)
+ * ];
+ *
+ * edges.push(new Edge(0, 1, -1));
+ * edges.push(new Edge(0, 2, 4));
+ * edges.push(new Edge(1, 2, 3));
+ * edges.push(new Edge(1, 3, 2));
+ * edges.push(new Edge(3, 1, 1));
+ * edges.push(new Edge(4, 3, -3));
+ * edges.push(new Edge(1, 4, 2));
+ * edges.push(new Edge(3, 2, 5));
+ *
+ * // {
+ * // parents: { '0': null, '1': 0, '2': 1, '3': 4, '4': 1 },
+ * // distances: { '0': 0, '1': -1, '2': 2, '3': -2, '4': 1 }
+ * // }
+ * var pathInfo = bellmanFord(vertexes, edges, 0);
+ *
+ * @module graphs/shortest-path/bellman-ford
+ */
+(function (exports) {
+
+ 'use strict';
+
+ exports.Vertex = require('../../data-structures/vertex').Vertex;
+ exports.Edge = require('../../data-structures/edge').Edge;
+
+ /**
+ * Computes shortest paths from a single source
+ * vertex to all of the other vertices.
+ *
+ * @public
+ * @param {Array} vertexes Vertices of the graph.
+ * @param {Array} edges Edges of the graph.
+ * @param {Number} source Start vertex.
+ * @returns {Object} Object with two arrays (parents and distances)
+ * with shortest-path information or undefined if the graph
+ * has a negative cycle.
+ */
+ exports.bellmanFord = function (vertexes, edges, source) {
+ var distances = {};
+ var parents = {};
+ var c;
+ if (source) {
+ for (var i = 0; i < vertexes.length; i += 1) {
+ distances[vertexes[i].id] = Infinity;
+ parents[vertexes[i].id] = null;
+ }
+ distances[source.id] = 0;
+ for (i = 0; i < vertexes.length - 1; i += 1) {
+ for (var j = 0; j < edges.length; j += 1) {
+ c = edges[j];
+ if (distances[c.from.id] + c.distance < distances[c.to.id]) {
+ distances[c.to.id] = distances[c.from.id] + c.distance;
+ parents[c.to.id] = c.from.id;
+ }
+ }
+ }
+
+ for (i = 0; i < edges.length; i += 1) {
+ c = edges[i];
+ if (distances[c.from.id] + c.distance < distances[c.to.id]) {
+ return undefined;
+ }
+ }
+ }
+
+ return { parents: parents, distances: distances };
+ };
+
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/graphs/shortest-path/dijkstra.js b/src/graphs/shortest-path/dijkstra.js
index 2a83d404..ea4a38e0 100644
--- a/src/graphs/shortest-path/dijkstra.js
+++ b/src/graphs/shortest-path/dijkstra.js
@@ -1,110 +1,124 @@
-/***********************************************
- A sample distance matrix
-
-var graph = [[NaN, 7, 9, NaN, NaN, 16],
- [7, NaN, 10, 15, NaN, NaN],
- [9, 10, NaN, 11, NaN, 2],
- [NaN, 15, 11, NaN, 6, NaN],
- [NaN, NaN, NaN, 6, NaN, 9],
- [16, NaN, 2, NaN, 9, NaN]];
-***********************************************/
+(function (exports) {
+ 'use strict';
+ var dijkstra = (function () {
-/**
- * Dijstra's shortest path algorithm.
- * For the implementation is not used the most suitable data structure (Fibonacci heap)
- * but the binary heap gives also good results. The implementation bellow finds
- * the minimum distance between two given nodes using a distance matrix.
- */
-var dijstra = function () {
-
- var Heap = require('../../data-structures/heap.js').Heap,
- current,
- visited,
- distance,
- unvisited;
-
+ var Heap = require('../../data-structures/heap.js').Heap;
+ var current;
+ var visited;
+ var distance;
+ var unvisited;
/**
- * Creates a new node instance
+ * Creates a new node instance.
*
* @constructor
* @private
- * @param {number} id The id of the node
- * @param {number} distance The distance from the beginning
+ * @param {Number} id Id of the node.
+ * @param {Number} distance Distance from the beginning.
*/
function Node(id, distance) {
- this.node = id;
- this.distance = distance;
+ this.node = id;
+ this.distance = distance;
}
/**
* Compares the distances between two nodes.
*
* @private
- * @param {object} a A node
- * @param {object} b A graph node
- * @returns {number} The
+ * @param {Node} a 1st node.
+ * @param {Node} b 2nd node.
+ * @returns {number} diff between node distances.
*/
function compareNodesDistance(a, b) {
- return b.distance - a.distance;
+ return b.distance - a.distance;
}
/**
- * Initialize all variables used for the algorithm
+ * Initialize all variables used for the algorithm.
*
* @private
- * @param {number} src A start node
+ * @param {number} src Start node.
+ * @param {Array} graph A distance matrix of the graph.
*/
- function init(src) {
- var currentTemp;
- current = {};
- visited = [];
- distance = [];
- unvisited = new Heap(compareNodesDistance);
- for (var i = 0; i < graph.length; i += 1) {
- currentTemp = new Node();
- if (src === i) {
- currentTemp.distance = 0;
- } else {
- currentTemp.distance = Infinity;
- }
- currentTemp.node = i;
- visited[i] = false;
- distance[i] = currentTemp;
- unvisited.add(currentTemp);
+ function init(src, graph) {
+ var currentTemp;
+ current = {};
+ visited = [];
+ distance = [];
+ unvisited = new Heap(compareNodesDistance);
+ for (var i = 0; i < graph.length; i += 1) {
+ currentTemp = new Node();
+ if (src === i) {
+ currentTemp.distance = 0;
+ } else {
+ currentTemp.distance = Infinity;
}
- current.node = src;
- current.distance = 0;
+ currentTemp.node = i;
+ visited[i] = false;
+ distance[i] = currentTemp;
+ unvisited.add(currentTemp);
+ }
+ current.node = src;
+ current.distance = 0;
}
/**
- * Dijkstra's shortest path algorithm
+ * Dijkstra's shortest path algorithm. Finds the minimum
+ * distance between two given nodes using a distance matrix.
+ * For the implementation is not used the most suitable data structure
+ * (Fibonacci heap) but the Binary heap gives also good results.
+ *
+ * Time complexity: O(|E|+|V|log(|V|)) where V and E are the number of
+ * vertices and edges respectively.
*
* @public
- * @param {number} src Source node
- * @param {number} dest Destination node
- * @param {array} graph A distance matrix of the graph
- * @returns {number} The shortest distance between the nodes
+ * @module graphs/shortest-path/dijkstra
+ * @param {Number} src Source node.
+ * @param {Number} dest Destination node.
+ * @param {Array} graph A distance matrix of the graph.
+ * @returns {Number} The shortest distance between two nodes.
+ *
+ * @example
+ * var dijkstra =
+ * require('path-to-algorithms/src/graphs/shortest-path/dijkstra').dijkstra;
+ * var distMatrix =
+ * [[Infinity, 7, 9, Infinity, Infinity, 16],
+ * [7, Infinity, 10, 15, Infinity, Infinity],
+ * [9, 10, Infinity, 11, Infinity, 2],
+ * [Infinity, 15, 11, Infinity, 6, Infinity],
+ * [Infinity, Infinity, Infinity, 6, Infinity, 9],
+ * [16, Infinity, 2, Infinity, 9, Infinity]];
+ * var shortestDist = dijkstra(0, 2, distMatrix); // 9
*/
return function (src, dest, graph) {
- var tempDistance = 0;
- init(src);
- while (current.node != dest && current.distance != Infinity) {
- for (var i = 0; i < graph.length; i += 1) {
- if (current.node !== i && //if it's not the current node
- !visited[i] && //and if we haven't visited this node
- !isNaN(graph[i][current.node])) { //and this node is sibling of the current...
+ var tempDistance = 0;
+ init(src, graph);
+ while (current.node !== dest && isFinite(current.distance)) {
+ for (var i = 0; i < graph.length; i += 1) {
+ if (current.node !== i && //if it's not the current node
+ !visited[i] && //and if we haven't visited this node
+ //and this node is sibling of the current...
+ Number.isFinite(graph[i][current.node])) {
- tempDistance = current.distance + graph[i][current.node];
- if (tempDistance < distance[i].distance) {
- distance[i].distance = tempDistance;
- }
- }
+ tempDistance = current.distance + graph[i][current.node];
+ if (tempDistance < distance[i].distance) {
+ distance[i].distance = tempDistance;
+ unvisited.update(current);
}
- visited[current.node] = true;
- current = unvisited.extract();
+ }
}
+ visited[current.node] = true;
+ current = unvisited.extract();
+ }
+ if (distance[dest]) {
return distance[dest].distance;
+ }
+ return Infinity;
};
-}();
+
+ })();
+
+ exports.dijkstra = dijkstra;
+
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/graphs/shortest-path/floyd-warshall.js b/src/graphs/shortest-path/floyd-warshall.js
new file mode 100644
index 00000000..6c25b804
--- /dev/null
+++ b/src/graphs/shortest-path/floyd-warshall.js
@@ -0,0 +1,84 @@
+(function (exports) {
+ 'use strict';
+
+ var floydWarshall = (function () {
+
+ /**
+ * Matrix used for the algorithm.
+ */
+ var dist;
+
+ /**
+ * Initialize the distance matrix.
+ *
+ * @private
+ * @param {Array} graph Distance matrix of the array.
+ * @return {Array} Distance matrix used for the algorithm.
+ */
+ function init(graph) {
+ var dist = [];
+ var size = graph.length;
+ for (var i = 0; i < size; i += 1) {
+ dist[i] = [];
+ for (var j = 0; j < size; j += 1) {
+ if (i === j) {
+ dist[i][j] = 0;
+ } else if (!isFinite(graph[i][j])) {
+ dist[i][j] = Infinity;
+ } else {
+ dist[i][j] = graph[i][j];
+ }
+ }
+ }
+ return dist;
+ }
+
+ /**
+ * Floyd-Warshall algorithm. Finds the shortest path between
+ * each two vertices.
+ * Complexity: O(|V|^3) where V is the number of vertices.
+ *
+ * @public
+ * @module graphs/shortest-path/floyd-warshall
+ * @param {Array} graph A distance matrix of the graph.
+ * @return {Array} Array which contains the shortest
+ * distance between each two vertices.
+ *
+ * @example
+ * var floydWarshall =
+ * require('path-to-algorithms/src/graphs/shortest-path/floyd-warshall').floydWarshall;
+ * var distMatrix =
+ * [[Infinity, 7, 9, Infinity, Infinity, 16],
+ * [7, Infinity, 10, 15, Infinity, Infinity],
+ * [9, 10, Infinity, 11, Infinity, 2],
+ * [Infinity, 15, 11, Infinity, 6, Infinity],
+ * [Infinity, Infinity, Infinity, 6, Infinity, 9],
+ * [16, Infinity, 2, Infinity, 9, Infinity]];
+ *
+ * // [ [ 0, 7, 9, 20, 20, 11 ],
+ * // [ 7, 0, 10, 15, 21, 12 ],
+ * // [ 9, 10, 0, 11, 11, 2 ],
+ * // [ 20, 15, 11, 0, 6, 13 ],
+ * // [ 20, 21, 11, 6, 0, 9 ],
+ * // [ 11, 12, 2, 13, 9, 0 ] ]
+ * var shortestDists = floydWarshall(distMatrix);
+ */
+ return function (graph) {
+ dist = init(graph);
+ var size = graph.length;
+ for (var k = 0; k < size; k += 1) {
+ for (var i = 0; i < size; i += 1) {
+ for (var j = 0; j < size; j += 1) {
+ if (dist[i][j] > dist[i][k] + dist[k][j]) {
+ dist[i][j] = dist[i][k] + dist[k][j];
+ }
+ }
+ }
+ }
+ return dist;
+ };
+ }());
+
+ exports.floydWarshall = floydWarshall;
+
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/graphs/shortest-path/floyd.js b/src/graphs/shortest-path/floyd.js
deleted file mode 100644
index c723aeb4..00000000
--- a/src/graphs/shortest-path/floyd.js
+++ /dev/null
@@ -1,74 +0,0 @@
-/* * * * * * * * * * * * * * * * * * * * * * * *
-
- A sample distance matrix
-
-var graph = [[NaN, 7, 9, NaN, NaN, 16],
- [7, NaN, 10, 15, NaN, NaN],
- [9, 10, NaN, 11, NaN, 2],
- [NaN, 15, 11, NaN, 6, NaN],
- [NaN, NaN, NaN, 6, NaN, 9],
- [16, NaN, 2, NaN, 9, NaN]];
-
-* * * * * * * * * * * * * * * * * * * * * * * */
-
-/**
- * Finds the shortest distance between all vertices of the graph
- * using the Floyd-Warshall algorithm.
- *
- * Complexity O(n^3)
- */
-var floydWarshall = (function () {
-
- /**
- * Matrix used for the algorithm.
- */
- var dist;
-
- /**
- * Initialize the distance matrix
- *
- * @private
- * @param {array} graph Distance matrix of the array
- * @return {array} Distance matrix used for the algorithm
- */
- function init(graph) {
- var dist = [];
- var size = graph.length;
- for (var i = 0; i < size; i += 1) {
- dist[i] = [];
- for (var j = 0; j < size; j += 1) {
- if (i === j) {
- dist[i][j] = 0;
- } else if (isNaN(graph[i][j])) {
- dist[i][j] = Infinity;
- } else {
- dist[i][j] = graph[i][j];
- }
- }
- }
- return dist;
- }
-
- /**
- * Finds the shortest path between each two vertices
- * Complexity O(n^3)
- *
- * @public
- * @param {array} graph The graph which should be processed
- * @return {array} The array which contains the shortest distance between each two vertices
- */
- return function (graph) {
- dist = init(graph);
- var size = graph.length;
- for (var k = 0; k < size; k += 1) {
- for (var i = 0; i < size; i += 1) {
- for (var j = 0; j < size; j += 1) {
- if (dist[i][j] > dist[i][k] + dist[k][j]) {
- dist[i][j] = dist[i][k] + dist[k][j];
- }
- }
- }
- }
- return dist;
- };
-}());
diff --git a/src/graphs/spanning-trees/kruskal.js b/src/graphs/spanning-trees/kruskal.js
new file mode 100644
index 00000000..20e031d3
--- /dev/null
+++ b/src/graphs/spanning-trees/kruskal.js
@@ -0,0 +1,81 @@
+// Kruskal's algorithm for minimal spanning tree implemented with the UnionFind datastructure.
+
+(function(exports) {
+ 'use strict';
+
+ var QuickUnion = require('../../sets/quickunion').QuickUnion;
+ var mergeSort = require('../../sorting/mergesort').mergeSort;
+ exports.Vertex = require('../../data-structures/vertex').Vertex;
+ exports.Edge = require('../../data-structures/edge').Edge;
+
+ exports.Graph = function (edges) {
+ this.edges = edges || [];
+ }
+
+ exports.Graph.prototype.kruskal = (function () {
+ var qunion;
+ var spanningTree;
+ var indexes;
+
+ /**
+ * Used for sorting the edges
+ *
+ * @private
+ * @param {Vertex} a First operand of the comparison.
+ * @param {Vertex} b Second operand of the comparison.
+ * @return {number} Number which which is equal, greater or
+ * less then zero and indicates whether the first vertex is
+ * "smaller" than the second.
+ */
+ function compareEdges(a, b) {
+ return a.distance - b.distance;
+ }
+
+ /**
+ * Initialize the algorithm.
+ *
+ * @private
+ */
+ function init() {
+ var edge;
+ var i = 0;
+
+ mergeSort(this.edges, compareEdges);
+ spanningTree = [];
+ indexes = {};
+
+ // Create links from vertices to QuickUnion elements
+ for (edge of this.edges) {
+ if (!(edge.from.id in indexes)) {
+ indexes[edge.from.id] = i;
+ i += 1;
+ }
+ if (!(edge.to.id in indexes)) {
+ indexes[edge.to.id] = i;
+ i += 1;
+ }
+ }
+
+ qunion = new QuickUnion(i);
+ }
+
+ return function () {
+ init.call(this);
+
+ var edge;
+
+ for (edge of this.edges) {
+ var from = indexes[edge.from.id];
+ var to = indexes[edge.to.id];
+ if (!qunion.connected(from, to)) {
+ qunion.union(from, to);
+ spanningTree.push(edge);
+ }
+ }
+
+ return new exports.Graph(spanningTree);
+ }
+
+ })();
+
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/graphs/spanning-trees/prim.js b/src/graphs/spanning-trees/prim.js
index ea5e8b85..54239587 100644
--- a/src/graphs/spanning-trees/prim.js
+++ b/src/graphs/spanning-trees/prim.js
@@ -1,171 +1,157 @@
-var Heap = require('../../data-structures/heap').Heap;
-
/**
- * Graph vertex
+ * Prim's algorithm is a greedy algorithm that finds a minimum
+ * spanning tree for a connected weighted undirected graph.
*
- * @constructor
- * @public
- * @param {number} id The id of the vertex
- */
-function Vertex(id) {
- this.id = id;
-}
-
-/**
- * Graph edge
+ * @example
*
- * @constructor
- * @public
- * @param {Vertex} e Vertex which this edge connects
- * @param {Vertex} v Vertex which this edge connects
- * @param {number} distance Weight of the node
- */
-function Edge(e, v, distance) {
- this.e = e;
- this.v = v;
- this.distance = distance;
-}
-
-/**
- * Graph
+ * var Prim = require('path-to-algorithms/src/graphs/spanning-trees/prim');
+ * var Graph = Prim.Graph;
+ * var Edge = Prim.Edge;
+ * var Vertex = Prim.Vertex;
*
- * @constructor
- * @public
- */
-function Graph(edges) {
- console.log(edges);
- this.edges = edges || [];
-}
-
-/**
- * Prim's algorithm for minimum spanning tree
+ * var graph, edges = [];
+ * edges.push(new Edge(new Vertex(0), new Vertex(1), 4));
+ * edges.push(new Edge(new Vertex(0), new Vertex(7), 8));
+ * edges.push(new Edge(new Vertex(1), new Vertex(7), 11));
+ * edges.push(new Edge(new Vertex(1), new Vertex(2), 8));
+ * edges.push(new Edge(new Vertex(2), new Vertex(8), 2));
+ * edges.push(new Edge(new Vertex(2), new Vertex(3), 7));
+ * edges.push(new Edge(new Vertex(2), new Vertex(5), 4));
+ * edges.push(new Edge(new Vertex(2), new Vertex(3), 7));
+ * edges.push(new Edge(new Vertex(3), new Vertex(4), 9));
+ * edges.push(new Edge(new Vertex(3), new Vertex(5), 14));
+ * edges.push(new Edge(new Vertex(4), new Vertex(5), 10));
+ * edges.push(new Edge(new Vertex(5), new Vertex(6), 2));
+ * edges.push(new Edge(new Vertex(6), new Vertex(8), 6));
+ * edges.push(new Edge(new Vertex(8), new Vertex(7), 7));
+ * graph = new Graph(edges, edges.length);
*
- * @public
- * @return {Graph} Graph which is the minimum spanning tree
+ * // { edges:
+ * // [ { e: '1', v: 0, distance: 4 },
+ * // { e: '2', v: 8, distance: 2 },
+ * // { e: '3', v: 2, distance: 7 },
+ * // { e: '4', v: 3, distance: 9 },
+ * // { e: '5', v: 2, distance: 4 },
+ * // { e: '6', v: 5, distance: 2 },
+ * // { e: '7', v: 0, distance: 8 },
+ * // { e: '8', v: 7, distance: 7 } ],
+ * // nodesCount: 0 }
+ * var spanningTree = graph.prim();
+ *
+ * @module graphs/spanning-trees/prim
*/
-Graph.prototype.prim = (function () {
-
+(function (exports) {
+
+ 'use strict';
+
+ var Heap = require('../../data-structures/heap').Heap;
+ exports.Vertex = require('../../data-structures/vertex').Vertex;
+ exports.Edge = require('../../data-structures/edge').Edge;
+
+ /**
+ * Graph.
+ *
+ * @constructor
+ * @public
+ * @param {Array} edges Array with graph edges.
+ * @param {Number} nodesCount Number of nodes in graph.
+ */
+ exports.Graph = function (edges, nodesCount) {
+ this.edges = edges || [];
+ this.nodesCount = nodesCount || 0;
+ };
+
+ /**
+ * Executes Prim's algorithm and returns minimum spanning tree.
+ *
+ * @public
+ * @method
+ * @return {Graph} Graph which is the minimum spanning tree.
+ */
+ exports.Graph.prototype.prim = (function () {
var queue;
/**
- * Initialize the algorithm.
+ * Used for comparitions in the heap
*
* @private
+ * @param {Vertex} a First operand of the comparition.
+ * @param {Vertex} b Second operand of the comparition.
+ * @return {number} Number which which is equal, greater or
+ * less then zero and indicates whether the first vertex is
+ * "greater" than the second.
*/
- function init() {
- queue = new Heap(compareEdges);
- this.edges.forEach(function (e) {
- queue.add(e);
- });
+ function compareEdges(a, b) {
+ return b.distance - a.distance;
}
/**
- * Used for comparitions in the heap
+ * Initialize the algorithm.
*
* @private
- * @param {Vertex} a First operand of the comparition
- * @param {Vertex} b Second operand of the comparition
- * @return {number} Number which which is equal, greater or less then zero and
- * indicates whether the first vertex is "greater" than the second.
*/
- function compareEdges(a, b) {
- return b.distance - a.distance;
+ function init() {
+ queue = new Heap(compareEdges);
}
- /**
- * Prim's algorithm implementation
- *
- * @public
- * @return {Graph} Minimum spanning tree.
- */
return function () {
- init.call(this);
- var inTheTree = {},
- current = queue.extract(),
- spannigTree = [];
- spannigTree.push(current);
- inTheTree[current.e.id] = true;
- while (queue.isEmpty()) {
- current = queue.extract();
- if (!inTheTree[current.v.id] ||
- !inTheTree[current.e.id]) {
- spannigTree.push(current);
- inTheTree[current.e.id] = true;
- inTheTree[current.v.id] = true;
+ init.call(this);
+ var inTheTree = {};
+ var startVertex = this.edges[0].e.id;
+ var spannigTree = [];
+ var parents = {};
+ var distances = {};
+ var current;
+ inTheTree[startVertex] = true;
+ queue.add({
+ node: startVertex,
+ distance: 0
+ });
+ const process = function (e) {
+ if (inTheTree[e.v.id] && inTheTree[e.e.id]) {
+ return;
+ }
+ var collection = queue.getCollection();
+ var node;
+ if (e.e.id === current) {
+ node = e.v.id;
+ } else if (e.v.id === current) {
+ node = e.e.id;
+ } else {
+ return;
+ }
+ for (var i = 0; i < collection.length; i += 1) {
+ if (collection[i].node === node) {
+ if (collection[i].distance > e.distance) {
+ queue.changeKey(i, {
+ node: node,
+ distance: e.distance
+ });
+ parents[node] = current;
+ distances[node] = e.distance;
}
+ return;
+ }
}
- return new Graph(spannigTree);
+ queue.add({
+ node: node,
+ distance: e.distance
+ });
+ parents[node] = current;
+ distances[node] = e.distance;
+ };
+ for (var i = 0; i < this.nodesCount - 1; i += 1) {
+ current = queue.extract().node;
+ inTheTree[current] = true;
+ this.edges.forEach(process);
+ }
+ for (var node in parents) {
+ spannigTree.push(
+ new exports.Edge(node, parents[node], distances[node]));
+ }
+ return new exports.Graph(spannigTree);
};
-}());
-
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * * * * * * * * * * * * * * Sample graph * * * * * * * * * * *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-
-var graph;
-
-(function () {
- var edges = [];
-
- edges.push(new Edge(
- new Vertex(0),
- new Vertex(1),
- 7
- ));
-
- edges.push(new Edge(
- new Vertex(0),
- new Vertex(2),
- 9
- ));
-
- edges.push(new Edge(
- new Vertex(0),
- new Vertex(5),
- 16
- ));
-
- edges.push(new Edge(
- new Vertex(1),
- new Vertex(2),
- 10
- ));
-
- edges.push(new Edge(
- new Vertex(1),
- new Vertex(3),
- 15
- ));
-
- edges.push(new Edge(
- new Vertex(2),
- new Vertex(3),
- 11
- ));
-
- edges.push(new Edge(
- new Vertex(2),
- new Vertex(5),
- 2
- ));
-
- edges.push(new Edge(
- new Vertex(3),
- new Vertex(4),
- 6
- ));
-
- edges.push(new Edge(
- new Vertex(4),
- new Vertex(5),
- 9
- ));
-
- graph = new Graph(edges);
-
-}());
-
-console.log(graph.prim());
+ }());
-* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/others/fibonacci.js b/src/others/fibonacci.js
new file mode 100644
index 00000000..324c32cd
--- /dev/null
+++ b/src/others/fibonacci.js
@@ -0,0 +1,40 @@
+/**
+ * Nth number of fibonacci's sequence
+ *
+ * Returns the nth number of fibonacci's sequence.
+ *
+ * @public
+ *
+ * @example
+ * var fibonacci = require('path-to-algorithms/src/others/fibonacci').fibonacci;
+ * var nth = fibonacci(20);
+ *
+ * console.log(nth); // 6765
+ *
+ * @param {Number} n The nth position in fibonacci's sequence
+ *
+ * @module others/fibonacci
+ */
+(function (exports) {
+ 'use strict';
+
+ function fibonacci(n) {
+ if (n > 97) {
+ throw 'Input too large, results in inaccurate fibonacci value.';
+ }
+ var n1 = 0;
+ var n2 = 1;
+ var aux;
+
+ while (n > 0) {
+ aux = n1;
+ n1 = n2;
+ n2 += aux;
+ n = n - 1;
+ }
+
+ return n1;
+ }
+
+ exports.fibonacci = fibonacci;
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/others/fibonacciMemory.js b/src/others/fibonacciMemory.js
new file mode 100644
index 00000000..1bbfc6a1
--- /dev/null
+++ b/src/others/fibonacciMemory.js
@@ -0,0 +1,32 @@
+/**
+ * Nth number of fibonacciMemory's sequence
+ *
+ * Returns the nth number of fibonacciMemory's sequence.
+ *
+ * @public
+ *
+ * @example
+ * var fibonacciMemory = require('path-to-algorithms/src/others/fibonacciMemory').fibonacciMemory;
+ * var nth = fibonacciMemory(20);
+ *
+ * console.log(nth); // 6765
+ *
+ * @param {Number} n The nth position in fibonacciMemory's sequence
+ *
+ * @module others/fibonacciMemory
+ */
+(function (exports) {
+ 'use strict';
+
+ function fibonacciMemory(n) {
+ var i = 0;
+ var aux = [0, 1];
+ while (n !== i) {
+ aux[i + 2] = aux[i] + aux[i + 1];
+ i += 1;
+ }
+ return aux[i];
+ }
+
+ exports.fibonacciMemory = fibonacciMemory;
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/others/hanoi.js b/src/others/hanoi.js
new file mode 100644
index 00000000..613ff98a
--- /dev/null
+++ b/src/others/hanoi.js
@@ -0,0 +1,47 @@
+(function (exports) {
+ 'use strict';
+
+ /**
+ * Returns all movements needed to solve Hanoi Tower problem.
+ *
+ * @public
+ * @module others/hanoi
+ *
+ * @example
+ *
+ * var hanoi = require('path-to-algorithms/src/others/hanoi').hanoi;
+ * var movements = hanoi(3, 'a', 'b', 'c');
+ *
+ * // Move a to c
+ * // Move a to b
+ * // Move c to b
+ * // Move a to c
+ * // Move b to a
+ * // Move b to c
+ * // Move a to c
+ * movements.forEach(function (move) {
+ * console.log('Move', move[0], 'to', move[1]);
+ * });
+ *
+ * @param {Number} count Count of the plates/stones.
+ * @param {String|Number} source Identifier of the 1st peg.
+ * @param {String|Number} intermediate Identifier of the 2nd peg.
+ * @param {String|Number} goal Identifier of the 3rd peg.
+ * @return Array which contains all the moves required
+ * in order to place all the plates onto the last peg.
+ */
+ function hanoi(count, source, intermediate, goal, result) {
+ result = result || [];
+ if (count === 1) {
+ result.push([source, goal]);
+ } else {
+ hanoi(count - 1, source, goal, intermediate, result);
+ result.push([source, goal]);
+ hanoi(count - 1, intermediate, source, goal, result);
+ }
+ return result;
+ }
+
+ exports.hanoi = hanoi;
+
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/others/levenshtein-distance.js b/src/others/levenshtein-distance.js
new file mode 100644
index 00000000..e3f34811
--- /dev/null
+++ b/src/others/levenshtein-distance.js
@@ -0,0 +1,61 @@
+(function (exports) {
+ 'use strict';
+
+ var levenshteinDistance = (function () {
+
+ function levenshteinDistance (s, ls, t, lt) {
+ var memo = [];
+ var currRowMemo;
+ var i;
+ var k;
+
+ for (k = 0; k <= lt; k += 1) {
+ memo[k] = k;
+ }
+
+ for (i = 1; i <= ls; i += 1) {
+ currRowMemo = [i];
+
+ for (k = 1; k <= lt; k += 1) {
+ currRowMemo[k] = Math.min(
+ currRowMemo[k - 1] + 1,
+ memo[k] + 1,
+ memo[k - 1] + (s[i - 1] !== t[k - 1] ? 1 : 0)
+ );
+ }
+
+ memo = currRowMemo;
+ }
+
+ return memo[lt];
+ }
+
+ /**
+ * The Levenshtein distance between two strings is a minimum number
+ * of edits needed to transform one string into the other, with the
+ * allowable edit operations being insertion, deletion,
+ * or substitution of a single character.
+ *
+ * @public
+ * @module others/levenshtein-distance
+ *
+ * @example
+ *
+ * var dist = require('path-to-algorithms/src/others/' +
+ * 'levenshtein-distance').levenshteinDistance;
+ * console.log(dist('kitten', 'sitting')); // 3
+ *
+ * @param {String} s Source string.
+ * @param {String} t Target string.
+ * @return {Number} Minimum number of edits needed
+ * to transform source string into the target string.
+ */
+ return function (s, t) {
+ return levenshteinDistance(s, s.length, t, t.length);
+ };
+ }());
+
+ exports.levenshteinDistance = levenshteinDistance;
+
+}(typeof exports === 'undefined' ? window : exports));
+
diff --git a/src/others/min-coins-change.js b/src/others/min-coins-change.js
new file mode 100644
index 00000000..fa9419d8
--- /dev/null
+++ b/src/others/min-coins-change.js
@@ -0,0 +1,48 @@
+(function (exports) {
+ 'use strict';
+
+ /**
+ * Returns the minimum number of coins from given set,
+ * which sum equals to given change. This is famous
+ * problem from the dynamic programming:
+ * {@link https://en.wikipedia.org/wiki/Change-making_problem}
+ *
+ * @public
+ * @module others/minCoinsChange
+ *
+ * @example
+ *
+ * var minCoinsChange =
+ * require('path-to-algorithms/src/others/min-coins-change')
+ * .minCoinsChange;
+ * var coins = minCoinsChange([1, 2, 3], 5); // [ 2, 3 ]
+ *
+ * @param {Array} coins The sorted list of the coins used for the change.
+ * @param {Number} change The change, which should be returned.
+ * @return Array which contains the minimum coins from the given
+ * list, required for the change.
+ */
+ function minCoinsChange(coins, change) {
+ var minChange = [[0]];
+ if (coins.indexOf(change) >= 0) {
+ return [change];
+ }
+ for (var i = 1; i <= change; i += 1) {
+ for (var j = 0; j < coins.length && coins[j] <= change; j += 1) {
+ for (var k = 0; k < minChange.length; k += 1) {
+ if (k + coins[j] === i) {
+ minChange[i] = minChange[k].concat([coins[j]]);
+ }
+ }
+ }
+ }
+ var result = minChange[change];
+ if (!result) {
+ return undefined;
+ }
+ return result.slice(1);
+ }
+
+ exports.minCoinsChange = minCoinsChange;
+
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/others/minimax.js b/src/others/minimax.js
new file mode 100644
index 00000000..b48fdb0b
--- /dev/null
+++ b/src/others/minimax.js
@@ -0,0 +1,120 @@
+(function (exports) {
+ 'use strict';
+ /* eslint max-params: 0 */
+
+ /**
+ * @param {Function} getPossibleNextStatesFn Function which returns all possible next moves with states .
+ * @param {Function} isGameOverFn Function which returns if game is over.
+ * @param {Function} getScoreFn Function which returns score.
+ * @return {Function} minimax function
+ */
+ function minimaxBuilder(
+ getPossibleNextStatesFn,
+ isGameOverFn,
+ getScoreFn
+ ) {
+ /**
+ * Minimax (sometimes MinMax, MM[1] or saddle point[2]) is a decision rule used in artificial intelligence,
+ * decision theory, game theory, statistics, and philosophy for minimizing the possible loss for a worst case (maximum loss) scenario.
+ * Optimized with alpha-beta pruning.
+ * {@link https://en.wikipedia.org/wiki/Minimax}
+ * {@link https://en.wikipedia.org/wiki/Alpha%E2%80%93beta_pruning}
+ *
+ * @public
+ * @module others/minimax
+ *
+ * @example
+ *
+ * var miniMax =
+ * require('path-to-algorithms/src/others/minimax').minimax;
+ * var result = minimax(
+ * [1, 2, 3],
+ * true,
+ * 5,
+ * -Infinity,
+ * Infinity,
+ * state => ({ move: 0, state: [2, 3, 4] }),
+ * state => state[1] < 3,
+ * state => state[1]
+ * );
+ *
+ * @param {*} state Current game state
+ * @param {Boolean} maximize Defines if the result should be maximized or minimized
+ * @param {Number} depth Defines the maximum depth search
+ * @param {Number} alpha Maximum score that the minimizing player is assured
+ * @param {Number} beta Minimum score that the maximizing player is assured
+ * @return {{score: Number, move: *}} which contains the minimum coins from the given
+ * list, required for the change.
+ */
+ const minimax = (
+ state,
+ maximize,
+ depth,
+ alpha,
+ beta
+ ) => {
+ if (depth === 0 || isGameOverFn(state)) {
+ const score = getScoreFn(state);
+ return {score, move: null};
+ }
+
+ const possibleMoveResults = getPossibleNextStatesFn(state);
+
+ if (maximize) {
+
+ let maxResult = {score: -Infinity, move: null};
+
+ for (const next of possibleMoveResults) {
+ const result = minimax(
+ next.state,
+ false,
+ depth - 1,
+ alpha,
+ beta
+ );
+
+ if (result.score > maxResult.score) {
+ maxResult = {score: result.score, move: next.move};
+ }
+
+ alpha = Math.max(alpha, result.score);
+
+ if (alpha >= beta) {
+ break;
+ }
+ }
+
+ return maxResult;
+ } else {
+ let minResult = {score: Infinity, move: null};
+
+ for (const next of possibleMoveResults) {
+ const result = minimax(
+ next.state,
+ true,
+ depth - 1,
+ alpha,
+ beta
+ );
+
+ if (result.score < minResult.score) {
+ minResult = {score: result.score, move: next.move};
+ }
+
+ beta = Math.min(beta, result.score);
+
+ if (beta <= alpha) {
+ break;
+ }
+ }
+
+ return minResult;
+ }
+ }
+
+ return minimax;
+ }
+
+ exports.minimaxBuilder = minimaxBuilder;
+
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/others/minkowski-distance.js b/src/others/minkowski-distance.js
new file mode 100644
index 00000000..e917bf80
--- /dev/null
+++ b/src/others/minkowski-distance.js
@@ -0,0 +1,79 @@
+(function (exports) {
+ 'use strict';
+
+ var minkowskiDistance = (function () {
+
+ function chebyshevDistance (x, y, lx, p, mathfn) {
+ var ret = -p;
+ var i;
+
+ for (i = 0; i < lx; i += 1) {
+ ret = mathfn(ret, Math.abs(x[i] - y[i]));
+ }
+
+ return ret;
+ }
+
+ function minkowskiDistance (x, lx, y, ly, p) {
+ var d;
+ var i;
+
+ if (lx !== ly) {
+ throw 'Both vectors should have same dimension';
+ }
+
+ if (isNaN(p)) {
+ throw 'The order "p" must be a number';
+ }
+
+ if (p === Number.POSITIVE_INFINITY) {
+ return chebyshevDistance(x, y, lx, p, Math.max);
+ } else if (p === Number.NEGATIVE_INFINITY) {
+ return chebyshevDistance(x, y, lx, p, Math.min);
+ } else if (p < 1) {
+ throw 'Order less than 1 will violate the triangle inequality';
+ } else {
+ d = 0;
+
+ for (i = 0; i < lx; i += 1) {
+ d += Math.pow(Math.abs(x[i] - y[i]), p);
+ }
+
+ return isNaN(d)
+ ? 0
+ : Math.pow(d, 1 / p);
+
+ }
+
+ }
+
+ /**
+ * The Minkowski distance between two points gets generalized
+ * metric distance
+ * when p === 1, this becomes same as Manhattan Distance
+ * when p === 2, this becomes same as Euclidean Distance
+ * when p === Positive or Negative Infinity,
+ * this becomes chebyshev distance
+ *
+ * @public
+ * @module others/minkowski-distance
+ *
+ * @example
+ * var dist = require('path-to-algorithms/src/others/' +
+ * 'minkowski-distance').minkowskiDistance;
+ * console.log(dist([0, 1], [1, 1], 2)); // 1
+ *
+ * @param {Array} x source point
+ * @param {Array} y target point
+ * @param {Number} p order of Minkowski distance
+ * @returns {Number} distance between two points, if distance
+ * is NaN, then this returns 0
+ */
+ return function (x, y, p) {
+ return minkowskiDistance (x, x.length, y, y.length, p);
+ };
+ }());
+
+ exports.minkowskiDistance = minkowskiDistance;
+
+}(typeof exports === 'undefined' ? window : exports));
diff --git a/src/primes/is-prime.js b/src/primes/is-prime.js
new file mode 100644
index 00000000..ca954fe0
--- /dev/null
+++ b/src/primes/is-prime.js
@@ -0,0 +1,49 @@
+(function (exports) {
+ 'use strict';
+
+ /**
+ * Advanced (optimised) method for checking if provided number is prime.
+ * For example for number 104743 it should return true, for 104744 - false.
+ *
+ * @module primes/is-prime
+ * @param {Number} number - Number that we check on prime.
+ * @returns {Boolean} Will return true if provided number is prime.
+ *
+ * @example
+ * var isPrime = require('path-to-algorithms/src/is-prime').isPrime;
+ *
+ * console.log(isPrime(7)); // true
+ * console.log(isPrime(18)); // false
+ */
+ exports.isPrime = function (number) {
+
+ if (number < 2) {
+ return false;
+ }
+
+ if (number % 2 === 0) {
+ return (number === 2);
+ }
+
+ if (number % 3 === 0) {
+ return (number === 3);
+ }
+
+ var horizon = Math.floor(Math.sqrt(number));
+ var factor = 5;
+
+ while (factor <= horizon) {
+
+ if (number % factor === 0) {
+ return false;
+ }
+
+ if (number % (factor + 2) === 0) {
+ return false;
+ }
+ factor += 6;
+ }
+ return true;
+ };
+
+}(typeof exports === 'undefined' ? window : exports));
diff --git a/src/primes/prime-factor-tree.js b/src/primes/prime-factor-tree.js
new file mode 100644
index 00000000..b803ff02
--- /dev/null
+++ b/src/primes/prime-factor-tree.js
@@ -0,0 +1,47 @@
+(function (exports) {
+ 'use strict';
+
+ /**
+ * Method will return list of all primes for provided number.
+ * For example for number 18 it should return following list of primes
+ * [2, 3, 3].
+ *
+ * @module primes/prime-factor-tree
+ * @param {Number} number - Number for which method will find all primes.
+ * @returns {Array} List of available primes for provided number.
+ *
+ * @example
+ * var primeFactorTree = require('path-to-algorithms/src/prime-factor-tree')
+ * .primeFactorTree;
+ *
+ * console.log(primeFactorTree(18)); // [2, 3, 3]
+ * console.log(primeFactorTree(600851475143)); // [71, 839, 1471, 6857]
+ */
+ exports.primeFactorTree = function (number) {
+ var array = [];
+ var s = 6;
+ while (number > 1 && number % 2 === 0) {
+ number /= 2;
+ array.push(2);
+ }
+ while (number > 2 && number % 3 === 0) {
+ number /= 3;
+ array.push(3);
+ }
+ while (number > 4) {
+ var p = s - 1;
+ var q = s + 1;
+ while (number > 4 && number % p === 0) {
+ number /= p;
+ array.push(p);
+ }
+ while (number > 4 && number % q === 0) {
+ number /= q;
+ array.push(q);
+ }
+ s += 6;
+ }
+ return array;
+ };
+
+}(typeof exports === 'undefined' ? window : exports));
diff --git a/src/primes/sieve-of-atkins.js b/src/primes/sieve-of-atkins.js
new file mode 100644
index 00000000..1f75cfd3
--- /dev/null
+++ b/src/primes/sieve-of-atkins.js
@@ -0,0 +1,87 @@
+(function (exports) {
+ 'use strict';
+
+ /**
+ * Sieve of Atkins.
+ *
+ * Modern algorithm for finding all prime numbers up to a specified integer.
+ *
+ * Returns list of primes up to specified limit.
+ *
+ * For example, for limit 10 it should return following list of primes:
+ * [2, 3, 5, 7].
+ *
+ * @module primes/sieve-of-atkins
+ * @param {Number} limit - Algorithm will returns list of primes up to
+ * specified limit.
+ * @returns {Array} Will return list with all prime numbers up to provided.
+ * limit.
+ *
+ * @example
+ * var sieveOfAtkins =
+ * require('path-to-algorithms/src/sieve-of-atkins').sieveOfAtkins;
+ *
+ * console.log(sieveOfAtkins(12)); // [2, 3, 5, 7, 11]
+ */
+ exports.sieveOfAtkins = function (limit) {
+ if (limit <= 1) {
+ return [];
+ }
+
+ const sieve = Array(limit + 1);
+
+ const testingLimit = Math.ceil(Math.sqrt(limit));
+
+ var i;
+ var j;
+ var n;
+
+ for (i = 1; i < testingLimit; i += 1) {
+ var ii = i * i;
+ for (j = 1; j < testingLimit; j += 1) {
+ var jj = j * j;
+ if (ii + jj >= limit) {
+ break;
+ }
+
+ n = 4 * ii + jj;
+ if (n <= limit && (n % 12 === 1 || n % 12 === 5)) {
+ sieve[n] = !sieve[n];
+ }
+
+ n = 3 * ii + jj;
+ if (n <= limit && (n % 12 === 7)) {
+ sieve[n] = !sieve[n];
+ }
+
+ n = 3 * ii - jj;
+ if (i > j && n <= limit && (n % 12 === 11)) {
+ sieve[n] = !sieve[n];
+ }
+ }
+ }
+
+ for (n = 5; n <= testingLimit; n += 1) {
+ if (sieve[n]) {
+ j = n * n;
+ for (i = j; i <= limit; i += j) {
+ sieve[i] = false;
+ }
+ }
+ }
+
+ const primes = [2];
+
+ if (limit > 2) {
+ primes.push(3);
+ }
+
+ sieve.forEach(function (value, key) {
+ if (value) {
+ this.push(key);
+ }
+ }, primes);
+
+ return primes;
+ }
+}(typeof exports === 'undefined' ? window : exports));
diff --git a/src/primes/sieve-of-eratosthenes.js b/src/primes/sieve-of-eratosthenes.js
new file mode 100644
index 00000000..c239ea0e
--- /dev/null
+++ b/src/primes/sieve-of-eratosthenes.js
@@ -0,0 +1,57 @@
+(function (exports) {
+ 'use strict';
+
+ /**
+ * Sieve of Eratosthenes.
+ *
+ * Simple, ancient algorithm for finding all prime numbers up to given limit.
+ *
+ * Returns list of primes up to specified limit.
+ *
+ * For example, for limit 10 it should return following list of primes:
+ * [2, 3, 5, 7].
+ *
+ * @module primes/sieve-of-eratosthenes
+ * @param {Number} limit - Algorithm will returns list of primes up to
+ * specified limit.
+ * @returns {Array} Will return list with all prime numbers up to provided.
+ * limit.
+ *
+ * @example
+ * var sieveOfEratosthenes =
+ * require('path-to-algorithms/src/sieve-of-eratosthenes').sieveOfEratosthenes;
+ *
+ * console.log(sieveOfEratosthenes(12)); // [2, 3, 5, 7, 11]
+ */
+ exports.sieveOfEratosthenes = function (limit) {
+ var sieve = [];
+ var primes = [];
+ var k;
+ var l;
+
+ sieve[1] = false;
+
+ for (k = 2; k <= limit; k += 1) {
+ sieve[k] = true;
+ }
+
+ for (k = 2; k * k <= limit; k += 1) {
+ if (sieve[k] !== true) {
+ continue;
+ }
+
+ for (l = k * k; l <= limit; l += k) {
+ sieve[l] = false;
+ }
+ }
+
+ sieve.forEach(function (value, key) {
+ if (value) {
+ this.push(key);
+ }
+ }, primes);
+
+ return primes;
+ };
+
+}(typeof exports === 'undefined' ? window : exports));
diff --git a/src/searching/binarysearch.js b/src/searching/binarysearch.js
new file mode 100644
index 00000000..efe6e28c
--- /dev/null
+++ b/src/searching/binarysearch.js
@@ -0,0 +1,46 @@
+(function (exports) {
+ 'use strict';
+
+ function id (val) { return val; }
+ function get (key) { return function (val) { return val[key]; }; }
+
+ /**
+ * Searches for specific element in a given array using
+ * the binary search algorithm.
+ * Time complexity: O(log N).
+ *
+ * @example
+ *
+ * var search = require('path-to-algorithms/src/searching/'+
+ * 'binarysearch').binarySearch;
+ * console.log(search([1, 2, 3, 4, 5], 4)); // 3
+ *
+ * @public
+ * @module searching/binarysearch
+ * @param {Array} array Input array.
+ * @param {Number} value Value of the element which index should be found.
+ * @returns {Number} Index of the element or -1 if not found.
+ */
+ function binarySearch(array, value, key) {
+ key = !key ? id : typeof key === 'string' ? get(key) : key;
+ value = key(value);
+ var middle = Math.floor(array.length / 2);
+ var left = 0;
+ var right = array.length;
+ while (right >= left) {
+ var middleValue = key(array[middle]);
+ if (middleValue === value) {
+ return middle;
+ } else if (middleValue > value) {
+ right = middle - 1;
+ } else {
+ left = middle + 1;
+ }
+ middle = Math.floor((left + right) / 2);
+ }
+ return -1;
+ }
+
+ exports.binarySearch = binarySearch;
+
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/searching/binarysearch/binarysearch.js b/src/searching/binarysearch/binarysearch.js
deleted file mode 100644
index ed6d1e8d..00000000
--- a/src/searching/binarysearch/binarysearch.js
+++ /dev/null
@@ -1,31 +0,0 @@
-(function (exports) {
-
- /**
- * Searchs for specific element in given array using the binary search algorithm.
- * It's complexity is O(log n)
- *
- * @public
- * @param {array} array Input array
- * @param {number} key The key of the element which index we should find
- * @returns {number} index The index of the element or -1 if not found
- */
- function binarySearch(array, key) {
- var middle = Math.floor(array.length / 2),
- left = 0,
- right = array.length;
- while (right >= left) {
- if (array[middle] === key) {
- return middle;
- } else if (array[middle] > key) {
- right = middle - 1;
- } else {
- left = middle + 1;
- }
- middle = Math.floor((left + right) / 2);
- }
- return -1;
- }
-
- exports.binarySearch = binarySearch;
-
-}(typeof exports === 'undefined' ? window : exports));
diff --git a/src/searching/binarysearch/recursive-binarysearch.js b/src/searching/binarysearch/recursive-binarysearch.js
deleted file mode 100644
index 7e1c3c61..00000000
--- a/src/searching/binarysearch/recursive-binarysearch.js
+++ /dev/null
@@ -1,42 +0,0 @@
-/**
- * Recursive version of binary search. It's complexity is O(log n).
- *
- * @public
- */
-var binarySearch = (function () {
-
- /**
- * Binary search.
- *
- * @pivate
- * @param {array} array Given array where we should find the index of the element
- * @param {number} key Key of the element which index should be found
- * @param {number} left Left index
- * @param {number} right Right index
- * @returns {number} index The index of the element or -1 if not found
- *
- */
- function recursiveBinarySearch(array, key, left, right) {
- if (left > right)
- return -1;
- var middle = Math.floor((right + left) / 2);
- if (array[middle] === key)
- return middle;
- else if (array[middle] > key)
- return recursiveBinarySearch(array, key, left, middle - 1);
- else
- return recursiveBinarySearch(array, key, middle + 1, right);
- }
-
- /**
- * Calls the binary search function with it's initial values.
- *
- * @param {array} array The input array
- * @param {number} key The key of the element which index should be found
- * @returns {number} index The index of the element or -1 if not found
- */
- return function (array, key) {
- return recursiveBinarySearch(array, key, 0, array.length);
- };
-
-}());
diff --git a/src/searching/interpolation-search.js b/src/searching/interpolation-search.js
new file mode 100644
index 00000000..04202079
--- /dev/null
+++ b/src/searching/interpolation-search.js
@@ -0,0 +1,55 @@
+(function(exports) {
+ 'use strict';
+ /**
+ * Searches for specific element in a given array using
+ * the interpolation search algorithm.
+ * Time complexity: O(log log N) when elements are uniformly
+ * distributed, and O(N) in the worst case
+ *
+ * @example
+ *
+ * var search = require('path-to-algorithms/src/searching/'+
+ * 'interpolation-search').interpolationSearch;
+ * console.log(search([1, 2, 3, 4, 5], 4)); // 3
+ *
+ * @public
+ * @module searching/interpolation-search
+ * @param {Array} sortedArray Input array.
+ * @param {Number} seekIndex of the element which index should be found.
+ * @returns {Number} Index of the element or -1 if not found.
+ */
+ function interpolationSearch(sortedArray, seekIndex) {
+ let leftIndex = 0;
+ let rightIndex = sortedArray.length - 1;
+
+ while (leftIndex <= rightIndex) {
+ const rangeDiff = sortedArray[rightIndex] - sortedArray[leftIndex];
+ const indexDiff = rightIndex - leftIndex;
+ const valueDiff = seekIndex - sortedArray[leftIndex];
+
+ if (valueDiff < 0) {
+ return -1;
+ }
+
+ if (!rangeDiff) {
+ return sortedArray[leftIndex] === seekIndex ? leftIndex : -1;
+ }
+
+ const middleIndex =
+ leftIndex + Math.floor((valueDiff * indexDiff) / rangeDiff);
+
+ if (sortedArray[middleIndex] === seekIndex) {
+ return middleIndex;
+ }
+
+ if (sortedArray[middleIndex] < seekIndex) {
+ leftIndex = middleIndex + 1;
+ } else {
+ rightIndex = middleIndex - 1;
+ }
+ }
+
+ return -1;
+ }
+ exports.interpolationSearch = interpolationSearch;
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/searching/jump-search.js b/src/searching/jump-search.js
new file mode 100644
index 00000000..d697c94a
--- /dev/null
+++ b/src/searching/jump-search.js
@@ -0,0 +1,56 @@
+(function(exports) {
+ 'use strict';
+ /**
+ * Searches for specific element in a given array using
+ * the jump search algorithm.
+ * Time complexity: O(log N).
+ *
+ * @example
+ *
+ * var search = require('path-to-algorithms/src/searching/'+
+ * 'jump-search').jumpSearch;
+ * console.log(search([1, 2, 3, 4, 5], 4)); // 3
+ *
+ * @public
+ * @module searching/jumpsearch
+ * @param {Array} sortedArray Input array.
+ * @param {Number} seekIndex of the element which index should be found.
+ * @returns {Number} Index of the element or -1 if not found.
+ */
+ function jumpSearch(sortedArray, seekIndex) {
+ // exit if array empty
+ const arrayLength = sortedArray.length;
+ if (!arrayLength) {
+ return -1;
+ }
+
+ // set jumpSize
+ const jumpSize = Math.floor(Math.sqrt(arrayLength));
+
+ let blockStart = 0;
+ let blockEnd = jumpSize;
+
+ while (seekIndex > sortedArray[Math.min(blockEnd, arrayLength) - 1]) {
+ blockStart = blockEnd;
+ blockEnd += jumpSize;
+
+ // if out of array bounds exit
+ if (blockStart > arrayLength) {
+ return -1;
+ }
+ }
+
+ let currentIndex = blockStart;
+ while (currentIndex < Math.min(blockEnd, arrayLength)) {
+ if (sortedArray[currentIndex] === seekIndex) {
+ return currentIndex;
+ }
+
+ currentIndex += 1;
+ }
+
+ return -1;
+ }
+
+ exports.jumpSearch = jumpSearch;
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/searching/knuth-morris-pratt.js b/src/searching/knuth-morris-pratt.js
new file mode 100644
index 00000000..b4aeb85b
--- /dev/null
+++ b/src/searching/knuth-morris-pratt.js
@@ -0,0 +1,79 @@
+(function (exports) {
+ 'use strict';
+
+ var kmp = (function () {
+ function builtKMPTable(str) {
+ var res = [];
+ var len;
+ var front;
+ var end;
+ var found;
+ for (var i = 1; i <= str.length; i += 1) {
+ front = Math.max(1, i - ((res[i - 2] || 0) + 1));
+ end = Math.min(i - 1, (res[i - 2] || 0) + 1);
+ found = false;
+ len = 0;
+ while (end >= 1 && front <= i && !found) {
+ if (str.substring(0, end) === str.substring(front, i)) {
+ found = true;
+ len = end;
+ } else {
+ end -= 1;
+ front += 1;
+ }
+ }
+ res[i - 1] = len;
+ }
+ return res;
+ }
+
+ /**
+ * Knuth–Morris–Pratt algorithm. Searches for the position of
+ * the first occurrence of a specified value in a string.
+ *
+ * @example
+ *
+ * var indexOf = require('path-to-algorithm/src/searching/'+
+ * 'knuth-morris-pratt').kmp;
+ * console.log(indexOf('hello', 'll')); // 2
+ *
+ * @public
+ * @module searching/knuth-morris-pratt
+ * @param {String} str String.
+ * @param {String} substr Substring.
+ * @return {Number} A Number, representing the position
+ * where the specified substring occurs for the first
+ * time, or -1 if it never occurs.
+ */
+ function indexOf(str, substr) {
+ if (str === substr) {
+ return 0;
+ }
+ var table = builtKMPTable(substr);
+ var i = 0;
+ var j = 0;
+ while (i < str.length) {
+ if (str[i] === substr[j]) {
+ i += 1;
+ j += 1;
+ }
+ if (j === substr.length) {
+ return i - j;
+ }
+ if (i < str.length && str[i] !== substr[j]) {
+ if (j > 0 && table[j - 1] !== 0) {
+ j = table[j - 1];
+ } else {
+ i += 1;
+ j = 0;
+ }
+ }
+ }
+ return -1;
+ }
+ return indexOf;
+ }());
+
+ exports.kmp = kmp;
+
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/searching/linearSearch.js b/src/searching/linearSearch.js
new file mode 100644
index 00000000..9a95dfa4
--- /dev/null
+++ b/src/searching/linearSearch.js
@@ -0,0 +1,24 @@
+(function (exports) {
+ 'use strict';
+
+ /**
+ * Searches for specific element in a given array
+ * using the linear search algorithm
+ * Time complexity: O(n)
+ *
+ * @param {Array} array Input array
+ * @param {Number} key the number whose index is to be found
+ * @returns {Number} the index of the first instance of number or else -1 if not found
+ */
+
+ const linearSearch = (array, key) => {
+ for (let i = 0; i < array.length; i += 1) {
+ if (array[i] === key) {
+ return i;
+ }
+ }
+ return -1;
+ };
+
+ exports.linearSearch = linearSearch;
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/searching/longest-common-subsequence.js b/src/searching/longest-common-subsequence.js
new file mode 100644
index 00000000..01361142
--- /dev/null
+++ b/src/searching/longest-common-subsequence.js
@@ -0,0 +1,86 @@
+(function (exports) {
+ 'use strict';
+
+ exports.longestCommonSubsequence = (function () {
+
+ /**
+ * Find the lengths of longest common sub-sequences
+ * of two strings and their substrings.
+ *
+ * Complexity: O(MN).
+ *
+ * @private
+ * @param {String} first string
+ * @param {String} second string
+ * @return {Array} two dimensional array with LCS
+ * lengths of input strings and their substrings.
+ *
+ */
+ function getLcsLengths(str1, str2) {
+ var result = [];
+ for (var i = -1; i < str1.length; i = i + 1) {
+ result[i] = [];
+ for (var j = -1; j < str2.length; j = j + 1) {
+ if (i === -1 || j === -1) {
+ result[i][j] = 0;
+ } else if (str1[i] === str2[j]) {
+ result[i][j] = result[i - 1][j - 1] + 1;
+ } else {
+ result[i][j] = Math.max(result[i - 1][j], result[i][j - 1]);
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Find longest common sub-sequences of two strings.
+ *
+ * Complexity: O(M + N).
+ *
+ * @private
+ * @param {String} first string
+ * @param {String} second string
+ * @return {Array} two dimensional array with LCS
+ * lengths of input strings and their substrings
+ * returned from 'getLcsLengths' function.
+ *
+ */
+ function getLcs(str1, str2, lcsLengthsMatrix) {
+ var execute = function (i, j) {
+ if (!lcsLengthsMatrix[i][j]) {
+ return '';
+ } else if (str1[i] === str2[j]) {
+ return execute(i - 1, j - 1) + str1[i];
+ } else if (lcsLengthsMatrix[i][j - 1] > lcsLengthsMatrix[i - 1][j]) {
+ return execute(i, j - 1);
+ } else {
+ return execute(i - 1, j);
+ }
+ };
+ return execute(str1.length - 1, str2.length - 1);
+ }
+
+ /**
+ * Algorithm from dynamic programming. It finds the longest
+ * common sub-sequence of two strings. For example for strings 'abcd'
+ * and 'axxcda' the longest common sub-sequence is 'acd'.
+ *
+ * @example
+ * var subsequence = require('path-to-algorithms/src/searching/'+
+ * 'longest-common-subsequence').longestCommonSubsequence;
+ * console.log(subsequence('abcd', 'axxcda'); // 'acd'
+ *
+ * @public
+ * @module searching/longest-common-subsequence
+ * @param {String} first input string.
+ * @param {String} second input string.
+ * @return {Array} Longest common subsequence.
+ */
+ return function (str1, str2) {
+ var lcsLengthsMatrix = getLcsLengths(str1, str2);
+ return getLcs(str1, str2, lcsLengthsMatrix);
+ };
+ })();
+
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/searching/longest-increasing-subsequence.js b/src/searching/longest-increasing-subsequence.js
new file mode 100644
index 00000000..6b4db8ea
--- /dev/null
+++ b/src/searching/longest-increasing-subsequence.js
@@ -0,0 +1,135 @@
+(function (exports) {
+ 'use strict';
+
+ exports.longestIncreasingSubsequence = (function () {
+
+ /**
+ * Find the index of the first largest element in array.
+ * Complexity: O(N).
+ *
+ * @private
+ * @param {Array} array The array in which the largest
+ * element should be found.
+ * @return {Number} index of the first largest element
+ */
+ function max(array) {
+ if (!array || !array.length) {
+ return -1;
+ }
+ var maxIdx = 0;
+ for (var i = 1; i < array.length; i += 1) {
+ if (array[maxIdx].distance < array[i].distance) {
+ maxIdx = i;
+ }
+ }
+ return maxIdx;
+ }
+
+ /**
+ * Default comparison method.
+ * @private
+ */
+ function asc(a, b) {
+ return a - b;
+ }
+
+ /**
+ * Creates directed graph from given array.
+ * Each element's neighbours are the elements which can be
+ * after the element in the resulting sequence.
+ * Complexity: O(N^2).
+ * @private
+ * @param {Array} array The input array.
+ * @param {Function} cmp Comparator.
+ * @return {Object} Graph represented with list of neighbours.
+ */
+ function buildDag(array, cmp) {
+ var result = [];
+ for (var i = 0; i < array.length; i += 1) {
+ result[i] = [];
+ for (var j = i + 1; j < array.length; j += 1) {
+ if (cmp(array[i], array[j]) < 0) {
+ result[i].push(j);
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Finds the longest increasing sub-sequence for given node.
+ * Complexity: O(N^N).
+ * @private
+ * @param {Object} dag Graph represented with list of neighbours.
+ * @param {number} node The current node.
+ * @return {object} The longest increasing sub-sequence for given node.
+ */
+ function find(dag, node) {
+ node = node || 0;
+ if (find.memo[node]) {
+ return find.memo[node];
+ }
+ var neighbours = dag[node];
+ var neighboursDistance = [];
+ var maxDist;
+ // var maxNode;
+ var distance;
+ var result;
+
+ if (!neighbours.length) {
+ return { distance: 1, neighbour: undefined, node: node };
+ }
+
+ for (var i = 0; i < neighbours.length; i += 1) {
+ neighboursDistance[i] = find(dag, neighbours[i]);
+ }
+
+ maxDist = max(neighboursDistance);
+ // maxNode = neighbours[maxDist];
+ distance = 1 + neighboursDistance[maxDist].distance;
+ find.memo[node] = result = {
+ distance: distance,
+ neighbour: neighboursDistance[maxDist],
+ node: node
+ };
+ return result;
+ }
+
+ /**
+ * Algorithm from dynamic programming. It finds the longest
+ * sub-sequence of increasing numbers. It is not required
+ * the numbers to be neighboring. For example for 1, 5, 2
+ * sequence the longest sub-sequence is 1, 2.
+ *
+ * @example
+ * var subsequence = require('path-to-algorithms/src/searching/'+
+ * 'longest-increasing-subsequence').longestIncreasingSubsequence;
+ * console.log(subsequence([1, 0, 4, 3, 5])); // 1, 4, 5
+ *
+ * @public
+ * @module searching/longest-increasing-subsequence
+ * @param {Array} array Input sequence.
+ * @param {Function} cmp Comparator.
+ * @return {Array} Longest increasing subsequence.
+ */
+ return function (array, cmp) {
+ cmp = cmp || asc;
+ var results = [];
+ var dag = buildDag(array, cmp);
+ var maxPath;
+ find.memo = [];
+ for (var i = 0; i < array.length; i += 1) {
+ results.push(find(dag, i));
+ }
+ maxPath = results[max(results)];
+ results = [];
+ while (maxPath) {
+ results.push(array[maxPath.node]);
+ maxPath = maxPath.neighbour;
+ }
+ return results;
+ };
+ })();
+
+})(typeof window === 'undefined' ? module.exports : window);
+
diff --git a/src/searching/longest-increasing-subsequence/longest-increasing-subsequence.js b/src/searching/longest-increasing-subsequence/longest-increasing-subsequence.js
deleted file mode 100644
index 5a1084bb..00000000
--- a/src/searching/longest-increasing-subsequence/longest-increasing-subsequence.js
+++ /dev/null
@@ -1,106 +0,0 @@
-(function (exports) {
-
- /**
- * Algorithm from dynamic programming.
- * It finds the longest sub-sequence of
- * increasing numbers. It is not required
- * the numbers to be neighboring.
- *
- * Example:
- * 1,5,2
- * The longest sub-sequence is 1,2.
- */
- exports.longestSubsequence = (function () {
-
- /**
- * Find the index of the first largest element in array.
- * Complexity O(n).
- *
- * @param {Array} array The array in which the largest element should be found
- * @param {Function} cmp Function used for comparison
- * @return {number} The index of the first largest element
- */
- function max(array, cmp) {
- if (!array || !array.length) return -1;
- if (!cmp) {
- cmp = function (a, b) { return a - b };
- }
- var max = 0;
- for (var i = 1; i < array.length; i += 1)
- if (cmp(array[max], array[i]) < 0) max = i;
- return max;
- }
-
- /**
- * Default comparison method.
- */
- function cmp(a, b) {
- return a.distance - b.distance;
- }
-
- /**
- * Creates directed graph from given array.
- * Each element's neighbours are the elements which can be
- * after the element in the resulting sequence.
- * Complexity O(n^2).
- *
- * @param {Array} array The input array
- * @return {Object} Graph represented with list of neighbours
- */
- function buildDag(array) {
- var result = [];
- for (var i = 0; i < array.length; i += 1) {
- result[i] = [];
- for (var j = i + 1; j < array.length; j += 1) {
- if (array[i] < array[j]) result[i].push(j);
- }
- }
- return result;
- }
-
- /**
- * Finds the longest sub-sequence for given node.
- * O(n^n).
- *
- * @param {Object} dag Graph represented with list of neighbours.
- * @param {number} node The current node.
- * @return {object} The longest sub-sequence for given node.
- */
- function find(dag, node) {
- node = node || 0;
- if (find.memo[node]) return find.memo[node];
- var neighbours = dag[node],
- neighboursDistance = [],
- maxDist, maxNode, distance, result;
-
- if (!neighbours.length) return { distance: 1, neighbour: undefined, node: node };
-
- for (var i = 0; i < neighbours.length; i += 1)
- neighboursDistance[i] = find(dag, neighbours[i]);
-
- maxDist = max(neighboursDistance, cmp);
- maxNode = neighbours[maxDist];
- distance = 1 + neighboursDistance[maxDist].distance;
- find.memo[node] = result = { distance: distance, neighbour: neighboursDistance[maxDist], node: node };
- return result;
- }
-
- return function (array) {
- var results = [],
- dag = buildDag(array),
- maxPath;
- find.memo = [];
- for (var i = 0; i < array.length; i += 1) {
- results.push(find(dag, i));
- }
- maxPath = results[max(results, cmp)];
- results = [];
- while (maxPath) {
- results.push(array[maxPath.node]);
- maxPath = maxPath.neighbour;
- }
- return results;
- };
- })();
-
-}(typeof exports === 'undefined' ? exports : this));
\ No newline at end of file
diff --git a/src/searching/maximum-subarray-divide-and-conquer.js b/src/searching/maximum-subarray-divide-and-conquer.js
new file mode 100644
index 00000000..31a7dd66
--- /dev/null
+++ b/src/searching/maximum-subarray-divide-and-conquer.js
@@ -0,0 +1,80 @@
+(function (exports) {
+ 'use strict';
+
+ /**
+ * Accepts an array and range. Finds the maximum sum of elements
+ * around the middle of the range.
+ * @private
+ * @param {Array} array Input array.
+ * @param {Number} left Left interval of the range.
+ * @param {Number} middle Middle of the range.
+ * @param {Number} right Right side of the range.
+ * @return {Number} The maximum sum including the middle element.
+ */
+ function crossSubarray(array, left, middle, right) {
+ var leftSum = -Infinity;
+ var rightSum = -Infinity;
+ var sum = 0;
+ var i;
+
+ for (i = middle; i >= left; i -= 1) {
+ if (sum + array[i] >= leftSum) {
+ leftSum = sum + array[i];
+ }
+ sum += array[i];
+ }
+ sum = 0;
+ for (i = middle + 1; i < right; i += 1) {
+ if (sum + array[i] >= rightSum) {
+ rightSum = sum + array[i];
+ }
+ sum += array[i];
+ }
+ return leftSum + rightSum;
+ }
+
+ /**
+ * @private
+ * @param {Array} array Input array.
+ * @param {Number} left Left side of the range.
+ * @param {Number} right Right side of the range.
+ * @return {Number} Maximum sum of the elements of
+ * subarray whithin the given range.
+ */
+ function maxSubarrayPartitioner(array, left, right) {
+ if (right - left <= 1) {
+ return array[left];
+ }
+ var middle = Math.floor((left + right) / 2);
+ var leftSum = maxSubarrayPartitioner(array, left, middle);
+ var rightSum = maxSubarrayPartitioner(array, middle, right);
+ var crossSum = crossSubarray(array, left, middle, right);
+
+ return Math.max(crossSum, leftSum, rightSum);
+ }
+
+ /**
+ * Finds the maximum sum of the elements of a subarray in a given array
+ * using the divide and conquer algorithm by Bentley, Jon (1984).
+ * For example, for the sequence of values -2, 1, -3, 4, -1, 2, 1, -5, 4
+ * the contiguous subarray with the largest sum is 4, -1, 2, 1, with sum 6.
+ *
+ * Time complexity: O(N log N).
+ *
+ * @example
+ * var max = require('path-to-algorithms/src/searching/'+
+ * 'maximum-subarray-divide-and-conquer').maxSubarray;
+ * console.log(max([-2, 1, -3, 4, -1, 2, 1, -5, 4])); // 6
+ *
+ * @public
+ * @module searching/maximum-subarray-divide-and-conquer
+ * @param {Array} array Input array.
+ * @return {Number} Maximum sum of the elements of a subarray.
+ */
+ function maxSubarray(array) {
+ return maxSubarrayPartitioner(array, 0, array.length);
+ }
+
+ exports.maxSubarray = maxSubarray;
+
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/searching/maximum-subarray.js b/src/searching/maximum-subarray.js
new file mode 100644
index 00000000..85ae9d11
--- /dev/null
+++ b/src/searching/maximum-subarray.js
@@ -0,0 +1,34 @@
+(function (exports) {
+ 'use strict';
+
+ /**
+ * Finds the maximum sum of the elements of a subarray in a given array
+ * using the Kadane's algorithm.
+ * For example, for the sequence of values -2, 1, -3, 4, -1, 2, 1, -5, 4
+ * the contiguous subarray with the largest sum is 4, -1, 2, 1, with sum 6.
+ *
+ * Time complexity: O(N).
+ *
+ * @example
+ * var max = require('path-to-algorithms/src/searching/'+
+ * 'maximum-subarray').maxSubarray;
+ * console.log(max([-2, 1, -3, 4, -1, 2, 1, -5, 4])); // 6
+ *
+ * @public
+ * @module searching/maximum-subarray
+ * @param {Array} array Input array.
+ * @return {Number} Maximum sum of the elements of a subarray.
+ */
+ function maxSubarray(array) {
+ var currentMax = array[0];
+ var max = array[0];
+ for (var i = 1; i < array.length; i += 1) {
+ currentMax = Math.max(array[i], currentMax + array[i]);
+ max = Math.max(max, currentMax);
+ }
+ return max;
+ }
+
+ exports.maxSubarray = maxSubarray;
+
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/searching/quickselect.js b/src/searching/quickselect.js
new file mode 100644
index 00000000..7ba9790c
--- /dev/null
+++ b/src/searching/quickselect.js
@@ -0,0 +1,67 @@
+(function (exports) {
+ 'use strict';
+
+ /**
+ * Returns the n-th smallest element of list within
+ * lo..hi inclusive (i.e. lo <= n <= hi).
+ * Time complexity: O(N).
+ *
+ * @example
+ *
+ * var quickselect = require('path-to-algorithms/src/searching/'+
+ * 'quickselect').quickselect;
+ * var result = quickselect([5, 1, 2, 2, 0, 3], 1, 0, 5);
+ * console.log(result); // 1
+ *
+ * @public
+ * @module searching/quickselect
+ * @param {Array} arr Input array.
+ * @param {Number} n A number of an element.
+ * @param {Number} lo Low index.
+ * @param {Number} hi High index.
+ * @return Returns n-th smallest element.
+ */
+ function quickselect(arr, n, lo, hi) {
+ function partition(arr, lo, hi, pivotIdx) {
+ function swap(arr, i, j) {
+ var temp = arr[i];
+ arr[i] = arr[j];
+ arr[j] = temp;
+ }
+ var pivot = arr[pivotIdx];
+ swap(arr, pivotIdx, hi);
+ for (var i = lo; i < hi; i += 1) {
+ if (arr[i] < pivot) {
+ swap(arr, i, lo);
+ lo += 1;
+ }
+ }
+ swap(arr, hi, lo);
+ return lo;
+ }
+
+ if (arr.length <= n) {
+ return undefined;
+ }
+ lo = lo || 0;
+ hi = hi || arr.length - 1;
+ if (lo === hi) {
+ return arr[lo];
+ }
+ while (hi >= lo) {
+ var pivotIdx =
+ partition(arr, lo, hi, lo + Math.floor(Math.random() * (hi - lo + 1)));
+ if (n === pivotIdx) {
+ return arr[pivotIdx];
+ }
+ if (n < pivotIdx) {
+ hi = pivotIdx - 1;
+ } else {
+ lo = pivotIdx + 1;
+ }
+ }
+ return undefined;
+ }
+ exports.quickselect = quickselect;
+
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/searching/recursive-binarysearch.js b/src/searching/recursive-binarysearch.js
new file mode 100644
index 00000000..bf4aa952
--- /dev/null
+++ b/src/searching/recursive-binarysearch.js
@@ -0,0 +1,53 @@
+(function (exports) {
+ 'use strict';
+
+ var binarySearch = (function () {
+ /**
+ * @private
+ * @param {Array} array Array where we should find the index of the element
+ * @param {Number} value Value of the element which index should be found
+ * @param {Number} left Left index
+ * @param {Number} right Right index
+ * @returns {Number} index The index of the element or -1 if not found
+ */
+ function recursiveBinarySearch(array, value, left, right) {
+ if (left > right) {
+ return -1;
+ }
+ var middle = Math.floor((right + left) / 2);
+ if (array[middle] === value) {
+ return middle;
+ } else if (array[middle] > value) {
+ return recursiveBinarySearch(array, value, left, middle - 1);
+ } else {
+ return recursiveBinarySearch(array, value, middle + 1, right);
+ }
+ }
+
+ /**
+ * Recursive version of binary search.
+ * Searches for specific element in a given array using
+ * the binary search algorithm.
+ * Time complexity: O(log N).
+ *
+ * @example
+ *
+ * var search = require('path-to-algorithms/src/searching/'+
+ * 'recursive-binarysearch').binarySearch;
+ * console.log(search([1, 2, 3, 4, 5], 4)); // 3
+ *
+ * @public
+ * @module searching/recursive-binarysearch
+ * @param {Array} array Input array.
+ * @param {Number} value Value of the element which index should be found.
+ * @returns {Number} Index of the element or -1 if not found.
+ */
+ return function (array, value) {
+ return recursiveBinarySearch(array, value, 0, array.length);
+ };
+
+ }());
+
+ exports.binarySearch = binarySearch;
+
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/searching/subarray/maximum-subarray-divide-and-conquer.js b/src/searching/subarray/maximum-subarray-divide-and-conquer.js
deleted file mode 100644
index 1e815a44..00000000
--- a/src/searching/subarray/maximum-subarray-divide-and-conquer.js
+++ /dev/null
@@ -1,75 +0,0 @@
-/**
- * Finds the maximum subarray using the divide and conquer algorithm
- * by Bentley, Jon (1984) (complexity O(n(logn)));
- */
-
-(function (exports) {
-
- 'use strict';
-
- /**
- * Accepts an array and range. Finds the maximum sum of elements
- * around the middle of the range.
- *
- * @param {array} array
- * @param {number} left - the left interval of the range
- * @param {number} middle - the middle of the range
- * @param {number} right - the right side of the range
- * @return {number} the maximum sum including the middle element
- */
- function crossSubarray(array, left, middle, right) {
- var leftSum = -Infinity,
- rightSum = -Infinity,
- sum = 0,
- i;
-
- for (i = middle; i >= left; i -= 1) {
- if (sum + array[i] >= leftSum) {
- leftSum = sum + array[i];
- }
- sum += array[i];
- }
- sum = 0;
- for (i = middle + 1; i < right; i += 1) {
- if (sum + array[i] >= rightSum) {
- rightSum = sum + array[i];
- }
- sum += array[i];
- }
- return leftSum + rightSum;
- }
-
- /**
- * Using divide and conquer finds the maximum sum of subarray of the given
- *
- * @param {array} array
- * @param {number} left side of the range
- * @param {number} the right side of the range
- * @return {number} the maximum sum of the elements of
- * subarray whithin the given range
- */
- function maxSubarrayPartitioner(array, left, right) {
- if (right - left <= 1) {
- return array[left];
- }
- var middle = Math.floor((left + right) / 2),
- leftSum = maxSubarrayPartitioner(array, left, middle),
- rightSum = maxSubarrayPartitioner(array, middle, right),
- crossSum = crossSubarray(array, left, middle, right);
-
- return Math.max(crossSum, leftSum, rightSum);
- }
-
- /**
- * Returns the maximum sum of the elements of a subarray of the given array
- *
- * @param {array} the array
- * @return the maximum sum
- */
- function maxSubarray(array) {
- return maxSubarrayPartitioner(array, 0, array.length);
- }
-
- exports.maxSubarray = maxSubarray;
-
-}(typeof exports === 'undefined' ? window : exports));
diff --git a/src/searching/subarray/maximum-subarray.js b/src/searching/subarray/maximum-subarray.js
deleted file mode 100644
index c7603557..00000000
--- a/src/searching/subarray/maximum-subarray.js
+++ /dev/null
@@ -1,20 +0,0 @@
-/**
- * Finds the maximum sum of subarray's element of given array using the Kadane's algorithm
- * It's complexity is O(n). The algorithm can be found here: https://en.wikipedia.org/wiki/Maximum_subarray_problem#Kadane.27s_algorithm
- *
- * @public
- * @param {array} array Input array
- * @returns {number} max The maximum sum of the elements of subarray of the input
- *
- */
-function maxSubarray(array) {
- var currentMax = 0,
- max = 0;
-
- for (var i = 0; i < array.length; i += 1) {
- currentMax = Math.max(0, currentMax + array[i]);
- max = Math.max(max, currentMax);
- }
-
- return max;
-}
diff --git a/src/sets/quickfind.js b/src/sets/quickfind.js
new file mode 100644
index 00000000..a5a465b1
--- /dev/null
+++ b/src/sets/quickfind.js
@@ -0,0 +1,78 @@
+/**
+ * Keeps track of a set of elements partitioned into a
+ * number of disjoint (nonoverlapping) subsets.
+ * Allows to check whether the path between two nodes exists.
+ * The algorithm is inspired by Robert Sedgewick's Java implementation.
+ *
+ * The algorithm is inspired by Robert Sedgewick's Java implementation.
+ * {@link http://algs4.cs.princeton.edu/home/}
+ *
+ * @example
+ *
+ * var QuickFind = require('path-to-algorithms/src/sets/quickfind').QuickFind;
+ *
+ * var qfind = new QuickFind(10);
+ * qfind.union(0, 1);
+ * qfind.union(2, 1);
+ * qfind.union(3, 4);
+ * qfind.union(8, 9);
+ * qfind.union(4, 8);
+ *
+ * console.log(qfind.connected(0, 9)); // false
+ * console.log(qfind.connected(3, 9)); // true
+ *
+ * @public
+ * @module sets/quickfind
+ */
+(function (exports) {
+ 'use strict';
+
+ /**
+ * Initialization.
+ * Time complexity: O(N).
+ *
+ * @public
+ * @constructor
+ * @param {Numner} size Count of the nodes.
+ */
+ exports.QuickFind = function (size) {
+ this._ids = [];
+ for (var i = 0; i < size; i += 1) {
+ this._ids[i] = i;
+ }
+ };
+
+ /**
+ * Connects two nodes - p and q.
+ * Time complexity: O(N).
+ *
+ * @public
+ * @method
+ * @param {Number} p The first node.
+ * @param {Number} q The second node.
+ */
+ exports.QuickFind.prototype.union = function (p, q) {
+ var size = this._ids.length;
+ var pval = this._ids[p];
+ var qval = this._ids[q];
+ for (var i = 0; i < size; i += 1) {
+ if (this._ids[i] === qval) {
+ this._ids[i] = pval;
+ }
+ }
+ };
+
+ /**
+ * Checks whether two nodes are connected.
+ * Time complexity: O(1).
+ *
+ * @public
+ * @method
+ * @param {Number} p The first node.
+ * @param {Number} q The second node.
+ * @return {Boolean}
+ */
+ exports.QuickFind.prototype.connected = function (p, q) {
+ return this._ids[p] === this._ids[q];
+ };
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/sets/quickunion.js b/src/sets/quickunion.js
new file mode 100644
index 00000000..0d8bb402
--- /dev/null
+++ b/src/sets/quickunion.js
@@ -0,0 +1,86 @@
+/**
+ * Keeps track of a set of elements partitioned into a
+ * number of disjoint (nonoverlapping) subsets.
+ * Allows to check whether the path between two nodes exists.
+ *
+ * The algorithm is inspired by Robert Sedgewick's Java implementation.
+ * {@link http://algs4.cs.princeton.edu/home/}
+ *
+ * @example
+ *
+ * var QuickUnion = require('path-to-algorithms/' +
+ * 'src/sets/quickunion').QuickUnion;
+ *
+ * var qunion = new QuickUnion(10);
+ * qunion.union(0, 1);
+ * qunion.union(2, 1);
+ * qunion.union(3, 4);
+ * qunion.union(8, 9);
+ * qunion.union(4, 8);
+ *
+ * console.log(qunion.connected(0, 9)); // false
+ * console.log(qunion.connected(3, 9)); // true
+ *
+ * @public
+ * @module sets/quickunion
+ */
+
+(function (exports) {
+ 'use strict';
+
+ /**
+ * Initialization.
+ * Time complexity: O(N).
+ *
+ * @public
+ * @constructor
+ * @param {Numner} size Count of the nodes.
+ */
+ exports.QuickUnion = function (n) {
+ this._ids = [];
+ for (var i = 0; i < n; i += 1) {
+ this._ids[i] = i;
+ }
+ };
+
+ /**
+ * Finds the root of given node.
+ * Time complexity: O(N).
+ * @private
+ * @param {Number} i The given node.
+ * @return {Number} Root of the given node.
+ */
+ exports.QuickUnion.prototype._root = function (i) {
+ while (i !== this._ids[i]) {
+ i = this._ids[i];
+ }
+ return i;
+ };
+
+ /**
+ * Connects two nodes - p and q.
+ * Time complexity: O(N).
+ *
+ * @public
+ * @method
+ * @param {Number} p The first node.
+ * @param {Number} q The second node.
+ */
+ exports.QuickUnion.prototype.union = function (p, q) {
+ var pRoot = this._root(p);
+ var qRoot = this._root(q);
+ this._ids[pRoot] = qRoot;
+ };
+
+ /**
+ * Checks whether two nodes are connected.
+ * Time complexity: O(N).
+ *
+ * @param {Number} p The first node.
+ * @param {Number} q The second node.
+ * @return {Boolean} True/false depending on whether the nodes are connected.
+ */
+ exports.QuickUnion.prototype.connected = function (p, q) {
+ return this._root(p) === this._root(q);
+ };
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/sets/weightquickunion.js b/src/sets/weightquickunion.js
new file mode 100644
index 00000000..2fc9b099
--- /dev/null
+++ b/src/sets/weightquickunion.js
@@ -0,0 +1,101 @@
+/**
+ * Keeps track of a set of elements partitioned into a
+ * number of disjoint (nonoverlapping) subsets.
+ * Allows to check whether the path between two nodes exists.
+ *
+ * The algorithm is inspired by Robert Sedgewick's Java implementation.
+ * {@link http://algs4.cs.princeton.edu/home/}
+ *
+ * @example
+ *
+ * var QuickUnion = require('path-to-algorithms/' +
+ * 'src/sets/weightquickunion').QuickUnion;
+ *
+ * var qunion = new QuickUnion(10);
+ * qunion.union(0, 1);
+ * qunion.union(2, 1);
+ * qunion.union(3, 4);
+ * qunion.union(8, 9);
+ * qunion.union(4, 8);
+ *
+ * console.log(qunion.connected(0, 9)); // false
+ * console.log(qunion.connected(3, 9)); // true
+ *
+ * @public
+ * @module sets/weightquickunion
+ */
+
+(function (exports) {
+ 'use strict';
+
+ /**
+ * Initialization.
+ * Time complexity: O(N).
+ *
+ * @public
+ * @constructor
+ * @param {Numner} size Count of the nodes.
+ */
+ exports.QuickUnion = function (n) {
+ this._ids = [];
+ this._size = [];
+ for (var i = 0; i < n; i += 1) {
+ this._ids[i] = i;
+ this._size[i] = 1;
+ }
+ };
+
+ /**
+ * Finds the root of given node.
+ * Time complexity: O(log N).
+ * @private
+ * @param {Number} i The given node.
+ * @return {Number} Root of the given node.
+ */
+ exports.QuickUnion.prototype._root = function (i) {
+ while (i !== this._ids[i]) {
+ // this._ids[i] = this._ids[this._ids[i]]; //enables the path compression
+ i = this._ids[i];
+ }
+ return i;
+ };
+
+ /**
+ * Checks whether two nodes are connected.
+ * Time complexity: O(log N).
+ *
+ * @param {Number} p The first node.
+ * @param {Number} q The second node.
+ * @return {Boolean} True/false depending on whether the nodes are connected.
+ */
+ exports.QuickUnion.prototype.connected = function (p, q) {
+ return this._root(p) === this._root(q);
+ };
+
+ /**
+ * Connects two nodes - p and q.
+ * Time complexity: O(log N).
+ *
+ * @public
+ * @method
+ * @param {Number} p The first node.
+ * @param {Number} q The second node.
+ */
+ exports.QuickUnion.prototype.union = function (p, q) {
+ var pf = this._root(p);
+ var qf = this._root(q);
+ if (pf === qf) {
+ return; // already linked
+ }
+ var psz = this._size[qf];
+ var qsz = this._size[pf];
+ if (psz < qsz) {
+ this._ids[pf] = qf;
+ this._size[qf] += psz;
+ } else {
+ this._ids[qf] = pf;
+ this._size[pf] += qsz;
+ }
+ };
+
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/shuffle/fisheryates.js b/src/shuffle/fisheryates.js
index 54032dc4..ccb26734 100644
--- a/src/shuffle/fisheryates.js
+++ b/src/shuffle/fisheryates.js
@@ -1,22 +1,32 @@
-/**
- * The shuffling algorithm of
- * Fisher-Yates. Complexity O(n)
- *
- * @param {array} array The array which should be shuffled
- * @return {array} The shuffled array.
- */
-function shuffle(array) {
- var size = array.length,
- rand, temp;
- for (var i = 1; i < size; i += 1) {
- rand = Math.round(Math.random() * i);
- temp = array[rand];
- array[rand] = array[i];
- array[i] = temp;
+(function (exports) {
+
+ 'use strict';
+
+ /**
+ * The shuffling algorithm of
+ * Fisher-Yates.
+ * Time complexity: O(N).
+ *
+ * @example
+ * var shuffle = require('path-to-algorithms/src/' +
+ * 'shuffle/fisheryates').shuffle;
+ * console.log(shuffle([1, 2, 3, 4, 5])); // shuffled array
+ *
+ * @public
+ * @module shuffle/fisheryates
+ * @param {Array} array Array which should be shuffled.
+ * @return {Array} Shuffled array.
+ */
+ function shuffle(array) {
+ var size = array.length;
+ var rand;
+ for (var i = 0; i < size; i += 1) {
+ rand = Math.floor(i + Math.random() * (size - i));
+ [array[rand], array[i]] = [array[i], array[rand]];
+ }
+ return array;
}
- return array;
-}
-//var array = [1,2,3,4,5,6,7,8,9];
-//console.log(array);
-//console.log(shuffle(array));
+ exports.shuffle = shuffle;
+
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/shuffle/richarddurstenfeld.js b/src/shuffle/richarddurstenfeld.js
index 26d507e3..789d8517 100644
--- a/src/shuffle/richarddurstenfeld.js
+++ b/src/shuffle/richarddurstenfeld.js
@@ -1,27 +1,36 @@
-/**
- * Shuffle of an array elements.
- * This algorithm is modified version of Fisher-Yates shuffle
- * algorithm and is introduced by Richard Durstenfeld.
- */
+(function (exports) {
-var array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+ 'use strict';
-/**
- * Shuffles an array. Complexity O(n).
- *
- * @param {array} array An array which should be shuffled
- * @returns {array} Shuffled array
- */
-function shuffle(array) {
- var arraySize = array.length - 1,
- rand, temp;
+ /**
+ * Shuffle of an array elements.
+ * This algorithm is modified version of Fisher-Yates shuffle
+ * algorithm and is introduced by Richard Durstenfeld.
+ * Time complexity: O(N).
+ *
+ * @example
+ * var shuffle = require('path-to-algorithms/src/shuffle' +
+ * '/richarddurstenfeld').shuffle;
+ * console.log(shuffle([1, 2, 3, 4, 5])); // random shuffled
+ *
+ * @public
+ * @module shuffle/richarddurstenfeld
+ * @param {Array} array An array which should be shuffled.
+ * @return {Array} Shuffled array.
+ */
+ function shuffle(array) {
+ var arraySize = array.length - 1;
+ var rand;
+ var temp;
for (var i = arraySize; i >= 0; i -= 1) {
- rand = Math.round(Math.random() * arraySize);
- temp = array[i];
- array[i] = array[rand];
- array[rand] = temp;
+ rand = Math.round(Math.random() * arraySize);
+ temp = array[i];
+ array[i] = array[rand];
+ array[rand] = temp;
}
return array;
-}
+ }
-console.log(shuffle(array));
+ exports.shuffle = shuffle;
+
+}(typeof exports === 'undefined' ? window : exports));
diff --git a/src/sorting/3-way-string-quicksort.js b/src/sorting/3-way-string-quicksort.js
new file mode 100644
index 00000000..ff8460e4
--- /dev/null
+++ b/src/sorting/3-way-string-quicksort.js
@@ -0,0 +1,70 @@
+(function (exports) {
+ 'use strict';
+
+ var quicksort = (function () {
+
+ function charAt(str, i) {
+ return (i < str.length) ? str.charCodeAt(i) : -1;
+ }
+
+ function swap(arr, i, j) {
+ var temp = arr[j];
+ arr[j] = arr[i];
+ arr[i] = temp;
+ }
+
+ function quicksort(arr, lo, hi, d) {
+ if (lo >= hi) {
+ return;
+ }
+ var lowPointer = lo;
+ var highPointer = hi;
+ var p = charAt(arr[lo], d);
+ var i = lo + 1;
+ var current;
+
+ while (i <= highPointer) {
+ current = charAt(arr[i], d);
+ if (current < p) {
+ swap(arr, i, lowPointer);
+ lowPointer += 1;
+ } else if (current > p) {
+ swap(arr, i, highPointer);
+ highPointer -= 1;
+ i += 1;
+ } else {
+ i += 1;
+ }
+ }
+
+ quicksort(arr, lo, lowPointer - 1, d);
+ if (p >= 0) {
+ quicksort(arr, lowPointer, highPointer, d + 1);
+ }
+ quicksort(arr, highPointer + 1, hi, d);
+ }
+
+ /**
+ * Effective inplace string sorting algorithm.
+ * Algorithm is NOT stable.
+ *
+ * @example
+ *
+ * var sort = require('path-to-algorithms/src/sorting'+
+ * '/3-way-string-quicksort').quicksort;
+ * console.log(sort(['bb', 'aa', 'cc'])); // [ 'aa', 'bb', 'cc' ]
+ *
+ * @public
+ * @module sorting/3-way-string-quicksort
+ * @param arr {Array} array which should be sorted.
+ * @return {Array} Sorted array.
+ */
+ return function sort(arr) {
+ quicksort(arr, 0, arr.length - 1, 0);
+ return arr;
+ };
+ }());
+
+ exports.quicksort = quicksort;
+
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/sorting/bubblesort.js b/src/sorting/bubblesort.js
new file mode 100644
index 00000000..f39a18e2
--- /dev/null
+++ b/src/sorting/bubblesort.js
@@ -0,0 +1,47 @@
+(function (exports) {
+ 'use strict';
+
+ function comparator(a, b) {
+ return a - b;
+ }
+
+ /**
+ * Bubble sort algorithm.
+ * Complexity: O(N^2).
+ *
+ * @example
+ * var sort = require('path-to-algorithms/src/' +
+ * 'sorting/bubblesort').bubbleSort;
+ * console.log(sort([2, 5, 1, 0, 4])); // [ 0, 1, 2, 4, 5 ]
+ *
+ * @public
+ * @module sorting/bubblesort
+ * @param {Array} array Input array.
+ * @param {Function} cmp Optional. A function that defines an
+ * alternative sort order. The function should return a negative,
+ * zero, or positive value, depending on the arguments.
+ * @return {Array} Sorted array.
+ */
+ function bubbleSort(array, cmp) {
+ cmp = cmp || comparator;
+ var temp;
+ for (var i = 0; i < array.length - 1 ; i += 1) {
+ var swapCount = 0;
+ for (var j = 0; j < array.length - 1 - i; j += 1) {
+ if (cmp(array[j], array[j + 1 ]) > 0) {
+ temp = array[j];
+ array[j] = array[j + 1];
+ array[j + 1] = temp;
+ swapCount += 1;
+ }
+ }
+ if (swapCount === 0){
+ break;
+ }
+ }
+ return array;
+ }
+
+ exports.bubbleSort = bubbleSort;
+
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/sorting/bubblesort/bubblesort.js b/src/sorting/bubblesort/bubblesort.js
deleted file mode 100644
index 9a481b89..00000000
--- a/src/sorting/bubblesort/bubblesort.js
+++ /dev/null
@@ -1,31 +0,0 @@
-(function (exports) {
-
- function comparator(a, b) {
- return a - b;
- }
-
- /**
- * The bubblesort algorithm. Complexity O(n^2).
- *
- * @public
- * @param {array} array Input array
- * @returns {array} array Sorted array
- */
- function bubbleSort(array, cmp) {
- cmp = cmp || comparator;
- var temp;
- for (var i = 0; i < array.length; i += 1) {
- for (var j = i; j > 0; j -= 1) {
- if (cmp(array[j], array[j - 1]) < 0) {
- temp = array[j];
- array[j] = array[j - 1];
- array[j - 1] = temp;
- }
- }
- }
- return array;
- }
-
- exports.bubbleSort = bubbleSort;
-
-}(typeof exports === 'undefined' ? window : exports));
diff --git a/src/sorting/linearsort/bucketsort.js b/src/sorting/bucketsort.js
similarity index 77%
rename from src/sorting/linearsort/bucketsort.js
rename to src/sorting/bucketsort.js
index b77c671e..73dab2f1 100644
--- a/src/sorting/linearsort/bucketsort.js
+++ b/src/sorting/bucketsort.js
@@ -2,12 +2,6 @@
'use strict';
- /**
- * Bucket sort. This algorithm has complexity O(n) in case the
- * data is with uniform distribution.
- *
- * @public
- */
var bucketSort = (function () {
/**
@@ -18,8 +12,8 @@
* @returns {array} array Sorted input array
*/
function insertionSort(array) {
- var current,
- j;
+ var current;
+ var j;
for (var i = 1; i < array.length; i += 1) {
current = array[i];
j = i - 1;
@@ -42,8 +36,9 @@
* from the input which are with suitable size.
*/
function createBuckets(array) {
- var buckets = [],
- currentBucket, current;
+ var buckets = [];
+ var currentBucket;
+ var current;
for (var i = 0; i < array.length; i += 1) {
current = array[i];
currentBucket = Math.floor(current);
@@ -78,8 +73,8 @@
* all elements form each bucket
*/
function unionBuckets(buckets) {
- var result = [],
- currentBucket;
+ var result = [];
+ var currentBucket;
for (var i = 0; i < buckets.length; i += 1) {
currentBucket = buckets[i];
if (currentBucket !== undefined) {
@@ -90,11 +85,20 @@
}
/**
- * Sorts given array with bucketsort
+ * Sorts given array with bucketsort.
+ * Time complexity: O(N) in case the
+ * data is with uniform distribution.
+ *
+ * @example
+ *
+ * var sort = require('path-to-algorithms/src/'+
+ * 'sorting/bucketsort').bucketSort;
+ * console.log(sort([2, 5, 1, 0, 4])); // [ 0, 1, 2, 4, 5 ]
*
* @public
- * @param {array} array Input array which should be sorted
- * @returns {array} Sorted array
+ * @module sorting/bucketsort
+ * @param {Array} array Input array which should be sorted.
+ * @return {Array} Sorted array.
*/
return function (array) {
var buckets = createBuckets(array);
@@ -105,4 +109,4 @@
exports.bucketSort = bucketSort;
-}(typeof exports === 'undefined' ? window : exports));
\ No newline at end of file
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/sorting/linearsort/countingsort.js b/src/sorting/countingsort.js
similarity index 51%
rename from src/sorting/linearsort/countingsort.js
rename to src/sorting/countingsort.js
index b235f803..fc8f809d 100644
--- a/src/sorting/linearsort/countingsort.js
+++ b/src/sorting/countingsort.js
@@ -1,25 +1,18 @@
(function (exports) {
-
'use strict';
- /**
- * Counting sort algorithm. It's with complexity O(n) but it's
- * correct only for array of integers.
- *
- * @public
- */
var countingSort = (function () {
/**
- * Gets the count of the elements into the input array
+ * Gets the count of the elements into the input array.
*
* @private
- * @param {array} array The input array
- * @returns {array} count The count of each element from the input array
+ * @param {Array} array The input array.
+ * @return {Array} The count of each element from the input array.
*/
function getCount(array) {
- var count = [],
- current;
+ var count = [];
+ var current;
for (var i = 0; i < array.length; i += 1) {
current = array[i];
count[current] = (count[current] || 0) + 1;
@@ -28,16 +21,16 @@
}
/**
- * Gets the count of the elements which are less than a given
+ * Gets the count of the elements which are less than a given.
*
* @private
- * @param {array} array The input array
- * @returns {array} less The count of the elements which
- * are less than each element from the input
+ * @param {Array} array The input array.
+ * @return {Array} less The count of the elements which.
+ * are less than each element from the input.
*/
function getLessCount(array) {
- var less = [],
- last;
+ var less = [];
+ var last;
less[0] = array[0] || 0;
for (var i = 1; i < array.length; i += 1) {
last = array[i - 1] || 0;
@@ -47,18 +40,18 @@
}
/**
- * Sorts the input array
+ * Sorts the input array.
*
* @private
- * @param {array} array Input which should be sorted
- * @param {array} less Count of the less elements for each element
- * @returns {array} result The sorted input
+ * @param {Array} array Input which should be sorted.
+ * @param {Array} less Count of the less elements for each element.
+ * @return {Array} The sorted input.
*/
function sort(array, less) {
- var result = [],
- currentPositions = [],
- current,
- position;
+ var result = [];
+ var currentPositions = [];
+ var current;
+ var position;
for (var i = 0; i < array.length; i += 1) {
current = array[i];
position = less[current];
@@ -72,11 +65,19 @@
}
/**
- * Sorts a given array
+ * Counting sort algorithm. It's correct only
+ * for array of integers.
+ * Time complexity: O(N).
+ *
+ * @example
+ * var sort = require('path-to-algorithms/src/' +
+ * 'sorting/countingsort').countingSort;
+ * console.log(sort([2, 5, 1, 3, 4])); // [ 1, 2, 3, 4, 5 ]
*
* @public
- * @param {array} array Array which should be sorted
- * @returns {array} array Sorted array
+ * @module sorting/countingsort
+ * @param {Array} array Array which should be sorted.
+ * @return {Array} Sorted array.
*/
return function (array) {
var less = getLessCount(getCount(array));
@@ -86,4 +87,4 @@
exports.countingSort = countingSort;
-}(typeof exports === 'undefined' ? window : exports));
\ No newline at end of file
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/sorting/heapsort/heapsort.js b/src/sorting/heapsort.js
similarity index 52%
rename from src/sorting/heapsort/heapsort.js
rename to src/sorting/heapsort.js
index aeb2df1d..765adc3a 100644
--- a/src/sorting/heapsort/heapsort.js
+++ b/src/sorting/heapsort.js
@@ -1,30 +1,26 @@
(function (exports) {
-
'use strict';
function comparator(a, b) {
return a - b;
}
- /**
- * The heapsort algorithm. It's complexity is O(nlog n).
- *
- * @public
- */
var heapSort = (function () {
/**
* Finds the correct place of given element in given max heap.
*
* @private
- * @param {array} array Array
- * @param {number} index Index of the element which palce in
- * the max heap should be found.
+ * @param {Array} array Array.
+ * @param {Number} index Index of the element which palce in
+ * the max heap should be found.
+ * @param {Number} heapSize Size of the heap.
+ * @param {function} cmp Comparison function.
*/
function heapify(array, index, heapSize, cmp) {
- var left = 2 * index + 1,
- right = 2 * index + 2,
- largest = index;
+ var left = 2 * index + 1;
+ var right = 2 * index + 2;
+ var largest = index;
if (left < heapSize && cmp(array[left], array[index]) > 0) {
largest = left;
@@ -46,8 +42,9 @@
* Builds max heap from given array.
*
* @private
- * @param {array} array Array which should be turned into max heap
- * @returns {array} array Array turned into max heap
+ * @param {Array} array Array which should be turned into max heap.
+ * @param {function} cmp Comparison function.
+ * @return {Array} array Array turned into max heap.
*/
function buildMaxHeap(array, cmp) {
for (var i = Math.floor(array.length / 2); i >= 0; i -= 1) {
@@ -57,16 +54,28 @@
}
/**
- * Heapsort. Turns the input array into max heap and after that sorts it.
+ * Heapsort. Turns the input array into max
+ * heap and after that sorts it.
+ * Time complexity: O(N log N).
+ *
+ * @example
+ *
+ * var sort = require('path-to-algorithms/src' +
+ * '/sorting/heapsort').heapSort;
+ * console.log(sort([2, 5, 1, 0, 4])); // [ 0, 1, 2, 4, 5 ]
*
* @public
- * @param {array} array Input array
- * @returns {array} array Sorted array
+ * @module sorting/heapsort
+ * @param {Array} array Input array.
+ * @param {Function} cmp Optional. A function that defines an
+ * alternative sort order. The function should return a negative,
+ * zero, or positive value, depending on the arguments.
+ * @return {Array} Sorted array.
*/
return function (array, cmp) {
cmp = cmp || comparator;
- var size = array.length,
- temp;
+ var size = array.length;
+ var temp;
buildMaxHeap(array, cmp);
for (var i = array.length - 1; i > 0; i -= 1) {
temp = array[0];
@@ -81,4 +90,4 @@
exports.heapSort = heapSort;
-}(typeof exports === 'undefined' ? window : exports));
\ No newline at end of file
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/sorting/insertionsort/insertion-binary-sort.js b/src/sorting/insertion-binary-sort.js
similarity index 54%
rename from src/sorting/insertionsort/insertion-binary-sort.js
rename to src/sorting/insertion-binary-sort.js
index 1b632f88..4ee6518a 100644
--- a/src/sorting/insertionsort/insertion-binary-sort.js
+++ b/src/sorting/insertion-binary-sort.js
@@ -1,5 +1,4 @@
(function (exports) {
-
'use strict';
function comparator(a, b) {
@@ -7,21 +6,32 @@
}
/**
- * Modified version of insertionsort. It uses binary search for finding
+ * Modified version of insertion sort. It uses binary search for finding
* where the current element should be inserted. It's correct because
* the binary search looks just in the first part of the array
- * which is actually sorted. It's complexity is O(n^2)
+ * which is actually sorted.
+ * Time complexity: O(N^2).
+ *
+ * @example
+ *
+ * var sort = require('path-to-algorithms/src' +
+ * '/sorting/insertion-binary-sort').insertionBinarySort;
+ * console.log(sort([2, 5, 1, 0, 4])); // [ 0, 1, 2, 4, 5 ]
*
* @public
- * @param {array} array Input array
- * @param {array} array Sorted array
+ * @module sorting/insertion-binary-sort
+ * @param {Array} array Input array.
+ * @param {Function} cmp Optional. A function that defines an
+ * alternative sort order. The function should return a negative,
+ * zero, or positive value, depending on the arguments.
+ * @return {Array} Sorted array.
*/
function insertionBinarySort(array, cmp) {
cmp = cmp || comparator;
- var current,
- middle,
- left,
- right;
+ var current;
+ var middle;
+ var left;
+ var right;
for (var i = 1; i < array.length; i += 1) {
current = array[i];
left = 0;
@@ -45,4 +55,4 @@
exports.insertionBinarySort = insertionBinarySort;
-}(typeof exports === 'undefined' ? window : exports));
\ No newline at end of file
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/sorting/insertionsort.js b/src/sorting/insertionsort.js
new file mode 100644
index 00000000..3e5e6659
--- /dev/null
+++ b/src/sorting/insertionsort.js
@@ -0,0 +1,44 @@
+(function (exports) {
+ 'use strict';
+
+ function compare(a, b) {
+ return a - b;
+ }
+
+ /**
+ * Insertionsort algorithm.
+ * Time complexity: O(N^2).
+ *
+ * @example
+ *
+ * var sort = require('path-to-algorithms/src' +
+ * '/sorting/insertion-sort').insertionSort;
+ * console.log(sort([2, 5, 1, 0, 4])); // [ 0, 1, 2, 4, 5 ]
+ *
+ * @public
+ * @module sorting/insertionsort
+ * @param {Array} array Input array.
+ * @param {Function} cmp Optional. A function that defines an
+ * alternative sort order. The function should return a negative,
+ * zero, or positive value, depending on the arguments.
+ * @return {Array} Sorted array.
+ */
+ function insertionSort(array, cmp) {
+ cmp = cmp || compare;
+ var current;
+ var j;
+ for (var i = 1; i < array.length; i += 1) {
+ current = array[i];
+ j = i - 1;
+ while (j >= 0 && cmp(array[j], current) > 0) {
+ array[j + 1] = array[j];
+ j -= 1;
+ }
+ array[j + 1] = current;
+ }
+ return array;
+ }
+
+ exports.insertionSort = insertionSort;
+
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/sorting/insertionsort/insertionsort.js b/src/sorting/insertionsort/insertionsort.js
deleted file mode 100644
index ef7bc1a1..00000000
--- a/src/sorting/insertionsort/insertionsort.js
+++ /dev/null
@@ -1,34 +0,0 @@
-(function (exports) {
-
- 'use strict';
-
- function compare(a, b) {
- return a - b;
- }
-
- /**
- * Insertionsort algorithm. It's complexity is O(n^2).
- *
- * @public
- * @param {array} array Input array
- * @returns {array} array Sorted array
- */
- function insertionSort(array, cmp) {
- cmp = cmp || compare;
- var current,
- j;
- for (var i = 1; i < array.length; i += 1) {
- current = array[i];
- j = i - 1;
- while (j >= 0 && cmp(array[j], current) > 0) {
- array[j + 1] = array[j];
- j -= 1;
- }
- array[j + 1] = current;
- }
- return array;
- }
-
- exports.insertionSort = insertionSort;
-
-}(typeof exports === 'undefined' ? window : exports));
\ No newline at end of file
diff --git a/src/sorting/insertionsort/recursive-insertionsort.js b/src/sorting/insertionsort/recursive-insertionsort.js
deleted file mode 100644
index fb94a3bd..00000000
--- a/src/sorting/insertionsort/recursive-insertionsort.js
+++ /dev/null
@@ -1,36 +0,0 @@
-(function (exports) {
-
- 'use strict';
-
- function compare(a, b) {
- return a - b;
- }
-
- /**
- * Recursive version of insertionsort. Complexity O(n^2).
- *
- * @public
- * @param {array} array Input array
- * @param {number} [max] Index of the element which place we should find
- * in the current function call
- */
- function recursiveInsertionSort(array, cmp, max) {
- cmp = cmp || compare;
- if (max <= 0) {
- return array;
- }
- if (max === undefined) {
- max = array.length - 1;
- }
- recursiveInsertionSort(array, cmp, max - 1);
- for (var i = max - 1, current = array[max];
- i >= 0 && cmp(current, array[i]) < 0; i -= 1) {
- array[i + 1] = array[i];
- }
- array[i + 1] = current;
- return array;
- }
-
- exports.recursiveInsertionSort = recursiveInsertionSort;
-
-}(typeof exports === 'undefined' ? window : exports));
\ No newline at end of file
diff --git a/src/sorting/lsd.js b/src/sorting/lsd.js
new file mode 100644
index 00000000..d1445203
--- /dev/null
+++ b/src/sorting/lsd.js
@@ -0,0 +1,51 @@
+(function (exports) {
+ 'use strict';
+
+ /**
+ * Sorts strings lexicographically.
+ * Time complexity: O(N*M) for N keys which have M or fewer digits.
+ *
+ * @example
+ *
+ * var sort = require('../src/sorting/lsd').lsd;
+ * // [ 'aab', 'aaa', 'acc', 'bbb', 'bcc' ]
+ * console.log(sort(['aab', 'bbb', 'aaa', 'acc', 'bcc']));
+ *
+ * @public
+ * @module sorting/lsd
+ * @param {Array} arr Array which should be sorted.
+ * @param {Number} letterIdx Optional. Index to start sorting from.
+ * @return {Array} Sorted array.
+ */
+ function lsd(arr, letterIdx) {
+ var temp;
+ var count;
+ letterIdx = letterIdx || 1;
+ for (var i = letterIdx - 1; i >= 0; i -= 1) {
+ count = [];
+ temp = [];
+ for (var j = 0; j < arr.length; j += 1) {
+ var charCode = arr[j].charCodeAt(i);
+ var old = count[charCode + 1] || 0;
+ count[charCode + 1] = old + 1;
+ }
+ for (var c = 0; c < count.length - 1; c += 1) {
+ count[c] = count[c] || 0;
+ count[c + 1] = count[c + 1] || 0;
+ count[c + 1] += count[c];
+ }
+ for (j = 0; j < arr.length; j += 1) {
+ var code = arr[j].charCodeAt(i);
+ temp[count[code]] = arr[j];
+ count[code] += 1;
+ }
+ for (j = 0; j < arr.length; j += 1) {
+ arr[j] = temp[j];
+ }
+ }
+ return arr;
+ }
+
+ exports.lsd = lsd;
+
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/sorting/mergesort.js b/src/sorting/mergesort.js
new file mode 100644
index 00000000..ab7c2a0c
--- /dev/null
+++ b/src/sorting/mergesort.js
@@ -0,0 +1,103 @@
+(function (exports) {
+ /**
+ * Mergesort module.
+ */
+ 'use strict';
+
+ var ll = require('../data-structures/linked-list.js');
+
+ function compare(a, b) {
+ return a - b;
+ }
+
+ /**
+ * Mergesort method which is recursively called for sorting the input array.
+ *
+ * @public
+ * @module sorting/mergesort
+ * @param {Array} array The array which should be sorted.
+ * @param {Function} cmp Compares two items in an array.
+ * @param {Number} start Left side of the subarray.
+ * @param {Number} end Right side of the subarray.
+ * @returns {Array} Array with sorted subarray.
+ *
+ * @example
+ * var array = [2, 4, 1, 5, 6, 7];
+ * var mergeSort =
+ * require('path-to-algorithms/src/sorting/mergesort').mergeSort;
+ * mergeSort(array); // [1, 2, 4, 5, 6, 7]
+ */
+ function mergeSort(array, cmp, start, end) {
+ cmp = cmp || compare;
+ start = start || 0;
+ end = end || array.length;
+ if (Math.abs(end - start) <= 1) {
+ return [];
+ }
+ var middle = Math.ceil((start + end) / 2);
+
+ mergeSort(array, cmp, start, middle);
+ mergeSort(array, cmp, middle, end);
+
+ return mergeSort.merge(array, cmp, start, middle, end);
+ }
+
+ /**
+ * Devides and sort merges two subarrays of given array
+ *
+ * @public
+ * @module sorting/mergesort/merge
+ * @param {Array} array The array which subarrays should be sorted.
+ * @param {Number} start The start of the first subarray.
+ * This subarray is with end middle - 1.
+ * @param {Number} middle The start of the second array.
+ * @param {Number} end end - 1 is the end of the second array.
+ * @returns {Array} The array with sorted subarray.
+ *
+ * @example
+ * var array = [1, 2, 3, 1, 4, 5, 6];
+ * var merge =
+ * require('path-to-algorithms/src/sorting/mergesort').merge;
+ * merge(array, function (a, b) { // [1, 1, 2, 3, 4, 5, 6]
+ * return a - b;
+ * }, 0, 4, 7);
+ */
+ mergeSort.merge = function (array, cmp, start, middle, end) {
+ var left = new ll.LinkedList();
+ var right = new ll.LinkedList();
+
+ var leftSize = middle - start;
+ var rightSize = end - middle;
+ var maxSize = Math.max(leftSize, rightSize);
+ var size = end - start;
+ var i;
+
+ for (i = 0; i < maxSize; i += 1) {
+ if (i < leftSize) {
+ left.push(array[start + i]);
+ }
+ if (i < rightSize) {
+ right.push(array[middle + i]);
+ }
+ }
+ i = 0;
+ while (i < size) {
+ if (left.first && right.first) {
+ if (cmp(left.first.data, right.first.data) > 0) {
+ array[start + i] = right.shift().data;
+ } else {
+ array[start + i] = left.shift().data;
+ }
+ } else if (left.first) {
+ array[start + i] = left.shift().data;
+ } else {
+ array[start + i] = right.shift().data;
+ }
+ i += 1;
+ }
+ return array;
+ };
+
+ exports.mergeSort = mergeSort;
+
+}(typeof exports === 'undefined' ? window : exports));
diff --git a/src/sorting/mergesort/mergesort.js b/src/sorting/mergesort/mergesort.js
deleted file mode 100644
index 506411f0..00000000
--- a/src/sorting/mergesort/mergesort.js
+++ /dev/null
@@ -1,93 +0,0 @@
-(function (exports) {
-
- 'use strict';
-
- var mergeSort = (function () {
-
- function compare(a, b) {
- return a - b;
- }
-
- /**
- * Mergesort method which is recursively called for sorting the input array.
- *
- * @private
- * @param {array} array The array which should be sorted
- * @param {number} start Left side of the subarray
- * @param {number} end Right side of the subarray
- * @returns {array} Array with sorted subarray
- */
- function mergesort(array, start, end, cmp) {
- if (Math.abs(end - start) <= 1) {
- return [];
- }
- var middle = Math.ceil((start + end) / 2);
-
- mergesort(array, start, middle, cmp);
- mergesort(array, middle, end, cmp);
-
- return merge(array, start, middle, end, cmp);
- }
-
- /**
- * Devides and sort merges two subarrays of given array
- *
- * @private
- * @param {array} array The array which subarrays should be sorted
- * @param {number} start The start of the first subarray. This subarray is with end middle - 1.
- * @param {number} middle The start of the second array
- * @param {number} end end - 1 is the end of the second array
- * @returns {array} The array with sorted subarray
- */
- function merge(array, start, middle, end, cmp) {
- var left = [],
- right = [],
- leftSize = middle - start,
- rightSize = end - middle,
- maxSize = Math.max(leftSize, rightSize),
- size = end - start,
- i;
-
- for (i = 0; i < maxSize; i += 1) {
- if (i < leftSize) {
- left[i] = array[start + i];
- }
- if (i < rightSize) {
- right[i] = array[middle + i];
- }
- }
- i = 0;
- while (i < size) {
- if (left.length && right.length) {
- if (cmp(left[0], right[0]) > 0) {
- array[start + i] = right.shift();
- } else {
- array[start + i] = left.shift();
- }
- } else if (left.length) {
- array[start + i] = left.shift();
- } else {
- array[start + i] = right.shift();
- }
- i += 1;
- }
- return array;
- }
-
- /**
- * Initial call to the mergesort method
- *
- * @public
- * @param {array} array The array which will be sorted
- * @returns {array} Sorted array
- */
- return function (array, cmp) {
- cmp = cmp || compare;
- return mergesort(array, 0, array.length, cmp);
- };
-
- }());
-
- exports.mergeSort = mergeSort;
-
-}(typeof exports === 'undefined' ? window : exports));
diff --git a/src/sorting/msd.js b/src/sorting/msd.js
new file mode 100644
index 00000000..f59e1718
--- /dev/null
+++ b/src/sorting/msd.js
@@ -0,0 +1,64 @@
+(function (exports) {
+ 'use strict';
+
+ function charCodeAt(str, i) {
+ return (i < str.length) ? str.charCodeAt(i) : -1;
+ }
+
+ function sort(arr, lo, hi, d) {
+ var temp = [];
+ var count = [];
+ var j;
+ var idx;
+ // Use Insertion sort when the
+ // array is smaller than given threshold
+ for (j = lo; j <= hi; j += 1) {
+ idx = charCodeAt(arr[j], d) + 2;
+ count[idx] = count[idx] || 0;
+ count[idx] += 1;
+ }
+ for (j = 0; j < count.length - 1; j += 1) {
+ count[j] = count[j] || 0;
+ count[j + 1] = count[j + 1] || 0;
+ count[j + 1] += count[j];
+ }
+ for (j = lo; j <= hi; j += 1) {
+ idx = charCodeAt(arr[j], d) + 1;
+ temp[count[idx]] = arr[j];
+ count[idx] += 1;
+ }
+ for (j = lo; j <= hi; j += 1) {
+ arr[j] = temp[j - lo];
+ }
+ for (j = 0; j < count.length - 2; j += 1) {
+ sort(arr, lo + count[j], lo + count[j + 1] - 1, d + 1);
+ }
+ }
+
+ /**
+ * Sorts given array lexicographically.
+ * Algorithms knows how to treat
+ * differently length strings.
+ * Algorithm is stable.
+ * Time complexity: O(N*M) for N keys which have M or fewer digits.
+ *
+ * @example
+ *
+ * var sort = require('../src/sorting/msd').msd;
+ * // [ 'aab', 'aaa', 'acc', 'bbb', 'bcc' ]
+ * console.log(sort(['aab', 'bbb', 'aaa', 'acc', 'bcc']));
+ *
+ * @public
+ * @module sorting/msd
+ * @param {Array} arr Array which should be sorted.
+ * @param {Number} d Optional. Digit from which sorting should start.
+ * @return {Array} Sorted array.
+ */
+ function msd(arr, d) {
+ d = d || 0;
+ sort(arr, 0, arr.length - 1, d);
+ return arr;
+ }
+
+ exports.msd = msd;
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/sorting/oddeven-sort.js b/src/sorting/oddeven-sort.js
new file mode 100644
index 00000000..2ed2a9ee
--- /dev/null
+++ b/src/sorting/oddeven-sort.js
@@ -0,0 +1,47 @@
+(function (exports) {
+ 'use strict';
+
+ /**
+ * Odd even sort algorithm.
+ * Complexity: O(N^2).
+ *
+ * @example
+ * var sort = require('path-to-algorithms/src/' +
+ * 'sorting/oddeven-sort').oddEvenSort;
+ * console.log(sort([2, 5, 1, 0, 4])); // [ 0, 1, 2, 4, 5 ]
+ *
+ * @public
+ * @module sorting/oddeven-sort
+ * @param {Array} array Input array.
+ * @return {Array} Sorted array.
+ */
+ function oddEvenSort(arr) {
+ function swap(arr, i, j) {
+ var temp = arr[i];
+ arr[i] = arr[j];
+ arr[j] = temp;
+ }
+
+ var sorted = false;
+ while (!sorted) {
+ sorted = true;
+ for (var i = 1; i < arr.length - 1; i += 2) {
+ if (arr[i] > arr[i + 1]) {
+ swap(arr, i, i + 1);
+ sorted = false;
+ }
+ }
+
+ for (i = 0; i < arr.length - 1; i += 2) {
+ if (arr[i] > arr[i + 1]) {
+ swap(arr, i, i + 1);
+ sorted = false;
+ }
+ }
+ }
+ return arr;
+ }
+
+ exports.oddEvenSort = oddEvenSort;
+
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/sorting/quicksort-declarative.js b/src/sorting/quicksort-declarative.js
new file mode 100644
index 00000000..062ef790
--- /dev/null
+++ b/src/sorting/quicksort-declarative.js
@@ -0,0 +1,68 @@
+(function (exports) {
+
+ 'use strict';
+
+ function compare(a, b) {
+ return a - b;
+ }
+
+ /**
+ * Quicksort algorithm (declarative variant)
+ *
+ * @public
+ * @param {array} array Array which should be sorted.
+ * @return {array} Sorted array.
+ */
+ var quickSort = (function () {
+
+ /**
+ * Recursively calls itself.
+ *
+ * @private
+ * @param {array} array Array which should be processed
+ */
+ function quicksort(array, cmp) {
+ if (array.length < 1) {
+ return array;
+ }
+
+ const [x, ...rest] = array;
+
+ return [
+ ...quicksort(rest.filter(v => cmp(v, x) < 0), cmp),
+ x,
+ ...quicksort(rest.filter(v => cmp(v, x) >= 0), cmp)
+ ];
+ }
+
+
+ /**
+ * Quicksort algorithm. In this version of quicksort used
+ * declarative programming mechanisms.
+ * Time complexity: O(N log(N)).
+ *
+ * @example
+ *
+ * var sort = require('path-to-algorithms/src' +
+ * '/sorting/quicksort-declarative').quickSort;
+ * console.log(sort([2, 5, 1, 0, 4])); // [ 0, 1, 2, 4, 5 ]
+ *
+ * @public
+ * @module sorting/quicksort-declarative
+ * @param {Array} array Input array.
+ * @param {Function} cmp Optional. A function that defines an
+ * alternative sort order. The function should return a negative,
+ * zero, or positive value, depending on the arguments.
+ * @return {Array} Sorted array.
+ */
+ return function (array, cmp) {
+ cmp = cmp || compare;
+ array = quicksort(array, cmp);
+ return array;
+ };
+
+ }());
+
+ exports.quickSort = quickSort;
+
+}(typeof exports === 'undefined' ? window : exports));
diff --git a/src/sorting/quicksort/quicksort-middle.js b/src/sorting/quicksort-middle.js
similarity index 67%
rename from src/sorting/quicksort/quicksort-middle.js
rename to src/sorting/quicksort-middle.js
index c85cdc8e..88729ff4 100644
--- a/src/sorting/quicksort/quicksort-middle.js
+++ b/src/sorting/quicksort-middle.js
@@ -1,9 +1,3 @@
-/**
- * Quicksort algorithm. It's with complexity O(n log(n)).
- * In this version of quicksort I use the middle element of the
- * array for pivot.
- */
-
(function (exports) {
'use strict';
@@ -23,8 +17,9 @@
/**
* Partitions the array in two parts by the middle elements.
- * All elemnts which are less than the chosen one goes left from it
+ * All elements which are less than the chosen one goes left from it
* all which are greater goes right from it.
+ * Uses Hoare's partitioning algorithm.
*
* @param {array} array Array which should be partitioned
* @param {number} left Left part of the array
@@ -32,8 +27,8 @@
* @return {number}
*/
function partition(array, left, right, cmp) {
- var pivot = array[Math.floor((left + right) / 2)],
- temp;
+ var pivot = array[Math.floor((left + right) / 2)];
+ var temp;
while (left <= right) {
while (cmp(array[left], pivot) < 0) {
left += 1;
@@ -72,8 +67,23 @@
}
/**
- * Quicksort's initial point
+ * Quicksort algorithm. In this version of quicksort used
+ * middle element of array for the pivot.
+ * Time complexity: O(N log(N)).
+ *
+ * @example
+ *
+ * var sort = require('path-to-algorithms/src' +
+ * '/sorting/quicksort-middle').quickSort;
+ * console.log(sort([2, 5, 1, 0, 4])); // [ 0, 1, 2, 4, 5 ]
+ *
* @public
+ * @module sorting/quicksort-middle
+ * @param {Array} array Input array.
+ * @param {Function} cmp Optional. A function that defines an
+ * alternative sort order. The function should return a negative,
+ * zero, or positive value, depending on the arguments.
+ * @return {Array} Sorted array.
*/
return function (array, cmp) {
cmp = cmp || compare;
@@ -85,4 +95,4 @@
exports.quickSort = quickSort;
-}(typeof exports === 'undefined' ? window : exports));
\ No newline at end of file
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/sorting/quicksort/quicksort.js b/src/sorting/quicksort.js
similarity index 88%
rename from src/sorting/quicksort/quicksort.js
rename to src/sorting/quicksort.js
index 0650c786..be3f6664 100644
--- a/src/sorting/quicksort/quicksort.js
+++ b/src/sorting/quicksort.js
@@ -14,7 +14,23 @@
}
/**
- * Partitions given subarray.
+ * Swap the places of two elements
+ *
+ * @private
+ * @param {array} array The array which contains the elements
+ * @param {number} i The index of the first element
+ * @param {number} j The index of the second element
+ * @returns {array} array The array with swapped elements
+ */
+ function swap(array, i, j) {
+ var temp = array[i];
+ array[i] = array[j];
+ array[j] = temp;
+ return array;
+ }
+
+ /**
+ * Partitions given subarray using Lomuto's partitioning algorithm.
*
* @private
* @param {array} array Input array
@@ -22,9 +38,9 @@
* @param {number} right The end of the subarray
*/
function partition(array, left, right, compare) {
- var cmp = array[right - 1],
- minEnd = left,
- maxEnd;
+ var cmp = array[right - 1];
+ var minEnd = left;
+ var maxEnd;
for (maxEnd = left; maxEnd < right - 1; maxEnd += 1) {
if (compare(array[maxEnd], cmp) < 0) {
swap(array, maxEnd, minEnd);
@@ -35,22 +51,6 @@
return minEnd;
}
- /**
- * Swap the places of two elements
- *
- * @private
- * @param {array} array The array which contains the elements
- * @param {number} i The index of the first element
- * @param {number} j The index of the second element
- * @returns {array} array The array with swaped elements
- */
- function swap(array, i, j) {
- var temp = array[i];
- array[i] = array[j];
- array[j] = temp;
- return array;
- }
-
/**
* Sorts given array.
*
@@ -84,4 +84,4 @@
exports.quickSort = quickSort;
-}(typeof exports === 'undefined' ? window : exports));
\ No newline at end of file
+}(typeof exports === 'undefined' ? window : exports));
diff --git a/src/sorting/radixsort.js b/src/sorting/radixsort.js
new file mode 100644
index 00000000..ef8325c4
--- /dev/null
+++ b/src/sorting/radixsort.js
@@ -0,0 +1,100 @@
+(function (exports) {
+ 'use strict';
+
+ var radixSort = (function () {
+
+ /**
+ * Returns the digit of a number that is 'lsdOffset'
+ * places from the least significant digit.
+ *
+ * @private
+ * @param {Number} number Number
+ * @param {Number} lsdOffset Offset of the digit to return, counting
+ * from the position of the least significant digit (e.g. lsdOffset = 0
+ * will return the least significant digit itself)
+ * @return {String} digit The specified number digit. Returns 'undefined'
+ * if lsdOffset is bigger or equal to the number of digits of the 'number'
+ * argument.
+ */
+ var getDigit = function (number, lsdOffset) {
+ var size = number.toString().length;
+ var digit;
+
+ if (lsdOffset >= 0 && lsdOffset < size) {
+ digit = number.toString()[size - 1 - lsdOffset];
+ }
+
+ return digit;
+ };
+
+ /**
+ * Least significant digit (LSD) Radix sort. A non-comparative,
+ * stable integer sorting algorithm.
+ * Worst-case time complexity is O(N K) for N keys with K being
+ * the average key length, measured in number of digits.
+ *
+ * @example
+ * var sort = require('path-to-algorithms/src/' +
+ * 'sorting/radixsort').radixSort;
+ * console.log(sort([2, 5, 1, 3, 4])); // [ 1, 2, 3, 4, 5 ]
+ *
+ * @public
+ * @module sorting/radixsort
+ * @param {Array} array Input integer array
+ * @return {Array} Sorted array
+ */
+ return function (array) {
+ var size = array.length;
+ var R = 10; /* Alphabet size ([0-9] for integers) */
+ var count;
+ var digit;
+ var i;
+ var j;
+
+ /* Find maximum key size */
+ var maxKeySize = (array[0] || '').toString().length;
+ for (i = 1; i < size; i += 1) {
+ var numStr = array[i].toString();
+ if (numStr.length > maxKeySize) {
+ maxKeySize = numStr.length;
+ }
+ }
+
+ for (i = 0; i < maxKeySize; i += 1) {
+ /* Initialize count */
+ count = [];
+ for (j = 0; j < R; j += 1) {
+ count[j] = 0;
+ }
+
+ /* Count frequency of each array element */
+ for (j = 0; j < size; j += 1) {
+ digit = getDigit(array[j], i) || 0;
+ count[digit] += 1;
+ }
+
+ /* Compute cumulates */
+ for (j = 1; j < R; j += 1) {
+ count[j] += count[j - 1];
+ }
+
+ /* Move elements to auxiliary array */
+ var aux = [];
+ for (j = size - 1; j >= 0; j -= 1) {
+ digit = getDigit(array[j], i) || 0;
+ count[digit] -= 1;
+ aux[count[digit]] = array[j];
+ }
+
+ /* Copy elements back from auxilary array */
+ for (j = 0; j < size; j += 1) {
+ array[j] = aux[j];
+ }
+ }
+ return array;
+ };
+ })();
+
+ exports.radixSort = radixSort;
+
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/sorting/readme.md b/src/sorting/readme.md
new file mode 100644
index 00000000..3d9d00f0
--- /dev/null
+++ b/src/sorting/readme.md
@@ -0,0 +1,21 @@
+# Comparison of all sorting algorithms
+
+| Algorithm | Complexity | When to use? |
+|----------------------------|-----------------------------------------------------|--------------|
+| 3-way-string-quicksort.js | O(N^2) | |
+| bubblesort.js | O(N^2) | |
+| bucketsort.js | O(N) | |
+| countingsort.js | O(N) | |
+| heapsort.js | O(N log N) | |
+| insertion-binary-sort.js | O(N^2) | |
+| insertionsort.js | O(N^2) | |
+| lsd.js | O(N*M) for N keys which have M or fewer digits | |
+| mergesort.js | O(n log(n)) | |
+| msd.js | O(N*M) for N keys which have M or fewer digits | |
+| oddeven-sort.js | O(N^2) | |
+| quicksort-middle.js | O(N log(N)) | |
+| quicksort.js | O(nlog n) | |
+| radixsort.js | O(N K) for N keys with K being | |
+| recursive-insertionsort.js | O(N^2) | |
+| selectionsort.js | O(N^2) | |
+| shellsort.js | O((nlog(n))^2) | |
diff --git a/src/sorting/recursive-insertionsort.js b/src/sorting/recursive-insertionsort.js
new file mode 100644
index 00000000..b34135c4
--- /dev/null
+++ b/src/sorting/recursive-insertionsort.js
@@ -0,0 +1,47 @@
+(function (exports) {
+ 'use strict';
+
+ function compare(a, b) {
+ return a - b;
+ }
+
+ /**
+ * Recursive version of insertion sort.
+ * Time complexity: O(N^2).
+ *
+ * @example
+ *
+ * var sort = require('path-to-algorithms/src/sorting/'+
+ * 'recursive-insertionsort').recursiveInsertionSort;
+ * console.log(sort([2, 5, 1, 0, 4])); // [ 0, 1, 2, 4, 5 ]
+ *
+ * @public
+ * @module sorting/recursive-insertionsort
+ * @param {Array} array Input array.
+ * @param {Function} cmp Optional. A function that defines an
+ * alternative sort order. The function should return a negative,
+ * zero, or positive value, depending on the arguments.
+ * @param {Number} max Optional. Index of the element which place
+ * we should find in the current function call.
+ * @return {Array} Sorted array.
+ */
+ function recursiveInsertionSort(array, cmp, max) {
+ cmp = cmp || compare;
+ if (max === undefined) {
+ max = array.length - 1;
+ }
+ if (max <= 0) {
+ return array;
+ }
+ recursiveInsertionSort(array, cmp, max - 1);
+ for (var i = max - 1, current = array[max];
+ i >= 0 && cmp(current, array[i]) < 0; i -= 1) {
+ array[i + 1] = array[i];
+ }
+ array[i + 1] = current;
+ return array;
+ }
+
+ exports.recursiveInsertionSort = recursiveInsertionSort;
+
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/sorting/selectionsort.js b/src/sorting/selectionsort.js
new file mode 100644
index 00000000..3f71ff5f
--- /dev/null
+++ b/src/sorting/selectionsort.js
@@ -0,0 +1,46 @@
+(function (exports) {
+ 'use strict';
+
+ function compare(a, b) {
+ return a - b;
+ }
+
+ /**
+ * Selection sort.
+ * Time complexity: O(N^2).
+ *
+ * @example
+ *
+ * var sort = require('path-to-algorithms/src/sorting/'+
+ * 'selectionsort').selectionSort;
+ * console.log(sort([2, 5, 1, 0, 4])); // [ 0, 1, 2, 4, 5 ]
+ *
+ * @public
+ * @module sorting/selectionsort
+ * @param {Array} array Input array.
+ * @param {Function} cmp Optional. A function that defines an
+ * alternative sort order. The function should return a negative,
+ * zero, or positive value, depending on the arguments.
+ * @return {Array} Sorted array.
+ */
+ var selectionSort = function (array, cmp) {
+ cmp = cmp || compare;
+ var idx;
+ var temp;
+ for (var i = 0; i < array.length - 1; i += 1) {
+ idx = i;
+ for (var j = i + 1; j < array.length; j += 1) {
+ if (cmp(array[idx], array[j]) > 0) {
+ idx = j;
+ }
+ }
+ temp = array[i];
+ array[i] = array[idx];
+ array[idx] = temp;
+ }
+ return array;
+ };
+
+ exports.selectionSort = selectionSort;
+
+})(typeof window === 'undefined' ? module.exports : window);
diff --git a/src/sorting/selectionsort/selectionsort.js b/src/sorting/selectionsort/selectionsort.js
deleted file mode 100644
index d24a5762..00000000
--- a/src/sorting/selectionsort/selectionsort.js
+++ /dev/null
@@ -1,37 +0,0 @@
-(function (exports) {
-
- 'use strict';
-
- function compare(a, b) {
- return a - b;
- }
-
- /**
- * Selection sort. It's complexity is O(n^2)
- *
- * @public
- * @param {array} array Array to be sorted
- * @return {array} The sorted array
- */
- var selectionSort = function (array, cmp) {
- cmp = cmp || compare;
- var min, idx, temp;
- for (var i = 0; i < array.length; i += 1) {
- idx = i;
- min = array[i];
- for (var j = i + 1; j < array.length; j += 1) {
- if (cmp(min, array[j]) > 0) {
- min = array[j];
- idx = j;
- }
- }
- temp = array[i];
- array[i] = min;
- array[idx] = temp;
- }
- return array;
- };
-
- exports.selectionSort = selectionSort;
-
-}(typeof exports === 'undefined' ? window : exports));
\ No newline at end of file
diff --git a/src/sorting/shellsort.js b/src/sorting/shellsort.js
new file mode 100644
index 00000000..b5b3d033
--- /dev/null
+++ b/src/sorting/shellsort.js
@@ -0,0 +1,53 @@
+(function (exports) {
+ 'use strict';
+
+ function compare(a, b) {
+ return a - b;
+ }
+
+ var shellSort = (function () {
+
+ var gaps = [701, 301, 132, 57, 23, 10, 4, 1];
+
+ /**
+ * Shellsort which uses the gaps 701, 301, 132, 57, 23, 10, 4, 1 and
+ * insertion sort to sort sub-arrays which match for the different gaps.
+ *
+ * @example
+ *
+ * var sort = require('path-to-algorithms/src/' +
+ * 'sorting/shellsort').shellSort;
+ * console.log(sort([2, 5, 1, 0, 4])); // [ 0, 1, 2, 4, 5 ]
+ *
+ * @public
+ * @module sorting/shellsort
+ * @param {Array} array Input array.
+ * @param {Function} cmp Optional. A function that defines an
+ * alternative sort order. The function should return a negative,
+ * zero, or positive value, depending on the arguments.
+ * @return {Array} Sorted array.
+ */
+ return function (array, cmp) {
+ cmp = cmp || compare;
+
+ var gap;
+ var current;
+ for (var k = 0; k < gaps.length; k += 1) {
+ gap = gaps[k];
+ for (var i = gap; i < array.length; i += gap) {
+ current = array[i];
+ for (var j = i;
+ j >= gap && cmp(array[j - gap], current) > 0; j -= gap) {
+ array[j] = array[j - gap];
+ }
+ array[j] = current;
+ }
+ }
+ return array;
+ };
+
+ }());
+
+ exports.shellSort = shellSort;
+
+}(typeof exports === 'undefined' ? window : exports));
diff --git a/src/sorting/shellsort/shellsort.js b/src/sorting/shellsort/shellsort.js
deleted file mode 100644
index ba340aac..00000000
--- a/src/sorting/shellsort/shellsort.js
+++ /dev/null
@@ -1,49 +0,0 @@
-(function (exports) {
-
- 'use strict';
-
-
- function compare(a, b) {
- return a - b;
- }
-
- /**
- * Shellsort
- *
- * Shellsort uses the gaps 701, 301, 132, 57, 23, 10, 4, 1 and uses
- * insertion sort to sort the sub-arrays which match for the different gaps.
- */
- var shellSort = (function () {
-
- var gaps = [701, 301, 132, 57, 23, 10, 4, 1];
-
- /**
- * Shellsort which uses the gaps in the lexical scope of the IIFE.
- *
- * @public
- * @param {array} array Array which should be sorted
- * @return {array} Sorted array
- */
- return function (array, cmp) {
- cmp = cmp || compare;
-
- var gap, current;
- for (var k = 0; k < gaps.length; k += 1) {
- gap = gaps[k];
- for (var i = gap; i < array.length; i += gap) {
- current = array[i];
- for (var j = i;
- j >= gap && cmp(array[j - gap], current) > 0; j -= gap) {
- array[j] = array[j - gap];
- }
- array[j] = current;
- }
- }
- return array;
- };
-
- }());
-
- exports.shellSort = shellSort;
-
-}(typeof exports === 'undefined' ? window : exports));
\ No newline at end of file
diff --git a/test/compression/burrows-wheeler/burrows-wheeler.spec.js b/test/compression/burrows-wheeler/burrows-wheeler.spec.js
new file mode 100644
index 00000000..94ea02dc
--- /dev/null
+++ b/test/compression/burrows-wheeler/burrows-wheeler.spec.js
@@ -0,0 +1,13 @@
+var bw = require('../../../src/compression/burrows-wheeler/burrows-wheeler').burrowsWheeler;
+
+describe('Burrows Wheeler', function () {
+ 'use strict';
+
+ it('should return "annnnb$aaaaa" for the entry "ananabanana"', function () {
+ expect(bw.encode('ananabanana')).toEqual('annnnb$aaaaa');
+ });
+
+ it('should return "ananabanana" for the entry "annnnb$aaaaa"', function () {
+ expect(bw.decode('annnnb$aaaaa')).toEqual('ananabanana');
+ });
+});
diff --git a/test/data-structures/avl-tree.spec.js b/test/data-structures/avl-tree.spec.js
new file mode 100644
index 00000000..509b4906
--- /dev/null
+++ b/test/data-structures/avl-tree.spec.js
@@ -0,0 +1,193 @@
+var mod = require('../../src/data-structures/avl-tree.js');
+var Node = mod.Node;
+var AVLTree = mod.AVLTree;
+
+describe('Node', function () {
+ 'use strict';
+
+ it('should be a constructor function', function () {
+ expect(typeof Node).toBe('function');
+ });
+});
+
+describe('AVL Tree', function () {
+ 'use strict';
+
+ it('should be a constructor function', function () {
+ expect(typeof AVLTree).toBe('function');
+ });
+ it('should start with null root', function () {
+ expect(new AVLTree()._root).toBe(null);
+ });
+ it('should insert and single rotate (leftRight) properly', function () {
+ var avlTree = new AVLTree();
+ avlTree.insert(66);
+ avlTree.insert(3);
+ avlTree.insert(5);
+ expect(avlTree._root.value).toBe(5);
+ expect(avlTree._root._left.value).toBe(3);
+ expect(avlTree._root._right.value).toBe(66);
+
+ expect(avlTree._root._height).toBe(2);
+ expect(avlTree._root._left._height).toBe(1);
+ expect(avlTree._root._right._height).toBe(1);
+ });
+ it('should insert and single rotate (rightLeft) properly', function () {
+ var avlTree = new AVLTree();
+ avlTree.insert(50);
+ avlTree.insert(75);
+ avlTree.insert(60);
+ expect(avlTree._root.value).toBe(60);
+ expect(avlTree._root._left.value).toBe(50);
+ expect(avlTree._root._right.value).toBe(75);
+
+ expect(avlTree._root._height).toBe(2);
+ expect(avlTree._root._left._height).toBe(1);
+ expect(avlTree._root._right._height).toBe(1);
+ });
+ it('should insert and double rotate (leftLeft) properly', function () {
+ var avlTree = new AVLTree();
+ avlTree.insert(50);
+ avlTree.insert(25);
+ avlTree.insert(10);
+ expect(avlTree._root.value).toBe(25);
+ expect(avlTree._root._left.value).toBe(10);
+ expect(avlTree._root._right.value).toBe(50);
+
+ expect(avlTree._root._height).toBe(2);
+ expect(avlTree._root._left._height).toBe(1);
+ expect(avlTree._root._right._height).toBe(1);
+ });
+ it('should insert and double rotate (rightRight) properly', function () {
+ var avlTree = new AVLTree();
+ avlTree.insert(50);
+ avlTree.insert(75);
+ avlTree.insert(100);
+ expect(avlTree._root.value).toBe(75);
+ expect(avlTree._root._left.value).toBe(50);
+ expect(avlTree._root._right.value).toBe(100);
+
+ expect(avlTree._root._height).toBe(2);
+ expect(avlTree._root._left._height).toBe(1);
+ expect(avlTree._root._right._height).toBe(1);
+ });
+ it('should insert multiple nodes and balance properly (1)', function () {
+ var avlTree = new AVLTree();
+ avlTree.insert(30);
+ avlTree.insert(15);
+ avlTree.insert(60);
+ avlTree.insert(90);
+ avlTree.insert(100);
+ expect(avlTree._root.value).toBe(30);
+ expect(avlTree._root._left.value).toBe(15);
+ expect(avlTree._root._right.value).toBe(90);
+ expect(avlTree._root._right._left.value).toBe(60);
+ expect(avlTree._root._right._right.value).toBe(100);
+
+ expect(avlTree._root._height).toBe(3);
+ expect(avlTree._root._left._height).toBe(1);
+ expect(avlTree._root._right._height).toBe(2);
+ expect(avlTree._root._right._left._height).toBe(1);
+ expect(avlTree._root._right._right._height).toBe(1);
+ });
+ it('should insert multiple nodes and balance properly (2)', function () {
+ var avlTree = new AVLTree();
+ avlTree.insert(24);
+ avlTree.insert(67);
+ avlTree.insert(33);
+ avlTree.insert(52);
+ avlTree.insert(11);
+ avlTree.insert(15);
+ avlTree.insert(26);
+ avlTree.insert(27);
+ // depth 1
+ expect(avlTree._root.value).toBe(33);
+ expect(avlTree._root._height).toBe(4);
+ // depth 2
+ expect(avlTree._root._left.value).toBe(15);
+ expect(avlTree._root._left._height).toBe(3);
+
+ expect(avlTree._root._right.value).toBe(67);
+ expect(avlTree._root._right._height).toBe(2);
+ // depth 3
+ expect(avlTree._root._left._left.value).toBe(11);
+ expect(avlTree._root._left._left._height).toBe(1);
+
+ expect(avlTree._root._left._right.value).toBe(26);
+ expect(avlTree._root._left._right._height).toBe(2);
+
+ expect(avlTree._root._right._left.value).toBe(52);
+ expect(avlTree._root._right._left._height).toBe(1);
+ // depth 4
+ expect(avlTree._root._left._right._left.value).toBe(24);
+ expect(avlTree._root._left._right._left._height).toBe(1);
+
+ expect(avlTree._root._left._right._right.value).toBe(27);
+ expect(avlTree._root._left._right._right._height).toBe(1);
+ });
+ it('should remove nodes and balance properly (1)', function () {
+ var avlTree = new AVLTree();
+ avlTree.insert(30);
+ avlTree.insert(15);
+ avlTree.insert(60);
+ avlTree.insert(90);
+ avlTree.insert(100);
+ avlTree.remove(15);
+ // depth 1
+ expect(avlTree._root.value).toBe(90);
+ expect(avlTree._root._height).toBe(3);
+ // depth 2
+ expect(avlTree._root._left.value).toBe(30);
+ expect(avlTree._root._left._height).toBe(2);
+
+ expect(avlTree._root._right.value).toBe(100);
+ expect(avlTree._root._right._height).toBe(1);
+ // depth 3
+ expect(avlTree._root._left._right.value).toBe(60);
+ expect(avlTree._root._left._right._height).toBe(1);
+ });
+ it('should remove nodes and balance properly (2)', function () {
+ var avlTree = new AVLTree();
+ avlTree.insert(55);
+ avlTree.insert(25);
+ avlTree.insert(11);
+ avlTree.insert(1);
+ avlTree.remove(55);
+ // depth 1
+ expect(avlTree._root.value).toBe(11);
+ expect(avlTree._root._height).toBe(2);
+ // depth 2
+ expect(avlTree._root._left.value).toBe(1);
+ expect(avlTree._root._left._height).toBe(1);
+
+ expect(avlTree._root._right.value).toBe(25);
+ expect(avlTree._root._right._height).toBe(1);
+ });
+ it('should remove nodes and balance properly (3)', function () {
+ var avlTree = new AVLTree();
+ avlTree.insert(55);
+ avlTree.insert(25);
+ avlTree.insert(11);
+ avlTree.insert(1);
+ avlTree.remove(55);
+ avlTree.insert(32);
+ avlTree.insert(37);
+ avlTree.insert(41);
+ avlTree.insert(8);
+ avlTree.insert(44);
+ avlTree.insert(6);
+ avlTree.remove(32);
+ avlTree.remove(11);
+ avlTree.remove(25);
+
+ // depth 1
+ expect(avlTree._root.value).toBe(37);
+ expect(avlTree._root._height).toBe(4);
+ // depth 2
+ expect(avlTree._root._left.value).toBe(6);
+ expect(avlTree._root._left._height).toBe(3);
+
+ expect(avlTree._root._right.value).toBe(41);
+ expect(avlTree._root._right._height).toBe(2);
+ });
+});
diff --git a/test/data-structures/binary-search-tree.spec.js b/test/data-structures/binary-search-tree.spec.js
new file mode 100644
index 00000000..fba5cb6f
--- /dev/null
+++ b/test/data-structures/binary-search-tree.spec.js
@@ -0,0 +1,88 @@
+var mod = require('../../src/data-structures/binary-search-tree.js');
+var Node = mod.Node;
+var BinaryTree = mod.BinaryTree;
+
+describe('Node', function () {
+ 'use strict';
+
+ it('should be a constructor function', function () {
+ expect(typeof Node).toBe('function');
+ });
+});
+
+describe('Binary Tree', function () {
+ 'use strict';
+
+ it('should be a constructor function', function () {
+ expect(typeof BinaryTree).toBe('function');
+ });
+ it('should start with null root', function () {
+ expect(new BinaryTree()._root).toBe(null);
+ });
+ it('should insert and remove single node properly', function () {
+ var bTree = new BinaryTree();
+ bTree.insert(15);
+ var node = bTree.find(15);
+ bTree.remove(node);
+ expect(bTree._root).toBe(null);
+ });
+ it('should remove root and replace with valid child', function () {
+ var bTree = new BinaryTree();
+ bTree.insert(15);
+ bTree.insert(30);
+ bTree.insert(45);
+ var node = bTree.find(15);
+ bTree.remove(node);
+ expect(bTree._root.value).toBe(30);
+ });
+ it('should insert multiple nodes properly', function () {
+ var bTree = new BinaryTree();
+ bTree.insert(10);
+ bTree.insert(5);
+ bTree.insert(15);
+ bTree.insert(4);
+ bTree.insert(6);
+ bTree.insert(14);
+ bTree.insert(16);
+ var leftRootChild = bTree._root._left;
+ var rightRootChild = bTree._root._right;
+ expect(bTree._root.value).toBe(10);
+ expect(leftRootChild.value).toBe(5);
+ expect(rightRootChild.value).toBe(15);
+ expect(leftRootChild._left.value).toBe(4);
+ expect(leftRootChild._right.value).toBe(6);
+ expect(rightRootChild._left.value).toBe(14);
+ expect(rightRootChild._right.value).toBe(16);
+ });
+ it('should remove multiple nodes properly', function () {
+ var bTree = new BinaryTree();
+ bTree.insert(10);
+ bTree.insert(5);
+ bTree.insert(15);
+ bTree.insert(4);
+ bTree.insert(6);
+ bTree.insert(7);
+ bTree.insert(14);
+ bTree.insert(16);
+ var leftRootChild = bTree._root._left;
+ var rightRootChild = bTree._root._right;
+ var sixteen = bTree.find(16);
+ bTree.remove(sixteen);
+ expect(bTree._root.value).toBe(10);
+ expect(leftRootChild.value).toBe(5);
+ expect(rightRootChild.value).toBe(15);
+ expect(leftRootChild._left.value).toBe(4);
+ expect(leftRootChild._right.value).toBe(6);
+ expect(leftRootChild._right._right.value).toBe(7);
+ expect(rightRootChild._left.value).toBe(14);
+ expect(rightRootChild._right).toBe(null);
+ var fourteen = bTree.find(14);
+ bTree.remove(fourteen);
+ expect(rightRootChild._left).toBe(null);
+ var five = bTree.find(5);
+ bTree.remove(five);
+ expect(leftRootChild.value).toBe(6);
+ expect(leftRootChild._left.value).toBe(4);
+ expect(leftRootChild._right.value).toBe(7);
+ });
+});
diff --git a/test/data-structures/bloomfilter.spec.js b/test/data-structures/bloomfilter.spec.js
new file mode 100644
index 00000000..e72d8748
--- /dev/null
+++ b/test/data-structures/bloomfilter.spec.js
@@ -0,0 +1,57 @@
+var mod = require('../../src/data-structures/bloomfilter.js');
+var Bitmap = mod.Bitmap;
+var Bloomfilter = mod.Bloomfilter;
+
+describe('Bitmap', function() {
+ 'use strict';
+
+ it('should be able to get and set values', function() {
+ var bitmap = new Bitmap(1024);
+ expect(bitmap.exists(0)).toBe(false);
+ bitmap.set(0, true);
+ expect(bitmap.exists(0)).toBe(true);
+ expect(bitmap.exists(1023)).toBe(false);
+ bitmap.set(1023, 1);
+ expect(bitmap.exists(1023)).toBe(true);
+ });
+
+ it('should be able to change everthing back', function() {
+ var bitmap = new Bitmap(2048);
+ for (var i = 0; i < 2048; i = i + 1) {
+ expect(bitmap.get(i)).toBe(0);
+ bitmap.set(i, 1);
+ expect(bitmap.get(i)).toBe(1);
+ bitmap.set(i, 0);
+ expect(bitmap.get(i)).toBe(0);
+ }
+ });
+});
+
+describe('Bloomfilter', function() {
+ 'use strict';
+ it('should be able to identify duplicates', function() {
+ var bloomfilter = new Bloomfilter(1024, 0.01);
+ expect(bloomfilter.get('a')).toBe(false);
+ expect(bloomfilter.get('b')).toBe(false);
+ bloomfilter.set('a');
+ expect(bloomfilter.get('a')).toBe(true);
+ expect(bloomfilter.get('b')).toBe(false);
+ bloomfilter.set('b');
+ expect(bloomfilter.get('a')).toBe(true);
+ expect(bloomfilter.get('b')).toBe(true);
+ });
+
+ it('should handle large amount of data inside', function() {
+ var bloomfilter = new Bloomfilter(4096, 0.001); // high precision
+
+ var falsePositive = 0;
+ for (var i = 0; i < 1024; i = i + 1) {
+ if (bloomfilter.get(i)) {
+ falsePositive = falsePositive + 1;
+ }
+ bloomfilter.set(i, true);
+ expect(bloomfilter.get(i)).toBe(true);
+ }
+ expect(falsePositive).toBeLessThan(100); // set a high theshold
+ });
+});
diff --git a/test/data-structures/hash-table.spec.js b/test/data-structures/hash-table.spec.js
new file mode 100644
index 00000000..bf3f362c
--- /dev/null
+++ b/test/data-structures/hash-table.spec.js
@@ -0,0 +1,223 @@
+var mod = require('../../src/data-structures/hash-table.js');
+var Node = mod.Node;
+var Hashtable = mod.Hashtable;
+
+describe('Node', function () {
+ 'use strict';
+
+ it('should be a constructor function', function () {
+ expect(typeof Node).toBe('function');
+ });
+});
+
+describe('Hash table', function () {
+ 'use strict';
+
+ it('should be a constructor function.', function () {
+ expect(typeof Hashtable).toBe('function');
+ });
+ it('should start with empty table.', function () {
+ expect(new Hashtable().buckets.length).toBe(0);
+ });
+ it('should put() K(int):V in table properly.', function () {
+ var hashTable = new Hashtable();
+ hashTable.put(10, 'value');
+ expect(hashTable.buckets[10].data).toBe('value');
+ });
+ it('should put() K(string):V in table properly.', function () {
+ var hashTable = new Hashtable();
+ hashTable.put('key', 'value');
+ /*
+ 'key' hashCode()'s to 106079. Then the hash is adjusted to fit
+ the number of configurable buckets (array size).
+ 106079 % 100 (100 is default maxBucketCount)
+ result is 79.
+ This is done to avoid using get() since it's untested at this point.
+ */
+ expect(hashTable.buckets[79].data).toBe('value');
+ });
+ it('should put() multiple K(int):Vs with hash collisions in properly (1).', function () {
+ var hashTable = new Hashtable();
+ // Same hash so going to same bucket, but different keys. Collision.
+ hashTable.put(10, 'value', 'someHash');
+ hashTable.put(35, 'anotherValue', 'someHash');
+ /*
+ 'someHash' hashCode()'s to 1504481314. Then the hash is adjusted to fit
+ the number of configurable buckets (array size).
+ 1504481314 % 100 (100 is default maxBucketCount)
+ result is 14.
+ This is done to avoid using get() since it's untested at this point.
+ */
+ expect(hashTable.buckets[14].data).toBe('value');
+ expect(hashTable.buckets[14].next.data).toBe('anotherValue');
+ });
+ it('should put() multiple K(int):Vs with hash collisions in properly (2).', function () {
+ var hashTable = new Hashtable();
+ hashTable.put(10, 'value', 'someHash');
+ hashTable.put(35, 'anotherValue', 'someHash');
+ hashTable.put(77, 'lastValue', 'someHash');
+ expect(hashTable.buckets[14].data).toBe('value');
+ expect(hashTable.buckets[14].next.data).toBe('anotherValue');
+ expect(hashTable.buckets[14].next.next.data).toBe('lastValue');
+ });
+ it('should put() multiple K(string):Vs with hash collisions in properly (1).', function () {
+ var hashTable = new Hashtable();
+ // Same hash so going to same bucket, but different keys. Collision.
+ hashTable.put('keyA', 'value', 'someHash');
+ hashTable.put('keyB', 'anotherValue', 'someHash');
+ /*
+ 'someHash' hashCode()'s to 1504481314. Then the hash is adjusted to fit
+ the number of configurable buckets (array size).
+ 1504481314 % 100 (100 is default maxBucketCount)
+ result is 14.
+ This is done to avoid using get() since it's untested at this point.
+ */
+ expect(hashTable.buckets[14].data).toBe('value');
+ expect(hashTable.buckets[14].next.data).toBe('anotherValue');
+ });
+ it('should put() multiple K(string):Vs with hash collisions in properly (2).', function () {
+ var hashTable = new Hashtable();
+ hashTable.put('keyA', 'value', 'someHash');
+ hashTable.put('keyB', 'anotherValue', 'someHash');
+ hashTable.put('keyC', 'lastValue', 'someHash');
+ expect(hashTable.buckets[14].data).toBe('value');
+ expect(hashTable.buckets[14].next.data).toBe('anotherValue');
+ expect(hashTable.buckets[14].next.next.data).toBe('lastValue');
+ });
+ it('should get() a K(int):V from table properly.', function () {
+ var hashTable = new Hashtable();
+ hashTable.put(10, 'value');
+ expect(hashTable.get(10)).toBe('value');
+ });
+ it('should get() a K(string):V from table properly.', function () {
+ var hashTable = new Hashtable();
+ hashTable.put('keyA', 'value');
+ expect(hashTable.get('keyA')).toBe('value');
+ });
+ it('should get() a K(int):V with collisions from table properly (1).', function () {
+ var hashTable = new Hashtable();
+ hashTable.put(10, 'value', 'someHash');
+ hashTable.put(35, 'anotherValue', 'someHash');
+ expect(hashTable.get(35, 'someHash')).toBe('anotherValue');
+ });
+ it('should get() a K(int):V with collisions from table properly (2).', function () {
+ var hashTable = new Hashtable();
+ hashTable.put(10, 'value', 'someHash');
+ hashTable.put(35, 'anotherValue', 'someHash');
+ hashTable.put(77, 'lastValue', 'someHash');
+ expect(hashTable.get(77, 'someHash')).toBe('lastValue');
+ });
+ it('should get() a K(int):V with collisions from table properly (3).', function () {
+ var hashTable = new Hashtable();
+ hashTable.put(10, 'value', 'someHash');
+ hashTable.put(35, 'anotherValue', 'someHash');
+ hashTable.put(77, 'lastValue', 'someHash');
+ expect(hashTable.get(35, 'someHash')).toBe('anotherValue');
+ });
+ it('should get() a K(int):V with collisions from table properly (4).', function () {
+ var hashTable = new Hashtable();
+ hashTable.put(10, 'value', 'someHash');
+ hashTable.put(35, 'anotherValue', 'someHash');
+ hashTable.put(77, 'lastValue', 'someHash');
+ expect(hashTable.get(10, 'someHash')).toBe('value');
+ });
+ it('should get() a K(string):V with collisions from table properly (1).', function () {
+ var hashTable = new Hashtable();
+ hashTable.put('keyA', 'value', 'someHash');
+ hashTable.put('keyB', 'anotherValue', 'someHash');
+ expect(hashTable.get('keyB', 'someHash')).toBe('anotherValue');
+ });
+ it('should get() a K(string):V with collisions from table properly (2).', function () {
+ var hashTable = new Hashtable();
+ hashTable.put('keyA', 'value', 'someHash');
+ hashTable.put('keyB', 'anotherValue', 'someHash');
+ hashTable.put('keyC', 'lastValue', 'someHash');
+ expect(hashTable.get('keyC', 'someHash')).toBe('lastValue');
+ });
+ it('should get() a K(string):V with collisions from table properly (3).', function () {
+ var hashTable = new Hashtable();
+ hashTable.put('keyA', 'value', 'someHash');
+ hashTable.put('keyB', 'anotherValue', 'someHash');
+ hashTable.put('keyC', 'lastValue', 'someHash');
+ expect(hashTable.get('keyB', 'someHash')).toBe('anotherValue');
+ });
+ it('should get() a K(string):V with collisions from table properly (4).', function () {
+ var hashTable = new Hashtable();
+ hashTable.put('keyA', 'value', 'someHash');
+ hashTable.put('keyB', 'anotherValue', 'someHash');
+ hashTable.put('keyC', 'lastValue', 'someHash');
+ expect(hashTable.get('keyA', 'someHash')).toBe('value');
+ });
+ it('should remove() a K(int):V from table properly (1).', function () {
+ // remove only node/link in bucket : (B)
+ var hashTable = new Hashtable();
+ hashTable.put(10, 'value');
+ hashTable.remove(10);
+ expect(hashTable.get(10)).toBe(undefined);
+ });
+ it('should remove() a K(int):V with collisions from table properly (2).', function () {
+ // remove start node/link in bucket : (B) - A
+ var hashTable = new Hashtable();
+ hashTable.put(10, 'value', 'someHash');
+ hashTable.put(35, 'anotherValue', 'someHash');
+ expect(hashTable.remove(10, 'someHash')).toBe('value');
+ expect(hashTable.get(35, 'someHash')).toBe('anotherValue');
+ expect(hashTable.get(10, 'someHash')).toBe(undefined);
+ });
+ it('should remove() a K(int):V with collisions from table properly (3).', function () {
+ // remove start node/link in bucket : (B) - A - C
+ var hashTable = new Hashtable();
+ hashTable.put(10, 'value', 'someHash');
+ hashTable.put(35, 'anotherValue', 'someHash');
+ hashTable.put(66, 'lastValue', 'someHash');
+ expect(hashTable.remove(10, 'someHash')).toBe('value');
+ expect(hashTable.get(35, 'someHash')).toBe('anotherValue');
+ expect(hashTable.get(66, 'someHash')).toBe('lastValue');
+ });
+ it('should remove() a K(int):V with collisions from table properly (4).', function () {
+ // remove middle node/link in bucket : A - (B) - C
+ var hashTable = new Hashtable();
+ hashTable.put(10, 'value', 'someHash');
+ hashTable.put(35, 'anotherValue', 'someHash');
+ hashTable.put(66, 'lastValue', 'someHash');
+ expect(hashTable.remove(35, 'someHash')).toBe('anotherValue');
+ expect(hashTable.get(10, 'someHash')).toBe('value');
+ expect(hashTable.get(66, 'someHash')).toBe('lastValue');
+ });
+ it('should remove() a K(string):V from table properly (1).', function () {
+ // remove only node/link in bucket : (B)
+ var hashTable = new Hashtable();
+ hashTable.put('keyA', 'value');
+ hashTable.remove('keyA');
+ expect(hashTable.get('keyA')).toBe(undefined);
+ });
+ it('should remove() a K(string):V with collisions from table properly (2).', function () {
+ // remove start node/link in bucket : (B) - A
+ var hashTable = new Hashtable();
+ hashTable.put('keyA', 'value', 'someHash');
+ hashTable.put('keyB', 'anotherValue', 'someHash');
+ expect(hashTable.remove('keyA', 'someHash')).toBe('value');
+ expect(hashTable.get('keyB', 'someHash')).toBe('anotherValue');
+ expect(hashTable.get('keyA', 'someHash')).toBe(undefined);
+ });
+ it('should remove() a K(string):V with collisions from table properly (3).', function () {
+ // remove start node/link in bucket : (B) - A - C
+ var hashTable = new Hashtable();
+ hashTable.put('keyA', 'value', 'someHash');
+ hashTable.put('keyB', 'anotherValue', 'someHash');
+ hashTable.put('keyC', 'lastValue', 'someHash');
+ expect(hashTable.remove('keyA', 'someHash')).toBe('value');
+ expect(hashTable.get('keyB', 'someHash')).toBe('anotherValue');
+ expect(hashTable.get('keyC', 'someHash')).toBe('lastValue');
+ });
+ it('should remove() a K(string):V with collisions from table properly (4).', function () {
+ // remove middle node/link in bucket : A - (B) - C
+ var hashTable = new Hashtable();
+ hashTable.put('keyA', 'value', 'someHash');
+ hashTable.put('keyB', 'anotherValue', 'someHash');
+ hashTable.put('keyC', 'lastValue', 'someHash');
+ expect(hashTable.remove('keyB', 'someHash')).toBe('anotherValue');
+ expect(hashTable.get('keyA', 'someHash')).toBe('value');
+ expect(hashTable.get('keyC', 'someHash')).toBe('lastValue');
+ });
+});
diff --git a/test/data-structures/heap.spec.js b/test/data-structures/heap.spec.js
new file mode 100644
index 00000000..ee44de4a
--- /dev/null
+++ b/test/data-structures/heap.spec.js
@@ -0,0 +1,95 @@
+var mod = require('../../src/data-structures/heap.js');
+var Heap = mod.Heap;
+
+describe('Heap', function () {
+ 'use strict';
+
+ it('should be a constructor function', function () {
+ expect(typeof Heap).toBe('function');
+ });
+ it('should have default comparison function', function () {
+ var heap = new Heap();
+ expect(typeof heap._cmp).toBe('function');
+ });
+ it('should add an object properly', function () {
+ var heap = new Heap();
+ heap.add(1);
+ expect(heap._heap[0]).toBe(1);
+ });
+ it('should remove an object properly', function () {
+ var heap = new Heap();
+ heap.add(1);
+ var res = heap.extract();
+ expect(res).toBe(1);
+ expect(heap._heap.length).toBe(0);
+ });
+ it('should add multiple nodes properly', function () {
+ var heap = new Heap();
+ heap.add(55);
+ heap.add(11);
+ heap.add(66);
+ expect(heap._heap.indexOf(55)).toBeGreaterThan(-1);
+ expect(heap._heap.indexOf(11)).toBeGreaterThan(-1);
+ expect(heap._heap.indexOf(66)).toBeGreaterThan(-1);
+ });
+ it('should remove multiple nodes properly (max heap)', function () {
+ var heap = new Heap();
+ heap.add(55);
+ heap.add(11);
+ heap.add(66);
+ var res = heap.extract();
+ expect(res).toBe(66);
+ res = heap.extract();
+ expect(res).toBe(55);
+ res = heap.extract();
+ expect(res).toBe(11);
+ });
+ it('should remove multiple nodes properly (min heap)', function () {
+ var heap = new Heap(function (a, b) {
+ return b - a;
+ });
+ heap.add(55);
+ heap.add(11);
+ heap.add(66);
+ var res = heap.extract();
+ expect(res).toBe(11);
+ res = heap.extract();
+ expect(res).toBe(55);
+ res = heap.extract();
+ expect(res).toBe(66);
+ });
+ it('should update top node properly', function () {
+ var heap = new Heap(function (a, b) {
+ return a.val - b.val;
+ });
+ var objectToUpdate = { val: 66 };
+ heap.add(objectToUpdate);
+ heap.add({ val: 11 });
+ heap.add({ val: 55 });
+ objectToUpdate.val = 0;
+ heap.update(objectToUpdate);
+ var res = heap.extract();
+ expect(res.val).toBe(55);
+ res = heap.extract();
+ expect(res.val).toBe(11);
+ res = heap.extract();
+ expect(res.val).toBe(0);
+ });
+ it('should update bottom node properly', function () {
+ var heap = new Heap(function (a, b) {
+ return a.val - b.val;
+ });
+ var objectToUpdate = { val: 0 };
+ heap.add(objectToUpdate);
+ heap.add({ val: 11 });
+ heap.add({ val: 55 });
+ objectToUpdate.val = 66;
+ heap.update(objectToUpdate);
+ var res = heap.extract();
+ expect(res.val).toBe(66);
+ res = heap.extract();
+ expect(res.val).toBe(55);
+ res = heap.extract();
+ expect(res.val).toBe(11);
+ });
+});
diff --git a/test/data-structures/interval-tree.spec.js b/test/data-structures/interval-tree.spec.js
new file mode 100644
index 00000000..c5745834
--- /dev/null
+++ b/test/data-structures/interval-tree.spec.js
@@ -0,0 +1,48 @@
+var mod = require('../../src/data-structures/interval-tree.js');
+var IntervalTree = mod.IntervalTree;
+
+describe('IntervalTree', function () {
+ 'use strict';
+
+ it('should correctly detect intersections', function () {
+ var it = new IntervalTree();
+
+ it.add([10383734, 10594186])
+ it.add([10383734, 10594186])
+ it.add([8891125, 9095610])
+ it.add([9495571, 9677853])
+ it.add([10093457, 10257167])
+ it.add([9303743, 9404967])
+ it.intersects([9303743, 9303744])
+ expect(it.intersects([9303743, 9303744])).toBe(true)
+ expect(it.intersects([10383734, 10383734])).toBe(true);
+
+ it.add([9495571, 9677853])
+ it.add([9303743, 9404967])
+
+ expect(it.intersects([9303743, 9303744])).toBe(true)
+ expect(it.intersects([9303742, 9303742])).toBe(false)
+
+ expect(it.intersects([9404967,9404967])).toBe(true)
+ expect(it.intersects([9404968,9404969])).toBe(false)
+
+ it = new IntervalTree();
+
+ expect(it.intersects([1,2])).toBe(false);
+
+ it.add([1,2]);
+ expect(it.contains(0.4)).toBe(false);
+ expect(it.contains(1.4)).toBe(true);
+
+ expect(it.intersects([0,3])).toBe(true);
+ expect(it.intersects([1.5,1.6])).toBe(true);
+ expect(it.intersects([2.1,3.0])).toBe(false);
+
+ it.add([1.4,2.1]);
+
+ expect(it.intersects([0,3])).toBe(true);
+ expect(it.intersects([1.5,1.6])).toBe(true);
+
+ expect(it.intersects([2.1,3.0])).toBe(true);
+ });
+});
diff --git a/test/data-structures/linked-list.spec.js b/test/data-structures/linked-list.spec.js
new file mode 100644
index 00000000..eb1d0e38
--- /dev/null
+++ b/test/data-structures/linked-list.spec.js
@@ -0,0 +1,177 @@
+var mod = require('../../src/data-structures/linked-list.js');
+var Node = mod.Node;
+var LinkedList = mod.LinkedList;
+
+describe('Node', function () {
+ 'use strict';
+
+ it('should be a constructor function', function () {
+ expect(typeof Node).toBe('function');
+ });
+ it('should construct properly', function () {
+ var node = new Node('data');
+ expect(node.data).toBe('data');
+ expect(node.next).toBe(null);
+ expect(node.prev).toBe(null);
+ });
+});
+
+describe('Linked List', function () {
+ 'use strict';
+
+ it('should be a constructor function', function () {
+ expect(typeof LinkedList).toBe('function');
+ });
+ it('should push properly', function () {
+ var linkedList = new LinkedList();
+ linkedList.push(1);
+ linkedList.push(2);
+ linkedList.push(3);
+ linkedList.push(4);
+ linkedList.push(5);
+ expect(linkedList.first.data).toBe(1);
+ expect(linkedList.first.next.data).toBe(2);
+ expect(linkedList.first.next.next.data).toBe(3);
+ expect(linkedList.first.next.next.next.data).toBe(4);
+ expect(linkedList.first.next.next.next.next.data).toBe(5);
+ expect(linkedList.last.data).toBe(5);
+ });
+ it('should pop properly', function () {
+ var linkedList = new LinkedList();
+ linkedList.push(1);
+ linkedList.push(2);
+ linkedList.push(3);
+ linkedList.push(4);
+ linkedList.push(5);
+ expect(linkedList.pop().data).toBe(5);
+ expect(linkedList.pop().data).toBe(4);
+ expect(linkedList.pop().data).toBe(3);
+ expect(linkedList.pop().data).toBe(2);
+ expect(linkedList.pop().data).toBe(1);
+ });
+ it('should shift properly', function () {
+ var linkedList = new LinkedList();
+ linkedList.push(1);
+ linkedList.push(2);
+ linkedList.push(3);
+ linkedList.push(4);
+ linkedList.push(5);
+ expect(linkedList.shift().data).toBe(1);
+ expect(linkedList.shift().data).toBe(2);
+ expect(linkedList.shift().data).toBe(3);
+ expect(linkedList.shift().data).toBe(4);
+ expect(linkedList.shift().data).toBe(5);
+ });
+ it('should reverse properly', function () {
+ var linkedList = new LinkedList();
+ linkedList.push(1);
+ linkedList.push(2);
+ linkedList.push(3);
+ linkedList.push(4);
+ linkedList.push(5);
+ linkedList.reverse();
+ expect(linkedList.shift().data).toBe(5);
+ expect(linkedList.shift().data).toBe(4);
+ expect(linkedList.shift().data).toBe(3);
+ expect(linkedList.shift().data).toBe(2);
+ expect(linkedList.shift().data).toBe(1);
+ });
+ it('should recursive reverse properly', function () {
+ var linkedList = new LinkedList();
+ linkedList.push(1);
+ linkedList.push(2);
+ linkedList.push(3);
+ linkedList.push(4);
+ linkedList.push(5);
+ linkedList.recursiveReverse();
+ expect(linkedList.shift().data).toBe(5);
+ expect(linkedList.shift().data).toBe(4);
+ expect(linkedList.shift().data).toBe(3);
+ expect(linkedList.shift().data).toBe(2);
+ expect(linkedList.shift().data).toBe(1);
+ });
+ it('should unshift properly', function () {
+ var linkedList = new LinkedList();
+ linkedList.push(1);
+ linkedList.push(2);
+ linkedList.push(3);
+ linkedList.push(4);
+ linkedList.push(5);
+ linkedList.unshift(3);
+ expect(linkedList.shift().data).toBe(3);
+ expect(linkedList.shift().data).toBe(1);
+ expect(linkedList.shift().data).toBe(2);
+ expect(linkedList.shift().data).toBe(3);
+ expect(linkedList.shift().data).toBe(4);
+ expect(linkedList.shift().data).toBe(5);
+ });
+ it('should properly check for existing cycle', function () {
+ var linkedList = new LinkedList();
+ var last = new Node(2);
+ var first = new Node(1);
+ last.next = first;
+ last.prev = first;
+ first.next = last;
+ first.prev = last;
+ linkedList.first = first;
+ linkedList.last = last;
+ expect(linkedList.hasCycle()).toBe(true);
+ });
+ it('should properly check for non existing cycle', function () {
+ var linkedList = new LinkedList();
+ linkedList.push(1);
+ linkedList.push(2);
+ linkedList.push(3);
+ linkedList.push(4);
+ linkedList.push(5);
+ expect(linkedList.hasCycle()).toBe(false);
+ });
+ it('should inorder properly', function () {
+ var linkedList = new LinkedList();
+ linkedList.push(1);
+ linkedList.push(2);
+ linkedList.push(3);
+ linkedList.push(4);
+ linkedList.push(5);
+ var pushedValue = 1;
+ function callback(node){
+ expect(node.data).toBe(pushedValue);
+ pushedValue += 1;
+ }
+ linkedList.inorder(callback);
+ });
+ it('should delete data properly', function () {
+ var linkedList = new LinkedList();
+ linkedList.push(1);
+ linkedList.push(2);
+ linkedList.push(3);
+ linkedList.push(4);
+ linkedList.push(5);
+ linkedList.remove(3);
+ expect(linkedList.first.data).toBe(1);
+ expect(linkedList.first.next.data).toBe(2);
+ expect(linkedList.first.next.next.data).toBe(4);
+ expect(linkedList.first.next.next.next.data).toBe(5);
+ expect(linkedList.last.data).toBe(5);
+ });
+ it('should delete complex data properly', function () {
+ var linkedList = new LinkedList();
+ var item1 = {id: 1};
+ var item2 = {id: 2};
+ var item3 = {id: 3};
+ var item4 = {id: 4};
+ var item5 = {id: 5};
+ linkedList.push(item1);
+ linkedList.push(item2);
+ linkedList.push(item3);
+ linkedList.push(item4);
+ linkedList.push(item5);
+ var equals = function(a, b) { return a.id === b.id };
+ linkedList.remove({id: 3}, equals);
+ expect(linkedList.first.data).toBe(item1);
+ expect(linkedList.first.next.data).toBe(item2);
+ expect(linkedList.first.next.next.data).toBe(item4);
+ expect(linkedList.first.next.next.next.data).toBe(item5);
+ expect(linkedList.last.data).toBe(item5);
+ });
+});
diff --git a/test/data-structures/red-black-tree.spec.js b/test/data-structures/red-black-tree.spec.js
index 219bf5eb..8cf1615a 100644
--- a/test/data-structures/red-black-tree.spec.js
+++ b/test/data-structures/red-black-tree.spec.js
@@ -1,18 +1,17 @@
-'use strict';
-
-var mod = require('../../src/data-structures/red-black-tree.js'),
- Node = mod.Node,
- RBTree = mod.RBTree,
- Colors = mod.Colors;
+var mod = require('../../src/data-structures/red-black-tree.js');
+var Vertex = mod.Node;
+var RBTree = mod.RBTree;
+var Colors = mod.Colors;
describe('Node', function () {
+ 'use strict';
it('should be a constructor function', function () {
- expect(typeof Node).toBe('function');
+ expect(typeof Vertex).toBe('function');
});
it('should set all properties via the constructor', function () {
- var node = new Node('key', 'value', 1, 2, Colors.RED);
+ var node = new Vertex('key', 'value', 1, 2, Colors.RED);
expect(node.getKey()).toBe('key');
expect(node.getLeft()).toBe(1);
expect(node.getRight()).toBe(2);
@@ -22,11 +21,11 @@ describe('Node', function () {
describe('Node flipColor', function () {
it('should has method flipColor', function () {
- var node = new Node();
+ var node = new Vertex();
expect(typeof node.flipColor).toBe('function');
});
it('should work properly', function () {
- var node = new Node();
+ var node = new Vertex();
expect(node.isRed()).toBe(false);
node.flipColor();
expect(node.isRed()).toBe(true);
@@ -37,6 +36,8 @@ describe('Node', function () {
});
describe('RBTree', function () {
+ 'use strict';
+
it('should be a constructor function', function () {
expect(typeof RBTree).toBe('function');
});
@@ -97,4 +98,20 @@ describe('RBTree', function () {
});
});
+ describe('levelOrderTraversal method', function () {
+ it('should be able to traverse tree in level order', function () {
+ var tree = new RBTree();
+ expect(tree.levelOrderTraversal()).toBe('Level Order Traversal -: Tree is empty');
+ tree.put(10);
+ tree.put(20);
+ expect(tree.levelOrderTraversal()).toBe('Level Order Traversal -: 20 10');
+ tree.put(30);
+ expect(tree.levelOrderTraversal()).toBe('Level Order Traversal -: 20 10 30');
+ tree.put(45);
+ expect(tree.levelOrderTraversal()).toBe('Level Order Traversal -: 20 10 45 30');
+ tree.put(5);
+ expect(tree.levelOrderTraversal()).toBe('Level Order Traversal -: 20 10 45 5 30');
+ });
+ });
+
});
diff --git a/test/data-structures/segment-tree.spec.js b/test/data-structures/segment-tree.spec.js
new file mode 100644
index 00000000..42bf127d
--- /dev/null
+++ b/test/data-structures/segment-tree.spec.js
@@ -0,0 +1,89 @@
+var SegmentTree = require('../../src/data-structures/segment-tree.js')
+ .SegmentTree;
+
+var defaultAggregate = function (a, b) {
+ 'use strict';
+ return Math.min(a, b);
+};
+
+describe('Segment Tree', function () {
+ 'use strict';
+
+ describe('indexing', function () {
+
+ it('should be a constructor function', function () {
+ expect(typeof SegmentTree).toBe('function');
+ });
+
+ it('should start with null original array', function () {
+ expect(new SegmentTree()._original).toBe(null);
+ });
+
+ it('should start with empty array as data', function () {
+ expect(new SegmentTree()._data).not.toBe(null);
+ expect(new SegmentTree()._data.length).toBe(0);
+ });
+
+ it('should work with empty arrays', function () {
+ var tree = SegmentTree.indexArray([], Infinity, defaultAggregate);
+ expect(tree._data).toBeTruthy();
+ expect(tree._data.length).toBe(0);
+ });
+
+ it('should index arrays with one element', function () {
+ var tree = SegmentTree.indexArray([1], Infinity, defaultAggregate);
+ expect(tree._data).toBeTruthy();
+ expect(tree._data.length).toBe(1);
+ });
+
+ it('should index any array', function () {
+ var tree = SegmentTree.indexArray([1, 2, 3], Infinity, defaultAggregate);
+ expect(tree._data).toEqual([1, 1, 3, 1, 2]);
+
+ tree = SegmentTree.indexArray([1, 2, 3, 6], Infinity, defaultAggregate);
+ expect(tree._data).toEqual([1, 1, 3, 1, 2, 3, 6]);
+ });
+
+ });
+
+ describe('should find the proper value at given interval', function () {
+
+ it('should properly find the minimum when in range', function () {
+ var tree = SegmentTree.indexArray([1], Infinity, defaultAggregate);
+ expect(tree.query(0, 0)).toBe(1);
+
+ tree = SegmentTree.indexArray([1, 2], Infinity, defaultAggregate);
+ expect(tree.query(0, 0)).toBe(1);
+ expect(tree.query(0, 1)).toBe(1);
+ expect(tree.query(1, 1)).toBe(2);
+
+ tree = SegmentTree.indexArray([1, -1, 2], Infinity, defaultAggregate);
+ expect(tree.query(0, 2)).toBe(-1);
+ expect(tree.query(0, 1)).toBe(-1);
+ expect(tree.query(1, 1)).toBe(-1);
+ expect(tree.query(1, 2)).toBe(-1);
+ expect(tree.query(2, 2)).toBe(2);
+ });
+
+ it('should properly find the minimum when outside range', function () {
+ var tree = SegmentTree.indexArray([1], Infinity, defaultAggregate);
+ expect(tree.query(0, 2)).toBe(1);
+
+ tree = SegmentTree.indexArray([1, 2, 3], Infinity, defaultAggregate);
+ expect(tree.query(0, 20)).toBe(1);
+ expect(tree.query(2, 20)).toBe(3);
+ expect(Number.isFinite(tree.query(20, 25))).toBe(false);
+ });
+
+ it('should throw when the start index is bigger than end', function () {
+ var tree = SegmentTree.indexArray([1], Infinity, defaultAggregate);
+ expect(function () {
+ tree.query(2, 1);
+ }).toThrow();
+ expect(function () {
+ tree.query(1, 1);
+ }).not.toThrow();
+ });
+ });
+});
+
diff --git a/test/data-structures/size-balanced-tree.spec.js b/test/data-structures/size-balanced-tree.spec.js
new file mode 100644
index 00000000..9051e3fc
--- /dev/null
+++ b/test/data-structures/size-balanced-tree.spec.js
@@ -0,0 +1,176 @@
+var mod = require('../../src/data-structures/size-balanced-tree.js');
+var Node = mod.Node;
+var Nil = mod.Nil;
+var SBTree = mod.SBTree;
+var updateChild = mod.updateChild;
+
+describe('Node', function () {
+ 'use strict';
+
+ it('should be a constructor function', function () {
+ expect(typeof Node).toBe('function');
+ });
+ it('should be a construct properly', function () {
+ var node = new Node(10, Nil, Nil, Nil, 1);
+ expect(node.value).toBe(10);
+ expect(node.left).toBe(Nil);
+ expect(node.right).toBe(Nil);
+ expect(node.parent).toBe(Nil);
+ expect(node.size).toBe(1);
+ });
+ it('should reference children/parent properly', function () {
+ var root = new Node(10, Nil, Nil, Nil, 1);
+ var left = new Node(5, root, Nil, Nil, 1);
+ var right = new Node(15, root, Nil, Nil, 1);
+ root.left = left;
+ root.right = right;
+ expect(root.value).toBe(10);
+ expect(root.left).toBe(left);
+ expect(root.right).toBe(right);
+ expect(root.parent).toBe(Nil);
+ expect(right.parent).toBe(root);
+ expect(left.parent).toBe(root);
+ expect(right.size).toBe(1);
+ expect(left.size).toBe(1);
+ expect(root.size).toBe(1);
+ root.updateSize();
+ expect(root.size).toBe(3);
+ });
+});
+
+describe('SBTree', function () {
+ 'use strict';
+
+ it('should be a constructor function', function () {
+ expect(typeof SBTree).toBe('function');
+ });
+ it('should start with null root', function () {
+ expect(new SBTree()._root).toBe(Nil);
+ });
+ it('should insert and remove correctly', function () {
+ var sTree = new SBTree();
+ expect(sTree.size).toBe(0);
+ sTree.insert(0, 10);
+ expect(sTree.size).toBe(1);
+ sTree.remove(0);
+ expect(sTree.size).toBe(0);
+ expect(sTree._root).toBe(Nil);
+ });
+
+ function checkNil() {
+ expect(Nil.size).toBe(0);
+ expect(Nil.left).toBe(Nil);
+ expect(Nil.right).toBe(Nil);
+ expect(Nil.parent).toBe(Nil);
+ expect(Nil.value).toBe(null);
+ }
+
+ it('test updateChild', function () {
+ checkNil();
+ var root = new Node(10, Nil, Nil, Nil, 1);
+ var left = new Node(5, root, Nil, Nil, 1);
+ var right = new Node(15, root, Nil, Nil, 1);
+ var leftLeft = new Node(10, left, Nil, Nil, 1);
+ left.left = leftLeft;
+ left.updateSize();
+ root.left = left;
+ root.right = right;
+ root.updateSize();
+ expect(root.size).toBe(4);
+
+ updateChild(left, leftLeft);
+ expect(leftLeft.parent).toBe(root);
+ expect(root.left).toBe(leftLeft);
+ expect(root.left.size).toBe(1);
+ checkNil();
+ });
+ // Returns a random integer between min (included) and max (excluded)
+ // Using Math.round() will give you a non-uniform distribution!
+ function getRandomInt(min, max) {
+ return Math.floor(Math.random() * (max - min)) + min;
+ }
+ // Returns a random integer between min (included) and max (included)
+ // Using Math.round() will give you a non-uniform distribution!
+ function getRandomIntInclusive(min, max) {
+ return Math.floor(Math.random() * (max - min + 1)) + min;
+ }
+
+ it('push and get 100000 elements, remove the array by always remove the first/last element', function () {
+ var sTree = new SBTree();
+ for (var i = 0; i < 200000; i += 1) {
+ sTree.push(i);
+ }
+ checkNil();
+ for (var i = 0; i < 200000; i += 1) {
+ var node = sTree.get(i);
+ expect(node.value).toBe(i);
+ }
+ for (var i = 0; i < 200000; i += 1) {
+ expect(sTree.get(0).value).toBe(i);
+ var node = sTree.remove(0); // Always remove the first element;
+ expect(node.value).toBe(i);
+ }
+ checkNil();
+ expect(sTree._root).toBe(Nil);
+ var count = 10000;
+ for (var i = 0; i < count; i += 1) {
+ sTree.insert(0, i);
+ }
+ for (var i = 0; i < count; i += 1) {
+ var node = sTree.remove(count - i - 1); // Always remove the last element;
+ expect(node.value).toBe(i);
+ expect(sTree.size).toBe(count - i - 1);
+ }
+ checkNil();
+ var expectedArray = [];
+ for (var i = 0; i < 100000; i += 1) {
+ var newPos = getRandomIntInclusive(0, sTree.size);
+ sTree.insert(newPos, i);
+ expectedArray.splice(newPos, 0, i);
+ }
+ expect(sTree.size).toBe(expectedArray.length);
+ for (var i = 0; i < sTree.size; i += 1) {
+ var node = sTree.get(i);
+ expect(node.value).toBe(expectedArray[i]);
+ }
+ for (var i = 0; i < 90000; i += 1) {
+ var removedPos = getRandomInt(0, sTree.size);
+ sTree.remove(removedPos);
+ expectedArray.splice(removedPos, 1);
+ }
+ for (var i = 0; i < sTree.size; i += 1) {
+ var node = sTree.get(i);
+ expect(node.value).toBe(expectedArray[i]);
+ }
+ checkNil();
+ });
+
+ it('test getIndex', function () {
+ var sTree = new SBTree();
+ for (var i = 0; i < 10000; i += 1) {
+ var key = i.toString();
+ sTree.push(key);
+ }
+
+ for (var i = 0; i < 100; i += 1) {
+ var item = sTree.get(i);
+ expect(item.value).toBe(i.toString());
+ expect(sTree.getIndex(item)).toBe(i);
+ }
+ });
+
+ it('test binary search', function () {
+ var sTree = new SBTree();
+ for (var i = 0; i < 10000; i += 1) {
+ sTree.push(i);
+ }
+ var cmp = function (a, b) {
+ return a - b;
+ }
+ expect(sTree.binarySearch(cmp, 10.5)).toBe(11)
+ expect(sTree.binarySearch(cmp, 0)).toBe(1)
+ expect(sTree.binarySearch(cmp, -1)).toBe(0)
+ expect(sTree.binarySearch(cmp, 9999)).toBe(10000)
+ expect(sTree.binarySearch(cmp, 10000)).toBe(10000)
+ });
+});
diff --git a/test/data-structures/splay-tree.spec.js b/test/data-structures/splay-tree.spec.js
new file mode 100644
index 00000000..78e31ebc
--- /dev/null
+++ b/test/data-structures/splay-tree.spec.js
@@ -0,0 +1,82 @@
+var mod = require('../../src/data-structures/splay-tree.js');
+var Node = mod.Node;
+var SplayTree = mod.SplayTree;
+
+describe('Node', function () {
+ 'use strict';
+
+ it('should be a constructor function', function () {
+ expect(typeof Node).toBe('function');
+ });
+ it('should be a construct properly', function () {
+ var node = new Node(10, null, null, null);
+ expect(node.value).toBe(10);
+ expect(node._left).toBe(null);
+ expect(node._right).toBe(null);
+ expect(node._parent).toBe(null);
+ });
+ it('should reference children/parent properly', function () {
+ var root = new Node(10, null, null, null);
+ var left = new Node(5, null, null, root);
+ var right = new Node(15, null, null, root);
+ root._left = left;
+ root._right = right;
+ expect(root.value).toBe(10);
+ expect(root._left).toBe(left);
+ expect(root._right).toBe(right);
+ expect(root._parent).toBe(null);
+ });
+});
+
+describe('SplayTree', function () {
+ 'use strict';
+
+ it('should be a constructor function', function () {
+ expect(typeof SplayTree).toBe('function');
+ });
+ it('should start with null root', function () {
+ expect(new SplayTree()._root).toBe(null);
+ });
+ it('should insert and remove correctly', function () {
+ var sTree = new SplayTree();
+ sTree.insert(10);
+ sTree.remove(10);
+ expect(sTree._root).toBe(null);
+ });
+ it('should splay correctly upon inserts', function () {
+ var sTree = new SplayTree();
+ sTree.insert(10);
+ sTree.insert(5);
+ sTree.insert(15);
+ sTree.insert(7);
+ sTree.insert(12);
+ expect(sTree._root.value).toBe(12);
+ expect(sTree._root._left.value).toBe(7);
+ expect(sTree._root._right.value).toBe(15);
+ });
+ it('should splay correctly upon search', function () {
+ var sTree = new SplayTree();
+ sTree.insert(10);
+ sTree.insert(5);
+ sTree.insert(15);
+ sTree.insert(7);
+ sTree.insert(12);
+ sTree.search(5);
+ expect(sTree._root.value).toBe(5);
+ expect(sTree._root._right.value).toBe(7);
+ expect(sTree._root._right._right.value).toBe(12);
+ });
+ it('should splay correctly upon remove', function () {
+ var sTree = new SplayTree();
+ sTree.insert(10);
+ sTree.insert(5);
+ sTree.insert(15);
+ sTree.insert(7);
+ sTree.insert(12);
+ sTree.remove(10);
+ expect(sTree._root.value).toBe(7);
+ expect(sTree._root._left.value).toBe(5);
+ expect(sTree._root._right.value).toBe(12);
+ expect(sTree._root._right._right.value).toBe(15);
+ });
+});
diff --git a/test/graphics/bezier.spec.js b/test/graphics/bezier.spec.js
new file mode 100644
index 00000000..56f83ff2
--- /dev/null
+++ b/test/graphics/bezier.spec.js
@@ -0,0 +1,54 @@
+var bezier = require('../../src/graphics/bezier');
+var linearBezier = bezier.linearBezier;
+var quadraticBezier = bezier.quadraticBezier;
+var cubicBezier = bezier.cubicBezier;
+
+// see https://www.geogebra.org/m/ek7RHvuc for graphical representation of test values
+
+describe('linearBezier', function () {
+ 'use strict';
+
+ it('should return 0.5 for p0=0 p1=1 t=0.5', function () {
+ expect(linearBezier(0, 1, 0.5)).toEqual(0.5);
+ });
+
+ it('should return -2.8 for p0=-4.67 p1=-0.7 t=0.47', function () {
+ expect(linearBezier(-4.67, -0.7, 0.47)).toBeCloseTo(-2.8, 1);
+ });
+
+ it('should return 2.67 for p0=-0.6 p1=6.33 t=0.47', function () {
+ expect(linearBezier(-0.6, 6.33, 0.47)).toBeCloseTo(2.67, 1);
+ });
+});
+
+describe('quadraticBezier', function () {
+ 'use strict';
+
+ it('should return 1 for p0=0 p1=1 p2=2 t=0.5', function () {
+ expect(quadraticBezier(0, 1, 2, 0.5)).toEqual(1);
+ });
+
+ it('should return 7.15 for p0=2.33 p1=8.23 p2=10.77 t=0.47', function () {
+ expect(quadraticBezier(2.33, 8.23, 10.77, 0.47)).toBeCloseTo(7.15, 1);
+ });
+
+ it('should return 6.84 for p0=4.67 p1=8.93 p2=4.9 t=0.47', function () {
+ expect(quadraticBezier(4.67, 8.93, 4.9, 0.47)).toBeCloseTo(6.84, 1);
+ });
+});
+
+describe('cubicBezier', function () {
+ 'use strict';
+
+ it('should return 1.5 for p0=0 p1=1 p2=2 p3=3 t=0.5', function () {
+ expect(cubicBezier(0, 1, 2, 3, 0.5)).toEqual(1.5);
+ });
+
+ it('should return 9.78 for p0=2.4 p1=1.33 p2=19.87 p3=18.13 t=0.47', function () {
+ expect(cubicBezier(2.4, 1.33, 19.87, 18.13, 0.47)).toBeCloseTo(9.78, 1);
+ });
+
+ it('should return -4.87 for p0=-7.03 p1=-1.4 p2=-10.63 p3=4.5 t=0.47', function () {
+ expect(cubicBezier(-7.03, -1.4, -10.63, 4.5, 0.47)).toBeCloseTo(-4.87, 1);
+ });
+});
diff --git a/test/graphics/grapham.spec.js b/test/graphics/grapham.spec.js
new file mode 100644
index 00000000..867b0875
--- /dev/null
+++ b/test/graphics/grapham.spec.js
@@ -0,0 +1,26 @@
+var convexHull = require('../../src/graphics/graham').convexHull;
+
+const points = [
+ { x: 0, y: 0 },
+ { x: 1, y: 0 },
+ { x: 0, y: 1 },
+ { x: 0.15, y: 0.15 },
+ { x: 0.5, y: 0.5 }
+];
+
+describe('Graham\'s algorithm for convex hull', function() {
+ 'use strict';
+
+ it('should not throw with empty list', () => {
+ expect(() => convexHull([])).not.toThrow();
+ });
+
+ it('should calculate the convex hull', () => {
+ expect(convexHull(points)).toEqual([
+ { x: 0, y: 0 },
+ { x: 1, y: 0 },
+ { x: 0.5, y: 0.5 },
+ { x: 0, y: 1 }
+ ]);
+ });
+});
diff --git a/test/graphs/others/tarjan-connected-components.spec.js b/test/graphs/others/tarjan-connected-components.spec.js
new file mode 100644
index 00000000..e24ecbef
--- /dev/null
+++ b/test/graphs/others/tarjan-connected-components.spec.js
@@ -0,0 +1,36 @@
+var tj = require('../../../src/graphs/others/tarjan-connected-components').tarjanConnectedComponents;
+
+var nonConnected = {
+ v1: [],
+ v2: [],
+ v3: [],
+ v4: [],
+ v5: []
+};
+
+var cyclicGraph = {
+ v1: ['v2'],
+ v2: ['v3'],
+ v3: ['v4'],
+ v4: ['v5'],
+ v5: ['v1']
+};
+
+describe('Tarjan\'s algorithm for finding connected components', function () {
+ 'use strict';
+ it('should be defined', function () {
+ expect(typeof tj).toBe('function');
+ });
+
+ it('should return an array', function () {
+ expect(tj() instanceof Array).toBeTruthy();
+ });
+
+ it('should work with non-connected graphs', function () {
+ expect(tj(nonConnected)).toEqual([['v1'], ['v2'], ['v3'], ['v4'], ['v5']]);
+ });
+
+ it('should workw ith cycles', function () {
+ expect(tj(cyclicGraph)).toEqual([['v5', 'v4', 'v3', 'v2', 'v1']]);
+ });
+});
diff --git a/test/graphs/others/topological-sort.spec.js b/test/graphs/others/topological-sort.spec.js
new file mode 100644
index 00000000..019804b7
--- /dev/null
+++ b/test/graphs/others/topological-sort.spec.js
@@ -0,0 +1,40 @@
+var ts = require('../../../src/graphs/others/topological-sort').topologicalSort;
+
+describe('Topological sort', function () {
+ 'use strict';
+ it('should be defined', function () {
+ expect(typeof ts).toBe('function');
+ });
+
+ it('should work with empty graphs', function () {
+ expect(ts({})).toEqual([]);
+ });
+
+ it('should give the proper topological order', function () {
+ expect(ts({ v1: [] })).toEqual(['v1']);
+ var graph = {
+ v1: ['v2'],
+ v2: ['v3'],
+ v3: []
+ };
+ expect(ts(graph)).toEqual(['v1', 'v2', 'v3']);
+ graph = {
+ v1: ['v2', 'v5'],
+ v2: [],
+ v3: ['v1', 'v2', 'v4', 'v5'],
+ v4: [],
+ v5: []
+ };
+ expect(ts(graph)).toEqual(['v3', 'v4', 'v1', 'v5', 'v2']);
+ });
+
+ it('should throw an error on cycle', function () {
+ function runTs() {
+ ts({
+ v1: ['v2'],
+ v2: ['v1']
+ });
+ }
+ expect(runTs).toThrow();
+ });
+});
diff --git a/test/graphs/searching/bfs.spec.js b/test/graphs/searching/bfs.spec.js
index c8133574..c47c24d7 100644
--- a/test/graphs/searching/bfs.spec.js
+++ b/test/graphs/searching/bfs.spec.js
@@ -1,58 +1,53 @@
-'use strict';
+/* jshint multistr: true */
-var sampleGraph = [[1, 1, 1, 0, 0, 0],
- [0, 1, 1, 1, 0, 0],
- [1, 0, 1, 1, 1, 0],
- [0, 1, 0, 1, 1, 0],
- [0, 1, 0, 1, 1, 0],
- [0, 1, 0, 1, 1, 0],
- [0, 0, 1, 1, 1, 1],
- [0, 0, 0, 0, 1, 1]];
+var graph = [[0, 0, 0, 0, 1],
+ [0, 0, 0, 1, 0],
+ [0, 0, 0, 0, 0],
+ [1, 0, 1, 0, 0],
+ [0, 1, 0, 1, 0]];
-var bfs = require('../../../src/graphs/searching/bfs').breadthFirstSearch;
+var bfs = require('../../../src/graphs/searching/bfs').bfs;
describe('BFS', function () {
+ 'use strict';
- it('should work with incorrect input', function () {
- expect(function () {
- bfs(null, [1, 1], [1, 1]);
- }).toThrow();
- expect(function () {
- bfs(sampleGraph, [-1, -1], [0, 0]);
- }).toThrow();
- expect(function () {
- bfs(sampleGraph, [0, -1], [-1, 0]);
- }).toThrow();
- expect(function () {
- bfs(sampleGraph, [0, 0], [-1, 0]);
- }).toThrow();
- expect(function () {
- bfs(sampleGraph, [0, 1000], [-1, 0]);
- }).toThrow();
- expect(function () {
- bfs(sampleGraph, [100000, 1000], [-1, 0]);
- }).toThrow();
- expect(function () {
- bfs(sampleGraph, [0, 0], [100, 100]);
- }).toThrow();
- expect(function () {
- bfs(sampleGraph, [0, 0], [5, 5]);
- }).not.toThrow();
+ it('should work with empty graph', function () {
+ expect(bfs([], 0, 0)).toEqual([0]);
});
- it('should work with 1x1 matrix', function () {
- var graph = [[1]];
- expect(bfs(graph, [0, 0], [0, 0])).toBeTruthy();
- graph = [[0]];
- expect(bfs(graph, [0, 0], [0, 0])).toBeFalsy();
+ it('should return the correct output when used with\
+ source node equals target node', function () {
+ expect(bfs(graph, 2, 2)).toEqual([2]);
});
- it('should work in the general case', function () {
- expect(bfs(sampleGraph, [0, 0], [1, 1])).toBeTruthy();
- expect(bfs(sampleGraph, [0, 0], [6, 5])).toBeTruthy();
- expect(bfs(sampleGraph, [0, 0], [0, 5])).toBeFalsy();
- expect(bfs(sampleGraph, [1, 1], [6, 5])).toBeTruthy();
- expect(bfs(sampleGraph, [1, 1], [0, 5])).toBeFalsy();
+ it('should return work with cycles', function () {
+ expect(bfs(graph, 0, 2)).toEqual([0, 4, 3, 2]);
});
-});
\ No newline at end of file
+ it('should return falsy value when there\'s no path', function () {
+ var graph = [[0, 0, 0, 0, 1],
+ [0, 0, 0, 1, 0],
+ [0, 0, 0, 0, 0],
+ [1, 0, 0, 0, 0],
+ [0, 1, 0, 1, 0]];
+ expect(bfs(graph, 0, 2)).toBeFalsy();
+ });
+
+ /**
+ * In this case the graph should not
+ * update the parent of 2, in case it was called
+ * with source 0 and target 2, after the first iteration.
+ *
+ * 0 ---> 1
+ * \ |
+ * \ v
+ * -> 2
+ */
+ it('should not update the parent node once set', function () {
+ var graph = [[0, 1, 1],
+ [0, 0, 1],
+ [0, 0, 0]];
+ expect(bfs(graph, 0, 2)).toEqual([0, 2]);
+ });
+
+});
diff --git a/test/graphs/searching/dfs.spec.js b/test/graphs/searching/dfs.spec.js
index 84dd9708..34d59d62 100644
--- a/test/graphs/searching/dfs.spec.js
+++ b/test/graphs/searching/dfs.spec.js
@@ -1,58 +1,32 @@
-'use strict';
+var dfs = require('../../../src/graphs/searching/dfs').dfs;
-var sampleGraph = [[1, 1, 1, 0, 0, 0],
- [0, 1, 1, 1, 0, 0],
- [1, 0, 1, 1, 1, 0],
- [0, 1, 0, 1, 1, 0],
- [0, 1, 0, 1, 1, 0],
- [0, 1, 0, 1, 1, 0],
- [0, 0, 1, 1, 1, 1],
- [0, 0, 0, 0, 1, 1]];
+describe('dfs', function () {
+ 'use strict';
-var dfs = require('../../../src/graphs/searching/dfs').depthFirstSearch;
+ it('should work with empty graph', function () {
+ expect(dfs([[]])).toBeTruthy();
+ });
-describe('dfs', function () {
+ it('should always find a path between node and itself', function () {
+ expect(dfs([[0]]), 0, 0).toBeTruthy();
+ });
- it('should work with incorrect input', function () {
- expect(function () {
- dfs(null, [1, 1], [1, 1]);
- }).toThrow();
- expect(function () {
- dfs(sampleGraph, [-1, -1], [0, 0]);
- }).toThrow();
- expect(function () {
- dfs(sampleGraph, [0, -1], [-1, 0]);
- }).toThrow();
- expect(function () {
- dfs(sampleGraph, [0, 0], [-1, 0]);
- }).toThrow();
- expect(function () {
- dfs(sampleGraph, [0, 1000], [-1, 0]);
- }).toThrow();
- expect(function () {
- dfs(sampleGraph, [100000, 1000], [-1, 0]);
- }).toThrow();
- expect(function () {
- dfs(sampleGraph, [0, 0], [100, 100]);
- }).toThrow();
- expect(function () {
- dfs(sampleGraph, [0, 0], [5, 5]);
- }).not.toThrow();
+ it('should always find a path between two directly connected nodes', function () {
+ expect(dfs([[0, 1], [1, 0]], 0, 1)).toBeTruthy();
+ expect(dfs([[0, 1], [1, 0]], 1, 0)).toBeTruthy();
});
- it('should work with 1x1 matrix', function () {
- var graph = [[1]];
- expect(dfs(graph, [0, 0], [0, 0])).toBeTruthy();
- graph = [[0]];
- expect(dfs(graph, [0, 0], [0, 0])).toBeFalsy();
+ it('should always find a path between two directly connected' +
+ 'connected nodes in a directed graph', function () {
+ expect(dfs([[0, 0], [1, 0]], 1, 0)).toBeTruthy();
});
- it('should work in the general case', function () {
- expect(dfs(sampleGraph, [0, 0], [1, 1])).toBeTruthy();
- expect(dfs(sampleGraph, [0, 0], [6, 5])).toBeTruthy();
- expect(dfs(sampleGraph, [0, 0], [0, 5])).toBeFalsy();
- expect(dfs(sampleGraph, [1, 1], [6, 5])).toBeTruthy();
- expect(dfs(sampleGraph, [1, 1], [0, 5])).toBeFalsy();
+ it('should always find a path between two indirectly connected nodes', function () {
+ expect(dfs([[0, 1, 0], [0, 0, 1], [0, 0, 0]], 0, 2)).toBeTruthy();
});
-});
\ No newline at end of file
+ it('should not find a path between two nodes, which are not connected', function () {
+ expect(dfs([[0, 0], [1, 0]], 0, 1)).toBeFalsy();
+ expect(dfs([[0, 0, 0], [0, 0, 1], [0, 0, 0]], 0, 2)).toBeFalsy();
+ });
+});
diff --git a/test/graphs/shortest-path/bellman-ford.spec.js b/test/graphs/shortest-path/bellman-ford.spec.js
new file mode 100644
index 00000000..79a55d4e
--- /dev/null
+++ b/test/graphs/shortest-path/bellman-ford.spec.js
@@ -0,0 +1,36 @@
+var exported =
+ require('../../../src/graphs/shortest-path/bellman-ford');
+var bellmanFord = exported.bellmanFord;
+var Vertex = exported.Vertex;
+var Edge = exported.Edge;
+
+describe('Bellman-Ford', function () {
+ 'use strict';
+ it('should exports a method called bellmanFord', function () {
+ expect(typeof bellmanFord).toBe('function');
+ });
+
+ it('should work for an empty graph', function () {
+ var vs = [];
+ var e = [];
+ expect(bellmanFord(vs, e, undefined))
+ .toEqual({ parents: {}, distances: {} });
+ });
+
+ it('should work for a graph with a single vertex', function () {
+ var vs = [new Vertex(1)];
+ var e = [];
+ expect(bellmanFord(vs, e, vs[0]))
+ .toEqual({ parents: { 1: null }, distances: { 1: 0 }});
+ });
+
+ it('should work in the general case', function () {
+ var vs = [new Vertex(1), new Vertex(2), new Vertex(3)];
+ var e = [new Edge(vs[0], vs[1], 2),
+ new Edge(vs[0], vs[2], 10),
+ new Edge(vs[1], vs[2], 1)
+ ];
+ var output = bellmanFord(vs, e, vs[0]);
+ expect(output.distances['3']).toBe(3);
+ });
+});
diff --git a/test/graphs/shortest-path/dijkstra.spec.js b/test/graphs/shortest-path/dijkstra.spec.js
new file mode 100644
index 00000000..ca13b147
--- /dev/null
+++ b/test/graphs/shortest-path/dijkstra.spec.js
@@ -0,0 +1,26 @@
+var dijkstra =
+ require('../../../src/graphs/shortest-path/dijkstra').dijkstra;
+
+describe('dijkstra', function () {
+ 'use strict';
+ it('should define a function', function () {
+ expect(dijkstra).toBeDefined();
+ expect(typeof dijkstra).toBe('function');
+ });
+
+ it('should work with empty graph', function () {
+ expect(dijkstra(0, 0, [])).toBe(Infinity);
+ });
+
+ it('should work when the src and dest are the same', function () {
+ expect(dijkstra(0, 0, [[0]])).toBe(0);
+ });
+
+ it('should work when there\'s no path', function () {
+ expect(dijkstra(0, 1, [[0, Infinity], [Infinity, 0]])).toBe(Infinity);
+ });
+
+ it('should find the shortest path', function () {
+ expect(dijkstra(0, 2, [[0, 1, 4], [1, 0, 1], [4, 1, 0]])).toBe(2);
+ });
+});
diff --git a/test/graphs/spanning-trees/kruskal.spec.js b/test/graphs/spanning-trees/kruskal.spec.js
new file mode 100644
index 00000000..f3094b95
--- /dev/null
+++ b/test/graphs/spanning-trees/kruskal.spec.js
@@ -0,0 +1,53 @@
+var kruskal = require('../../../src/graphs/spanning-trees/kruskal');
+
+describe('Kruskal', function() {
+ 'use strict';
+
+ it('should define a function', function () {
+ expect(kruskal).toBeDefined();
+ expect(typeof kruskal).toBe('object');
+ expect(typeof kruskal.Graph).toBe('function');
+ expect(typeof kruskal.Edge).toBe('function');
+ expect(typeof kruskal.Vertex).toBe('function');
+ });
+
+ it('should work with an empty graph', function() {
+ var graph = new kruskal.Graph([], 0);
+ var spanningTree = graph.kruskal();
+
+ expect(spanningTree.edges.length).toEqual(0);
+ });
+
+ it('should correctly compute general example', function() {
+ var nodes = [];
+ var edges = [];
+ var i;
+ for (i = 0; i < 7; i += 1) {
+ nodes[i] = new kruskal.Vertex(i);
+ }
+
+ edges.push(new kruskal.Edge(nodes[0], nodes[1], 7));
+ edges.push(new kruskal.Edge(nodes[1], nodes[2], 8));
+ edges.push(new kruskal.Edge(nodes[2], nodes[4], 5));
+ edges.push(new kruskal.Edge(nodes[4], nodes[6], 9));
+ edges.push(new kruskal.Edge(nodes[5], nodes[6], 11));
+ edges.push(new kruskal.Edge(nodes[3], nodes[5], 6));
+ edges.push(new kruskal.Edge(nodes[0], nodes[3], 5));
+ edges.push(new kruskal.Edge(nodes[1], nodes[4], 7));
+ edges.push(new kruskal.Edge(nodes[1], nodes[3], 9));
+ edges.push(new kruskal.Edge(nodes[3], nodes[4], 15));
+ edges.push(new kruskal.Edge(nodes[4], nodes[5], 8));
+
+ var graph = new kruskal.Graph(edges);
+ var spanningTree = graph.kruskal();
+
+ expect(spanningTree.edges.length).toEqual(6);
+
+ var sum = spanningTree.edges.reduce(function(acc, edge) {
+ return acc += edge.distance;
+ }, 0);
+
+ expect(sum).toEqual(39);
+
+ })
+});
diff --git a/test/others/fibonacci.spec.js b/test/others/fibonacci.spec.js
new file mode 100644
index 00000000..80adb5ac
--- /dev/null
+++ b/test/others/fibonacci.spec.js
@@ -0,0 +1,28 @@
+var mod = require('../../src/others/fibonacci.js');
+var fibonacci = mod.fibonacci;
+
+describe('fibonacci algorithm', function () {
+ 'use strict';
+
+ it('should return value 1 with input 1.', function () {
+ expect(fibonacci(1)).toBe(1);
+ });
+ it('should return value 1 with input 2.', function () {
+ expect(fibonacci(2)).toBe(1);
+ });
+ it('should return value 2 with input 3.', function () {
+ expect(fibonacci(3)).toBe(2);
+ });
+ it('should return value 3 with input 4.', function () {
+ expect(fibonacci(4)).toBe(3);
+ });
+ it('should return value 5 with input 5.', function () {
+ expect(fibonacci(5)).toBe(5);
+ });
+ it('should be 83621143489848422977 with input 97.', function () {
+ expect(fibonacci(97)).toBe(83621143489848422977);
+ });
+ it('should throw when input is too large.', function () {
+ expect(function () {fibonacci(98)}).toThrow('Input too large, results in inaccurate fibonacci value.');
+ });
+});
diff --git a/test/others/fibonacciMemory.spec.js b/test/others/fibonacciMemory.spec.js
new file mode 100644
index 00000000..f90ac1df
--- /dev/null
+++ b/test/others/fibonacciMemory.spec.js
@@ -0,0 +1,28 @@
+var mod = require('../../src/others/fibonacciMemory.js');
+var fibonacci = mod.fibonacciMemory;
+
+describe('fibonacci with Memory algorithm', function () {
+ 'use strict';
+
+ it('should return value 1 with input 1.', function () {
+ expect(fibonacci(1)).toBe(1);
+ });
+ it('should return value 6 with input 8.', function () {
+ expect(fibonacci(6)).toBe(8);
+ });
+ it('should return value 7 with input 13.', function () {
+ expect(fibonacci(7)).toBe(13);
+ });
+ it('should return value 8 with input 21.', function () {
+ expect(fibonacci(8)).toBe(21);
+ });
+ it('should return value 9 with input 34.', function () {
+ expect(fibonacci(9)).toBe(34);
+ });
+ it('should return value 10 with input 55.', function () {
+ expect(fibonacci(10)).toBe(55);
+ });
+ it('should be 135301852344706760000 with input 98.', function () {
+ expect(fibonacci(98)).toBe(135301852344706760000);
+ });
+});
diff --git a/test/others/levenshtein-distance.spec.js b/test/others/levenshtein-distance.spec.js
new file mode 100644
index 00000000..8ff572bb
--- /dev/null
+++ b/test/others/levenshtein-distance.spec.js
@@ -0,0 +1,58 @@
+var mod = require('../../src/others/levenshtein-distance.js');
+var levenshteinDistance = mod.levenshteinDistance;
+
+describe('Levenstein\'s minimum edit distance algorithm', function () {
+ 'use strict';
+
+ it('should be defined', function () {
+ expect(levenshteinDistance).toBeDefined();
+ });
+
+ it('"" -> "" should return 0.', function () {
+ expect(levenshteinDistance('', '')).toBe(0);
+ });
+
+ it('"T" -> "" should return 1.', function () {
+ expect(levenshteinDistance('T', '')).toBe(1);
+ });
+
+ it('"cake" -> "rake" should return 1.', function () {
+ expect(levenshteinDistance('cake', 'rake')).toBe(1);
+ });
+
+ it('"Sofia" -> "Sof" should return 2.', function () {
+ expect(levenshteinDistance('Sofia', 'Sof')).toBe(2);
+ });
+
+ it('"kitten" -> "sitting" should return 3', function () {
+ expect(levenshteinDistance('kitten', 'sitting')).toBe(3);
+ });
+
+ it('"google" -> "lookat" should return 4.', function () {
+ expect(levenshteinDistance('google', 'lookat')).toBe(4);
+ });
+
+ it('"emacs" -> "vim" should return 5.', function () {
+ expect(levenshteinDistance('emacs', 'vim')).toBe(5);
+ });
+
+ it('"coffee" -> "cocoa" should return 4.', function () {
+ expect(levenshteinDistance('coffee', 'cocoa')).toBe(4);
+ });
+
+ it('"Munich" -> "Muenchen" should return 4.', function () {
+ expect(levenshteinDistance('Munich', 'Muenchen')).toBe(4);
+ });
+
+ it('"rosebud" -> "budrose" should return 6.', function () {
+ expect(levenshteinDistance('rosebud', 'budrose')).toBe(6);
+ });
+
+ it('"decided" -> "decisive" should return 4.', function () {
+ expect(levenshteinDistance('decided', 'decisive')).toBe(4);
+ });
+
+ it('"similar" -> "simile" should return 2.', function () {
+ expect(levenshteinDistance('similar', 'simile')).toBe(2);
+ });
+});
diff --git a/test/others/min-coins-sum.spec.js b/test/others/min-coins-sum.spec.js
new file mode 100644
index 00000000..f0e46644
--- /dev/null
+++ b/test/others/min-coins-sum.spec.js
@@ -0,0 +1,29 @@
+var minCoinsChange =
+ require('../../src/others/min-coins-change.js').minCoinsChange;
+
+describe('Change making problem', function () {
+ 'use strict';
+
+ it('should be defined', function () {
+ expect(minCoinsChange).toBeDefined();
+ });
+
+ it('should work for 0 change', function () {
+ expect(minCoinsChange([1, 2], 0)).toEqual([]);
+ });
+
+ it('should work for change equals to array element', function () {
+ expect(minCoinsChange([1, 2], 1)).toEqual([1]);
+ });
+
+ it('should return the minimum amount of coins', function () {
+ expect(minCoinsChange([1], 2)).toEqual([1, 1]);
+ expect(minCoinsChange([1, 2], 3)).toEqual([1, 2]);
+ // [2, 3, 2, 3] or [1, 3, 3, 3]
+ expect(minCoinsChange([1, 2, 3], 10).length).toEqual(4);
+ });
+
+ it('should return undefined for combination, which is not possible', function () {
+ expect(minCoinsChange([1, 2, 3], 0.5)).not.toBeDefined();
+ });
+});
diff --git a/test/others/minimax.spec.js b/test/others/minimax.spec.js
new file mode 100644
index 00000000..a867d893
--- /dev/null
+++ b/test/others/minimax.spec.js
@@ -0,0 +1,277 @@
+const minimaxBuilder = require('../../src/others/minimax.js').minimaxBuilder;
+
+describe('Minimax', function () {
+ 'use strict';
+
+ it('builder should be defined', function () {
+ expect(minimaxBuilder).toBeDefined();
+ });
+
+ describe('with tic tac toe', function () {
+ let game = ticTacToe();
+
+ function getAllNextStates(state) {
+ const possibleMoves = game.emptyCells(state);
+
+ return possibleMoves.map(move => ({
+ move,
+ state: game.nextState(state, move),
+ }));
+ }
+
+ const minimaxForX = minimaxBuilder(
+ getAllNextStates,
+ state => game.isGameOver(state),
+ state => game.getScore(state).x - game.getScore(state).o
+ )
+
+ const minimaxForO = minimaxBuilder(
+ getAllNextStates,
+ state => game.isGameOver(state),
+ state => game.getScore(state).o - game.getScore(state).x
+ )
+
+ it('should win versus dumb agent as first player', function () {
+ let state = game.newState('x');
+
+ while (!game.isGameOver(state)) {
+ if (state.turn === 'x') {
+ state = game.nextState(state, minimaxForX(state, true, 5, -Infinity, Infinity).move);
+ } else {
+ const move = game.emptyCells(state)[0];
+ state = game.nextState(state, move);
+ }
+ }
+
+ expect(game.isGameOver(state)).toBe(true);
+ expect(game.getScore(state)).toEqual({x: 1, o: 0});
+ });
+
+ it('should win versus dumb agent as second player', function () {
+ let state = game.newState('x');
+
+ while (!game.isGameOver(state)) {
+ if (state.turn === 'o') {
+ state = game.nextState(state, minimaxForO(state, true, 5, -Infinity, Infinity).move);
+ } else {
+ const move = game.emptyCells(state)[0];
+ state = game.nextState(state, move);
+ }
+ }
+
+ expect(game.isGameOver(state)).toBe(true);
+ expect(game.getScore(state)).toEqual({x: 0, o: 1});
+ });
+
+
+ it('should be a tie for two minimax agents', function () {
+ let state = game.newState('x');
+
+ while (!game.isGameOver(state)) {
+ if (state.turn === 'o') {
+ state = game.nextState(state, minimaxForO(state, true, 5, -Infinity, Infinity).move);
+ } else {
+ state = game.nextState(state, minimaxForX(state, true, 5, -Infinity, Infinity).move);
+ }
+ }
+ expect(game.isGameOver(state)).toBe(true);
+ expect(game.getScore(state)).toEqual({x: 0, o: 0});
+ });
+ });
+
+ describe('with simple game', function () {
+ let game = simpleGame();
+
+ const minimaxForA = minimaxBuilder(
+ state => [true, false].map(move => ({ move, state: game.nextState(state, move)})),
+ state => game.isGameOver(state),
+ state => game.getScore(state).A - game.getScore(state).B
+ );
+ const minimaxForB = minimaxBuilder(
+ state => [true, false].map(move => ({ move, state: game.nextState(state, move)})),
+ state => game.isGameOver(state),
+ state => game.getScore(state).B - game.getScore(state).A
+ );
+
+ it('should win versus dumb agent as a first player', function () {
+ /* o
+ / \
+ o o
+ / \ / \
+ o o o o
+ / \ / \ / \ / \
+ -1 1 1 1 1 -1 1 -1
+ */
+ const binaryTree = [0, 0, 0, 0, 0, 0, 0, -1, 1, 1, 1, 1, -1, 1, -1];
+ let state = game.newState(binaryTree);
+
+ while (!game.isGameOver(state)) {
+ if (state.turn === 'A') {
+ state = game.nextState(state, minimaxForA(state, true, 5, -Infinity, Infinity).move);
+ } else {
+ state = game.nextState(state, false);
+ }
+ }
+
+ expect(game.isGameOver(state)).toBe(true);
+ expect(game.getScore(state)).toEqual({A: 1, B: -1});
+ });
+
+ it('should win versus dumb agent as a second player', function () {
+ /* o
+ / \
+ o o
+ / \ / \
+ -1 -1 -1 1
+ */
+ const binaryTree = [0, 0, 0, -1, -1, -1, 1];
+ let state = game.newState(binaryTree);
+
+ while (!game.isGameOver(state)) {
+ if (state.turn === 'B') {
+ state = game.nextState(state, minimaxForB(state, true, 5, -Infinity, Infinity).move);
+ } else {
+ state = game.nextState(state, false);
+ }
+ }
+
+ expect(game.isGameOver(state)).toBe(true);
+ expect(game.getScore(state)).toEqual({A: -1, B: 1});
+ });
+ });
+});
+
+function ticTacToe() {
+ 'use strict';
+
+ function newState(turn) {
+ return {
+ board: [[0, 0, 0],
+ [0, 0, 0],
+ [0, 0, 0]],
+ turn
+ };
+ }
+
+ function emptyCells(state) {
+ const result = [];
+ state.board.forEach((row, y) => {
+ row.forEach((cell, x) => {
+ if (cell === 0) {
+ result.push({x, y})
+ }
+ });
+ });
+
+ return result;
+ }
+
+ function getWinner(state) {
+ const winVariants = [
+ [{x: 0, y: 0}, {x: 0, y: 1}, {x: 0, y: 2}],
+ [{x: 1, y: 0}, {x: 1, y: 1}, {x: 1, y: 2}],
+ [{x: 2, y: 0}, {x: 2, y: 1}, {x: 2, y: 2}],
+
+ [{x: 0, y: 0}, {x: 1, y: 0}, {x: 2, y: 0}],
+ [{x: 0, y: 1}, {x: 1, y: 1}, {x: 2, y: 1}],
+ [{x: 0, y: 2}, {x: 1, y: 0}, {x: 2, y: 2}],
+
+ [{x: 0, y: 0}, {x: 1, y: 1}, {x: 2, y: 2}],
+ [{x: 2, y: 0}, {x: 1, y: 1}, {x: 2, y: 0}],
+ ];
+
+ for (const variant of winVariants) {
+ const combo = variant.map(cell => state.board[cell.y][cell.x]).join('');
+ if (combo === 'xxx') {
+ return 'x';
+ } else if (combo === 'ooo') {
+ return 'o';
+ }
+ }
+
+ return null;
+ }
+
+ function allFieldsMarked(state) {
+ return state.board.every(row => row.every(cell => cell !== 0));
+ }
+
+ function isGameOver(state) {
+ return allFieldsMarked(state) || getWinner(state) !== null;
+ }
+
+ function getScore(state) {
+ if (getWinner(state) === 'x') {
+ return {x: 1, o: 0};
+ } else if (getWinner(state) === 'o') {
+ return {x: 0, o: 1};
+ }
+
+ return {x: 0, o: 0};
+ }
+
+ function nextState(state, move) {
+ const newBoard = state.board.map(row => row.slice());
+ newBoard[move.y][move.x] = state.turn;
+ return {
+ board: newBoard,
+ turn: state.turn === 'x' ? 'o' : 'x',
+ };
+ }
+
+ return {
+ newState,
+ getScore,
+ nextState,
+ isGameOver,
+ emptyCells,
+ }
+}
+
+
+/* A simple game made for the purpose of minimax testing. The game has a binary tree with end values: 1 for player A win and -1 for player B win.
+ Game starts from the root node and each player has a binary choose - "false" moves to the left child and "true" moves to the right child.
+ The game ends when the very bottom leaf is reached.
+ o
+ / \
+ o o
+ / \ / \
+ 1 -1 -1 -1
+ */
+function simpleGame() {
+ 'use strict';
+
+ function newState(binaryTree) {
+ return {
+ turn: 'A',
+ tree: binaryTree,
+ position: 0,
+ };
+ }
+
+ function nextState(state, move) {
+ return {
+ tree: state.tree,
+ position: move ? state.position * 2 + 2 : state.position * 2 + 1,
+ turn: state.turn === 'A' ? 'B' : 'A',
+ };
+ }
+
+ function isGameOver(state) {
+ return state.tree[state.position] !== 0;
+ }
+
+ function getScore(state) {
+ return {
+ A: state.tree[state.position],
+ B: state.tree[state.position] === 0 ? 0 : -state.tree[state.position],
+ }
+ }
+
+ return {
+ newState,
+ nextState,
+ isGameOver,
+ getScore,
+ }
+}
diff --git a/test/others/minkowski-distance.spec.js b/test/others/minkowski-distance.spec.js
new file mode 100644
index 00000000..1c1795cf
--- /dev/null
+++ b/test/others/minkowski-distance.spec.js
@@ -0,0 +1,42 @@
+var mod = require('../../src/others/minkowski-distance.js');
+var minkowskiDistance = mod.minkowskiDistance;
+
+describe('Minkowski Distance', function () {
+ 'use strict';
+
+ it('should return 1 with points (0, 1), (1, 1) in order 1.', function () {
+ expect(minkowskiDistance([0, 1], [1, 1], 1)).toBe(1);
+ });
+ it('should return 2 with points (0, 1), (1, 1) in order 2.', function () {
+ expect(minkowskiDistance([0, 1], [1, 1], 2)).toBe(1);
+ });
+ it('should return 2 with points (0, 1, 4), (1, 1, 6) in order Positive Infinity.', function () {
+ expect(minkowskiDistance([0, 1, 4], [1, 1, 6], Number.POSITIVE_INFINITY)).toBe(2);
+ });
+ it('should return 0 with points (0, 1, 4), (1, 1, 6) in order Negative Infinity.', function () {
+ expect(minkowskiDistance([0, 1, 4], [1, 1, 6], Number.NEGATIVE_INFINITY)).toBe(0);
+ });
+ it('should return 8.372966759705923 with points (0, 3, 4, 5), (7, 6, 3, -1) in order 3.', function () {
+ expect(minkowskiDistance([0, 3, 4, 5], [7, 6, 3, -1], 3)).toBe(8.372966759705923);
+ });
+ it('should throw when both vectors don\'t have same dimension', function () {
+ expect(function () {
+ minkowskiDistance([1, 2], [1], 1)
+ }).toThrow('Both vectors should have same dimension');
+ });
+ it('should throw when p is not defined', function () {
+ expect(function () {
+ minkowskiDistance([1, 2], [1, 2])
+ }).toThrow('The order "p" must be a number');
+ });
+ it('should throw when p is not a number', function () {
+ expect(function () {
+ minkowskiDistance([1, 2], [1, 2], NaN)
+ }).toThrow('The order "p" must be a number');
+ });
+ it('should throw when p is less than 1', function () {
+ expect(function () {
+ minkowskiDistance([1, 2], [1, 2], 0)
+ }).toThrow('Order less than 1 will violate the triangle inequality');
+ });
+});
diff --git a/test/primes/is-prime.spec.js b/test/primes/is-prime.spec.js
new file mode 100644
index 00000000..65bd4ace
--- /dev/null
+++ b/test/primes/is-prime.spec.js
@@ -0,0 +1,28 @@
+var isPrime = require('../../src/primes/is-prime').isPrime;
+
+describe('Advanced (optimised) method that checks number on prime', function () {
+ 'use strict';
+
+ it('should give true for number 104743', function () {
+ expect(isPrime(104743)).toBe(true);
+ });
+
+ it('should give false for number 104744', function () {
+ expect(isPrime(104744)).toBe(false);
+ });
+
+ it('the 10001st prime number should be 104743', function () {
+ var count = 1; //we know that 2 is prime
+ var value = 1;
+
+ while (count < 10001) {
+ value += 2;
+
+ if (isPrime(value)) {
+ count += 1;
+ }
+ }
+
+ expect(value).toEqual(104743);
+ });
+});
diff --git a/test/primes/prime-factor-tree.spec.js b/test/primes/prime-factor-tree.spec.js
new file mode 100644
index 00000000..d8d8c5dd
--- /dev/null
+++ b/test/primes/prime-factor-tree.spec.js
@@ -0,0 +1,28 @@
+var primeFactorTree = require('../../src/primes/prime-factor-tree').primeFactorTree;
+
+describe('Prime factor tree', function () {
+ 'use strict';
+
+ it('for number 104743 should return [104743]', function () {
+ expect(primeFactorTree(104743).toString()).toEqual([104743].toString());
+ });
+
+ it('for number 18 should return [2, 3, 3]', function () {
+ expect(primeFactorTree(18).toString()).toEqual([2, 3, 3].toString());
+ });
+
+ it('should give the empty list for number less or equal 1', function () {
+ expect(primeFactorTree(-12).toString()).toEqual([].toString());
+ expect(primeFactorTree(0).toString()).toEqual([].toString());
+ expect(primeFactorTree(1).toString()).toEqual([].toString());
+ });
+
+ it('sum of primes for given number 600851475143 should be 9238', function () {
+ var primes = primeFactorTree(600851475143);
+ var sumOfPrimes = primes.reduce(function (previousValue, currentValue) {
+ return previousValue + currentValue;
+ });
+
+ expect(sumOfPrimes).toEqual(9238);
+ });
+});
diff --git a/test/primes/sieve-of-atkins.spec.js b/test/primes/sieve-of-atkins.spec.js
new file mode 100644
index 00000000..c371d915
--- /dev/null
+++ b/test/primes/sieve-of-atkins.spec.js
@@ -0,0 +1,26 @@
+var sieveOfAtkins =
+ require('../../src/primes/sieve-of-atkins').sieveOfAtkins;
+
+describe('Sieve Of Atkins', function () {
+ 'use strict';
+
+ it('should give the right sequence of primes for limit 12', function () {
+ expect(sieveOfAtkins(12).toString())
+ .toEqual([2, 3, 5, 7, 11].toString());
+ });
+
+ it('should give the empty list for limit less or equal 1', function () {
+ expect(sieveOfAtkins(-12).toString()).toEqual([].toString());
+ expect(sieveOfAtkins(0).toString()).toEqual([].toString());
+ expect(sieveOfAtkins(1).toString()).toEqual([].toString());
+ });
+
+ it('sum of prime numbers up to 2000000 limit should be 142913828922', function () {
+ var sieve = sieveOfAtkins(2000000);
+ var sumOfPrimes = sieve.reduce(function (previousValue, currentValue) {
+ return previousValue + currentValue;
+ });
+
+ expect(sumOfPrimes).toEqual(142913828922);
+ });
+});
diff --git a/test/primes/sieve-of-eratosthenes.spec.js b/test/primes/sieve-of-eratosthenes.spec.js
new file mode 100644
index 00000000..5d9e166c
--- /dev/null
+++ b/test/primes/sieve-of-eratosthenes.spec.js
@@ -0,0 +1,26 @@
+var sieveOfEratosthenes =
+ require('../../src/primes/sieve-of-eratosthenes').sieveOfEratosthenes;
+
+describe('Sieve Of Eratosthenes', function () {
+ 'use strict';
+
+ it('should give the right sequence of primes for limit 12', function () {
+ expect(sieveOfEratosthenes(12).toString())
+ .toEqual([2, 3, 5, 7, 11].toString());
+ });
+
+ it('should give the empty list for limit less or equal 1', function () {
+ expect(sieveOfEratosthenes(-12).toString()).toEqual([].toString());
+ expect(sieveOfEratosthenes(0).toString()).toEqual([].toString());
+ expect(sieveOfEratosthenes(1).toString()).toEqual([].toString());
+ });
+
+ it('sum of prime numbers up to 2000000 limit should be 142913828922', function () {
+ var sieve = sieveOfEratosthenes(2000000);
+ var sumOfPrimes = sieve.reduce(function (previousValue, currentValue) {
+ return previousValue + currentValue;
+ });
+
+ expect(sumOfPrimes).toEqual(142913828922);
+ });
+});
diff --git a/test/searching/binarysearch.spec.js b/test/searching/binarysearch.spec.js
new file mode 100644
index 00000000..13dbbaca
--- /dev/null
+++ b/test/searching/binarysearch.spec.js
@@ -0,0 +1,37 @@
+var binarySearch =
+ require('../../src/searching/binarysearch').binarySearch;
+
+describe('Binary search', function () {
+ 'use strict';
+
+ it('should find the element at position 0 ', function () {
+ expect(binarySearch([1, 2, 3, 4, 6, 8], 1)).toBe(0);
+ });
+
+ it('should find the element in position arr.length - 1', function () {
+ var arr = [1, 2, 3, 4, 6, 8];
+ expect(binarySearch(arr, 8)).toBe(arr.length - 1);
+ });
+
+ it('should work with arrays with 2 elements', function () {
+ expect(binarySearch([1, 8], 1)).toBe(0);
+ expect(binarySearch([1, 8], 8)).toBe(1);
+ });
+
+ it('should return a negative number for missing elements', function () {
+ expect(binarySearch([1, 2, 3], 4)).toBeLessThan(0);
+ });
+
+ it('should work with empty arrays', function () {
+ expect(binarySearch([], 4)).toBe(-1);
+ });
+
+ it('should work with a key string', function () {
+ expect(binarySearch([{ x: 1 }, { x: 2 }, { x: 3 }], { x: 2 }, 'x')).toBe(1);
+ });
+
+ it('should work with a key function', function () {
+ expect(binarySearch([{ x: 1 }, { x: 2 }, { x: 3 }],
+ { x: 2 }, function (o) { return o.x; })).toBe(1);
+ });
+});
diff --git a/test/searching/interpolation-search.spec.js b/test/searching/interpolation-search.spec.js
new file mode 100644
index 00000000..26757a4e
--- /dev/null
+++ b/test/searching/interpolation-search.spec.js
@@ -0,0 +1,22 @@
+var interpolationSearch = require('../../src/searching/interpolation-search')
+ .interpolationSearch;
+
+describe('Interpolation search', function() {
+ 'use strict';
+
+ it('should find the element at position 0 ', function() {
+ expect(interpolationSearch([1, 2, 3, 4, 6, 8], 1)).toBe(0);
+ });
+
+ it('should find the element at position 4 ', function() {
+ expect(interpolationSearch([1, 2, 3, 4, 6, 8], 6)).toBe(4);
+ });
+
+ it('should return -1 if element is not found', function() {
+ expect(interpolationSearch([1, 2, 3, 4, 6, 8], 17)).toBe(-1);
+ });
+
+ it('should return -1 if array is empty', function() {
+ expect(interpolationSearch([], 10)).toBe(-1);
+ });
+});
diff --git a/test/searching/jump-search.spec.js b/test/searching/jump-search.spec.js
new file mode 100644
index 00000000..3f9b2b76
--- /dev/null
+++ b/test/searching/jump-search.spec.js
@@ -0,0 +1,21 @@
+var jumpSearch = require('../../src/searching/jump-search').jumpSearch;
+
+describe('Jump search', function() {
+ 'use strict';
+
+ it('should find the element at position 0 ', function() {
+ expect(jumpSearch([1, 2, 3, 4, 6, 8], 1)).toBe(0);
+ });
+
+ it('should find the element at position 4 ', function() {
+ expect(jumpSearch([1, 2, 3, 4, 6, 8], 6)).toBe(4);
+ });
+
+ it('should return -1 ', function() {
+ expect(jumpSearch([1, 2, 3, 4, 6, 8], 10)).toBe(-1);
+ });
+
+ it('should return -1 ', function() {
+ expect(jumpSearch([], 10)).toBe(-1);
+ });
+});
diff --git a/test/searching/knuth-morris-pratt.spec.js b/test/searching/knuth-morris-pratt.spec.js
new file mode 100644
index 00000000..b12b7a0e
--- /dev/null
+++ b/test/searching/knuth-morris-pratt.spec.js
@@ -0,0 +1,25 @@
+var indexOf = require('../../src/searching/knuth-morris-pratt').kmp;
+
+describe('The string searching algorithm of Knuth-Morris-Pratt', function () {
+ 'use strict';
+
+ it('should find the empty string in any string', function () {
+ expect(indexOf('', '')).toBe(0);
+ expect(indexOf('foo', '')).toBe(0);
+ });
+
+ it('should return negative value for patterns, which are ' +
+ 'not part of the string', function () {
+ expect(indexOf('foo', 'bar') < 0).toBeTruthy();
+ expect(indexOf('f', 'foobar') < 0).toBeTruthy();
+ expect(indexOf('foobar', 'fobar') < 0).toBeTruthy();
+ });
+
+ it('should return the first index of the matching pattern', function () {
+ expect(indexOf('foo', 'f')).toBe(0);
+ expect(indexOf('foo', 'oo')).toBe(1);
+ expect(indexOf('foo', 'o')).toBe(1);
+ expect(indexOf('foobar', 'foo')).toBe(0);
+ expect(indexOf('foobar', 'bar')).toBe(3);
+ });
+});
diff --git a/test/searching/linearSearch.spec.js b/test/searching/linearSearch.spec.js
new file mode 100644
index 00000000..6540bf5a
--- /dev/null
+++ b/test/searching/linearSearch.spec.js
@@ -0,0 +1,28 @@
+var linearSearch =
+ require('../../src/searching/linearSearch').linearSearch;
+
+describe('Linear Search', function () {
+ 'use strict';
+
+ it('should find the element at position 0 ', function () {
+ expect(linearSearch([1, 2, 3, 4, 6, 8], 1)).toBe(0);
+ });
+
+ it('should find the element in position arr.length - 1', function () {
+ var arr = [1, 2, 3, 4, 6, 8];
+ expect(linearSearch(arr, 8)).toBe(arr.length - 1);
+ });
+
+ it('should work with arrays with 2 elements', function () {
+ expect(linearSearch([1, 8], 1)).toBe(0);
+ expect(linearSearch([1, 8], 8)).toBe(1);
+ });
+
+ it('should return a negative number for missing elements', function () {
+ expect(linearSearch([1, 2, 3], 4)).toBeLessThan(0);
+ });
+
+ it('should work with empty arrays', function () {
+ expect(linearSearch([], 4)).toBe(-1);
+ });
+});
diff --git a/test/searching/longest-common-subsequence.spec.js b/test/searching/longest-common-subsequence.spec.js
new file mode 100644
index 00000000..24fc47cd
--- /dev/null
+++ b/test/searching/longest-common-subsequence.spec.js
@@ -0,0 +1,48 @@
+var longestCommonSubsequence =
+ require('../../src/searching/' +
+ 'longest-common-subsequence')
+ .longestCommonSubsequence;
+
+describe('longest common subsequence', function () {
+ 'use strict';
+
+ it('should work with empty strings', function () {
+ expect(longestCommonSubsequence('', '')).toBe('');
+ });
+
+ it('should work with first string empty', function () {
+ expect(longestCommonSubsequence('', 'abcd')).toBe('');
+ });
+
+ it('should work with second string empty', function () {
+ expect(longestCommonSubsequence('abcd', '')).toBe('');
+ });
+
+ it('should work if there is no lcs', function () {
+ expect(longestCommonSubsequence('qtwer', 'zvxcv')).toBe('');
+ });
+
+ it('should work if lcs is whole first string', function () {
+ expect(longestCommonSubsequence('abc', 'abcdefghi')).toBe('abc');
+ });
+
+ it('should work if lcs is whole second string', function () {
+ expect(longestCommonSubsequence('qwerty', 'rty')).toBe('rty');
+ });
+
+ it('should work with repeated letter', function () {
+ expect(longestCommonSubsequence('AAATC', 'GGTAGGC')).toBe('AC');
+ });
+
+ it('should work with custom characters', function () {
+ expect(longestCommonSubsequence(':-)', 'B-)')).toBe('-)');
+ });
+
+ it('should work with long strings', function () {
+ expect(longestCommonSubsequence('this is the first string', 'that is second')).toBe('tht is sn');
+ });
+
+ it('should work with very long strings', function () {
+ expect(longestCommonSubsequence('giiiiiiit1huuuuuu2bbb', 'zzxxcvasdfgmntplpliiggggu2b222')).toBe('giiu2b');
+ });
+});
diff --git a/test/searching/longest-increasing-subsequence.spec.js b/test/searching/longest-increasing-subsequence.spec.js
new file mode 100644
index 00000000..d6e214e7
--- /dev/null
+++ b/test/searching/longest-increasing-subsequence.spec.js
@@ -0,0 +1,46 @@
+var longestIncreasingSubsequence =
+ require('../../src/searching/' +
+ 'longest-increasing-subsequence')
+ .longestIncreasingSubsequence;
+
+describe('longest increasing subsequence', function () {
+ 'use strict';
+
+ var sequence;
+ beforeEach(function () {
+ sequence = [5, 2, 8, 6, 3, 6, 9, 7, 11];
+ });
+
+ it('should work with empty array', function () {
+ expect(longestIncreasingSubsequence([]).length).toBe(0);
+ });
+
+ it('should return the only element in a single element array', function () {
+ var array = [1];
+ expect(longestIncreasingSubsequence(array)).toEqual([1]);
+ });
+
+ it('should give the right length', function () {
+ expect(longestIncreasingSubsequence(sequence).length).toBe(5);
+ });
+
+ it('should work with empty arrays', function () {
+ expect(longestIncreasingSubsequence([]).length).toBe(0);
+ });
+
+ it('should return the correct path', function () {
+ expect(longestIncreasingSubsequence(sequence).toString())
+ .toBe([2, 3, 6, 9, 11].toString());
+ });
+
+ it('should work with a custom comparator', function () {
+ var cmp = function (a, b) {
+ return b - a;
+ };
+ var seq = [1, 2, -1];
+ var result = longestIncreasingSubsequence(seq, cmp);
+ expect(result.length).toBe(2);
+ expect(result).toEqual([1, -1]);
+ });
+});
+
diff --git a/test/searching/longest-increasing-subsequence/longest-increasing-subsequence.spec.js b/test/searching/longest-increasing-subsequence/longest-increasing-subsequence.spec.js
deleted file mode 100644
index 78c48bb9..00000000
--- a/test/searching/longest-increasing-subsequence/longest-increasing-subsequence.spec.js
+++ /dev/null
@@ -1,28 +0,0 @@
-'use strict';
-
-var longestSubsequence =
- require('../../../src/searching/' +
- 'longest-increasing-subsequence/longest-increasing-subsequence')
- .longestSubsequence;
-
-describe('longest subsequence', function () {
-
- var sequence;
- beforeEach(function () {
- sequence = [5, 2, 8, 6, 3, 6, 9, 7, 11];
- });
-
- it('should give the right length', function () {
- expect(longestSubsequence(sequence).length).toBe(5);
- });
-
- it('should work with empty arrays', function () {
- expect(longestSubsequence([]).length).toBe(0);
- });
-
- it('should return the correct path', function () {
- expect(longestSubsequence(sequence).toString())
- .toBe([2, 3, 6, 9, 11].toString());
- });
-
-});
\ No newline at end of file
diff --git a/test/searching/subarray/maximum-subarray-divide-and-conquer.spec.js b/test/searching/maximum-subarray-divide-and-conquer.spec.js
similarity index 90%
rename from test/searching/subarray/maximum-subarray-divide-and-conquer.spec.js
rename to test/searching/maximum-subarray-divide-and-conquer.spec.js
index 40deb2e9..cfd58cf3 100644
--- a/test/searching/subarray/maximum-subarray-divide-and-conquer.spec.js
+++ b/test/searching/maximum-subarray-divide-and-conquer.spec.js
@@ -1,10 +1,9 @@
-'use strict';
-
var maxSubArray =
- require('../../../src/searching/subarray/maximum-subarray-divide-and-conquer')
+ require('../../src/searching/maximum-subarray-divide-and-conquer')
.maxSubarray;
describe('Maximum subarray implemented with divide and conquer', function () {
+ 'use strict';
it('should work with empty arrays', function () {
expect(isNaN(maxSubArray([]))).toBeTruthy();
@@ -34,4 +33,4 @@ describe('Maximum subarray implemented with divide and conquer', function () {
expect(maxSubArray([-10, -1, -2, -3, -1])).toBe(-1);
});
-});
\ No newline at end of file
+});
diff --git a/test/searching/maximum-subarray.spec.js b/test/searching/maximum-subarray.spec.js
new file mode 100644
index 00000000..66daa8c7
--- /dev/null
+++ b/test/searching/maximum-subarray.spec.js
@@ -0,0 +1,29 @@
+var maxSubArray = require('../../src/searching/maximum-subarray').maxSubarray;
+
+describe('Maximum subarray', function() {
+ 'use strict';
+
+ it('should work with empty arrays', function() {
+ expect(maxSubArray([])).toBeUndefined();
+ });
+
+ it('should return the only element when an array with single element is passed', function() {
+ expect(maxSubArray([42])).toBe(42);
+ });
+
+ it('should return the only negative element when an array with single element is passed', function() {
+ expect(maxSubArray([-42])).toBe(-42);
+ });
+
+ it('should return the zero when an array with single element, which is zero is passed', function() {
+ expect(maxSubArray([0])).toBe(0);
+ });
+
+ it('should return the max sum of a subarray', function() {
+ expect(maxSubArray([1, -1, 2, 3, -1])).toBe(5);
+ });
+
+ it('should return the max negative number when array with negative numbers is provided', function() {
+ expect(maxSubArray([-10, -1, -2, -3, -1])).toBe(-1);
+ });
+});
diff --git a/test/searching/quickselect.spec.js b/test/searching/quickselect.spec.js
new file mode 100644
index 00000000..e48f0532
--- /dev/null
+++ b/test/searching/quickselect.spec.js
@@ -0,0 +1,31 @@
+var quickselect = require('../../src/searching/quickselect').quickselect;
+
+describe('quickselect', function () {
+ 'use strict';
+
+ it('should be defined as function', function () {
+ expect(typeof quickselect).toBe('function');
+ });
+
+ it('should work with empty array', function () {
+ expect(quickselect([], 1)).toBe(undefined);
+ });
+
+ it('should find the only element in the list', function () {
+ expect(quickselect([1], 0)).toBe(1);
+ });
+
+ it('should return undefined if the list is smaller than the index',
+ function () {
+ expect(quickselect([2, 1], 3)).toBeUndefined();
+ });
+
+ it('should find the element if in sorted order', function () {
+ expect(quickselect([1, 2], 0)).toBe(1);
+ expect(quickselect([1, 2], 1)).toBe(2);
+ });
+
+ it('should fine the element if not in sorted order', function () {
+ expect(quickselect([2, 1, 9, 6], 3)).toBe(9);
+ });
+});
diff --git a/test/searching/binarysearch/binarysearch.spec.js b/test/searching/recursive-binarysearch.spec.js
similarity index 72%
rename from test/searching/binarysearch/binarysearch.spec.js
rename to test/searching/recursive-binarysearch.spec.js
index 606c8729..4ab687b3 100644
--- a/test/searching/binarysearch/binarysearch.spec.js
+++ b/test/searching/recursive-binarysearch.spec.js
@@ -1,9 +1,8 @@
-'use strict';
-
var binarySearch =
- require('../../../src/searching/binarysearch/binarysearch').binarySearch;
+ require('../../src/searching/recursive-binarysearch').binarySearch;
describe('Binary search', function () {
+ 'use strict';
it('should find the element at position 0 ', function () {
expect(binarySearch([1, 2, 3, 4, 6, 8], 1)).toBe(0);
@@ -18,12 +17,12 @@ describe('Binary search', function () {
expect(binarySearch([1, 8], 8)).toBe(1);
});
- it('should return -1 for missing elements', function () {
- expect(binarySearch([1, 2, 3], 4)).toBe(-1);
+ it('should return a negative number for missing elements', function () {
+ expect(binarySearch([1, 2, 3], 4)).toBeLessThan(0);
});
it('should work with empty arrays', function () {
expect(binarySearch([], 4)).toBe(-1);
});
-});
\ No newline at end of file
+});
diff --git a/test/sorting/3-way-string-quicksort.spec.js b/test/sorting/3-way-string-quicksort.spec.js
new file mode 100644
index 00000000..57d8114a
--- /dev/null
+++ b/test/sorting/3-way-string-quicksort.spec.js
@@ -0,0 +1,36 @@
+var quicksort =
+ require('../../src/sorting/3-way-string-quicksort.js').quicksort;
+
+describe('Most-Significant Digit', function () {
+ 'use strict';
+
+ it('should work with empty arrays', function () {
+ expect(quicksort([]).length).toBe(0);
+ });
+
+ it('should work with arrays with a single element', function () {
+ var arr = ['a'];
+ quicksort(arr);
+ expect(arr.length).toBe(1);
+ expect(arr[0]).toBe('a');
+ });
+
+ it('should work with arrays with equally length strings', function () {
+ var arr = ['bb', 'aa', 'cc'];
+ quicksort(arr);
+ expect(arr.length).toBe(3);
+ expect(arr[0]).toBe('aa');
+ expect(arr[1]).toBe('bb');
+ expect(arr[2]).toBe('cc');
+ });
+
+ it('should work with arrays with differently length strings', function () {
+ var arr = ['bb', 'aaa', 'a', 'aa'];
+ quicksort(arr);
+ expect(arr.length).toBe(4);
+ expect(arr[0]).toBe('a');
+ expect(arr[1]).toBe('aa');
+ expect(arr[2]).toBe('aaa');
+ expect(arr[3]).toBe('bb');
+ });
+});
diff --git a/test/sorting/bubblesort.spec.js b/test/sorting/bubblesort.spec.js
new file mode 100644
index 00000000..d0cf17b4
--- /dev/null
+++ b/test/sorting/bubblesort.spec.js
@@ -0,0 +1,5 @@
+var sortTestCase = require('./sort.testcase.js');
+var bubbleSort =
+ require('../../src/sorting/bubblesort.js').bubbleSort;
+
+sortTestCase(bubbleSort, 'Bubble sort');
diff --git a/test/sorting/bubblesort/bubblesort.spec.js b/test/sorting/bubblesort/bubblesort.spec.js
deleted file mode 100644
index 706cba72..00000000
--- a/test/sorting/bubblesort/bubblesort.spec.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var sortTestCase = require('../sort.testcase.js'),
- bubbleSort = require('../../../src/sorting/bubblesort/bubblesort.js').bubbleSort;
-
-sortTestCase(bubbleSort, 'Bubble sort');
\ No newline at end of file
diff --git a/test/sorting/bucketsort.spec.js b/test/sorting/bucketsort.spec.js
new file mode 100644
index 00000000..cbae094e
--- /dev/null
+++ b/test/sorting/bucketsort.spec.js
@@ -0,0 +1,18 @@
+var bs =
+ require('../../src/sorting/bucketsort').bucketSort;
+
+describe('bucketsort', function () {
+ 'use strict';
+
+ it('should sort the empty array', function () {
+ expect(bs([])).toEqual([]);
+ });
+
+ it('should return array with the same count of elements', function () {
+ expect(bs([2, 3, 4]).length).toBe(3);
+ });
+
+ it('should sort the given array in ascending order', function () {
+ expect(bs([42, 3, 10])).toEqual([3, 10, 42]);
+ });
+});
diff --git a/test/sorting/countingsort.spec.js b/test/sorting/countingsort.spec.js
new file mode 100644
index 00000000..4d5cf771
--- /dev/null
+++ b/test/sorting/countingsort.spec.js
@@ -0,0 +1,18 @@
+var cs =
+ require('../../src/sorting/countingsort').countingSort;
+
+describe('countingsort', function () {
+ 'use strict';
+
+ it('should sort the empty array', function () {
+ expect(cs([])).toEqual([]);
+ });
+
+ it('should return array with the same count of elements', function () {
+ expect(cs([2, 3, 4]).length).toBe(3);
+ });
+
+ it('should sort the given array in ascending order', function () {
+ expect(cs([42, 3, 10])).toEqual([3, 10, 42]);
+ });
+});
diff --git a/test/sorting/heapsort.spec.js b/test/sorting/heapsort.spec.js
new file mode 100644
index 00000000..2546a007
--- /dev/null
+++ b/test/sorting/heapsort.spec.js
@@ -0,0 +1,4 @@
+var sortTestCase = require('./sort.testcase.js');
+var heapSort = require('../../src/sorting/heapsort.js').heapSort;
+
+sortTestCase(heapSort, 'Heap sort');
diff --git a/test/sorting/heapsort/heapsort.spec.js b/test/sorting/heapsort/heapsort.spec.js
deleted file mode 100644
index 25e3173f..00000000
--- a/test/sorting/heapsort/heapsort.spec.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var sortTestCase = require('../sort.testcase.js'),
- heapSort = require('../../../src/sorting/heapsort/heapsort.js').heapSort;
-
-sortTestCase(heapSort, 'Heap sort');
\ No newline at end of file
diff --git a/test/sorting/insertionbinarysort.spec.js b/test/sorting/insertionbinarysort.spec.js
new file mode 100644
index 00000000..6718b240
--- /dev/null
+++ b/test/sorting/insertionbinarysort.spec.js
@@ -0,0 +1,6 @@
+var sortTestCase = require('./sort.testcase.js');
+var insertionBinarySort =
+ require('../../src/sorting/' +
+ 'insertion-binary-sort.js').insertionBinarySort;
+
+sortTestCase(insertionBinarySort, 'Insertion binary sort');
diff --git a/test/sorting/insertionsort.spec.js b/test/sorting/insertionsort.spec.js
new file mode 100644
index 00000000..0be5a50d
--- /dev/null
+++ b/test/sorting/insertionsort.spec.js
@@ -0,0 +1,5 @@
+var sortTestCase = require('./sort.testcase.js');
+var insertionSort = require('../../src/sorting/' +
+ 'insertionsort.js').insertionSort;
+
+sortTestCase(insertionSort, 'Insertion sort');
diff --git a/test/sorting/insertionsort/insertionbinarysort.spec.js b/test/sorting/insertionsort/insertionbinarysort.spec.js
deleted file mode 100644
index a7bc4861..00000000
--- a/test/sorting/insertionsort/insertionbinarysort.spec.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var sortTestCase = require('../sort.testcase.js'),
- insertionBinarySort = require('../../../src/sorting/insertionsort/insertion-binary-sort.js').insertionBinarySort;
-
-sortTestCase(insertionBinarySort, 'Insertion binary sort');
\ No newline at end of file
diff --git a/test/sorting/insertionsort/insertionsort.spec.js b/test/sorting/insertionsort/insertionsort.spec.js
deleted file mode 100644
index 34057e4a..00000000
--- a/test/sorting/insertionsort/insertionsort.spec.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var sortTestCase = require('../sort.testcase.js'),
- insertionSort = require('../../../src/sorting/insertionsort/insertionsort.js').insertionSort;
-
-sortTestCase(insertionSort, 'Insertion sort');
\ No newline at end of file
diff --git a/test/sorting/insertionsort/recursiveinsertionsort.spec.js b/test/sorting/insertionsort/recursiveinsertionsort.spec.js
deleted file mode 100644
index 6e96eafd..00000000
--- a/test/sorting/insertionsort/recursiveinsertionsort.spec.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var sortTestCase = require('../sort.testcase.js'),
- recursiveInsertionSort = require('../../../src/sorting/insertionsort/recursive-insertionsort.js').recursiveInsertionSort;
-
-sortTestCase(recursiveInsertionSort, 'Recursive insertion sort');
\ No newline at end of file
diff --git a/test/sorting/lsd.spec.js b/test/sorting/lsd.spec.js
new file mode 100644
index 00000000..738ae492
--- /dev/null
+++ b/test/sorting/lsd.spec.js
@@ -0,0 +1,34 @@
+var lsd = require('../../src/sorting/lsd.js').lsd;
+
+describe('Least-Significant Digit', function () {
+ 'use strict';
+
+ it('should work with empty arrays', function () {
+ expect(lsd([]).length).toBe(0);
+ });
+
+ it('should work with arrays with a single element', function () {
+ var arr = ['a'];
+ lsd(arr);
+ expect(arr.length).toBe(1);
+ expect(arr[0]).toBe('a');
+ });
+
+ it('should work with arrays with equally length strings', function () {
+ var arr = ['bb', 'aa', 'cc'];
+ lsd(arr);
+ expect(arr.length).toBe(3);
+ expect(arr[0]).toBe('aa');
+ expect(arr[1]).toBe('bb');
+ expect(arr[2]).toBe('cc');
+ });
+
+ it('should work with arrays with equally length strings', function () {
+ var arr = ['bbb', 'aac', 'aaa'];
+ lsd(arr, 3);
+ expect(arr.length).toBe(3);
+ expect(arr[0]).toBe('aaa');
+ expect(arr[1]).toBe('aac');
+ expect(arr[2]).toBe('bbb');
+ });
+});
diff --git a/test/sorting/mergesort.spec.js b/test/sorting/mergesort.spec.js
new file mode 100644
index 00000000..528d0a55
--- /dev/null
+++ b/test/sorting/mergesort.spec.js
@@ -0,0 +1,5 @@
+var sortTestCase = require('./sort.testcase.js');
+var mergeSort =
+ require('../../src/sorting/mergesort.js').mergeSort;
+
+sortTestCase(mergeSort, 'Merge sort');
diff --git a/test/sorting/mergesort/mergesort.spec.js b/test/sorting/mergesort/mergesort.spec.js
deleted file mode 100644
index 31d6028e..00000000
--- a/test/sorting/mergesort/mergesort.spec.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var sortTestCase = require('../sort.testcase.js'),
- mergeSort = require('../../../src/sorting/mergesort/mergesort.js').mergeSort;
-
-sortTestCase(mergeSort, 'Merge sort');
\ No newline at end of file
diff --git a/test/sorting/msd.spec.js b/test/sorting/msd.spec.js
new file mode 100644
index 00000000..245acfbd
--- /dev/null
+++ b/test/sorting/msd.spec.js
@@ -0,0 +1,35 @@
+var msd = require('../../src/sorting/msd.js').msd;
+
+describe('Most-Significant Digit', function () {
+ 'use strict';
+
+ it('should work with empty arrays', function () {
+ expect(msd([]).length).toBe(0);
+ });
+
+ it('should work with arrays with a single element', function () {
+ var arr = ['a'];
+ msd(arr);
+ expect(arr.length).toBe(1);
+ expect(arr[0]).toBe('a');
+ });
+
+ it('should work with arrays with equally length strings', function () {
+ var arr = ['bb', 'aa', 'cc'];
+ msd(arr);
+ expect(arr.length).toBe(3);
+ expect(arr[0]).toBe('aa');
+ expect(arr[1]).toBe('bb');
+ expect(arr[2]).toBe('cc');
+ });
+
+ it('should work with arrays with differently length strings', function () {
+ var arr = ['bb', 'aaa', 'a', 'aa'];
+ msd(arr);
+ expect(arr.length).toBe(4);
+ expect(arr[0]).toBe('a');
+ expect(arr[1]).toBe('aa');
+ expect(arr[2]).toBe('aaa');
+ expect(arr[3]).toBe('bb');
+ });
+});
diff --git a/test/sorting/oddeven-sort.spec.js b/test/sorting/oddeven-sort.spec.js
new file mode 100644
index 00000000..bc928ab4
--- /dev/null
+++ b/test/sorting/oddeven-sort.spec.js
@@ -0,0 +1,18 @@
+var oes =
+ require('../../src/sorting/oddeven-sort').oddEvenSort;
+
+describe('oddeven-sort', function () {
+ 'use strict';
+
+ it('should sort the empty array', function () {
+ expect(oes([])).toEqual([]);
+ });
+
+ it('should return array with the same count of elements', function () {
+ expect(oes([2, 3, 4]).length).toBe(3);
+ });
+
+ it('should sort the given array in ascending order', function () {
+ expect(oes([42, 3, 10])).toEqual([3, 10, 42]);
+ });
+});
diff --git a/test/sorting/quicksort-declarative.spec.js b/test/sorting/quicksort-declarative.spec.js
new file mode 100644
index 00000000..dfe4f06d
--- /dev/null
+++ b/test/sorting/quicksort-declarative.spec.js
@@ -0,0 +1,5 @@
+var sortTestCase = require('./sort.testcase.js');
+var quickSort =
+ require('../../src/sorting/quicksort-declarative.js').quickSort;
+
+sortTestCase(quickSort, 'Quick sort');
diff --git a/test/sorting/quicksort-middle.spec.js b/test/sorting/quicksort-middle.spec.js
new file mode 100644
index 00000000..02745cb2
--- /dev/null
+++ b/test/sorting/quicksort-middle.spec.js
@@ -0,0 +1,5 @@
+var sortTestCase = require('./sort.testcase.js');
+var quickSort =
+ require('../../src/sorting/quicksort-middle.js').quickSort;
+
+sortTestCase(quickSort, 'Quick sort');
diff --git a/test/sorting/quicksort.spec.js b/test/sorting/quicksort.spec.js
new file mode 100644
index 00000000..2d1e6baa
--- /dev/null
+++ b/test/sorting/quicksort.spec.js
@@ -0,0 +1,5 @@
+var sortTestCase = require('./sort.testcase.js');
+var quickSort =
+ require('../../src/sorting/quicksort.js').quickSort;
+
+sortTestCase(quickSort, 'Quick sort');
diff --git a/test/sorting/quicksort/quicksort-middle.spec.js b/test/sorting/quicksort/quicksort-middle.spec.js
deleted file mode 100644
index d12276b8..00000000
--- a/test/sorting/quicksort/quicksort-middle.spec.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var sortTestCase = require('../sort.testcase.js'),
- quickSort = require('../../../src/sorting/quicksort/quicksort-middle.js').quickSort;
-
-sortTestCase(quickSort, 'Quick sort');
\ No newline at end of file
diff --git a/test/sorting/quicksort/quicksort.spec.js b/test/sorting/quicksort/quicksort.spec.js
deleted file mode 100644
index e6f84a8f..00000000
--- a/test/sorting/quicksort/quicksort.spec.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var sortTestCase = require('../sort.testcase.js'),
- quickSort = require('../../../src/sorting/quicksort/quicksort.js').quickSort;
-
-sortTestCase(quickSort, 'Quick sort');
\ No newline at end of file
diff --git a/test/sorting/radixsort.spec.js b/test/sorting/radixsort.spec.js
new file mode 100644
index 00000000..4197be94
--- /dev/null
+++ b/test/sorting/radixsort.spec.js
@@ -0,0 +1,18 @@
+var rx =
+ require('../../src/sorting/radixsort.js').radixSort;
+
+describe('radixsort', function () {
+ 'use strict';
+
+ it('should sort the empty array', function () {
+ expect(rx([])).toEqual([]);
+ });
+
+ it('should return array with the same count of elements', function () {
+ expect(rx([2, 3, 4]).length).toBe(3);
+ });
+
+ it('should sort the given array in ascending order', function () {
+ expect(rx([42, 3, 10])).toEqual([3, 10, 42]);
+ });
+});
diff --git a/test/sorting/recursiveinsertionsort.spec.js b/test/sorting/recursiveinsertionsort.spec.js
new file mode 100644
index 00000000..1f9d409a
--- /dev/null
+++ b/test/sorting/recursiveinsertionsort.spec.js
@@ -0,0 +1,5 @@
+var sortTestCase = require('./sort.testcase.js');
+var recursiveInsertionSort = require('../../src/sorting/' +
+ 'recursive-insertionsort.js').recursiveInsertionSort;
+
+sortTestCase(recursiveInsertionSort, 'Recursive insertion sort');
diff --git a/test/sorting/selectionsort.spec.js b/test/sorting/selectionsort.spec.js
new file mode 100644
index 00000000..d36ad19a
--- /dev/null
+++ b/test/sorting/selectionsort.spec.js
@@ -0,0 +1,6 @@
+var sortTestCase = require('./sort.testcase.js');
+var selectionSort =
+ require('../../src/sorting/selectionsort.js')
+ .selectionSort;
+
+sortTestCase(selectionSort, 'Selection sort');
diff --git a/test/sorting/selectionsort/selectionsort.spec.js b/test/sorting/selectionsort/selectionsort.spec.js
deleted file mode 100644
index 73718b13..00000000
--- a/test/sorting/selectionsort/selectionsort.spec.js
+++ /dev/null
@@ -1,5 +0,0 @@
-var sortTestCase = require('../sort.testcase.js'),
- selectionSort = require('../../../src/sorting/selectionsort/selectionsort.js')
- .selectionSort;
-
-sortTestCase(selectionSort, 'Selection sort');
\ No newline at end of file
diff --git a/test/sorting/shellsort.spec.js b/test/sorting/shellsort.spec.js
new file mode 100644
index 00000000..ec644711
--- /dev/null
+++ b/test/sorting/shellsort.spec.js
@@ -0,0 +1,5 @@
+var sortTestCase = require('./sort.testcase.js');
+var shellSort = require('../../src/sorting/shellsort.js')
+ .shellSort;
+
+sortTestCase(shellSort, 'Shell sort');
diff --git a/test/sorting/shellsort/shellsort.spec.js b/test/sorting/shellsort/shellsort.spec.js
deleted file mode 100644
index ec2a8674..00000000
--- a/test/sorting/shellsort/shellsort.spec.js
+++ /dev/null
@@ -1,5 +0,0 @@
-var sortTestCase = require('../sort.testcase.js'),
- shellSort = require('../../../src/sorting/shellsort/shellsort.js')
- .shellSort;
-
-sortTestCase(shellSort, 'Shell sort');
\ No newline at end of file
diff --git a/test/sorting/sort.testcase.js b/test/sorting/sort.testcase.js
index 68382432..d12c1a9f 100644
--- a/test/sorting/sort.testcase.js
+++ b/test/sorting/sort.testcase.js
@@ -1,21 +1,20 @@
module.exports = function (sort, algorithmName, options) {
-
'use strict';
options = options || {
integers: false,
- reverse : true
+ reverse: true
};
describe(algorithmName, function () {
function createRandomArray(config) {
config = config || {};
- var size = config.size || 100,
- precision = config.precision || 2,
- multiplier = config.multiplier || 100;
-
+ var size = config.size || 100;
+ var precision = config.precision || 2;
+ var multiplier = config.multiplier || 100;
var result = [];
+
for (var i = size; i > 0; i -= 1) {
result.push(parseFloat((Math.random() *
multiplier).toFixed(precision)));
@@ -40,7 +39,7 @@ module.exports = function (sort, algorithmName, options) {
precision: 0
});
}
- sort(array);
+ array = sort(array);
for (var i = 0; i < array.length - 1; i += 1) {
expect(array[i] <= array[i + 1]).toBeTruthy();
}
@@ -54,7 +53,7 @@ module.exports = function (sort, algorithmName, options) {
}
var array = createRandomArray();
- sort(array, comparator);
+ array = sort(array, comparator);
for (var i = 0; i < array.length - 1; i += 1) {
expect(array[i] >= array[i + 1]).toBeTruthy();
@@ -63,4 +62,4 @@ module.exports = function (sort, algorithmName, options) {
}
});
-};
\ No newline at end of file
+};
diff --git a/yarn.lock b/yarn.lock
new file mode 100644
index 00000000..068ad093
--- /dev/null
+++ b/yarn.lock
@@ -0,0 +1,4063 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@jeremyckahn/minami@^1.3.1":
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/@jeremyckahn/minami/-/minami-1.3.1.tgz#cec9a26c1484b0cacdc9d7a86eb476fe864a0515"
+ integrity sha512-jeOFPfq3zLxnQ0dhlhrZd5J0qZDdF1wkrNlr6ErVaGtjPTq9gn/NIK0GDOmGcAJgN/6yKwRdMxPy33u12lQWiQ==
+
+abbrev@1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
+ integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
+
+accepts@~1.3.4:
+ version "1.3.5"
+ resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2"
+ integrity sha1-63d99gEXI6OxTopywIBcjoZ0a9I=
+ dependencies:
+ mime-types "~2.1.18"
+ negotiator "0.6.1"
+
+acorn-jsx@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b"
+ integrity sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=
+ dependencies:
+ acorn "^3.0.4"
+
+acorn@^3.0.4:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a"
+ integrity sha1-ReN/s56No/JbruP/U2niu18iAXo=
+
+acorn@^5.5.0:
+ version "5.7.3"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279"
+ integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==
+
+ajv-keywords@^1.0.0:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c"
+ integrity sha1-MU3QpLM2j609/NxU7eYXG4htrzw=
+
+ajv@^4.7.0:
+ version "4.11.8"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536"
+ integrity sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=
+ dependencies:
+ co "^4.6.0"
+ json-stable-stringify "^1.0.1"
+
+ansi-colors@^1.0.1:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-1.1.0.tgz#6374b4dd5d4718ff3ce27a671a3b1cad077132a9"
+ integrity sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==
+ dependencies:
+ ansi-wrap "^0.1.0"
+
+ansi-escapes@^1.1.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
+ integrity sha1-06ioOzGapneTZisT52HHkRQiMG4=
+
+ansi-gray@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/ansi-gray/-/ansi-gray-0.1.1.tgz#2962cf54ec9792c48510a3deb524436861ef7251"
+ integrity sha1-KWLPVOyXksSFEKPetSRDaGHvclE=
+ dependencies:
+ ansi-wrap "0.1.0"
+
+ansi-regex@^2.0.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
+ integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8=
+
+ansi-regex@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
+ integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
+
+ansi-styles@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
+ integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=
+
+ansi-wrap@0.1.0, ansi-wrap@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf"
+ integrity sha1-qCJQ3bABXponyoLoLqYDu/pF768=
+
+anymatch@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb"
+ integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==
+ dependencies:
+ micromatch "^3.1.4"
+ normalize-path "^2.1.1"
+
+apache-crypt@^1.1.2:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/apache-crypt/-/apache-crypt-1.2.1.tgz#d6fc72aa6d27d99c95a94fd188d731eefffa663c"
+ integrity sha1-1vxyqm0n2ZyVqU/RiNcx7v/6Zjw=
+ dependencies:
+ unix-crypt-td-js "^1.0.0"
+
+apache-md5@^1.0.6:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/apache-md5/-/apache-md5-1.1.2.tgz#ee49736b639b4f108b6e9e626c6da99306b41692"
+ integrity sha1-7klza2ObTxCLbp5ibG2pkwa0FpI=
+
+append-buffer@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/append-buffer/-/append-buffer-1.0.2.tgz#d8220cf466081525efea50614f3de6514dfa58f1"
+ integrity sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=
+ dependencies:
+ buffer-equal "^1.0.0"
+
+aproba@^1.0.3:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
+ integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==
+
+archy@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40"
+ integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=
+
+are-we-there-yet@~1.1.2:
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21"
+ integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==
+ dependencies:
+ delegates "^1.0.0"
+ readable-stream "^2.0.6"
+
+argparse@^1.0.7:
+ version "1.0.10"
+ resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
+ integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
+ dependencies:
+ sprintf-js "~1.0.2"
+
+arr-diff@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
+ integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=
+
+arr-filter@^1.1.1:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/arr-filter/-/arr-filter-1.1.2.tgz#43fdddd091e8ef11aa4c45d9cdc18e2dff1711ee"
+ integrity sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4=
+ dependencies:
+ make-iterator "^1.0.0"
+
+arr-flatten@^1.0.1, arr-flatten@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1"
+ integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==
+
+arr-map@^2.0.0, arr-map@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/arr-map/-/arr-map-2.0.2.tgz#3a77345ffc1cf35e2a91825601f9e58f2e24cac4"
+ integrity sha1-Onc0X/wc814qkYJWAfnljy4kysQ=
+ dependencies:
+ make-iterator "^1.0.0"
+
+arr-union@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4"
+ integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=
+
+array-differ@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031"
+ integrity sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=
+
+array-each@^1.0.0, array-each@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/array-each/-/array-each-1.0.1.tgz#a794af0c05ab1752846ee753a1f211a05ba0c44f"
+ integrity sha1-p5SvDAWrF1KEbudTofIRoFugxE8=
+
+array-initial@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/array-initial/-/array-initial-1.1.0.tgz#2fa74b26739371c3947bd7a7adc73be334b3d795"
+ integrity sha1-L6dLJnOTccOUe9enrcc74zSz15U=
+ dependencies:
+ array-slice "^1.0.0"
+ is-number "^4.0.0"
+
+array-last@^1.1.1:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/array-last/-/array-last-1.3.0.tgz#7aa77073fec565ddab2493f5f88185f404a9d336"
+ integrity sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==
+ dependencies:
+ is-number "^4.0.0"
+
+array-slice@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-1.1.0.tgz#e368ea15f89bc7069f7ffb89aec3a6c7d4ac22d4"
+ integrity sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==
+
+array-sort@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/array-sort/-/array-sort-1.0.0.tgz#e4c05356453f56f53512a7d1d6123f2c54c0a88a"
+ integrity sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==
+ dependencies:
+ default-compare "^1.0.0"
+ get-value "^2.0.6"
+ kind-of "^5.0.2"
+
+array-union@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
+ integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=
+ dependencies:
+ array-uniq "^1.0.1"
+
+array-uniq@^1.0.1, array-uniq@^1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6"
+ integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=
+
+array-unique@^0.3.2:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
+ integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=
+
+arrify@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
+ integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=
+
+assign-symbols@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
+ integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=
+
+async-done@^1.2.0, async-done@^1.2.2:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/async-done/-/async-done-1.3.2.tgz#5e15aa729962a4b07414f528a88cdf18e0b290a2"
+ integrity sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==
+ dependencies:
+ end-of-stream "^1.1.0"
+ once "^1.3.2"
+ process-nextick-args "^2.0.0"
+ stream-exhaust "^1.0.1"
+
+async-each@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.2.tgz#8b8a7ca2a658f927e9f307d6d1a42f4199f0f735"
+ integrity sha512-6xrbvN0MOBKSJDdonmSSz2OwFSgxRaVtBDes26mj9KIGtDo+g9xosFRSC+i1gQh2oAN/tQ62AI/pGZGQjVOiRg==
+
+async-settle@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/async-settle/-/async-settle-1.0.0.tgz#1d0a914bb02575bec8a8f3a74e5080f72b2c0c6b"
+ integrity sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs=
+ dependencies:
+ async-done "^1.2.2"
+
+async@2.6.1:
+ version "2.6.1"
+ resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610"
+ integrity sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==
+ dependencies:
+ lodash "^4.17.10"
+
+atob@^2.1.1:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
+ integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
+
+babel-code-frame@^6.16.0:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
+ integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=
+ dependencies:
+ chalk "^1.1.3"
+ esutils "^2.0.2"
+ js-tokens "^3.0.2"
+
+babylon@7.0.0-beta.19:
+ version "7.0.0-beta.19"
+ resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.19.tgz#e928c7e807e970e0536b078ab3e0c48f9e052503"
+ integrity sha512-Vg0C9s/REX6/WIXN37UKpv5ZhRi6A4pjHlpkE34+8/a6c2W1Q692n3hmc+SZG5lKRnaExLUbxtJ1SVT+KaCQ/A==
+
+bach@^1.0.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/bach/-/bach-1.2.0.tgz#4b3ce96bf27134f79a1b414a51c14e34c3bd9880"
+ integrity sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA=
+ dependencies:
+ arr-filter "^1.1.1"
+ arr-flatten "^1.0.1"
+ arr-map "^2.0.0"
+ array-each "^1.0.0"
+ array-initial "^1.0.0"
+ array-last "^1.1.1"
+ async-done "^1.2.2"
+ async-settle "^1.0.0"
+ now-and-later "^2.0.0"
+
+balanced-match@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
+ integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
+
+base@^0.11.1:
+ version "0.11.2"
+ resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f"
+ integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==
+ dependencies:
+ cache-base "^1.0.1"
+ class-utils "^0.3.5"
+ component-emitter "^1.2.1"
+ define-property "^1.0.0"
+ isobject "^3.0.1"
+ mixin-deep "^1.2.0"
+ pascalcase "^0.1.1"
+
+basic-auth@~2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a"
+ integrity sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==
+ dependencies:
+ safe-buffer "5.1.2"
+
+batch@0.6.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16"
+ integrity sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=
+
+bcryptjs@^2.3.0:
+ version "2.4.3"
+ resolved "https://registry.yarnpkg.com/bcryptjs/-/bcryptjs-2.4.3.tgz#9ab5627b93e60621ff7cdac5da9733027df1d0cb"
+ integrity sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms=
+
+beeper@^1.0.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/beeper/-/beeper-1.1.1.tgz#e6d5ea8c5dad001304a70b22638447f69cb2f809"
+ integrity sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=
+
+binary-extensions@^1.0.0:
+ version "1.13.0"
+ resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.0.tgz#9523e001306a32444b907423f1de2164222f6ab1"
+ integrity sha512-EgmjVLMn22z7eGGv3kcnHwSnJXmFHjISTY9E/S5lIcTD3Oxw05QTcBLNkJFzcb3cNueUdF/IN4U+d78V0zO8Hw==
+
+bluebird@~3.5.0:
+ version "3.5.3"
+ resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.3.tgz#7d01c6f9616c9a51ab0f8c549a79dfe6ec33efa7"
+ integrity sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==
+
+brace-expansion@^1.1.7:
+ version "1.1.11"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
+ integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
+ dependencies:
+ balanced-match "^1.0.0"
+ concat-map "0.0.1"
+
+braces@^2.3.1, braces@^2.3.2:
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729"
+ integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==
+ dependencies:
+ arr-flatten "^1.1.0"
+ array-unique "^0.3.2"
+ extend-shallow "^2.0.1"
+ fill-range "^4.0.0"
+ isobject "^3.0.1"
+ repeat-element "^1.1.2"
+ snapdragon "^0.8.1"
+ snapdragon-node "^2.0.1"
+ split-string "^3.0.2"
+ to-regex "^3.0.1"
+
+buffer-equal@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-1.0.0.tgz#59616b498304d556abd466966b22eeda3eca5fbe"
+ integrity sha1-WWFrSYME1Var1GaWayLu2j7KX74=
+
+buffer-from@^1.0.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
+ integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
+
+bufferstreams@^1.1.1:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/bufferstreams/-/bufferstreams-1.1.3.tgz#a8515ac024fa90e8fa7d58c11b13dea1f28abe72"
+ integrity sha512-HaJnVuslRF4g2kSDeyl++AaVizoitCpL9PglzCYwy0uHHyvWerfvEb8jWmYbF1z4kiVFolGomnxSGl+GUQp2jg==
+ dependencies:
+ readable-stream "^2.0.2"
+
+cache-base@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2"
+ integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==
+ dependencies:
+ collection-visit "^1.0.0"
+ component-emitter "^1.2.1"
+ get-value "^2.0.6"
+ has-value "^1.0.0"
+ isobject "^3.0.1"
+ set-value "^2.0.0"
+ to-object-path "^0.3.0"
+ union-value "^1.0.0"
+ unset-value "^1.0.0"
+
+caller-path@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f"
+ integrity sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=
+ dependencies:
+ callsites "^0.2.0"
+
+callsites@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca"
+ integrity sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=
+
+camelcase@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
+ integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo=
+
+catharsis@~0.8.9:
+ version "0.8.9"
+ resolved "https://registry.yarnpkg.com/catharsis/-/catharsis-0.8.9.tgz#98cc890ca652dd2ef0e70b37925310ff9e90fc8b"
+ integrity sha1-mMyJDKZS3S7w5ws3klMQ/56Q/Is=
+ dependencies:
+ underscore-contrib "~0.3.0"
+
+chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
+ integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=
+ dependencies:
+ ansi-styles "^2.2.1"
+ escape-string-regexp "^1.0.2"
+ has-ansi "^2.0.0"
+ strip-ansi "^3.0.0"
+ supports-color "^2.0.0"
+
+chokidar@^2.0.0:
+ version "2.1.8"
+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917"
+ integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==
+ dependencies:
+ anymatch "^2.0.0"
+ async-each "^1.0.1"
+ braces "^2.3.2"
+ glob-parent "^3.1.0"
+ inherits "^2.0.3"
+ is-binary-path "^1.0.0"
+ is-glob "^4.0.0"
+ normalize-path "^3.0.0"
+ path-is-absolute "^1.0.0"
+ readdirp "^2.2.1"
+ upath "^1.1.1"
+ optionalDependencies:
+ fsevents "^1.2.7"
+
+chokidar@^2.0.4:
+ version "2.1.5"
+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.5.tgz#0ae8434d962281a5f56c72869e79cb6d9d86ad4d"
+ integrity sha512-i0TprVWp+Kj4WRPtInjexJ8Q+BqTE909VpH8xVhXrJkoc5QC8VO9TryGOqTr+2hljzc1sC62t22h5tZePodM/A==
+ dependencies:
+ anymatch "^2.0.0"
+ async-each "^1.0.1"
+ braces "^2.3.2"
+ glob-parent "^3.1.0"
+ inherits "^2.0.3"
+ is-binary-path "^1.0.0"
+ is-glob "^4.0.0"
+ normalize-path "^3.0.0"
+ path-is-absolute "^1.0.0"
+ readdirp "^2.2.1"
+ upath "^1.1.1"
+ optionalDependencies:
+ fsevents "^1.2.7"
+
+chownr@^1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b"
+ integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==
+
+circular-json@^0.3.1:
+ version "0.3.3"
+ resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66"
+ integrity sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==
+
+class-utils@^0.3.5:
+ version "0.3.6"
+ resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
+ integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==
+ dependencies:
+ arr-union "^3.1.0"
+ define-property "^0.2.5"
+ isobject "^3.0.0"
+ static-extend "^0.1.1"
+
+cli-cursor@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987"
+ integrity sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=
+ dependencies:
+ restore-cursor "^1.0.1"
+
+cli-width@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639"
+ integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=
+
+cliui@^3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"
+ integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=
+ dependencies:
+ string-width "^1.0.1"
+ strip-ansi "^3.0.1"
+ wrap-ansi "^2.0.0"
+
+clone-buffer@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58"
+ integrity sha1-4+JbIHrE5wGvch4staFnksrD3Fg=
+
+clone-stats@^0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-0.0.1.tgz#b88f94a82cf38b8791d58046ea4029ad88ca99d1"
+ integrity sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=
+
+clone-stats@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680"
+ integrity sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=
+
+clone@^1.0.0:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
+ integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4=
+
+clone@^2.1.1:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
+ integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=
+
+cloneable-readable@^1.0.0:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/cloneable-readable/-/cloneable-readable-1.1.3.tgz#120a00cb053bfb63a222e709f9683ea2e11d8cec"
+ integrity sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==
+ dependencies:
+ inherits "^2.0.1"
+ process-nextick-args "^2.0.0"
+ readable-stream "^2.3.5"
+
+co@^4.6.0:
+ version "4.6.0"
+ resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
+ integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=
+
+code-point-at@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
+ integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
+
+collection-map@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/collection-map/-/collection-map-1.0.0.tgz#aea0f06f8d26c780c2b75494385544b2255af18c"
+ integrity sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw=
+ dependencies:
+ arr-map "^2.0.2"
+ for-own "^1.0.0"
+ make-iterator "^1.0.0"
+
+collection-visit@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0"
+ integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=
+ dependencies:
+ map-visit "^1.0.0"
+ object-visit "^1.0.0"
+
+color-support@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2"
+ integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==
+
+colors@latest:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.3.tgz#39e005d546afe01e01f9c4ca8fa50f686a01205d"
+ integrity sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==
+
+commander@2.15.1:
+ version "2.15.1"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f"
+ integrity sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==
+
+component-emitter@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
+ integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=
+
+concat-map@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+ integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
+
+concat-stream@^1.5.2, concat-stream@^1.6.0:
+ version "1.6.2"
+ resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
+ integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
+ dependencies:
+ buffer-from "^1.0.0"
+ inherits "^2.0.3"
+ readable-stream "^2.2.2"
+ typedarray "^0.0.6"
+
+connect@^3.6.6:
+ version "3.6.6"
+ resolved "https://registry.yarnpkg.com/connect/-/connect-3.6.6.tgz#09eff6c55af7236e137135a72574858b6786f524"
+ integrity sha1-Ce/2xVr3I24TcTWnJXSFi2eG9SQ=
+ dependencies:
+ debug "2.6.9"
+ finalhandler "1.1.0"
+ parseurl "~1.3.2"
+ utils-merge "1.0.1"
+
+console-control-strings@^1.0.0, console-control-strings@~1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
+ integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
+
+convert-source-map@^1.5.0:
+ version "1.7.0"
+ resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442"
+ integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==
+ dependencies:
+ safe-buffer "~5.1.1"
+
+copy-descriptor@^0.1.0:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
+ integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
+
+copy-props@^2.0.1:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/copy-props/-/copy-props-2.0.5.tgz#03cf9ae328d4ebb36f8f1d804448a6af9ee3f2d2"
+ integrity sha512-XBlx8HSqrT0ObQwmSzM7WE5k8FxTV75h1DX1Z3n6NhQ/UYYAvInWYmG06vFt7hQZArE2fuO62aihiWIVQwh1sw==
+ dependencies:
+ each-props "^1.3.2"
+ is-plain-object "^5.0.0"
+
+core-util-is@~1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
+ integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
+
+cors@latest:
+ version "2.8.5"
+ resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29"
+ integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==
+ dependencies:
+ object-assign "^4"
+ vary "^1"
+
+d@1:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f"
+ integrity sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=
+ dependencies:
+ es5-ext "^0.10.9"
+
+dateformat@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-2.2.0.tgz#4065e2013cf9fb916ddfd82efb506ad4c6769062"
+ integrity sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=
+
+debug@2.6.9, debug@^2.1.1, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3:
+ version "2.6.9"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
+ integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
+ dependencies:
+ ms "2.0.0"
+
+decamelize@^1.1.1:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
+ integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
+
+decode-uri-component@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
+ integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=
+
+deep-extend@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
+ integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
+
+deep-is@~0.1.3:
+ version "0.1.3"
+ resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
+ integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
+
+default-compare@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/default-compare/-/default-compare-1.0.0.tgz#cb61131844ad84d84788fb68fd01681ca7781a2f"
+ integrity sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==
+ dependencies:
+ kind-of "^5.0.2"
+
+default-resolution@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/default-resolution/-/default-resolution-2.0.0.tgz#bcb82baa72ad79b426a76732f1a81ad6df26d684"
+ integrity sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=
+
+define-properties@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
+ integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
+ dependencies:
+ object-keys "^1.0.12"
+
+define-property@^0.2.5:
+ version "0.2.5"
+ resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116"
+ integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=
+ dependencies:
+ is-descriptor "^0.1.0"
+
+define-property@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6"
+ integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY=
+ dependencies:
+ is-descriptor "^1.0.0"
+
+define-property@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d"
+ integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==
+ dependencies:
+ is-descriptor "^1.0.2"
+ isobject "^3.0.1"
+
+delegates@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
+ integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
+
+depd@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
+ integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
+
+destroy@~1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
+ integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
+
+detect-file@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7"
+ integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=
+
+detect-libc@^1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
+ integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=
+
+doctrine@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
+ integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==
+ dependencies:
+ esutils "^2.0.2"
+
+duplexer2@0.0.2:
+ version "0.0.2"
+ resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.0.2.tgz#c614dcf67e2fb14995a91711e5a617e8a60a31db"
+ integrity sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=
+ dependencies:
+ readable-stream "~1.1.9"
+
+duplexer@~0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1"
+ integrity sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=
+
+duplexify@^3.6.0:
+ version "3.7.1"
+ resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309"
+ integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==
+ dependencies:
+ end-of-stream "^1.0.0"
+ inherits "^2.0.1"
+ readable-stream "^2.0.0"
+ stream-shift "^1.0.0"
+
+each-props@^1.3.2:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/each-props/-/each-props-1.3.2.tgz#ea45a414d16dd5cfa419b1a81720d5ca06892333"
+ integrity sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==
+ dependencies:
+ is-plain-object "^2.0.1"
+ object.defaults "^1.1.0"
+
+ee-first@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
+ integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
+
+encodeurl@~1.0.1, encodeurl@~1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
+ integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
+
+end-of-stream@^1.0.0, end-of-stream@^1.1.0:
+ version "1.4.4"
+ resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
+ integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
+ dependencies:
+ once "^1.4.0"
+
+error-ex@^1.2.0:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
+ integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
+ dependencies:
+ is-arrayish "^0.2.1"
+
+es-abstract@^1.17.5:
+ version "1.17.7"
+ resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.7.tgz#a4de61b2f66989fc7421676c1cb9787573ace54c"
+ integrity sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==
+ dependencies:
+ es-to-primitive "^1.2.1"
+ function-bind "^1.1.1"
+ has "^1.0.3"
+ has-symbols "^1.0.1"
+ is-callable "^1.2.2"
+ is-regex "^1.1.1"
+ object-inspect "^1.8.0"
+ object-keys "^1.1.1"
+ object.assign "^4.1.1"
+ string.prototype.trimend "^1.0.1"
+ string.prototype.trimstart "^1.0.1"
+
+es-abstract@^1.18.0-next.0:
+ version "1.18.0-next.1"
+ resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0-next.1.tgz#6e3a0a4bda717e5023ab3b8e90bec36108d22c68"
+ integrity sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==
+ dependencies:
+ es-to-primitive "^1.2.1"
+ function-bind "^1.1.1"
+ has "^1.0.3"
+ has-symbols "^1.0.1"
+ is-callable "^1.2.2"
+ is-negative-zero "^2.0.0"
+ is-regex "^1.1.1"
+ object-inspect "^1.8.0"
+ object-keys "^1.1.1"
+ object.assign "^4.1.1"
+ string.prototype.trimend "^1.0.1"
+ string.prototype.trimstart "^1.0.1"
+
+es-to-primitive@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
+ integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==
+ dependencies:
+ is-callable "^1.1.4"
+ is-date-object "^1.0.1"
+ is-symbol "^1.0.2"
+
+es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14:
+ version "0.10.49"
+ resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.49.tgz#059a239de862c94494fec28f8150c977028c6c5e"
+ integrity sha512-3NMEhi57E31qdzmYp2jwRArIUsj1HI/RxbQ4bgnSB+AIKIxsAmTiK83bYMifIcpWvEc3P1X30DhUKOqEtF/kvg==
+ dependencies:
+ es6-iterator "~2.0.3"
+ es6-symbol "~3.1.1"
+ next-tick "^1.0.0"
+
+es6-iterator@^2.0.1, es6-iterator@~2.0.1, es6-iterator@~2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7"
+ integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c=
+ dependencies:
+ d "1"
+ es5-ext "^0.10.35"
+ es6-symbol "^3.1.1"
+
+es6-map@^0.1.3:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0"
+ integrity sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=
+ dependencies:
+ d "1"
+ es5-ext "~0.10.14"
+ es6-iterator "~2.0.1"
+ es6-set "~0.1.5"
+ es6-symbol "~3.1.1"
+ event-emitter "~0.3.5"
+
+es6-set@~0.1.5:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1"
+ integrity sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=
+ dependencies:
+ d "1"
+ es5-ext "~0.10.14"
+ es6-iterator "~2.0.1"
+ es6-symbol "3.1.1"
+ event-emitter "~0.3.5"
+
+es6-symbol@3.1.1, es6-symbol@^3.1.1, es6-symbol@~3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77"
+ integrity sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=
+ dependencies:
+ d "1"
+ es5-ext "~0.10.14"
+
+es6-weak-map@^2.0.1:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f"
+ integrity sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=
+ dependencies:
+ d "1"
+ es5-ext "^0.10.14"
+ es6-iterator "^2.0.1"
+ es6-symbol "^3.1.1"
+
+escape-html@~1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
+ integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
+
+escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5, escape-string-regexp@~1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+ integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
+
+escope@^3.6.0:
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3"
+ integrity sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=
+ dependencies:
+ es6-map "^0.1.3"
+ es6-weak-map "^2.0.1"
+ esrecurse "^4.1.0"
+ estraverse "^4.1.1"
+
+eslint@^3.0.0:
+ version "3.19.0"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.19.0.tgz#c8fc6201c7f40dd08941b87c085767386a679acc"
+ integrity sha1-yPxiAcf0DdCJQbh8CFdnOGpnmsw=
+ dependencies:
+ babel-code-frame "^6.16.0"
+ chalk "^1.1.3"
+ concat-stream "^1.5.2"
+ debug "^2.1.1"
+ doctrine "^2.0.0"
+ escope "^3.6.0"
+ espree "^3.4.0"
+ esquery "^1.0.0"
+ estraverse "^4.2.0"
+ esutils "^2.0.2"
+ file-entry-cache "^2.0.0"
+ glob "^7.0.3"
+ globals "^9.14.0"
+ ignore "^3.2.0"
+ imurmurhash "^0.1.4"
+ inquirer "^0.12.0"
+ is-my-json-valid "^2.10.0"
+ is-resolvable "^1.0.0"
+ js-yaml "^3.5.1"
+ json-stable-stringify "^1.0.0"
+ levn "^0.3.0"
+ lodash "^4.0.0"
+ mkdirp "^0.5.0"
+ natural-compare "^1.4.0"
+ optionator "^0.8.2"
+ path-is-inside "^1.0.1"
+ pluralize "^1.2.1"
+ progress "^1.1.8"
+ require-uncached "^1.0.2"
+ shelljs "^0.7.5"
+ strip-bom "^3.0.0"
+ strip-json-comments "~2.0.1"
+ table "^3.7.8"
+ text-table "~0.2.0"
+ user-home "^2.0.0"
+
+espree@^3.4.0:
+ version "3.5.4"
+ resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7"
+ integrity sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==
+ dependencies:
+ acorn "^5.5.0"
+ acorn-jsx "^3.0.0"
+
+esprima@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
+ integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
+
+esquery@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708"
+ integrity sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==
+ dependencies:
+ estraverse "^4.0.0"
+
+esrecurse@^4.1.0:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf"
+ integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==
+ dependencies:
+ estraverse "^4.1.0"
+
+estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13"
+ integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=
+
+esutils@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
+ integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=
+
+etag@~1.8.1:
+ version "1.8.1"
+ resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
+ integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
+
+event-emitter@~0.3.5:
+ version "0.3.5"
+ resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39"
+ integrity sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=
+ dependencies:
+ d "1"
+ es5-ext "~0.10.14"
+
+event-stream@3.3.4:
+ version "3.3.4"
+ resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571"
+ integrity sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=
+ dependencies:
+ duplexer "~0.1.1"
+ from "~0"
+ map-stream "~0.1.0"
+ pause-stream "0.0.11"
+ split "0.3"
+ stream-combiner "~0.0.4"
+ through "~2.3.1"
+
+exit-hook@^1.0.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8"
+ integrity sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=
+
+exit@^0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c"
+ integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=
+
+expand-brackets@^2.1.4:
+ version "2.1.4"
+ resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622"
+ integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI=
+ dependencies:
+ debug "^2.3.3"
+ define-property "^0.2.5"
+ extend-shallow "^2.0.1"
+ posix-character-classes "^0.1.0"
+ regex-not "^1.0.0"
+ snapdragon "^0.8.1"
+ to-regex "^3.0.1"
+
+expand-tilde@^2.0.0, expand-tilde@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502"
+ integrity sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=
+ dependencies:
+ homedir-polyfill "^1.0.1"
+
+extend-shallow@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
+ integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=
+ dependencies:
+ is-extendable "^0.1.0"
+
+extend-shallow@^3.0.0, extend-shallow@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8"
+ integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=
+ dependencies:
+ assign-symbols "^1.0.0"
+ is-extendable "^1.0.1"
+
+extend@^3.0.0:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
+ integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
+
+extglob@^2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543"
+ integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==
+ dependencies:
+ array-unique "^0.3.2"
+ define-property "^1.0.0"
+ expand-brackets "^2.1.4"
+ extend-shallow "^2.0.1"
+ fragment-cache "^0.2.1"
+ regex-not "^1.0.0"
+ snapdragon "^0.8.1"
+ to-regex "^3.0.1"
+
+fancy-log@^1.1.0, fancy-log@^1.3.2:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.3.tgz#dbc19154f558690150a23953a0adbd035be45fc7"
+ integrity sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==
+ dependencies:
+ ansi-gray "^0.1.1"
+ color-support "^1.1.3"
+ parse-node-version "^1.0.0"
+ time-stamp "^1.0.0"
+
+fast-levenshtein@^1.0.0:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz#e6a754cc8f15e58987aa9cbd27af66fd6f4e5af9"
+ integrity sha1-5qdUzI8V5YmHqpy9J69m/W9OWvk=
+
+fast-levenshtein@~2.0.4:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
+ integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
+
+faye-websocket@0.11.x:
+ version "0.11.1"
+ resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.1.tgz#f0efe18c4f56e4f40afc7e06c719fd5ee6188f38"
+ integrity sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg=
+ dependencies:
+ websocket-driver ">=0.5.1"
+
+figures@^1.3.5:
+ version "1.7.0"
+ resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e"
+ integrity sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=
+ dependencies:
+ escape-string-regexp "^1.0.5"
+ object-assign "^4.1.0"
+
+file-entry-cache@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361"
+ integrity sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=
+ dependencies:
+ flat-cache "^1.2.1"
+ object-assign "^4.0.1"
+
+filename-reserved-regex@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/filename-reserved-regex/-/filename-reserved-regex-1.0.0.tgz#e61cf805f0de1c984567d0386dc5df50ee5af7e4"
+ integrity sha1-5hz4BfDeHJhFZ9A4bcXfUO5a9+Q=
+
+filenamify-url@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/filenamify-url/-/filenamify-url-1.0.0.tgz#b32bd81319ef5863b73078bed50f46a4f7975f50"
+ integrity sha1-syvYExnvWGO3MHi+1Q9GpPeXX1A=
+ dependencies:
+ filenamify "^1.0.0"
+ humanize-url "^1.0.0"
+
+filenamify@^1.0.0:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/filenamify/-/filenamify-1.2.1.tgz#a9f2ffd11c503bed300015029272378f1f1365a5"
+ integrity sha1-qfL/0RxQO+0wABUCknI3jx8TZaU=
+ dependencies:
+ filename-reserved-regex "^1.0.0"
+ strip-outer "^1.0.0"
+ trim-repeated "^1.0.0"
+
+fill-range@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7"
+ integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=
+ dependencies:
+ extend-shallow "^2.0.1"
+ is-number "^3.0.0"
+ repeat-string "^1.6.1"
+ to-regex-range "^2.1.0"
+
+finalhandler@1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.0.tgz#ce0b6855b45853e791b2fcc680046d88253dd7f5"
+ integrity sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=
+ dependencies:
+ debug "2.6.9"
+ encodeurl "~1.0.1"
+ escape-html "~1.0.3"
+ on-finished "~2.3.0"
+ parseurl "~1.3.2"
+ statuses "~1.3.1"
+ unpipe "~1.0.0"
+
+find-up@^1.0.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
+ integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=
+ dependencies:
+ path-exists "^2.0.0"
+ pinkie-promise "^2.0.0"
+
+findup-sync@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc"
+ integrity sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=
+ dependencies:
+ detect-file "^1.0.0"
+ is-glob "^3.1.0"
+ micromatch "^3.0.4"
+ resolve-dir "^1.0.1"
+
+findup-sync@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-3.0.0.tgz#17b108f9ee512dfb7a5c7f3c8b27ea9e1a9c08d1"
+ integrity sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==
+ dependencies:
+ detect-file "^1.0.0"
+ is-glob "^4.0.0"
+ micromatch "^3.0.4"
+ resolve-dir "^1.0.1"
+
+fined@^1.0.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/fined/-/fined-1.1.1.tgz#95d88ff329123dd1a6950fdfcd321f746271e01f"
+ integrity sha512-jQp949ZmEbiYHk3gkbdtpJ0G1+kgtLQBNdP5edFP7Fh+WAYceLQz6yO1SBj72Xkg8GVyTB3bBzAYrHJVh5Xd5g==
+ dependencies:
+ expand-tilde "^2.0.2"
+ is-plain-object "^2.0.3"
+ object.defaults "^1.1.0"
+ object.pick "^1.2.0"
+ parse-filepath "^1.0.1"
+
+flagged-respawn@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/flagged-respawn/-/flagged-respawn-1.0.1.tgz#e7de6f1279ddd9ca9aac8a5971d618606b3aab41"
+ integrity sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==
+
+flat-cache@^1.2.1:
+ version "1.3.4"
+ resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.4.tgz#2c2ef77525cc2929007dfffa1dd314aa9c9dee6f"
+ integrity sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==
+ dependencies:
+ circular-json "^0.3.1"
+ graceful-fs "^4.1.2"
+ rimraf "~2.6.2"
+ write "^0.2.1"
+
+flush-write-stream@^1.0.2:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8"
+ integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==
+ dependencies:
+ inherits "^2.0.3"
+ readable-stream "^2.3.6"
+
+for-in@^1.0.1, for-in@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
+ integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=
+
+for-own@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b"
+ integrity sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=
+ dependencies:
+ for-in "^1.0.1"
+
+fragment-cache@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19"
+ integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=
+ dependencies:
+ map-cache "^0.2.2"
+
+fresh@0.5.2:
+ version "0.5.2"
+ resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
+ integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
+
+from@~0:
+ version "0.1.7"
+ resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe"
+ integrity sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=
+
+fs-extra@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-5.0.0.tgz#414d0110cdd06705734d055652c5411260c31abd"
+ integrity sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ==
+ dependencies:
+ graceful-fs "^4.1.2"
+ jsonfile "^4.0.0"
+ universalify "^0.1.0"
+
+fs-minipass@^1.2.7:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7"
+ integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==
+ dependencies:
+ minipass "^2.6.0"
+
+fs-mkdirp-stream@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz#0b7815fc3201c6a69e14db98ce098c16935259eb"
+ integrity sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=
+ dependencies:
+ graceful-fs "^4.1.11"
+ through2 "^2.0.3"
+
+fs.realpath@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+ integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
+
+fsevents@^1.2.7:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.7.tgz#4851b664a3783e52003b3c66eb0eee1074933aa4"
+ integrity sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw==
+ dependencies:
+ nan "^2.9.2"
+ node-pre-gyp "^0.10.0"
+
+function-bind@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
+ integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
+
+gauge@~2.7.3:
+ version "2.7.4"
+ resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
+ integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=
+ dependencies:
+ aproba "^1.0.3"
+ console-control-strings "^1.0.0"
+ has-unicode "^2.0.0"
+ object-assign "^4.1.0"
+ signal-exit "^3.0.0"
+ string-width "^1.0.1"
+ strip-ansi "^3.0.1"
+ wide-align "^1.1.0"
+
+generate-function@^2.0.0:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.3.1.tgz#f069617690c10c868e73b8465746764f97c3479f"
+ integrity sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==
+ dependencies:
+ is-property "^1.0.2"
+
+generate-object-property@^1.1.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0"
+ integrity sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=
+ dependencies:
+ is-property "^1.0.0"
+
+get-caller-file@^1.0.1:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a"
+ integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==
+
+get-value@^2.0.3, get-value@^2.0.6:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
+ integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=
+
+gh-pages@^1.1.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/gh-pages/-/gh-pages-1.2.0.tgz#1acb92801078f7c038a167f447221d1496ccfbee"
+ integrity sha512-cGLYAvxtlQ1iTwAS4g7FreZPXoE/g62Fsxln2mmR19mgs4zZI+XJ+wVVUhBFCF/0+Nmvbq+abyTWue1m1BSnmg==
+ dependencies:
+ async "2.6.1"
+ commander "2.15.1"
+ filenamify-url "^1.0.0"
+ fs-extra "^5.0.0"
+ globby "^6.1.0"
+ graceful-fs "4.1.11"
+ rimraf "^2.6.2"
+
+glob-parent@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
+ integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=
+ dependencies:
+ is-glob "^3.1.0"
+ path-dirname "^1.0.0"
+
+glob-stream@^6.1.0:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-6.1.0.tgz#7045c99413b3eb94888d83ab46d0b404cc7bdde4"
+ integrity sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=
+ dependencies:
+ extend "^3.0.0"
+ glob "^7.1.1"
+ glob-parent "^3.1.0"
+ is-negated-glob "^1.0.0"
+ ordered-read-streams "^1.0.0"
+ pumpify "^1.3.5"
+ readable-stream "^2.1.5"
+ remove-trailing-separator "^1.0.1"
+ to-absolute-glob "^2.0.0"
+ unique-stream "^2.0.2"
+
+glob-watcher@^5.0.3:
+ version "5.0.5"
+ resolved "https://registry.yarnpkg.com/glob-watcher/-/glob-watcher-5.0.5.tgz#aa6bce648332924d9a8489be41e3e5c52d4186dc"
+ integrity sha512-zOZgGGEHPklZNjZQaZ9f41i7F2YwE+tS5ZHrDhbBCk3stwahn5vQxnFmBJZHoYdusR6R1bLSXeGUy/BhctwKzw==
+ dependencies:
+ anymatch "^2.0.0"
+ async-done "^1.2.0"
+ chokidar "^2.0.0"
+ is-negated-glob "^1.0.0"
+ just-debounce "^1.0.0"
+ normalize-path "^3.0.0"
+ object.defaults "^1.1.0"
+
+glob@^7.0.0, glob@^7.0.3, glob@^7.0.6, glob@^7.1.3:
+ version "7.1.3"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
+ integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^3.0.4"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
+glob@^7.1.1:
+ version "7.1.6"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
+ integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^3.0.4"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
+global-modules@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea"
+ integrity sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==
+ dependencies:
+ global-prefix "^1.0.1"
+ is-windows "^1.0.1"
+ resolve-dir "^1.0.0"
+
+global-prefix@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe"
+ integrity sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=
+ dependencies:
+ expand-tilde "^2.0.2"
+ homedir-polyfill "^1.0.1"
+ ini "^1.3.4"
+ is-windows "^1.0.1"
+ which "^1.2.14"
+
+globals@^9.14.0:
+ version "9.18.0"
+ resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a"
+ integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==
+
+globby@^6.1.0:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c"
+ integrity sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=
+ dependencies:
+ array-union "^1.0.1"
+ glob "^7.0.3"
+ object-assign "^4.0.1"
+ pify "^2.0.0"
+ pinkie-promise "^2.0.0"
+
+glogg@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/glogg/-/glogg-1.0.2.tgz#2d7dd702beda22eb3bffadf880696da6d846313f"
+ integrity sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==
+ dependencies:
+ sparkles "^1.0.0"
+
+graceful-fs@4.1.11:
+ version "4.1.11"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
+ integrity sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=
+
+graceful-fs@^4.0.0:
+ version "4.2.4"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb"
+ integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==
+
+graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9:
+ version "4.1.15"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00"
+ integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==
+
+gulp-cli@^2.2.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/gulp-cli/-/gulp-cli-2.3.0.tgz#ec0d380e29e52aa45e47977f0d32e18fd161122f"
+ integrity sha512-zzGBl5fHo0EKSXsHzjspp3y5CONegCm8ErO5Qh0UzFzk2y4tMvzLWhoDokADbarfZRL2pGpRp7yt6gfJX4ph7A==
+ dependencies:
+ ansi-colors "^1.0.1"
+ archy "^1.0.0"
+ array-sort "^1.0.0"
+ color-support "^1.1.3"
+ concat-stream "^1.6.0"
+ copy-props "^2.0.1"
+ fancy-log "^1.3.2"
+ gulplog "^1.0.0"
+ interpret "^1.4.0"
+ isobject "^3.0.1"
+ liftoff "^3.1.0"
+ matchdep "^2.0.0"
+ mute-stdout "^1.0.0"
+ pretty-hrtime "^1.0.0"
+ replace-homedir "^1.0.0"
+ semver-greatest-satisfied-range "^1.1.0"
+ v8flags "^3.2.0"
+ yargs "^7.1.0"
+
+gulp-eslint@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/gulp-eslint/-/gulp-eslint-3.0.1.tgz#04e57e3e18c6974267c12cf6855dc717d4a313bd"
+ integrity sha1-BOV+PhjGl0JnwSz2hV3HF9SjE70=
+ dependencies:
+ bufferstreams "^1.1.1"
+ eslint "^3.0.0"
+ gulp-util "^3.0.6"
+
+gulp-jasmine@^2.0.1:
+ version "2.4.2"
+ resolved "https://registry.yarnpkg.com/gulp-jasmine/-/gulp-jasmine-2.4.2.tgz#5a7f47e27370c3619ac0a2a442be399671409db3"
+ integrity sha1-Wn9H4nNww2GawKKkQr45lnFAnbM=
+ dependencies:
+ arrify "^1.0.0"
+ gulp-util "^3.0.0"
+ jasmine "^2.3.0"
+ jasmine-terminal-reporter "^1.0.0"
+ through2 "^2.0.0"
+
+gulp-util@^3.0.0, gulp-util@^3.0.6:
+ version "3.0.8"
+ resolved "https://registry.yarnpkg.com/gulp-util/-/gulp-util-3.0.8.tgz#0054e1e744502e27c04c187c3ecc505dd54bbb4f"
+ integrity sha1-AFTh50RQLifATBh8PsxQXdVLu08=
+ dependencies:
+ array-differ "^1.0.0"
+ array-uniq "^1.0.2"
+ beeper "^1.0.0"
+ chalk "^1.0.0"
+ dateformat "^2.0.0"
+ fancy-log "^1.1.0"
+ gulplog "^1.0.0"
+ has-gulplog "^0.1.0"
+ lodash._reescape "^3.0.0"
+ lodash._reevaluate "^3.0.0"
+ lodash._reinterpolate "^3.0.0"
+ lodash.template "^3.0.0"
+ minimist "^1.1.0"
+ multipipe "^0.1.2"
+ object-assign "^3.0.0"
+ replace-ext "0.0.1"
+ through2 "^2.0.0"
+ vinyl "^0.5.0"
+
+gulp@^4.0.2:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/gulp/-/gulp-4.0.2.tgz#543651070fd0f6ab0a0650c6a3e6ff5a7cb09caa"
+ integrity sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==
+ dependencies:
+ glob-watcher "^5.0.3"
+ gulp-cli "^2.2.0"
+ undertaker "^1.2.1"
+ vinyl-fs "^3.0.0"
+
+gulplog@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/gulplog/-/gulplog-1.0.0.tgz#e28c4d45d05ecbbed818363ce8f9c5926229ffe5"
+ integrity sha1-4oxNRdBey77YGDY86PnFkmIp/+U=
+ dependencies:
+ glogg "^1.0.0"
+
+has-ansi@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
+ integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=
+ dependencies:
+ ansi-regex "^2.0.0"
+
+has-gulplog@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/has-gulplog/-/has-gulplog-0.1.0.tgz#6414c82913697da51590397dafb12f22967811ce"
+ integrity sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=
+ dependencies:
+ sparkles "^1.0.0"
+
+has-symbols@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8"
+ integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==
+
+has-unicode@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
+ integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=
+
+has-value@^0.3.1:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f"
+ integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=
+ dependencies:
+ get-value "^2.0.3"
+ has-values "^0.1.4"
+ isobject "^2.0.0"
+
+has-value@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177"
+ integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=
+ dependencies:
+ get-value "^2.0.6"
+ has-values "^1.0.0"
+ isobject "^3.0.0"
+
+has-values@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771"
+ integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E=
+
+has-values@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f"
+ integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=
+ dependencies:
+ is-number "^3.0.0"
+ kind-of "^4.0.0"
+
+has@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
+ integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
+ dependencies:
+ function-bind "^1.1.1"
+
+homedir-polyfill@^1.0.1:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8"
+ integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==
+ dependencies:
+ parse-passwd "^1.0.0"
+
+hosted-git-info@^2.1.4:
+ version "2.8.9"
+ resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9"
+ integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==
+
+http-auth@3.1.x:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/http-auth/-/http-auth-3.1.3.tgz#945cfadd66521eaf8f7c84913d377d7b15f24e31"
+ integrity sha1-lFz63WZSHq+PfISRPTd9exXyTjE=
+ dependencies:
+ apache-crypt "^1.1.2"
+ apache-md5 "^1.0.6"
+ bcryptjs "^2.3.0"
+ uuid "^3.0.0"
+
+http-errors@~1.6.2:
+ version "1.6.3"
+ resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d"
+ integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=
+ dependencies:
+ depd "~1.1.2"
+ inherits "2.0.3"
+ setprototypeof "1.1.0"
+ statuses ">= 1.4.0 < 2"
+
+http-parser-js@>=0.4.0:
+ version "0.5.0"
+ resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.0.tgz#d65edbede84349d0dc30320815a15d39cc3cbbd8"
+ integrity sha512-cZdEF7r4gfRIq7ezX9J0T+kQmJNOub71dWbgAXVHDct80TKP4MCETtZQ31xyv38UwgzkWPYF/Xc0ge55dW9Z9w==
+
+humanize-url@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/humanize-url/-/humanize-url-1.0.1.tgz#f4ab99e0d288174ca4e1e50407c55fbae464efff"
+ integrity sha1-9KuZ4NKIF0yk4eUEB8VfuuRk7/8=
+ dependencies:
+ normalize-url "^1.0.0"
+ strip-url-auth "^1.0.0"
+
+iconv-lite@^0.4.4:
+ version "0.4.24"
+ resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
+ integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
+ dependencies:
+ safer-buffer ">= 2.1.2 < 3"
+
+ignore-walk@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8"
+ integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==
+ dependencies:
+ minimatch "^3.0.4"
+
+ignore@^3.2.0:
+ version "3.3.10"
+ resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043"
+ integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==
+
+imurmurhash@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
+ integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
+
+indent-string@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80"
+ integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=
+ dependencies:
+ repeating "^2.0.0"
+
+inflight@^1.0.4:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+ integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
+ dependencies:
+ once "^1.3.0"
+ wrappy "1"
+
+inherits@2, inherits@2.0.3, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
+ integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
+
+inherits@^2.0.1:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
+ integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+
+ini@^1.3.4, ini@~1.3.0:
+ version "1.3.7"
+ resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84"
+ integrity sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==
+
+inquirer@^0.12.0:
+ version "0.12.0"
+ resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e"
+ integrity sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=
+ dependencies:
+ ansi-escapes "^1.1.0"
+ ansi-regex "^2.0.0"
+ chalk "^1.0.0"
+ cli-cursor "^1.0.1"
+ cli-width "^2.0.0"
+ figures "^1.3.5"
+ lodash "^4.3.0"
+ readline2 "^1.0.1"
+ run-async "^0.1.0"
+ rx-lite "^3.1.2"
+ string-width "^1.0.1"
+ strip-ansi "^3.0.0"
+ through "^2.3.6"
+
+interpret@^1.0.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296"
+ integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==
+
+interpret@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e"
+ integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==
+
+invert-kv@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
+ integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY=
+
+is-absolute@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-absolute/-/is-absolute-1.0.0.tgz#395e1ae84b11f26ad1795e73c17378e48a301576"
+ integrity sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==
+ dependencies:
+ is-relative "^1.0.0"
+ is-windows "^1.0.1"
+
+is-accessor-descriptor@^0.1.6:
+ version "0.1.6"
+ resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6"
+ integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=
+ dependencies:
+ kind-of "^3.0.2"
+
+is-accessor-descriptor@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656"
+ integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==
+ dependencies:
+ kind-of "^6.0.0"
+
+is-arrayish@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
+ integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=
+
+is-binary-path@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898"
+ integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=
+ dependencies:
+ binary-extensions "^1.0.0"
+
+is-buffer@^1.1.5:
+ version "1.1.6"
+ resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
+ integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
+
+is-callable@^1.1.4, is-callable@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.2.tgz#c7c6715cd22d4ddb48d3e19970223aceabb080d9"
+ integrity sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==
+
+is-data-descriptor@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
+ integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=
+ dependencies:
+ kind-of "^3.0.2"
+
+is-data-descriptor@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7"
+ integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==
+ dependencies:
+ kind-of "^6.0.0"
+
+is-date-object@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e"
+ integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==
+
+is-descriptor@^0.1.0:
+ version "0.1.6"
+ resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca"
+ integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==
+ dependencies:
+ is-accessor-descriptor "^0.1.6"
+ is-data-descriptor "^0.1.4"
+ kind-of "^5.0.0"
+
+is-descriptor@^1.0.0, is-descriptor@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec"
+ integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==
+ dependencies:
+ is-accessor-descriptor "^1.0.0"
+ is-data-descriptor "^1.0.0"
+ kind-of "^6.0.2"
+
+is-extendable@^0.1.0, is-extendable@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
+ integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=
+
+is-extendable@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4"
+ integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==
+ dependencies:
+ is-plain-object "^2.0.4"
+
+is-extglob@^2.1.0, is-extglob@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+ integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
+
+is-finite@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa"
+ integrity sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=
+ dependencies:
+ number-is-nan "^1.0.0"
+
+is-fullwidth-code-point@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
+ integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs=
+ dependencies:
+ number-is-nan "^1.0.0"
+
+is-fullwidth-code-point@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
+ integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
+
+is-glob@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a"
+ integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=
+ dependencies:
+ is-extglob "^2.1.0"
+
+is-glob@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0"
+ integrity sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=
+ dependencies:
+ is-extglob "^2.1.1"
+
+is-my-ip-valid@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz#7b351b8e8edd4d3995d4d066680e664d94696824"
+ integrity sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==
+
+is-my-json-valid@^2.10.0:
+ version "2.19.0"
+ resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.19.0.tgz#8fd6e40363cd06b963fa877d444bfb5eddc62175"
+ integrity sha512-mG0f/unGX1HZ5ep4uhRaPOS8EkAY8/j6mDRMJrutq4CqhoJWYp7qAlonIPy3TV7p3ju4TK9fo/PbnoksWmsp5Q==
+ dependencies:
+ generate-function "^2.0.0"
+ generate-object-property "^1.1.0"
+ is-my-ip-valid "^1.0.0"
+ jsonpointer "^4.0.0"
+ xtend "^4.0.0"
+
+is-negated-glob@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-negated-glob/-/is-negated-glob-1.0.0.tgz#6910bca5da8c95e784b5751b976cf5a10fee36d2"
+ integrity sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=
+
+is-negative-zero@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.0.tgz#9553b121b0fac28869da9ed459e20c7543788461"
+ integrity sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=
+
+is-number@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
+ integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=
+ dependencies:
+ kind-of "^3.0.2"
+
+is-number@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff"
+ integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==
+
+is-plain-obj@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
+ integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4=
+
+is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
+ integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==
+ dependencies:
+ isobject "^3.0.1"
+
+is-plain-object@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344"
+ integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==
+
+is-property@^1.0.0, is-property@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84"
+ integrity sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=
+
+is-regex@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.1.tgz#c6f98aacc546f6cec5468a07b7b153ab564a57b9"
+ integrity sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==
+ dependencies:
+ has-symbols "^1.0.1"
+
+is-relative@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-1.0.0.tgz#a1bb6935ce8c5dba1e8b9754b9b2dcc020e2260d"
+ integrity sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==
+ dependencies:
+ is-unc-path "^1.0.0"
+
+is-resolvable@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88"
+ integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==
+
+is-symbol@^1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937"
+ integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==
+ dependencies:
+ has-symbols "^1.0.1"
+
+is-unc-path@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-unc-path/-/is-unc-path-1.0.0.tgz#d731e8898ed090a12c352ad2eaed5095ad322c9d"
+ integrity sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==
+ dependencies:
+ unc-path-regex "^0.1.2"
+
+is-utf8@^0.2.0, is-utf8@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
+ integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=
+
+is-valid-glob@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-valid-glob/-/is-valid-glob-1.0.0.tgz#29bf3eff701be2d4d315dbacc39bc39fe8f601aa"
+ integrity sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=
+
+is-windows@^1.0.1, is-windows@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
+ integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==
+
+is-wsl@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d"
+ integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=
+
+isarray@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
+ integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=
+
+isarray@1.0.0, isarray@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
+ integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
+
+isexe@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+ integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
+
+isobject@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
+ integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=
+ dependencies:
+ isarray "1.0.0"
+
+isobject@^3.0.0, isobject@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
+ integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
+
+jasmine-core@~2.99.0:
+ version "2.99.1"
+ resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.99.1.tgz#e6400df1e6b56e130b61c4bcd093daa7f6e8ca15"
+ integrity sha1-5kAN8ea1bhMLYcS80JPap/boyhU=
+
+jasmine-terminal-reporter@^1.0.0:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/jasmine-terminal-reporter/-/jasmine-terminal-reporter-1.0.3.tgz#896f1ec8fdf4bf6aecdd41c503eda7347f61526b"
+ integrity sha1-iW8eyP30v2rs3UHFA+2nNH9hUms=
+ dependencies:
+ indent-string "^2.1.0"
+ pluralize "^1.2.1"
+
+jasmine@^2.3.0:
+ version "2.99.0"
+ resolved "https://registry.yarnpkg.com/jasmine/-/jasmine-2.99.0.tgz#8ca72d102e639b867c6489856e0e18a9c7aa42b7"
+ integrity sha1-jKctEC5jm4Z8ZImFbg4YqceqQrc=
+ dependencies:
+ exit "^0.1.2"
+ glob "^7.0.6"
+ jasmine-core "~2.99.0"
+
+js-tokens@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
+ integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls=
+
+js-yaml@^3.5.1:
+ version "3.13.1"
+ resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
+ integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
+ dependencies:
+ argparse "^1.0.7"
+ esprima "^4.0.0"
+
+js2xmlparser@~3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/js2xmlparser/-/js2xmlparser-3.0.0.tgz#3fb60eaa089c5440f9319f51760ccd07e2499733"
+ integrity sha1-P7YOqgicVED5MZ9RdgzNB+JJlzM=
+ dependencies:
+ xmlcreate "^1.0.1"
+
+jsdoc@3.5.5:
+ version "3.5.5"
+ resolved "https://registry.yarnpkg.com/jsdoc/-/jsdoc-3.5.5.tgz#484521b126e81904d632ff83ec9aaa096708fa4d"
+ integrity sha512-6PxB65TAU4WO0Wzyr/4/YhlGovXl0EVYfpKbpSroSj0qBxT4/xod/l40Opkm38dRHRdQgdeY836M0uVnJQG7kg==
+ dependencies:
+ babylon "7.0.0-beta.19"
+ bluebird "~3.5.0"
+ catharsis "~0.8.9"
+ escape-string-regexp "~1.0.5"
+ js2xmlparser "~3.0.0"
+ klaw "~2.0.0"
+ marked "~0.3.6"
+ mkdirp "~0.5.1"
+ requizzle "~0.2.1"
+ strip-json-comments "~2.0.1"
+ taffydb "2.6.2"
+ underscore "~1.8.3"
+
+json-stable-stringify-without-jsonify@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
+ integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
+
+json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af"
+ integrity sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=
+ dependencies:
+ jsonify "~0.0.0"
+
+jsonfile@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
+ integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=
+ optionalDependencies:
+ graceful-fs "^4.1.6"
+
+jsonify@~0.0.0:
+ version "0.0.0"
+ resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
+ integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=
+
+jsonpointer@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9"
+ integrity sha1-T9kss04OnbPInIYi7PUfm5eMbLk=
+
+just-debounce@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/just-debounce/-/just-debounce-1.0.0.tgz#87fccfaeffc0b68cd19d55f6722943f929ea35ea"
+ integrity sha1-h/zPrv/AtozRnVX2cilD+SnqNeo=
+
+kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0:
+ version "3.2.2"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
+ integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=
+ dependencies:
+ is-buffer "^1.1.5"
+
+kind-of@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57"
+ integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc=
+ dependencies:
+ is-buffer "^1.1.5"
+
+kind-of@^5.0.0, kind-of@^5.0.2:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d"
+ integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==
+
+kind-of@^6.0.0, kind-of@^6.0.2:
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051"
+ integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==
+
+klaw@~2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/klaw/-/klaw-2.0.0.tgz#59c128e0dc5ce410201151194eeb9cbf858650f6"
+ integrity sha1-WcEo4Nxc5BAgEVEZTuucv4WGUPY=
+ dependencies:
+ graceful-fs "^4.1.9"
+
+last-run@^1.1.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/last-run/-/last-run-1.1.1.tgz#45b96942c17b1c79c772198259ba943bebf8ca5b"
+ integrity sha1-RblpQsF7HHnHchmCWbqUO+v4yls=
+ dependencies:
+ default-resolution "^2.0.0"
+ es6-weak-map "^2.0.1"
+
+lazystream@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4"
+ integrity sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=
+ dependencies:
+ readable-stream "^2.0.5"
+
+lcid@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
+ integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=
+ dependencies:
+ invert-kv "^1.0.0"
+
+lead@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/lead/-/lead-1.0.0.tgz#6f14f99a37be3a9dd784f5495690e5903466ee42"
+ integrity sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=
+ dependencies:
+ flush-write-stream "^1.0.2"
+
+levn@^0.3.0, levn@~0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
+ integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=
+ dependencies:
+ prelude-ls "~1.1.2"
+ type-check "~0.3.2"
+
+liftoff@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-3.1.0.tgz#c9ba6081f908670607ee79062d700df062c52ed3"
+ integrity sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==
+ dependencies:
+ extend "^3.0.0"
+ findup-sync "^3.0.0"
+ fined "^1.0.1"
+ flagged-respawn "^1.0.0"
+ is-plain-object "^2.0.4"
+ object.map "^1.0.0"
+ rechoir "^0.6.2"
+ resolve "^1.1.7"
+
+live-server@^1.2.0:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/live-server/-/live-server-1.2.1.tgz#670630dd409d22fe9c513ab1c1894686c757153e"
+ integrity sha512-Yn2XCVjErTkqnM3FfTmM7/kWy3zP7+cEtC7x6u+wUzlQ+1UW3zEYbbyJrc0jNDwiMDZI0m4a0i3dxlGHVyXczw==
+ dependencies:
+ chokidar "^2.0.4"
+ colors latest
+ connect "^3.6.6"
+ cors latest
+ event-stream "3.3.4"
+ faye-websocket "0.11.x"
+ http-auth "3.1.x"
+ morgan "^1.9.1"
+ object-assign latest
+ opn latest
+ proxy-middleware latest
+ send latest
+ serve-index "^1.9.1"
+
+load-json-file@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
+ integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=
+ dependencies:
+ graceful-fs "^4.1.2"
+ parse-json "^2.2.0"
+ pify "^2.0.0"
+ pinkie-promise "^2.0.0"
+ strip-bom "^2.0.0"
+
+lodash._basecopy@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36"
+ integrity sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=
+
+lodash._basetostring@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz#d1861d877f824a52f669832dcaf3ee15566a07d5"
+ integrity sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=
+
+lodash._basevalues@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz#5b775762802bde3d3297503e26300820fdf661b7"
+ integrity sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=
+
+lodash._getnative@^3.0.0:
+ version "3.9.1"
+ resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5"
+ integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=
+
+lodash._isiterateecall@^3.0.0:
+ version "3.0.9"
+ resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c"
+ integrity sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=
+
+lodash._reescape@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/lodash._reescape/-/lodash._reescape-3.0.0.tgz#2b1d6f5dfe07c8a355753e5f27fac7f1cde1616a"
+ integrity sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=
+
+lodash._reevaluate@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz#58bc74c40664953ae0b124d806996daca431e2ed"
+ integrity sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=
+
+lodash._reinterpolate@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
+ integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=
+
+lodash._root@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692"
+ integrity sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=
+
+lodash.escape@^3.0.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-3.2.0.tgz#995ee0dc18c1b48cc92effae71a10aab5b487698"
+ integrity sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=
+ dependencies:
+ lodash._root "^3.0.0"
+
+lodash.isarguments@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a"
+ integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=
+
+lodash.isarray@^3.0.0:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55"
+ integrity sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=
+
+lodash.keys@^3.0.0:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a"
+ integrity sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=
+ dependencies:
+ lodash._getnative "^3.0.0"
+ lodash.isarguments "^3.0.0"
+ lodash.isarray "^3.0.0"
+
+lodash.restparam@^3.0.0:
+ version "3.6.1"
+ resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805"
+ integrity sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=
+
+lodash.template@^3.0.0:
+ version "3.6.2"
+ resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-3.6.2.tgz#f8cdecc6169a255be9098ae8b0c53d378931d14f"
+ integrity sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=
+ dependencies:
+ lodash._basecopy "^3.0.0"
+ lodash._basetostring "^3.0.0"
+ lodash._basevalues "^3.0.0"
+ lodash._isiterateecall "^3.0.0"
+ lodash._reinterpolate "^3.0.0"
+ lodash.escape "^3.0.0"
+ lodash.keys "^3.0.0"
+ lodash.restparam "^3.0.0"
+ lodash.templatesettings "^3.0.0"
+
+lodash.templatesettings@^3.0.0:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz#fb307844753b66b9f1afa54e262c745307dba8e5"
+ integrity sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=
+ dependencies:
+ lodash._reinterpolate "^3.0.0"
+ lodash.escape "^3.0.0"
+
+lodash@^4.0.0, lodash@^4.17.10, lodash@^4.3.0:
+ version "4.17.21"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
+ integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
+
+make-iterator@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/make-iterator/-/make-iterator-1.0.1.tgz#29b33f312aa8f547c4a5e490f56afcec99133ad6"
+ integrity sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==
+ dependencies:
+ kind-of "^6.0.2"
+
+map-cache@^0.2.0, map-cache@^0.2.2:
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
+ integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=
+
+map-stream@~0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194"
+ integrity sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=
+
+map-visit@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f"
+ integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=
+ dependencies:
+ object-visit "^1.0.0"
+
+marked@~0.3.6:
+ version "0.3.19"
+ resolved "https://registry.yarnpkg.com/marked/-/marked-0.3.19.tgz#5d47f709c4c9fc3c216b6d46127280f40b39d790"
+ integrity sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg==
+
+matchdep@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/matchdep/-/matchdep-2.0.0.tgz#c6f34834a0d8dbc3b37c27ee8bbcb27c7775582e"
+ integrity sha1-xvNINKDY28OzfCfui7yyfHd1WC4=
+ dependencies:
+ findup-sync "^2.0.0"
+ micromatch "^3.0.4"
+ resolve "^1.4.0"
+ stack-trace "0.0.10"
+
+micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4:
+ version "3.1.10"
+ resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
+ integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==
+ dependencies:
+ arr-diff "^4.0.0"
+ array-unique "^0.3.2"
+ braces "^2.3.1"
+ define-property "^2.0.2"
+ extend-shallow "^3.0.2"
+ extglob "^2.0.4"
+ fragment-cache "^0.2.1"
+ kind-of "^6.0.2"
+ nanomatch "^1.2.9"
+ object.pick "^1.3.0"
+ regex-not "^1.0.0"
+ snapdragon "^0.8.1"
+ to-regex "^3.0.2"
+
+mime-db@~1.38.0:
+ version "1.38.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.38.0.tgz#1a2aab16da9eb167b49c6e4df2d9c68d63d8e2ad"
+ integrity sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==
+
+mime-types@~2.1.17, mime-types@~2.1.18:
+ version "2.1.22"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.22.tgz#fe6b355a190926ab7698c9a0556a11199b2199bd"
+ integrity sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==
+ dependencies:
+ mime-db "~1.38.0"
+
+mime@1.4.1:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6"
+ integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==
+
+minimatch@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
+ integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
+ dependencies:
+ brace-expansion "^1.1.7"
+
+minimist@^1.1.0, minimist@^1.2.0, minimist@^1.2.6:
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
+ integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
+
+minipass@^2.6.0, minipass@^2.9.0:
+ version "2.9.0"
+ resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6"
+ integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==
+ dependencies:
+ safe-buffer "^5.1.2"
+ yallist "^3.0.0"
+
+minizlib@^1.3.3:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d"
+ integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==
+ dependencies:
+ minipass "^2.9.0"
+
+mixin-deep@^1.2.0:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566"
+ integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==
+ dependencies:
+ for-in "^1.0.2"
+ is-extendable "^1.0.1"
+
+mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.5, mkdirp@~0.5.1:
+ version "0.5.6"
+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6"
+ integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==
+ dependencies:
+ minimist "^1.2.6"
+
+morgan@^1.9.1:
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.9.1.tgz#0a8d16734a1d9afbc824b99df87e738e58e2da59"
+ integrity sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA==
+ dependencies:
+ basic-auth "~2.0.0"
+ debug "2.6.9"
+ depd "~1.1.2"
+ on-finished "~2.3.0"
+ on-headers "~1.0.1"
+
+ms@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
+ integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
+
+multipipe@^0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-0.1.2.tgz#2a8f2ddf70eed564dff2d57f1e1a137d9f05078b"
+ integrity sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=
+ dependencies:
+ duplexer2 "0.0.2"
+
+mute-stdout@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/mute-stdout/-/mute-stdout-1.0.1.tgz#acb0300eb4de23a7ddeec014e3e96044b3472331"
+ integrity sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==
+
+mute-stream@0.0.5:
+ version "0.0.5"
+ resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0"
+ integrity sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=
+
+nan@^2.9.2:
+ version "2.13.2"
+ resolved "https://registry.yarnpkg.com/nan/-/nan-2.13.2.tgz#f51dc7ae66ba7d5d55e1e6d4d8092e802c9aefe7"
+ integrity sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==
+
+nanomatch@^1.2.9:
+ version "1.2.13"
+ resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
+ integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==
+ dependencies:
+ arr-diff "^4.0.0"
+ array-unique "^0.3.2"
+ define-property "^2.0.2"
+ extend-shallow "^3.0.2"
+ fragment-cache "^0.2.1"
+ is-windows "^1.0.2"
+ kind-of "^6.0.2"
+ object.pick "^1.3.0"
+ regex-not "^1.0.0"
+ snapdragon "^0.8.1"
+ to-regex "^3.0.1"
+
+natural-compare@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
+ integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
+
+needle@^2.2.1:
+ version "2.2.4"
+ resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.4.tgz#51931bff82533b1928b7d1d69e01f1b00ffd2a4e"
+ integrity sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA==
+ dependencies:
+ debug "^2.1.2"
+ iconv-lite "^0.4.4"
+ sax "^1.2.4"
+
+negotiator@0.6.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
+ integrity sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=
+
+next-tick@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c"
+ integrity sha1-yobR/ogoFpsBICCOPchCS524NCw=
+
+node-pre-gyp@^0.10.0:
+ version "0.10.3"
+ resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc"
+ integrity sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A==
+ dependencies:
+ detect-libc "^1.0.2"
+ mkdirp "^0.5.1"
+ needle "^2.2.1"
+ nopt "^4.0.1"
+ npm-packlist "^1.1.6"
+ npmlog "^4.0.2"
+ rc "^1.2.7"
+ rimraf "^2.6.1"
+ semver "^5.3.0"
+ tar "^4"
+
+nopt@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
+ integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=
+ dependencies:
+ abbrev "1"
+ osenv "^0.1.4"
+
+normalize-package-data@^2.3.2:
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
+ integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==
+ dependencies:
+ hosted-git-info "^2.1.4"
+ resolve "^1.10.0"
+ semver "2 || 3 || 4 || 5"
+ validate-npm-package-license "^3.0.1"
+
+normalize-path@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
+ integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=
+ dependencies:
+ remove-trailing-separator "^1.0.1"
+
+normalize-path@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
+ integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
+
+normalize-url@^1.0.0:
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.9.1.tgz#2cc0d66b31ea23036458436e3620d85954c66c3c"
+ integrity sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=
+ dependencies:
+ object-assign "^4.0.1"
+ prepend-http "^1.0.0"
+ query-string "^4.1.0"
+ sort-keys "^1.0.0"
+
+now-and-later@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/now-and-later/-/now-and-later-2.0.1.tgz#8e579c8685764a7cc02cb680380e94f43ccb1f7c"
+ integrity sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==
+ dependencies:
+ once "^1.3.2"
+
+npm-bundled@^1.0.1:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd"
+ integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==
+
+npm-packlist@^1.1.6:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.1.tgz#19064cdf988da80ea3cee45533879d90192bbfbc"
+ integrity sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==
+ dependencies:
+ ignore-walk "^3.0.1"
+ npm-bundled "^1.0.1"
+
+npmlog@^4.0.2:
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
+ integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==
+ dependencies:
+ are-we-there-yet "~1.1.2"
+ console-control-strings "~1.1.0"
+ gauge "~2.7.3"
+ set-blocking "~2.0.0"
+
+number-is-nan@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
+ integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
+
+object-assign@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2"
+ integrity sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=
+
+object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@latest:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+ integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
+
+object-copy@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c"
+ integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw=
+ dependencies:
+ copy-descriptor "^0.1.0"
+ define-property "^0.2.5"
+ kind-of "^3.0.3"
+
+object-inspect@^1.8.0:
+ version "1.8.0"
+ resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0"
+ integrity sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==
+
+object-keys@^1.0.12, object-keys@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
+ integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
+
+object-visit@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb"
+ integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=
+ dependencies:
+ isobject "^3.0.0"
+
+object.assign@^4.0.4, object.assign@^4.1.0, object.assign@^4.1.1:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.1.tgz#303867a666cdd41936ecdedfb1f8f3e32a478cdd"
+ integrity sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA==
+ dependencies:
+ define-properties "^1.1.3"
+ es-abstract "^1.18.0-next.0"
+ has-symbols "^1.0.1"
+ object-keys "^1.1.1"
+
+object.defaults@^1.0.0, object.defaults@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/object.defaults/-/object.defaults-1.1.0.tgz#3a7f868334b407dea06da16d88d5cd29e435fecf"
+ integrity sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=
+ dependencies:
+ array-each "^1.0.1"
+ array-slice "^1.0.0"
+ for-own "^1.0.0"
+ isobject "^3.0.0"
+
+object.map@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/object.map/-/object.map-1.0.1.tgz#cf83e59dc8fcc0ad5f4250e1f78b3b81bd801d37"
+ integrity sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=
+ dependencies:
+ for-own "^1.0.0"
+ make-iterator "^1.0.0"
+
+object.pick@^1.2.0, object.pick@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747"
+ integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=
+ dependencies:
+ isobject "^3.0.1"
+
+object.reduce@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/object.reduce/-/object.reduce-1.0.1.tgz#6fe348f2ac7fa0f95ca621226599096825bb03ad"
+ integrity sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60=
+ dependencies:
+ for-own "^1.0.0"
+ make-iterator "^1.0.0"
+
+on-finished@~2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
+ integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=
+ dependencies:
+ ee-first "1.1.1"
+
+on-headers@~1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f"
+ integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==
+
+once@^1.3.0, once@^1.3.1, once@^1.3.2, once@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+ integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
+ dependencies:
+ wrappy "1"
+
+onetime@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789"
+ integrity sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=
+
+opn@latest:
+ version "5.5.0"
+ resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc"
+ integrity sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==
+ dependencies:
+ is-wsl "^1.1.0"
+
+optionator@^0.8.2:
+ version "0.8.2"
+ resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64"
+ integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=
+ dependencies:
+ deep-is "~0.1.3"
+ fast-levenshtein "~2.0.4"
+ levn "~0.3.0"
+ prelude-ls "~1.1.2"
+ type-check "~0.3.2"
+ wordwrap "~1.0.0"
+
+ordered-read-streams@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz#77c0cb37c41525d64166d990ffad7ec6a0e1363e"
+ integrity sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=
+ dependencies:
+ readable-stream "^2.0.1"
+
+os-homedir@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
+ integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
+
+os-locale@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9"
+ integrity sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=
+ dependencies:
+ lcid "^1.0.0"
+
+os-tmpdir@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
+ integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
+
+osenv@^0.1.4:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410"
+ integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==
+ dependencies:
+ os-homedir "^1.0.0"
+ os-tmpdir "^1.0.0"
+
+parse-filepath@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/parse-filepath/-/parse-filepath-1.0.2.tgz#a632127f53aaf3d15876f5872f3ffac763d6c891"
+ integrity sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=
+ dependencies:
+ is-absolute "^1.0.0"
+ map-cache "^0.2.0"
+ path-root "^0.1.1"
+
+parse-json@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
+ integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=
+ dependencies:
+ error-ex "^1.2.0"
+
+parse-node-version@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/parse-node-version/-/parse-node-version-1.0.1.tgz#e2b5dbede00e7fa9bc363607f53327e8b073189b"
+ integrity sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==
+
+parse-passwd@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
+ integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=
+
+parseurl@~1.3.2:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3"
+ integrity sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=
+
+pascalcase@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
+ integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=
+
+path-dirname@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"
+ integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=
+
+path-exists@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
+ integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=
+ dependencies:
+ pinkie-promise "^2.0.0"
+
+path-is-absolute@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+ integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
+
+path-is-inside@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
+ integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=
+
+path-parse@^1.0.6:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
+ integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
+
+path-root-regex@^0.1.0:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/path-root-regex/-/path-root-regex-0.1.2.tgz#bfccdc8df5b12dc52c8b43ec38d18d72c04ba96d"
+ integrity sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=
+
+path-root@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/path-root/-/path-root-0.1.1.tgz#9a4a6814cac1c0cd73360a95f32083c8ea4745b7"
+ integrity sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=
+ dependencies:
+ path-root-regex "^0.1.0"
+
+path-type@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
+ integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=
+ dependencies:
+ graceful-fs "^4.1.2"
+ pify "^2.0.0"
+ pinkie-promise "^2.0.0"
+
+pause-stream@0.0.11:
+ version "0.0.11"
+ resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445"
+ integrity sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=
+ dependencies:
+ through "~2.3"
+
+pify@^2.0.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
+ integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw=
+
+pinkie-promise@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
+ integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o=
+ dependencies:
+ pinkie "^2.0.0"
+
+pinkie@^2.0.0:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
+ integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA=
+
+pluralize@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45"
+ integrity sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=
+
+posix-character-classes@^0.1.0:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
+ integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=
+
+prelude-ls@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
+ integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=
+
+prepend-http@^1.0.0:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
+ integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=
+
+pretty-hrtime@^1.0.0:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1"
+ integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=
+
+process-nextick-args@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
+ integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
+
+process-nextick-args@~2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa"
+ integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==
+
+progress@^1.1.8:
+ version "1.1.8"
+ resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be"
+ integrity sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=
+
+proxy-middleware@latest:
+ version "0.15.0"
+ resolved "https://registry.yarnpkg.com/proxy-middleware/-/proxy-middleware-0.15.0.tgz#a3fdf1befb730f951965872ac2f6074c61477a56"
+ integrity sha1-o/3xvvtzD5UZZYcqwvYHTGFHelY=
+
+pump@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909"
+ integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==
+ dependencies:
+ end-of-stream "^1.1.0"
+ once "^1.3.1"
+
+pumpify@^1.3.5:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce"
+ integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==
+ dependencies:
+ duplexify "^3.6.0"
+ inherits "^2.0.3"
+ pump "^2.0.0"
+
+query-string@^4.1.0:
+ version "4.3.4"
+ resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb"
+ integrity sha1-u7aTucqRXCMlFbIosaArYJBD2+s=
+ dependencies:
+ object-assign "^4.1.0"
+ strict-uri-encode "^1.0.0"
+
+range-parser@~1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e"
+ integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=
+
+rc@^1.2.7:
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
+ integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
+ dependencies:
+ deep-extend "^0.6.0"
+ ini "~1.3.0"
+ minimist "^1.2.0"
+ strip-json-comments "~2.0.1"
+
+read-pkg-up@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
+ integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=
+ dependencies:
+ find-up "^1.0.0"
+ read-pkg "^1.0.0"
+
+read-pkg@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
+ integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=
+ dependencies:
+ load-json-file "^1.0.0"
+ normalize-package-data "^2.3.2"
+ path-type "^1.0.0"
+
+readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.5, readable-stream@^2.1.5, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6:
+ version "2.3.7"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
+ integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
+ dependencies:
+ core-util-is "~1.0.0"
+ inherits "~2.0.3"
+ isarray "~1.0.0"
+ process-nextick-args "~2.0.0"
+ safe-buffer "~5.1.1"
+ string_decoder "~1.1.1"
+ util-deprecate "~1.0.1"
+
+readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.2.2, readable-stream@~2.3.6:
+ version "2.3.6"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
+ integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==
+ dependencies:
+ core-util-is "~1.0.0"
+ inherits "~2.0.3"
+ isarray "~1.0.0"
+ process-nextick-args "~2.0.0"
+ safe-buffer "~5.1.1"
+ string_decoder "~1.1.1"
+ util-deprecate "~1.0.1"
+
+readable-stream@~1.1.9:
+ version "1.1.14"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
+ integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk=
+ dependencies:
+ core-util-is "~1.0.0"
+ inherits "~2.0.1"
+ isarray "0.0.1"
+ string_decoder "~0.10.x"
+
+readdirp@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525"
+ integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==
+ dependencies:
+ graceful-fs "^4.1.11"
+ micromatch "^3.1.10"
+ readable-stream "^2.0.2"
+
+readline2@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35"
+ integrity sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=
+ dependencies:
+ code-point-at "^1.0.0"
+ is-fullwidth-code-point "^1.0.0"
+ mute-stream "0.0.5"
+
+rechoir@^0.6.2:
+ version "0.6.2"
+ resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
+ integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=
+ dependencies:
+ resolve "^1.1.6"
+
+regex-not@^1.0.0, regex-not@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c"
+ integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==
+ dependencies:
+ extend-shallow "^3.0.2"
+ safe-regex "^1.1.0"
+
+remove-bom-buffer@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz#c2bf1e377520d324f623892e33c10cac2c252b53"
+ integrity sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==
+ dependencies:
+ is-buffer "^1.1.5"
+ is-utf8 "^0.2.1"
+
+remove-bom-stream@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz#05f1a593f16e42e1fb90ebf59de8e569525f9523"
+ integrity sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=
+ dependencies:
+ remove-bom-buffer "^3.0.0"
+ safe-buffer "^5.1.0"
+ through2 "^2.0.3"
+
+remove-trailing-separator@^1.0.1, remove-trailing-separator@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
+ integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8=
+
+repeat-element@^1.1.2:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce"
+ integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==
+
+repeat-string@^1.6.1:
+ version "1.6.1"
+ resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
+ integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc=
+
+repeating@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda"
+ integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=
+ dependencies:
+ is-finite "^1.0.0"
+
+replace-ext@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924"
+ integrity sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=
+
+replace-ext@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.1.tgz#2d6d996d04a15855d967443631dd5f77825b016a"
+ integrity sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==
+
+replace-homedir@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/replace-homedir/-/replace-homedir-1.0.0.tgz#e87f6d513b928dde808260c12be7fec6ff6e798c"
+ integrity sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw=
+ dependencies:
+ homedir-polyfill "^1.0.1"
+ is-absolute "^1.0.0"
+ remove-trailing-separator "^1.1.0"
+
+require-directory@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
+ integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I=
+
+require-main-filename@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
+ integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=
+
+require-uncached@^1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3"
+ integrity sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=
+ dependencies:
+ caller-path "^0.1.0"
+ resolve-from "^1.0.0"
+
+requizzle@~0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/requizzle/-/requizzle-0.2.1.tgz#6943c3530c4d9a7e46f1cddd51c158fc670cdbde"
+ integrity sha1-aUPDUwxNmn5G8c3dUcFY/GcM294=
+ dependencies:
+ underscore "~1.6.0"
+
+resolve-dir@^1.0.0, resolve-dir@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43"
+ integrity sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=
+ dependencies:
+ expand-tilde "^2.0.0"
+ global-modules "^1.0.0"
+
+resolve-from@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226"
+ integrity sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=
+
+resolve-options@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/resolve-options/-/resolve-options-1.1.0.tgz#32bb9e39c06d67338dc9378c0d6d6074566ad131"
+ integrity sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=
+ dependencies:
+ value-or-function "^3.0.0"
+
+resolve-url@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
+ integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
+
+resolve@^1.1.6, resolve@^1.1.7:
+ version "1.10.0"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.10.0.tgz#3bdaaeaf45cc07f375656dfd2e54ed0810b101ba"
+ integrity sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==
+ dependencies:
+ path-parse "^1.0.6"
+
+resolve@^1.10.0, resolve@^1.4.0:
+ version "1.17.0"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444"
+ integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==
+ dependencies:
+ path-parse "^1.0.6"
+
+restore-cursor@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541"
+ integrity sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=
+ dependencies:
+ exit-hook "^1.0.0"
+ onetime "^1.0.0"
+
+ret@~0.1.10:
+ version "0.1.15"
+ resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
+ integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==
+
+rimraf@^2.6.1, rimraf@^2.6.2, rimraf@~2.6.2:
+ version "2.6.3"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
+ integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==
+ dependencies:
+ glob "^7.1.3"
+
+run-async@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389"
+ integrity sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=
+ dependencies:
+ once "^1.3.0"
+
+rx-lite@^3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102"
+ integrity sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=
+
+safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
+ integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
+
+safe-buffer@^5.1.0, safe-buffer@^5.1.2, safe-buffer@^5.2.1:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
+ integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
+
+safe-regex@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
+ integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4=
+ dependencies:
+ ret "~0.1.10"
+
+"safer-buffer@>= 2.1.2 < 3":
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
+ integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
+
+sax@^1.2.4:
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
+ integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
+
+semver-greatest-satisfied-range@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz#13e8c2658ab9691cb0cd71093240280d36f77a5b"
+ integrity sha1-E+jCZYq5aRywzXEJMkAoDTb3els=
+ dependencies:
+ sver-compat "^1.5.0"
+
+"semver@2 || 3 || 4 || 5":
+ version "5.7.1"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
+ integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
+
+semver@^5.3.0:
+ version "5.6.0"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004"
+ integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==
+
+send@latest:
+ version "0.16.2"
+ resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1"
+ integrity sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==
+ dependencies:
+ debug "2.6.9"
+ depd "~1.1.2"
+ destroy "~1.0.4"
+ encodeurl "~1.0.2"
+ escape-html "~1.0.3"
+ etag "~1.8.1"
+ fresh "0.5.2"
+ http-errors "~1.6.2"
+ mime "1.4.1"
+ ms "2.0.0"
+ on-finished "~2.3.0"
+ range-parser "~1.2.0"
+ statuses "~1.4.0"
+
+serve-index@^1.9.1:
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239"
+ integrity sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=
+ dependencies:
+ accepts "~1.3.4"
+ batch "0.6.1"
+ debug "2.6.9"
+ escape-html "~1.0.3"
+ http-errors "~1.6.2"
+ mime-types "~2.1.17"
+ parseurl "~1.3.2"
+
+set-blocking@^2.0.0, set-blocking@~2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
+ integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
+
+set-value@^0.4.3:
+ version "0.4.3"
+ resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1"
+ integrity sha1-fbCPnT0i3H945Trzw79GZuzfzPE=
+ dependencies:
+ extend-shallow "^2.0.1"
+ is-extendable "^0.1.1"
+ is-plain-object "^2.0.1"
+ to-object-path "^0.3.0"
+
+set-value@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274"
+ integrity sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==
+ dependencies:
+ extend-shallow "^2.0.1"
+ is-extendable "^0.1.1"
+ is-plain-object "^2.0.3"
+ split-string "^3.0.1"
+
+setprototypeof@1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
+ integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==
+
+shelljs@^0.7.5:
+ version "0.7.8"
+ resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.8.tgz#decbcf874b0d1e5fb72e14b164a9683048e9acb3"
+ integrity sha1-3svPh0sNHl+3LhSxZKloMEjprLM=
+ dependencies:
+ glob "^7.0.0"
+ interpret "^1.0.0"
+ rechoir "^0.6.2"
+
+signal-exit@^3.0.0:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
+ integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=
+
+slice-ansi@0.0.4:
+ version "0.0.4"
+ resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35"
+ integrity sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=
+
+snapdragon-node@^2.0.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
+ integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==
+ dependencies:
+ define-property "^1.0.0"
+ isobject "^3.0.0"
+ snapdragon-util "^3.0.1"
+
+snapdragon-util@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2"
+ integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==
+ dependencies:
+ kind-of "^3.2.0"
+
+snapdragon@^0.8.1:
+ version "0.8.2"
+ resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d"
+ integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==
+ dependencies:
+ base "^0.11.1"
+ debug "^2.2.0"
+ define-property "^0.2.5"
+ extend-shallow "^2.0.1"
+ map-cache "^0.2.2"
+ source-map "^0.5.6"
+ source-map-resolve "^0.5.0"
+ use "^3.1.0"
+
+sort-keys@^1.0.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad"
+ integrity sha1-RBttTTRnmPG05J6JIK37oOVD+a0=
+ dependencies:
+ is-plain-obj "^1.0.0"
+
+source-map-resolve@^0.5.0:
+ version "0.5.2"
+ resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259"
+ integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==
+ dependencies:
+ atob "^2.1.1"
+ decode-uri-component "^0.2.0"
+ resolve-url "^0.2.1"
+ source-map-url "^0.4.0"
+ urix "^0.1.0"
+
+source-map-url@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
+ integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=
+
+source-map@^0.5.6:
+ version "0.5.7"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
+ integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
+
+sparkles@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.1.tgz#008db65edce6c50eec0c5e228e1945061dd0437c"
+ integrity sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==
+
+spdx-correct@^3.0.0:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9"
+ integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==
+ dependencies:
+ spdx-expression-parse "^3.0.0"
+ spdx-license-ids "^3.0.0"
+
+spdx-exceptions@^2.1.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d"
+ integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==
+
+spdx-expression-parse@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679"
+ integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==
+ dependencies:
+ spdx-exceptions "^2.1.0"
+ spdx-license-ids "^3.0.0"
+
+spdx-license-ids@^3.0.0:
+ version "3.0.6"
+ resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz#c80757383c28abf7296744998cbc106ae8b854ce"
+ integrity sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw==
+
+split-string@^3.0.1, split-string@^3.0.2:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
+ integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==
+ dependencies:
+ extend-shallow "^3.0.0"
+
+split@0.3:
+ version "0.3.3"
+ resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f"
+ integrity sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=
+ dependencies:
+ through "2"
+
+sprintf-js@~1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
+ integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
+
+stack-trace@0.0.10:
+ version "0.0.10"
+ resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0"
+ integrity sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=
+
+static-extend@^0.1.1:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
+ integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=
+ dependencies:
+ define-property "^0.2.5"
+ object-copy "^0.1.0"
+
+"statuses@>= 1.4.0 < 2":
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
+ integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
+
+statuses@~1.3.1:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e"
+ integrity sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=
+
+statuses@~1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087"
+ integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==
+
+stream-combiner@~0.0.4:
+ version "0.0.4"
+ resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14"
+ integrity sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=
+ dependencies:
+ duplexer "~0.1.1"
+
+stream-exhaust@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/stream-exhaust/-/stream-exhaust-1.0.2.tgz#acdac8da59ef2bc1e17a2c0ccf6c320d120e555d"
+ integrity sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==
+
+stream-shift@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d"
+ integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==
+
+strict-uri-encode@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
+ integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=
+
+string-width@^1.0.1, string-width@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
+ integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=
+ dependencies:
+ code-point-at "^1.0.0"
+ is-fullwidth-code-point "^1.0.0"
+ strip-ansi "^3.0.0"
+
+"string-width@^1.0.2 || 2", string-width@^2.0.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
+ integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
+ dependencies:
+ is-fullwidth-code-point "^2.0.0"
+ strip-ansi "^4.0.0"
+
+string.prototype.trimend@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913"
+ integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==
+ dependencies:
+ define-properties "^1.1.3"
+ es-abstract "^1.17.5"
+
+string.prototype.trimstart@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54"
+ integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==
+ dependencies:
+ define-properties "^1.1.3"
+ es-abstract "^1.17.5"
+
+string_decoder@~0.10.x:
+ version "0.10.31"
+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
+ integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=
+
+string_decoder@~1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
+ integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
+ dependencies:
+ safe-buffer "~5.1.0"
+
+strip-ansi@^3.0.0, strip-ansi@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
+ integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=
+ dependencies:
+ ansi-regex "^2.0.0"
+
+strip-ansi@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
+ integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8=
+ dependencies:
+ ansi-regex "^3.0.0"
+
+strip-bom@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
+ integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=
+ dependencies:
+ is-utf8 "^0.2.0"
+
+strip-bom@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
+ integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=
+
+strip-json-comments@~2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
+ integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
+
+strip-outer@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/strip-outer/-/strip-outer-1.0.1.tgz#b2fd2abf6604b9d1e6013057195df836b8a9d631"
+ integrity sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==
+ dependencies:
+ escape-string-regexp "^1.0.2"
+
+strip-url-auth@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/strip-url-auth/-/strip-url-auth-1.0.1.tgz#22b0fa3a41385b33be3f331551bbb837fa0cd7ae"
+ integrity sha1-IrD6OkE4WzO+PzMVUbu4N/oM164=
+
+supports-color@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
+ integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=
+
+sver-compat@^1.5.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/sver-compat/-/sver-compat-1.5.0.tgz#3cf87dfeb4d07b4a3f14827bc186b3fd0c645cd8"
+ integrity sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg=
+ dependencies:
+ es6-iterator "^2.0.1"
+ es6-symbol "^3.1.1"
+
+table@^3.7.8:
+ version "3.8.3"
+ resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f"
+ integrity sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=
+ dependencies:
+ ajv "^4.7.0"
+ ajv-keywords "^1.0.0"
+ chalk "^1.1.1"
+ lodash "^4.0.0"
+ slice-ansi "0.0.4"
+ string-width "^2.0.0"
+
+taffydb@2.6.2:
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/taffydb/-/taffydb-2.6.2.tgz#7cbcb64b5a141b6a2efc2c5d2c67b4e150b2a268"
+ integrity sha1-fLy2S1oUG2ou/CxdLGe04VCyomg=
+
+tar@^4:
+ version "4.4.19"
+ resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.19.tgz#2e4d7263df26f2b914dee10c825ab132123742f3"
+ integrity sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==
+ dependencies:
+ chownr "^1.1.4"
+ fs-minipass "^1.2.7"
+ minipass "^2.9.0"
+ minizlib "^1.3.3"
+ mkdirp "^0.5.5"
+ safe-buffer "^5.2.1"
+ yallist "^3.1.1"
+
+text-table@~0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
+ integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
+
+through2-filter@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-3.0.0.tgz#700e786df2367c2c88cd8aa5be4cf9c1e7831254"
+ integrity sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==
+ dependencies:
+ through2 "~2.0.0"
+ xtend "~4.0.0"
+
+through2@^2.0.0, through2@^2.0.3, through2@~2.0.0:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd"
+ integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==
+ dependencies:
+ readable-stream "~2.3.6"
+ xtend "~4.0.1"
+
+through@2, through@^2.3.6, through@~2.3, through@~2.3.1:
+ version "2.3.8"
+ resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
+ integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
+
+time-stamp@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3"
+ integrity sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=
+
+to-absolute-glob@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz#1865f43d9e74b0822db9f145b78cff7d0f7c849b"
+ integrity sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=
+ dependencies:
+ is-absolute "^1.0.0"
+ is-negated-glob "^1.0.0"
+
+to-object-path@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af"
+ integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=
+ dependencies:
+ kind-of "^3.0.2"
+
+to-regex-range@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38"
+ integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=
+ dependencies:
+ is-number "^3.0.0"
+ repeat-string "^1.6.1"
+
+to-regex@^3.0.1, to-regex@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce"
+ integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==
+ dependencies:
+ define-property "^2.0.2"
+ extend-shallow "^3.0.2"
+ regex-not "^1.0.2"
+ safe-regex "^1.1.0"
+
+to-through@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/to-through/-/to-through-2.0.0.tgz#fc92adaba072647bc0b67d6b03664aa195093af6"
+ integrity sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=
+ dependencies:
+ through2 "^2.0.3"
+
+trim-repeated@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/trim-repeated/-/trim-repeated-1.0.0.tgz#e3646a2ea4e891312bf7eace6cfb05380bc01c21"
+ integrity sha1-42RqLqTokTEr9+rObPsFOAvAHCE=
+ dependencies:
+ escape-string-regexp "^1.0.2"
+
+type-check@~0.3.2:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
+ integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=
+ dependencies:
+ prelude-ls "~1.1.2"
+
+typedarray@^0.0.6:
+ version "0.0.6"
+ resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
+ integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
+
+unc-path-regex@^0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa"
+ integrity sha1-5z3T17DXxe2G+6xrCufYxqadUPo=
+
+underscore-contrib@~0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/underscore-contrib/-/underscore-contrib-0.3.0.tgz#665b66c24783f8fa2b18c9f8cbb0e2c7d48c26c7"
+ integrity sha1-ZltmwkeD+PorGMn4y7Dix9SMJsc=
+ dependencies:
+ underscore "1.6.0"
+
+underscore@1.6.0, underscore@~1.6.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.6.0.tgz#8b38b10cacdef63337b8b24e4ff86d45aea529a8"
+ integrity sha1-izixDKze9jM3uLJOT/htRa6lKag=
+
+underscore@~1.8.3:
+ version "1.8.3"
+ resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022"
+ integrity sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=
+
+undertaker-registry@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/undertaker-registry/-/undertaker-registry-1.0.1.tgz#5e4bda308e4a8a2ae584f9b9a4359a499825cc50"
+ integrity sha1-XkvaMI5KiirlhPm5pDWaSZglzFA=
+
+undertaker@^1.2.1:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/undertaker/-/undertaker-1.3.0.tgz#363a6e541f27954d5791d6fa3c1d321666f86d18"
+ integrity sha512-/RXwi5m/Mu3H6IHQGww3GNt1PNXlbeCuclF2QYR14L/2CHPz3DFZkvB5hZ0N/QUkiXWCACML2jXViIQEQc2MLg==
+ dependencies:
+ arr-flatten "^1.0.1"
+ arr-map "^2.0.0"
+ bach "^1.0.0"
+ collection-map "^1.0.0"
+ es6-weak-map "^2.0.1"
+ fast-levenshtein "^1.0.0"
+ last-run "^1.1.0"
+ object.defaults "^1.0.0"
+ object.reduce "^1.0.0"
+ undertaker-registry "^1.0.0"
+
+union-value@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4"
+ integrity sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=
+ dependencies:
+ arr-union "^3.1.0"
+ get-value "^2.0.6"
+ is-extendable "^0.1.1"
+ set-value "^0.4.3"
+
+unique-stream@^2.0.2:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/unique-stream/-/unique-stream-2.3.1.tgz#c65d110e9a4adf9a6c5948b28053d9a8d04cbeac"
+ integrity sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==
+ dependencies:
+ json-stable-stringify-without-jsonify "^1.0.1"
+ through2-filter "^3.0.0"
+
+universalify@^0.1.0:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
+ integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
+
+unix-crypt-td-js@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/unix-crypt-td-js/-/unix-crypt-td-js-1.0.0.tgz#1c0824150481bc7a01d49e98f1ec668d82412f3b"
+ integrity sha1-HAgkFQSBvHoB1J6Y8exmjYJBLzs=
+
+unpipe@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
+ integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=
+
+unset-value@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559"
+ integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=
+ dependencies:
+ has-value "^0.3.1"
+ isobject "^3.0.0"
+
+upath@^1.1.1:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.2.tgz#3db658600edaeeccbe6db5e684d67ee8c2acd068"
+ integrity sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==
+
+urix@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
+ integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=
+
+use@^3.1.0:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
+ integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==
+
+user-home@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f"
+ integrity sha1-nHC/2Babwdy/SGBODwS4tJzenp8=
+ dependencies:
+ os-homedir "^1.0.0"
+
+util-deprecate@~1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+ integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
+
+utils-merge@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
+ integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
+
+uuid@^3.0.0:
+ version "3.3.2"
+ resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
+ integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==
+
+v8flags@^3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-3.2.0.tgz#b243e3b4dfd731fa774e7492128109a0fe66d656"
+ integrity sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==
+ dependencies:
+ homedir-polyfill "^1.0.1"
+
+validate-npm-package-license@^3.0.1:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
+ integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==
+ dependencies:
+ spdx-correct "^3.0.0"
+ spdx-expression-parse "^3.0.0"
+
+value-or-function@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/value-or-function/-/value-or-function-3.0.0.tgz#1c243a50b595c1be54a754bfece8563b9ff8d813"
+ integrity sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=
+
+vary@^1:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
+ integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
+
+vinyl-fs@^3.0.0:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-3.0.3.tgz#c85849405f67428feabbbd5c5dbdd64f47d31bc7"
+ integrity sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==
+ dependencies:
+ fs-mkdirp-stream "^1.0.0"
+ glob-stream "^6.1.0"
+ graceful-fs "^4.0.0"
+ is-valid-glob "^1.0.0"
+ lazystream "^1.0.0"
+ lead "^1.0.0"
+ object.assign "^4.0.4"
+ pumpify "^1.3.5"
+ readable-stream "^2.3.3"
+ remove-bom-buffer "^3.0.0"
+ remove-bom-stream "^1.2.0"
+ resolve-options "^1.1.0"
+ through2 "^2.0.0"
+ to-through "^2.0.0"
+ value-or-function "^3.0.0"
+ vinyl "^2.0.0"
+ vinyl-sourcemap "^1.1.0"
+
+vinyl-sourcemap@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz#92a800593a38703a8cdb11d8b300ad4be63b3e16"
+ integrity sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=
+ dependencies:
+ append-buffer "^1.0.2"
+ convert-source-map "^1.5.0"
+ graceful-fs "^4.1.6"
+ normalize-path "^2.1.1"
+ now-and-later "^2.0.0"
+ remove-bom-buffer "^3.0.0"
+ vinyl "^2.0.0"
+
+vinyl@^0.5.0:
+ version "0.5.3"
+ resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.5.3.tgz#b0455b38fc5e0cf30d4325132e461970c2091cde"
+ integrity sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=
+ dependencies:
+ clone "^1.0.0"
+ clone-stats "^0.0.1"
+ replace-ext "0.0.1"
+
+vinyl@^2.0.0:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.2.1.tgz#23cfb8bbab5ece3803aa2c0a1eb28af7cbba1974"
+ integrity sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==
+ dependencies:
+ clone "^2.1.1"
+ clone-buffer "^1.0.0"
+ clone-stats "^1.0.0"
+ cloneable-readable "^1.0.0"
+ remove-trailing-separator "^1.0.1"
+ replace-ext "^1.0.0"
+
+websocket-driver@>=0.5.1:
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.0.tgz#0caf9d2d755d93aee049d4bdd0d3fe2cca2a24eb"
+ integrity sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=
+ dependencies:
+ http-parser-js ">=0.4.0"
+ websocket-extensions ">=0.1.1"
+
+websocket-extensions@>=0.1.1:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42"
+ integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==
+
+which-module@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
+ integrity sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=
+
+which@^1.2.14:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
+ integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
+ dependencies:
+ isexe "^2.0.0"
+
+wide-align@^1.1.0:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"
+ integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==
+ dependencies:
+ string-width "^1.0.2 || 2"
+
+wordwrap@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
+ integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=
+
+wrap-ansi@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
+ integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=
+ dependencies:
+ string-width "^1.0.1"
+ strip-ansi "^3.0.1"
+
+wrappy@1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+ integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
+
+write@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757"
+ integrity sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=
+ dependencies:
+ mkdirp "^0.5.1"
+
+xmlcreate@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/xmlcreate/-/xmlcreate-1.0.2.tgz#fa6bf762a60a413fb3dd8f4b03c5b269238d308f"
+ integrity sha1-+mv3YqYKQT+z3Y9LA8WyaSONMI8=
+
+xtend@^4.0.0, xtend@~4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
+ integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68=
+
+xtend@~4.0.0:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
+ integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
+
+y18n@^3.2.1:
+ version "3.2.2"
+ resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.2.tgz#85c901bd6470ce71fc4bb723ad209b70f7f28696"
+ integrity sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==
+
+yallist@^3.0.0, yallist@^3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
+ integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
+
+yargs-parser@5.0.0-security.0:
+ version "5.0.0-security.0"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0-security.0.tgz#4ff7271d25f90ac15643b86076a2ab499ec9ee24"
+ integrity sha512-T69y4Ps64LNesYxeYGYPvfoMTt/7y1XtfpIslUeK4um+9Hu7hlGoRtaDLvdXb7+/tfq4opVa2HRY5xGip022rQ==
+ dependencies:
+ camelcase "^3.0.0"
+ object.assign "^4.1.0"
+
+yargs@^7.1.0:
+ version "7.1.1"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.1.tgz#67f0ef52e228d4ee0d6311acede8850f53464df6"
+ integrity sha512-huO4Fr1f9PmiJJdll5kwoS2e4GqzGSsMT3PPMpOwoVkOK8ckqAewMTZyA6LXVQWflleb/Z8oPBEvNsMft0XE+g==
+ dependencies:
+ camelcase "^3.0.0"
+ cliui "^3.2.0"
+ decamelize "^1.1.1"
+ get-caller-file "^1.0.1"
+ os-locale "^1.4.0"
+ read-pkg-up "^1.0.1"
+ require-directory "^2.1.1"
+ require-main-filename "^1.0.1"
+ set-blocking "^2.0.0"
+ string-width "^1.0.2"
+ which-module "^1.0.0"
+ y18n "^3.2.1"
+ yargs-parser "5.0.0-security.0"