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 d2d76109..945b4238 100644 --- a/readme.md +++ b/readme.md @@ -1,24 +1,95 @@ -## Note +## About -Note that not all algorithms are well tested so bugs are quite possible. +This repository contains JavaScript implementations of famous computer science algorithms. -## About +API reference with usage examples available +here. + +## Development + +**To install all dev dependencies** + +Call: + +```bash +npm install +``` + +**To setup repository with documentation** -This repository contains different famous Computer Science algorithms implemented in JavaScript +```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. -In order to run the tests use: +**To run tests** -```Bash -jasmine-node test/ +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 + +[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) | +:---: |:---: |:---: |:---: |:---: |:---: | +[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) | + +[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) | +:---: |:---: |:---: |:---: |:---: |:---: | +[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) | + +[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) | +:---: |:---: |:---: |:---: |:---: |:---: | +[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) | + +[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) | +:---: |:---: |:---: |:---: |:---: |:---: | +[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) | + +[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) | +:---: |:---: |:---: |:---: |:---: |:---: | +[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) | + +[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) | +:---: |:---: |:---: |:---: |:---: |:---: | +[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) | + +[fanixk](https://github.com/fanixk) |[wlx199x](https://github.com/wlx199x) |[shaunak1111](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 index 74024f41..a1940f32 100644 --- a/src/combinatorics/cartesianproduct.js +++ b/src/combinatorics/cartesianproduct.js @@ -14,6 +14,29 @@ } } + /** + * 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, []); @@ -23,4 +46,4 @@ exports.cartesianProduct = cartesianProduct; -}(typeof exports === 'undefined' ? window : exports)); +}((typeof window === 'undefined') ? module.exports : window)); diff --git a/src/combinatorics/combinations.js b/src/combinatorics/combinations.js index fbd5fa3f..9f72d17e 100644 --- a/src/combinatorics/combinations.js +++ b/src/combinatorics/combinations.js @@ -15,6 +15,30 @@ } } + /** + * 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, []); @@ -27,4 +51,4 @@ exports.combinations = combinations; -}(typeof exports === 'undefined' ? window : exports)); +}((typeof window === 'undefined') ? module.exports : window)); diff --git a/src/combinatorics/permutations.js b/src/combinatorics/permutations.js index 4430e33a..0ab94b77 100644 --- a/src/combinatorics/permutations.js +++ b/src/combinatorics/permutations.js @@ -10,14 +10,6 @@ arr[j] = temp; } - /** - * Finds all the permutations of given array. - * Complexity O(n*n!). - * - * @param {Array} arr Array to find the permutations of - * @param {Number} current Current element - * @returns {Array} Array containing all the permutations - */ function permutations(arr, current) { if (current >= arr.length) { return res.push(arr.slice()); @@ -29,6 +21,33 @@ } } + /** + * 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); @@ -41,4 +60,4 @@ exports.permutations = permutations; -}(typeof exports === 'undefined' ? window : exports)); +}((typeof window === 'undefined') ? module.exports : window)); diff --git a/src/combinatorics/variations-repetion.js b/src/combinatorics/variations-repetion.js deleted file mode 100644 index d9eb4984..00000000 --- a/src/combinatorics/variations-repetion.js +++ /dev/null @@ -1,28 +0,0 @@ -(function (exports) { - 'use strict'; - - var variationsWithRepetion = (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); - } - } - - return function (arr, k) { - res = []; - variations(arr, k, 0, []); - var temp = res; - res = undefined; - return temp; - }; - }()); - - exports.variationsWithRepetion = variationsWithRepetion; - -}(typeof exports === 'undefined' ? window : exports)); 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 fa9e7532..f5cebb37 100644 --- a/src/compression/runlength/runlength.js +++ b/src/compression/runlength/runlength.js @@ -10,23 +10,19 @@ var runLengthEncoding = (function () { /** - * Convers a given string to sequence of numbers + * Converts a given string to sequence of numbers * This takes O(n). */ function convertToAscii(str) { - var result = '', - currentChar = '', - i = 0; + var result = []; + var currentChar = ''; + var 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; - } - } - result += currentChar; + currentChar = new Array(9 - currentChar.length).join('0') + currentChar; + result.push(currentChar); } - return result; + return result.join(''); } /** @@ -34,26 +30,21 @@ * Takes O(n^2). */ function runLength(vector) { - var result = '', - zeros = 0, - zerosTemp = '', - wordLength = 0, - i = 0; + 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); - wordLength = zerosTemp.length - 1; - while (wordLength) { - result = result + '1'; - wordLength -= 1; - } - result += '0' + zerosTemp; + result.push(new Array(zerosTemp.length).join('1')); + result.push('0' + zerosTemp); zeros = 0; } } - return result; + return result.join(''); } /** @@ -70,4 +61,4 @@ exports.runLength = runLengthEncoding; -}(typeof exports === 'undefined' ? window : exports)); \ 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 b15f3b46..cf059a27 100644 --- a/src/data-structures/binary-search-tree.js +++ b/src/data-structures/binary-search-tree.js @@ -1,191 +1,238 @@ +/** + * Binary search tree. + * + * @example + * var BST = require('path-to-algorithms/src/data-structures'+ + * '/binary-search-tree'); + * var bst = new BST.BinaryTree(); + * + * bst.insert(2000); + * bst.insert(1989); + * bst.insert(1991); + * bst.insert(2001); + * bst.insert(1966); + * + * var node = bst.find(1989); + * console.log(node.value); // 1989 + * + * var minNode = bst.findMin(); + * console.log(minNode.value); // 1966 + * + * var maxNode = bst.findMax(); + * console.log(maxNode.value); //2001 + * + * @module data-structures/binary-search-tree + */ (function (exports) { 'use strict'; /** - * Implementation of binary search tree. - */ - - /** - * A node of the tree + * Node of the tree. * * @public * @constructor - * @param {number|string} Value of the node - * @param {Node} Left subling - * @param {Node} Right sibling - * @param {Node} Parent of the node + * @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. */ - function Node(value, left, right, parent) { + exports.Node = function (value, left, right, parent) { + /** + * @member {Number|String} + */ this.value = value; this._left = left; this._right = right; this._parent = parent; - } + }; /** - * Defines the binary tree + * Binary tree. * * @public * @constructor */ - function BinaryTree() { + exports.BinaryTree = function () { 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. + * 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 - * @param {number|string} Value - * @param {[Node]} Current node + * @method + * @param {Number|String} value Node value. + * @param {Node} current Current node. */ - BinaryTree.prototype.insert = function (value, current) { + exports.BinaryTree.prototype.insert = function (value, current) { if (this._root === null) { - this._root = new Node(value, null, null, null); + this._root = new exports.Node(value, null, null, null); return; } var insertKey; current = current || this._root; - if (current.value > value) + if (current.value > value) { insertKey = '_left'; - else + } else { insertKey = '_right'; - if (!current[insertKey]) - current[insertKey] = new Node(value, null, null, current); - else + } + if (!current[insertKey]) { + current[insertKey] = new exports.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. + * In-order traversal from the given node. * * @private - * @param {Node} Node from which to start the traversal - * @param {Function} Callback which will be called for each traversed node + * @param {Node} current Node from which to start the traversal. + * @param {Function} callback Callback which + * will be called for each traversed node. */ - BinaryTree.prototype._inorder = function (current, callback) { - if (!current) + exports.BinaryTree.prototype._inorder = function (current, callback) { + if (!current) { return; + } this._inorder(current._left, callback); - if (typeof callback === 'function') + if (typeof callback === 'function') { callback(current); + } this._inorder(current._right, callback); }; /** - * Inorder traversal of the whole binary search tree + * In-order traversal of the whole binary search tree. * * @public - * @param {Function} Callback which will be called for each traversed node + * @method + * @param {Function} callback Callback which will be + * called for each traversed node. */ - BinaryTree.prototype.inorder = function (callback) { + exports.BinaryTree.prototype.inorder = function (callback) { return this._inorder(this._root, callback); }; /** - * Post-order traversal from given node + * Post-order traversal from given node. * * @private - * @param {Node} Node from which to start the traversal - * @param {Function} Callback which will be called for each traversed node + * @param {Node} current Node from which to start the traversal. + * @param {Function} callback Callback which will + * be called for each traversed node */ - BinaryTree.prototype._postorder = function (current, callback) { - if (!current) + exports.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); + if (typeof callback === 'function') { + callback(current); + } }; /** - * Post-order traversal of the whole tree + * Post-order traversal of the whole tree. * * @public - * @param {Function} Callback which will be called for each traversed node + * @param {Function} callback Callback which + * will be called for each traversed node. */ - BinaryTree.prototype.postorder = function (callback) { + exports.BinaryTree.prototype.postorder = function (callback) { return this._postorder(this._root, callback); }; /** - * Pre-order traversal of the tree from given node + * 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 + * @param {Node} current Node from which to start the traversal. + * @param {Function} callback Callback which + * will be called for each traversed node. */ - BinaryTree.prototype._preorder = function (current, callback) { - if (!current) + exports.BinaryTree.prototype._preorder = function (current, callback) { + if (!current) { return; - if (typeof callback === 'function') + } + if (typeof callback === 'function') { callback(current); + } this._preorder(current._left, callback); this._preorder(current._right, callback); }; /** - * Pre-order preorder traversal of the whole tree - * + * Pre-order preorder traversal of the whole tree. + * * @public - * @param {Function} Callback which will be called for each traversed node + * @param {Function} callback Callback which will + * be called for each traversed node. */ - BinaryTree.prototype.preorder = function (callback) { + exports.BinaryTree.prototype.preorder = function (callback) { return this._preorder(this._root, callback); }; /** - * Finds a node by it's value. Average runtime complexity O(log n) + * 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 + * @param {Number|String} value of the node which should be found. */ - BinaryTree.prototype.find = function (value) { + exports.BinaryTree.prototype.find = function (value) { return this._find(value, this._root); }; /** - * Finds a node by it's value in given sub-tree. Average runtime complexity: O(log n). + * 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 + * @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) + exports.BinaryTree.prototype._find = function (value, current) { + if (!current) { return null; - - if (current.value === value) + } + + if (current.value === value) { return current; - - if (current.value > value) + } + + if (current.value > value) { return this._find(value, current._left); - - if (current.value < value) + } + + if (current.value < value) { return this._find(value, current._right); - + } }; /** - * Replaces given child with new one, for given parent + * Replaces given child with new one, for given parent. * * @private - * @param {Node} Parent node - * @param {Node} Child to be replaced - * @param {Node} Child replacement + * @param {Node} parent Parent node. + * @param {Node} oldChild Child to be replaced. + * @param {Node} newChild Child replacement. */ - BinaryTree.prototype._replaceChild = function (parent, oldChild, newChild) { + exports.BinaryTree.prototype._replaceChild = function (parent, oldChild, newChild) { if (!parent) { this._root = newChild; - this._root._parent = null; + if (this._root !== null){ + this._root._parent = null; + } } else { - - if (parent._left === oldChild) + if (parent._left === oldChild) { parent._left = newChild; - else + } else { parent._right = newChild; - + } if (newChild) { newChild._parent = parent; } @@ -193,91 +240,103 @@ }; /** - * Removes node from the tree. Average runtime complexity: O(log n). + * 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 + * @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) + exports.BinaryTree.prototype.remove = function (node) { + if (!node) { return false; - + } if (node._left && node._right) { - var min = this._findMin(node._right), - temp = node.value; - + 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) + if (node._left) { this._replaceChild(node._parent, node, node._left); - else if (node._right) + } else if (node._right) { this._replaceChild(node._parent, node, node._right); - else + } else { this._replaceChild(node._parent, node, null); + } return true; } }; /** - * Finds the node with minimum value in given sub-tree + * 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 + * @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. */ - BinaryTree.prototype._findMin = function (node, current) { + exports.BinaryTree.prototype._findMin = function (node, current) { current = current || { value: Infinity }; - if (!node) + if (!node) { return current; - if (current.value > node.value) + } + if (current.value > node.value) { current = node; + } return this._findMin(node._left, current); }; /** - * Finds the node with maximum value in given sub-tree + * 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 + * @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. */ - BinaryTree.prototype._findMax = function (node, current) { + exports.BinaryTree.prototype._findMax = function (node, current) { current = current || { value: -Infinity }; - if (!node) + if (!node) { return current; - if (current.value < node.value) + } + if (current.value < node.value) { current = node; + } return this._findMax(node._right, current); }; /** - * Finds the node with minimum value in the whole tree + * Finds the node with minimum value in the whole tree. * * @public - * @returns {Node} The minimum node of the tree + * @returns {Node} The minimum node of the tree. */ - BinaryTree.prototype.findMin = function () { + exports.BinaryTree.prototype.findMin = function () { return this._findMin(this._root); }; /** - * Finds the maximum node of the tree + * Finds the node with maximum value in the whole tree. * * @public - * @returns {Node} The maximum node of the tree + * @returns {Node} The maximum node of the tree. * */ - BinaryTree.prototype.findMax = function () { + exports.BinaryTree.prototype.findMax = function () { return this._findMax(this._root); }; - - BinaryTree.prototype._isBalanced = function (current) { + /** + * 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; } @@ -288,66 +347,89 @@ }; /** - * Returns whether the BST is balanced + * Returns whether the BST is balanced. * * @public - * @returns {Boolean} Whether the tree is balanced or not + * @returns {Boolean} Whether the tree is balanced or not. */ - BinaryTree.prototype.isBalanced = function () { + exports.BinaryTree.prototype.isBalanced = function () { return this._isBalanced(this._root); }; /** - * Finds the diameter of the binary tree + * Finds the diameter of the binary tree. * * @public - * @returns {Number} The longest path in the BST + * @returns {Number} The longest path in the BST. */ - BinaryTree.prototype.getDiameter = function () { + exports.BinaryTree.prototype.getDiameter = function () { var getDiameter = function (root) { if (!root) { return 0; } - var leftHeight = this._getHeight(root._left), - rightHeight = this._getHeight(root._right), - path = leftHeight + rightHeight + 1; + 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 + * Returns the height of the tree. * * @public - * @returns {Number} The height of the tree + * @returns {Number} The height of the tree. */ - BinaryTree.prototype.getHeight = function () { + exports.BinaryTree.prototype.getHeight = function () { return this._getHeight(this._root); }; - BinaryTree.prototype._getHeight = function (node) { + /** + * 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)); + 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 + * @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. */ - BinaryTree.prototype.lowestCommonAncestor = function (firstNode, secondNode, current) { + exports.BinaryTree.prototype.lowestCommonAncestor = function (firstNode, secondNode) { return this._lowestCommonAncestor(firstNode, secondNode, this._root); }; - BinaryTree.prototype._lowestCommonAncestor = function (firstNode, secondNode, current) { - var firstNodeInLeft = this._existsInSubtree(firstNode, current._left), - secondNodeInLeft = this._existsInSubtree(secondNode, current._left), - firstNodeInRight = this._existsInSubtree(firstNode, current._right), - secondNodeInRight = this._existsInSubtree(secondNode, current._right); + /** + * 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; @@ -361,17 +443,23 @@ return null; }; - BinaryTree.prototype._existsInSubtree = function (node, root) { + /** + * 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 === root.value) { + if (node.value === root.value) { return true; } - return this._existsInSubtree(node, root._left) || this._existsInSubtree(node, root._right); + return this._existsInSubtree(node, root._left) || + this._existsInSubtree(node, root._right); }; - exports.BinaryTree = BinaryTree; - exports.Node = Node; - -}(typeof exports === 'undefined' ? window : exports)); +})(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 44146d5a..cb936575 100644 --- a/src/data-structures/heap.js +++ b/src/data-structures/heap.js @@ -1,13 +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; @@ -16,22 +58,23 @@ 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) { @@ -39,7 +82,8 @@ } if (right < this._heap.length && - this._cmp(this._heap[right], this._heap[index]) > 0) { + this._cmp(this._heap[right], this._heap[index]) > 0 && + this._cmp(this._heap[right], this._heap[left]) > 0) { extr = right; } @@ -52,18 +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) { + exports.Heap.prototype.changeKey = function (index, value) { this._heap[index] = value; - var elem = this._heap[index], - parent = Math.floor(index / 2), - temp; + 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]; @@ -72,16 +117,20 @@ index = parent; parent = Math.floor(parent / 2); } + this._heapify(index); } return parent; }; /** - * Updates given node. This operation is useful + * Updates a given node. This operation is useful * in algorithms like Dijkstra, A* where we need - * to decrease/increase the value of givne node. + * to decrease/increase value of the given node. + * + * @public + * @param {Number|Object} node Node which should be updated. */ - Heap.prototype.update = function (node) { + exports.Heap.prototype.update = function (node) { var idx = this._heap.indexOf(node); if (idx >= 0) { this.changeKey(idx, node); @@ -89,53 +138,58 @@ }; /** - * Adds new element to the heap. Complexity O(log n). + * Adds new element to the heap.

