├── .eslintrc.yml ├── .gitignore ├── .travis.yml ├── History.md ├── LICENSE ├── README.md ├── docs ├── assets │ ├── anchor.js │ ├── bass-addons.css │ ├── bass.css │ ├── fonts │ │ ├── EOT │ │ │ ├── SourceCodePro-Bold.eot │ │ │ └── SourceCodePro-Regular.eot │ │ ├── LICENSE.txt │ │ ├── OTF │ │ │ ├── SourceCodePro-Bold.otf │ │ │ └── SourceCodePro-Regular.otf │ │ ├── TTF │ │ │ ├── SourceCodePro-Bold.ttf │ │ │ └── SourceCodePro-Regular.ttf │ │ ├── WOFF │ │ │ ├── OTF │ │ │ │ ├── SourceCodePro-Bold.otf.woff │ │ │ │ └── SourceCodePro-Regular.otf.woff │ │ │ └── TTF │ │ │ │ ├── SourceCodePro-Bold.ttf.woff │ │ │ │ └── SourceCodePro-Regular.ttf.woff │ │ ├── WOFF2 │ │ │ ├── OTF │ │ │ │ ├── SourceCodePro-Bold.otf.woff2 │ │ │ │ └── SourceCodePro-Regular.otf.woff2 │ │ │ └── TTF │ │ │ │ ├── SourceCodePro-Bold.ttf.woff2 │ │ │ │ └── SourceCodePro-Regular.ttf.woff2 │ │ └── source-code-pro.css │ ├── github.css │ ├── site.js │ └── style.css └── index.html ├── example ├── iris.js └── test.js ├── package.json ├── src └── svm.js ├── test ├── .eslintrc.yml └── svm.js └── yarn.lock /.eslintrc.yml: -------------------------------------------------------------------------------- 1 | extends: 'eslint-config-cheminfo' 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 27 | node_modules 28 | 29 | # generated by webstorm, I think 30 | .idea 31 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "stable" 4 | - "6" 5 | - "4" 6 | -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | 2 | ## [2.1.2](https://github.com/mljs/svm/compare/v2.1.1...v2.1.2) (2016-08-16) 3 | 4 | 5 | ### Bug Fixes 6 | 7 | * put iris dataset as a dev dependency ([77e0c5a](https://github.com/mljs/svm/commit/77e0c5a)) 8 | 9 | 10 | 11 | 12 | ## [2.1.1](https://github.com/mljs/svm/compare/v2.1.0...v2.1.1) (2016-07-27) 13 | 14 | 15 | 16 | 17 | # [2.1.0](https://github.com/mljs/svm/compare/v2.0.1...v2.1.0) (2016-07-26) 18 | 19 | 20 | 21 | 22 | ## [2.0.1](https://github.com/mljs/svm/compare/v2.0.0...v2.0.1) (2016-07-25) 23 | 24 | 25 | ### Bug Fixes 26 | 27 | * don't update alpha if it has not changed much ([0b951dd](https://github.com/mljs/svm/commit/0b951dd)) 28 | 29 | 30 | 31 | 32 | # [2.0.0](https://github.com/mljs/svm/compare/v1.0.2...v2.0.0) (2016-07-24) 33 | 34 | 35 | ### Features 36 | 37 | * add option to provide a RNG ([ae28d35](https://github.com/mljs/svm/commit/ae28d35)) 38 | 39 | 40 | 41 | 42 | ## 1.0.2 (2015-07-03) 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 ml.js 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ml-svm 2 | 3 | [![NPM version][npm-image]][npm-url] 4 | [![build status][travis-image]][travis-url] 5 | [![David deps][david-image]][david-url] 6 | [![npm download][download-image]][download-url] 7 | 8 | Support Vector Machines in Javascript 9 | 10 | ## :warning: :warning: This is a simplified implementation of SVM, primarily meant for students to understand the algorithm. For real world applications, please check out [libsvm-js](https://github.com/mljs/libsvm) :warning: :warning: 11 | 12 | Implementation of [this simplified Sequential Minimization Optimization algorithm](http://cs229.stanford.edu/materials/smo.pdf) 13 | 14 | ## Installation 15 | 16 | `npm install ml-svm` 17 | 18 | ## API 19 | [API documentation](https://mljs.github.io/svm) 20 | 21 | ## Example 22 | 23 | ```js 24 | // Instantiate the svm classifier 25 | var SVM = require('ml-svm'); 26 | 27 | var options = { 28 | C: 0.01, 29 | tol: 10e-4, 30 | maxPasses: 10, 31 | maxIterations: 10000, 32 | kernel: 'rbf', 33 | kernelOptions: { 34 | sigma: 0.5 35 | } 36 | }; 37 | 38 | var svm = new SVM(options); 39 | 40 | // Train the classifier - we give him an xor 41 | var features = [[0,0],[0,1],[1,1],[1,0]]; 42 | var labels = [1, -1, 1, -1]; 43 | svm.train(features, labels); 44 | 45 | // Let's see how narrow the margin is 46 | var margins = svm.margin(features); 47 | 48 | // Let's see if it is separable by testing on the training data 49 | svm.predict(features); // [1, -1, 1, -1] 50 | 51 | // I want to see what my support vectors are 52 | var supportVectors = svm.supportVectors(); 53 | 54 | // Now we want to save the model for later use 55 | var model = svm.toJSON(); 56 | 57 | /// ... later, you can make predictions without retraining the model 58 | var importedSvm = SVM.load(model); 59 | importedSvm.predict(features); // [1, -1, 1, -1] 60 | ``` 61 | 62 | 63 | ## Authors 64 | 65 | - [Miguel Asencio](https://github.com/maasencioh) 66 | - [Daniel Kostro](https://github.com/stropitek) 67 | 68 | ## License 69 | 70 | [MIT](./LICENSE) 71 | 72 | [npm-image]: https://img.shields.io/npm/v/ml-svm.svg?style=flat-square 73 | [npm-url]: https://npmjs.org/package/ml-svm 74 | [travis-image]: https://img.shields.io/travis/mljs/svm/master.svg?style=flat-square 75 | [travis-url]: https://travis-ci.org/mljs/svm 76 | [david-image]: https://img.shields.io/david/mljs/svm.svg?style=flat-square 77 | [david-url]: https://david-dm.org/mljs/svm 78 | [download-image]: https://img.shields.io/npm/dm/ml-svm.svg?style=flat-square 79 | [download-url]: https://npmjs.org/package/ml-svm 80 | -------------------------------------------------------------------------------- /docs/assets/anchor.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * AnchorJS - v1.2.1 - 2015-07-02 3 | * https://github.com/bryanbraun/anchorjs 4 | * Copyright (c) 2015 Bryan Braun; Licensed MIT 5 | */ 6 | 7 | function AnchorJS(options) { 8 | 'use strict'; 9 | 10 | this.options = options || {}; 11 | 12 | this._applyRemainingDefaultOptions = function(opts) { 13 | this.options.icon = this.options.hasOwnProperty('icon') ? opts.icon : '\ue9cb'; // Accepts characters (and also URLs?), like '#', '¶', '❡', or '§'. 14 | this.options.visible = this.options.hasOwnProperty('visible') ? opts.visible : 'hover'; // Also accepts 'always' 15 | this.options.placement = this.options.hasOwnProperty('placement') ? opts.placement : 'right'; // Also accepts 'left' 16 | this.options.class = this.options.hasOwnProperty('class') ? opts.class : ''; // Accepts any class name. 17 | }; 18 | 19 | this._applyRemainingDefaultOptions(options); 20 | 21 | this.add = function(selector) { 22 | var elements, 23 | elsWithIds, 24 | idList, 25 | elementID, 26 | i, 27 | roughText, 28 | tidyText, 29 | index, 30 | count, 31 | newTidyText, 32 | readableID, 33 | anchor; 34 | 35 | this._applyRemainingDefaultOptions(this.options); 36 | 37 | // Provide a sensible default selector, if none is given. 38 | if (!selector) { 39 | selector = 'h1, h2, h3, h4, h5, h6'; 40 | } else if (typeof selector !== 'string') { 41 | throw new Error('The selector provided to AnchorJS was invalid.'); 42 | } 43 | 44 | elements = document.querySelectorAll(selector); 45 | if (elements.length === 0) { 46 | return false; 47 | } 48 | 49 | this._addBaselineStyles(); 50 | 51 | // We produce a list of existing IDs so we don't generate a duplicate. 52 | elsWithIds = document.querySelectorAll('[id]'); 53 | idList = [].map.call(elsWithIds, function assign(el) { 54 | return el.id; 55 | }); 56 | 57 | for (i = 0; i < elements.length; i++) { 58 | 59 | if (elements[i].hasAttribute('id')) { 60 | elementID = elements[i].getAttribute('id'); 61 | } else { 62 | roughText = elements[i].textContent; 63 | 64 | // Refine it so it makes a good ID. Strip out non-safe characters, replace 65 | // spaces with hyphens, truncate to 32 characters, and make toLowerCase. 66 | // 67 | // Example string: // '⚡⚡⚡ Unicode icons are cool--but they definitely don't belong in a URL fragment.' 68 | tidyText = roughText.replace(/[^\w\s-]/gi, '') // ' Unicode icons are cool--but they definitely dont belong in a URL fragment' 69 | .replace(/\s+/g, '-') // '-Unicode-icons-are-cool--but-they-definitely-dont-belong-in-a-URL-fragment' 70 | .replace(/-{2,}/g, '-') // '-Unicode-icons-are-cool-but-they-definitely-dont-belong-in-a-URL-fragment' 71 | .substring(0, 64) // '-Unicode-icons-are-cool-but-they-definitely-dont-belong-in-a-URL' 72 | .replace(/^-+|-+$/gm, '') // 'Unicode-icons-are-cool-but-they-definitely-dont-belong-in-a-URL' 73 | .toLowerCase(); // 'unicode-icons-are-cool-but-they-definitely-dont-belong-in-a-url' 74 | 75 | // Compare our generated ID to existing IDs (and increment it if needed) 76 | // before we add it to the page. 77 | newTidyText = tidyText; 78 | count = 0; 79 | do { 80 | if (index !== undefined) { 81 | newTidyText = tidyText + '-' + count; 82 | } 83 | // .indexOf is supported in IE9+. 84 | index = idList.indexOf(newTidyText); 85 | count += 1; 86 | } while (index !== -1); 87 | index = undefined; 88 | idList.push(newTidyText); 89 | 90 | // Assign it to our element. 91 | // Currently the setAttribute element is only supported in IE9 and above. 92 | elements[i].setAttribute('id', newTidyText); 93 | 94 | elementID = newTidyText; 95 | } 96 | 97 | readableID = elementID.replace(/-/g, ' '); 98 | 99 | // The following code builds the following DOM structure in a more effiecient (albeit opaque) way. 100 | // ''; 101 | anchor = document.createElement('a'); 102 | anchor.className = 'anchorjs-link ' + this.options.class; 103 | anchor.href = '#' + elementID; 104 | anchor.setAttribute('aria-label', 'Anchor link for: ' + readableID); 105 | anchor.setAttribute('data-anchorjs-icon', this.options.icon); 106 | 107 | if (this.options.visible === 'always') { 108 | anchor.style.opacity = '1'; 109 | } 110 | 111 | if (this.options.icon === '\ue9cb') { 112 | anchor.style.fontFamily = 'anchorjs-icons'; 113 | anchor.style.fontStyle = 'normal'; 114 | anchor.style.fontVariant = 'normal'; 115 | anchor.style.fontWeight = 'normal'; 116 | anchor.style.lineHeight = 1; 117 | } 118 | 119 | if (this.options.placement === 'left') { 120 | anchor.style.position = 'absolute'; 121 | anchor.style.marginLeft = '-1em'; 122 | anchor.style.paddingRight = '0.5em'; 123 | elements[i].insertBefore(anchor, elements[i].firstChild); 124 | } else { // if the option provided is `right` (or anything else). 125 | anchor.style.paddingLeft = '0.375em'; 126 | elements[i].appendChild(anchor); 127 | } 128 | } 129 | 130 | return this; 131 | }; 132 | 133 | this.remove = function(selector) { 134 | var domAnchor, 135 | elements = document.querySelectorAll(selector); 136 | for (var i = 0; i < elements.length; i++) { 137 | domAnchor = elements[i].querySelector('.anchorjs-link'); 138 | if (domAnchor) { 139 | elements[i].removeChild(domAnchor); 140 | } 141 | } 142 | return this; 143 | }; 144 | 145 | this._addBaselineStyles = function() { 146 | // We don't want to add global baseline styles if they've been added before. 147 | if (document.head.querySelector('style.anchorjs') !== null) { 148 | return; 149 | } 150 | 151 | var style = document.createElement('style'), 152 | linkRule = 153 | ' .anchorjs-link {' + 154 | ' opacity: 0;' + 155 | ' text-decoration: none;' + 156 | ' -webkit-font-smoothing: antialiased;' + 157 | ' -moz-osx-font-smoothing: grayscale;' + 158 | ' }', 159 | hoverRule = 160 | ' *:hover > .anchorjs-link,' + 161 | ' .anchorjs-link:focus {' + 162 | ' opacity: 1;' + 163 | ' }', 164 | anchorjsLinkFontFace = 165 | ' @font-face {' + 166 | ' font-family: "anchorjs-icons";' + 167 | ' font-style: normal;' + 168 | ' font-weight: normal;' + // Icon from icomoon; 10px wide & 10px tall; 2 empty below & 4 above 169 | ' src: url(data:application/x-font-ttf;charset=utf-8;base64,AAEAAAALAIAAAwAwT1MvMg8SBTUAAAC8AAAAYGNtYXAWi9QdAAABHAAAAFRnYXNwAAAAEAAAAXAAAAAIZ2x5Zgq29TcAAAF4AAABNGhlYWQEZM3pAAACrAAAADZoaGVhBhUDxgAAAuQAAAAkaG10eASAADEAAAMIAAAAFGxvY2EAKACuAAADHAAAAAxtYXhwAAgAVwAAAygAAAAgbmFtZQ5yJ3cAAANIAAAB2nBvc3QAAwAAAAAFJAAAACAAAwJAAZAABQAAApkCzAAAAI8CmQLMAAAB6wAzAQkAAAAAAAAAAAAAAAAAAAABEAAAAAAAAAAAAAAAAAAAAABAAADpywPA/8AAQAPAAEAAAAABAAAAAAAAAAAAAAAgAAAAAAADAAAAAwAAABwAAQADAAAAHAADAAEAAAAcAAQAOAAAAAoACAACAAIAAQAg6cv//f//AAAAAAAg6cv//f//AAH/4xY5AAMAAQAAAAAAAAAAAAAAAQAB//8ADwABAAAAAAAAAAAAAgAANzkBAAAAAAEAAAAAAAAAAAACAAA3OQEAAAAAAQAAAAAAAAAAAAIAADc5AQAAAAACADEARAJTAsAAKwBUAAABIiYnJjQ/AT4BMzIWFxYUDwEGIicmND8BNjQnLgEjIgYPAQYUFxYUBw4BIwciJicmND8BNjIXFhQPAQYUFx4BMzI2PwE2NCcmNDc2MhcWFA8BDgEjARQGDAUtLXoWOR8fORYtLTgKGwoKCjgaGg0gEhIgDXoaGgkJBQwHdR85Fi0tOAobCgoKOBoaDSASEiANehoaCQkKGwotLXoWOR8BMwUFLYEuehYXFxYugC44CQkKGwo4GkoaDQ0NDXoaShoKGwoFBe8XFi6ALjgJCQobCjgaShoNDQ0NehpKGgobCgoKLYEuehYXAAEAAAABAACiToc1Xw889QALBAAAAAAA0XnFFgAAAADRecUWAAAAAAJTAsAAAAAIAAIAAAAAAAAAAQAAA8D/wAAABAAAAAAAAlMAAQAAAAAAAAAAAAAAAAAAAAUAAAAAAAAAAAAAAAACAAAAAoAAMQAAAAAACgAUAB4AmgABAAAABQBVAAIAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAADgCuAAEAAAAAAAEADgAAAAEAAAAAAAIABwCfAAEAAAAAAAMADgBLAAEAAAAAAAQADgC0AAEAAAAAAAUACwAqAAEAAAAAAAYADgB1AAEAAAAAAAoAGgDeAAMAAQQJAAEAHAAOAAMAAQQJAAIADgCmAAMAAQQJAAMAHABZAAMAAQQJAAQAHADCAAMAAQQJAAUAFgA1AAMAAQQJAAYAHACDAAMAAQQJAAoANAD4YW5jaG9yanMtaWNvbnMAYQBuAGMAaABvAHIAagBzAC0AaQBjAG8AbgBzVmVyc2lvbiAxLjAAVgBlAHIAcwBpAG8AbgAgADEALgAwYW5jaG9yanMtaWNvbnMAYQBuAGMAaABvAHIAagBzAC0AaQBjAG8AbgBzYW5jaG9yanMtaWNvbnMAYQBuAGMAaABvAHIAagBzAC0AaQBjAG8AbgBzUmVndWxhcgBSAGUAZwB1AGwAYQByYW5jaG9yanMtaWNvbnMAYQBuAGMAaABvAHIAagBzAC0AaQBjAG8AbgBzRm9udCBnZW5lcmF0ZWQgYnkgSWNvTW9vbi4ARgBvAG4AdAAgAGcAZQBuAGUAcgBhAHQAZQBkACAAYgB5ACAASQBjAG8ATQBvAG8AbgAuAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==) format("truetype");' + 170 | ' }', 171 | pseudoElContent = 172 | ' [data-anchorjs-icon]::after {' + 173 | ' content: attr(data-anchorjs-icon);' + 174 | ' }', 175 | firstStyleEl; 176 | 177 | style.className = 'anchorjs'; 178 | style.appendChild(document.createTextNode('')); // Necessary for Webkit. 179 | 180 | // We place it in the head with the other style tags, if possible, so as to 181 | // not look out of place. We insert before the others so these styles can be 182 | // overridden if necessary. 183 | firstStyleEl = document.head.querySelector('[rel="stylesheet"], style'); 184 | if (firstStyleEl === undefined) { 185 | document.head.appendChild(style); 186 | } else { 187 | document.head.insertBefore(style, firstStyleEl); 188 | } 189 | 190 | style.sheet.insertRule(linkRule, style.sheet.cssRules.length); 191 | style.sheet.insertRule(hoverRule, style.sheet.cssRules.length); 192 | style.sheet.insertRule(pseudoElContent, style.sheet.cssRules.length); 193 | style.sheet.insertRule(anchorjsLinkFontFace, style.sheet.cssRules.length); 194 | }; 195 | } 196 | 197 | var anchors = new AnchorJS(); 198 | -------------------------------------------------------------------------------- /docs/assets/bass-addons.css: -------------------------------------------------------------------------------- 1 | .input { 2 | font-family: inherit; 3 | display: block; 4 | width: 100%; 5 | height: 2rem; 6 | padding: .5rem; 7 | margin-bottom: 1rem; 8 | border: 1px solid #ccc; 9 | font-size: .875rem; 10 | border-radius: 3px; 11 | box-sizing: border-box; 12 | } 13 | -------------------------------------------------------------------------------- /docs/assets/bass.css: -------------------------------------------------------------------------------- 1 | /*! Basscss | http://basscss.com | MIT License */ 2 | 3 | .h1{ font-size: 2rem } 4 | .h2{ font-size: 1.5rem } 5 | .h3{ font-size: 1.25rem } 6 | .h4{ font-size: 1rem } 7 | .h5{ font-size: .875rem } 8 | .h6{ font-size: .75rem } 9 | 10 | .font-family-inherit{ font-family:inherit } 11 | .font-size-inherit{ font-size:inherit } 12 | .text-decoration-none{ text-decoration:none } 13 | 14 | .bold{ font-weight: bold; font-weight: bold } 15 | .regular{ font-weight:normal } 16 | .italic{ font-style:italic } 17 | .caps{ text-transform:uppercase; letter-spacing: .2em; } 18 | 19 | .left-align{ text-align:left } 20 | .center{ text-align:center } 21 | .right-align{ text-align:right } 22 | .justify{ text-align:justify } 23 | 24 | .nowrap{ white-space:nowrap } 25 | .break-word{ word-wrap:break-word } 26 | 27 | .line-height-1{ line-height: 1 } 28 | .line-height-2{ line-height: 1.125 } 29 | .line-height-3{ line-height: 1.25 } 30 | .line-height-4{ line-height: 1.5 } 31 | 32 | .list-style-none{ list-style:none } 33 | .underline{ text-decoration:underline } 34 | 35 | .truncate{ 36 | max-width:100%; 37 | overflow:hidden; 38 | text-overflow:ellipsis; 39 | white-space:nowrap; 40 | } 41 | 42 | .list-reset{ 43 | list-style:none; 44 | padding-left:0; 45 | } 46 | 47 | .inline{ display:inline } 48 | .block{ display:block } 49 | .inline-block{ display:inline-block } 50 | .table{ display:table } 51 | .table-cell{ display:table-cell } 52 | 53 | .overflow-hidden{ overflow:hidden } 54 | .overflow-scroll{ overflow:scroll } 55 | .overflow-auto{ overflow:auto } 56 | 57 | .clearfix:before, 58 | .clearfix:after{ 59 | content:" "; 60 | display:table 61 | } 62 | .clearfix:after{ clear:both } 63 | 64 | .left{ float:left } 65 | .right{ float:right } 66 | 67 | .fit{ max-width:100% } 68 | 69 | .max-width-1{ max-width: 24rem } 70 | .max-width-2{ max-width: 32rem } 71 | .max-width-3{ max-width: 48rem } 72 | .max-width-4{ max-width: 64rem } 73 | 74 | .border-box{ box-sizing:border-box } 75 | 76 | .align-baseline{ vertical-align:baseline } 77 | .align-top{ vertical-align:top } 78 | .align-middle{ vertical-align:middle } 79 | .align-bottom{ vertical-align:bottom } 80 | 81 | .m0{ margin:0 } 82 | .mt0{ margin-top:0 } 83 | .mr0{ margin-right:0 } 84 | .mb0{ margin-bottom:0 } 85 | .ml0{ margin-left:0 } 86 | .mx0{ margin-left:0; margin-right:0 } 87 | .my0{ margin-top:0; margin-bottom:0 } 88 | 89 | .m1{ margin: .5rem } 90 | .mt1{ margin-top: .5rem } 91 | .mr1{ margin-right: .5rem } 92 | .mb1{ margin-bottom: .5rem } 93 | .ml1{ margin-left: .5rem } 94 | .mx1{ margin-left: .5rem; margin-right: .5rem } 95 | .my1{ margin-top: .5rem; margin-bottom: .5rem } 96 | 97 | .m2{ margin: 1rem } 98 | .mt2{ margin-top: 1rem } 99 | .mr2{ margin-right: 1rem } 100 | .mb2{ margin-bottom: 1rem } 101 | .ml2{ margin-left: 1rem } 102 | .mx2{ margin-left: 1rem; margin-right: 1rem } 103 | .my2{ margin-top: 1rem; margin-bottom: 1rem } 104 | 105 | .m3{ margin: 2rem } 106 | .mt3{ margin-top: 2rem } 107 | .mr3{ margin-right: 2rem } 108 | .mb3{ margin-bottom: 2rem } 109 | .ml3{ margin-left: 2rem } 110 | .mx3{ margin-left: 2rem; margin-right: 2rem } 111 | .my3{ margin-top: 2rem; margin-bottom: 2rem } 112 | 113 | .m4{ margin: 4rem } 114 | .mt4{ margin-top: 4rem } 115 | .mr4{ margin-right: 4rem } 116 | .mb4{ margin-bottom: 4rem } 117 | .ml4{ margin-left: 4rem } 118 | .mx4{ margin-left: 4rem; margin-right: 4rem } 119 | .my4{ margin-top: 4rem; margin-bottom: 4rem } 120 | 121 | .mxn1{ margin-left: -.5rem; margin-right: -.5rem; } 122 | .mxn2{ margin-left: -1rem; margin-right: -1rem; } 123 | .mxn3{ margin-left: -2rem; margin-right: -2rem; } 124 | .mxn4{ margin-left: -4rem; margin-right: -4rem; } 125 | 126 | .ml-auto{ margin-left:auto } 127 | .mr-auto{ margin-right:auto } 128 | .mx-auto{ margin-left:auto; margin-right:auto; } 129 | 130 | .p0{ padding:0 } 131 | .pt0{ padding-top:0 } 132 | .pr0{ padding-right:0 } 133 | .pb0{ padding-bottom:0 } 134 | .pl0{ padding-left:0 } 135 | .px0{ padding-left:0; padding-right:0 } 136 | .py0{ padding-top:0; padding-bottom:0 } 137 | 138 | .p1{ padding: .5rem } 139 | .pt1{ padding-top: .5rem } 140 | .pr1{ padding-right: .5rem } 141 | .pb1{ padding-bottom: .5rem } 142 | .pl1{ padding-left: .5rem } 143 | .py1{ padding-top: .5rem; padding-bottom: .5rem } 144 | .px1{ padding-left: .5rem; padding-right: .5rem } 145 | 146 | .p2{ padding: 1rem } 147 | .pt2{ padding-top: 1rem } 148 | .pr2{ padding-right: 1rem } 149 | .pb2{ padding-bottom: 1rem } 150 | .pl2{ padding-left: 1rem } 151 | .py2{ padding-top: 1rem; padding-bottom: 1rem } 152 | .px2{ padding-left: 1rem; padding-right: 1rem } 153 | 154 | .p3{ padding: 2rem } 155 | .pt3{ padding-top: 2rem } 156 | .pr3{ padding-right: 2rem } 157 | .pb3{ padding-bottom: 2rem } 158 | .pl3{ padding-left: 2rem } 159 | .py3{ padding-top: 2rem; padding-bottom: 2rem } 160 | .px3{ padding-left: 2rem; padding-right: 2rem } 161 | 162 | .p4{ padding: 4rem } 163 | .pt4{ padding-top: 4rem } 164 | .pr4{ padding-right: 4rem } 165 | .pb4{ padding-bottom: 4rem } 166 | .pl4{ padding-left: 4rem } 167 | .py4{ padding-top: 4rem; padding-bottom: 4rem } 168 | .px4{ padding-left: 4rem; padding-right: 4rem } 169 | 170 | .col{ 171 | float:left; 172 | box-sizing:border-box; 173 | } 174 | 175 | .col-right{ 176 | float:right; 177 | box-sizing:border-box; 178 | } 179 | 180 | .col-1{ 181 | width:8.33333%; 182 | } 183 | 184 | .col-2{ 185 | width:16.66667%; 186 | } 187 | 188 | .col-3{ 189 | width:25%; 190 | } 191 | 192 | .col-4{ 193 | width:33.33333%; 194 | } 195 | 196 | .col-5{ 197 | width:41.66667%; 198 | } 199 | 200 | .col-6{ 201 | width:50%; 202 | } 203 | 204 | .col-7{ 205 | width:58.33333%; 206 | } 207 | 208 | .col-8{ 209 | width:66.66667%; 210 | } 211 | 212 | .col-9{ 213 | width:75%; 214 | } 215 | 216 | .col-10{ 217 | width:83.33333%; 218 | } 219 | 220 | .col-11{ 221 | width:91.66667%; 222 | } 223 | 224 | .col-12{ 225 | width:100%; 226 | } 227 | @media (min-width: 40em){ 228 | 229 | .sm-col{ 230 | float:left; 231 | box-sizing:border-box; 232 | } 233 | 234 | .sm-col-right{ 235 | float:right; 236 | box-sizing:border-box; 237 | } 238 | 239 | .sm-col-1{ 240 | width:8.33333%; 241 | } 242 | 243 | .sm-col-2{ 244 | width:16.66667%; 245 | } 246 | 247 | .sm-col-3{ 248 | width:25%; 249 | } 250 | 251 | .sm-col-4{ 252 | width:33.33333%; 253 | } 254 | 255 | .sm-col-5{ 256 | width:41.66667%; 257 | } 258 | 259 | .sm-col-6{ 260 | width:50%; 261 | } 262 | 263 | .sm-col-7{ 264 | width:58.33333%; 265 | } 266 | 267 | .sm-col-8{ 268 | width:66.66667%; 269 | } 270 | 271 | .sm-col-9{ 272 | width:75%; 273 | } 274 | 275 | .sm-col-10{ 276 | width:83.33333%; 277 | } 278 | 279 | .sm-col-11{ 280 | width:91.66667%; 281 | } 282 | 283 | .sm-col-12{ 284 | width:100%; 285 | } 286 | 287 | } 288 | @media (min-width: 52em){ 289 | 290 | .md-col{ 291 | float:left; 292 | box-sizing:border-box; 293 | } 294 | 295 | .md-col-right{ 296 | float:right; 297 | box-sizing:border-box; 298 | } 299 | 300 | .md-col-1{ 301 | width:8.33333%; 302 | } 303 | 304 | .md-col-2{ 305 | width:16.66667%; 306 | } 307 | 308 | .md-col-3{ 309 | width:25%; 310 | } 311 | 312 | .md-col-4{ 313 | width:33.33333%; 314 | } 315 | 316 | .md-col-5{ 317 | width:41.66667%; 318 | } 319 | 320 | .md-col-6{ 321 | width:50%; 322 | } 323 | 324 | .md-col-7{ 325 | width:58.33333%; 326 | } 327 | 328 | .md-col-8{ 329 | width:66.66667%; 330 | } 331 | 332 | .md-col-9{ 333 | width:75%; 334 | } 335 | 336 | .md-col-10{ 337 | width:83.33333%; 338 | } 339 | 340 | .md-col-11{ 341 | width:91.66667%; 342 | } 343 | 344 | .md-col-12{ 345 | width:100%; 346 | } 347 | 348 | } 349 | @media (min-width: 64em){ 350 | 351 | .lg-col{ 352 | float:left; 353 | box-sizing:border-box; 354 | } 355 | 356 | .lg-col-right{ 357 | float:right; 358 | box-sizing:border-box; 359 | } 360 | 361 | .lg-col-1{ 362 | width:8.33333%; 363 | } 364 | 365 | .lg-col-2{ 366 | width:16.66667%; 367 | } 368 | 369 | .lg-col-3{ 370 | width:25%; 371 | } 372 | 373 | .lg-col-4{ 374 | width:33.33333%; 375 | } 376 | 377 | .lg-col-5{ 378 | width:41.66667%; 379 | } 380 | 381 | .lg-col-6{ 382 | width:50%; 383 | } 384 | 385 | .lg-col-7{ 386 | width:58.33333%; 387 | } 388 | 389 | .lg-col-8{ 390 | width:66.66667%; 391 | } 392 | 393 | .lg-col-9{ 394 | width:75%; 395 | } 396 | 397 | .lg-col-10{ 398 | width:83.33333%; 399 | } 400 | 401 | .lg-col-11{ 402 | width:91.66667%; 403 | } 404 | 405 | .lg-col-12{ 406 | width:100%; 407 | } 408 | 409 | } 410 | .flex{ display:-webkit-box; display:-webkit-flex; display:-ms-flexbox; display:flex } 411 | 412 | @media (min-width: 40em){ 413 | .sm-flex{ display:-webkit-box; display:-webkit-flex; display:-ms-flexbox; display:flex } 414 | } 415 | 416 | @media (min-width: 52em){ 417 | .md-flex{ display:-webkit-box; display:-webkit-flex; display:-ms-flexbox; display:flex } 418 | } 419 | 420 | @media (min-width: 64em){ 421 | .lg-flex{ display:-webkit-box; display:-webkit-flex; display:-ms-flexbox; display:flex } 422 | } 423 | 424 | .flex-column{ -webkit-box-orient:vertical; -webkit-box-direction:normal; -webkit-flex-direction:column; -ms-flex-direction:column; flex-direction:column } 425 | .flex-wrap{ -webkit-flex-wrap:wrap; -ms-flex-wrap:wrap; flex-wrap:wrap } 426 | 427 | .items-start{ -webkit-box-align:start; -webkit-align-items:flex-start; -ms-flex-align:start; -ms-grid-row-align:flex-start; align-items:flex-start } 428 | .items-end{ -webkit-box-align:end; -webkit-align-items:flex-end; -ms-flex-align:end; -ms-grid-row-align:flex-end; align-items:flex-end } 429 | .items-center{ -webkit-box-align:center; -webkit-align-items:center; -ms-flex-align:center; -ms-grid-row-align:center; align-items:center } 430 | .items-baseline{ -webkit-box-align:baseline; -webkit-align-items:baseline; -ms-flex-align:baseline; -ms-grid-row-align:baseline; align-items:baseline } 431 | .items-stretch{ -webkit-box-align:stretch; -webkit-align-items:stretch; -ms-flex-align:stretch; -ms-grid-row-align:stretch; align-items:stretch } 432 | 433 | .self-start{ -webkit-align-self:flex-start; -ms-flex-item-align:start; align-self:flex-start } 434 | .self-end{ -webkit-align-self:flex-end; -ms-flex-item-align:end; align-self:flex-end } 435 | .self-center{ -webkit-align-self:center; -ms-flex-item-align:center; align-self:center } 436 | .self-baseline{ -webkit-align-self:baseline; -ms-flex-item-align:baseline; align-self:baseline } 437 | .self-stretch{ -webkit-align-self:stretch; -ms-flex-item-align:stretch; align-self:stretch } 438 | 439 | .justify-start{ -webkit-box-pack:start; -webkit-justify-content:flex-start; -ms-flex-pack:start; justify-content:flex-start } 440 | .justify-end{ -webkit-box-pack:end; -webkit-justify-content:flex-end; -ms-flex-pack:end; justify-content:flex-end } 441 | .justify-center{ -webkit-box-pack:center; -webkit-justify-content:center; -ms-flex-pack:center; justify-content:center } 442 | .justify-between{ -webkit-box-pack:justify; -webkit-justify-content:space-between; -ms-flex-pack:justify; justify-content:space-between } 443 | .justify-around{ -webkit-justify-content:space-around; -ms-flex-pack:distribute; justify-content:space-around } 444 | 445 | .content-start{ -webkit-align-content:flex-start; -ms-flex-line-pack:start; align-content:flex-start } 446 | .content-end{ -webkit-align-content:flex-end; -ms-flex-line-pack:end; align-content:flex-end } 447 | .content-center{ -webkit-align-content:center; -ms-flex-line-pack:center; align-content:center } 448 | .content-between{ -webkit-align-content:space-between; -ms-flex-line-pack:justify; align-content:space-between } 449 | .content-around{ -webkit-align-content:space-around; -ms-flex-line-pack:distribute; align-content:space-around } 450 | .content-stretch{ -webkit-align-content:stretch; -ms-flex-line-pack:stretch; align-content:stretch } 451 | .flex-auto{ 452 | -webkit-box-flex:1; 453 | -webkit-flex:1 1 auto; 454 | -ms-flex:1 1 auto; 455 | flex:1 1 auto; 456 | min-width:0; 457 | min-height:0; 458 | } 459 | .flex-none{ -webkit-box-flex:0; -webkit-flex:none; -ms-flex:none; flex:none } 460 | 461 | .order-0{ -webkit-box-ordinal-group:1; -webkit-order:0; -ms-flex-order:0; order:0 } 462 | .order-1{ -webkit-box-ordinal-group:2; -webkit-order:1; -ms-flex-order:1; order:1 } 463 | .order-2{ -webkit-box-ordinal-group:3; -webkit-order:2; -ms-flex-order:2; order:2 } 464 | .order-3{ -webkit-box-ordinal-group:4; -webkit-order:3; -ms-flex-order:3; order:3 } 465 | .order-last{ -webkit-box-ordinal-group:100000; -webkit-order:99999; -ms-flex-order:99999; order:99999 } 466 | 467 | .relative{ position:relative } 468 | .absolute{ position:absolute } 469 | .fixed{ position:fixed } 470 | 471 | .top-0{ top:0 } 472 | .right-0{ right:0 } 473 | .bottom-0{ bottom:0 } 474 | .left-0{ left:0 } 475 | 476 | .z1{ z-index: 1 } 477 | .z2{ z-index: 2 } 478 | .z3{ z-index: 3 } 479 | .z4{ z-index: 4 } 480 | 481 | .border{ 482 | border-style:solid; 483 | border-width: 1px; 484 | } 485 | 486 | .border-top{ 487 | border-top-style:solid; 488 | border-top-width: 1px; 489 | } 490 | 491 | .border-right{ 492 | border-right-style:solid; 493 | border-right-width: 1px; 494 | } 495 | 496 | .border-bottom{ 497 | border-bottom-style:solid; 498 | border-bottom-width: 1px; 499 | } 500 | 501 | .border-left{ 502 | border-left-style:solid; 503 | border-left-width: 1px; 504 | } 505 | 506 | .border-none{ border:0 } 507 | 508 | .rounded{ border-radius: 3px } 509 | .circle{ border-radius:50% } 510 | 511 | .rounded-top{ border-radius: 3px 3px 0 0 } 512 | .rounded-right{ border-radius: 0 3px 3px 0 } 513 | .rounded-bottom{ border-radius: 0 0 3px 3px } 514 | .rounded-left{ border-radius: 3px 0 0 3px } 515 | 516 | .not-rounded{ border-radius:0 } 517 | 518 | .hide{ 519 | position:absolute !important; 520 | height:1px; 521 | width:1px; 522 | overflow:hidden; 523 | clip:rect(1px, 1px, 1px, 1px); 524 | } 525 | 526 | @media (max-width: 40em){ 527 | .xs-hide{ display:none !important } 528 | } 529 | 530 | @media (min-width: 40em) and (max-width: 52em){ 531 | .sm-hide{ display:none !important } 532 | } 533 | 534 | @media (min-width: 52em) and (max-width: 64em){ 535 | .md-hide{ display:none !important } 536 | } 537 | 538 | @media (min-width: 64em){ 539 | .lg-hide{ display:none !important } 540 | } 541 | 542 | .display-none{ display:none !important } 543 | 544 | -------------------------------------------------------------------------------- /docs/assets/fonts/EOT/SourceCodePro-Bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mljs/svm/392a1d09b33faa3be43dbb119114642cba3a9c64/docs/assets/fonts/EOT/SourceCodePro-Bold.eot -------------------------------------------------------------------------------- /docs/assets/fonts/EOT/SourceCodePro-Regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mljs/svm/392a1d09b33faa3be43dbb119114642cba3a9c64/docs/assets/fonts/EOT/SourceCodePro-Regular.eot -------------------------------------------------------------------------------- /docs/assets/fonts/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. 2 | 3 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 4 | 5 | This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL 6 | 7 | 8 | ----------------------------------------------------------- 9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 10 | ----------------------------------------------------------- 11 | 12 | PREAMBLE 13 | The goals of the Open Font License (OFL) are to stimulate worldwide 14 | development of collaborative font projects, to support the font creation 15 | efforts of academic and linguistic communities, and to provide a free and 16 | open framework in which fonts may be shared and improved in partnership 17 | with others. 18 | 19 | The OFL allows the licensed fonts to be used, studied, modified and 20 | redistributed freely as long as they are not sold by themselves. The 21 | fonts, including any derivative works, can be bundled, embedded, 22 | redistributed and/or sold with any software provided that any reserved 23 | names are not used by derivative works. The fonts and derivatives, 24 | however, cannot be released under any other type of license. The 25 | requirement for fonts to remain under this license does not apply 26 | to any document created using the fonts or their derivatives. 27 | 28 | DEFINITIONS 29 | "Font Software" refers to the set of files released by the Copyright 30 | Holder(s) under this license and clearly marked as such. This may 31 | include source files, build scripts and documentation. 32 | 33 | "Reserved Font Name" refers to any names specified as such after the 34 | copyright statement(s). 35 | 36 | "Original Version" refers to the collection of Font Software components as 37 | distributed by the Copyright Holder(s). 38 | 39 | "Modified Version" refers to any derivative made by adding to, deleting, 40 | or substituting -- in part or in whole -- any of the components of the 41 | Original Version, by changing formats or by porting the Font Software to a 42 | new environment. 43 | 44 | "Author" refers to any designer, engineer, programmer, technical 45 | writer or other person who contributed to the Font Software. 46 | 47 | PERMISSION & CONDITIONS 48 | Permission is hereby granted, free of charge, to any person obtaining 49 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 50 | redistribute, and sell modified and unmodified copies of the Font 51 | Software, subject to the following conditions: 52 | 53 | 1) Neither the Font Software nor any of its individual components, 54 | in Original or Modified Versions, may be sold by itself. 55 | 56 | 2) Original or Modified Versions of the Font Software may be bundled, 57 | redistributed and/or sold with any software, provided that each copy 58 | contains the above copyright notice and this license. These can be 59 | included either as stand-alone text files, human-readable headers or 60 | in the appropriate machine-readable metadata fields within text or 61 | binary files as long as those fields can be easily viewed by the user. 62 | 63 | 3) No Modified Version of the Font Software may use the Reserved Font 64 | Name(s) unless explicit written permission is granted by the corresponding 65 | Copyright Holder. This restriction only applies to the primary font name as 66 | presented to the users. 67 | 68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 69 | Software shall not be used to promote, endorse or advertise any 70 | Modified Version, except to acknowledge the contribution(s) of the 71 | Copyright Holder(s) and the Author(s) or with their explicit written 72 | permission. 73 | 74 | 5) The Font Software, modified or unmodified, in part or in whole, 75 | must be distributed entirely under this license, and must not be 76 | distributed under any other license. The requirement for fonts to 77 | remain under this license does not apply to any document created 78 | using the Font Software. 79 | 80 | TERMINATION 81 | This license becomes null and void if any of the above conditions are 82 | not met. 83 | 84 | DISCLAIMER 85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 93 | OTHER DEALINGS IN THE FONT SOFTWARE. 94 | -------------------------------------------------------------------------------- /docs/assets/fonts/OTF/SourceCodePro-Bold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mljs/svm/392a1d09b33faa3be43dbb119114642cba3a9c64/docs/assets/fonts/OTF/SourceCodePro-Bold.otf -------------------------------------------------------------------------------- /docs/assets/fonts/OTF/SourceCodePro-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mljs/svm/392a1d09b33faa3be43dbb119114642cba3a9c64/docs/assets/fonts/OTF/SourceCodePro-Regular.otf -------------------------------------------------------------------------------- /docs/assets/fonts/TTF/SourceCodePro-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mljs/svm/392a1d09b33faa3be43dbb119114642cba3a9c64/docs/assets/fonts/TTF/SourceCodePro-Bold.ttf -------------------------------------------------------------------------------- /docs/assets/fonts/TTF/SourceCodePro-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mljs/svm/392a1d09b33faa3be43dbb119114642cba3a9c64/docs/assets/fonts/TTF/SourceCodePro-Regular.ttf -------------------------------------------------------------------------------- /docs/assets/fonts/WOFF/OTF/SourceCodePro-Bold.otf.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mljs/svm/392a1d09b33faa3be43dbb119114642cba3a9c64/docs/assets/fonts/WOFF/OTF/SourceCodePro-Bold.otf.woff -------------------------------------------------------------------------------- /docs/assets/fonts/WOFF/OTF/SourceCodePro-Regular.otf.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mljs/svm/392a1d09b33faa3be43dbb119114642cba3a9c64/docs/assets/fonts/WOFF/OTF/SourceCodePro-Regular.otf.woff -------------------------------------------------------------------------------- /docs/assets/fonts/WOFF/TTF/SourceCodePro-Bold.ttf.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mljs/svm/392a1d09b33faa3be43dbb119114642cba3a9c64/docs/assets/fonts/WOFF/TTF/SourceCodePro-Bold.ttf.woff -------------------------------------------------------------------------------- /docs/assets/fonts/WOFF/TTF/SourceCodePro-Regular.ttf.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mljs/svm/392a1d09b33faa3be43dbb119114642cba3a9c64/docs/assets/fonts/WOFF/TTF/SourceCodePro-Regular.ttf.woff -------------------------------------------------------------------------------- /docs/assets/fonts/WOFF2/OTF/SourceCodePro-Bold.otf.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mljs/svm/392a1d09b33faa3be43dbb119114642cba3a9c64/docs/assets/fonts/WOFF2/OTF/SourceCodePro-Bold.otf.woff2 -------------------------------------------------------------------------------- /docs/assets/fonts/WOFF2/OTF/SourceCodePro-Regular.otf.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mljs/svm/392a1d09b33faa3be43dbb119114642cba3a9c64/docs/assets/fonts/WOFF2/OTF/SourceCodePro-Regular.otf.woff2 -------------------------------------------------------------------------------- /docs/assets/fonts/WOFF2/TTF/SourceCodePro-Bold.ttf.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mljs/svm/392a1d09b33faa3be43dbb119114642cba3a9c64/docs/assets/fonts/WOFF2/TTF/SourceCodePro-Bold.ttf.woff2 -------------------------------------------------------------------------------- /docs/assets/fonts/WOFF2/TTF/SourceCodePro-Regular.ttf.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mljs/svm/392a1d09b33faa3be43dbb119114642cba3a9c64/docs/assets/fonts/WOFF2/TTF/SourceCodePro-Regular.ttf.woff2 -------------------------------------------------------------------------------- /docs/assets/fonts/source-code-pro.css: -------------------------------------------------------------------------------- 1 | @font-face{ 2 | font-family: 'Source Code Pro'; 3 | font-weight: 400; 4 | font-style: normal; 5 | font-stretch: normal; 6 | src: url('EOT/SourceCodePro-Regular.eot') format('embedded-opentype'), 7 | url('WOFF2/TTF/SourceCodePro-Regular.ttf.woff2') format('woff2'), 8 | url('WOFF/OTF/SourceCodePro-Regular.otf.woff') format('woff'), 9 | url('OTF/SourceCodePro-Regular.otf') format('opentype'), 10 | url('TTF/SourceCodePro-Regular.ttf') format('truetype'); 11 | } 12 | 13 | @font-face{ 14 | font-family: 'Source Code Pro'; 15 | font-weight: 700; 16 | font-style: normal; 17 | font-stretch: normal; 18 | src: url('EOT/SourceCodePro-Bold.eot') format('embedded-opentype'), 19 | url('WOFF2/TTF/SourceCodePro-Bold.ttf.woff2') format('woff2'), 20 | url('WOFF/OTF/SourceCodePro-Bold.otf.woff') format('woff'), 21 | url('OTF/SourceCodePro-Bold.otf') format('opentype'), 22 | url('TTF/SourceCodePro-Bold.ttf') format('truetype'); 23 | } 24 | -------------------------------------------------------------------------------- /docs/assets/github.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | github.com style (c) Vasily Polovnyov 4 | 5 | */ 6 | 7 | .hljs { 8 | display: block; 9 | overflow-x: auto; 10 | padding: 0.5em; 11 | color: #333; 12 | background: #f8f8f8; 13 | -webkit-text-size-adjust: none; 14 | } 15 | 16 | .hljs-comment, 17 | .diff .hljs-header, 18 | .hljs-javadoc { 19 | color: #998; 20 | font-style: italic; 21 | } 22 | 23 | .hljs-keyword, 24 | .css .rule .hljs-keyword, 25 | .hljs-winutils, 26 | .nginx .hljs-title, 27 | .hljs-subst, 28 | .hljs-request, 29 | .hljs-status { 30 | color: #1184CE; 31 | } 32 | 33 | .hljs-number, 34 | .hljs-hexcolor, 35 | .ruby .hljs-constant { 36 | color: #ed225d; 37 | } 38 | 39 | .hljs-string, 40 | .hljs-tag .hljs-value, 41 | .hljs-phpdoc, 42 | .hljs-dartdoc, 43 | .tex .hljs-formula { 44 | color: #ed225d; 45 | } 46 | 47 | .hljs-title, 48 | .hljs-id, 49 | .scss .hljs-preprocessor { 50 | color: #900; 51 | font-weight: bold; 52 | } 53 | 54 | .hljs-list .hljs-keyword, 55 | .hljs-subst { 56 | font-weight: normal; 57 | } 58 | 59 | .hljs-class .hljs-title, 60 | .hljs-type, 61 | .vhdl .hljs-literal, 62 | .tex .hljs-command { 63 | color: #458; 64 | font-weight: bold; 65 | } 66 | 67 | .hljs-tag, 68 | .hljs-tag .hljs-title, 69 | .hljs-rules .hljs-property, 70 | .django .hljs-tag .hljs-keyword { 71 | color: #000080; 72 | font-weight: normal; 73 | } 74 | 75 | .hljs-attribute, 76 | .hljs-variable, 77 | .lisp .hljs-body { 78 | color: #008080; 79 | } 80 | 81 | .hljs-regexp { 82 | color: #009926; 83 | } 84 | 85 | .hljs-symbol, 86 | .ruby .hljs-symbol .hljs-string, 87 | .lisp .hljs-keyword, 88 | .clojure .hljs-keyword, 89 | .scheme .hljs-keyword, 90 | .tex .hljs-special, 91 | .hljs-prompt { 92 | color: #990073; 93 | } 94 | 95 | .hljs-built_in { 96 | color: #0086b3; 97 | } 98 | 99 | .hljs-preprocessor, 100 | .hljs-pragma, 101 | .hljs-pi, 102 | .hljs-doctype, 103 | .hljs-shebang, 104 | .hljs-cdata { 105 | color: #999; 106 | font-weight: bold; 107 | } 108 | 109 | .hljs-deletion { 110 | background: #fdd; 111 | } 112 | 113 | .hljs-addition { 114 | background: #dfd; 115 | } 116 | 117 | .diff .hljs-change { 118 | background: #0086b3; 119 | } 120 | 121 | .hljs-chunk { 122 | color: #aaa; 123 | } 124 | -------------------------------------------------------------------------------- /docs/assets/site.js: -------------------------------------------------------------------------------- 1 | /* global anchors */ 2 | 3 | // add anchor links to headers 4 | anchors.options.placement = 'left'; 5 | anchors.add('h3'); 6 | 7 | // Filter UI 8 | var tocElements = document.getElementById('toc') 9 | .getElementsByTagName('li'); 10 | 11 | document.getElementById('filter-input') 12 | .addEventListener('keyup', function (e) { 13 | 14 | var i, element, children; 15 | 16 | // enter key 17 | if (e.keyCode === 13) { 18 | // go to the first displayed item in the toc 19 | for (i = 0; i < tocElements.length; i++) { 20 | element = tocElements[i]; 21 | if (!element.classList.contains('display-none')) { 22 | location.replace(element.firstChild.href); 23 | return e.preventDefault(); 24 | } 25 | } 26 | } 27 | 28 | var match = function () { 29 | return true; 30 | }; 31 | 32 | var value = this.value.toLowerCase(); 33 | 34 | if (!value.match(/^\s*$/)) { 35 | match = function (element) { 36 | return element.firstChild.innerHTML.toLowerCase().indexOf(value) !== -1; 37 | }; 38 | } 39 | 40 | for (i = 0; i < tocElements.length; i++) { 41 | element = tocElements[i]; 42 | children = Array.from(element.getElementsByTagName('li')); 43 | if (match(element) || children.some(match)) { 44 | element.classList.remove('display-none'); 45 | } else { 46 | element.classList.add('display-none'); 47 | } 48 | } 49 | }); 50 | 51 | var toggles = document.getElementsByClassName('toggle-step-sibling'); 52 | for (var i = 0; i < toggles.length; i++) { 53 | toggles[i].addEventListener('click', toggleStepSibling); 54 | } 55 | 56 | function toggleStepSibling() { 57 | var stepSibling = this.parentNode.parentNode.parentNode.getElementsByClassName('toggle-target')[0]; 58 | var klass = 'display-none'; 59 | if (stepSibling.classList.contains(klass)) { 60 | stepSibling.classList.remove(klass); 61 | stepSibling.innerHTML = '▾'; 62 | } else { 63 | stepSibling.classList.add(klass); 64 | stepSibling.innerHTML = '▸'; 65 | } 66 | } 67 | 68 | var items = document.getElementsByClassName('toggle-sibling'); 69 | for (var j = 0; j < items.length; j++) { 70 | items[j].addEventListener('click', toggleSibling); 71 | } 72 | 73 | function toggleSibling() { 74 | var stepSibling = this.parentNode.getElementsByClassName('toggle-target')[0]; 75 | var icon = this.getElementsByClassName('icon')[0]; 76 | var klass = 'display-none'; 77 | if (stepSibling.classList.contains(klass)) { 78 | stepSibling.classList.remove(klass); 79 | icon.innerHTML = '▾'; 80 | } else { 81 | stepSibling.classList.add(klass); 82 | icon.innerHTML = '▸'; 83 | } 84 | } 85 | 86 | function showHashTarget(targetId) { 87 | var hashTarget = document.getElementById(targetId); 88 | // new target is hidden 89 | if (hashTarget && hashTarget.offsetHeight === 0 && 90 | hashTarget.parentNode.parentNode.classList.contains('display-none')) { 91 | hashTarget.parentNode.parentNode.classList.remove('display-none'); 92 | } 93 | } 94 | 95 | window.addEventListener('hashchange', function() { 96 | showHashTarget(location.hash.substring(1)); 97 | }); 98 | 99 | showHashTarget(location.hash.substring(1)); 100 | 101 | var toclinks = document.getElementsByClassName('pre-open'); 102 | for (var k = 0; k < toclinks.length; k++) { 103 | toclinks[k].addEventListener('mousedown', preOpen, false); 104 | } 105 | 106 | function preOpen() { 107 | showHashTarget(this.hash.substring(1)); 108 | } 109 | -------------------------------------------------------------------------------- /docs/assets/style.css: -------------------------------------------------------------------------------- 1 | .documentation { 2 | font-family: Helvetica, sans-serif; 3 | color: #666; 4 | line-height: 1.5; 5 | background: #f5f5f5; 6 | } 7 | 8 | .black { 9 | color: #666; 10 | } 11 | 12 | .bg-white { 13 | background-color: #fff; 14 | } 15 | 16 | h4 { 17 | margin: 20px 0 10px 0; 18 | } 19 | 20 | .documentation h3 { 21 | color: #000; 22 | } 23 | 24 | .border-bottom { 25 | border-color: #ddd; 26 | } 27 | 28 | a { 29 | color: #1184CE; 30 | text-decoration: none; 31 | } 32 | 33 | .documentation a[href]:hover { 34 | text-decoration: underline; 35 | } 36 | 37 | a:hover { 38 | cursor: pointer; 39 | } 40 | 41 | .py1-ul li { 42 | padding: 5px 0; 43 | } 44 | 45 | .max-height-100 { 46 | max-height: 100%; 47 | } 48 | 49 | section:target h3 { 50 | font-weight:700; 51 | } 52 | 53 | .documentation td, 54 | .documentation th { 55 | padding: .25rem .25rem; 56 | } 57 | 58 | h1:hover .anchorjs-link, 59 | h2:hover .anchorjs-link, 60 | h3:hover .anchorjs-link, 61 | h4:hover .anchorjs-link { 62 | opacity: 1; 63 | } 64 | 65 | .fix-3 { 66 | width: 25%; 67 | max-width: 244px; 68 | } 69 | 70 | .fix-3 { 71 | width: 25%; 72 | max-width: 244px; 73 | } 74 | 75 | @media (min-width: 52em) { 76 | .fix-margin-3 { 77 | margin-left: 25%; 78 | } 79 | } 80 | 81 | .pre, pre, code, .code { 82 | font-family: Source Code Pro,Menlo,Consolas,Liberation Mono,monospace; 83 | font-size: 14px; 84 | } 85 | 86 | .fill-light { 87 | background: #F9F9F9; 88 | } 89 | 90 | .width2 { 91 | width: 1rem; 92 | } 93 | 94 | .input { 95 | font-family: inherit; 96 | display: block; 97 | width: 100%; 98 | height: 2rem; 99 | padding: .5rem; 100 | margin-bottom: 1rem; 101 | border: 1px solid #ccc; 102 | font-size: .875rem; 103 | border-radius: 3px; 104 | box-sizing: border-box; 105 | } 106 | 107 | table { 108 | border-collapse: collapse; 109 | } 110 | 111 | .prose table th, 112 | .prose table td { 113 | text-align: left; 114 | padding:8px; 115 | border:1px solid #ddd; 116 | } 117 | 118 | .prose table th:nth-child(1) { border-right: none; } 119 | .prose table th:nth-child(2) { border-left: none; } 120 | 121 | .prose table { 122 | border:1px solid #ddd; 123 | } 124 | 125 | .prose-big { 126 | font-size: 18px; 127 | line-height: 30px; 128 | } 129 | 130 | .quiet { 131 | opacity: 0.7; 132 | } 133 | 134 | .minishadow { 135 | box-shadow: 2px 2px 10px #f3f3f3; 136 | } 137 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ml-svm 2.1.2 | Documentation 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 |

