├── .editorconfig ├── .eslintrc.yml ├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── assets └── lambda-talk.jpg ├── docs ├── docco.css ├── index.html └── public │ ├── fonts │ ├── aller-bold.eot │ ├── aller-bold.ttf │ ├── aller-bold.woff │ ├── aller-light.eot │ ├── aller-light.ttf │ ├── aller-light.woff │ ├── roboto-black.eot │ ├── roboto-black.ttf │ └── roboto-black.woff │ └── stylesheets │ └── normalize.css ├── package.json ├── src └── index.js └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = tab 6 | indent_size = 4 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | 15 | [*.{yml,yaml}] 16 | indent_style = space 17 | -------------------------------------------------------------------------------- /.eslintrc.yml: -------------------------------------------------------------------------------- 1 | # YAML allows comments. 2 | root: true 3 | parser: babel-eslint 4 | extends: fullstack 5 | rules: 6 | semi: [1, never] 7 | new-cap: 0 8 | no-unused-vars: 0 9 | id-length: 0 10 | func-call-spacing: 0 11 | no-spaced-func: 0 12 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to this Project 2 | 3 | Thank you for your interest! Please note that for pull requests to be merged, you should: 4 | 5 | * Include unit tests 6 | * Add any relevant documentation 7 | * Reference any relevant issues 8 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | For bugs, please include the following: 2 | 3 | * What is the expected behavior? 4 | * What is the actual behavior? 5 | * What steps reproduce the behavior? 6 | 7 | --- 8 | 9 | *Issue description here…* 10 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Assignee Tasks 2 | 3 | - [ ] added unit tests 4 | - [ ] written relevant docs 5 | - [ ] referenced any relevant issues 6 | 7 | ### Guidelines 8 | 9 | Please add a description of this Pull Request's motivation, scope, outstanding issues or potential alternatives, reasoning behind the current solution, and any other relevant information for posterity. 10 | 11 | --- 12 | 13 | *Your PR Notes Here* 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build 2 | build 3 | dist 4 | 5 | # Cache 6 | .eslintcache 7 | 8 | # Packages 9 | node_modules 10 | bower_components 11 | 12 | # OS-generated files 13 | .DS_Store 14 | .DS_Store? 15 | ._* 16 | .Spotlight-V100 17 | .Trashes 18 | ehthumbs.db 19 | Thumbs.db 20 | 21 | # Logs and databases 22 | *.log 23 | *.sqlite 24 | 25 | # Vim swap files 26 | *.sw? 27 | 28 | # IDE files 29 | .idea 30 | .vscode 31 | 32 | # repos / submodules 33 | .git 34 | .svn 35 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, 8 | body size, disability, ethnicity, gender identity and expression, level of 9 | experience, nationality, personal appearance, race, religion, or sexual 10 | identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention 26 | or advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an 52 | appointed representative at an online or offline event. Representation of a 53 | project may be further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team lead or repo owner. All complaints will 59 | be reviewed and investigated and will result in a response that is deemed 60 | necessary and appropriate to the circumstances. The project team is obligated 61 | to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 71 | version 1.4, available at [http://contributor-covenant.org/version/1/4][vrsn] 72 | 73 | [homepage]: http://contributor-covenant.org 74 | [vrsn]: http://contributor-covenant.org/version/1/4/ 75 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Gabriel Lebec 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 𝜆as.js, or A Flock of Functions 2 | 3 | ### Combinators, Lambda Calculus, and Church Encodings in JavaScript 4 | 5 | This repo contains notes and runnable examples of the lambda calculus as expressed through JavaScript. 6 | 7 | ## Contents 8 | 9 | Visit [https://glebec.github.io/lambda-talk](https://glebec.github.io/lambda-talk) for a formatted version of the code. 10 | 11 | The runnable JS file is in [`src/index.js`](src/index.js). Execute the file is by cloning this repo and running `npm start`. Or, view the REPL [here](https://repl.it/Jgu4/236). 12 | 13 | ## Presentation 14 | 15 | This repo was created as an accompaniment to a lecture talk given at Fullstack Academy of Code on 2017-08-24. You can view videos of that talk (in two parts) below: 16 | 17 | ### Part I 18 | 19 | [![Lambda as JS, or A Flock of Functions: Part I](https://img.youtube.com/vi/3VQ382QG-y4/0.jpg)](https://www.youtube.com/watch?v=3VQ382QG-y4&list=PLpkHU923F2XFWv-XfVuvWuxq41h21nOPK&index=1) 20 | 21 | ### Part II 22 | 23 | [![Lambda as JS, or A Flock of Functions: Part I](https://img.youtube.com/vi/pAnLQ9jwN-E/0.jpg)](https://www.youtube.com/watch?v=pAnLQ9jwN-E&list=PLpkHU923F2XFWv-XfVuvWuxq41h21nOPK&index=2) 24 | 25 | ### Slides 26 | 27 | [Click to view the original slide deck.](https://speakerdeck.com/glebec/lambda-as-js-or-a-flock-of-functions-combinators-lambda-calculus-and-church-encodings-in-javascript) 28 | 29 | [![Lambda as JS - Presentation Cover Image](assets/lambda-talk.jpg)](https://speakerdeck.com/glebec/lambda-as-js-or-a-flock-of-functions-combinators-lambda-calculus-and-church-encodings-in-javascript) 30 | 31 | **Update**: the first part of the presentation has been slightly modified over time; the deck used for the 2019-10 Smartly.io DevTalks can be seen [here](https://speakerdeck.com/glebec/lambda-calc-talk-smartly-dot-io-version). 32 | 33 | ## Additional Resources 34 | 35 | * [_Combinator Birds_ · Rathman](http://bit.ly/2iudab9) 36 | * [_To Mock a Mockingbird_ · Smullyan](http://amzn.to/2g9AlXl) 37 | * [_To Dissect a Mockingbird_ · Keenan](http://dkeenan.com/Lambda) 38 | * [_A Tutorial Introduction to the Lambda Calculus_ · Rojas](http://bit.ly/1agRC97) 39 | * [_Lambda Calculus_ · Wikipedia](http://bit.ly/1TsPkGn) 40 | * [_The Lambda Calculus_ · Stanford](http://stanford.io/2vtg8hp) 41 | * [_History of Lambda-calculus and Combinatory Logic_ · Cardone, Hindley](http://bit.ly/2wCxv4k) 42 | * [_An Introduction to Functional Programming through Lambda Calculus_ · Michaelson](http://amzn.to/2vtts56) 43 | -------------------------------------------------------------------------------- /assets/lambda-talk.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glebec/lambda-talk/d0d302d2b6f87fb1f7186a04fca149fff7cc7f91/assets/lambda-talk.jpg -------------------------------------------------------------------------------- /docs/docco.css: -------------------------------------------------------------------------------- 1 | /*--------------------- Typography ----------------------------*/ 2 | 3 | @font-face { 4 | font-family: 'aller-light'; 5 | src: url('public/fonts/aller-light.eot'); 6 | src: url('public/fonts/aller-light.eot?#iefix') format('embedded-opentype'), 7 | url('public/fonts/aller-light.woff') format('woff'), 8 | url('public/fonts/aller-light.ttf') format('truetype'); 9 | font-weight: normal; 10 | font-style: normal; 11 | } 12 | 13 | @font-face { 14 | font-family: 'aller-bold'; 15 | src: url('public/fonts/aller-bold.eot'); 16 | src: url('public/fonts/aller-bold.eot?#iefix') format('embedded-opentype'), 17 | url('public/fonts/aller-bold.woff') format('woff'), 18 | url('public/fonts/aller-bold.ttf') format('truetype'); 19 | font-weight: normal; 20 | font-style: normal; 21 | } 22 | 23 | @font-face { 24 | font-family: 'roboto-black'; 25 | src: url('public/fonts/roboto-black.eot'); 26 | src: url('public/fonts/roboto-black.eot?#iefix') format('embedded-opentype'), 27 | url('public/fonts/roboto-black.woff') format('woff'), 28 | url('public/fonts/roboto-black.ttf') format('truetype'); 29 | font-weight: normal; 30 | font-style: normal; 31 | } 32 | 33 | /*--------------------- Layout ----------------------------*/ 34 | html { height: 100%; } 35 | body { 36 | font-family: "aller-light"; 37 | font-size: 14px; 38 | line-height: 18px; 39 | color: #30404f; 40 | margin: 0; padding: 0; 41 | height:100%; 42 | } 43 | #container { min-height: 100%; } 44 | 45 | a { 46 | color: #000; 47 | } 48 | 49 | b, strong { 50 | font-weight: normal; 51 | font-family: "aller-bold"; 52 | } 53 | 54 | p { 55 | margin: 15px 0 0px; 56 | } 57 | .annotation ul, .annotation ol { 58 | margin: 25px 0; 59 | } 60 | .annotation ul li, .annotation ol li { 61 | font-size: 14px; 62 | line-height: 18px; 63 | margin: 10px 0; 64 | } 65 | 66 | h1, h2, h3, h4, h5, h6 { 67 | color: #112233; 68 | line-height: 1em; 69 | font-weight: normal; 70 | font-family: "roboto-black"; 71 | text-transform: uppercase; 72 | margin: 30px 0 15px 0; 73 | } 74 | 75 | h1 { 76 | margin-top: 40px; 77 | } 78 | h2 { 79 | font-size: 1.26em; 80 | } 81 | 82 | hr { 83 | border: 0; 84 | background: 1px #ddd; 85 | height: 1px; 86 | margin: 20px 0; 87 | } 88 | 89 | pre, tt, code { 90 | font-size: 12px; line-height: 16px; 91 | font-family: Menlo, Monaco, Consolas, "Lucida Console", monospace; 92 | margin: 0; padding: 0; 93 | } 94 | .annotation pre { 95 | display: block; 96 | margin: 0; 97 | padding: 7px 10px; 98 | background: #fcfcfc; 99 | -moz-box-shadow: inset 0 0 10px rgba(0,0,0,0.1); 100 | -webkit-box-shadow: inset 0 0 10px rgba(0,0,0,0.1); 101 | box-shadow: inset 0 0 10px rgba(0,0,0,0.1); 102 | overflow-x: auto; 103 | } 104 | .annotation pre code { 105 | border: 0; 106 | padding: 0; 107 | background: transparent; 108 | } 109 | 110 | 111 | blockquote { 112 | border-left: 5px solid #ccc; 113 | margin: 0; 114 | padding: 1px 0 1px 1em; 115 | } 116 | .sections blockquote p { 117 | font-family: Menlo, Consolas, Monaco, monospace; 118 | font-size: 12px; line-height: 16px; 119 | color: #999; 120 | margin: 10px 0 0; 121 | white-space: pre-wrap; 122 | } 123 | 124 | ul.sections { 125 | list-style: none; 126 | padding:0 0 5px 0;; 127 | margin:0; 128 | } 129 | 130 | /* 131 | Force border-box so that % widths fit the parent 132 | container without overlap because of margin/padding. 133 | 134 | More Info : http://www.quirksmode.org/css/box.html 135 | */ 136 | ul.sections > li > div { 137 | -moz-box-sizing: border-box; /* firefox */ 138 | -ms-box-sizing: border-box; /* ie */ 139 | -webkit-box-sizing: border-box; /* webkit */ 140 | -khtml-box-sizing: border-box; /* konqueror */ 141 | box-sizing: border-box; /* css3 */ 142 | } 143 | 144 | 145 | /*---------------------- Jump Page -----------------------------*/ 146 | #jump_to, #jump_page { 147 | margin: 0; 148 | background: white; 149 | -webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777; 150 | -webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px; 151 | font: 16px Arial; 152 | cursor: pointer; 153 | text-align: right; 154 | list-style: none; 155 | } 156 | 157 | #jump_to a { 158 | text-decoration: none; 159 | } 160 | 161 | #jump_to a.large { 162 | display: none; 163 | } 164 | #jump_to a.small { 165 | font-size: 22px; 166 | font-weight: bold; 167 | color: #676767; 168 | } 169 | 170 | #jump_to, #jump_wrapper { 171 | position: fixed; 172 | right: 0; top: 0; 173 | padding: 10px 15px; 174 | margin:0; 175 | } 176 | 177 | #jump_wrapper { 178 | display: none; 179 | padding:0; 180 | } 181 | 182 | #jump_to:hover #jump_wrapper { 183 | display: block; 184 | } 185 | 186 | #jump_page_wrapper{ 187 | position: fixed; 188 | right: 0; 189 | top: 0; 190 | bottom: 0; 191 | } 192 | 193 | #jump_page { 194 | padding: 5px 0 3px; 195 | margin: 0 0 25px 25px; 196 | max-height: 100%; 197 | overflow: auto; 198 | } 199 | 200 | #jump_page .source { 201 | display: block; 202 | padding: 15px; 203 | text-decoration: none; 204 | border-top: 1px solid #eee; 205 | } 206 | 207 | #jump_page .source:hover { 208 | background: #f5f5ff; 209 | } 210 | 211 | #jump_page .source:first-child { 212 | } 213 | 214 | /*---------------------- Low resolutions (> 320px) ---------------------*/ 215 | @media only screen and (min-width: 320px) { 216 | .pilwrap { display: none; } 217 | 218 | ul.sections > li > div { 219 | display: block; 220 | padding:5px 10px 0 10px; 221 | } 222 | 223 | ul.sections > li > div.annotation ul, ul.sections > li > div.annotation ol { 224 | padding-left: 30px; 225 | } 226 | 227 | ul.sections > li > div.content { 228 | overflow-x:auto; 229 | -webkit-box-shadow: inset 0 0 5px #e5e5ee; 230 | box-shadow: inset 0 0 5px #e5e5ee; 231 | border: 1px solid #dedede; 232 | margin:5px 10px 5px 10px; 233 | padding-bottom: 5px; 234 | } 235 | 236 | ul.sections > li > div.annotation pre { 237 | margin: 7px 0 7px; 238 | padding-left: 15px; 239 | } 240 | 241 | ul.sections > li > div.annotation p tt, .annotation code { 242 | background: #f8f8ff; 243 | border: 1px solid #dedede; 244 | font-size: 12px; 245 | padding: 0 0.2em; 246 | } 247 | } 248 | 249 | /*---------------------- (> 481px) ---------------------*/ 250 | @media only screen and (min-width: 481px) { 251 | #container { 252 | position: relative; 253 | } 254 | body { 255 | background-color: #F5F5FF; 256 | font-size: 15px; 257 | line-height: 21px; 258 | } 259 | pre, tt, code { 260 | line-height: 18px; 261 | } 262 | p, ul, ol { 263 | margin: 0 0 15px; 264 | } 265 | 266 | 267 | #jump_to { 268 | padding: 5px 10px; 269 | } 270 | #jump_wrapper { 271 | padding: 0; 272 | } 273 | #jump_to, #jump_page { 274 | font: 10px Arial; 275 | text-transform: uppercase; 276 | } 277 | #jump_page .source { 278 | padding: 5px 10px; 279 | } 280 | #jump_to a.large { 281 | display: inline-block; 282 | } 283 | #jump_to a.small { 284 | display: none; 285 | } 286 | 287 | 288 | 289 | #background { 290 | position: absolute; 291 | top: 0; bottom: 0; 292 | width: 350px; 293 | background: #fff; 294 | border-right: 1px solid #e5e5ee; 295 | z-index: -1; 296 | } 297 | 298 | ul.sections > li > div.annotation ul, ul.sections > li > div.annotation ol { 299 | padding-left: 40px; 300 | } 301 | 302 | ul.sections > li { 303 | white-space: nowrap; 304 | } 305 | 306 | ul.sections > li > div { 307 | display: inline-block; 308 | } 309 | 310 | ul.sections > li > div.annotation { 311 | max-width: 350px; 312 | min-width: 350px; 313 | min-height: 5px; 314 | padding: 13px; 315 | overflow-x: hidden; 316 | white-space: normal; 317 | vertical-align: top; 318 | text-align: left; 319 | } 320 | ul.sections > li > div.annotation pre { 321 | margin: 15px 0 15px; 322 | padding-left: 15px; 323 | } 324 | 325 | ul.sections > li > div.content { 326 | padding: 13px; 327 | vertical-align: top; 328 | border: none; 329 | -webkit-box-shadow: none; 330 | box-shadow: none; 331 | } 332 | 333 | .pilwrap { 334 | position: relative; 335 | display: inline; 336 | } 337 | 338 | .pilcrow { 339 | font: 12px Arial; 340 | text-decoration: none; 341 | color: #454545; 342 | position: absolute; 343 | top: 3px; left: -20px; 344 | padding: 1px 2px; 345 | opacity: 0; 346 | -webkit-transition: opacity 0.2s linear; 347 | } 348 | .for-h1 .pilcrow { 349 | top: 47px; 350 | } 351 | .for-h2 .pilcrow, .for-h3 .pilcrow, .for-h4 .pilcrow { 352 | top: 35px; 353 | } 354 | 355 | ul.sections > li > div.annotation:hover .pilcrow { 356 | opacity: 1; 357 | } 358 | } 359 | 360 | /*---------------------- (> 1025px) ---------------------*/ 361 | @media only screen and (min-width: 1025px) { 362 | 363 | body { 364 | font-size: 16px; 365 | line-height: 24px; 366 | } 367 | 368 | #background { 369 | width: 525px; 370 | } 371 | ul.sections > li > div.annotation { 372 | max-width: 525px; 373 | min-width: 525px; 374 | padding: 10px 25px 1px 50px; 375 | } 376 | ul.sections > li > div.content { 377 | padding: 9px 15px 16px 25px; 378 | } 379 | } 380 | 381 | /*---------------------- Syntax Highlighting -----------------------------*/ 382 | 383 | td.linenos { background-color: #f0f0f0; padding-right: 10px; } 384 | span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; } 385 | /* 386 | 387 | github.com style (c) Vasily Polovnyov 388 | 389 | */ 390 | 391 | pre code { 392 | display: block; padding: 0.5em; 393 | color: #000; 394 | background: #f8f8ff 395 | } 396 | 397 | pre .hljs-comment, 398 | pre .hljs-template_comment, 399 | pre .hljs-diff .hljs-header, 400 | pre .hljs-javadoc { 401 | color: #408080; 402 | font-style: italic 403 | } 404 | 405 | pre .hljs-keyword, 406 | pre .hljs-assignment, 407 | pre .hljs-literal, 408 | pre .hljs-css .hljs-rule .hljs-keyword, 409 | pre .hljs-winutils, 410 | pre .hljs-javascript .hljs-title, 411 | pre .hljs-lisp .hljs-title, 412 | pre .hljs-subst { 413 | color: #954121; 414 | /*font-weight: bold*/ 415 | } 416 | 417 | pre .hljs-number, 418 | pre .hljs-hexcolor { 419 | color: #40a070 420 | } 421 | 422 | pre .hljs-string, 423 | pre .hljs-tag .hljs-value, 424 | pre .hljs-phpdoc, 425 | pre .hljs-tex .hljs-formula { 426 | color: #219161; 427 | } 428 | 429 | pre .hljs-title, 430 | pre .hljs-id { 431 | color: #19469D; 432 | } 433 | pre .hljs-params { 434 | color: #00F; 435 | } 436 | 437 | pre .hljs-javascript .hljs-title, 438 | pre .hljs-lisp .hljs-title, 439 | pre .hljs-subst { 440 | font-weight: normal 441 | } 442 | 443 | pre .hljs-class .hljs-title, 444 | pre .hljs-haskell .hljs-label, 445 | pre .hljs-tex .hljs-command { 446 | color: #458; 447 | font-weight: bold 448 | } 449 | 450 | pre .hljs-tag, 451 | pre .hljs-tag .hljs-title, 452 | pre .hljs-rules .hljs-property, 453 | pre .hljs-django .hljs-tag .hljs-keyword { 454 | color: #000080; 455 | font-weight: normal 456 | } 457 | 458 | pre .hljs-attribute, 459 | pre .hljs-variable, 460 | pre .hljs-instancevar, 461 | pre .hljs-lisp .hljs-body { 462 | color: #008080 463 | } 464 | 465 | pre .hljs-regexp { 466 | color: #B68 467 | } 468 | 469 | pre .hljs-class { 470 | color: #458; 471 | font-weight: bold 472 | } 473 | 474 | pre .hljs-symbol, 475 | pre .hljs-ruby .hljs-symbol .hljs-string, 476 | pre .hljs-ruby .hljs-symbol .hljs-keyword, 477 | pre .hljs-ruby .hljs-symbol .hljs-keymethods, 478 | pre .hljs-lisp .hljs-keyword, 479 | pre .hljs-tex .hljs-special, 480 | pre .hljs-input_number { 481 | color: #990073 482 | } 483 | 484 | pre .hljs-builtin, 485 | pre .hljs-constructor, 486 | pre .hljs-built_in, 487 | pre .hljs-lisp .hljs-title { 488 | color: #0086b3 489 | } 490 | 491 | pre .hljs-preprocessor, 492 | pre .hljs-pi, 493 | pre .hljs-doctype, 494 | pre .hljs-shebang, 495 | pre .hljs-cdata { 496 | color: #999; 497 | font-weight: bold 498 | } 499 | 500 | pre .hljs-deletion { 501 | background: #fdd 502 | } 503 | 504 | pre .hljs-addition { 505 | background: #dfd 506 | } 507 | 508 | pre .hljs-diff .hljs-change { 509 | background: #0086b3 510 | } 511 | 512 | pre .hljs-chunk { 513 | color: #aaa 514 | } 515 | 516 | pre .hljs-tex .hljs-formula { 517 | opacity: 0.5; 518 | } 519 | -------------------------------------------------------------------------------- /docs/public/fonts/aller-bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glebec/lambda-talk/d0d302d2b6f87fb1f7186a04fca149fff7cc7f91/docs/public/fonts/aller-bold.eot -------------------------------------------------------------------------------- /docs/public/fonts/aller-bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glebec/lambda-talk/d0d302d2b6f87fb1f7186a04fca149fff7cc7f91/docs/public/fonts/aller-bold.ttf -------------------------------------------------------------------------------- /docs/public/fonts/aller-bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glebec/lambda-talk/d0d302d2b6f87fb1f7186a04fca149fff7cc7f91/docs/public/fonts/aller-bold.woff -------------------------------------------------------------------------------- /docs/public/fonts/aller-light.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glebec/lambda-talk/d0d302d2b6f87fb1f7186a04fca149fff7cc7f91/docs/public/fonts/aller-light.eot -------------------------------------------------------------------------------- /docs/public/fonts/aller-light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glebec/lambda-talk/d0d302d2b6f87fb1f7186a04fca149fff7cc7f91/docs/public/fonts/aller-light.ttf -------------------------------------------------------------------------------- /docs/public/fonts/aller-light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glebec/lambda-talk/d0d302d2b6f87fb1f7186a04fca149fff7cc7f91/docs/public/fonts/aller-light.woff -------------------------------------------------------------------------------- /docs/public/fonts/roboto-black.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glebec/lambda-talk/d0d302d2b6f87fb1f7186a04fca149fff7cc7f91/docs/public/fonts/roboto-black.eot -------------------------------------------------------------------------------- /docs/public/fonts/roboto-black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glebec/lambda-talk/d0d302d2b6f87fb1f7186a04fca149fff7cc7f91/docs/public/fonts/roboto-black.ttf -------------------------------------------------------------------------------- /docs/public/fonts/roboto-black.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glebec/lambda-talk/d0d302d2b6f87fb1f7186a04fca149fff7cc7f91/docs/public/fonts/roboto-black.woff -------------------------------------------------------------------------------- /docs/public/stylesheets/normalize.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v2.0.1 | MIT License | git.io/normalize */ 2 | 3 | /* ========================================================================== 4 | HTML5 display definitions 5 | ========================================================================== */ 6 | 7 | /* 8 | * Corrects `block` display not defined in IE 8/9. 9 | */ 10 | 11 | article, 12 | aside, 13 | details, 14 | figcaption, 15 | figure, 16 | footer, 17 | header, 18 | hgroup, 19 | nav, 20 | section, 21 | summary { 22 | display: block; 23 | } 24 | 25 | /* 26 | * Corrects `inline-block` display not defined in IE 8/9. 27 | */ 28 | 29 | audio, 30 | canvas, 31 | video { 32 | display: inline-block; 33 | } 34 | 35 | /* 36 | * Prevents modern browsers from displaying `audio` without controls. 37 | * Remove excess height in iOS 5 devices. 38 | */ 39 | 40 | audio:not([controls]) { 41 | display: none; 42 | height: 0; 43 | } 44 | 45 | /* 46 | * Addresses styling for `hidden` attribute not present in IE 8/9. 47 | */ 48 | 49 | [hidden] { 50 | display: none; 51 | } 52 | 53 | /* ========================================================================== 54 | Base 55 | ========================================================================== */ 56 | 57 | /* 58 | * 1. Sets default font family to sans-serif. 59 | * 2. Prevents iOS text size adjust after orientation change, without disabling 60 | * user zoom. 61 | */ 62 | 63 | html { 64 | font-family: sans-serif; /* 1 */ 65 | -webkit-text-size-adjust: 100%; /* 2 */ 66 | -ms-text-size-adjust: 100%; /* 2 */ 67 | } 68 | 69 | /* 70 | * Removes default margin. 71 | */ 72 | 73 | body { 74 | margin: 0; 75 | } 76 | 77 | /* ========================================================================== 78 | Links 79 | ========================================================================== */ 80 | 81 | /* 82 | * Addresses `outline` inconsistency between Chrome and other browsers. 83 | */ 84 | 85 | a:focus { 86 | outline: thin dotted; 87 | } 88 | 89 | /* 90 | * Improves readability when focused and also mouse hovered in all browsers. 91 | */ 92 | 93 | a:active, 94 | a:hover { 95 | outline: 0; 96 | } 97 | 98 | /* ========================================================================== 99 | Typography 100 | ========================================================================== */ 101 | 102 | /* 103 | * Addresses `h1` font sizes within `section` and `article` in Firefox 4+, 104 | * Safari 5, and Chrome. 105 | */ 106 | 107 | h1 { 108 | font-size: 2em; 109 | } 110 | 111 | /* 112 | * Addresses styling not present in IE 8/9, Safari 5, and Chrome. 113 | */ 114 | 115 | abbr[title] { 116 | border-bottom: 1px dotted; 117 | } 118 | 119 | /* 120 | * Addresses style set to `bolder` in Firefox 4+, Safari 5, and Chrome. 121 | */ 122 | 123 | b, 124 | strong { 125 | font-weight: bold; 126 | } 127 | 128 | /* 129 | * Addresses styling not present in Safari 5 and Chrome. 130 | */ 131 | 132 | dfn { 133 | font-style: italic; 134 | } 135 | 136 | /* 137 | * Addresses styling not present in IE 8/9. 138 | */ 139 | 140 | mark { 141 | background: #ff0; 142 | color: #000; 143 | } 144 | 145 | 146 | /* 147 | * Corrects font family set oddly in Safari 5 and Chrome. 148 | */ 149 | 150 | code, 151 | kbd, 152 | pre, 153 | samp { 154 | font-family: monospace, serif; 155 | font-size: 1em; 156 | } 157 | 158 | /* 159 | * Improves readability of pre-formatted text in all browsers. 160 | */ 161 | 162 | pre { 163 | white-space: pre; 164 | white-space: pre-wrap; 165 | word-wrap: break-word; 166 | } 167 | 168 | /* 169 | * Sets consistent quote types. 170 | */ 171 | 172 | q { 173 | quotes: "\201C" "\201D" "\2018" "\2019"; 174 | } 175 | 176 | /* 177 | * Addresses inconsistent and variable font size in all browsers. 178 | */ 179 | 180 | small { 181 | font-size: 80%; 182 | } 183 | 184 | /* 185 | * Prevents `sub` and `sup` affecting `line-height` in all browsers. 186 | */ 187 | 188 | sub, 189 | sup { 190 | font-size: 75%; 191 | line-height: 0; 192 | position: relative; 193 | vertical-align: baseline; 194 | } 195 | 196 | sup { 197 | top: -0.5em; 198 | } 199 | 200 | sub { 201 | bottom: -0.25em; 202 | } 203 | 204 | /* ========================================================================== 205 | Embedded content 206 | ========================================================================== */ 207 | 208 | /* 209 | * Removes border when inside `a` element in IE 8/9. 210 | */ 211 | 212 | img { 213 | border: 0; 214 | } 215 | 216 | /* 217 | * Corrects overflow displayed oddly in IE 9. 218 | */ 219 | 220 | svg:not(:root) { 221 | overflow: hidden; 222 | } 223 | 224 | /* ========================================================================== 225 | Figures 226 | ========================================================================== */ 227 | 228 | /* 229 | * Addresses margin not present in IE 8/9 and Safari 5. 230 | */ 231 | 232 | figure { 233 | margin: 0; 234 | } 235 | 236 | /* ========================================================================== 237 | Forms 238 | ========================================================================== */ 239 | 240 | /* 241 | * Define consistent border, margin, and padding. 242 | */ 243 | 244 | fieldset { 245 | border: 1px solid #c0c0c0; 246 | margin: 0 2px; 247 | padding: 0.35em 0.625em 0.75em; 248 | } 249 | 250 | /* 251 | * 1. Corrects color not being inherited in IE 8/9. 252 | * 2. Remove padding so people aren't caught out if they zero out fieldsets. 253 | */ 254 | 255 | legend { 256 | border: 0; /* 1 */ 257 | padding: 0; /* 2 */ 258 | } 259 | 260 | /* 261 | * 1. Corrects font family not being inherited in all browsers. 262 | * 2. Corrects font size not being inherited in all browsers. 263 | * 3. Addresses margins set differently in Firefox 4+, Safari 5, and Chrome 264 | */ 265 | 266 | button, 267 | input, 268 | select, 269 | textarea { 270 | font-family: inherit; /* 1 */ 271 | font-size: 100%; /* 2 */ 272 | margin: 0; /* 3 */ 273 | } 274 | 275 | /* 276 | * Addresses Firefox 4+ setting `line-height` on `input` using `!important` in 277 | * the UA stylesheet. 278 | */ 279 | 280 | button, 281 | input { 282 | line-height: normal; 283 | } 284 | 285 | /* 286 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` 287 | * and `video` controls. 288 | * 2. Corrects inability to style clickable `input` types in iOS. 289 | * 3. Improves usability and consistency of cursor style between image-type 290 | * `input` and others. 291 | */ 292 | 293 | button, 294 | html input[type="button"], /* 1 */ 295 | input[type="reset"], 296 | input[type="submit"] { 297 | -webkit-appearance: button; /* 2 */ 298 | cursor: pointer; /* 3 */ 299 | } 300 | 301 | /* 302 | * Re-set default cursor for disabled elements. 303 | */ 304 | 305 | button[disabled], 306 | input[disabled] { 307 | cursor: default; 308 | } 309 | 310 | /* 311 | * 1. Addresses box sizing set to `content-box` in IE 8/9. 312 | * 2. Removes excess padding in IE 8/9. 313 | */ 314 | 315 | input[type="checkbox"], 316 | input[type="radio"] { 317 | box-sizing: border-box; /* 1 */ 318 | padding: 0; /* 2 */ 319 | } 320 | 321 | /* 322 | * 1. Addresses `appearance` set to `searchfield` in Safari 5 and Chrome. 323 | * 2. Addresses `box-sizing` set to `border-box` in Safari 5 and Chrome 324 | * (include `-moz` to future-proof). 325 | */ 326 | 327 | input[type="search"] { 328 | -webkit-appearance: textfield; /* 1 */ 329 | -moz-box-sizing: content-box; 330 | -webkit-box-sizing: content-box; /* 2 */ 331 | box-sizing: content-box; 332 | } 333 | 334 | /* 335 | * Removes inner padding and search cancel button in Safari 5 and Chrome 336 | * on OS X. 337 | */ 338 | 339 | input[type="search"]::-webkit-search-cancel-button, 340 | input[type="search"]::-webkit-search-decoration { 341 | -webkit-appearance: none; 342 | } 343 | 344 | /* 345 | * Removes inner padding and border in Firefox 4+. 346 | */ 347 | 348 | button::-moz-focus-inner, 349 | input::-moz-focus-inner { 350 | border: 0; 351 | padding: 0; 352 | } 353 | 354 | /* 355 | * 1. Removes default vertical scrollbar in IE 8/9. 356 | * 2. Improves readability and alignment in all browsers. 357 | */ 358 | 359 | textarea { 360 | overflow: auto; /* 1 */ 361 | vertical-align: top; /* 2 */ 362 | } 363 | 364 | /* ========================================================================== 365 | Tables 366 | ========================================================================== */ 367 | 368 | /* 369 | * Remove most spacing between table cells. 370 | */ 371 | 372 | table { 373 | border-collapse: collapse; 374 | border-spacing: 0; 375 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "g-lebec-lambda-talk", 3 | "version": "1.0.0", 4 | "description": "A demonstration of the lambda calculus in JavaScript", 5 | "engines": { 6 | "node": ">=8.0.0" 7 | }, 8 | "main": "src/index.js", 9 | "scripts": { 10 | "start": "node src", 11 | "test": "node src", 12 | "build": "docco src/index.js", 13 | "precommit": "./bin/build", 14 | "lint": "esw --ext .js,.jsx --ignore-path .gitignore --cache --format node_modules/eslint-formatter-pretty", 15 | "lint-watch": "npm run lint -- --watch", 16 | "dev": "nodemon src" 17 | }, 18 | "author": "Gabriel Lebec (https://github.com/glebec)", 19 | "license": "MIT", 20 | "homepage": "https://github.com/glebec/lambda-talk#readme", 21 | "repository": { 22 | "type": "git", 23 | "url": "https://github.com/glebec/lambda-talk" 24 | }, 25 | "bugs": "https://github.com/glebec/lambda-talk/issues", 26 | "dependencies": { 27 | "chalk": "^2.1.0" 28 | }, 29 | "devDependencies": { 30 | "babel-eslint": "^7.2.3", 31 | "docco": "^0.7.0", 32 | "eslint": "^3.19.0", 33 | "eslint-config-fullstack": "^3.0.0", 34 | "eslint-formatter-pretty": "^1.1.0", 35 | "eslint-plugin-react": "^7.0.1", 36 | "eslint-watch": "^3.1.0", 37 | "husky": "^0.13.4", 38 | "nodemon": "^1.11.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | // # Lambda as JS, or A Flock of Functions 2 | 3 | // ### Combinators, Lambda Calculus, and Church Encodings in JavaScript 4 | 5 | // #### Notes for [a talk by Gabriel Lebec (click for videos and slides)](https://github.com/glebec/lambda-talk) 6 | 7 | const chalk = require('chalk') 8 | const green = chalk.green.bind(chalk) 9 | const red = chalk.red.bind(chalk) 10 | 11 | const errs = [] 12 | 13 | function demo (msg, bool) { 14 | if (typeof bool === 'function') bool = bool(true)(false) 15 | if (!!bool !== bool) throw TypeError('second arg must be boolean (JS or LC)') 16 | console.log(`${bool ? green('✔') : red('✖')} ${msg}`) 17 | if (!bool) errs.push(Error(red(`Spec fail: ${msg} -> ${bool}`))) 18 | } 19 | 20 | function logErrsAndSetExitCode () { 21 | errs.forEach(err => console.error(err)) 22 | if (errs.length) process.exitCode = 1 23 | } 24 | 25 | function header (str) { 26 | console.log('\n' + str + '\n') 27 | } 28 | 29 | // ## Introduction 30 | 31 | // The Lambda Calculus is a symbol manipulation framework developed by the mathematician Alonzo Church in the 1930s. It was intended to be an extremely tiny syntax which could nevertheless suffice to calculate anything computable. The mathematical advantage of such a syntax is that with such extreme simplicity, it becomes easier to write formal proofs about computational logic – demonstrated when Church solved David Hilbert's famous Decision Problem using LC. 32 | 33 | // Another famous mathematician, Alan Turing, formulated a different model of universal computation – the eponymous Turing Machine. A TM is a hypothetical device, again of extreme simplicity; it can read or write to cells on an infinite tape, each cell containing data or instructions. Turing published a paper also solving the Decision Problem, mere months after Church. 34 | 35 | // Turing proved that the Turing Machine and Lambda Calculus are totally equivalent. Everything that one can calculate, the other can. Not only this, but Turing and Church posited (in the "Church-Turing Thesis") that these systems capture the definition of computability in a universal way. 36 | 37 | // Turing Machines are exciting because if a hypothetical machine can compute anything computable, then perhaps a real machine can as well. Modern computers add many features and optimizations beyond what is featured in an actual Turing Machine; these features make the machine more convenient and performant, but do not compromise its essential nature as a universal computing device. 38 | 39 | // As machine codes, assemblers, compilers, and higher-level languages have developed to program these real machines, they have largely evolved with a focus on the essence of the machine – memory, statefulness, effects, imperative instructions and so forth. Over time, some of these languages have shifted ever farther into pure abstractions and conceptual description over more machine-centric and stateful models. 40 | 41 | // However, mathematicians and computer scientists have long known that the entirely abstract lambda calculus, being equivalent to a TM, meant that computations could be expressed in a style totally independent from machine instructions. Instead, a language consisting of first-class function expressions – aka lambda abstractions – could be subsequently compiled into machine code. Such a language would benefit from decades of mathematical research. And just as real computers extend Turing Machines with extra power and convenience, these _functional languages_ would extend the lambda calculus with additional features and under-the-hood shortcuts (such as hardware-based arithmetic). 42 | 43 | // What follows is a demonstration, mostly for enjoyment and insight, of the surprising and delightful omnipotence of the lambda calculus. JavaScript, like any functional language, is closely related to LC; it contains the necessary ingredients (variables, parentheses, first-class functions) nestled among the additional luxuries most programmers take for granted. 44 | 45 | // # First steps with simple combinators 46 | 47 | // Starting simple. A lambda abstraction is simply an anonymous unary function. In LC there are no named functions, but for convenience we will use names. In mathematical notation, `:=` means "is defined as". 48 | 49 | 50 | // ## Identity 51 | 52 | // Here is an almost trivial function: Identity, defined as `λx.x`. `λ` is used to indicate the start of a lambda abstraction (read: function expression). The sole parameter is listed to the left of the `.`, and the return expression is written after the `.`. 53 | 54 | header('I := λx.x') 55 | const I = x => x 56 | 57 | // In LC, variables may be static tokens that stand for whatever you want. We'll use ES2015 Symbols for this. 58 | 59 | const tweet = Symbol('tweet') 60 | const chirp = Symbol('chirp') 61 | 62 | // In LC, juxtaposition is function application. That is, `M I` means "apply the `M` function to the `I` argument". A space is not strictly necessary; `fx` usually means "apply `f` to `x`". Some of our examples will use multi-letter variables; to disambiguate them from multiple single-letter variables, we will frequently use SPACED UPPERCASE. 63 | 64 | // ```lc 65 | // I tweet 66 | // = (λx.x) tweet 67 | // = tweet 68 | // ``` 69 | 70 | demo('I tweet = tweet', I(tweet) === tweet) 71 | demo('I chirp = chirp', I(chirp) === chirp) 72 | 73 | // in LC, valid arguments include other lambda abstractions. This is the meaning of "first-class" in the phrase "first-class functions"; functions are values which may be passed into or returned from other functions. In this sense, functions are both like verbs (they can perform a calculation) and nouns (they can be the subject or object of a calculation). 74 | 75 | // ```lc 76 | // I I 77 | // = (λx.x)(λx.x) 78 | // = λx.x 79 | // ``` 80 | 81 | demo('I I = I', I(I) === I) 82 | 83 | // of course we can build up more complex expressions. In LC, function application associates left; that is, `a b c d` = `((a b) c) d`. Evaluating terms by substituting arguments into function bodies has the fancy term of "β-reduction". A reducible expression (or "redex") that has been completely simplified in this fashion is said to be in its "β-normal" or just "normal" form. 84 | 85 | // ```lc 86 | // id id id id tweet <--- the initial reducible expression ("redex") 87 | // = (((id id) id) id) tweet <--- application associates left 88 | // = (( id id) id) tweet <--- evaluating function applications ("β-reduction") 89 | // = ( id id) tweet <--- continuing β-reduction 90 | // = id tweet <--- more β-reduction 91 | // = tweet <--- normal form of the original redex 92 | // ``` 93 | 94 | // LC has great overlap with combinatory logic. A pioneer of CL was the mathematician Haskell Curry, whose name now adorns the Haskell language as well as the functional concept of currying. (Curry actually cited the technique from Schönfinkel, and Frege used it even earlier.) Combinatory logic is concerned with combinators, that is, functions which operate only on their inputs. The Identity function is a combinator, often abbreviated I, sometimes called the Idiot bird. 95 | 96 | header('Idiot := I') 97 | const Idiot = I 98 | 99 | 100 | // ## Self-Application 101 | 102 | // Curry was an avid birdwatcher, and the logician Raymond Smullyan named many combinators after birds in his honor. The self-application combinator M (for "Mockingbird"), aka ω (lowercase omega), looks like this: 103 | 104 | header('Mockingbird := M := ω := λf.ff') 105 | // Remember, `fx` means "apply f to x." So `ff` means "apply f to itself". 106 | const ω = fn => fn(fn) 107 | const M = ω 108 | const Mockingbird = M 109 | 110 | // Can you guess what the Mockingbird of Identity is? 111 | 112 | // ```lc 113 | // M I 114 | // = (λf.ff)(λx.x) 115 | // = (λx.x)(λx.x) = I I 116 | // = λx.x = I 117 | // ``` 118 | 119 | // That's right, it's the same as Identity of Identity… which is Identity. 120 | 121 | demo('M I = I I = I', M(I) === I(I) && I(I) === I) 122 | 123 | // What about… the Mockingbird of Mockingbird? 124 | 125 | // That's the Ω (big Omega) Combinator. It diverges (goes on forever). 126 | 127 | // ```lc 128 | // M M 129 | // = (λf.ff)(λf.ff) 130 | // = (λf.ff)(λf.ff) 131 | // = (λf.ff)(λf.ff) 132 | // = (λf.ff)(λf.ff) 133 | // ... 134 | // ``` 135 | 136 | try { 137 | M(M) 138 | } catch (err) { 139 | demo('M M = M M = M M = ' + err.message, true) 140 | } 141 | 142 | 143 | // ## Church Encodings: Booleans 144 | 145 | header('First encodings: boolean value functions') 146 | 147 | // OK this is nice and all, but how can we do anything real with only functions? Let's start with booleans. Here we need some multi-arg functions… in lambda calc, `λabc.a` is just shorthand for `λa.λb.λc.a`, or `λa.(λb.(λc.a)))`. In other words, all functions are curried. 148 | 149 | // ### True and False 150 | 151 | header('T := λxy.x') 152 | const T = thn => els => thn 153 | 154 | header('F := λxy.y') 155 | const F = thn => els => els 156 | 157 | // Hm. How can "true" and "false" be functions? Well, the point of booleans is to _select_ between a then-case and an else-case. The LC booleans are just functions which do that! `T` takes two vals and returns the first; `F` takes two vals and returns the second. If you apply an unknown bool func to two vals, the first val will be returned if the bool was true, else the second val will be returned. 158 | 159 | demo('T tweet chirp = tweet', T(tweet)(chirp) === tweet) 160 | demo('F tweet chirp = chirp', F(tweet)(chirp) === chirp) 161 | 162 | // ### Flipping Arguments 163 | 164 | // Another fun way we could have produced F was with the Cardinal combinator. The Cardinal, aka `C`, aka `flip`, takes a binary (two-argument) function, and produces a function with reversed argument order. 165 | 166 | header('Cardinal := C := flip := λfab.fba') 167 | const flip = func => a => b => func(b)(a) 168 | const C = flip 169 | const Cardinal = C 170 | 171 | // With the Cardinal, we can derive `F` from the flip of `T`: 172 | 173 | header('F = C T') 174 | 175 | demo('flip T tweet chirp = chirp', flip(T)(tweet)(chirp) === chirp) 176 | 177 | // Regardless of whether you define `F` manually, or as the flip of `T`, these functions are _encodings_ of boolean values. They represent booleans in useful and meaningful ways, which preserve the behavior of the values. Specifically, they are Church encodings – representations developed / discovered by Alonzo Church. Their real power is revealed when we start defining logical operations on them. 178 | 179 | // ### Negation 180 | 181 | header('NOT := λb.bFT') 182 | const NOT = chooseOne => chooseOne(F)(T) 183 | 184 | // Remember, booleans in the LC are really functions which select one of two arguments. Try reducing the expression `NOT T` yourself, then check your work below. 185 | 186 | // NOT T 187 | // = (λb.bFT) T 188 | // = TFT 189 | // = (λxy.x) F T 190 | // = F 191 | 192 | demo('NOT T = F', NOT(T) === F) 193 | demo('NOT F = T', NOT(F) === T) 194 | 195 | // There's another way we could define `NOT`, however, and we've already seen it. Remember how the flip of `T` (aka the Cardinal of `T`) is `F`? It works the other way too – `C F = T`! At least, `C F` yields a function that behaves identically to `T`: 196 | 197 | demo('CF = T', C(F)(tweet)(chirp) === tweet) 198 | demo('CT = F', C(T)(tweet)(chirp) === chirp) 199 | 200 | // This means that when it comes to Church encodings of booleans, the Cardinal behaves just like our manually-defined `NOT`. 201 | 202 | // ### Conjunction and Disjunction 203 | 204 | // Can you construct a function for boolean `AND`? It will have to take two unknown boolean functions as parameters, and route to an output of the correct boolean result. Give it a try. 205 | 206 | header('AND := λpq.pqF') 207 | 208 | // (λpq.pqp also works; can you see why?) 209 | 210 | const AND = p => q => p(q)(F) 211 | 212 | demo('AND F F = F', AND(F)(F) === F) 213 | demo('AND T F = F', AND(T)(F) === F) 214 | demo('AND F T = F', AND(F)(T) === F) 215 | demo('AND T T = T', AND(T)(T) === T) 216 | 217 | // If you work through the logic, you might notice that this function exhibits short-circuiting. If `p = F`, we don't bother using `q`. Similarly, our `OR` function below short circuits; if `p = T`, we don't bother using `q`. 218 | 219 | header('OR := λpq.pTq') 220 | 221 | // (λpq.ppq also works) 222 | 223 | const OR = p => q => p(T)(q) 224 | 225 | demo('OR F F = F', OR(F)(F) === F) 226 | demo('OR T F = T', OR(T)(F) === T) 227 | demo('OR F T = T', OR(F)(T) === T) 228 | demo('OR T T = T', OR(T)(T) === T) 229 | 230 | // `λpq.ppq` also works because if `p` is true, it is supposed to select `T`, but `p = T`, so we can just reuse it. Notice something interesting here: `λpq.ppq` behaves exactly like the Mockingbird. It takes a value, `p`, and self-applies `p` (producing `pp`). Well, `Mp = pp`, and you can apply that result to another value `q`, to get `ppq`; therefore, `Mpq = ppq`. So `M` and `λpq.ppq` behave identically (i.e. they are "extensionally equivalent", and in fact `λpq.ppq` is sometimes called `M*` or "the Mockinbird once-removed". The Mockingbird works as a boolean `OR` function: 231 | 232 | demo('M F F = F', M(F)(F) === F) 233 | demo('M T F = T', M(T)(F) === T) 234 | demo('M F T = T', M(F)(T) === T) 235 | demo('M T T = T', M(T)(T) === T) 236 | 237 | // ### Demo: De Morgan's Laws 238 | 239 | // With working booleans, we can illustrate some more complex logic, such as one of De Morgan's Laws: `!(p && q) === (!p) || (!q)`. 240 | 241 | header('De Morgan: not (and P Q) = or (not P) (not Q)') 242 | 243 | function deMorgansLawDemo (p, q) { return NOT(AND(p)(q)) === OR(NOT(p))(NOT(q)) } 244 | 245 | demo('NOT (AND F F) = OR (NOT F) (NOT F)', deMorgansLawDemo(F, F)) 246 | demo('NOT (AND T F) = OR (NOT T) (NOT F)', deMorgansLawDemo(T, F)) 247 | demo('NOT (AND F T) = OR (NOT F) (NOT T)', deMorgansLawDemo(F, T)) 248 | demo('NOT (AND T T) = OR (NOT T) (NOT T)', deMorgansLawDemo(T, T)) 249 | 250 | // ### Boolean Equality 251 | 252 | // However, this whole time we have been cheating in the demonstrations. Lambda calculus doesn't have any `===` operator to check for equality! Don't fret though, everything is functions. We can define our own equality function for booleans. 253 | 254 | header('BEQ := λpq.p (qTF) (qFT)') 255 | const BEQ = p => q => p( q(T)(F) )( q(F)(T) ) 256 | 257 | demo('BEQ F F = T', BEQ( BEQ(F)(F) )(T)) 258 | demo('BEQ F T = F', BEQ( BEQ(F)(T) )(F)) 259 | demo('BEQ T F = F', BEQ( BEQ(T)(F) )(F)) 260 | demo('BEQ T T = T', BEQ( BEQ(T)(T) )(T)) 261 | 262 | // Not a JS operator in sight (our `demo` function accepts church encodings). But for clarity's sake, we'll go back to using JS's equality operator in our `demo` calls. 263 | 264 | 265 | // ## Church Encodings: Numerals 266 | 267 | header('Numbers') 268 | 269 | // Booleans are neat, but surely to compute arithmetic you need language-supported math. Right? …Nah. You can construct math from scratch. 270 | 271 | // The Church encoding for a natural number n is an n-fold "compositor" (composing combinator). In other words, "2" is a function that composes a function `f` twice: `2 f x = f(f(x))`. Whereas "4" is a function that composes any `f` four times: `4 f x = f(f(f(f(x)`. In this sense, 2 and 3 can be read more like "two-fold" and "three-fold", or "twice" and "thrice". 272 | 273 | // ### Hard-Coded Numbers 274 | 275 | // In this system, `ZERO` is a function which applies a function `f` zero times to `x`. So… `ZERO` ignores the function argument, just returning `x`; `0 f x = x`. 276 | 277 | header('0 := λfx.x') 278 | // (fun fact, `0 = F`) 279 | const ZERO = fn => x => x 280 | 281 | // Zero applications of Mockingbird to `tweet` is just `tweet`. Good thing too, because applying Mockingbird to `tweet` would throw an error in JS (though it would work fine in LC, just by not simplifying further). 282 | 283 | demo('0 M tweet = tweet', ZERO(M)(tweet) === tweet) 284 | 285 | // We could hard-code `ONCE` as a single application of `f`… 286 | 287 | header('hard-coded 1 and 2') 288 | 289 | header('1 := λfx.fx') 290 | const ONCE = fn => x => fn(x) 291 | 292 | // Another fun fact – this is one step removed from `I`, called `I*` ("I-star"). In fact we could have shortened this to be `1 := I`. So 0 is false and 1 is identity, how nice! 293 | 294 | demo('1 I tweet = tweet', ONCE(I)(tweet) === tweet) 295 | 296 | // Identity is a bit boring, however, because the n-fold composition of `I` is always `I`, even for n = 0. The above example doesn't really prove our function is doing anything interesting. Let's cheat a bit with some string ops (note, this is polluting LC with some JS, but it's just for demonstration): 297 | 298 | const λ = 'λ' 299 | const yell = str => str + '!' 300 | 301 | demo('0 yell λ = λ', ZERO(yell)(λ) === 'λ') 302 | demo('1 yell λ = yell λ = λ!', ONCE(yell)(λ) === 'λ!') 303 | 304 | // we could also hard-code `TWICE`. 305 | 306 | header('2 := λfx.f(fx)') 307 | const TWICE = fn => x => fn(fn(x)) 308 | 309 | demo('2 yell λ = yell (yell λ) = λ!!', TWICE(yell)(λ) === 'λ!!') 310 | 311 | // ### Successor 312 | 313 | // This hard-coding works, but is very limiting. We can't do true arithmetic like this, where operations on numbers generate other numbers. What we need is a way to count up. 314 | 315 | header('SUCCESSOR') 316 | 317 | header('SUCCESSOR := λnfx.f(nfx)') 318 | const SUCCESSOR = num => fn => x => fn(num(fn)(x)) 319 | 320 | // Don't get lost in the weeds. All we are saying is that the successor of `n` does `n` compositions of `f` to a value `x`, and then it does _one more_ application of `f` to the result. Therefore, it ends up doing 1 + n compositions of `f` in total. 321 | 322 | const newOnce = SUCCESSOR(ZERO) 323 | const newTwice = SUCCESSOR(SUCCESSOR(ZERO)) // we can use multiple successors on zero, or… 324 | const newThrice = SUCCESSOR(newTwice) // …apply successor to already-obtained numbers. 325 | 326 | demo('1 yell λ = λ!', newOnce(yell)(λ) === 'λ!') 327 | demo('2 yell λ = λ!!', newTwice(yell)(λ) === 'λ!!') 328 | demo('3 yell λ = λ!!!', newThrice(yell)(λ) === 'λ!!!') 329 | 330 | // ### Composition and Point-Free Notation 331 | 332 | // There is another way to write successor. Point-free (some joke "point-less") notation means to define a function purely as a combination of other functions, without explicitly writing final arguments. Sometimes this style reveals what a function *is* rather than what explain what it *does*. Other times it can be abused to produce incomprehensible gibberish. Successor is a reasonable candidate for it, however. 333 | 334 | // We are doing n-fold compositions, so let's define an actual `compose` function to help. Composition is often notated as `∘` in infix position: `(f ∘ g) x = f(g(x))`. However, Lambda Calculus only includes prefix position function application. Smullyan named this the Bluebird after Curry's `B` combinator. 335 | 336 | header('Bluebird := B := (∘) := compose := λfgx.f(gx)') 337 | const compose = f => g => x => f(g(x)) 338 | const B = compose 339 | const Bluebird = B 340 | 341 | demo('(B NOT NOT) T = NOT (NOT T)', (B(NOT)(NOT))(T) === NOT(NOT(T))) 342 | demo('(B yell NOT) F = yell (NOT F)', (B(yell)(NOT))(F) === yell(NOT(F))) 343 | 344 | // Now that we have an actual composition function, we can define successor without mentioning the final `x` value argument. 345 | 346 | header('SUCC := λnf.f∘(nf) = λnf.Bf(nf)') 347 | const SUCC = num => fn => compose( fn )( num(fn) ) 348 | 349 | // This is just a terse way of repeating what we already know: if a given `n` composes some function `f` n times, then the successor of n is a function which composes one additional `f`, for a total of 1 + n compositions. 350 | 351 | const n0 = ZERO 352 | const n1 = SUCC(n0) 353 | const n2 = SUCC(SUCC(n0)) 354 | const n3 = SUCC(SUCC(SUCC(n0))) 355 | const n4 = SUCC(n3) 356 | 357 | demo('1 yell λ = λ!', n1(yell)(λ) === 'λ!') 358 | demo('2 yell λ = λ!!', n2(yell)(λ) === 'λ!!') 359 | demo('3 yell λ = λ!!!', n3(yell)(λ) === 'λ!!!') 360 | demo('4 yell λ = λ!!!!', n4(yell)(λ) === 'λ!!!!') 361 | 362 | // ### Arithmetic 363 | 364 | // #### Addition 365 | 366 | // Things will get pretty slow if we can only increment by 1. Let's add addition. 367 | 368 | header('ADD := λab.a(succ)b') 369 | const ADD = numA => numB => numA(SUCC)(numB) 370 | 371 | // Aha, addition is just the Ath successor of B. Makes sense. For example, `ADD 3 2 = 3 SUCC 2`, which could be read as "thrice successor of twice". 372 | 373 | const n5 = ADD(n2)(n3) 374 | const n6 = ADD(n3)(n3) 375 | 376 | demo('ADD 5 2 yell λ = λ!!!!!!!', ADD(n5)(n2)(yell)(λ) === 'λ!!!!!!!') 377 | demo('ADD 0 3 yell λ = λ!!!', ADD(n0)(n3)(yell)(λ) === 'λ!!!') 378 | demo('ADD 2 2 = 4', ADD(n2)(n2)(yell)(λ) === n4(yell)(λ)) 379 | 380 | // These equivalence checks using `yell` and `'λ'` are a bit verbose. It's annoying, but a mathematical truth, that there can be no general algorithm to decide if two functions are equivalent – and we cannot rely on JS function equality because we are generating independent function objects. Since `yell` and `'λ'` are already impure non-LC code, we might as well go all the way and define `church` and `jsnum` to convert between Church encodings and JS numbers. 381 | 382 | header('LC <-> JS: church & jsnum') 383 | 384 | function church (n) { return n === 0 ? n0 : SUCC(church(n - 1)) } 385 | function jsnum (c) { return c(x => x + 1)(0) } 386 | 387 | demo( 'church(5) = n5', church(5)(yell)(λ) === n5(yell)(λ)) 388 | demo( 'jsnum(n5) === 5', jsnum(n5) === 5) 389 | demo('jsnum(church(2)) === 2', jsnum(church(2)) === 2) 390 | 391 | // #### Multiplication 392 | 393 | // Back to math. How about multiplication? 394 | 395 | header('MULT := λab.a∘b = compose') 396 | const MULT = compose 397 | 398 | // How beautiful! Multiplication is the composition of numbers. For example, `MULT 3 2 = 3 ∘ 2`, which could be read as "thrice of twice", or "three of (two of (someFn))". If you compose a function `f` two times — `f ∘ f` — and then you compose that result three times — `(f∘f) ∘ (f∘f) ∘ (f∘f)` — you get the six-fold composition of f: `f ∘ f ∘ f ∘ f ∘ f ∘ f`. It helps to know that composition is associative — `f ∘ (g ∘ h) = (f ∘ g) ∘ h`. 399 | 400 | demo('MULT 1 5 = 5', jsnum( MULT(n1)(n5) ) === 5) 401 | demo('MULT 3 2 = 6', jsnum( MULT(n3)(n2) ) === 6) 402 | demo('MULT 4 0 = 0', jsnum( MULT(n4)(n0) ) === 0) 403 | demo('MULT 6 2 yell λ = λ!!!!!!!!!!!!', MULT(n6)(n2)(yell)(λ) === 'λ!!!!!!!!!!!!') 404 | 405 | const n8 = MULT(n4)(n2) 406 | const n9 = SUCC(n8) 407 | 408 | // #### Exponentiation 409 | 410 | // Exponentiation is remarkably clean too. When we say 2^3, we are saying "multiply two by itself three times"; or putting it another way, "twice of twice of twice". So for any base and power, the result is the power-fold composition of the base: 411 | 412 | header('Thrush := POW := λab.ba') 413 | const POW = numA => numB => numB(numA) 414 | 415 | // As you can see, we also call this combinator the Thrush. Unfortunately we have a name collision as we already defined `T` as the church encoding of true, so we omit the single-letter version of this combinator. There is another letter sometimes reserved for true, in which case we can use `T` for Thrush; the alternate true combinator name is coming up soon. 416 | 417 | demo('POW 2 3 = 8', jsnum( POW(n2)(n3) ) === 8) 418 | demo('POW 3 2 = 9', jsnum( POW(n3)(n2) ) === 9) 419 | demo('POW 6 1 = 6', jsnum( POW(n6)(n1) ) === 6) 420 | demo('POW 5 0 = 1', jsnum( POW(n5)(n0) ) === 1) 421 | 422 | // ### Num -> Bool 423 | 424 | // As stated earlier, there is no general function-equivalence algorithm (this lies at the heart of Church's research efforts into "decidability"). But just as we did for booleans, we can develop a specific equality check for numbers. 425 | 426 | // #### Zero Equality 427 | 428 | // We start with zero. If our input is zero, we want to produce `T`. Otherwise, we want to produce `F`. In our function below, if the input is zero, we run the inner function zero times, which means we return the final argument (`T`). However, if the input is any number greater than zero, we run the inner function at least once; that inner function is designed to always produce `F`. 429 | 430 | header('ISZERO := λn.n(λ_.F)T') 431 | const ISZERO = num => num(_ => F)(T) 432 | 433 | demo('ISZERO 0 = T', ISZERO(n0) === T) 434 | demo('ISZERO 1 = F', ISZERO(n1) === F) 435 | demo('ISZERO 2 = F', ISZERO(n2) === F) 436 | 437 | // #### The Kestrel 438 | 439 | // ISZERO used a nice trick to produce a constant. We'll abstract that out. This is the Kestrel combinator `K`, named for the German word "Konstante". The `K` combinator takes a value, and produces a function which ignores its input, always returning the original value. So, `K0` is a function that always returns 0; (`K tweet`) is a function which always returns tweet. 440 | 441 | header('Kestrel combinator and IS0') 442 | 443 | header('Kestrel := K := konst := λk_.k') 444 | const konst = k => _ => k 445 | const K = konst 446 | const Kestrel = K 447 | 448 | demo('K0 tweet = 0', K(n0)(tweet) === n0) 449 | demo('K0 chirp = 0', K(n0)(chirp) === n0) 450 | demo('K tweet chirp = tweet', K(tweet)(chirp) === tweet) 451 | 452 | // With K, we can redefine our isZero function more concisely. 453 | 454 | header('IS0 := λn.n(KF)T') 455 | const IS0 = num => num(K(F))(T) 456 | 457 | demo('IS0 0 = T', IS0(n0) === T) 458 | demo('IS0 1 = F', IS0(n1) === F) 459 | demo('IS0 2 = F', IS0(n2) === F) 460 | 461 | // `K` should look familiar; it's "alpha-equivalent" to `T`. Alpha-equivalence means it is identical except for variable names, which are arbitrary and don't affect the behavior: `λk_.k = λab.a`. 462 | 463 | // #### The Kite 464 | 465 | // We can also make `F` out of `K` and `I`. Try tracing through the logic and confirming that `KI = F`. This result is known as the Kite. 466 | 467 | header(' K = T') 468 | header('Kite := KI = F') 469 | const Tru = K 470 | const Fls = K(I) 471 | const Kite = Fls 472 | 473 | demo('K tweet chirp = tweet', Tru(tweet)(chirp) === tweet) 474 | demo('KI tweet chirp = chirp', Fls(tweet)(chirp) === chirp) 475 | demo('De Morgan using K and KI', deMorgansLawDemo(K, K(I))) 476 | 477 | // ### Interlude: Predecessor (So Far) 478 | 479 | // We're still a way off from numeric equality. To get it working we'll need `succ`'s opposite, `pred` (predecessor). For a given num, `pred` gives you the number that came before, unless we're at 0, in which case it just gives you 0. It is possible to define predecessor using only the tools we've built thus far, but it's quite difficult to comprehend. Glance at it, but we'll be seeing a better version soon: 480 | 481 | header('PREDECESSOR := λn.n (λg.IS0 (g 1) I (B SUCC g)) (K0) 0') 482 | const PREDECESSOR = num => num(g => IS0(g(n1))(I)(B(SUCC)(g)))(K(n0))(n0) 483 | 484 | demo('PREDECESSOR 0 = 0', jsnum( PREDECESSOR(n0) ) === 0) 485 | demo('PREDECESSOR 1 = 0', jsnum( PREDECESSOR(n1) ) === 0) 486 | demo('PREDECESSOR 2 = 1', jsnum( PREDECESSOR(n2) ) === 1) 487 | demo('PREDECESSOR 3 = 2', jsnum( PREDECESSOR(n3) ) === 2) 488 | 489 | // Idiots, Bluebirds, and Kestrels — oh my! The essence of this formulation for `PREDECESSOR` is a machine of sorts which, if skipped, yields `K0 0 = 0`; if run once, produces `I K0 0 = 0`; and if run n times, produces `(n - 1) succ (I K0 0) = n - 1`. However, there are other versions of predecessor, including one that is far clearer than this. To get there, we are going to have to take a small detour into functional data structures. 490 | 491 | // ## Functional Data Structures: Pair 492 | 493 | header('Pair: a Tiny Functional Data Structure') 494 | 495 | // There are varying definitions for "data structure". In this context we will use it to mean a way of organizing information, plus an interface for accessing that information (some might argue that this is closer to the definition of an Abstract Data Type). In the lambda calculus, we do not have objects, arrays, sets or what-have-you… only functions. But we've already seen that functions capture values through *closure*, and are able to produce those values again later. That's the essence of the K combinator, in fact. 496 | 497 | // Here we define a more complex entity, the Church encoding for "pair". Smullyan named this combinator the Vireo. 498 | 499 | header('Vireo := V := PAIR := λabf.fab') 500 | const PAIR = a => b => f => f(a)(b) 501 | const V = PAIR 502 | const Vireo = V 503 | 504 | // `PAIR` takes two arbitrary values, a and b, and returns a function ("the pair") closing over those values. When the pair is fed a final argument f, f is applied to a and b. So our pair can "provide" a and b, in that order, to any binary function. 505 | 506 | const examplePair = PAIR(tweet)(chirp) 507 | 508 | demo('(PAIR tweet chirp) T = tweet', examplePair(T) === tweet) 509 | demo('(PAIR tweet chirp) F = chirp', examplePair(F) === chirp) 510 | 511 | // ### Opening the Closure 512 | 513 | // As you can see, when a pair is fed the binary function `T` or `F`, it has the effect of extracting out one member of the pair. To make this more expressive and English-y, we can define FST (first) and SND (second) functions that perform this work for us: 514 | 515 | header('FST := λp.pT; SND = λp.pF') 516 | const FST = somePair => somePair(T) 517 | const SND = somePair => somePair(F) 518 | 519 | demo('FST (PAIR tweet chirp) = tweet', FST(examplePair) === tweet) 520 | demo('SND (PAIR tweet chirp) = chirp', SND(examplePair) === chirp) 521 | 522 | // ### Immutability 523 | 524 | // There isn't any way to change the closed-over variables, but that's a good thing – immutability means that we never accidentally mess up data someone else was relying on. We can generate new data instead. 525 | 526 | header('SET_FST := λcp.PAIR c (SND p)') 527 | const SET_FST = newFirst => oldP => PAIR(newFirst)(SND(oldP)) 528 | 529 | demo('FST (SET_FST chirp (PAIR tweet tweet)) = chirp', FST( SET_FST(chirp)(PAIR(tweet)(tweet)) ) === chirp) 530 | demo('SND (SET_FST chirp (PAIR tweet tweet)) = tweet', SND( SET_FST(chirp)(PAIR(tweet)(tweet)) ) === tweet) 531 | 532 | // It would help to have a shorthand for pairs. We will use to stand in for `(pair a b)`. 533 | 534 | header('SET_SND := λcp.PAIR (FST p) c') 535 | const SET_SND = newSecond => oldP => PAIR(FST(oldP))(newSecond) 536 | 537 | demo('FST (SET_SND chirp ) = tweet', FST( SET_SND(chirp)(PAIR(tweet)(tweet)) ) === tweet) 538 | demo('SND (SET_SND chirp ) = chirp', SND( SET_SND(chirp)(PAIR(tweet)(tweet)) ) === chirp) 539 | 540 | // ### Counting Up with Memory 541 | 542 | // Back on track towards our cleaner `PRED`, we will define a special pair function Φ (aka PHI) which moves the second element to the first, and increments the second element by 1. In shorthand, `Φ = `. The use of this function will become apparent shortly. 543 | 544 | header('PHI := Φ := λp.PAIR (SND p) (SUCC (SND p))') 545 | const Φ = oldPair => PAIR(SND(oldPair))(SUCC(SND(oldPair))) 546 | const PHI = Φ 547 | 548 | const examplePairChirp0 = PAIR(chirp)(n0) 549 | const examplePairTweet4 = PAIR(tweet)(n4) 550 | 551 | demo('Φ = <0, 1>', 552 | jsnum( FST(Φ(examplePairChirp0)) ) === 0 && 553 | jsnum( SND(Φ(examplePairChirp0)) ) === 1 554 | ) 555 | demo('Φ = <4, 5>', 556 | jsnum( FST(Φ(examplePairTweet4)) ) === 4 && 557 | jsnum( SND(Φ(examplePairTweet4)) ) === 5 558 | ) 559 | 560 | // ## Back to Arithmetic 561 | 562 | // ### A Cleaner Predecessor 563 | 564 | // At long last, we can return to our predecessor function. With the help of Φ, it is wonderfully simple… well, relatively speaking at least. 565 | 566 | header('PRED := λn.FST (n Φ <0, 0>)') 567 | const PRED = n => FST( n(Φ)(PAIR(n0)(n0)) ) 568 | 569 | // All we do is successive applications of Φ to a seed pair <0, 0>. After n applications, the pair is . Then we can pluck off the first value of the pair! In effect, we count up to n, but keep the predecessor around for easy reference. 570 | 571 | // n | n Φ <0, 0> | first of result pair 572 | // --|------------|--------------------- 573 | // 0 | <0, 0> | 0 574 | // 1 | <0, 1> | 0 575 | // 2 | <1, 2> | 1 576 | // 3 | <2, 3> | 2 577 | 578 | demo('PRED 0 = 0', jsnum( PRED(n0) ) === 0) 579 | demo('PRED 1 = 0', jsnum( PRED(n1) ) === 0) 580 | demo('PRED 2 = 1', jsnum( PRED(n2) ) === 1) 581 | demo('PRED 3 = 2', jsnum( PRED(n3) ) === 2) 582 | 583 | // ### Subtraction At Last 584 | 585 | // Now that the epic `pred` exists, we can do subtraction… at least, down to 0. 586 | 587 | header('SUB := λab.b PRED a') 588 | const SUB = a => b => b(PRED)(a) 589 | 590 | const n7 = ADD(n4)(n3) 591 | 592 | demo('SUB 5 2 = 3', jsnum( SUB(n5)(n2) ) === 3) 593 | demo('SUB 4 0 = 4', jsnum( SUB(n4)(n0) ) === 4) 594 | demo('SUB 2 2 = 0', jsnum( SUB(n2)(n7) ) === 0) 595 | demo('SUB 2 7 = 0', jsnum( SUB(n2)(n7) ) === 0) 596 | 597 | // ### Number Comparisons 598 | 599 | // This kind of limited subtraction enables less-than-or-equal-to. 600 | 601 | header('LEQ := λab.IS0(SUB a b)') 602 | const LEQ = a => b => IS0(SUB(a)(b)) 603 | 604 | demo('LEQ 3 2 = F', LEQ(n3)(n2) === F) 605 | demo('LEQ 3 3 = T', LEQ(n3)(n3) === T) 606 | demo('LEQ 3 4 = T', LEQ(n3)(n4) === T) 607 | 608 | // Finally we can test for numeric equality. 🎉🎉🎉 609 | 610 | header('eq := λab.AND (LEQ a b) (LEQ b a)') 611 | const EQ = a => b => AND (LEQ(a)(b)) (LEQ(b)(a)) 612 | 613 | demo('EQ 4 6 = F', EQ(n4)(n5) === F) 614 | demo('EQ 7 3 = F', EQ(n7)(n3) === F) 615 | demo('EQ 5 5 = T', EQ(n5)(n5) === T) 616 | demo('EQ (ADD 3 6) (POW 3 2) = T', EQ(ADD(n3)(n6))(POW(n3)(n2)) === T) 617 | 618 | // ## More Composition 619 | 620 | // Of course we can use composition to create other results. At first glance, it would seem like greater-than can be the composition of `NOT` and `LEQ`. But this doesn't work because `LEQ` is a two-arg function, and compose only works with unary functions. Thanks to the beautiful Blackbird combinator, however, we can create point-free compositions where the rightmost function is binary. 621 | 622 | header('Blackbird := B′ := BBB') 623 | const B1 = compose(compose)(compose) 624 | const Blackbird = B1 625 | 626 | // If you find B1 confusing, the point-ful version might help: `B1 := λfgxy.f(g x y)`. Also, why Smullyan chose "B1" instead of "B2", I can only guess. 627 | 628 | header('GT := B1 NOT LEQ') 629 | const GT = B1(NOT)(LEQ) 630 | 631 | demo('GT 6 2 = T', GT(n6)(n2) === T) 632 | demo('GT 4 4 = F', GT(n4)(n4) === F) 633 | demo('GT 4 5 = F', GT(n4)(n5) === F) 634 | 635 | // Another use of Blackbird: `neq := B1 not eq`. 636 | 637 | // ## Final Notes 638 | 639 | // There are church encodings and lambda techniques for lists, types, rationals, reals, and anything else that is computable – plus the astonishing Y-combinator, which enables recursion in a syntax where functions are all anonymous. We also omitted the Starling, which can be combined with the Kestrel in various ways to produce *every other function.* For now, we will end with an actual real-world classic math problem, calculated entirely using lambda calculus – only converted back to JS numbers at the end, purely for display purposes. 640 | 641 | header('FIB := λn.n (λfab.f b (ADD a b)) K 0 1') 642 | const FIB = n => n(f => a => b => f(b)(ADD(a)(b)))(K)(n0)(n1) 643 | 644 | demo('FIB 0 = 0', jsnum( FIB(n0) ) === 0) 645 | demo('FIB 1 = 1', jsnum( FIB(n1) ) === 1) 646 | demo('FIB 2 = 1', jsnum( FIB(n2) ) === 1) 647 | demo('FIB 3 = 2', jsnum( FIB(n3) ) === 2) 648 | demo('FIB 4 = 3', jsnum( FIB(n4) ) === 3) 649 | demo('FIB 5 = 5', jsnum( FIB(n5) ) === 5) 650 | demo('FIB 6 = 8', jsnum( FIB(n6) ) === 8) 651 | 652 | logErrsAndSetExitCode() 653 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | abbrev@1: 6 | version "1.1.0" 7 | resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f" 8 | 9 | acorn-jsx@^3.0.0: 10 | version "3.0.1" 11 | resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" 12 | dependencies: 13 | acorn "^3.0.4" 14 | 15 | acorn@^3.0.4: 16 | version "3.3.0" 17 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" 18 | 19 | acorn@^5.0.1: 20 | version "5.0.3" 21 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.0.3.tgz#c460df08491463f028ccb82eab3730bf01087b3d" 22 | 23 | ajv-keywords@^1.0.0: 24 | version "1.5.1" 25 | resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" 26 | 27 | ajv@^4.7.0, ajv@^4.9.1: 28 | version "4.11.8" 29 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" 30 | dependencies: 31 | co "^4.6.0" 32 | json-stable-stringify "^1.0.1" 33 | 34 | ansi-escapes@^1.1.0, ansi-escapes@^1.4.0: 35 | version "1.4.0" 36 | resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" 37 | 38 | ansi-regex@^2.0.0: 39 | version "2.1.1" 40 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" 41 | 42 | ansi-styles@^2.2.1: 43 | version "2.2.1" 44 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" 45 | 46 | ansi-styles@^3.1.0: 47 | version "3.2.0" 48 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88" 49 | dependencies: 50 | color-convert "^1.9.0" 51 | 52 | anymatch@^1.3.0: 53 | version "1.3.0" 54 | resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507" 55 | dependencies: 56 | arrify "^1.0.0" 57 | micromatch "^2.1.5" 58 | 59 | aproba@^1.0.3: 60 | version "1.1.2" 61 | resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.2.tgz#45c6629094de4e96f693ef7eab74ae079c240fc1" 62 | 63 | are-we-there-yet@~1.1.2: 64 | version "1.1.4" 65 | resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" 66 | dependencies: 67 | delegates "^1.0.0" 68 | readable-stream "^2.0.6" 69 | 70 | argparse@^1.0.7: 71 | version "1.0.9" 72 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" 73 | dependencies: 74 | sprintf-js "~1.0.2" 75 | 76 | arr-diff@^2.0.0: 77 | version "2.0.0" 78 | resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" 79 | dependencies: 80 | arr-flatten "^1.0.1" 81 | 82 | arr-flatten@^1.0.1: 83 | version "1.0.3" 84 | resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.3.tgz#a274ed85ac08849b6bd7847c4580745dc51adfb1" 85 | 86 | array-union@^1.0.1: 87 | version "1.0.2" 88 | resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" 89 | dependencies: 90 | array-uniq "^1.0.1" 91 | 92 | array-uniq@^1.0.1: 93 | version "1.0.3" 94 | resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" 95 | 96 | array-unique@^0.2.1: 97 | version "0.2.1" 98 | resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" 99 | 100 | arrify@^1.0.0: 101 | version "1.0.1" 102 | resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" 103 | 104 | asn1@~0.2.3: 105 | version "0.2.3" 106 | resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" 107 | 108 | assert-plus@1.0.0, assert-plus@^1.0.0: 109 | version "1.0.0" 110 | resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" 111 | 112 | assert-plus@^0.2.0: 113 | version "0.2.0" 114 | resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" 115 | 116 | async-each@^1.0.0: 117 | version "1.0.1" 118 | resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" 119 | 120 | asynckit@^0.4.0: 121 | version "0.4.0" 122 | resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" 123 | 124 | aws-sign2@~0.6.0: 125 | version "0.6.0" 126 | resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" 127 | 128 | aws4@^1.2.1: 129 | version "1.6.0" 130 | resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" 131 | 132 | babel-code-frame@^6.16.0, babel-code-frame@^6.22.0: 133 | version "6.22.0" 134 | resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4" 135 | dependencies: 136 | chalk "^1.1.0" 137 | esutils "^2.0.2" 138 | js-tokens "^3.0.0" 139 | 140 | babel-eslint@^7.2.3: 141 | version "7.2.3" 142 | resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-7.2.3.tgz#b2fe2d80126470f5c19442dc757253a897710827" 143 | dependencies: 144 | babel-code-frame "^6.22.0" 145 | babel-traverse "^6.23.1" 146 | babel-types "^6.23.0" 147 | babylon "^6.17.0" 148 | 149 | babel-messages@^6.23.0: 150 | version "6.23.0" 151 | resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" 152 | dependencies: 153 | babel-runtime "^6.22.0" 154 | 155 | babel-polyfill@^6.20.0: 156 | version "6.23.0" 157 | resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.23.0.tgz#8364ca62df8eafb830499f699177466c3b03499d" 158 | dependencies: 159 | babel-runtime "^6.22.0" 160 | core-js "^2.4.0" 161 | regenerator-runtime "^0.10.0" 162 | 163 | babel-runtime@^6.22.0: 164 | version "6.23.0" 165 | resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b" 166 | dependencies: 167 | core-js "^2.4.0" 168 | regenerator-runtime "^0.10.0" 169 | 170 | babel-traverse@^6.23.1: 171 | version "6.25.0" 172 | resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.25.0.tgz#2257497e2fcd19b89edc13c4c91381f9512496f1" 173 | dependencies: 174 | babel-code-frame "^6.22.0" 175 | babel-messages "^6.23.0" 176 | babel-runtime "^6.22.0" 177 | babel-types "^6.25.0" 178 | babylon "^6.17.2" 179 | debug "^2.2.0" 180 | globals "^9.0.0" 181 | invariant "^2.2.0" 182 | lodash "^4.2.0" 183 | 184 | babel-types@^6.23.0, babel-types@^6.25.0: 185 | version "6.25.0" 186 | resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.25.0.tgz#70afb248d5660e5d18f811d91c8303b54134a18e" 187 | dependencies: 188 | babel-runtime "^6.22.0" 189 | esutils "^2.0.2" 190 | lodash "^4.2.0" 191 | to-fast-properties "^1.0.1" 192 | 193 | babylon@^6.17.0, babylon@^6.17.2: 194 | version "6.17.3" 195 | resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.17.3.tgz#1327d709950b558f204e5352587fd0290f8d8e48" 196 | 197 | balanced-match@^0.4.1: 198 | version "0.4.2" 199 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" 200 | 201 | bcrypt-pbkdf@^1.0.0: 202 | version "1.0.1" 203 | resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" 204 | dependencies: 205 | tweetnacl "^0.14.3" 206 | 207 | binary-extensions@^1.0.0: 208 | version "1.8.0" 209 | resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.8.0.tgz#48ec8d16df4377eae5fa5884682480af4d95c774" 210 | 211 | block-stream@*: 212 | version "0.0.9" 213 | resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" 214 | dependencies: 215 | inherits "~2.0.0" 216 | 217 | bluebird@^3.4.7: 218 | version "3.5.0" 219 | resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c" 220 | 221 | boom@2.x.x: 222 | version "2.10.1" 223 | resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" 224 | dependencies: 225 | hoek "2.x.x" 226 | 227 | brace-expansion@^1.1.7: 228 | version "1.1.7" 229 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.7.tgz#3effc3c50e000531fb720eaff80f0ae8ef23cf59" 230 | dependencies: 231 | balanced-match "^0.4.1" 232 | concat-map "0.0.1" 233 | 234 | braces@^1.8.2: 235 | version "1.8.5" 236 | resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" 237 | dependencies: 238 | expand-range "^1.8.1" 239 | preserve "^0.2.0" 240 | repeat-element "^1.1.2" 241 | 242 | caller-path@^0.1.0: 243 | version "0.1.0" 244 | resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" 245 | dependencies: 246 | callsites "^0.2.0" 247 | 248 | callsites@^0.2.0: 249 | version "0.2.0" 250 | resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" 251 | 252 | caseless@~0.12.0: 253 | version "0.12.0" 254 | resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" 255 | 256 | chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: 257 | version "1.1.3" 258 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" 259 | dependencies: 260 | ansi-styles "^2.2.1" 261 | escape-string-regexp "^1.0.2" 262 | has-ansi "^2.0.0" 263 | strip-ansi "^3.0.0" 264 | supports-color "^2.0.0" 265 | 266 | chalk@^2.1.0: 267 | version "2.1.0" 268 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.1.0.tgz#ac5becf14fa21b99c6c92ca7a7d7cfd5b17e743e" 269 | dependencies: 270 | ansi-styles "^3.1.0" 271 | escape-string-regexp "^1.0.5" 272 | supports-color "^4.0.0" 273 | 274 | chokidar@^1.4.3: 275 | version "1.7.0" 276 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" 277 | dependencies: 278 | anymatch "^1.3.0" 279 | async-each "^1.0.0" 280 | glob-parent "^2.0.0" 281 | inherits "^2.0.1" 282 | is-binary-path "^1.0.0" 283 | is-glob "^2.0.0" 284 | path-is-absolute "^1.0.0" 285 | readdirp "^2.0.0" 286 | optionalDependencies: 287 | fsevents "^1.0.0" 288 | 289 | ci-info@^1.0.0: 290 | version "1.0.0" 291 | resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.0.0.tgz#dc5285f2b4e251821683681c381c3388f46ec534" 292 | 293 | circular-json@^0.3.1: 294 | version "0.3.1" 295 | resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d" 296 | 297 | cli-cursor@^1.0.1: 298 | version "1.0.2" 299 | resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" 300 | dependencies: 301 | restore-cursor "^1.0.1" 302 | 303 | cli-width@^2.0.0: 304 | version "2.1.0" 305 | resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" 306 | 307 | co@^4.6.0: 308 | version "4.6.0" 309 | resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" 310 | 311 | code-point-at@^1.0.0: 312 | version "1.1.0" 313 | resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" 314 | 315 | color-convert@^1.9.0: 316 | version "1.9.0" 317 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a" 318 | dependencies: 319 | color-name "^1.1.1" 320 | 321 | color-name@^1.1.1: 322 | version "1.1.3" 323 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 324 | 325 | combined-stream@^1.0.5, combined-stream@~1.0.5: 326 | version "1.0.5" 327 | resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" 328 | dependencies: 329 | delayed-stream "~1.0.0" 330 | 331 | "commander@>= 0.5.2": 332 | version "2.11.0" 333 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" 334 | 335 | concat-map@0.0.1: 336 | version "0.0.1" 337 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 338 | 339 | concat-stream@^1.5.2: 340 | version "1.6.0" 341 | resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" 342 | dependencies: 343 | inherits "^2.0.3" 344 | readable-stream "^2.2.2" 345 | typedarray "^0.0.6" 346 | 347 | configstore@^1.0.0: 348 | version "1.4.0" 349 | resolved "https://registry.yarnpkg.com/configstore/-/configstore-1.4.0.tgz#c35781d0501d268c25c54b8b17f6240e8a4fb021" 350 | dependencies: 351 | graceful-fs "^4.1.2" 352 | mkdirp "^0.5.0" 353 | object-assign "^4.0.1" 354 | os-tmpdir "^1.0.0" 355 | osenv "^0.1.0" 356 | uuid "^2.0.1" 357 | write-file-atomic "^1.1.2" 358 | xdg-basedir "^2.0.0" 359 | 360 | console-control-strings@^1.0.0, console-control-strings@~1.1.0: 361 | version "1.1.0" 362 | resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" 363 | 364 | core-js@^2.4.0: 365 | version "2.4.1" 366 | resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" 367 | 368 | core-util-is@~1.0.0: 369 | version "1.0.2" 370 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" 371 | 372 | cryptiles@2.x.x: 373 | version "2.0.5" 374 | resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" 375 | dependencies: 376 | boom "2.x.x" 377 | 378 | d@1: 379 | version "1.0.0" 380 | resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" 381 | dependencies: 382 | es5-ext "^0.10.9" 383 | 384 | dashdash@^1.12.0: 385 | version "1.14.1" 386 | resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" 387 | dependencies: 388 | assert-plus "^1.0.0" 389 | 390 | debug@^2.1.1, debug@^2.2.0, debug@^2.6.3: 391 | version "2.6.8" 392 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" 393 | dependencies: 394 | ms "2.0.0" 395 | 396 | deep-extend@~0.4.0: 397 | version "0.4.2" 398 | resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" 399 | 400 | deep-is@~0.1.3: 401 | version "0.1.3" 402 | resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" 403 | 404 | del@^2.0.2: 405 | version "2.2.2" 406 | resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" 407 | dependencies: 408 | globby "^5.0.0" 409 | is-path-cwd "^1.0.0" 410 | is-path-in-cwd "^1.0.0" 411 | object-assign "^4.0.1" 412 | pify "^2.0.0" 413 | pinkie-promise "^2.0.0" 414 | rimraf "^2.2.8" 415 | 416 | delayed-stream@~1.0.0: 417 | version "1.0.0" 418 | resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" 419 | 420 | delegates@^1.0.0: 421 | version "1.0.0" 422 | resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" 423 | 424 | docco@^0.7.0: 425 | version "0.7.0" 426 | resolved "https://registry.yarnpkg.com/docco/-/docco-0.7.0.tgz#d606e5a990cba052ca1e1803a9c587ecee3c5c38" 427 | dependencies: 428 | commander ">= 0.5.2" 429 | fs-extra ">= 0.6.0" 430 | highlight.js ">= 8.0.x" 431 | marked ">= 0.2.7" 432 | underscore ">= 1.0.0" 433 | 434 | doctrine@^2.0.0: 435 | version "2.0.0" 436 | resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.0.0.tgz#c73d8d2909d22291e1a007a395804da8b665fe63" 437 | dependencies: 438 | esutils "^2.0.2" 439 | isarray "^1.0.0" 440 | 441 | duplexer@~0.1.1: 442 | version "0.1.1" 443 | resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" 444 | 445 | duplexify@^3.2.0: 446 | version "3.5.0" 447 | resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.5.0.tgz#1aa773002e1578457e9d9d4a50b0ccaaebcbd604" 448 | dependencies: 449 | end-of-stream "1.0.0" 450 | inherits "^2.0.1" 451 | readable-stream "^2.0.0" 452 | stream-shift "^1.0.0" 453 | 454 | ecc-jsbn@~0.1.1: 455 | version "0.1.1" 456 | resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" 457 | dependencies: 458 | jsbn "~0.1.0" 459 | 460 | end-of-stream@1.0.0: 461 | version "1.0.0" 462 | resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.0.0.tgz#d4596e702734a93e40e9af864319eabd99ff2f0e" 463 | dependencies: 464 | once "~1.3.0" 465 | 466 | es5-ext@^0.10.14, es5-ext@^0.10.9, es5-ext@~0.10.14: 467 | version "0.10.23" 468 | resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.23.tgz#7578b51be974207a5487821b56538c224e4e7b38" 469 | dependencies: 470 | es6-iterator "2" 471 | es6-symbol "~3.1" 472 | 473 | es6-iterator@2, es6-iterator@^2.0.1, es6-iterator@~2.0.1: 474 | version "2.0.1" 475 | resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.1.tgz#8e319c9f0453bf575d374940a655920e59ca5512" 476 | dependencies: 477 | d "1" 478 | es5-ext "^0.10.14" 479 | es6-symbol "^3.1" 480 | 481 | es6-map@^0.1.3: 482 | version "0.1.5" 483 | resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" 484 | dependencies: 485 | d "1" 486 | es5-ext "~0.10.14" 487 | es6-iterator "~2.0.1" 488 | es6-set "~0.1.5" 489 | es6-symbol "~3.1.1" 490 | event-emitter "~0.3.5" 491 | 492 | es6-promise@^3.0.2: 493 | version "3.3.1" 494 | resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.3.1.tgz#a08cdde84ccdbf34d027a1451bc91d4bcd28a613" 495 | 496 | es6-set@~0.1.5: 497 | version "0.1.5" 498 | resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" 499 | dependencies: 500 | d "1" 501 | es5-ext "~0.10.14" 502 | es6-iterator "~2.0.1" 503 | es6-symbol "3.1.1" 504 | event-emitter "~0.3.5" 505 | 506 | es6-symbol@3.1.1, es6-symbol@^3.1, es6-symbol@^3.1.1, es6-symbol@~3.1, es6-symbol@~3.1.1: 507 | version "3.1.1" 508 | resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" 509 | dependencies: 510 | d "1" 511 | es5-ext "~0.10.14" 512 | 513 | es6-weak-map@^2.0.1: 514 | version "2.0.2" 515 | resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f" 516 | dependencies: 517 | d "1" 518 | es5-ext "^0.10.14" 519 | es6-iterator "^2.0.1" 520 | es6-symbol "^3.1.1" 521 | 522 | escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: 523 | version "1.0.5" 524 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 525 | 526 | escope@^3.6.0: 527 | version "3.6.0" 528 | resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" 529 | dependencies: 530 | es6-map "^0.1.3" 531 | es6-weak-map "^2.0.1" 532 | esrecurse "^4.1.0" 533 | estraverse "^4.1.1" 534 | 535 | eslint-config-fullstack@^3.0.0: 536 | version "3.0.0" 537 | resolved "https://registry.yarnpkg.com/eslint-config-fullstack/-/eslint-config-fullstack-3.0.0.tgz#bbec44b3c825d9a444d4e942ea4e9a68acf115c3" 538 | 539 | eslint-formatter-pretty@^1.1.0: 540 | version "1.1.0" 541 | resolved "https://registry.yarnpkg.com/eslint-formatter-pretty/-/eslint-formatter-pretty-1.1.0.tgz#ab4d06da02fed8c13ae9f0dc540a433ef7ed6f5e" 542 | dependencies: 543 | ansi-escapes "^1.4.0" 544 | chalk "^1.1.3" 545 | log-symbols "^1.0.2" 546 | plur "^2.1.2" 547 | string-width "^2.0.0" 548 | 549 | eslint-plugin-react@^7.0.1: 550 | version "7.0.1" 551 | resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.0.1.tgz#e78107e1e559c6e2b17786bb67c2e2a010ad0d2f" 552 | dependencies: 553 | doctrine "^2.0.0" 554 | has "^1.0.1" 555 | jsx-ast-utils "^1.3.4" 556 | 557 | eslint-watch@^3.1.0: 558 | version "3.1.0" 559 | resolved "https://registry.yarnpkg.com/eslint-watch/-/eslint-watch-3.1.0.tgz#8a98006f7d7c583262f6fd78613f0ff406044930" 560 | dependencies: 561 | babel-polyfill "^6.20.0" 562 | bluebird "^3.4.7" 563 | chalk "^1.1.3" 564 | chokidar "^1.4.3" 565 | debug "^2.6.3" 566 | keypress "^0.2.1" 567 | lodash "^4.17.4" 568 | optionator "^0.8.2" 569 | source-map-support "^0.4.14" 570 | text-table "^0.2.0" 571 | unicons "0.0.3" 572 | 573 | eslint@^3.19.0: 574 | version "3.19.0" 575 | resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.19.0.tgz#c8fc6201c7f40dd08941b87c085767386a679acc" 576 | dependencies: 577 | babel-code-frame "^6.16.0" 578 | chalk "^1.1.3" 579 | concat-stream "^1.5.2" 580 | debug "^2.1.1" 581 | doctrine "^2.0.0" 582 | escope "^3.6.0" 583 | espree "^3.4.0" 584 | esquery "^1.0.0" 585 | estraverse "^4.2.0" 586 | esutils "^2.0.2" 587 | file-entry-cache "^2.0.0" 588 | glob "^7.0.3" 589 | globals "^9.14.0" 590 | ignore "^3.2.0" 591 | imurmurhash "^0.1.4" 592 | inquirer "^0.12.0" 593 | is-my-json-valid "^2.10.0" 594 | is-resolvable "^1.0.0" 595 | js-yaml "^3.5.1" 596 | json-stable-stringify "^1.0.0" 597 | levn "^0.3.0" 598 | lodash "^4.0.0" 599 | mkdirp "^0.5.0" 600 | natural-compare "^1.4.0" 601 | optionator "^0.8.2" 602 | path-is-inside "^1.0.1" 603 | pluralize "^1.2.1" 604 | progress "^1.1.8" 605 | require-uncached "^1.0.2" 606 | shelljs "^0.7.5" 607 | strip-bom "^3.0.0" 608 | strip-json-comments "~2.0.1" 609 | table "^3.7.8" 610 | text-table "~0.2.0" 611 | user-home "^2.0.0" 612 | 613 | espree@^3.4.0: 614 | version "3.4.3" 615 | resolved "https://registry.yarnpkg.com/espree/-/espree-3.4.3.tgz#2910b5ccd49ce893c2ffffaab4fd8b3a31b82374" 616 | dependencies: 617 | acorn "^5.0.1" 618 | acorn-jsx "^3.0.0" 619 | 620 | esprima@^3.1.1: 621 | version "3.1.3" 622 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" 623 | 624 | esquery@^1.0.0: 625 | version "1.0.0" 626 | resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.0.tgz#cfba8b57d7fba93f17298a8a006a04cda13d80fa" 627 | dependencies: 628 | estraverse "^4.0.0" 629 | 630 | esrecurse@^4.1.0: 631 | version "4.1.0" 632 | resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220" 633 | dependencies: 634 | estraverse "~4.1.0" 635 | object-assign "^4.0.1" 636 | 637 | estraverse@^4.0.0, estraverse@^4.1.1, estraverse@^4.2.0: 638 | version "4.2.0" 639 | resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" 640 | 641 | estraverse@~4.1.0: 642 | version "4.1.1" 643 | resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2" 644 | 645 | esutils@^2.0.2: 646 | version "2.0.2" 647 | resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" 648 | 649 | event-emitter@~0.3.5: 650 | version "0.3.5" 651 | resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" 652 | dependencies: 653 | d "1" 654 | es5-ext "~0.10.14" 655 | 656 | event-stream@~3.3.0: 657 | version "3.3.4" 658 | resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" 659 | dependencies: 660 | duplexer "~0.1.1" 661 | from "~0" 662 | map-stream "~0.1.0" 663 | pause-stream "0.0.11" 664 | split "0.3" 665 | stream-combiner "~0.0.4" 666 | through "~2.3.1" 667 | 668 | exit-hook@^1.0.0: 669 | version "1.1.1" 670 | resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" 671 | 672 | expand-brackets@^0.1.4: 673 | version "0.1.5" 674 | resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" 675 | dependencies: 676 | is-posix-bracket "^0.1.0" 677 | 678 | expand-range@^1.8.1: 679 | version "1.8.2" 680 | resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" 681 | dependencies: 682 | fill-range "^2.1.0" 683 | 684 | extend@~3.0.0: 685 | version "3.0.1" 686 | resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" 687 | 688 | extglob@^0.3.1: 689 | version "0.3.2" 690 | resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" 691 | dependencies: 692 | is-extglob "^1.0.0" 693 | 694 | extsprintf@1.0.2: 695 | version "1.0.2" 696 | resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" 697 | 698 | fast-levenshtein@~2.0.4: 699 | version "2.0.6" 700 | resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" 701 | 702 | figures@^1.3.5: 703 | version "1.7.0" 704 | resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" 705 | dependencies: 706 | escape-string-regexp "^1.0.5" 707 | object-assign "^4.1.0" 708 | 709 | file-entry-cache@^2.0.0: 710 | version "2.0.0" 711 | resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" 712 | dependencies: 713 | flat-cache "^1.2.1" 714 | object-assign "^4.0.1" 715 | 716 | filename-regex@^2.0.0: 717 | version "2.0.1" 718 | resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" 719 | 720 | fill-range@^2.1.0: 721 | version "2.2.3" 722 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" 723 | dependencies: 724 | is-number "^2.1.0" 725 | isobject "^2.0.0" 726 | randomatic "^1.1.3" 727 | repeat-element "^1.1.2" 728 | repeat-string "^1.5.2" 729 | 730 | find-parent-dir@^0.3.0: 731 | version "0.3.0" 732 | resolved "https://registry.yarnpkg.com/find-parent-dir/-/find-parent-dir-0.3.0.tgz#33c44b429ab2b2f0646299c5f9f718f376ff8d54" 733 | 734 | flat-cache@^1.2.1: 735 | version "1.2.2" 736 | resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.2.tgz#fa86714e72c21db88601761ecf2f555d1abc6b96" 737 | dependencies: 738 | circular-json "^0.3.1" 739 | del "^2.0.2" 740 | graceful-fs "^4.1.2" 741 | write "^0.2.1" 742 | 743 | for-in@^1.0.1: 744 | version "1.0.2" 745 | resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" 746 | 747 | for-own@^0.1.4: 748 | version "0.1.5" 749 | resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" 750 | dependencies: 751 | for-in "^1.0.1" 752 | 753 | forever-agent@~0.6.1: 754 | version "0.6.1" 755 | resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" 756 | 757 | form-data@~2.1.1: 758 | version "2.1.4" 759 | resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" 760 | dependencies: 761 | asynckit "^0.4.0" 762 | combined-stream "^1.0.5" 763 | mime-types "^2.1.12" 764 | 765 | from@~0: 766 | version "0.1.7" 767 | resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" 768 | 769 | "fs-extra@>= 0.6.0": 770 | version "4.0.1" 771 | resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.1.tgz#7fc0c6c8957f983f57f306a24e5b9ddd8d0dd880" 772 | dependencies: 773 | graceful-fs "^4.1.2" 774 | jsonfile "^3.0.0" 775 | universalify "^0.1.0" 776 | 777 | fs.realpath@^1.0.0: 778 | version "1.0.0" 779 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 780 | 781 | fsevents@^1.0.0: 782 | version "1.1.1" 783 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.1.tgz#f19fd28f43eeaf761680e519a203c4d0b3d31aff" 784 | dependencies: 785 | nan "^2.3.0" 786 | node-pre-gyp "^0.6.29" 787 | 788 | fstream-ignore@^1.0.5: 789 | version "1.0.5" 790 | resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" 791 | dependencies: 792 | fstream "^1.0.0" 793 | inherits "2" 794 | minimatch "^3.0.0" 795 | 796 | fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: 797 | version "1.0.11" 798 | resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" 799 | dependencies: 800 | graceful-fs "^4.1.2" 801 | inherits "~2.0.0" 802 | mkdirp ">=0.5 0" 803 | rimraf "2" 804 | 805 | function-bind@^1.0.2: 806 | version "1.1.0" 807 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771" 808 | 809 | gauge@~2.7.3: 810 | version "2.7.4" 811 | resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" 812 | dependencies: 813 | aproba "^1.0.3" 814 | console-control-strings "^1.0.0" 815 | has-unicode "^2.0.0" 816 | object-assign "^4.1.0" 817 | signal-exit "^3.0.0" 818 | string-width "^1.0.1" 819 | strip-ansi "^3.0.1" 820 | wide-align "^1.1.0" 821 | 822 | generate-function@^2.0.0: 823 | version "2.0.0" 824 | resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" 825 | 826 | generate-object-property@^1.1.0: 827 | version "1.2.0" 828 | resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" 829 | dependencies: 830 | is-property "^1.0.0" 831 | 832 | getpass@^0.1.1: 833 | version "0.1.7" 834 | resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" 835 | dependencies: 836 | assert-plus "^1.0.0" 837 | 838 | glob-base@^0.3.0: 839 | version "0.3.0" 840 | resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" 841 | dependencies: 842 | glob-parent "^2.0.0" 843 | is-glob "^2.0.0" 844 | 845 | glob-parent@^2.0.0: 846 | version "2.0.0" 847 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" 848 | dependencies: 849 | is-glob "^2.0.0" 850 | 851 | glob@^7.0.0, glob@^7.0.3, glob@^7.0.5: 852 | version "7.1.2" 853 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" 854 | dependencies: 855 | fs.realpath "^1.0.0" 856 | inflight "^1.0.4" 857 | inherits "2" 858 | minimatch "^3.0.4" 859 | once "^1.3.0" 860 | path-is-absolute "^1.0.0" 861 | 862 | globals@^9.0.0, globals@^9.14.0: 863 | version "9.18.0" 864 | resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" 865 | 866 | globby@^5.0.0: 867 | version "5.0.0" 868 | resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" 869 | dependencies: 870 | array-union "^1.0.1" 871 | arrify "^1.0.0" 872 | glob "^7.0.3" 873 | object-assign "^4.0.1" 874 | pify "^2.0.0" 875 | pinkie-promise "^2.0.0" 876 | 877 | got@^3.2.0: 878 | version "3.3.1" 879 | resolved "https://registry.yarnpkg.com/got/-/got-3.3.1.tgz#e5d0ed4af55fc3eef4d56007769d98192bcb2eca" 880 | dependencies: 881 | duplexify "^3.2.0" 882 | infinity-agent "^2.0.0" 883 | is-redirect "^1.0.0" 884 | is-stream "^1.0.0" 885 | lowercase-keys "^1.0.0" 886 | nested-error-stacks "^1.0.0" 887 | object-assign "^3.0.0" 888 | prepend-http "^1.0.0" 889 | read-all-stream "^3.0.0" 890 | timed-out "^2.0.0" 891 | 892 | graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6: 893 | version "4.1.11" 894 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" 895 | 896 | har-schema@^1.0.5: 897 | version "1.0.5" 898 | resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" 899 | 900 | har-validator@~4.2.1: 901 | version "4.2.1" 902 | resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" 903 | dependencies: 904 | ajv "^4.9.1" 905 | har-schema "^1.0.5" 906 | 907 | has-ansi@^2.0.0: 908 | version "2.0.0" 909 | resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" 910 | dependencies: 911 | ansi-regex "^2.0.0" 912 | 913 | has-flag@^2.0.0: 914 | version "2.0.0" 915 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" 916 | 917 | has-unicode@^2.0.0: 918 | version "2.0.1" 919 | resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" 920 | 921 | has@^1.0.1: 922 | version "1.0.1" 923 | resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" 924 | dependencies: 925 | function-bind "^1.0.2" 926 | 927 | hawk@~3.1.3: 928 | version "3.1.3" 929 | resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" 930 | dependencies: 931 | boom "2.x.x" 932 | cryptiles "2.x.x" 933 | hoek "2.x.x" 934 | sntp "1.x.x" 935 | 936 | "highlight.js@>= 8.0.x": 937 | version "9.12.0" 938 | resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.12.0.tgz#e6d9dbe57cbefe60751f02af336195870c90c01e" 939 | 940 | hoek@2.x.x: 941 | version "2.16.3" 942 | resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" 943 | 944 | http-signature@~1.1.0: 945 | version "1.1.1" 946 | resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" 947 | dependencies: 948 | assert-plus "^0.2.0" 949 | jsprim "^1.2.2" 950 | sshpk "^1.7.0" 951 | 952 | husky@^0.13.4: 953 | version "0.13.4" 954 | resolved "https://registry.yarnpkg.com/husky/-/husky-0.13.4.tgz#48785c5028de3452a51c48c12c4f94b2124a1407" 955 | dependencies: 956 | chalk "^1.1.3" 957 | find-parent-dir "^0.3.0" 958 | is-ci "^1.0.9" 959 | normalize-path "^1.0.0" 960 | 961 | ignore-by-default@^1.0.0: 962 | version "1.0.1" 963 | resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" 964 | 965 | ignore@^3.2.0: 966 | version "3.3.3" 967 | resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.3.tgz#432352e57accd87ab3110e82d3fea0e47812156d" 968 | 969 | imurmurhash@^0.1.4: 970 | version "0.1.4" 971 | resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" 972 | 973 | infinity-agent@^2.0.0: 974 | version "2.0.3" 975 | resolved "https://registry.yarnpkg.com/infinity-agent/-/infinity-agent-2.0.3.tgz#45e0e2ff7a9eb030b27d62b74b3744b7a7ac4216" 976 | 977 | inflight@^1.0.4: 978 | version "1.0.6" 979 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 980 | dependencies: 981 | once "^1.3.0" 982 | wrappy "1" 983 | 984 | inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1: 985 | version "2.0.3" 986 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 987 | 988 | ini@~1.3.0: 989 | version "1.3.4" 990 | resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" 991 | 992 | inquirer@^0.12.0: 993 | version "0.12.0" 994 | resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" 995 | dependencies: 996 | ansi-escapes "^1.1.0" 997 | ansi-regex "^2.0.0" 998 | chalk "^1.0.0" 999 | cli-cursor "^1.0.1" 1000 | cli-width "^2.0.0" 1001 | figures "^1.3.5" 1002 | lodash "^4.3.0" 1003 | readline2 "^1.0.1" 1004 | run-async "^0.1.0" 1005 | rx-lite "^3.1.2" 1006 | string-width "^1.0.1" 1007 | strip-ansi "^3.0.0" 1008 | through "^2.3.6" 1009 | 1010 | interpret@^1.0.0: 1011 | version "1.0.3" 1012 | resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.3.tgz#cbc35c62eeee73f19ab7b10a801511401afc0f90" 1013 | 1014 | invariant@^2.2.0: 1015 | version "2.2.2" 1016 | resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" 1017 | dependencies: 1018 | loose-envify "^1.0.0" 1019 | 1020 | irregular-plurals@^1.0.0: 1021 | version "1.2.0" 1022 | resolved "https://registry.yarnpkg.com/irregular-plurals/-/irregular-plurals-1.2.0.tgz#38f299834ba8c00c30be9c554e137269752ff3ac" 1023 | 1024 | is-binary-path@^1.0.0: 1025 | version "1.0.1" 1026 | resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" 1027 | dependencies: 1028 | binary-extensions "^1.0.0" 1029 | 1030 | is-buffer@^1.1.5: 1031 | version "1.1.5" 1032 | resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc" 1033 | 1034 | is-ci@^1.0.9: 1035 | version "1.0.10" 1036 | resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.0.10.tgz#f739336b2632365061a9d48270cd56ae3369318e" 1037 | dependencies: 1038 | ci-info "^1.0.0" 1039 | 1040 | is-dotfile@^1.0.0: 1041 | version "1.0.3" 1042 | resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" 1043 | 1044 | is-equal-shallow@^0.1.3: 1045 | version "0.1.3" 1046 | resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" 1047 | dependencies: 1048 | is-primitive "^2.0.0" 1049 | 1050 | is-extendable@^0.1.1: 1051 | version "0.1.1" 1052 | resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" 1053 | 1054 | is-extglob@^1.0.0: 1055 | version "1.0.0" 1056 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" 1057 | 1058 | is-finite@^1.0.0: 1059 | version "1.0.2" 1060 | resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" 1061 | dependencies: 1062 | number-is-nan "^1.0.0" 1063 | 1064 | is-fullwidth-code-point@^1.0.0: 1065 | version "1.0.0" 1066 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" 1067 | dependencies: 1068 | number-is-nan "^1.0.0" 1069 | 1070 | is-fullwidth-code-point@^2.0.0: 1071 | version "2.0.0" 1072 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" 1073 | 1074 | is-glob@^2.0.0, is-glob@^2.0.1: 1075 | version "2.0.1" 1076 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" 1077 | dependencies: 1078 | is-extglob "^1.0.0" 1079 | 1080 | is-my-json-valid@^2.10.0: 1081 | version "2.16.0" 1082 | resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz#f079dd9bfdae65ee2038aae8acbc86ab109e3693" 1083 | dependencies: 1084 | generate-function "^2.0.0" 1085 | generate-object-property "^1.1.0" 1086 | jsonpointer "^4.0.0" 1087 | xtend "^4.0.0" 1088 | 1089 | is-npm@^1.0.0: 1090 | version "1.0.0" 1091 | resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4" 1092 | 1093 | is-number@^2.0.2, is-number@^2.1.0: 1094 | version "2.1.0" 1095 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" 1096 | dependencies: 1097 | kind-of "^3.0.2" 1098 | 1099 | is-path-cwd@^1.0.0: 1100 | version "1.0.0" 1101 | resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" 1102 | 1103 | is-path-in-cwd@^1.0.0: 1104 | version "1.0.0" 1105 | resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" 1106 | dependencies: 1107 | is-path-inside "^1.0.0" 1108 | 1109 | is-path-inside@^1.0.0: 1110 | version "1.0.0" 1111 | resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" 1112 | dependencies: 1113 | path-is-inside "^1.0.1" 1114 | 1115 | is-posix-bracket@^0.1.0: 1116 | version "0.1.1" 1117 | resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" 1118 | 1119 | is-primitive@^2.0.0: 1120 | version "2.0.0" 1121 | resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" 1122 | 1123 | is-property@^1.0.0: 1124 | version "1.0.2" 1125 | resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" 1126 | 1127 | is-redirect@^1.0.0: 1128 | version "1.0.0" 1129 | resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" 1130 | 1131 | is-resolvable@^1.0.0: 1132 | version "1.0.0" 1133 | resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" 1134 | dependencies: 1135 | tryit "^1.0.1" 1136 | 1137 | is-stream@^1.0.0: 1138 | version "1.1.0" 1139 | resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" 1140 | 1141 | is-typedarray@~1.0.0: 1142 | version "1.0.0" 1143 | resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" 1144 | 1145 | isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: 1146 | version "1.0.0" 1147 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 1148 | 1149 | isobject@^2.0.0: 1150 | version "2.1.0" 1151 | resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" 1152 | dependencies: 1153 | isarray "1.0.0" 1154 | 1155 | isstream@~0.1.2: 1156 | version "0.1.2" 1157 | resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" 1158 | 1159 | js-tokens@^3.0.0: 1160 | version "3.0.1" 1161 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7" 1162 | 1163 | js-yaml@^3.5.1: 1164 | version "3.8.4" 1165 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.4.tgz#520b4564f86573ba96662af85a8cafa7b4b5a6f6" 1166 | dependencies: 1167 | argparse "^1.0.7" 1168 | esprima "^3.1.1" 1169 | 1170 | jsbn@~0.1.0: 1171 | version "0.1.1" 1172 | resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" 1173 | 1174 | json-schema@0.2.3: 1175 | version "0.2.3" 1176 | resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" 1177 | 1178 | json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: 1179 | version "1.0.1" 1180 | resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" 1181 | dependencies: 1182 | jsonify "~0.0.0" 1183 | 1184 | json-stringify-safe@~5.0.1: 1185 | version "5.0.1" 1186 | resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" 1187 | 1188 | jsonfile@^3.0.0: 1189 | version "3.0.1" 1190 | resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-3.0.1.tgz#a5ecc6f65f53f662c4415c7675a0331d0992ec66" 1191 | optionalDependencies: 1192 | graceful-fs "^4.1.6" 1193 | 1194 | jsonify@~0.0.0: 1195 | version "0.0.0" 1196 | resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" 1197 | 1198 | jsonpointer@^4.0.0: 1199 | version "4.0.1" 1200 | resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" 1201 | 1202 | jsprim@^1.2.2: 1203 | version "1.4.0" 1204 | resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.0.tgz#a3b87e40298d8c380552d8cc7628a0bb95a22918" 1205 | dependencies: 1206 | assert-plus "1.0.0" 1207 | extsprintf "1.0.2" 1208 | json-schema "0.2.3" 1209 | verror "1.3.6" 1210 | 1211 | jsx-ast-utils@^1.3.4: 1212 | version "1.4.1" 1213 | resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz#3867213e8dd79bf1e8f2300c0cfc1efb182c0df1" 1214 | 1215 | keypress@^0.2.1: 1216 | version "0.2.1" 1217 | resolved "https://registry.yarnpkg.com/keypress/-/keypress-0.2.1.tgz#1e80454250018dbad4c3fe94497d6e67b6269c77" 1218 | 1219 | kind-of@^3.0.2: 1220 | version "3.2.2" 1221 | resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" 1222 | dependencies: 1223 | is-buffer "^1.1.5" 1224 | 1225 | latest-version@^1.0.0: 1226 | version "1.0.1" 1227 | resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-1.0.1.tgz#72cfc46e3e8d1be651e1ebb54ea9f6ea96f374bb" 1228 | dependencies: 1229 | package-json "^1.0.0" 1230 | 1231 | levn@^0.3.0, levn@~0.3.0: 1232 | version "0.3.0" 1233 | resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" 1234 | dependencies: 1235 | prelude-ls "~1.1.2" 1236 | type-check "~0.3.2" 1237 | 1238 | lodash._baseassign@^3.0.0: 1239 | version "3.2.0" 1240 | resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" 1241 | dependencies: 1242 | lodash._basecopy "^3.0.0" 1243 | lodash.keys "^3.0.0" 1244 | 1245 | lodash._basecopy@^3.0.0: 1246 | version "3.0.1" 1247 | resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" 1248 | 1249 | lodash._bindcallback@^3.0.0: 1250 | version "3.0.1" 1251 | resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" 1252 | 1253 | lodash._createassigner@^3.0.0: 1254 | version "3.1.1" 1255 | resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" 1256 | dependencies: 1257 | lodash._bindcallback "^3.0.0" 1258 | lodash._isiterateecall "^3.0.0" 1259 | lodash.restparam "^3.0.0" 1260 | 1261 | lodash._getnative@^3.0.0: 1262 | version "3.9.1" 1263 | resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" 1264 | 1265 | lodash._isiterateecall@^3.0.0: 1266 | version "3.0.9" 1267 | resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" 1268 | 1269 | lodash.assign@^3.0.0: 1270 | version "3.2.0" 1271 | resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" 1272 | dependencies: 1273 | lodash._baseassign "^3.0.0" 1274 | lodash._createassigner "^3.0.0" 1275 | lodash.keys "^3.0.0" 1276 | 1277 | lodash.defaults@^3.1.2: 1278 | version "3.1.2" 1279 | resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-3.1.2.tgz#c7308b18dbf8bc9372d701a73493c61192bd2e2c" 1280 | dependencies: 1281 | lodash.assign "^3.0.0" 1282 | lodash.restparam "^3.0.0" 1283 | 1284 | lodash.isarguments@^3.0.0: 1285 | version "3.1.0" 1286 | resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" 1287 | 1288 | lodash.isarray@^3.0.0: 1289 | version "3.0.4" 1290 | resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" 1291 | 1292 | lodash.keys@^3.0.0: 1293 | version "3.1.2" 1294 | resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" 1295 | dependencies: 1296 | lodash._getnative "^3.0.0" 1297 | lodash.isarguments "^3.0.0" 1298 | lodash.isarray "^3.0.0" 1299 | 1300 | lodash.restparam@^3.0.0: 1301 | version "3.6.1" 1302 | resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" 1303 | 1304 | lodash@^4.0.0, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0: 1305 | version "4.17.4" 1306 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" 1307 | 1308 | log-symbols@^1.0.2: 1309 | version "1.0.2" 1310 | resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18" 1311 | dependencies: 1312 | chalk "^1.0.0" 1313 | 1314 | loose-envify@^1.0.0: 1315 | version "1.3.1" 1316 | resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" 1317 | dependencies: 1318 | js-tokens "^3.0.0" 1319 | 1320 | lowercase-keys@^1.0.0: 1321 | version "1.0.0" 1322 | resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" 1323 | 1324 | map-stream@~0.1.0: 1325 | version "0.1.0" 1326 | resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194" 1327 | 1328 | "marked@>= 0.2.7": 1329 | version "0.3.6" 1330 | resolved "https://registry.yarnpkg.com/marked/-/marked-0.3.6.tgz#b2c6c618fccece4ef86c4fc6cb8a7cbf5aeda8d7" 1331 | 1332 | micromatch@^2.1.5: 1333 | version "2.3.11" 1334 | resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" 1335 | dependencies: 1336 | arr-diff "^2.0.0" 1337 | array-unique "^0.2.1" 1338 | braces "^1.8.2" 1339 | expand-brackets "^0.1.4" 1340 | extglob "^0.3.1" 1341 | filename-regex "^2.0.0" 1342 | is-extglob "^1.0.0" 1343 | is-glob "^2.0.1" 1344 | kind-of "^3.0.2" 1345 | normalize-path "^2.0.1" 1346 | object.omit "^2.0.0" 1347 | parse-glob "^3.0.4" 1348 | regex-cache "^0.4.2" 1349 | 1350 | mime-db@~1.27.0: 1351 | version "1.27.0" 1352 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1" 1353 | 1354 | mime-types@^2.1.12, mime-types@~2.1.7: 1355 | version "2.1.15" 1356 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed" 1357 | dependencies: 1358 | mime-db "~1.27.0" 1359 | 1360 | minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4: 1361 | version "3.0.4" 1362 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 1363 | dependencies: 1364 | brace-expansion "^1.1.7" 1365 | 1366 | minimist@0.0.8: 1367 | version "0.0.8" 1368 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 1369 | 1370 | minimist@^1.2.0: 1371 | version "1.2.0" 1372 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" 1373 | 1374 | "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1: 1375 | version "0.5.1" 1376 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 1377 | dependencies: 1378 | minimist "0.0.8" 1379 | 1380 | ms@2.0.0: 1381 | version "2.0.0" 1382 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 1383 | 1384 | mute-stream@0.0.5: 1385 | version "0.0.5" 1386 | resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" 1387 | 1388 | nan@^2.3.0: 1389 | version "2.6.2" 1390 | resolved "https://registry.yarnpkg.com/nan/-/nan-2.6.2.tgz#e4ff34e6c95fdfb5aecc08de6596f43605a7db45" 1391 | 1392 | natural-compare@^1.4.0: 1393 | version "1.4.0" 1394 | resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" 1395 | 1396 | nested-error-stacks@^1.0.0: 1397 | version "1.0.2" 1398 | resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-1.0.2.tgz#19f619591519f096769a5ba9a86e6eeec823c3cf" 1399 | dependencies: 1400 | inherits "~2.0.1" 1401 | 1402 | node-pre-gyp@^0.6.29: 1403 | version "0.6.36" 1404 | resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.36.tgz#db604112cb74e0d477554e9b505b17abddfab786" 1405 | dependencies: 1406 | mkdirp "^0.5.1" 1407 | nopt "^4.0.1" 1408 | npmlog "^4.0.2" 1409 | rc "^1.1.7" 1410 | request "^2.81.0" 1411 | rimraf "^2.6.1" 1412 | semver "^5.3.0" 1413 | tar "^2.2.1" 1414 | tar-pack "^3.4.0" 1415 | 1416 | nodemon@^1.11.0: 1417 | version "1.11.0" 1418 | resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.11.0.tgz#226c562bd2a7b13d3d7518b49ad4828a3623d06c" 1419 | dependencies: 1420 | chokidar "^1.4.3" 1421 | debug "^2.2.0" 1422 | es6-promise "^3.0.2" 1423 | ignore-by-default "^1.0.0" 1424 | lodash.defaults "^3.1.2" 1425 | minimatch "^3.0.0" 1426 | ps-tree "^1.0.1" 1427 | touch "1.0.0" 1428 | undefsafe "0.0.3" 1429 | update-notifier "0.5.0" 1430 | 1431 | nopt@^4.0.1: 1432 | version "4.0.1" 1433 | resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" 1434 | dependencies: 1435 | abbrev "1" 1436 | osenv "^0.1.4" 1437 | 1438 | nopt@~1.0.10: 1439 | version "1.0.10" 1440 | resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" 1441 | dependencies: 1442 | abbrev "1" 1443 | 1444 | normalize-path@^1.0.0: 1445 | version "1.0.0" 1446 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-1.0.0.tgz#32d0e472f91ff345701c15a8311018d3b0a90379" 1447 | 1448 | normalize-path@^2.0.1: 1449 | version "2.1.1" 1450 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" 1451 | dependencies: 1452 | remove-trailing-separator "^1.0.1" 1453 | 1454 | npmlog@^4.0.2: 1455 | version "4.1.0" 1456 | resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.0.tgz#dc59bee85f64f00ed424efb2af0783df25d1c0b5" 1457 | dependencies: 1458 | are-we-there-yet "~1.1.2" 1459 | console-control-strings "~1.1.0" 1460 | gauge "~2.7.3" 1461 | set-blocking "~2.0.0" 1462 | 1463 | number-is-nan@^1.0.0: 1464 | version "1.0.1" 1465 | resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" 1466 | 1467 | oauth-sign@~0.8.1: 1468 | version "0.8.2" 1469 | resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" 1470 | 1471 | object-assign@^3.0.0: 1472 | version "3.0.0" 1473 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2" 1474 | 1475 | object-assign@^4.0.1, object-assign@^4.1.0: 1476 | version "4.1.1" 1477 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 1478 | 1479 | object.omit@^2.0.0: 1480 | version "2.0.1" 1481 | resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" 1482 | dependencies: 1483 | for-own "^0.1.4" 1484 | is-extendable "^0.1.1" 1485 | 1486 | once@^1.3.0, once@^1.3.3: 1487 | version "1.4.0" 1488 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 1489 | dependencies: 1490 | wrappy "1" 1491 | 1492 | once@~1.3.0: 1493 | version "1.3.3" 1494 | resolved "https://registry.yarnpkg.com/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20" 1495 | dependencies: 1496 | wrappy "1" 1497 | 1498 | onetime@^1.0.0: 1499 | version "1.1.0" 1500 | resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" 1501 | 1502 | optionator@^0.8.2: 1503 | version "0.8.2" 1504 | resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" 1505 | dependencies: 1506 | deep-is "~0.1.3" 1507 | fast-levenshtein "~2.0.4" 1508 | levn "~0.3.0" 1509 | prelude-ls "~1.1.2" 1510 | type-check "~0.3.2" 1511 | wordwrap "~1.0.0" 1512 | 1513 | os-homedir@^1.0.0: 1514 | version "1.0.2" 1515 | resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" 1516 | 1517 | os-tmpdir@^1.0.0: 1518 | version "1.0.2" 1519 | resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" 1520 | 1521 | osenv@^0.1.0, osenv@^0.1.4: 1522 | version "0.1.4" 1523 | resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" 1524 | dependencies: 1525 | os-homedir "^1.0.0" 1526 | os-tmpdir "^1.0.0" 1527 | 1528 | package-json@^1.0.0: 1529 | version "1.2.0" 1530 | resolved "https://registry.yarnpkg.com/package-json/-/package-json-1.2.0.tgz#c8ecac094227cdf76a316874ed05e27cc939a0e0" 1531 | dependencies: 1532 | got "^3.2.0" 1533 | registry-url "^3.0.0" 1534 | 1535 | parse-glob@^3.0.4: 1536 | version "3.0.4" 1537 | resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" 1538 | dependencies: 1539 | glob-base "^0.3.0" 1540 | is-dotfile "^1.0.0" 1541 | is-extglob "^1.0.0" 1542 | is-glob "^2.0.0" 1543 | 1544 | path-is-absolute@^1.0.0: 1545 | version "1.0.1" 1546 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 1547 | 1548 | path-is-inside@^1.0.1: 1549 | version "1.0.2" 1550 | resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" 1551 | 1552 | path-parse@^1.0.5: 1553 | version "1.0.5" 1554 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" 1555 | 1556 | pause-stream@0.0.11: 1557 | version "0.0.11" 1558 | resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" 1559 | dependencies: 1560 | through "~2.3" 1561 | 1562 | performance-now@^0.2.0: 1563 | version "0.2.0" 1564 | resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" 1565 | 1566 | pify@^2.0.0: 1567 | version "2.3.0" 1568 | resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" 1569 | 1570 | pinkie-promise@^2.0.0: 1571 | version "2.0.1" 1572 | resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" 1573 | dependencies: 1574 | pinkie "^2.0.0" 1575 | 1576 | pinkie@^2.0.0: 1577 | version "2.0.4" 1578 | resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" 1579 | 1580 | plur@^2.1.2: 1581 | version "2.1.2" 1582 | resolved "https://registry.yarnpkg.com/plur/-/plur-2.1.2.tgz#7482452c1a0f508e3e344eaec312c91c29dc655a" 1583 | dependencies: 1584 | irregular-plurals "^1.0.0" 1585 | 1586 | pluralize@^1.2.1: 1587 | version "1.2.1" 1588 | resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" 1589 | 1590 | prelude-ls@~1.1.2: 1591 | version "1.1.2" 1592 | resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" 1593 | 1594 | prepend-http@^1.0.0: 1595 | version "1.0.4" 1596 | resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" 1597 | 1598 | preserve@^0.2.0: 1599 | version "0.2.0" 1600 | resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" 1601 | 1602 | process-nextick-args@~1.0.6: 1603 | version "1.0.7" 1604 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" 1605 | 1606 | progress@^1.1.8: 1607 | version "1.1.8" 1608 | resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" 1609 | 1610 | ps-tree@^1.0.1: 1611 | version "1.1.0" 1612 | resolved "https://registry.yarnpkg.com/ps-tree/-/ps-tree-1.1.0.tgz#b421b24140d6203f1ed3c76996b4427b08e8c014" 1613 | dependencies: 1614 | event-stream "~3.3.0" 1615 | 1616 | punycode@^1.4.1: 1617 | version "1.4.1" 1618 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" 1619 | 1620 | qs@~6.4.0: 1621 | version "6.4.0" 1622 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" 1623 | 1624 | randomatic@^1.1.3: 1625 | version "1.1.6" 1626 | resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb" 1627 | dependencies: 1628 | is-number "^2.0.2" 1629 | kind-of "^3.0.2" 1630 | 1631 | rc@^1.0.1, rc@^1.1.7: 1632 | version "1.2.1" 1633 | resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.1.tgz#2e03e8e42ee450b8cb3dce65be1bf8974e1dfd95" 1634 | dependencies: 1635 | deep-extend "~0.4.0" 1636 | ini "~1.3.0" 1637 | minimist "^1.2.0" 1638 | strip-json-comments "~2.0.1" 1639 | 1640 | read-all-stream@^3.0.0: 1641 | version "3.1.0" 1642 | resolved "https://registry.yarnpkg.com/read-all-stream/-/read-all-stream-3.1.0.tgz#35c3e177f2078ef789ee4bfafa4373074eaef4fa" 1643 | dependencies: 1644 | pinkie-promise "^2.0.0" 1645 | readable-stream "^2.0.0" 1646 | 1647 | readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.2.2: 1648 | version "2.2.11" 1649 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.11.tgz#0796b31f8d7688007ff0b93a8088d34aa17c0f72" 1650 | dependencies: 1651 | core-util-is "~1.0.0" 1652 | inherits "~2.0.1" 1653 | isarray "~1.0.0" 1654 | process-nextick-args "~1.0.6" 1655 | safe-buffer "~5.0.1" 1656 | string_decoder "~1.0.0" 1657 | util-deprecate "~1.0.1" 1658 | 1659 | readdirp@^2.0.0: 1660 | version "2.1.0" 1661 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" 1662 | dependencies: 1663 | graceful-fs "^4.1.2" 1664 | minimatch "^3.0.2" 1665 | readable-stream "^2.0.2" 1666 | set-immediate-shim "^1.0.1" 1667 | 1668 | readline2@^1.0.1: 1669 | version "1.0.1" 1670 | resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" 1671 | dependencies: 1672 | code-point-at "^1.0.0" 1673 | is-fullwidth-code-point "^1.0.0" 1674 | mute-stream "0.0.5" 1675 | 1676 | rechoir@^0.6.2: 1677 | version "0.6.2" 1678 | resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" 1679 | dependencies: 1680 | resolve "^1.1.6" 1681 | 1682 | regenerator-runtime@^0.10.0: 1683 | version "0.10.5" 1684 | resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" 1685 | 1686 | regex-cache@^0.4.2: 1687 | version "0.4.3" 1688 | resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" 1689 | dependencies: 1690 | is-equal-shallow "^0.1.3" 1691 | is-primitive "^2.0.0" 1692 | 1693 | registry-url@^3.0.0: 1694 | version "3.1.0" 1695 | resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" 1696 | dependencies: 1697 | rc "^1.0.1" 1698 | 1699 | remove-trailing-separator@^1.0.1: 1700 | version "1.0.2" 1701 | resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.0.2.tgz#69b062d978727ad14dc6b56ba4ab772fd8d70511" 1702 | 1703 | repeat-element@^1.1.2: 1704 | version "1.1.2" 1705 | resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" 1706 | 1707 | repeat-string@^1.5.2: 1708 | version "1.6.1" 1709 | resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" 1710 | 1711 | repeating@^1.1.2: 1712 | version "1.1.3" 1713 | resolved "https://registry.yarnpkg.com/repeating/-/repeating-1.1.3.tgz#3d4114218877537494f97f77f9785fab810fa4ac" 1714 | dependencies: 1715 | is-finite "^1.0.0" 1716 | 1717 | request@^2.81.0: 1718 | version "2.81.0" 1719 | resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" 1720 | dependencies: 1721 | aws-sign2 "~0.6.0" 1722 | aws4 "^1.2.1" 1723 | caseless "~0.12.0" 1724 | combined-stream "~1.0.5" 1725 | extend "~3.0.0" 1726 | forever-agent "~0.6.1" 1727 | form-data "~2.1.1" 1728 | har-validator "~4.2.1" 1729 | hawk "~3.1.3" 1730 | http-signature "~1.1.0" 1731 | is-typedarray "~1.0.0" 1732 | isstream "~0.1.2" 1733 | json-stringify-safe "~5.0.1" 1734 | mime-types "~2.1.7" 1735 | oauth-sign "~0.8.1" 1736 | performance-now "^0.2.0" 1737 | qs "~6.4.0" 1738 | safe-buffer "^5.0.1" 1739 | stringstream "~0.0.4" 1740 | tough-cookie "~2.3.0" 1741 | tunnel-agent "^0.6.0" 1742 | uuid "^3.0.0" 1743 | 1744 | require-uncached@^1.0.2: 1745 | version "1.0.3" 1746 | resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" 1747 | dependencies: 1748 | caller-path "^0.1.0" 1749 | resolve-from "^1.0.0" 1750 | 1751 | resolve-from@^1.0.0: 1752 | version "1.0.1" 1753 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" 1754 | 1755 | resolve@^1.1.6: 1756 | version "1.3.3" 1757 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.3.3.tgz#655907c3469a8680dc2de3a275a8fdd69691f0e5" 1758 | dependencies: 1759 | path-parse "^1.0.5" 1760 | 1761 | restore-cursor@^1.0.1: 1762 | version "1.0.1" 1763 | resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" 1764 | dependencies: 1765 | exit-hook "^1.0.0" 1766 | onetime "^1.0.0" 1767 | 1768 | rimraf@2, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.6.1: 1769 | version "2.6.1" 1770 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" 1771 | dependencies: 1772 | glob "^7.0.5" 1773 | 1774 | run-async@^0.1.0: 1775 | version "0.1.0" 1776 | resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" 1777 | dependencies: 1778 | once "^1.3.0" 1779 | 1780 | rx-lite@^3.1.2: 1781 | version "3.1.2" 1782 | resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" 1783 | 1784 | safe-buffer@^5.0.1, safe-buffer@~5.0.1: 1785 | version "5.0.1" 1786 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7" 1787 | 1788 | semver-diff@^2.0.0: 1789 | version "2.1.0" 1790 | resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" 1791 | dependencies: 1792 | semver "^5.0.3" 1793 | 1794 | semver@^5.0.3, semver@^5.3.0: 1795 | version "5.3.0" 1796 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" 1797 | 1798 | set-blocking@~2.0.0: 1799 | version "2.0.0" 1800 | resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" 1801 | 1802 | set-immediate-shim@^1.0.1: 1803 | version "1.0.1" 1804 | resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" 1805 | 1806 | shelljs@^0.7.5: 1807 | version "0.7.8" 1808 | resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.8.tgz#decbcf874b0d1e5fb72e14b164a9683048e9acb3" 1809 | dependencies: 1810 | glob "^7.0.0" 1811 | interpret "^1.0.0" 1812 | rechoir "^0.6.2" 1813 | 1814 | signal-exit@^3.0.0: 1815 | version "3.0.2" 1816 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" 1817 | 1818 | slice-ansi@0.0.4: 1819 | version "0.0.4" 1820 | resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" 1821 | 1822 | slide@^1.1.5: 1823 | version "1.1.6" 1824 | resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" 1825 | 1826 | sntp@1.x.x: 1827 | version "1.0.9" 1828 | resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" 1829 | dependencies: 1830 | hoek "2.x.x" 1831 | 1832 | source-map-support@^0.4.14: 1833 | version "0.4.15" 1834 | resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.15.tgz#03202df65c06d2bd8c7ec2362a193056fef8d3b1" 1835 | dependencies: 1836 | source-map "^0.5.6" 1837 | 1838 | source-map@^0.5.6: 1839 | version "0.5.6" 1840 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" 1841 | 1842 | split@0.3: 1843 | version "0.3.3" 1844 | resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f" 1845 | dependencies: 1846 | through "2" 1847 | 1848 | sprintf-js@~1.0.2: 1849 | version "1.0.3" 1850 | resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" 1851 | 1852 | sshpk@^1.7.0: 1853 | version "1.13.1" 1854 | resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3" 1855 | dependencies: 1856 | asn1 "~0.2.3" 1857 | assert-plus "^1.0.0" 1858 | dashdash "^1.12.0" 1859 | getpass "^0.1.1" 1860 | optionalDependencies: 1861 | bcrypt-pbkdf "^1.0.0" 1862 | ecc-jsbn "~0.1.1" 1863 | jsbn "~0.1.0" 1864 | tweetnacl "~0.14.0" 1865 | 1866 | stream-combiner@~0.0.4: 1867 | version "0.0.4" 1868 | resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14" 1869 | dependencies: 1870 | duplexer "~0.1.1" 1871 | 1872 | stream-shift@^1.0.0: 1873 | version "1.0.0" 1874 | resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" 1875 | 1876 | string-length@^1.0.0: 1877 | version "1.0.1" 1878 | resolved "https://registry.yarnpkg.com/string-length/-/string-length-1.0.1.tgz#56970fb1c38558e9e70b728bf3de269ac45adfac" 1879 | dependencies: 1880 | strip-ansi "^3.0.0" 1881 | 1882 | string-width@^1.0.1, string-width@^1.0.2: 1883 | version "1.0.2" 1884 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" 1885 | dependencies: 1886 | code-point-at "^1.0.0" 1887 | is-fullwidth-code-point "^1.0.0" 1888 | strip-ansi "^3.0.0" 1889 | 1890 | string-width@^2.0.0: 1891 | version "2.0.0" 1892 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.0.0.tgz#635c5436cc72a6e0c387ceca278d4e2eec52687e" 1893 | dependencies: 1894 | is-fullwidth-code-point "^2.0.0" 1895 | strip-ansi "^3.0.0" 1896 | 1897 | string_decoder@~1.0.0: 1898 | version "1.0.2" 1899 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.2.tgz#b29e1f4e1125fa97a10382b8a533737b7491e179" 1900 | dependencies: 1901 | safe-buffer "~5.0.1" 1902 | 1903 | stringstream@~0.0.4: 1904 | version "0.0.5" 1905 | resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" 1906 | 1907 | strip-ansi@^3.0.0, strip-ansi@^3.0.1: 1908 | version "3.0.1" 1909 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" 1910 | dependencies: 1911 | ansi-regex "^2.0.0" 1912 | 1913 | strip-bom@^3.0.0: 1914 | version "3.0.0" 1915 | resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" 1916 | 1917 | strip-json-comments@~2.0.1: 1918 | version "2.0.1" 1919 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" 1920 | 1921 | supports-color@^2.0.0: 1922 | version "2.0.0" 1923 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" 1924 | 1925 | supports-color@^4.0.0: 1926 | version "4.2.1" 1927 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.2.1.tgz#65a4bb2631e90e02420dba5554c375a4754bb836" 1928 | dependencies: 1929 | has-flag "^2.0.0" 1930 | 1931 | table@^3.7.8: 1932 | version "3.8.3" 1933 | resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" 1934 | dependencies: 1935 | ajv "^4.7.0" 1936 | ajv-keywords "^1.0.0" 1937 | chalk "^1.1.1" 1938 | lodash "^4.0.0" 1939 | slice-ansi "0.0.4" 1940 | string-width "^2.0.0" 1941 | 1942 | tar-pack@^3.4.0: 1943 | version "3.4.0" 1944 | resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.0.tgz#23be2d7f671a8339376cbdb0b8fe3fdebf317984" 1945 | dependencies: 1946 | debug "^2.2.0" 1947 | fstream "^1.0.10" 1948 | fstream-ignore "^1.0.5" 1949 | once "^1.3.3" 1950 | readable-stream "^2.1.4" 1951 | rimraf "^2.5.1" 1952 | tar "^2.2.1" 1953 | uid-number "^0.0.6" 1954 | 1955 | tar@^2.2.1: 1956 | version "2.2.1" 1957 | resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" 1958 | dependencies: 1959 | block-stream "*" 1960 | fstream "^1.0.2" 1961 | inherits "2" 1962 | 1963 | text-table@^0.2.0, text-table@~0.2.0: 1964 | version "0.2.0" 1965 | resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" 1966 | 1967 | through@2, through@^2.3.6, through@~2.3, through@~2.3.1: 1968 | version "2.3.8" 1969 | resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" 1970 | 1971 | timed-out@^2.0.0: 1972 | version "2.0.0" 1973 | resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-2.0.0.tgz#f38b0ae81d3747d628001f41dafc652ace671c0a" 1974 | 1975 | to-fast-properties@^1.0.1: 1976 | version "1.0.3" 1977 | resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" 1978 | 1979 | touch@1.0.0: 1980 | version "1.0.0" 1981 | resolved "https://registry.yarnpkg.com/touch/-/touch-1.0.0.tgz#449cbe2dbae5a8c8038e30d71fa0ff464947c4de" 1982 | dependencies: 1983 | nopt "~1.0.10" 1984 | 1985 | tough-cookie@~2.3.0: 1986 | version "2.3.2" 1987 | resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" 1988 | dependencies: 1989 | punycode "^1.4.1" 1990 | 1991 | tryit@^1.0.1: 1992 | version "1.0.3" 1993 | resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" 1994 | 1995 | tunnel-agent@^0.6.0: 1996 | version "0.6.0" 1997 | resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" 1998 | dependencies: 1999 | safe-buffer "^5.0.1" 2000 | 2001 | tweetnacl@^0.14.3, tweetnacl@~0.14.0: 2002 | version "0.14.5" 2003 | resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" 2004 | 2005 | type-check@~0.3.2: 2006 | version "0.3.2" 2007 | resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" 2008 | dependencies: 2009 | prelude-ls "~1.1.2" 2010 | 2011 | typedarray@^0.0.6: 2012 | version "0.0.6" 2013 | resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" 2014 | 2015 | uid-number@^0.0.6: 2016 | version "0.0.6" 2017 | resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" 2018 | 2019 | undefsafe@0.0.3: 2020 | version "0.0.3" 2021 | resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-0.0.3.tgz#ecca3a03e56b9af17385baac812ac83b994a962f" 2022 | 2023 | "underscore@>= 1.0.0": 2024 | version "1.8.3" 2025 | resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" 2026 | 2027 | unicons@0.0.3: 2028 | version "0.0.3" 2029 | resolved "https://registry.yarnpkg.com/unicons/-/unicons-0.0.3.tgz#6e6a7a1a6eaebb01ca3d8b12ad9687279eaba524" 2030 | 2031 | universalify@^0.1.0: 2032 | version "0.1.1" 2033 | resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7" 2034 | 2035 | update-notifier@0.5.0: 2036 | version "0.5.0" 2037 | resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-0.5.0.tgz#07b5dc2066b3627ab3b4f530130f7eddda07a4cc" 2038 | dependencies: 2039 | chalk "^1.0.0" 2040 | configstore "^1.0.0" 2041 | is-npm "^1.0.0" 2042 | latest-version "^1.0.0" 2043 | repeating "^1.1.2" 2044 | semver-diff "^2.0.0" 2045 | string-length "^1.0.0" 2046 | 2047 | user-home@^2.0.0: 2048 | version "2.0.0" 2049 | resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" 2050 | dependencies: 2051 | os-homedir "^1.0.0" 2052 | 2053 | util-deprecate@~1.0.1: 2054 | version "1.0.2" 2055 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 2056 | 2057 | uuid@^2.0.1: 2058 | version "2.0.3" 2059 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" 2060 | 2061 | uuid@^3.0.0: 2062 | version "3.0.1" 2063 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" 2064 | 2065 | verror@1.3.6: 2066 | version "1.3.6" 2067 | resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c" 2068 | dependencies: 2069 | extsprintf "1.0.2" 2070 | 2071 | wide-align@^1.1.0: 2072 | version "1.1.2" 2073 | resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" 2074 | dependencies: 2075 | string-width "^1.0.2" 2076 | 2077 | wordwrap@~1.0.0: 2078 | version "1.0.0" 2079 | resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" 2080 | 2081 | wrappy@1: 2082 | version "1.0.2" 2083 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 2084 | 2085 | write-file-atomic@^1.1.2: 2086 | version "1.3.4" 2087 | resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.4.tgz#f807a4f0b1d9e913ae7a48112e6cc3af1991b45f" 2088 | dependencies: 2089 | graceful-fs "^4.1.11" 2090 | imurmurhash "^0.1.4" 2091 | slide "^1.1.5" 2092 | 2093 | write@^0.2.1: 2094 | version "0.2.1" 2095 | resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" 2096 | dependencies: 2097 | mkdirp "^0.5.1" 2098 | 2099 | xdg-basedir@^2.0.0: 2100 | version "2.0.0" 2101 | resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2" 2102 | dependencies: 2103 | os-homedir "^1.0.0" 2104 | 2105 | xtend@^4.0.0: 2106 | version "4.0.1" 2107 | resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" 2108 | --------------------------------------------------------------------------------