+ * Complexity: O(log N). * * @public - * @param {number} value The new value which will be inserted - * @returns {number} The index of the inserted value + * @param {Number|Object} value Value which will be inserted. + * @return {Number} Index of the inserted value. */ - Heap.prototype.add = function (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). + * 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 () { + 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.getCollection = function () { + exports.Heap.prototype.getCollection = function () { return this._heap; }; - Heap.prototype.isEmpty = function () { + /** + * Checks or heap is empty. + * + * @public + * @returns {Boolean} Returns true if heap is empty. + */ + exports.Heap.prototype.isEmpty = function () { return !this._heap.length; }; - exports.Heap = Heap; - -}(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 index 249daff9..24663c98 100644 --- a/src/data-structures/interval-tree.js +++ b/src/data-structures/interval-tree.js @@ -1,20 +1,82 @@ +/** + * 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'; - function Node(start, end, left, right) { + /** + * 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; - } + }; - function IntervalTree() { + /** + * 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 Node(interval[0], interval[1]); + var child = new exports.Node(interval[0], interval[1]); + child.max = interval[1]; child.parentNode = node; node[side] = child; if (node.max < interval[1]) { @@ -43,9 +105,16 @@ } } - IntervalTree.prototype.add = function (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 Node(interval[0], interval[1]); + this.root = new exports.Node(interval[0], interval[1]); + this.root.max = interval[1]; return; } addHelper(this.root, interval); @@ -58,7 +127,8 @@ if (node.interval[0] <= point && node.interval[1] >= point) { return true; } - var result = false, temp; + var result = false; + var temp; ['left', 'right'].forEach(function (key) { temp = node[key]; if (temp) { @@ -70,10 +140,24 @@ return result; } - IntervalTree.prototype.contains = function (point) { + /** + * 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; @@ -81,7 +165,8 @@ if (intersects(node.interval, interval)) { return true; } - var result = false, temp; + var result = false; + var temp; ['left', 'right'].forEach(function (side) { temp = node[side]; if (temp && temp.max >= interval[0]) { @@ -91,12 +176,16 @@ return result; } - 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]); - } - - IntervalTree.prototype.intersects = function (interval) { + /** + * 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); }; @@ -107,13 +196,30 @@ return 1 + Math.max(heightHelper(node.left), heightHelper(node.right)); } - IntervalTree.prototype.height = function () { + /** + * Returns height of the tree. + * + * @public + * @method + * @return {Number} Height of the tree. + */ + exports.IntervalTree.prototype.height = function () { return heightHelper(this.root); }; - IntervalTree.prototype.findMax = function (node) { - var stack = [node], - current, max = -Infinity, maxNode; + /** + * 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) { @@ -131,7 +237,7 @@ }; // adjust the max value - IntervalTree.prototype._removeHelper = function (interval, node) { + exports.IntervalTree.prototype._removeHelper = function (interval, node) { if (!node) { return; } @@ -174,8 +280,8 @@ // Adjust the max value var p = node.parentNode; if (p) { - var maxNode = this.findMax(p), - max = maxNode.interval[1]; + var maxNode = this.findMax(p); + var max = maxNode.interval[1]; while (maxNode) { if (maxNode.max === node.interval[1]) { maxNode.max = max; @@ -192,11 +298,15 @@ } }; - IntervalTree.prototype.remove = function (interval) { + /** + * 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); }; - exports.Node = Node; - exports.IntervalTree = IntervalTree; - -}(typeof exports === 'undefined' ? window : exports)); +})(typeof window === 'undefined' ? module.exports : window); diff --git a/src/data-structures/linked-list.js b/src/data-structures/linked-list.js index fdf208ba..9027f16e 100644 --- a/src/data-structures/linked-list.js +++ b/src/data-structures/linked-list.js @@ -1,19 +1,87 @@ +/** + * 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'; - function Node(data) { + /** + * 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; - } + }; - function LinkedList() { + /** + * Linked list. + * + * @public + * @constructor + */ + exports.LinkedList = function () { this.first = null; this.last = null; - } + }; - LinkedList.prototype.push = function (data) { - var node = new Node(data); + /** + * 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 { @@ -24,8 +92,15 @@ } }; - LinkedList.prototype.unshift = function (data) { - var node = new Node(data); + /** + * 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 { @@ -36,7 +111,14 @@ } }; - LinkedList.prototype.inorder = function (cb) { + /** + * 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); @@ -44,14 +126,24 @@ } }; - LinkedList.prototype.remove = function (data) { + /** + * 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, - next, prev; + var temp = this.first; + var next; + var prev; while (temp) { - if (temp.data === data) { + var dataFound = equals ? equals(temp.data, data) : temp.data === data; + if (dataFound) { next = temp.next; prev = temp.prev; if (next) { @@ -73,9 +165,16 @@ return false; }; - LinkedList.prototype.hasCycle = function () { - var fast = this.first, - slow = this.first; + /** + * 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; @@ -92,7 +191,14 @@ } }; - LinkedList.prototype.pop = function () { + /** + * Return last node from the linked list. + * + * @public + * @method + * @return {Node} Last node. + */ + exports.LinkedList.prototype.pop = function () { if (this.last === null) { return null; } @@ -101,7 +207,14 @@ return temp; }; - LinkedList.prototype.shift = function () { + /** + * Return first node from the linked list. + * + * @public + * @method + * @return {Node} First node. + */ + exports.LinkedList.prototype.shift = function () { if (this.first === null) { return null; } @@ -110,13 +223,20 @@ return temp; }; - LinkedList.prototype.recursiveReverse = function () { + /** + * 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; } @@ -124,33 +244,36 @@ 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; }; - LinkedList.prototype.reverse = function () { + /** + * Reverses the linked list iteratively + * + * @public + * @method + */ + exports.LinkedList.prototype.reverse = function () { if (!this.first || !this.first.next) { return; } - var current = this.first.next, - prev = this.first, - temp; - while (current) { - temp = current.next; - current.next = prev; - prev = current; - current = temp; - } - this.first.next = null; - temp = this.first; - this.first = prev; - this.last = temp; - }; + var current = this.first + var next - exports.LinkedList = LinkedList; - exports.Node = Node; + do { + next = current.next + current.next = current.prev + current.prev = next + current = next + } while (next) -}(typeof exports === 'undefined' ? window : exports)); + 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 index 663234d0..e6b917c4 100644 --- a/src/data-structures/suffix-tree.js +++ b/src/data-structures/suffix-tree.js @@ -1,6 +1,3 @@ -// TODO -// 1) The algorithm is quite ineffective, better use -// Ukkomen's algorithm to build it in O(n) complexity. (function (exports) { 'use strict'; @@ -44,9 +41,9 @@ // 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, - suffixSuffix = suffix.substr(prefix.length, suffix.length), - currentSuffix = temp.substr(prefix.length, temp.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); @@ -69,37 +66,7 @@ } }; - -// function isSubstr(tree, str) { -// if (!tree) { -// return false; -// } -// if (tree.nodes[str[0]]) { -// return isSubstr(tree, str.substr(1, str.length)); -// } -// var match = ''; -// for (var i = 0; i < Math.min(tree.value.length, str.length); i += 1) { -// if (tree.value[i] === str[i]) { -// match += str[i]; -// } else { -// break; -// } -// } -// if (match.length === str.length) { -// return true; -// } -// return false; -// } - - // var suffix = new SuffixTree(); - // suffix.build('banana'); - // console.log(suffix); - // - // var st = new SuffixTree(); - // st.build('Since these cases are very common use cases, the problem was easily solved by choosing either a random index for the pivot, choosing the middle index of the partition or (especially for longer partitions) choosing the median of the first, middle and last element of the partition for the pivot. With these modifications, the worst case of Quick sort has less chances to occur, but worst case can still occur if the input array is such that the maximum (or minimum) element is always chosen as pivot.'); - // console.log(JSON.stringify(st)); - exports.Node = Node; exports.SuffixTree = SuffixTree; -}(typeof exports === 'undefined' ? window : exports)); \ No newline at end of file +}(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 cd050ac0..73267f32 100644 --- a/src/graphics/bresenham-line-drawing.js +++ b/src/graphics/bresenham-line-drawing.js @@ -1,6 +1,15 @@ (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) @@ -8,17 +17,19 @@ * @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) { - 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; + 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) { - drawPoint(x1, y1); + drawPointStrategy(x1, y1); doubledError = error + error; if (doubledError > -dy) { error -= dy; @@ -31,15 +42,6 @@ } } - /** - * 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); - } - 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 index f0db1a36..f32ee48a 100644 --- a/src/graphs/others/topological-sort.js +++ b/src/graphs/others/topological-sort.js @@ -1,10 +1,6 @@ (function (exports) { 'use strict'; - /** - * Complexity O(|E|), where E is the set - * which contains all edges and |E| is their count. - */ var topologicalSort = (function () { function topologicalSortHelper(node, visited, temp, graph, result) { @@ -24,10 +20,33 @@ 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 = [], - visited = [], - temp = []; + var result = []; + var visited = []; + var temp = []; for (var node in graph) { if (!visited[node] && !temp[node]) { topologicalSortHelper(node, visited, temp, graph, result); @@ -40,4 +59,3 @@ exports.topologicalSort = topologicalSort; }(typeof exports === 'undefined' ? window : exports)); - diff --git a/src/graphs/searching/bfs.js b/src/graphs/searching/bfs.js index 8f037681..9b3e1cad 100644 --- a/src/graphs/searching/bfs.js +++ b/src/graphs/searching/bfs.js @@ -13,20 +13,32 @@ } /** - * Returns the shortest path between - * startNode and targetNode. - * Time complexity O(|V|*|V|), because we use adjust matrix. + * Breath-First graph searching algorithm. + * Returns the shortest path between startNode and targetNode.

+ * Time complexity: O(|V|^2). * - * @param {array} graph The adjust matrix, which represents the graph - * @param {number} startNode The start node - * @param {number} targetNode The target, which should be reached - * @returns {array} The shortest path from startNode to targetNode + * @public + * @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, startNode, targetNode) { - var parents = [], - queue = [], - visited = [], - current; + var parents = []; + var queue = []; + var visited = []; + var current; queue.push(startNode); parents[startNode] = null; visited[startNode] = true; 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/shortest-path/bellman-ford.js b/src/graphs/shortest-path/bellman-ford.js index b5d80939..d7fcf45b 100644 --- a/src/graphs/shortest-path/bellman-ford.js +++ b/src/graphs/shortest-path/bellman-ford.js @@ -1,57 +1,90 @@ -(function (global) { +/** + * 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'; - function Edge(u, v, weight) { - this.from = u; - this.to = v; - this.weight = weight; - } + exports.Vertex = require('../../data-structures/vertex').Vertex; + exports.Edge = require('../../data-structures/edge').Edge; - // Complexity O(|V||E|) - function bellmanFord(vertexes, edges, source) { - var distances = {}, parents = {}, c; - for (var i = 0; i < vertexes.length; i += 1) { - distances[vertexes[i]] = Infinity; - parents[vertexes[i]] = null; - } - distances[source] = 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] + c.weight < distances[c.to]) { - distances[c.to] = distances[c.from] + c.weight; - parents[c.to] = c.from; + /** + * 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] + c.weight < distances[c.to]) { - return undefined; + 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 }; - } - - global.Edge = Edge; - global.bellmanFord = bellmanFord; - -}((typeof window === 'undefined') ? global : window)); + }; -// var glob = (typeof window === 'undefined') ? global : window; -// var Edge = glob.Edge; -// var bellmanFord = glob.bellmanFord; -// var edges = []; -// var vertexes = [0, 1, 2, 3, 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)); -// -// console.log(bellmanFord(vertexes, edges, 0)); +})(typeof window === 'undefined' ? module.exports : window); diff --git a/src/graphs/shortest-path/dijkstra.js b/src/graphs/shortest-path/dijkstra.js index 37de6669..ea4a38e0 100644 --- a/src/graphs/shortest-path/dijkstra.js +++ b/src/graphs/shortest-path/dijkstra.js @@ -1,114 +1,124 @@ -/*********************************************** - A sample distance matrix - -var graph = [[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]]; -***********************************************/ - - -/** - * 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 () { +(function (exports) { 'use strict'; - var Heap = require('../../data-structures/heap.js').Heap, - current, - visited, - distance, - unvisited; + var dijkstra = (function () { + var Heap = require('../../data-structures/heap.js').Heap; + var current; + var visited; + var distance; + var unvisited; - /** - * Creates a new node instance - * - * @constructor - * @private - * @param {number} id The id of the node - * @param {number} distance The distance from the beginning - */ - function Node(id, distance) { - this.node = id; - this.distance = distance; - } + /** + * Creates a new node instance. + * + * @constructor + * @private + * @param {Number} id Id of the node. + * @param {Number} distance Distance from the beginning. + */ + function Node(id, 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 - */ - function compareNodesDistance(a, b) { - return b.distance - a.distance; - } + /** + * Compares the distances between two nodes. + * + * @private + * @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; + } - /** - * Initialize all variables used for the algorithm - * - * @private - * @param {number} src A start node - */ - 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; + /** + * Initialize all variables used for the algorithm. + * + * @private + * @param {number} src Start node. + * @param {Array} graph A distance matrix of the graph. + */ + 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; + } + currentTemp.node = i; + visited[i] = false; + distance[i] = currentTemp; + unvisited.add(currentTemp); } - currentTemp.node = i; - visited[i] = false; - distance[i] = currentTemp; - unvisited.add(currentTemp); + current.node = src; + current.distance = 0; } - current.node = src; - current.distance = 0; - } - /** - * Dijkstra's shortest path algorithm - * - * @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 - */ - return function (src, dest, graph) { - 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 - Number.isFinite(graph[i][current.node])) { //and this node is sibling of the current... + /** + * 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 + * @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, 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; - current.distance = tempDistance; - unvisited.update(current); + 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(); - } - return distance[dest].distance; - }; -}(); + 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 41ff368e..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 6e088852..54239587 100644 --- a/src/graphs/spanning-trees/prim.js +++ b/src/graphs/spanning-trees/prim.js @@ -1,106 +1,118 @@ -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) { - 'use strict'; - 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) { - 'use strict'; - 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, nodesCount) { - 'use strict'; - this.edges = edges || []; - this.nodesCount = nodesCount || 0; -} - -/** - * 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); + * + * // { 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(); * - * @public - * @return {Graph} Graph which is the minimum spanning tree + * @module graphs/spanning-trees/prim */ -Graph.prototype.prim = (function () { +(function (exports) { + 'use strict'; - var queue; + var Heap = require('../../data-structures/heap').Heap; + exports.Vertex = require('../../data-structures/vertex').Vertex; + exports.Edge = require('../../data-structures/edge').Edge; /** - * Initialize the algorithm. + * Graph. * - * @private - */ - function init() { - queue = new Heap(compareEdges); - } - - /** - * 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. + * @constructor + * @public + * @param {Array} edges Array with graph edges. + * @param {Number} nodesCount Number of nodes in graph. */ - function compareEdges(a, b) { - return b.distance - a.distance; - } + exports.Graph = function (edges, nodesCount) { + this.edges = edges || []; + this.nodesCount = nodesCount || 0; + }; /** - * Prim's algorithm implementation + * Executes Prim's algorithm and returns minimum spanning tree. * * @public - * @return {Graph} Minimum spanning tree. + * @method + * @return {Graph} Graph which is the minimum spanning tree. */ - return function () { - init.call(this); - var inTheTree = {}, - startVertex = this.edges[0].e.id, - spannigTree = [], - parents = {}, - distances = {}, - current; - inTheTree[startVertex] = true; - queue.add({ - node: startVertex, - distance: 0 - }); - for (var i = 0; i < this.nodesCount - 1; i += 1) { - current = queue.extract().node; - inTheTree[current] = true; - this.edges.forEach(function (e) { + exports.Graph.prototype.prim = (function () { + var queue; + + /** + * 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 compareEdges(a, b) { + return b.distance - a.distance; + } + + /** + * Initialize the algorithm. + * + * @private + */ + function init() { + queue = new Heap(compareEdges); + } + + return function () { + 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(), - node; + var collection = queue.getCollection(); + var node; if (e.e.id === current) { node = e.v.id; } else if (e.v.id === current) { @@ -127,43 +139,19 @@ Graph.prototype.prim = (function () { }); parents[node] = current; distances[node] = e.distance; - }); - console.log(queue._heap); - console.log(); - } - for (var node in parents) { - spannigTree.push(new Edge(node, parents[node], distances[node])); - } - return new Graph(spannigTree); - }; - -}()); - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * * * * * * * * * * * * * Sample graph * * * * * * * * * * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -(function () { - 'use strict'; - 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, 9); - - console.log(graph.prim()); -}()); + }; + 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); + }; + }()); -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +})(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 index 95ec58ea..613ff98a 100644 --- a/src/others/hanoi.js +++ b/src/others/hanoi.js @@ -1,15 +1,47 @@ -/* - * Hanoi towers - */ -function hanoi(count, source, intermediate, goal, result) { +(function (exports) { 'use strict'; - 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); + + /** + * 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; } - 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 index 07edbeef..e3f34811 100644 --- a/src/others/levenshtein-distance.js +++ b/src/others/levenshtein-distance.js @@ -3,24 +3,53 @@ var levenshteinDistance = (function () { - function levenshteinDistance(s, ls, t, lt) { - if (ls === 0) { - return lt; - } - if (lt === 0) { - return ls; + function levenshteinDistance (s, ls, t, lt) { + var memo = []; + var currRowMemo; + var i; + var k; + + for (k = 0; k <= lt; k += 1) { + memo[k] = k; } - var cost; - if (s[ls - 1] === t[lt - 1]) { - cost = 0; - } else { - cost = 1; + + 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 Math.min(levenshteinDistance(s, ls - 1, t, lt) + 1, - levenshteinDistance(s, ls, t, lt - 1) + 1, - levenshteinDistance(s, ls - 1, t, lt - 1) + cost); + + 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); }; @@ -28,4 +57,5 @@ exports.levenshteinDistance = levenshteinDistance; -}(typeof exports === 'undefined' ? window : exports)); \ No newline at end of file +}(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 b042e069..00000000 --- a/src/searching/binarysearch/recursive-binarysearch.js +++ /dev/null @@ -1,49 +0,0 @@ -(function (exports) { - 'use strict'; - /** - * Recursive version of binary search. It's complexity is O(log n). - * - * @public - */ - var binarySearch = (function () { - /** - * Binary search. - * - * @pivate - * @param {array} array 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); - }; - - }()); - - exports.binarySearch = binarySearch; - -}(typeof exports === 'undefined' ? window : exports)); 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/knuth-morris-pratt.js b/src/searching/knuth-morris-pratt.js similarity index 52% rename from src/searching/knuth-morris-pratt/knuth-morris-pratt.js rename to src/searching/knuth-morris-pratt.js index 83d02abb..b4aeb85b 100644 --- a/src/searching/knuth-morris-pratt/knuth-morris-pratt.js +++ b/src/searching/knuth-morris-pratt.js @@ -3,8 +3,11 @@ var kmp = (function () { function builtKMPTable(str) { - var res = [], - len, front, end, found; + 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); @@ -24,9 +27,31 @@ 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) { - var table = builtKMPTable(substr), - i = 0, j = 0; + 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; @@ -36,10 +61,11 @@ return i - j; } if (i < str.length && str[i] !== substr[j]) { - if (table[j - 1] !== 0) { + if (j > 0 && table[j - 1] !== 0) { j = table[j - 1]; } else { i += 1; + j = 0; } } } @@ -50,4 +76,4 @@ exports.kmp = kmp; -}(typeof exports === 'undefined' ? window : exports)); \ No newline at end of file +})(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 b71111bc..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)); 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/quickselect.js b/src/searching/quickselect.js similarity index 57% rename from src/searching/quickselect/quickselect.js rename to src/searching/quickselect.js index d49ca2e6..7ba9790c 100644 --- a/src/searching/quickselect/quickselect.js +++ b/src/searching/quickselect.js @@ -1,7 +1,26 @@ (function (exports) { 'use strict'; - // O(n) + /** + * 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) { @@ -22,7 +41,7 @@ } if (arr.length <= n) { - return NaN; + return undefined; } lo = lo || 0; hi = hi || arr.length - 1; @@ -41,8 +60,8 @@ lo = pivotIdx + 1; } } - return NaN; + return undefined; } exports.quickselect = quickselect; -}(typeof exports === 'undefined' ? window : exports)); +})(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 index 0b048b1c..a5a465b1 100644 --- a/src/sets/quickfind.js +++ b/src/sets/quickfind.js @@ -1,29 +1,60 @@ +/** + * 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'; + /** - * Checks whether there is a path between two nodes. - * The initialization is O(n). + * Initialization.

+ * Time complexity: O(N). * + * @public * @constructor - * @param {numner} size The count of the nodes + * @param {Numner} size Count of the nodes. */ - function QuickFind(size) { + exports.QuickFind = function (size) { this._ids = []; for (var i = 0; i < size; i += 1) { this._ids[i] = i; } - } + }; /** - * Connects two nodes - p and q. - * Complexity O(n). + * Connects two nodes - p and q.

+ * Time complexity: O(N). * - * @param {number} p The first node - * @param {number} q The second node + * @public + * @method + * @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]; + 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; @@ -32,26 +63,16 @@ }; /** - * Checks whether two nodes are connected. - * Complexity O(1). - * - * @param {number} p The first node - * @param {number} q The second node + * 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} */ - QuickFind.prototype.connected = function (p, q) { + exports.QuickFind.prototype.connected = function (p, q) { return this._ids[p] === this._ids[q]; }; - - exports.QuickFind = QuickFind; - - //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 -}(typeof exports === 'undefined' ? window : exports)); +})(typeof window === 'undefined' ? module.exports : window); diff --git a/src/sets/quickunion.js b/src/sets/quickunion.js index 4ff3908a..0d8bb402 100644 --- a/src/sets/quickunion.js +++ b/src/sets/quickunion.js @@ -1,64 +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'; + /** - * Checks whether path between two nodes exists. - * The initialization has O(n) complexity. + * Initialization.

+ * Time complexity: O(N). * + * @public * @constructor - * @param {number} n Nodes count - * + * @param {Numner} size Count of the nodes. */ - function QuickUnion(n) { + exports.QuickUnion = function (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 + * Finds the root of given node.

+ * Time complexity: O(N). + * @private + * @param {Number} i The given node. + * @return {Number} Root of the given node. */ - QuickUnion.prototype._root = function (i) { - while (i !== this._ids[i]) i = this._ids[i]; + exports.QuickUnion.prototype._root = function (i) { + while (i !== this._ids[i]) { + i = this._ids[i]; + } return i; }; /** - * Unions two nodes. - * Complexity O(n). + * Connects two nodes - p and q.

+ * Time complexity: O(N). * - * @param {number} p The first node - * @param {number} q The second node + * @public + * @method + * @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); + 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. - * Complexity O(n). + * 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. + * @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) { + exports.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 - exports.QuickUnion = QuickUnion; -}(typeof exports === 'undefined' ? window : exports)); +})(typeof window === 'undefined' ? module.exports : window); diff --git a/src/sets/weightquickunion.js b/src/sets/weightquickunion.js index cb88c289..2fc9b099 100644 --- a/src/sets/weightquickunion.js +++ b/src/sets/weightquickunion.js @@ -1,58 +1,92 @@ +/** + * 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'; + /** - * 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) { + * 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. - * The complexity is around O(logn) - * - * @param {number} i The given node - * @return {number} The root of the node - */ - QuickUnion.prototype._root = function (i) { + * 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 + // this._ids[i] = 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) { + * 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); }; /** - * Unions two nodes. - * Complexity O(logn) - * - * @param {number} p The first node - * @param {number} q The second node - */ - QuickUnion.prototype.union = function (p, 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 + if (pf === qf) { + return; // already linked + } var psz = this._size[qf]; var qsz = this._size[pf]; if (psz < qsz) { @@ -64,14 +98,4 @@ } }; - //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 - exports.QuickUnion = QuickUnion; -}(typeof exports === 'undefined' ? window : exports)); +})(typeof window === 'undefined' ? module.exports : window); diff --git a/src/shuffle/fisheryates.js b/src/shuffle/fisheryates.js index 1eaa460b..ccb26734 100644 --- a/src/shuffle/fisheryates.js +++ b/src/shuffle/fisheryates.js @@ -1,26 +1,32 @@ (function (exports) { + 'use strict'; /** * The shuffling algorithm of - * Fisher-Yates. Complexity O(n) + * 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 * - * @param {array} array The array which should be shuffled - * @return {array} The 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, - 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; + 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; } exports.shuffle = shuffle; -}(typeof exports === 'undefined' ? window : exports)); - +})(typeof window === 'undefined' ? module.exports : window); diff --git a/src/shuffle/richarddurstenfeld.js b/src/shuffle/richarddurstenfeld.js index a409d8b2..789d8517 100644 --- a/src/shuffle/richarddurstenfeld.js +++ b/src/shuffle/richarddurstenfeld.js @@ -1,20 +1,27 @@ (function (exports) { + 'use strict'; + /** * Shuffle of an array elements. * This algorithm is modified version of Fisher-Yates shuffle - * algorithm and is introduced by Richard Durstenfeld. - */ - - /** - * Shuffles an array. Complexity O(n). + * 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 * - * @param {array} array An array which should be shuffled - * @returns {array} Shuffled array + * @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, - rand, temp; + 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]; @@ -27,4 +34,3 @@ exports.shuffle = shuffle; }(typeof exports === 'undefined' ? window : exports)); - diff --git a/src/sorting/3-way-string-quicksort/quicksort.js b/src/sorting/3-way-string-quicksort.js similarity index 60% rename from src/sorting/3-way-string-quicksort/quicksort.js rename to src/sorting/3-way-string-quicksort.js index bf6b6a79..ff8460e4 100644 --- a/src/sorting/3-way-string-quicksort/quicksort.js +++ b/src/sorting/3-way-string-quicksort.js @@ -1,10 +1,6 @@ (function (exports) { 'use strict'; - /** - * Effective inplace string sorting algorithm. - * The algorithm is NOT stable. - */ var quicksort = (function () { function charAt(str, i) { @@ -21,11 +17,11 @@ if (lo >= hi) { return; } - var lowPointer = lo, - highPointer = hi, - p = charAt(arr[lo], d), - i = lo + 1, - current; + 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); @@ -48,6 +44,21 @@ 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; @@ -56,4 +67,4 @@ exports.quicksort = quicksort; -}(typeof exports === 'undefined' ? window : exports)); +})(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/least-significant-digit/lsd.js b/src/sorting/lsd.js similarity index 59% rename from src/sorting/least-significant-digit/lsd.js rename to src/sorting/lsd.js index a1c3169f..d1445203 100644 --- a/src/sorting/least-significant-digit/lsd.js +++ b/src/sorting/lsd.js @@ -2,16 +2,24 @@ 'use strict'; /** - * Sorts strings lexicographically. - * Complexity O(n*m) + * 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 - * @param {Array} arr Input array - * @param {Number} letterIdx Index to start sorting from - * @returns {Array} Sorted array + * @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, count; + var temp; + var count; letterIdx = letterIdx || 1; for (var i = letterIdx - 1; i >= 0; i -= 1) { count = []; @@ -40,5 +48,4 @@ exports.lsd = lsd; -}(typeof exports === 'undefined' ? window : exports)); - +})(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/most-significant-digit/msd.js b/src/sorting/msd.js similarity index 61% rename from src/sorting/most-significant-digit/msd.js rename to src/sorting/msd.js index 2e4ab4f4..f59e1718 100644 --- a/src/sorting/most-significant-digit/msd.js +++ b/src/sorting/msd.js @@ -1,5 +1,4 @@ (function (exports) { - 'use strict'; function charCodeAt(str, i) { @@ -7,9 +6,10 @@ } function sort(arr, lo, hi, d) { - var temp = [], - count = [], - j, idx; + 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) { @@ -37,18 +37,23 @@ /** * Sorts given array lexicographically. - * The algorithms knows how to treat - * differently length strings. - * The algorithm is stable. + * 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 * - * Complexity O(n*m) + * var sort = require('../src/sorting/msd').msd; + * // [ 'aab', 'aaa', 'acc', 'bbb', 'bcc' ] + * console.log(sort(['aab', 'bbb', 'aaa', 'acc', 'bcc'])); * * @public - * @param {Array} arr The array, which needs to be sorted - * @param {Number} d The digit from which the sorting should start - * @return {Array} The sorted array + * @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); @@ -56,4 +61,4 @@ } exports.msd = msd; -}(typeof exports === 'undefined' ? window : exports)); +})(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 4ffa6e1c..c47c24d7 100644 --- a/test/graphs/searching/bfs.spec.js +++ b/test/graphs/searching/bfs.spec.js @@ -1,7 +1,5 @@ /* jshint multistr: true */ -'use strict'; - var graph = [[0, 0, 0, 0, 1], [0, 0, 0, 1, 0], [0, 0, 0, 0, 0], @@ -11,6 +9,7 @@ var graph = [[0, 0, 0, 0, 1], var bfs = require('../../../src/graphs/searching/bfs').bfs; describe('BFS', function () { + 'use strict'; it('should work with empty graph', function () { expect(bfs([], 0, 0)).toEqual([0]); @@ -41,7 +40,7 @@ describe('BFS', function () { * * 0 ---> 1 * \ | - * \ v + * \ v * -> 2 */ it('should not update the parent node once set', function () { @@ -51,4 +50,4 @@ describe('BFS', function () { expect(bfs(graph, 0, 2)).toEqual([0, 2]); }); -}); \ No newline at end of file +}); 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/quicksort.spec.js b/test/sorting/3-way-string-quicksort.spec.js similarity index 91% rename from test/sorting/3-way-string-quicksort/quicksort.spec.js rename to test/sorting/3-way-string-quicksort.spec.js index 0fcf13e5..57d8114a 100644 --- a/test/sorting/3-way-string-quicksort/quicksort.spec.js +++ b/test/sorting/3-way-string-quicksort.spec.js @@ -1,5 +1,5 @@ var quicksort = - require('../../../src/sorting/3-way-string-quicksort/quicksort.js').quicksort; + require('../../src/sorting/3-way-string-quicksort.js').quicksort; describe('Most-Significant Digit', function () { 'use strict'; 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/least-significant-digit/lsd.spec.js b/test/sorting/lsd.spec.js similarity index 91% rename from test/sorting/least-significant-digit/lsd.spec.js rename to test/sorting/lsd.spec.js index 6115998d..738ae492 100644 --- a/test/sorting/least-significant-digit/lsd.spec.js +++ b/test/sorting/lsd.spec.js @@ -1,4 +1,4 @@ -var lsd = require('../../../src/sorting/least-significant-digit/lsd.js').lsd; +var lsd = require('../../src/sorting/lsd.js').lsd; describe('Least-Significant Digit', function () { 'use strict'; 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/most-significant-digit/msd.spec.js b/test/sorting/msd.spec.js similarity index 92% rename from test/sorting/most-significant-digit/msd.spec.js rename to test/sorting/msd.spec.js index b1f4bc74..245acfbd 100644 --- a/test/sorting/most-significant-digit/msd.spec.js +++ b/test/sorting/msd.spec.js @@ -1,4 +1,4 @@ -var msd = require('../../../src/sorting/most-significant-digit/msd.js').msd; +var msd = require('../../src/sorting/msd.js').msd; describe('Most-Significant Digit', function () { 'use strict'; 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"