ml-svm

17 |
2.1.2
18 | 23 |
24 | 89 |
90 | 93 |
94 |
95 |
96 | 97 | 98 |
99 | 100 | 101 |
102 |

103 | SVM 104 |

105 | 106 | 107 | src/svm.js 108 | 109 | 110 |
111 | 112 | 113 |

Simplified version of the Sequential Minimal Optimization algorithm for training 114 | support vector machines

115 | 116 | 117 |
new SVM(options: [object])
118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 |
Parameters
129 |
130 | 131 |
132 |
133 | options ([object]) SVM options 134 | 135 |
136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 155 | 157 | 158 | 159 | 160 | 164 | 166 | 167 | 168 | 169 | 173 | 175 | 176 | 177 | 178 | 182 | 184 | 185 | 186 | 187 | 191 | 193 | 194 | 195 | 196 | 200 | 203 | 204 | 205 | 206 | 210 | 212 | 213 | 214 | 215 |
NameDescription
options.C [number] 152 | 153 | (default 1) 154 | regularization parameter 156 |
options.tol [number] 161 | 162 | (default 1e-4) 163 | numerical tolerance 165 |
options.alphaTol [number] 170 | 171 | (default 1e-6) 172 | alpha tolerance, threshold to decide support vectors 174 |
options.maxPasses [number] 179 | 180 | (default 10) 181 | max number of times to iterate over alphas without changing 183 |
options.maxIterations [number] 188 | 189 | (default 10000) 190 | max number of iterations 192 |
options.kernel [string] 197 | 198 | (default linear) 199 | the kind of kernel. 201 | List of kernels 202 |
options.random [function] 207 | 208 | (default Math.random) 209 | custom random number generator 211 |
216 | 217 |
218 | 219 |
220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 |
Static Members
232 |
233 | 234 |
235 |
236 |
237 | 238 | load(model) 239 |
240 |
241 | 299 |
300 | 301 |
302 | 303 | 304 | 305 | 306 |
Instance Members
307 |
308 | 309 |
310 |
311 |
312 | 313 | train(features, labels) 314 |
315 |
316 | 373 |
374 | 375 |
376 |
377 |
378 | 379 | predict(features) 380 |
381 |
382 | 440 |
441 | 442 |
443 |
444 |
445 | 446 | margin(features) 447 |
448 |
449 | 507 |
508 | 509 |
510 |
511 |
512 | 513 | supportVectors() 514 |
515 |
516 | 561 |
562 | 563 |
564 |
565 |
566 | 567 | toJSON() 568 |
569 |
570 | 615 |
616 | 617 |
618 | 619 | 620 | 621 | 622 |
623 | 624 | 625 | 626 |
627 |
628 |
629 | 630 | 631 | 632 | 633 | -------------------------------------------------------------------------------- /example/iris.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const iris = require('ml-dataset-iris'); 4 | const CV = require('ml-cross-validation'); 5 | const SVM = require('..'); 6 | 7 | 8 | var labels = iris.getClasses(); 9 | const features = iris.getNumbers(); 10 | 11 | // Separate in 2 categories 12 | labels = labels.map(label => { 13 | if(label === labels[0]) return 1; 14 | return -1; 15 | }); 16 | // 17 | // const features = [[20, 10],[30,30]]; 18 | // var labels = [-1, 1]; 19 | 20 | // var svm = new SVM(); 21 | // svm.train(features, labels); 22 | 23 | console.time('cv'); 24 | const result = CV.leaveOneOut(SVM, features, labels, { 25 | kernel: 'rbf', 26 | C: 1, 27 | kernelOptions: { 28 | sigma: 0.2, 29 | } 30 | }); 31 | console.timeEnd('cv'); 32 | console.log(result); 33 | 34 | -------------------------------------------------------------------------------- /example/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var SVM = require('..'); 4 | 5 | var options = { 6 | kernel: 'linear', 7 | C:1, 8 | }; 9 | 10 | var svm = new SVM(options); 11 | 12 | const features = [[0,2],[0,0],[2,2],[2,0]]; 13 | var labels = [-1, -1, 1, 1]; 14 | 15 | // var features = [[0,0],[0,1],[1,1],[1,0]]; 16 | // var labels = [1, -1, 1, -1]; 17 | 18 | for(var i=0; i<1000; i++) { 19 | svm.train(features, labels); 20 | svm.predict(features); 21 | } 22 | 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ml-svm", 3 | "version": "2.1.2", 4 | "description": "Support Vector Machine in Javascript", 5 | "main": "src/svm.js", 6 | "directories": { 7 | "lib": "src", 8 | "test": "test" 9 | }, 10 | "scripts": { 11 | "eslint": "eslint src test", 12 | "eslint-fix": "npm run eslint -- --fix", 13 | "test": "npm run test-mocha && npm run eslint", 14 | "test-mocha": "mocha --require should --reporter mocha-better-spec-reporter" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/mljs/svm" 19 | }, 20 | "keywords": [ 21 | "super", 22 | "vector", 23 | "machine", 24 | "data", 25 | "mining", 26 | "datamining", 27 | "machine", 28 | "learning" 29 | ], 30 | "author": "Miguel Asencio", 31 | "license": "MIT", 32 | "bugs": { 33 | "url": "https://github.com/mljs/svm/issues" 34 | }, 35 | "homepage": "https://github.com/mljs/svm", 36 | "devDependencies": { 37 | "eslint": "^3.1.0", 38 | "eslint-config-cheminfo": "^1.3.1", 39 | "eslint-plugin-no-only-tests": "^1.1.0", 40 | "ml-cross-validation": "^1.0.1", 41 | "ml-dataset-iris": "^1.0.0", 42 | "ml-xsadd": "^1.0.0", 43 | "mocha": "^3.0.2", 44 | "mocha-better-spec-reporter": "^3.0.2", 45 | "should": "^11.1.0" 46 | }, 47 | "dependencies": { 48 | "ml-kernel": "^2.2.0", 49 | "ml-stat": "^1.2.0" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/svm.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const Kernel = require('ml-kernel'); 3 | const stat = require('ml-stat').array; 4 | 5 | var defaultOptions = { 6 | C: 1, 7 | tol: 1e-4, 8 | maxPasses: 10, 9 | maxIterations: 10000, 10 | kernel: 'linear', 11 | alphaTol: 1e-6, 12 | random: Math.random, 13 | whitening: true 14 | }; 15 | 16 | /** 17 | * Simplified version of the Sequential Minimal Optimization algorithm for training 18 | * support vector machines 19 | * @param {object} [options] - SVM options 20 | * @param {number} [options.C=1] - regularization parameter 21 | * @param {number} [options.tol=1e-4] - numerical tolerance 22 | * @param {number} [options.alphaTol=1e-6] - alpha tolerance, threshold to decide support vectors 23 | * @param {number} [options.maxPasses=10] - max number of times to iterate over alphas without changing 24 | * @param {number} [options.maxIterations=10000] - max number of iterations 25 | * @param {string} [options.kernel=linear] - the kind of kernel. {@link https://github.com/mljs/kernel/tree/1252de5f9012776e6e0eb06c7b434b8631fb21f0 List of kernels} 26 | * @param {function} [options.random=Math.random] - custom random number generator 27 | * @constructor 28 | */ 29 | function SVM(options) { 30 | this.options = Object.assign({}, defaultOptions, options); 31 | 32 | this.kernel = new Kernel(this.options.kernel, this.options.kernelOptions); 33 | this.b = 0; 34 | } 35 | 36 | /** 37 | * Train the SVM model 38 | * @param {Array>} features - training data features 39 | * @param {Array} labels - training data labels in the domain {1,-1} 40 | */ 41 | SVM.prototype.train = function (features, labels) { 42 | if (features.length !== labels.length) { 43 | throw new Error('Features and labels should have the same length'); 44 | } 45 | if (features.length < 2) { 46 | throw new Error('Cannot train with less than 2 observations'); 47 | } 48 | this._trained = false; 49 | this._loaded = false; 50 | this.N = labels.length; 51 | this.D = features[0].length; 52 | if (this.options.whitening) { 53 | this.X = new Array(this.N); 54 | for (var i = 0; i < this.N; i++) { 55 | this.X[i] = new Array(this.D); 56 | } 57 | this.minMax = new Array(this.D); 58 | // Apply normalization and keep normalization parameters 59 | for (var j = 0; j < this.D; j++) { 60 | var d = new Array(this.N); 61 | for (i = 0; i < this.N; i++) { 62 | d[i] = features[i][j]; 63 | } 64 | this.minMax[j] = stat.minMax(d); 65 | for (i = 0; i < this.N; i++) { 66 | this.X[i][j] = (features[i][j] - this.minMax[j].min) / (this.minMax[j].max - this.minMax[j].min); 67 | } 68 | } 69 | } else { 70 | this.X = features; 71 | } 72 | this.Y = labels; 73 | this.b = 0; 74 | this.W = undefined; 75 | 76 | var kernel = this.kernel.compute(this.X); 77 | var m = labels.length; 78 | var alpha = new Array(m).fill(0); 79 | this.alphas = alpha; 80 | for (var a = 0; a < m; a++) { 81 | alpha[a] = 0; 82 | } 83 | 84 | var b1 = 0, 85 | b2 = 0, 86 | iter = 0, 87 | passes = 0, 88 | Ei = 0, 89 | Ej = 0, 90 | ai = 0, 91 | aj = 0, 92 | L = 0, 93 | H = 0, 94 | eta = 0; 95 | 96 | while (passes < this.options.maxPasses && iter < this.options.maxIterations) { 97 | var numChange = 0; 98 | for (i = 0; i < m; i++) { 99 | Ei = this._marginOnePrecomputed(i, kernel) - labels[i]; 100 | if (labels[i] * Ei < -this.options.tol && alpha[i] < this.options.C || labels[i] * Ei > this.options.tol && alpha[i] > 0) { 101 | j = i; 102 | while (j === i) { 103 | j = Math.floor(this.options.random() * m); 104 | } 105 | 106 | Ej = this._marginOnePrecomputed(j, kernel) - labels[j]; 107 | ai = alpha[i]; 108 | aj = alpha[j]; 109 | if (labels[i] === labels[j]) { 110 | L = Math.max(0, ai + aj - this.options.C); 111 | H = Math.min(this.options.C, ai + aj); 112 | } else { 113 | L = Math.max(0, aj - ai); 114 | H = Math.min(this.options.C, this.options.C + aj + ai); 115 | } 116 | if (Math.abs(L - H) < 1e-4) { 117 | continue; 118 | } 119 | 120 | eta = 2 * kernel[i][j] - kernel[i][i] - kernel[j][j]; 121 | if (eta >= 0) { 122 | continue; 123 | } 124 | var newaj = alpha[j] - labels[j] * (Ei - Ej) / eta; 125 | if (newaj > H) { 126 | newaj = H; 127 | } else if (newaj < L) { 128 | newaj = L; 129 | } 130 | if (Math.abs(aj - newaj) < 10e-4) { 131 | continue; 132 | } 133 | alpha[j] = newaj; 134 | alpha[i] = alpha[i] + labels[i] * labels[j] * (aj - newaj); 135 | b1 = this.b - Ei - labels[i] * (alpha[i] - ai) * kernel[i][i] - labels[j] * (alpha[j] - aj) * kernel[i][j]; 136 | b2 = this.b - Ej - labels[i] * (alpha[i] - ai) * kernel[i][j] - labels[j] * (alpha[j] - aj) * kernel[j][j]; 137 | this.b = (b1 + b2) / 2; 138 | if (alpha[i] < this.options.C && alpha[i] > 0) { 139 | this.b = b1; 140 | } 141 | if (alpha[j] < this.options.C && alpha[j] > 0) { 142 | this.b = b2; 143 | } 144 | numChange += 1; 145 | } 146 | } 147 | iter++; 148 | if (numChange === 0) { 149 | passes += 1; 150 | } else { 151 | passes = 0; 152 | } 153 | } 154 | if (iter === this.options.maxIterations) { 155 | throw new Error('max iterations reached'); 156 | } 157 | 158 | this.iterations = iter; 159 | 160 | // Compute the weights (useful for fast decision on new test instances when linear SVM) 161 | if (this.options.kernel === 'linear') { 162 | this.W = new Array(this.D); 163 | for (var r = 0; r < this.D; r++) { 164 | this.W[r] = 0; 165 | for (var w = 0; w < m; w++) { 166 | this.W[r] += labels[w] * alpha[w] * this.X[w][r]; 167 | } 168 | } 169 | } 170 | 171 | // Keep only support vectors 172 | // It will compute decision on new test instances faster 173 | // We also keep the index of the support vectors 174 | // in the original data 175 | var nX = []; 176 | var nY = []; 177 | var nAlphas = []; 178 | this._supportVectorIdx = []; 179 | for (i = 0; i < this.N; i++) { 180 | if (this.alphas[i] > this.options.alphaTol) { 181 | nX.push(this.X[i]); 182 | nY.push(labels[i]); 183 | nAlphas.push(this.alphas[i]); 184 | this._supportVectorIdx.push(i); 185 | 186 | } 187 | } 188 | this.X = nX; 189 | this.Y = nY; 190 | this.N = nX.length; 191 | this.alphas = nAlphas; 192 | 193 | 194 | // A flag to say this SVM has been trained 195 | this._trained = true; 196 | }; 197 | 198 | /** 199 | * Get prediction ({-1,1}) given one observation's features. 200 | * @private 201 | * @param {Array} p The observation's features. 202 | * @return {number} Classification result ({-1,1}) 203 | */ 204 | SVM.prototype.predictOne = function (p) { 205 | var margin = this.marginOne(p); 206 | return margin > 0 ? 1 : -1; 207 | }; 208 | 209 | /** 210 | * Predict the classification outcome of a trained svm given one or several observations' features. 211 | * @param {Array} features - The observation(s)' features 212 | * @return {Array|number} An array of {-1, 1} if several observations are given or a number if one observation 213 | * is given 214 | */ 215 | SVM.prototype.predict = function (features) { 216 | if (!this._trained && !this._loaded) { 217 | throw new Error('Cannot predict, you need to train the SVM first'); 218 | } 219 | 220 | if (Array.isArray(features) && Array.isArray(features[0])) { 221 | return features.map(this.predictOne.bind(this)); 222 | } else { 223 | return this.predictOne(features); 224 | } 225 | }; 226 | 227 | /** 228 | * Get margin given one observation's features 229 | * @private 230 | * @param {Array} features - Features 231 | * @param {boolean} [noWhitening=false] 232 | * @return {number} - The computed margin 233 | */ 234 | SVM.prototype.marginOne = function (features, noWhitening) { 235 | // Apply normalization 236 | if (this.options.whitening && !noWhitening) { 237 | features = this._applyWhitening(features); 238 | } 239 | var ans = this.b, i; 240 | if (this.options.kernel === 'linear' && this.W) { 241 | // Use weights, it's faster 242 | for (i = 0; i < this.W.length; i++) { 243 | ans += this.W[i] * features[i]; 244 | } 245 | } else { 246 | for (i = 0; i < this.N; i++) { 247 | ans += this.alphas[i] * this.Y[i] * this.kernel.compute([features], [this.X[i]])[0][0]; 248 | } 249 | } 250 | return ans; 251 | }; 252 | 253 | 254 | /** 255 | * Get a margin using the precomputed kernel. Much faster than normal margin computation 256 | * @private 257 | * @param {number} index - Train data index 258 | * @param {Array< Array >} kernel - The precomputed kernel 259 | * @return {number} Computed margin 260 | * @private 261 | */ 262 | SVM.prototype._marginOnePrecomputed = function (index, kernel) { 263 | var ans = this.b, i; 264 | for (i = 0; i < this.N; i++) { 265 | ans += this.alphas[i] * this.Y[i] * kernel[index][i]; 266 | } 267 | return ans; 268 | }; 269 | 270 | 271 | /** 272 | * Returns the margin of one or several observations given its features 273 | * @param {Array >|Array} features - Features from on or several observations. 274 | * @return {number|Array} The computed margin. Is an Array if several observations' features given, or a number if 275 | * only one observation's features given 276 | */ 277 | SVM.prototype.margin = function (features) { 278 | if (Array.isArray(features)) { 279 | return features.map(this.marginOne.bind(this)); 280 | } else { 281 | return this.marginOne(features); 282 | } 283 | }; 284 | 285 | /** 286 | * Get support vectors indexes of the trained classifier. WARINNG: this method does not work for svm instances 287 | * created from {@link #SVM.load load} if linear kernel 288 | * @return {Array} The indices in the training vector of the support vectors 289 | */ 290 | SVM.prototype.supportVectors = function () { 291 | if (!this._trained && !this._loaded) { 292 | throw new Error('Cannot get support vectors, you need to train the SVM first'); 293 | } 294 | if (this._loaded && this.options.kernel === 'linear') { 295 | throw new Error('Cannot get support vectors from saved linear model, you need to train the SVM to have them'); 296 | } 297 | return this._supportVectorIdx; 298 | }; 299 | 300 | /** 301 | * Create a SVM instance from a saved model 302 | * @param {object} model - Object such as returned by a trained SVM instance with {@link #SVM#toJSON toJSON} 303 | * @return {SVM} Instance of svm classifier 304 | */ 305 | SVM.load = function (model) { 306 | this._loaded = true; 307 | this._trained = false; 308 | var svm = new SVM(model.options); 309 | if (model.options.kernel === 'linear') { 310 | svm.W = model.W.slice(); 311 | svm.D = svm.W.length; 312 | } else { 313 | svm.X = model.X.slice(); 314 | svm.Y = model.Y.slice(); 315 | svm.alphas = model.alphas.slice(); 316 | svm.N = svm.X.length; 317 | svm.D = svm.X[0].length; 318 | } 319 | svm.minMax = model.minMax; 320 | svm.b = model.b; 321 | svm._loaded = true; 322 | svm._trained = false; 323 | return svm; 324 | }; 325 | 326 | /** 327 | * Export the minimal object that enables to reload the model 328 | * @return {object} Model object that can be reused with {@link #SVM.load load} 329 | */ 330 | SVM.prototype.toJSON = function () { 331 | if (!this._trained && !this._loaded) { 332 | throw new Error('Cannot export, you need to train the SVM first'); 333 | } 334 | 335 | var model = {}; 336 | model.options = Object.assign({}, this.options); 337 | model.b = this.b; 338 | model.minMax = this.minMax; 339 | if (model.options.kernel === 'linear') { 340 | model.W = this.W.slice(); 341 | } else { 342 | // Exporting non-linear models is heavier 343 | model.X = this.X.slice(); 344 | model.Y = this.Y.slice(); 345 | model.alphas = this.alphas.slice(); 346 | } 347 | return model; 348 | }; 349 | 350 | SVM.prototype._applyWhitening = function (features) { 351 | if (!this.minMax) { 352 | throw new Error('Could not apply whitening'); 353 | } 354 | 355 | var whitened = new Array(features.length); 356 | for (var j = 0; j < features.length; j++) { 357 | whitened[j] = (features[j] - this.minMax[j].min) / (this.minMax[j].max - this.minMax[j].min); 358 | } 359 | return whitened; 360 | }; 361 | 362 | module.exports = SVM; 363 | -------------------------------------------------------------------------------- /test/.eslintrc.yml: -------------------------------------------------------------------------------- 1 | env: 2 | mocha: true 3 | -------------------------------------------------------------------------------- /test/svm.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var SVM = require('..'); 3 | var xsadd = require('ml-xsadd'); 4 | var random = new xsadd(0).random; 5 | 6 | var data = { 7 | linear1: { 8 | features: [[0, -200], [400, 600], [200, 0]], 9 | labels: [-1, 1, -1] 10 | }, 11 | linear2: { 12 | features: [[0, -200], [1, 600], [1 / 2, 0]], 13 | labels: [-1, 1, -1] 14 | }, 15 | linear3: { 16 | features: [[0, 1], [4, 6], [2, 0]], 17 | labels: [-1, 1, -1] 18 | }, 19 | xor: { 20 | features: [[0, 0], [0, 1], [1, 1], [1, 0]], 21 | labels: [1, -1, 1, -1] 22 | } 23 | }; 24 | describe('SVM', function () { 25 | it('should solve a linearly separable case', function () { 26 | var features = data.linear1.features; 27 | var labels = data.linear1.labels; 28 | var svm = new SVM({random}); 29 | svm.train(features, labels); 30 | svm.predict(features).should.eql(labels); 31 | svm.predict(features[0]).should.eql(labels[0]); 32 | svm.supportVectors().should.eql([1, 2]); 33 | }); 34 | 35 | it('should reload the linear model', function () { 36 | var features = data.linear3.features; 37 | var labels = data.linear3.labels; 38 | var svm = new SVM({random}); 39 | svm.train(features, labels); 40 | var exp = JSON.parse(JSON.stringify(svm)); 41 | var reloadedSvm = SVM.load(exp); 42 | reloadedSvm.predict(features).should.eql(labels); 43 | (function () { 44 | reloadedSvm.supportVectors(); 45 | }).should.throw(/Cannot get support vectors from saved linear model/); 46 | }); 47 | 48 | it('should solve a linearly separable case without whitening', function () { 49 | var features = data.linear3.features; 50 | var labels = data.linear3.labels; 51 | var svm = new SVM({ 52 | random, 53 | whitening: false 54 | }); 55 | svm.train(features, labels); 56 | svm.predict(features).should.eql(labels); 57 | }); 58 | 59 | it('Some cases are not separable without whitening', function () { 60 | var features = data.linear2.features; 61 | var labels = data.linear2.labels; 62 | var svm = new SVM({ 63 | random 64 | }); 65 | var svm1 = new SVM({ 66 | random, 67 | whitening: false 68 | }); 69 | 70 | svm.train(features, labels); 71 | svm1.train(features, labels); 72 | 73 | svm.predict(features).should.eql(labels); 74 | svm1.predict(features).should.not.eql(labels); 75 | }); 76 | 77 | 78 | it('should solve xor with rbf', function () { 79 | var svm = new SVM({ 80 | kernel: 'rbf', 81 | kernelOptions: { 82 | sigma: 0.1 83 | }, 84 | random 85 | }); 86 | //var features = data.xor.features; 87 | var width = 200, height = 200; 88 | var features = [[width / 4, height / 4], [3 * width / 4, height / 4], [3 * width / 4, 3 * height / 4], [width / 4, 3 * height / 4]]; 89 | // var labels = data.xor.labels; 90 | var labels = [-1, 1, -1, 1]; 91 | svm.train(features, labels); 92 | svm.predict(features).should.eql(labels); 93 | }); 94 | 95 | it('should solve xor with reloaded model', function () { 96 | var svm = new SVM({ 97 | kernel: 'rbf', 98 | kernelOptions: { 99 | sigma: 0.1 100 | }, 101 | random 102 | }); 103 | var features = data.xor.features; 104 | var labels = data.xor.labels; 105 | svm.train(features, labels); 106 | var model = JSON.parse(JSON.stringify(svm)); 107 | var reloadedSvm = SVM.load(model); 108 | reloadedSvm.predict(features).should.eql(labels); 109 | }); 110 | }); 111 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | acorn-jsx@^3.0.0: 4 | version "3.0.1" 5 | resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" 6 | dependencies: 7 | acorn "^3.0.4" 8 | 9 | acorn@^3.0.4: 10 | version "3.3.0" 11 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" 12 | 13 | acorn@^4.0.1: 14 | version "4.0.3" 15 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.3.tgz#1a3e850b428e73ba6b09d1cc527f5aaad4d03ef1" 16 | 17 | ajv-keywords@^1.0.0: 18 | version "1.1.1" 19 | resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.1.1.tgz#02550bc605a3e576041565628af972e06c549d50" 20 | 21 | ajv@^4.7.0: 22 | version "4.8.0" 23 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.8.0.tgz#011df5c4a08edb29574a477269afb15a6f97abe5" 24 | dependencies: 25 | co "^4.6.0" 26 | json-stable-stringify "^1.0.1" 27 | 28 | ansi-escapes@^1.1.0: 29 | version "1.4.0" 30 | resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" 31 | 32 | ansi-regex@^2.0.0: 33 | version "2.0.0" 34 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.0.0.tgz#c5061b6e0ef8a81775e50f5d66151bf6bf371107" 35 | 36 | ansi-styles@^2.2.1: 37 | version "2.2.1" 38 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" 39 | 40 | argparse@^1.0.7: 41 | version "1.0.9" 42 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" 43 | dependencies: 44 | sprintf-js "~1.0.2" 45 | 46 | array-union@^1.0.1: 47 | version "1.0.2" 48 | resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" 49 | dependencies: 50 | array-uniq "^1.0.1" 51 | 52 | array-uniq@^1.0.1: 53 | version "1.0.3" 54 | resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" 55 | 56 | arrify@^1.0.0: 57 | version "1.0.1" 58 | resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" 59 | 60 | balanced-match@^0.4.1: 61 | version "0.4.2" 62 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" 63 | 64 | brace-expansion@^1.0.0: 65 | version "1.1.6" 66 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9" 67 | dependencies: 68 | balanced-match "^0.4.1" 69 | concat-map "0.0.1" 70 | 71 | browser-stdout@1.3.0: 72 | version "1.3.0" 73 | resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.0.tgz#f351d32969d32fa5d7a5567154263d928ae3bd1f" 74 | 75 | caller-path@^0.1.0: 76 | version "0.1.0" 77 | resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" 78 | dependencies: 79 | callsites "^0.2.0" 80 | 81 | callsites@^0.2.0: 82 | version "0.2.0" 83 | resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" 84 | 85 | chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3, chalk@1.1.3: 86 | version "1.1.3" 87 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" 88 | dependencies: 89 | ansi-styles "^2.2.1" 90 | escape-string-regexp "^1.0.2" 91 | has-ansi "^2.0.0" 92 | strip-ansi "^3.0.0" 93 | supports-color "^2.0.0" 94 | 95 | circular-json@^0.3.0: 96 | version "0.3.1" 97 | resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d" 98 | 99 | cli-cursor@^1.0.1: 100 | version "1.0.2" 101 | resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" 102 | dependencies: 103 | restore-cursor "^1.0.1" 104 | 105 | cli-width@^2.0.0: 106 | version "2.1.0" 107 | resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" 108 | 109 | co@^4.6.0: 110 | version "4.6.0" 111 | resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" 112 | 113 | code-point-at@^1.0.0: 114 | version "1.0.1" 115 | resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.0.1.tgz#1104cd34f9b5b45d3eba88f1babc1924e1ce35fb" 116 | dependencies: 117 | number-is-nan "^1.0.0" 118 | 119 | commander@2.9.0: 120 | version "2.9.0" 121 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" 122 | dependencies: 123 | graceful-readlink ">= 1.0.0" 124 | 125 | concat-map@0.0.1: 126 | version "0.0.1" 127 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 128 | 129 | concat-stream@^1.4.6: 130 | version "1.5.2" 131 | resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.2.tgz#708978624d856af41a5a741defdd261da752c266" 132 | dependencies: 133 | inherits "~2.0.1" 134 | readable-stream "~2.0.0" 135 | typedarray "~0.0.5" 136 | 137 | core-util-is@~1.0.0: 138 | version "1.0.2" 139 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" 140 | 141 | d@^0.1.1, d@~0.1.1: 142 | version "0.1.1" 143 | resolved "https://registry.yarnpkg.com/d/-/d-0.1.1.tgz#da184c535d18d8ee7ba2aa229b914009fae11309" 144 | dependencies: 145 | es5-ext "~0.10.2" 146 | 147 | data-uri-to-buffer@0.0.4: 148 | version "0.0.4" 149 | resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-0.0.4.tgz#46e13ab9da8e309745c8d01ce547213ebdb2fe3f" 150 | 151 | debug@^2.1.1, debug@2.2.0: 152 | version "2.2.0" 153 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" 154 | dependencies: 155 | ms "0.7.1" 156 | 157 | deep-is@~0.1.3: 158 | version "0.1.3" 159 | resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" 160 | 161 | del@^2.0.2: 162 | version "2.2.2" 163 | resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" 164 | dependencies: 165 | globby "^5.0.0" 166 | is-path-cwd "^1.0.0" 167 | is-path-in-cwd "^1.0.0" 168 | object-assign "^4.0.1" 169 | pify "^2.0.0" 170 | pinkie-promise "^2.0.0" 171 | rimraf "^2.2.8" 172 | 173 | diff@1.4.0: 174 | version "1.4.0" 175 | resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" 176 | 177 | diff@2.2.2: 178 | version "2.2.2" 179 | resolved "https://registry.yarnpkg.com/diff/-/diff-2.2.2.tgz#5f813f994a0caa1a2ef79200759c4b89ca233a81" 180 | 181 | doctrine@^1.2.2: 182 | version "1.5.0" 183 | resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" 184 | dependencies: 185 | esutils "^2.0.2" 186 | isarray "^1.0.0" 187 | 188 | es5-ext@^0.10.7, es5-ext@^0.10.8, es5-ext@~0.10.11, es5-ext@~0.10.2, es5-ext@~0.10.7: 189 | version "0.10.12" 190 | resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.12.tgz#aa84641d4db76b62abba5e45fd805ecbab140047" 191 | dependencies: 192 | es6-iterator "2" 193 | es6-symbol "~3.1" 194 | 195 | es6-iterator@2: 196 | version "2.0.0" 197 | resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.0.tgz#bd968567d61635e33c0b80727613c9cb4b096bac" 198 | dependencies: 199 | d "^0.1.1" 200 | es5-ext "^0.10.7" 201 | es6-symbol "3" 202 | 203 | es6-map@^0.1.3: 204 | version "0.1.4" 205 | resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.4.tgz#a34b147be224773a4d7da8072794cefa3632b897" 206 | dependencies: 207 | d "~0.1.1" 208 | es5-ext "~0.10.11" 209 | es6-iterator "2" 210 | es6-set "~0.1.3" 211 | es6-symbol "~3.1.0" 212 | event-emitter "~0.3.4" 213 | 214 | es6-set@~0.1.3: 215 | version "0.1.4" 216 | resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.4.tgz#9516b6761c2964b92ff479456233a247dc707ce8" 217 | dependencies: 218 | d "~0.1.1" 219 | es5-ext "~0.10.11" 220 | es6-iterator "2" 221 | es6-symbol "3" 222 | event-emitter "~0.3.4" 223 | 224 | es6-symbol@~3.1, es6-symbol@~3.1.0, es6-symbol@3: 225 | version "3.1.0" 226 | resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.0.tgz#94481c655e7a7cad82eba832d97d5433496d7ffa" 227 | dependencies: 228 | d "~0.1.1" 229 | es5-ext "~0.10.11" 230 | 231 | es6-weak-map@^2.0.1: 232 | version "2.0.1" 233 | resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.1.tgz#0d2bbd8827eb5fb4ba8f97fbfea50d43db21ea81" 234 | dependencies: 235 | d "^0.1.1" 236 | es5-ext "^0.10.8" 237 | es6-iterator "2" 238 | es6-symbol "3" 239 | 240 | escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5, escape-string-regexp@1.0.5: 241 | version "1.0.5" 242 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 243 | 244 | escope@^3.6.0: 245 | version "3.6.0" 246 | resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" 247 | dependencies: 248 | es6-map "^0.1.3" 249 | es6-weak-map "^2.0.1" 250 | esrecurse "^4.1.0" 251 | estraverse "^4.1.1" 252 | 253 | eslint-config-cheminfo@^1.3.1: 254 | version "1.5.1" 255 | resolved "https://registry.yarnpkg.com/eslint-config-cheminfo/-/eslint-config-cheminfo-1.5.1.tgz#c1ecda74cf2f9165a0fff13c1a2b4b63f660e47b" 256 | 257 | eslint-plugin-no-only-tests@^1.1.0: 258 | version "1.1.0" 259 | resolved "https://registry.yarnpkg.com/eslint-plugin-no-only-tests/-/eslint-plugin-no-only-tests-1.1.0.tgz#24068cafdbccc08d2f9c2d962005793c5940fcd5" 260 | 261 | eslint@^3.1.0: 262 | version "3.8.0" 263 | resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.8.0.tgz#4fbbf6833d66654860c23a099c47a0f086de34b7" 264 | dependencies: 265 | chalk "^1.1.3" 266 | concat-stream "^1.4.6" 267 | debug "^2.1.1" 268 | doctrine "^1.2.2" 269 | escope "^3.6.0" 270 | espree "^3.3.1" 271 | estraverse "^4.2.0" 272 | esutils "^2.0.2" 273 | file-entry-cache "^2.0.0" 274 | glob "^7.0.3" 275 | globals "^9.2.0" 276 | ignore "^3.1.5" 277 | imurmurhash "^0.1.4" 278 | inquirer "^0.12.0" 279 | is-my-json-valid "^2.10.0" 280 | is-resolvable "^1.0.0" 281 | js-yaml "^3.5.1" 282 | json-stable-stringify "^1.0.0" 283 | levn "^0.3.0" 284 | lodash "^4.0.0" 285 | mkdirp "^0.5.0" 286 | natural-compare "^1.4.0" 287 | optionator "^0.8.2" 288 | path-is-inside "^1.0.1" 289 | pluralize "^1.2.1" 290 | progress "^1.1.8" 291 | require-uncached "^1.0.2" 292 | shelljs "^0.6.0" 293 | strip-bom "^3.0.0" 294 | strip-json-comments "~1.0.1" 295 | table "^3.7.8" 296 | text-table "~0.2.0" 297 | user-home "^2.0.0" 298 | 299 | espree@^3.3.1: 300 | version "3.3.2" 301 | resolved "https://registry.yarnpkg.com/espree/-/espree-3.3.2.tgz#dbf3fadeb4ecb4d4778303e50103b3d36c88b89c" 302 | dependencies: 303 | acorn "^4.0.1" 304 | acorn-jsx "^3.0.0" 305 | 306 | esprima@^2.6.0: 307 | version "2.7.3" 308 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" 309 | 310 | esrecurse@^4.1.0: 311 | version "4.1.0" 312 | resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220" 313 | dependencies: 314 | estraverse "~4.1.0" 315 | object-assign "^4.0.1" 316 | 317 | estraverse@^4.1.1, estraverse@^4.2.0: 318 | version "4.2.0" 319 | resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" 320 | 321 | estraverse@~4.1.0: 322 | version "4.1.1" 323 | resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2" 324 | 325 | esutils@^2.0.2: 326 | version "2.0.2" 327 | resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" 328 | 329 | event-emitter@~0.3.4: 330 | version "0.3.4" 331 | resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.4.tgz#8d63ddfb4cfe1fae3b32ca265c4c720222080bb5" 332 | dependencies: 333 | d "~0.1.1" 334 | es5-ext "~0.10.7" 335 | 336 | exit-hook@^1.0.0: 337 | version "1.1.1" 338 | resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" 339 | 340 | fast-levenshtein@~2.0.4: 341 | version "2.0.5" 342 | resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.5.tgz#bd33145744519ab1c36c3ee9f31f08e9079b67f2" 343 | 344 | figures@^1.3.5: 345 | version "1.7.0" 346 | resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" 347 | dependencies: 348 | escape-string-regexp "^1.0.5" 349 | object-assign "^4.1.0" 350 | 351 | file-entry-cache@^2.0.0: 352 | version "2.0.0" 353 | resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" 354 | dependencies: 355 | flat-cache "^1.2.1" 356 | object-assign "^4.0.1" 357 | 358 | flat-cache@^1.2.1: 359 | version "1.2.1" 360 | resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.1.tgz#6c837d6225a7de5659323740b36d5361f71691ff" 361 | dependencies: 362 | circular-json "^0.3.0" 363 | del "^2.0.2" 364 | graceful-fs "^4.1.2" 365 | write "^0.2.1" 366 | 367 | fs.realpath@^1.0.0: 368 | version "1.0.0" 369 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 370 | 371 | generate-function@^2.0.0: 372 | version "2.0.0" 373 | resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" 374 | 375 | generate-object-property@^1.1.0: 376 | version "1.2.0" 377 | resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" 378 | dependencies: 379 | is-property "^1.0.0" 380 | 381 | glob@^7.0.3, glob@^7.0.5: 382 | version "7.1.1" 383 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" 384 | dependencies: 385 | fs.realpath "^1.0.0" 386 | inflight "^1.0.4" 387 | inherits "2" 388 | minimatch "^3.0.2" 389 | once "^1.3.0" 390 | path-is-absolute "^1.0.0" 391 | 392 | glob@7.0.5: 393 | version "7.0.5" 394 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.5.tgz#b4202a69099bbb4d292a7c1b95b6682b67ebdc95" 395 | dependencies: 396 | fs.realpath "^1.0.0" 397 | inflight "^1.0.4" 398 | inherits "2" 399 | minimatch "^3.0.2" 400 | once "^1.3.0" 401 | path-is-absolute "^1.0.0" 402 | 403 | globals@^9.2.0: 404 | version "9.12.0" 405 | resolved "https://registry.yarnpkg.com/globals/-/globals-9.12.0.tgz#992ce90828c3a55fa8f16fada177adb64664cf9d" 406 | 407 | globby@^5.0.0: 408 | version "5.0.0" 409 | resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" 410 | dependencies: 411 | array-union "^1.0.1" 412 | arrify "^1.0.0" 413 | glob "^7.0.3" 414 | object-assign "^4.0.1" 415 | pify "^2.0.0" 416 | pinkie-promise "^2.0.0" 417 | 418 | graceful-fs@^4.1.2: 419 | version "4.1.9" 420 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.9.tgz#baacba37d19d11f9d146d3578bc99958c3787e29" 421 | 422 | graceful-fs@4.1.3: 423 | version "4.1.3" 424 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.3.tgz#92033ce11113c41e2628d61fdfa40bc10dc0155c" 425 | 426 | "graceful-readlink@>= 1.0.0": 427 | version "1.0.1" 428 | resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" 429 | 430 | growl@1.9.2: 431 | version "1.9.2" 432 | resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f" 433 | 434 | has-ansi@^2.0.0: 435 | version "2.0.0" 436 | resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" 437 | dependencies: 438 | ansi-regex "^2.0.0" 439 | 440 | has-flag@^1.0.0: 441 | version "1.0.0" 442 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" 443 | 444 | ignore@^3.1.5: 445 | version "3.2.0" 446 | resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.0.tgz#8d88f03c3002a0ac52114db25d2c673b0bf1e435" 447 | 448 | imurmurhash@^0.1.4: 449 | version "0.1.4" 450 | resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" 451 | 452 | inflight@^1.0.4: 453 | version "1.0.6" 454 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 455 | dependencies: 456 | once "^1.3.0" 457 | wrappy "1" 458 | 459 | inherits@~2.0.1, inherits@2: 460 | version "2.0.3" 461 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 462 | 463 | inquirer@^0.12.0: 464 | version "0.12.0" 465 | resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" 466 | dependencies: 467 | ansi-escapes "^1.1.0" 468 | ansi-regex "^2.0.0" 469 | chalk "^1.0.0" 470 | cli-cursor "^1.0.1" 471 | cli-width "^2.0.0" 472 | figures "^1.3.5" 473 | lodash "^4.3.0" 474 | readline2 "^1.0.1" 475 | run-async "^0.1.0" 476 | rx-lite "^3.1.2" 477 | string-width "^1.0.1" 478 | strip-ansi "^3.0.0" 479 | through "^2.3.6" 480 | 481 | is-fullwidth-code-point@^1.0.0: 482 | version "1.0.0" 483 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" 484 | dependencies: 485 | number-is-nan "^1.0.0" 486 | 487 | is-my-json-valid@^2.10.0: 488 | version "2.15.0" 489 | resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz#936edda3ca3c211fd98f3b2d3e08da43f7b2915b" 490 | dependencies: 491 | generate-function "^2.0.0" 492 | generate-object-property "^1.1.0" 493 | jsonpointer "^4.0.0" 494 | xtend "^4.0.0" 495 | 496 | is-path-cwd@^1.0.0: 497 | version "1.0.0" 498 | resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" 499 | 500 | is-path-in-cwd@^1.0.0: 501 | version "1.0.0" 502 | resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" 503 | dependencies: 504 | is-path-inside "^1.0.0" 505 | 506 | is-path-inside@^1.0.0: 507 | version "1.0.0" 508 | resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" 509 | dependencies: 510 | path-is-inside "^1.0.1" 511 | 512 | is-property@^1.0.0: 513 | version "1.0.2" 514 | resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" 515 | 516 | is-resolvable@^1.0.0: 517 | version "1.0.0" 518 | resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" 519 | dependencies: 520 | tryit "^1.0.1" 521 | 522 | isarray@^1.0.0, isarray@~1.0.0: 523 | version "1.0.0" 524 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 525 | 526 | js-yaml@^3.5.1: 527 | version "3.6.1" 528 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.6.1.tgz#6e5fe67d8b205ce4d22fad05b7781e8dadcc4b30" 529 | dependencies: 530 | argparse "^1.0.7" 531 | esprima "^2.6.0" 532 | 533 | json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: 534 | version "1.0.1" 535 | resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" 536 | dependencies: 537 | jsonify "~0.0.0" 538 | 539 | json3@3.3.2: 540 | version "3.3.2" 541 | resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" 542 | 543 | jsonify@~0.0.0: 544 | version "0.0.0" 545 | resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" 546 | 547 | jsonpointer@^4.0.0: 548 | version "4.0.0" 549 | resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.0.tgz#6661e161d2fc445f19f98430231343722e1fcbd5" 550 | 551 | levn@^0.3.0, levn@~0.3.0: 552 | version "0.3.0" 553 | resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" 554 | dependencies: 555 | prelude-ls "~1.1.2" 556 | type-check "~0.3.2" 557 | 558 | lodash._baseassign@^3.0.0: 559 | version "3.2.0" 560 | resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" 561 | dependencies: 562 | lodash._basecopy "^3.0.0" 563 | lodash.keys "^3.0.0" 564 | 565 | lodash._basecopy@^3.0.0: 566 | version "3.0.1" 567 | resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" 568 | 569 | lodash._basecreate@^3.0.0: 570 | version "3.0.3" 571 | resolved "https://registry.yarnpkg.com/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz#1bc661614daa7fc311b7d03bf16806a0213cf821" 572 | 573 | lodash._getnative@^3.0.0: 574 | version "3.9.1" 575 | resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" 576 | 577 | lodash._isiterateecall@^3.0.0: 578 | version "3.0.9" 579 | resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" 580 | 581 | lodash.create@3.1.1: 582 | version "3.1.1" 583 | resolved "https://registry.yarnpkg.com/lodash.create/-/lodash.create-3.1.1.tgz#d7f2849f0dbda7e04682bb8cd72ab022461debe7" 584 | dependencies: 585 | lodash._baseassign "^3.0.0" 586 | lodash._basecreate "^3.0.0" 587 | lodash._isiterateecall "^3.0.0" 588 | 589 | lodash.isarguments@^3.0.0: 590 | version "3.1.0" 591 | resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" 592 | 593 | lodash.isarray@^3.0.0: 594 | version "3.0.4" 595 | resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" 596 | 597 | lodash.keys@^3.0.0: 598 | version "3.1.2" 599 | resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" 600 | dependencies: 601 | lodash._getnative "^3.0.0" 602 | lodash.isarguments "^3.0.0" 603 | lodash.isarray "^3.0.0" 604 | 605 | lodash@^4.0.0, lodash@^4.3.0: 606 | version "4.16.4" 607 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.16.4.tgz#01ce306b9bad1319f2a5528674f88297aeb70127" 608 | 609 | minimatch@^3.0.2: 610 | version "3.0.3" 611 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" 612 | dependencies: 613 | brace-expansion "^1.0.0" 614 | 615 | minimatch@3.0.0: 616 | version "3.0.0" 617 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.0.tgz#5236157a51e4f004c177fb3c527ff7dd78f0ef83" 618 | dependencies: 619 | brace-expansion "^1.0.0" 620 | 621 | minimist@0.0.8: 622 | version "0.0.8" 623 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 624 | 625 | mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@0.5.1: 626 | version "0.5.1" 627 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 628 | dependencies: 629 | minimist "0.0.8" 630 | 631 | ml-array-utils@^0.3.0: 632 | version "0.3.0" 633 | resolved "https://registry.yarnpkg.com/ml-array-utils/-/ml-array-utils-0.3.0.tgz#c0cc5afdc1cb051f5a83b1ce71641c243672f649" 634 | dependencies: 635 | ml-stat "^1.0.1" 636 | 637 | ml-combinations@^1.0.1: 638 | version "1.0.1" 639 | resolved "https://registry.yarnpkg.com/ml-combinations/-/ml-combinations-1.0.1.tgz#12de0e538d7ed5ff4fcf209924878ea66a8ba451" 640 | 641 | ml-cross-validation@^1.0.1: 642 | version "1.0.1" 643 | resolved "https://registry.yarnpkg.com/ml-cross-validation/-/ml-cross-validation-1.0.1.tgz#2ee48f0382326cdb6bb5913874122a4caa8142d0" 644 | dependencies: 645 | ml-combinations "^1.0.1" 646 | 647 | ml-dataset-iris@^1.0.0: 648 | version "1.0.0" 649 | resolved "https://registry.yarnpkg.com/ml-dataset-iris/-/ml-dataset-iris-1.0.0.tgz#420f32cb5b874f0a3b008fc999cb30c6dcd7e12a" 650 | 651 | ml-distance-euclidean@^1.0.0: 652 | version "1.0.0" 653 | resolved "https://registry.yarnpkg.com/ml-distance-euclidean/-/ml-distance-euclidean-1.0.0.tgz#08447c2233641a2b2a9b4c29e5f792d28f1d5b95" 654 | 655 | ml-kernel-gaussian@^2.0.1: 656 | version "2.0.1" 657 | resolved "https://registry.yarnpkg.com/ml-kernel-gaussian/-/ml-kernel-gaussian-2.0.1.tgz#a01aef9f44f5bcc11341b09a383b1b32f11933c0" 658 | dependencies: 659 | ml-distance-euclidean "^1.0.0" 660 | 661 | ml-kernel-polynomial@^2.0.0: 662 | version "2.0.0" 663 | resolved "https://registry.yarnpkg.com/ml-kernel-polynomial/-/ml-kernel-polynomial-2.0.0.tgz#8ec02c02ccb68bf25a92fbccb4d55a4b387c8313" 664 | 665 | ml-kernel-sigmoid@^1.0.0: 666 | version "1.0.0" 667 | resolved "https://registry.yarnpkg.com/ml-kernel-sigmoid/-/ml-kernel-sigmoid-1.0.0.tgz#884b28be13f61a60a5173f04240e8096eb1d9cd2" 668 | 669 | ml-kernel@^2.2.0: 670 | version "2.3.2" 671 | resolved "https://registry.yarnpkg.com/ml-kernel/-/ml-kernel-2.3.2.tgz#1a47266647d78002fcff14cbcc28795f88c03fe5" 672 | dependencies: 673 | ml-distance-euclidean "^1.0.0" 674 | ml-kernel-gaussian "^2.0.1" 675 | ml-kernel-polynomial "^2.0.0" 676 | ml-kernel-sigmoid "^1.0.0" 677 | ml-matrix "^2.0.0" 678 | 679 | ml-matrix@^2.0.0: 680 | version "2.1.0" 681 | resolved "https://registry.yarnpkg.com/ml-matrix/-/ml-matrix-2.1.0.tgz#d8f43720620313ebb517a98e0974b8eb8847b869" 682 | dependencies: 683 | ml-array-utils "^0.3.0" 684 | 685 | ml-stat@^1.0.1, ml-stat@^1.2.0: 686 | version "1.3.3" 687 | resolved "https://registry.yarnpkg.com/ml-stat/-/ml-stat-1.3.3.tgz#8a5493b0f67382fbf705c260e070436655a7dcfa" 688 | 689 | ml-xsadd@^1.0.0: 690 | version "1.0.0" 691 | resolved "https://registry.yarnpkg.com/ml-xsadd/-/ml-xsadd-1.0.0.tgz#f53c350ee54c9738a9f77a386cdc5d2bc62385d0" 692 | 693 | mocha-better-spec-reporter@^3.0.2: 694 | version "3.0.2" 695 | resolved "https://registry.yarnpkg.com/mocha-better-spec-reporter/-/mocha-better-spec-reporter-3.0.2.tgz#8d6d979ae0a9ce62b47ba301f13906979aee428d" 696 | dependencies: 697 | chalk "1.1.3" 698 | data-uri-to-buffer "0.0.4" 699 | diff "2.2.2" 700 | graceful-fs "4.1.3" 701 | minimatch "3.0.0" 702 | should-format "0.3.2" 703 | should-type "0.2.0" 704 | source-map "0.5.3" 705 | stack-trace "0.0.9" 706 | 707 | mocha@^3.0.2: 708 | version "3.1.2" 709 | resolved "https://registry.yarnpkg.com/mocha/-/mocha-3.1.2.tgz#51f93b432bf7e1b175ffc22883ccd0be32dba6b5" 710 | dependencies: 711 | browser-stdout "1.3.0" 712 | commander "2.9.0" 713 | debug "2.2.0" 714 | diff "1.4.0" 715 | escape-string-regexp "1.0.5" 716 | glob "7.0.5" 717 | growl "1.9.2" 718 | json3 "3.3.2" 719 | lodash.create "3.1.1" 720 | mkdirp "0.5.1" 721 | supports-color "3.1.2" 722 | 723 | ms@0.7.1: 724 | version "0.7.1" 725 | resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" 726 | 727 | mute-stream@0.0.5: 728 | version "0.0.5" 729 | resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" 730 | 731 | natural-compare@^1.4.0: 732 | version "1.4.0" 733 | resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" 734 | 735 | number-is-nan@^1.0.0: 736 | version "1.0.1" 737 | resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" 738 | 739 | object-assign@^4.0.1, object-assign@^4.1.0: 740 | version "4.1.0" 741 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" 742 | 743 | once@^1.3.0: 744 | version "1.4.0" 745 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 746 | dependencies: 747 | wrappy "1" 748 | 749 | onetime@^1.0.0: 750 | version "1.1.0" 751 | resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" 752 | 753 | optionator@^0.8.2: 754 | version "0.8.2" 755 | resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" 756 | dependencies: 757 | deep-is "~0.1.3" 758 | fast-levenshtein "~2.0.4" 759 | levn "~0.3.0" 760 | prelude-ls "~1.1.2" 761 | type-check "~0.3.2" 762 | wordwrap "~1.0.0" 763 | 764 | os-homedir@^1.0.0: 765 | version "1.0.2" 766 | resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" 767 | 768 | path-is-absolute@^1.0.0: 769 | version "1.0.1" 770 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 771 | 772 | path-is-inside@^1.0.1: 773 | version "1.0.2" 774 | resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" 775 | 776 | pify@^2.0.0: 777 | version "2.3.0" 778 | resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" 779 | 780 | pinkie-promise@^2.0.0: 781 | version "2.0.1" 782 | resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" 783 | dependencies: 784 | pinkie "^2.0.0" 785 | 786 | pinkie@^2.0.0: 787 | version "2.0.4" 788 | resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" 789 | 790 | pluralize@^1.2.1: 791 | version "1.2.1" 792 | resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" 793 | 794 | prelude-ls@~1.1.2: 795 | version "1.1.2" 796 | resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" 797 | 798 | process-nextick-args@~1.0.6: 799 | version "1.0.7" 800 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" 801 | 802 | progress@^1.1.8: 803 | version "1.1.8" 804 | resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" 805 | 806 | readable-stream@~2.0.0: 807 | version "2.0.6" 808 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" 809 | dependencies: 810 | core-util-is "~1.0.0" 811 | inherits "~2.0.1" 812 | isarray "~1.0.0" 813 | process-nextick-args "~1.0.6" 814 | string_decoder "~0.10.x" 815 | util-deprecate "~1.0.1" 816 | 817 | readline2@^1.0.1: 818 | version "1.0.1" 819 | resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" 820 | dependencies: 821 | code-point-at "^1.0.0" 822 | is-fullwidth-code-point "^1.0.0" 823 | mute-stream "0.0.5" 824 | 825 | require-uncached@^1.0.2: 826 | version "1.0.2" 827 | resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.2.tgz#67dad3b733089e77030124678a459589faf6a7ec" 828 | dependencies: 829 | caller-path "^0.1.0" 830 | resolve-from "^1.0.0" 831 | 832 | resolve-from@^1.0.0: 833 | version "1.0.1" 834 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" 835 | 836 | restore-cursor@^1.0.1: 837 | version "1.0.1" 838 | resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" 839 | dependencies: 840 | exit-hook "^1.0.0" 841 | onetime "^1.0.0" 842 | 843 | rimraf@^2.2.8: 844 | version "2.5.4" 845 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" 846 | dependencies: 847 | glob "^7.0.5" 848 | 849 | run-async@^0.1.0: 850 | version "0.1.0" 851 | resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" 852 | dependencies: 853 | once "^1.3.0" 854 | 855 | rx-lite@^3.1.2: 856 | version "3.1.2" 857 | resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" 858 | 859 | shelljs@^0.6.0: 860 | version "0.6.1" 861 | resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.6.1.tgz#ec6211bed1920442088fe0f70b2837232ed2c8a8" 862 | 863 | should-equal@^1.0.0: 864 | version "1.0.1" 865 | resolved "https://registry.yarnpkg.com/should-equal/-/should-equal-1.0.1.tgz#0b6e9516f2601a9fb0bb2dcc369afa1c7e200af7" 866 | dependencies: 867 | should-type "^1.0.0" 868 | 869 | should-format@^3.0.2: 870 | version "3.0.2" 871 | resolved "https://registry.yarnpkg.com/should-format/-/should-format-3.0.2.tgz#1a543ad3abfea5dc2bea4a0ba875ede60fe22b19" 872 | dependencies: 873 | should-type "^1.3.0" 874 | should-type-adaptors "^1.0.1" 875 | 876 | should-format@0.3.2: 877 | version "0.3.2" 878 | resolved "https://registry.yarnpkg.com/should-format/-/should-format-0.3.2.tgz#a59831e01a2ddee149911bc7148be5c80319e1ff" 879 | dependencies: 880 | should-type "0.2.0" 881 | 882 | should-type-adaptors@^1.0.1: 883 | version "1.0.1" 884 | resolved "https://registry.yarnpkg.com/should-type-adaptors/-/should-type-adaptors-1.0.1.tgz#efe5553cdf68cff66e5c5f51b712dc351c77beaa" 885 | dependencies: 886 | should-type "^1.3.0" 887 | should-util "^1.0.0" 888 | 889 | should-type@^1.0.0, should-type@^1.3.0, should-type@^1.4.0: 890 | version "1.4.0" 891 | resolved "https://registry.yarnpkg.com/should-type/-/should-type-1.4.0.tgz#0756d8ce846dfd09843a6947719dfa0d4cff5cf3" 892 | 893 | should-type@0.2.0: 894 | version "0.2.0" 895 | resolved "https://registry.yarnpkg.com/should-type/-/should-type-0.2.0.tgz#6707ef95529d989dcc098fe0753ab1f9136bb7f6" 896 | 897 | should-util@^1.0.0: 898 | version "1.0.0" 899 | resolved "https://registry.yarnpkg.com/should-util/-/should-util-1.0.0.tgz#c98cda374aa6b190df8ba87c9889c2b4db620063" 900 | 901 | should@^11.1.0: 902 | version "11.1.1" 903 | resolved "https://registry.yarnpkg.com/should/-/should-11.1.1.tgz#760756475f0217ebbc5a141cbbf35f02f64feb07" 904 | dependencies: 905 | should-equal "^1.0.0" 906 | should-format "^3.0.2" 907 | should-type "^1.4.0" 908 | should-type-adaptors "^1.0.1" 909 | should-util "^1.0.0" 910 | 911 | slice-ansi@0.0.4: 912 | version "0.0.4" 913 | resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" 914 | 915 | source-map@0.5.3: 916 | version "0.5.3" 917 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.3.tgz#82674b85a71b0be76c3e7416d15e9f5252eb3be0" 918 | 919 | sprintf-js@~1.0.2: 920 | version "1.0.3" 921 | resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" 922 | 923 | stack-trace@0.0.9: 924 | version "0.0.9" 925 | resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.9.tgz#a8f6eaeca90674c333e7c43953f275b451510695" 926 | 927 | string_decoder@~0.10.x: 928 | version "0.10.31" 929 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" 930 | 931 | string-width@^1.0.1: 932 | version "1.0.2" 933 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" 934 | dependencies: 935 | code-point-at "^1.0.0" 936 | is-fullwidth-code-point "^1.0.0" 937 | strip-ansi "^3.0.0" 938 | 939 | strip-ansi@^3.0.0: 940 | version "3.0.1" 941 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" 942 | dependencies: 943 | ansi-regex "^2.0.0" 944 | 945 | strip-bom@^3.0.0: 946 | version "3.0.0" 947 | resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" 948 | 949 | strip-json-comments@~1.0.1: 950 | version "1.0.4" 951 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" 952 | 953 | supports-color@^2.0.0: 954 | version "2.0.0" 955 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" 956 | 957 | supports-color@3.1.2: 958 | version "3.1.2" 959 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.1.2.tgz#72a262894d9d408b956ca05ff37b2ed8a6e2a2d5" 960 | dependencies: 961 | has-flag "^1.0.0" 962 | 963 | table@^3.7.8: 964 | version "3.8.0" 965 | resolved "https://registry.yarnpkg.com/table/-/table-3.8.0.tgz#252166c7f3286684a9d561b0f3a8929caf3a997b" 966 | dependencies: 967 | ajv "^4.7.0" 968 | ajv-keywords "^1.0.0" 969 | chalk "^1.1.1" 970 | lodash "^4.0.0" 971 | slice-ansi "0.0.4" 972 | string-width "^1.0.1" 973 | 974 | text-table@~0.2.0: 975 | version "0.2.0" 976 | resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" 977 | 978 | through@^2.3.6: 979 | version "2.3.8" 980 | resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" 981 | 982 | tryit@^1.0.1: 983 | version "1.0.2" 984 | resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.2.tgz#c196b0073e6b1c595d93c9c830855b7acc32a453" 985 | 986 | type-check@~0.3.2: 987 | version "0.3.2" 988 | resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" 989 | dependencies: 990 | prelude-ls "~1.1.2" 991 | 992 | typedarray@~0.0.5: 993 | version "0.0.6" 994 | resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" 995 | 996 | user-home@^2.0.0: 997 | version "2.0.0" 998 | resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" 999 | dependencies: 1000 | os-homedir "^1.0.0" 1001 | 1002 | util-deprecate@~1.0.1: 1003 | version "1.0.2" 1004 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 1005 | 1006 | wordwrap@~1.0.0: 1007 | version "1.0.0" 1008 | resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" 1009 | 1010 | wrappy@1: 1011 | version "1.0.2" 1012 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 1013 | 1014 | write@^0.2.1: 1015 | version "0.2.1" 1016 | resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" 1017 | dependencies: 1018 | mkdirp "^0.5.1" 1019 | 1020 | xtend@^4.0.0: 1021 | version "4.0.1" 1022 | resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" 1023 | 1024 | --------------------------------------------------------------------------------